OperatorΒΆ

The Operator class represents a term in an equation and can be instantiated with different value types. An Operator is either explicit, implicit or temporal, and can be scalable by an additional coefficient, for example a scalar value or a further field. The Operator implementation uses Type Erasure (more details [1] [2] [3]) to achieve polymorphism without inheritance. Consequently, the class needs only to implement the interface which is used in the DSL and which is shown in the below example:

Example:
NeoFOAM::dsl::Operator<NeoFOAM::scalar> divTerm =
    Divergence(NeoFOAM::dsl::Operator<NeoFOAM::scalar>::Type::Explicit, exec, ...);

NeoFOAM::dsl::Operator<NeoFOAM::scalar> ddtTerm =
    TimeTerm(NeoFOAM::dsl::Operator<NeoFOAM::scalar>::Type::Temporal, exec, ..);

To fit the specification of the Expression (storage in a vector), the Operator needs to be able to be scaled:

NeoFOAM::Field<NeoFOAM::scalar> scalingField(exec, nCells, 2.0);
auto sF = scalingField.span();

dsl::Operator<NeoFOAM::scalar> customTerm =
    CustomTerm(dsl::Operator<NeoFOAM::scalar>::Type::Explicit, exec, nCells, 1.0);

auto constantScaledTerm = 2.0 * customTerm; // A constant scaling factor of 2 for the term.
auto fieldScaledTerm = scalingField * customTerm; // scalingField is used to scale the term.

// Operator also supports a similar syntax as OpenFOAM
auto multiScaledTerm = (scale + scale + scale + scale) * customTerm;

// Operator also supports the use of a lambda as scaling function to reduce the number of temporaries generated
auto lambdaScaledTerm =
    (KOKKOS_LAMBDA(const NeoFOAM::size_t i) { return sF[i] + sF[i] + sF[i]  + sF[i]; }) * customTerm;
To add a user-defined Operator, a new derived class must be created, inheriting from OperatorMixin,

and provide the definitions of the below virtual functions that are required for the Operator interface:

  • build: build the term

  • explicitOperation: perform the explicit operation

  • implicitOperation: perform the implicit operation

  • getType: get the type of the term

  • exec: get the executor

  • volumeField: get the volume field

An example can be found in test/dsl/operator.cpp.

The required scaling of the term is handled by the Coeff type which can be retrieved by the getCoefficient function of Operator.