xdevs/
simulator.rs

1use crate::traits::{AbstractSimulator, Bag};
2
3#[cfg(feature = "std")]
4pub mod std;
5
6/// A DEVS simulator that uses a virtual clock (i.e., no real time is used).
7pub struct Simulator<M: AbstractSimulator> {
8    model: M,
9}
10
11impl<M: AbstractSimulator> Simulator<M> {
12    #[inline]
13    pub const fn new(model: M) -> Self {
14        Self { model }
15    }
16
17    /// It executes the simulation of the inner DEVS model from `t_start` to `t_stop`.
18    /// It provides support for real time execution via the following arguments:
19    ///
20    /// - `wait_until`: a closure that is called between state transitions.
21    ///   It receives the time of the next state transition and a mutable reference to the input ports.
22    ///   It returns the actual time "waited".
23    ///   If the returned time is equal to the input time, an internal/confluent state transition is performed.
24    ///   Otherwise, it assumes that an external event happened and executes the external transition function.
25    /// - `propagate_output`: a closure that is called after output functions.
26    ///   It receives a mutable reference to the output ports so the closure can access to output events.
27    ///   Feel free to ignore this argument if you do not need to propagate output messages.
28    #[inline]
29    pub fn simulate_rt(
30        &mut self,
31        t_start: f64,
32        t_stop: f64,
33        mut wait_until: impl FnMut(f64, &mut M::Input) -> f64,
34        mut propagate_output: impl FnMut(&M::Output),
35    ) {
36        let mut t = t_start;
37        let mut t_next_internal = self.model.start(t);
38        while t < t_stop {
39            let t_until = f64::min(t_next_internal, t_stop);
40            t = wait_until(t_until, self.model.get_input_mut());
41            if t >= t_next_internal {
42                self.model.lambda(t);
43                propagate_output(self.model.get_output());
44            } else if self.model.get_input().is_empty() {
45                continue; // avoid spurious external transitions
46            }
47            t_next_internal = self.model.delta(t);
48        }
49        self.model.stop(t_stop);
50    }
51
52    /// It executes the simulation of the inner DEVS model from `t_start` to `t_stop`.
53    /// It uses a virtual clock (i.e., no real time is used).
54    #[inline]
55    pub fn simulate_vt(&mut self, t_start: f64, t_stop: f64) {
56        self.simulate_rt(t_start, t_stop, |t, _| t, |_| {});
57    }
58}