Skip to main content

fmi_schema/fmi2/
variable_dependency.rs

1use std::{fmt::Display, str::FromStr};
2
3use crate::utils::AttrList;
4
5/// Dependency of scalar Unknown from Knowns in Continuous-Time and Event Mode (ModelExchange), and
6/// at Communication Points (CoSimulation): Unknown=f(Known_1, Known_2, ...).
7/// The Knowns are "inputs", "continuous states" and "independent variable" (usually time)".
8#[derive(Default, PartialEq, Debug)]
9pub struct Fmi2VariableDependency {
10    /// ScalarVariable index of Unknown
11    pub index: u32,
12
13    /// Defines the dependency of the Unknown (directly or indirectly via auxiliary variables) on
14    /// the Knowns in Continuous-Time and Event Mode ([`super::ModelExchange`]) and at
15    /// Communication Points ([`super::CoSimulation`]).
16    ///
17    /// If not present, it must be assumed that the Unknown depends on all Knowns. If present as
18    /// empty list, the Unknown depends on none of the Knowns. Otherwise the Unknown depends on
19    /// the Knowns defined by the given [`super::ScalarVariable`] indices. The indices are
20    /// ordered according to size, starting with the smallest index.
21    pub dependencies: Vec<u32>,
22
23    /// If not present, it must be assumed that the Unknown depends on the Knowns without a
24    /// particular structure. Otherwise, the corresponding Known v enters the equation as:
25    ///
26    /// * [`DependenciesKind::Dependent`]:  no particular structure, f(v)
27    /// * [`DependenciesKind::Constant`]:   constant factor, c*v (only for Real variablse)
28    /// * [`DependenciesKind::Fixed`]:      fixed factor, p*v (only for Real variables)
29    /// * [`DependenciesKind::Tunable`]:    tunable factor, p*v (only for Real variables)
30    /// * [`DependenciesKind::Discrete`]:   discrete factor, d*v (only for Real variables)
31    ///
32    /// If [`Self::dependencies_kind`] is present, [`Self::dependencies`] must be present and must
33    /// have the same number of list elements.
34    pub dependencies_kind: Vec<DependenciesKind>,
35}
36
37// Custom implementation of XmlRead and XmlWrite for Fmi2VariableDependency to allow multiple tags.
38impl<'__input> ::hard_xml::XmlRead<'__input> for Fmi2VariableDependency {
39    fn from_reader(reader: &mut ::hard_xml::XmlReader<'__input>) -> ::hard_xml::XmlResult<Self> {
40        use ::hard_xml::XmlError;
41        use ::hard_xml::xmlparser::{ElementEnd, Token};
42
43        let mut __self_index = None;
44        let mut __self_dependencies = Vec::new();
45        let mut __self_dependencies_kind = Vec::new();
46
47        let tag = reader
48            .find_element_start(None)?
49            .expect("Expected start element");
50        let _ = reader.next().unwrap()?;
51
52        while let Some((__key, __value)) = reader.find_attribute()? {
53            match __key {
54                "index" => {
55                    __self_index = Some(
56                        <u32 as std::str::FromStr>::from_str(&__value)
57                            .map_err(|e| XmlError::FromStr(e.into()))?,
58                    );
59                }
60                "dependencies" => {
61                    let attr_list = <AttrList<u32> as std::str::FromStr>::from_str(&__value)
62                        .map_err(|e| XmlError::FromStr(e.into()))?;
63                    __self_dependencies = attr_list.0;
64                }
65                "dependenciesKind" => {
66                    let attr_list =
67                        <AttrList<DependenciesKind> as std::str::FromStr>::from_str(&__value)
68                            .map_err(|e| XmlError::FromStr(e.into()))?;
69                    __self_dependencies_kind = attr_list.0;
70                }
71                key => {
72                    return Err(XmlError::UnknownField {
73                        name: "Fmi2VariableDependency".to_owned(),
74                        field: key.to_owned(),
75                    });
76                }
77            }
78        }
79
80        if let Token::ElementEnd {
81            end: ElementEnd::Empty,
82            ..
83        } = reader.next().unwrap()?
84        {
85            return Ok(Fmi2VariableDependency {
86                index: __self_index.ok_or(XmlError::MissingField {
87                    name: "Fmi2VariableDependency".to_owned(),
88                    field: "index".to_owned(),
89                })?,
90                dependencies: __self_dependencies,
91                dependencies_kind: __self_dependencies_kind,
92            });
93        }
94
95        if let Some(__tag) = reader.find_element_start(Some(tag))? {
96            return Err(XmlError::UnknownField {
97                name: "Fmi2VariableDependency".to_owned(),
98                field: __tag.to_owned(),
99            });
100        }
101
102        Ok(Fmi2VariableDependency {
103            index: __self_index.ok_or(XmlError::MissingField {
104                name: "Fmi2VariableDependency".to_owned(),
105                field: "index".to_owned(),
106            })?,
107            dependencies: __self_dependencies,
108            dependencies_kind: __self_dependencies_kind,
109        })
110    }
111}
112
113impl ::hard_xml::XmlWrite for Fmi2VariableDependency {
114    fn to_writer<W: std::io::Write>(
115        &self,
116        writer: &mut ::hard_xml::XmlWriter<W>,
117    ) -> ::hard_xml::XmlResult<()> {
118        writer.write_element_start("Unknown")?;
119        writer.write_attribute("index", &format!("{}", self.index))?;
120
121        if !self.dependencies.is_empty() {
122            writer.write_attribute(
123                "dependencies",
124                &format!("{}", AttrList(self.dependencies.clone())),
125            )?;
126        }
127
128        if !self.dependencies_kind.is_empty() {
129            writer.write_attribute(
130                "dependenciesKind",
131                &format!("{}", AttrList(self.dependencies_kind.clone())),
132            )?;
133        }
134
135        writer.write_element_end_empty()?;
136        Ok(())
137    }
138}
139
140#[derive(Clone, Default, PartialEq, Debug)]
141pub enum DependenciesKind {
142    #[default]
143    Dependent,
144    Constant,
145    Fixed,
146    Tunable,
147    Discrete,
148}
149
150impl FromStr for DependenciesKind {
151    type Err = String;
152
153    fn from_str(s: &str) -> Result<Self, Self::Err> {
154        match s {
155            "dependent" => Ok(DependenciesKind::Dependent),
156            "constant" => Ok(DependenciesKind::Constant),
157            "fixed" => Ok(DependenciesKind::Fixed),
158            "tunable" => Ok(DependenciesKind::Tunable),
159            "discrete" => Ok(DependenciesKind::Discrete),
160            _ => Err(format!("Invalid DependenciesKind: {}", s)),
161        }
162    }
163}
164
165impl Display for DependenciesKind {
166    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167        let s = match self {
168            DependenciesKind::Dependent => "dependent",
169            DependenciesKind::Constant => "constant",
170            DependenciesKind::Fixed => "fixed",
171            DependenciesKind::Tunable => "tunable",
172            DependenciesKind::Discrete => "discrete",
173        };
174        write!(f, "{}", s)
175    }
176}