Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,947 changes: 1,109 additions & 838 deletions OMPython/ModelicaSystem.py

Large diffs are not rendered by default.

920 changes: 575 additions & 345 deletions OMPython/OMCSession.py

Large diffs are not rendered by default.

63 changes: 47 additions & 16 deletions OMPython/__init__.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,82 @@
# -*- coding: utf-8 -*-
"""
OMPython is a Python interface to OpenModelica.
To get started, create an OMCSessionZMQ object:
from OMPython import OMCSessionZMQ
omc = OMCSessionZMQ()
To get started on a local OMC server, create an OMCSessionLocal object:

```
import OMPython
omc = OMPython.OMCSessionLocal()
omc.sendExpression("command")
```

"""

from OMPython.ModelicaSystem import (
LinearizationResult,
ModelicaSystem,
ModelicaSystemCmd,
ModelicaSystemOMC,
ModelExecutionCmd,
ModelicaSystemDoE,
ModelicaDoEOMC,
ModelicaSystemError,
ModelicaSystemRunner,
ModelicaDoERunner,

doe_get_solutions,
)
from OMPython.OMCSession import (
OMPathABC,
OMCPath,
OMCSession,

OMSessionRunner,

OMCSessionABC,

ModelExecutionData,
ModelExecutionException,

OMCSessionCmd,
OMCSessionException,
OMCSessionRunData,
OMCSessionZMQ,
OMCSessionPort,
OMCSessionLocal,
OMCSessionDocker,
OMCSessionDockerContainer,
OMCSessionException,
OMCSessionLocal,
OMCSessionPort,
OMCSessionWSL,
OMCSessionZMQ,
)

# global names imported if import 'from OMPython import *' is used
__all__ = [
'LinearizationResult',

'ModelExecutionData',
'ModelExecutionException',

'ModelicaSystem',
'ModelicaSystemCmd',
'ModelicaSystemOMC',
'ModelExecutionCmd',
'ModelicaSystemDoE',
'ModelicaDoEOMC',
'ModelicaSystemError',

'ModelicaSystemRunner',
'ModelicaDoERunner',

'OMPathABC',
'OMCPath',

'OMCSession',
'OMSessionRunner',

'OMCSessionABC',

'doe_get_solutions',

'OMCSessionCmd',
'OMCSessionDocker',
'OMCSessionDockerContainer',
'OMCSessionException',
'OMCSessionRunData',
'OMCSessionZMQ',
'OMCSessionPort',
'OMCSessionLocal',
'OMCSessionDocker',
'OMCSessionDockerContainer',
'OMCSessionWSL',
'OMCSessionZMQ',
]
4 changes: 2 additions & 2 deletions tests/test_FMIExport.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


def test_CauerLowPassAnalog():
mod = OMPython.ModelicaSystem()
mod = OMPython.ModelicaSystemOMC()
mod.model(
model_name="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog",
libraries=["Modelica"],
Expand All @@ -20,7 +20,7 @@ def test_CauerLowPassAnalog():


def test_DrumBoiler():
mod = OMPython.ModelicaSystem()
mod = OMPython.ModelicaSystemOMC()
mod.model(
model_name="Modelica.Fluid.Examples.DrumBoiler.DrumBoiler",
libraries=["Modelica"],
Expand Down
4 changes: 2 additions & 2 deletions tests/test_FMIImport.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def model_firstorder(tmp_path):

def test_FMIImport(model_firstorder):
# create model & simulate it
mod1 = OMPython.ModelicaSystem()
mod1 = OMPython.ModelicaSystemOMC()
mod1.model(
model_file=model_firstorder,
model_name="M",
Expand All @@ -35,7 +35,7 @@ def test_FMIImport(model_firstorder):

# import FMU & check & simulate
# TODO: why is '--allowNonStandardModelica=reinitInAlgorithms' needed? any example without this possible?
mod2 = OMPython.ModelicaSystem(command_line_options=['--allowNonStandardModelica=reinitInAlgorithms'])
mod2 = OMPython.ModelicaSystemOMC(command_line_options=['--allowNonStandardModelica=reinitInAlgorithms'])
mo = mod2.convertFmu2Mo(fmu=fmu)
assert os.path.exists(mo)

Expand Down
51 changes: 34 additions & 17 deletions tests/test_ModelicaSystemDoE.py → tests/test_ModelicaDoEOMC.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,56 +51,73 @@ def param_doe() -> dict[str, list]:
return param


def test_ModelicaSystemDoE_local(tmp_path, model_doe, param_doe):
def test_ModelicaDoEOMC_local(tmp_path, model_doe, param_doe):
tmpdir = tmp_path / 'DoE'
tmpdir.mkdir(exist_ok=True)

doe_mod = OMPython.ModelicaSystemDoE(
mod = OMPython.ModelicaSystemOMC()
mod.model(
model_file=model_doe,
model_name="M",
)

doe_mod = OMPython.ModelicaDoEOMC(
mod=mod,
parameters=param_doe,
resultpath=tmpdir,
simargs={"override": {'stopTime': 1.0}},
simargs={"override": {'stopTime': '1.0'}},
)

_run_ModelicaSystemDoe(doe_mod=doe_mod)
_run_ModelicaDoEOMC(doe_mod=doe_mod)


@skip_on_windows
@skip_python_older_312
def test_ModelicaSystemDoE_docker(tmp_path, model_doe, param_doe):
def test_ModelicaDoEOMC_docker(tmp_path, model_doe, param_doe):
omcs = OMPython.OMCSessionDocker(docker="openmodelica/openmodelica:v1.25.0-minimal")
assert omcs.sendExpression("getVersion()") == "OpenModelica 1.25.0"

doe_mod = OMPython.ModelicaSystemDoE(
mod = OMPython.ModelicaSystemOMC(
session=omcs,
)
mod.model(
model_file=model_doe,
model_name="M",
)

doe_mod = OMPython.ModelicaDoEOMC(
mod=mod,
parameters=param_doe,
session=omcs,
simargs={"override": {'stopTime': 1.0}},
simargs={"override": {'stopTime': '1.0'}},
)

_run_ModelicaSystemDoe(doe_mod=doe_mod)
_run_ModelicaDoEOMC(doe_mod=doe_mod)


@pytest.mark.skip(reason="Not able to run WSL on github")
@skip_python_older_312
def test_ModelicaSystemDoE_WSL(tmp_path, model_doe, param_doe):
tmpdir = tmp_path / 'DoE'
tmpdir.mkdir(exist_ok=True)
def test_ModelicaDoEOMC_WSL(tmp_path, model_doe, param_doe):
omcs = OMPython.OMCSessionWSL()
assert omcs.sendExpression("getVersion()") == "OpenModelica 1.25.0"

doe_mod = OMPython.ModelicaSystemDoE(
mod = OMPython.ModelicaSystemOMC(
session=omcs,
)
mod.model(
model_file=model_doe,
model_name="M",
)

doe_mod = OMPython.ModelicaDoEOMC(
mod=mod,
parameters=param_doe,
resultpath=tmpdir,
simargs={"override": {'stopTime': 1.0}},
simargs={"override": {'stopTime': '1.0'}},
)

_run_ModelicaSystemDoe(doe_mod=doe_mod)
_run_ModelicaDoEOMC(doe_mod=doe_mod)


def _run_ModelicaSystemDoe(doe_mod):
def _run_ModelicaDoEOMC(doe_mod):
doe_count = doe_mod.prepare()
assert doe_count == 16

Expand Down
158 changes: 158 additions & 0 deletions tests/test_ModelicaDoERunner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import pathlib
import sys

import numpy as np
import pytest

import OMPython

skip_python_older_312 = pytest.mark.skipif(
sys.version_info < (3, 12),
reason="OMCPath(non-local) only working for Python >= 3.12.",
)


@pytest.fixture
def model_doe(tmp_path: pathlib.Path) -> pathlib.Path:
# see: https://trac.openmodelica.org/OpenModelica/ticket/4052
mod = tmp_path / "M.mo"
# TODO: update for bool and string parameters; check if these can be used in DoE
mod.write_text("""
model M
parameter Integer p=1;
parameter Integer q=1;
parameter Real a = -1;
parameter Real b = -1;
Real x[p];
Real y[q];
equation
der(x) = a * fill(1.0, p);
der(y) = b * fill(1.0, q);
end M;
""")
return mod


@pytest.fixture
def param_doe() -> dict[str, list]:
param = {
# simple
'a': [5, 6],
'b': [7, 8],
}
return param


def test_ModelicaDoERunner_ModelicaSystemOMC(tmp_path, model_doe, param_doe):
tmpdir = tmp_path / 'DoE'
tmpdir.mkdir(exist_ok=True)

mod = OMPython.ModelicaSystemOMC()
mod.model(
model_file=model_doe,
model_name="M",
)

resultfile_mod = mod.getWorkDirectory() / f"{mod.get_model_name()}_res_mod.mat"
_run_simulation(mod=mod, resultfile=resultfile_mod, param=param_doe)

doe_mod = OMPython.ModelicaDoERunner(
mod=mod,
parameters=param_doe,
resultpath=tmpdir,
)

_run_ModelicaDoERunner(doe_mod=doe_mod)

_check_runner_result(mod=mod, doe_mod=doe_mod)


def test_ModelicaDoERunner_ModelicaSystemRunner(tmp_path, model_doe, param_doe):
tmpdir = tmp_path / 'DoE'
tmpdir.mkdir(exist_ok=True)

mod = OMPython.ModelicaSystemOMC()
mod.model(
model_file=model_doe,
model_name="M",
)

resultfile_mod = mod.getWorkDirectory() / f"{mod.get_model_name()}_res_mod.mat"
_run_simulation(mod=mod, resultfile=resultfile_mod, param=param_doe)

# run the model using only the runner class
omcs = OMPython.OMSessionRunner(
version=mod.get_session().get_version(),
)
modr = OMPython.ModelicaSystemRunner(
session=omcs,
work_directory=mod.getWorkDirectory(),
)
modr.setup(
model_name="M",
)
doe_mod = OMPython.ModelicaDoERunner(
mod=modr,
parameters=param_doe,
resultpath=tmpdir,
)

_run_ModelicaDoERunner(doe_mod=doe_mod)

_check_runner_result(mod=mod, doe_mod=doe_mod)


def _run_simulation(mod, resultfile, param):
simOptions = {"stopTime": 1.0, "stepSize": 0.1, "tolerance": 1e-8}
mod.setSimulationOptions(**simOptions)
mod.simulate(resultfile=resultfile)

assert resultfile.exists()


def _run_ModelicaDoERunner(doe_mod):
doe_count = doe_mod.prepare()
assert doe_count == 4

doe_def = doe_mod.get_doe_definition()
assert isinstance(doe_def, dict)
assert len(doe_def.keys()) == doe_count

doe_cmd = doe_mod.get_doe_command()
assert isinstance(doe_cmd, dict)
assert len(doe_cmd.keys()) == doe_count

doe_status = doe_mod.simulate()
assert doe_status is True


def _check_runner_result(mod, doe_mod):
doe_cmd = doe_mod.get_doe_command()
doe_def = doe_mod.get_doe_definition()

doe_sol = OMPython.doe_get_solutions(
msomc=mod,
resultpath=doe_mod.get_resultpath(),
doe_def=doe_def,
)
assert isinstance(doe_sol, dict)
assert len(doe_sol.keys()) == len(doe_cmd.keys())

assert sorted(doe_def.keys()) == sorted(doe_cmd.keys())
assert sorted(doe_cmd.keys()) == sorted(doe_sol.keys())

for resultfilename in doe_def:
row = doe_def[resultfilename]

assert resultfilename in doe_sol
sol = doe_sol[resultfilename]

var_dict = {
# simple / non-structural parameters
'a': float(row['a']),
'b': float(row['b']),
}

for var in var_dict:
assert var in sol['data']
assert np.isclose(sol['data'][var][-1], var_dict[var])
Loading