Skip to main content

fmi_export/fmi3/instance/
impl_cs.rs

1use crate::fmi3::{
2    Model, ModelGetSetStates, ModelState, UserModel,
3    traits::{Context, ModelGetSet, ModelLoggingCategory},
4};
5use fmi::fmi3::{CoSimulation, Fmi3Error, Fmi3Res};
6
7use super::ModelInstance;
8
9impl<M, C> CoSimulation for ModelInstance<M, C>
10where
11    M: Model + UserModel + ModelGetSet<M> + ModelGetSetStates,
12    C: Context<M>,
13{
14    fn enter_step_mode(&mut self) -> Result<Fmi3Res, Fmi3Error> {
15        self.context.log(
16            Fmi3Res::OK.into(),
17            M::LoggingCategory::trace_category(),
18            format_args!("enter_step_mode()"),
19        );
20        self.assert_instance_type(fmi::InterfaceType::CoSimulation)?;
21
22        match self.state {
23            ModelState::EventMode => {
24                self.state = ModelState::StepMode;
25                Ok(Fmi3Res::OK)
26            }
27            ModelState::StepMode => Ok(Fmi3Res::OK),
28            _ => {
29                self.context.log(
30                    Fmi3Error::Error.into(),
31                    M::LoggingCategory::default(),
32                    format_args!("enter_step_mode() called in invalid state {:?}", self.state),
33                );
34                Err(Fmi3Error::Error)
35            }
36        }
37    }
38
39    fn get_output_derivatives(
40        &mut self,
41        vrs: &[fmi::fmi3::binding::fmi3ValueReference],
42        orders: &[i32],
43        _values: &mut [f64],
44    ) -> Result<Fmi3Res, Fmi3Error> {
45        self.context.log(
46            Fmi3Error::Error.into(),
47            M::LoggingCategory::default(),
48            format_args!(
49                "get_output_derivatives(vrs: {:?}, orders: {:?}) not implemented",
50                vrs, orders
51            ),
52        );
53        Err(Fmi3Error::Error)
54    }
55
56    #[allow(clippy::too_many_arguments)]
57    fn do_step(
58        &mut self,
59        current_communication_point: f64,
60        communication_step_size: f64,
61        no_set_fmu_state_prior_to_current_point: bool,
62        event_handling_needed: &mut bool,
63        terminate_simulation: &mut bool,
64        early_return: &mut bool,
65        last_successful_time: &mut f64,
66    ) -> Result<Fmi3Res, Fmi3Error> {
67        self.context.log(
68            Fmi3Res::OK.into(),
69            M::LoggingCategory::trace_category(),
70            format_args!(
71                "do_step(t: {}, h: {}, no_set_state_prior: {})",
72                current_communication_point,
73                communication_step_size,
74                no_set_fmu_state_prior_to_current_point
75            ),
76        );
77        self.assert_instance_type(fmi::InterfaceType::CoSimulation)?;
78
79        match self.state {
80            ModelState::StepMode => {}
81            _ => {
82                self.context.log(
83                    Fmi3Error::Error.into(),
84                    M::LoggingCategory::default(),
85                    format_args!("do_step() called in invalid state {:?}", self.state),
86                );
87                return Err(Fmi3Error::Error);
88            }
89        }
90
91        let result = self.model.do_step(
92            &mut self.context,
93            current_communication_point,
94            communication_step_size,
95            no_set_fmu_state_prior_to_current_point,
96        )?;
97
98        *event_handling_needed = result.event_handling_needed;
99        *terminate_simulation = result.terminate_simulation;
100        *early_return = self.context.early_return_allowed() && result.early_return;
101        *last_successful_time = result.last_successful_time;
102
103        // Mark values dirty so subsequent getters recompute at the new time
104        self.is_dirty_values = true;
105
106        // Remain in StepMode after a successful step
107        Ok(Fmi3Res::OK)
108    }
109}