Skip to content

Commit 16150c7

Browse files
syntronadeas31
andauthored
Update override handling (#402)
* [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 * [ModelicaSystem] parse OM version in __init__() * [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 ... * [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 * [ModelicaSystem] simplify call to sendExpression() * [ModelicaSystem] check for dict content using len() == 0 * [ModelicaSystem] fix overwrite file (write only if there is content) * [ModelicaSystem] add docstring for _process_override_data() --------- Co-authored-by: Adeel Asghar <adeel.asghar@liu.se>
1 parent b007f13 commit 16150c7

File tree

1 file changed

+65
-64
lines changed

1 file changed

+65
-64
lines changed

OMPython/ModelicaSystem.py

Lines changed: 65 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import os
1212
import pathlib
1313
import queue
14+
import re
1415
import textwrap
1516
import threading
1617
from typing import Any, cast, Optional
@@ -19,8 +20,6 @@
1920

2021
import numpy as np
2122

22-
import re
23-
2423
from OMPython.OMCSession import (
2524
OMCSessionException,
2625
OMCSessionRunData,
@@ -332,14 +331,14 @@ def __init__(
332331
self._simulate_options: dict[str, str] = {}
333332
self._override_variables: dict[str, str] = {}
334333
self._simulate_options_override: dict[str, str] = {}
335-
self._linearization_options: dict[str, str | float] = {
336-
'startTime': 0.0,
337-
'stopTime': 1.0,
338-
'stepSize': 0.002,
339-
'tolerance': 1e-8,
334+
self._linearization_options: dict[str, str] = {
335+
'startTime': str(0.0),
336+
'stopTime': str(1.0),
337+
'stepSize': str(0.002),
338+
'tolerance': str(1e-8),
340339
}
341340
self._optimization_options = self._linearization_options | {
342-
'numberOfIntervals': 500,
341+
'numberOfIntervals': str(500),
343342
}
344343
self._linearized_inputs: list[str] = [] # linearization input list
345344
self._linearized_outputs: list[str] = [] # linearization output list
@@ -351,7 +350,8 @@ def __init__(
351350
self._session = OMCSessionLocal(omhome=omhome)
352351

353352
# get OpenModelica version
354-
self._version = self._session.sendExpression("getVersion()", parsed=True)
353+
version_str = self.sendExpression(expr="getVersion()")
354+
self._version = self._parse_om_version(version=version_str)
355355
# set commandLineOptions using default values or the user defined list
356356
if command_line_options is None:
357357
# set default command line options to improve the performance of linearization and to avoid recompilation if
@@ -950,7 +950,7 @@ def getSimulationOptions(
950950
def getLinearizationOptions(
951951
self,
952952
names: Optional[str | list[str]] = None,
953-
) -> dict[str, str | float] | list[str | float]:
953+
) -> dict[str, str] | list[str]:
954954
"""Get simulation options used for linearization.
955955
956956
Args:
@@ -964,17 +964,16 @@ def getLinearizationOptions(
964964
returned.
965965
If `names` is a list, a list with one value for each option name
966966
in names is returned: [option1_value, option2_value, ...].
967-
Some option values are returned as float when first initialized,
968-
but always as strings after setLinearizationOptions is used to
969-
change them.
967+
968+
The option values are always returned as strings.
970969
971970
Examples:
972971
>>> mod.getLinearizationOptions()
973-
{'startTime': 0.0, 'stopTime': 1.0, 'stepSize': 0.002, 'tolerance': 1e-08}
972+
{'startTime': '0.0', 'stopTime': '1.0', 'stepSize': '0.002', 'tolerance': '1e-08'}
974973
>>> mod.getLinearizationOptions("stopTime")
975-
[1.0]
974+
['1.0']
976975
>>> mod.getLinearizationOptions(["tolerance", "stopTime"])
977-
[1e-08, 1.0]
976+
['1e-08', '1.0']
978977
"""
979978
if names is None:
980979
return self._linearization_options
@@ -988,7 +987,7 @@ def getLinearizationOptions(
988987
def getOptimizationOptions(
989988
self,
990989
names: Optional[str | list[str]] = None,
991-
) -> dict[str, str | float] | list[str | float]:
990+
) -> dict[str, str] | list[str]:
992991
"""Get simulation options used for optimization.
993992
994993
Args:
@@ -1002,9 +1001,8 @@ def getOptimizationOptions(
10021001
returned.
10031002
If `names` is a list, a list with one value for each option name
10041003
in names is returned: [option1_value, option2_value, ...].
1005-
Some option values are returned as float when first initialized,
1006-
but always as strings after setOptimizationOptions is used to
1007-
change them.
1004+
1005+
The option values are always returned as string.
10081006
10091007
Examples:
10101008
>>> mod.getOptimizationOptions()
@@ -1023,13 +1021,47 @@ def getOptimizationOptions(
10231021

10241022
raise ModelicaSystemError("Unhandled input for getOptimizationOptions()")
10251023

1026-
def parse_om_version(self, version: str) -> tuple[int, int, int]:
1024+
def _parse_om_version(self, version: str) -> tuple[int, int, int]:
10271025
match = re.search(r"v?(\d+)\.(\d+)\.(\d+)", version)
10281026
if not match:
10291027
raise ValueError(f"Version not found in: {version}")
10301028
major, minor, patch = map(int, match.groups())
1029+
10311030
return major, minor, patch
10321031

1032+
def _process_override_data(
1033+
self,
1034+
om_cmd: ModelicaSystemCmd,
1035+
override_file: OMCPath,
1036+
override_var: dict[str, str],
1037+
override_sim: dict[str, str],
1038+
) -> None:
1039+
"""
1040+
Define the override parameters. As the definition of simulation specific override parameter changes with OM
1041+
1.26.0, version specific code is needed. Please keep in mind, that this will fail if OMC is not used to run the
1042+
model executable.
1043+
"""
1044+
if len(override_var) == 0 and len(override_sim) == 0:
1045+
return
1046+
1047+
override_content = ""
1048+
if override_var:
1049+
override_content += "\n".join([f"{key}={value}" for key, value in override_var.items()]) + "\n"
1050+
1051+
# simulation options are not read from override file from version >= 1.26.0,
1052+
# pass them to simulation executable directly as individual arguments
1053+
# see https://github.com/OpenModelica/OpenModelica/pull/14813
1054+
if override_sim:
1055+
if self._version >= (1, 26, 0):
1056+
for key, opt_value in override_sim.items():
1057+
om_cmd.arg_set(key=key, val=str(opt_value))
1058+
else:
1059+
override_content += "\n".join([f"{key}={value}" for key, value in override_sim.items()]) + "\n"
1060+
1061+
if override_content:
1062+
override_file.write_text(override_content)
1063+
om_cmd.arg_set(key="overrideFile", val=override_file.as_posix())
1064+
10331065
def simulate_cmd(
10341066
self,
10351067
result_file: OMCPath,
@@ -1073,29 +1105,12 @@ def simulate_cmd(
10731105
if simargs:
10741106
om_cmd.args_set(args=simargs)
10751107

1076-
if self._override_variables or self._simulate_options_override:
1077-
override_file = result_file.parent / f"{result_file.stem}_override.txt"
1078-
1079-
# simulation options are not read from override file from version >= 1.26.0,
1080-
# pass them to simulation executable directly as individual arguments
1081-
# see https://github.com/OpenModelica/OpenModelica/pull/14813
1082-
major, minor, patch = self.parse_om_version(self._version)
1083-
if (major, minor, patch) >= (1, 26, 0):
1084-
for key, opt_value in self._simulate_options_override.items():
1085-
om_cmd.arg_set(key=key, val=str(opt_value))
1086-
override_content = (
1087-
"\n".join([f"{key}={value}" for key, value in self._override_variables.items()])
1088-
+ "\n"
1089-
)
1090-
else:
1091-
override_content = (
1092-
"\n".join([f"{key}={value}" for key, value in self._override_variables.items()])
1093-
+ "\n".join([f"{key}={value}" for key, value in self._simulate_options_override.items()])
1094-
+ "\n"
1095-
)
1096-
1097-
override_file.write_text(override_content)
1098-
om_cmd.arg_set(key="overrideFile", val=override_file.as_posix())
1108+
self._process_override_data(
1109+
om_cmd=om_cmd,
1110+
override_file=result_file.parent / f"{result_file.stem}_override.txt",
1111+
override_var=self._override_variables,
1112+
override_sim=self._simulate_options_override,
1113+
)
10991114

11001115
if self._inputs: # if model has input quantities
11011116
for key, val in self._inputs.items():
@@ -1775,26 +1790,12 @@ def linearize(
17751790
modelname=self._model_name,
17761791
)
17771792

1778-
# See comment in simulate_cmd regarding override file and OM version
1779-
major, minor, patch = self.parse_om_version(self._version)
1780-
if (major, minor, patch) >= (1, 26, 0):
1781-
for key, opt_value in self._linearization_options.items():
1782-
om_cmd.arg_set(key=key, val=str(opt_value))
1783-
override_content = (
1784-
"\n".join([f"{key}={value}" for key, value in self._override_variables.items()])
1785-
+ "\n"
1786-
)
1787-
else:
1788-
override_content = (
1789-
"\n".join([f"{key}={value}" for key, value in self._override_variables.items()])
1790-
+ "\n".join([f"{key}={value}" for key, value in self._linearization_options.items()])
1791-
+ "\n"
1792-
)
1793-
1794-
override_file = self.getWorkDirectory() / f'{self._model_name}_override_linear.txt'
1795-
override_file.write_text(override_content)
1796-
1797-
om_cmd.arg_set(key="overrideFile", val=override_file.as_posix())
1793+
self._process_override_data(
1794+
om_cmd=om_cmd,
1795+
override_file=self.getWorkDirectory() / f'{self._model_name}_override_linear.txt',
1796+
override_var=self._override_variables,
1797+
override_sim=self._linearization_options,
1798+
)
17981799

17991800
if self._inputs:
18001801
for key, data in self._inputs.items():

0 commit comments

Comments
 (0)