1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! FMI 2.0 API
pub mod import;
pub mod instance;
// Re-export
pub use fmi_schema::fmi2 as schema;
#[doc = "Autogenerated bindings for the FMI 2.0 API"]
pub use fmi_sys::fmi2 as binding;
use crate::traits::FmiStatus;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct CallbackFunctions {
pub logger: binding::fmi2CallbackLogger,
pub allocate_memory: binding::fmi2CallbackAllocateMemory,
pub free_memory: binding::fmi2CallbackFreeMemory,
pub step_finished: binding::fmi2StepFinished,
pub component_environment: binding::fmi2ComponentEnvironment,
}
#[repr(C)]
#[derive(Debug)]
pub enum StatusKind {
/// Can be called when the fmi2DoStep function returned fmi2Pending. The function delivers
/// fmi2Pending if the computation is not finished. Otherwise the function returns the result
/// of the asynchronously executed fmi2DoStep call
DoStepStatus = binding::fmi2StatusKind_fmi2DoStepStatus as _,
/// Can be called when the fmi2DoStep function returned fmi2Pending. The function delivers a
/// string which informs about the status of the currently running asynchronous fmi2DoStep
/// computation.
PendingStatus = binding::fmi2StatusKind_fmi2PendingStatus as _,
/// Returns the end time of the last successfully completed communication step. Can be called
/// after fmi2DoStep(...) returned fmi2Discard.
LastSuccessfulTime = binding::fmi2StatusKind_fmi2LastSuccessfulTime as _,
/// Returns true, if the slave wants to terminate the simulation. Can be called after
/// fmi2DoStep(...) returned fmi2Discard. Use fmi2LastSuccessfulTime to determine the time
/// instant at which the slave terminated
Terminated = binding::fmi2StatusKind_fmi2Terminated as _,
}
#[derive(Debug)]
pub enum Fmi2Res {
/// All well
OK,
/// Things are not quite right, but the computation can continue. Function “logger” was called
/// in the model (see below), and it is expected that this function has shown the prepared
/// information message to the user.
Warning,
/// This status is returned only from the co-simulation interface, if the slave executes the
/// function in an asynchronous way. That means the slave starts to compute but returns
/// immediately.
///
/// The master has to call [`crate::fmi2::instance::CoSimulation::do_step_status`] to
/// determine if the slave has finished the computation. Can be returned only by
/// [`crate::fmi2::instance::CoSimulation::do_step`] and by
/// [`crate::fmi2::instance::CoSimulation::do_step_status`].
Pending,
}
#[derive(Debug, thiserror::Error)]
pub enum Fmi2Error {
#[error("TypesPlatform of loaded API ({0}) doesn't match expected (default)")]
TypesPlatformMismatch(String),
/// For “model exchange”: It is recommended to perform a smaller step size and evaluate the
/// model equations again, for example because an iterative solver in the model did not
/// converge or because a function is outside of its domain (for example sqrt(\<negative
/// number\>)). If this is not possible, the simulation has to be terminated.
///
/// For “co-simulation”: [`Fmi2Error::Discard`] is returned also if the slave is not able to
/// return the required status information. The master has to decide if the simulation run
/// can be continued.
///
/// In both cases, function “logger” was called in the FMU (see below) and it is expected that
/// this function has shown the prepared information message to the user if the FMU was
/// called in debug mode (loggingOn = true). Otherwise, “logger” should not show a message.
#[error("Discard")]
Discard,
/// The FMU encountered an error. The simulation cannot be continued with this FMU instance. If
/// one of the functions returns [`Fmi2Error::Error`], it can be tried to restart the
/// simulation from a formerly stored FMU state by
/// calling [`crate::fmi2::instance::Instance::set_fmu_state`]. This can be done if the capability
/// flag `can_get_and_set_fmu_state` is true and
/// [`crate::fmi2::instance::Instance::get_fmu_state`] was called before in non-erroneous state. If
/// not, the simulation cannot be continued and [`crate::fmi2::instance::Common::reset`] must be
/// called afterwards.
#[error("Error")]
Error,
/// The model computations are irreparably corrupted for all FMU instances.
#[error("Fatal")]
Fatal,
}
#[derive(Debug)]
pub struct Fmi2Status(binding::fmi2Status);
impl FmiStatus for Fmi2Status {
type Res = Fmi2Res;
type Err = Fmi2Error;
/// Convert to [`Result<Fmi2Res, Fmi2Error>`]
#[inline]
fn ok(self) -> Result<Fmi2Res, Fmi2Error> {
self.into()
}
#[inline]
fn is_error(&self) -> bool {
self.0 == binding::fmi2Status_fmi2Error || self.0 == binding::fmi2Status_fmi2Fatal
}
}
impl From<binding::fmi2Status> for Fmi2Status {
fn from(status: binding::fmi2Status) -> Self {
Self(status)
}
}
impl From<Fmi2Status> for Result<Fmi2Res, Fmi2Error> {
fn from(Fmi2Status(status): Fmi2Status) -> Self {
match status {
binding::fmi2Status_fmi2OK => Ok(Fmi2Res::OK),
binding::fmi2Status_fmi2Warning => Ok(Fmi2Res::Warning),
binding::fmi2Status_fmi2Discard => Err(Fmi2Error::Discard),
binding::fmi2Status_fmi2Error => Err(Fmi2Error::Error),
binding::fmi2Status_fmi2Fatal => Err(Fmi2Error::Fatal),
_ => unreachable!("Invalid status"),
}
}
}