1mod 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}