Skip to main content

fmi_sim/sim/fmi2/
cs.rs

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    /// Main loop of the co-simulation
55    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        //TODO save final FMU state
99
100        self.inst.terminate()?;
101
102        Ok(stats)
103    }
104}