fmi_sim/sim/fmi3/
io.rs

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