1use fmi::{
2 EventFlags,
3 fmi2::{
4 Fmi2Error,
5 import::Fmi2Import,
6 instance::{CoSimulation, InstanceCS},
7 },
8 traits::FmiInstance,
9};
10
11use crate::{
12 Error,
13 sim::{
14 InputState, RecorderState, SimState, SimStateTrait, SimStats,
15 interpolation::Linear,
16 io::StartValues,
17 params::SimParams,
18 traits::{InstRecordValues, InstSetValues, SimApplyStartValues},
19 },
20};
21
22impl SimStateTrait<InstanceCS, Fmi2Import> for SimState<InstanceCS> {
23 fn new(
24 import: &Fmi2Import,
25 sim_params: SimParams,
26 input_state: InputState<InstanceCS>,
27 recorder_state: RecorderState<InstanceCS>,
28 ) -> Result<Self, Error> {
29 log::trace!("Instantiating CS Simulation: {sim_params:#?}");
30 let inst = import.instantiate_cs("inst1", true, true)?;
31 Ok(Self {
32 sim_params,
33 input_state,
34 recorder_state,
35 inst,
36 event_flags: EventFlags::default(),
37 })
38 }
39}
40
41impl SimApplyStartValues<InstanceCS> for SimState<InstanceCS> {
42 fn apply_start_values(
43 &mut self,
44 start_values: &StartValues<<InstanceCS as FmiInstance>::ValueRef>,
45 ) -> Result<(), Error> {
46 start_values.variables.iter().for_each(|(vr, ary)| {
47 self.inst.set_array(&[*vr], ary);
48 });
49 Ok(())
50 }
51}
52
53impl SimState<InstanceCS> {
54 pub fn main_loop(&mut self) -> Result<SimStats, Fmi2Error> {
56 let mut stats = SimStats::default();
57
58 loop {
59 let time = self.sim_params.start_time
60 + stats.num_steps as f64 * self.sim_params.output_interval;
61
62 self.inst
63 .record_outputs(time, &mut self.recorder_state)
64 .expect("Failed to record outputs");
65
66 self.input_state
67 .apply_input::<Linear>(time, &mut self.inst, true, true, false)
68 .expect("Failed to apply inputs");
69
70 if time >= self.sim_params.stop_time {
71 stats.end_time = time;
72 break;
73 }
74
75 match self
76 .inst
77 .do_step(time, self.sim_params.output_interval, true)
78 {
79 Err(Fmi2Error::Discard) => {
80 if self.inst.terminated()? {
81 let time = self.inst.last_successful_time()?;
82
83 self.inst
84 .record_outputs(time, &mut self.recorder_state)
85 .unwrap();
86
87 stats.end_time = time;
88 break;
89 }
90 }
91 Err(e) => return Err(e),
92 _ => {}
93 }
94
95 stats.num_steps += 1;
96 }
97
98 self.inst.terminate()?;
101
102 Ok(stats)
103 }
104}