Simulation

One function handles running the simulation: simulate.

SystemsOfSystems.simulateFunction
simulate(user_data; t, init_fcn, rates_fcn, updates_fcn, seed, options)

Runs a simulation, returning a SimHistory containing its log, start and stop times, final model, and termination reason.

  • user_data: Can be anything used by the init_fcn
  • t: A collection of strictly increasing, finite times. The sim will step to exactly each given time, plus as many other steps as are required by the solver and models. At the very least, this must contain a start time and end time.
  • init_fcn: Will be called with (t_start, user_data, seed), where t_start is the first element of the above t input. This must return a ModelDescription.
  • rates_fcn: Will be called with (t, model) and is expected to return a RatesOutput.
  • updates_fcn: Will be called with (t, model) and is expected to return an UpdatesOutput, or nothing when there are no updates, outputs, replacement t_next, or stop request.
  • seed: A top-level seed (Int) to control all random number generation in the sim. The init_fcn receives this as a BranchingSeed.
  • options: See SimOptions.
source

Simulation Results

simulate returns one SimHistory. It contains the requested start time, the last completed simulation time, the final model, the log, and the reason the simulation stopped.

history = simulate(...)

history.t_start
history.t_stop
history.model
history.stop

Julia's property destructuring is convenient when only part of the result is needed:

(; t_stop, model) = simulate(...)

succeeded reports whether the simulation ended normally. Reaching the requested end time and a deliberate stop request both count as success; an exception or numerical solver failure does not.

if !succeeded(history)
    @warn "Simulation failed" reason = history.stop
end
SystemsOfSystems.SimHistoryType

A container for simulation results, including fields for:

  • t_start: The simulation's start time
  • t_stop: The last time completed by the simulation
  • log: The log containing the time series for each variable of each model
  • model: The final model constructed in the sim
  • stop: The normal stop or failure reason that ended the simulation

This type acts like a log itself, so for instance these do the same thing:

history["/models/plant"]["position"]
history.log["/models/plant"]["position"]

The keys, values, and pairs functions also pass through to the underlying log.

source
SystemsOfSystems.succeededFunction
succeeded(h::SimHistory)

Returns true if the simulation ended without throwing an error or failing to converge on a solution.

source

Recorded Histories

SimHistory forwards the dictionary-like log interface, so users normally do not need to access its log field directly. These expressions are equivalent:

history["/vehicle/controller"]["command"]
history.log["/vehicle/controller"]["command"]

Each model path returns a Logs.ModelHistory. Its constants, states, outputs, and submodels can be accessed by string or symbol. Logging policies may omit selected variables while preserving the model-history structure.

Logs.gather_all_time_series collects every recorded TimeSeries into one ordered dictionary. Its keys combine the model path and variable name, making it useful for searching, exporting, or passing a flat collection to another tool.

all_series = Logs.gather_all_time_series(history)
position = all_series["/vehicle:position"]
SystemsOfSystems.Logs.ModelHistoryType
ModelHistory

A container for the recorded history of one model.

The named-tuple fields contain the model's constants, state and output time series, and recursive submodel histories. path identifies the model, using / for the root.

A model logging policy may omit constants and time-series fields from these named tuples. Constants preserve their declaration form: raw constants remain raw values, while constants declared with VariableDescription retain that description and its metadata.

ModelHistory is mutable to give large, recursively parameterized histories reference semantics. Its fields are established during log construction and are not normally reassigned; samples are appended to the contained time series.

source
SystemsOfSystems.Logs.gather_all_time_seriesFunction
gather_all_time_series(history)

Collects every TimeSeries below a ModelHistory, AbstractLog, or SimHistory into an ordered dictionary. Keys identify both the model and variable, such as "/aircraft/imu:angular_velocity".

source

Time-Series Utilities

SystemsOfSystems.select derives a new time series while preserving its timestamps and metadata. It is public but qualified because select is a common name in data-analysis packages.

speed = SystemsOfSystems.select(history["/"]["velocity"]; title = "Speed") do velocity
    abs(velocity)
end

plot_ts creates a new Makie figure. plot_ts! adds a time series to an existing figure or layout target. Either function requires a loaded Makie backend.

using CairoMakie

figure = Figure()
plot_ts!(figure[1, 1], history["/"]["position"])
figure
SystemsOfSystems.TimeSeriesStuff.selectFunction
select(f, ts::TimeSeries; kwargs)

Applies f to each data element and returns the results as a new TimeSeries. Time and the associated metadata come from ts by default. A derived series representing a new signal can provide a new path and title.

Keyword arguments:

  • title: Title for the new time series
  • dimensions: Dimensions for the transformed data
  • path: Complete signal path associated with the new time series
  • discrete: Whether the new time series is discrete
  • interpolator: Interpolation policy for the new time series
  • groups: Dimension groups for the new time series

Example:

accelerometer_ts = SystemsOfSystems.select(measurements_ts) do measurement
    measurement.accelerometer
end
source
select(ts::TimeSeries, dimension::AbstractString; kwargs)

Selects the dimension with the given label as a new TimeSeries.

source
select(ts::TimeSeries, dimensions::AbstractVector{<:AbstractString}; kwargs)

Selects the dimensions with the given labels as a new TimeSeries of tuples.

source
SystemsOfSystems.TimeSeriesStuff.plot_tsFunction
plot_ts(time_series; kwargs...)

Creates a Makie figure containing one or more time series. A Makie backend such as GLMakie or CairoMakie must be loaded before calling this function.

source
plot_ts(ts::TimeSeries)

Plots all of the dimensions of a single TimeSeries, returning the Makie.Figure. Any figure_kwargs will be passed to the Makie.Figure. If there is no content, nothing is returned.

source
plot_ts(tss::Vector{<:Pair{String, <:TimeSeries}}; skip_units_check = false)

This combines multiple time series in a single plot. The input is a vector of string-time-series pairs, where the string becomes the legend label for the plot. This ignores plot groups; every dimension gets its own axis.

By default, this checks to make sure the units are consistent and errors if they are not. Set skip_units_check = true to skip the check.

If there is no content, nothing is returned.

Example:

plot_ts(
    [
        "truth" => truth_ts,
        "measured" => measured_ts,
    ]
)
source
plot_ts(tss::Vector, figure_kwargs = (;))

This combines multiple time series in a single plot, stacked vertically. Any figure_kwargs will be passed to the Makie.Figure. If there is no content, nothing is returned.

Example:

plot_ts([truth_ts, measured_ts])
source
plot_ts(tss::Matrix, figure_kwargs = (;))

This combines multiple time series in a single plot, arranged in a matrix. Any figure_kwargs will be passed to the Makie.Figure. If there is no content, nothing is returned.

Example:

plot_ts(
    [
        ts1  ts2;
        ts3  ts4;
    ]
)
source
SystemsOfSystems.TimeSeriesStuff.plot_ts!Function
plot_ts!(target, time_series; kwargs...)

Adds one or more time series to an existing Makie figure or layout target. A Makie backend such as GLMakie or CairoMakie must be loaded before calling this function.

source
plot_ts!(f, ts::TimeSeries)

Adds a TimeSeries to a given figure (or any "block" within a figure), f. All new axes are returned.

source
plot_ts!(f, tss::Vector{<:Pair{String, <:TimeSeries}}; skip_units_check = false)

This combines multiple time series in a single plot in the given figure (or any "block"), f. The tss input is a vector of string-time-series pairs, where the string becomes the legend label for the plot. This ignores plot groups; every dimension gets its own axis.

By default, this checks to make sure the units are consistent and errors if they are not. Set skip_units_check = true to skip the check.

All new axes are returned.

See plot_ts(tss::Vector{<:Pair{String, <:TimeSeries}}) for more.

source

Stop Reasons

The history.stop field retains the specific reason the simulation ended. Normal stop reasons subtype AbstractStopReason, while exceptions and numerical failures subtype AbstractFailureReason. Most code can use succeeded(history) and only inspect the concrete reason when reporting or recovering from a failure.

SystemsOfSystems.AbstractTerminationReasonType

The common supertype for every reason a simulation ceased running.

Normal stop requests and failures are deliberately separate categories. A model or hook request is part of the modeled lifecycle; a numerical or software failure means that lifecycle could not produce another valid sample.

source
SystemsOfSystems.Solvers.SolverStepSizeUnderflowType

The proposed floating-point step was too small to produce a later official rational time.

Reporting this explicitly is preferable to repeatedly accepting a zero-duration step, which would leave the simulation loop unable to make progress.

source
SystemsOfSystems.describeFunction
describe(reason::AbstractTerminationReason)

Returns a concise, human-readable description of why a simulation stopped.

source