Skip to main content

fmi_sim/sim/
traits.rs

1use std::path::Path;
2
3use arrow::{
4    array::{ArrayRef, RecordBatch},
5    datatypes::{Field, Schema},
6};
7use fmi::traits::{FmiImport, FmiInstance};
8
9use crate::{
10    Error,
11    options::{CoSimulationOptions, ModelExchangeOptions},
12};
13
14use super::{
15    RecorderState, SimStats,
16    interpolation::{Interpolate, PreLookup},
17    io::StartValues,
18    solver::Solver,
19};
20
21/// Interface for building the Arrow schema for the inputs and outputs of an FMU.
22pub trait ImportSchemaBuilder: FmiImport {
23    /// Build the schema for the inputs of the model.
24    fn inputs_schema(&self) -> Schema;
25    /// Build the schema for the outputs of the model.
26    fn outputs_schema(&self) -> Schema;
27    /// Build a list of (Field, ValueReference) for the continuous inputs.
28    fn continuous_inputs(&self) -> impl Iterator<Item = (Field, Self::ValueRef)> + '_;
29    /// Build a list of Schema column (index, ValueReference) for the discrete inputs.
30    fn discrete_inputs(&self) -> impl Iterator<Item = (Field, Self::ValueRef)> + '_;
31    /// Build a list of Schema column (index, ValueReference) for the outputs.
32    fn outputs(&self) -> impl Iterator<Item = (Field, Self::ValueRef)> + '_;
33    /// Parse a list of "var=value" strings.
34    ///
35    /// # Returns
36    /// A tuple of two lists of (ValueReference, Array) tuples. The first list contains any variable with
37    /// `Causality = StructuralParameter` and the second list contains regular parameters.
38    fn parse_start_values(
39        &self,
40        start_values: &[String],
41    ) -> anyhow::Result<StartValues<Self::ValueRef>>;
42
43    /// Maximum binary size advertised by the model description for a given value reference.
44    ///
45    /// Defaults to `None` when no binary metadata is available.
46    fn binary_max_size(&self, _vr: Self::ValueRef) -> Option<usize> {
47        None
48    }
49}
50
51pub trait InstSetValues: FmiInstance {
52    fn set_array(
53        &mut self,
54        vrs: &[<Self as FmiInstance>::ValueRef],
55        values: &arrow::array::ArrayRef,
56    );
57    fn set_interpolated<I: Interpolate>(
58        &mut self,
59        vr: <Self as FmiInstance>::ValueRef,
60        pl: &PreLookup,
61        array: &ArrayRef,
62    ) -> anyhow::Result<()>;
63}
64
65pub trait InstRecordValues: FmiInstance + Sized {
66    fn record_outputs(
67        &mut self,
68        time: f64,
69        recorder: &mut RecorderState<Self>,
70    ) -> anyhow::Result<()>;
71}
72
73/// Interface for handling events in the simulation.
74/// Implemented by ME in fmi2 and ME+CS in fmi3.
75pub trait SimHandleEvents {
76    /// Handle events during the simulation.
77    ///
78    /// # Returns
79    /// Returns a tuple of (reset_solver: bool, terminate_simulation: bool)
80    fn handle_events(&mut self, time: f64, input_event: bool) -> Result<(bool, bool), Error>;
81}
82
83pub trait SimMe<Inst> {
84    /// Main loop of the model-exchange simulation
85    fn main_loop<S>(&mut self, solver: S) -> Result<SimStats, Error>
86    where
87        S: Solver<Inst>;
88}
89
90pub trait SimDefaultInitialize {
91    fn default_initialize(&mut self) -> Result<(), Error>;
92}
93
94pub trait SimApplyStartValues<Inst: FmiInstance> {
95    fn apply_start_values(
96        &mut self,
97        start_values: &StartValues<Inst::ValueRef>,
98    ) -> Result<(), Error>;
99}
100
101pub trait SimInitialize<Inst: FmiInstance>: SimDefaultInitialize {
102    fn initialize<P: AsRef<Path>>(
103        &mut self,
104        start_values: StartValues<Inst::ValueRef>,
105        fmu_state_file: Option<P>,
106    ) -> Result<(), Error>;
107}
108
109pub trait FmiSim: FmiImport + ImportSchemaBuilder {
110    /// Simulate the model using Model Exchange.
111    #[cfg(feature = "me")]
112    fn simulate_me(
113        &self,
114        options: &ModelExchangeOptions,
115        input_data: Option<RecordBatch>,
116    ) -> Result<(RecordBatch, SimStats), Error>;
117
118    /// Simulate the model using Co-Simulation.
119    #[cfg(feature = "cs")]
120    fn simulate_cs(
121        &self,
122        options: &CoSimulationOptions,
123        input_data: Option<RecordBatch>,
124    ) -> Result<(RecordBatch, SimStats), Error>;
125}