Skip to content

Add more complete SolverUtils bindings to NekPy

Dave Moxey requested to merge dmoxey/nektar:feature/python-solverutils into master

Issue/feature addressed

This MR adds a more complete set of bindings for the SolverUtils library, allowing users to write Python-side solvers via subclasses to EquationSystem and UnsteadySystem. There are some other improvements:

  • Fix a memory leak in Array<OneD, ...>
  • Add support for automatic conversion for more complex types based on the 1D array class, particularly Array<OneD, Array<OneD, NekDouble>> and Array<OneD, std::shared_ptr<T>>
  • SessionReader now includes some additional bindings for useful functions like GetVariables

Implementation

The implementation is reasonably involved. The main additions are as follows.

NekFactory

There is more generic support for NekFactory, which should make binding future factory-pattern based classes easier/with less boilerplate. This will be backported to some of the other classes (e.g. modules within NekMesh/FieldConvert) in a future MR. The pattern used is

#include <SolverUtils/Python/EquationSystem.h>

void export_EquationSystem()
{
    static NekFactory_Register<EquationSystemFactory> fac(
        GetEquationSystemFactory());

    py::class_<EqSysWrap, std::shared_ptr<EqSysWrap>, boost::noncopyable>(
        // in this case we assume equationsystem classes will have constructors
        // rather than specify a specific creator function
        "EquationSystem", py::init<LibUtilities::SessionReaderSharedPtr,
                                   SpatialDomains::MeshGraphSharedPtr>())

        // usual stuff here for wrapping member functions...

        
        // Factory functions.
        .def("Create", &EquationSystem_Create)
        .staticmethod("Create")
        .def("Register", [](std::string const &filterName,
                            py::object &obj) { fac(filterName, obj); })
        .staticmethod("Create");
}

SharedArray

To facilitate more complex types, constructors have been templated based on std::enable_if_t and SFINAE patterns. For example:

template <typename T> struct OneDArrayToPython
{
    static PyObject *convert(Array<OneD, T> const &arr)
    {
        return convert_impl(arr);
    }

    template <typename U                                       = T,
              std::enable_if_t<std::is_arithmetic<U>::value> * = nullptr>
    static PyObject *convert_impl(Array<OneD, U> const &arr)
    {
        // converter for normal floating-point and integral types
    }

    template <typename U                                     = T,
              std::enable_if_t<is_shared_ptr<U>::value ||
                               is_nekarray_oned<U>::value> * = nullptr>
    {
        // converter for array and std::shared_ptr types
    }

Tests

Unit tests have been added for EquationSystem and two demos supplied to show the use of bindings for UnsteadySystem and EquationSystem.

Suggested reviewers

Please suggest any people who would be appropriate to review your code.

Notes

Please add any other information that could be useful for reviewers.

Checklist

  • Functions and classes, or changes to them, are documented.
  • [ ] User guide/documentation is updated.
  • Changelog is updated.
  • Suitable tests added for new functionality.
  • Contributed code is correctly formatted. (See the contributing guidelines).
  • License added to any new files.
  • No extraneous files have been added (e.g. compiler output or test data files).
Edited by Dave Moxey

Merge request reports