fmi_schema/fmi2/
scalar_variable.rs

1use yaserde_derive::{YaDeserialize, YaSerialize};
2
3use crate::default_wrapper;
4
5/// Enumeration that defines the causality of the variable.
6#[derive(Clone, Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
7pub enum Causality {
8    #[yaserde(rename = "parameter")]
9    Parameter,
10    #[yaserde(rename = "calculatedParameter")]
11    CalculatedParameter,
12    #[yaserde(rename = "input")]
13    Input,
14    #[yaserde(rename = "output")]
15    Output,
16    #[default]
17    #[yaserde(rename = "local")]
18    Local,
19    #[yaserde(rename = "independent")]
20    Independent,
21}
22
23/// Enumeration that defines the time dependency of the variable, in other words it defines the time instants when a variable can change its value.
24///
25/// The default is [`Variability::Continuous`].
26#[derive(Clone, Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
27pub enum Variability {
28    /// The value of the variable never changes.
29    #[yaserde(rename = "constant")]
30    Constant,
31    /// The value of the variable is fixed after initialization, in other words after `exit_initialization_mode()` was called the variable value does not change anymore.
32    #[yaserde(rename = "fixed")]
33    Fixed,
34    /// The value of the variable is constant between external events (ModelExchange) and between Communication Points (CoSimulation) due to changing variables with causality = "parameter" or "input" and variability = "tunable".
35    #[yaserde(rename = "tunable")]
36    Tunable,
37    /// * ModelExchange: The value of the variable is constant between external and internal events (= time, state, step events defined implicitly in the FMU).
38    /// * CoSimulation: By convention, the variable is from a “real” sampled data system and its value is only changed at Communication Points (also inside the slave).
39    #[yaserde(rename = "discrete")]
40    Discrete,
41    /// Only a variable of type = "Real" can be "continuous".
42    /// * ModelExchange: No restrictions on value changes.
43    /// * CoSimulation: By convention, the variable is from a differential
44    #[default]
45    #[yaserde(rename = "continuous")]
46    Continuous,
47}
48
49#[derive(Clone, Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
50pub enum Initial {
51    #[default]
52    #[yaserde(rename = "exact")]
53    Exact,
54    #[yaserde(rename = "approx")]
55    Approx,
56    #[yaserde(rename = "calculated")]
57    Calculated,
58}
59
60#[derive(Clone, Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
61pub struct Real {
62    /// If present, name of type defined with TypeDefinitions / SimpleType providing defaults.
63    #[yaserde(attribute = true, rename = "declaredType")]
64    pub declared_type: Option<String>,
65
66    /// Value before initialization, if initial=exact or approx.
67    /// max >= start >= min required
68    #[yaserde(attribute = true)]
69    pub start: Option<f64>,
70
71    /// If present, this variable is the derivative of variable with ScalarVariable index
72    /// "derivative".
73    #[yaserde(attribute = true)]
74    pub derivative: Option<u32>,
75
76    /// Only for ModelExchange and if variable is a continuous-time state:
77    /// If true, state can be reinitialized at an event by the FMU
78    /// If false, state will never be reinitialized at an event by the FMU
79    #[yaserde(attribute = true, rename = "reinit")]
80    pub reinit: Option<bool>,
81}
82
83#[derive(Clone, Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
84pub struct Integer {
85    /// If present, name of type defined with TypeDefinitions / SimpleType providing defaults.
86    #[yaserde(attribute = true, rename = "declaredType")]
87    pub declared_type: Option<String>,
88
89    /// Value before initialization, if initial=exact or approx.
90    /// max >= start >= min required
91    #[yaserde(attribute = true)]
92    pub start: Option<i32>,
93}
94
95#[derive(Clone, Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
96pub struct Boolean {
97    /// If present, name of type defined with TypeDefinitions / SimpleType providing defaults.
98    #[yaserde(attribute = true, rename = "declaredType")]
99    pub declared_type: Option<String>,
100
101    /// Value before initialization, if initial=exact or approx.
102    #[yaserde(attribute = true)]
103    pub start: Option<bool>,
104}
105
106#[derive(Clone, PartialEq, Debug, YaSerialize, YaDeserialize)]
107pub enum ScalarVariableElement {
108    #[yaserde(flatten = true)]
109    Real(Real),
110    #[yaserde(flatten = true)]
111    Integer(Integer),
112    #[yaserde(flatten = true)]
113    Boolean(Boolean),
114    #[yaserde(flatten = true)]
115    String,
116    #[yaserde(flatten = true)]
117    Enumeration,
118}
119
120impl Default for ScalarVariableElement {
121    fn default() -> Self {
122        Self::Real(Real::default())
123    }
124}
125
126#[cfg(feature = "arrow")]
127impl ScalarVariableElement {
128    pub fn data_type(&self) -> arrow::datatypes::DataType {
129        match self {
130            ScalarVariableElement::Real(_) => arrow::datatypes::DataType::Float64,
131            ScalarVariableElement::Integer(_) => arrow::datatypes::DataType::Int32,
132            ScalarVariableElement::Boolean(_) => arrow::datatypes::DataType::Boolean,
133            ScalarVariableElement::String => arrow::datatypes::DataType::Utf8,
134            ScalarVariableElement::Enumeration => arrow::datatypes::DataType::Int32,
135        }
136    }
137}
138
139#[derive(Default, Debug, YaSerialize, YaDeserialize)]
140pub struct ScalarVariable {
141    /// The full, unique name of the variable.
142    #[yaserde(attribute = true)]
143    pub name: String,
144
145    /// A handle of the variable to efficiently identify the variable value in the model interface.
146    #[yaserde(attribute = true, rename = "valueReference")]
147    pub value_reference: u32,
148
149    /// An optional description string describing the meaning of the variable.
150    #[yaserde(attribute = true)]
151    pub description: Option<String>,
152
153    /// Enumeration that defines the causality of the variable.
154    #[yaserde(attribute = true, default = "default_wrapper")]
155    pub causality: Causality,
156
157    /// Enumeration that defines the time dependency of the variable, in other words it defines the
158    /// time instants when a variable can change its value.
159    #[yaserde(attribute = true, default = "default_wrapper")]
160    pub variability: Variability,
161
162    /// Enumeration that defines how the variable is initialized. It is not allowed to provide a
163    /// value for initial if `causality`=`Input` or `Independent`.
164    #[yaserde(attribute = true)]
165    pub initial: Option<Initial>,
166
167    #[yaserde(flatten = true)]
168    pub elem: ScalarVariableElement,
169}
170
171impl ScalarVariable {
172    pub fn is_continuous_input(&self) -> bool {
173        matches!(
174            (&self.elem, &self.causality),
175            (ScalarVariableElement::Real { .. }, Causality::Input)
176        )
177    }
178}
179
180#[cfg(test)]
181mod tests {
182    use super::*;
183
184    #[test]
185    fn test_scalar_variable() {
186        let s = r#"
187        <ScalarVariable
188            name="inertia1.J"
189            valueReference="1073741824"
190            description="Moment of load inertia"
191            causality="parameter"
192            variability="fixed">
193            <Real declaredType="Modelica.SIunits.Inertia" start="1"/>
194        </ScalarVariable>
195        "#;
196        let sv: ScalarVariable = yaserde::de::from_str(s).unwrap();
197        assert_eq!(sv.name, "inertia1.J");
198        assert_eq!(sv.value_reference, 1073741824);
199        assert_eq!(sv.description, Some("Moment of load inertia".into()));
200        assert_eq!(sv.causality, Causality::Parameter);
201        assert_eq!(sv.variability, Variability::Fixed);
202        assert_eq!(
203            sv.elem,
204            ScalarVariableElement::Real(Real {
205                declared_type: Some("Modelica.SIunits.Inertia".to_string()),
206                start: Some(1.0),
207                derivative: None,
208                reinit: None
209            })
210        );
211    }
212}