|
| 1 | +# Environments |
| 2 | + |
| 3 | +A simulation environment manages the simulation time as well as the scheduling and processing of events. It also provides means to step through or execute the simulation. |
| 4 | + |
| 5 | +The base type for all environments is `Environment`. “Normal” simulations use its subtype `Simulation`. |
| 6 | + |
| 7 | +## Simulation control |
| 8 | + |
| 9 | +SimJulia is very flexible in terms of simulation execution. You can run your simulation until there are no more events, until a certain simulation time is reached, or until a certain event is triggered. You can also step through the simulation event by event. Furthermore, you can mix these things as you like. |
| 10 | + |
| 11 | +For example, you could run your simulation until an interesting event occurs. You could then step through the simulation event by event for a while; and finally run the simulation until there are no more events left and your processes have all terminated. |
| 12 | + |
| 13 | +The most important function here is `run`: |
| 14 | + |
| 15 | +- If you call it with an instance of the environment as the only argument (`run(env)`), it steps through the simulation until there are no more events left. If your processes run forever, this function will never terminate (unless you kill your script by e.g., pressing `Ctrl-C`). |
| 16 | + |
| 17 | +- In most cases it is advisable to stop your simulation when it reaches a certain simulation time. Therefore, you can pass the desired time via a second argument, e.g.: `run(env, 10)`. |
| 18 | + |
| 19 | + The simulation will then stop when the internal clock reaches 10 but will not process any events scheduled for time 10. This is similar to a new environment where the clock is 0 but (obviously) no events have yet been processed. |
| 20 | + |
| 21 | + If you want to integrate your simulation in a GUI and want to draw a process bar, you can repeatedly call this function with increasing until values and update your progress bar after each call: |
| 22 | + |
| 23 | +```julia |
| 24 | +sim = Simulation() |
| 25 | +for t in 1:100 |
| 26 | + run(sim, t) |
| 27 | + update(progressbar, t) |
| 28 | +end |
| 29 | +``` |
| 30 | + |
| 31 | +- Instead of passing a number as second argument to `run`, you can also pass any event to it. `run` will then return when the event has been processed. |
| 32 | + |
| 33 | + Assuming that the current time is 0, `run(env, Timeout(env, 5))` is equivalent to `run(env, 5)`. |
| 34 | + |
| 35 | + You can also pass other types of events (remember, that a `Process` is an event, too): |
| 36 | + |
| 37 | +```jldoctest |
| 38 | +using ResumableFunctions |
| 39 | +using SimJulia |
| 40 | +
|
| 41 | +@resumable function my_process(env::Environment) |
| 42 | + @yield Timeout(env, 1) |
| 43 | + "Monty Python's Flying Circus" |
| 44 | +end |
| 45 | +
|
| 46 | +sim = Simulation() |
| 47 | +proc = @process my_process(sim) |
| 48 | +run(sim, proc) |
| 49 | +
|
| 50 | +# output |
| 51 | +
|
| 52 | +"Monty Python's Flying Circus" |
| 53 | +``` |
| 54 | + |
| 55 | +To step through the simulation event by event, the environment offers `step`. This function processes the next scheduled event. It raises an `EmptySchedule` exception if no event is available. |
| 56 | + |
| 57 | +In a typical use case, you use this function in a loop like: |
| 58 | +```julia |
| 59 | +while now(sim) < 10 |
| 60 | + step(sim) |
| 61 | +end |
| 62 | +``` |
| 63 | + |
| 64 | +## State access |
| 65 | + |
| 66 | +The environment allows you to get the current simulation time via the function `now`. The simulation time is a number without unit and is increased via `Timeout` events. |
| 67 | + |
| 68 | +By default, the simulation starts at time 0, but you can pass an `initial_time` to the `Simulation` constructor to use something else. |
| 69 | + |
| 70 | +Note |
| 71 | + |
| 72 | +!!! note |
| 73 | + Although the simulation time is technically unitless, you can pretend that it is, for example, in milliseconds and use it like a timestamp returned by `Base.Dates.datetime2epochm` to calculate a date or the day of the week. The `Simulation` constructor and the `run` function accept as argument a `Base.Dates.DateTime` and the `Timeout` constructor a `Base.Dates.Delay`. Together with the convenience function `nowDateTime` a simulation can transparantly schedule its events in seconds, minutes, hours, days, ... |
| 74 | + |
| 75 | +The function `active_process` is comparable to `Base.Libc.getpid` and returns the current active `Process`. If no process is active, a `NullException` is thrown. A process is active when its process function is being executed. It becomes inactive (or suspended) when it yields an event. |
| 76 | + |
| 77 | +Thus, it only makes sense to call this function from within a process function or a function that is called by your process function: |
0 commit comments