Skip to content

Commit adf5f7c

Browse files
committed
[ModelicaSystem] use OMCPath for nearly all file system interactions
remove pathlib - use OMCPath and (for type hints) os.PathLike
1 parent 5b139d4 commit adf5f7c

File tree

1 file changed

+37
-34
lines changed

1 file changed

+37
-34
lines changed

OMPython/ModelicaSystem.py

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,15 @@
3838
import numbers
3939
import numpy as np
4040
import os
41-
import pathlib
4241
import platform
4342
import re
4443
import subprocess
45-
import tempfile
4644
import textwrap
4745
from typing import Optional, Any
4846
import warnings
4947
import xml.etree.ElementTree as ET
5048

51-
from OMPython.OMCSession import OMCSessionException, OMCSessionZMQ, OMCProcessLocal
49+
from OMPython.OMCSession import OMCSessionException, OMCSessionZMQ, OMCProcessLocal, OMCPath
5250

5351
# define logger using the current module name as ID
5452
logger = logging.getLogger(__name__)
@@ -114,8 +112,8 @@ def __getitem__(self, index: int):
114112
class ModelicaSystemCmd:
115113
"""A compiled model executable."""
116114

117-
def __init__(self, runpath: pathlib.Path, modelname: str, timeout: Optional[float] = None) -> None:
118-
self._runpath = pathlib.Path(runpath).resolve().absolute()
115+
def __init__(self, runpath: OMCPath, modelname: str, timeout: Optional[float] = None) -> None:
116+
self._runpath = runpath
119117
self._model_name = modelname
120118
self._timeout = timeout
121119
self._args: dict[str, str | None] = {}
@@ -175,7 +173,7 @@ def args_set(self, args: dict[str, Optional[str | dict[str, str]]]) -> None:
175173
for arg in args:
176174
self.arg_set(key=arg, val=args[arg])
177175

178-
def get_exe(self) -> pathlib.Path:
176+
def get_exe(self) -> OMCPath:
179177
"""Get the path to the compiled model executable."""
180178
if platform.system() == "Windows":
181179
path_exe = self._runpath / f"{self._model_name}.exe"
@@ -295,7 +293,7 @@ def parse_simflags(simflags: str) -> dict[str, Optional[str | dict[str, str]]]:
295293
class ModelicaSystem:
296294
def __init__(
297295
self,
298-
fileName: Optional[str | os.PathLike | pathlib.Path] = None,
296+
fileName: Optional[str | os.PathLike] = None,
299297
modelName: Optional[str] = None,
300298
lmodel: Optional[list[str | tuple[str, str]]] = None,
301299
commandLineOptions: Optional[str] = None,
@@ -384,9 +382,13 @@ def __init__(
384382

385383
self._lmodel = lmodel # may be needed if model is derived from other model
386384
self._model_name = modelName # Model class name
387-
self._file_name = pathlib.Path(fileName).resolve() if fileName is not None else None # Model file/package name
385+
if fileName is not None:
386+
file_name = self._getconn.omcpath(fileName).resolve()
387+
else:
388+
file_name = None
389+
self._file_name: Optional[OMCPath] = file_name # Model file/package name
388390
self._simulated = False # True if the model has already been simulated
389-
self._result_file: Optional[pathlib.Path] = None # for storing result file
391+
self._result_file: Optional[OMCPath] = None # for storing result file
390392
self._variable_filter = variableFilter
391393

392394
if self._file_name is not None and not self._file_name.is_file(): # if file does not exist
@@ -398,7 +400,7 @@ def __init__(
398400
self.setCommandLineOptions("--linearizationDumpLanguage=python")
399401
self.setCommandLineOptions("--generateSymbolicLinearization")
400402

401-
self._work_dir: pathlib.Path = self.setWorkDirectory(customBuildDirectory)
403+
self._work_dir: OMCPath = self.setWorkDirectory(customBuildDirectory)
402404

403405
if self._file_name is not None:
404406
self._loadLibrary(lmodel=self._lmodel)
@@ -418,7 +420,7 @@ def setCommandLineOptions(self, commandLineOptions: Optional[str] = None):
418420
exp = f'setCommandLineOptions("{commandLineOptions}")'
419421
self.sendExpression(exp)
420422

421-
def _loadFile(self, fileName: pathlib.Path):
423+
def _loadFile(self, fileName: OMCPath):
422424
# load file
423425
self.sendExpression(f'loadFile("{fileName.as_posix()}")')
424426

@@ -446,17 +448,17 @@ def _loadLibrary(self, lmodel: list):
446448
'1)["Modelica"]\n'
447449
'2)[("Modelica","3.2.3"), "PowerSystems"]\n')
448450

449-
def setWorkDirectory(self, customBuildDirectory: Optional[str | os.PathLike] = None) -> pathlib.Path:
451+
def setWorkDirectory(self, customBuildDirectory: Optional[str | os.PathLike] = None) -> OMCPath:
450452
"""
451453
Define the work directory for the ModelicaSystem / OpenModelica session. The model is build within this
452454
directory. If no directory is defined a unique temporary directory is created.
453455
"""
454456
if customBuildDirectory is not None:
455-
workdir = pathlib.Path(customBuildDirectory).absolute()
457+
workdir = self._getconn.omcpath(customBuildDirectory).absolute()
456458
if not workdir.is_dir():
457459
raise IOError(f"Provided work directory does not exists: {customBuildDirectory}!")
458460
else:
459-
workdir = pathlib.Path(tempfile.mkdtemp()).absolute()
461+
workdir = self._getconn.omcpath_tempdir().absolute()
460462
if not workdir.is_dir():
461463
raise IOError(f"{workdir} could not be created")
462464

@@ -469,7 +471,7 @@ def setWorkDirectory(self, customBuildDirectory: Optional[str | os.PathLike] = N
469471
# ... and also return the defined path
470472
return workdir
471473

472-
def getWorkDirectory(self) -> pathlib.Path:
474+
def getWorkDirectory(self) -> OMCPath:
473475
"""
474476
Return the defined working directory for this ModelicaSystem / OpenModelica session.
475477
"""
@@ -487,7 +489,7 @@ def buildModel(self, variableFilter: Optional[str] = None):
487489
buildModelResult = self._requestApi("buildModel", self._model_name, properties=varFilter)
488490
logger.debug("OM model build result: %s", buildModelResult)
489491

490-
xml_file = pathlib.Path(buildModelResult[0]).parent / buildModelResult[1]
492+
xml_file = self._getconn.omcpath(buildModelResult[0]).parent / buildModelResult[1]
491493
self._xmlparse(xml_file=xml_file)
492494

493495
def sendExpression(self, expr: str, parsed: bool = True):
@@ -514,7 +516,7 @@ def _requestApi(self, apiName, entity=None, properties=None): # 2
514516

515517
return self.sendExpression(exp)
516518

517-
def _xmlparse(self, xml_file: pathlib.Path):
519+
def _xmlparse(self, xml_file: OMCPath):
518520
if not xml_file.is_file():
519521
raise ModelicaSystemError(f"XML file not generated: {xml_file}")
520522

@@ -934,7 +936,7 @@ def getOptimizationOptions(self, names: Optional[str | list[str]] = None) -> dic
934936

935937
def simulate_cmd(
936938
self,
937-
result_file: pathlib.Path,
939+
result_file: OMCPath,
938940
simflags: Optional[str] = None,
939941
simargs: Optional[dict[str, Optional[str | dict[str, str]]]] = None,
940942
timeout: Optional[float] = None,
@@ -1039,10 +1041,13 @@ def simulate(
10391041
# default result file generated by OM
10401042
self._result_file = self.getWorkDirectory() / f"{self._model_name}_res.mat"
10411043
elif os.path.exists(resultfile):
1042-
self._result_file = pathlib.Path(resultfile)
1044+
self._result_file = self._getconn.omcpath(resultfile)
10431045
else:
10441046
self._result_file = self.getWorkDirectory() / resultfile
10451047

1048+
if not isinstance(self._result_file, OMCPath):
1049+
raise ModelicaSystemError(f"Invalid result file path: {self._result_file} - must be an OMCPath object!")
1050+
10461051
om_cmd = self.simulate_cmd(
10471052
result_file=self._result_file,
10481053
simflags=simflags,
@@ -1060,7 +1065,7 @@ def simulate(
10601065
# check for an empty (=> 0B) result file which indicates a crash of the model executable
10611066
# see: https://github.com/OpenModelica/OMPython/issues/261
10621067
# https://github.com/OpenModelica/OpenModelica/issues/13829
1063-
if self._result_file.stat().st_size == 0:
1068+
if self._result_file.size() == 0:
10641069
self._result_file.unlink()
10651070
raise ModelicaSystemError("Empty result file - this indicates a crash of the model executable!")
10661071

@@ -1109,7 +1114,7 @@ def getSolutions(
11091114
raise ModelicaSystemError("No result file found. Run simulate() first.")
11101115
result_file = self._result_file
11111116
else:
1112-
result_file = pathlib.Path(resultfile)
1117+
result_file = self._getconn.omcpath(resultfile)
11131118

11141119
# check for result file exits
11151120
if not result_file.is_file():
@@ -1399,11 +1404,9 @@ def setInputs(
13991404
else:
14001405
raise ModelicaSystemError(f"Data cannot be evaluated for {repr(key)}: {repr(val)}")
14011406

1402-
self._has_inputs = True
1403-
14041407
return True
14051408

1406-
def _createCSVData(self, csvfile: Optional[pathlib.Path] = None) -> pathlib.Path:
1409+
def _createCSVData(self, csvfile: Optional[OMCPath] = None) -> OMCPath:
14071410
"""
14081411
Create a csv file with inputs for the simulation/optimization of the model. If csvfile is provided as argument,
14091412
this file is used; else a generic file name is created.
@@ -1578,15 +1581,15 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
15781581
timeout=timeout,
15791582
)
15801583

1581-
overrideLinearFile = self.getWorkDirectory() / f'{self._model_name}_override_linear.txt'
1582-
1583-
with open(file=overrideLinearFile, mode="w", encoding="utf-8") as fh:
1584-
for key1, value1 in self._override_variables.items():
1585-
fh.write(f"{key1}={value1}\n")
1586-
for key2, value2 in self._linearization_options.items():
1587-
fh.write(f"{key2}={value2}\n")
1584+
override_content = (
1585+
"\n".join([f"{key}={value}" for key, value in self._override_variables.items()])
1586+
+ "\n".join([f"{key}={value}" for key, value in self._linearization_options.items()])
1587+
+ "\n"
1588+
)
1589+
override_file = self.getWorkDirectory() / f'{self._model_name}_override_linear.txt'
1590+
override_file.write_text(override_content)
15881591

1589-
om_cmd.arg_set(key="overrideFile", val=overrideLinearFile.as_posix())
1592+
om_cmd.arg_set(key="overrideFile", val=override_file.as_posix())
15901593

15911594
if self._inputs:
15921595
for key in self._inputs:
@@ -1608,13 +1611,13 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
16081611
om_cmd.args_set(args=simargs)
16091612

16101613
# the file create by the model executable which contains the matrix and linear inputs, outputs and states
1611-
linear_file = self._tempdir / "linearized_model.py"
1614+
linear_file = self.getWorkDirectory() / "linearized_model.py"
16121615
linear_file.unlink(missing_ok=True)
16131616

16141617
returncode = om_cmd.run()
16151618
if returncode != 0:
16161619
raise ModelicaSystemError(f"Linearize failed with return code: {returncode}")
1617-
if not linear_file.exists():
1620+
if not linear_file.is_file():
16181621
raise ModelicaSystemError(f"Linearization failed: {linear_file} not found!")
16191622

16201623
self._simulated = True

0 commit comments

Comments
 (0)