agent cannot be resolved to a variable in function body but works in other blocks - anylogic

I currently have a function that gets checked at certain time intervals. I want a hold to unblock upon satisfaction of the condition in the function body. However, agent can never be resolved to a variable, even though this convention of referring to the agent works in other process blocks. The agent that is present in the (((Patient)agent) is the agent that cannot be resolved to a variable. Patient is an agent type and has the variable isMorning that gets set to true or false upstream in the model. Below is the code in the function block, and the parameters are set to Just action (returns nothing). The (((Patient)agent) would be in a queue block prior to the hold.
if (((Patient)agent).isMorning == true && SurgeonMorning.idle() > 0){
hold.unblock();}
else if (((Patient)agent).isMorning == false && SurgeonAfternoon.idle() == 0){
hold.unblock();}

If this is code in a function, you need to provide a function argument and use that instead of agent.
In the properties of the function under arguments, add an entry myPatient and specify the type as Patient (right side from the dropdown).
Then, you can use the code as
if (myPatient.isMorning == true && SurgeonMorning.idle() > 0){
hold.unblock();}
else if (myPatient.isMorning == false && SurgeonAfternoon.idle() == 0){
hold.unblock();}
Check the help to understand functions more. And this article to understand when (and when not) you can use these little keywords like agent: https://www.benjamin-schumann.com/blog/2016/2/4/the-magic-lightbulb-and-how-it-can-help-your-anylogic-modelling

Related

Check if agent connected to an agent is on the wait block - anylogic

Direct question: how to check if an agent is waiting in the wait block?
More details? below, thank you.
I was following Mr. Felipe's answer to a similar question (this one: Anylogic - Combined multiple items back to original owner )
On step number 4 of his answer, he said " On the passengerWait, on the onEnter action you will check if all the bags connected to the passenger are on the bagWait block... if they are... then you will free (wait.free(agent)) the passenger and the bags "
Do you know how to check this? I have the same problem between single patient and single drug.
To avoid going into the details of your model and naming of blocks, I will provide you with something generic that should help you achieve what you need.
The first step is to know how to iterate through the agents inside the wait block. To do that, you need a for loop with the syntax shown in the code below. (Replace Agent with the agent type of agents in the wait block, replace waitBlock with you wait block's name.)
The character a now refers to the agent in the wait block being evaluated in each iteration.
Now, you just add your condition where you check if any of the agents in the wait block match your condition which is whether they are equal to whichever connected agent to the one going through the wait block.
Agent x = null;
for( Agent a : waitBlock ) {
if( a.equals(agent.agentLink.getConnectedAgent()) ) {
x = a ;
break;
}
}
if( x != null ) {
waitBlock.free( x );
}
Another simplified code would be:
Agent x = findFirst( waitBlock , a -> a.equals(agent.agentLink.getConnectedAgent()) );
if( x != null ) {
waitBlock.free(x);
}
I figured out how to do that:
Make a new variable in the Passenger agent and call it
variable_IsWaitingForBag
Make a new variable in the Bag agent and call it variable_IsWaitingForPassenger
In onEnter of passengerWait, use the following:
if(agent.agentLink_myBag.getConnectedAgent().variable_IsWaitingForPassenger)
{
passengerWait.free(agent);
bagWait.free(agent.agentLink_myPassenger.getConnectedAgent());
}
agent.variable_IsWaitingForBag=true;
Do the opposite in onEnter of the bagWait block

RuntimeException: Cannot put: [0][0][0] is occupied in Anylogic

I have RackStore block to store agents where the cells are chosen explicitly with the help of a function. I am getting this error when I run the simulation. Here,cells were assigned to all four agents that entered the block, but I think it throws this error when resources arrive for an agent.
I can't understand the reason for this error as all the agents that entered the block were already assigned to cells and it's not trying to put anything again. I have tried the simulation with various no. of agents (5-150 agents), the error always appears after all the agents arrive at rackStore block and an agent is trying to exit.
My rackStore properties are: rackStore property_part_1, rackStore property_part_2
The getCell(double weight, Carrier carrier) function is defined below. It returns an integer array of size 3.
//Iterate through rows
int lev=0;
int row=0;
for (int r=0; r<=1; ++r) {
// Iterate through positions
for(int p=0; p<=9; ++p){
//Check which level it belongs to as per weight
lev=getLevel(weight);
//Check if cell is free
if(carrier==Truck){
if (palletRack4.isFree(r,p,lev)== true ){
int[] arr={r,p,lev};
//traceln("truck pos: "+ arr);
if(arr==null){traceln("truckPos NULL");}
return arr; }
else {continue;}}
else{
if (palletRack5.isFree(r,p,lev)== true ){
int[] arr={r,p,lev};
//traceln("train pos: "+ arr);
if(arr==null){traceln("trainPos NULL");}
return arr; }
else {continue;}}
}
}
if(carrier==Truck){
PalletRackLocation ploc=palletRack4.getFreeCell(true);
//traceln("Carrier: " + carrier);
//traceln("Free cell from P4: "+ ploc);
int[] arr1={ploc.row,ploc.position,ploc.level};
if(arr1==null){traceln("randTruckPos NULL");}
return arr1;}
else{
PalletRackLocation ploc=palletRack5.getFreeCell(true);
//traceln("Carrier: " + carrier);
//traceln("Free cell from P5: "+ ploc);
int[] arr1={ploc.row,ploc.position,ploc.level};
if(arr1==null){traceln("randTrainPos NULL");}
return arr1;}
You're not setting up your RackStore block properly. As the properties state, you have to specify expressions for the row, position and level when you choose "The cell is specified explicitly". But you are trying to use 'internal' pallet rack put functions to do this (inside your "on enter" actions for the block) and leaving those expressions blank. So likely the blank settings means it tries to add agents to location (0,0,0) after having already added them somewhere else (and thus subsequent agents will try to get added there giving you the error shown).
If the block's "on enter" actions occur before those row, position and level expressions are evaluated (do some traceln statements to check; I imagine they are but this is really an internal block sequencing detail that can't be explicitly 'knowable' a priori) you can then keep your on-enter code as-is (but remove the put calls) and then specify the row, position and level from the agent parameters you just set up.
(P.S. The error trace shows that the error is in the rack storage stage—it's occurring inside the onEnter method of the RackStore block—not when an agent tries to leave the rack. It's probable at a Java level that the block performs the user-specified on-enter action code and then the cell allocation and pallet rack 'put' inside the onEnter method that the error trace shows— presumably in that order, but you should check that as mentioned.)

Fastlane set options auto value

I would like to submit my lane with optional options. So for example the lane:
lane :mylane do |options|
mailgun(
to: "#{options[:mailto]}"
....
)
end
How do I give :mailto a default value? So if I would run fastlane mylane it would automatically set :mailto to mail#example.com.
But if I would runfastlane mylane mailto:"secondmail#example.com" it would use that value
As Lyndsey Ferguson pointed out in a comment on this answer, the following is simplest:
mail_addr = options.fetch(:mailto, 'mail#example.com')
where the first parameter of fetch is the option to fetch, and the second is the default value if the option was not passed in.
I just want to add that this works a lot better than the other suggestion:
options[:mailto] || 'mail#example.com'
when dealing with boolean options.
Fastlane (or maybe Ruby) interprets true, false, yes, and no as boolean values instead of strings (maybe others too, though I tried N, n, NO, and FALSE and they were treated as strings), so if in your lane implementation you had:
options[:my_option] || true
or
(options[:my_option] || 'true') == 'true'
you would get unexpected behaviour.
If you didn't pass in myOption at all, this would default to true as you would expect. If you passed in true this would also return true. But if you passed in false this would turn into true, which you of course wouldn't want.
Using options.fetch(:myOption, true) works great with boolean flags like the ones mentioned above and therefore seems better to use in general.
Here's a very thorough example in case you want to test it yourself:
lane :my_lane do |options|
puts("You passed in #{options[:my_option]}")
my_option = options[:my_option] || true
if my_option
puts('Using options[:my_option], the result is true')
else
puts('Using options[:my_option] the result is false')
end
my_option_fetched = options.fetch(:my_option, true)
if my_option_fetched
puts('Using fetched, the result is true')
else
puts('Using fetched, the result is false')
end
end
Outputs:
fastlane my_lane my_option:true
You passed in true
Using options[:my_option], the result is true
Using fetched, the result is true
fastlane my_lane my_option:false
You passed in false
Using options[:my_option], the result is true
Using fetched, the result is false
fastlane my_lane my_option:no
You passed in false
Using options[:my_option], the result is true
Using fetched, the result is false
Note, e.g. FALSE would default to true as it is not being interpreted as a boolean, which seems reasonable to me.
(Fastlane 1.77.0, Ruby 2.7.2)
EDIT: It's worth noting that if you pass an empty string instead of nothing/null you would not get the default value from the fetch method.
I'm not sure there's a way to make Fastlane pass a default. The processing is pretty simple:
https://github.com/fastlane/fastlane/blob/master/fastlane/lib/fastlane/command_line_handler.rb#L10
But you can easily do this in your Fastfile:
lane :mylane do |options|
mail_addr = options[:mailto] || "mail#example.com"
mailgun(
to: "#{mail_addr}"
....
)
end

Can i have 2 conditions in protractor expect function? Also give me expect statement to verify whether the getText() has the expected value?

Here i want to combine the below 2 expectations into one.
expect(button.getText()).toEqual('Process Successful');
expect(button.getText().indexOf('- code 3001')).toBeGreaterThan(0);
Also whether the below statement is correct or not. I am trying to verify in the getText() whether expected value is present in the text.
expect(button.getText().indexOf('- code 3001')).toBeGreaterThan(0);
You can use expect().toContain() to verify text contained in string.
expect(button.getText()).toContain('Process Successful');
expect(button.getText()).toContain('- code 3001');
You can also do it in another way,
var buttonContainsText = button.getText().then(function(text){
return (text.indexOf('Process Successful') > -1) && (text.indexOf('- code 3001') > -1)
})
expect(buttonContainsText).toBeTruthy();

Boolean logic failure

I am having a strange problem with boolean logic. I must be doing something daft, but I can't figure it out.
In the below code firstMeasure.isInvisibleArea is true and measureBuffer1 is nil.
Even though test1 is evaluating to NO for some reason it is still dropping into my if statement.
It works ok if I use the commented out line.
Any idea why this happens?
BOOL firstVisible = firstMeasure.isInVisibleArea;
BOOL notFirstVisible = !(firstMeasure.isInVisibleArea);
BOOL measureBufferNil = measureBuffer1 == nil;
BOOL test1 = measureBuffer1 == nil && !firstMeasure.isInVisibleArea;
BOOL test2 = measureBufferNil && !firstVisible;
if (measureBuffer1 == nil && !firstMeasure.isInVisibleArea)
//if (measureBufferNil && !firstVisible)
{
//do some action
}
Update 1:
I isolated the problem to !firstMeasure.isInVisibleArea as I've entirely taken on the measureBuffer bit.
Inside isInVisible area is a small calculation (it doesn't modify anything though), but the calculation is using self.view.frame. I am going take this out of the equation as well and see what happens. My hunch is that self.view.frame is changing between the two calls to isInVisibleArea.
Update 2:
This is indeed the problem. I have added the answer in more detail below
When in doubt, you should fully parenthesize. Without looking up the precedence rules, what I think what is happening is that = is getting higher precedence than == or &&. So try:
BOOL test1 = ((measureBuffer1 == nil) && !firstMeasure.isInVisibleArea);
While you certainly can parenthesize, you should also know that nil objects evaluate to boolean NO and non-nil objects evaluate to boolean YES. So you could just as easily write this:
BOOL firstVisible = firstMeasure.isInVisibleArea;
BOOL notFirstVisible = !(firstMeasure.isInVisibleArea);
BOOL measureBufferNil = measureBuffer1;
BOOL test1 = !measureBuffer1 && !firstMeasure.isInVisibleArea;
BOOL test2 = measureBufferNil && !firstVisible;
if (measureBuffer1 && !firstMeasure.isInVisibleArea) {
//do some action
}
You would end up with the same results. I agree with GoatRider, though. It's always far better to parenthesize your conditional expressions to clarify what you really want to happen than it is to rely on the language's operator precedence to do it for you.
If test1 is evaluating to NO as you say, then drop test1 into the if statement:
if(test1){
//see if this executes?
}
See what that does.
My hunch was correct, it is related to the view frame changing between calls to firstMeasure.isInVisible area.
This whole routine is called in response to the view moving. I think I need to grab the value of firstMeasure.isInVisibleArea at the start of the method and use that value throughout.
Phew. Boolean logic isn't broken. All is right with the world.
Thanks for all your input