use crate::traits::FmiInterfaceType;
use super::Annotations;
#[derive(Default, PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
#[xml(tag = "ModelExchange", strict(unknown_attribute, unknown_element))]
pub struct Fmi3ModelExchange {
#[xml(child = "Annotations")]
pub annotations: Option<Annotations>,
#[xml(attr = "modelIdentifier")]
pub model_identifier: String,
#[xml(attr = "needsExecutionTool")]
pub needs_execution_tool: Option<bool>,
#[xml(attr = "canBeInstantiatedOnlyOncePerProcess")]
pub can_be_instantiated_only_once_per_process: Option<bool>,
#[xml(attr = "canGetAndSetFMUState")]
pub can_get_and_set_fmu_state: Option<bool>,
#[xml(attr = "canSerializeFMUState")]
pub can_serialize_fmu_state: Option<bool>,
#[xml(attr = "providesDirectionalDerivatives")]
pub provides_directional_derivatives: Option<bool>,
#[xml(attr = "providesAdjointDerivatives")]
pub provides_adjoint_derivatives: Option<bool>,
#[xml(attr = "providesPerElementDependencies")]
pub provides_per_element_dependencies: Option<bool>,
#[xml(attr = "needsCompletedIntegratorStep")]
pub needs_completed_integrator_step: Option<bool>,
#[xml(attr = "providesEvaluateDiscreteStates")]
pub provides_evaluate_discrete_states: Option<bool>,
}
#[derive(Default, PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
#[xml(tag = "CoSimulation", strict(unknown_attribute, unknown_element))]
pub struct Fmi3CoSimulation {
#[xml(child = "Annotations")]
pub annotations: Option<Annotations>,
#[xml(attr = "modelIdentifier")]
pub model_identifier: String,
#[xml(attr = "needsExecutionTool")]
pub needs_execution_tool: Option<bool>,
#[xml(attr = "canBeInstantiatedOnlyOncePerProcess")]
pub can_be_instantiated_only_once_per_process: Option<bool>,
#[xml(attr = "canGetAndSetFMUState")]
pub can_get_and_set_fmu_state: Option<bool>,
#[xml(attr = "canSerializeFMUState")]
pub can_serialize_fmu_state: Option<bool>,
#[xml(attr = "providesDirectionalDerivatives")]
pub provides_directional_derivatives: Option<bool>,
#[xml(attr = "providesAdjointDerivatives")]
pub provides_adjoint_derivatives: Option<bool>,
#[xml(attr = "providesPerElementDependencies")]
pub provides_per_element_dependencies: Option<bool>,
#[xml(attr = "canHandleVariableCommunicationStepSize")]
pub can_handle_variable_communication_step_size: Option<bool>,
#[xml(attr = "fixedInternalStepSize")]
pub fixed_internal_step_size: Option<f64>,
#[xml(attr = "maxOutputDerivativeOrder")]
pub max_output_derivative_order: Option<u32>,
#[xml(attr = "recommendedIntermediateInputSmoothness")]
pub recommended_intermediate_input_smoothness: Option<i32>,
#[xml(attr = "providesIntermediateUpdate")]
pub provides_intermediate_update: Option<bool>,
#[xml(attr = "mightReturnEarlyFromDoStep")]
pub might_return_early_from_do_step: Option<bool>,
#[xml(attr = "canReturnEarlyAfterIntermediateUpdate")]
pub can_return_early_after_intermediate_update: Option<bool>,
#[xml(attr = "hasEventMode")]
pub has_event_mode: Option<bool>,
#[xml(attr = "providesEvaluateDiscreteStates")]
pub provides_evaluate_discrete_states: Option<bool>,
}
#[derive(Default, PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
#[xml(tag = "ScheduledExecution", strict(unknown_attribute, unknown_element))]
pub struct Fmi3ScheduledExecution {
#[xml(child = "Annotations")]
pub annotations: Option<Annotations>,
#[xml(attr = "modelIdentifier")]
pub model_identifier: String,
#[xml(attr = "needsExecutionTool")]
pub needs_execution_tool: Option<bool>,
#[xml(attr = "canBeInstantiatedOnlyOncePerProcess")]
pub can_be_instantiated_only_once_per_process: Option<bool>,
#[xml(attr = "canGetAndSetFMUState")]
pub can_get_and_set_fmu_state: Option<bool>,
#[xml(attr = "canSerializeFMUState")]
pub can_serialize_fmu_state: Option<bool>,
#[xml(attr = "providesDirectionalDerivatives")]
pub provides_directional_derivatives: Option<bool>,
#[xml(attr = "providesAdjointDerivatives")]
pub provides_adjoint_derivatives: Option<bool>,
#[xml(attr = "providesPerElementDependencies")]
pub provides_per_element_dependencies: Option<bool>,
}
macro_rules! impl_fmi_interface_type {
($name:ident) => {
impl FmiInterfaceType for $name {
fn model_identifier(&self) -> &str {
&self.model_identifier
}
fn needs_execution_tool(&self) -> Option<bool> {
self.needs_execution_tool
}
fn can_be_instantiated_only_once_per_process(&self) -> Option<bool> {
self.can_be_instantiated_only_once_per_process
}
fn can_get_and_set_fmu_state(&self) -> Option<bool> {
self.can_get_and_set_fmu_state
}
fn can_serialize_fmu_state(&self) -> Option<bool> {
self.can_serialize_fmu_state
}
fn provides_directional_derivatives(&self) -> Option<bool> {
self.provides_directional_derivatives
}
fn provides_adjoint_derivatives(&self) -> Option<bool> {
self.provides_adjoint_derivatives
}
fn provides_per_element_dependencies(&self) -> Option<bool> {
self.provides_per_element_dependencies
}
}
};
}
impl_fmi_interface_type!(Fmi3ModelExchange);
impl_fmi_interface_type!(Fmi3CoSimulation);
impl_fmi_interface_type!(Fmi3ScheduledExecution);
#[cfg(test)]
mod tests {
use super::*;
use hard_xml::{XmlRead, XmlWrite};
#[test]
fn test_model_exchange_roundtrip() {
let xml = r#"<ModelExchange modelIdentifier="test" needsCompletedIntegratorStep="true" providesEvaluateDiscreteStates="false"/>"#;
let me = Fmi3ModelExchange::from_str(xml).unwrap();
assert_eq!(me.model_identifier, "test");
assert_eq!(me.needs_completed_integrator_step, Some(true));
assert_eq!(me.provides_evaluate_discrete_states, Some(false));
let xml_out = me.to_string().unwrap();
let me2 = Fmi3ModelExchange::from_str(&xml_out).unwrap();
assert_eq!(me, me2);
}
#[test]
fn test_co_simulation_attributes() {
let xml = r#"<CoSimulation modelIdentifier="test" canHandleVariableCommunicationStepSize="true" hasEventMode="false"/>"#;
let cs = Fmi3CoSimulation::from_str(xml).unwrap();
assert_eq!(cs.model_identifier, "test");
assert_eq!(cs.can_handle_variable_communication_step_size, Some(true));
assert_eq!(cs.has_event_mode, Some(false));
}
#[test]
fn test_scheduled_execution_basic() {
let xml = r#"<ScheduledExecution modelIdentifier="test"/>"#;
let se = Fmi3ScheduledExecution::from_str(xml).unwrap();
assert_eq!(se.model_identifier, "test");
}
#[test]
fn test_fmi_interface_type_trait() {
let me = Fmi3ModelExchange {
model_identifier: "test".to_string(),
needs_execution_tool: Some(true),
can_get_and_set_fmu_state: Some(false),
..Default::default()
};
assert_eq!(me.model_identifier(), "test");
assert_eq!(me.needs_execution_tool(), Some(true));
assert_eq!(me.can_get_and_set_fmu_state(), Some(false));
}
}