Chrono::PyEngine reference

Chrono::PyEngine is a Python wrapper for Chrono::Engine. It is a set of Python modules that correspond to the main units of Chrono::Engine, as shown in this scheme:

First steps with Python

After the installation, you are ready to use Chrono::PyEngine from Python. To begin:

  • start your editor, for example PyScripter.
  • create a new blank Python script file, for example ''

Now you can type Python programs in this new Python file, execute it, save it on disk, etc.

Let's see a first program.

  • First of all, you should use the import keyword to specify which Python modules must be load and used in your program. Most of the core functionalities of Chrono::Engine are in a module called pychrono, hence write:
1 import pychrono as chrono

Note that the as chrono is optional: but if you avoid it you must call all Chrono::Engine functions using the syntax pychrono.ChClassFoo..., whereas if you use as chrono you simply rename the namespace just like the C++ equivalent: chrono.ChClassFoo...

  • Let's create a 3D vector object:
1 my_vect1 = chrono.ChVectorD()

(Note that all PyChrono::Engine classes are prefixed by the chrono word).

  • Modify the properties of that vector object; this is done using the **.** dot operator:
1 my_vect1.x=5
2 my_vect1.y=2
3 my_vect1.z=3
  • Some classes have build parameters, for example anothe vector can be built by passing the 3 coordinates for quick initialization:
1 my_vect2 = chrono.ChVectorD(3,4,5)
  • Most operator-overloading features that are available in C++ for the Chrono::Engine vectors and matrices are also available in Python, for example:
1 my_vect4 = my_vect1*10 + my_vect2
  • Member functions of an object can be called simply using the **.** dot operator, just like in C++:
1 my_len = my_vect4.Length()
2 print ('vector length =', my_len)
  • You can use most of the classes that you would use in C++, for example let's play with quaternions and matrices:
1 my_quat = chrono.ChQuaternionD(1,2,3,4)
2 my_qconjugate = ~my_quat
3 print ('quat. conjugate =', my_qconjugate)
4 print ('quat. dot product=', my_qconjugate ^ my_quat)
5 print ('quat. product=', my_qconjugate % my_quat)
6 ma = chrono.ChMatrixDynamicD(4,4)
7 ma.FillDiag(-2)
8 mb = chrono.ChMatrixDynamicD(4,4)
9 mb.FillElem(10)
10 mc = (ma-mb)*0.1; # operator overloading of +,-,* is supported
11 print (mc);
12 mr = chrono.ChMatrix33D()
13 mr.FillDiag(20)
14 print (mr*my_vect1);
  • If you want to know the list of methods and/or properties that are available in a class, you can simply use the code completion feature of PyScripter: for example once you type chrono. you will see a pop-up window with a list of available classes, constants, etc.
Learn additional lessons by reading the PyChrono::Engine tutorials.
Most classes behave like their C++ counterparts, so you are invited to look at the C++ API documentation to understand their features.
There are also few but important differences between C++ and Python that are worth mentioning, so read also the following section!

Differences between Python and C++

Not all the functionalities of the C++ API can be mapped 1:1 to the Python API, of course. Python is an interpreted language that differs from C++ for many reasons, so there are some differences and limitations, but also advantages. If you already used the C++ API of Chrono::Engine, you will find that this documentation is useful for easily jumping into the PyChrono::Engine development.

Object creation

In C++ you can create objects in two ways: on the stack and on the heap (the latter is used for dynamic allocation). For example, respectively, this is object creation in C++ language

chrono::ChSystem my_system; // on stack, or..
chrono::ChSystem* my_system_pointer = new chrono::ChSystem(); // on heap

In the second case, in C++ you must remember to deallocate the object with delete (my_system_pointer) soon or later. In Python, object creation is always done in a single way: objectname = namespace.classname() , and it does not require that you remember to delete an object, because the lifetime of an object is automatically managed by Python. So object creation in Python is simply:

1 my_vect = chrono.ChSystem()

Note that the = operator in Python does not mean copy (except for simple types such as integers, floats, etc.) but means assign, so for example

1 my_systemA = chrono.ChSystem()
2 my_systemB = my_systemA # assign another handle to the same system
3 my_systemA.SetTol(2)
4 print (my_systemB.GetTol())

will output 2, because you created a single ChSystem object, with two handles pointing to it.

Templated classes

Currently there is no support for templated clases in Python. On the other side, there are some templated classes in the C++ API of Chrono::Engine, expecially for vectors, matrices, etc., because in C++ you might want to create vectors of floats, or doubles, or integers, etc. by using the <> syntax, as:

ChVector<float> my_vect; // vector of floats
ChVector<double> my_vect; // vector of double precision floats
ChVector<int> my_vect; // vector of integers
ChVector<> my_vect; // default: as ChVector<double>
ChQuaternion<float> my_vect; // quaternion of floats
ChQuaternion<double> my_vect; // quaternion of double precision floats
... // etc.

In PyChrono::Engine, we simply decided to support only the <double> templated versions, that are used most of the times. Templated classes are renamed by appending a D at the end (to remember that they represent the <double> templated versions). In detail, this is a list of the Python classes that are equivalent to C++ templated classes:

1 chrono.ChVectorD # as ChVector<double> in c++
2 chrono.ChQuaternionD # as ChQuaternion<double> in c++
3 chrono.ChMatrix33D # as ChMatrix33<double> in c++
4 chrono.ChMatrixNMD # as ChMatrixNM<double> in c++
5 chrono.ChMatrixDynamicD # as ChMatrixDynamic<double> in c++
6 chrono.ChMatrixD # as ChMatrix<double> in c++
7 chrono.ChFrameD # as ChFrame<double> in c++
8 chrono.ChFrameMovingD # as ChFrameMoving<double> in c++
9 chrono.ChCoordsysD # as ChCoordsys<double> in c++

There is a (quite limited) support for templates of templates, especially for the std::vector<> container. The concept is the same: the C++ template is translated in a special name in Python. For std::vector, we prepend the vector_ prefix:

1 chrono.vector_ChVectorD # as std::vector<ChVector<double>> in c++

ChVector x y z members

In C++ you access the x y z components of a 3D vector using the functions x() y() z(), that return a reference to the components. To avoid some issues, we drop the () parentheses and we mapped these functions to direct access to x y z class members in Python, so:

my_vector.x() = 123;
double sum = my_vector.y() + my_vector.z();


1 chrono.ChVectorD my_vector
2 my_vector.x = 123
3 sum = my_vector.y + my_vector.z

A similar concept is applied for quaternions components e0 e1 e2 e3, eg. one uses myquaternion.e0 in Python, instead of myquaternion.e0() in C++.

Shared pointers

Except for vectors, matrices, etc., most of the complex objects that you create with the Chrono::Engine API are managed via C++ shared pointers. This is the case of ChBody parts, ChLink constraints, etc. Shared pointers are a C++ technology that allows the user to create objects and do not worry about deletion, because deletion is managed automatically. In the Chrono::Engine C++ API such shared pointers are based on templates; as we said previously templates are not supported in Python, but this is not an issue, because Chrono::PyEngine automatically handle objects with shared pointers if necessary PyChrono::Engine.

This is an example of **shared pointers in C++** :

std::shared_ptr<ChLinkLockRevolute> my_link_BC(new ChLinkLockRevolute);

This is the equivalent syntax in Python :

1 my_link_BC = chrono.ChLinkLockRevolute()
When you create a shared pointer object in PyChrono::Engine, also the referenced object is created. For instance, in the last example, a revolute joint is created at the same line. If you need other shared pointers to the same object, simply type my_link_other = my_link_BC etc.

Downcasting and upcasting


Upcasting of derived classes to the base class works automatically in Python and does not require intervention. We managed to do this also for shared pointers. For example ChSystem.Add() requires a (shared)pointer to a ChPhysicsItem object, that is a base class, but you can pass it a ChBody, a ChLinkGears, etc. that are derived classes. The same in Python.


A bigger problem is the downcasting of base classes to derived classes. That is, if a function returns a pointer to a base class, how to understand that a specific returned object belongs to a derived class? At the time of writing, an automatic downcasting is performed only for classes inherited from ChFunction and ChAsset. Otherwise, one has to perform manual downcasting using the CastToXXXYYYZZZ() helper functions; this is a bit similar to the dynamic_cast<derived>(base) method in C++. Currently such casting functions are provided for almost all shared pointers. Use this in Python as in the following example:

1 myvis = chrono.CastToChVisualizationShared(myasset)
2 print ('Could be cast to visualization object?', !myvis.IsNull())

Not supported classes

We managed to map in Python most of the C++ classes of common interest, but maybe that there are still some classes or functions that are not yet mapped to Python. This can be understood in the following way. Functions that are correctly mapped will return objects whose type is echoed in the interpreter window as:

1 my_system.Get_G_acc()
2 <pychrono.ChVectorD;
3 proxy of <Swig Object of type 'chrono::ChVector< double > *' at 0x03EDCEA8> >

A function that is not yet mapped, for instance ChSystem.GetSystemDescriptor(), will give a shorter echo, that represents the type information for a pointer to an object that is unusable in Python:

1 my_system.GetSystemDescriptor()
2 <Swig Object of type 'chrono::ChSystemDescriptor *' at 0x03EDD800>
As the development of PyChrono::Engine proceeds, the latter case will happen less an less frequently. Tell us if you encounter this type of problem in some function, so we can fix it.

Demos and examples

You can find examples of use in these tutorials