From 429fe877667e23c251297a8389b6a00835436a66 Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 27 Dec 2025 21:00:13 +0100 Subject: [PATCH 1/7] [ModelicaSystem] move import re Pylint is recommenting to order the imports in several sections alphabetically: (1) python standard library (2) third party packages (3) current package --- OMPython/ModelicaSystem.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index 9db3da33..20e6df10 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -11,6 +11,7 @@ import os import pathlib import queue +import re import textwrap import threading from typing import Any, cast, Optional @@ -19,8 +20,6 @@ import numpy as np -import re - from OMPython.OMCSession import ( OMCSessionException, OMCSessionRunData, From 237e5cbaa68784395770dc7e58eb5034e99d08ed Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 27 Dec 2025 21:07:00 +0100 Subject: [PATCH 2/7] [ModelicaSystem] parse OM version in __init__() --- OMPython/ModelicaSystem.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index 20e6df10..e6ca53bb 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -350,7 +350,8 @@ def __init__( self._session = OMCSessionLocal(omhome=omhome) # get OpenModelica version - self._version = self._session.sendExpression("getVersion()", parsed=True) + version_str = self._session.sendExpression("getVersion()", parsed=True) + self._version = self._parse_om_version(version=version_str) # set commandLineOptions using default values or the user defined list if command_line_options is None: # set default command line options to improve the performance of linearization and to avoid recompilation if @@ -1022,11 +1023,12 @@ def getOptimizationOptions( raise ModelicaSystemError("Unhandled input for getOptimizationOptions()") - def parse_om_version(self, version: str) -> tuple[int, int, int]: + def _parse_om_version(self, version: str) -> tuple[int, int, int]: match = re.search(r"v?(\d+)\.(\d+)\.(\d+)", version) if not match: raise ValueError(f"Version not found in: {version}") major, minor, patch = map(int, match.groups()) + return major, minor, patch def simulate_cmd( @@ -1078,8 +1080,7 @@ def simulate_cmd( # simulation options are not read from override file from version >= 1.26.0, # pass them to simulation executable directly as individual arguments # see https://github.com/OpenModelica/OpenModelica/pull/14813 - major, minor, patch = self.parse_om_version(self._version) - if (major, minor, patch) >= (1, 26, 0): + if self._version >= Version("1.26.0"): for key, opt_value in self._simulate_options_override.items(): om_cmd.arg_set(key=key, val=str(opt_value)) override_content = ( @@ -1775,8 +1776,7 @@ def linearize( ) # See comment in simulate_cmd regarding override file and OM version - major, minor, patch = self.parse_om_version(self._version) - if (major, minor, patch) >= (1, 26, 0): + if self._version >= Version("1.26.0"): for key, opt_value in self._linearization_options.items(): om_cmd.arg_set(key=key, val=str(opt_value)) override_content = ( From 1f3ec8704e9fb904c648545390029a79f641b432 Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 27 Dec 2025 21:21:05 +0100 Subject: [PATCH 3/7] [ModelicaSystem] simplify processing of override data Would it make sense to combine this code and the code in linearize() in one new function? def _process_override_data(self, om_cmd, sim_override, file_override) -> None: The code could: (1) check the version; set command line parameters as needed (2) create the content of the override file (3) create the overwrite file and set it as command line parameter The advantage would be, that the modified code is not in two places but only in one ... --- OMPython/ModelicaSystem.py | 80 +++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index e6ca53bb..2f7b6bd4 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -1031,6 +1031,33 @@ def _parse_om_version(self, version: str) -> tuple[int, int, int]: return major, minor, patch + def _process_override_data( + self, + om_cmd: ModelicaSystemCmd, + override_file: OMCPath, + override_var: dict[str, str], + override_sim: dict[str, str], + ) -> None: + if not override_var and not override_sim: + return + + override_content = "" + if override_var: + override_content += "\n".join([f"{key}={value}" for key, value in override_var.items()]) + "\n" + + # simulation options are not read from override file from version >= 1.26.0, + # pass them to simulation executable directly as individual arguments + # see https://github.com/OpenModelica/OpenModelica/pull/14813 + if override_sim: + if self._version >= (1, 26, 0): + for key, opt_value in override_sim.items(): + om_cmd.arg_set(key=key, val=str(opt_value)) + else: + override_content += "\n".join([f"{key}={value}" for key, value in override_sim.items()]) + "\n" + + override_file.write_text(override_content) + om_cmd.arg_set(key="overrideFile", val=override_file.as_posix()) + def simulate_cmd( self, result_file: OMCPath, @@ -1074,28 +1101,12 @@ def simulate_cmd( if simargs: om_cmd.args_set(args=simargs) - if self._override_variables or self._simulate_options_override: - override_file = result_file.parent / f"{result_file.stem}_override.txt" - - # simulation options are not read from override file from version >= 1.26.0, - # pass them to simulation executable directly as individual arguments - # see https://github.com/OpenModelica/OpenModelica/pull/14813 - if self._version >= Version("1.26.0"): - for key, opt_value in self._simulate_options_override.items(): - om_cmd.arg_set(key=key, val=str(opt_value)) - override_content = ( - "\n".join([f"{key}={value}" for key, value in self._override_variables.items()]) - + "\n" - ) - else: - override_content = ( - "\n".join([f"{key}={value}" for key, value in self._override_variables.items()]) - + "\n".join([f"{key}={value}" for key, value in self._simulate_options_override.items()]) - + "\n" - ) - - override_file.write_text(override_content) - om_cmd.arg_set(key="overrideFile", val=override_file.as_posix()) + self._process_override_data( + om_cmd=om_cmd, + override_file=result_file.parent / f"{result_file.stem}_override.txt", + override_var=self._override_variables, + override_sim=self._simulate_options_override, + ) if self._inputs: # if model has input quantities for key, val in self._inputs.items(): @@ -1775,25 +1786,12 @@ def linearize( modelname=self._model_name, ) - # See comment in simulate_cmd regarding override file and OM version - if self._version >= Version("1.26.0"): - for key, opt_value in self._linearization_options.items(): - om_cmd.arg_set(key=key, val=str(opt_value)) - override_content = ( - "\n".join([f"{key}={value}" for key, value in self._override_variables.items()]) - + "\n" - ) - else: - override_content = ( - "\n".join([f"{key}={value}" for key, value in self._override_variables.items()]) - + "\n".join([f"{key}={value}" for key, value in self._linearization_options.items()]) - + "\n" - ) - - override_file = self.getWorkDirectory() / f'{self._model_name}_override_linear.txt' - override_file.write_text(override_content) - - om_cmd.arg_set(key="overrideFile", val=override_file.as_posix()) + self._process_override_data( + om_cmd=om_cmd, + override_file=self.getWorkDirectory() / f'{self._model_name}_override_linear.txt', + override_var=self._override_variables, + override_sim=self._linearization_options, + ) if self._inputs: for key, data in self._inputs.items(): From cd3a9b9a3aa90fb870cf7b26b00a7255a303b2db Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 27 Dec 2025 21:32:21 +0100 Subject: [PATCH 4/7] [ModelicaSystem] define _linearization_options and _optimization_options as dict[str, str] * after OMC is run, the values will be string anyway * simplify code / align on one common definition for these dicts --- OMPython/ModelicaSystem.py | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index 2f7b6bd4..3b25845d 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -331,14 +331,14 @@ def __init__( self._simulate_options: dict[str, str] = {} self._override_variables: dict[str, str] = {} self._simulate_options_override: dict[str, str] = {} - self._linearization_options: dict[str, str | float] = { - 'startTime': 0.0, - 'stopTime': 1.0, - 'stepSize': 0.002, - 'tolerance': 1e-8, + self._linearization_options: dict[str, str] = { + 'startTime': str(0.0), + 'stopTime': str(1.0), + 'stepSize': str(0.002), + 'tolerance': str(1e-8), } self._optimization_options = self._linearization_options | { - 'numberOfIntervals': 500, + 'numberOfIntervals': str(500), } self._linearized_inputs: list[str] = [] # linearization input list self._linearized_outputs: list[str] = [] # linearization output list @@ -950,7 +950,7 @@ def getSimulationOptions( def getLinearizationOptions( self, names: Optional[str | list[str]] = None, - ) -> dict[str, str | float] | list[str | float]: + ) -> dict[str, str] | list[str]: """Get simulation options used for linearization. Args: @@ -964,17 +964,16 @@ def getLinearizationOptions( returned. If `names` is a list, a list with one value for each option name in names is returned: [option1_value, option2_value, ...]. - Some option values are returned as float when first initialized, - but always as strings after setLinearizationOptions is used to - change them. + + The option values are always returned as strings. Examples: >>> mod.getLinearizationOptions() - {'startTime': 0.0, 'stopTime': 1.0, 'stepSize': 0.002, 'tolerance': 1e-08} + {'startTime': '0.0', 'stopTime': '1.0', 'stepSize': '0.002', 'tolerance': '1e-08'} >>> mod.getLinearizationOptions("stopTime") - [1.0] + ['1.0'] >>> mod.getLinearizationOptions(["tolerance", "stopTime"]) - [1e-08, 1.0] + ['1e-08', '1.0'] """ if names is None: return self._linearization_options @@ -988,7 +987,7 @@ def getLinearizationOptions( def getOptimizationOptions( self, names: Optional[str | list[str]] = None, - ) -> dict[str, str | float] | list[str | float]: + ) -> dict[str, str] | list[str]: """Get simulation options used for optimization. Args: @@ -1002,9 +1001,8 @@ def getOptimizationOptions( returned. If `names` is a list, a list with one value for each option name in names is returned: [option1_value, option2_value, ...]. - Some option values are returned as float when first initialized, - but always as strings after setOptimizationOptions is used to - change them. + + The option values are always returned as string. Examples: >>> mod.getOptimizationOptions() From 843cb2c0225fb915601dd270ab92cdbd04b5d6b6 Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 27 Dec 2025 22:08:50 +0100 Subject: [PATCH 5/7] [ModelicaSystem] simplify call to sendExpression() --- OMPython/ModelicaSystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index 3b25845d..a1643348 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -350,7 +350,7 @@ def __init__( self._session = OMCSessionLocal(omhome=omhome) # get OpenModelica version - version_str = self._session.sendExpression("getVersion()", parsed=True) + version_str = self.sendExpression(expr="getVersion()") self._version = self._parse_om_version(version=version_str) # set commandLineOptions using default values or the user defined list if command_line_options is None: From 052f61e3369530f1f967d2c7781b77eefa54ae1b Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 27 Dec 2025 22:50:51 +0100 Subject: [PATCH 6/7] [ModelicaSystem] check for dict content using len() == 0 --- OMPython/ModelicaSystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index a1643348..f5530b80 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -1036,7 +1036,7 @@ def _process_override_data( override_var: dict[str, str], override_sim: dict[str, str], ) -> None: - if not override_var and not override_sim: + if len(override_var) == 0 and len(override_sim) == 0: return override_content = "" From 27d894b356662f08d4726b35ea21bc2e103fea19 Mon Sep 17 00:00:00 2001 From: syntron Date: Sun, 28 Dec 2025 23:41:33 +0100 Subject: [PATCH 7/7] [ModelicaSystem] fix overwrite file (write only if there is content) --- OMPython/ModelicaSystem.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index f5530b80..bf8ca91e 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -1053,8 +1053,9 @@ def _process_override_data( else: override_content += "\n".join([f"{key}={value}" for key, value in override_sim.items()]) + "\n" - override_file.write_text(override_content) - om_cmd.arg_set(key="overrideFile", val=override_file.as_posix()) + if override_content: + override_file.write_text(override_content) + om_cmd.arg_set(key="overrideFile", val=override_file.as_posix()) def simulate_cmd( self,