Skip to main content

fmi_sim/sim/fmi2/
io.rs

1//! FMI2-specific input and output implementation
2
3use arrow::{
4    array::{
5        ArrayRef, AsArray, BooleanBuilder, Float64Array, Float64Builder, Int32Builder,
6        StringBuilder, downcast_array,
7    },
8    datatypes::{DataType, Float64Type, Int32Type},
9};
10use fmi::{fmi2::instance::Common, traits::FmiInstance};
11use itertools::Itertools;
12
13use crate::sim::{
14    RecorderState,
15    interpolation::{Interpolate, PreLookup},
16    io::Recorder,
17    traits::{InstRecordValues, InstSetValues},
18};
19
20macro_rules! impl_recorder {
21    ($getter:ident, $builder_type:ident, $inst:expr, $vr:ident, $builder:ident) => {{
22        let mut value = [std::default::Default::default()];
23        $inst.$getter(&[*$vr], &mut value)?;
24        $builder
25            .as_any_mut()
26            .downcast_mut::<$builder_type>()
27            .expect(concat!("column is not ", stringify!($builder_type)))
28            .append_value(value[0]);
29    }};
30}
31
32macro_rules! impl_record_values {
33    ($inst:ty) => {
34        impl InstRecordValues for $inst {
35            fn record_outputs(
36                &mut self,
37                time: f64,
38                recorder: &mut RecorderState<Self>,
39            ) -> anyhow::Result<()> {
40                log::trace!("Recording variables at time {}", time);
41
42                recorder.time.append_value(time);
43                for Recorder {
44                    field,
45                    value_reference: vr,
46                    builder,
47                    ..
48                } in &mut recorder.recorders
49                {
50                    log::trace!(
51                        "Recording variable VR={} of type {:?}",
52                        vr,
53                        field.data_type()
54                    );
55                    match field.data_type() {
56                        DataType::Boolean => {
57                            let mut value = [std::default::Default::default()];
58                            self.get_boolean(&[*vr], &mut value)?;
59                            builder
60                                .as_any_mut()
61                                .downcast_mut::<BooleanBuilder>()
62                                .expect(concat!("column is not ", stringify!($builder_type)))
63                                .append_value(value[0] > 0);
64                        }
65                        DataType::Int32 => {
66                            impl_recorder!(get_integer, Int32Builder, self, vr, builder)
67                        }
68                        DataType::Float64 => {
69                            impl_recorder!(get_real, Float64Builder, self, vr, builder)
70                        }
71                        DataType::Utf8 => {
72                            let mut values = vec![std::ffi::CString::new("").unwrap()];
73                            if self.get_string(&[*vr], &mut values).is_ok() {
74                                let string_value = values[0].to_str().unwrap_or("");
75                                builder
76                                    .as_any_mut()
77                                    .downcast_mut::<StringBuilder>()
78                                    .expect("column is not StringBuilder")
79                                    .append_value(string_value);
80                            } else {
81                                // Handle error case by appending empty string
82                                builder
83                                    .as_any_mut()
84                                    .downcast_mut::<StringBuilder>()
85                                    .expect("column is not StringBuilder")
86                                    .append_value("");
87                            }
88                        }
89                        _ => unimplemented!("Unsupported data type: {:?}", field.data_type()),
90                    }
91                }
92
93                println!("Recorded outputs at time {}", time);
94                Ok(())
95            }
96        }
97    };
98}
99
100macro_rules! impl_set_values {
101    ($t:ty) => {
102        impl InstSetValues for $t {
103            fn set_array(&mut self, vrs: &[Self::ValueRef], values: &ArrayRef) {
104                match values.data_type() {
105                    DataType::Boolean => {
106                        let values = values
107                            .as_boolean()
108                            .iter()
109                            .map(|x| x.unwrap() as i32)
110                            .collect_vec();
111                        let _ = self.set_boolean(vrs, &values);
112                    }
113                    DataType::Int32 => {
114                        let _ = self.set_integer(vrs, values.as_primitive::<Int32Type>().values());
115                    }
116                    DataType::Float64 => {
117                        let _ = self.set_real(vrs, values.as_primitive::<Float64Type>().values());
118                    }
119                    DataType::Utf8 => {
120                        let cstrings: Vec<std::ffi::CString> = values
121                            .as_string::<i32>()
122                            .iter()
123                            .flatten()
124                            .map(|s| std::ffi::CString::new(s).unwrap())
125                            .collect();
126                        let _ = self.set_string(vrs, &cstrings);
127                    }
128                    _ => unimplemented!("Unsupported data type"),
129                }
130            }
131
132            fn set_interpolated<I: Interpolate>(
133                &mut self,
134                vr: <Self as FmiInstance>::ValueRef,
135                pl: &PreLookup,
136                array: &ArrayRef,
137            ) -> anyhow::Result<()> {
138                match array.data_type() {
139                    DataType::Boolean => todo!(),
140                    DataType::Int32 => {
141                        let array = array.as_primitive::<Int32Type>();
142                        let value = I::interpolate(pl, &array);
143                        self.set_integer(&[vr], &[value])?;
144                    }
145                    DataType::Float64 => {
146                        let array: Float64Array = downcast_array(&array);
147                        let value = I::interpolate(pl, &array);
148                        self.set_real(&[vr], &[value])?;
149                    }
150                    _ => unimplemented!("Unsupported data type: {:?}", array.data_type()),
151                }
152                Ok(())
153            }
154        }
155    };
156}
157
158#[cfg(feature = "cs")]
159impl_set_values!(fmi::fmi2::instance::InstanceCS);
160#[cfg(feature = "cs")]
161impl_record_values!(fmi::fmi2::instance::InstanceCS);
162
163#[cfg(feature = "me")]
164impl_set_values!(fmi::fmi2::instance::InstanceME);
165#[cfg(feature = "me")]
166impl_record_values!(fmi::fmi2::instance::InstanceME);