Skip to main content

fmi_export/fmi3/instance/
context.rs

1use std::{collections::BTreeMap, path::PathBuf};
2
3use fmi::fmi3::Fmi3Status;
4
5use crate::fmi3::{
6    UserModel,
7    instance::{IntermediateUpdateClosure, LogMessageClosure},
8    traits::{Context, ModelLoggingCategory},
9};
10
11/// Basic context for Model-Exchange FMU instances
12pub struct BasicContext<M: UserModel> {
13    /// Map of logging categories to their enabled state.
14    /// This is used to track which categories are enabled for logging.
15    logging_on: BTreeMap<M::LoggingCategory, bool>,
16    /// Callback for logging messages.
17    log_message: LogMessageClosure,
18    /// Path to the resources directory.
19    resource_path: PathBuf,
20    /// Simulation stop time.
21    stop_time: Option<f64>,
22    /// Current simulation time.
23    time: f64,
24    /// Whether early return is allowed for CS steps.
25    early_return_allowed: bool,
26    /// Optional FMI intermediate update callback (CS).
27    intermediate_update: Option<IntermediateUpdateClosure>,
28}
29
30impl<M: UserModel> BasicContext<M> {
31    pub fn new(
32        logging_on: bool,
33        log_message: LogMessageClosure,
34        resource_path: PathBuf,
35        early_return_allowed: bool,
36        intermediate_update: Option<IntermediateUpdateClosure>,
37    ) -> Self {
38        let logging_on = <M as UserModel>::LoggingCategory::all_categories()
39            .map(|category| (category, logging_on))
40            .collect();
41        Self {
42            logging_on,
43            log_message,
44            resource_path,
45            stop_time: None,
46            time: 0.0,
47            early_return_allowed,
48            intermediate_update,
49        }
50    }
51
52    pub fn intermediate_update(&self) -> Option<&IntermediateUpdateClosure> {
53        self.intermediate_update.as_ref()
54    }
55}
56
57impl<M> Context<M> for BasicContext<M>
58where
59    M: UserModel + 'static,
60{
61    fn logging_on(&self, category: <M as UserModel>::LoggingCategory) -> bool {
62        matches!(self.logging_on.get(&category), Some(true))
63    }
64
65    fn set_logging(&mut self, category: <M as UserModel>::LoggingCategory, enabled: bool) {
66        self.logging_on.insert(category, enabled);
67    }
68
69    /// Log a message if the specified logging category is enabled.
70    fn log(&self, status: Fmi3Status, category: M::LoggingCategory, args: std::fmt::Arguments<'_>) {
71        if self.logging_on(category) {
72            // Call the logging callback
73            (self.log_message)(status, &category.to_string(), args);
74        } else {
75            eprintln!("Logging disabled for category: {}", category);
76        }
77    }
78
79    /// Get the path to the resources directory.
80    fn resource_path(&self) -> &PathBuf {
81        &self.resource_path
82    }
83
84    fn initialize(&mut self, start_time: f64, stop_time: Option<f64>) {
85        self.time = start_time;
86        self.stop_time = stop_time;
87    }
88
89    fn time(&self) -> f64 {
90        self.time
91    }
92
93    fn set_time(&mut self, time: f64) {
94        self.time = time;
95    }
96
97    fn stop_time(&self) -> Option<f64> {
98        self.stop_time
99    }
100
101    fn early_return_allowed(&self) -> bool {
102        self.early_return_allowed
103    }
104
105    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
106        self
107    }
108}