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        yaserde::de::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.as_ref().map(|de| de.start_time)
42    }
43
44    fn stop_time(&self) -> Option<f64> {
45        self.default_experiment.as_ref().map(|de| de.stop_time)
46    }
47
48    fn tolerance(&self) -> Option<f64> {
49        self.default_experiment.as_ref().map(|de| de.tolerance)
50    }
51
52    fn step_size(&self) -> Option<f64> {
53        None
54    }
55}
56
57impl VariableCounts for ModelVariables {
58    fn model_counts(&self) -> Counts {
59        self.variables
60            .iter()
61            .fold(Counts::default(), |mut cts, sv| {
62                match sv.variability {
63                    Variability::Constant => {
64                        cts.num_constants += 1;
65                    }
66                    Variability::Continuous => {
67                        cts.num_continuous += 1;
68                    }
69                    Variability::Discrete => {
70                        cts.num_discrete += 1;
71                    }
72                    _ => {}
73                }
74                match sv.causality {
75                    Causality::CalculatedParameter => {
76                        cts.num_calculated_parameters += 1;
77                    }
78                    Causality::Parameter => {
79                        cts.num_parameters += 1;
80                    }
81                    Causality::Input => {
82                        cts.num_inputs += 1;
83                    }
84                    Causality::Output => {
85                        cts.num_outputs += 1;
86                    }
87                    Causality::Local => {
88                        cts.num_local += 1;
89                    }
90                    Causality::Independent => {
91                        cts.num_independent += 1;
92                    }
93                }
94                match sv.elem {
95                    ScalarVariableElement::Real { .. } => {
96                        cts.num_real_vars += 1;
97                    }
98                    ScalarVariableElement::Integer { .. } => {
99                        cts.num_integer_vars += 1;
100                    }
101                    ScalarVariableElement::Enumeration => {
102                        cts.num_enum_vars += 1;
103                    }
104                    ScalarVariableElement::Boolean { .. } => {
105                        cts.num_bool_vars += 1;
106                    }
107                    ScalarVariableElement::String => {
108                        cts.num_string_vars += 1;
109                    }
110                }
111                cts
112            })
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn test_default_experiment() {
122        let s = r##"<DefaultExperiment stopTime="3.0" tolerance="0.0001"/>"##;
123        let x: DefaultExperiment = yaserde::de::from_str(s).unwrap();
124        assert_eq!(x.start_time, 0.0);
125        assert_eq!(x.stop_time, 3.0);
126        assert_eq!(x.tolerance, 0.0001);
127
128        let s = r#"<DefaultExperiment startTime = "0.20000000000000000e+00" stopTime = "1.50000000000000000e+00" tolerance = "0.0001"/>"#;
129        let x: DefaultExperiment = yaserde::de::from_str(s).unwrap();
130        assert_eq!(x.start_time, 0.2);
131        assert_eq!(x.stop_time, 1.5);
132        assert_eq!(x.tolerance, 0.0001);
133    }
134
135    #[test]
136    fn test_model_variables() {
137        let s = r##"
138            <ModelVariables>
139                <ScalarVariable name="x[1]" valueReference="0" initial="exact"> <Real/> </ScalarVariable> <!-- idex="5" -->
140                <ScalarVariable name="x[2]" valueReference="1" initial="exact"> <Real/> </ScalarVariable> <!-- index="6" -->
141                <ScalarVariable name="der(x[1])" valueReference="2"> <Real derivative="5"/> </ScalarVariable> <!-- index="7" -->
142                <ScalarVariable name="der(x[2])" valueReference="3"> <Real derivative="6"/> </ScalarVariable> <!-- index="8" -->
143            </ModelVariables>
144        "##;
145        let x: ModelVariables = yaserde::de::from_str(s).unwrap();
146        assert_eq!(x.variables.len(), 4);
147        assert!(
148            x.variables
149                .iter()
150                .map(|v| &v.name)
151                .zip(["x[1]", "x[2]", "der(x[1])", "der(x[2])"].iter())
152                .all(|(a, b)| a == b)
153        );
154    }
155
156    #[test]
157    fn test_model_structure() {
158        let s = r##"
159            <ModelStructure>
160                <Outputs>
161                    <Unknown index="3" />
162                    <Unknown index="4" />
163                </Outputs>
164                <Derivatives>
165                    <Unknown index="7" />
166                    <Unknown index="8" />
167                </Derivatives>
168                <InitialUnknowns>
169                    <Unknown index="3" />
170                    <Unknown index="4" />
171                    <Unknown index="7" dependencies="5 2" />
172                    <Unknown index="8" dependencies="5 6" />
173                </InitialUnknowns>
174            </ModelStructure>
175        "##;
176        let ms: ModelStructure = yaserde::de::from_str(s).unwrap();
177        assert_eq!(ms.outputs.unknowns.len(), 2);
178        assert_eq!(ms.outputs.unknowns[0].index, 3);
179        assert_eq!(ms.outputs.unknowns[1].index, 4);
180        assert_eq!(ms.derivatives.unknowns.len(), 2);
181        assert_eq!(ms.derivatives.unknowns[0].index, 7);
182        assert_eq!(ms.derivatives.unknowns[1].index, 8);
183        assert_eq!(ms.initial_unknowns.unknowns.len(), 4);
184        assert_eq!(ms.initial_unknowns.unknowns[0].index, 3);
185        assert_eq!(ms.initial_unknowns.unknowns[1].index, 4);
186        assert_eq!(ms.initial_unknowns.unknowns[2].index, 7);
187        assert_eq!(ms.initial_unknowns.unknowns[2].dependencies, vec! {5, 2});
188        assert_eq!(ms.initial_unknowns.unknowns[3].dependencies, vec! {5, 6});
189    }
190}