Skip to main content

fmi_sim/sim/fmi3/
mod.rs

1use arrow::array::RecordBatch;
2
3use fmi::{
4    fmi3::{Common, import::Fmi3Import},
5    traits::{FmiImport, FmiInstance},
6};
7
8use crate::{
9    Error,
10    options::{CoSimulationOptions, ModelExchangeOptions},
11    sim::{
12        InputState, RecorderState, SimState, SimStateTrait,
13        params::SimParams,
14        traits::{ImportSchemaBuilder, SimInitialize},
15    },
16};
17
18use super::{
19    SimStats,
20    io::StartValues,
21    traits::{FmiSim, InstSetValues},
22};
23
24#[cfg(feature = "cs")]
25mod cs;
26mod io;
27#[cfg(feature = "me")]
28mod me;
29mod schema;
30
31macro_rules! impl_sim_apply_start_values {
32    ($inst:ty) => {
33        impl super::traits::SimApplyStartValues<$inst> for super::SimState<$inst> {
34            fn apply_start_values(
35                &mut self,
36                start_values: &StartValues<<$inst as FmiInstance>::ValueRef>,
37            ) -> Result<(), Error> {
38                if !start_values.structural_parameters.is_empty() {
39                    self.inst
40                        .enter_configuration_mode()
41                        .map_err(fmi::Error::from)?;
42                    for (vr, ary) in &start_values.structural_parameters {
43                        //log::trace!("Setting structural parameter `{}`", (*vr).into());
44                        self.inst.set_array(&[(*vr)], ary);
45                    }
46                    self.inst
47                        .exit_configuration_mode()
48                        .map_err(fmi::Error::from)?;
49                }
50
51                start_values.variables.iter().for_each(|(vr, ary)| {
52                    self.inst.set_array(&[*vr], ary);
53                });
54
55                Ok(())
56            }
57        }
58    };
59}
60
61#[cfg(feature = "me")]
62impl_sim_apply_start_values!(fmi::fmi3::instance::InstanceME);
63#[cfg(feature = "cs")]
64impl_sim_apply_start_values!(fmi::fmi3::instance::InstanceCS);
65
66impl FmiSim for Fmi3Import {
67    #[cfg(feature = "me")]
68    fn simulate_me(
69        &self,
70        options: &ModelExchangeOptions,
71        input_data: Option<RecordBatch>,
72    ) -> Result<(RecordBatch, SimStats), Error> {
73        use crate::sim::{solver, traits::SimMe};
74        use fmi::fmi3::{ModelExchange, instance::InstanceME};
75
76        let sim_params =
77            SimParams::new_from_options(&options.common, self.model_description(), true, false);
78
79        let start_values = self.parse_start_values(&options.common.initial_values)?;
80        let input_state = InputState::new(self, input_data)?;
81        let recorder_state = RecorderState::new(self, &sim_params);
82
83        let start_time = sim_params.start_time;
84        let tol = sim_params.tolerance.unwrap_or_default();
85
86        let mut sim_state =
87            SimState::<InstanceME>::new(self, sim_params, input_state, recorder_state)?;
88
89        let nx = sim_state
90            .inst
91            .get_number_of_continuous_states()
92            .map_err(|e| Error::from(fmi::Error::from(e)))?;
93        let nz = sim_state
94            .inst
95            .get_number_of_event_indicators()
96            .map_err(|e| Error::from(fmi::Error::from(e)))?;
97
98        let solver: solver::Euler = solver::Solver::<InstanceME>::new(start_time, tol, nx, nz, ());
99
100        sim_state.initialize(start_values, options.common.initial_fmu_state_file.as_ref())?;
101        let stats = sim_state.main_loop(solver)?;
102
103        Ok((sim_state.recorder_state.finish(), stats))
104    }
105
106    #[cfg(feature = "cs")]
107    fn simulate_cs(
108        &self,
109        options: &CoSimulationOptions,
110        input_data: Option<RecordBatch>,
111    ) -> Result<(RecordBatch, SimStats), Error> {
112        use fmi::fmi3::instance::InstanceCS;
113
114        let sim_params = SimParams::new_from_options(
115            &options.common,
116            self.model_description(),
117            options.event_mode_used,
118            options.early_return_allowed,
119        );
120
121        let start_values = self.parse_start_values(&options.common.initial_values)?;
122        let input_state = InputState::new(self, input_data)?;
123        let output_state = RecorderState::new(self, &sim_params);
124
125        let mut sim_state =
126            SimState::<InstanceCS>::new(self, sim_params, input_state, output_state)?;
127        sim_state.initialize(start_values, options.common.initial_fmu_state_file.as_ref())?;
128        let stats = sim_state.main_loop()?;
129
130        Ok((sim_state.recorder_state.finish(), stats))
131    }
132}