Skip to main content

fmi_sim/
lib.rs

1#![doc=include_str!( "../README.md")]
2//! ## Feature flags
3#![doc = document_features::document_features!()]
4#![deny(unsafe_code)]
5#![deny(clippy::all)]
6
7use arrow::array::RecordBatch;
8use fmi::schema::{MajorVersion, traits::FmiModelDescription};
9use sim::SimStats;
10
11pub mod options;
12pub mod sim;
13
14/// Sim error
15#[derive(Debug, thiserror::Error)]
16pub enum Error {
17    #[error(transparent)]
18    FmiError(#[from] fmi::Error),
19
20    #[error(transparent)]
21    SolverError(#[from] sim::solver::SolverError),
22
23    #[error(transparent)]
24    ArrowError(#[from] arrow::error::ArrowError),
25
26    #[error(transparent)]
27    Other(#[from] anyhow::Error),
28}
29
30/// Simulate an FMI model parameterized by the given top-level options.
31///
32/// # Returns
33/// A tuple of the record batch of the simulation results and the statistics of the simulation.
34pub fn simulate(options: &options::FmiSimOptions) -> Result<(RecordBatch, SimStats), Error> {
35    let mini_descr = fmi::import::peek_descr_path(&options.model)?;
36    let version = mini_descr.major_version().map_err(fmi::Error::from)?;
37
38    log::debug!("Loaded {mini_descr:?}");
39
40    // Read optional input data
41    let input_data = options
42        .input_file
43        .as_ref()
44        .inspect(|p| log::debug!("Reading input data from {}", p.display()))
45        .map(sim::util::read_csv_file)
46        .transpose()?;
47
48    match version {
49        MajorVersion::FMI1 => Err(fmi::Error::UnsupportedFmiVersion(version).into()),
50
51        #[cfg(feature = "fmi2")]
52        MajorVersion::FMI2 => {
53            let import: fmi::fmi2::import::Fmi2Import = fmi::import::from_path(&options.model)?;
54
55            // Register FMU log categories for proper filtering
56            //if let Some(log_categories) = &import.model_description().log_categories {
57            //    let category_names = log_categories.categories.iter()
58            //        .map(|cat| cat.name.clone())
59            //        .collect::<Vec<_>>();
60            //    crate::logging::register_fmu_log_categories(category_names);
61            //}
62
63            sim::simulate_with(input_data, &options.interface, import)
64        }
65
66        #[cfg(feature = "fmi3")]
67        MajorVersion::FMI3 => {
68            let import: fmi::fmi3::import::Fmi3Import = fmi::import::from_path(&options.model)?;
69
70            // Register FMU log categories for proper filtering
71            //if let Some(log_categories) = &import.model_description().log_categories {
72            //    let category_names = log_categories.categories.iter()
73            //        .map(|cat| cat.name.clone())
74            //        .collect::<Vec<_>>();
75            //    crate::logging::register_fmu_log_categories(category_names);
76            //}
77
78            sim::simulate_with(input_data, &options.interface, import)
79        }
80    }
81}