Skip to content

Refactor operators

Tobias Leibner requested to merge refactor-operators into master

Remaining todos:

  • update functionals accordingly
  • make all c++ tests pass
  • update Python bindings

This completely rewrites the (global) operators to address several issues we've had over the time. This is the main change I want to have in dune-gdt before we write the paper. Once this is in, we can have a first release of a wheel.


  • the Python bindings are not adapted yet and will not compile, I am first aiming for passing headercheck and C++ tests
  • the current documentation is not up to date, but I do not really don't know where to put it I was playing around with tutorials in Jupyter Notebook using xeus-cling for interactive C++ code and surrounding Markdown cells, which would be my favorite solutions (however, I get lots of segfaults as our code seems to be a bit too much still); doxygen feels clumsy and not-read-by-many to me. I will just start to explain some of the concepts here if it would help the rest of you and we'll see where this ends up, though.
  • I started to adapt @tobiasleibner advection-with-reconstruction operators, but did not try to compile them, all other operators should be working by now

The main changes are:

  • there is a cascade of three interfaces:
    • BilinearFormInterface, allowing for
      • apply2(v, u) and
      • norm(u), where u and v are grid functions;
    • ForwardOperatorInterface : public BilinearFormInterface, additionally allowing for
      • apply(u, range_vector), reading a grid function u and writing into a range_vector (plus convenience methods for DiscreteFunction and the like); and
    • OperatorInterface : public ForwardOperatorInterface, additionally allowing for
      • apply(source_vector, range_vector), reading a source_vector and writing into a range_vector, which then allows for
      • jacobian(...) and
      • apply_inverse(...) all based on vectors, plus the usual convenience methods.

(The main difference between ForwardOperatorInterface and OperatorInterface is, that the former acts on grid functions only and does not require a discrete source space, while the latter requires discrete source space but may additionally implement apply for grid functions.)

For each of the three interfaces there is exactly one default class

  • BilinearForm, allowing to += local element/intersection bilinear forms
  • ForwardOperator, allowing to += local element and intersection operators
  • Operator, allowing to += local element and intersection operators

which then implements the rest of the respective interface (including jacobian and apply_inverse using dampened newton). Each of the three are appendable to the GridWalker, given all additional required information.

Each more general class allows to be converted to a more specific one given additional information, e.g.

  • the BilinearForm can be converted to a MatrixOperator given a matrix or a discrete source space and
  • the ForwardOperator can be converted to an Operator given a discrete source space.

Thus, there is now only one well-defined place where things happen. I.e., to assemble a bilinear form into a matrix, one cannot append the local bilinear forms to the MatrixOperator, but creates the BilinearForm first and then converts this to a MatrixOperator. In particular, one can still use the defined bilinear form as a product for arbitrary functions.

Some examples:

  • products can be easily built from bilinear forms as usual
  • all bilinear forms and forward operators can now be applied to everything a GridFunction can handle, see use of norms
  • an IPDG bilinear form assembled into a matrix (not the most elegant way of bilinear form to matrix conversion for efficient test code though)
  • arbitrary nonlinear operators can be built by appending local operators as usual
Edited by Dr. Felix Tobias Schindler

Merge request reports