Trait Simulation

Source
pub trait Simulation<M: Model>: Sized {
    type StepError: Error + Send + Sync + 'static + From<M::Error>;

    // Required methods
    fn model(&self) -> &M;
    fn advance_time(
        &mut self,
        state: &State<M>,
        dt: Duration,
    ) -> Result<M::Input, Self::StepError>;

    // Provided methods
    fn step(
        &mut self,
        input: M::Input,
        dt: Duration,
    ) -> Result<State<M>, Self::StepError>
       where M::Input: Clone { ... }
    fn step_from_state(
        &mut self,
        state: &State<M>,
        dt: Duration,
    ) -> Result<State<M>, Self::StepError>
       where M::Input: Clone { ... }
    fn step_many(
        &mut self,
        initial_input: M::Input,
        steps: usize,
        dt: Duration,
    ) -> Result<Vec<State<M>>, Self::StepError>
       where M::Input: Clone,
             M::Output: Clone { ... }
    fn into_step_iter(
        self,
        initial_input: M::Input,
        dt: Duration,
    ) -> impl Iterator<Item = Result<State<M>, Self::StepError>>
       where M::Input: Clone,
             M::Output: Clone { ... }
}
Expand description

Trait for defining a transient simulation in Twine.

A Simulation advances a Model forward in time by computing its next input with [advance_time] and then calling the model to produce a new State representing the system at the corresponding future moment.

§Stepping Methods

After implementing [advance_time], the following methods are available for advancing the simulation:

Required Associated Types§

Source

type StepError: Error + Send + Sync + 'static + From<M::Error>

The error type returned if a simulation step fails.

This type must implement From<M::Error> so errors produced by the model (via Model::call) can be automatically converted using the ? operator. This requirement allows simulations to propagate model errors cleanly when calling the model during a step or within [advance_time].

Implementations may:

  • Reuse the model’s error type directly (type StepError = M::Error).
  • Wrap it in a custom enum with additional error variants.
  • Use boxed dynamic errors for maximum flexibility.

Required Methods§

Source

fn model(&self) -> &M

Provides a reference to the model being simulated.

Source

fn advance_time( &mut self, state: &State<M>, dt: Duration, ) -> Result<M::Input, Self::StepError>

Computes the next input for the model, advancing the simulation in time.

Given the current State and a proposed time step dt, this method generates the next Model::Input to drive the simulation forward.

This method is the primary customization point for incrementing time, integrating state variables, enforcing constraints, applying control logic, or incorporating external events. It takes &mut self to support stateful integration algorithms such as adaptive time stepping, multistep methods, or PID controllers that need to record history.

Implementations may interpret or adapt the proposed time step dt as needed (e.g., for adaptive time stepping), and are free to update any fields of the input required to continue the simulation.

§Parameters
  • state: The current simulation state.
  • dt: The proposed time step.
§Returns

The next input, computed from the current State and proposed dt.

§Errors

Returns a [StepError] if computing the next input fails.

Provided Methods§

Source

fn step( &mut self, input: M::Input, dt: Duration, ) -> Result<State<M>, Self::StepError>
where M::Input: Clone,

Advances the simulation by one step, starting from an initial input.

This method first calls the model with the given input to compute the initial output, forming a complete State. It then delegates to [step_from_state] to compute the next state. As a result, the model is called twice: once to initialize the state, and once after advancing.

§Parameters
  • input: The model input at the start of the step.
  • dt: The proposed time step.
§Errors

Returns a [StepError] if computing the next input or calling the model fails.

Source

fn step_from_state( &mut self, state: &State<M>, dt: Duration, ) -> Result<State<M>, Self::StepError>
where M::Input: Clone,

Advances the simulation by one step from a known State.

This method computes the next input using [advance_time], then calls the model to produce the resulting State.

§Parameters
  • state: The current simulation state.
  • dt: The proposed time step.
§Errors

Returns a [StepError] if computing the next input or calling the model fails.

Source

fn step_many( &mut self, initial_input: M::Input, steps: usize, dt: Duration, ) -> Result<Vec<State<M>>, Self::StepError>
where M::Input: Clone, M::Output: Clone,

Runs the simulation for a fixed number of steps and collects the results.

Starting from the given input, this method advances the simulation by steps iterations using the proposed time step dt.

§Parameters
  • initial_input: The model input at the start of the simulation.
  • steps: The number of steps to run.
  • dt: The proposed time step for each iteration.
§Returns

A Vec of length steps + 1 containing each State computed during the run, including the initial one.

§Errors

Returns a [StepError] if any step fails. No further steps are taken after an error.

Source

fn into_step_iter( self, initial_input: M::Input, dt: Duration, ) -> impl Iterator<Item = Result<State<M>, Self::StepError>>
where M::Input: Clone, M::Output: Clone,

Consumes the simulation and creates an iterator that advances it repeatedly.

The iterator calls the simulation’s stepping logic with a constant dt, yielding each resulting State in sequence. If a step fails, the error is returned and iteration stops.

This method supports lazy or streaming evaluation and integrates cleanly with iterator adapters such as .take(n), .map(...), or .find(...). It is memory-efficient and performs no intermediate allocations.

§Parameters
  • initial_input: The model input at the start of the simulation.
  • dt: The proposed time step for each iteration.
§Returns

An iterator over Result<State<M>, StepError> steps.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§