Skip to content

Commit 2001229

Browse files
syntronarun3688
andauthored
include c library files from external Modelica libraries
*simplify usage of subprocess.Popen() * add linearization test Co-authored-by: arun3688 <rain100falls@gmail.com>
1 parent 60f865d commit 2001229

2 files changed

Lines changed: 94 additions & 39 deletions

File tree

OMPython/__init__.py

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,55 @@ def setTempDirectory(self, customBuildDirectory):
928928
def getWorkDirectory(self):
929929
return self.tempdir
930930

931+
def _run_cmd(self, cmd: list, verbose: bool = True):
932+
logger.debug("Run OM command {} in {}".format(cmd, self.tempdir))
933+
934+
if platform.system() == "Windows":
935+
omhome = os.path.join(os.environ.get("OPENMODELICAHOME"))
936+
dllPath = (os.path.join(omhome, "bin")
937+
+ os.pathsep + os.path.join(omhome, "lib/omc")
938+
+ os.pathsep + os.path.join(omhome, "lib/omc/cpp")
939+
+ os.pathsep + os.path.join(omhome, "lib/omc/omsicpp"))
940+
941+
# include path to resources of defined external libraries
942+
for element in self.lmodel:
943+
if element is not None:
944+
if isinstance(element, str):
945+
if element.endswith("package.mo"):
946+
pkgpath = element[:-10] + '/Resources/Library/'
947+
for wver in ['win32', 'win64']:
948+
pkgpath_wver = pkgpath + '/' + wver
949+
if os.path.exists(pkgpath_wver):
950+
dllPath = pkgpath_wver + os.pathsep + dllPath
951+
952+
# fix backslash in path definitions
953+
dllPath = dllPath.replace("\\", "/")
954+
955+
my_env = os.environ.copy()
956+
my_env["PATH"] = dllPath + os.pathsep + my_env["PATH"]
957+
else:
958+
# TODO: how to handle path to resources of external libraries for any system not Windows?
959+
my_env = None
960+
961+
currentDir = os.getcwd()
962+
try:
963+
os.chdir(self.tempdir)
964+
p = subprocess.Popen(cmd, env=my_env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
965+
stdout, stderr = p.communicate()
966+
967+
stdout = stdout.decode('ascii').strip()
968+
stderr = stderr.decode('ascii').strip()
969+
if stderr:
970+
logger.warning("OM error: {}".format(stderr))
971+
if verbose and stdout:
972+
logger.info("OM output:\n{}".format(stdout))
973+
p.wait()
974+
p.terminate()
975+
os.chdir(currentDir)
976+
except Exception as e:
977+
os.chdir(currentDir)
978+
raise Exception("Error running command {}: {}".format(repr(cmd), e))
979+
931980
def buildModel(self, variableFilter=None, verbose=True):
932981
if variableFilter is not None:
933982
self.variableFilter = variableFilter
@@ -1280,32 +1329,15 @@ def simulate(self, resultfile=None, simflags=None, verbose=True): # 11
12801329
getExeFile = os.path.join(self.tempdir, '{}.{}'.format(self.modelName, "exe")).replace("\\", "/")
12811330
else:
12821331
getExeFile = os.path.join(self.tempdir, self.modelName).replace("\\", "/")
1283-
currentDir = os.getcwd()
1284-
if (os.path.exists(getExeFile)):
1332+
1333+
if os.path.exists(getExeFile):
12851334
cmd = getExeFile + override + csvinput + r + simflags
12861335
cmd = cmd.split(" ")
1287-
#print(cmd)
1288-
os.chdir(self.tempdir)
1289-
if (platform.system() == "Windows"):
1290-
omhome = os.path.join(os.environ.get("OPENMODELICAHOME"))
1291-
dllPath = os.path.join(omhome, "bin").replace("\\", "/") + os.pathsep + os.path.join(omhome, "lib/omc").replace("\\", "/") + os.pathsep + os.path.join(omhome, "lib/omc/cpp").replace("\\", "/") + os.pathsep + os.path.join(omhome, "lib/omc/omsicpp").replace("\\", "/")
1292-
my_env = os.environ.copy()
1293-
my_env["PATH"] = dllPath + os.pathsep + my_env["PATH"]
1294-
if not verbose:
1295-
p = subprocess.Popen(cmd, env=my_env, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
1296-
else:
1297-
p = subprocess.Popen(cmd, env=my_env)
1298-
else:
1299-
if not verbose:
1300-
p = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
1301-
else:
1302-
p = subprocess.Popen(cmd)
1303-
p.wait()
1304-
p.terminate()
1305-
os.chdir(currentDir)
1336+
self._run_cmd(cmd=cmd, verbose=verbose)
1337+
13061338
self.simulationFlag = True
13071339
else:
1308-
raise Exception("Error: Application file path not found: " + getExeFile)
1340+
raise Exception("Error: Application file path not found: " + getExeFile)
13091341

13101342
# to extract simulation results
13111343
def getSolutions(self, varList=None, resultfile=None): # 12
@@ -1741,23 +1773,11 @@ def linearize(self, lintime = None, simflags= None): # 22
17411773
if simflags is None:
17421774
simflags = ""
17431775

1744-
currentDir = os.getcwd()
17451776
if (os.path.exists(getExeFile)):
17461777
cmd = getExeFile + linruntime + override + csvinput + simflags
1747-
# print(cmd)
1748-
os.chdir(self.tempdir)
1749-
if (platform.system() == "Windows"):
1750-
omhome = os.path.join(os.environ.get("OPENMODELICAHOME"))
1751-
dllPath = os.path.join(omhome, "bin").replace("\\", "/") + os.pathsep + os.path.join(omhome, "lib/omc").replace("\\", "/") + os.pathsep + os.path.join(omhome, "lib/omc/cpp").replace("\\", "/") + os.pathsep + os.path.join(omhome, "lib/omc/omsicpp").replace("\\", "/")
1752-
my_env = os.environ.copy()
1753-
my_env["PATH"] = dllPath + os.pathsep + my_env["PATH"]
1754-
p = subprocess.Popen(cmd, env=my_env)
1755-
p.wait()
1756-
p.terminate()
1757-
else:
1758-
os.system(cmd)
1778+
cmd = cmd.split(' ')
1779+
self._run_cmd(cmd=cmd)
17591780
else:
1760-
os.chdir(currentDir)
17611781
raise Exception("Error: Application file path not found: " + getExeFile)
17621782

17631783
# code to get the matrix and linear inputs, outputs and states
@@ -1780,13 +1800,10 @@ def linearize(self, lintime = None, simflags= None): # 22
17801800
self.linearoutputs = outputVars
17811801
self.linearstates = stateVars
17821802
return [A, B, C, D]
1783-
os.chdir(currentDir)
17841803
except:
1785-
os.chdir(currentDir)
17861804
raise Exception("ModuleNotFoundError: No module named 'linearized_model'")
17871805
else:
17881806
errormsg = self.getconn.sendExpression("getErrorString()")
1789-
os.chdir(currentDir)
17901807
return print("Linearization failed: ", "\"" , linearFile,"\"" ," not found \n", errormsg)
17911808

17921809

tests/test_linearization.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import OMPython
2+
import tempfile, shutil, os
3+
import pytest
4+
5+
class Test_Linearization:
6+
def loadModel(self):
7+
self.tmp = tempfile.mkdtemp(prefix='tmpOMPython.tests')
8+
with open("%s/linearTest.mo" % self.tmp, "w") as fout:
9+
fout.write("""
10+
model linearTest
11+
Real x1(start=1);
12+
Real x2(start=-2);
13+
Real x3(start=3);
14+
Real x4(start=-5);
15+
parameter Real a=3,b=2,c=5,d=7,e=1,f=4;
16+
equation
17+
a*x1 = b*x2 -der(x1);
18+
der(x2) + c*x3 + d*x1 = x4;
19+
f*x4 - e*x3 - der(x3) = x1;
20+
der(x4) = x1 + x2 + der(x3) + x4;
21+
end linearTest;
22+
""")
23+
24+
def __del__(self):
25+
shutil.rmtree(self.tmp, ignore_errors=True)
26+
27+
def test_example(self):
28+
self.loadModel()
29+
filePath = os.path.join(self.tmp,"linearTest.mo").replace("\\", "/")
30+
print(filePath)
31+
mod = OMPython.ModelicaSystem(filePath, "linearTest")
32+
[A, B, C, D] = mod.linearize()
33+
expected_matrixA = [[-3, 2, 0, 0], [-7, 0, -5, 1], [-1, 0, -1, 4], [0, 1, -1, 5]]
34+
assert A == expected_matrixA, f"Matrix does not match the expected value. Got: {A}, Expected: {expected_matrixA}"
35+
assert B == [], f"Matrix does not match the expected value. Got: {B}, Expected: {[]}"
36+
assert C == [], f"Matrix does not match the expected value. Got: {C}, Expected: {[]}"
37+
assert D == [], f"Matrix does not match the expected value. Got: {D}, Expected: {[]}"
38+

0 commit comments

Comments
 (0)