Skip to content

Commit a036aef

Browse files
committed
Merge branch 'ModelicaSystem_linearize' into OMCPath_merge
2 parents 08e95f5 + ab0beae commit a036aef

1 file changed

Lines changed: 46 additions & 45 deletions

File tree

OMPython/ModelicaSystem.py

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@
3232
CONDITIONS OF OSMC-PL.
3333
"""
3434

35+
import ast
3536
import csv
3637
from dataclasses import dataclass
37-
import importlib
3838
import logging
3939
import numbers
4040
import numpy as np
@@ -1449,14 +1449,6 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
14491449
compatibility, because linearize() used to return `[A, B, C, D]`.
14501450
"""
14511451

1452-
# replacement for depreciated importlib.load_module()
1453-
def load_module_from_path(module_name, file_path):
1454-
spec = importlib.util.spec_from_file_location(module_name, file_path)
1455-
module_def = importlib.util.module_from_spec(spec)
1456-
spec.loader.exec_module(module_def)
1457-
1458-
return module_def
1459-
14601452
if len(self._quantities) == 0:
14611453
# if self._quantities has no content, the xml file was not parsed; see self._xmlparse()
14621454
raise ModelicaSystemError(
@@ -1496,50 +1488,59 @@ def load_module_from_path(module_name, file_path):
14961488
if simargs:
14971489
om_cmd.args_set(args=simargs)
14981490

1491+
# the file create by the model executable which contains the matrix and linear inputs, outputs and states
1492+
linear_file = self._tempdir / "linearized_model.py"
1493+
1494+
linear_file.unlink(missing_ok=True)
1495+
14991496
returncode = om_cmd.run()
15001497
if returncode != 0:
15011498
raise ModelicaSystemError(f"Linearize failed with return code: {returncode}")
15021499

15031500
self._simulated = True
15041501

1505-
# code to get the matrix and linear inputs, outputs and states
1506-
linearFile = self._tempdir / "linearized_model.py"
1502+
if not linear_file.exists():
1503+
raise ModelicaSystemError(f"Linearization failed: {linear_file} not found!")
15071504

1508-
# support older openmodelica versions before OpenModelica v1.16.2 where linearize() generates "linear_model_name.mo" file
1509-
if not linearFile.exists():
1510-
linearFile = pathlib.Path(f'linear_{self._model_name}.py')
1511-
1512-
if not linearFile.exists():
1513-
raise ModelicaSystemError(f"Linearization failed: {linearFile} not found!")
1514-
1515-
# this function is called from the generated python code linearized_model.py at runtime,
1516-
# to improve the performance by directly reading the matrices A, B, C and D from the julia code and avoid building the linearized modelica model
1505+
# extract data from the python file with the linearized model using the ast module - this allows to get the
1506+
# needed information without executing the created code
1507+
linear_data = {}
1508+
linear_file_content = linear_file.read_text()
15171509
try:
1518-
# do not add the linearfile directory to path, as multiple execution of linearization will always use the first added path, instead execute the file
1519-
# https://github.com/OpenModelica/OMPython/issues/196
1520-
module = load_module_from_path(module_name="linearized_model", file_path=linearFile.as_posix())
1521-
1522-
result = module.linearized_model()
1523-
(n, m, p, x0, u0, A, B, C, D, stateVars, inputVars, outputVars) = result
1524-
self._linearized_inputs = inputVars
1525-
self._linearized_outputs = outputVars
1526-
self._linearized_states = stateVars
1527-
# TODO: why is here a mypy warning?
1528-
return LinearizationResult(
1529-
int(n),
1530-
int(m),
1531-
int(p),
1532-
A,
1533-
B,
1534-
C,
1535-
D,
1536-
x0,
1537-
u0,
1538-
stateVars,
1539-
inputVars,
1540-
outputVars)
1541-
except ModuleNotFoundError as ex:
1542-
raise ModelicaSystemError("No module named 'linearized_model'") from ex
1510+
# ignore possible typing errors below (mypy) - these are caught by the try .. except .. block
1511+
linear_file_ast = ast.parse(linear_file_content)
1512+
for body_part in linear_file_ast.body[0].body: # type: ignore
1513+
if not isinstance(body_part, ast.Assign):
1514+
continue
1515+
1516+
target = body_part.targets[0].id # type: ignore
1517+
value = ast.literal_eval(body_part.value)
1518+
1519+
linear_data[target] = value
1520+
except (AttributeError, IndexError, ValueError, SyntaxError, TypeError) as ex:
1521+
raise ModelicaSystemError(f"Error parsing linearization file {linear_file}!") from ex
1522+
1523+
# remove the file
1524+
linear_file.unlink()
1525+
1526+
self._linearized_inputs = linear_data["inputVars"]
1527+
self._linearized_outputs = linear_data["outputVars"]
1528+
self._linearized_states = linear_data["stateVars"]
1529+
1530+
return LinearizationResult(
1531+
n=linear_data["n"],
1532+
m=linear_data["m"],
1533+
p=linear_data["p"],
1534+
x0=linear_data["x0"],
1535+
u0=linear_data["u0"],
1536+
A=linear_data["A"],
1537+
B=linear_data["B"],
1538+
C=linear_data["C"],
1539+
D=linear_data["D"],
1540+
stateVars=linear_data["stateVars"],
1541+
inputVars=linear_data["inputVars"],
1542+
outputVars=linear_data["outputVars"],
1543+
)
15431544

15441545
def getLinearInputs(self) -> list[str]:
15451546
"""Get names of input variables of the linearized model."""

0 commit comments

Comments
 (0)