DUECA/DUSIME
|
Since March 2018, DUECA has been extended with the option to use Python as a scripting language for defining this DUECA set-up (dueca_cnf.py) and the DUECA simulation or model (dueca_mod.py). In addition to scripting your configuration, you can also use python from a running simulation. Of course, there are limitations, since the python code might not run strictly real-time. However, parts with less stringent timing constraints, like a plot of some of your signals, can now be programmed in Python.
To read the dueca_cnf.py and dueca_mod.py scripts, DUECA starts a Python interpreter from C++. Before that interpreter can be started, all C++ classes and functions that can be created or called from Python are exposed to the interpreter in an initialization cycle. This cycle adds the dueca
namespace and all relevant classes. User defined modules can also use the interpreter to run pieces of Python code, and can offer classes and interfaces to be run in the initialization phase.
Modules in DUECA are all of type "Module" internally. They are created based on the name of the module, and Python actually does not differentiate between different "Module" objects, they all look the same to Python. We need to be able to expose some module data to the python script, and for that we need to explain to python that our module has a certain accessible data class. The DUECA interface to Python is based on boost::python, so we need the boost:python headers. In the example we also use boost::python::numpy, this is also added to the includes. Modify your header file to include:
In this example we will expose a few arrays as numpy arrays to Python. To keep things flexible, we will put the numpy arrays in a Python dictionary (dict). Let's assume your new module is called "MyModule". Then we declare this python dictionary (on the C++ side) as a publicly accessible member of the MyModule class. In your class declaration, include something like:
The MyModule instances are created in the normal fashion. However, we will explain to Python that the MyModule class exists, and that it has a data member called "data", which we will link to the data_dict we defined above.
A bit of python glue code is needed to expose the module class to Python, here is an example, put it somewhere in your MyModule.cxx file:
This glue code explains to the Python scripting that there is a MyModule class, and that it has a "data" member. The AddInitFunction object ensures that the start function is available to the python interpreter; after the start of the interpreter startfunc will be called.
The next step is some code to show the module instance itself to Python. To do that, we make a Python object that wraps the C++ object, and then – from the C++ side – add that object to the Python workspace. This can be done in the Module::complete() method of your module:
Don't forget that we used the fixed name "mymodule" here. In a real implementation, it would be better to make the python variable name configurable (check ParameterTable).
Now we can interact with the Python script, knowing that Python now has an object "mymodule" in its namespace, that refers to this module. You can access the mymodule.data dictionary, and read the "time" and "sine" vectors in there.
There are several options for letting python run, one option would be to define a python-side function, find it in the main namespace, and call it. The simplest option is to just define and run a piece of python script, for example in your doCalculation method:
This prints the data dictionary of the newly created module, using the python-side print function.