Files
MeanField_SERiF/src/include/serif/discretization/quadrature/backend/order.hpp

125 lines
5.8 KiB
C++

#pragma once
/**
* @file order.hpp
* @author Emily M. Boudreaux
*
* @brief File containing the resolve_operand_order function and related utilities. These are used to determine the static order of an integrator for a given operand or form type.
*/
#include <type_traits>
#include "serif/discretization/functional_space/space.hpp"
#include "serif/discretization/blocks/concepts.hpp"
#include "serif/discretization/forms/operands.hpp"
#include "serif/utils/error/errors.hpp"
namespace serif::discretization::quadrature::backend::mfem {
/**
* @brief A helper struct to extract the functional space traits from a DiscreteFunctionalSpace.
* @tparam FunctionalSpaceT The functional space type to extract traits from.
*/
template <typename FunctionalSpaceT>
struct DiscreteFunctionalSpaceTraits;
/**
* @brief A specialization of the DiscreteFunctionalSpaceTraits struct for a DiscreteFunctionalSpace. This struct is used to extract the functional space traits from a DiscreteFunctionalSpace.
*
* @tparam SpaceV The functional space family.
* @tparam OrderV The order of the functional space.
* @tparam RankV The rank of the functional space.
*
* @todo Could we remove this?
*/
template <auto SpaceV, auto OrderV, auto RankV>
struct DiscreteFunctionalSpaceTraits<functional_space::DiscreteFunctionalSpace<SpaceV, OrderV, RankV>> final {
static constexpr auto space = SpaceV; ///< The functional space family.
static constexpr auto order = static_cast<int>(OrderV); ///< The order of the functional space.
static constexpr std::size_t rank = static_cast<std::size_t>(RankV); ///< The rank of the functional space.
};
/**
* @brief A helper alias to extract the functional space traits from a DiscreteFunctionalSpace.
* @tparam FunctionalSpaceT The functional space type to extract traits from.
*/
template <blocks::HasFunctionalSpace TermT>
using FunctionalSpaceTraits = DiscreteFunctionalSpaceTraits<typename TermT::FunctionalSpace>;
/**
* @brief A function to resolve the static order of an MFEM integrator for a given operand type.
*
* @tparam OperandT The operand type to resolve the static order for.
*
* @return The static order of the MFEM integrator for the given operand type.
*
* @todo We already have some of this information in the form_traits file, we should probably extract the order boost from there.
*/
template <forms::IsOperand OperandT>
[[nodiscard]] consteval int resolve_operand_order() noexcept {
using Operand = std::remove_cvref_t<OperandT>;
using Term = Operand::term_type;
using Operation = Operand::operation_type;
if constexpr (!blocks::HasFunctionalSpace<Term>) {
static_assert(std::same_as<Operation, forms::Operation::Value>, "Non-Spatial terms only support the value operation at the moment.");
return 0;
} else {
using Space = FunctionalSpaceTraits<Term>;
constexpr auto family = Space::space.family;
constexpr int order = Space::order;
if constexpr (std::same_as<Operation, forms::Operation::Value>) {
if constexpr (family == functional_space::Family::hdiv) {
return order + 1;
} else {
return order;
}
} else if constexpr (std::same_as<Operation, forms::Operation::Gradient>) {
static_assert(family == functional_space::Family::h1, "Only H1 spaces support the gradient operation at the moment.");
return order > 0 ? order - 1 : 0;
} else if constexpr (std::same_as<Operation, forms::Operation::Divergence>) {
static_assert(Space::rank == 1 && (family == functional_space::Family::hdiv || family == functional_space::Family::h1), "Divergence requires a vector H1 or H(div) term.");
if constexpr (family == functional_space::Family::hdiv) {
return order;
} else {
return order > 0 ? order - 1 : 0;
}
} else if constexpr (std::same_as<Operation, forms::Operation::Curl>) {
static_assert(family == functional_space::Family::hcurl, "Only H(curl) spaces support the curl operation at the moment.");
return order > 0 ? order - 1 : 0;
} else if constexpr (std::same_as<Operation, forms::Operation::NormalTrace>) {
static_assert(family == functional_space::Family::hdiv, "Only H(div) spaces support the normal trace operation at the moment.");
return order;
} else {
static_assert(false, "Unsupported operation type. This indicates that an operation was used which is not currently registered in the operand configuration system. If you are a developer and you are seeing this error, please register your operation in the resolve_operand_order function in discretization/quadrature/detail.hpp. If you are a user and you are seeing this error, please report it to the SERiF developers.");
return 0;
}
}
}
/**
* @brief Sums the dynamic orders in a span of integers.
* @param dynamic_orders The span of dynamic orders to sum.
* @return The sum of the dynamic orders.
*/
[[nodiscard]] inline int sum_dynamic_orders(const std::span<const int> dynamic_orders) {
int total = 0;
for (const int order : dynamic_orders) {
if (order < 0) {
utils::errors::serif_error<std::invalid_argument, utils::errors::SERiFErrorCode::INVALID_QUADRATURE_ORDER>("Dynamic quadrature order cannot be negative. Received {}.", order);
}
total += order;
}
return total;
}
}