From c2405e58cf1978022eba03c5932e63ceaaf2538f Mon Sep 17 00:00:00 2001 From: Lennart Ochel Date: Sat, 5 Apr 2025 17:05:14 +0200 Subject: [PATCH 01/12] Add simulation support to oms3 api --- CMakeLists.txt | 4 +- include/OMSimulator/OMSimulator.h | 1 + include/OMSimulator/OMSimulator3.h | 71 ++++++++++++++++++++++++++++++ src/OMSimulatorPython/capi.py | 28 ++++++++++++ 4 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 include/OMSimulator/OMSimulator3.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 76184672e..b82555e85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,8 @@ project(OMSimulator) # Options to enable/disable specific components option(OMS_ENABLE_OMSimulator "Enable OMSimulator component" ON) -option(OMS_ENABLE_OMSimulatorGui "Enable OMSimulator GUI component" ON) -option(OMS_ENABLE_PIP "Enable pip component" ON) +option(OMS_ENABLE_OMSimulatorGui "Enable OMSimulator GUI component" OFF) +option(OMS_ENABLE_PIP "Enable pip component" OFF) option(OMS_ENABLE_TESTSUITE "Enable the OMSimulator testsuite" OFF) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/config.cmake/") diff --git a/include/OMSimulator/OMSimulator.h b/include/OMSimulator/OMSimulator.h index 6a55662e7..da17e5e0a 100644 --- a/include/OMSimulator/OMSimulator.h +++ b/include/OMSimulator/OMSimulator.h @@ -33,6 +33,7 @@ #define _OMSIMULATOR_H_ #include "OMSimulator/Types.h" +#include "OMSimulator/OMSimulator3.h" /* define OMSimulatorLib_EXPORTS *only* when building the DLL */ #if defined(OMS_STATIC) diff --git a/include/OMSimulator/OMSimulator3.h b/include/OMSimulator/OMSimulator3.h new file mode 100644 index 000000000..132c7603d --- /dev/null +++ b/include/OMSimulator/OMSimulator3.h @@ -0,0 +1,71 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR + * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from OSMC, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ + +#pragma once + +#include "OMSimulator/Types.h" + +/* define OMSimulatorLib_EXPORTS *only* when building the DLL */ +#if defined(OMS_STATIC) + #define OMSAPI + #define OMSCALL +#else + #if defined(_MSC_VER) || defined(__MINGW32__) + #ifdef OMSimulatorLib_EXPORTS + #define OMSAPI __declspec(dllexport) + #define OMSCALL __cdecl + #else + #define OMSAPI __declspec(dllimport) + #define OMSCALL __cdecl + #endif + #else + #define OMSAPI + #define OMSCALL + #endif +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +OMSAPI void* OMSCALL oms3_modelJson(char* model_json_desc); +OMSAPI oms_status_enu_t OMSCALL oms3_instantiate(void* model); +OMSAPI oms_status_enu_t OMSCALL oms3_initialize(void* model); +OMSAPI oms_status_enu_t OMSCALL oms3_simulate(void* model); +OMSAPI oms_status_enu_t OMSCALL oms3_stepUntil(void* model, double stopTime); +OMSAPI oms_status_enu_t OMSCALL oms3_terminate(void* model); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/OMSimulatorPython/capi.py b/src/OMSimulatorPython/capi.py index 12ebcb8b5..0281e15cc 100644 --- a/src/OMSimulatorPython/capi.py +++ b/src/OMSimulatorPython/capi.py @@ -185,6 +185,34 @@ def __init__(self): self.obj.oms_terminate.argtypes = [ctypes.c_char_p] self.obj.oms_terminate.restype = ctypes.c_int + # oms3 api + self.obj.oms3_modelJson.argtypes = [ctypes.c_char_p] + self.obj.oms3_modelJson.restype = ctypes.c_void_p + self.obj.oms3_instantiate.argtypes = [ctypes.c_void_p] + self.obj.oms3_instantiate.restype = ctypes.c_int + self.obj.oms3_initialize.argtypes = [ctypes.c_void_p] + self.obj.oms3_initialize.restype = ctypes.c_int + self.obj.oms3_simulate.argtypes = [ctypes.c_void_p] + self.obj.oms3_simulate.restype = ctypes.c_int + self.obj.oms3_stepUntil.argtypes = [ctypes.c_void_p, ctypes.c_double] + self.obj.oms3_stepUntil.restype = ctypes.c_int + self.obj.oms3_terminate.argtypes = [ctypes.c_void_p] + self.obj.oms3_terminate.restype = ctypes.c_int + + def oms3_modelJson(self, model_json_desc): + return self.obj.oms3_modelJson(model_json_desc.encode('utf-8')) + def oms3_instantiate(self, model): + return self.obj.oms3_instantiate(model) + def oms3_initialize(self, model): + return self.obj.oms3_initialize(model) + def oms3_simulate(self, model): + return self.obj.oms3_simulate(model) + def oms3_stepUntil(self, model, stopTime): + return self.obj.oms3_stepUntil(model, stopTime) + def oms3_terminate(self, model): + return self.obj.oms3_terminate(model) + + # oms2 api def activateVariant(self, crefA, crefB): return self.obj.oms_activateVariant(crefA.encode(), crefB.encode()) def addBus(self, crefA): From 8b51a6a22fefd66ed98d86446cc1b8b1cf0ba6b4 Mon Sep 17 00:00:00 2001 From: Lennart Ochel Date: Sat, 5 Apr 2025 17:08:50 +0200 Subject: [PATCH 02/12] Remove #endif --- include/OMSimulator/OMSimulator3.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/OMSimulator/OMSimulator3.h b/include/OMSimulator/OMSimulator3.h index 132c7603d..078ba8f1b 100644 --- a/include/OMSimulator/OMSimulator3.h +++ b/include/OMSimulator/OMSimulator3.h @@ -67,5 +67,3 @@ OMSAPI oms_status_enu_t OMSCALL oms3_terminate(void* model); #ifdef __cplusplus } #endif - -#endif From fc77ad6f796bc65fb1e34d7e6dae5c726cead85c Mon Sep 17 00:00:00 2001 From: Lennart Ochel Date: Sat, 5 Apr 2025 18:39:43 +0200 Subject: [PATCH 03/12] Remove oms2 bindings --- include/OMSimulator/OMSimulator.h | 7 +- include/OMSimulator/OMSimulator3.h | 69 ----- src/OMSimulatorLib/OMSimulator.cpp | 26 ++ src/OMSimulatorPython/capi.py | 415 ++--------------------------- 4 files changed, 58 insertions(+), 459 deletions(-) delete mode 100644 include/OMSimulator/OMSimulator3.h diff --git a/include/OMSimulator/OMSimulator.h b/include/OMSimulator/OMSimulator.h index da17e5e0a..632675181 100644 --- a/include/OMSimulator/OMSimulator.h +++ b/include/OMSimulator/OMSimulator.h @@ -33,7 +33,6 @@ #define _OMSIMULATOR_H_ #include "OMSimulator/Types.h" -#include "OMSimulator/OMSimulator3.h" /* define OMSimulatorLib_EXPORTS *only* when building the DLL */ #if defined(OMS_STATIC) @@ -160,6 +159,12 @@ OMSAPI oms_status_enu_t OMSCALL oms_simulate(const char* cref); OMSAPI oms_status_enu_t OMSCALL oms_stepUntil(const char* cref, double stopTime); OMSAPI oms_status_enu_t OMSCALL oms_terminate(const char* cref); +OMSAPI oms_status_enu_t OMSCALL oms3_instantiateFromJson(char* model_json_desc, void** out_model_ptr); +OMSAPI oms_status_enu_t OMSCALL oms3_initialize(void* model); +OMSAPI oms_status_enu_t OMSCALL oms3_simulate(void* model); +OMSAPI oms_status_enu_t OMSCALL oms3_stepUntil(void* model, double stopTime); +OMSAPI oms_status_enu_t OMSCALL oms3_terminate(void* model); + #ifdef __cplusplus } #endif diff --git a/include/OMSimulator/OMSimulator3.h b/include/OMSimulator/OMSimulator3.h deleted file mode 100644 index 078ba8f1b..000000000 --- a/include/OMSimulator/OMSimulator3.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is part of OpenModelica. - * - * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), - * c/o Linköpings universitet, Department of Computer and Information Science, - * SE-58183 Linköping, Sweden. - * - * All rights reserved. - * - * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR - * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. - * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES - * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, - * ACCORDING TO RECIPIENTS CHOICE. - * - * The OpenModelica software and the Open Source Modelica - * Consortium (OSMC) Public License (OSMC-PL) are obtained - * from OSMC, either from the above address, - * from the URLs: http://www.ida.liu.se/projects/OpenModelica or - * http://www.openmodelica.org, and in the OpenModelica distribution. - * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. - * - * This program is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH - * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. - * - * See the full OSMC Public License conditions for more details. - * - */ - -#pragma once - -#include "OMSimulator/Types.h" - -/* define OMSimulatorLib_EXPORTS *only* when building the DLL */ -#if defined(OMS_STATIC) - #define OMSAPI - #define OMSCALL -#else - #if defined(_MSC_VER) || defined(__MINGW32__) - #ifdef OMSimulatorLib_EXPORTS - #define OMSAPI __declspec(dllexport) - #define OMSCALL __cdecl - #else - #define OMSAPI __declspec(dllimport) - #define OMSCALL __cdecl - #endif - #else - #define OMSAPI - #define OMSCALL - #endif -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - -OMSAPI void* OMSCALL oms3_modelJson(char* model_json_desc); -OMSAPI oms_status_enu_t OMSCALL oms3_instantiate(void* model); -OMSAPI oms_status_enu_t OMSCALL oms3_initialize(void* model); -OMSAPI oms_status_enu_t OMSCALL oms3_simulate(void* model); -OMSAPI oms_status_enu_t OMSCALL oms3_stepUntil(void* model, double stopTime); -OMSAPI oms_status_enu_t OMSCALL oms3_terminate(void* model); - -#ifdef __cplusplus -} -#endif diff --git a/src/OMSimulatorLib/OMSimulator.cpp b/src/OMSimulatorLib/OMSimulator.cpp index 6484405b4..cf787cd71 100644 --- a/src/OMSimulatorLib/OMSimulator.cpp +++ b/src/OMSimulatorLib/OMSimulator.cpp @@ -1691,3 +1691,29 @@ oms_status_enu_t oms_setTolerance(const char* cref, double relativeTolerance) return logError_SystemNotInModel(model->getCref(), front); } + + +oms_status_enu_t oms3_instantiateFromJson(char* model_json_desc, void** out_model_ptr) +{ + return oms_status_ok; +} + +oms_status_enu_t oms3_initialize(void* model) +{ + return oms_status_ok; +} + +oms_status_enu_t oms3_simulate(void* model) +{ + return oms_status_ok; +} + +oms_status_enu_t oms3_stepUntil(void* model, double stopTime) +{ + return oms_status_ok; +} + +oms_status_enu_t oms3_terminate(void* model) +{ + return oms_status_ok; +} diff --git a/src/OMSimulatorPython/capi.py b/src/OMSimulatorPython/capi.py index 0281e15cc..5e0520a85 100644 --- a/src/OMSimulatorPython/capi.py +++ b/src/OMSimulatorPython/capi.py @@ -1,5 +1,17 @@ import ctypes import os +from enum import Enum + + +class Status(Enum): + '''Enumeration for status codes (oms_status_enu_t).''' + ok = 0 + warning = 1 + discard = 2 + error = 3 + fatal = 4 + pending = 5 + class capi: def __init__(self): @@ -24,172 +36,10 @@ def __init__(self): if os.name == 'nt' and dllSearchPath: # Windows dllDir.close() - self.obj.oms_activateVariant.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_activateVariant.restype = ctypes.c_int - self.obj.oms_addBus.argtypes = [ctypes.c_char_p] - self.obj.oms_addBus.restype = ctypes.c_int - self.obj.oms_addConnection.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_bool] - self.obj.oms_addConnection.restype = ctypes.c_int - self.obj.oms_addConnector.argtypes = [ctypes.c_char_p, ctypes.c_int, ctypes.c_int] - self.obj.oms_addConnector.restype = ctypes.c_int - self.obj.oms_addConnectorToBus.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_addConnectorToBus.restype = ctypes.c_int - self.obj.oms_addResources.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_addResources.restype = ctypes.c_int - self.obj.oms_addSignalsToResults.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_addSignalsToResults.restype = ctypes.c_int - self.obj.oms_addSubModel.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_addSubModel.restype = ctypes.c_int - self.obj.oms_addSystem.argtypes = [ctypes.c_char_p, ctypes.c_int] - self.obj.oms_addSystem.restype = ctypes.c_int - self.obj.oms_compareSimulationResults.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_double, ctypes.c_double] - self.obj.oms_compareSimulationResults.restype = ctypes.c_int - self.obj.oms_copySystem.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_copySystem.restype = ctypes.c_int - self.obj.oms_delete.argtypes = [ctypes.c_char_p] - self.obj.oms_delete.restype = ctypes.c_int - self.obj.oms_deleteConnection.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_deleteConnection.restype = ctypes.c_int - self.obj.oms_deleteConnectorFromBus.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_deleteConnectorFromBus.restype = ctypes.c_int - self.obj.oms_deleteResources.argtypes = [ctypes.c_char_p] - self.obj.oms_deleteResources.restype = ctypes.c_int - self.obj.oms_doStep.argtypes = [ctypes.c_char_p] - self.obj.oms_doStep.restype = ctypes.c_int - self.obj.oms_duplicateVariant.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_duplicateVariant.restype = ctypes.c_int - self.obj.oms_export.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_export.restype = ctypes.c_int - self.obj.oms_exportDependencyGraphs.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_exportDependencyGraphs.restype = ctypes.c_int - self.obj.oms_exportSnapshot.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_char_p)] - self.obj.oms_exportSnapshot.restype = ctypes.c_int - self.obj.oms_exportSSMTemplate.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_exportSSMTemplate.restype = ctypes.c_int - self.obj.oms_exportSSVTemplate.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_exportSSVTemplate.restype = ctypes.c_int - self.obj.oms_freeMemory.argtypes = [ctypes.c_void_p] - self.obj.oms_freeMemory.restype = None - self.obj.oms_getBoolean.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_bool)] - self.obj.oms_getBoolean.restype = ctypes.c_int - self.obj.oms_getDirectionalDerivative.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_double)] - self.obj.oms_getDirectionalDerivative.restype = ctypes.c_int - self.obj.oms_getFixedStepSize.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_double)] - self.obj.oms_getFixedStepSize.restype = ctypes.c_int - self.obj.oms_getInteger.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_int)] - self.obj.oms_getInteger.restype = ctypes.c_int - self.obj.oms_getModelState.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_int)] - self.obj.oms_getModelState.restype = ctypes.c_int - self.obj.oms_getReal.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_double)] - self.obj.oms_getReal.restype = ctypes.c_int - self.obj.oms_getResultFile.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_char_p), ctypes.POINTER(ctypes.c_int)] - self.obj.oms_getResultFile.restype = ctypes.c_int - self.obj.oms_getSolver.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_int)] - self.obj.oms_getSolver.restype = ctypes.c_int - self.obj.oms_getStartTime.argtypes = [ctypes.c_char_p] - self.obj.oms_getStartTime.restype = ctypes.c_int - self.obj.oms_getStopTime.argtypes = [ctypes.c_char_p] - self.obj.oms_getStopTime.restype = ctypes.c_int - self.obj.oms_getString.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_char_p)] - self.obj.oms_getString.restype = ctypes.c_int - self.obj.oms_getSystemType.argtypes = [ctypes.c_char_p] - self.obj.oms_getSystemType.restype = ctypes.c_int - self.obj.oms_getState.argtypes = [ctypes.c_char_p] - self.obj.oms_getState.restype = ctypes.c_int - self.obj.oms_setState.argtypes = [ctypes.c_char_p] - self.obj.oms_setState.restype = ctypes.c_int - self.obj.oms_freeState.argtypes = [ctypes.c_char_p] - self.obj.oms_freeState.restype = ctypes.c_int - self.obj.oms_getTime.argtypes = [ctypes.c_char_p] - self.obj.oms_getTime.restype = ctypes.c_int - self.obj.oms_getVariableStepSize.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double)] - self.obj.oms_getVariableStepSize.restype = ctypes.c_int self.obj.oms_getVersion.argtypes = None self.obj.oms_getVersion.restype = ctypes.c_char_p - self.obj.oms_importFile.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_char_p)] - self.obj.oms_importFile.restype = ctypes.c_int - self.obj.oms_importSnapshot.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_char_p)] - self.obj.oms_importSnapshot.restype = ctypes.c_int - self.obj.oms_initialize.argtypes = [ctypes.c_char_p] - self.obj.oms_initialize.restype = ctypes.c_int - self.obj.oms_instantiate.argtypes = [ctypes.c_char_p] - self.obj.oms_instantiate.restype = ctypes.c_int - self.obj.oms_list.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_char_p)] - self.obj.oms_list.restype = ctypes.c_int - self.obj.oms_listVariants.argtypes = [ctypes.c_char_p] - self.obj.oms_listVariants.restype = ctypes.c_int - self.obj.oms_listUnconnectedConnectors.argtypes = [ctypes.c_char_p] - self.obj.oms_listUnconnectedConnectors.restype = ctypes.c_int - self.obj.oms_loadSnapshot.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_char_p)] - self.obj.oms_loadSnapshot.restype = ctypes.c_int - self.obj.oms_newModel.argtypes = [ctypes.c_char_p] - self.obj.oms_newModel.restype = ctypes.c_int - self.obj.oms_newResources.argtypes = [ctypes.c_char_p] - self.obj.oms_newResources.restype = ctypes.c_int - self.obj.oms_reduceSSV.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_reduceSSV.restype = ctypes.c_int - self.obj.oms_referenceResources.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_referenceResources.restype = ctypes.c_int - self.obj.oms_removeSignalsFromResults.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_removeSignalsFromResults.restype = ctypes.c_int - self.obj.oms_rename.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_rename.restype = ctypes.c_int - self.obj.oms_replaceSubModel.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_bool, ctypes.POINTER(ctypes.c_int)] - self.obj.oms_replaceSubModel.restype = ctypes.c_int - self.obj.oms_reset.argtypes = [ctypes.c_char_p] - self.obj.oms_reset.restype = ctypes.c_int - self.obj.oms_setBoolean.argtypes = [ctypes.c_char_p, ctypes.c_bool] - self.obj.oms_setBoolean.restype = ctypes.c_int - self.obj.oms_setCommandLineOption.argtypes = [ctypes.c_char_p] - self.obj.oms_setCommandLineOption.restype = ctypes.c_int - self.obj.oms_setFixedStepSize.argtypes = [ctypes.c_char_p, ctypes.c_double] - self.obj.oms_setFixedStepSize.restype = ctypes.c_int - self.obj.oms_setInteger.argtypes = [ctypes.c_char_p, ctypes.c_int] - self.obj.oms_setInteger.restype = ctypes.c_int - self.obj.oms_setLogFile.argtypes = [ctypes.c_char_p] - self.obj.oms_setLogFile.restype = ctypes.c_int - self.obj.oms_setLoggingInterval.argtypes = [ctypes.c_char_p, ctypes.c_double] - self.obj.oms_setLoggingInterval.restype = ctypes.c_int - self.obj.oms_setLoggingLevel.argtypes = [ctypes.c_int] - self.obj.oms_setLoggingLevel.restype = ctypes.c_int - self.obj.oms_setMaxLogFileSize.argtypes = [ctypes.c_ulong] - self.obj.oms_setMaxLogFileSize.restype = None - self.obj.oms_setReal.argtypes = [ctypes.c_char_p, ctypes.c_double] - self.obj.oms_setReal.restype = ctypes.c_int - self.obj.oms_setRealInputDerivative.argtypes = [ctypes.c_char_p, ctypes.c_double] - self.obj.oms_setRealInputDerivative.restype = ctypes.c_int - self.obj.oms_setResultFile.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int] - self.obj.oms_setResultFile.restype = ctypes.c_int - self.obj.oms_setSolver.argtypes = [ctypes.c_char_p, ctypes.c_int] - self.obj.oms_setSolver.restype = ctypes.c_int - self.obj.oms_setStartTime.argtypes = [ctypes.c_char_p, ctypes.c_double] - self.obj.oms_setStartTime.restype = ctypes.c_int - self.obj.oms_setStopTime.argtypes = [ctypes.c_char_p, ctypes.c_double] - self.obj.oms_setStopTime.restype = ctypes.c_int - self.obj.oms_setString.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_setString.restype = ctypes.c_int - self.obj.oms_setTempDirectory.argtypes = [ctypes.c_char_p] - self.obj.oms_setTempDirectory.restype = ctypes.c_int - self.obj.oms_setTolerance.argtypes = [ctypes.c_char_p, ctypes.c_double, ctypes.c_double] - self.obj.oms_setTolerance.restype = ctypes.c_int - self.obj.oms_setUnit.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - self.obj.oms_setUnit.restype = ctypes.c_int - self.obj.oms_setVariableStepSize.argtypes = [ctypes.c_char_p, ctypes.c_double, ctypes.c_double, ctypes.c_double] - self.obj.oms_setVariableStepSize.restype = ctypes.c_int - self.obj.oms_setWorkingDirectory.argtypes = [ctypes.c_char_p] - self.obj.oms_setWorkingDirectory.restype = ctypes.c_int - self.obj.oms_simulate.argtypes = [ctypes.c_char_p] - self.obj.oms_simulate.restype = ctypes.c_int - self.obj.oms_stepUntil.argtypes = [ctypes.c_char_p, ctypes.c_double] - self.obj.oms_stepUntil.restype = ctypes.c_int - self.obj.oms_terminate.argtypes = [ctypes.c_char_p] - self.obj.oms_terminate.restype = ctypes.c_int - - # oms3 api - self.obj.oms3_modelJson.argtypes = [ctypes.c_char_p] - self.obj.oms3_modelJson.restype = ctypes.c_void_p - self.obj.oms3_instantiate.argtypes = [ctypes.c_void_p] - self.obj.oms3_instantiate.restype = ctypes.c_int + self.obj.oms3_instantiateFromJson.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_void_p)] + self.obj.oms3_instantiateFromJson.restype = ctypes.c_int self.obj.oms3_initialize.argtypes = [ctypes.c_void_p] self.obj.oms3_initialize.restype = ctypes.c_int self.obj.oms3_simulate.argtypes = [ctypes.c_void_p] @@ -199,232 +49,19 @@ def __init__(self): self.obj.oms3_terminate.argtypes = [ctypes.c_void_p] self.obj.oms3_terminate.restype = ctypes.c_int - def oms3_modelJson(self, model_json_desc): - return self.obj.oms3_modelJson(model_json_desc.encode('utf-8')) - def oms3_instantiate(self, model): - return self.obj.oms3_instantiate(model) - def oms3_initialize(self, model): + def getVersion(self): + return self.obj.oms_getVersion().decode('utf-8') + def instantiateFromJson(self, model_json_desc): + model_ptr = ctypes.c_void_p() + status = self.obj.oms3_instantiateFromJson(model_json_desc.encode('utf-8'), ctypes.byref(model_ptr)) + if status != Status.ok: + return [None, status] + return [model_ptr, status] + def initialize(self, model): return self.obj.oms3_initialize(model) - def oms3_simulate(self, model): + def simulate(self, model): return self.obj.oms3_simulate(model) - def oms3_stepUntil(self, model, stopTime): + def stepUntil(self, model, stopTime): return self.obj.oms3_stepUntil(model, stopTime) - def oms3_terminate(self, model): + def terminate(self, model): return self.obj.oms3_terminate(model) - - # oms2 api - def activateVariant(self, crefA, crefB): - return self.obj.oms_activateVariant(crefA.encode(), crefB.encode()) - def addBus(self, crefA): - return self.obj.oms_addBus(crefA.encode()) - def addConnection(self, crefA, crefB, suppressUnit=False): - return self.obj.oms_addConnection(crefA.encode(), crefB.encode(), suppressUnit) - def addConnector(self, cref, causality, type_): - return self.obj.oms_addConnector(cref.encode(), causality, type_) - def addConnectorToBus(self, busCref, connectorCref): - return self.obj.oms_addConnectorToBus(busCref.encode(), connectorCref.encode()) - def addResources(self, cref, path): - return self.obj.oms_addResources(cref.encode(), path.encode()) - def addSignalsToResults(self, cref, regex): - return self.obj.oms_addSignalsToResults(cref.encode(), regex.encode()) - def addSubModel(self, cref, fmuPath): - return self.obj.oms_addSubModel(cref.encode(), fmuPath.encode()) - def addSystem(self, ident, type_): - return self.obj.oms_addSystem(ident.encode(), type_) - def compareSimulationResults(self, filenameA, filenameB, var, relTol, absTol): - return self.obj.oms_compareSimulationResults(filenameA.encode(), filenameB.encode(), var.encode(), relTol, absTol) - def copySystem(self, source, target): - return self.obj.oms_copySystem(source.encode(), target.encode()) - def delete(self, cref): - return self.obj.oms_delete(cref.encode()) - def deleteConnection(self, crefA, crefB): - return self.obj.oms_deleteConnection(crefA.encode(), crefB.encode()) - def deleteConnectorFromBus(self, busCref, connectorCref): - return self.obj.oms_deleteConnectorFromBus(busCref.encode(), connectorCref.encode()) - def deleteResources(self, crefA): - return self.obj.oms_deleteResources(crefA.encode()) - def doStep(self, cref): - return self.obj.oms_doStep(cref.encode()) - def duplicateVariant(self, crefA, crefB): - return self.obj.oms_duplicateVariant(crefA.encode(), crefB.encode()) - def export(self, cref, filename): - return self.obj.oms_export(cref.encode(), filename.encode()) - def exportDependencyGraphs(self, cref, initialization, event, simulation): - return self.obj.oms_exportDependencyGraphs(cref.encode(), initialization.encode(), event.encode(), simulation.encode()) - def exportSnapshot(self, ident): - contents = ctypes.c_char_p() - status = self.obj.oms_exportSnapshot(ident.encode(), ctypes.byref(contents)) - contents_ = contents.value.decode('utf-8') if contents.value else None - self.obj.oms_freeMemory(contents) - return [contents_, status] - def exportSSMTemplate(self, ident, filename): - return self.obj.oms_exportSSMTemplate(ident.encode(), filename.encode()) - def exportSSVTemplate(self, ident, filename): - return self.obj.oms_exportSSVTemplate(ident.encode(), filename.encode()) - def getBoolean(self, cref): - value = ctypes.c_bool() - status = self.obj.oms_getBoolean(cref.encode(), ctypes.byref(value)) - return [value.value, status] - def getDirectionalDerivative(self, crefA, crefB=""): - value = ctypes.c_double() - status = self.obj.oms_getDirectionalDerivative(crefA.encode(), crefB.encode(), ctypes.byref(value)) - return [value.value, status] - def getFixedStepSize(self, cref): - value = ctypes.c_double() - status = self.obj.oms_getFixedStepSize(cref.encode(), ctypes.byref(value)) - return [value.value, status] - def getInteger(self, cref): - value = ctypes.c_int() - status = self.obj.oms_getInteger(cref.encode(), ctypes.byref(value)) - return [value.value, status] - def getModelState(self, cref): - value = ctypes.c_int() - status = self.obj.oms_getModelState(cref.encode(), ctypes.byref(value)) - return [value.value, status] - def getReal(self, cref): - value = ctypes.c_double() - status = self.obj.oms_getReal(cref.encode(), ctypes.byref(value)) - return [value.value, status] - def getResultFile(self, cref): - filename = ctypes.c_char_p() - bufferSize = ctypes.c_int() - status = self.obj.oms_getResultFile(cref.encode(), ctypes.byref(filename), ctypes.byref(bufferSize)) - return [filename.value.decode('utf-8') if filename.value else None, bufferSize.value, status] - def getSolver(self, cref): - value = ctypes.c_int() - status = self.obj.oms_getSolver(cref.encode(), ctypes.byref(value)) - return [value.value, status] - def getStartTime(self, cref): - startTime = ctypes.c_double() - status = self.obj.oms_getStartTime(cref.encode(), ctypes.byref(startTime)) - return [startTime.value, status] - def getStopTime(self, cref): - stopTime = ctypes.c_double() - status = self.obj.oms_getStopTime(cref.encode(), ctypes.byref(stopTime)) - return [stopTime.value, status] - def getString(self, cref): - value = ctypes.c_char_p() - status = self.obj.oms_getString(cref.encode(), ctypes.byref(value)) - value_ = value.value.decode('utf-8') if value.value else None - self.obj.oms_freeMemory(value) - return [value_, status] - def getSystemType(self, cref): - type_ = ctypes.c_int() - status = self.obj.oms_getSystemType(cref.encode(), ctypes.byref(type_)) - return [type_.value, status] - def getState(self, cref): - return self.obj.oms_getState(cref.encode()) - def setState(self, cref): - return self.obj.oms_setState(cref.encode()) - def freeState(self, cref): - return self.obj.oms_freeState(cref.encode()) - def getTime(self, cref): - time = ctypes.c_double() - status = self.obj.oms_getTime(cref.encode(), ctypes.byref(time)) - return [time.value, status] - def getVariableStepSize(self, cref): - initialStepSize = ctypes.c_double() - minimumStepSize = ctypes.c_double() - maximumStepSize = ctypes.c_double() - status = self.obj.oms_getVariableStepSize(cref.encode(), ctypes.byref(initialStepSize), ctypes.byref(minimumStepSize), ctypes.byref(maximumStepSize)) - return [initialStepSize.value, minimumStepSize.value, maximumStepSize.value, status] - def getVersion(self): - return self.obj.oms_getVersion().decode('utf-8') - def importFile(self, filename): - cref = ctypes.c_char_p() - status = self.obj.oms_importFile(filename.encode(), ctypes.byref(cref)) - return [cref.value.decode('utf-8') if cref.value else None, status] - def importSnapshot(self, ident, snapshot): - newCref = ctypes.c_char_p() - status = self.obj.oms_importSnapshot(ident.encode(), snapshot.encode(), ctypes.byref(newCref)) - return [newCref.value.decode('utf-8') if newCref.value else None, status] - def initialize(self, cref): - return self.obj.oms_initialize(cref.encode()) - def instantiate(self, cref): - return self.obj.oms_instantiate(cref.encode()) - def list(self, ident): - contents = ctypes.c_char_p() - status = self.obj.oms_list(ident.encode(), ctypes.byref(contents)) - contents_ = contents.value.decode('utf-8') if contents.value else None - self.obj.oms_freeMemory(contents) - return [contents_, status] - def listVariants(self, ident): - contents = ctypes.c_char_p() - status = self.obj.oms_listVariants(ident.encode(), ctypes.byref(contents)) - contents_ = contents.value.decode('utf-8') if contents.value else None - self.obj.oms_freeMemory(contents) - return [contents_, status] - def listUnconnectedConnectors(self, ident): - contents = ctypes.c_char_p() - status = self.obj.oms_listUnconnectedConnectors(ident.encode(), ctypes.byref(contents)) - contents_ = contents.value.decode('utf-8') if contents.value else None - self.obj.oms_freeMemory(contents) - return [contents_, status] - def loadSnapshot(self, ident, snapshot): - newCref = ctypes.c_char_p() - status = self.obj.oms_loadSnapshot(ident.encode(), snapshot.encode(), ctypes.byref(newCref)) - return [newCref.value.decode('utf-8') if newCref.value else None, status] - def newModel(self, cref): - return self.obj.oms_newModel(cref.encode()) - def newResources(self, crefA): - return self.obj.oms_newResources(crefA.encode()) - def reduceSSV(self, crefA, crefB, crefC, crefD=""): - return self.obj.oms_reduceSSV(crefA.encode(), crefB.encode(), crefC.encode(), crefD.encode()) - def referenceResources(self, crefA, crefB=""): - return self.obj.oms_referenceResources(crefA.encode(), crefB.encode()) - def removeSignalsFromResults(self, cref, regex): - return self.obj.oms_removeSignalsFromResults(cref.encode(), regex.encode()) - def rename(self, cref, newcref): - return self.obj.oms_rename(cref.encode(), newcref.encode()) - def replaceSubModel(self, cref, fmuPath, dryRun): - value = ctypes.c_int() - status = self.obj.oms_replaceSubModel(cref.encode(), fmuPath.encode(), dryRun, ctypes.byref(value)) - return [value.value, status] - def reset(self, cref): - return self.obj.oms_reset(cref.encode()) - def setBoolean(self, signal, value): - return self.obj.oms_setBoolean(signal.encode(), value) - def setCommandLineOption(self, cmd): - return self.obj.oms_setCommandLineOption(cmd.encode()) - def setFixedStepSize(self, cref, stepSize): - return self.obj.oms_setFixedStepSize(cref.encode(), stepSize) - def setInteger(self, signal, value): - return self.obj.oms_setInteger(signal.encode(), value) - def setLogFile(self, filename): - return self.obj.oms_setLogFile(filename.encode()) - def setLoggingInterval(self, cref, loggingInterval): - return self.obj.oms_setLoggingInterval(cref.encode(), loggingInterval) - def setLoggingLevel(self, level): - return self.obj.oms_setLoggingLevel(level) - def setMaxLogFileSize(self, size): - return self.obj.oms_setMaxLogFileSize(size) - def setReal(self, signal, value): - return self.obj.oms_setReal(signal.encode(), value) - def setRealInputDerivative(self, signal, value): - return self.obj.oms_setRealInputDerivative(signal.encode(), value) - def setResultFile(self, cref, filename, bufferSize=1): - return self.obj.oms_setResultFile(cref.encode(), filename.encode(), bufferSize) - def setSolver(self, cref, solver): - return self.obj.oms_setSolver(cref.encode(), solver) - def setStartTime(self, cref, startTime): - return self.obj.oms_setStartTime(cref.encode(), startTime) - def setStopTime(self, cref, stopTime): - return self.obj.oms_setStopTime(cref.encode(), stopTime) - def setString(self, signal, value): - return self.obj.oms_setString(signal.encode(), value.encode()) - def setTempDirectory(self, newTempDir): - return self.obj.oms_setTempDirectory(newTempDir.encode()) - def setTolerance(self, cref, relativeTolerance): - return self.obj.oms_setTolerance(cref.encode(), relativeTolerance) - def setUnit(self, signal, value): - return self.obj.oms_setUnit(signal.encode(), value.encode()) - def setVariableStepSize(self, cref, initialStepSize, minimumStepSize, maximumStepSize): - return self.obj.oms_setVariableStepSize(cref.encode(), initialStepSize, minimumStepSize, maximumStepSize) - def setWorkingDirectory(self, path): - return self.obj.oms_setWorkingDirectory(path.encode()) - def simulate(self, cref): - return self.obj.oms_simulate(cref.encode()) - def stepUntil(self, cref, stopTime): - return self.obj.oms_stepUntil(cref.encode(), stopTime) - def terminate(self, cref): - return self.obj.oms_terminate(cref.encode()) From f6ea239755a746e8a244d99da2e8f2a5c2081e30 Mon Sep 17 00:00:00 2001 From: Lennart Ochel Date: Sat, 5 Apr 2025 19:36:06 +0200 Subject: [PATCH 04/12] Return Status enum instead of integer --- src/OMSimulatorPython/capi.py | 37 ++++++++++----- testsuite/resources/sim.json | 87 +++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 11 deletions(-) create mode 100644 testsuite/resources/sim.json diff --git a/src/OMSimulatorPython/capi.py b/src/OMSimulatorPython/capi.py index 5e0520a85..88a59639f 100644 --- a/src/OMSimulatorPython/capi.py +++ b/src/OMSimulatorPython/capi.py @@ -51,17 +51,32 @@ def __init__(self): def getVersion(self): return self.obj.oms_getVersion().decode('utf-8') - def instantiateFromJson(self, model_json_desc): + + def instantiateFromJson(self, model_json_desc) -> tuple: + '''Instantiate a model from a JSON description.''' model_ptr = ctypes.c_void_p() status = self.obj.oms3_instantiateFromJson(model_json_desc.encode('utf-8'), ctypes.byref(model_ptr)) if status != Status.ok: - return [None, status] - return [model_ptr, status] - def initialize(self, model): - return self.obj.oms3_initialize(model) - def simulate(self, model): - return self.obj.oms3_simulate(model) - def stepUntil(self, model, stopTime): - return self.obj.oms3_stepUntil(model, stopTime) - def terminate(self, model): - return self.obj.oms3_terminate(model) + return None, Status(status) + return model_ptr, Status(status) + + def initialize(self, model) -> Status: + '''Enters initialization mode.''' + status = self.obj.oms3_initialize(model) + return Status(status) + + def simulate(self, model) -> Status: + '''Exits initialization mode and runs the simulation until stopTime is reached.''' + status = self.obj.oms3_simulate(model) + return Status(status) + + def stepUntil(self, model, stopTime) -> Status: + '''Step the simulation until the specified stop time. + Note: If the model is in initialization mode, this will exit initialization mode.''' + status = self.obj.oms3_stepUntil(model, stopTime) + return Status(status) + + def terminate(self, model) -> Status: + '''Terminate the simulation and free resources.''' + status = self.obj.oms3_terminate(model) + return Status(status) diff --git a/testsuite/resources/sim.json b/testsuite/resources/sim.json new file mode 100644 index 000000000..50a4ca3f4 --- /dev/null +++ b/testsuite/resources/sim.json @@ -0,0 +1,87 @@ +{ + "components": [ + { + "name": "Plant", + "type": "model exchange", + "path": "resources/Plant.fmu" + }, + { + "name": "Controller", + "type": "co-simulation", + "path": "resources/Controller.fmu" + }, + { + "name": "Sensor", + "type": "model exchange", + "path": "resources/Sensor.fmu" + } + ], + "simulation units": [ + { + "components": [ + "Controller" + ], + "solver": { + "type": "co-simulation" + }, + "connections": [] + }, + { + "components": [ + "Plant", + "Sensor" + ], + "solver": { + "type": "CVODE", + "stepSize": 0.01, + "tolerance": 1e-5 + }, + "connections": [ + { + "start element": "Sensor", + "start connector": "output", + "end element": "Plant", + "end connector": "input" + } + ] + } + ], + "connections": [ + { + "start element": "Controller", + "start connector": "output", + "end element": "Plant", + "end connector": "input" + }, + { + "start element": "Sensor", + "start connector": "output", + "end element": "Controller", + "end connector": "input" + } + ], + "result file": "simulation_result.csv", + "signals": [ + { + "element": "Plant", + "connector": "output" + }, + { + "element": "Sensor", + "connector": "output" + }, + { + "element": "Controller", + "connector": "output" + }, + { + "element": "Controller", + "connector": "input" + } + ], + "simulation settings": { + "start time": 0.0, + "stop time": 10.0, + "tolerance": 1e-6 + } +} From cadcb0b53d0e5d8b718ea25957938cdccf58af72 Mon Sep 17 00:00:00 2001 From: Lennart Ochel Date: Sat, 5 Apr 2025 20:24:50 +0200 Subject: [PATCH 05/12] Add test --- src/OMSimulatorPython/__init__.py | 7 ++-- src/OMSimulatorPython/capi.py | 3 ++ testsuite/Makefile | 8 +++- testsuite/simulation/Makefile | 51 ++++++++++++++++++++++++ testsuite/simulation/SimpleSimulation.py | 33 +++++++++++++++ 5 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 testsuite/simulation/Makefile create mode 100644 testsuite/simulation/SimpleSimulation.py diff --git a/src/OMSimulatorPython/__init__.py b/src/OMSimulatorPython/__init__.py index 5e1da1f72..5d70c2751 100644 --- a/src/OMSimulatorPython/__init__.py +++ b/src/OMSimulatorPython/__init__.py @@ -4,6 +4,7 @@ OpenModelica FMI & SSP based simulator. ''' +from OMSimulator.capi import Capi from OMSimulator.connection import Connection from OMSimulator.connector import Connector from OMSimulator.cref import CRef @@ -15,10 +16,8 @@ from OMSimulator.system import System from OMSimulator.variable import Causality, SignalType, Variable -from OMSimulator import capi - # Define public API -__all__ = ['Connection', 'Connector', 'CRef', 'FMU', 'Settings', 'SSD', 'SSP', 'SSV', 'System', 'Causality', 'SignalType', 'Variable'] +__all__ = ['Capi', 'Connection', 'Connector', 'CRef', 'FMU', 'Settings', 'SSD', 'SSP', 'SSV', 'System', 'Causality', 'SignalType', 'Variable'] __version__ = '@OMS_SHORT_VERSION_STRING@' __author__ = 'Open Source Modelica Consortium (OSMC)' @@ -28,4 +27,4 @@ c/o Linköpings universitet, Department of Computer and Information Science, SE-58183 Linköping, Sweden.''' -version = capi.capi().getVersion() +version = Capi.getVersion() diff --git a/src/OMSimulatorPython/capi.py b/src/OMSimulatorPython/capi.py index 88a59639f..d503fe2d8 100644 --- a/src/OMSimulatorPython/capi.py +++ b/src/OMSimulatorPython/capi.py @@ -80,3 +80,6 @@ def terminate(self, model) -> Status: '''Terminate the simulation and free resources.''' status = self.obj.oms3_terminate(model) return Status(status) + + +Capi = capi() diff --git a/testsuite/Makefile b/testsuite/Makefile index 6e4a6c9e4..98e94fa3d 100644 --- a/testsuite/Makefile +++ b/testsuite/Makefile @@ -2,7 +2,7 @@ all: difftool resources test -test: api.log parker.log dcmotor.log +test: api.log parker.log dcmotor.log simulation.log partest: difftool resources cd partest && time ./runtests.pl -nocolour -with-xml @@ -23,4 +23,8 @@ parker.log: difftool dcmotor.log: difftool @$(MAKE) -C dcmotor -f Makefile test > $@ - @grep == dcmotor.log \ No newline at end of file + @grep == dcmotor.log + +simulation.log: difftool + @$(MAKE) -C simulation -f Makefile test > $@ + @grep == simulation.log diff --git a/testsuite/simulation/Makefile b/testsuite/simulation/Makefile new file mode 100644 index 000000000..0e61e970f --- /dev/null +++ b/testsuite/simulation/Makefile @@ -0,0 +1,51 @@ +TEST = ../rtest -v + +TESTFILES = \ +SimpleSimulation.py \ + +# Run make failingtest +FAILINGTESTFILES = \ + +# Dependency files that are not .lua or Makefile +# Add them here or they will be cleaned. +DEPENDENCIES = \ +*.lua \ +*.py \ +Makefile \ + +CLEAN = `ls | grep -w -v -f deps.tmp` + +.PHONY : test clean getdeps failingtest + +test: + @echo + @echo Running tests... + @$(TEST) $(TESTFILES) + +baseline: + @echo + @echo Updating badelines... + @$(TEST) -b $(TESTFILES) + +# Cleans all files that are not listed as dependencies +clean: + @echo $(DEPENDENCIES) | sed 's/ /\\\|/g' > deps.tmp + @rm -rf $(CLEAN) + +# Run this if you want to list out the files (dependencies). +# do it after cleaning and updating the folder +# then you can get a list of file names (which must be dependencies +# since you got them from repository + your own new files) +# then add them to the DEPENDENCIES. You can find the +# list in deps.txt +getdeps: + @echo $(DEPENDENCIES) | sed 's/ /\\\|/g' > deps.tmp + @echo $(CLEAN) | sed -r 's/deps.txt|deps.tmp//g' | sed 's/ / \\\n/g' > deps.txt + @echo Dependency list saved in deps.txt. + @echo Copy the list from deps.txt and add it to the Makefile @DEPENDENCIES + +failingtest: + @echo + @echo Running failing tests... + @echo + @$(TEST) $(FAILINGTESTFILES) diff --git a/testsuite/simulation/SimpleSimulation.py b/testsuite/simulation/SimpleSimulation.py new file mode 100644 index 000000000..9137a10ce --- /dev/null +++ b/testsuite/simulation/SimpleSimulation.py @@ -0,0 +1,33 @@ +## status: correct +## teardown_command: +## linux: yes +## ucrt64: yes +## win: yes +## mac: yes + +from OMSimulator import Capi, Settings + +Settings.suppressPath = True + +# read json object from file +with open('../resources/sim.json', 'r') as file: + json_data = file.read() + +model, status = Capi.instantiateFromJson(json_data) +print(f'status: {status}') +status = Capi.initialize(model) +print(f'status: {status}') +status = Capi.simulate(model) +print(f'status: {status}') +status = Capi.simulate(model) +print(f'status: {status}') +status = Capi.terminate(model) +print(f'status: {status}') + +## Result: +## status: Status.ok +## status: Status.ok +## status: Status.ok +## status: Status.ok +## status: Status.ok +## endResult From 5eb96eb46f48cb46a3b78147c9f050ae4f0c7c9d Mon Sep 17 00:00:00 2001 From: Lennart Ochel Date: Sat, 5 Apr 2025 21:49:43 +0200 Subject: [PATCH 06/12] Update test --- src/OMSimulatorLib/OMSimulator.cpp | 2 + testsuite/resources/sim.json | 63 ++++++++++-------------- testsuite/simulation/SimpleSimulation.py | 19 +++---- 3 files changed, 35 insertions(+), 49 deletions(-) diff --git a/src/OMSimulatorLib/OMSimulator.cpp b/src/OMSimulatorLib/OMSimulator.cpp index cf787cd71..5a37f399c 100644 --- a/src/OMSimulatorLib/OMSimulator.cpp +++ b/src/OMSimulatorLib/OMSimulator.cpp @@ -1695,6 +1695,8 @@ oms_status_enu_t oms_setTolerance(const char* cref, double relativeTolerance) oms_status_enu_t oms3_instantiateFromJson(char* model_json_desc, void** out_model_ptr) { + *out_model_ptr = nullptr; + logDebug(model_json_desc); return oms_status_ok; } diff --git a/testsuite/resources/sim.json b/testsuite/resources/sim.json index 50a4ca3f4..1e03ecb20 100644 --- a/testsuite/resources/sim.json +++ b/testsuite/resources/sim.json @@ -1,25 +1,15 @@ { - "components": [ - { - "name": "Plant", - "type": "model exchange", - "path": "resources/Plant.fmu" - }, - { - "name": "Controller", - "type": "co-simulation", - "path": "resources/Controller.fmu" - }, - { - "name": "Sensor", - "type": "model exchange", - "path": "resources/Sensor.fmu" - } - ], "simulation units": [ { "components": [ - "Controller" + { + "name": "Controller", + "type": "co-simulation", + "path": "resources/Controller.fmu", + "variables": [ + "output" + ] + } ], "solver": { "type": "co-simulation" @@ -28,8 +18,23 @@ }, { "components": [ - "Plant", - "Sensor" + { + "name": "Plant", + "type": "model exchange", + "path": "resources/Plant.fmu", + "variables": [ + "input", + "output" + ] + }, + { + "name": "Sensor", + "type": "model exchange", + "path": "resources/Sensor.fmu", + "variables": [ + "output" + ] + } ], "solver": { "type": "CVODE", @@ -61,24 +66,6 @@ } ], "result file": "simulation_result.csv", - "signals": [ - { - "element": "Plant", - "connector": "output" - }, - { - "element": "Sensor", - "connector": "output" - }, - { - "element": "Controller", - "connector": "output" - }, - { - "element": "Controller", - "connector": "input" - } - ], "simulation settings": { "start time": 0.0, "stop time": 10.0, diff --git a/testsuite/simulation/SimpleSimulation.py b/testsuite/simulation/SimpleSimulation.py index 9137a10ce..67629d3e5 100644 --- a/testsuite/simulation/SimpleSimulation.py +++ b/testsuite/simulation/SimpleSimulation.py @@ -14,20 +14,17 @@ json_data = file.read() model, status = Capi.instantiateFromJson(json_data) -print(f'status: {status}') +print(f'instantiateFromJson: {status}') status = Capi.initialize(model) -print(f'status: {status}') +print(f'initialize: {status}') status = Capi.simulate(model) -print(f'status: {status}') -status = Capi.simulate(model) -print(f'status: {status}') +print(f'simulate: {status}') status = Capi.terminate(model) -print(f'status: {status}') +print(f'terminate: {status}') ## Result: -## status: Status.ok -## status: Status.ok -## status: Status.ok -## status: Status.ok -## status: Status.ok +## instantiateFromJson: Status.ok +## initialize: Status.ok +## simulate: Status.ok +## terminate: Status.ok ## endResult From 4bcac9d6d1b7cfdf48c674dc12a09751880afe81 Mon Sep 17 00:00:00 2001 From: Lennart Ochel Date: Fri, 11 Apr 2025 12:08:35 +0200 Subject: [PATCH 07/12] WIP --- testsuite/resources/sim.json | 15 ++++-------- testsuite/resources/sim_singleFMU.json | 33 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 11 deletions(-) create mode 100644 testsuite/resources/sim_singleFMU.json diff --git a/testsuite/resources/sim.json b/testsuite/resources/sim.json index 1e03ecb20..ed463b81c 100644 --- a/testsuite/resources/sim.json +++ b/testsuite/resources/sim.json @@ -4,11 +4,9 @@ "components": [ { "name": "Controller", - "type": "co-simulation", + "type": "FMI 2 CS", "path": "resources/Controller.fmu", - "variables": [ - "output" - ] + "variables": ["output"] } ], "solver": { @@ -22,18 +20,13 @@ "name": "Plant", "type": "model exchange", "path": "resources/Plant.fmu", - "variables": [ - "input", - "output" - ] + "variables": ["input", "output"] }, { "name": "Sensor", "type": "model exchange", "path": "resources/Sensor.fmu", - "variables": [ - "output" - ] + "variables": ["output"] } ], "solver": { diff --git a/testsuite/resources/sim_singleFMU.json b/testsuite/resources/sim_singleFMU.json new file mode 100644 index 000000000..03907f429 --- /dev/null +++ b/testsuite/resources/sim_singleFMU.json @@ -0,0 +1,33 @@ +{ + "temp dir": "temp", + "working dir": "working", + "simulation units": [ + { + "components": [ + { + "name": "", + "type": "FMI 2 ME", + "path": "resources/Controller.fmu", + "variables": { + "output": 15, + "state1": 0 + } + } + ], + "solver": { + "type": "model exchange", + "solver": "CVODE", + "stepSize": 0.01, + "tolerance": 1e-5 + }, + "connections": [] + } + ], + "connections": [], + "result file": "simulation_result.csv", + "simulation settings": { + "start time": 0.0, + "stop time": 10.0, + "tolerance": 1e-6 + } +} From 5439be960999a2d78849cb8abcf9a63c93de9700 Mon Sep 17 00:00:00 2001 From: Lennart Ochel Date: Tue, 29 Apr 2025 08:42:19 +0200 Subject: [PATCH 08/12] Move tests around --- src/OMSimulatorPython/system.py | 15 ++++++++------- testsuite/api/Makefile | 3 --- testsuite/simulation/Makefile | 4 ++++ testsuite/{api => simulation}/exportJson1.py | 0 testsuite/{api => simulation}/exportJson2.py | 0 testsuite/{api => simulation}/exportJson3.py | 0 testsuite/{api => simulation}/exportJson4.py | 0 7 files changed, 12 insertions(+), 10 deletions(-) rename testsuite/{api => simulation}/exportJson1.py (100%) rename testsuite/{api => simulation}/exportJson2.py (100%) rename testsuite/{api => simulation}/exportJson3.py (100%) rename testsuite/{api => simulation}/exportJson4.py (100%) diff --git a/src/OMSimulatorPython/system.py b/src/OMSimulatorPython/system.py index 76d599962..9928309ff 100644 --- a/src/OMSimulatorPython/system.py +++ b/src/OMSimulatorPython/system.py @@ -1,18 +1,17 @@ +import json import logging +from collections import defaultdict from lxml import etree as ET from OMSimulator.component import Component -from OMSimulator.connector import Connector from OMSimulator.connection import Connection +from OMSimulator.connector import Connector +from OMSimulator.elementgeometry import ElementGeometry from OMSimulator.fmu import FMU -from OMSimulator.values import Values from OMSimulator.ssv import SSV -from OMSimulator.elementgeometry import ElementGeometry - -from OMSimulator import CRef, namespace, utils +from OMSimulator.values import Values -from collections import defaultdict -import json +from OMSimulator import Capi, CRef, namespace, utils logger = logging.getLogger(__name__) @@ -305,6 +304,8 @@ def instantiate(self): # Dump JSON json_string = json.dumps(data, indent=2) print(json_string) + model, status = Capi.instantiateFromJson(json_string) + print(status) def processElements(self, elements_dict: dict, connections: list, data: dict, solver_groups : defaultdict, componentSolver : dict, solver_connections : defaultdict, systemName = None): diff --git a/testsuite/api/Makefile b/testsuite/api/Makefile index 562ba03af..d2771609d 100644 --- a/testsuite/api/Makefile +++ b/testsuite/api/Makefile @@ -3,9 +3,6 @@ TEST = ../rtest -v TESTFILES = \ create_ssp_file.py \ cref.py \ -exportJson1.py \ -exportJson2.py \ -exportJson4.py \ fmuinfo.py \ invalidSSD.py \ invalidSSV.py \ diff --git a/testsuite/simulation/Makefile b/testsuite/simulation/Makefile index 0e61e970f..a1ce7a5e7 100644 --- a/testsuite/simulation/Makefile +++ b/testsuite/simulation/Makefile @@ -1,6 +1,10 @@ TEST = ../rtest -v TESTFILES = \ +exportJson1.py \ +exportJson2.py \ +exportJson3.py \ +exportJson4.py \ SimpleSimulation.py \ # Run make failingtest diff --git a/testsuite/api/exportJson1.py b/testsuite/simulation/exportJson1.py similarity index 100% rename from testsuite/api/exportJson1.py rename to testsuite/simulation/exportJson1.py diff --git a/testsuite/api/exportJson2.py b/testsuite/simulation/exportJson2.py similarity index 100% rename from testsuite/api/exportJson2.py rename to testsuite/simulation/exportJson2.py diff --git a/testsuite/api/exportJson3.py b/testsuite/simulation/exportJson3.py similarity index 100% rename from testsuite/api/exportJson3.py rename to testsuite/simulation/exportJson3.py diff --git a/testsuite/api/exportJson4.py b/testsuite/simulation/exportJson4.py similarity index 100% rename from testsuite/api/exportJson4.py rename to testsuite/simulation/exportJson4.py From 72bc5004daa8176d0d2bb11dd789bddf733a2770 Mon Sep 17 00:00:00 2001 From: Lennart Ochel Date: Tue, 29 Apr 2025 08:43:13 +0200 Subject: [PATCH 09/12] Expected output --- testsuite/simulation/exportJson1.py | 1 + testsuite/simulation/exportJson2.py | 1 + testsuite/simulation/exportJson3.py | 1 + testsuite/simulation/exportJson4.py | 1 + 4 files changed, 4 insertions(+) diff --git a/testsuite/simulation/exportJson1.py b/testsuite/simulation/exportJson1.py index e2a38e280..1808aec81 100644 --- a/testsuite/simulation/exportJson1.py +++ b/testsuite/simulation/exportJson1.py @@ -77,4 +77,5 @@ ## "tolerance": 1e-06 ## } ## } +## Status.ok ## endResult diff --git a/testsuite/simulation/exportJson2.py b/testsuite/simulation/exportJson2.py index 679db63b3..093934450 100644 --- a/testsuite/simulation/exportJson2.py +++ b/testsuite/simulation/exportJson2.py @@ -262,4 +262,5 @@ ## "tolerance": 1e-06 ## } ## } +## Status.ok ## endResult diff --git a/testsuite/simulation/exportJson3.py b/testsuite/simulation/exportJson3.py index f3e76e6e9..ecc865403 100644 --- a/testsuite/simulation/exportJson3.py +++ b/testsuite/simulation/exportJson3.py @@ -198,4 +198,5 @@ ## "tolerance": 1e-06 ## } ## } +## Status.ok ## endResult diff --git a/testsuite/simulation/exportJson4.py b/testsuite/simulation/exportJson4.py index c18835915..077174ba1 100644 --- a/testsuite/simulation/exportJson4.py +++ b/testsuite/simulation/exportJson4.py @@ -157,4 +157,5 @@ ## "tolerance": 1e-06 ## } ## } +## Status.ok ## endResult From 7b1e8c9cef3e8317560f70abae78f1ca5189c5f0 Mon Sep 17 00:00:00 2001 From: Lennart Ochel Date: Tue, 29 Apr 2025 11:16:26 +0200 Subject: [PATCH 10/12] Add instantiated_model.py --- src/OMSimulatorPython/CMakeLists.txt | 3 ++- src/OMSimulatorPython/__init__.py | 18 +++++++++++++++++- src/OMSimulatorPython/instantiated_model.py | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 src/OMSimulatorPython/instantiated_model.py diff --git a/src/OMSimulatorPython/CMakeLists.txt b/src/OMSimulatorPython/CMakeLists.txt index 04db30bb8..d86556c27 100644 --- a/src/OMSimulatorPython/CMakeLists.txt +++ b/src/OMSimulatorPython/CMakeLists.txt @@ -28,12 +28,13 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/OMSimulatorPython3.in" "${CMAKE_CURR install(FILES "${CMAKE_CURRENT_BINARY_DIR}/__init__.py" "${CMAKE_CURRENT_BINARY_DIR}/capi.py" + "${CMAKE_CURRENT_SOURCE_DIR}/component.py" "${CMAKE_CURRENT_SOURCE_DIR}/connection.py" "${CMAKE_CURRENT_SOURCE_DIR}/connector.py" - "${CMAKE_CURRENT_SOURCE_DIR}/component.py" "${CMAKE_CURRENT_SOURCE_DIR}/cref.py" "${CMAKE_CURRENT_SOURCE_DIR}/elementgeometry.py" "${CMAKE_CURRENT_SOURCE_DIR}/fmu.py" + "${CMAKE_CURRENT_SOURCE_DIR}/instantiated_model.py" "${CMAKE_CURRENT_SOURCE_DIR}/namespace.py" "${CMAKE_CURRENT_SOURCE_DIR}/settings.py" "${CMAKE_CURRENT_SOURCE_DIR}/ssd.py" diff --git a/src/OMSimulatorPython/__init__.py b/src/OMSimulatorPython/__init__.py index 5d70c2751..c9af017bb 100644 --- a/src/OMSimulatorPython/__init__.py +++ b/src/OMSimulatorPython/__init__.py @@ -15,9 +15,25 @@ from OMSimulator.ssv import SSV from OMSimulator.system import System from OMSimulator.variable import Causality, SignalType, Variable +from OMSimulator.instantiated_model import InstantiatedModel # Define public API -__all__ = ['Capi', 'Connection', 'Connector', 'CRef', 'FMU', 'Settings', 'SSD', 'SSP', 'SSV', 'System', 'Causality', 'SignalType', 'Variable'] +__all__ = [ + 'Capi', + 'Causality', + 'Connection', + 'Connector', + 'CRef', + 'FMU', + 'InstantiatedModel', + 'Settings', + 'SignalType', + 'SSD', + 'SSP', + 'SSV', + 'System', + 'Variable', + ] __version__ = '@OMS_SHORT_VERSION_STRING@' __author__ = 'Open Source Modelica Consortium (OSMC)' diff --git a/src/OMSimulatorPython/instantiated_model.py b/src/OMSimulatorPython/instantiated_model.py new file mode 100644 index 000000000..6bee3a736 --- /dev/null +++ b/src/OMSimulatorPython/instantiated_model.py @@ -0,0 +1,19 @@ + + + + +class InstantiatedModel: + def __init__(self, json_description): + pass + + def initialize(self): + pass + + def simulate(self): + pass + + def setValues(self): + pass + + def getValues(self): + pass From b9ebe8d48ccbe574b13166b868e8920e4083c496 Mon Sep 17 00:00:00 2001 From: Lennart Ochel Date: Tue, 29 Apr 2025 12:35:46 +0200 Subject: [PATCH 11/12] WIP --- src/OMSimulatorPython/instantiated_model.py | 21 +++++++++++---------- src/OMSimulatorPython/system.py | 8 +++----- testsuite/simulation/exportJson1.py | 1 - testsuite/simulation/exportJson2.py | 1 - testsuite/simulation/exportJson3.py | 1 - testsuite/simulation/exportJson4.py | 1 - 6 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/OMSimulatorPython/instantiated_model.py b/src/OMSimulatorPython/instantiated_model.py index 6bee3a736..072a4a307 100644 --- a/src/OMSimulatorPython/instantiated_model.py +++ b/src/OMSimulatorPython/instantiated_model.py @@ -1,19 +1,20 @@ - - - +from OMSimulator.capi import Capi, Status class InstantiatedModel: def __init__(self, json_description): - pass - - def initialize(self): - pass - - def simulate(self): - pass + print(json_description) + self.model, status = Capi.instantiateFromJson(json_description) + if status != Status.ok: + raise RuntimeError(f"Failed to instantiate model: {status}") def setValues(self): pass def getValues(self): pass + + def initialize(self): + Capi.initialize(self.model) + + def simulate(self): + Capi.simulate(self.model) diff --git a/src/OMSimulatorPython/system.py b/src/OMSimulatorPython/system.py index 9928309ff..0c9d6fc8e 100644 --- a/src/OMSimulatorPython/system.py +++ b/src/OMSimulatorPython/system.py @@ -8,6 +8,7 @@ from OMSimulator.connector import Connector from OMSimulator.elementgeometry import ElementGeometry from OMSimulator.fmu import FMU +from OMSimulator.instantiated_model import InstantiatedModel from OMSimulator.ssv import SSV from OMSimulator.values import Values @@ -267,7 +268,7 @@ def setSolver(self, cref: CRef, name: str): raise ValueError(f"Component '{first}' not found in {self.name}") self.elements[first].setSolver(name) - def instantiate(self): + def instantiate(self) -> InstantiatedModel: """Instantiates the system and its components.""" data = { "simulation units": [] @@ -303,10 +304,7 @@ def instantiate(self): # Dump JSON json_string = json.dumps(data, indent=2) - print(json_string) - model, status = Capi.instantiateFromJson(json_string) - print(status) - + return InstantiatedModel(json_string) def processElements(self, elements_dict: dict, connections: list, data: dict, solver_groups : defaultdict, componentSolver : dict, solver_connections : defaultdict, systemName = None): """Processes the elements and connections in the system.""" diff --git a/testsuite/simulation/exportJson1.py b/testsuite/simulation/exportJson1.py index 1808aec81..e2a38e280 100644 --- a/testsuite/simulation/exportJson1.py +++ b/testsuite/simulation/exportJson1.py @@ -77,5 +77,4 @@ ## "tolerance": 1e-06 ## } ## } -## Status.ok ## endResult diff --git a/testsuite/simulation/exportJson2.py b/testsuite/simulation/exportJson2.py index 093934450..679db63b3 100644 --- a/testsuite/simulation/exportJson2.py +++ b/testsuite/simulation/exportJson2.py @@ -262,5 +262,4 @@ ## "tolerance": 1e-06 ## } ## } -## Status.ok ## endResult diff --git a/testsuite/simulation/exportJson3.py b/testsuite/simulation/exportJson3.py index ecc865403..f3e76e6e9 100644 --- a/testsuite/simulation/exportJson3.py +++ b/testsuite/simulation/exportJson3.py @@ -198,5 +198,4 @@ ## "tolerance": 1e-06 ## } ## } -## Status.ok ## endResult diff --git a/testsuite/simulation/exportJson4.py b/testsuite/simulation/exportJson4.py index 077174ba1..c18835915 100644 --- a/testsuite/simulation/exportJson4.py +++ b/testsuite/simulation/exportJson4.py @@ -157,5 +157,4 @@ ## "tolerance": 1e-06 ## } ## } -## Status.ok ## endResult From 2427a844c4f9c8f757f8522fbabfd4c0359c0e08 Mon Sep 17 00:00:00 2001 From: Lennart Ochel Date: Tue, 29 Apr 2025 12:52:47 +0200 Subject: [PATCH 12/12] WIP --- src/OMSimulatorLib/OMSimulator.cpp | 8 ++++---- src/OMSimulatorPython/instantiated_model.py | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/OMSimulatorLib/OMSimulator.cpp b/src/OMSimulatorLib/OMSimulator.cpp index 5a37f399c..38bab7724 100644 --- a/src/OMSimulatorLib/OMSimulator.cpp +++ b/src/OMSimulatorLib/OMSimulator.cpp @@ -1702,20 +1702,20 @@ oms_status_enu_t oms3_instantiateFromJson(char* model_json_desc, void** out_mode oms_status_enu_t oms3_initialize(void* model) { - return oms_status_ok; + return oms_status_error; } oms_status_enu_t oms3_simulate(void* model) { - return oms_status_ok; + return oms_status_error; } oms_status_enu_t oms3_stepUntil(void* model, double stopTime) { - return oms_status_ok; + return oms_status_error; } oms_status_enu_t oms3_terminate(void* model) { - return oms_status_ok; + return oms_status_error; } diff --git a/src/OMSimulatorPython/instantiated_model.py b/src/OMSimulatorPython/instantiated_model.py index 072a4a307..4c8323cc1 100644 --- a/src/OMSimulatorPython/instantiated_model.py +++ b/src/OMSimulatorPython/instantiated_model.py @@ -14,7 +14,21 @@ def getValues(self): pass def initialize(self): - Capi.initialize(self.model) + status = Capi.initialize(self.model) + if status != Status.ok: + raise RuntimeError(f"Failed to initialize model: {status}") def simulate(self): - Capi.simulate(self.model) + status = Capi.simulate(self.model) + if status != Status.ok: + raise RuntimeError(f"Failed to simulate model: {status}") + + def stepUntil(self, stopTime): + status = Capi.stepUntil(self.model, stopTime) + if status != Status.ok: + raise RuntimeError(f"Failed to step until {stopTime}: {status}") + + def terminate(self): + status = Capi.terminate(self.model) + if status != Status.ok: + raise RuntimeError(f"Failed to terminate model: {status}")