[forms] Make caching infrastructure more flexible and allow caching of sub-expressions
So far caching was only available for evaluation of test and trial functions and we only supported using the same bases for both. This MR makes the caching infrastructure much more general by providing a flexible mechanism for registering (custom) caches.
We now create one global CacheManager
and pass it to the composed operator defing
the variational form which forwards it to all sub-expressions.
Each subexpression may now register its own cache in the manager.
This has several consequences:
- The interaction of operators and caches is now much easier to understand.
- Composed operators can register their own caches for intermediate values. So far this is only implemented for the shape functions (as before) and bound unary operators (new). But the new approach is easily extendable.
- All caches are shared across multiple instances using unique ids. E.g. coefficient functions now automatically reuse the shape function cache of the test and trial basis if possible and the same coefficient is evaluated only once, even if it shows up multiple times in the form
- As a byproduct we should now automatically get support for different test- and trial-basis and for caching of bases in coefficients not related to the test and trial bases.
- When different bases (each with its own cache) are involved, they
will share the
LocalView
. In contrast a bound operator (aka discrete grid function) had to maintain its ownLocalView
so far. - Storage for caches with custom type is implemented using type-erasure, which has no negative performance impact here.
- In applications with many coefficients given by FE functions this may improve performance significantly (e.g. Navier-Stokes with variable density).
This also unifies the interface of operators with different arity which allows for subsequent cleanup and simplification with less special cases.