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