fmi_sim/sim/fmi2/
cs.rs

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    /// Main loop of the co-simulation
54    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        //TODO save final FMU state
97
98        self.inst.terminate().map_err(Into::into)?;
99
100        Ok(stats)
101    }
102}