Dr. Arne JachensDr. Arne Jachens

python Library

ModelicaExecution

You may use OMPython to control Modelica simulations from within Python.
You always have to instantiate the ModelicaSystem(...) once - this is time-consuming, and as part of the result, you get *_init.xml and *.exe files.

To perform parameter studies, it is more efficient to call this *.exe directly.
To varry the parameters, there are two optiones:

  1. Edit the _init.xml. The XML is more complicated to read, and for large models, this xml gets large too, the parsing gets time consuming.
  2. Put the few parameters of interest into a JSON file und utilize the ExternData extension; to install follow: File > Manage Libraries > Install Library.

The JSON file might look like:
{"NoWL": "1", "TAmbient": 42.0, "ILaser": 1.8, "greenLaser": {"pi": "3.14159"}}

myLibrary.Testing.Test_JSON.mo

And the usage within Modelicy is like:

within myLibrary.Testing;

model Test_JSON

 inner parameter ExternData.JSONFile configuration(fileName=Modelica.Utilities.Files.loadResource("modelica://myLibrary/myParameters.json")) "parameters to modify" annotation(Placement(transformation(extent={{-80,60},{-60,80}})));
  final parameter Integer NoWL  = configuration.getInteger("myParameters.NoWL");
  final parameter nSI.Temperature_degC TAmbient = configuration.getReal("myParameters.TAmbient");
  parameter SI.Current ILaser = configuration.getReal("myParameters.ILaser");
  Real pi = configuration.getReal("myParameters.greenLaser.pi");
equation

end Test_JSON;

ModelicaExecution.py

import  os, sys, argparse
import  time
import  json
import  shutil as  shutil
import  subprocess
import  pdb #for  debugging only pdb.set_trace()
from OMPython import  OMCSessionZMQ,ModelicaSystem
from colorama import  Fore, Back, Style #colorful messages



#=======================================#
#                                       #
#         Dr. Arne Jachens              #
#            2022-05-13                 #
#=======================================#
class ModelicaExecution:
    """
    Uses Modelica.ExternData to have parameters in JSON file,
    uses OMPython to build the EXE,
    EXE may be re-run for  parameter stuies directly.
    pre-requirements:
    * https://www.openmodelica.org/ version 1.19.x
    * https://github.com/OpenModelica/OMPython
    """
    
    def   __init__(self, compile, debug=False, modelConf={"libPath":"../", "model":"myLibrary.myModel", "execPath":"./", "parametersFile":"myParameters.json", "optionsFile": " "}):
        """
        set debug=True to have more insight into the processing
        When initializing, configure library to model of interest.
        Otherwise, some example default will be set.
        Optionally, call with command line arguments.
        """
        self.compile        = compile
        self.debug          = debug
        self.libPath        = modelConf["libPath"]        #where is package.mo
        self.model          = modelConf["model"]          #without extension .mo !
        self.execPath       = modelConf["execPath"]       #local?
        self.parametersFile = modelConf["parametersFile"] #JSON format
        self.optionsFile    = modelConf["optionsFile"]    #JSON format
        self.date           = time.strftime('%Y-%m-%d')
        outDir = str(self.date)
        if not os.path.exists(outDir):
            os.makedirs(outDir)
            
        self.__echo("Find results in: ./"+outDir+"/", 'okay')


    #=======================================#
    def  __echo(self, msg, type="error"):
        """
        Display ERROR in red.
        """
        if type=='okay':
            print(Back.GREEN + msg + Style.RESET_ALL)
        else type=='warn':
            print(Fore.MAGENTA + Style.BRIGHT + 'Warning: '+ msg + Style.RESET_ALL)
        else:
            print(Fore.RED + Style.BRIGHT + 'ERROR: '+ msg + Style.RESET_ALL)

    #============================#
    def   dict2json(self,dict,file):
        """
        Write modified dictionary to JSON.
        """
        if self.debug:
            print("writeJSON:",dict)
            
        with open(file, 'w') as    outfile:
            json.dump(dict, outfile)
        
    #============================#
    def   json2dict(self,file):
        """
        Read JSON file to dictionary.
        """
        try:
            with open(file) as    json_file:
                dict = json.load(json_file)
        except:
            #self.__echo("File not found: "+file, 'error')
            print("File not found: "+file)
            dict = {}
            
        return dict
    
    #============================#
    def  compileModel(self):
        """
        To interact with the Modelica simulation, 
        it needs to be instantiated and compiled first.
        This takes some time, results are the *_init.xml and *.exe files.
        """
        libPackage = str(self.libPath) + "/package.mo"
        if self.debug:
            self.__echo("ModelicaSystem( " + libPackage + " , " + self.model + " )", 'okay')

        try:
            mod = ModelicaSystem(libPackage, self.model, ["Modelica"])
        except:
            self.__echo("compilation failed!", 'error')
            self.__echo("path to package.mo \n\t"+libPackage, 'warn')
            self.__echo("model hieracy main.sub.model without extension! \n\t"+self.model, 'warn')
            print("Did you run it in OpenModelica first?\n")
            exit()

        try:
            simOpt = self.json2dict(self.optionsFile)
        except:
            self.__echo("No simulation options specified, using default\n",'warn')
            simOpt = {
                'startTime' : 0,
                'stopTime'  : 10,
                'tolerance' : 1E-6,
                'stepSize'  : 0.1
            }
        mod.setSimulationOptions(simOpt)

        try:
            mod.simulate()
            self.__secureResult()
        except:
            self.__echo("simulation failed!", 'error')
            exit()
        else:
            if self.debug:
                self.__echo("compile Model: "+ str(self.model), 'okay')
        
        #clean temporary files:
        cmd = "del *.c *.h *.o *.log *.libs *.makefile *.json" 
        os.system(cmd)
            
        return
        
    #============================#
    def  runModel(self):
        """
        Re-run the model.exe
        after you modified the JSON configuration.
        """
        cmd = self.model+".exe"

        error = False
        try:
            output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, cwd=self.execPath)
        except subprocess.CalledProcessError as  exc:
            self.__echo("Status : FAIL"+str(exc.returncode)+str(exc.output), 'error')
            print(cmd)
            error = True
        else:
            if str(output).find("assert")>0:
                self.__echo("Modelica ASSERT", 'warn')
                self.__echo(cmd+"\nModelica FAILED\n"+outputStr, 'warn')
                error = True
            else self.debug:
                fileName = self.__secureResult()
                self.__echo("run Model: " + fileName, 'okay')

        return error
        
    #============================#
    def  __secureResult(self):
        """
        Avoind to override the result,
        rename it with timestamp.
        """
        now = time.strftime('%H%M%S')
        fileName1 = self.model+"_res.mat"
        fileName2 = self.date + "/" + self.model + "_" + now + "_res.mat"
        shutil.copy(fileName1,fileName2)
        return fileName2
        
    #============================#
    def  commandLineArguments(self):
        """
        Optionally, parse command line arguments.
        """
        parser = argparse.ArgumentParser(description="Write configuration to JSON file and rund model.")
        parser.add_argument("-e", "--execPath",       help="Path where executable can be found", required = False)
        parser.add_argument("-l", "--libPath",        help="Modelica library, where is the package.mo", required = False)
        parser.add_argument("-m", "--model",          help="Name of model to be run", required = False)
        parser.add_argument("-o", "--optionsFile",    help="JSON file with simulation options", required = False)
        parser.add_argument("-p", "--parametersFile", help="JSON file with parameters", required = False)
        parser.add_argument("-d", "--debug",          help="debugging {True, False}", required = False)
        parser.add_argument(      "--compile",        help="Set True to compile the model first", required = True)
        argDict = vars(parser.parse_args())
        
        if argDict['debug']=="True" or argDict['debug']=="1":
            argDict['debug'] = True
        else:
            argDict['debug'] = False
            
        if argDict['compile']=="True" or argDict['compile']=="1":
            argDict['compile'] = True
        else:
            argDict['compile'] = False
            
        for  a in argDict:
            if not argDict[a] is None:
                self.__dict__[a] = argDict[a]
                if argDict['debug']:
                    print("setting",a,self.__dict__[a])
       
            


#=======================================#
if __name__ == "__main__":
    """
    pythonOM ModelicaExecution.py --compile False
    """
    debug = False
    debug = True
    compile = True
    
    modelConf={"libPath":"../../", "model":"HUDcalculator.TestHUDcalculator.Test_LED_JSON", "execPath":"./", "parametersFile":"TestHUDcalculator/Test_LED_JSON.json", "optionsFile": ""}
    ME = ModelicaExecution(compile, debug, modelConf)
    ME.commandLineArguments()
    
    if ME.compile:
        ME.compileModel()
        
    file = str(ME.libPath) + "/" + str(ME.parametersFile)
    parameters = ME.json2dict(file)
    if debug:
        keys = parameters.keys()
        for   k in keys:
            print("\t",k,":\t",parameters[k])
    parameters['Test_LED_JSON']['TAmbientStart'] = 20.0
    ME.dict2json(parameters,file)
    
    for   i in range(3):
        parameters['Test_LED_JSON']['TAmbientStart'] = float(parameters['Test_LED_JSON']['TAmbientStart'])+1
        print(i,parameters['Test_LED_JSON']['TAmbientStart'])
        ME.dict2json(parameters,file)
        ME.runModel()

Index of Library

1CIEcolorCoordinates_Spectrum.py
2MatlabStructures.py
3ModelicaExecution.py
4ModelicaMatFilter.py
5OperateAllFiles.py
6dictionaryStatistics.py
7familienKonto.py
8makeDoc.py
9plotTimeSeries.py
10readData2DictOfArrays.py
11replaceInFile.py
12showPointOnCIExy.py
13testNumpyMatrix.py
14writeDictOfArrays.py
15writeTSV.py

Der gesamte Sourcecode darf gemäß GNU General Public License weiterverbreitet werden.