Reputation: 389
I'm having difficulty finding the documentation I need to work with Resources and resourcePools - there is no "resource API documentation" that I can find.
I would like to programatically create static resources (of a custom type) and then add these resources to a resourcePool. When creating the resources, I'd like to be able to specify their property values prior to adding them to the resourcePool. In my mind the code would look something like this:
Room myRoom;
myRoom = new Room("redRoom", 20);
addTo_myResourcePool(myRoom);
myRoom = new Room("greenRoom", 10);
addTo_myResourcePool(myRoom);
Does anyone know if there are ways to achieve this end?
Upvotes: 2
Views: 1427
Reputation: 2517
There are several related points here.
AnyLogic is designed such that you only change the agents in a resource pool via changing the capacity of the pool. This can be done directly via the pool's set_capacity
function (if the pool's capacity is set to be defined "Directly"), but is more commonly done indirectly by linking the pool's capacity to a schedule (to represent shift patterns or any other pre-defined changes over time in capacity).
Resource pools will keep agents by default when the capacity decreases (i.e., they exist but are 'unavailable'), but you can set it to delete them. What you'll want will depend on what the resources and any resource-specific attributes/state represent.
If you need to address/access the agents in the resource pool independently from their use as seized/released resources you would have the pool store them in a custom population (rather than put them in the default population along with all other agents not created in a custom population) via the "Add units to" setting. Then you can access that population explicitly (e.g., loop through it) whenever you need to. Otherwise this aspect is not necessary.
If your resource pool is of custom agents with parameters (or other state that needs initialising in a particular way), the standard approach is to have direct/indirect capacity increases create the unit (with default parameter values) and then do any follow-on initialisation in the "On new unit" action (where you have access to the newly-created unit via the agent
keyword).
You can alternatively do it via a dynamic expression for the "New resource unit" (as in Jaco's answer) but this doesn't particularly gain you anything (though it's equally valid). Yes, it's a bit more 'object-oriented', but there are loads of barriers AnyLogic puts up to doing things in a proper OO way anyway — as you say, the more 'obvious' OO approach would just be to have methods on the resource pool which add/remove agents. Basically, the standard 'design pattern' on blocks which create agents, like a Resource Pool or a Source block, is to let it create them with default info and then customise it in the appropriate action.
You could also use the "On startup" action of the resource pool agent as well / instead, but normally you would be using information from the process-containing agent to determine what state the new resource agent should have, which makes the "On startup" action less useful.
Finally(!), if you have an unchanging set of resource pool agents and it's easier to initialise them together (e.g., because there is some database input data for all of them that can thus just be looped through once), then just do that in your "On startup" action of the agent containing the resource pool (which runs after the resource pool has initialised and created default-state agents). That will require them in a custom population so you can loop through just those agents. But your question seemed to imply you were concerned about dynamic additions of resource agents.
But, as some of my other comments indicated, there are various subtleties/restrictions in how resource pools work (really based on them currently being designed as a pool where the explicit identity of each individual is not fully 'controllable') which mean that what you actually need may go beyond this.
A couple of examples:
If you wanted your resources to be explicit individual staff with info tracked across shifts (e.g., with their state changing to reflect experience or the history of tasks they've conducted), you have the complication that you can't control which resources (if you didn't delete them on capacity decrease) 'come back' when the capacity changes, so you may need more complex workarounds such as having separate resource pools for each distinct shift and seizing from resource sets including all such pools — only one of them (the active shift one) will have non-zero capacity at any given time unless the shifts overlap.
If capacity decreases (representing end-of-shift), you can't control / determine which resource agents are chosen to go off-shift. Plus there are issues regarding resource agents which are still active finishing a task before they actually 'leave' (given that shift-ends weren't set to pre-empt) — because they still exist until they finish, if you increase the capacity again whilst they're working AnyLogic won't create a new resource agent (it will just add this existing agent back as an 'active' agent in the pool). So that makes some other things harder...
Upvotes: 1
Reputation: 3940
One option is to create a population of your resource agent, which I assume is of type room based on your code.
Then you have a function that will add a new agent to the population and return it to the caller.
And now you only need to add this to the new resource unit
call in the resource pool object
Do not change the "Add Units to" option since we are already doing this in the function.
I tested this in a small model by having two buttons to increase and decrease the capacity during execution using
resourcePool.set_capacity(max(0, resourcePool.size() + 1));
and
remove_myResource(myResource.get(myResource.size()-1));
resourcePool.set_capacity(max(0, myResource.size()));
Upvotes: 1
Reputation: 9421
There's a trick I use for this, that works sometimes, but I wouldn't generalize it as a final solution...I only do it when i have a few different unit characteristics, which seems to be your case.
step 1: create a population of resourcePools... each resource pool will correspond to one kind of agent characteristics, and all resourcePools use the same resource (agent) type
step 2: in the on new unit of the resource pool, you will use the index of the resourcePool population to generate the unit with particular characteristics... then you can just do something like resourcePool.get(i).set_capacity(whatever) in order to generate a resource unit with the exact characteristics you want
step 3: when you seize the resource, you will use alternatives... each resourcePool from the resourcePool population will be 1 option among the alternatives to use... you will need to create a function that retourns a ResourcePool[][]
step 4: you will use conditions to select the unit based on its characteristics (customize resource selection)
Upvotes: 2
Reputation: 12795
This is a bit of a blind spot in AnyLogic. It can only be done indirectly:
If you want to manually create a resource, you must call myResourcePool.set_Capacity(myResourcePool.getCapacity()+1)
Destroying 1 resource works vice-versa.
Also, make sure to "destroy resources on capacity decrease" so the agents are destroyed from the population
Upvotes: 2