User guide
Installation
Simulate.jl runs on Julia versions ≥ v"1.0" [1]. The current stable, registered version is installed with
pkg> add SimulateThe development version is installed with:
pkg> add("https://github.com/pbayer/Simulate.jl")The package is then loaded with
julia> using SimulateThe clock
Simulate.Clock — Type.Clock(Δt::Number=0; t0::Number=0, unit::FreeUnits=NoUnits)Create a new simulation clock.
Arguments
- Δt::Number=0: time increment. If no Δt is given, the simulation doesn't tick, but jumps from event to event. Δt can be set later with- sample_time!.
- t0::Number=0: start time for simulation
- unit::FreeUnits=NoUnits: clock time unit. Units can be set explicitely by setting e.g.- unit=minuteor implicitly by giving Δt as a time or else setting t0 to a time, e.g.- t0=60s.
Fields
- state::SState: clock state
- time::Float64: clock time
- unit::FreeUnits: time unit
- events::PriorityQueue{SimEvent,Float64}: scheduled events
- cevents::Array{SimCond,1}: conditional events
- processes::Dict{Any, SimProcess}: registered processes
- end_time::Float64: end time for simulation
- evcount::Int64: event counter
- scount::Int64: sample count
- tev::Float64: next event time
- Δt::Float64: sampling time, timestep between ticks
- sexpr::Array{Sample,1}: sampling expressions to evaluate at each tick
- tsa::Float64: next sample time
Examples
julia> using Simulate, Unitful
julia> import Unitful: s, minute, hr
julia> c = Clock()                 # create a unitless clock (standard)
Clock: state=Simulate.Undefined(), time=0.0, unit=, events: 0, cevents: 0, processes: 0, sampling: 0, sample rate Δt=0.0
julia> init!(c)                    # initialize it explicitly (normally done implicitly)
Simulate.Idle()
julia> c = Clock(1s, unit=minute)  # create a clock with units, does conversions automatically
Clock: state=Simulate.Undefined(), time=0.0, unit=minute, events: 0, cevents: 0, processes: 0, sampling: 0, sample rate Δt=0.016666666666666666
julia> c = Clock(1s)               # create a clock with implicit unit setting
Clock: state=Simulate.Undefined(), time=0.0, unit=s, events: 0, cevents: 0, processes: 0, sampling: 0, sample rate Δt=1.0
julia> c = Clock(t0=60s)           # another example of implicit unit setting
Clock: state=Simulate.Undefined(), time=60.0, unit=s, events: 0, cevents: 0, processes: 0, sampling: 0, sample rate Δt=0.0
julia> c = Clock(1s, t0=1hr)       # if given times with different units, Δt takes precedence
Clock: state=Simulate.Undefined(), time=3600.0, unit=s, events: 0, cevents: 0, processes: 0, sampling: 0, sample rate Δt=1.0The central clock is 𝐶. You can set time units and query the current simulation time.
Simulate.𝐶 — Constant.𝐶
Clk𝐶 (𝐶 = \itC+tab) or Clk is the central simulation clock. If you do one simulation at a time, you can use 𝐶 or Clk for time keeping.
Examples
julia> using Simulate
julia> reset!(𝐶)
"clock reset to t₀=0.0, sampling rate Δt=0.0."
julia> 𝐶  # central clock
Clock: state=Simulate.Idle(), time=0.0, unit=, events: 0, cevents: 0, processes: 0, sampling: 0, sample rate Δt=0.0
julia> 𝐶 === Clk
true
Simulate.setUnit! — Function.setUnit!(sim::Clock, new::FreeUnits)set a clock to a new time unit in Unitful. If necessary convert current clock times to the new unit.
Arguments
- sim::Clock
- new::FreeUnits: new is one of- ms,- s,- minuteor- hror another Unitful- Timeunit.
Examples
julia> using Simulate, Unitful
julia> import Unitful: Time, s, minute, hr
julia> c = Clock(t0=60)     # setup a new clock with t0=60
Clock: state=Simulate.Undefined(), time=60.0, unit=, events: 0, cevents: 0, processes: 0, sampling: 0, sample rate Δt=0.0
julia> tau(c) # current time is 60.0 NoUnits
60.0
julia> setUnit!(c, s)       # set clock unit to Unitful.s
60.0 s
julia> tau(c) # current time is now 60.0 s
60.0 s
julia> setUnit!(c, minute)  # set clock unit to Unitful.minute
1.0 minute
julia> tau(c)               # current time is now 1.0 minute
1.0 minute
julia> typeof(tau(c))       # tau(c) now returns a time Quantity ...
Quantity{Float64,𝐓,Unitful.FreeUnits{(minute,),𝐓,nothing}}
julia> isa(tau(c), Time)
true
julia> uconvert(s, tau(c))  # ... which can be converted to other time units
60.0 s
julia> tau(c).val           # it has a value of 1.0
1.0
julia> c.time               # internal clock time is set to 1.0 (a Float64)
1.0
julia> c.unit               # internal clock unit is set to Unitful.minute
minuteSimulate.tau — Method.tau(sim::Clock=𝐶)
τ(sim::Clock=𝐶)Return the current simulation time (τ = \tau+tab).
Examples
julia> using Simulate
julia> reset!(𝐶)
"clock reset to t₀=0.0, sampling rate Δt=0.0."
julia> tau() # gives the central time
0.0
julia> τ() # alias, gives the central time
0.0Simulate.@tau — Macro.@tau(sim::Clock)
@tau sim
@tau()
@taureturn the current simulation time.
Arguments
- sim::Clock: if no clock argument is given, it returns 𝐶's time.
Events
Events are scheduled on the clock's timeline and are triggered at a given simulation time or under conditions which may become true during simulation.
Expressions and functions as events and conditions
Julia expressions and functions can be scheduled as events.
Simulate.Timing — Type.TimingEnumeration type for scheduling events and timed conditions:
- at: schedule an event at a given time,
- after: schedule an event a given time after current time,
- every: schedule an event every given time from now on,
- before: a timed condition is true before a given time,
- until: delay until t.
Simulate.SimFunction — Type.SimFunction(func::Function, arg...; kw...)
SF(func::Function, arg...; kw...)Prepare a function for being called as an event in a simulation.
Arguments, fields
- func::Function: function to be executed at a later simulation time
- arg...: arguments to the function
- kw...: keyword arguments
If the variables stored in a SimFunction are composite types, they can change until they are evaluated later by func.
Example
julia> using Simulate
julia> f(a,b,c; d=4, e=5) = a+b+c+d+e       # if you define a function and ...
f (generic function with 1 method)
julia> sf = SF(f, 10, 20, 30, d=14, e=15);  # store it as SimFunction
julia> sf.func(sf.arg...; sf.kw...)         # it can be executed later
89
julia> d = Dict(:a => 1, :b => 2);          # we set up a dictionary
julia> g(t) = t[:a] + t[:b]                 # and a function adding :a and :b
g (generic function with 1 method)
julia> g(d)                                 # our add function gives 3
3
julia> ff = SimFunction(g, d);              # we set up a SimFunction
julia> d[:a] = 10;                          # later somehow we change d
julia> ff.func(ff.arg...)                   # calling ff then gives a different result
12Simulate.@SF — Macro.@SF(f::Symbol, arg...)
@SF f arg...create a SimFunction from arguments f, arg...
Arguments
- f::Symbol: a function given as a symbol, e.g.- :fif f() is your function,
- arg...: further arguments to your function
- keyword arguments don't work with this macro, use SF instead.
- if you give @SF as argument(s) to a function, you must enclose it/them in parentheses ( @SF ... ) or ( (@SF ...), (@SF ...) )
Examples
julia> using Simulate
julia> a = 1
1
julia> incra() = global a += 1             # create a simple increment function
incra (generic function with 1 method)
julia> event!((@SF incra), after, 3);      # schedule an increment after 3 time units
julia> a                                   # nothing happened to a
1
julia> run!(𝐶, 5)                          # run the simulation
"run! finished with 1 clock events, 0 sample steps, simulation time: 5.0"
julia> a                                   # now it should have been incremented
2
julia> event!((@SF incra), (@tau :>= 8));  # schedule a conditional event
julia> run!(𝐶, 5)
"run! finished with 0 clock events, 301 sample steps, simulation time: 10.0"
julia> a                                   # the conditional event was triggered
3
julia> event!(((@SF incra), (@SF incra)),  # two increments
        ((@tau :>= 12), (@val :a :<= 3))); # on two conditions
julia> run!(𝐶, 5)
"run! finished with 0 clock events, 201 sample steps, simulation time: 15.0"
julia> a                                   # two increments happened
5Simulate.SimExpr — Constant.SimExpr = Union{Expr, SimFunction}A type which is either a SimFunction or Julia expression, Expr-type.
SimFunctions and expressions can be given to events on their own or in arrays or tuples, even mixed:
function events()
    event!(:(i += 1), after, 10)  # one expression
    event!(SF(f, 1, 2, 3, diff=pi), every, 1)  # one SimFunction
    event!((:(i += 1), SF(g, j)), [:(tau() ≥ 50), SF(isready, input), :(a ≤ 10)]) # two SimExpr under three conditions
endAll given expressions or functions are then evaluated at a given simulation time or when during simulation the given conditions become true.
Timed events
SimFunctions and expressions can be scheduled for execution at given clock times.
Simulate.event! — Method.event!(sim::Clock, ex::Union{SimExpr, Array, Tuple}, t::Number; scope::Module=Main, cycle::Number=0.0)::Float64
event!(ex::Union{SimExpr, Array, Tuple}, t::Number; scope::Module=Main, cycle::Number=0.0)Schedule an event for a given simulation time.
Arguments
- sim::Clock: simulation clock, if no clock is given, the event goes to 𝐶,
- ex::{SimExpr, Array, Tuple}: an expression or SimFunction or an array or tuple of them,
- t::Realor- t::Time: simulation time, if t < sim.time set t = sim.time,
- scope::Module=Main: scope for expressions to be evaluated in,
- cycle::Float64=0.0: repeat cycle time for an event.
returns
Scheduled internal simulation time (unitless) for that event. May return a time > t from repeated applications of nextfloat(t) if there are events scheduled for t.
Examples
julia> using Simulate, Unitful
julia> import Unitful: s, minute, hr
julia> myfunc(a, b) = a+b
myfunc (generic function with 1 method)
julia> event!(𝐶, SimFunction(myfunc, 1, 2), 1) # a 1st event to 1
1.0
julia> event!(𝐶, SimFunction(myfunc, 2, 3), 1) #  a 2nd event to the same time
1.0000000000000002
julia> event!(𝐶, SimFunction(myfunc, 3, 4), 1s)
Warning: clock has no time unit, ignoring units
1.0000000000000004
julia> setUnit!(𝐶, s)
0.0 s
julia> event!(𝐶, SimFunction(myfunc, 4, 5), 1minute)
60.0As a convenience the Timing can be also choosen using at, after or every t.
Simulate.event! — Method.event!(sim::Clock, ex::Union{SimExpr, Array, Tuple}, T::Timing, t::Number; scope::Module=Main)::Float64
event!(ex::Union{SimExpr, Array, Tuple}, T::Timing, t::Number; scope::Module=Main)Schedule a timed event, that is an event with a timing.
Arguments
- sim::Clock: simulation clock, if no clock is given, the event goes to 𝐶,
- ex::{SimExpr, Array, Tuple}: an expression or SimFunction or an array or tuple of them,
- T::Timing: a timing,- at,- afteror- every(- beforebehaves like- at),
- t::Float64or- t::Time: simulation time,
- scope::Module=Main: scope for the expressions to be evaluated
returns
Scheduled internal simulation time (unitless) for that event.
Examples
julia> using Simulate, Unitful
julia> import Unitful: s, minute, hr
julia> setUnit!(𝐶, s)
0.0 s
julia> myfunc(a, b) = a+b
myfunc (generic function with 1 method)
julia> event!(𝐶, SimFunction(myfunc, 5, 6), after, 1hr)
3600.0Conditional events
They are evaluated at each clock tick (like sampling functions) and are fired when all conditions are met.
Simulate.event! — Method.event!(sim::Clock, ex::Union{SimExpr, Array, Tuple}, cond::Union{SimExpr, Array, Tuple}; scope::Module=Main):
event!(ex::Union{SimExpr, Array, Tuple}, cond::Union{SimExpr, Array, Tuple}; scope::Module=Main)Schedule a conditional event.
It is executed immediately if the conditions are met, else the condition is checked at each clock tick Δt. A conditional event is triggered only once. After that it is removed from the clock. If no sampling rate Δt is setup, a default sampling rate is setup depending on the scale of the remaining simulation time $Δt = scale(t_r)/100$ or $0.01$ if $t_r = 0$.
Arguments
- sim::Clock: simulation clock, if no clock is given, the event goes to 𝐶,
- ex::{SimExpr, Array, Tuple}: an expression or SimFunction or an array or tuple of them,
- cond::{SimExpr, Array, Tuple}: a condition is an expression or SimFunction or an array or tuple of them. It is true only if all expressions or SimFunctions therein return true,
- scope::Module=Main: scope for the expressions to be evaluated
returns
current simulation time tau(sim).
Examples
julia> using Simulate
julia> c = Clock()   # create a new clock
Clock: state=Simulate.Undefined(), time=0.0, unit=, events: 0, cevents: 0, processes: 0, sampling: 0, sample rate Δt=0.0
julia> event!(c, SF((x)->println(tau(x), ": now I'm triggered"), c), (@tau c :>= 5))
0.0
julia> c             # a conditional event turns sampling on
Clock: state=Simulate.Undefined(), time=0.0, unit=, events: 0, cevents: 1, processes: 0, sampling: 0, sample rate Δt=0.01
julia> run!(c, 10)   # sampling is not exact, so it takes 501 sample steps to fire the event
5.009999999999938: now I'm triggered
"run! finished with 0 clock events, 501 sample steps, simulation time: 10.0"After the event is triggered, sampling is again switched off.
Since conditions often are not met exactly you should prefer inequalities like <, ≤, ≥, > to equality == in order to get sure that a fulfilled condition can be detected, e.g. $:(tau() ≥ 100)$ is preferable to $:(tau() == 100)$.
There are some helper functions and macros for defining conditions. It is usually more convenient to use the macros since the generate the necessary SimFunctions directly:
Simulate.tau — Method.tau(sim::Clock, check::Function, x::Union{Number,Symbol}; m::Module=Main)
tau(check::Function, x::Union{Number,Symbol}; m::Module=Main)Compare the current simulation time against a number or a variable.
Arguments
- sim::Clock: clock variable, if not given, it is 𝐶.
- check::Function: a comparison operator like ≥, >, ==, <, ≤,
- x::Union{Number,Symbol}: a number or a symbolic variable like- :a, a symbolic variable can be evaluated later at event time,
- m::Module=Main: the evaluation scope, if a symbolic variable is given.
Examples
julia> using Simulate
julia> tau(>=, 1)
false
julia> tau(<, 1)
true
julia> a = 1
1
julia> tau(<=, :a, @__MODULE__)
trueSimulate.@tau — Macro.@tau(sim::Clock, check::Symbol, val)
@tau sim check val
@tau(check::Symbol, val)
@tau check valcreate a SimFunction comparing current simulation time with a given value or variable.
Arguments
- sim::Clock: if no clock is given, it compares with 𝐶's time,
- check::Symbol: the check operator must be given as a symbol e.g.- :<,
- val::Union{Number, QuoteNode}: a value or a symbolic variable,
If you give @tau as argument(s) to a function, you must enclose it/them in parentheses ( @tau ... ) or ( (@tau ...), (@tau ...) )!
Examples
julia> using Simulate
julia> reset!(𝐶)
"clock reset to t₀=0.0, sampling rate Δt=0.0."
julia> sf = @tau :≥ 100;
julia> Simulate.simExec(sf)
false
julia> Simulate.simExec(@tau < 100)                ### wrong !!
ERROR: syntax: "<" is not a unary operator
julia> Simulate.simExec(@tau :< 100)               ### correct
true
julia> a = 1
1
julia> Simulate.simExec(@tau :< :a)
true
julia> event!(SF(()->global a+=1), (@tau :>= 3))   ### create a conditional event
0.0
julia> a
1
julia> run!(𝐶, 5)                                  ### run
"run! finished with 0 clock events, 301 sample steps, simulation time: 5.0"
julia> a
2Simulate.val — Function.val(a::Union{Number, Symbol}, check::Function, x::Union{Number, Symbol}, m::Module=Main)Compare two variables or numbers.
Arguments
- a,- xUnion{Number, Symbol}: a number or a symbolic variable like- :a, a symbolic variable can be evaluated later at event time,
- check::Function: a comparison operator like ≥, >, ==, <, ≤,
- m::Module=Main: the evaluation scope, if a symbolic variable is given.
Examples
julia> using Simulate
julia> val(1, <=, 2)
true
julia> a = 1
1
julia> val(:a, <=, 2, @__MODULE__)
trueSimulate.@val — Macro.@val(a, check::QuoteNode, b)
@val a check bCreate a Simfunction comparing two values a and b or two symbolic variables :a and :b. The comparison operator must be given symbolically, e.g. :≤.
Arguments
- a, b:: a number, expression or symbol
- check::QuoteNode: a comparison operator as a symbol like- :>or- :≤
If you give @val as argument(s) to a function, you must enclose it/them in parentheses ( @val ... ) or e.g. ( (@tau ...), (@val ...) )!
Examples
julia> using Simulate
julia> reset!(𝐶)
"clock reset to t₀=0.0, sampling rate Δt=0.0."
julia> Simulate.simExec(@val 1 :≤ 2)
true
julia> a = 1
1
julia> Simulate.simExec(@val :a :≤ 2)
true
julia> event!(SF(()->global a+=1), ((@tau :>= 3), (@val :a :<= 3))); # a conditional event
julia> run!(𝐶, 5)
"run! finished with 0 clock events, 301 sample steps, simulation time: 5.0"
julia> a
2Processes
Julia functions can be registered and run as processes if they have an input and an output channel as their first two arguments. They follow another (the process-oriented) scheme and can be suspended and reactivated by the scheduler if they wait for something or delay. They must not (but are free to) handle and create events explicitly.
Simulate.SimProcess — Type.SimProcess( id, func::Function, arg...; kw...)
SP(id, func::Function, arg...; kw...)Prepare a function to run as a process in a simulation.
Arguments, fields
- id: some unique identification, it should get registered with
- func::Function: a function- f(arg...; kw...)
- arg...: further arguments to- f
- kw...: keyword arguments to- f
A function as a SimProcess most often runs in a loop. It has to give back control by e.g. doing a take!(input) or by calling delay! etc., which will yield it. Otherwise it will starve everything else!
Examples
julia> using Simulate
Simulate.@SP — Macro.@SP(id, f::Symbol, arg...)
@SP id f arg...create a SimProcess from arguments f, arg...
keyword arguments don't work with this macro, use SP instead.
Simulate.SimException — Type.SimException(ev::SEvent, value=nothing)Define a SimException, which can be thrown to processes.
Arguments, fields
- ev::SEvent: delivers an event to the interrupted task
- value=nothing: deliver some other value
Simulate.process! — Function.process!(sim::Clock, p::SimProcess, cycles=Inf)
process!(p::SimProcess, cycles=Inf)Register a SimProcess to a clock, start it as an asynchronous process and return the id it was registered with. It can then be found under sim.processes[id].
Arguments
- sim::Clock: clock, if no clock is given, it runs under 𝐶,
- p::SimProcess
- cycles::Number=Inf: number of cycles the process should run.
Simulate.interrupt! — Function.interrupt!(p::SimProcess, ev::SEvent, value=nothing)Interrupt a SimProcess by throwing a SimException to it.
Simulate.stop! — Method.Stop a SimProcess
Delay and wait …
Processes must not handle their events explicitly, but can call delay! or wait! or take! and put! … on their channels. This usually comes in handy. They are then suspended until certain conditions are met or requested resources are available.
Simulate.delay! — Function.delay!(sim::Clock, t::Number)
delay!(t::Number)Delay a process for a time interval t on the clock sim. Suspend the calling process until being reactivated by the clock at the appropriate time.
Arguments
- sim::Clock: clock, if no clock is given, the delay goes to- 𝐶.
- t::Number: the time interval for the delay.
delay!(sim::Clock, T::Timing, t::Number)
delay!(T::Timing, t::Number)Used for delaying a process until a given time t.
Arguments
- sim::Clock: if no clock is given, the delay goes to 𝐶,
- T::Timing: only- untilis accepted,
- t::Number: delay until time t if t > sim.time, else give a warning.
Simulate.wait! — Function.wait!(sim::Clock, cond::Union{SimExpr, Array, Tuple}; scope::Module=Main)
wait!(cond::Union{SimExpr, Array, Tuple}; scope::Module=Main)Wait on a clock for a condition to become true. Suspend the calling process until the given condition is true.
Arguments
- sim::Clock: clock, if no clock is given, the delay goes to- 𝐶.
- cond::Union{SimExpr, Array, Tuple}: a condition is an expression or SimFunction or an array or tuple of them. It is true only if all expressions or SimFunctions therein return true.
- scope::Module=Main: evaluation scope for given expressions
Now
If processes want IO-operations to finish before letting the clock proceed, they can enclose those operations in a now! call.
Simulate.now! — Function.now!(sim::Clock, op::Union{SimExpr, Array, Tuple})
now!(op::Union{SimExpr, Array, Tuple})Let the given operation be executed now! by the clock. Thus the clock cannot proceed before the op is finished.
Arguments
- sim::Clock:
- op::Union{SimExpr, Array, Tuple}:
Continuous sampling
Functions or expressions can register for sampling and are then executed "continuously" at each clock increment Δt.
Simulate.sample_time! — Function.sample_time!(sim::Clock, Δt::Number)
sample_time!(Δt::Number)set the clock's sample rate starting from now (tau(sim)).
Arguments
- sim::Clock: if no clock is given, set the sample rate on 𝐶,
- Δt::Number: sample rate, time interval for sampling
Simulate.sample! — Function.sample!(sim::Clock, ex::Union{Expr, SimFunction}, Δt::Number=sim.Δt; scope::Module=Main)
sample!(ex::Union{Expr, SimFunction}, Δt::Number=sim.Δt; scope::Module=Main)enqueue an expression for sampling.
Arguments
- sim::Clock: if no clock is given, it samples on 𝐶,
- ex::Union{Expr, SimFunction}: an expression or function,
- Δt::Number=sim.Δt: set the clock's sampling rate, if no Δt is given, it takes the current sampling rate, if that is 0, it calculates one,
- scope::Module=Main: optional, an evaluation scope for a given expression.
Running simulations
If we run the clock, events are triggered, conditions are evaluated, sampling is done and delays are executed … Thus we run a simulation. We can also step through a simulation or stop and resume a clock, reset ist and so on.
Simulate.reset! — Function.reset!(sim::Clock, Δt::Number=0; t0::Number=0, hard::Bool=true, unit=NoUnits)reset a clock
Arguments
- sim::Clock
- Δt::Number=0: time increment
- t0::Float64=0or- t0::Time: start time
- hard::Bool=true: time is reset, all scheduled events and sampling are deleted. If hard=false, then only time is reset, event and sampling times are adjusted accordingly.
- unit=NoUnits: the Time unit for the clock after reset. If a- Δt::Timeis given, its Time unit goes into the clock Time unit. If only t0::Time is given, its Time unit goes into the clock time unit.
Examples
julia> using Simulate, Unitful
julia> import Unitful: s
julia> c = Clock(1s, t0=60s)
Clock: state=Simulate.Undefined(), time=60.0, unit=s, events: 0, cevents: 0, processes: 0, sampling: 0, sample rate Δt=1.0
julia> reset!(c)
"clock reset to t₀=0.0, sampling rate Δt=0.0."
julia> c
Clock: state=Simulate.Idle(), time=0.0, unit=, events: 0, cevents: 0, processes: 0, sampling: 0, sample rate Δt=0.0Simulate.incr! — Function.incr!(sim::Clock)Take one simulation step, execute the next tick or event.
Simulate.run! — Function.run!(sim::Clock, duration::Number)Run a simulation for a given duration. Call scheduled events and evaluate sampling expressions at each tick in that timeframe.
Simulate.stop! — Method.stop!(sim::Clock)Stop a running simulation.
Simulate.resume! — Function.resume!(sim::Clock)Resume a halted simulation.
Simulate.sync! — Function.sync!(sim::Clock, to::Clock=𝐶)Force a synchronization of two clocks. Change all registered times of sim accordingly. Convert or force sim.unit to to.unit.
Logging
A Logger allows to register variables and to record their states on demand. The last record is stored in the logging variable. According to the Logger's state it can be printed or stored in a table.
Example
julia> sim = Clock(); # create a clock
julia> l = Logger(); # create a logging variable
julia> init!(l, sim); # initialize the logger
julia> (a, b, c) = 1, 1, 1 # create some variables
(1, 1, 1)
julia> setup!(l, [:a, :b, :c], scope = m); # register them for logging
ERROR: UndefVarError: m not defined
julia> record!(l) # record the variables with the current clock time
Warning: undefined transition Logger, ::Simulate.Empty, ::Simulate.Log)
julia> l.last # show the last record
NamedTuple()
julia> function f()  # a function for increasing and recording the variables
         global a += 1
         global b = a^2
         global c = a^3
         record!(l)
       end
f (generic function with 1 method)
julia> switch!(l, 1); # switch logger to printing
Warning: undefined transition Logger, ::Simulate.Empty, ::Simulate.Switch)
julia> f() # increase and record the variables
Warning: undefined transition Logger, ::Simulate.Empty, ::Simulate.Log)
julia> switch!(l, 2); # switch logger to storing in data table
Warning: undefined transition Logger, ::Simulate.Empty, ::Simulate.Switch)
julia> for i in 1:10 # create some events
           event!(sim, :(f()), i, scope = m)
       end
ERROR: UndefVarError: m not defined
julia> run!(sim, 10) # run a simulation
"run! finished with 0 clock events, 0 sample steps, simulation time: 10.0"
julia> l.df # view the recorded values
0×0 DataFrames.DataFrameTypes
Simulate.Logger — Type.Logger()Setup and return a logging variable.
Functions
Simulate.init! — Function.init!(sim::Clock)initialize a clock.
init!(L::Logger, sim::Clock)Initialize a Logger.
Simulate.setup! — Function.setup!(L::Logger, vars::Array{Symbol})Setup a logger with logging variables.
Arguments
- L::Logger
- vars::Array{Symbol}: An array of symbols, e.g. of global variables
- scope::Module = Main: Scope in which to evaluate the variables
Simulate.switch! — Function.switch!(L::Logger, to::Number=0)Switch the operating mode of a logger.
to = 0: no output, to = 1: print, `to = 2: store in log table"
Simulate.record! — Function.record!(L::Logger)record the logging variables with the current operating mode.
Simulate.clear! — Function.clear!(L::Logger)clear the loggers last record and data table.
currently builds fail on x86 machines with Julia 1.0, Appveyor is set to allow this. There is an issue in the repo, maybe someone can look into it or fix it.