From 0021224254bd6033052432b61d5c27a4cff52f06 Mon Sep 17 00:00:00 2001 From: Peter Meisrimel Date: Tue, 3 Dec 2024 17:11:05 +0100 Subject: [PATCH] WIP; first go at adding FMI import --- MANIFEST.in | 2 + setup.py | 10 +- src/pyfmi/fmi.pxd | 2 +- src/pyfmi/fmi.pyx | 86 ++++- src/pyfmi/fmi3/__init__.py | 16 + src/pyfmi/fmi3/fmi3.pxd | 82 ++++ src/pyfmi/fmi3/fmi3.pyx | 636 ++++++++++++++++++++++++++++++++ src/pyfmi/fmi3/fmil3_import.pxd | 615 ++++++++++++++++++++++++++++++ src/pyfmi/fmil_import.pxd | 3 +- 9 files changed, 1441 insertions(+), 11 deletions(-) create mode 100644 src/pyfmi/fmi3/__init__.py create mode 100644 src/pyfmi/fmi3/fmi3.pxd create mode 100644 src/pyfmi/fmi3/fmi3.pyx create mode 100644 src/pyfmi/fmi3/fmil3_import.pxd diff --git a/MANIFEST.in b/MANIFEST.in index 8aaaf77e..f07b6d31 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,4 +2,6 @@ include CHANGELOG include LICENSE include src/pyfmi/*.pyx include src/pyfmi/*.pxd +include src/pyfmi/fmi3/*.pyx +include src/pyfmi/fmi3/*.pxd exclude src/pyfmi/*.dll diff --git a/setup.py b/setup.py index 0361e316..29ec21d9 100644 --- a/setup.py +++ b/setup.py @@ -214,7 +214,10 @@ def check_extensions(): ext_list[-1].extra_compile_args = ["-O2", "-fno-strict-aliasing"] ext_list[-1].extra_link_args = extra_link_flags """ - incl_path = [".", "src", os.path.join("src", "pyfmi")] + incl_path = [".", + "src", + os.path.join("src", "pyfmi"), + os.path.join("src", "pyfmi", "fmi3")] #FMI PYX ext_list += cythonize([os.path.join("src", "pyfmi", "fmi.pyx")], include_path = incl_path, @@ -251,6 +254,11 @@ def check_extensions(): ext_list += cythonize([os.path.join("src", "pyfmi", "test_util.pyx")], include_path = incl_path, compiler_directives={'language_level' : "3str"}) + + # FMI3 + ext_list += cythonize([os.path.join("src", "pyfmi", "fmi3", "fmi3.pyx")], + include_path = incl_path, + compiler_directives={'language_level' : "3str"}) for i in range(len(ext_list)): diff --git a/src/pyfmi/fmi.pxd b/src/pyfmi/fmi.pxd index ddd81781..e83bd344 100644 --- a/src/pyfmi/fmi.pxd +++ b/src/pyfmi/fmi.pxd @@ -51,7 +51,7 @@ cdef class ScalarVariable: """ cdef object _name cdef FMIL.fmi1_value_reference_t _value_reference - cdef object _description #A characater pointer but we need an own reference and this is sufficient + cdef object _description #A character pointer but we need an own reference and this is sufficient cdef FMIL.fmi1_base_type_enu_t _type cdef FMIL.fmi1_variability_enu_t _variability cdef FMIL.fmi1_causality_enu_t _causality diff --git a/src/pyfmi/fmi.pyx b/src/pyfmi/fmi.pyx index 3fb043ec..387bb633 100644 --- a/src/pyfmi/fmi.pyx +++ b/src/pyfmi/fmi.pyx @@ -40,6 +40,10 @@ cimport numpy as np from numpy cimport PyArray_DATA cimport pyfmi.fmil_import as FMIL +cimport pyfmi.fmi3.fmil3_import as FMIL3 + +# TODO: This looks a bit stupid +from pyfmi.fmi3.fmi3 cimport FMUModelCS3, FMUModelME3 from pyfmi.common.core import create_temp_dir @@ -8783,8 +8787,10 @@ def load_fmu(fmu, log_file_name = "", kind = 'auto', cdef FMIL.fmi_version_enu_t version cdef FMIL.fmi1_import_t* fmu_1 = NULL cdef FMIL.fmi2_import_t* fmu_2 = NULL + cdef FMIL3.fmi3_import_t* fmu_3 = NULL cdef FMIL.fmi1_fmu_kind_enu_t fmu_1_kind cdef FMIL.fmi2_fmu_kind_enu_t fmu_2_kind + cdef FMIL3.fmi3_fmu_kind_enu_t fmu_3_kind cdef list log_data = [] #Variables for deallocation @@ -8795,6 +8801,7 @@ def load_fmu(fmu, log_file_name = "", kind = 'auto', check_fmu_args(allow_unzipped_fmu, fmu, fmu_full_path) #Check that kind-argument is well-defined + # TODO: FMI3: SE if not kind.lower() == 'auto': if (kind.upper() != 'ME' and kind.upper() != 'CS'): raise FMUException('Input-argument "kind" can only be "ME", "CS" or "auto" (default) and not: ' + kind) @@ -8838,7 +8845,7 @@ def load_fmu(fmu, log_file_name = "", kind = 'auto', _handle_load_fmu_exception(fmu, log_data) raise InvalidVersionException("The FMU could not be loaded. The FMU version could not be determined. Enable logging for possibly more information.") - if version > 2: + if version >= FMIL.fmi_version_unsupported_enu: #Delete the context last_error = FMIL.jm_get_last_error(&callbacks) FMIL.fmi_import_free_context(context) @@ -8873,10 +8880,10 @@ def load_fmu(fmu, log_file_name = "", kind = 'auto', #Compare fmu_kind with input-specified kind if fmu_1_kind == FMI_ME and kind.upper() != 'CS': - model=FMUModelME1(fmu, log_file_name,log_level, _unzipped_dir=fmu_temp_dir, + model=FMUModelME1(fmu, log_file_name,log_level, _unzipped_dir = fmu_temp_dir, allow_unzipped_fmu = allow_unzipped_fmu) elif (fmu_1_kind == FMI_CS_STANDALONE or fmu_1_kind == FMI_CS_TOOL) and kind.upper() != 'ME': - model=FMUModelCS1(fmu, log_file_name,log_level, _unzipped_dir=fmu_temp_dir, + model=FMUModelCS1(fmu, log_file_name,log_level, _unzipped_dir = fmu_temp_dir, allow_unzipped_fmu = allow_unzipped_fmu) else: FMIL.fmi1_import_free(fmu_1) @@ -8922,18 +8929,18 @@ def load_fmu(fmu, log_file_name = "", kind = 'auto', #FMU kind is known if kind.lower() == 'auto': if fmu_2_kind == FMIL.fmi2_fmu_kind_cs: - model = FMUModelCS2(fmu, log_file_name,log_level, _unzipped_dir=fmu_temp_dir, + model = FMUModelCS2(fmu, log_file_name,log_level, _unzipped_dir = fmu_temp_dir, allow_unzipped_fmu = allow_unzipped_fmu) elif fmu_2_kind == FMIL.fmi2_fmu_kind_me or fmu_2_kind == FMIL.fmi2_fmu_kind_me_and_cs: - model = FMUModelME2(fmu, log_file_name,log_level, _unzipped_dir=fmu_temp_dir, + model = FMUModelME2(fmu, log_file_name,log_level, _unzipped_dir = fmu_temp_dir, allow_unzipped_fmu = allow_unzipped_fmu) elif kind.upper() == 'CS': if fmu_2_kind == FMIL.fmi2_fmu_kind_cs or fmu_2_kind == FMIL.fmi2_fmu_kind_me_and_cs: - model = FMUModelCS2(fmu, log_file_name,log_level, _unzipped_dir=fmu_temp_dir, + model = FMUModelCS2(fmu, log_file_name,log_level, _unzipped_dir = fmu_temp_dir, allow_unzipped_fmu = allow_unzipped_fmu) elif kind.upper() == 'ME': if fmu_2_kind == FMIL.fmi2_fmu_kind_me or fmu_2_kind == FMIL.fmi2_fmu_kind_me_and_cs: - model = FMUModelME2(fmu, log_file_name,log_level, _unzipped_dir=fmu_temp_dir, + model = FMUModelME2(fmu, log_file_name,log_level, _unzipped_dir = fmu_temp_dir, allow_unzipped_fmu = allow_unzipped_fmu) #Could not match FMU kind with input-specified kind @@ -8943,7 +8950,65 @@ def load_fmu(fmu, log_file_name = "", kind = 'auto', if not allow_unzipped_fmu: FMIL.fmi_import_rmdir(&callbacks, fmu_temp_dir) _handle_load_fmu_exception(fmu, log_data) - raise FMUException("FMU is a {} and not a {}".format(decode(FMIL.fmi2_fmu_kind_to_string(fmu_2_kind)), decode(kind.upper()))) + raise FMUException("FMU is a {} and not a {}".format(decode(FMIL.fmi2_fmu_kind_to_string(fmu_2_kind)), decode(kind.upper()))) + + elif version == FMIL.fmi_version_3_0_enu: + #Check fmu-kind and compare with input-specified kind + fmu_3 = FMIL3.fmi3_import_parse_xml(context, fmu_temp_dir, NULL) + + if fmu_3 is NULL: + #Delete the context + last_error = FMIL.jm_get_last_error(&callbacks) + FMIL.fmi_import_free_context(context) + if not allow_unzipped_fmu: + FMIL.fmi_import_rmdir(&callbacks, fmu_temp_dir) + if callbacks.log_level >= FMIL.jm_log_level_error: + _handle_load_fmu_exception(fmu, log_data) + raise InvalidXMLException("The FMU could not be loaded. The model data from 'modelDescription.xml' within the FMU could not be read. "+decode(last_error)) + else: + _handle_load_fmu_exception(fmu, log_data) + raise InvalidXMLException("The FMU could not be loaded. The model data from 'modelDescription.xml' within the FMU could not be read. Enable logging for possible nore information.") + + fmu_3_kind = FMIL3.fmi3_import_get_fmu_kind(fmu_3) + + #FMU kind is unknown + if fmu_3_kind == FMIL3.fmi3_fmu_kind_unknown: + last_error = FMIL.jm_get_last_error(&callbacks) + FMIL3.fmi3_import_free(fmu_3) + FMIL.fmi_import_free_context(context) + if not allow_unzipped_fmu: + FMIL.fmi_import_rmdir(&callbacks, fmu_temp_dir) + if callbacks.log_level >= FMIL.jm_log_level_error: + _handle_load_fmu_exception(fmu, log_data) + raise FMUException("The FMU kind could not be determined. "+decode(last_error)) + else: + _handle_load_fmu_exception(fmu, log_data) + raise FMUException("The FMU kind could not be determined. Enable logging for possibly more information.") + + #FMU kind is known + if kind.lower() == 'auto': + if fmu_3_kind & FMIL3.fmi3_fmu_kind_me: + model = FMUModelME3(fmu, log_file_name, log_level, _unzipped_dir = fmu_temp_dir, + allow_unzipped_fmu = allow_unzipped_fmu) + elif fmu_3_kind & FMIL3.fmi3_fmu_kind_cs: + model = FMUModelCS3(fmu, log_file_name, log_level, _unzipped_dir = fmu_temp_dir, + allow_unzipped_fmu = allow_unzipped_fmu) + # TODO: else: SE + elif kind.upper() == 'CS': + model = FMUModelCS3(fmu, log_file_name, log_level, _unzipped_dir = fmu_temp_dir, + allow_unzipped_fmu = allow_unzipped_fmu) + elif kind.upper() == 'ME': + model = FMUModelME3(fmu, log_file_name, log_level, _unzipped_dir = fmu_temp_dir, + allow_unzipped_fmu = allow_unzipped_fmu) + + #Could not match FMU kind with input-specified kind + if model is None: + FMIL3.fmi3_import_free(fmu_3) + FMIL.fmi_import_free_context(context) + if not allow_unzipped_fmu: + FMIL.fmi_import_rmdir(&callbacks, fmu_temp_dir) + _handle_load_fmu_exception(fmu, log_data) + raise FMUException("FMU is a {} and not a {}".format(decode(FMIL3.fmi3_fmu_kind_to_string(fmu_3_kind)), decode(kind.upper()))) else: #This else-statement ensures that the variables "context" and "version" are defined before proceeding @@ -8971,6 +9036,11 @@ def load_fmu(fmu, log_file_name = "", kind = 'auto', FMIL.fmi_import_free_context(context) #FMIL.fmi_import_rmdir(&callbacks, fmu_temp_dir) + if version == FMIL.fmi_version_3_0_enu: + FMIL3.fmi3_import_free(fmu_3) + FMIL.fmi_import_free_context(context) + #FMIL.fmi_import_rmdir(&callbacks, fmu_temp_dir) + return model diff --git a/src/pyfmi/fmi3/__init__.py b/src/pyfmi/fmi3/__init__.py new file mode 100644 index 00000000..8962836d --- /dev/null +++ b/src/pyfmi/fmi3/__init__.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (C) 2024 Modelon AB +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . diff --git a/src/pyfmi/fmi3/fmi3.pxd b/src/pyfmi/fmi3/fmi3.pxd new file mode 100644 index 00000000..9f9d49e0 --- /dev/null +++ b/src/pyfmi/fmi3/fmi3.pxd @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (C) 2024 Modelon AB +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +""" +Module containing the FMI3 interface Python wrappers. +""" +import numpy as np +cimport numpy as np + +from pyfmi.fmi cimport ModelBase, WorkerClass2 +cimport pyfmi.fmil_import as FMIL +cimport pyfmi.fmi3.fmil3_import as FMIL3 + +cdef class FMUModelBase3(ModelBase): + """FMI3 Model loaded from a dll.""" + # FMIL related variables + cdef FMIL.fmi_import_context_t* _context + # cdef FMIL3.fmi3_callback_functions_t callBackFunctions # TODO: const? + cdef FMIL3.fmi3_import_t* _fmu + cdef FMIL3.fmi3_fmu_kind_enu_t _fmu_kind + cdef FMIL.fmi_version_enu_t _version # TODO: To BASE? + cdef FMIL3.fmi3_instance_environment_t _instance_environment # TODO: What is this meant to do? # TODO: const? + cdef FMIL3.fmi3_log_message_callback_ft _log_message # TODO + # cdef FMIL.jm_string last_error + # cdef FMIL.size_t _nEventIndicators + # cdef FMIL.size_t _nContinuousStates + # cdef FMIL.fmi2_event_info_t _eventInfo + + # Internal values + # cdef public float _last_accepted_time, _relative_tolerance + cdef double time + cdef object _fmu_full_path + cdef public object _enable_logging + cdef int _allow_unzipped_fmu # TODO: Move to FMUBase? + cdef int _allocated_dll, _allocated_context, _allocated_xml, _allocated_fmu, _initialized_fmu + cdef object _modelName + # cdef public list _save_real_variables_val + # cdef public list _save_int_variables_val + # cdef public list _save_bool_variables_val + cdef object _t + # cdef public object _pyEventInfo + cdef char* _fmu_temp_dir + # cdef object _states_references + # cdef object _inputs_references + # cdef object _outputs_references + # cdef object _derivatives_references + # cdef object _derivatives_states_dependencies + # cdef object _derivatives_inputs_dependencies + # cdef object _derivatives_states_dependencies_kind + # cdef object _derivatives_inputs_dependencies_kind + # cdef object _outputs_states_dependencies + # cdef object _outputs_inputs_dependencies + # cdef object _outputs_states_dependencies_kind + # cdef object _outputs_inputs_dependencies_kind + # cdef object _A, _B, _C, _D + # cdef public object _group_A, _group_B, _group_C, _group_D + # cdef object _mask_A + # cdef object _A_row_ind, _A_col_ind + cdef public object _has_entered_init_mode + # cdef WorkerClass2 _worker_object + +cdef class FMUModelCS3(FMUModelBase3): + """FMI3 CoSimulation Model loaded from a dll.""" + pass + +cdef class FMUModelME3(FMUModelBase3): + """FMI3 ModelExchange Model loaded from a dll.""" + pass diff --git a/src/pyfmi/fmi3/fmi3.pyx b/src/pyfmi/fmi3/fmi3.pyx new file mode 100644 index 00000000..0c2efbaf --- /dev/null +++ b/src/pyfmi/fmi3/fmi3.pyx @@ -0,0 +1,636 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (C) 2024 Modelon AB +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +# distutils: define_macros=NPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION + +import os +import logging + +# TODO: Status comparisons should actually use the FMIL.jm_status_enum + +from pyfmi.fmi cimport ( + ModelBase, + # WorkerClass2, + import_and_get_version, + # FMUException, + # check_fmu_args, + # create_temp_dir, + # InvalidVersionException +) +# TODO: cyclic dependencies right here +# from pyfmi.fmi import ( +# # PyEventInfo, +# FMUException, +# check_fmu_args, +# create_temp_dir, +# InvalidVersionException, +# # InvalidBinaryException, +# # InvalidXMLException, +# ) +cimport pyfmi.fmil_import as FMIL +cimport pyfmi.fmi3.fmil3_import as FMIL3 + +from pyfmi.common.core import create_temp_dir + +from pyfmi.fmi_util cimport encode, decode + +# Should use the same variable as in fmi.pyx +FMI_DEFAULT_LOG_LEVEL = FMIL.jm_log_level_error + +#CALLBACKS +cdef void importlogger3(FMIL.jm_callbacks* c, FMIL.jm_string module, FMIL.jm_log_level_enu_t log_level, FMIL.jm_string message): + if c.context != NULL: + (c.context)._logger(module, log_level, message) + +# XXX: These shouldn't be here, but otherwise we get cyclic dependencies of fmi.pyx & fmi3.pyx +class FMUException(Exception): + pass +class InvalidFMUException(FMUException): + pass +class InvalidXMLException(InvalidFMUException): + pass +class InvalidBinaryException(InvalidFMUException): + pass +class InvalidVersionException(InvalidFMUException): + pass + +# XXX: These shouldn't be here, but otherwise we get cyclic dependencies of fmi.pyx & fmi3.pyx +def check_fmu_args(allow_unzipped_fmu, fmu, fmu_full_path): + """ Function utilized by two base classes and load_fmu that does the + error checking for the three input arguments named 'allow_unzipped_fmu', 'fmu' and + the constructed variable 'fmu_full_path'. + """ + if allow_unzipped_fmu: + if not os.path.isdir(fmu): + msg = "Argument named 'fmu' must be a directory if argument 'allow_unzipped_fmu' is set to True." + raise FMUException(msg) + if not os.path.isfile(os.path.join(fmu, 'modelDescription.xml')): + err_msg = "Specified fmu path '{}' needs".format(fmu) + err_msg += " to contain a modelDescription.xml according to the FMI specification." + raise FMUException(err_msg) + else: + # Check that the file referenced by fmu is appropriate + if not fmu_full_path.endswith('.fmu' if isinstance(fmu_full_path, str) else encode('.fmu')): + raise FMUException("Instantiating an FMU requires an FMU (.fmu) file, specified file has extension {}".format(os.path.splitext(fmu_full_path)[1])) + + if not os.path.isfile(fmu_full_path): + raise FMUException('Could not locate the FMU in the specified directory.') + + +cdef class FMUModelBase3(ModelBase): + """ + FMI Model loaded from a dll. + """ + def __init__(self, fmu, log_file_name = "", log_level = FMI_DEFAULT_LOG_LEVEL, + _unzipped_dir = None, _connect_dll = True, allow_unzipped_fmu = False): + """ + Constructor of the model. + + Parameters:: + + fmu -- + Name of the fmu as a string. + + log_file_name -- + Filename for file used to save log messages. + This argument can also be a stream if it supports 'write', for full functionality + it must also support 'seek' and 'readlines'. If the stream requires use of other methods, such as 'drain' + for asyncio-streams, then this needs to be implemented on the user-side, there is no additional methods invoked + on the stream instance after 'write' has been invoked on the PyFMI side. + The stream must also be open and writable during the entire time. + Default: "" (Generates automatically) + + log_level -- + Determines the logging output. Can be set between 0 + (no logging) and 7 (everything). + Default: 2 (log error messages) + allow_unzipped_fmu -- + If set to True, the argument 'fmu' can be a path specifying a directory + to an unzipped FMU. The structure of the unzipped FMU must conform + to the FMI specification. + Default: False + + Returns:: + + A model as an object from the class FMUModelFMU3 + """ + + cdef int status + cdef dict reals_continuous + cdef dict reals_discrete + cdef dict int_discrete + cdef dict bool_discrete + + #Call super + ModelBase.__init__(self) + + #Contains the log information + self._log = [] + + #Used for deallocation + self._allocated_context = 0 + self._allocated_dll = 0 + self._allocated_xml = 0 + self._allocated_fmu = 0 + self._initialized_fmu = 0 + self._fmu_temp_dir = NULL + self._fmu_log_name = NULL + + # Used to adjust behavior if FMU is unzipped + self._allow_unzipped_fmu = 1 if allow_unzipped_fmu else 0 + + #Default values + # self._t = None + # self._A = None + # self._group_A = None + # self._mask_A = None + # self._B = None + # self._group_B = None + # self._C = None + # self._group_C = None + # self._D = None + # self._group_D = None + # self._states_references = None + # self._derivatives_references = None + # self._outputs_references = None + # self._inputs_references = None + # self._derivatives_states_dependencies = None + # self._derivatives_inputs_dependencies = None + # self._outputs_states_dependencies = None + # self._outputs_inputs_dependencies = None + # self._has_entered_init_mode = False + # self._last_accepted_time = 0.0 + + #Internal values + # self._pyEventInfo = PyEventInfo() + # self._worker_object = WorkerClass2() + + #Specify the general callback functions + self.callbacks.malloc = FMIL.malloc + self.callbacks.calloc = FMIL.calloc + self.callbacks.realloc = FMIL.realloc + self.callbacks.free = FMIL.free + self.callbacks.logger = importlogger3 + self.callbacks.context = self + + #Specify FMI3 related callbacks + # self.callBackFunctions.logger = FMIL3.fmi3_log_forwarding + # self.callBackFunctions.allocateMemory = FMIL.calloc + # self.callBackFunctions.freeMemory = FMIL.free + # self.callBackFunctions.stepFinished = NULL + # self.callBackFunctions.componentEnvironment = NULL + + self._instance_environment = NULL # TODO + self._log_message = NULL # TODO + + if log_level >= FMIL.jm_log_level_nothing and log_level <= FMIL.jm_log_level_all: + if log_level == FMIL.jm_log_level_nothing: + enable_logging = False + else: + enable_logging = True + self.callbacks.log_level = log_level + else: + raise FMUException("The log level must be between %d and %d"%(FMIL.jm_log_level_nothing, FMIL.jm_log_level_all)) + self._enable_logging = enable_logging + + self._fmu_full_path = encode(os.path.abspath(fmu)) + check_fmu_args(self._allow_unzipped_fmu, fmu, self._fmu_full_path) + + # Create a struct for allocation + self._context = FMIL.fmi_import_allocate_context(&self.callbacks) + self._allocated_context = 1 + + #Get the FMI version of the provided model + if _unzipped_dir: + fmu_temp_dir = encode(_unzipped_dir) + elif self._allow_unzipped_fmu: + fmu_temp_dir = encode(fmu) + else: + fmu_temp_dir = encode(create_temp_dir()) + fmu_temp_dir = os.path.abspath(fmu_temp_dir) + self._fmu_temp_dir = FMIL.malloc((FMIL.strlen(fmu_temp_dir)+1)*sizeof(char)) + FMIL.strcpy(self._fmu_temp_dir, fmu_temp_dir) + + if _unzipped_dir: + # If the unzipped directory is provided we assume that the version + # is correct. This is due to that the method to get the version + # unzips the FMU which we already have done. + self._version = FMIL.fmi_version_3_0_enu + else: + self._version = import_and_get_version(self._context, self._fmu_full_path, + fmu_temp_dir, self._allow_unzipped_fmu) + + # Check the version + if self._version == FMIL.fmi_version_unknown_enu: + last_error = decode(FMIL.jm_get_last_error(&self.callbacks)) + if enable_logging: + raise InvalidVersionException("The FMU could not be loaded. The FMU version could not be determined. " + last_error) + else: + raise InvalidVersionException("The FMU could not be loaded. The FMU version could not be determined. Enable logging for possibly more information.") + + if self._version != FMIL.fmi_version_3_0_enu: + last_error = decode(FMIL.jm_get_last_error(&self.callbacks)) + if enable_logging: + raise InvalidVersionException("The FMU could not be loaded. The FMU version is not supported by this class. " + last_error) + else: + raise InvalidVersionException("The FMU could not be loaded. The FMU version is not supported by this class. Enable logging for possibly more information.") + + # Parse xml and check fmu-kind + self._fmu = FMIL3.fmi3_import_parse_xml(self._context, self._fmu_temp_dir, NULL) + + if self._fmu is NULL: + last_error = decode(FMIL.jm_get_last_error(&self.callbacks)) + if enable_logging: + raise InvalidXMLException("The FMU could not be loaded. The model data from 'modelDescription.xml' within the FMU could not be read. " + last_error) + else: + raise InvalidXMLException("The FMU could not be loaded. The model data from 'modelDescription.xml' within the FMU could not be read. Enable logging for possible more information.") + + # self.callBackFunctions.componentEnvironment = self._fmu + self._fmu_kind = FMIL3.fmi3_import_get_fmu_kind(self._fmu) + print("\t PyFMI, fmu_kind: ", self._fmu_kind) + self._allocated_xml = 1 + + #FMU kind is unknown + if self._fmu_kind == FMIL3.fmi3_fmu_kind_unknown: + last_error = decode(FMIL.jm_get_last_error(&self.callbacks)) + if enable_logging: + raise InvalidVersionException("The FMU could not be loaded. The FMU kind could not be determined. " + last_error) + else: + raise InvalidVersionException("The FMU could not be loaded. The FMU kind could not be determined. Enable logging for possibly more information.") + else: + if isinstance(self, FMUModelME3): + self._fmu_kind = FMIL3.fmi3_fmu_kind_me + elif isinstance(self, FMUModelCS3): + self._fmu_kind = FMIL3.fmi3_fmu_kind_cs + else: + # TODO: This was simplified from FMUModel2; is there a use in supporting this as stand-alone, isn't this meant to be an abstract base class? + # TODO: Scheduled execution + raise FMUException("FMUModelBase3 cannot be used directly, use FMUModelME3 or FMUModelCS3.") + + # Connect the DLL + if _connect_dll: + self._log_handler.capi_start_callback(self._max_log_size_msg_sent, self._current_log_size) + # status = FMIL3.fmi3_import_create_dllfmu(self._fmu, self._fmu_kind, &self.callBackFunctions) + status = FMIL3.fmi3_import_create_dllfmu(self._fmu, self._fmu_kind, self._instance_environment, self._log_message) + self._log_handler.capi_end_callback(self._max_log_size_msg_sent, self._current_log_size) + if status == FMIL.jm_status_error: + last_error = decode(FMIL3.fmi3_import_get_last_error(self._fmu)) + if enable_logging: + raise InvalidBinaryException("The FMU could not be loaded. Error loading the binary. " + last_error) + else: + raise InvalidBinaryException("The FMU could not be loaded. Error loading the binary. Enable logging for possibly more information.") + self._allocated_dll = 1 + + # Load information from model + if isinstance(self, FMUModelME3): + self._modelId = decode(FMIL3.fmi3_import_get_model_identifier_ME(self._fmu)) + elif isinstance(self, FMUModelCS3): + self._modelId = decode(FMIL3.fmi3_import_get_model_identifier_CS(self._fmu)) + else: + # TODO: SE + raise FMUException("FMUModelBase3 cannot be used directly, use FMUModelME3 or FMUModelCS3.") + + # Connect the DLL + self._modelName = decode(FMIL3.fmi3_import_get_model_name(self._fmu)) + print("\tfmi3.pyx model name :", self._modelName) + # TODO + # self._log_handler.capi_start_callback(self._max_log_size_msg_sent, self._current_log_size) + # self._nEventIndicators = FMIL.fmi2_import_get_number_of_event_indicators(self._fmu) # TODO: needs wrapper now + # self._log_handler.capi_end_callback(self._max_log_size_msg_sent, self._current_log_size) + # self._log_handler.capi_start_callback(self._max_log_size_msg_sent, self._current_log_size) + # self._nContinuousStates = FMIL.fmi2_import_get_number_of_continuous_states(self._fmu) # TODO: needs wrapper now + # self._log_handler.capi_end_callback(self._max_log_size_msg_sent, self._current_log_size) + + if not isinstance(log_file_name, str): + self._set_log_stream(log_file_name) + for i in range(len(self._log)): + self._log_stream.write("FMIL: module = %s, log level = %d: %s\n"%(self._log[i][0], self._log[i][1], self._log[i][2])) + else: + fmu_log_name = encode((self._modelId + "_log.txt") if log_file_name == "" else log_file_name) + self._fmu_log_name = FMIL.malloc((FMIL.strlen(fmu_log_name)+1)*sizeof(char)) + FMIL.strcpy(self._fmu_log_name, fmu_log_name) + + # Create the log file + with open(self._fmu_log_name, 'w') as file: + for i in range(len(self._log)): + file.write("FMIL: module = %s, log level = %d: %s\n"%(self._log[i][0], self._log[i][1], self._log[i][2])) + + self._log = [] + + def instantiate(self, name = "Model", visible = False): + """ + Instantiate the model. + + Parameters:: + + name -- + The name of the instance. + Default: 'Model' + + visible -- + Defines if the simulator application window should be visible or not. + Default: False, not visible. + + Calls the low-level FMI function: fmi3Instantiate. + """ + + cdef FMIL3.fmi3_boolean_t log = False # TODO; should be taken from function parameter + cdef FMIL3.fmi3_boolean_t vis = visible + cdef FMIL.jm_status_enu_t status + instanceName = encode(name) + + # TODO: Should likely have separate functions for the different FMU types + + self._log_handler.capi_start_callback(self._max_log_size_msg_sent, self._current_log_size) + if isinstance(self, FMUModelME3): + # TODO: Call is outdated on current FMIL master + print("Instantiating Model Exchange FMU") + status = FMIL3.fmi3_import_instantiate_model_exchange(self._fmu, instanceName, NULL, vis, log, NULL, NULL) + elif isinstance(self, FMUModelCS3): + # TODO + print("Instantiating Co Simulation FMU") + # TODO + # status = FMIL3.fmi3_import_instantiate_co_simulation(self._fmu, instanceName, NULL, vis, log, NULL, NULL) + pass + else: + raise FMUException('The instance is an instance of an ME-model or a CS-model. Use load_fmu for correct loading.') + self._log_handler.capi_end_callback(self._max_log_size_msg_sent, self._current_log_size) + + if status != FMIL.jm_status_success: + raise FMUException('Failed to instantiate the model. See the log for possibly more information.') + + self._allocated_fmu = 1 + + def initialize(self, tolerance_defined=True, tolerance="Default", start_time="Default", stop_time_defined=False, stop_time="Default"): + """ + Initializes the model and computes initial values for all variables. + Additionally calls the setup experiment, if not already called. + + Parameters:: + + tolerance_defined -- + Specifies if the model is to be solved with an error + controlled algorithm. + Default: True + + tolerance -- + The tolerance used by the error controlled algorithm. + Default: The tolerance defined in the model description + + start_time -- + Start time of the simulation. + Default: The start time defined in the model description. + + stop_time_defined -- + Defines if a fixed stop time is defined or not. If this is + set the simulation cannot go past the defined stop time. + Default: False + + stop_time -- + Stop time of the simulation. + Default: The stop time defined in the model description. + + Calls the low-level FMI functions: fmi2_import_setup_experiment (optionally) + fmi2EnterInitializationMode, + fmi2ExitInitializationMode + """ + log_open = self._log_open() + if not log_open and self.get_log_level() > 2: + self._open_log_file() + + + try: + self.time = 0. # TODO + # if self.time is None: + # self.setup_experiment(tolerance_defined, tolerance, start_time, stop_time_defined, stop_time) + # TODO: What setup_experiment previously did now needs to be done here + # TODO: Forward input to enter_initialization_mode + self.enter_initialization_mode() + self.exit_initialization_mode() + except Exception: + if not log_open and self.get_log_level() > 2: + self._close_log_file() + + raise + + if not log_open and self.get_log_level() > 2: + self._close_log_file() + + def enter_initialization_mode(self): + """ + Enters initialization mode by calling the low level FMI function + fmi3EnterInitializationMode. + + Note that the method initialize() performs both the enter and + exit of initialization mode. + """ + # TODO: Fill with sensible values + cdef FMIL3.fmi3_boolean_t tolerance_defined = True + cdef FMIL3.fmi3_boolean_t stop_time_defined = True + cdef FMIL3.fmi3_float64_t tolerance = 1e-6 + cdef FMIL3.fmi3_float64_t start_time = 0 + cdef FMIL3.fmi3_float64_t stop_time = 1 + + if self.time is None: + raise FMUException("Setup Experiment has to be called prior to the initialization method.") + + + self._log_handler.capi_start_callback(self._max_log_size_msg_sent, self._current_log_size) + status = FMIL3.fmi3_import_enter_initialization_mode( + self._fmu, + tolerance_defined, + tolerance, + start_time, + stop_time_defined, + stop_time + ) + self._log_handler.capi_end_callback(self._max_log_size_msg_sent, self._current_log_size) + + if status == 1: + if self._enable_logging: + logging.warning( + 'Enter Initialize returned with a warning.' \ + ' Check the log for information (model.get_log).') + else: + logging.warning('Enter Initialize returned with a warning.' \ + ' Enable logging for more information, (load_fmu(..., log_level=4)).') + + if status > 1: + if self._enable_logging: + raise FMUException( + 'Enter Initialize returned with an error.' \ + ' Check the log for information (model.get_log).') + else: + raise FMUException('Enter Initialize returned with an error.' \ + ' Enable logging for more information, (load_fmu(..., log_level=4)).') + + self._has_entered_init_mode = True + + # TODO: Workaround to be able to legally call terminate directly afterwards + # initialize otherwise leads to event mode + return status + + def exit_initialization_mode(self): + """ + Exit initialization mode by calling the low level FMI function + fmi2ExitInitializationMode. + + Note that the method initialize() performs both the enter and + exit of initialization mode. + """ + self._log_handler.capi_start_callback(self._max_log_size_msg_sent, self._current_log_size) + status = FMIL3.fmi3_import_exit_initialization_mode(self._fmu) + self._log_handler.capi_end_callback(self._max_log_size_msg_sent, self._current_log_size) + + if status == 1: + if self._enable_logging: + logging.warning( + 'Exit Initialize returned with a warning.' \ + ' Check the log for information (model.get_log).') + else: + logging.warning('Exit Initialize returned with a warning.' \ + ' Enable logging for more information, (load_fmu(..., log_level=4)).') + + if status > 1: + if self._enable_logging: + raise FMUException( + 'Exit Initialize returned with an error.' \ + ' Check the log for information (model.get_log).') + else: + raise FMUException('Exit Initialize returned with an error.' \ + ' Enable logging for more information, (load_fmu(..., log_level=4)).') + + + self._initialized_fmu = 1 + status = FMIL3.fmi3_import_enter_continuous_time_mode(self._fmu) + + return status + + def terminate(self): + """ + Calls the FMI function fmi3Terminate() on the FMU. + After this call, any call to a function changing the state of the FMU will fail. + """ + self._log_handler.capi_start_callback(self._max_log_size_msg_sent, self._current_log_size) + FMIL3.fmi3_import_terminate(self._fmu) + self._log_handler.capi_end_callback(self._max_log_size_msg_sent, self._current_log_size) + self._initialized_fmu = 0 # Do not call terminate again in dealloc + +cdef class FMUModelCS3(FMUModelBase3): + """ + Model-exchange model loaded from a dll + """ + pass + +cdef class FMUModelME3(FMUModelBase3): + """ + Model-exchange model loaded from a dll + """ + def __init__(self, fmu, log_file_name = "", log_level = FMI_DEFAULT_LOG_LEVEL, + _unzipped_dir = None, _connect_dll = True, allow_unzipped_fmu = False): + """ + Constructor of the model. + + Parameters:: + + fmu -- + Name of the fmu as a string. + + log_file_name -- + Filename for file used to save log messages. + This argument can also be a stream if it supports 'write', for full functionality + it must also support 'seek' and 'readlines'. If the stream requires use of other methods, such as 'drain' + for asyncio-streams, then this needs to be implemented on the user-side, there is no additional methods invoked + on the stream instance after 'write' has been invoked on the PyFMI side. + The stream must also be open and writable during the entire time. + Default: "" (Generates automatically) + + log_level -- + Determines the logging output. Can be set between 0 + (no logging) and 7 (everything). + Default: 2 (log error messages) + allow_unzipped_fmu -- + If set to True, the argument 'fmu' can be a path specifying a directory + to an unzipped FMU. The structure of the unzipped FMU must conform + to the FMI specification. + Default: False + + Returns:: + + A model as an object from the class FMUModelME3 + """ + #Call super + FMUModelBase3.__init__(self, fmu, log_file_name, log_level, + _unzipped_dir, _connect_dll, allow_unzipped_fmu) + + if not (self._fmu_kind & FMIL3.fmi3_fmu_kind_me): + raise InvalidVersionException('The FMU could not be loaded. This class only supports FMI 3.0 for Model Exchange.') + + # if self.get_capability_flags()['needsExecutionTool']: + # raise FMUException("The FMU specifies 'needsExecutionTool=true' which implies that it requires an external execution tool to simulate, this is not supported.") + + # self._eventInfo.newDiscreteStatesNeeded = FMI2_FALSE + # self._eventInfo.terminateSimulation = FMI2_FALSE + # self._eventInfo.nominalsOfContinuousStatesChanged = FMI2_FALSE + # self._eventInfo.valuesOfContinuousStatesChanged = FMI2_TRUE + # self._eventInfo.nextEventTimeDefined = FMI2_FALSE + # self._eventInfo.nextEventTime = 0.0 + + # self.force_finite_differences = 0 + + # # State nominals retrieved before initialization + # self._preinit_nominal_continuous_states = None + + # TODO: duplicate? + # self._modelId = decode(FMIL3.fmi3_import_get_model_identifier_ME(self._fmu)) + + if _connect_dll: + self.instantiate() + + def __dealloc__(self): + """ + Deallocate memory allocated + """ + self._invoked_dealloc = 1 + + if self._initialized_fmu == 1: + FMIL3.fmi3_import_terminate(self._fmu) + + if self._allocated_fmu == 1: + FMIL3.fmi3_import_free_instance(self._fmu) + + if self._allocated_dll == 1: + FMIL3.fmi3_import_destroy_dllfmu(self._fmu) + + if self._allocated_xml == 1: + FMIL3.fmi3_import_free(self._fmu) + + if self._fmu_temp_dir != NULL: + if not self._allow_unzipped_fmu: + FMIL.fmi_import_rmdir(&self.callbacks, self._fmu_temp_dir) + FMIL.free(self._fmu_temp_dir) + self._fmu_temp_dir = NULL + + if self._allocated_context == 1: + FMIL.fmi_import_free_context(self._context) + + if self._fmu_log_name != NULL: + FMIL.free(self._fmu_log_name) + self._fmu_log_name = NULL + + if self._log_stream: + self._log_stream = None diff --git a/src/pyfmi/fmi3/fmil3_import.pxd b/src/pyfmi/fmi3/fmil3_import.pxd new file mode 100644 index 00000000..d0918b9c --- /dev/null +++ b/src/pyfmi/fmi3/fmil3_import.pxd @@ -0,0 +1,615 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (C) 2024 Modelon AB +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +cimport pyfmi.fmil_import as FMIL +from libcpp cimport bool # TODO: Possible issue due to https://github.com/cython/cython/issues/5730 ?? + +#============================================== +# C headers +#============================================== +# cdef extern from "stdlib.h": +# ctypedef long unsigned int size_t + +# void*malloc(size_t) +# void free(void*ptr) +# void*calloc(size_t, size_t) +# void*realloc(void*, size_t) + +# cdef extern from "string.h": +# int memcmp(void*s1, void*s2, size_t n); + +# cdef extern from "stdio.h": +# ctypedef struct FILE: +# pass +# int fprintf(FILE *restrict, const char*restrict, ...) +# FILE *fopen(const char*path, const char*mode) +# int fclose(FILE *file_pointer) + +# #SEE http://wiki.cython.org/FAQ#HowdoIusevariableargs. +# cdef extern from "stdarg.h": +# ctypedef struct va_list: +# pass +# ctypedef struct fake_type: +# pass +# void va_start(va_list, void* arg) +# #void* va_arg(va_list, fake_type) +# void va_end(va_list) +# int vsnprintf(char*str, size_t size, char*format, va_list ap) + +cdef extern from 'fmilib.h': + # TODO: This has taken a few shortcuts + +# #FMI VARIABLE TYPE DEFINITIONS +# ctypedef double fmi2_real_t + ctypedef bool fmi3_boolean_t + # ctypedef void* fmi3_component_t + ctypedef void* fmi3_instance_environment_t + ctypedef const char* fmi3_string_t + ctypedef double fmi3_float64_t +# ctypedef int fmi2_integer_t +# # ctypedef long unsigned int size_t # same as via stdlib.h +# ctypedef void* jm_voidp +# ctypedef char* jm_string +# ctypedef char fmi2_byte_t +# ctypedef void* fmi2_FMU_state_t +# ctypedef void* fmi2_component_environment_t +# ctypedef size_t fmi2_value_reference_t + +# #STRUCTS +# ctypedef enum jm_log_level_enu_t: +# jm_log_level_nothing = 0 +# jm_log_level_fatal = 1 +# jm_log_level_error = 2 +# jm_log_level_warning = 3 +# jm_log_level_info = 4 +# jm_log_level_verbose = 5 +# jm_log_level_debug = 6 +# jm_log_level_all = 7 + +# ctypedef enum fmi2_boolean_enu_t: +# fmi2_true = 1 +# fmi2_false = 0 + + # ctypedef enum fmi2_type_t: + # fmi2_model_exchange, + # fmi2_cosimulation + + ctypedef enum fmi3_status_t: + fmi3_status_ok = 0 + fmi3_status_warning = 1 + fmi3_status_discard = 2 + fmi3_status_error = 3 + fmi3_status_fatal = 4 + +# cdef enum fmi2_variable_alias_kind_enu_t: +# fmi2_variable_is_not_alias = 0 +# fmi2_variable_is_alias = 1 + +# cdef enum fmi2_base_type_enu_t: +# fmi2_base_type_real = 0 +# fmi2_base_type_int = 1 +# fmi2_base_type_bool = 2 +# fmi2_base_type_str = 3 +# fmi2_base_type_enum = 4 + +# ctypedef enum jm_status_enu_t: +# jm_status_error = -1 +# jm_status_success = 0 +# jm_status_warning = 1 + +# ctypedef enum fmi_version_enu_t: +# fmi_version_unknown_enu = 0 +# fmi_version_1_enu = 1 +# fmi_version_2_0_enu = 2 +# fmi_version_unsupported_enu = 3 + +# cdef enum fmi2_causality_enu_t: +# fmi2_causality_enu_parameter = 0 +# fmi2_causality_enu_calculated_parameter = 1 +# fmi2_causality_enu_input = 2 +# fmi2_causality_enu_output = 3 +# fmi2_causality_enu_local = 4 +# fmi2_causality_enu_independent = 5 +# fmi2_causality_enu_unknown = 6 + + cdef enum fmi3_fmu_kind_enu_t: + fmi3_fmu_kind_unknown = 1 + fmi3_fmu_kind_me = 2 + fmi3_fmu_kind_cs = 4 + fmi3_fmu_kind_se = 8 + +# cdef enum fmi2_variability_enu_t: +# fmi2_variability_enu_constant = 0 +# fmi2_variability_enu_fixed = 1 +# fmi2_variability_enu_tunable = 2 +# fmi2_variability_enu_discrete = 3 +# fmi2_variability_enu_continuous = 4 +# fmi2_variability_enu_unknown = 5 + +# cdef enum fmi2_variable_naming_convension_enu_t: +# fmi2_naming_enu_flat = 0 +# fmi2_naming_enu_structured = 1 +# fmi2_naming_enu_unknown = 2 + +# ctypedef enum fmi2_status_kind_t: +# fmi2_do_step_status = 0 +# fmi2_pending_status = 1 +# fmi2_last_successful_time = 2 +# fmi2_terminated = 3 + +# ctypedef struct fmi2_event_info_t: +# fmi3_boolean_t newDiscreteStatesNeeded +# fmi3_boolean_t terminateSimulation +# fmi3_boolean_t nominalsOfContinuousStatesChanged +# fmi3_boolean_t valuesOfContinuousStatesChanged +# fmi3_boolean_t nextEventTimeDefined +# fmi2_real_t nextEventTime + +# cdef enum fmi2_dependency_factor_kind_enu_t: +# fmi2_dependency_factor_kind_dependent = 0 +# fmi2_dependency_factor_kind_constant = 1 +# fmi2_dependency_factor_kind_fixed = 2 +# fmi2_dependency_factor_kind_tunable = 3 +# fmi2_dependency_factor_kind_discrete = 4 + +# cdef enum fmi2_initial_enu_t: +# fmi2_initial_enu_exact = 0 +# fmi2_initial_enu_approx = 1 +# fmi2_initial_enu_calculated = 2 +# fmi2_initial_enu_unknown = 3 + +# cdef enum fmi2_capabilities_enu_t: +# fmi2_me_needsExecutionTool = 0 +# fmi2_me_completedIntegratorStepNotNeeded = 1 +# fmi2_me_canBeInstantiatedOnlyOncePerProcess = 2 +# fmi2_me_canNotUseMemoryManagementFunctions = 3 +# fmi2_me_canGetAndSetFMUstate = 4 +# fmi2_me_canSerializeFMUstate = 5 +# fmi2_me_providesDirectionalDerivatives = 6 +# fmi2_me_completedEventIterationIsProvided = 7 +# fmi2_cs_needsExecutionTool = 8 +# fmi2_cs_canHandleVariableCommunicationStepSize = 9 +# fmi2_cs_canInterpolateInputs = 10 +# fmi2_cs_maxOutputDerivativeOrder = 11 +# fmi2_cs_canRunAsynchronuously = 12 +# fmi2_cs_canBeInstantiatedOnlyOncePerProcess = 13 +# fmi2_cs_canNotUseMemoryManagementFunctions = 14 +# fmi2_cs_canGetAndSetFMUstate = 15 +# fmi2_cs_canSerializeFMUstate = 16 +# fmi2_cs_providesDirectionalDerivatives = 17 +# fmi2_capabilities_Num = 18 + +# cdef enum fmi2_SI_base_units_enu_t: +# fmi2_SI_base_unit_kg = 0 +# fmi2_SI_base_unit_m = 1 +# fmi2_SI_base_unit_s = 2 +# fmi2_SI_base_unit_A = 3 +# fmi2_SI_base_unit_K = 4 +# fmi2_SI_base_unit_mol = 5 +# fmi2_SI_base_unit_cd = 6 +# fmi2_SI_base_unit_rad = 7 +# fmi2_SI_base_units_Num = 8 + +# cdef struct fmi2_import_model_counts_t: +# unsigned int num_constants +# unsigned int num_tunable +# unsigned int num_fixed +# unsigned int num_discrete +# unsigned int num_continuous +# unsigned int num_inputs +# unsigned int num_outputs +# unsigned int num_local +# unsigned int num_parameters +# unsigned int num_real_vars +# unsigned int num_integer_vars +# unsigned int num_enum_vars +# unsigned int num_bool_vars +# unsigned int num_string_vars + +# cdef struct fmi2_xml_variable_t: +# pass +# ctypedef fmi2_xml_variable_t fmi2_import_variable_t + +# ctypedef int(*jm_compare_ft)(void*, void*) +# ctypedef jm_voidp(*jm_malloc_f)(size_t) +# ctypedef jm_voidp(*jm_calloc_f)(size_t, size_t) +# ctypedef jm_voidp(*jm_realloc_f)(void*, size_t) +# ctypedef void(*jm_free_f)(jm_voidp) + ctypedef void (*fmi3_log_message_callback_ft) ( + fmi3_instance_environment_t instanceEnvironment, + fmi3_status_t status, + fmi3_string_t category, + fmi3_string_t messages + ) +# #ctypedef void(*fmi2_callback_logger_ft)(fmi3_component_t c,fmi3_string_t instanceName, fmi3_status_t status, fmi3_string_t category,fmi3_string_t message,...) +# ctypedef void(*fmi2_callback_logger_ft)(fmi2_component_environment_t c,fmi3_string_t instanceName, fmi3_status_t status, fmi3_string_t category,fmi3_string_t message,...) +# ctypedef void(*fmi2_step_finished_ft)(fmi2_component_environment_t env, fmi3_status_t status) +# ctypedef void (*jm_logger_f)(jm_callbacks* c, jm_string module, jm_log_level_enu_t log_level, jm_string message) except * +# ctypedef void*(*fmi2_callback_allocate_memory_ft)(size_t, size_t) +# ctypedef void(*fmi2_callback_free_memory_ft)(void*) + ctypedef int(*fmi3_xml_element_start_handle_ft)(void*, char*, void*, char*, char**) + ctypedef int(*fmi3_xml_element_data_handle_ft)(void*, char*, int) + ctypedef int(*fmi3_xml_element_end_handle_ft)(void*, char*) +# ctypedef int(*fmi2_import_variable_filter_function_ft)(fmi2_import_variable_t*, void*) + + cdef struct fmi3_xml_callbacks_t: + fmi3_xml_element_start_handle_ft startHandle + fmi3_xml_element_data_handle_ft dataHandle + fmi3_xml_element_end_handle_ft endHandle + void* context + +# cdef struct jm_callbacks: +# jm_malloc_f malloc +# jm_calloc_f calloc +# jm_realloc_f realloc +# jm_free_f free +# jm_logger_f logger +# jm_log_level_enu_t log_level +# jm_voidp context +# char* errMessageBuffer + + # ctypedef struct fmi2_callback_functions_t: + # fmi2_callback_logger_ft logger + # fmi2_callback_allocate_memory_ft allocateMemory + # fmi2_callback_free_memory_ft freeMemory + # fmi2_step_finished_ft stepFinished + # fmi2_component_environment_t componentEnvironment + +# cdef struct jm_named_ptr: +# jm_voidp ptr +# jm_string name + + cdef struct fmi3_import_t: + pass + + # TODO: Should this be taken from fmil_import? + # cdef struct fmi_xml_context_t: + # pass + + # ctypedef fmi_xml_context_t fmi_import_context_t + +# cdef struct fmi2_xml_real_variable_t: +# pass +# ctypedef fmi2_xml_real_variable_t fmi2_import_real_variable_t + +# cdef struct fmi2_xml_display_unit_t: +# pass +# ctypedef fmi2_xml_display_unit_t fmi2_import_display_unit_t + +# cdef struct fmi2_xml_unit_definitions_t: +# pass +# ctypedef fmi2_xml_unit_definitions_t fmi2_import_unit_definitions_t + +# cdef struct fmi2_import_variable_list_t: +# pass + +# cdef struct fmi2_xml_variable_typedef_t: +# pass +# ctypedef fmi2_xml_variable_typedef_t fmi2_import_variable_typedef_t + +# cdef struct fmi2_xml_integer_variable_t: +# pass +# ctypedef fmi2_xml_integer_variable_t fmi2_import_integer_variable_t + +# cdef struct fmi2_xml_real_typedef_t: +# pass +# ctypedef fmi2_xml_real_typedef_t fmi2_import_real_typedef_t + +# cdef struct fmi2_xml_enum_variable_t: +# pass +# ctypedef fmi2_xml_enum_variable_t fmi2_import_enum_variable_t + +# cdef struct fmi2_xml_type_definitions_t: +# pass +# ctypedef fmi2_xml_type_definitions_t fmi3_import_type_definitions_t + +# cdef struct fmi2_xml_enumeration_typedef_t: +# pass +# ctypedef fmi2_xml_enumeration_typedef_t fmi2_import_enumeration_typedef_t + +# cdef struct fmi2_xml_integer_typedef_t: +# pass +# ctypedef fmi2_xml_integer_typedef_t fmi2_import_integer_typedef_t + +# cdef struct fmi2_xml_unit_t: +# pass +# ctypedef fmi2_xml_unit_t fmi2_import_unit_t + +# cdef struct fmi2_xml_bool_variable_t: +# pass +# ctypedef fmi2_xml_bool_variable_t fmi2_import_bool_variable_t + +# cdef struct fmi2_xml_string_variable_t: +# pass +# ctypedef fmi2_xml_string_variable_t fmi2_import_string_variable_t + +# cdef struct __va_list_tag: +# pass + +# #FMI SPECIFICATION METHODS (3.0) +# # basic + FMIL.jm_status_enu_t fmi3_import_create_dllfmu(fmi3_import_t*, fmi3_fmu_kind_enu_t, const fmi3_instance_environment_t, const fmi3_log_message_callback_ft) + # TODO: CS, SE + # FMIL.jm_status_enu_t fmi3_import_instantiate_model_exchange( + # fmi3_import_t* fmu, + # fmi3_string_t instanceName, + # fmi3_string_t resourcePath, + # fmi3_boolean_t visible, + # fmi3_boolean_t loggingOn + # ) + # TODO: This is outdated on current FMIL master + FMIL.jm_status_enu_t fmi3_import_instantiate_model_exchange( + fmi3_import_t* fmu, + fmi3_string_t instanceName, + fmi3_string_t resourcePath, + fmi3_boolean_t visible, + fmi3_boolean_t loggingOn, + fmi3_instance_environment_t instanceEnvironment, + fmi3_log_message_callback_ft logMessage + ) + void fmi3_import_free_instance(fmi3_import_t* fmu) +# char* fmi2_import_get_types_platform(fmi3_import_t*) +# int fmi2_import_setup_experiment(fmi3_import_t* fmu, fmi3_boolean_t toleranceDefined, fmi2_real_t tolerance,fmi2_real_t startTime, fmi3_boolean_t stopTimeDefined,fmi2_real_t stopTime) +# int fmi2_import_do_step(fmi3_import_t*, fmi2_real_t, fmi2_real_t, fmi3_boolean_t) nogil +# int fmi2_import_completed_integrator_step(fmi3_component_t, fmi3_boolean_t, fmi3_boolean_t*, fmi3_boolean_t*) + FMIL.jm_status_enu_t fmi3_import_terminate(fmi3_import_t*) + + # modes + FMIL.jm_status_enu_t fmi3_import_enter_initialization_mode( + fmi3_import_t* fmu, + fmi3_boolean_t toleranceDefined, + fmi3_float64_t tolerance, + fmi3_float64_t startTime, + fmi3_boolean_t stopTimeDefined, + fmi3_float64_t stopTime + ); + FMIL.jm_status_enu_t fmi3_import_exit_initialization_mode(fmi3_import_t* fmu) +# int fmi2_import_enter_event_mode(fmi3_import_t* fmu) + FMIL.jm_status_enu_t fmi3_import_enter_continuous_time_mode(fmi3_import_t* fmu) + +# # misc +# int fmi2_import_set_debug_logging(fmi3_import_t*, fmi3_boolean_t, size_t, fmi3_string_t*) +# int fmi2_import_reset(fmi3_import_t* fmu) +# int fmi2_import_cancel_step(fmi3_import_t*) +# int fmi2_import_new_discrete_states(fmi3_import_t* fmu, fmi2_event_info_t* eventInfo) +# char* fmi2_import_get_version(fmi3_import_t*) + +# # setting +# int fmi2_import_set_time(fmi3_import_t*, fmi2_real_t) +# int fmi2_import_set_integer(fmi3_import_t*, fmi2_value_reference_t *, size_t, fmi2_integer_t *) +# int fmi2_import_set_real(fmi3_import_t*, fmi2_value_reference_t *, size_t, fmi2_real_t *) +# int fmi2_import_set_boolean(fmi3_import_t*, fmi2_value_reference_t *, size_t, fmi3_boolean_t *) +# int fmi2_import_set_string(fmi3_import_t*, fmi2_value_reference_t *, size_t, fmi3_string_t *) + +# int fmi2_import_set_continuous_states(fmi3_import_t*, fmi2_real_t *, size_t) +# int fmi2_import_set_real_input_derivatives(fmi3_import_t*, fmi2_value_reference_t *, size_t, fmi2_integer_t *, fmi2_real_t *) + +# # getting +# int fmi2_import_get_integer(fmi3_import_t*, fmi2_value_reference_t *, size_t, fmi2_integer_t *) +# int fmi2_import_get_real(fmi3_import_t*, fmi2_value_reference_t *, size_t, fmi2_real_t *) +# int fmi2_import_get_string(fmi3_import_t*, fmi2_value_reference_t *, size_t, fmi3_string_t *) +# int fmi2_import_get_boolean(fmi3_import_t*, fmi2_value_reference_t *, size_t, fmi3_boolean_t *) + +# int fmi2_import_get_derivatives(fmi3_import_t*, fmi2_real_t *, size_t) +# int fmi2_import_get_event_indicators(fmi3_import_t*, fmi2_real_t *, size_t) +# int fmi2_import_get_continuous_states(fmi3_import_t*, fmi2_real_t *, size_t) +# int fmi2_import_get_nominals_of_continuous_states(fmi3_import_t* fmu, fmi2_real_t *, size_t nx) +# int fmi2_import_get_directional_derivative(fmi3_import_t*, fmi2_value_reference_t*, size_t, fmi2_value_reference_t*, size_t, fmi2_real_t*, fmi2_real_t*) +# int fmi2_import_get_real_output_derivatives(fmi3_import_t*, fmi2_value_reference_t *, size_t, fmi2_integer_t *, fmi2_real_t *) + +# int fmi2_import_get_status(fmi3_import_t* fmu, const fmi2_status_kind_t s, fmi3_status_t* value) +# int fmi2_import_get_integer_status(fmi3_import_t*, int, fmi2_integer_t *) +# int fmi2_import_get_real_status(fmi3_import_t*, int, fmi2_real_t *) +# int fmi2_import_get_boolean_status(fmi3_import_t*, int, fmi3_boolean_t *) +# int fmi2_import_get_string_status(fmi3_import_t*, int, fmi3_string_t *) + +# # save states +# int fmi2_import_get_fmu_state(fmi3_import_t*, fmi2_FMU_state_t *) +# int fmi2_import_set_fmu_state(fmi3_import_t*, fmi2_FMU_state_t) +# int fmi2_import_free_fmu_state(fmi3_import_t*, fmi2_FMU_state_t *) +# int fmi2_import_serialized_fmu_state_size(fmi3_import_t*, fmi2_FMU_state_t, size_t *) +# int fmi2_import_serialize_fmu_state(fmi3_import_t*, fmi2_FMU_state_t, fmi2_byte_t *, size_t) +# int fmi2_import_de_serialize_fmu_state(fmi3_import_t*, fmi2_byte_t *, size_t, fmi2_FMU_state_t *) + +# #FMI HELPER METHODS (2.0) +# char* fmi2_import_get_GUID(fmi3_import_t*) +# char* fmi2_import_get_description(fmi3_import_t*) +# char* fmi2_import_get_author(fmi3_import_t*) +# char* fmi2_import_get_license(fmi3_import_t*) +# char* fmi2_import_get_generation_tool(fmi3_import_t*) +# char* fmi2_import_get_generation_date_and_time(fmi3_import_t*) +# fmi2_variable_naming_convension_enu_t fmi2_import_get_naming_convention(fmi3_import_t*) + const char* fmi3_import_get_model_name(fmi3_import_t*) + + fmi3_fmu_kind_enu_t fmi3_import_get_fmu_kind(fmi3_import_t*) + +# unsigned int fmi2_import_get_capability(fmi3_import_t*, fmi2_capabilities_enu_t) +# double fmi2_import_get_default_experiment_stop(fmi3_import_t*) +# double fmi2_import_get_default_experiment_start(fmi3_import_t*) +# double fmi2_import_get_default_experiment_step(fmi3_import_t*) + +# #FMI XML METHODS + +# ###Model information + +# #CONVERTER METHODS +# fmi2_import_integer_variable_t * fmi2_import_get_variable_as_integer(fmi2_import_variable_t*) +# fmi2_import_real_variable_t * fmi2_import_get_variable_as_real(fmi2_import_variable_t*) +# fmi2_import_bool_variable_t * fmi2_import_get_variable_as_boolean(fmi2_import_variable_t*) +# fmi2_import_enum_variable_t * fmi2_import_get_variable_as_enum(fmi2_import_variable_t*) +# fmi2_import_string_variable_t * fmi2_import_get_variable_as_string(fmi2_import_variable_t*) + +# #INTEGER +# int fmi2_import_get_integer_type_min(fmi2_import_integer_typedef_t *) +# int fmi2_import_get_integer_type_max(fmi2_import_integer_typedef_t *) + +# int fmi2_import_get_integer_variable_max(fmi2_import_integer_variable_t *) +# int fmi2_import_get_integer_variable_min(fmi2_import_integer_variable_t *) +# int fmi2_import_get_integer_variable_start(fmi2_import_integer_variable_t *) + +# #OTHER HELPER METHODS +# void jm_set_default_callbacks(jm_callbacks *) +# jm_string jm_get_last_error(jm_callbacks *) +# # void jm_clear_last_error(jm_callbacks *) +# void jm_log(jm_callbacks *, char*, int, char*) +# void* mempcpy(void*, void*, size_t) +# void* memcpy(void*, void*, size_t) +# void* memset(void*, int, size_t) +# char* strcat(char*, char*) +# char* strcpy(char*, char*) +# size_t strlen(char*) +# jm_callbacks * jm_get_default_callbacks() +# void jm_log_v(jm_callbacks *, char*, int, char*, __va_list_tag *) + + # unsorted, but does NOT invoke CAPI calls + void fmi3_import_free(fmi3_import_t*) + +# size_t fmi2_import_get_number_of_event_indicators(fmi3_import_t*) +# size_t fmi2_import_get_number_of_continuous_states(fmi3_import_t*) +# fmi2_import_variable_list_t* fmi2_import_get_outputs_list(fmi3_import_t*) +# void fmi2_import_get_outputs_dependencies(fmi3_import_t* fmu, size_t** startIndex, size_t** dependency, char** factorKind) +# void fmi2_import_get_derivatives_dependencies(fmi3_import_t* fmu, size_t** startIndex, size_t** dependency, char** factorKind) +# int fmi2_import_get_enum_type_item_value(fmi2_import_enumeration_typedef_t *, unsigned int) +# char* fmi2_import_get_variable_name(fmi2_import_variable_t*) +# fmi2_real_t fmi2_import_get_real_variable_nominal(fmi2_import_real_variable_t *) +# int fmi2_import_get_variable_has_start(fmi2_import_variable_t*) + char* fmi3_fmu_kind_to_string(fmi3_fmu_kind_enu_t) +# char* fmi2_import_get_string_variable_start(fmi2_import_string_variable_t *) +# double fmi2_import_get_default_experiment_tolerance(fmi3_import_t*) +# int fmi2_import_get_real_type_is_relative_quantity(fmi2_import_real_typedef_t *) +# unsigned int fmi2_import_get_enum_type_size(fmi2_import_enumeration_typedef_t *) +# fmi2_import_variable_list_t* fmi2_import_get_derivatives_list(fmi3_import_t* fmu) +# fmi2_import_real_variable_t* fmi2_import_get_real_variable_derivative_of(fmi2_import_real_variable_t* v) +# fmi2_causality_enu_t fmi2_import_get_causality(fmi2_import_variable_t*) +# fmi2_import_variable_list_t * fmi2_import_get_variable_aliases(fmi3_import_t*, fmi2_import_variable_t*) +# fmi2_import_variable_list_t * fmi2_import_get_variable_list(fmi3_import_t*, int) +# fmi2_import_variable_typedef_t * fmi2_import_get_variable_declared_type(fmi2_import_variable_t*) +# fmi3_boolean_t fmi2_import_get_boolean_variable_start(fmi2_import_bool_variable_t *) +# fmi2_import_enumeration_typedef_t * fmi2_import_get_type_as_enum(fmi2_import_variable_typedef_t *) +# fmi2_import_unit_t * fmi2_import_get_real_type_unit(fmi2_import_real_typedef_t *) +# int fmi2_import_get_enum_variable_min(fmi2_import_enum_variable_t *) +# char* fmi2_import_get_display_unit_name(fmi2_import_display_unit_t *) +# fmi2_real_t fmi2_import_get_real_variable_min(fmi2_import_real_variable_t *) +# fmi2_initial_enu_t fmi2_import_get_initial(fmi2_import_variable_t*) +# int fmi2_import_get_real_type_is_unbounded(fmi2_import_real_typedef_t *) +# fmi2_import_variable_t* fmi2_import_get_variable(fmi2_import_variable_list_t *, size_t) +# char* fmi2_import_get_variable_description(fmi2_import_variable_t*) + const char* fmi3_import_get_model_identifier_CS(fmi3_import_t*) +# char* fmi2_import_get_log_category(fmi3_import_t*, size_t) + const char* fmi3_import_get_last_error(fmi3_import_t*) +# char* fmi2_import_get_enum_type_item_description(fmi2_import_enumeration_typedef_t *, unsigned int) +# fmi2_value_reference_t fmi2_import_get_variable_vr(fmi2_import_variable_t*) +# fmi2_import_display_unit_t * fmi2_import_get_type_display_unit(fmi2_import_real_typedef_t *) +# fmi2_import_variable_t* fmi2_import_get_variable_by_name(fmi3_import_t*, char*) +# double fmi2_import_get_real_type_min(fmi2_import_real_typedef_t *) +# fmi2_import_variable_t* fmi2_import_get_variable_by_vr(fmi3_import_t*, fmi2_base_type_enu_t, fmi2_value_reference_t) +# fmi2_real_t fmi2_import_get_real_variable_max(fmi2_import_real_variable_t *) +# fmi2_import_variable_list_t * fmi2_import_get_derivatives_list(fmi3_import_t*) +# void fmi2_import_free_variable_list(fmi2_import_variable_list_t *) + void fmi3_log_forwarding(fmi3_instance_environment_t, fmi3_status_t, fmi3_string_t, fmi3_string_t) + fmi3_import_t* fmi3_import_parse_xml(FMIL.fmi_import_context_t*, char*, fmi3_xml_callbacks_t*) +# fmi2_real_t fmi2_import_get_real_variable_start(fmi2_import_real_variable_t *) + +# size_t fmi2_import_get_log_categories_num(fmi3_import_t*) +# char* fmi2_import_get_type_quantity(fmi2_import_variable_typedef_t *) +# char* fmi2_import_get_unit_name(fmi2_import_unit_t *) +# fmi2_import_variable_t* fmi2_import_get_variable_alias_base(fmi3_import_t*, fmi2_import_variable_t*) + const char* fmi3_import_get_model_identifier_ME(fmi3_import_t*) + void fmi3_import_destroy_dllfmu(fmi3_import_t*) +# double fmi2_import_get_real_type_nominal(fmi2_import_real_typedef_t *) +# fmi2_import_real_typedef_t * fmi2_import_get_type_as_real(fmi2_import_variable_typedef_t *) +# char* fmi2_import_get_copyright(fmi3_import_t*) +# fmi2_real_t fmi2_import_convert_to_display_unit(fmi2_real_t, fmi2_import_display_unit_t *, int) +# fmi2_import_unit_t * fmi2_import_get_real_variable_unit(fmi2_import_real_variable_t *) +# fmi2_import_display_unit_t * fmi2_import_get_real_variable_display_unit(fmi2_import_real_variable_t *) +# int fmi2_import_get_enum_variable_max(fmi2_import_enum_variable_t *) +# char* fmi2_import_get_type_name(fmi2_import_variable_typedef_t *) +# double fmi2_import_get_real_type_max(fmi2_import_real_typedef_t *) +# size_t fmi2_import_get_variable_list_size(fmi2_import_variable_list_t *) +# fmi2_variable_alias_kind_enu_t fmi2_import_get_variable_alias_kind(fmi2_import_variable_t*) +# int fmi2_import_get_enum_variable_start(fmi2_import_enum_variable_t *) +# fmi2_base_type_enu_t fmi2_import_get_variable_base_type(fmi2_import_variable_t*) +# fmi2_variability_enu_t fmi2_import_get_variability(fmi2_import_variable_t*) +# char* fmi2_import_get_type_description(fmi2_import_variable_typedef_t *) +# fmi2_import_integer_typedef_t * fmi2_import_get_type_as_int(fmi2_import_variable_typedef_t *) +# char* fmi2_import_get_enum_type_item_name(fmi2_import_enumeration_typedef_t *, unsigned int) +# char* fmi2_import_get_model_version(fmi3_import_t*) +# fmi3_boolean_t fmi2_import_get_real_variable_relative_quantity(fmi2_import_real_variable_t* v) +# fmi3_boolean_t fmi2_import_get_real_variable_unbounded(fmi2_import_real_variable_t* v) + +# # unsorted & unused!!! +# size_t fmi2_import_get_derivative_index(fmi2_import_variable_t*) +# void fmi2_default_callback_logger(fmi3_component_t c, fmi3_string_t instanceName, fmi3_status_t status, fmi3_string_t category, fmi3_string_t message, ...) +# void fmi2_import_init_logger(jm_callbacks *, fmi2_callback_functions_t *) +# fmi2_import_unit_t * fmi2_import_get_unit(fmi2_import_unit_definitions_t *, unsigned int) +# fmi2_import_variable_typedef_t * fmi2_import_get_typedef(fmi3_import_type_definitions_t *, unsigned int) +# size_t fmi2_import_get_input_index(fmi2_import_variable_t*) +# size_t fmi2_SI_base_unit_exp_to_string(int *, size_t, char*) +# double fmi2_import_get_SI_unit_factor(fmi2_import_unit_t *) +# unsigned int fmi2_import_get_unit_definitions_number(fmi2_import_unit_definitions_t *) +# fmi2_import_variable_list_t * fmi2_import_join_var_list(fmi2_import_variable_list_t *, fmi2_import_variable_list_t *) +# size_t fmi2_import_get_state_index(fmi2_import_variable_t*) +# int fmi2_import_var_list_push_back(fmi2_import_variable_list_t *, fmi2_import_variable_t*) +# fmi2_import_variable_list_t * fmi2_import_append_to_var_list(fmi2_import_variable_list_t *, fmi2_import_variable_t*) +# void fmi2_log_forwarding_v(fmi3_component_t, fmi3_string_t, int, fmi3_string_t, fmi3_string_t, __va_list_tag *) +# fmi2_base_type_enu_t fmi2_import_get_base_type(fmi2_import_variable_typedef_t *) +# unsigned int fmi2_import_get_unit_display_unit_number(fmi2_import_unit_t *) +# fmi2_value_reference_t * fmi2_import_get_value_referece_list(fmi2_import_variable_list_t *) +# int fmi2_import_clear_last_error(fmi3_import_t*) +# unsigned int fmi2_import_get_type_definition_number(fmi3_import_type_definitions_t *) +# char* fmi2_SI_base_unit_to_string(fmi2_SI_base_units_enu_t) +# unsigned int fmi2_import_get_enum_type_max(fmi2_import_enumeration_typedef_t *) +# fmi2_import_unit_definitions_t * fmi2_import_get_unit_definitions(fmi3_import_t*) +# void fmi2_import_get_dependencies_derivatives_on_inputs(fmi3_import_t*, size_t * *, size_t * *, char* *) +# fmi2_import_variable_list_t * fmi2_import_prepend_to_var_list(fmi2_import_variable_list_t *, fmi2_import_variable_t*) +# void fmi2_import_set_debug_mode(fmi3_import_t*, int) +# char* fmi2_import_get_vendor_name(fmi3_import_t*, size_t) +# double fmi2_import_get_SI_unit_offset(fmi2_import_unit_t *) +# void fmi2_import_expand_variable_references(fmi3_import_t*, char*, char*, size_t) +# size_t fmi2_import_get_variable_original_order(fmi2_import_variable_t*) +# char* fmi2_variability_to_string(fmi2_variability_enu_t) +# fmi2_import_variable_list_t * fmi2_import_create_var_list(fmi3_import_t*, fmi2_import_variable_t*) +# fmi2_real_t fmi2_import_get_display_unit_offset(fmi2_import_display_unit_t *) +# fmi2_import_variable_list_t * fmi2_import_get_sublist(fmi2_import_variable_list_t *, size_t, size_t) +# fmi2_import_variable_list_t * fmi2_import_clone_variable_list(fmi2_import_variable_list_t *) +# unsigned int fmi2_import_get_enum_type_min(fmi2_import_enumeration_typedef_t *) +# char* fmi2_causality_to_string(fmi2_causality_enu_t) +# fmi2_real_t fmi2_import_convert_from_display_unit(fmi2_real_t, fmi2_import_display_unit_t *, int) +# double fmi2_import_convert_from_SI_base_unit(double, fmi2_import_unit_t *) +# int * fmi2_import_get_SI_unit_exponents(fmi2_import_unit_t *) +# char* fmi2_import_get_enum_type_value_name(fmi2_import_enumeration_typedef_t *, int) +# fmi2_import_display_unit_t * fmi2_import_get_unit_display_unit(fmi2_import_unit_t *, size_t) +# fmi2_initial_enu_t fmi2_get_valid_initial(fmi2_variability_enu_t, fmi2_causality_enu_t, fmi2_initial_enu_t) +# fmi2_import_variable_list_t * fmi2_import_filter_variables(fmi2_import_variable_list_t *, fmi2_import_variable_filter_function_ft, void*) +# void fmi2_import_get_dependencies_outputs_on_states(fmi3_import_t*, size_t * *, size_t * *, char* *) +# char* fmi2_base_type_to_string(fmi2_base_type_enu_t) +# size_t fmi2_import_get_vendors_num(fmi3_import_t*) +# void fmi2_import_collect_model_counts(fmi3_import_t*, fmi2_import_model_counts_t *) +# char* fmi2_dependency_factor_kind_to_string(fmi2_dependency_factor_kind_enu_t) +# char* fmi3_status_to_string(int) +# char* fmi2_import_get_model_standard_version(fmi3_import_t*) +# size_t fmi2_import_get_output_index(fmi2_import_variable_t*) +# fmi2_import_unit_t * fmi2_import_get_base_unit(fmi2_import_display_unit_t *) +# fmi2_initial_enu_t fmi2_get_default_initial(fmi2_variability_enu_t, fmi2_causality_enu_t) +# double fmi2_import_convert_to_SI_base_unit(double, fmi2_import_unit_t *) +# void fmi2_import_get_dependencies_derivatives_on_states(fmi3_import_t*, size_t * *, size_t * *, char* *) +# char* fmi2_naming_convention_to_string(fmi2_variable_naming_convension_enu_t) +# fmi3_import_type_definitions_t * fmi2_import_get_type_definitions(fmi3_import_t*) +# char* fmi2_initial_to_string(fmi2_initial_enu_t) +# char* fmi2_capability_to_string(fmi2_capabilities_enu_t) +# fmi2_import_variable_list_t * fmi2_import_get_states_list(fmi3_import_t*) +# fmi2_real_t fmi2_import_get_display_unit_factor(fmi2_import_display_unit_t *) diff --git a/src/pyfmi/fmil_import.pxd b/src/pyfmi/fmil_import.pxd index df38383b..c55fb439 100644 --- a/src/pyfmi/fmil_import.pxd +++ b/src/pyfmi/fmil_import.pxd @@ -136,7 +136,8 @@ cdef extern from 'fmilib.h': fmi_version_unknown_enu = 0 fmi_version_1_enu = 1 fmi_version_2_0_enu = 2 - fmi_version_unsupported_enu = 3 + fmi_version_3_0_enu = 3 + fmi_version_unsupported_enu = 4 cdef enum fmi1_causality_enu_t: fmi1_causality_enu_input = 0