question

martin.j avatar image
1 Like"
martin.j asked Lars Jacobsen commented

Bug Report - Wait For Event on Tracked Variable in object label

I have run into a problem with the Wait For Event activity that waits for a value on a Kinetic Tracked Variable on an object label. I have created a loop that will represent a decision tree, that triggers when the kinetic variable reaches its specified value (20), but sometimes under some very unclear conditions the event triggers more than once and the token loops multiple times as a consequence - More seriously, sometimes it goes into an infinite loop.

Please see attached model - SomeTestOrOther.fsm

In the Source activity I set the offset time for when i change the rate of the Kinetic Tracked Variable on the FR-Object - this has an influence on the issue.

In the first Custom Code activity I set the rate to 0.8611 - the rate seem to have an influence on the issue as well.

If the offset time is 0 there is no problem - the event triggers when the kinetic value hits 20 around 23 seconds in and the loop is triggered once. But if the offset value is 200 the loop is triggered twice at 223 sec, and if the offset time is 500 the event is triggered continously causing an infinite loop. Going to 1000 secs also causes just a double loop.

However if I chance the rate value to just 0.86, the issue at 200 sec disapears and at 500 sec it becomes just a double loop. If the rate is set to a whole integer value I have been unable to reproduce the issiue - it always loops just once as expected.

Apparently there is some issue with the event trigger, that is affected by both the time and the rate of change, which makes the error very dificult to pinpoint, and it makes my reliance on Wait For Event on label-tracked-variables somewhat dangerous.

I have tested this in versions 20.2.3 , 21.0.3 , 21.0.4 & 21.1.0 the problem persists the same in all of these.

FlexSim 21.1.0
wait for eventbug reportflexsim 21.1.0kinetic tracked variabletracked variable on label
sometestorother.fsm (34.4 KiB)
· 2
5 |100000

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

Lars Jacobsen avatar image Lars Jacobsen commented ·

@jason.lightfoot. Can you help with this questions?

0 Likes 0 ·
Joerg Vogel avatar image Joerg Vogel commented ·

Perhaps there is code line that rounds a double. And your combination of rate and condition level produces more events.

0 Likes 0 ·
Phil BoBo avatar image
2 Likes"
Phil BoBo answered Lars Jacobsen commented

First, this situation absolutely needs a Breathe activity. You should not be waiting for the OnChange of a tracked variable from within the execution of that tracked variable's OnChange. You use a Breathe before waiting for the event again in order to let that event finish processing.

If you put a Breathe activity of 0 time, then it will consistently behave as expected to create an infinite loop of activities in 0 time, stalling the model.

What is happening

At time 0, the token enters the Wait for Event and evaluates whether the change rule (Increase To or Through Value) is met. Because the tracked variable is not >= 20, it calculates the time when the change rule will be met, based on the current time, the value of the tracked variable, and its rate of change. It schedules an event for that time.

During that event, it evaluates whether the the change rule is met. Since the value is now 20, it has met the change rule and releases the token. You send the token right back into that listener without any time change, and then it evaluates whether the change rule is met. Since 20 >= 20, it releases the token, continuing that loop of creating events in 0 time because you didn't have any delay.

Why it is inconsistent

The calculation for the time of the event where the rule will be met is based on floating-point precision values. Sometimes, the result of a floating point value calculation is not exactly equal to its mathematical equivalent. In the case where it doesn't cause an infinite loop of events, it is because the value of the tracked variable is 19.999999999999998 at the time of the event. When this is the case, 19.999999999999998 is not >= 20, but the calculation of the time when it will become 20 can sometimes evaluate to essentially 0 (1.65e-14) because of how floating-point precision values work in calculations. This causes an infinite loop that can actually crash the program when the breathe is missing because the calculation is all happening recursively in-line without any breaks in the evaluation of the original event.

Conclusion

Although this behavior may not be intuitive, it is intentional based on the design of how the Wait for Event activity works. You need a tiny delay before you re-evaluate the OnChange rule in this particular situation.

· 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.

martin.j avatar image martin.j commented ·

Ok, got it. It does however mean that 'wait for event' is not a viable way to make decision trees since even a short delay in the 'breathe' activity could cause us to miss an event that we should otherwhise have caught. The alternative is to use eventbased sources that dont have this problem, but they lack persistence of information - basically you cant keep information on the token through multiple iteration of the decision tree.

Clearly, building complex state-machines will require a bit more thinking on my part...

0 Likes 0 ·
Lars Jacobsen avatar image Lars Jacobsen martin.j commented ·

@Phil BoBo The problem Martin describes applies in particular when you listen to a group of objects, as some objects might trigger the wait for event at the exact same time. A possible solution for dev could be to have the option of using AND in "listen for event". Current OR is the only possibility.

0 Likes 0 ·
Matthew Gillespie avatar image Matthew Gillespie ♦♦ Lars Jacobsen commented ·

@Lars Christian J2

You can do an AND by having two Wait for Events or Event-triggered sources and then synchronizing the two tokens. An AND doesn't make much sense as a built-in feature because the two events are always going to happen at different times.

0 Likes 0 ·
Show more comments
Lars Jacobsen avatar image
0 Likes"
Lars Jacobsen answered Joerg Vogel commented

When the "Wait for Event" happens, the token is immediately returned to the "Wait for Event" activity. Thus the current state is unchanged and the "Wait for Event" activity fires again, creating an infinite loop. If there is a short delay before the token returns to "Wait for Event", everything seems to work as expected.

· 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.

martin.j avatar image martin.j commented ·

Indeed, or I could simply use an event-based source to create a new token for the decision tree every time which seems to cirkuvent the issue, but it does not explain why there is a difference based on these seemingly unrelated parameters.

I would argue that an event should not be able to trigger the same token twice, but I dont know what the developers had in mind when they made this system. Either the Wait For Event activity with a looping token should always go into an infinite loop, or it should never do it. It should not be up to unpredictable random guesswork how this logic will perform.

I would like to hear from FlexSims developers what they had in mind when designing this interaction - Is this really working as intended?

0 Likes 0 ·
Joerg Vogel avatar image Joerg Vogel martin.j commented ·

@martin.jensen, @Lars Christian J2, you have seen this behavior for a long time in FlexSim. There is the delay parameter in a delayed message. You can choose to set to -1 or 0 to let a message be received currently but with a slight difference. The message is received at current processing or in next processing step cycle, but still at current time. And you see often in Process Flow tutorials the meaningless delay activity Breathe. It delays the runtime for a process by exactly 0 seconds. It just lets the CPU step at current time to a new processing cycle to evaluate changes made in the model currently. How do you evaluate made changes in a sequentially organized model at the same time, when you don’t let the FlexSim engine repeat the tree logic several times? There has been an advice to rerank objects in the tree to get a logical precise behavior. I am not sure, how I should rank a process flow logic to be executed after for example a source in a model, when the process flow tree node is previous to the source in the tools tree branch. You are asking about a system behavior strongly influenced by windows or CPU binary code execution. This behavior is a matter of multi threaded and multi core CPU code execution and internal processing priority. I am not an expert in programming, but if I write programs for robots then task priority is a matter I must always beware of in multi task programs. When and how long does a task get processing time on the CPU. What does happen in my source code if I have a Wait or Wait Until structure implemented? How does this mess up my logic? When do I set up an interrupt to be active again? Do I initiate an infinite loop execution, if I rearm an interrupt to early?

0 Likes 0 ·
martin.j avatar image martin.j Joerg Vogel commented ·

Hello Jörg, thank you for your insight. If this issue could be solved by adding a "Breathe" activity with a delay time of 0, I would not have mentioned it - But it can't. This means that it is more than just a problem with the event triggering multiple times in the same CPU process cycle, but is in fact by my estimates and issue with how the "Wait For Event" deals with this particular situation. Besides if the Wait For Event activity is setup to listen to almost any other type of event there is no problem, they trigger only once. (I have not tested every single event type, but several.)

The only way to deal with this is, as Lars suggested, to add an actual delay to the process. If the Delay Activity has even a tiny delay time the issue is resolved, but we also run the risk of missing out on another event that should actually be caught by our Wait For Event Activity which may be listening for multiple events or events on multiple objects in a group. Those should actually trigger, and be registerd by our looping token, but not create infinite loops.

1 Like 1 ·
Show more comments