Skip to content

Commit 3ec9ca8

Browse files
committed
[ModelicaSystem] use OMCPath for nearly all file system interactions
1 parent 90ff171 commit 3ec9ca8

File tree

1 file changed

+49
-41
lines changed

1 file changed

+49
-41
lines changed

OMPython/ModelicaSystem.py

Lines changed: 49 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
"""
3434

3535
import ast
36-
import csv
3736
from dataclasses import dataclass
3837
import logging
3938
import numbers
@@ -43,13 +42,12 @@
4342
import platform
4443
import re
4544
import subprocess
46-
import tempfile
4745
import textwrap
4846
from typing import Optional, Any
4947
import warnings
5048
import xml.etree.ElementTree as ET
5149

52-
from OMPython.OMCSession import OMCSessionException, OMCSessionZMQ, OMCProcessLocal
50+
from OMPython.OMCSession import OMCSessionException, OMCSessionZMQ, OMCProcessLocal, OMCPath
5351

5452
# define logger using the current module name as ID
5553
logger = logging.getLogger(__name__)
@@ -385,9 +383,9 @@ def __init__(
385383

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

393391
if self._file_name is not None and not self._file_name.is_file(): # if file does not exist
@@ -399,7 +397,7 @@ def __init__(
399397
self.setCommandLineOptions("--linearizationDumpLanguage=python")
400398
self.setCommandLineOptions("--generateSymbolicLinearization")
401399

402-
self._tempdir = self.setTempDirectory(customBuildDirectory)
400+
self._tempdir: OMCPath = self.setTempDirectory(customBuildDirectory)
403401

404402
if self._file_name is not None:
405403
self._loadLibrary(lmodel=self._lmodel)
@@ -419,7 +417,7 @@ def setCommandLineOptions(self, commandLineOptions: Optional[str] = None):
419417
exp = f'setCommandLineOptions("{commandLineOptions}")'
420418
self.sendExpression(exp)
421419

422-
def _loadFile(self, fileName: pathlib.Path):
420+
def _loadFile(self, fileName: OMCPath):
423421
# load file
424422
self.sendExpression(f'loadFile("{fileName.as_posix()}")')
425423

@@ -447,14 +445,14 @@ def _loadLibrary(self, lmodel: list):
447445
'1)["Modelica"]\n'
448446
'2)[("Modelica","3.2.3"), "PowerSystems"]\n')
449447

450-
def setTempDirectory(self, customBuildDirectory: Optional[str | os.PathLike | pathlib.Path] = None) -> pathlib.Path:
448+
def setTempDirectory(self, customBuildDirectory: Optional[str | os.PathLike | pathlib.Path] = None) -> OMCPath:
451449
# create a unique temp directory for each session and build the model in that directory
452450
if customBuildDirectory is not None:
453451
if not os.path.exists(customBuildDirectory):
454452
raise IOError(f"{customBuildDirectory} does not exist")
455-
tempdir = pathlib.Path(customBuildDirectory).absolute()
453+
tempdir = self._getconn.omcpath(customBuildDirectory).absolute()
456454
else:
457-
tempdir = pathlib.Path(tempfile.mkdtemp()).absolute()
455+
tempdir = self._getconn.omcpath_tempdir().absolute()
458456
if not tempdir.is_dir():
459457
raise IOError(f"{tempdir} could not be created")
460458

@@ -464,7 +462,7 @@ def setTempDirectory(self, customBuildDirectory: Optional[str | os.PathLike | pa
464462

465463
return tempdir
466464

467-
def getWorkDirectory(self) -> pathlib.Path:
465+
def getWorkDirectory(self) -> OMCPath:
468466
return self._tempdir
469467

470468
def buildModel(self, variableFilter: Optional[str] = None):
@@ -479,7 +477,7 @@ def buildModel(self, variableFilter: Optional[str] = None):
479477
buildModelResult = self._requestApi("buildModel", self._model_name, properties=varFilter)
480478
logger.debug("OM model build result: %s", buildModelResult)
481479

482-
xml_file = pathlib.Path(buildModelResult[0]).parent / buildModelResult[1]
480+
xml_file = self._getconn.omcpath(buildModelResult[0]).parent / buildModelResult[1]
483481
self._xmlparse(xml_file=xml_file)
484482

485483
def sendExpression(self, expr: str, parsed: bool = True):
@@ -506,7 +504,7 @@ def _requestApi(self, apiName, entity=None, properties=None): # 2
506504

507505
return self.sendExpression(exp)
508506

509-
def _xmlparse(self, xml_file: pathlib.Path):
507+
def _xmlparse(self, xml_file: OMCPath):
510508
if not xml_file.is_file():
511509
raise ModelicaSystemError(f"XML file not generated: {xml_file}")
512510

@@ -926,7 +924,7 @@ def getOptimizationOptions(self, names: Optional[str | list[str]] = None) -> dic
926924

927925
def simulate_cmd(
928926
self,
929-
result_file: pathlib.Path,
927+
result_file: OMCPath,
930928
simflags: Optional[str] = None,
931929
simargs: Optional[dict[str, Optional[str | dict[str, str]]]] = None,
932930
timeout: Optional[float] = None,
@@ -953,7 +951,11 @@ def simulate_cmd(
953951
An instance if ModelicaSystemCmd to run the requested simulation.
954952
"""
955953

956-
om_cmd = ModelicaSystemCmd(runpath=self._tempdir, modelname=self._model_name, timeout=timeout)
954+
om_cmd = ModelicaSystemCmd(
955+
runpath=pathlib.Path(self.getWorkDirectory()),
956+
modelname=self._model_name,
957+
timeout=timeout,
958+
)
957959

958960
# always define the result file to use
959961
om_cmd.arg_set(key="r", val=result_file.as_posix())
@@ -965,15 +967,13 @@ def simulate_cmd(
965967
if simargs:
966968
om_cmd.args_set(args=simargs)
967969

968-
overrideFile = self._tempdir / f"{self._model_name}_override.txt"
970+
overrideFile = self.getWorkDirectory() / f"{self._model_name}_override.txt"
969971
if self._override_variables or self._simulate_options_override:
970972
tmpdict = self._override_variables.copy()
971973
tmpdict.update(self._simulate_options_override)
972-
# write to override file
973-
with open(file=overrideFile, mode="w", encoding="utf-8") as fh:
974-
for key, value in tmpdict.items():
975-
fh.write(f"{key}={value}\n")
976974

975+
override_content = "\n".join([f"{key}={value}" for key, value in tmpdict.items()]) + "\n"
976+
overrideFile.write_text(override_content)
977977
om_cmd.arg_set(key="overrideFile", val=overrideFile.as_posix())
978978

979979
if self._inputs: # if model has input quantities
@@ -1024,11 +1024,14 @@ def simulate(
10241024

10251025
if resultfile is None:
10261026
# default result file generated by OM
1027-
self._result_file = self._tempdir / f"{self._model_name}_res.mat"
1027+
self._result_file = self.getWorkDirectory() / f"{self._model_name}_res.mat"
10281028
elif os.path.exists(resultfile):
1029-
self._result_file = pathlib.Path(resultfile)
1029+
self._result_file = self._getconn.omcpath(resultfile)
10301030
else:
1031-
self._result_file = self._tempdir / resultfile
1031+
self._result_file = self.getWorkDirectory() / resultfile
1032+
1033+
if not isinstance(self._result_file, OMCPath):
1034+
raise ModelicaSystemError(f"Invalid result file path: {self._result_file} - must be an OMCPath object!")
10321035

10331036
om_cmd = self.simulate_cmd(
10341037
result_file=self._result_file,
@@ -1047,7 +1050,7 @@ def simulate(
10471050
# check for an empty (=> 0B) result file which indicates a crash of the model executable
10481051
# see: https://github.com/OpenModelica/OMPython/issues/261
10491052
# https://github.com/OpenModelica/OpenModelica/issues/13829
1050-
if self._result_file.stat().st_size == 0:
1053+
if self._result_file.size() == 0:
10511054
self._result_file.unlink()
10521055
raise ModelicaSystemError("Empty result file - this indicates a crash of the model executable!")
10531056

@@ -1092,7 +1095,7 @@ def getSolutions(self, varList: Optional[str | list[str]] = None, resultfile: Op
10921095
raise ModelicaSystemError("No result file found. Run simulate() first.")
10931096
result_file = self._result_file
10941097
else:
1095-
result_file = pathlib.Path(resultfile)
1098+
result_file = self._getconn.omcpath(resultfile)
10961099

10971100
# check for result file exits
10981101
if not result_file.is_file():
@@ -1388,7 +1391,7 @@ def setInputs(
13881391

13891392
return True
13901393

1391-
def _createCSVData(self, csvfile: Optional[pathlib.Path] = None) -> pathlib.Path:
1394+
def _createCSVData(self, csvfile: Optional[OMCPath] = None) -> OMCPath:
13921395
"""
13931396
Create a csv file with inputs for the simulation/optimization of the model. If csvfile is provided as argument,
13941397
this file is used; else a generic file name is created.
@@ -1434,11 +1437,12 @@ def _createCSVData(self, csvfile: Optional[pathlib.Path] = None) -> pathlib.Path
14341437
csv_rows.append(row)
14351438

14361439
if csvfile is None:
1437-
csvfile = self._tempdir / f'{self._model_name}.csv'
1440+
csvfile = self.getWorkDirectory() / f'{self._model_name}.csv'
1441+
1442+
# basic definition of a CSV file using csv_rows as input
1443+
csv_content = "\n".join([",".join(map(str, row)) for row in csv_rows]) + "\n"
14381444

1439-
with open(file=csvfile, mode="w", encoding="utf-8", newline="") as fh:
1440-
writer = csv.writer(fh)
1441-
writer.writerows(csv_rows)
1445+
csvfile.write_text(csv_content)
14421446

14431447
return csvfile
14441448

@@ -1557,17 +1561,21 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
15571561
"use ModelicaSystem() to build the model first"
15581562
)
15591563

1560-
om_cmd = ModelicaSystemCmd(runpath=self._tempdir, modelname=self._model_name, timeout=timeout)
1561-
1562-
overrideLinearFile = self._tempdir / f'{self._model_name}_override_linear.txt'
1564+
om_cmd = ModelicaSystemCmd(
1565+
runpath=pathlib.Path(self.getWorkDirectory()),
1566+
modelname=self._model_name,
1567+
timeout=timeout,
1568+
)
15631569

1564-
with open(file=overrideLinearFile, mode="w", encoding="utf-8") as fh:
1565-
for key1, value1 in self._override_variables.items():
1566-
fh.write(f"{key1}={value1}\n")
1567-
for key2, value2 in self._linearization_options.items():
1568-
fh.write(f"{key2}={value2}\n")
1570+
override_content = (
1571+
"\n".join([f"{key}={value}" for key, value in self._override_variables.items()])
1572+
+ "\n".join([f"{key}={value}" for key, value in self._linearization_options.items()])
1573+
+ "\n"
1574+
)
1575+
override_file = self.getWorkDirectory() / f'{self._model_name}_override_linear.txt'
1576+
override_file.write_text(override_content)
15691577

1570-
om_cmd.arg_set(key="overrideFile", val=overrideLinearFile.as_posix())
1578+
om_cmd.arg_set(key="overrideFile", val=override_file.as_posix())
15711579

15721580
if self._inputs:
15731581
for key in self._inputs:
@@ -1589,7 +1597,7 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
15891597
om_cmd.args_set(args=simargs)
15901598

15911599
# the file create by the model executable which contains the matrix and linear inputs, outputs and states
1592-
linear_file = self._tempdir / "linearized_model.py"
1600+
linear_file = self.getWorkDirectory() / "linearized_model.py"
15931601

15941602
linear_file.unlink(missing_ok=True)
15951603

@@ -1599,7 +1607,7 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
15991607

16001608
self._simulated = True
16011609

1602-
if not linear_file.exists():
1610+
if not linear_file.is_file():
16031611
raise ModelicaSystemError(f"Linearization failed: {linear_file} not found!")
16041612

16051613
# extract data from the python file with the linearized model using the ast module - this allows to get the

0 commit comments

Comments
 (0)