Skip to main content

fmi_schema/fmi3/
interface_type.rs

1use crate::traits::FmiInterfaceType;
2
3use super::Annotations;
4
5#[derive(Default, PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
6#[xml(tag = "ModelExchange", strict(unknown_attribute, unknown_element))]
7pub struct Fmi3ModelExchange {
8    #[xml(child = "Annotations")]
9    pub annotations: Option<Annotations>,
10    /// Short class name according to C syntax, for example, A_B_C.
11    #[xml(attr = "modelIdentifier")]
12    pub model_identifier: String,
13    /// If true, a tool is needed to execute the FMU. The FMU implements the communication to this tool.
14    #[xml(attr = "needsExecutionTool")]
15    pub needs_execution_tool: Option<bool>,
16    /// If true, the FMU must be instantiated only once per process.
17    #[xml(attr = "canBeInstantiatedOnlyOncePerProcess")]
18    pub can_be_instantiated_only_once_per_process: Option<bool>,
19    /// If true, the environment may inquire the internal FMU state and may restore it.
20    #[xml(attr = "canGetAndSetFMUState")]
21    pub can_get_and_set_fmu_state: Option<bool>,
22    /// If true, the environment may serialize the internal FMU state.
23    #[xml(attr = "canSerializeFMUState")]
24    pub can_serialize_fmu_state: Option<bool>,
25    /// If true, the directional derivative of the equations may be retrieved using fmi3GetDirectionalDerivative.
26    #[xml(attr = "providesDirectionalDerivatives")]
27    pub provides_directional_derivatives: Option<bool>,
28    /// If true, the adjoint derivatives of the equations may be retrieved using fmi3GetAdjointDerivative
29    #[xml(attr = "providesAdjointDerivatives")]
30    pub provides_adjoint_derivatives: Option<bool>,
31    #[xml(attr = "providesPerElementDependencies")]
32    pub provides_per_element_dependencies: Option<bool>,
33    #[xml(attr = "needsCompletedIntegratorStep")]
34    pub needs_completed_integrator_step: Option<bool>,
35    #[xml(attr = "providesEvaluateDiscreteStates")]
36    pub provides_evaluate_discrete_states: Option<bool>,
37}
38
39#[derive(Default, PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
40#[xml(tag = "CoSimulation", strict(unknown_attribute, unknown_element))]
41pub struct Fmi3CoSimulation {
42    #[xml(child = "Annotations")]
43    pub annotations: Option<Annotations>,
44    /// Short class name according to C syntax, for example, A_B_C.
45    #[xml(attr = "modelIdentifier")]
46    pub model_identifier: String,
47    /// If true, a tool is needed to execute the FMU. The FMU implements the communication to this tool.
48    #[xml(attr = "needsExecutionTool")]
49    pub needs_execution_tool: Option<bool>,
50    /// If true, the FMU must be instantiated only once per process.
51    #[xml(attr = "canBeInstantiatedOnlyOncePerProcess")]
52    pub can_be_instantiated_only_once_per_process: Option<bool>,
53    /// If true, the environment may inquire the internal FMU state and may restore it.
54    #[xml(attr = "canGetAndSetFMUState")]
55    pub can_get_and_set_fmu_state: Option<bool>,
56    /// If true, the environment may serialize the internal FMU state.
57    #[xml(attr = "canSerializeFMUState")]
58    pub can_serialize_fmu_state: Option<bool>,
59    /// If true, the directional derivative of the equations may be retrieved using fmi3GetDirectionalDerivative.
60    #[xml(attr = "providesDirectionalDerivatives")]
61    pub provides_directional_derivatives: Option<bool>,
62    /// If true, the adjoint derivatives of the equations may be retrieved using fmi3GetAdjointDerivative
63    #[xml(attr = "providesAdjointDerivatives")]
64    pub provides_adjoint_derivatives: Option<bool>,
65    #[xml(attr = "providesPerElementDependencies")]
66    pub provides_per_element_dependencies: Option<bool>,
67    #[xml(attr = "canHandleVariableCommunicationStepSize")]
68    pub can_handle_variable_communication_step_size: Option<bool>,
69    #[xml(attr = "fixedInternalStepSize")]
70    pub fixed_internal_step_size: Option<f64>,
71    #[xml(attr = "maxOutputDerivativeOrder")]
72    pub max_output_derivative_order: Option<u32>,
73    #[xml(attr = "recommendedIntermediateInputSmoothness")]
74    pub recommended_intermediate_input_smoothness: Option<i32>,
75    #[xml(attr = "providesIntermediateUpdate")]
76    pub provides_intermediate_update: Option<bool>,
77    #[xml(attr = "mightReturnEarlyFromDoStep")]
78    pub might_return_early_from_do_step: Option<bool>,
79    #[xml(attr = "canReturnEarlyAfterIntermediateUpdate")]
80    pub can_return_early_after_intermediate_update: Option<bool>,
81    #[xml(attr = "hasEventMode")]
82    pub has_event_mode: Option<bool>,
83    #[xml(attr = "providesEvaluateDiscreteStates")]
84    pub provides_evaluate_discrete_states: Option<bool>,
85}
86
87#[derive(Default, PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
88#[xml(tag = "ScheduledExecution", strict(unknown_attribute, unknown_element))]
89pub struct Fmi3ScheduledExecution {
90    #[xml(child = "Annotations")]
91    pub annotations: Option<Annotations>,
92    /// Short class name according to C syntax, for example, A_B_C.
93    #[xml(attr = "modelIdentifier")]
94    pub model_identifier: String,
95    /// If true, a tool is needed to execute the FMU. The FMU implements the communication to this tool.
96    #[xml(attr = "needsExecutionTool")]
97    pub needs_execution_tool: Option<bool>,
98    /// If true, the FMU must be instantiated only once per process.
99    #[xml(attr = "canBeInstantiatedOnlyOncePerProcess")]
100    pub can_be_instantiated_only_once_per_process: Option<bool>,
101    /// If true, the environment may inquire the internal FMU state and may restore it.
102    #[xml(attr = "canGetAndSetFMUState")]
103    pub can_get_and_set_fmu_state: Option<bool>,
104    /// If true, the environment may serialize the internal FMU state.
105    #[xml(attr = "canSerializeFMUState")]
106    pub can_serialize_fmu_state: Option<bool>,
107    /// If true, the directional derivative of the equations may be retrieved using fmi3GetDirectionalDerivative.
108    #[xml(attr = "providesDirectionalDerivatives")]
109    pub provides_directional_derivatives: Option<bool>,
110    /// If true, the adjoint derivatives of the equations may be retrieved using fmi3GetAdjointDerivative
111    #[xml(attr = "providesAdjointDerivatives")]
112    pub provides_adjoint_derivatives: Option<bool>,
113    #[xml(attr = "providesPerElementDependencies")]
114    pub provides_per_element_dependencies: Option<bool>,
115}
116
117/// Macro to generate FMI3 interface type structs with common fields from fmi3InterfaceType
118macro_rules! impl_fmi_interface_type {
119    ($name:ident) => {
120        impl FmiInterfaceType for $name {
121            fn model_identifier(&self) -> &str {
122                &self.model_identifier
123            }
124
125            fn needs_execution_tool(&self) -> Option<bool> {
126                self.needs_execution_tool
127            }
128
129            fn can_be_instantiated_only_once_per_process(&self) -> Option<bool> {
130                self.can_be_instantiated_only_once_per_process
131            }
132
133            fn can_get_and_set_fmu_state(&self) -> Option<bool> {
134                self.can_get_and_set_fmu_state
135            }
136
137            fn can_serialize_fmu_state(&self) -> Option<bool> {
138                self.can_serialize_fmu_state
139            }
140
141            fn provides_directional_derivatives(&self) -> Option<bool> {
142                self.provides_directional_derivatives
143            }
144
145            fn provides_adjoint_derivatives(&self) -> Option<bool> {
146                self.provides_adjoint_derivatives
147            }
148
149            fn provides_per_element_dependencies(&self) -> Option<bool> {
150                self.provides_per_element_dependencies
151            }
152        }
153    };
154}
155
156impl_fmi_interface_type!(Fmi3ModelExchange);
157impl_fmi_interface_type!(Fmi3CoSimulation);
158impl_fmi_interface_type!(Fmi3ScheduledExecution);
159
160#[cfg(test)]
161mod tests {
162    use super::*;
163    use hard_xml::{XmlRead, XmlWrite};
164
165    #[test]
166    fn test_model_exchange_roundtrip() {
167        let xml = r#"<ModelExchange modelIdentifier="test" needsCompletedIntegratorStep="true" providesEvaluateDiscreteStates="false"/>"#;
168
169        let me = Fmi3ModelExchange::from_str(xml).unwrap();
170        assert_eq!(me.model_identifier, "test");
171        assert_eq!(me.needs_completed_integrator_step, Some(true));
172        assert_eq!(me.provides_evaluate_discrete_states, Some(false));
173
174        let xml_out = me.to_string().unwrap();
175        let me2 = Fmi3ModelExchange::from_str(&xml_out).unwrap();
176        assert_eq!(me, me2);
177    }
178
179    #[test]
180    fn test_co_simulation_attributes() {
181        let xml = r#"<CoSimulation modelIdentifier="test" canHandleVariableCommunicationStepSize="true" hasEventMode="false"/>"#;
182
183        let cs = Fmi3CoSimulation::from_str(xml).unwrap();
184        assert_eq!(cs.model_identifier, "test");
185        assert_eq!(cs.can_handle_variable_communication_step_size, Some(true));
186        assert_eq!(cs.has_event_mode, Some(false));
187    }
188
189    #[test]
190    fn test_scheduled_execution_basic() {
191        let xml = r#"<ScheduledExecution modelIdentifier="test"/>"#;
192
193        let se = Fmi3ScheduledExecution::from_str(xml).unwrap();
194        assert_eq!(se.model_identifier, "test");
195    }
196
197    #[test]
198    fn test_fmi_interface_type_trait() {
199        let me = Fmi3ModelExchange {
200            model_identifier: "test".to_string(),
201            needs_execution_tool: Some(true),
202            can_get_and_set_fmu_state: Some(false),
203            ..Default::default()
204        };
205
206        assert_eq!(me.model_identifier(), "test");
207        assert_eq!(me.needs_execution_tool(), Some(true));
208        assert_eq!(me.can_get_and_set_fmu_state(), Some(false));
209    }
210}