Prioritising pallet racks in a racking system - anylogic

I am currently attempting to model a warehouse in AnyLogic. I have been using the Rack system with 5 pallet racks. I need the model to fill the pallet racks one at a time, i.e. currently when i initialise the model at 50% utilisation, all of the pallet racks are filled to 50% and i would like 2 and a half pallet racks to be filled up. Conversely, i would like the RackPick block to pick products from a single pallet rack until it is totally empty before it moves onto the next full pallet rack within the racking system. How can i achieve this? I am new to Anylogic.

I will show you how to do it with storing... You will have to do something similar with the picking.
You will need the following things:
Put the palletRacks in the order of priority in your rackSystem
Your agent will have a parameter called palletRack of type PalletRack with default value main.getPalletRack()
You need to create that getPalletRack function in main.
This function will use the following code:
for(PalletRack p : rackSystem.palletRacks){ //loops through the palletRacks of the rack system
if(p.hasSpace()) //checks if it has space
return p; // if it has space, return the palletRack
}
return null;
if you are familiar with this, you can also just have this in the function:
return findFirst(rackSystem.palletRacks,p->p.hasSpace());
Both do the same thing... but the second is not known by a new AnyLogic user
Finally:
In your rackStore, you will do the following:

Related

The storage does not contain the agent - Anylogic

I'm facing an issue with the project I'm developing using Anylogic.
I would like to have a rack store block and a rack pick block to select a pallet rack programmatically, choosing it from an array list.
In particular, rack store is working in this way:
rack store block
The rack pick block gives me an error, saying that the first pallet rack does not contain the agent, even though, by debugging, it says that that pallet rack has no free space and moreover the agents in it are of the correct type and the agent to be picked seems to be correctly positioned in the pallet rack.
The rack pick block is the following: rack pick block
The info I was talking about the item are visible here and I printed them with the following piece of code:
traceln(palletRackListKuka.get(0).getByIndex(0).agentInfo());
traceln("class is " + palletRackListKuka.get(0).randomAgent().getClass());
traceln("has space is " + palletRackListKuka.get(0).hasSpace());
How can I solve this? Please ask for further details in case I was not clear enough.
The way RackStore and RackPick work is that the agent flowing through the blocks is the one stored and picked.
Thus your error is likely because the pallet rack you choose (programmatically) in your RackPick block is not the same pallet rack you stored that agent in when it passed through the RackStore block earlier. Your console statements just show that the pallet rack has some agents of the required type, not the agent that is flowing through the RackPick block.
You can just add the pallet rack you stored the agent in as an extra field (variable) inside it, which you then reference when picking it.
Edit: To do that, you are already providing an expression for the pallet rack to store in, so instead make that a function call to a function you create (returning a type PalletRack) which selects the pallet rack and stores it in a type PalletRack variable inside your IndustrialContainer agent.
If you want 'decoupled' picking (i.e., what to pick is determined externally in some way) that is something different where you have to have some mechanism to then
choose which specific agent you want to pick (say out of 1000 instances of the same product) which will typically relate to your 'storage/retrieval policy';
'inject' that agent into a RackPick block to pick it (e.g., via an Enter block).
See the Distribution Center example model for a version of this.

Using different pallet racks in a process flow with an id for every pallet rack

I would like to use different pallet racks in one process flow. So that I give my pallets an ID and connect it with a database. I decide in which pallet rack my pallets have to store from my forklifts. Is this possible?
And how could I do this? It doesnt work to give the pallet racks an ID and connect it with the database where I insert my pallets into source block.
Rack store and rack pick should know which pallet rack head for.
Simply switch the Pallet rack choice to the dynamic mode and write some custom condition as below. If it is true, you use palletRack, else you use palletRack1.
someCondition must be boolean, obviously.
You can make this as complex as you like (any number of racks, any detail for your condition). For this, you might want to create your own function getMyPalletRack that takes some decisive arguments and returns a PalletRack. Then, call that in the "Pallet rack/Rack system" field instead.

Error in deleteSelf(): Agent should belong to some population

I have the following model where I have a pallet agent and a box agent with a population of boxes inside the pallet agent. So pallets arrive then a forklift moves them to a table and then they enter the "delay" block that takes it to the entrance block of the Box Process. In the bottom, flowchart forklifts remove boxes from the pallets and move them to a node as shown in the picture. Once all the boxes have been removed from a pallet, a forklift takes the pallets out and they get sunk.
Currently, the removed boxes are added to a queue and they stay there. I want to remove/destroy them with a sink. When I add a sink instead of/ or after the queue I get the following error
Exception during discrete event execution:
root.pallets[0].boxes[-1]:
Error in deleteSelf(): Agent should belong to some population
java.lang.RuntimeException: root.pallets[0].boxes[-1]:
Error in deleteSelf(): Agent should belong to some population
Is there a way to get around this error. I remove the boxes from the pallets in a statechart inside the pallet agent that loops until all the boxes are removed:
if (boxes.size() > 0){
Box b = boxes(0);
b.box_location = this.getXYZ();
remove_boxes(b);
get_Main().enter.take(b);
current_N_Boxes--;}
Thank you!
Agents flowing through a process must exist inside a population. You are removing the boxes from their population (inside the pallet agent) before trying to delete them, hence the error.
There are several ways to handle this:
Use Batch/Unbatch or Pickup/Dropoff blocks to 'properly' have agents inside agents with both parents and childs moving through processes at different times. (AnyLogic handles having the unbatched/dropped-off agents still existing in the default population.)
Create your box agents inside a master population in Main, and use collections in your pallet agents to refer to the boxes inside them. Then you can 'remove' them from the pallet (by removing them from the pallet's collection) whilst keeping them in the master population until they end their part of the process.
Move your box agents to a population in Main (say unpalettedBoxes) when removing them from the pallet (use the goToPopulation function in the box agent) and proceed as in 2.

Rackstore and rackpick multiple agents at a time in anylogic

I am trying to develop a model that essentially shows the movement of material in the warehouse.
I want the rackstore block to move multiple boxes at a time in the rack using crane. In the current model, crane takes one box at a time, stores it in the rack and comes back to take next box.
Not sure if RackStore supports that, but as always, you can find a solution in AnyLogic.
One simple fix: bundle your packages together into 1 agent using the batch object. Then, they stay together until being taken out by the crane at the end (via RackPick) and you can un-batch them to their original agents. Have a look at some example models using batching.
cheers
Depending on the details of your model, one option is to use batch as Benjamin stated, but I think I feel the pickup dropoff blocks would work better because with the dropoff you can drop the boxes one by one, while the batch forces you to separate all the boxes at once...
So with the rackstore you can't do this, but if you use the pickup and then dropoff, you will have to store somewhere in your model what rack positions are free though, because when you move the crane you will have to choose the rack position yourself, while the rackstore does it automatically...
Nevertheless, the batch may also work... it depends on the details of your model

Pick front item from a two deep pallet rack

I'm am storing agents two deep in a single pallet rack with a rackStore block. When I take items out of the rack with rackStore it tries the take the agents at the back first and I get the error below saying it couldn't be picked as there are other agents in front of it.
Anyone know how I can pick from the front instead?
This is big fail in the AnyLogic Software and it is something they have to fix urgently. Since when it comes to deep positions, you have to control everything manually.
I will give you an example that is definitely not optimal on how to solve your particular question and it will be just a step for you to understand how to extend it to something more than this. Because even though this should be a very easy question, it is not. This will work only 2 racks with 2 levels deep, 1 level of height, and a unique row.
So this is the structure you would need:
Since I have no idea how long your products stay on the rack, I will assume something, which is that with the event, I will make the decision on wether getting or not a product from the rack every 5 seconds (this is absolutely arbitrary).
You will need a custom agent to store the deep position. I call the agent Box and I will have a population of boxes. Not in the picture that I also add agents to the custom population boxes.The box agent will have 2 variables: deep and position which will store the position and deep level of the agent in the rack (you will need also level and row if you have a more complex rack)
Now on the event, which runs cyclically every 5 seconds, I have the following action: (it activates if there is a box waiting, if there is a resource available and if there is no forklift moving a product to the pallet rack) I have to do this because I cannot know where the forklift is going to put the box until the box is already in the pallet rack. Then I check if a box is not behind another with the findFirst function and if everything ok, a box is sent to be picked.
if(wait.size()>0 && resourcePool.idle()>0 && rackStore.size()==0){
Box bx=findFirst(wait,b->b.deep==0);
if(bx!=null)
wait.free(bx);
}
On the rackStore exit I need to store the positions so in the "on exit" action, this code will help (you check if there is another box in the same position, and if there is, you update the value of the deep variable. Then you store the value of the position and deep of the new agent)
Box box=findFirst(wait,b->b.position==position);
if(box!=null){
box.deep++;
}
agent.deep=0;
agent.position=position;
Finally on the rackPick on exit action, once the product is picked and delivered, you update the deep value of the box that was behind it (if any)
Box bx2=findFirst(wait,b->b.position==agent.position);
if(bx2!=null){
bx2.deep--;
}
I know all this looks a bit crazy, but you have to create all the logic yourself when it comes to using deep levels...