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.)
Related
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
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
I've created a class with various properties in VB6.
The properties are
PiccoId
OrderId
UserId
StockCode
Quantity
At the top of the class I have declared 2 instances of classes I'm using.
Dim stkLine As CSOPSLine ' This is the class where the properties are declared and read
Private SOPSLines As cSLine ' This class creates the new objects and sets the property values
When the user enters the order number on a handheld barcode scanner, I'm creating an object to associate with this particular scanner like so:
Set SOPSLines = New cSLine
Set SOPSLines = getSOPSLine(ID, sOrder, "", "", 0)
In the next stage of the process, the user needs to enter their user ID so it can be seen which user scanned in the item.
I need to update the property of this same object, but I'm not sure how - Currently I am trying to do it within my getSOPSLine function, like this:
Dim line As New CSOPSLine
Dim bFound As Boolean
bFound = False
For Each line In SOPSLines.Items
If line.PiccoId = ID Then
line.OrderId = OrderId
line.Quantity = Qty
line.StockCode = stock
line.UserId = UserId
Set getSOPSLine = line
bFound = True
Exit For
End If
Next
If bFound = False Then
Set line = SOPSLines.Add(ID, OrderId, UserId, stock, Qty)
Set getSOPSLine = line
End If
Set line = Nothing
However, as I'm not storing sOrder at class level (Due to the fact multiple users can be using barcode scanners, the order ID can't be kept at class level as other users will just overwrite it),
I'm not sure how once I've got the next variable (In this case, userID, and the other variables after this stage) I can update the same object as I've just created.
I've tried to do something like
Set stkLine = getSOPSLine(ID, stkLine.OrderId, pUser, "", 0)
but it errors saying
object or with block variable has not been set
How can I update the properties of stkLine without constantly creating new objects?
EDIT
To clarify:
When the application receives data from the handheld barcode scanner, a select case is entered, with one case for each of the variables being entered (E.g. Order ID, user ID, stock code etc.)
The first case sets the order ID.
The code here is
Case FRAME_ORDER_SELECTION
On Error Resume Next
Dim sOrder As Long
sOrder = Picco.GetData(ID, 50)
If sOrder = 0 Then
Call Picco.Send(ID, FRAME_ORDER_SELECTION)
Exit Sub
Else
With Picco
Call .ClearForm(ID)
Call .Text(ID, LINE_1, "===== User ID =====")
Call .Text(ID, LINE_2, "")
Call .NewField(ID, 60, 5, FLD_LINE + SND_ENTER)
Call .Send(ID, FRAME_LINE_ADD)
Set SOPSLines = New cSLine
Set SOPSLines = getSOPSLine(ID, sOrder, "", "", 0)
End With
End If
frameid = FRAME_LINE_ADD
m_iLastFrameId = FRAME_ORDER_SELECTION
On Error GoTo Picco_DataArrived_Err
This is where the object is created.
The next case is after the user enters their user ID into the scanner.
Case FRAME_LINE_ADD
On Error Resume Next
Dim pUser As String
pUser = ""
pUser = Picco.GetData(ID, 60)
If pUser = "" Then
Exit Sub
End If
On Error GoTo Picco_DataArrived_Err
With Picco
Call .ClearForm(ID)
Call .Text(ID, LINE_1, "===== Add Line =====")
Call .Text(ID, LINE_2, "")
Call .Text(ID, LINE_7, "Scan or type code")
Call .NewField(ID, FIELD_POS, 18, FLD_LINE + FLD_READER + SND_ENTER)
Call .Send(ID, FRAME_LINE_QTY)
End With
Set stkLine = getSOPSLine(ID, stkLine.OrderId, pUser, "", 0)
frameid = FRAME_LINE_QTY
m_iLastFrameId = FRAME_LINE_ADD
Then there will be 2 or 3 more cases when populating the rest of the required values.
What I need to do, is in the second case (And all other following cases) update the properties of the object created in the first case.
I'm using the getSOPSLine function as this gets the object with the matching barcode scanner ID (As multiple users may be accessing different orders, they need to be kept separate in this way), but I'm not sure how to update the object where the scanner ID matches.
When you call getSOPSLine in each Case, enter some temporary values for the variables that you're not setting.
Example;
In the UserID case: stkLine = getSOPSLine(ID, 0, pUser, "", 0)
Then, in the getSOPSLine() function, change it so that instead of setting the values automatically, it instead only updates them if they don't equal 0, or "", or whichever temporary variables you use.
That way you're updating the same object, but aren't storing data that may get overwritten.
I'm not sure what you're confused about; I think that you must have some misunderstanding of what objects, variables, and properties are that is preventing you from asking this in a way that I understand. I'm not sure how your code lines up with your questions. But I'll give this a shot:
Private SOPSLines As cSLine
Set SOPSLines = New cSLine
Set SOPSLines = getSOPSLine(ID, sOrder, "", "", 0)
This declares a class-level variable, that can hold a cSLine object. That seems reasonable. Then you create a new instance of cSLine to put in that variable. But I don't know why, because you then point the variable to a different instance entirely, which is the instance returned from your getSOPSLine function. That middle line doesn't seem to be doing anything, and I'm not sure what you're trying to do with it.
I've tried to do something like
Set stkLine = getSOPSLine(ID, stkLine.OrderId, pUser, "", 0)
but it errors saying
object or with block variable has not been set
Well, then it sounds like stkLine isn't set to an object. I don't see any code that's trying to set stkLine other than that line. So when you try to get stkLine.OrderId, there isn't an object to get the OrderID property of, so it gives you an error.
I need to update the property of this same object, but I'm not sure how
Well, if there's an object you care about, you probably have it in a variable somewhere. You use variable.property = value syntax to assign value to the property of the object currently stored in variable.
But again, I'm not sure where your confusion is, since you're clearly assigning properties of objects in your code already.
If you're not understanding how objects work in VB, I'd recommend reading through the Working with Objects chapter of the documentation.
And if your confusion lies elsewhere, perhaps you could put together a more specific question about what you're trying to do?
i am creating a basic GROUND CONTROL STATION for a CubeSat, dividing it in two parts: COMMANDS (with no problems) and TELEMETRY. I am using C code and GTK; in the telemetry windowt I need to show some info everytime a telemetry packet is received so I've tried to use a gtkview/gtkentry for each info, but I don't know, how to update the message shown in them.
In particular, an example is:
//View PACKET NUMBER
view = gtk_text_view_new();
frame = gtk_frame_new("Packet number");
gtk_container_add(GTK_CONTAINER(frame), view);
gtk_text_view_set_editable(GTK_TEXT_VIEW(view),FALSE);
gtk_table_attach(GTK_TABLE(table2),frame,0,1,0,1,GTK_FILL,GTK_FILL,5,5);
buff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
gtk_text_buffer_get_iter_at_offset(buff, &iter, 0);
gtk_text_buffer_insert(buff, &iter,"waiting", -1);
so, first there is the text "WAITING", then when a packet is received I want to update that text: how can I do this?
I've tried repeating this code but changing "waiting" with a variable referring to "packet number", but I obtain core dump
I've also tried with this code, but I have always same problem.
viewprova = gtk_entry_new();
frameprova = gtk_frame_new("Packet number");
gtk_container_add(GTK_CONTAINER(frameprova), viewprova);
gtk_entry_set_editable(GTK_ENTRY(viewprova),FALSE);
gtk_table_attach(GTK_TABLE(table2),frameprova,0,1,0,1,GTK_FILL,GTK_FILL,5,5);
gtk_entry_set_text(GTK_ENTRY(viewprova),"waiting");
frameprova = gtk_frame_new("Packet number");
viewprova = gtk_label_new ("waiting");
gtk_container_add(GTK_CONTAINER(frameprova), viewprova);
gtk_table_attach(GTK_TABLE(table2),frameprova,0,1,0,1,GTK_FILL,GTK_FILL,5,5);
Thanks for the help!
A function such as gtk_label_new() that accepts a C string can't take an integer instead, C functions are not polymorphic. You need to build a string representation and pass that, for instance using snprintf() to format the number into a string buffer.
Ok, so if I understood you correctly, you know how to setup your text displaying widgets, but not, how to fill them with new contents, correct? Look at your code, and at what you're doing. First, you're creating a text widget. Then you fill it with initial text. This second part is the one you repeat:
In case of GtkEntry, gtk_entry_set_text(GTK_ENTRY(viewprova), "My new text");
In case of GtkTextView (actually you're using the underlying TextBuffer), gtk_text_buffer_set_text(buff, "My new text", -1);
I have following code to find if row is selected, which is selected and which text is in row of GtkTreeView. Code is in key-release event handler.
char *ntext;
if (gtk_tree_selection_get_selected(treeselen, &modelen ,&iteren))
{
gtk_tree_model_get(modelen, &iteren, cEng, &ntext, -1);
... etc...
This works ok when my view is not empty. But when list is empty I get "segmentation fault".
I think that before this is needed to check if GtkTreeView is empty.
How to do that?
Actually, later I find if list is partially filled with clicking on unfilled area segfault happens too. So I need solution for that too.
From your description, it appears when you say GtkTreeView is empty you mean in model (GtkTreeModel which is implemented by GtkListStore or GtkTreeStore associated with your GtkTreeView) the data rows are added but are empty i.e. data is not set. In that case you need to check the value returned by gtk_tree_model_get (assuming cEng is valid otherwise you will get a warning message while running the program). Problem mostly is in ...etc.... Just add a NULL check to ntext before operating on it.
char *ntext;
if (gtk_tree_selection_get_selected(treeselen, &modelen ,&iteren))
{
gtk_tree_model_get(modelen, &iteren, cEng, &ntext, -1);
if( ntext == NULL )
{
printf("Data is NULL!\n");
/* Handle this case */
}
else
{
.... etc ....
}
}
This could also be the case in you button-press or release callback as well.
Hope this helps!