Track collection in Anylogic - anylogic

I'm building a pedestrian model using Anylogic. I have set my agents move in several groups between S2/S3/S4 and S1 (the movement direction is indicated by the blue two-way arrow in the figure). Background picture for problem statement
I have build a cyclic event and type these code in "action" to collect their track data:
t = time(); //get time
for(Agent p: level.getPeds()){
x = p.getX(); //position x
y = p.getY(); //Position y
id = p.getId(); //get pedestrian id
collectionTime.add(t); //add data
collectionID.add(id);
collectionX.add(x);
collectionY.add(y);
Timeid.add(t,id);
XY.add(x,y);
}
I also add these code in "Main-Agent type_Agent actions_On destroy" to write data into excel file:
TrackCollection.writeDataSet(Timeid,1,1,1); //TrackCollection is the name of excel file
TrackCollection.writeDataSet(XY,1,1,3);
But in this way I can only collect all the trajectories together in the model. How can I collect the tracks of these different groups separately? Or how to collect tracks from different PedSources?

Your question is a bit unclear, nevertheless, if you are creating groups, you can do this after creating a groupId variable in your pedestrian agent.
for(Pedestrian p : group.getPeds()){
p.groupId=group.getId();
}
you can use this groupId and export it to your excel too so you can keep track of the groups

Related

Paraview - get current time_index in ProgrammableSource

I have an array that has exactly as many rows as there are time steps in the animation. Now I want to have the row associated to the current time step as vtkTable as output of a ProgrammableSource. My code (for the ProgrammableSource) so far looks like this:
import numpy as np
file = "table.csv"
tbl = np.genfromtxt(file, names=True, delimiter=",", autostrip=True)
for n in tbl.dtype.names:
v = tbl[n][2]
output.RowData.append(v, n)
Which currently always writes out the third line (v = tbl[n][2]). Is there a way to pass the current time step (index) in place of [2]?
The best is to make your Programmable Source timesteps aware.
So you should fill the Information Script (advanced property) to declare the list of available timesteps, and then in the main script, get current timestep and output the data you want.
See this example from the doc.

Count the sum of outputs

I have created an agent type named "Process" with a basic flow process inside (source-process-sink), in that agent i added a data output (named Treated) that counts the number of agents that went through the sink.
Now in my main i've put a population of that agent "Process" (lets say a population of 10)
my goal is to create a chart that shows the number counted by the data output of every agent of the "Process" population i tried to do a sum function { sum(Process.Treated, p ->p.count())} but it did not work
To know how many agent passes in the sink block of the "Process" Population, you do not have to count. It is enough for you to access the data in the sink block itself in the following way: process_population(index).sink.count()
You can use a bar chart to display for each member of your population the amount of agents that have left the sink block:
DataItem myDataItem = new DataItem();
for (int i = 0 ; i < process_population.size() ; i++)
{
myDataItem.setValue(process_population(i).sink.count());
MychartBar.addDataItem(myDataItem, "Titel" , Color);
}
MychartBar.updateData();
If you really want to invest and you want to add an X-axis with labels with the name or the index of each agent in your population, you can do the following instructions:
Put text labels below your chart bar in the lower left corner.
Define the Replication property for it as the population size: process_population.size().
For its X position property use the following code:
MychartBar.getX((MychartBar.getWidth()/(process_population.size()-1))*index
Under the Text property, you can put index + 1 to get the index of the agent or put any variable that is inside the agent, for example its name process_population(index).name
Good luck!

AnyLogic: how to programmatically populate the Experiment page with information from Database?

I have a Supply Chain simulation model where the names and locations of the warehouses are fed from the database that I have in the model. What I want to achieve is the following:
When simulation starts, it copies the warehouse names from the DB and links them to the respective agents on the Experiment page. That is to say, let's say I have two warehouses: WH1, WH2. It should display theses as text on the Experiment page and when I click on WH1, it should take me to the respective agent. I have various plots inside the agents. The idea is to give the user the flexibility to be able to interact the model and take screenshots of the plots of whatever warehouses they wish.
Is this achievable in AnyLogic? If yes, how?
I tried to follow the recommendation of AnyLogic of creating interim variables, but can't really scale this up when I have hundreds of nodes.
Write into the "on click" field of the replicated Text object:
I resolved this issue in the following manner. This creates the list of my agents, sorts them alphabetically by agentName in the Main agent.
Initializing the variables. Here quotient and reminder helps me to keep track of the columns; which of each should contain 60 agent names numberPerColumn.
int row=0;
int numberPerColumn=60;
int quotient=0;
int remainder=0;
int i1=0;
int newIndex=0;
Looping through the agents, creating ShapeText object to display their names.
while (i1<myAgents.size())
{
int ii=i1;
String myAgentName = myAgent.name;
ShapeText text = new ShapeText(
SHAPE_DRAW_2D, true, 300, 300.0, 0.0, 0.0,
black, myAgentName,
font, ALIGNMENT_LEFT )
{
//3. Overriding the onClick() method with the action that I want to happen upon click. In this case, it will take me to the `viewArea` inside `myAgent`.
#Override
public boolean onClick(double x, double y)
{
myAgent.viewArea.navigateTo();
return false;
}};
//4. Setting the objects' position programmatically.
quotient=i1/numberPerColumn;
remainder=i1%numberPerColumn;
text.setPos(quotient*250+50, -4550+remainder*20);
presentation.add(text);
i1+=1;
}

How can I inject agents in a source block from an uploaded database table?

I am trying to inject agents from a database into a specific source block. The database consists of 2 columns of "OrderType" & "OrderAmount". I wish to inject "OrderAmount" of agents of their corresponding "OrderType" into this source, while retaining the differentiation (I.E. by storing a parameter attribute ID of each entry/agent in the corresponding agenttype of the source block).
I have saved the entries from the database in collections and constructed a table as such (For both arrays; type = double):
double [][] ArrayCustomerOrders = new double [coll_CustomerOrderType.size()][2];
for (int i = 0; i < coll_CustomerOrderType.size(); i++) {
ArrayCustomerOrders[i][0] = coll_CustomerOrderType.get(i);
ArrayCustomerOrders[i][1] = coll_CustomerOrderAmount.get(i);
}
I tried playing around with the source block calls of inject() function in the same event as I constructed the order table in, but was unable to inject eligible arguments.
Does anyone have a suggestion on how to go about this?
In your case, you can simply replace the Source block with an Enter block (named "myEnterBlock"):
Create an empty agent population pop_Orders with an agent type that has 2 parameters p_Type and p_Amount.
In your for-loop code, when you have the current order type and amount, create such an agent and push it into the Enter block directly:
myEnterBlock.take(add_pop_Orders(currentType, currentAmount))

Condition For Select Output based on distance between two different GIS Nodes

I am trying to find a condition to put in select output that is based on distance between two GIS points. My network includes a tram with people and I want my person to get off at tram stop nearest to its house. The tram moves in a counter loop and I want to place condition so that the person exits drops off at the right tram stop. Could you please help me with it?
I have already tried distanceByRoute but I don't know how to form a condition for it via statechart or in selectOutput.enter image description here
Assumptions
You have a population of Station-Agents named stations
You have a population of Passenger-Agents named passengers
You have a population of Tram-Agents named trams
You have a population of Home-Agents named homes
Step by step
Add toTram-Agent a variable nextStation of type Station in which the moveTo-Block always saves the current arrival station
Add to Passenger-Agent a parameter of type Home named home where at model startup a Home-Agent is filled in
Create a function named getNearestStation, with a input parameter of type Passenger and output of type Station:
//initialize with first station
Station nearestStation = stations.get(0);
double distanceToNearestStation = passenger.home.distanceByRoute(nearestStation);
double currentDistance;
for(Station station:stations){
currentDistance = passenger.home.distanceByRoute(station);
//save it if you find a closer station
if( currentDistance < distanceToNearestStation){
nearestStation = station;
distanceToNearestStation = passenger.home.distanceByRoute(station);
}
}
return nearestStation;
Instead of having a Station Agent, you could also use GISPoint for both your Variable nextStation inside tram and in the getNearestStation code.
Add a dropoff-Block to your flowchart and set the dropoff condition to the following:
getNearestStation(agent).equals(container.nextStation)
Additional note
In order to make the distance calculation less often, execute the getNearestStation only once at initialization of each passenger and save it in a variable, instead of calculating it each time it passes the dropoff block.
enter image description here
tramCollection here is my collection of tram stops (in GIS/INode) located on my map in Main.