0

I have an industrial simulation with 2 agent types, operators and machines. Each agent type has statecharts controlling different aspects of their logic, like production, idle, etc. And while entering and exiting each single one of the states of the statecharts, times are calculated to determine how long each operator or machine spends in each state. So by the end of the simulation, I would print them or plot them using histograms to see the percentage of each step/state.

The problem that I'm having is the simulation's length is 480 minutes or 28800 seconds, but the sum of the time I calculate are different between runs and between agents (because I have 9 machines (from the agent type machine) and 6 operators (from the agent type operator)). For example, I would have 28750 seconds for operator#1 and 29000 seconds for operator#2 and so on.

I thought the reason the time was under 28800s was because sometimes the simulation is over before the agent leaves the current state, so the function wouldn't update because it didn't start the exist action. This make sense to me. But what makes no sense is the agents that exceed the length of the simulation (>28800s), some agents' time sums exceed the whole duration of the simulation, and I don't understand why.

Is there any way to know if the problem comes from a mistake I made while modeling or is this a problem with AnyLogic itself? I had a similar issue some while ago with the way AnyLogic calculate distance and got in contact with support, so I'm guessing maybe this time again it is some issue in the way AnyLogic handles time.


Edit, more details for @Artem P.:

Here is an example of the code used to calculate time elapsed, and the sum of codes, plus an example of the statechart:

This is the statechart of the machine, for example.

Statechart

In the entry action and exit action of each of these states (the lowest level states, not the higher levels ones) there is code to calculate entry time, then exist time, and the subtraction, for example these are the entry and exit actions for the waiting state:

Waiting state entry and exit actions

I then add each time to its own DataSet so that I can plot them in a histogram and have a percentage view of all the times, hence the TnPAttente_DS.update();

If you need more detail, I'm happy to share!

Ismail
  • 3
  • 3
  • Couple of extra questions: 1) How do you define `TnPAttnte_DS` and `TnPAttnte_DS.update();`? 2) Do you have any static variables? 3) How did you define model stop condition? – Artem P. Jun 03 '21 at 15:27
  • 1) `TnPAttente_DS` is just the dataset that stores the data after I calculate all the `time_exit - time_entry` and the `TnPAttente_DS.update()` is for efficiency I guess? Because I don't let the dataset update automatically, I only update it once it actually stores something. 2) What do you mean by static variables? I guess all my variables are dynamic? because they are all changing over time, idk I don't understand your question. 3) model runs for 8 hours or 480 minutes or 28800 seconds that's the stop condition, it runs until it's over, I want to simulate one work shift (8 hours) – Ismail Jun 03 '21 at 20:48

2 Answers2

0

Time operations are generally very dependent on the time unit of the model and how the actual adding is done. So, for example, if your model time unit is SECOND and you calculate total in SECOND, i.e. using something like:

double startTime = time();
...
double elapsedTime += time() - startTime;

then having a value of 29000 seconds in elapsedTime variable is impossible as value returned by time() would never reach that value.

However, if you're operating in minutes and need your value in seconds then there can very well be a rounding issue somewhere that accumulates over model run time. So, overall, the advice is: make sure that counting is done in the right units and avoid rounding.

Of course, a more detailed advice can be provided should you share the code and model layout via screenshots.

Artem P.
  • 816
  • 1
  • 6
  • 8
  • Best never call `time()` but give it the unit as an argument, such as `time(MINUTE)`. This way, you can always rely on the units. – Benjamin Jun 02 '21 at 16:07
  • Yes I am doing exacly like @Benjamin said. I am using `time(SECOND)`. But it still doesn't add up to the 28800 seconds of the simulation, it's either a bit less or a bit more (usually in the range of 10 to 100 seconds less or more) – Ismail Jun 03 '21 at 07:42
0

There could be a number of reasons why this isn't working:

  • Are you definitely setting the start time (enter action) and incrementing the elapsed time (exit action) in every simple state? Your screenshot shows you're using composite states: make sure you're not double-counting time via the composite state and the simple states.

  • Your start and elapsed-time variables need to be of type double, with instances of each per state per agent, and those variables not set/changed anywhere other than when their respective states start/end. (You'd be better structuring them via, say, a map of state to elapsed time; this also helps avoid silly mistakes such as typos meaning you are updating the variable for another state instead of the correct one. But you need to know a bit of Java for this.) Looks like you're using a single start time variable per agent which should be fine since exit actions will always fire before entry actions (so you'll be using its value before you reset it).

  • Are you allowing for the 'extra' time at simulation end (where they've been in a state for some time but not left it)? Though that would only result in under-counting time, not over-counting.

  • Rounding issues (as mentioned by Artem) if you're not getting the time value in the model time units (which necessitates division under the covers).

Stuart Rossiter
  • 2,432
  • 1
  • 17
  • 20
  • Hi! Thanks for your answer, * Yes my `startTime` variables are of type `double`! They are just not explicitly stated because of the way AnyLogic works, but when the simulation is compiled, they are indeed of type `double`! * Again, this is something internal to AnyLogic and I don't have much control over it, time incrementing is handled by AnyLogic and not by me. * I agree with this one, it's what I was trying to explain in the 1st half of the 3rd paragraph, but this would only explain the times that are smaller than the length of the simulation and would not explain the ones higher. – Ismail Jun 03 '21 at 08:09
  • * Rounding should not be an issue since all times are handled in `SECONDS` – Ismail Jun 03 '21 at 08:11
  • What do you mean by 'not explicitly stated'? When you define a Variable in an Agent, you explicitly specify its type. I'm aware you're handling in seconds from the other answer's comments but I'm writing this as a 'complete' answer that covers all the possibilities. – Stuart Rossiter Jun 03 '21 at 08:17
  • They are explicitly stated, my bad. Each one of the variables used are of type `double`. I thought you weren't familiar with AnyLogic. [Here you can see a variable used to calculate one portion of time](https://imgur.com/U9hihfs) and as you can see it is explicitly stated of type `double`. I think the 3rd answer is the closest one to what's really happening, but it's only half of the answer, because I still don't understand why the sum overshoots the total length of the simulation. It makes no sense, it's like time is being added from nothing, time coming from void. – Ismail Jun 03 '21 at 08:24
  • Didn't see you were using composite states too; updated the answer (since that's an area where you might be double-counting time and thus get over the sim length). – Stuart Rossiter Jun 03 '21 at 08:34
  • Thanks! I'm only counting time in simple states. Composite states are only there to act as a "box" of states of the same "nature", if that makes sense. – Ismail Jun 03 '21 at 09:16
  • You sure it's not something silly such as a typo meaning you're updating the wrong variable for a particular state (especially if you have separate variables for each state)? See my updated answer. – Stuart Rossiter Jun 03 '21 at 10:45
  • I double checked, there is no typo. The names of variables are different from one another so it'd be really hard to make a typo in this regard. I'll just double check the logic of the statecharts from start to finish, because I feel like that's where I'll find the problem, if there is one. Because I'm also thinking about some flaw in AnyLogic. I've had a similar issue 2 years ago, I used to use 2 ways of calculating distance which are supposed to return the same result but they weren't. I discussed it with the support and it got fixed in the following patch. – Ismail Jun 03 '21 at 10:56
  • An issue with distance calculations is a bit different to model time not being returned correctly! This should 100% be a model error not an AnyLogic bug, unless it's something very strange and subtle such as certain transitions causing entry/exit actions not to be executed in the right order (which should be impossible). – Stuart Rossiter Jun 03 '21 at 11:00
  • Yes I even moved all time calculations in entry actions to the top so they are executed first, and all the ones in exit actions to the bottom so they are executed last. But it didn't change anything, since they are all executed at the same time anyway, but I did it just to be sure. Anyways, thanks a lot for your help! I will check my code from start to finish and I'll see where the flaw is. If I have any new details to share I'll make sure to do it! Thanks again! :D – Ismail Jun 03 '21 at 11:07
  • If this is part of a larger model, your best bet is to try to reproduce the problem in a simpler model (and attempting to do that often cause you to realise the issue, or at least narrow down what 'features' are or aren't causing it). – Stuart Rossiter Jun 03 '21 at 11:09