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}