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:
- 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.
- 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
Der gesamte Sourcecode darf gemäß GNU General Public License weiterverbreitet werden.