From df3e39a006511b32bd959c5783635439ec691779 Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 23 Aug 2025 19:42:52 +0200 Subject: [PATCH 01/12] [ModelicaSystem] allow to modify default command line options --- OMPython/ModelicaSystem.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index 6966d157..fd1d7a0e 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -352,7 +352,7 @@ def __init__( fileName: Optional[str | os.PathLike | pathlib.Path] = None, modelName: Optional[str] = None, lmodel: Optional[list[str | tuple[str, str]]] = None, - commandLineOptions: Optional[str] = None, + commandLineOptions: Optional[list[str]] = None, variableFilter: Optional[str] = None, customBuildDirectory: Optional[str | os.PathLike] = None, omhome: Optional[str] = None, @@ -374,8 +374,9 @@ def __init__( lmodel=["Modelica"] for just the library name and lmodel=[("Modelica","3.2.3")] for specifying both the name and the version. - commandLineOptions: String with extra command line options to be - provided to omc via setCommandLineOptions(). + commandLineOptions: List with extra command line options as elements. The list elements are + provided to omc via setCommandLineOptions(). If set, the default values will be overridden. + To disable any command line options, use an empty list. variableFilter: A regular expression. Only variables fully matching the regexp will be stored in the result file. Leaving it unspecified is equivalent to ".*". @@ -426,8 +427,17 @@ def __init__( else: self._getconn = OMCSessionZMQ(omhome=omhome) - # set commandLineOptions if provided by users - self.setCommandLineOptions(commandLineOptions=commandLineOptions) + # set commandLineOptions using default values or the user defined list + if commandLineOptions is None: + # set default command Line Options for linearization as + # linearize() will use the simulation executable and runtime + # flag -l to perform linearization + commandLineOptions = [ + "--linearizationDumpLanguage=python", + "--generateSymbolicLinearization", + ] + for opt in commandLineOptions: + self.setCommandLineOptions(commandLineOptions=opt) if lmodel is None: lmodel = [] @@ -445,12 +455,6 @@ def __init__( if self._file_name is not None and not self._file_name.is_file(): # if file does not exist raise IOError(f"{self._file_name} does not exist!") - # set default command Line Options for linearization as - # linearize() will use the simulation executable and runtime - # flag -l to perform linearization - self.setCommandLineOptions("--linearizationDumpLanguage=python") - self.setCommandLineOptions("--generateSymbolicLinearization") - self._work_dir: pathlib.Path = self.setWorkDirectory(customBuildDirectory) if self._file_name is not None: From 3bfe2ed961b7e8a5004f01fb9d03c5c5ce02c49c Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 23 Aug 2025 20:27:35 +0200 Subject: [PATCH 02/12] [ModelicaSystem] update setCommandLineOptions() --- OMPython/ModelicaSystem.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index fd1d7a0e..0135f120 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -468,10 +468,10 @@ def __init__( if build: self.buildModel(variableFilter) - def setCommandLineOptions(self, commandLineOptions: Optional[str] = None): - # set commandLineOptions if provided by users - if commandLineOptions is None: - return + def setCommandLineOptions(self, commandLineOptions: str): + """ + Set the provided command line option via OMC setCommandLineOptions(). + """ exp = f'setCommandLineOptions("{commandLineOptions}")' self.sendExpression(exp) From bfeb6738ba5896a37d6a4b397a17a3ab7c0ee911 Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 23 Aug 2025 20:29:11 +0200 Subject: [PATCH 03/12] [ModelicaSystem] improve comment --- OMPython/ModelicaSystem.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index 0135f120..d4105ea3 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -429,9 +429,8 @@ def __init__( # set commandLineOptions using default values or the user defined list if commandLineOptions is None: - # set default command Line Options for linearization as - # linearize() will use the simulation executable and runtime - # flag -l to perform linearization + # set default command line options to improve the performance of linearization and to avoid recompilation if + # the simulation executable is reused in linearize() via the runtime flag '-l' commandLineOptions = [ "--linearizationDumpLanguage=python", "--generateSymbolicLinearization", From 6c44d1377b36c2095d17cba01eec591193441863 Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 23 Aug 2025 21:57:24 +0200 Subject: [PATCH 04/12] [ModelicaSystem] split __init__() new: * __init__() - initialisation * model_definition() - model related definitions --- OMPython/ModelicaSystem.py | 115 +++++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 51 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index d4105ea3..ac04fff3 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -349,15 +349,10 @@ def parse_simflags(simflags: str) -> dict[str, Optional[str | dict[str, Any] | n class ModelicaSystem: def __init__( self, - fileName: Optional[str | os.PathLike | pathlib.Path] = None, - modelName: Optional[str] = None, - lmodel: Optional[list[str | tuple[str, str]]] = None, commandLineOptions: Optional[list[str]] = None, - variableFilter: Optional[str] = None, customBuildDirectory: Optional[str | os.PathLike] = None, omhome: Optional[str] = None, omc_process: Optional[OMCProcessLocal] = None, - build: bool = True, ) -> None: """Initialize, load and build a model. @@ -365,44 +360,17 @@ def __init__( xml files, etc. Args: - fileName: Path to the model file. Either absolute or relative to - the current working directory. - modelName: The name of the model class. If it is contained within - a package, "PackageName.ModelName" should be used. - lmodel: List of libraries to be loaded before the model itself is - loaded. Two formats are supported for the list elements: - lmodel=["Modelica"] for just the library name - and lmodel=[("Modelica","3.2.3")] for specifying both the name - and the version. commandLineOptions: List with extra command line options as elements. The list elements are provided to omc via setCommandLineOptions(). If set, the default values will be overridden. To disable any command line options, use an empty list. - variableFilter: A regular expression. Only variables fully - matching the regexp will be stored in the result file. - Leaving it unspecified is equivalent to ".*". customBuildDirectory: Path to a directory to be used for temporary files like the model executable. If left unspecified, a tmp directory will be created. - omhome: OPENMODELICAHOME value to be used when creating the OMC - session. + omhome: path to OMC to be used when creating the OMC session (see OMCSessionZMQ). omc_process: definition of a (local) OMC process to be used. If unspecified, a new local session will be created. - build: Boolean controlling whether or not the model should be - built when constructor is called. If False, the constructor - simply loads the model without compiling. - - Examples: - mod = ModelicaSystem("ModelicaModel.mo", "modelName") - mod = ModelicaSystem("ModelicaModel.mo", "modelName", ["Modelica"]) - mod = ModelicaSystem("ModelicaModel.mo", "modelName", [("Modelica","3.2.3"), "PowerSystems"]) """ - if fileName is None and modelName is None and not lmodel: # all None - raise ModelicaSystemError("Cannot create ModelicaSystem object without any arguments") - - if modelName is None: - raise ModelicaSystemError("A modelname must be provided (argument modelName)!") - self._quantities: list[dict[str, Any]] = [] self._params: dict[str, str] = {} # even numerical values are stored as str self._inputs: dict[str, list | None] = {} @@ -438,34 +406,79 @@ def __init__( for opt in commandLineOptions: self.setCommandLineOptions(commandLineOptions=opt) - if lmodel is None: - lmodel = [] - - if not isinstance(lmodel, list): - raise ModelicaSystemError(f"Invalid input type for lmodel: {type(lmodel)} - list expected!") - - self._lmodel = lmodel # may be needed if model is derived from other model - self._model_name = modelName # Model class name - self._file_name = pathlib.Path(fileName).resolve() if fileName is not None else None # Model file/package name self._simulated = False # True if the model has already been simulated self._result_file: Optional[pathlib.Path] = None # for storing result file - self._variable_filter = variableFilter + + self._work_dir: pathlib.Path = self.setWorkDirectory(customBuildDirectory) + + self._model_name: Optional[str] = None + self._lmodel: Optional[list[str | tuple[str, str]]] = None + self._file_name: Optional[os.PathLike] + self._variable_filter: Optional[str] = None + + def model_definition( + self, + model: str, + file: Optional[str | os.PathLike | pathlib.Path] = None, + libraries: Optional[list[str | tuple[str, str]]] = None, + variable_filter: Optional[str] = None, + build: bool = True, + ) -> None: + """Initialize, load and build a model. + + The constructor loads the model file and builds it, generating exe and + xml files, etc. + + Args: + file: Path to the model file. Either absolute or relative to + the current working directory. + model: The name of the model class. If it is contained within + a package, "PackageName.ModelName" should be used. + libraries: List of libraries to be loaded before the model itself is + loaded. Two formats are supported for the list elements: + lmodel=["Modelica"] for just the library name + and lmodel=[("Modelica","3.2.3")] for specifying both the name + and the version. + variable_filter: A regular expression. Only variables fully + matching the regexp will be stored in the result file. + Leaving it unspecified is equivalent to ".*". + build: Boolean controlling whether the model should be + built when constructor is called. If False, the constructor + simply loads the model without compiling. + + Examples: + mod = ModelicaSystem() + # and then one of the lines below + mod.setup_model(model="modelName", file="ModelicaModel.mo", ) + mod.setup_model(model="modelName", file="ModelicaModel.mo", libraries=["Modelica"]) + mod.setup_model(model="modelName", file="ModelicaModel.mo", libraries=[("Modelica","3.2.3"), "PowerSystems"]) + """ + + if not isinstance(model, str): + raise ModelicaSystemError("A model name must be provided (argument modelName)!") + + if libraries is None: + libraries = [] + + if not isinstance(libraries, list): + raise ModelicaSystemError(f"Invalid input type for lmodel: {type(libraries)} - list expected!") + + # set variables + self._model_name = model # Model class name + self._lmodel = libraries # may be needed if model is derived from other model + self._file_name = pathlib.Path(file).resolve() if file is not None else None # Model file/package name + self._variable_filter = variable_filter if self._file_name is not None and not self._file_name.is_file(): # if file does not exist raise IOError(f"{self._file_name} does not exist!") - self._work_dir: pathlib.Path = self.setWorkDirectory(customBuildDirectory) - - if self._file_name is not None: + if self._lmodel: self._loadLibrary(lmodel=self._lmodel) + if self._file_name is not None: self._loadFile(fileName=self._file_name) - # allow directly loading models from MSL without fileName - elif fileName is None and modelName is not None: - self._loadLibrary(lmodel=self._lmodel) - if build: - self.buildModel(variableFilter) + self.buildModel(variable_filter) def setCommandLineOptions(self, commandLineOptions: str): """ From 2034fc0286b0ff655fb4088d60c4805b6b2c3240 Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 23 Aug 2025 21:57:45 +0200 Subject: [PATCH 05/12] [ModelicaSystem] split __init__() - mypy fix in ModelicaSystemCmd --- OMPython/ModelicaSystem.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index ac04fff3..0e95eed7 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -114,7 +114,15 @@ def __getitem__(self, index: int): class ModelicaSystemCmd: """A compiled model executable.""" - def __init__(self, runpath: pathlib.Path, modelname: str, timeout: Optional[float] = None) -> None: + def __init__( + self, + runpath: pathlib.Path, + modelname: Optional[str] = None, + timeout: Optional[float] = None, + ) -> None: + if modelname is None: + raise ModelicaSystemError("Missing model name!") + self._runpath = pathlib.Path(runpath).resolve().absolute() self._model_name = modelname self._timeout = timeout From aabfa14b327d404543b95b49339ba95b7975232a Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 23 Aug 2025 21:58:14 +0200 Subject: [PATCH 06/12] [ModelicaSystem] split __init__() - mypy fix in convertMo2Fmu() --- OMPython/ModelicaSystem.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index 0e95eed7..9bc25a37 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -1537,9 +1537,13 @@ def _createCSVData(self, csvfile: Optional[pathlib.Path] = None) -> pathlib.Path return csvfile - def convertMo2Fmu(self, version: str = "2.0", fmuType: str = "me_cs", - fileNamePrefix: str = "", - includeResources: bool = True) -> str: + def convertMo2Fmu( + self, + version: str = "2.0", + fmuType: str = "me_cs", + fileNamePrefix: Optional[str] = None, + includeResources: bool = True, + ) -> str: """Translate the model into a Functional Mockup Unit. Args: @@ -1555,12 +1559,12 @@ def convertMo2Fmu(self, version: str = "2.0", fmuType: str = "me_cs", '/tmp/tmpmhfx9umo/CauerLowPassAnalog.fmu' """ - if fileNamePrefix == "": + if fileNamePrefix is None: + if self._model_name is None: + raise ModelicaSystemError("Missing model name!") fileNamePrefix = self._model_name - if includeResources: - includeResourcesStr = "true" - else: - includeResourcesStr = "false" + includeResourcesStr = "true" if includeResources else "false" + properties = (f'version="{version}", fmuType="{fmuType}", ' f'fileNamePrefix="{fileNamePrefix}", includeResources={includeResourcesStr}') fmu = self._requestApi(apiName='buildModelFMU', entity=self._model_name, properties=properties) From 8cc8f50e5331d6e4923231f3523bfde1c377b7a9 Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 23 Aug 2025 22:12:21 +0200 Subject: [PATCH 07/12] [ModelicaSystem] split __init__() - update unittest --- tests/test_FMIExport.py | 13 ++++++-- tests/test_ModelicaSystem.py | 56 ++++++++++++++++++++++++++------- tests/test_ModelicaSystemCmd.py | 6 +++- tests/test_OMSessionCmd.py | 7 +++-- tests/test_linearization.py | 13 ++++++-- tests/test_optimization.py | 6 +++- 6 files changed, 80 insertions(+), 21 deletions(-) diff --git a/tests/test_FMIExport.py b/tests/test_FMIExport.py index f47b87ae..688c7ef2 100644 --- a/tests/test_FMIExport.py +++ b/tests/test_FMIExport.py @@ -4,8 +4,11 @@ def test_CauerLowPassAnalog(): - mod = OMPython.ModelicaSystem(modelName="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", - lmodel=["Modelica"]) + mod = OMPython.ModelicaSystem() + mod.model_definition( + model="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", + libraries=["Modelica"], + ) tmp = mod.getWorkDirectory() try: fmu = mod.convertMo2Fmu(fileNamePrefix="CauerLowPassAnalog") @@ -15,7 +18,11 @@ def test_CauerLowPassAnalog(): def test_DrumBoiler(): - mod = OMPython.ModelicaSystem(modelName="Modelica.Fluid.Examples.DrumBoiler.DrumBoiler", lmodel=["Modelica"]) + mod = OMPython.ModelicaSystem() + mod.model_definition( + model="Modelica.Fluid.Examples.DrumBoiler.DrumBoiler", + libraries=["Modelica"], + ) tmp = mod.getWorkDirectory() try: fmu = mod.convertMo2Fmu(fileNamePrefix="DrumBoiler") diff --git a/tests/test_ModelicaSystem.py b/tests/test_ModelicaSystem.py index 8e9b8a8e..ebccda22 100644 --- a/tests/test_ModelicaSystem.py +++ b/tests/test_ModelicaSystem.py @@ -22,9 +22,13 @@ def model_firstorder(tmp_path): def test_ModelicaSystem_loop(model_firstorder): def worker(): filePath = model_firstorder.as_posix() - m = OMPython.ModelicaSystem(filePath, "M") - m.simulate() - m.convertMo2Fmu(fmuType="me") + mod = OMPython.ModelicaSystem() + mod.model_definition( + file=filePath, + model="M", + ) + mod.simulate() + mod.convertMo2Fmu(fmuType="me") for _ in range(10): worker() @@ -32,7 +36,11 @@ def worker(): def test_setParameters(): omc = OMPython.OMCSessionZMQ() model_path = omc.sendExpression("getInstallationDirectoryPath()") + "/share/doc/omc/testmodels/" - mod = OMPython.ModelicaSystem(model_path + "BouncingBall.mo", "BouncingBall") + mod = OMPython.ModelicaSystem() + mod.model_definition( + file=model_path + "BouncingBall.mo", + model="BouncingBall", + ) # method 1 mod.setParameters(pvals={"e": 1.234}) @@ -61,7 +69,11 @@ def test_setParameters(): def test_setSimulationOptions(): omc = OMPython.OMCSessionZMQ() model_path = omc.sendExpression("getInstallationDirectoryPath()") + "/share/doc/omc/testmodels/" - mod = OMPython.ModelicaSystem(fileName=model_path + "BouncingBall.mo", modelName="BouncingBall") + mod = OMPython.ModelicaSystem() + mod.model_definition( + file=model_path + "BouncingBall.mo", + model="BouncingBall", + ) # method 1 mod.setSimulationOptions(simOptions={"stopTime": 1.234}) @@ -94,7 +106,11 @@ def test_relative_path(model_firstorder): model_relative = str(model_file) assert "/" not in model_relative - mod = OMPython.ModelicaSystem(fileName=model_relative, modelName="M") + mod = OMPython.ModelicaSystem() + mod.model_definition( + file=model_relative, + model="M", + ) assert float(mod.getParameters("a")[0]) == -1 finally: model_file.unlink() # clean up the temporary file @@ -104,17 +120,25 @@ def test_customBuildDirectory(tmp_path, model_firstorder): filePath = model_firstorder.as_posix() tmpdir = tmp_path / "tmpdir1" tmpdir.mkdir() - m = OMPython.ModelicaSystem(filePath, "M", customBuildDirectory=tmpdir) - assert m.getWorkDirectory().resolve() == tmpdir.resolve() + mod = OMPython.ModelicaSystem(customBuildDirectory=tmpdir) + mod.model_definition( + file=filePath, + model="M", + ) + assert mod.getWorkDirectory().resolve() == tmpdir.resolve() result_file = tmpdir / "a.mat" assert not result_file.exists() - m.simulate(resultfile="a.mat") + mod.simulate(resultfile="a.mat") assert result_file.is_file() def test_getSolutions(model_firstorder): filePath = model_firstorder.as_posix() - mod = OMPython.ModelicaSystem(filePath, "M") + mod = OMPython.ModelicaSystem() + mod.model_definition( + file=filePath, + model="M", + ) x0 = 1 a = -1 tau = -1 / a @@ -151,7 +175,11 @@ def test_getters(tmp_path): y = der(x); end M_getters; """) - mod = OMPython.ModelicaSystem(fileName=model_file.as_posix(), modelName="M_getters") + mod = OMPython.ModelicaSystem() + mod.model_definition( + file=model_file.as_posix(), + model="M_getters", + ) q = mod.getQuantities() assert isinstance(q, list) @@ -343,7 +371,11 @@ def test_simulate_inputs(tmp_path): y = x; end M_input; """) - mod = OMPython.ModelicaSystem(fileName=model_file.as_posix(), modelName="M_input") + mod = OMPython.ModelicaSystem() + mod.model_definition( + file=model_file.as_posix(), + model="M_input", + ) mod.setSimulationOptions(simOptions={"stopTime": 1.0}) diff --git a/tests/test_ModelicaSystemCmd.py b/tests/test_ModelicaSystemCmd.py index 3544a1bd..c25a7fb7 100644 --- a/tests/test_ModelicaSystemCmd.py +++ b/tests/test_ModelicaSystemCmd.py @@ -17,7 +17,11 @@ def model_firstorder(tmp_path): @pytest.fixture def mscmd_firstorder(model_firstorder): - mod = OMPython.ModelicaSystem(fileName=model_firstorder.as_posix(), modelName="M") + mod = OMPython.ModelicaSystem() + mod.model_definition( + file=model_firstorder.as_posix(), + model="M", + ) mscmd = OMPython.ModelicaSystemCmd(runpath=mod.getWorkDirectory(), modelname=mod._model_name) return mscmd diff --git a/tests/test_OMSessionCmd.py b/tests/test_OMSessionCmd.py index 1588fac8..c024338b 100644 --- a/tests/test_OMSessionCmd.py +++ b/tests/test_OMSessionCmd.py @@ -8,8 +8,11 @@ def test_isPackage(): def test_isPackage2(): - mod = OMPython.ModelicaSystem(modelName="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", - lmodel=["Modelica"]) + mod = OMPython.ModelicaSystem() + mod.model_definition( + model="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", + libraries=["Modelica"], + ) omccmd = OMPython.OMCSessionCmd(session=mod._getconn) assert omccmd.isPackage('Modelica') diff --git a/tests/test_linearization.py b/tests/test_linearization.py index 6af565c6..be9dff87 100644 --- a/tests/test_linearization.py +++ b/tests/test_linearization.py @@ -24,7 +24,11 @@ def model_linearTest(tmp_path): def test_example(model_linearTest): - mod = OMPython.ModelicaSystem(model_linearTest, "linearTest") + mod = OMPython.ModelicaSystem() + mod.model_definition( + file=model_linearTest, + model="linearTest", + ) [A, B, C, D] = mod.linearize() expected_matrixA = [[-3, 2, 0, 0], [-7, 0, -5, 1], [-1, 0, -1, 4], [0, 1, -1, 5]] assert A == expected_matrixA, f"Matrix does not match the expected value. Got: {A}, Expected: {expected_matrixA}" @@ -55,7 +59,12 @@ def test_getters(tmp_path): y2 = phi + u1; end Pendulum; """) - mod = OMPython.ModelicaSystem(fileName=model_file.as_posix(), modelName="Pendulum", lmodel=["Modelica"]) + mod = OMPython.ModelicaSystem() + mod.model_definition( + file=model_file.as_posix(), + model="Pendulum", + libraries=["Modelica"], + ) d = mod.getLinearizationOptions() assert isinstance(d, dict) diff --git a/tests/test_optimization.py b/tests/test_optimization.py index b4164397..938216bb 100644 --- a/tests/test_optimization.py +++ b/tests/test_optimization.py @@ -33,7 +33,11 @@ def test_optimization_example(tmp_path): end BangBang2021; """) - mod = OMPython.ModelicaSystem(fileName=model_file.as_posix(), modelName="BangBang2021") + mod = OMPython.ModelicaSystem() + mod.model_definition( + file=model_file.as_posix(), + model="BangBang2021", + ) mod.setOptimizationOptions(optimizationOptions={"numberOfIntervals": 16, "stopTime": 1, From 6e154f368d7f7d1508f93f7441a71cb660231f43 Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 23 Aug 2025 22:13:10 +0200 Subject: [PATCH 08/12] [ModelicaSystem] rename model_definition() => model() --- OMPython/ModelicaSystem.py | 12 ++++++------ tests/test_FMIExport.py | 8 ++++---- tests/test_ModelicaSystem.py | 32 ++++++++++++++++---------------- tests/test_ModelicaSystemCmd.py | 4 ++-- tests/test_OMSessionCmd.py | 4 ++-- tests/test_linearization.py | 8 ++++---- tests/test_optimization.py | 4 ++-- 7 files changed, 36 insertions(+), 36 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index 9bc25a37..1b9eedfb 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -424,9 +424,9 @@ def __init__( self._file_name: Optional[os.PathLike] self._variable_filter: Optional[str] = None - def model_definition( + def model( self, - model: str, + name: str, file: Optional[str | os.PathLike | pathlib.Path] = None, libraries: Optional[list[str | tuple[str, str]]] = None, variable_filter: Optional[str] = None, @@ -440,7 +440,7 @@ def model_definition( Args: file: Path to the model file. Either absolute or relative to the current working directory. - model: The name of the model class. If it is contained within + name: The name of the model class. If it is contained within a package, "PackageName.ModelName" should be used. libraries: List of libraries to be loaded before the model itself is loaded. Two formats are supported for the list elements: @@ -462,8 +462,8 @@ def model_definition( mod.setup_model(model="modelName", file="ModelicaModel.mo", libraries=[("Modelica","3.2.3"), "PowerSystems"]) """ - if not isinstance(model, str): - raise ModelicaSystemError("A model name must be provided (argument modelName)!") + if not isinstance(name, str): + raise ModelicaSystemError("A model name must be provided (argument name)!") if libraries is None: libraries = [] @@ -472,7 +472,7 @@ def model_definition( raise ModelicaSystemError(f"Invalid input type for lmodel: {type(libraries)} - list expected!") # set variables - self._model_name = model # Model class name + self._model_name = name # Model class name self._lmodel = libraries # may be needed if model is derived from other model self._file_name = pathlib.Path(file).resolve() if file is not None else None # Model file/package name self._variable_filter = variable_filter diff --git a/tests/test_FMIExport.py b/tests/test_FMIExport.py index 688c7ef2..f92c39bc 100644 --- a/tests/test_FMIExport.py +++ b/tests/test_FMIExport.py @@ -5,8 +5,8 @@ def test_CauerLowPassAnalog(): mod = OMPython.ModelicaSystem() - mod.model_definition( - model="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", + mod.model( + name="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", libraries=["Modelica"], ) tmp = mod.getWorkDirectory() @@ -19,8 +19,8 @@ def test_CauerLowPassAnalog(): def test_DrumBoiler(): mod = OMPython.ModelicaSystem() - mod.model_definition( - model="Modelica.Fluid.Examples.DrumBoiler.DrumBoiler", + mod.model( + name="Modelica.Fluid.Examples.DrumBoiler.DrumBoiler", libraries=["Modelica"], ) tmp = mod.getWorkDirectory() diff --git a/tests/test_ModelicaSystem.py b/tests/test_ModelicaSystem.py index ebccda22..80d3f324 100644 --- a/tests/test_ModelicaSystem.py +++ b/tests/test_ModelicaSystem.py @@ -23,9 +23,9 @@ def test_ModelicaSystem_loop(model_firstorder): def worker(): filePath = model_firstorder.as_posix() mod = OMPython.ModelicaSystem() - mod.model_definition( + mod.model( file=filePath, - model="M", + name="M", ) mod.simulate() mod.convertMo2Fmu(fmuType="me") @@ -37,9 +37,9 @@ def test_setParameters(): omc = OMPython.OMCSessionZMQ() model_path = omc.sendExpression("getInstallationDirectoryPath()") + "/share/doc/omc/testmodels/" mod = OMPython.ModelicaSystem() - mod.model_definition( + mod.model( file=model_path + "BouncingBall.mo", - model="BouncingBall", + name="BouncingBall", ) # method 1 @@ -70,9 +70,9 @@ def test_setSimulationOptions(): omc = OMPython.OMCSessionZMQ() model_path = omc.sendExpression("getInstallationDirectoryPath()") + "/share/doc/omc/testmodels/" mod = OMPython.ModelicaSystem() - mod.model_definition( + mod.model( file=model_path + "BouncingBall.mo", - model="BouncingBall", + name="BouncingBall", ) # method 1 @@ -107,9 +107,9 @@ def test_relative_path(model_firstorder): assert "/" not in model_relative mod = OMPython.ModelicaSystem() - mod.model_definition( + mod.model( file=model_relative, - model="M", + name="M", ) assert float(mod.getParameters("a")[0]) == -1 finally: @@ -121,9 +121,9 @@ def test_customBuildDirectory(tmp_path, model_firstorder): tmpdir = tmp_path / "tmpdir1" tmpdir.mkdir() mod = OMPython.ModelicaSystem(customBuildDirectory=tmpdir) - mod.model_definition( + mod.model( file=filePath, - model="M", + name="M", ) assert mod.getWorkDirectory().resolve() == tmpdir.resolve() result_file = tmpdir / "a.mat" @@ -135,9 +135,9 @@ def test_customBuildDirectory(tmp_path, model_firstorder): def test_getSolutions(model_firstorder): filePath = model_firstorder.as_posix() mod = OMPython.ModelicaSystem() - mod.model_definition( + mod.model( file=filePath, - model="M", + name="M", ) x0 = 1 a = -1 @@ -176,9 +176,9 @@ def test_getters(tmp_path): end M_getters; """) mod = OMPython.ModelicaSystem() - mod.model_definition( + mod.model( file=model_file.as_posix(), - model="M_getters", + name="M_getters", ) q = mod.getQuantities() @@ -372,9 +372,9 @@ def test_simulate_inputs(tmp_path): end M_input; """) mod = OMPython.ModelicaSystem() - mod.model_definition( + mod.model( file=model_file.as_posix(), - model="M_input", + name="M_input", ) mod.setSimulationOptions(simOptions={"stopTime": 1.0}) diff --git a/tests/test_ModelicaSystemCmd.py b/tests/test_ModelicaSystemCmd.py index c25a7fb7..73795aa2 100644 --- a/tests/test_ModelicaSystemCmd.py +++ b/tests/test_ModelicaSystemCmd.py @@ -18,9 +18,9 @@ def model_firstorder(tmp_path): @pytest.fixture def mscmd_firstorder(model_firstorder): mod = OMPython.ModelicaSystem() - mod.model_definition( + mod.model( file=model_firstorder.as_posix(), - model="M", + name="M", ) mscmd = OMPython.ModelicaSystemCmd(runpath=mod.getWorkDirectory(), modelname=mod._model_name) return mscmd diff --git a/tests/test_OMSessionCmd.py b/tests/test_OMSessionCmd.py index c024338b..b670407a 100644 --- a/tests/test_OMSessionCmd.py +++ b/tests/test_OMSessionCmd.py @@ -9,8 +9,8 @@ def test_isPackage(): def test_isPackage2(): mod = OMPython.ModelicaSystem() - mod.model_definition( - model="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", + mod.model( + name="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", libraries=["Modelica"], ) omccmd = OMPython.OMCSessionCmd(session=mod._getconn) diff --git a/tests/test_linearization.py b/tests/test_linearization.py index be9dff87..bc6aadbf 100644 --- a/tests/test_linearization.py +++ b/tests/test_linearization.py @@ -25,9 +25,9 @@ def model_linearTest(tmp_path): def test_example(model_linearTest): mod = OMPython.ModelicaSystem() - mod.model_definition( + mod.model( file=model_linearTest, - model="linearTest", + name="linearTest", ) [A, B, C, D] = mod.linearize() expected_matrixA = [[-3, 2, 0, 0], [-7, 0, -5, 1], [-1, 0, -1, 4], [0, 1, -1, 5]] @@ -60,9 +60,9 @@ def test_getters(tmp_path): end Pendulum; """) mod = OMPython.ModelicaSystem() - mod.model_definition( + mod.model( file=model_file.as_posix(), - model="Pendulum", + name="Pendulum", libraries=["Modelica"], ) diff --git a/tests/test_optimization.py b/tests/test_optimization.py index 938216bb..7b0a42d5 100644 --- a/tests/test_optimization.py +++ b/tests/test_optimization.py @@ -34,9 +34,9 @@ def test_optimization_example(tmp_path): """) mod = OMPython.ModelicaSystem() - mod.model_definition( + mod.model( file=model_file.as_posix(), - model="BangBang2021", + name="BangBang2021", ) mod.setOptimizationOptions(optimizationOptions={"numberOfIntervals": 16, From f5defcf4a60d40903e7945a295ea95b17e7c923f Mon Sep 17 00:00:00 2001 From: syntron Date: Sun, 24 Aug 2025 21:35:59 +0200 Subject: [PATCH 09/12] [ModelicaSystem] fix error message --- OMPython/ModelicaSystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index 1b9eedfb..cc05d8f1 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -469,7 +469,7 @@ def model( libraries = [] if not isinstance(libraries, list): - raise ModelicaSystemError(f"Invalid input type for lmodel: {type(libraries)} - list expected!") + raise ModelicaSystemError(f"Invalid input type for libraries: {type(libraries)} - list expected!") # set variables self._model_name = name # Model class name From defea963c2b7b85f8ec4b8cb2a8068ec87801a0a Mon Sep 17 00:00:00 2001 From: syntron Date: Sun, 24 Aug 2025 21:36:27 +0200 Subject: [PATCH 10/12] [ModelicaSystem.definition()] check if it was called before --- OMPython/ModelicaSystem.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index cc05d8f1..458a2c40 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -457,11 +457,15 @@ def model( Examples: mod = ModelicaSystem() # and then one of the lines below - mod.setup_model(model="modelName", file="ModelicaModel.mo", ) - mod.setup_model(model="modelName", file="ModelicaModel.mo", libraries=["Modelica"]) - mod.setup_model(model="modelName", file="ModelicaModel.mo", libraries=[("Modelica","3.2.3"), "PowerSystems"]) + mod.model(name="modelName", file="ModelicaModel.mo", ) + mod.model(name="modelName", file="ModelicaModel.mo", libraries=["Modelica"]) + mod.model(name="modelName", file="ModelicaModel.mo", libraries=[("Modelica","3.2.3"), "PowerSystems"]) """ + if self._model_name is not None: + raise ModelicaSystemError("Can not reuse this instance of ModelicaSystem " + f"defined for {repr(self._model_name)}!") + if not isinstance(name, str): raise ModelicaSystemError("A model name must be provided (argument name)!") From 9024e6bb8ea63ded2c670ae5b43623c3c924ed6e Mon Sep 17 00:00:00 2001 From: syntron Date: Sun, 24 Aug 2025 21:37:41 +0200 Subject: [PATCH 11/12] [ModelicaSystem] rename lmodel => libraries --- OMPython/ModelicaSystem.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index 458a2c40..8ac69b67 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -420,7 +420,7 @@ def __init__( self._work_dir: pathlib.Path = self.setWorkDirectory(customBuildDirectory) self._model_name: Optional[str] = None - self._lmodel: Optional[list[str | tuple[str, str]]] = None + self._libraries: Optional[list[str | tuple[str, str]]] = None self._file_name: Optional[os.PathLike] self._variable_filter: Optional[str] = None @@ -477,15 +477,15 @@ def model( # set variables self._model_name = name # Model class name - self._lmodel = libraries # may be needed if model is derived from other model + self._libraries = libraries # may be needed if model is derived from other model self._file_name = pathlib.Path(file).resolve() if file is not None else None # Model file/package name self._variable_filter = variable_filter if self._file_name is not None and not self._file_name.is_file(): # if file does not exist raise IOError(f"{self._file_name} does not exist!") - if self._lmodel: - self._loadLibrary(lmodel=self._lmodel) + if self._libraries: + self._loadLibrary(libraries=self._libraries) if self._file_name is not None: self._loadFile(fileName=self._file_name) @@ -504,9 +504,9 @@ def _loadFile(self, fileName: pathlib.Path): self.sendExpression(f'loadFile("{fileName.as_posix()}")') # for loading file/package, loading model and building model - def _loadLibrary(self, lmodel: list): + def _loadLibrary(self, libraries: list): # load Modelica standard libraries or Modelica files if needed - for element in lmodel: + for element in libraries: if element is not None: if isinstance(element, str): if element.endswith(".mo"): From df4805a96d6fc9fcb3fdadaf902440e4277bab94 Mon Sep 17 00:00:00 2001 From: syntron Date: Mon, 25 Aug 2025 09:26:32 +0200 Subject: [PATCH 12/12] [ModelicaSystem] update docstring for __init__() and model() --- OMPython/ModelicaSystem.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index 8ac69b67..1fbcb1e9 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -362,10 +362,7 @@ def __init__( omhome: Optional[str] = None, omc_process: Optional[OMCProcessLocal] = None, ) -> None: - """Initialize, load and build a model. - - The constructor loads the model file and builds it, generating exe and - xml files, etc. + """Create a ModelicaSystem instance. To define the model use model() or convertFmu2Mo(). Args: commandLineOptions: List with extra command line options as elements. The list elements are @@ -432,10 +429,9 @@ def model( variable_filter: Optional[str] = None, build: bool = True, ) -> None: - """Initialize, load and build a model. + """Load and build a Modelica model. - The constructor loads the model file and builds it, generating exe and - xml files, etc. + This method loads the model file and builds it if requested (build == True). Args: file: Path to the model file. Either absolute or relative to