[PYTHON] Run Open Modelica from Jupyter Lab

Introduction

OpenModelica (hereinafter referred to as OM) may be unsatisfactory due to its weak parameter study function and result processing, analysis, and visualization functions. Since OM has a function to link with Python, it may be possible to make up for the lack of OM by executing calculations and processing results in Python. To confirm this, first verify the operation of the Python-OM linkage function and process the calculation results with a data analysis library called Pandas. Python is almost inexperienced, so please point out any mistakes.

OM-Python integration function

OM has three functions for linking with Python. It mainly executes OM commands from Python.

omc.sendExpression("simulate(BouncingBall, stopTime=3.0)")
mod.simulate()

Operation verification of OMPython

We will verify the operation of the most basic OMPython. Execution on the Python side is done in Jupyter Lab.

environment

Windows10 Home 1809 conda version : 4.5.4 conda-build version : 3.10.5 python version : 3.6.5.final.0 JupyterLab : 1.2.6 OpenModelica : 1.13.2 64bit

Installation

Install according to the ReadMe below. https://github.com/OpenModelica/OMPython

It is assumed that OM and Anaconda are installed in advance.

①. Start Anaconda Prompt and move to the following folder Here, "% OPENMODELICAHOME%" is the path directly under the folder where OM is installed.

cd %OPENMODELICAHOME%\share\omc\scripts\PythonInterface

②. Install with the following command

python -m pip install -U .

I got this message.

Could not install packages due to an EnvironmentError: [WinError 5]Access denied.: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\Anaconda3_64\\Lib\\site-packages\\future'
Consider using the `--user` option or check the permissions.

The error message is very kind. Re-execute with --user as told. done.

python -m pip install --user -U .
Message
``` Processing c:\openmodelica1.13.264bit\share\omc\scripts\pythoninterface Collecting future (from OMPython==3.1.2) Requirement not upgraded as not directly required: pyparsing in c:\program files (x86)\microsoft visual studio\shared\anaconda3_64\lib\site-packages (from OMPython==3.1.2) (2.2.0) Requirement not upgraded as not directly required: numpy in c:\program files (x86)\microsoft visual studio\shared\anaconda3_64\lib\site-packages (from OMPython==3.1.2) (1.14.3) Requirement not upgraded as not directly required: pyzmq in c:\program files (x86)\microsoft visual studio\shared\anaconda3_64\lib\site-packages (from OMPython==3.1.2) (17.0.0) Building wheels for collected packages: OMPython Running setup.py bdist_wheel for OMPython ... done Stored in directory: C:\Users\(username)\AppData\Local\Temp\pip-ephem-wheel-cache-9tdaz1nu\wheels\f8\d4\a6\7ac1ac1efe24abce84d7e039a174e937595e5add3c4dd178c9 Successfully built OMPython Installing collected packages: future, OMPython The scripts futurize.exe and pasteurize.exe are installed in 'C:\Users\(username)\AppData\Roaming\Python\Python36\Scripts' which is not on PATH. Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. Successfully installed OMPython-3.1.2 future-0.18.2 You are using pip version 10.0.1, however version 20.0.2 is available. You should consider upgrading via the 'python -m pip install --upgrade pip' command. ```

③. Start Jupyter Lab to check if it is installed. To start it, start Anaconda Navigator from the start menu and start "Jupyter Lab". Select Python for Notebook.

image.png

image.png

④. Execute the following

import OMPython
help(OMPython.ModelicaSystem)

The image of Jupyter Lab looks like this. Intuitive and easy to operate. Execute with Ctrl + Enter. Insert cell b and delete d twice.

image.png

Success if the following results are returned

Help on class ModelicaSystem in module OMPython:

class ModelicaSystem(builtins.object) | Methods defined here: |
| del(self) |
| init(self, fileName=None, modelName=None, lmodel=[], useCorba=False) | "constructor" | It initializes to load file and build a model, generating object, exe, xml, mat, and json files. etc. It can be called : | •without any arguments: In this case it neither loads a file nor build a model. This is useful when a FMU needed to convert to Modelica model | •with two arguments as file name with ".mo" extension and the model name respectively | •with three arguments, the first and second are file name and model name respectively and the third arguments is Modelica standard library to load a model, which is common in such models where the model is based on the standard library. For example, here is a model named "dcmotor.mo" below table 4-2, which is located in the directory of OpenModelica at "C:\OpenModelica1.9.4-dev.beta2\share\doc\omc estmodels". | Note: If the model file is not in the current working directory, then the path where file is located must be included together with file name. Besides, if the Modelica model contains several different models within the same package, then in order to build the specific model, in second argument, user must put the package name with dot(.) followed by specific model name. | ex: myModel = ModelicaSystem("ModelicaModel.mo", "modelName") |
| convertFmu2Mo(self, fmuName) | In order to load FMU, at first it needs to be translated into Modelica model. This method is used to generate Modelica model from the given FMU. It generates "fmuName_me_FMU.mo". It can be called: | •only without any arguments | Currently, it only supports Model Exchange conversion. |
| - Input arguments: s1 | * s1: name of FMU file, including extension .fmu |
| convertMo2Fmu(self) | This method is used to generate FMU from the given Modelica model. It creates "modelName.fmu" in the current working directory. It can be called: | •only without any arguments |
| getContinuous(self, *names) | This method returns dict. The key is continuous names and value is corresponding continuous value. | If *name is None then the function will return dict which contain all continuous names as key and value as corresponding values. eg., getContinuous() | Otherwise variable number of arguments can be passed as continuous name in string format separated by commas. eg., getContinuous('cName1', 'cName2') |
| getInputs(self, *names) | This method returns dict. The key is input names and value is corresponding input value. | If *name is None then the function will return dict which contain all input names as key and value as corresponding values. eg., getInputs() | Otherwise variable number of arguments can be passed as input name in string format separated by commas. eg., getInputs('iName1', 'iName2') |
| getLinearInputs(self) |
| getLinearOutputs(self) |
| getLinearQuantityInformation(self) |
| getLinearStates(self) |
| getLinearizationOptions(self, *names) | This method returns dict. The key is linearize option names and value is corresponding linearize option value. | If *name is None then the function will return dict which contain all linearize option names as key and value as corresponding values. eg., getLinearizationOptions() | Otherwise variable number of arguments can be passed as simulation option name in string format separated by commas. eg., getLinearizationOptions('linName1', 'linName2') |
| getOptimizationOptions(self, *names) |
| getOutputs(self, *names) | This method returns dict. The key is output names and value is corresponding output value. | If *name is None then the function will return dict which contain all output names as key and value as corresponding values. eg., getOutputs() | Otherwise variable number of arguments can be passed as output name in string format separated by commas. eg., getOutputs(opName1', 'opName2') |
| getParameters(self, *names) | This method returns dict. The key is parameter names and value is corresponding parameter value. | If *name is None then the function will return dict which contain all parameter names as key and value as corresponding values. eg., getParameters() | Otherwise variable number of arguments can be passed as parameter name in string format separated by commas. eg., getParameters('paraName1', 'paraName2') |
| getQuantities(self, names=None) | This method returns list of dictionaries. It displays details of quantities such as name, value, changeable, and description, where changeable means if value for corresponding quantity name is changeable or not. It can be called : | •without argument: it returns list of dictionaries of all quantities | •with a single argument as list of quantities name in string format: it returns list of dictionaries of only particular quantities name | •a single argument as a single quantity name (or in list) in string format: it returns list of dictionaries of the particular quantity name |
| getSimulationOptions(self, *names) | This method returns dict. The key is simulation option names and value is corresponding simulation option value. | If *name is None then the function will return dict which contain all simulation option names as key and value as corresponding values. eg., getSimulationOptions() | Otherwise variable number of arguments can be passed as simulation option name in string format separated by commas. eg., getSimulationOptions('simName1', 'simName2') |
| getSolutions(self, *varList) | This method returns tuple of numpy arrays. It can be called: | •with a list of quantities name in string format as argument: it returns the simulation results of the corresponding names in the same order. Here it supports Python unpacking depending upon the number of variables assigned. |
| linearize(self) | This method linearizes model according to the linearized options. This will generate a linear model that consists of matrices A, B, C and D. It can be called: | •only without any arguments |
| optimize(self) | This method optimizes model according to the optimized options. It can be called: | •only without any arguments |
| requestApi(self, apiName, entity=None, properties=None) | # request to OMC |
| setContinuous(self, **cvals) | This method is used to set continuous values. It can be called: | •with a sequence of continuous name and assigning corresponding values as arguments as show in the example below: | setContinuousValues(cName1 = 10.9, cName2 = 0.066) |
| setInputs(self, **nameVal) | This method is used to set input values. It can be called: | •with a sequence of input name and assigning corresponding values as arguments as show in the example below: | setParameterValues(iName = [(t0, v0), (t1, v0), (t1, v2), (t3, v2)...]), where tj<=tj+1 |
| setLinearizationOptions(self, **linearizationOptions) | This method is used to set linearization options. It can be called: | •with a sequence of linearization options name and assigning corresponding value as arguments as show in the example below | setLinearizationOptions(stopTime=0, stepSize = 10) |
| setOptimizationOptions(self, **optimizationOptions) | This method is used to set optimization options. It can be called: | •with a sequence of optimization options name and assigning corresponding values as arguments as show in the example below: | setOptimizationOptions(stopTime = 10,simflags = '-lv LOG_IPOPT -optimizerNP 1') |
| setParameters(self, **pvals) | This method is used to set parameter values. It can be called: | •with a sequence of parameter name and assigning corresponding value as arguments as show in the example below: | setParameterValues(pName1 = 10.9, pName2 = 0.066) |
| setSimulationOptions(self, **simOptions) | This method is used to set simulation options. It can be called: | •with a sequence of simulation options name and assigning corresponding values as arguments as show in the example below: | setSimulationOptions(stopTime = 100, solver = 'euler') |
| simulate(self) | This method simulates model according to the simulation options. It can be called: | •only without any arguments: simulate the model

Data descriptors defined here:
dict
dictionary for instance variables (if defined)
weakref
list of weak references to the object (if defined)

Test model execution

Follow the official tutorial below. The calculation target is the behavior of the bouncing ball. https://www.openmodelica.org/doc/OpenModelicaUsersGuide/OpenModelicaUsersGuide-v1.13.2.pdf

①. Load the model, move the folder, etc. to execute the calculation image.png

②. Execution of calculation Output with csv for result processing with Pandas later image.png

③. Acquisition of calculated value image.png

④. Result plot image.png

Impressions

Python and Jupyter Lab are intuitive and easy to operate. If you get used to Pandas, it's probably okay. I was convinced that it was a standard tool for data analysis with easy operability. However, since the confirmation and processing of the result is command-based, like MATLAB and Excel. I would be happy if I could create a graph by simply selecting data with the mouse more graphically and clicking the buttons. Processing such as calculation execution and data processing (extracting necessary results, averaging and difference) is done in Python. I think that you can use Excel etc. properly for graph creation and report creation for submission for the processed numerical values.

Postscript In the following article, there was a very easy-to-understand consideration about how to use Excel and Python properly. https://qiita.com/taka000826/items/ca8fa4a1a392728f688c

OMPython worked fine and did a good job. After all, I just hit the OMShell command as it is It is very helpful because Python covers the behavior that OMShell is not good at. I will continue to use it in the future.

Recommended Posts

Run Open Modelica from Jupyter Lab
Jupyter Lab begins
How to Git from GCP's Jupyter Lab to GSR
Run Django tests for currently open buffers from Emacs
Run python from excel
Open Jupyter Lab (or Jupyter Notebook) by specifying a directory
Install Python Jupyter lab
Run BigQuery from Lambda
Run illustrator script from python
Make Jupyter Lab accessible remotely
Label images on jupyter lab
Error: 500 (Internal Server Error) Jupyter lab
Run Jupyter Notebook on windows