Skip to content

Commit

Permalink
include c library files from external Modelica libraries
Browse files Browse the repository at this point in the history
*simplify usage of subprocess.Popen()
* add linearization test
Co-authored-by: arun3688 <[email protected]>
  • Loading branch information
syntron authored Nov 7, 2024
1 parent 60f865d commit 2001229
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 39 deletions.
95 changes: 56 additions & 39 deletions OMPython/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,55 @@ def setTempDirectory(self, customBuildDirectory):
def getWorkDirectory(self):
return self.tempdir

def _run_cmd(self, cmd: list, verbose: bool = True):
logger.debug("Run OM command {} in {}".format(cmd, self.tempdir))

if platform.system() == "Windows":
omhome = os.path.join(os.environ.get("OPENMODELICAHOME"))
dllPath = (os.path.join(omhome, "bin")
+ os.pathsep + os.path.join(omhome, "lib/omc")
+ os.pathsep + os.path.join(omhome, "lib/omc/cpp")
+ os.pathsep + os.path.join(omhome, "lib/omc/omsicpp"))

# include path to resources of defined external libraries
for element in self.lmodel:
if element is not None:
if isinstance(element, str):
if element.endswith("package.mo"):
pkgpath = element[:-10] + '/Resources/Library/'
for wver in ['win32', 'win64']:
pkgpath_wver = pkgpath + '/' + wver
if os.path.exists(pkgpath_wver):
dllPath = pkgpath_wver + os.pathsep + dllPath

# fix backslash in path definitions
dllPath = dllPath.replace("\\", "/")

my_env = os.environ.copy()
my_env["PATH"] = dllPath + os.pathsep + my_env["PATH"]
else:
# TODO: how to handle path to resources of external libraries for any system not Windows?
my_env = None

currentDir = os.getcwd()
try:
os.chdir(self.tempdir)
p = subprocess.Popen(cmd, env=my_env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()

stdout = stdout.decode('ascii').strip()
stderr = stderr.decode('ascii').strip()
if stderr:
logger.warning("OM error: {}".format(stderr))
if verbose and stdout:
logger.info("OM output:\n{}".format(stdout))
p.wait()
p.terminate()
os.chdir(currentDir)
except Exception as e:
os.chdir(currentDir)
raise Exception("Error running command {}: {}".format(repr(cmd), e))

def buildModel(self, variableFilter=None, verbose=True):
if variableFilter is not None:
self.variableFilter = variableFilter
Expand Down Expand Up @@ -1280,32 +1329,15 @@ def simulate(self, resultfile=None, simflags=None, verbose=True): # 11
getExeFile = os.path.join(self.tempdir, '{}.{}'.format(self.modelName, "exe")).replace("\\", "/")
else:
getExeFile = os.path.join(self.tempdir, self.modelName).replace("\\", "/")
currentDir = os.getcwd()
if (os.path.exists(getExeFile)):

if os.path.exists(getExeFile):
cmd = getExeFile + override + csvinput + r + simflags
cmd = cmd.split(" ")
#print(cmd)
os.chdir(self.tempdir)
if (platform.system() == "Windows"):
omhome = os.path.join(os.environ.get("OPENMODELICAHOME"))
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("\\", "/")
my_env = os.environ.copy()
my_env["PATH"] = dllPath + os.pathsep + my_env["PATH"]
if not verbose:
p = subprocess.Popen(cmd, env=my_env, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
else:
p = subprocess.Popen(cmd, env=my_env)
else:
if not verbose:
p = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
else:
p = subprocess.Popen(cmd)
p.wait()
p.terminate()
os.chdir(currentDir)
self._run_cmd(cmd=cmd, verbose=verbose)

self.simulationFlag = True
else:
raise Exception("Error: Application file path not found: " + getExeFile)
raise Exception("Error: Application file path not found: " + getExeFile)

# to extract simulation results
def getSolutions(self, varList=None, resultfile=None): # 12
Expand Down Expand Up @@ -1741,23 +1773,11 @@ def linearize(self, lintime = None, simflags= None): # 22
if simflags is None:
simflags = ""

currentDir = os.getcwd()
if (os.path.exists(getExeFile)):
cmd = getExeFile + linruntime + override + csvinput + simflags
# print(cmd)
os.chdir(self.tempdir)
if (platform.system() == "Windows"):
omhome = os.path.join(os.environ.get("OPENMODELICAHOME"))
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("\\", "/")
my_env = os.environ.copy()
my_env["PATH"] = dllPath + os.pathsep + my_env["PATH"]
p = subprocess.Popen(cmd, env=my_env)
p.wait()
p.terminate()
else:
os.system(cmd)
cmd = cmd.split(' ')
self._run_cmd(cmd=cmd)
else:
os.chdir(currentDir)
raise Exception("Error: Application file path not found: " + getExeFile)

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


Expand Down
38 changes: 38 additions & 0 deletions tests/test_linearization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import OMPython
import tempfile, shutil, os
import pytest

class Test_Linearization:
def loadModel(self):
self.tmp = tempfile.mkdtemp(prefix='tmpOMPython.tests')
with open("%s/linearTest.mo" % self.tmp, "w") as fout:
fout.write("""
model linearTest
Real x1(start=1);
Real x2(start=-2);
Real x3(start=3);
Real x4(start=-5);
parameter Real a=3,b=2,c=5,d=7,e=1,f=4;
equation
a*x1 = b*x2 -der(x1);
der(x2) + c*x3 + d*x1 = x4;
f*x4 - e*x3 - der(x3) = x1;
der(x4) = x1 + x2 + der(x3) + x4;
end linearTest;
""")

def __del__(self):
shutil.rmtree(self.tmp, ignore_errors=True)

def test_example(self):
self.loadModel()
filePath = os.path.join(self.tmp,"linearTest.mo").replace("\\", "/")
print(filePath)
mod = OMPython.ModelicaSystem(filePath, "linearTest")
[A, B, C, D] = mod.linearize()
expected_matrixA = [[-3, 2, 0, 0], [-7, 0, -5, 1], [-1, 0, -1, 4], [0, 1, -1, 5]]
assert A == expected_matrixA, f"Matrix does not match the expected value. Got: {A}, Expected: {expected_matrixA}"
assert B == [], f"Matrix does not match the expected value. Got: {B}, Expected: {[]}"
assert C == [], f"Matrix does not match the expected value. Got: {C}, Expected: {[]}"
assert D == [], f"Matrix does not match the expected value. Got: {D}, Expected: {[]}"

0 comments on commit 2001229

Please sign in to comment.