Skip to content

Commit 91a2839

Browse files
authored
Merge branch 'master' into add_ModelicaSystemCmd
2 parents 4aaf761 + 64a16ef commit 91a2839

2 files changed

Lines changed: 73 additions & 8 deletions

File tree

OMPython/ModelicaSystem.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,11 @@
4545
import importlib
4646
import pathlib
4747
from dataclasses import dataclass
48+
import textwrap
4849
from typing import Optional
4950
import warnings
5051

51-
from OMPython.OMCSession import OMCSessionZMQ
52+
from OMPython.OMCSession import OMCSessionZMQ, OMCSessionException
5253

5354
# define logger using the current module name as ID
5455
logger = logging.getLogger(__name__)
@@ -495,8 +496,14 @@ def buildModel(self, variableFilter=None):
495496
self.xmlparse()
496497

497498
def sendExpression(self, expr, parsed=True):
498-
logger.debug("sendExpression(%r, %r)", expr, parsed)
499-
return self.getconn.sendExpression(expr, parsed)
499+
try:
500+
retval = self.getconn.sendExpression(expr, parsed)
501+
except OMCSessionException as ex:
502+
raise ModelicaSystemError(f"Error executing {repr(expr)}") from ex
503+
504+
logger.debug(f"Result of executing {repr(expr)}: {textwrap.shorten(repr(retval), width=100)}")
505+
506+
return retval
500507

501508
# request to OMC
502509
def requestApi(self, apiName, entity=None, properties=None): # 2
@@ -588,7 +595,7 @@ def getContinuous(self, names=None): # 4
588595
try:
589596
value = self.getSolutions(i)
590597
self.continuouslist[i] = value[0][-1]
591-
except Exception as ex:
598+
except OMCSessionException as ex:
592599
raise ModelicaSystemError(f"{i} could not be computed") from ex
593600
return self.continuouslist
594601

@@ -1255,8 +1262,7 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
12551262
linearFile = pathlib.Path(f'linear_{self.modelName}.py')
12561263

12571264
if not linearFile.exists():
1258-
errormsg = self.sendExpression("getErrorString()")
1259-
raise ModelicaSystemError(f"Linearization failed: {linearFile} not found: {errormsg}")
1265+
raise ModelicaSystemError(f"Linearization failed: {linearFile} not found!")
12601266

12611267
# this function is called from the generated python code linearized_model.py at runtime,
12621268
# 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

OMPython/OMCSession.py

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import os
4242
import pathlib
4343
import psutil
44+
import re
4445
import signal
4546
import subprocess
4647
import sys
@@ -325,6 +326,9 @@ def __init__(self, timeout=10.00,
325326
# connect to the running omc instance using ZMQ
326327
self._connect_to_omc(timeout)
327328

329+
self._re_log_entries = None
330+
self._re_log_raw = None
331+
328332
def __del__(self):
329333
try:
330334
self.sendExpression("quit()")
@@ -549,6 +553,62 @@ def sendExpression(self, command, parsed=True):
549553
return None
550554
else:
551555
result = self._omc.recv_string()
556+
557+
if command == "getErrorString()":
558+
# no error handling if 'getErrorString()' is called
559+
pass
560+
elif command == "getMessagesStringInternal()":
561+
# no error handling if 'getMessagesStringInternal()' is called; parsing NOT possible!
562+
if parsed:
563+
logger.warning("Result of 'getMessagesStringInternal()' cannot be parsed - set parsed to False!")
564+
parsed = False
565+
else:
566+
# allways check for error
567+
self._omc.send_string('getMessagesStringInternal()', flags=zmq.NOBLOCK)
568+
error_raw = self._omc.recv_string()
569+
# run error handling only if there is something to check
570+
if error_raw != "{}\n":
571+
if not self._re_log_entries:
572+
self._re_log_entries = re.compile(pattern=r'record OpenModelica\.Scripting\.ErrorMessage'
573+
'(.*?)'
574+
r'end OpenModelica\.Scripting\.ErrorMessage;',
575+
flags=re.MULTILINE | re.DOTALL)
576+
if not self._re_log_raw:
577+
self._re_log_raw = re.compile(
578+
pattern=r"\s+message = \"(.*?)\",\n" # message
579+
r"\s+kind = .OpenModelica.Scripting.ErrorKind.(.*?),\n" # kind
580+
r"\s+level = .OpenModelica.Scripting.ErrorLevel.(.*?),\n" # level
581+
r"\s+id = (.*?)" # id
582+
"(,\n|\n)", # end marker
583+
flags=re.MULTILINE | re.DOTALL)
584+
585+
# extract all ErrorMessage records
586+
log_entries = self._re_log_entries.findall(string=error_raw)
587+
for log_entry in reversed(log_entries):
588+
log_raw = self._re_log_raw.findall(string=log_entry)
589+
if len(log_raw) != 1 or len(log_raw[0]) != 5:
590+
logger.warning("Invalid ErrorMessage record returned by 'getMessagesStringInternal()':"
591+
f" {repr(log_entry)}!")
592+
593+
log_message = log_raw[0][0].encode().decode('unicode_escape')
594+
log_kind = log_raw[0][1]
595+
log_level = log_raw[0][2]
596+
log_id = log_raw[0][3]
597+
598+
msg = (f"[OMC log for 'sendExpression({command}, {parsed})']: "
599+
f"[{log_kind}:{log_level}:{log_id}] {log_message}")
600+
601+
# response according to the used log level
602+
# see: https://build.openmodelica.org/Documentation/OpenModelica.Scripting.ErrorLevel.html
603+
if log_level == 'error':
604+
raise OMCSessionException(msg)
605+
elif log_level == 'warning':
606+
logger.warning(msg)
607+
elif log_level == 'notification':
608+
logger.info(msg)
609+
else: # internal
610+
logger.debug(msg)
611+
552612
if parsed is True:
553613
try:
554614
return om_parser_typed(result)
@@ -557,7 +617,6 @@ def sendExpression(self, command, parsed=True):
557617
try:
558618
return om_parser_basic(result)
559619
except (TypeError, UnboundLocalError) as ex:
560-
logger.warning('OMParser error: %s. Returning the unparsed result.', ex)
561-
return result
620+
raise OMCSessionException("Cannot parse OMC result") from ex
562621
else:
563622
return result

0 commit comments

Comments
 (0)