I want to convert from Point to Agent that gives me proper location - anylogic

I am working on agent-based modelling where I have created a function that generates a random point inside a region and then converts that point to agent. However, when I use this function later, the points don't give me a proper location on the map for further computation. I want to know what I am doing wrong? Or how can this be improved.
The return type for the function is ArrayList
ArrayList<DeliveryHouse> House = new ArrayList<DeliveryHouse>();
int i;
Point p;
DeliveryHouse h;
for(i=0;i<packagesC2C;i++)
{
p = main.Region2.randomPointInside();
h = main.deliveryHouse.setLocation(p);
House.add(i, h);
};
return House;

The major problem I see with your code is that you are not initializing the agent "h" but pointing it to one agent you have at main which means you keep changing its location in the loop and it will only reflect the last location. The array list you created will have multiple references to same agent instead of one agent per location.
If you want to create an agent per location you need to create an agent population called "deliveryHouses" of the agent type "DeliveryHouse" and change your code to the following. Note that the population will have all the agents so you do not need any output from the function.
int i;
Point p;
for(i=0;i<packagesC2C;i++)
{
DeliveryHouse h = main.add_deliveryHouses();
p = main.Region2.randomPointInside();
h.setLocation(p);
}

Related

Anylogic find agent in population and access one of its variables

I want to find the index my agent has in its population (named dullieses), which lives in my Main-agent.
I want to find one of my dullieses-agent via one of its variables (DullyID) which, in this example, shall be equal to my counter variable. Both are of type int.
I have tried the following to no avail:
int i = 0;
for ( i = 0; i < dullieses.size(); i++){
if (Main.dullieses(i).DullyID == counter){
traceln("I found myself! I have the index " + i);
break;
}
}
Error code: Cannot make a static reference to the non-static method dullies(int) from type Main.
How can I find my agent in my population and find its index?
I think you're probably already in main and don't need to add Main..
Anyway, I would recommend using:
Dully d = findFirst( dullieses, d -> d.ID == counter );
d.variable = 10;
I used variable and 10 as random examples, but this should give you the idea. Also replace Dully with whatever your agent type name is.
You don't need to use a custom ID parameter in your agents (at least not for what you're doing here).
All agents in a population have the getIndex function which returns their index in the population. Just be wary that, if you remove agents from a population, their indices will change (so you can't, for example, use their index as a unique ID for them in that case).

Ironpython script in Ansys Customization tool

I'm a beginner in Python and I'm working with the Ansys Customization Tool (ACT) to add my own extension.
Is there a direct way to fill a file with every node's coordinates after deformation?
hopefully in 3 lines or columns: x , y , z
So far I only found the GetNodeValue object but it only gives me the displacement and I need the deformed coordinates for the entire model.
My first idea was to add the displacements to the initial coordinates but I didn't manage to do it.
Many thanks for your help
Lara
APDL Snippet
Add an APDL Snippet in the solution part of the tree:
/prep7
UPGEOM,1,1,1,file,rst ! adds the displacements to the nodal coordinates.
cdwrite,geom,nodesAndelements,geom ! Writes node and element data to nodesAndelement.geom
I'm not sure if you can work with the output format from cdwrite, but this is the quickest solution i can think of.
If you want to automate you have to insert the command snippet via
solution = ExtAPI.DataModel.Project.Model.Analyses[0].Solution
fullPath = "path//to//snippet"
snippet = solution.AddCommandSnippet()
snippet.ImportTextFile(fullPath)
ACT
If you want to stay in ACT it could be done like this:
global nodeResults
import units
analysis = ExtAPI.DataModel.Project.Model.Analyses[0]
mesh = analysis.MeshData
# Get nodes
allNodes = mesh.Nodes
# get the result data
reader = analysis.GetResultsData()
# get the deformation result
myDeformation = reader.GetResult("U")
nodeResultsTemp = []
result_unit = myDeformation.GetComponentInfo("X").Unit
for node in allNodes:
# get node deformation and convert values in meter
deformationNode1 = myDeformation.GetNodeValues(node.Id)
deformationNode1[0] = units.ConvertUnit(deformationNode1[0],result_unit,"m","Length")
deformationNode1[1] = units.ConvertUnit(deformationNode1[1],result_unit,"m","Length")
deformationNode1[2] = units.ConvertUnit(deformationNode1[2],result_unit,"m","Length")
# add node coordinates (in meter) to the displacement
mesh_unit = mesh.Unit
node1 = mesh.NodeById(node.Id)
node1CoorX = units.ConvertUnit(node1.X,mesh_unit,"m","Length")
node1CoorY = units.ConvertUnit(node1.Y,mesh_unit,"m","Length")
node1CoorZ = units.ConvertUnit(node1.Z,mesh_unit,"m","Length")
deformationNode1[0] = deformationNode1[0]+node1CoorX
deformationNode1[1] = deformationNode1[1]+node1CoorY
deformationNode1[2] = deformationNode1[2]+node1CoorZ
nodeResultsTemp.append([node1.X,node1.Y,node1.Z,deformationNode1[0],deformationNode1[1],deformationNode1[2]])
nodeResults = nodeResultsTemp

Looking for advice on improving a custom function in AnyLogic

I'm estimating last mile delivery costs in an large urban network using by-route distances. I have over 8000 customer agents and over 100 retail store agents plotted in a GIS map using lat/long coordinates. Each customer receives deliveries from its nearest store (by route). The goal is to get two distance measures in this network for each store:
d0_bar: the average distance from a store to all of its assigned customers
d1_bar: the average distance between all customers common to a single store
I've written a startup function with a simple foreach loop to assign each customer to a store based on by-route distance (customers have a parameter, "customer.pStore" of Store type). This function also adds, in turn, each customer to the store agent's collection of customers ("store.colCusts"; it's an array list with Customer type elements).
Next, I have a function that iterates through the store agent population and calculates the two average distance measures above (d0_bar & d1_bar) and writes the results to a txt file (see code below). The code works, fortunately. However, the problem is that with such a massive dataset, the process of iterating through all customers/stores and retrieving distances via the openstreetmap.org API takes forever. It's been initializing ("Please wait...") for about 12 hours. What can I do to make this code more efficient? Or, is there a better way in AnyLogic of getting these two distance measures for each store in my network?
Thanks in advance.
//for each store, record all customers assigned to it
for (Store store : stores)
{
distancesStore.print(store.storeCode + "," + store.colCusts.size() + "," + store.colCusts.size()*(store.colCusts.size()-1)/2 + ",");
//calculates average distance from store j to customer nodes that belong to store j
double sumFirstDistByStore = 0.0;
int h = 0;
while (h < store.colCusts.size())
{
sumFirstDistByStore += store.distanceByRoute(store.colCusts.get(h));
h++;
}
distancesStore.print((sumFirstDistByStore/store.colCusts.size())/1609.34 + ",");
//calculates average of distances between all customer nodes belonging to store j
double custDistSumPerStore = 0.0;
int loopLimit = store.colCusts.size();
int i = 0;
while (i < loopLimit - 1)
{
int j = 1;
while (j < loopLimit)
{
custDistSumPerStore += store.colCusts.get(i).distanceByRoute(store.colCusts.get(j));
j++;
}
i++;
}
distancesStore.print((custDistSumPerStore/(loopLimit*(loopLimit-1)/2))/1609.34);
distancesStore.println();
}
Firstly a few simple comments:
Have you tried timing a single distanceByRoute call? E.g. can you try running store.distanceByRoute(store.colCusts.get(0)); just to see how long a single call takes on your system. Routing is generally pretty slow, but it would be good to know what the speed limit is.
The first simple change is to use java parallelism. Instead of using this:
for (Store store : stores)
{ ...
use this:
stores.parallelStream().forEach(store -> {
...
});
this will process stores entries in parallel using standard Java streams API.
It also looks like the second loop - where avg distance between customers is calculated doesn't take account of mirroring. That is to say distance a->b is equal to b->a. Hence, for example, 4 customers will require 6 calculations: 1->2, 1->3, 1->4, 2->3, 2->4, 3->4. Whereas in case of 4 customers your second while loop will perform 9 calculations: i=0, j in {1,2,3}; i=1, j in {1,2,3}; i=2, j in {1,2,3}, which seems wrong unless I am misunderstanding your intention.
Generally, for long running operations it is a good idea to include some traceln to show progress with associated timing.
Please have a look at above and post results. With more information additional performance improvements may be possible.

AnyLogic - custom network

I'm still having troubles with AnyLogic...I'm developing an epidemic SIRS model and I want to define my own network.
In particular, I have this matrix that defines the daily average number of contacts between age class
and therefore I want every agent to establish contact with other agents according to this matrix...it is driving me crazy :S
AgeClass is a parameter calculated with the following function
I thought to setup an event that occurs once at the beginning with the following code
Now I am saying "connect n times to a random agent"...what I want to say is "connect n times to a random agent with AgeClass k" is there a way to do so?
thanks for the support!
ps when I write int i = AgeClass i takes the value of the parameter AgeClass of the agent that is running the code, right? So i it will be different for different agents?
Probably, you have already found a solution. Here a way to do it:
Regarding age, you don't need that big if/else if sequence. Just do something like this:
int ageClass = 0; // a variable of agents
ageClass = (int) floor(age / 5.0);
if (age >= 70.0 ) ageClass == 14; // just to be sure that max class is 14
return ageClass;
Regarding the network. I would create a function named setup, so that you can put it in agent actions, on startup, e.g. setup();
You can create a link to agents object at the agent level (Person in my code, I use a connection object named contacts). The function would be something like:
// loop through age groups
for (int i = 0; i < network[0].length; i++) {
ArrayList<Person> ageGroupPeople = new ArrayList<Person>();
for (Person p : population ) {
if ( p.ageClass == i ) { ageGroupPeople.add(p) } \\ create pool of potential alters by age
}
\\ create network per agent
for (Person ego : population ) {
for (int k = 0; k < poisson(network[ego.ageClass][i]); k++) {
Person alter = randomFrom(ageGroupPeople);
if ( ego != alter ) { ego.contacts.connectTo(alter);}
}
}
I haven't checked the code and how slow might be, it is just one way to do it.
In AnyLogic, you can represent a matrix as two-dimensional Java array:
http://help.anylogic.com/topic/com.xj.anylogic.help/html/code/Arrays.html
After initializing the matrix, you may define custom contact network using the element 'Link to agents':
http://help.anylogic.com/topic/com.xj.anylogic.help/html/agentbased/Link.html

Is there a way to change directory in Modelica/Dymola automatically?

I have the following problem:
I have over 20 different models which I want to simulate one after another but I want to change the simulation directory each time.
Right now I'm manually changing directory after each simulation (from ./ModelOne to ./ModelTwo) and I'd like to know if there's a way to change it automatically when I initialize or translate the new model.
Regards
Nev
the best way is to write a script I think:
pathOfSave = {"E:\\work\\modelica\\SimulationResult\\Model1\\","E:\\work\\modelica\\SimulationResult\\Model2\\"};
nbSim = 2;
pathOfMod = { "MyModel.",
"MyModel.};
modelsToSimulate = { ""Model1" ,
"Model2"};
//If equdistant=true: ensure that the same number of data points is written in all result files
//store variables at events is disabled.
experimentSetupOutput(equdistant=false, events=false);
//Keep in the plot memory the last nbSim results
experimentSetupOutput(equdistant=false, events=false);
for i in 1:nbSim loop
//delete the result file if it already exists
Modelica.Utilities.Files.removeFile(pathOfSave + modelsToSimulate[i]);
//translate models
translateModel(pathOfMod[i]+modelsToSimulate[i]);
// simulate
simulateModel(
pathOfMod[i]+modelsToSimulate[i],
method="dassl",
stopTime=186350,
numberOfIntervals=nbOfPoi,
resultFile=pathOfSave + modelsToSimulate[i]);
end for;
You can also put the command cd("mynewpath") in the initial algorithm section, if you want it tobe attached to the model.
model example
Real variable;
protected
parameter String currDir = Modelica.Utilities.System.getWorkDirectory();
initial algorithm
cd("C:\\Users\\xxx\\Documents\\Dymola\\MyModelFolder");
equation
variable = time;
when terminal() then
cd(currDir);
end when;
end example;
In any case you can find all commands of dymola in the manual one under the section "builtin commands".
I hope this helps,
Marco