Skip to content

Commit 77cd50b

Browse files
committed
💄✅ boundary conditions added to simulation_options, removed from init + addition of warning for conflicting 'x' parameter
1 parent 7947195 commit 77cd50b

2 files changed

Lines changed: 62 additions & 21 deletions

File tree

‎modelitool/simulate.py‎

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
import tempfile
3+
import warnings
34
from pathlib import Path
45

56
import pandas as pd
@@ -15,7 +16,6 @@ def __init__(
1516
self,
1617
model_path: Path | str,
1718
simulation_options: dict[str, float | str | int] = None,
18-
x: pd.DataFrame = None,
1919
output_list: list[str] = None,
2020
simulation_path: Path = None,
2121
x_combitimetable_name: str = None,
@@ -33,9 +33,6 @@ def __init__(
3333
- simulation_options (dict[str, float | str | int], optional):
3434
Options for the simulation. May include values for "startTime",
3535
"stopTime", "stepSize", "tolerance", "solver", "outputFormat".
36-
- x (pd.DataFrame, optional): Input data for the simulation. Index shall
37-
be a DatetimeIndex or integers. Columns must match the combi time table
38-
used to specify boundary conditions in the Modelica System.
3936
- output_list (list[str], optional): List of output variables. Default
4037
will output all available variables.
4138
- simulation_path (Path, optional): Path to run the simulation and
@@ -57,7 +54,7 @@ def __init__(
5754
if not os.path.exists(self._simulation_path):
5855
os.mkdir(simulation_path)
5956

60-
self._x = x if x is not None else pd.DataFrame()
57+
self._x = pd.DataFrame()
6158
self.output_list = output_list
6259
self.omc = OMCSessionZMQ()
6360
self.omc.sendExpression(f'cd("{self._simulation_path.as_posix()}")')
@@ -105,6 +102,13 @@ def simulate(
105102
self.set_param_dict(parameter_dict)
106103

107104
if simulation_options is not None:
105+
if x is not None and 'x' in simulation_options:
106+
warnings.warn(
107+
"Boundary file 'x' specified both in simulation_options and as a direct parameter."
108+
" The 'x' provided in simulate() will be used.",
109+
UserWarning
110+
)
111+
108112
self._set_simulation_options(simulation_options)
109113

110114
if x is not None:
@@ -172,18 +176,24 @@ def get_parameters(self):
172176
return self.model.getParameters()
173177

174178
def _set_simulation_options(self, simulation_options):
175-
self.model.setSimulationOptions(
176-
[
177-
f'startTime={simulation_options["startTime"]}',
178-
f'stopTime={simulation_options["stopTime"]}',
179-
f'stepSize={simulation_options["stepSize"]}',
180-
f'tolerance={simulation_options["tolerance"]}',
181-
f'solver={simulation_options["solver"]}',
182-
f'outputFormat={simulation_options["outputFormat"]}',
183-
]
184-
)
179+
standard_options = {
180+
'startTime': simulation_options.get('startTime'),
181+
'stopTime': simulation_options.get('stopTime'),
182+
'stepSize': simulation_options.get('stepSize'),
183+
'tolerance': simulation_options.get('tolerance'),
184+
'solver': simulation_options.get('solver'),
185+
'outputFormat': simulation_options.get('outputFormat')
186+
}
187+
188+
# Filtrer les options None
189+
options = [f'{k}={v}' for k, v in standard_options.items() if v is not None]
190+
self.model.setSimulationOptions(options)
185191
self.simulation_options = simulation_options
186192

193+
# Gérer x s'il est présent dans les options
194+
if 'x' in simulation_options:
195+
self._set_x(simulation_options['x'])
196+
187197
def _set_x(self, df: pd.DataFrame):
188198
"""Sets the input data for the simulation and updates the corresponding file."""
189199
if not self._x.equals(df):
@@ -244,3 +254,4 @@ def library_contents(library_path):
244254
for file in files:
245255
file_path = os.path.join(root, file)
246256
print(file_path)
257+

‎tests/test_simulate.py‎

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,19 +98,49 @@ def test_set_boundaries_df(self):
9898
"outputFormat": "mat",
9999
}
100100

101-
x = pd.DataFrame(
101+
x_options = pd.DataFrame(
102102
{"Boundaries.y[1]": [10, 20, 30], "Boundaries.y[2]": [3, 4, 5]},
103103
index=pd.date_range("2009-07-13 00:00:00", periods=3, freq="h"),
104104
)
105+
x_direct = pd.DataFrame(
106+
{"Boundaries.y[1]": [100, 200, 300], "Boundaries.y[2]": [30, 40, 50]},
107+
index=pd.date_range("2009-07-13 00:00:00", periods=3, freq="h"),
108+
)
109+
110+
simu = OMModel(
111+
model_path="TestLib.boundary_test",
112+
package_path=PACKAGE_DIR / "package.mo",
113+
lmodel=["Modelica"],
114+
)
115+
116+
simulation_options_with_x = simulation_options.copy()
117+
simulation_options_with_x['x'] = x_options
118+
res1 = simu.simulate(simulation_options=simulation_options_with_x)
119+
res1 = res1.loc[:, ["Boundaries.y[1]", "Boundaries.y[2]"]]
120+
np.testing.assert_allclose(x_options.to_numpy(), res1.to_numpy())
121+
assert np.all([x_options.index[i] == res1.index[i] for i in range(len(x_options.index))])
122+
assert np.all([x_options.columns[i] == res1.columns[i] for i in range(len(x_options.columns))])
105123

106124
simu = OMModel(
107125
model_path="TestLib.boundary_test",
108126
package_path=PACKAGE_DIR / "package.mo",
109127
lmodel=["Modelica"],
110128
)
129+
res2 = simu.simulate(simulation_options=simulation_options, x=x_direct)
130+
res2 = res2.loc[:, ["Boundaries.y[1]", "Boundaries.y[2]"]]
131+
np.testing.assert_allclose(x_direct.to_numpy(), res2.to_numpy())
132+
assert np.all([x_direct.index[i] == res2.index[i] for i in range(len(x_direct.index))])
133+
assert np.all([x_direct.columns[i] == res2.columns[i] for i in range(len(x_direct.columns))])
111134

112-
res = simu.simulate(simulation_options=simulation_options, x=x)
113-
res = res.loc[:, ["Boundaries.y[1]", "Boundaries.y[2]"]]
114-
assert np.all([x.index[i] == res.index[i] for i in range(len(x.index))])
115-
np.testing.assert_allclose(x.to_numpy(), res.to_numpy())
116-
assert np.all([x.columns[i] == res.columns[i] for i in range(len(x.columns))])
135+
simu = OMModel(
136+
model_path="TestLib.boundary_test",
137+
package_path=PACKAGE_DIR / "package.mo",
138+
lmodel=["Modelica"],
139+
)
140+
with pytest.warns(UserWarning,
141+
match="Boundary file 'x' specified both in simulation_options and as a direct parameter"):
142+
res3 = simu.simulate(simulation_options=simulation_options_with_x, x=x_direct)
143+
res3 = res3.loc[:, ["Boundaries.y[1]", "Boundaries.y[2]"]]
144+
np.testing.assert_allclose(x_direct.to_numpy(), res3.to_numpy())
145+
with pytest.raises(AssertionError):
146+
np.testing.assert_allclose(x_options.to_numpy(), res3.to_numpy())

0 commit comments

Comments
 (0)