Rheolef
7.2
an efficient C++ finite element environment
|
form expressions: concept and class hierarchy
This page explains the design of the class hierarchy used for the representation of form
expressions and how they fit together. Casual users probably need not concern themselves with these details, but it may be useful for both advanced users and Rheolef's developers.
Expressions involving forms are computed in a lazy way: nothing is done until a conversion to the form
class is explicitly required. Recall that form
are represented by distributed sparse matrix. This approach allows many memory and computing time optimizations. Moreover, it enable new features, such as matrix inversion on the fly during assembly process when matrix are block diagonal at the element level. Such a feature is heavily used by hybrid discontinuous Galerkin and HHO methods. In these cases, complex expressions are evaluated in only one loop instead of several ones with temporary variables. Note that matrix-matrix products cannot be assembled efficiently in a lazy way, since the sparsity pattern is expected to change: in these cases, temporaries are used.
The efficient lazy implementation is obtained by using the expression template technique in C++. In consequence, if a
is a form
, then, for instance, -a
and lambda*a
, where lambda
is a scalar, are no longer a form
but a form expression. It leads to represent at compile time an expression tree by a hierarchy of classes. Each class represent a node of the expression tree while leaves, also called terminals, are the field themselves.
Any class representing an expression node tree derives from the form_lazy_base
and is called here a form_lazy
: it is represented by a C++ concept. Since concepts in C++ would be available only with the forthcoming 2020 standard, these concepts are actually represented by traits in Rheolef.
The form_lazy
concept is defined by:
form_lazy: form | integrate (opt_domain form_test opts) | +- form_lazy | constant * form_lazy | form_lazy / constant | form_lazy +- form_lazy | form_lazy * form_lazy | trans (form_lazy) | inv (form_lazy) | lump (form_lazy)
The opt_domain
stands for an optional domain specification and opts for an optional integrate_option
variable. Finally, the form_test
concept involved by the integrate
call is defined by:
form_test: field_test * field_trial field_trial * field_test
where field_test
has been defined by field_lazy
and field_trial
is obtained by replacing test
by trial
in the field expression.
The implementation is similar to those of the field_lazy
class hierarchy.