API for Accessing OpenModelica Models From Python

B. Lie S. Bajracharya, A. Mengist, L. Buffoni, A. Kumar University College of Southeast Norway M. Sjolund,¨ A. Asghar, A. Pop, P. Fritzson Porsgrunn, Norway Linkoping¨ University Email: [email protected] Sweden Email: [email protected]

Abstract—This paper describes a new API for operating packages in Python, or freely develop one’s own analysis on models in Python, through OpenModelica. routines in Python. Modelica is an object oriented, acausal language for describ- ing dynamic models in the form of Differential Algebraic Modelica and OpenModelica Shell in themselves have Equations. Modelica and various implementations such as relatively little support for advanced analysis of models. OpenModelica have limited support for model analysis, and Examples of such desirable analysis capabilities could it is of interest to integrate Modelica code with scripting lan- be (i) study of model sensitivity, (ii) random number guages such as Python, which facilitate the needed analysis possibilities. The API is based on a new class ModelicaSystem generation and statistical analysis, (iii) Monte Carlo sim- within package OMPython of OpenModelica, with methods ulation, (iv) advanced plotting capabilities, (v) general that operate on instantiated models. Emphasis has been put optimization capabilities, (vi) linear analysis and control on specification of a systematic structure for the various synthesis, etc. Scripting languages such as MATLAB and methods of the class. A simple case study involving a water Python hold most of these desirable analysis capabilities, tank is used to illustrate the basic ideas. and it is of interest to integrate Modelica models with such Keywords-OpenModelica, Modelica, Python, Python API script languages. The free JModelica.org tool includes a Python package for converting Modelica models to FMUs, I.INTRODUCTION and then for importing the FMU as a Python object. This Modelica is a modern, equation based, acausal language way, Modelica models can essentially be simulated from for encoding models of dynamic systems in the form Python — Optimica is also supported. It is possible to do of differential algebraic equations (DAEs), see e.g. [3] more advanced analysis with JModelica.org3 via CasADi, on Modelica and e.g. [2] on DAEs. OpenModelica1 [4] see e.g. [7] and [8]. However, the possibilities in the work is a mature, freely available toolset that includes Open- of Perera et al. use an old version of JModelica.org. It Modelica Connection Editor (flow sheeting, textual editor would be more ideal if these possibilities were supported with debugging facilities, and simulation environment) by the tool developer. and the OMShell (command line execution, script based It is thus of interest to develop an extension of execution). OpenModelica Shell supports commands for OMPython which enables simulation and analysis of Mod- simulation of Modelica models, for use of the Modelica elica models with a better integration with the Python extension Optimica, for carrying out analytic linearization language, and in particular that such an extension is pro- via the Modelica package Modelica LinearSystem2, and vided by the OpenModelica developers. A Python API4 for for converting Modelica models into Functional Mock-Up controlling Modelica simulation and analysis from Python Units (FMUs) as well as for converting FMUs back to was proposed in February 20155. Based on this proposal, Modelica models. A tool OMPython has been developed a first version of a Python API has been implemented [1], and communicates with OpenModelica via CORBA, [5], and has then been further revised. This paper discusses [6]. Essentially, OMPython is a Python package which the API, and illustrates how it can be used for automatic makes it possible to pass OpenModelica Shell commands analysis of Modelica models from Python, exemplified by as strings to a Python function, and then receive the results a simple water tank model. The paper is organized as back into Python. This possibility does, however, require follows. In Section 2, an overview of the API is given. good knowledge of OpenModelica Shell commands and In Section 3, use of the API is illustrated through simple syntax. A tool, PySimulator,2 has been developed to ease analysis of a nonlinear reactor model. In Section 4, the API the use of Modelica from Python, [9], [6]. Essentially, is discussed, some conclusions are drawn, and future work PySimulator provides a GUI based on Python, where Mod- is discussed. Appendices hold details of the nonlinear elica models can be run and results can presented. It is also reactor model. possible to analyze the results using various packages in Python, e.g. FFT analysis. However, PySimulator currently does not give the user full freedom to integrate Modelica models with Python and use the full available set of 3www.JModelica.org 4API = Application Programming Interface 1www.openmodelica.org 5Python API for Accessing OpenModelica Models, by B. Lie, February 2https://pypi.python.org/pypi/PySimulator 20, 2015, communicated to P. Fritzson at Linkoping¨ University. II.OVERVIEW OF PYTHON API In this subsection, we discuss how to import the class, A. Goal and how to use the constructor to instantiate an object. The object is imported from package OMPython, i.e. Modeling and the use of Modelica with Python is of with Python commands8: interest to a wide range of engineering disciplines. The computer science threshold of using Modelica with Python >>> from OMPython import ModelicaSystem should be low. Ideally, the OMPython extension should Other Python packages to be used such as numpy, work with simple one-click Python installations such 6 7 matplotlib, pandas, etc. must be imported in a as Anaconda and Canopy . Furthermore, the extension similar manner. should support both 32 bit and 64 bit OpenModelica, The object constructor requires a minimum of 2 input work with both 32 bit and 64 bit Python, with Python arguments which are strings, and may need a third string 2.7 and Python 3.X, and on platforms Windows, OSX and input argument. . These requirements e.g. imply that results should be returned as standard Python structures. However, it is • The first input argument must be a string with the reasonable that the OMPython extension depends on the file name of the Modelica code, with Modelica file NumPy package. Because Python has excellent plotting extension .mo. If the Modelica file is not in the capabilities e.g. via Matplotlib, the OpenModelica Shell current directory of Python, then the file path must facility for plotting results should not be implemented — also be included. this is more naturally handled directly in Python. • The second input argument must be a string with the name of the Modelica model, including the names- B. Installing the OMPython extension pace if the model is wrapped within a Modelica Under Windows, the new OMPython package. extension will be automatically installed • A third input argument is used if the Modelica model in a file __init__.py in directory builds on other Modelica code, e.g. the Modelica share\omc\scripts\PythonInterface\OMPython Standard Library. in the OpenModelica directory when OpenModelica The result of using the object constructor is a Python is downloaded and installed. In order to activate the object. extension, the user must next run the command python Example 1: Use of constructor. setup.py install from the command line in Suppose we have a Modelica model with name CSTR the directory of the setup.py file, which is in the wrapped in a Modelica package Reactors — stored in file PythonInterface subdirectory. It follows that in Reactor.mo: order to activate the extension, the user must first install package Reactors Python on the relevant computer. Under Linux/OSX, // ... pip pypi OMPython is part of ( ) and is not shipped model CSTR with the OpenModelica installer. /// ... . Status end CSTR; // Currently, the Python API is in a development status end Reactors; and has been tested with 32 bit Python 2.7 from the Anaconda installation in tandem with 32 bit OpenMod- If this model does not use any external Modelica code elica v. 1.9.4 under Windows 8.1 and OpenModelica v. and the file is located in the current Python directory, the 1.9.6 under Windows 10, and a modified __init__.py following Python code instantiates a Python object mod: file. OpenModelica uses CORBA for communication, and >>> mod = ModelicaSystem(’Reactors.mo’, CORBA compatibility needs some refinement. The code ’Reactors.CSTR’) is somewhat unstable when run from the Spyder IDE used with the Anaconda installation, but runs fine from Jupyter The user is free to choose any valid Python label name notebooks. for the Python object. All methods of class ModelicaSystem refers to the D. Description of the API instantiated object, in standard Python fashion. Thus, The API is described in the subsections below. method simulate() is invoked with the Python com- 1) Python Class and Constructor: The name of the mand: Python class which is used for operation on Modelica >>> mod.simulate() models, is ModelicaSystem. This class is equipped with an object constructor of the same name as the class. In In the subsequent overview of methods, the object name addition, the class is equipped with a number of methods is not included. In practice, of course, it must be included for manipulating the instantiated objects. in order to operate on the object in question.

6www.continuum.io/downloads 8The Python prompt >>> is not typed, and does not appear in script 7www.enthought.com/products/canopy files, in iPython or in Jupyter notebooks. Methods may have no input arguments, one, or several • Variability — ’continuous’, input arguments. Methods may or may not return results ’parameter’. — if the methods do not return results, the results are When applying the Pandas method DataFrame to the stored within the object. returned list of dictionaries, the result is a conveniently 2) Utility routines, converting Modelica ↔ FMU: Two typeset table in Jupyter notebooks. Modelica constants utility methods convert files between Modelica files with are not included in the returned quantities. file extension .mo and Functional Mock-up Unit (FMU) Standard get methods: We consider files with file extension .fmu. methods getXXXs(), where XXXs is in 1) convertMo2Fmu() — method for converting the {Continuous, Parameters, Inputs, Outputs, Modelica model of the object, say ModelName, SimulationOptions, OptimizationOptions, into FMU file. LinearizationOptions}. Thus, methods • Required input arguments: none, operates on the getContinuous(), getParameters(), etc. Modelica file associated with the object. Two calling possibilities are accepted. • Optional input arguments: • getXXXs(), i.e. without input argument, returns a – className: string with the class name that dictionary with names as keys and values as ... values. should be translated, • getXXXs(S), where S is a sequence of strings of – version: string with FMU version, “1.0” names, returns a tuple of values for the specified or “2.0”; the default is “1.0”. names. – fmuType: string with FMU type, “me” Getting solutions: We consider method (model exchange) or “cs” (co-simulation); getSolutions(). Two calling possibilities are the default is “me”. accepted. – fileNamePrefix: string; the default is • getSolutions(), i.e. without input arguments, \’className\’. returns a list of strings of names of quantities for – generatedFileName: string, returns the which there is a solution = time series.9 full path of the generated FMU. • getSolutions(S), where S is a sequence of • Result: file ModelName.fmu in the current strings of names, returns a tuple of values = 1D directory numpy arrays = time series for the specified names. 2) convertFmu2Mo(s) — method for converting an Setting methods: The information that can FMU file into a Modelica file. be set is a subset of the information that can setXXXs() • Required input arguments: string s, where s is be set. Thus, we consider methods , name of FMU file, including extension .fmu. where XXXs is in {Parameters, Inputs, SimulationOptions OptimizationOptions • Optional input arguments: a number of optional , , input arguments, e.g. the possibility to change LinearizationOptions}, thus methods working directory for the imported FMU files. setParameters(), setInputs(), etc. Two • Result: Assume the name of the calling possibilities are accepted. file is fmuName.fmu. Then file • setXXXs(K), with K being a sequence of keyword fmuName_me_FMU.mo is generated in assignments of type quantity name = value. the current Python directory. Here, the quantity name could be a parameter name 3) Getting and setting information: Quite a few meth- (i.e., not a string), an input name, etc. ods are dedicated to getting and setting information about – For parameters and simula- objects. With two exceptions — getQuantities() tion/optimization/linearization options, the and getSolutions() — the get methods have identi- value should be a numerical value or a string cal use of input arguments and results, while all the set (e.g. a string of ODE solver name such as methods have identical use of input arguments, with results ’dassl’, etc.). stored in the object. – For inputs, the value could be a numerical value Getting quantity information: Method if the input is constant in the time range of the getQuantities() does not accept input arguments, simulation, and returns a list of dictionaries, one dictionary for each – For inputs, the value could alternatively quantity. Each dictionary has the following keys — with be a list of tuples (tj, uj), i.e., values being strings, too. [(t1, u1) , (t2, u2) ,..., (tN , uN )] where the (t , u ) • Changeable — value ’true’ or ’false’, input varies linearly between j j and (t , u ) t ≤ t • Description — the string used in Modelica to j+1 j+1 , where j j+1, and where describe the quantity, e.g. ’Mass in tank, kg’, at most two subsequent time indices tj, tj+1 • Name — the name of the quantity, e.g. ’T’, can have the same value. As an example, ’der(T)’, ’n[1]’, ’mod1.T’, etc., [..., (1,10), (1,20), ...] describes • Value — the value of the quantity, e.g. ’None’, 9The reason why a dictionary with every name as key and time series ’5.0’, etc., as values is not returned, is that the amount of data would be exhaustive. Figure 2. Functional diagram of tank with influent and effluent flow.

Table I PARAMETERSFORDRIVENTANKWITHCONSTANTCROSSSECTIONAL AREA.

Parameter Value Unit Comment ρ 1 kg /L Density of liquid A 5 dm2 Constant cross sectional area Figure 1. Driven water tank, with externally available quantities framed K 5 kg / s Valve constant hO 3 dm Level scaling in red: initial mass is emptied through bottom at rate m˙ e, while at the same time water enters the tank at rate m˙ i.

Water with initial mass m (0) is emptied by gravity a perfect jump in input value from value 10 to through a hole in the bottom at effluent mass flow rate value 20 at time instance 1. m˙ e, while at the same time water is filled into the tank at – This type of sequence of input arguments influent mass flow rate m˙ i. does not work for certain quantity names, Our modeling objective is to find the liquid level h. e.g. ’der(T)’, ’n[1]’, ’mod1.T’, because This objective is illustrated by the functional diagram in Python does not allow for label names der(T), Fig. 2. The functional diagram depicts the causality of n[1], mod1.T, etc. the system (“Tank with influent and effluent mass flow”), • setXXXs(**D), with D being a dictionary with where inputs (green arrow) cause a change in the system quantity names as keywords and values as described and is observed at outputs (orange arrow)11. Here, the with the alternative input argument K. input variable is the influent mass flow rate m˙ i, while the 4) Operating on Python object: simulation, optimiza- output variable is the quantity we are interested in, h. tion: The following methods operate on the object, and B. Model summary have no input arguments. The methods have no return values, instead the results are stored within the object. The model can be summarized in a form suitable for implementation in Modelica as • simulate() — simulates the system with the given simulation options dm =m ˙ i − m˙ e • optimize() — optimizes the Optimica problem dt with the given optimization options m = ρV To retrieve the results, method getSolutions() is V = Ah r used as described previously. h 10 5) Operating on Python object: linearization : The m˙ e = K . hO following methods are proposed for linearization: To complete the model description, we need to specify • linearize() — with no input argument, returns model parameters and operating conditions. Model param- a tuple of 2D numpy arrays (matrices) A, B, C and eters (constants) are given in Table I. D. The operating conditions are given in Table II. • getLinearInputs() — with no input argument, returns a list of strings of names of inputs used when C. Modelica encoding of model forming matrices B and D. The Modelica code describes the core model of the tank, • getLinearOutputs() — with no input argu- ModWaterTank, and consists of a first section where ment, returns a list of strings of names of outputs used when forming matrices C and D. 11Although Modelica is an acausal modeling language, it is useful to • getLinearStates() — with no input argument, think in terms of causality during model development. returns a list of strings of names of states used when forming matrices A, B, C and D. Table II OPERATING CONDITION FOR DRIVEN TANK WITH CONSTANT CROSS III.USEOF API FOR MODEL ANALYSIS SECTIONALAREA. A. Case study: simple tank filled with liquid Quantity Value Unit Comment We consider the tank in Fig. 1 filled with water. h (0) 1.5 dm Initial level m (0) ρh (0) A kg Initial mass 10This part of the API is not completed at the moment, and may m˙ i (t) 2 kg / s Nominal influent mass flow rate; change. may be varied constants and variables are specified, and a second section (algebraic variables), V and md_e.12 where the model equations are specified. One input variable is defined — md_i — this is the influent mass flow rate m˙ i, see Table II. Inputs are model ModWaterTank characterized by that their values are not specified in // Main driven water tank model model the core model — here ModWaterTank. Instead, // author: Bernt Lie their values must be given in an external model/code — // University College of we will specify this input in Python. Finally, 1 output is // Southeast Norway given — h. // April 18, 2016 In the second section of model ModWaterTank, the // Model equations exactly map the mathematical model // Parameters given in Section III-B. constant Real rho = 1 "Density"; For illustrative purposes, the core model parameter Real A = 5 "Tank area"; ModWaterTank is wrapped within a package named parameter Real K = 5 "Valve const"; WaterTank and stored in file WaterTank.mo, parameter Real h_max = 3 "Scaling"; // Initial state parameters package WaterTank parameter Real h_0 = 1.5 // Package for simulating "Init.level"; // driven water tank parameter Real m_0 = rho*h_0*A // author: Bernt Lie "Init.mass"; // University College of // Declaring variables // Southeast Norway // -- states // April 18, 2016 Real m(start = m_0, fixed = true) // "Mass in tank, kg"; model ModWaterTank // -- auxiliary variables // Main driven water tank model Real V "Tank liquid volume, L"; // .... Real md_e "Effluent mass flow"; .... // -- input variables end ModWaterTank; input Real md_i "Influent mass // End package flow"; end WaterTank; // -- output variables D. Use of Python API output Real h "Tank liquid level, First, the following Python statements are executed — dm"; we did this in Jupyter notebook. // Equations constituting the model equation from OMPython import ModelicaSystem // Differential equation import numpy as np der(m) = md_i - md_e; import numpy.random as nr // Algebraic equations %matplotlib inline m = rho*V; import matplotlib.pyplot as plt V = A*h; import pandas as pd md_e = K*sqrt(h/h_max); LW = 2 end ModWaterTank; Here, we use NumPy to handle simulation results, As seen from the first section of model etc. The random number package will be used in ModWaterTank, the model has 4 essential parameters a sensitivity/Monte Carlo study. The magic function (rho-h_max) of which one is a Modelica constant %matplotlib inline is used to embed Matplotlib (rho) while other 3 are design parameters, compare this plots within the Jupyter notebook; to save these plots into to Table I. Furthermore, the model contains 2 “initial files, simply right-click the plots. However, more options state” parameters, where 1 of them can be chosen at for saving files are available if the magic function is liberty, h_0, while the other one, m_0, is computed excluded, and instead command plt.show() is added automatically from h_0, see Table II. The purpose of after the plot commands have been completed. Pandas the “free parameter” h_0 is that it is easier for the are used to illustrate presenting data in tables in Jupyter user to specify level than mass. Also, free “initial state” notebook. Finally, label LW is used to give a conform line parameters makes it possible for the user to change the width in plots. ModWaterTank initial states from outside of model , E. Basic simulation of model e.g., from Python. We instantiate object tank with the following com- Next, one variable is given with initial value — the mand: state m — is initialized with the “initial state” parameter m_0. Then, 2 variables are defined as auxiliary variables 12md is notation for m with a dot, m˙ , i.e., a mass flow rate. Figure 3. Typesetting of Data Frame of quantity list in Jupyter notebook.

Figure 4. Tank level when starting from steady state, and m˙ i (t) varies tank = ModelicaSystem(’WaterTank.mo’, in a straight line between the points (tj , m˙ i (tj )) given by the list ’WaterTank.ModWaterTank’) [(0, 3), (2, 3), (2, 4), (6, 4), (6, 2), (10, 2)]. whereupon Python/Jupyter notebook responds that the OMC Server is up and running the file. Next, we are To this end, we want to simulate the system for a long interested in which quantities are available in the model. time, until the level reaches steady state. Possible inputs In the sequel, Python prompt >>> is used when Jupyter are: notebook actually uses In[*] — where * is some num- ber, while the response in Jupyter notebook is prepended >>> tank.getInputs() with Out[*]. {’md_i’: None} >>> q = tank.getQuantities() where value None implies that the available input, md_i, >>> type(q) has yet not been set. We could use None as input, list which will be interpreted as zero. But let us instead set >>> len(q) m˙ i = 3, simulate for a long time, and change “initial state” 11 parameter h (0) to the steady state value of h: >>> q[0] {’Changeable’: ’true’, >>> tank.setInputs(md_i=3) ’Description’: ’Mass in tank, kg’, >>> tank.setSimulationOptions\ ’Name’: ’m’, (stopTime=1e4, stepSize=10) ’Value’: None, >>> tank.simulate() ’Variability’: ’continuous’} >>> h = tank.getSolutions(’h’) >>> pd.DataFrame(q) >>> tank.setParameters(h_0 = h[-1])

The last command leads Jupyter notebook to typeset a Next, we set back to stop time to 10, and specify an tabular presentation of the quantities, Fig. 3. The results input sequence with a couple of jumps: in Fig. 3 should be compared to the Modelica model in Section III-C. Observe that Modelica constants are not >>> tank.setSimulationOptions\ included in the quantity list. (stopTime=10, stepSize=0.02) Next, we check the simulation options: >>> tank.setInputs(md_i = [(0,3),(2,3), (2,4),(6,4),(6,2),(10,2)]) >>> tank.getSimulationOptions() {’solver’: ’dassl’, Finally, we simulate the model with the time varying input, ’startTime’: 0.0, and plot the result: ’stepSize’: 0.002, ’stopTime’: 1.0, >>> tank.simulate() ’tolerance’: 1e-06} >>> tm, h = tank.getSolutions(’time’,\ ’h’) It should be observed that the stepSize is the fre- >>> plt.plot(tm,h,linewidth=LW, quency at which solutions are stored, and is not the step color=’blue’, label=r’$h$’) size of the solver. The number of data points stored, is >>> plt.title(’Water tank level’) thus (stopTime-startTime)/stepSize with due >>> plt.xlabel(r’time $t$ [s]’) rounding. This means that if we increase the stopTime to >>> plt.ylabel(r’$h$ [dm]’) a large number, we should also increase the stepSize to avoid storing a large number of information. The result is displayed in Fig. 4. Tank level sensitivity REFERENCES 1.8 h [1] Bajracharya, S. (2016). Enhanced OpenModelica Python

1.6 Interface. MSc thesis, Department of Computer and Infor- mation Science, Linkoping¨ University, Sweden.

1.4 [2] Brenan, K.E., Campbell, S.L., Petzold, L.R. (1987). Nu- merical Solution of Initial-Value Problems in Differential- 1.2 Algebraic Equations, 2nd edition. SIAM, Philadelphia. [dm] h

1.0 [3] Fritzson, P. (2014). Principles of Object-Oriented Modeling and Simulation with Modelica 3.3: A Cyber-Physical Ap- proach, second edition. Wiley-IEEE Press, Piscataway, NJ. 0.8 ISBN 978-1-118-85912-4.

0.6 0 2 4 6 8 10 [4] Fritzson, P., Aronsson, P., Pop, A., Lundvall, H., Nystrom,¨ time t [s] K., Saldamli, L., Broman, D., Sandholm, A. (2006). “Open- Modelica – A Free Open-Source Environment for System Modeling, Simulation, and Teaching”. Proceedings of the Figure 5. Uncertainty in tank level with a 5% uncertainty in valve constant K. The input is like in Fig. 4. 2006 IEEE Conference on Computer Aided Control System Design, Munich, Germany, October 4–6, 2006.

[5] Ganeson, A.K. (2012). Design and Implementation of a F. Parameter sensitivity/Monte Carlo simulation User Friendly OpenModelica - Python interface. Master’s Thesis, Department of Computer and Information Sci- It is of interest to study how the model behavior varies ence, Linkoping¨ University. Reg Nr: LIU-IDA/LITH-EX- with varying uncertain parameter values, e.g. the effluent A12/037SE . valve constant K. This can be done as follows: [6] Ganeson, A.K., Fritzson, F., Rogovchenko, O., Asghar, A., >>> par = tank.getParameters() Sjolund,¨ M., Pfeiffer, A. (2012). “An OpenModelica Python >>> K = par[’K’] Interface and its use in PySimulator ”. Proceedings of the 9th >>> KK = K + (nr.randn(10)-0.5) K/20 International Modelica Conference, September 3-5, 2012, * Munich, Germany. DOI 10.3384/ecp12076537. >>> tank.simulate() >>> tm, h = tank.getSolutions(’time’,\ [7] Perera, M. Anushka S., Lie, B., and Pfeiffer, C.F. (2015). ’h’) “Structural Observability Analysis of Large Scale Systems >>> plt.plot(tm,h,linewidth = LW, Using Modelica and Python”. Modeling, Identification and color = ’red’, label=r’$h$’) Control, Vol 36, No 1, pp. 53–65. >>> for k in KK: [8] Perera, M. Anushka S., Hauge, T.A., and Pfeiffer, C.F. tank.setParameters(K=k); (2015). “Parameter and State Estimation of Large-Scale tank.simulate() Complex Systems Using Python Tools”. Modeling, Identi- tm, h = tank.getSolutions\ fication and Control, Vol 36, No 3, pp. 189–198. (’time’,’h’) [9] Pfeiffer, A., Hellerer, M., Hartweg, S., Otter, M., and Reiner, plt.plot(tm,h,linewidth=LW, M. (2012). “PySimulator – A Simulation and Analysis Envi- color=’red’,linestyle=\ ronment in Python with Plugin Infrastructure”. Proceedings ’dotted’,label=’_nolabel_’) of the 9th International Modelica Conference, September 3- >>> plt.title(’Tank level sensitivity’) 5, 2012, Munich, Germany. DOI 10.3384/ecp12076523. >>> plt.xlabel(r’time $t$ [s]’) >>> plt.ylabel(r’$h$ [dm]’) >>> plt.legend() The result is as shown in Fig. 5.

IV. DISCUSSIONANDCONCLUSIONS This paper introduces some ongoing work on extend- ing OpenModelica with a Python API, so that Modelica models can be run and analyzed from within Python. The new Python API is briefly described, and the use of this API is then illustrated by simulating a very simple model of a water tank. Future work will include further testing, e.g., with optimization, extending the API so that it works on more platforms, and extending the API to include analytic model linearization.