I have an agent which needs to seize two different equipment units, one excavator, and one truck. It seizes excavator first, release it and then it seizes truck. I added some functions to the release excavator block but interestingly the agent goes to seize truck block without going to release excavator block! so thus functions do not work. How this is possible?
Please see the attached file. How can I solve this? Thank you.
That's weird. Have you tried adding any other block in between seize and release exc? In some cases it happens that some code isn't executed (i.e. in the options on a selectOutput) because you defined the conditions in the block inmediately before that. But in your case the counters remain in 0 and the next ones have the same value as the previous ones (you're sure the blocks are properly connected, right? they seem to be connected at first sight).
Related
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.
In my simulation I have different types of resources. At the start of my simulation I define several parameters to the different resources (machines). I want a predefined number of agents (e.g. 50) to run through my resource, so I chose to use a wait block inside my resources. So if there are more than 50 agents inside this resource, the wait block should release all 50 agents at once and block afterwards immediately.
The code in the wait block looks like this: Code
So if an agent with the attribute machine1 comes into the resource and if the condition self.size() == 50 isn't true yet, the program jumps to the default case instead of staying in case machine1 until this condition is true. Is there some code for an possible else-Block, something like "self.stayInWaitBlockUntilIfConditionIsTrue"? Or another solution for my problem maybe with hold blocks? Didn't find something on AnyLogic help page.
Inside case machine1:, if you put an else statement saying else {break;}, it should work.
I am trying to stopDelay at delayNucSafe1 (See Screenshot) when the car exits at carMovetoScale1 They way I am currently doing it is at the "On Exit" block of carMovetoScale1 typing: delayNucSafe1 .stopDelay() but I am getting an error that says:
Description: The method stopDelay(Agent) in the type Delay is not applicable for the arguments (). Location: Scale House/Main/carMoveToScale1 - CarMoveTo
Logic Flowchar
where I am asking to stopDelay
Can someone help with this?
The stopDelay(Agent) method is for use when there are multiple agents waiting within the delay and you need to stop the delay for ONE specific agent. If this is the case for you, you would need to know which agent you want to stop the delay for.
For instance, you would call: delayNucSafe1.stopDelay(delayNucSafe1.get(0)) to stop the delay for the agent at index 0 in delayNucSafe1. (This code would also work if there is only 1 agent in the delay).
On the other hand, if you know for sure that there will only ever be 1 agent in the delay (or if you'd like to stop the delay for every agent simultaneously), you would use the method: stopDelayForAll(). This method has the benefit that it doesn't need an argument, but it will obviously cause problems if there are multiple agents waiting in the delay, each of which need to be released independently.
So in summary:
delayNucSafe1.stopDelay(delayNucSafe1.get(agentIndex))
will stop the delay for the agent at index agentIndex within delayNucSafe1. And:
delayNucSafe1.stopDelayForAll()
requires no arguments, and will stop the delay for all agents within delayNucSafe1
I have an airlock (small room called AL_2216) between 2 areas. The airlock has many different agent types passing through it (cart, product, operator, etc). There are queuing areas on either side of the airlock.
Because the space is small, I built a short flowchart that has a queue and restricted area blocks that all agents must pass through when going through this space. If the restricted area's capacity is full, the agents wait in either the InsideQueueArea or OutsideQueueArea depending on the direction they're going.
I send agents via Exit and Enter blocks to this flowchart and it works great on the top portion of the flowchart.
BUT if I try to use an Enter or Exit block in the prepare flowchart, I get this error:
I tried using a custom block instead of Enter and Exit blocks, but that creates a new instance of the code each time and the restrictions don't work together across the multiple custom blocks.
This airlock is just one of many in my model. Without referring to the same code, I'll have multiple copies that need to refer to each other's restricted areas and the flowcharts become huge and complicated. Is there a way to get around this?
EDIT:
I'm not sure what to do with these ports. They have no properties that do anything:
EDIT2:
Here's a file to see the behavior - Model2.zip
The Prepared flowchart portion is set to "ignore" so the code will run. You can see the operators and the carts passing through AL_2216 with only 2 being allowed at a time. If you uncheck "ignore" for the prepare flowchart, the error will trigger.
AnyLogic sent the right answer!!
So I was asking Anylogic a different question and they recognized my name from this post! They sent a fix to me and it works exactly the way it should! The exception error message I was getting "out: 0 isn't supported for..." made me think the exit/enter blocks were not supported in perparation flowcharts.
But actually, the seizeCart block didn't know where to start the prep flowchart because it wasn't directly connected to the resource task start block. A quick setting change under the Advanced section of the seizeCart block defining which resource task start block to start at did the trick! Here's the email from AnyLogic:
-The error text and documentation are not sufficient for understanding this (the error text is confusing), I suppose it is obsolete error text. We will rectify the description;
-Under the question there is a more generic discussion which seems to be unrelated to the initial problem. Please let me know if I miss something or if your model does not work as you expect even after adjustment of seizeCart block property.
I think you should replace the Enter and Exit blocks that lead to the bottom input of your seizeCart Seize block with simple Port objects (from the Agent palette).
As per the help for Seize:
So it wants a direct link to a ResourceTaskStart flow and your Enter/Exit combinations might be ... not "direct" enough... Try it.
So here's what I ended up doing. It's the best I could come up with that could be easily replicated for lots of airlocks.
I've added a wait block (dummyThruAL_2216) to my Product flowchart prior to seizing the cart. This wait block injects a new Agent into sourceDummy at the cartHome node. The dummy then seizes a cart and moves through the airlock and it's restriction. Upon exiting the restriction, I check what type of agent and direct the agent to the correct exit block. The dummy agent and cart move to the Product where the dummy agent releases the cart and sinks. The sink frees the wait block and the Product seizes the cart that is right next to it and continues on it's journey.
It's an easy copy/paste to add more airlocks. Not as nice as my original, but what are you going to do... Thanks for everyone's help and suggestions.
As others have said, there are (not really documented) restrictions on what blocks you can use in preparation and wrap-up flowcharts, which mean what you're attempting won't work.
As you say, it's important to keep a single 'instance' of the airlock flow so that the restrictions (queue and restricted area) are 'global' when this represents the same physical airlock. (Otherwise a repeated custom block is precisely what you should use for each different physical airlock.)
Your best option (and assuming you needed to attach the Cart resource to the Product) is probably to
Add dummy agents (via Source block inject calls) to a separate mini-process that represents your resource preparation requirement (but now not attached to the Seize block).
Replace the Seize in your main process with a Seize-Wait-Release-Seize combination:
The Seize block seizes the cart as normal (without moving or attaching it; no 'Send seized resources' or 'Attach seized resources' options) and then injects an agent into your mini-process (which can use Exit and Enter blocks to use the airlock sub-process). This agent represents the seized resource agent (Cart) and thus should start where it starts and be animated so it looks like it. (You can make the actual Cart temporarily non-visible during this mini-process.)
When the agent reaches the end of the mini-process (at a Sink block), instantly move the related Cart to your node (use jumpTo), make it visible again and free the Product agent from the Wait block
Release the seized Cart and then immediately re-Seize it, but now attaching it (so the animation looks correct). If you use the Resource selection 'Nearest to the agent' option you should be guaranteed to seize the correct cart. (You can also use the 'Customise resource choice' option with some code to ensure that you absolutely always choose the same Cart.)
(It is simpler than the above if you don't care about having a correct animation, and you can use custom blocks to make this block combination reusable and thus not too clunky.)
Edit: A very similar alternative which also works (and is the basis for your own answer) is to have a dummy agent representing your Product in the sub-flow which seizes (and attaches) the actual Cart agent, leaving it at the Product's location to be immediately seized as above. This is slightly better since you don't have to worry about the visibility and 'jumping' of the real resource agent, plus you can move a Seize and a Release from the main flow (which now just has Wait-Seize) to the sub-flow (thus 'hiding them away').
I'm simulating a security control process, and i can't do that each passenger pickup their baggage. I have tried with Match, Combine, Pickup, but I still can't execute the commands correctly.
I've created the follow flowchart, and the problem is in the wReclaimPax, pickup and wReclaimBags blocks (you can see them in the picture).
https://ibb.co/v3V57Tm
I saw this link Anylogic - Combined multiple items back to original owner to understand something, but I still need help.
I've created 3 functions:
isMatch:
if(equipaje.pasajeroLink.equals(pasajero.equipajeLink)){
return true;
}
return false;
paxBags:
for(int i=0;i<wait.size();i++){
Pasajero p=(Pasajero)wait.get(i);
if(isMatch(p,bag))
return p;
}
return null;
bagsPax:
for(int i=0;i<wait.size();i++){
Equipaje e=(Equipaje)wait.get(i);
if(isMatch(pasajero,e))
return e;
}
return null;
Assumed context
You haven't really explained how your code is related to your process but I'm assuming the following:
Because this is luggage-retrieval, you want to ensure that a passenger
agent (Pasajero) only enters the Pickup block (representing taking bag from
carousel) when his bag (Equipaje agent by the look of it) has
arrived into the wReclaimBag Wait, and been released from it to
queue4 Queue.
For this you need triggers (to remove agents from Wait blocks) when
either a passenger (Pasajero) arrives in wReclaimPax Wait, or a bag (Equipaje) arrives
in the wReclaimBag Wait (because you don't know whether the passenger or their bag will get to their respective Wait blocks first).
So your paxBags function is called in on-entry action of the wReclaimBag Wait, and your bagsPax function in the on-entry action of the wReclaimPax Wait.
Possible problems with current approach
Without knowing more of your model it's hard to say but problems I can think of based on what you've supplied are:
Your functions return the Pasajero or Equipaje if there is one that matches. Your match check relies seemingly on bidirectional connections (links) between Pasajero and Equipaje. Obviously if they're not setup properly the model won't work and, if you're using bidirectional connections you shouldn't need to check both ends.
Your functions need calling so that, if they return non null, they then free the matching agent from the other Wait block, and free themselves. Are you doing that? Without checking, there may be issues with calling free for yourself as you enter a Wait block (since this kind of depends on AnyLogic internals as to whether you count as being 'in' the block at this stage and can be freed). If this seems to be the problem you could create a timeout 0 dynamic event instance to do the free so that you're not doing it within the scope of the on-enter action.
Your pickup block (since it's been setup so that the entering agent will always want to pickup the first agent (Equipaje) in queue4) just needs to be set as waiting for quantity 1 (though see below).
If you've done all this the most likely problem is that the underlying events ordering of AnyLogic is affecting things. When you free agents I'm fairly sure the freeing actually happens in a timeout 0 event scheduled under-the-covers. So it may be that the passenger arrives at the Pickup before their Equipment arrives in queue4 though, if you set the Pickup to be "Exact quantity (wait for)", with quantity of 1, it should handle that.
The animation of the process (numbers in/out/within each block and details when clicking on blocks) should also help you debug what is going wrong; e.g., are bags being left in the Wait when they should have been released, etc.
P.S. With this kind of thing you should always create a minimal example model to make testing the issue/solution easier (and for sharing in help forums such as this where the rest of the complexity of your model is irrelevant). Often you find the problem 'naturally' in the process of trying to construct such a model that reproduces your problem in a minimal way.