question

TiredStudent avatar image
0 Likes"
TiredStudent asked Felix Möhlmann commented

'QueueJoining' custom code does not follow the If else statement

QueueandOperator.fsmExplanation of my simulation:


After the first processor 'QueueJoining' connecting to the source,

I have three queues


(Port 1 and 2) - 2 Queues are towards checkout with operators (1 Queue served by 2 Operators on 1 Processor each)

(Port 3) 1 Queue is towards checkout by self (No operators)


The goal is for the three queues to self balance itself.

In order to self balance itself, I need to first consider two conditions.


Two Conditions are Queue Length and Queue Average Waiting Time.

The first processor will send the object to the Queue with the Shortest Queue Length and Shortest Average Waiting Time.

Special Conditions to fulfil:

Context:

- Operator work in three shifts, five hours per work shift.

- Operator have a tea break for 15 min after working for every 1 hour and 15 min, so in my simulation timetable there are 3 tea breaks per work shift.


Therefore, if Port 3 does not fulfil the two conditions, the first processor will have to see if Port 1 and Port 2 have two working operators, if only one operator is working instead of 2 in that Port, it will send to the other Port, else it should just follow the main Two Conditions - Queue Length and Queue Average Waiting Time.

By default at the start of the simulation the first processor will send to Port 1



My current issue with my 'QueueJoining' does not follow the If else statement of my Output custom code and choses to fulfil Port 1 first, followed by 2 and 3 which is not what I have in mind.

Additionally I am having stuck at figuring out how to pull the information whether the operator is on duty at their processor so that we can determine if we should send the object to its connected queue.
Is there an issue with how I set my timetable as currently the object is at the processor even when the operator is not on duty.

Should I simplify my timetable so that it will be in one timetable instead for ease of extraction?

If possible is there any guidance or resources you can point me towards to so I can successfully resolve this issues and move towards my goal?


FlexSim 24.1.1
timetablesoperaterif-else condition
queueandoperator.fsm (896.5 KiB)
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

1 Answer

Felix Möhlmann avatar image
0 Likes"
Felix Möhlmann answered Felix Möhlmann commented

Your code is missing curly braces "{}" to properly group the conditions. If the first condition is false it currently skips the rest of the code.

You could just check the state of the operators to see if they are active or not.

checkout01.centerObjects[1].stats.state().value != STATE_ON_BREAK

I don't understand why the time tables are setup as they are. Why are the breaks placed inbetween times where the operators should be off?

And you are using a Down Behaviour from the People Module (mostly meant for the HC environment). The standard operator does not support this down behaviour and the down time is ignored because of this.

· 4
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

TiredStudent avatar image TiredStudent commented ·

hello there,

thanks for getting back to me. my updated model is rectifiedv3.fsm

I have tried the "{}", the model logic showed promise at the start of the simulation, but eventually the "ProcessJoining" will have the tendency of ignoring my first and second queue after some time of running the simulation. Is my if and else if statement incorrect?

I have fixed my timetable. (Operator 1 and 3 will be the first pair that take a 15mins break after 1 hour 15 mins, followed closely by Operator 2 and 4 taking 15 mins break once 1 and 3 returns; this allows me to fulfil 3 tea breaks per work shift. Next, every 5 hours they will go for a 5mins shift change, 1 and 3 first, 2 and 4 next)
May I enquire if it is normal when the operator does not go for a break when it is scheduled to do so and continue finish processing its current tasks? Is my operator ignoring my planned schedule?

I noticed that my Queue 1 and Queue 2 will still send the Objects to the Processor or the Object still remain at the Processor even when my operator is not on duty the processor so I tried using if, else if checkout01.centerObjects[1].stats.state().value != STATE_ON_BREAK
at the Queue01, unfortunately, I am receiving label error, how should I label the operator state at the processor or operator itself?

Additionally, from my understanding of
https://docs.flexsim.com/en/21.2/Using3DObjects/CreatingCustomObjectsAnimations/CreatingCustomAnimations/CreatingCustomAnimations.html
do I use

resumeanimation(object, animation) == 1

after selecting Pick Operator with Animation at the processor to allow me to loop the animation '31' until the object finishes its processing time on the processor?

Lastly, is there a way for me to visually differentiate operator of different shift as the schedule only has On Down and On Resume.

Thank you for your warm advice.

rectifiedv3.fsm


0 Likes 0 ·
rectifiedv3.fsm (895.8 KiB)
Felix Möhlmann avatar image Felix Möhlmann TiredStudent commented ·

With the current distribution logic you are getting the same issue that I described here. The average wait time changes slower the longer the model runs. So a lot of customers get released to one queue, then it takes a while for the avg staytime to adjust and overtake the other queues again. Then a lot of customers are released to the next queue and so on. It's an instable setup that will create larger and larger 'batches' of customers in a single queue as time goes on.

It works a lot better if you multiply the number of customers and the avg staytime instead of adding them. That way the number of customers always stays the most relevant factor when determining the port.

For the operator to immediately go to the break location you have to allow the task sequence created by the time table to pre-empt the current one.

1743146990064.png

".centerObjects" is a method of the Object class so you have to cast the checkout as such in the code (instead of treenode)

The animation you chose does not repeat by default and the "start animation" task only allows to specify the speed type but not the repeat type of the animation. You could alter the task sequence to instead send a message to the executing operator and start the animation in the OnMessage trigger with the "startanimation()" command to have access to all options.

Though it would be easier to just choose a different animation (for example 32 - "Typing") that repeats by default. (It would look weird anyway if the operators where repeatedly sitting down)

You could change the color of the operator in the time table down function when a changeover occurs (check if the state matches the one you chose for the shift change 'breaks' and cycle the color). I have implemented this in the first time table as an example.

rectifiedv4.fsm

0 Likes 0 ·
1743146990064.png (17.4 KiB)
rectifiedv4.fsm (896.7 KiB)
TiredStudent avatar image TiredStudent Felix Möhlmann commented ·

hello there,

thanks for teaching me about the difference between Object and treenode.

Problem 1:
I noticed you mentioned 'sort by that result ' in the other link you referenced, so in my 'QueueJoining' I tried using an array and one 'for' loop to retrieve the active minimum value of the array list of (priority1, priority2, priority3)

// Store priority in an array
Array prioritylist = Array(3);

// Find index of minimum
for (int i = 1; i < 4000; i++) {
prioritylist[1] = priority1;
prioritylist[2] = priority2;
prioritylist[3] = priority3;

double lowestpriorityscore =  Math.min(prioritylist);
int index = prioritylist.indexOf(lowestpriorityscore);
return index;
}


Updated* Is this the correct way of retrieving the index of the smallest value in the list? Or am I heading in the wrong direction of doing it the harder way or completely wrong logic?


Problem 2:
Relating to Problem1, is there a way to replace the 4000 in i < 4000 ? This is so that it will be i < 'maxcustomer the source can generate.'

for (int i = 1; i < 4000; i++)


Problem 3:

I noticed that despite having a custom code in sendtoport of 'CustomerQueue01' and 'CustomerQueue02'

/**Custom Code*/
Object item = param(1);
Object current = ownerobject(c);

Object checkout03 = model().find("CheckoutStation3");
Object checkout04 = model().find("CheckoutStation4");

if ((checkout03.centerObjects[1].stats.state().value != STATE_ON_BREAK) && 
(checkout04.centerObjects[1].stats.state().value == STATE_ON_BREAK)){
return 1;
}

else if ((checkout03.centerObjects[1].stats.state().value == STATE_ON_BREAK) && 
(checkout04.centerObjects[1].stats.state().value != STATE_ON_BREAK)){
return 2;
}

else{
return 0 ;
}

when the operator goes on break, the 'item' will still be at the processor, am I missing a case in my code?

screenshot-2025-03-29-024503.png


Thank you for your warm guidance.

DisributionArray_V5.fsm


0 Likes 0 ·
Show more comments