3.5. Contributing code
3.5.1. Structure of the package
The functionality of the
pde package is split into multiple sub-package.
The domain, together with its symmetries, periodicities, and discretizations, is
described by classes defined in
Discretized fields are represented by classes in
fields, which have
methods for differential operators with various boundary conditions collected
The actual pdes are collected in
pdes and the respective solvers
are defined in
3.5.2. Extending functionality
All code is build on a modular basis, making it easy to introduce new classes
that integrate with the rest of the package. For instance, it is simple to
define a new partial differential equation by subclassing
Alternatively, PDEs can be defined by specifying their evolution rates using
mathematical expressions by creating instances of the class
Moreover, new grids can be introduced by subclassing
It is also possible to only use parts of the package, e.g., the discretized
differential operators from
New operators can be associated with grids by registering them using
For instance, to create a new operator for the cylindrical grid one needs to
define a factory function that creates the operator. This factory function takes
an instance of
Boundaries as an argument and
returns a function that takes as an argument the actual data array for the grid.
Note that the grid itself is an attribute of
This operator would be registered with the grid by calling
CylindricalSymGrid.register_operator("operator", make_operator), where the
first argument is the name of the operator and the second argument is the
3.5.3. Design choices
The data layout of field classes (subclasses of
FieldBase) was chosen to allow for a simple
decomposition of different fields and tensor components. Consequently, the data
is laid out in memory such that spatial indices are last. For instance, the data
of a vector field
field defined on a 2d Cartesian grid will have three
dimensions and can be accessed as
field.data[vector_component, x, y],
vector_component is either 0 or 1.
3.5.4. Coding style
The coding style is enforced using isort
and black. Moreover, we use Google Style docstrings,
which might be best learned by example.
The documentation, including the docstrings, are written using reStructuredText, with examples in the
To ensure the integrity of the code, we also try to provide many test functions,
which are typically contained in separate modules in sub-packages called
These tests can be ran using scripts in the
tests subfolder in the root
This folder also contain a script
tests_types.sh, which uses
to check the consistency of the python type annotations.
We use these type annotations for additional documentation and they have also
already been useful for finding some bugs.
We also have some conventions that should make the package more consistent and
thus easier to use. For instance, we try to use
properties instead of getter
and setter methods as often as possible.
Because we use a lot of
numba just-in-time compilation to speed up computations,
we need to pass around (compiled) functions regularly. The names of the methods
and functions that make such functions, i.e. that return callables, should start
with ‘make_*’ where the wildcard should describe the purpose of the function
3.5.5. Running unit tests
pde package contains several unit tests, typically contained in
tests in the folder of a given module. These tests ensure that
basic functions work as expected, in particular when code is changed in future
versions. To run all tests, there are a few convenience scripts in the root
tests. The most basic script is
pytest to run the tests in the sub-modules of the
package. Clearly, the python package
pytest needs to be installed. There
are also additional scripts that for instance run tests in parallel (need the
pytest-xdist installed), measure test coverage (need
pytest-cov installed), and make simple performance measurements.
Moreover, there is a script
test_types.sh, which uses
check the consistency of the python type annotations and there is a script
format_code.sh, which formats the code automatically to adhere to our style.
Before committing a change to the code repository, it is good practice to run the tests, check the type annotations, and the coding style with the scripts described above.