I have an agent, called "AGV", which is used as a transporter in my model. It is the agent for my fleet named "OrderFleet".
How can I get the distance travelled at the end of my simulation runs for my AGVs?
If I put AGV.getDistanceTravelled(METER); into the "On destroy" of my main agent, called "main", I receive the error:
Cannot make a static reference to the non-static method
getDistanceTravelled(Length Units) from the type AGV.
AGV is an agent type not an agent, so you cannot use the getDistanceTravelled() function on it. To resolve your issue, start by creating a population of agents of type AGV by dragging and dropping to Main the "Agent" element of the "Agent" Palette.
Then, make sure the new transporters in your fleet block are added to that population by doing the following:
Now, in the On Destroy field you can write the following code:
for( AGV a : AGVs ) {
traceln(a.getDistanceTravelled(METER));
}
This will return the distance travelled of each AGV in that fleet.
You need to put the code into the "on destroy" section of your AGV agent type, not Main. (Main is destroyed only once at the end of the model and does, obviously, not travel itself at all :) ).
If you do not have a separate agent type for the AGVs yet, you need to create (and apply) it. See the example models where this is shown in detail
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 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.
resourceUnitsOfSeize (Agent Seize); Returns resource units currently seized by this agent from the given ResourcePool block. But if I have TransporterFleet instead of resourcePool what is the alternative code to get the transporter unit currently seized by this agent?
I have a trench agent which is a material type agnet. It siezed an excavator from excavatorFleet in a transpoter flow block called seizeExc. So I used the following function and I got the following error: I tried to use the same code but it did not work.
How to do this please? Thanks.
Second Error:
The same code is working for any Seize block. I changed the Return Value type to other; List of Excavator, and I typed return resourceUnitsOfSeize(seizeExc);
instead of return trenchRoom.resourceUnitsOfSeize(seizeExc);
Also for the same purpose, we can use another function with the following properties:
Type: Collection ResourceRequest and Function body: return excavatorFleet.getRequests();
Hopefully In both cases I can get transporters that have been seized by a trenchRoom agent.
:)
I am doing a simulation project of a logistics system. I created an agent named "AGV" with a variable "power"and I have a Resource Pool of it. I want to use the "Unit with top rating" in the "Resource Selection" of the Seize block to preferentially select the AGV with the lowest power.But when I type in "1/unit.power" in "Unit rating", the system reports an error. It seems that I cannot call the variable "power" located in the "AGV" agent. How can I solve this problem, or is there any other way to achieve my purpose.
unit is of type agent and you have to cast it as type AGV... Or whatever your type is for your agent AGV... use lowercase for populations or agents and use Uppercase first letter for classes or Agent types... That's notation standards..
Now let's assume your agent type is called AGV... be sure you use the correct type...
Then use 1.0/((AGV)unit).power
Then use 1.0 because if your variable power is an int you will have problems, if it's a double it's all good.
But let's hope you don't have power=0... because if you do, then maybe it's better to do:
-((AGV)unit).power instead, otherwise it's fine
I want to implement a connected autonomous vehicle fleet in AnyLogic. Because of this, a vehicle agent has the ability to change its route. My understanding is that using the standard "MoveTo" block lets you move the vehicle agent only once by telling it what road to move the agent to.
For example:
Any vehicle following the above block can be created on any road that is specified in road4Source, then move to another road specified in moveToRoad2 block and then will be destroyed/deleted/discarded when it reaches the endOfRoute block.
However, since the vehicle can choose the route for itself, I only know the Origin and the Destination of the vehicle and not sure what route it will take. So, the number of MoveTo blocks should ideally be dynamic.
Considering this, is it possible to reuse MoveTo blocks (consider it a kind of a while loop) so that that the vehicle remains in the MoveTo block until it reaches the Destination (a particular road in my case)?
Something like this:
So that in the Road argument of moveToRoad2, I can put something like(could be wrong just for illustration):
car.getRoad() == car.destination ? endOfRoute : car.getRoad()
where car.getRoad() would return the road that the vehicle wants to go to and if it is equal to the destination of the car then it would go the endOfRoute block.
EDIT 1
I understand now that if there are two connections to the same port, AnyLogic will throw an error:
Out port can't be connected with more than one In Port.
So is there any other way to achieve what I want to do here?
First, this is the configuration you want:
Then you need to generate a collection of roads that the car will take... This collection is generated in the carSource... or you can update it as you progress in the "loop".
the car agent must have a variable that will start with 0 and will increment +1 every time it exits carMoveTo...
So the new road that the car will take is:
collection.get(car.variable)
And on exit of carMoveTo:
car.variable++;
In the selectOutput the condition for true would be:
agent.variable==collection.size()
I hope this helps...
Nevertheless, if you have too much traffic, you will see big problems in your model because the car doesn't necessarily recognize traffic after the destination in the carMoveTo so you may have crushes... or maybe not... depends on different factors.