1use fmi::traits::{FmiEventHandler, FmiInstance, FmiModelExchange};
4
5use crate::Error;
6
7use super::{
8 SimState, SimStats,
9 interpolation::Linear,
10 solver::Solver,
11 traits::{InstRecordValues, InstSetValues, SimHandleEvents, SimMe},
12};
13
14impl<Inst> SimMe<Inst> for SimState<Inst>
15where
16 Inst: FmiInstance + FmiModelExchange + InstSetValues + InstRecordValues + FmiEventHandler,
17{
18 fn main_loop<S>(&mut self, solver_params: S::Params) -> Result<SimStats, Error>
19 where
20 S: Solver<Inst>,
21 {
22 let mut stats = SimStats::default();
23 self.inst.enter_continuous_time_mode().map_err(Into::into)?;
24
25 let nx = self.inst.get_number_of_continuous_state_values();
26 let nz = self.inst.get_number_of_event_indicator_values();
27
28 let mut solver = <S as Solver<Inst>>::new(
29 self.sim_params.start_time,
30 self.sim_params.tolerance.unwrap_or_default(),
31 nx,
32 nz,
33 solver_params,
34 );
35
36 let mut time = self.sim_params.start_time;
37
38 loop {
39 self.inst.record_outputs(time, &mut self.recorder_state)?;
40
41 if time >= self.sim_params.stop_time {
42 break;
43 }
44
45 let next_regular_point = self.sim_params.start_time
47 + (stats.num_steps + 1) as f64 * self.sim_params.output_interval;
48 let next_input_event_time = self.input_state.next_input_event(time);
49
50 let input_event = next_regular_point >= next_input_event_time;
51 let time_event = next_regular_point >= self.next_event_time.unwrap_or(f64::INFINITY);
52
53 let next_communication_point = if input_event || time_event {
55 next_input_event_time.min(self.next_event_time.unwrap_or(f64::INFINITY))
56 } else {
57 next_regular_point
58 };
59
60 let (time_reached, state_event) =
61 solver.step(&mut self.inst, next_communication_point)?;
62 time = time_reached;
63
64 self.inst.set_time(time).map_err(Into::into)?;
65
66 self.input_state
67 .apply_input::<Linear>(time, &mut self.inst, false, true, false)?;
68
69 if time == next_regular_point {
70 stats.num_steps += 1;
71 }
72
73 let mut step_event = false;
74 let mut terminate = false;
75
76 self.inst
77 .completed_integrator_step(true, &mut step_event, &mut terminate)
78 .map_err(Into::into)?;
79
80 if terminate {
81 log::info!("Termination requested by FMU");
82 break;
83 }
84
85 if input_event || time_event || state_event || step_event {
86 log::trace!(
87 "Event encountered at t = {time}. [INPUT/TIME/STATE/STEP] = [{input_event}/{time_event}/{state_event}/{step_event}]"
88 );
89 stats.num_events += 1;
90 let mut terminate = false;
91 let reset_solver = self.handle_events(time, input_event, &mut terminate)?;
92
93 if terminate {
94 break;
95 }
96
97 self.inst.enter_continuous_time_mode().map_err(Into::into)?;
98
99 if reset_solver {
100 solver.reset(&mut self.inst, time)?;
101 }
102 }
103 }
104
105 self.inst.terminate().map_err(Into::into)?;
106
107 Ok(stats)
108 }
109}