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 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::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 mut sim_state =
84 SimState::<InstanceME>::new(self, sim_params, input_state, recorder_state)?;
85 sim_state.initialize(start_values, options.common.initial_fmu_state_file.as_ref())?;
86 let stats = sim_state.main_loop::<solver::Euler>(())?;
87
88 Ok((sim_state.recorder_state.finish(), stats))
89 }
90
91 #[cfg(feature = "cs")]
92 fn simulate_cs(
93 &self,
94 options: &CoSimulationOptions,
95 input_data: Option<RecordBatch>,
96 ) -> Result<(RecordBatch, SimStats), Error> {
97 use fmi::fmi3::instance::InstanceCS;
98
99 let sim_params = SimParams::new_from_options(
100 &options.common,
101 self.model_description(),
102 options.event_mode_used,
103 options.early_return_allowed,
104 );
105
106 let start_values = self.parse_start_values(&options.common.initial_values)?;
107 let input_state = InputState::new(self, input_data)?;
108 let output_state = RecorderState::new(self, &sim_params);
109
110 let mut sim_state =
111 SimState::<InstanceCS>::new(self, sim_params, input_state, output_state)?;
112 sim_state.initialize(start_values, options.common.initial_fmu_state_file.as_ref())?;
113 let stats = sim_state.main_loop()?;
114
115 Ok((sim_state.recorder_state.finish(), stats))
116 }
117}