Skip to content

Commit 025daae

Browse files
authored
fix loadFile for package.mo: don't copy it out of its package directory (#476)
* add test for loading structured package
1 parent 8f7930b commit 025daae

9 files changed

Lines changed: 68 additions & 10 deletions

File tree

‎OMPython/ModelicaSystem.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,11 @@ def _set_compatibility_helper(
195195
input_args.append(args[0])
196196
elif pkey in kwargs:
197197
input_args.append(kwargs[pkey])
198+
elif kwargs:
199+
# New-style call, e.g. setInputs(u1=10, u2=0) instead of the old
200+
# setInputs(name={"u1": 10, "u2": 0}) / setInputs("u1=10,u2=0").
201+
# Treat kwargs itself as the payload instead of silently dropping it.
202+
input_args.append(kwargs)
198203

199204
# the code below is based on _prepare_input_data2()
200205

‎OMPython/modelica_system_omc.py‎

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,24 @@ def model(
140140
if not file_path.is_file():
141141
raise IOError(f"Model file {file_path} does not exist!")
142142

143-
self._file_name = self.getWorkDirectory() / file_path.name
144-
if (isinstance(self._session, OMCSessionLocal)
145-
and file_path.as_posix() == self._file_name.as_posix()):
146-
pass
147-
elif self._file_name.is_file():
148-
raise IOError(f"Simulation model file {self._file_name} exist - not overwriting!")
143+
if isinstance(self._session, OMCSessionLocal) and file_path.name == "package.mo":
144+
# Structured/directory-based package: OMC requires the enclosing
145+
# directory's name to match the package name declared inside
146+
# package.mo, and the package may span sibling .mo files in that
147+
# same directory tree (e.g. Tests/StableBouncingBall.mo). Copying
148+
# just this one file into a randomly-named work directory breaks
149+
# both of those, so load it in place instead.
150+
self._file_name = self._session.omcpath(file_path)
149151
else:
150-
content = file_path.read_text(encoding='utf-8')
151-
self._file_name.write_text(content)
152+
self._file_name = self.getWorkDirectory() / file_path.name
153+
if (isinstance(self._session, OMCSessionLocal)
154+
and file_path.as_posix() == self._file_name.as_posix()):
155+
pass
156+
elif self._file_name.is_file():
157+
raise IOError(f"Simulation model file {self._file_name} exist - not overwriting!")
158+
else:
159+
content = file_path.read_text(encoding='utf-8')
160+
self._file_name.write_text(content)
152161

153162
if self._file_name is not None:
154163
self._loadFile(fileName=self._file_name)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
within BouncingBalls.Tests;
2+
3+
model BouncingBall "The 'classic' bouncing ball model"
4+
type Height=Real(unit="m");
5+
type Velocity=Real(unit="m/s");
6+
parameter Real e=0.8 "Coefficient of restitution";
7+
parameter Height h0=1.0 "Initial height";
8+
Height h "Height";
9+
Velocity v(start=0.0, fixed=true) "Velocity";
10+
initial equation
11+
h = h0;
12+
equation
13+
v = der(h);
14+
der(v) = -9.81;
15+
when h<0 then
16+
reinit(v, -e*pre(v));
17+
end when;
18+
annotation(
19+
experiment(StartTime = 0, StopTime = 10, Tolerance = 1e-06, Interval = 0.01),
20+
__OpenModelica_commandLineOptions = "--matchingAlgorithm=PFPlusExt --indexReductionMethod=dynamicStateSelection -d=initialization,NLSanalyticJacobian",
21+
__OpenModelica_simulationFlags(lv = "LOG_STDOUT,LOG_ASSERT,LOG_STATS", s = "dassl", variableFilter = ".*"));
22+
end BouncingBall;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
within BouncingBalls;
2+
package Tests "Tests"
3+
end Tests;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
BouncingBall
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
within ;
2+
package BouncingBalls "Test"
3+
end BouncingBalls;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Tests

‎tests/test_ModelicaSystemOMC.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,21 @@ def test_relative_path(model_firstorder):
140140
model_file.unlink() # clean up the temporary file
141141

142142

143+
def test_load_structured_package():
144+
# Regression test for loading a directory-based package via its package.mo:
145+
# OMC requires the enclosing directory's name to match the package name, and
146+
# the package spans a sibling file in a nested subdirectory
147+
# (Tests/BouncingBall.mo). Both break if package.mo gets copied out of
148+
# its directory instead of being loaded in place.
149+
package_dir = pathlib.Path(__file__).parent / "resources" / "BouncingBalls"
150+
151+
mod = OMPython.ModelicaSystemOMC()
152+
mod.model(
153+
model_file=package_dir / "package.mo",
154+
model_name="BouncingBalls.Tests.BouncingBall")
155+
mod.simulate()
156+
157+
143158
def test_customBuildDirectory(tmp_path, model_firstorder):
144159
tmpdir = tmp_path / "tmpdir1"
145160
tmpdir.mkdir()

‎tests/test_linearization.py‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,10 @@ def test_getters(tmp_path):
8282
assert mod.getLinearInputs() == ["u1", "u2"]
8383
assert mod.getLinearStates() == ["omega", "phi"]
8484
assert mod.getLinearOutputs() == ["y1", "y2"]
85-
assert np.isclose(A, [[0, param_g / param_l], [1, 0]]).all()
85+
assert np.isclose(A, [[0, param_g/param_l], [1, 0]]).all()
8686
assert np.isclose(B, [[0, 0], [0, 1]]).all()
8787
assert np.isclose(C, [[0.5, 1], [0, 1]]).all()
8888
assert np.isclose(D, [[1, 0], [1, 0]]).all()
89-
9089
# test LinearizationResult
9190
result = mod.linearize()
9291
assert result[0] == A

0 commit comments

Comments
 (0)