fmi_export/fmi3/traits/
mod.rs1use std::{fmt::Display, path::PathBuf, str::FromStr};
2
3use fmi::{
4 EventFlags,
5 fmi3::{Fmi3Error, Fmi3Res, Fmi3Status, binding},
6 schema::fmi3::AppendToModelVariables,
7};
8
9use crate::fmi3::ModelState;
10
11mod model_get_set;
12mod wrappers;
13
14pub use model_get_set::{ModelGetSet, ModelGetSetStates};
15pub use wrappers::{Fmi3CoSimulation, Fmi3Common, Fmi3ModelExchange, Fmi3ScheduledExecution};
16
17pub trait Context<M: UserModel> {
19 fn logging_on(&self, category: M::LoggingCategory) -> bool;
21
22 fn set_logging(&mut self, category: M::LoggingCategory, enabled: bool);
24
25 fn log(&self, status: Fmi3Status, category: M::LoggingCategory, args: std::fmt::Arguments<'_>);
27
28 fn resource_path(&self) -> &PathBuf;
30
31 fn initialize(&mut self, start_time: f64, stop_time: Option<f64>);
32
33 fn time(&self) -> f64;
35
36 fn set_time(&mut self, time: f64);
38
39 fn stop_time(&self) -> Option<f64>;
41
42 fn early_return_allowed(&self) -> bool {
44 false
45 }
46
47 fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
48}
49
50pub trait Model: Default {
55 const MODEL_NAME: &'static str;
56 const INSTANTIATION_TOKEN: &'static str;
57
58 const MAX_EVENT_INDICATORS: usize;
60
61 const SUPPORTS_MODEL_EXCHANGE: bool;
63
64 const SUPPORTS_CO_SIMULATION: bool;
66
67 const SUPPORTS_SCHEDULED_EXECUTION: bool;
69
70 fn build_metadata(
75 variables: &mut fmi::schema::fmi3::ModelVariables,
76 model_structure: &mut fmi::schema::fmi3::ModelStructure,
77 vr_offset: u32,
78 prefix: Option<&str>,
79 ) -> u32;
80
81 fn build_terminals(_terminals: &mut Vec<fmi::schema::fmi3::Terminal>, _prefix: Option<&str>) {}
83
84 fn build_toplevel_terminals() -> Option<fmi::schema::fmi3::Fmi3TerminalsAndIcons> {
86 let mut terminals = Vec::new();
87 Self::build_terminals(&mut terminals, None);
88 if terminals.is_empty() {
89 return None;
90 }
91 let fmi_version = unsafe { std::ffi::CStr::from_ptr(binding::fmi3Version.as_ptr() as _) }
92 .to_string_lossy();
93 Some(fmi::schema::fmi3::Fmi3TerminalsAndIcons {
94 fmi_version: fmi_version.to_string(),
95 terminals: Some(fmi::schema::fmi3::Terminals { terminals }),
96 annotations: None,
97 })
98 }
99
100 fn build_toplevel_metadata() -> ModelMetadata {
102 let mut variables = fmi::schema::fmi3::ModelVariables::default();
103 let time = fmi::schema::fmi3::FmiFloat64::new(
104 "time".to_string(),
105 0,
106 None,
107 fmi::schema::fmi3::Causality::Independent,
108 fmi::schema::fmi3::Variability::Continuous,
109 None,
110 None,
111 );
112 AppendToModelVariables::append_to_variables(time, &mut variables);
113 let mut structure = fmi::schema::fmi3::ModelStructure::default();
114 let _num_vars = Self::build_metadata(&mut variables, &mut structure, 1, None);
115 let terminals = Self::build_toplevel_terminals();
116 ModelMetadata {
117 model_variables: variables,
118 model_structure: structure,
119 terminals,
120 }
121 }
122
123 fn set_start_values(&mut self);
125
126 fn validate_variable_setting(
130 vr: binding::fmi3ValueReference,
131 state: &ModelState,
132 ) -> Result<(), &'static str> {
133 let _ = (vr, state);
136 Ok(())
137 }
138}
139
140pub struct ModelMetadata {
142 pub model_variables: fmi::schema::fmi3::ModelVariables,
143 pub model_structure: fmi::schema::fmi3::ModelStructure,
144 pub terminals: Option<fmi::schema::fmi3::Fmi3TerminalsAndIcons>,
145}
146
147#[allow(dead_code)]
149pub trait TerminalProvider {
150 fn terminal(name: &str, prefix: Option<&str>) -> fmi::schema::fmi3::Terminal;
151}
152
153pub trait ModelLoggingCategory: Display + FromStr + Ord + Copy + Default {
154 fn all_categories() -> impl Iterator<Item = Self>;
156 fn trace_category() -> Self;
158 fn error_category() -> Self;
160}
161
162#[derive(Debug, Clone, Copy, Default)]
164pub struct CSDoStepResult {
165 pub event_handling_needed: bool,
166 pub terminate_simulation: bool,
167 pub early_return: bool,
168 pub last_successful_time: f64,
169}
170
171impl CSDoStepResult {
172 pub fn completed(last_successful_time: f64) -> Self {
173 Self {
174 event_handling_needed: false,
175 terminate_simulation: false,
176 early_return: false,
177 last_successful_time,
178 }
179 }
180}
181
182pub trait UserModel: Sized {
186 type LoggingCategory: ModelLoggingCategory + 'static;
190
191 fn configurate(&mut self, _context: &dyn Context<Self>) -> Result<(), Fmi3Error> {
194 Ok(())
195 }
196
197 fn calculate_values(&mut self, _context: &dyn Context<Self>) -> Result<Fmi3Res, Fmi3Error> {
200 Ok(Fmi3Res::OK)
201 }
202
203 fn event_update(
212 &mut self,
213 _context: &dyn Context<Self>,
214 event_flags: &mut EventFlags,
215 ) -> Result<Fmi3Res, Fmi3Error> {
216 event_flags.reset();
217 Ok(Fmi3Res::OK)
218 }
219
220 fn get_event_indicators(
229 &mut self,
230 _context: &dyn Context<Self>,
231 indicators: &mut [f64],
232 ) -> Result<bool, Fmi3Error> {
233 for indicator in indicators.iter_mut() {
235 *indicator = 0.0;
236 }
237 Ok(true)
238 }
239
240 fn do_step(
244 &mut self,
245 context: &mut dyn Context<Self>,
246 current_communication_point: f64,
247 communication_step_size: f64,
248 _no_set_fmu_state_prior_to_current_point: bool,
249 ) -> Result<CSDoStepResult, Fmi3Error> {
250 let target_time = current_communication_point + communication_step_size;
251 context.set_time(target_time);
252 Ok(CSDoStepResult::completed(target_time))
253 }
254}