Skip to content

Commit 463db6f

Browse files
committed
Merge branch 'test_cleanup' into v4.1.0-syntron5
2 parents 85178ff + f86d410 commit 463db6f

4 files changed

Lines changed: 112 additions & 35 deletions

File tree

OMPython/ModelicaSystem.py

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import logging
3939
import numbers
4040
import os
41+
import pathlib
4142
import queue
4243
import textwrap
4344
import threading
@@ -450,18 +451,30 @@ def model(
450451
# set variables
451452
self._model_name = name # Model class name
452453
self._libraries = libraries # may be needed if model is derived from other model
453-
if file is not None:
454-
file_name = self._session.omcpath(file).resolve()
455-
else:
456-
file_name = None
457-
self._file_name = file_name # Model file/package name
458454
self._variable_filter = variable_filter
459455

460-
if self._file_name is not None and not self._file_name.is_file(): # if file does not exist
461-
raise IOError(f"{self._file_name} does not exist!")
462-
463456
if self._libraries:
464457
self._loadLibrary(libraries=self._libraries)
458+
459+
self._file_name = None
460+
if file is not None:
461+
file_path = pathlib.Path(file)
462+
# special handling for OMCProcessLocal - consider a relative path
463+
if isinstance(self._session.omc_process, OMCProcessLocal) and not file_path.is_absolute():
464+
file_path = pathlib.Path.cwd() / file_path
465+
if not file_path.is_file():
466+
raise IOError(f"Model file {file_path} does not exist!")
467+
468+
self._file_name = self.getWorkDirectory() / file_path.name
469+
if (isinstance(self._session.omc_process, OMCProcessLocal)
470+
and file_path.as_posix() == self._file_name.as_posix()):
471+
pass
472+
elif self._file_name.is_file():
473+
raise IOError(f"Simulation model file {self._file_name} exist - not overwriting!")
474+
else:
475+
content = file_path.read_text(encoding='utf-8')
476+
self._file_name.write_text(content)
477+
465478
if self._file_name is not None:
466479
self._loadFile(fileName=self._file_name)
467480

@@ -1635,7 +1648,7 @@ def convertMo2Fmu(
16351648
fmuType: str = "me_cs",
16361649
fileNamePrefix: Optional[str] = None,
16371650
includeResources: bool = True,
1638-
) -> str:
1651+
) -> OMCPath:
16391652
"""Translate the model into a Functional Mockup Unit.
16401653
16411654
Args:
@@ -1662,15 +1675,19 @@ def convertMo2Fmu(
16621675
properties = (f'version="{version}", fmuType="{fmuType}", '
16631676
f'fileNamePrefix="{fileNamePrefix}", includeResources={includeResourcesStr}')
16641677
fmu = self._requestApi(apiName='buildModelFMU', entity=self._model_name, properties=properties)
1678+
fmu_path = self._session.omcpath(fmu)
16651679

16661680
# report proper error message
1667-
if not os.path.exists(fmu):
1668-
raise ModelicaSystemError(f"Missing FMU file: {fmu}")
1681+
if not fmu_path.is_file():
1682+
raise ModelicaSystemError(f"Missing FMU file: {fmu_path.as_posix()}")
16691683

1670-
return fmu
1684+
return fmu_path
16711685

16721686
# to convert FMU to Modelica model
1673-
def convertFmu2Mo(self, fmuName): # 20
1687+
def convertFmu2Mo(
1688+
self,
1689+
fmu: os.PathLike,
1690+
) -> OMCPath:
16741691
"""
16751692
In order to load FMU, at first it needs to be translated into Modelica model. This method is used to generate
16761693
Modelica model from the given FMU. It generates "fmuName_me_FMU.mo".
@@ -1679,13 +1696,24 @@ def convertFmu2Mo(self, fmuName): # 20
16791696
>>> convertFmu2Mo("c:/BouncingBall.Fmu")
16801697
"""
16811698

1682-
fileName = self._requestApi(apiName='importFMU', entity=fmuName)
1699+
fmu_path = self._session.omcpath(fmu)
1700+
1701+
if not fmu_path.is_file():
1702+
raise ModelicaSystemError(f"Missing FMU file: {fmu_path.as_posix()}")
1703+
1704+
filename = self._requestApi(apiName='importFMU', entity=fmu_path.as_posix())
1705+
filepath = self.getWorkDirectory() / filename
16831706

16841707
# report proper error message
1685-
if not os.path.exists(fileName):
1686-
raise ModelicaSystemError(f"Missing file {fileName}")
1708+
if not filepath.is_file():
1709+
raise ModelicaSystemError(f"Missing file {filepath.as_posix()}")
1710+
1711+
self.model(
1712+
name=f"{fmu_path.stem}_me_FMU",
1713+
file=filepath,
1714+
)
16871715

1688-
return fileName
1716+
return filepath
16891717

16901718
def optimize(self) -> dict[str, Any]:
16911719
"""Perform model-based optimization.

tests/test_FMIImport.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import numpy as np
2+
import os
3+
import pytest
4+
import shutil
5+
6+
import OMPython
7+
8+
9+
@pytest.fixture
10+
def model_firstorder(tmp_path):
11+
mod = tmp_path / "M.mo"
12+
mod.write_text("""model M
13+
Real x(start = 1, fixed = true);
14+
parameter Real a = -1;
15+
equation
16+
der(x) = x*a;
17+
end M;
18+
""")
19+
return mod
20+
21+
22+
def test_FMIImport(model_firstorder):
23+
filePath = model_firstorder.as_posix()
24+
25+
# create model & simulate it
26+
mod1 = OMPython.ModelicaSystem()
27+
mod1.model(file=filePath, name="M")
28+
mod1.simulate()
29+
30+
# create FMU & check
31+
fmu = mod1.convertMo2Fmu(fileNamePrefix="M")
32+
assert os.path.exists(fmu)
33+
34+
# import FMU & check & simulate
35+
# TODO: why is '--allowNonStandardModelica=reinitInAlgorithms' needed? any example without this possible?
36+
mod2 = OMPython.ModelicaSystem(commandLineOptions=['--allowNonStandardModelica=reinitInAlgorithms'])
37+
mo = mod2.convertFmu2Mo(fmu=fmu)
38+
assert os.path.exists(mo)
39+
40+
mod2.simulate()
41+
42+
# get and verify result
43+
res1 = mod1.getSolutions(['time', 'x'])
44+
res2 = mod2.getSolutions(['time', 'x'])
45+
46+
# check last value for time
47+
assert res1[0][-1] == res2[0][-1] == 1.0
48+
# check last value for x
49+
assert np.isclose(res1[1][-1], 0.3678794515) # 0.36787945153397683
50+
assert np.isclose(res2[1][-1], 0.3678794515) # 0.3678794515707647
51+
52+
# cleanup
53+
tmp2 = mod1.getWorkDirectory()
54+
shutil.rmtree(tmp2, ignore_errors=True)
55+
56+
tmp2 = mod2.getWorkDirectory()
57+
shutil.rmtree(tmp2, ignore_errors=True)

tests/test_ModelicaSystem.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,11 @@ def worker():
5151

5252
def test_setParameters():
5353
omc = OMPython.OMCSessionZMQ()
54-
model_path = omc.sendExpression("getInstallationDirectoryPath()") + "/share/doc/omc/testmodels/"
54+
model_path_str = omc.sendExpression("getInstallationDirectoryPath()") + "/share/doc/omc/testmodels"
55+
model_path = omc.omcpath(model_path_str)
5556
mod = OMPython.ModelicaSystem()
5657
mod.model(
57-
file=model_path + "BouncingBall.mo",
58+
file=model_path / "BouncingBall.mo",
5859
name="BouncingBall",
5960
)
6061

@@ -85,10 +86,11 @@ def test_setParameters():
8586

8687
def test_setSimulationOptions():
8788
omc = OMPython.OMCSessionZMQ()
88-
model_path = omc.sendExpression("getInstallationDirectoryPath()") + "/share/doc/omc/testmodels/"
89+
model_path_str = omc.sendExpression("getInstallationDirectoryPath()") + "/share/doc/omc/testmodels"
90+
model_path = omc.omcpath(model_path_str)
8991
mod = OMPython.ModelicaSystem()
9092
mod.model(
91-
file=model_path + "BouncingBall.mo",
93+
file=model_path / "BouncingBall.mo",
9294
name="BouncingBall",
9395
)
9496

@@ -112,7 +114,6 @@ def test_setSimulationOptions():
112114
assert d["tolerance"] == "1.2e-08"
113115

114116

115-
@pytest.mark.skip("will fail / fix available")
116117
def test_relative_path(model_firstorder):
117118
cwd = pathlib.Path.cwd()
118119
(fd, name) = tempfile.mkstemp(prefix='tmpOMPython.tests', dir=cwd, text=True)
@@ -152,30 +153,25 @@ def test_customBuildDirectory(tmp_path, model_firstorder):
152153

153154
@skip_on_windows
154155
@skip_python_older_312
155-
def test_getSolutions_docker(model_firstorder_content):
156+
def test_getSolutions_docker(model_firstorder):
156157
omcp = OMPython.OMCProcessDocker(docker="openmodelica/openmodelica:v1.25.0-minimal")
157158
omc = OMPython.OMCSessionZMQ(omc_process=omcp)
158159

159-
modelpath = omc.omcpath_tempdir() / 'M.mo'
160-
modelpath.write_text(model_firstorder_content)
161-
162-
file_path = pathlib.Path(modelpath)
163160
mod = OMPython.ModelicaSystem(
164161
omc_process=omc.omc_process,
165162
)
166163
mod.model(
167164
name="M",
168-
file=file_path,
165+
file=model_firstorder.as_posix(),
169166
)
170167

171168
_run_getSolutions(mod)
172169

173170

174171
def test_getSolutions(model_firstorder):
175-
filePath = model_firstorder.as_posix()
176172
mod = OMPython.ModelicaSystem()
177173
mod.model(
178-
file=filePath,
174+
file=model_firstorder.as_posix(),
179175
name="M",
180176
)
181177

tests/test_ModelicaSystemDoE.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,11 @@ def test_ModelicaSystemDoE_docker(tmp_path, model_doe, param_doe):
7171
omc = OMPython.OMCSessionZMQ(omc_process=omcp)
7272
assert omc.sendExpression("getVersion()") == "OpenModelica 1.25.0"
7373

74-
modelpath = omc.omcpath_tempdir() / 'M.mo'
75-
modelpath.write_text(model_doe.read_text())
76-
7774
doe_mod = OMPython.ModelicaSystemDoE(
78-
fileName=modelpath.as_posix(),
75+
fileName=model_doe.as_posix(),
7976
modelName="M",
8077
parameters=param_doe,
8178
omc_process=omcp,
82-
resultpath=modelpath.parent,
8379
simargs={"override": {'stopTime': 1.0}},
8480
)
8581

0 commit comments

Comments
 (0)