1use anyhow::Context;
2use fmi::{
3 fmi3::{CoSimulation, Fmi3Model, import::Fmi3Import, instance::InstanceCS},
4 traits::FmiInstance,
5};
6
7use crate::{
8 Error,
9 sim::{
10 InputState, RecorderState, SimState, SimStateTrait, SimStats,
11 interpolation::Linear,
12 params::SimParams,
13 traits::{InstRecordValues, SimHandleEvents},
14 },
15};
16
17impl<'a> SimStateTrait<'a, InstanceCS<'a>, Fmi3Import> for SimState<InstanceCS<'a>> {
18 fn new(
19 import: &'a Fmi3Import,
20 sim_params: SimParams,
21 input_state: InputState<InstanceCS<'a>>,
22 output_state: RecorderState<InstanceCS<'a>>,
23 ) -> Result<Self, Error> {
24 let inst = import.instantiate_cs(
25 "inst1",
26 true,
27 true,
28 sim_params.event_mode_used,
29 sim_params.early_return_allowed,
30 &[],
31 )?;
32 Ok(Self {
33 sim_params,
34 input_state,
35 recorder_state: output_state,
36 inst,
37 next_event_time: None,
38 })
39 }
40}
41
42impl<'a> SimState<InstanceCS<'a>> {
43 pub fn main_loop(&mut self) -> Result<SimStats, Error> {
45 let mut stats = SimStats::default();
46
47 if self.sim_params.event_mode_used {
48 self.inst.enter_step_mode().map_err(fmi::Error::from)?;
49 }
50
51 let mut time = self.sim_params.start_time;
52
53 loop {
54 self.inst.record_outputs(time, &mut self.recorder_state)?;
55
56 if time >= self.sim_params.stop_time {
57 break;
58 }
59
60 let next_regular_point = self.sim_params.start_time
62 + (stats.num_steps + 1) as f64 * self.sim_params.output_interval;
63 let next_input_event_time = self.input_state.next_input_event(time);
64 let next_communication_point = next_input_event_time.min(next_regular_point);
66 let input_event = next_regular_point > next_input_event_time;
67
68 let step_size = next_communication_point - time;
69
70 let mut event_encountered = false;
71 let mut terminate_simulation = false;
72 let mut early_return = false;
73 let mut last_successful_time = 0.0;
74
75 if self.sim_params.event_mode_used {
76 self.input_state
77 .apply_input::<Linear>(time, &mut self.inst, false, true, false)?;
78 } else {
79 self.input_state
80 .apply_input::<Linear>(time, &mut self.inst, true, true, true)?;
81 }
82
83 self.inst
84 .do_step(
85 time,
86 step_size,
87 true,
88 &mut event_encountered,
89 &mut terminate_simulation,
90 &mut early_return,
91 &mut last_successful_time,
92 )
93 .ok()
94 .context("do_step")?;
95
96 if early_return && !self.sim_params.early_return_allowed {
97 panic!("Early return is not allowed.");
98 }
99
100 if terminate_simulation {
101 break;
102 }
103
104 if early_return && last_successful_time < next_communication_point {
105 time = last_successful_time;
106 } else {
107 time = next_communication_point;
108 }
109
110 if time == next_regular_point {
111 stats.num_steps += 1;
112 }
113
114 if self.sim_params.event_mode_used && (input_event || event_encountered) {
115 log::trace!("Event encountered at t = {time}");
116 self.handle_events(time, input_event, &mut terminate_simulation)?;
117
118 self.inst
119 .enter_step_mode()
120 .ok()
121 .context("enter_step_mode")?;
122 }
123 }
124
125 self.inst.terminate().ok().context("terminate")?;
126
127 stats.end_time = time;
128 Ok(stats)
129 }
130}