diff --git a/src/include/serif/discretization/forms/operands.hpp b/src/include/serif/discretization/forms/operands.hpp index 305bea23..ed4f559d 100644 --- a/src/include/serif/discretization/forms/operands.hpp +++ b/src/include/serif/discretization/forms/operands.hpp @@ -45,6 +45,7 @@ namespace serif::discretization::forms { std::same_as, Operation::Curl> || std::same_as, Operation::NormalTrace>; + /** * @brief Compile time representation of some operand. An operand associates a term to an operation type (e.g. the gradient of gravitational potential where * gravitational potential is the term and gradient is the operation). @@ -52,45 +53,61 @@ namespace serif::discretization::forms { * @tparam OperationT The operation to associate to that term, must be one of the operations from @ref Operation (enforced by satisfying @ref IsOperation). * * @note An operand does not know how to do anything. Like a lot of the other parts of SERiF at this level this is compile time metadata which allows - * the compiler to select the correct overloads, without runtime overhead, in order to run the correct computations. Do not be fooled into thinking + * the compiler to select the correct overloads, without runtime dispatch overhead, in order to run the correct computations. Do not be fooled into thinking * that this actually has any computations buried within it. * - * As I say in teh note this is a compile time representation of some metadata; however, because of that it may + * As I say in the note this is a compile time representation of some metadata; however, because of that it may * be challenging for a new developer to track where exactly this is used. Broadly this system is used so that a developer - * can inform the backend how to integrate point-wise contributions. Consider some scalar field \f$\lambda\f$ over the stellar domain which - * describes local point-wise residual contributions. A weak residual can be computed a number of ways; however, the most natural might be - * something like + * can inform the backend how to evaluate physical inputs and integrate point-wise contributions. + * + * When used as the test operand of a Contribution, the operation applies to the test function. When used in a contribution's + * Operands list, it applies to a physical input field whose evaluated value is supplied to evaluate(). + * + * Consider some scalar field \f$\lambda\f$ over the stellar domain which describes local point-wise residual contributions. + * A weak residual can be computed a number of ways; however, the most natural might be something like * * \f[ - * \int_{\Omega_{\text{stellar}}} q \lambda dV \approx \sum_{i=1}^{N} q_i \lambda_i w_i + * R_i = \int_{\Omega_{\text{stellar}}} q_i \lambda\,dV + * \approx \sum_{k=1}^{N_q} q_i(x_k)\lambda(x_k)W_k * \f] * - * or for some vector field \f$\mathbf\lambda}\f$ over the stellar domain which describes local point-wise residual contributions + * Here, \f$i\f$ identifies the test function and corresponding residual entry, while \f$k\f$ identifies a quadrature point. + * The weight \f$W_k\f$ includes both the quadrature weight and the geometric volume factor. + * + * Or, for some vector field \f$\boldsymbol{\lambda}\f$ over the stellar domain which describes local point-wise residual contributions, * * \f[ - * \int_{\Omega_{\text{stellar}}} \mathbf{v}\cdot\lambda dV \approx \sum_{i=1}^{N} \mathbf{v}_i\cdot\lambda_i w_i + * R_i = \int_{\Omega_{\text{stellar}}} \mathbf{v}_i\cdot\boldsymbol{\lambda}\,dV + * \approx \sum_{k=1}^{N_q} \mathbf{v}_i(x_k)\cdot\boldsymbol{\lambda}(x_k)W_k * \f] * - * However, there may be some different inner product between the test function and the point-wise residual contribution which emerges from the derivation. Say for - * example you find that really you need the divergence of the test function, e.g. + * However, a different operation on the test function may emerge from the weak-form derivation. Say, for + * example, you find that really you need the divergence of the test function paired with a scalar contribution \f$\lambda\f$, e.g. * * \f[ - * \int_{\Omega_{\text{stellar}}} \left(\nabla\cdot\mathbf{v}\right)\mathbf{\lambda} dV \approx \sum_{i=1}^{N} \left(\nabla\cdot\mathbf{v}_i\right)\cdot\lambda_i w_i + * R_i = \int_{\Omega_{\text{stellar}}} \left(\nabla\cdot\mathbf{v}_i\right)\lambda\,dV + * \approx \sum_{k=1}^{N_q} \left(\nabla\cdot\mathbf{v}_i\right)(x_k)\lambda(x_k)W_k * \f] * * As there are a series of different, though effectively enumerable, options here, we can use a compile time tag to let the backend - * select, at 0 runtime cost, what operation needs to be applied to the test function. + * select, without runtime dispatch overhead, what operation needs to be applied to the test function. Evaluating that operation and + * performing the integration still require numerical work at runtime. * * By default, if you do not specify an operation type (the second template parameter) then the operation type - * will default to @ref Operation::Value, which seems to be the most common case, at least for this class of problems. In addition you may select + * will default to @ref Operation::Value, which seems to be the most common case, at least for this class of problems. + * In addition, the operand vocabulary includes the following tags, whose meanings when applied to test functions are: * - * - @ref Operation::Gradient (\f$\int_{\Omega} \nabla q \cdot \lambda dV\f$) - * - @ref Operation::Divergence (\f$\int_{\Omega} \left(\nabla\cdot\mathbf{v}\right)\mathbf{\lambda} dV\f$) - * - @ref Operation::Curl (\f$\int_{\Omega} \left(\nabla\times\mathbf{v}\right)\cdot\mathbf{\lambda} dV\f$) - * - @ref Operation::NormalTrace (\f$\int_{\partial\Omega} \hat{n}\cdot\mathbf{v}\lambda dS\f$) + * - @ref Operation::Gradient (\f$\int_{\Omega} \nabla q_i \cdot \boldsymbol{\lambda}\,dV\f$) + * - @ref Operation::Divergence (\f$\int_{\Omega} \left(\nabla\cdot\mathbf{v}_i\right)\lambda\,dV\f$) + * - @ref Operation::Curl (\f$\int_{\Omega} \left(\nabla\times\mathbf{v}_i\right)\cdot\boldsymbol{\lambda}\,dV\f$) + * - @ref Operation::NormalTrace (\f$\int_{\partial\Omega} \left(\hat{\mathbf{n}}\cdot\mathbf{v}_i\right)\lambda\,dS\f$) * - * In the equation system you may find documentation for the "contributions" system which makes heavy use of Operations to determine - * what residual blocks to contribute the actual residuals to. + * @note Declaring an operation tag does not itself provide a backend implementation. The current MFEM volume-equation backend supports + * Value and Divergence for its supported field spaces. Gradient, Curl, and NormalTrace require additional backend support; + * NormalTrace also requires an appropriate boundary integration path. + * + * In the equation system you may find documentation for the "contributions" system, which uses the term in the test operand to determine + * which residual block receives the contribution, and its operation to determine how the test function enters the integrand. */ template // We choose to default to the value operation because it is the most common. struct Operand final {