Skip to content

Commit 6c7ea7c

Browse files
committed
??? update ... (ModelicaSystemDoE)
1 parent 7e5c8e3 commit 6c7ea7c

9 files changed

Lines changed: 409 additions & 160 deletions

OMPython/ModelicaSystem.py

Lines changed: 240 additions & 131 deletions
Large diffs are not rendered by default.

OMPython/OMCSession.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@
4242
import os
4343
import pathlib
4444
import platform
45-
import psutil
46-
import pyparsing
4745
import re
4846
import shutil
4947
import signal
@@ -56,6 +54,9 @@
5654
import warnings
5755
import zmq
5856

57+
import psutil
58+
import pyparsing
59+
5960
# TODO: replace this with the new parser
6061
from OMPython.OMTypedParser import parseString as om_parser_typed
6162
from OMPython.OMParser import om_parser_basic
@@ -878,7 +879,7 @@ class OMCProcessLocal(OMCProcess):
878879
def __init__(
879880
self,
880881
timeout: float = 10.00,
881-
omhome: Optional[str] = None,
882+
omhome: Optional[str | os.PathLike] = None,
882883
) -> None:
883884

884885
super().__init__(timeout=timeout)
@@ -891,7 +892,7 @@ def __init__(
891892
self._omc_port = self._omc_port_get()
892893

893894
@staticmethod
894-
def _omc_home_get(omhome: Optional[str] = None) -> pathlib.Path:
895+
def _omc_home_get(omhome: Optional[str | os.PathLike] = None) -> pathlib.Path:
895896
# use the provided path
896897
if omhome is not None:
897898
return pathlib.Path(omhome)
@@ -1005,7 +1006,7 @@ def __init__(
10051006
self,
10061007
timeout: float = 10.00,
10071008
dockerExtraArgs: Optional[list] = None,
1008-
dockerOpenModelicaPath: str = "omc",
1009+
dockerOpenModelicaPath: str | os.PathLike = "omc",
10091010
dockerNetwork: Optional[str] = None,
10101011
port: Optional[int] = None,
10111012
) -> None:
@@ -1028,7 +1029,7 @@ def _docker_process_get(self, docker_cid: str) -> Optional[DummyPopen]:
10281029
raise NotImplementedError("Docker not supported on win32!")
10291030

10301031
docker_process = None
1031-
for idx in range(0, 40):
1032+
for _ in range(0, 40):
10321033
dockerTop = subprocess.check_output(["docker", "top", docker_cid]).decode().strip()
10331034
docker_process = None
10341035
for line in dockerTop.split("\n"):
@@ -1143,7 +1144,7 @@ def __init__(
11431144
timeout: float = 10.00,
11441145
docker: Optional[str] = None,
11451146
dockerExtraArgs: Optional[list] = None,
1146-
dockerOpenModelicaPath: str = "omc",
1147+
dockerOpenModelicaPath: str | os.PathLike = "omc",
11471148
dockerNetwork: Optional[str] = None,
11481149
port: Optional[int] = None,
11491150
) -> None:
@@ -1253,7 +1254,7 @@ def _docker_omc_start(self) -> Tuple[subprocess.Popen, DummyPopen, str]:
12531254
raise OMCSessionException(f"Invalid content for docker container ID file path: {docker_cid_file}")
12541255

12551256
docker_cid = None
1256-
for idx in range(0, 40):
1257+
for _ in range(0, 40):
12571258
try:
12581259
with open(file=docker_cid_file, mode="r", encoding="utf-8") as fh:
12591260
docker_cid = fh.read().strip()
@@ -1286,7 +1287,7 @@ def __init__(
12861287
timeout: float = 10.00,
12871288
dockerContainer: Optional[str] = None,
12881289
dockerExtraArgs: Optional[list] = None,
1289-
dockerOpenModelicaPath: str = "omc",
1290+
dockerOpenModelicaPath: str | os.PathLike = "omc",
12901291
dockerNetwork: Optional[str] = None,
12911292
port: Optional[int] = None,
12921293
) -> None:

tests/test_FMIExport.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import OMPython
22
import shutil
33
import os
4+
import pathlib
45

56

67
def test_CauerLowPassAnalog():
78
mod = OMPython.ModelicaSystem(modelName="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog",
89
lmodel=["Modelica"])
9-
tmp = mod.getWorkDirectory()
10+
# TODO [OMCPath]: need to work using OMCPath
11+
tmp = pathlib.Path(mod.getWorkDirectory())
1012
try:
1113
fmu = mod.convertMo2Fmu(fileNamePrefix="CauerLowPassAnalog")
1214
assert os.path.exists(fmu)
@@ -16,7 +18,8 @@ def test_CauerLowPassAnalog():
1618

1719
def test_DrumBoiler():
1820
mod = OMPython.ModelicaSystem(modelName="Modelica.Fluid.Examples.DrumBoiler.DrumBoiler", lmodel=["Modelica"])
19-
tmp = mod.getWorkDirectory()
21+
# TODO [OMCPath]: need to work using OMCPath
22+
tmp = pathlib.Path(mod.getWorkDirectory())
2023
try:
2124
fmu = mod.convertMo2Fmu(fileNamePrefix="DrumBoiler")
2225
assert os.path.exists(fmu)

tests/test_ModelicaSystemCmd.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,19 @@
55
@pytest.fixture
66
def model_firstorder(tmp_path):
77
mod = tmp_path / "M.mo"
8-
mod.write_text("""model M
9-
Real x(start = 1, fixed = true);
10-
parameter Real a = -1;
11-
equation
12-
der(x) = x*a;
13-
end M;
14-
""")
8+
mod.write_text("""
9+
model M
10+
parameter Integer p=1;
11+
parameter Integer q=1;
12+
parameter Real a = -1;
13+
parameter Real b = -1;
14+
Real x[p];
15+
Real y[q];
16+
equation
17+
der(x) = a * fill(1.0, p);
18+
der(y) = b * fill(1.0, q);
19+
end M;
20+
""")
1521
return mod
1622

1723

@@ -38,6 +44,16 @@ def test_simflags(mscmd_firstorder):
3844

3945
assert mscmd.get_cmd_args() == [
4046
'-noEventEmit',
41-
'-override=b=2,a=1,x=3',
47+
'-override=a=1,b=2,x=3',
48+
'-noRestart',
49+
]
50+
51+
mscmd.args_set({
52+
"override": {'b': None},
53+
})
54+
55+
assert mscmd.get_cmd_args() == [
56+
'-noEventEmit',
57+
'-override=a=1,x=3',
4258
'-noRestart',
4359
]

tests/test_ModelicaSystemDoE.py

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,24 @@
22
import OMPython
33
import pathlib
44
import pytest
5+
import sys
6+
7+
skip_on_windows = pytest.mark.skipif(
8+
sys.platform.startswith("win"),
9+
reason="OpenModelica Docker image is Linux-only; skipping on Windows.",
10+
)
11+
12+
skip_python_older_312 = pytest.mark.skipif(
13+
sys.version_info < (3, 12),
14+
reason="OMCPath(non-local) only working for Python >= 3.12.",
15+
)
516

617

718
@pytest.fixture
819
def model_doe(tmp_path: pathlib.Path) -> pathlib.Path:
920
# see: https://trac.openmodelica.org/OpenModelica/ticket/4052
1021
mod = tmp_path / "M.mo"
22+
# TODO: update for bool and string parameters; check if these can be used in DoE
1123
mod.write_text("""
1224
model M
1325
parameter Integer p=1;
@@ -37,7 +49,47 @@ def param_doe() -> dict[str, list]:
3749
return param
3850

3951

40-
def test_ModelicaSystemDoE(tmp_path, model_doe, param_doe):
52+
# @pytest.mark.skip(reason="No OMC")
53+
def test_ModelicaSystemDoE_local(tmp_path, model_doe, param_doe):
54+
tmpdir = tmp_path / 'DoE'
55+
tmpdir.mkdir(exist_ok=True)
56+
57+
doe_mod = OMPython.ModelicaSystemDoE(
58+
fileName=model_doe.as_posix(),
59+
modelName="M",
60+
parameters=param_doe,
61+
resultpath=tmpdir,
62+
simargs={"override": {'stopTime': 1.0}},
63+
)
64+
65+
_run_ModelicaSystemDoe(doe_mod=doe_mod)
66+
67+
68+
@skip_on_windows
69+
@skip_python_older_312
70+
def test_ModelicaSystemDoE_docker(tmp_path, model_doe, param_doe):
71+
omcp = OMPython.OMCProcessDocker(docker="openmodelica/openmodelica:v1.25.0-minimal")
72+
omc = OMPython.OMCSessionZMQ(omc_process=omcp)
73+
assert omc.sendExpression("getVersion()") == "OpenModelica 1.25.0"
74+
75+
modelpath = omc.omcpath_tempdir() / 'M.mo'
76+
modelpath.write_text(model_doe.read_text())
77+
78+
doe_mod = OMPython.ModelicaSystemDoE(
79+
fileName=modelpath.as_posix(),
80+
modelName="M",
81+
parameters=param_doe,
82+
omc_process=omcp,
83+
resultpath=modelpath.parent,
84+
simargs={"override": {'stopTime': 1.0}},
85+
)
86+
87+
_run_ModelicaSystemDoe(doe_mod=doe_mod)
88+
89+
90+
@pytest.mark.skip(reason="Not able to run WSL on github")
91+
@skip_python_older_312
92+
def test_ModelicaSystemDoE_WSL(tmp_path, model_doe, param_doe):
4193
tmpdir = tmp_path / 'DoE'
4294
tmpdir.mkdir(exist_ok=True)
4395

@@ -48,20 +100,34 @@ def test_ModelicaSystemDoE(tmp_path, model_doe, param_doe):
48100
resultpath=tmpdir,
49101
simargs={"override": {'stopTime': 1.0}},
50102
)
103+
104+
_run_ModelicaSystemDoe(doe_mod=doe_mod)
105+
106+
107+
def _run_ModelicaSystemDoe(doe_mod):
51108
doe_count = doe_mod.prepare()
52109
assert doe_count == 16
53110

54-
doe_dict = doe_mod.get_doe()
55-
assert isinstance(doe_dict, dict)
56-
assert len(doe_dict.keys()) == 16
111+
doe_def = doe_mod.get_doe_definition()
112+
assert isinstance(doe_def, dict)
113+
assert len(doe_def.keys()) == doe_count
114+
115+
doe_cmd = doe_mod.get_doe_command()
116+
assert isinstance(doe_cmd, dict)
117+
assert len(doe_cmd.keys()) == doe_count
57118

58119
doe_status = doe_mod.simulate()
59120
assert doe_status is True
60121

61-
doe_sol = doe_mod.get_solutions()
122+
doe_sol = doe_mod.get_doe_solutions()
123+
assert isinstance(doe_sol, dict)
124+
assert len(doe_sol.keys()) == doe_count
125+
126+
assert sorted(doe_def.keys()) == sorted(doe_cmd.keys())
127+
assert sorted(doe_cmd.keys()) == sorted(doe_sol.keys())
62128

63-
for resultfilename in doe_dict:
64-
row = doe_dict[resultfilename]
129+
for resultfilename in doe_def:
130+
row = doe_def[resultfilename]
65131

66132
assert resultfilename in doe_sol
67133
sol = doe_sol[resultfilename]

tests/test_OMCPath.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ def test_OMCPath_OMCProcessDocker():
4343
del om
4444

4545

46+
@skip_python_older_312
47+
def test_OMCPath_local():
48+
om = OMPython.OMCProcessLocal()
49+
50+
_run_OMCPath_checks(om)
51+
52+
del om
53+
54+
4655
@pytest.mark.skip(reason="Not able to run WSL on github")
4756
@skip_python_older_312
4857
def test_OMCPath_OMCProcessWSL():

tests/test_OMCSessionRunData.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import sys
2+
import pytest
3+
import OMPython
4+
5+
skip_on_windows = pytest.mark.skipif(
6+
sys.platform.startswith("win"),
7+
reason="OpenModelica Docker image is Linux-only; skipping on Windows.",
8+
)
9+
10+
11+
@skip_on_windows
12+
def test_docker():
13+
# TODO: test OMCSessionRunData for valid content
14+
15+
omcp = OMPython.OMCProcessDocker(docker="openmodelica/openmodelica:v1.25.0-minimal")
16+
om = OMPython.OMCSessionZMQ(omc_process=omcp)
17+
assert om.sendExpression("getVersion()") == "OpenModelica 1.25.0"
18+
19+
omcpInner = OMPython.OMCProcessDockerContainer(dockerContainer=omcp.get_docker_container_id())
20+
omInner = OMPython.OMCSessionZMQ(omc_process=omcpInner)
21+
assert omInner.sendExpression("getVersion()") == "OpenModelica 1.25.0"
22+
23+
omcp2 = OMPython.OMCProcessDocker(docker="openmodelica/openmodelica:v1.25.0-minimal", port=11111)
24+
om2 = OMPython.OMCSessionZMQ(omc_process=omcp2)
25+
assert om2.sendExpression("getVersion()") == "OpenModelica 1.25.0"
26+
27+
del omcp2
28+
del om2
29+
30+
del omcpInner
31+
del omInner
32+
33+
del omcp
34+
del om

tests/test_ZMQ.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,17 @@
66

77
@pytest.fixture
88
def model_time_str():
9-
return """model M
10-
Real r = time;
9+
return """
10+
model M
11+
parameter Integer p=1;
12+
parameter Integer q=1;
13+
parameter Real a = -1;
14+
parameter Real b = -1;
15+
Real x[p];
16+
Real y[q];
17+
equation
18+
der(x) = a * fill(1.0, p);
19+
der(y) = b * fill(1.0, q);
1120
end M;
1221
"""
1322

tests/test_optimization.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ def test_optimization_example(tmp_path):
4747

4848
r = mod.optimize()
4949
# it is necessary to specify resultfile, otherwise it wouldn't find it.
50-
time, f, v = mod.getSolutions(["time", "f", "v"], resultfile=r["resultFile"])
50+
resultfile_str = r["resultFile"]
51+
resultfile_omcpath = mod._getconn.omcpath(resultfile_str)
52+
time, f, v = mod.getSolutions(["time", "f", "v"], resultfile=resultfile_omcpath.as_posix())
5153
assert np.isclose(f[0], 10)
5254
assert np.isclose(f[-1], -10)
5355

0 commit comments

Comments
 (0)