How to trace ped's location within different nodes? - AnyLogic - anylogic

Is it possible to modify agent's variable by tracing it's position whether it's inside or outside a certain node?
I have a string variable position inside pedestrian which I want to define depending if agent is outside, inside green or red node (ex. "Green", "Red" or "None".).
I digged up the following code that works fine where it comes to tracing if agents are inside a given node or not, but I don't know how to use it so it actually modifies a variable inside an agent.
nodeGreen.getPeds(),p->node.contains(p.getX(),p.getY())
my simple model with green and red node
new agent - "pedestrian" with string variable
Many thanks for help,
Peter

Well, you need to periodically check within the Pedestrian agent and adjust the variable accordingly.
Best set a cyclic event that executes:
if (main.nodeGreen.contains(getX(), getY()) {
position = "Green"
} else if // ... do for the other types
Side note: using Strings here is very error-prone and not scalable. Maybe create a function instead in your Pedestrian agent type such as f_getCurrentNode that returns a Node using the (adjusted) code above. Make it return null if the ped is in no node. Now, you can dynamically check for each agent where it is.

Related

Can stopline behavior be toggled dynamically?

This model simulates cars pulling up to pumps at a gas/petrol station. I have a custom car agent 'MyCar' that passes through an upstream stopline. At this stopline it calls the agent's function which checks the availability of the two pump stations in the roadNetwork in Main. This function returns a RoadNetworkConstant 'PASS_THROUGH_STOP_LINE' or 'STOP_BEFORE_STOP_LINE'.
I'm unable to pass this constant value back into the 'Stop line behavior' property in a CarMoveTo block (for a different stop line further downstream but before the car reaches the pumps) in Main even when I start typing the name of my agent 'MyCar'.
Is it possible to change the Stop Line Behavior dynamically? If so, is this a resonable approach? If not, what would you suggest?
You need to use 'car', not 'MyCar'. Check out the magic light bulb and how keywords work for you: https://www.google.com/url?q=https://www.benjamin-schumann.com/blog/2016/2/4/the-magic-lightbulb-and-how-it-can-help-your-anylogic-modelling&sa=U&ved=2ahUKEwiuz-ytq9D8AhWsSvEDHZccDTUQFnoECAkQAg&usg=AOvVaw3XapUwKyi_Bi9_2JjGrN0b

Set transporter speed based on parameter of transported product?

In my model I am transporting (path guided) several types of products (motors) by an agv trough a manufacturing line with 27 cycles. It´s a flowing manufacturing line. That means the product gets manufactured while the agv is constantly running.
To model that I created an agent population called "motors" with parameter "axelType" (string) which is loaded from column "axel_type" in database "manufacturing_sequence" (local excelsheet) and is placed on Main.
Each motor is placed on an transporter "agvAssembly" (in Flowchart as: Transporter) and runs from node "locationCycle1" all the way to "locationCycle27".
Now I want to change the transporters speed at each of the 27 cycle nodes dependent on the currently loaded motor. To do that I got another database called "speeds_axel" which includes all the needed speeds for the cycles and respective parameter name for axelType (column axel_type).
So now, when the transporter enters a node I have to check first the nodes name. Than I want to read out the parameter "axelType" of the currently in that node entered agent "Motor" and search in the database for the respective speed.
In the block "transporter Fleet" - "On enter node:" I wrote as an example for cycle 1 the following:
if (node == locationCycle1) {
unit.setMaximumSpeed(
selectFrom(speeds_axel)
.where(speeds_axel.axel_type.eq(motor.axelType))
.firstResult(false, speeds_axel.cycle1)/60.0,MPS);
}
When running the model I get the following error:
"motor cannot be resolved to a variable"
(location: TransporterFleet)
I think that error accures because my approach doesn't specify which motor I mean. How can I clarify to AnyLogic that I always mean the current motor which enters the node?
I need something like this:
if (node == locationCycle1) {
unit.setMaximumSpeed(
selectFrom(speeds_axel)
.where(speeds_axel.axel_type.eq("get motor which is currently in locationCycle1".axelType))
.firstResult(false, speeds_axel.cycle1)/60.0,MPS);
}
the biggest problem in your model is that you don't follow conventions. An agent type should be named with an uppercase first letter
Why is this important? Because you want to make the difference between Motor, motor, and motors
Motor is the class (or Agent Type)
motor is an instance of that class (or agent type)
motors is a population.
Since you don't follow this convention, you make mistakes of this kind since motor is a class
in your case when you do motor.cycle1
if you followed the conventions, you would be doing
Motor.cycle1 (which is obvioulsy wrong)
Note that Motor is the Agent Type name, and what you really want is to know for a particular motor what the value of cycle1 is
The first thing you need to do with this model, is get back to using the conventions, and this will probably solve this problem and many problems in the future.
Just because you have a population called motors (which the agents within your flow 'come from' --- though it looks like they don't actually; see later), this does not mean that you can 'magically' refer to the current agent via the singular form motor at any point in the code. (And, similarly, your agent type being Motor does not mean you can use the lower-case form to refer to 'the current one'.)
In Transporter Fleet block "On enter node" actions, you refer to the current transporter via the unit keyword; see the help page. The motor is not the transporter; it's the thing being transported.
So, just use the "On exit" (or, better, "On at exit") actions of your MoveByTransporter blocks (which trigger on arrival at the destination node), where you can refer to the current motor (the agent in the flow) via the agent keyword; again, see the block help.
But, from a quick glance, there appear to be a few important changes/simplifications you should also make (though hard to definitively tell without details of all your code):
You are using a Source block to add agents (motors) to the flow when you have already created the motors in your population. You should be using an Enter block instead to add the (already-existing) Motor agents to the flow at the appropriate time (triggered by code: I imagine you want one to start at model start time, requiring code in Main's "On startup" action, and then others added either at certain simulation times or when earlier motors reach a certain stage in the process...). If your population was actually just for 'templates' of data for each motor axle type (and you would then potentially create multiple instances of motors for a given axle type) then your current logic might make sense, but your screenshot of your manufacturing_sequence table makes clear that isn't the case. (If you did go that route, you would want to rename your population so that its purpose was clear.)
It looks like you have a 'looping' process (with the same process behaviour for all your in-sequence nodes), so you should look to make your process generic with an explicit loop (so you don't have near-copies of blocks for every node in your sequence). There is a fair amount of detail in terms of how you do this but roughly:
Track the node the motor is currently in (or its sequence number) via a variable in the Motor agent.
Use a collection (List) which contains the nodes-in-order to determine where it has to go to next.
Your process would have a MoveByTransporter --> Delay --> SelectOutput sequence (plus TimeMeasureStart/End if you're using them), where SelectOutput loops back to the MoveByTransporter if the motor is not yet at the last node.

Customize the coordinates of the entity in pedWait

In a pedwait entity, I want each element that enters to have my own specified coordinates. I use the method: ped.setXY(100,100), but it has no effect. What should I do?
First you need to read the Java doc when using a new function.
The setXY function states "Sets the coordinates of the agent location. Should only be used to initialize the agent location. Assumes the agent is not moving."
The other options that I would have suggested if you were using normal agents would be to use jumpto() or moveTo() but if you try these in a pedestrian model you will get an UnsupportedOperationException error.
Pedestrians are special kind of agents so you can use all the normal agent functions on them.
The correct way to do this is to use the waiting location inside the Wait block

Using agent parameters from main to different agent?

For a project I'm trying to select the right output if a parameter of the created agent is true. The agent is created in the main but goes into a different agent for the selection of the output. If I use a select in the main and use the statement for the parameter as condition it works fine. Whenever it enters the agent and I use the same statement it gives an error (Description: product1 cannot be resolved or is not a field. Location: testCase5/Transport/selectOutput - SelectOutput).
I tried using different conditions like main.agent.product1 . Can't seem to solve the issue. I know that it has to do something with declaration probably but I'm clueless at the moment.
//for the condition that works if I put the selectOutput in the main
agent.product1
//for the condition in the agent I tried the same but didn't work. also tried
main.agent.product1 // Gives the same error but for (Description: agentcannot be resolved or is not a field.)
(Main)agent.product1
//And a few more
In AnyLogic each block of a project flow (regardless if from the process modeling library, the pedestrian library or another) has the type of Agent that is flowing through it defined in its properties. You can find this setting as Agent type in the block's properties under Advanced.
If you fail to set this correctly (meaning this setting equals the type of Agents you let flow through it), it will still flow through, BUT: you cannot access the specific properties of the Agent type.
That said, usually you do not even have to think about, because AnyLogic has an automatism there: The first block of your process flow, typically a Source-block or a Enter-block is the only block where you have to make the correct setting, all attached blocks get it then automatically!
However this does not work when:
You have separate flows (eg. you leave one flow through an Exit-block and enter another by an Enter). You'll manually have to put the correct setting also for the first block of the second process flow.
Your process flow is continued inside of another Agent/Custom Block, as in your example. AnyLogic doesnt realize the process flow inside your custom block is logically connected to the outside process flow in main. You have to specifiy manually again the Agent type flowing through in the first block of your process inside your Custom Block.

How to set one of the predefined layout patterns just for one agent type? (preferably by code)

I plan to use two types of agents in my simulation.
For one agent type I plan to use set the position explicitly by the setXYZ() method called in the "On startup" action of that agent type.
Fort the second agent type I plan to use one of the predefined layout patterns (random or ring) as described in:
https://help.anylogic.com/index.jsp?topic=%2Fcom.anylogic.help%2Fhtml%2Fagentbased%2FContinuous_Layouts.html
The problem is the following code placed in in the "On startup" action of the Main agent type doesn't differentiante between my two agent types (and places all the agents in a circle e.g.):
setLayoutType(Agent.LAYOUT_RING);
applyLayout();
Shall I somehow modify the code above (as I've tried already) or is there another way?
I think the layout type has to be the same for all agents present in the space... nevertheless... you can do this:
//first you apply the ring layout to everything
setLayoutType(Agent.LAYOUT_RING);
applyLayout();
//then you define the type of agent you don't want to follow the ring layout separately
for(int i=0;i<100;i++){//assuming you will create 100 agents initially
MyAgent p=add_myAgents();//you need to create your agents after the ring layout is applied though..
p.setXY(uniform(0,500), uniform(0,500));//assuming your agents are in a 500x500 square in main
}
I don't know if there is a better way... but this is what I know is possible