Few blocks in the Anylogic Process Modeling Library like "Source" have actions like "On exit" and "On at exit". What is the difference between the two?
I was trying to create a simple flow of:
source -> SelectOutput -> Service -> Sink
The agent being created by source block has a Boolean property "is_vip".
When I assigned agent.is_vip to true or false in the "on exit" action of the source, the routing did not work, but when I moved the logic to "on at exit" of the source block, the routing started working.
There is no question here, but you are correct and that is the difference between the boxes. OnAtExit is evaluated before an agent exits the block. OnExit is evaluated after it left.
If a downstream block like SelectOutput depends on some upstream changes, they will not be registered if done in upstream OnExit as the agent is already in the SelectOutput block.
Always safer to use OnAtExit
Related
I am trying to use priority based queuing in my queue block. My process is as follows:
source, wait, queue, packing_machine
On exit of the wait block, the agent gets assigned a priority in agent.atrPriority. In queue I have selected Queuing: Priority based and at Agent priority I use: agent.atrPriority.
By printing to the console I am checking if the sequence in which the agents enter the packing_machine block is correct (according to their priority), but it isn't. It keeps sending the agents from queue to packing_station on a FIFO basis.
I have tried assiging agent.atrPriority at different places in the model, but I do not think that that is the problem. i have also tried using agents comparison with agent1.atrPriority.before(agent2.atrPriority); but it gives the error ' Cannot invoke before(int) on the primitive type int.
Does anyone know why it is not working accordingly?
The queue is working, so it is not a bug.
Try a quick test: put another delay between the Wait and the Queue. Set the delay duration to be 0.0001 sec or something tiny.
If this fixes it, the culprit is that you change the atrPriority field "on Exit" of Wait, which is effectively too late. It basically changes after the downstream Queue accesses the priority value.
Another option: change the atrPriority value before you call wait.free(...). This way, you can be sure the priority is set to the right value before the agent enters the queue
I am wondering how I can combine "while condition is true" and "given quantity" at the same time, regarding AnyLogic dropoff block.
The following chart is working well. While condition (agent.aclass == true) is true, element agent (Cargo) are dropped off. For your reference, Cargo has a bool parameter (aclass or !aclass) .
However, my problem is that "all available element agents are dropped off". I would like to specify a certain quantify (for example, 1, 2, or whatever) to be dropped off, keeping the condition "while condition is true".
Would you help me?
All agents are dropped off even though I want to specify the quantity to be dropped off.
Yes, the Dropoff block doesn't support what you want directly, since the dropoff 'protocol' can only be "All available" or "Specified number" or "While condition is true".
Easy solution
The easy way to get round it is to incorporate the 'have I dropped off beyond my threshold?' check into the condition.
So you would
Maintain a count (via an int Variable called, say, numDroppedOffThisBatch) of the number currently dropped off in the current 'batch', reset when the agent enters the Dropoff block ("On enter" action).
Change your Dropoff while condition to be agent.classA && (numDroppedOffThisBatch++ < 2) if, say, your threshold was 2.
That is, you only dropoff it it's a class A cargo and the number you have previously dropped off for this carrier agent is less than the threshold. The ++ after the variable name is a postfix operator in Java, which means it only increments the variable after it has been used in the expression. (So it does represent the number already dropped off.) You could equally have used ++numDroppedOffThisBatch <= 2 but the variable name is a bit misleading then.
Overly-complex but interesting alternative
Another option is as below, which effectively 'instantly re picks-up' (i.e., in zero sim time) the agents that shouldn't really have been dropped off. This is much more complex but is an interesting approach to understand (and similar things are useful in other contexts), so I've left it in...
It's tricky because you have to understand some under-the-covers details of the order in which things happen with a Dropoff block. Basically, dropped-off agents have their "On dropoff" actions run and are sent to their next block before the carrier agent leaves the Dropoff block. This actually makes things easier for us since we know we can 'initially process' dropped-off agents before the carrier agent leaves. So, we
Dropoff using the while condition as currently, but then have the dropping-off agent go into Pickup block (set to pickup "All available agents") and the dropped-off agents go into a Select Output block which goes either to a Queue (attached to the Pickup block via its special port) or its normal current destination (which looks like a MoveTo block from your (tiny!) screenshot).
Maintain a count (via an int Variable called, say, numDroppedOffThisBatch) of the number currently dropped off in the current 'batch', reset when the agent enters the Dropoff block ("On enter" action) and incremented as the dropped-off agents are dropped-off ("On dropoff" action) which is before they actually leave the block or test the following SelectOutput condition.
Also maintain another count variable numProcessedThisBatch (also reset to zero when the carrier agent enters the Dropoff block).
Agents dropped off then go into a SelectOutput which, if numProcessedThisBatch is greater than or equal to your 'how many should really have been dropped off' threshold, get routed to the Queue; otherwise they carry on as normal. (Note we are not checking numDroppedOffThisBatch here, which will always be the total number dropped off at this point.)
When a dropped-off agent enters the Queue or MoveTo blocks (i.e., when it finishes 'processing' either way), increment numProcessedThisBatch.
Below is a sample process flow screenshot (note the meaningful naming of blocks). The bit outside the red box is just stuff I added to setup a carrier agent with a mixture of class A and non-class-A Cargo agents via the buttons (and I just represented the 'follow on' flows for the carrier and should-actually-have-been-dropped-off cargo agents as nominal Delay blocks).
Here I had the carrier agent contain 3 class-A cargo agents and 2 non-class-A one, with a threshold of 2 agents to 'actually' dropoff (which I held in a variable for clarity).
To make the sequencing clearer (and to show how everything occurs at the same sim time), below are some traceln console messages produced which help understand what's happening. (The ones after I manually set up the carrier via the buttons are prefixed with the simulation time.)
Creating cargo class A agent
Creating cargo class A agent
Creating cargo class A agent
Creating cargo non-class-A agent
Creating cargo non-class-A agent
Creating carrier agent
6.699999999999991: carrier dropping off cargo agents by condition
6.699999999999991: cargo On dropoff action
6.699999999999991: cargo On dropoff action
6.699999999999991: cargo On dropoff action
6.699999999999991: Cargo agent starting normal process: class A true
6.699999999999991: Cargo agent starting normal process: class A true
6.699999999999991: Cargo agent ready for instant pickup: class A true
6.699999999999991: Carrier agent entering post-dropoff pickup
Notes:
It would also be a lot better to then encapsulate all this dropoff-by-condition-and-number logic into a custom block which you can then reuse wherever you want it (and avoid polluting the main process-containing agent with variables). That's obviously another level of detail and complexity.
This behaviour of the Dropoff block with a following SelectOutput is actually quite subtle. SelectOutput block conditions are evaluated before agents actually leave the previous block. (Because SelectOutputs are just routing decisions, they aren't really 'part' of the flow, in the sense that agents spend no time there; think of them as being used to say 'Where should I go next when I leave the preceding block?'.) That is why many blocks (like Delay) have "On exit" and "On at exit" actions. (The latter runs before AnyLogic even tries to see what block it should go to next, so will happen before a following SelectOutput check.) It just happens that Dropoff blocks run their "On dropoff" actions before checking what the onward block might be; thus they function in the same way as "On at exit" actions in other blocks.
I want to use SelectOutput5 block in order to differentiate same agents according to machines which they have been assigned. As you can see the images, one of the example of my SelectOutput5 block's condition is;
agent.st2Tezgah == "M117";
However even though st2Tezgah parameter has M117 value in it, it does not trigger and it goes false section.
I check the parameter with traceln(agent.st2Tezgah) as you can see the image, the value is true.
Why SelectOutput5 does not trigger properly?
Flowchart
Code
Traceln
st2Tezgah parameter
DB
Result
Two things:
Always compare strings using .equals("myString"), not ==.
Make sure you do not set the st2Tezgah variable "just before" the SelectOutput5. Try having a delay (with 0 duration) before it and see if it works. If so, you need to learn about the difference of "on exit" and "on at exit" (subtle but important here)
I have a source and a variable. in the "on exit" source section there is "variable=source.count()". The source generates n agents by inject fuction, but the variable has value n-1. why?
thanks for the help.
so I assume you want to count the agents that have been generated on that source.
Using a variable is in the first place redundant since you can use source.count() everywhere in your model instead of the variable, and it will work.
Nevertheless if you insist in using a variable, you need to use the variable in the block AFTER the source since it seems that the count is made internally in anylogic after the "on exit" action.
so for instance if you have a delay block after the source, write variable=source.out.count(); in the "on enter" action of the delay block.
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.