1use 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 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) .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) .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 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<'_>);