Skip to main content

fmi_sim/sim/fmi3/
io.rs

1//! FMI3-specific input and output implementation
2
3use anyhow::Context;
4use arrow::{
5    array::{
6        ArrayRef, AsArray, BinaryBuilder, BooleanBuilder, Float32Array, Float32Builder,
7        Float64Array, Float64Builder, Int8Builder, Int16Builder, Int32Builder, Int64Builder,
8        StringBuilder, UInt8Array, UInt8Builder, UInt16Array, UInt16Builder, UInt32Array,
9        UInt32Builder, UInt64Array, UInt64Builder, downcast_array,
10    },
11    datatypes::{
12        DataType, Float32Type, Float64Type, Int8Type, Int16Type, Int32Type, Int64Type, UInt8Type,
13        UInt16Type, UInt32Type, UInt64Type,
14    },
15};
16
17use crate::sim::{
18    RecorderState,
19    interpolation::{Interpolate, PreLookup},
20    io::Recorder,
21    traits::{InstRecordValues, InstSetValues},
22};
23
24use fmi::{fmi3::GetSet, traits::FmiInstance};
25
26use itertools::Itertools;
27
28const DEFAULT_BINARY_BUFFER_SIZE: usize = 1024;
29
30macro_rules! impl_recorder {
31    ($getter:ident, $builder_type:ident, $inst:expr, $vr:ident, $builder:ident) => {{
32        let mut value = [std::default::Default::default()];
33        $inst.$getter(&[*$vr], &mut value)?;
34        $builder
35            .as_any_mut()
36            .downcast_mut::<$builder_type>()
37            .expect(concat!("column is not ", stringify!($builder_type)))
38            .append_value(value[0]);
39    }};
40}
41
42macro_rules! impl_record_values {
43    ($inst:ty) => {
44        impl InstRecordValues for $inst {
45            fn record_outputs(
46                &mut self,
47                time: f64,
48                recorder: &mut RecorderState<Self>,
49            ) -> anyhow::Result<()> {
50                log::trace!("Recording variables at time {}", time);
51
52                recorder.time.append_value(time);
53                for Recorder {
54                    field,
55                    value_reference: vr,
56                    builder,
57                    binary_max_size,
58                } in &mut recorder.recorders
59                {
60                    log::trace!(
61                        "Recording variable VR={} of type {:?}",
62                        vr,
63                        field.data_type()
64                    );
65                    match field.data_type() {
66                        DataType::Boolean => {
67                            impl_recorder!(get_boolean, BooleanBuilder, self, vr, builder)
68                        }
69                        DataType::Int8 => {
70                            impl_recorder!(get_int8, Int8Builder, self, vr, builder)
71                        }
72                        DataType::Int16 => {
73                            impl_recorder!(get_int16, Int16Builder, self, vr, builder)
74                        }
75                        DataType::Int32 => {
76                            impl_recorder!(get_int32, Int32Builder, self, vr, builder)
77                        }
78                        DataType::Int64 => {
79                            impl_recorder!(get_int64, Int64Builder, self, vr, builder)
80                        }
81                        DataType::UInt8 => {
82                            impl_recorder!(get_uint8, UInt8Builder, self, vr, builder)
83                        }
84                        DataType::UInt16 => {
85                            impl_recorder!(get_uint16, UInt16Builder, self, vr, builder)
86                        }
87                        DataType::UInt32 => {
88                            impl_recorder!(get_uint32, UInt32Builder, self, vr, builder)
89                        }
90                        DataType::UInt64 => {
91                            impl_recorder!(get_uint64, UInt64Builder, self, vr, builder)
92                        }
93                        DataType::Float32 => {
94                            impl_recorder!(get_float32, Float32Builder, self, vr, builder)
95                        }
96                        DataType::Float64 => {
97                            impl_recorder!(get_float64, Float64Builder, self, vr, builder)
98                        }
99                        DataType::Binary => {
100                            let buffer_len = binary_max_size.unwrap_or(DEFAULT_BINARY_BUFFER_SIZE);
101                            let mut data = vec![0u8; buffer_len];
102                            let mut value = [data.as_mut_slice()];
103                            let sizes = self
104                                .get_binary(&[*vr], &mut value)
105                                .context("Failed to get binary data")?;
106                            let actual_size = sizes.get(0).copied().unwrap_or(0);
107                            data.truncate(actual_size);
108                            builder
109                                .as_any_mut()
110                                .downcast_mut::<BinaryBuilder>()
111                                .expect("column is not Binary")
112                                .append_value(data);
113                        }
114                        DataType::Utf8 => {
115                            let mut values = [std::ffi::CString::new("").unwrap()];
116                            let _ = self.get_string(&[*vr], &mut values);
117                            let string_value = values[0].to_string_lossy();
118                            builder
119                                .as_any_mut()
120                                .downcast_mut::<StringBuilder>()
121                                .expect("column is not Utf8")
122                                .append_value(string_value);
123                        }
124                        _ => unimplemented!("Unsupported data type: {:?}", field.data_type()),
125                    }
126                }
127                Ok(())
128            }
129        }
130    };
131}
132
133macro_rules! impl_set_values {
134    ($t:ty) => {
135        impl InstSetValues for $t {
136            fn set_array(&mut self, vrs: &[Self::ValueRef], values: &ArrayRef) {
137                match values.data_type() {
138                    DataType::Boolean => {
139                        let values = values.as_boolean().iter().map(|x| x.unwrap()).collect_vec();
140                        self.set_boolean(vrs, &values).unwrap();
141                    }
142                    DataType::Int8 => {
143                        self.set_int8(vrs, values.as_primitive::<Int8Type>().values()).unwrap();
144                    }
145                    DataType::Int16 => {
146                        self.set_int16(vrs, values.as_primitive::<Int16Type>().values()).unwrap();
147                    }
148                    DataType::Int32 => {
149                        self.set_int32(vrs, values.as_primitive::<Int32Type>().values()).unwrap();
150                    }
151                    DataType::Int64 => {
152                        self.set_int64(vrs, values.as_primitive::<Int64Type>().values()).unwrap();
153                    }
154                    DataType::UInt8 => {
155                        self.set_uint8(vrs, values.as_primitive::<UInt8Type>().values()).unwrap();
156                    }
157                    DataType::UInt16 => {
158                        self.set_uint16(vrs, values.as_primitive::<UInt16Type>().values()).unwrap();
159                    }
160                    DataType::UInt32 => {
161                        self.set_uint32(vrs, values.as_primitive::<UInt32Type>().values()).unwrap();
162                    }
163                    DataType::UInt64 => {
164                        self.set_uint64(vrs, values.as_primitive::<UInt64Type>().values()).unwrap();
165                    }
166                    DataType::Float16 => {
167                        unimplemented!()
168                    }
169                    DataType::Float32 => {
170                        self.set_float32(vrs, values.as_primitive::<Float32Type>().values()).unwrap();
171                    }
172                    DataType::Float64 => {
173                        self.set_float64(vrs, values.as_primitive::<Float64Type>().values()).unwrap();
174                    }
175                    DataType::Binary => {
176                        let binary_refs: Vec<&[u8]> = values
177                            .as_binary::<i32>()
178                            .iter()
179                            .filter_map(|opt| opt) // Filter out None values
180                            .collect();
181                        let _ = self.set_binary(vrs, &binary_refs);
182                    }
183                    DataType::FixedSizeBinary(_) => todo!(),
184                    DataType::LargeBinary => todo!(),
185                    DataType::Utf8 => {
186                        let string_values: Vec<std::ffi::CString> = values
187                            .as_string::<i32>()
188                            .iter()
189                            .filter_map(|opt| opt) // Filter out None values
190                            .map(|s| std::ffi::CString::new(s).unwrap())
191                            .collect();
192                        let _ = self.set_string(vrs, &string_values);
193                    }
194                    DataType::LargeUtf8 => todo!(),
195                    _ => unimplemented!("Unsupported data type"),
196                }
197            }
198
199            fn set_interpolated<I: Interpolate>(
200                &mut self,
201                vr: <Self as FmiInstance>::ValueRef,
202                pl: &PreLookup,
203                array: &ArrayRef,
204            ) -> anyhow::Result<()> {
205                match array.data_type() {
206                    DataType::Boolean => todo!(),
207                    DataType::Int8 => {
208                        let array = array.as_primitive::<Int8Type>();
209                        let value = I::interpolate(pl, &array);
210                        self.set_int8(&[vr], &[value])?;
211                    }
212                    DataType::Int16 => {
213                        let array = array.as_primitive::<Int16Type>();
214                        let value = I::interpolate(pl, &array);
215                        self.set_int16(&[vr], &[value])?;
216                    }
217                    DataType::Int32 => {
218                        let array = array.as_primitive::<Int32Type>();
219                        let value = I::interpolate(pl, &array);
220                        self.set_int32(&[vr], &[value])?;
221                    }
222                    DataType::Int64 => {
223                        let array = array.as_primitive::<Int64Type>();
224                        let value = I::interpolate(pl, &array);
225                        self.set_int64(&[vr], &[value])?;
226                    }
227                    DataType::UInt8 => {
228                        let array: UInt8Array = downcast_array(&array);
229                        let value = I::interpolate(pl, &array);
230                        self.set_uint8(&[vr], &[value])?;
231                    }
232                    DataType::UInt16 => {
233                        let array: UInt16Array = downcast_array(&array);
234                        let value = I::interpolate(pl, &array);
235                        self.set_uint16(&[vr], &[value])?;
236                    }
237                    DataType::UInt32 => {
238                        let array: UInt32Array = downcast_array(&array);
239                        let value = I::interpolate(pl, &array);
240                        self.set_uint32(&[vr], &[value])?;
241                    }
242                    DataType::UInt64 => {
243                        let array: UInt64Array = downcast_array(&array);
244                        let value = I::interpolate(pl, &array);
245                        self.set_uint64(&[vr], &[value])?;
246                    }
247                    DataType::Float32 => {
248                        let array: Float32Array = downcast_array(&array);
249                        let value = I::interpolate(pl, &array);
250                        self.set_float32(&[vr], &[value])?;
251                    }
252                    DataType::Float64 => {
253                        let array: Float64Array = downcast_array(&array);
254                        let value = I::interpolate(pl, &array);
255                        self.set_float64(&[vr], &[value])?;
256                    }
257                    DataType::Binary => todo!(),
258                    DataType::Utf8 => {
259                        // For string interpolation, we use the next index value (no real interpolation for strings)
260                        let array = array.as_string::<i32>();
261                        let index = pl.next_index().min(array.iter().count().saturating_sub(1));
262                        if let Some(Some(value)) = array.iter().nth(index) {
263                            let cstring = std::ffi::CString::new(value).unwrap();
264                            let _ = self.set_string(&[vr], &[cstring]);
265                        }
266                    }
267                    _ => unimplemented!("Unsupported data type: {:?}", array.data_type()),
268                }
269                Ok(())
270            }
271        }
272    };
273}
274
275#[cfg(feature = "cs")]
276impl_set_values!(fmi::fmi3::instance::InstanceCS);
277#[cfg(feature = "cs")]
278impl_record_values!(fmi::fmi3::instance::InstanceCS);
279
280#[cfg(feature = "me")]
281impl_set_values!(fmi::fmi3::instance::InstanceME);
282#[cfg(feature = "me")]
283impl_record_values!(fmi::fmi3::instance::InstanceME);