Causal is a clocked simulation environment. That is, model components are evolved in different time intervals, called the sampling interval. During the simulation, model components are triggered by these generated time pulses. A Clock instance is used to to generate those time pulses. The simulation time settings–the simulation start time, stop time, sampling interval–are configured through the Clock.

Construction of Clock

Construction of Clock is done by specifying its start time and final time and the simulation sampling period.

julia> using Causal # hide

julia> Clock(0., 1, 10.)
Clock(gen:0.0:1.0:10.0, paused:false)

julia> Clock{Int}(1, 1, 10)
ERROR: MethodError: no method matching (Clock{Int64, CB} where CB)(::Int64, ::Int64, ::Int64)

Basic Usage of Clocks

A Clock has a Callback list so that a Callback can be constructed to trigger specific events configured with the time settings. See the following case study.

Let us consider a Clock with initial time of 0, sampling interval of 1 and final time of 10.

julia> using Causal # hide

julia> clk = Clock(0., 1., 10.)
Clock(gen:0.0:1.0:10.0, paused:false)

Notice that clk is not running, since it is not set. Now, let us set it

julia> set!(clk)
ERROR: UndefVarError: set! not defined

clk is ready to run, i.e., to be iterated. The following commands generated clock ticks and shows it on the console.

julia> for t in clk
           @show t
t = 0.0
t = 1.0
t = 2.0
t = 3.0
t = 4.0
t = 5.0
t = 6.0
t = 7.0
t = 8.0
t = 9.0
t = 10.0

At this point, clk is out of time. The current time of clk does not advance any more.

julia> take!(clk)
ERROR: MethodError: no method matching take!(::Clock{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Nothing})
Closest candidates are:
  take!(!Matched::IOBuffer) at iobuffer.jl:385
  take!(!Matched::Base.GenericIOBuffer) at iobuffer.jl:370
  take!(!Matched::Channel) at channels.jl:383

But, clk can be reset again.

julia> set!(clk, 0., 1., 10.)
ERROR: UndefVarError: set! not defined

Consider that we want to configure an alarm. For this, let us consider that when the time of clk is greater than 5 an alarm message is printed on the console. To this end, we need to construct a Callback and add it to the callbacks of clk. (When constructed callback list of clk is empty.)

julia> condition(clk) = clk.t > 5
condition (generic function with 1 method)

julia> action(clk) = println("Clock time = ", clk.t)
action (generic function with 1 method)

julia> clk = Clock(0., 1., 10., callbacks=Callback(condition=condition, action=action))
Clock(gen:0.0:1.0:10.0, paused:false)

julia> set!(clk)
ERROR: UndefVarError: set! not defined

Now, let us run clk by iterating it.

julia> for t in clk
           @show t
ERROR: type Clock has no field t

Note that we, constructed a simple callback. It is of course possible to construct more complex callbacks.

Usage of Clocks with ProgressMeter

It also possible to iterate the Clocks by using a progress meter. See ProgressMeter for further information for progress meter.

using Causal
using ProgressMeter
clk = Clock(0., 0.01, 1.)
@showprogress for t in clk 

Note that clk is just iterated.

Full API

mutable struct Clock{T, CB}

Clock generates time instants to sample the systems. A Clock is an iterable


  • generator::Any

    Internal generator. Can be any iterable

  • paused::Bool

    If true, clock iteration is halted

  • callbacks::Any

    Callback set. See Callback

  • name::Symbol

    Name of clock

  • uuid::Base.UUID

    Identiy number of clock


julia> clk = Clock(0 : 2) 
Clock(gen:0:2, paused:false)

julia> for t in clk 
       @show t 
t = 0
t = 1
t = 2

Pauses clk. When paused, the iteration of clock is halted.


julia> clk = Clock(0 : 5)
Clock(gen:0:5, paused:false)

julia> iterate(clk) 
(0, 0)

julia> iterate(clk, 1)
(2, 2)

julia> pause!(clk) 
Clock(gen:0:5, paused:true)

julia> iterate(clk, 1)
┌ Warning: Clock is paused
└ @ Causal ~/.julia/dev/Causal/src/components/sources/clock.jl:41