Skip to main content

fmi_schema/fmi2/
mod.rs

1//! FMI2.0 schema definitions
2//!
3//! This module contains the definitions of the FMI2.0 XML schema.
4
5mod attribute_groups;
6mod interface_type;
7mod model_description;
8mod scalar_variable;
9mod r#type;
10mod unit;
11mod variable_dependency;
12
13use std::str::FromStr;
14
15pub use attribute_groups::*;
16pub use interface_type::*;
17pub use model_description::*;
18pub use scalar_variable::*;
19pub use r#type::*;
20pub use unit::*;
21pub use variable_dependency::*;
22
23use crate::{
24    Error,
25    variable_counts::{Counts, VariableCounts},
26};
27
28pub type ScalarVariableMap<'a> = std::collections::HashMap<String, &'a ScalarVariable>;
29pub type UnknownsTuple<'a> = (&'a ScalarVariable, Vec<&'a ScalarVariable>);
30
31impl FromStr for Fmi2ModelDescription {
32    type Err = Error;
33
34    fn from_str(s: &str) -> Result<Self, Self::Err> {
35        hard_xml::XmlRead::from_str(s).map_err(Error::XmlParse)
36    }
37}
38
39impl crate::traits::DefaultExperiment for Fmi2ModelDescription {
40    fn start_time(&self) -> Option<f64> {
41        self.default_experiment
42            .as_ref()
43            .and_then(|de| de.start_time)
44    }
45
46    fn stop_time(&self) -> Option<f64> {
47        self.default_experiment.as_ref().and_then(|de| de.stop_time)
48    }
49
50    fn tolerance(&self) -> Option<f64> {
51        self.default_experiment.as_ref().and_then(|de| de.tolerance)
52    }
53
54    fn step_size(&self) -> Option<f64> {
55        self.default_experiment.as_ref().and_then(|de| de.step_size)
56    }
57}
58
59impl VariableCounts for ModelVariables {
60    fn model_counts(&self) -> Counts {
61        self.variables
62            .iter()
63            .fold(Counts::default(), |mut cts, sv| {
64                match sv.variability.unwrap_or_default() {
65                    Variability::Constant => {
66                        cts.num_constants += 1;
67                    }
68                    Variability::Continuous => {
69                        cts.num_continuous += 1;
70                    }
71                    Variability::Discrete => {
72                        cts.num_discrete += 1;
73                    }
74                    _ => {}
75                }
76                match sv.causality {
77                    Causality::CalculatedParameter => {
78                        cts.num_calculated_parameters += 1;
79                    }
80                    Causality::Parameter => {
81                        cts.num_parameters += 1;
82                    }
83                    Causality::Input => {
84                        cts.num_inputs += 1;
85                    }
86                    Causality::Output => {
87                        cts.num_outputs += 1;
88                    }
89                    Causality::Local => {
90                        cts.num_local += 1;
91                    }
92                    Causality::Independent => {
93                        cts.num_independent += 1;
94                    }
95                }
96                match sv.elem {
97                    ScalarVariableElement::Real { .. } => {
98                        cts.num_real_vars += 1;
99                    }
100                    ScalarVariableElement::Integer { .. } => {
101                        cts.num_integer_vars += 1;
102                    }
103                    ScalarVariableElement::Enumeration => {
104                        cts.num_enum_vars += 1;
105                    }
106                    ScalarVariableElement::Boolean { .. } => {
107                        cts.num_bool_vars += 1;
108                    }
109                    ScalarVariableElement::String => {
110                        cts.num_string_vars += 1;
111                    }
112                }
113                cts
114            })
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use hard_xml::XmlRead;
121
122    use super::*;
123
124    #[test]
125    fn test_default_experiment() {
126        let s = r##"<DefaultExperiment stopTime="3.0" tolerance="0.0001"/>"##;
127        let x = DefaultExperiment::from_str(s).unwrap();
128        assert_eq!(x.start_time, None);
129        assert_eq!(x.stop_time, Some(3.0));
130        assert_eq!(x.tolerance, Some(0.0001));
131
132        let s = r#"<DefaultExperiment startTime="0.20000000000000000e+00" stopTime="1.50000000000000000e+00" tolerance="0.0001"/>"#;
133        let x = DefaultExperiment::from_str(s).unwrap();
134        assert_eq!(x.start_time, Some(0.2));
135        assert_eq!(x.stop_time, Some(1.5));
136        assert_eq!(x.tolerance, Some(0.0001));
137    }
138
139    #[test]
140    fn test_model_variables() {
141        let s = r##"
142            <ModelVariables>
143                <ScalarVariable name="x[1]" valueReference="0" initial="exact"> <Real/> </ScalarVariable> <!-- idex="5" -->
144                <ScalarVariable name="x[2]" valueReference="1" initial="exact"> <Real/> </ScalarVariable> <!-- index="6" -->
145                <ScalarVariable name="der(x[1])" valueReference="2"> <Real derivative="5"/> </ScalarVariable> <!-- index="7" -->
146                <ScalarVariable name="der(x[2])" valueReference="3"> <Real derivative="6"/> </ScalarVariable> <!-- index="8" -->
147            </ModelVariables>
148        "##;
149        let x = ModelVariables::from_str(s).unwrap();
150        assert_eq!(x.variables.len(), 4);
151        assert!(
152            x.variables
153                .iter()
154                .map(|v| &v.name)
155                .zip(["x[1]", "x[2]", "der(x[1])", "der(x[2])"].iter())
156                .all(|(a, b)| a == b)
157        );
158    }
159
160    #[test]
161    fn test_model_structure() {
162        let s = r##"
163            <ModelStructure>
164                <Outputs>
165                    <Unknown index="3" />
166                    <Unknown index="4" />
167                </Outputs>
168                <Derivatives>
169                    <Unknown index="7" />
170                    <Unknown index="8" />
171                </Derivatives>
172                <InitialUnknowns>
173                    <Unknown index="3" />
174                    <Unknown index="4" />
175                    <Unknown index="7" dependencies="5 2" />
176                    <Unknown index="8" dependencies="5 6" />
177                </InitialUnknowns>
178            </ModelStructure>
179        "##;
180        let ms = ModelStructure::from_str(s).unwrap();
181        assert_eq!(ms.outputs.unknowns.len(), 2);
182        assert_eq!(ms.outputs.unknowns[0].index, 3);
183        assert_eq!(ms.outputs.unknowns[1].index, 4);
184        assert_eq!(ms.derivatives.unknowns.len(), 2);
185        assert_eq!(ms.derivatives.unknowns[0].index, 7);
186        assert_eq!(ms.derivatives.unknowns[1].index, 8);
187        assert_eq!(ms.initial_unknowns.unknowns.len(), 4);
188        assert_eq!(ms.initial_unknowns.unknowns[0].index, 3);
189        assert_eq!(ms.initial_unknowns.unknowns[1].index, 4);
190        assert_eq!(ms.initial_unknowns.unknowns[2].index, 7);
191        assert_eq!(ms.initial_unknowns.unknowns[2].dependencies, vec! {5, 2});
192        assert_eq!(ms.initial_unknowns.unknowns[3].dependencies, vec! {5, 6});
193    }
194}