User guide
Installation
Simulate.jl
runs on Julia versions ≥ v"1.0" [1]. The current stable, registered version is installed with
pkg> add Simulate
The development version is installed with:
pkg> add("https://github.com/pbayer/Simulate.jl")
The package is then loaded with
julia> using Simulate
The 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 withsample_time!
.t0::Number=0
: start time for simulationunit::FreeUnits=NoUnits
: clock time unit. Units can be set explicitely by setting e.g.unit=minute
or implicitly by giving Δt as a time or else setting t0 to a time, e.g.t0=60s
.
Fields
state::SState
: clock statetime::Float64
: clock timeunit::FreeUnits
: time unitevents::PriorityQueue{SimEvent,Float64}
: scheduled eventscevents::Array{SimCond,1}
: conditional eventsprocesses::Dict{Any, SimProcess}
: registered processesend_time::Float64
: end time for simulationevcount::Int64
: event counterscount::Int64
: sample counttev::Float64
: next event timeΔt::Float64
: sampling time, timestep between tickssexpr::Array{Sample,1}
: sampling expressions to evaluate at each ticktsa::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.0
The 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 ofms
,s
,minute
orhr
or another UnitfulTime
unit.
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
minute
Simulate.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.0
Simulate.@tau
— Macro.@tau(sim::Clock)
@tau sim
@tau()
@tau
return 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.Timing
Enumeration 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 timearg...
: arguments to the functionkw...
: 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
12
Simulate.@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.:f
if 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
5
Simulate.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
end
All 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::Real
ort::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.0
As 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
,after
orevery
(before
behaves likeat
),t::Float64
ort::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.0
Conditional 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__)
true
Simulate.@tau
— Macro.@tau(sim::Clock, check::Symbol, val)
@tau sim check val
@tau(check::Symbol, val)
@tau check val
create 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
2
Simulate.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__)
true
Simulate.@val
— Macro.@val(a, check::QuoteNode, b)
@val a check b
Create 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 symbolcheck::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
2
Processes
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 withfunc::Function
: a functionf(arg...; kw...)
arg...
: further arguments tof
kw...
: keyword arguments tof
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 taskvalue=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
: onlyuntil
is 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 incrementt0::Float64=0
ort0::Time
: start timehard::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::Time
is 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.0
Simulate.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.DataFrame
Types
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 variablesscope::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.