125 lines
5.8 KiB
C++
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;
|
|
}
|
|
}
|
|
|