Refactor operators
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.
Notes:
- 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)
, whereu
andv
are grid functions;
-
-
ForwardOperatorInterface : public BilinearFormInterface
, additionally allowing for-
apply(u, range_vector)
, reading a grid functionu
and writing into arange_vector
(plus convenience methods forDiscreteFunction
and the like); and
-
-
OperatorInterface : public ForwardOperatorInterface
, additionally allowing for-
apply(source_vector, range_vector)
, reading asource_vector
and writing into arange_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 aMatrixOperator
given a matrix or a discrete source space and - the
ForwardOperator
can be converted to anOperator
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