feat(quadrature): quadrature system brought over
Ported and dramatically cleaned up the quadrature system. This includes centralizing all field definitions
This commit is contained in:
@@ -1 +1,65 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "serif/discretization/blocks/fields.hpp"
|
||||
|
||||
namespace serif::discretization::blocks {
|
||||
template <typename FieldCandidate>
|
||||
concept Field = std::derived_from<FieldCandidate, field>;
|
||||
|
||||
template <typename T>
|
||||
concept Term = std::derived_from<std::remove_cvref_t<T>, term_base> && // a term must derive from term_base
|
||||
requires {typename std::remove_cvref_t<T>::field_type;} && // a term must have a field_type member
|
||||
Field<typename std::remove_cvref_t<T>::field_type>; // That field type member must be a valid field
|
||||
|
||||
template <typename T>
|
||||
concept HasFunctionalSpace =
|
||||
Term<T> &&
|
||||
requires {
|
||||
typename std::remove_cvref_t<T>::FunctionalSpace;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept HasSupport =
|
||||
Term<T> &&
|
||||
requires {
|
||||
typename std::remove_cvref_t<T>::Support;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept HasQuantity =
|
||||
Term<T> &&
|
||||
requires {
|
||||
typename std::remove_cvref_t<T>::Quantity;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept HasValueBlock =
|
||||
Term<T> &&
|
||||
requires {
|
||||
typename std::remove_cvref_t<T>::value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept HasResidualBlock =
|
||||
Term<T> &&
|
||||
requires {
|
||||
typename std::remove_cvref_t<T>::residual;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept SpatialTerm =
|
||||
Term<T> &&
|
||||
HasFunctionalSpace<T> &&
|
||||
HasSupport<T>;
|
||||
|
||||
template <typename T>
|
||||
concept PhysicalSpatialTerm =
|
||||
SpatialTerm<T> &&
|
||||
HasQuantity<T>;
|
||||
|
||||
template <typename T>
|
||||
struct IsSpatialTerm : std::bool_constant<SpatialTerm<T>> {};
|
||||
|
||||
template <typename T>
|
||||
struct IsPhysicalSpatialTerm : std::bool_constant<PhysicalSpatialTerm<T>> {};
|
||||
}
|
||||
@@ -1,65 +1,130 @@
|
||||
#pragma once
|
||||
#include <string_view>
|
||||
|
||||
#include "base.hpp"
|
||||
#include "serif/dimensions/dimensions.hpp"
|
||||
#include "serif/discretization/blocks/base.hpp"
|
||||
#include "serif/discretization/functional_space/space.hpp"
|
||||
#include "serif/discretization/domain/concepts.hpp"
|
||||
#include "serif/discretization/domain/physical_domains.hpp"
|
||||
#include "serif/utils/types/type_list.hpp"
|
||||
|
||||
#include "serif/meta/names.hpp"
|
||||
|
||||
namespace serif::discretization::blocks {
|
||||
struct field {};
|
||||
struct term {};
|
||||
struct term_base {};
|
||||
|
||||
template <typename FieldT>
|
||||
struct term : term_base {
|
||||
using field_type = FieldT;
|
||||
};
|
||||
|
||||
struct density final : field {
|
||||
struct mass final : term {
|
||||
static constexpr std::string_view name = meta::type_name<density>();
|
||||
|
||||
struct mass final : term<density> { // Note the reading here is mass density (that is this is not in reference to the common FEM usage of mass as a term in a weak form)
|
||||
static constexpr std::string_view name = meta::type_name<mass>();
|
||||
|
||||
using FunctionalSpace = functional_space::DiscreteFunctionalSpace<functional_space::L2, 2, 0>; // second order scalar L2 space
|
||||
using Support = domain::StellarDomains;
|
||||
using Quantity = dimensions::Density;
|
||||
static constexpr std::string_view symbol = "ρ";
|
||||
|
||||
struct value final : value_block_base {};
|
||||
struct residual final : residual_block_base {};
|
||||
};
|
||||
static inline constexpr mass mass_density_term{};
|
||||
|
||||
static inline constexpr mass mass_term{};
|
||||
using Terms = utils::types::TypeList<mass>;
|
||||
};
|
||||
|
||||
struct displacement final : field {
|
||||
struct geometry final : term {
|
||||
static constexpr std::string_view name = meta::type_name<displacement>();
|
||||
|
||||
struct vector final : term<displacement> { // Similarly this is the displacement vector
|
||||
static constexpr std::string_view name = meta::type_name<vector>();
|
||||
|
||||
using FunctionalSpace = functional_space::DiscreteFunctionalSpace<functional_space::H1, 3, 1>; // third order vector H1 space
|
||||
using Support = domain::AllDomains;
|
||||
using Quantity = dimensions::Length;
|
||||
static constexpr std::string_view symbol = "d";
|
||||
|
||||
struct value final : value_block_base {};
|
||||
struct residual final : residual_block_base {};
|
||||
};
|
||||
static inline constexpr vector vector_term{};
|
||||
|
||||
static inline constexpr geometry geometry_term{};
|
||||
using Terms = utils::types::TypeList<vector>;
|
||||
};
|
||||
|
||||
struct surface_deformation final : field {
|
||||
struct parameters final : term {
|
||||
struct surface_deformation final : field { // Surface deformation is a more general field that the others, it is not pointwise defined over the domain. Use concepts to constrain this as a non spatial field.
|
||||
static constexpr std::string_view name = meta::type_name<surface_deformation>();
|
||||
|
||||
struct coefficients final : term<surface_deformation> {
|
||||
static constexpr std::string_view name = meta::type_name<coefficients>();
|
||||
|
||||
struct value final : value_block_base {};
|
||||
};
|
||||
|
||||
struct shape_equilibrium final : term {
|
||||
struct shape_equilibrium final : term<surface_deformation> {
|
||||
static constexpr std::string_view name = meta::type_name<shape_equilibrium>();
|
||||
|
||||
struct residual final : residual_block_base {};
|
||||
};
|
||||
|
||||
static inline constexpr parameters parameters_term{};
|
||||
static inline constexpr coefficients coefficients_term{};
|
||||
static inline constexpr shape_equilibrium shape_equilibrium_term{};
|
||||
|
||||
using Terms = utils::types::TypeList<coefficients, shape_equilibrium>;
|
||||
};
|
||||
|
||||
struct gravity final : field {
|
||||
struct gradient final : term {
|
||||
static constexpr std::string_view name = meta::type_name<gravity>();
|
||||
|
||||
struct gradient final : term<gravity> {
|
||||
static constexpr std::string_view name = meta::type_name<gradient>();
|
||||
|
||||
using FunctionalSpace = functional_space::DiscreteFunctionalSpace<functional_space::Hdiv, 2, 1>;
|
||||
using Support = domain::AllDomains;
|
||||
using Quantity = dimensions::Acceleration;
|
||||
static constexpr std::string_view symbol = "∇φ";
|
||||
|
||||
struct value final : value_block_base {};
|
||||
struct residual final : residual_block_base {};
|
||||
};
|
||||
|
||||
struct potential final : term {
|
||||
struct potential final : term<gravity> {
|
||||
static constexpr std::string_view name = meta::type_name<potential>();
|
||||
|
||||
using FunctionalSpace = functional_space::DiscreteFunctionalSpace<functional_space::L2, 2, 0>;
|
||||
using Support = domain::AllDomains;
|
||||
using Quantity = dimensions::GravitationalPotential;
|
||||
static constexpr std::string_view symbol = "φ";
|
||||
|
||||
struct value final : value_block_base {};
|
||||
struct residual final : residual_block_base {};
|
||||
};
|
||||
|
||||
static inline constexpr potential potential_term{};
|
||||
static inline constexpr gradient gradient_term{};
|
||||
|
||||
using Terms = utils::types::TypeList<potential, gradient>;
|
||||
};
|
||||
|
||||
struct enthalpy final : field {
|
||||
struct specific final : term {
|
||||
static constexpr std::string_view name = meta::type_name<enthalpy>();
|
||||
|
||||
struct specific final : term<enthalpy> {
|
||||
static constexpr std::string_view name = meta::type_name<specific>();
|
||||
|
||||
using FunctionalSpace = functional_space::DiscreteFunctionalSpace<functional_space::H1, 3, 0>;
|
||||
using Support = domain::StellarDomains;
|
||||
using Quantity = dimensions::SpecificEnthalpy;
|
||||
static constexpr std::string_view symbol = "h";
|
||||
|
||||
struct value final : value_block_base { };
|
||||
struct residual final : residual_block_base { };
|
||||
};
|
||||
|
||||
static inline constexpr specific specific_term{};
|
||||
};
|
||||
|
||||
using Terms = utils::types::TypeList<specific>;
|
||||
};
|
||||
}
|
||||
|
||||
43
src/include/serif/discretization/blocks/runtime.hpp
Normal file
43
src/include/serif/discretization/blocks/runtime.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include <string_view>
|
||||
#include "serif/discretization/blocks/concepts.hpp"
|
||||
|
||||
namespace serif::discretization::blocks {
|
||||
struct FieldDescriptor final {
|
||||
std::string_view name;
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator==(const FieldDescriptor&, const FieldDescriptor&) noexcept = default;
|
||||
};
|
||||
|
||||
struct TermDescriptor final {
|
||||
FieldDescriptor field;
|
||||
std::string_view name;
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator==(const TermDescriptor&, const TermDescriptor&) noexcept = default;
|
||||
};
|
||||
|
||||
template <Field FieldT>
|
||||
inline constexpr FieldDescriptor field_descriptor{.name = FieldT::name};
|
||||
|
||||
template <Term TermT>
|
||||
inline constexpr TermDescriptor term_descriptor{
|
||||
.field = field_descriptor<typename TermT::field_type>,
|
||||
.name = TermT::name
|
||||
};
|
||||
}
|
||||
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::blocks::FieldDescriptor> : std::formatter<std::string_view> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::blocks::FieldDescriptor& fd, FormatContext& ctx) const {
|
||||
return std::formatter<std::string_view>::format(fd.name, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::blocks::TermDescriptor> : std::formatter<std::string> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::blocks::TermDescriptor& td, FormatContext& ctx) const {
|
||||
return std::formatter<std::string>::format(std::format("TermDescriptor(field={}, name={})", td.field, td.name), ctx);
|
||||
}
|
||||
};
|
||||
@@ -1 +1,32 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "serif/discretization/blocks/concepts.hpp"
|
||||
|
||||
namespace serif::discretization::blocks {
|
||||
template <Term TermT>
|
||||
using FieldOf = std::remove_cvref_t<TermT>::field_type;
|
||||
|
||||
template <HasFunctionalSpace TermT>
|
||||
using FunctionalSpaceOf = std::remove_cvref_t<TermT>::FunctionalSpace;
|
||||
|
||||
template <HasSupport TermT>
|
||||
using SupportOf = std::remove_cvref_t<TermT>::Support;
|
||||
|
||||
template <HasQuantity TermT>
|
||||
using QuantityOf = std::remove_cvref_t<TermT>::Quantity;
|
||||
|
||||
template <typename FieldT>
|
||||
using TermsOf = FieldT::Terms;
|
||||
|
||||
template <SpatialTerm TermT>
|
||||
struct SpatialTermTraits {
|
||||
using FunctionalSpace = TermT::FunctionalSpace;
|
||||
using Support = TermT::Support;
|
||||
|
||||
static constexpr auto family = FunctionalSpace::functionalSpace.family;
|
||||
static constexpr int order = FunctionalSpace::order;
|
||||
static constexpr std::size_t rank = FunctionalSpace::rank;
|
||||
};
|
||||
}
|
||||
@@ -1,6 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <string_view>
|
||||
#include <span>
|
||||
#include <array>
|
||||
#include <format>
|
||||
#include <numeric>
|
||||
|
||||
#include "serif/discretization/domain/types.hpp"
|
||||
#include "serif/utils/misc/std_helper/cleaning.hpp"
|
||||
@@ -17,10 +22,33 @@ namespace serif::discretization::domain {
|
||||
concept IsBoundary = AIsBaseClassOfB<T, Boundary>;
|
||||
|
||||
// A DomainSet is several volumes treated as one. StellarDomains
|
||||
// (core + envelope) is the motivating example.
|
||||
// (core + envelope) is a motivating example.
|
||||
template <IsDomain... DomainTs>
|
||||
struct DomainSet {
|
||||
static constexpr std::size_t count = CountVariadicArguments<DomainTs...>();
|
||||
|
||||
static inline const std::array<std::string_view, count> names{
|
||||
DomainTs::name...
|
||||
};
|
||||
};
|
||||
|
||||
// Do not make the constructors of this class explicit. We want to be able to pass a single domain or a domain set to functions that take a DomainOrSet.
|
||||
class DomainOrSet final {
|
||||
public:
|
||||
template <IsDomain DomainT>
|
||||
// ReSharper disable once CppNonExplicitConvertingConstructor
|
||||
constexpr DomainOrSet(DomainT) noexcept : m_domains(&DomainT::name, 1) {}
|
||||
|
||||
template <IsDomain... DomainTs>
|
||||
// ReSharper disable once CppNonExplicitConvertingConstructor
|
||||
constexpr DomainOrSet(DomainSet<DomainTs...>) noexcept : m_domains(DomainSet<DomainTs...>::names) {}
|
||||
|
||||
[[nodiscard]] constexpr std::span<const std::string_view> domains() const noexcept {
|
||||
return m_domains;
|
||||
}
|
||||
|
||||
private:
|
||||
std::span<const std::string_view> m_domains;
|
||||
};
|
||||
|
||||
template <IsBoundary... BoundaryTs>
|
||||
@@ -53,3 +81,25 @@ namespace serif::discretization::domain {
|
||||
template <typename BoundaryT, typename BoundaryIDT>
|
||||
concept BoundaryIsIdentifiedBy = utils::misc::std_helper::SameType<BoundaryT, typename BoundaryIDT::boundary_type>;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::domain::DomainOrSet> : std::formatter<std::string_view> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::domain::DomainOrSet& dos, FormatContext& ctx) const {
|
||||
auto join = [&](std::span<const std::string_view> strings, std::string_view delimiter) {
|
||||
return std::accumulate(
|
||||
strings.begin(),
|
||||
strings.end(),
|
||||
std::string{},
|
||||
[delimiter](std::string acc, std::string_view s) {
|
||||
if (!acc.empty()) {
|
||||
acc += delimiter;
|
||||
}
|
||||
acc += s;
|
||||
return acc;
|
||||
}
|
||||
);
|
||||
};
|
||||
return std::formatter<std::string_view>::format(std::format("DomainOrSet(domains=[{}])", join(dos.domains(), ", ")), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
10
src/include/serif/discretization/forms/concept.hpp
Normal file
10
src/include/serif/discretization/forms/concept.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include "serif/discretization/forms/forms.hpp"
|
||||
|
||||
namespace serif::discretization::forms {
|
||||
template <typename FormCandidate>
|
||||
concept Form = std::derived_from<std::remove_cvref_t<FormCandidate>, form> && // A form must derive from form
|
||||
requires {
|
||||
typename std::remove_cvref_t<FormCandidate>::operand_types; // a form must define a type list of operand types for the trial and test terms
|
||||
}; // We could consider strengthening this to enforce that the type list (operand_types) contains only operand types and that there is an entry for TrialT and TestT
|
||||
}
|
||||
48
src/include/serif/discretization/forms/form_traits.hpp
Normal file
48
src/include/serif/discretization/forms/form_traits.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "serif/discretization/forms/concept.hpp"
|
||||
#include "serif/discretization/forms/forms.hpp"
|
||||
|
||||
namespace serif::discretization::forms {
|
||||
template <Form FormT>
|
||||
struct FormTraits {
|
||||
static constexpr int trial_order_reduction = 0;
|
||||
static constexpr int test_order_reduction = 0;
|
||||
};
|
||||
|
||||
template <blocks::Term TrialT, blocks::Term TestT>
|
||||
struct FormTraits<mass<TrialT, TestT>> {
|
||||
static constexpr int trial_order_reduction = 0;
|
||||
static constexpr int test_order_reduction = 0;
|
||||
};
|
||||
|
||||
template <blocks::Term TrialT, blocks::Term TestT>
|
||||
struct FormTraits<divergence<TrialT, TestT>> {
|
||||
static constexpr int trial_order_reduction = 1;
|
||||
static constexpr int test_order_reduction = 0;
|
||||
};
|
||||
|
||||
template <blocks::Term TrialT, blocks::Term TestT>
|
||||
struct FormTraits<source<TrialT, TestT>> {
|
||||
static constexpr int trial_order_reduction = 0;
|
||||
static constexpr int test_order_reduction = 0;
|
||||
};
|
||||
|
||||
template <blocks::Term TrialT, blocks::Term TestT>
|
||||
struct FormTraits<force<TrialT, TestT>> {
|
||||
static constexpr int trial_order_reduction = 0;
|
||||
static constexpr int test_order_reduction = 0;
|
||||
};
|
||||
|
||||
template <blocks::Term TrialT, blocks::Term TestT>
|
||||
struct FormTraits<boundary_flux<TrialT, TestT>> {
|
||||
static constexpr int trial_order_reduction = 0;
|
||||
static constexpr int test_order_reduction = 0;
|
||||
};
|
||||
|
||||
template <blocks::Term TrialT, blocks::Term TestT>
|
||||
struct FormTraits<projection<TrialT, TestT>> {
|
||||
static constexpr int trial_order_reduction = 0;
|
||||
static constexpr int test_order_reduction = 0;
|
||||
};
|
||||
}
|
||||
73
src/include/serif/discretization/forms/forms.hpp
Normal file
73
src/include/serif/discretization/forms/forms.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
|
||||
#include "serif/discretization/blocks/concepts.hpp"
|
||||
#include "serif/discretization/forms/operands.hpp"
|
||||
#include "serif/utils/types/type_list.hpp"
|
||||
#include "serif/meta/names.hpp"
|
||||
|
||||
namespace serif::discretization::forms {
|
||||
struct form {};
|
||||
|
||||
template <blocks::Term TrialT, blocks::Term TestT>
|
||||
struct mass final : form {
|
||||
static constexpr std::string_view name = meta::template_name<mass>();
|
||||
|
||||
using trial_type = TrialT;
|
||||
using test_type = TestT;
|
||||
|
||||
using operand_types = utils::types::TypeList<Operand<TrialT>, Operand<TestT>>;
|
||||
};
|
||||
|
||||
template <blocks::Term TrialT, blocks::Term TestT>
|
||||
struct divergence final : form {
|
||||
static constexpr std::string_view name = meta::template_name<divergence>();
|
||||
|
||||
using trial_type = TrialT;
|
||||
using test_type = TestT;
|
||||
|
||||
using operand_types = utils::types::TypeList<Operand<TrialT, Operation::Divergence>, Operand<TestT>>;
|
||||
};
|
||||
|
||||
template <blocks::Term TrialT, blocks::Term TestT>
|
||||
struct source final : form {
|
||||
static constexpr std::string_view name = meta::template_name<source>();
|
||||
|
||||
using trial_type = TrialT;
|
||||
using test_type = TestT;
|
||||
|
||||
using operand_types = utils::types::TypeList<Operand<TrialT>, Operand<TestT>>;
|
||||
};
|
||||
|
||||
template <blocks::Term TrialT, blocks::Term TestT>
|
||||
struct force final : form {
|
||||
static constexpr std::string_view name = meta::template_name<force>();
|
||||
|
||||
using trial_type = TrialT;
|
||||
using test_type = TestT;
|
||||
|
||||
using operand_types = utils::types::TypeList<Operand<TrialT>, Operand<TestT>>;
|
||||
};
|
||||
|
||||
template <blocks::Term TrialT, blocks::Term TestT>
|
||||
struct boundary_flux final : form {
|
||||
static constexpr std::string_view name = meta::template_name<boundary_flux>();
|
||||
|
||||
using trial_type = TrialT;
|
||||
using test_type = TestT;
|
||||
|
||||
using operand_types = utils::types::TypeList<Operand<TrialT, Operation::NormalTrace>, Operand<TestT, Operation::NormalTrace>>;
|
||||
};
|
||||
|
||||
template <blocks::Term TrialT, blocks::Term TestT>
|
||||
struct projection final : form {
|
||||
static constexpr std::string_view name = meta::template_name<projection>();
|
||||
|
||||
using trial_type = TrialT;
|
||||
using test_type = TestT;
|
||||
|
||||
using operand_types = utils::types::TypeList<Operand<TrialT>, Operand<TestT>>;
|
||||
};
|
||||
}
|
||||
38
src/include/serif/discretization/forms/operands.hpp
Normal file
38
src/include/serif/discretization/forms/operands.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
|
||||
#include "serif/discretization/blocks/concepts.hpp"
|
||||
|
||||
namespace serif::discretization::forms {
|
||||
struct Operation {
|
||||
struct Value {};
|
||||
struct Gradient {};
|
||||
struct Divergence {};
|
||||
struct Curl {};
|
||||
struct NormalTrace {};
|
||||
};
|
||||
|
||||
template <typename OperationCandidate>
|
||||
concept IsOperation =
|
||||
std::same_as<std::remove_cvref_t<OperationCandidate>, Operation::Value> ||
|
||||
std::same_as<std::remove_cvref_t<OperationCandidate>, Operation::Gradient> ||
|
||||
std::same_as<std::remove_cvref_t<OperationCandidate>, Operation::Divergence> ||
|
||||
std::same_as<std::remove_cvref_t<OperationCandidate>, Operation::Curl> ||
|
||||
std::same_as<std::remove_cvref_t<OperationCandidate>, Operation::NormalTrace>;
|
||||
|
||||
template <blocks::Term TermT, IsOperation OperationT = Operation::Value> // We choose to default to the value operation because it is the most common.
|
||||
struct Operand final {
|
||||
using term_type = TermT;
|
||||
using operation_type = OperationT;
|
||||
};
|
||||
|
||||
template <typename OperandCandidate>
|
||||
concept IsOperand = requires { // Recall that requires expressions are not evaluated. What this checks is that it is valid syntax given the type to requires the term type and operation type. It does not check that the term type is a valid term or that the operation type is a valid operation.
|
||||
typename std::remove_cvref_t<OperandCandidate>::term_type;
|
||||
typename std::remove_cvref_t<OperandCandidate>::operation_type; } &&
|
||||
blocks::Term<typename std::remove_cvref_t<OperandCandidate>::term_type> && // Then here, now that we know we can safely ask for the term type we validate it is actually a valid term
|
||||
IsOperation<typename std::remove_cvref_t<OperandCandidate>::operation_type>; // And here we validate that the operation type is actually a valid operation
|
||||
|
||||
};
|
||||
34
src/include/serif/discretization/forms/runtime.hpp
Normal file
34
src/include/serif/discretization/forms/runtime.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include <format>
|
||||
|
||||
#include "serif/discretization/blocks/runtime.hpp"
|
||||
#include "serif/discretization/forms/concept.hpp"
|
||||
|
||||
namespace serif::discretization::forms {
|
||||
struct FormDescriptor final {
|
||||
std::string_view name;
|
||||
|
||||
blocks::TermDescriptor trial;
|
||||
blocks::TermDescriptor test;
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator==(const FormDescriptor&, const FormDescriptor&) noexcept = default;
|
||||
};
|
||||
|
||||
template <Form FormT>
|
||||
inline constexpr FormDescriptor form_descriptor{
|
||||
.name = FormT::name,
|
||||
.trial = blocks::term_descriptor<typename FormT::trial_type>,
|
||||
.test = blocks::term_descriptor<typename FormT::test_type>
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::forms::FormDescriptor> : std::formatter<std::string> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::forms::FormDescriptor& fd, FormatContext& ctx) const {
|
||||
return std::formatter<std::string>::format(std::format("FormDescriptor(name={}, trial={}, test={})", fd.name, fd.trial, fd.test), ctx);
|
||||
}
|
||||
};
|
||||
167
src/include/serif/discretization/functional_space/space.hpp
Normal file
167
src/include/serif/discretization/functional_space/space.hpp
Normal file
@@ -0,0 +1,167 @@
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
#include <format>
|
||||
|
||||
#include "serif/meta/enums.hpp"
|
||||
|
||||
namespace serif::discretization::functional_space {
|
||||
template <std::size_t R>
|
||||
struct Rank {
|
||||
constexpr static std::size_t value = R;
|
||||
};
|
||||
|
||||
enum class Family {
|
||||
l2,
|
||||
h1,
|
||||
hdiv,
|
||||
hcurl
|
||||
};
|
||||
|
||||
inline static auto Family2StringMap = meta::enum_to_enum_string_map<Family>();
|
||||
inline static auto String2FamilyMap = meta::enum_to_string_enum_map<Family>();
|
||||
|
||||
enum class Continuity {
|
||||
discontinuous,
|
||||
continuous,
|
||||
normal_continuous,
|
||||
tangential_continuous
|
||||
};
|
||||
|
||||
inline static auto Continuity2StringMap = meta::enum_to_enum_string_map<Continuity>();
|
||||
inline static auto String2ContinuityMap = meta::enum_to_string_enum_map<Continuity>();
|
||||
|
||||
enum class Trace {
|
||||
none,
|
||||
value,
|
||||
normal,
|
||||
tangential
|
||||
};
|
||||
|
||||
inline static auto Trace2StringMap = meta::enum_to_enum_string_map<Trace>();
|
||||
inline static auto String2TraceMap = meta::enum_to_string_enum_map<Trace>();
|
||||
|
||||
enum class Mapping {
|
||||
identity,
|
||||
contravariant_piola,
|
||||
covariant_piola
|
||||
};
|
||||
|
||||
inline static auto Mapping2StringMap = meta::enum_to_enum_string_map<Mapping>();
|
||||
inline static auto String2MappingMap = meta::enum_to_string_enum_map<Mapping>();
|
||||
|
||||
struct SpaceDescriptor final {
|
||||
const Family family;
|
||||
const Continuity continuity;
|
||||
const Trace trace;
|
||||
const Mapping mapping;
|
||||
};
|
||||
|
||||
inline static constexpr SpaceDescriptor L2{
|
||||
.family = Family::l2,
|
||||
.continuity = Continuity::discontinuous,
|
||||
.trace = Trace::none,
|
||||
.mapping = Mapping::identity
|
||||
};
|
||||
|
||||
inline static constexpr SpaceDescriptor H1{
|
||||
.family = Family::h1,
|
||||
.continuity = Continuity::continuous,
|
||||
.trace = Trace::value,
|
||||
.mapping = Mapping::identity
|
||||
};
|
||||
|
||||
inline static constexpr SpaceDescriptor Hdiv{
|
||||
.family = Family::hdiv,
|
||||
.continuity = Continuity::normal_continuous,
|
||||
.trace = Trace::normal,
|
||||
.mapping = Mapping::contravariant_piola
|
||||
};
|
||||
|
||||
inline static constexpr SpaceDescriptor Hcurl{
|
||||
.family = Family::hcurl,
|
||||
.continuity = Continuity::tangential_continuous,
|
||||
.trace = Trace::tangential,
|
||||
.mapping = Mapping::covariant_piola
|
||||
};
|
||||
|
||||
template <typename SpaceDescriptorCandidate>
|
||||
concept IsSpaceDescriptor = std::is_same_v<SpaceDescriptor, SpaceDescriptorCandidate>;
|
||||
|
||||
template <SpaceDescriptor Space, int Order, std::size_t R>
|
||||
struct DiscreteFunctionalSpace {
|
||||
static constexpr SpaceDescriptor functional_space = Space;
|
||||
static constexpr int order = Order;
|
||||
using rank = Rank<R>;
|
||||
};
|
||||
}
|
||||
|
||||
template <std::size_t R>
|
||||
struct std::formatter<serif::discretization::functional_space::Rank<R>> : std::formatter<std::string> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::functional_space::Rank<R>& /*rank*/, FormatContext& ctx) const {
|
||||
if (R == 0) {
|
||||
return std::formatter<std::string>::format("Scalar", ctx);
|
||||
} else if (R == 1) {
|
||||
return std::formatter<std::string>::format("Vector", ctx);
|
||||
} else if (R >=2) {
|
||||
return std::formatter<std::string>::format("Rank " + std::to_string(R) + " tensor", ctx);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::functional_space::SpaceDescriptor> : std::formatter<std::string> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::functional_space::SpaceDescriptor& space, FormatContext& ctx) const {
|
||||
return std::formatter<std::string>::format(std::format("SpaceDescriptor(family={}, continuity={}, trace={}, mapping={})",
|
||||
serif::discretization::functional_space::Family2StringMap.at(space.family),
|
||||
serif::discretization::functional_space::Continuity2StringMap.at(space.continuity),
|
||||
serif::discretization::functional_space::Trace2StringMap.at(space.trace),
|
||||
serif::discretization::functional_space::Mapping2StringMap.at(space.mapping)), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
// formatter for DiscreteFunctionalSpace
|
||||
template <serif::discretization::functional_space::SpaceDescriptor Space, int Order, std::size_t R>
|
||||
struct std::formatter<serif::discretization::functional_space::DiscreteFunctionalSpace<Space, Order, R>> : std::formatter<std::string> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::functional_space::DiscreteFunctionalSpace<Space, Order, R>& space, FormatContext& ctx) const {
|
||||
return std::formatter<std::string>::format(std::format("DiscreteFunctionalSpace(functional_space={}, order={}, rank={})",
|
||||
space.functional_space,
|
||||
space.order,
|
||||
space.rank), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
// formatter for each enum
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::functional_space::Family> : std::formatter<std::string> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::functional_space::Family& family, FormatContext& ctx) const {
|
||||
return std::formatter<std::string>::format(serif::discretization::functional_space::Family2StringMap.at(family), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::functional_space::Continuity> : std::formatter<std::string> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::functional_space::Continuity& continuity, FormatContext& ctx) const {
|
||||
return std::formatter<std::string>::format(serif::discretization::functional_space::Continuity2StringMap.at(continuity), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::functional_space::Trace> : std::formatter<std::string> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::functional_space::Trace& trace, FormatContext& ctx) const {
|
||||
return std::formatter<std::string>::format(serif::discretization::functional_space::Trace2StringMap.at(trace), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::functional_space::Mapping> : std::formatter<std::string> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::functional_space::Mapping& mapping, FormatContext& ctx) const {
|
||||
return std::formatter<std::string>::format(serif::discretization::functional_space::Mapping2StringMap.at(mapping), ctx);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "mfem/fem/intrules.hpp"
|
||||
|
||||
namespace serif::discretization::quadrature::backend::mfem {
|
||||
template <typename IntegratorT>
|
||||
concept HasReferenceSetIntegrationRule = requires (IntegratorT &integrator, const ::mfem::IntegrationRule &integration_rule) {
|
||||
integrator.SetIntegrationRule(integration_rule);
|
||||
};
|
||||
|
||||
template <typename IntegratorT>
|
||||
concept HasPointerSetIntegrationRule = requires (IntegratorT &integrator, const ::mfem::IntegrationRule &integration_rule) {
|
||||
integrator.SetIntRule(&integration_rule);
|
||||
};
|
||||
|
||||
template <typename IntegratorT>
|
||||
concept HasSetIntRule = requires (IntegratorT &integrator, const ::mfem::IntegrationRule &integration_rule) {
|
||||
integrator.SetIntRule(integration_rule);
|
||||
};
|
||||
|
||||
template <typename IntegratorT>
|
||||
concept ConfigurableIntegrator = HasReferenceSetIntegrationRule<IntegratorT> ||
|
||||
HasPointerSetIntegrationRule<IntegratorT> ||
|
||||
HasSetIntRule<IntegratorT>;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "mfem/fem/intrules.hpp"
|
||||
|
||||
#include "serif/discretization/quadrature/backend/mfem/concepts.hpp"
|
||||
|
||||
namespace serif::discretization::quadrature::backend::mfem {
|
||||
template <ConfigurableIntegrator IntegratorT>
|
||||
void set_integration_rule(IntegratorT &integrator, const ::mfem::IntegrationRule &integration_rule) {
|
||||
if constexpr (HasReferenceSetIntegrationRule<IntegratorT>) {
|
||||
integrator.SetIntegrationRule(integration_rule);
|
||||
} else if constexpr (HasPointerSetIntegrationRule<IntegratorT>) {
|
||||
integrator.SetIntegrationRule(&integration_rule);
|
||||
} else {
|
||||
integrator.SetIntRule(&integration_rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
#include <span>
|
||||
|
||||
#include "mfem/fem/geom.hpp"
|
||||
#include "mfem/fem/intrules.hpp"
|
||||
|
||||
#include "serif/discretization/blocks/traits.hpp"
|
||||
#include "serif/discretization/quadrature/rules.hpp"
|
||||
|
||||
#include "serif/discretization/quadrature/backend/order.hpp"
|
||||
|
||||
#include "serif/discretization/domain/concepts.hpp"
|
||||
#include "serif/discretization/quadrature/policy.hpp"
|
||||
#include "serif/discretization/quadrature/query.hpp"
|
||||
|
||||
#include "serif/discretization/quadrature/backend/mfem/concepts.hpp"
|
||||
#include "serif/discretization/quadrature/backend/mfem/mfem_static_order.hpp"
|
||||
|
||||
// We may want to consider renaming this file to runtime to stick to convention. The reason
|
||||
// I did not initially is that this is more specific than pure runtime projection of compile
|
||||
// time invariants (which is what most of the other files named runtime.hpp do). Something to think
|
||||
// about
|
||||
|
||||
// Note also that you will see ::mfem throughout. This is an important syntax to use here since MFEM's
|
||||
// code lives in the mfem namespace; however, we also have code living in an mfem namespace.
|
||||
// Outside of translation units that include using namespace serif::discretization::quadrature::backend
|
||||
// and outside of the serif::discretization::quadrature::backend::mfem namespace itself these two things
|
||||
// do not conflict. However, in those two cases there is a degeneracy the compiler cannot
|
||||
// resolve between mfem:: and mfem:: (see what I did there?) Using ::mfem explicitly tells the compiler
|
||||
// that we are looking from the root of the namespace tree not the current namespace. This is important to avoid ambiguity and compiler errors.
|
||||
|
||||
namespace serif::discretization::quadrature::backend::mfem {
|
||||
struct MFEMQuadratureContext final {
|
||||
QuadratureRole role = QuadratureRole::discretization;
|
||||
|
||||
::mfem::Geometry::Type geometry = ::mfem::Geometry::INVALID;
|
||||
int geometry_weight_order = 0;
|
||||
|
||||
std::span<const int> dynamic_orders{};
|
||||
domain::DomainOrSet domain = domain::AllDomains{};
|
||||
|
||||
MappingKind mapping = MappingKind::none;
|
||||
};
|
||||
|
||||
struct MFEMRule final {
|
||||
Resolution resolution;
|
||||
|
||||
const ::mfem::IntegrationRule *integration_rule = nullptr;
|
||||
};
|
||||
|
||||
class MFEMResolver final {
|
||||
public:
|
||||
explicit MFEMResolver (Policy policy) noexcept : m_policy(std::move(policy)) {} // Do we actually want to use move rvalue semantics here?
|
||||
|
||||
template <forms::Form FormT>
|
||||
[[nodiscard]] MFEMRule resolve(const MFEMQuadratureContext& context) const {
|
||||
if (context.geometry_weight_order < 0) {
|
||||
utils::errors::serif_error<std::invalid_argument, utils::errors::SERiFErrorCode::INVALID_QUADRATURE_ORDER>("MFEM geometry weight order must be non-negative. Received an order of {}", context.geometry_weight_order);
|
||||
}
|
||||
|
||||
const int dynamic_order = sum_dynamic_orders(context.dynamic_orders);
|
||||
const int base_order = mfem_form_static_order<FormT> + dynamic_order + context.geometry_weight_order;
|
||||
|
||||
const Query query {
|
||||
.form = forms::form_descriptor<FormT>,
|
||||
.role = context.role,
|
||||
.domain = context.domain,
|
||||
.mapping = context.mapping,
|
||||
.base_order = base_order
|
||||
};
|
||||
|
||||
const Resolution resolution = m_policy.resolve(query);
|
||||
|
||||
const ::mfem::IntegrationRule &integration_rule = ::mfem::IntRules.Get(context.geometry, resolution.order);
|
||||
return MFEMRule{.resolution = resolution, .integration_rule = &integration_rule};
|
||||
}
|
||||
|
||||
template <forms::Form FormT, ConfigurableIntegrator IntegratorT>
|
||||
Resolution configure(IntegratorT &integrator, const MFEMQuadratureContext& context) const {
|
||||
const MFEMRule rule = resolve<FormT>(context);
|
||||
set_integration_rule(integrator, *rule.integration_rule);
|
||||
return rule.resolution;
|
||||
}
|
||||
|
||||
private:
|
||||
Policy m_policy;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "serif/discretization/blocks/concepts.hpp"
|
||||
#include "serif/discretization/forms/operands.hpp"
|
||||
#include "serif/utils/types/type_list.hpp"
|
||||
#include "serif/discretization/quadrature/backend/order.hpp"
|
||||
|
||||
namespace serif::discretization::quadrature::backend::mfem {
|
||||
template <typename OperandListT>
|
||||
struct MFEMOperandListOrder;
|
||||
|
||||
template <forms::IsOperand... OperandTs>
|
||||
struct MFEMOperandListOrder<utils::types::TypeList<OperandTs...>> final {
|
||||
static constexpr int value = (resolve_operand_order<OperandTs>() + ... + 0);
|
||||
};
|
||||
|
||||
template <forms::Form FormT>
|
||||
inline constexpr int mfem_form_static_order = MFEMOperandListOrder<typename FormT::operand_types>::value;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#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 {
|
||||
template <typename FunctionalSpaceT>
|
||||
struct DiscreteFunctionalSpaceTraits;
|
||||
|
||||
template <auto SpaceV, auto OrderV, auto RankV>
|
||||
struct DiscreteFunctionalSpaceTraits<functional_space::DiscreteFunctionalSpace<SpaceV, OrderV, RankV>> final {
|
||||
static constexpr auto space = SpaceV;
|
||||
static constexpr auto order = static_cast<int>(OrderV);
|
||||
static constexpr std::size_t rank = static_cast<std::size_t>(RankV);
|
||||
};
|
||||
|
||||
template <blocks::HasFunctionalSpace TermT>
|
||||
using FunctionalSpaceTraits = DiscreteFunctionalSpaceTraits<typename TermT::FunctionalSpace>;
|
||||
|
||||
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<forms::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(family == functional_space::Family::hdiv, "Only H(div) spaces support the divergence operation at the moment.");
|
||||
|
||||
return order;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[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;
|
||||
}
|
||||
}
|
||||
|
||||
20
src/include/serif/discretization/quadrature/policy.hpp
Normal file
20
src/include/serif/discretization/quadrature/policy.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "serif/discretization/quadrature/query.hpp"
|
||||
#include "serif/discretization/quadrature/rules.hpp"
|
||||
|
||||
namespace serif::discretization::quadrature {
|
||||
class Policy final {
|
||||
public:
|
||||
explicit Policy(RuleSet ruleSet);
|
||||
|
||||
[[nodiscard]] Resolution resolve(const Query &query) const;
|
||||
|
||||
private:
|
||||
[[nodiscard]] static int compute_base_order(const Query &query);
|
||||
[[nodiscard]] const RuleControl &get_role_control(QuadratureRole role) const;
|
||||
|
||||
private:
|
||||
RuleSet m_ruleSet;
|
||||
};
|
||||
}
|
||||
74
src/include/serif/discretization/quadrature/query.hpp
Normal file
74
src/include/serif/discretization/quadrature/query.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include <format>
|
||||
#include <string>
|
||||
|
||||
#include "serif/discretization/quadrature/rules.hpp"
|
||||
#include "serif/discretization/domain/physical_domains.hpp"
|
||||
#include "serif/discretization/forms/form_traits.hpp"
|
||||
#include "serif/discretization/forms/runtime.hpp"
|
||||
|
||||
namespace serif::discretization::quadrature {
|
||||
struct Query final {
|
||||
forms::FormDescriptor form;
|
||||
|
||||
QuadratureRole role = QuadratureRole::discretization;
|
||||
domain::DomainOrSet domain = domain::AllDomains{};
|
||||
MappingKind mapping = MappingKind::none;
|
||||
|
||||
int trial_order = 0;
|
||||
int test_order = 0;
|
||||
int coefficient_order = 0;
|
||||
int geometry_weight_order = 0;
|
||||
int trial_order_reduction = 0;
|
||||
int test_order_reduction = 0;
|
||||
|
||||
std::optional<int> base_order;
|
||||
};
|
||||
|
||||
template <forms::Form FormT>
|
||||
[[nodiscard]] constexpr Query make_query(
|
||||
const QuadratureRole role,
|
||||
const domain::DomainOrSet domain,
|
||||
const MappingKind mapping,
|
||||
const int trialOrder,
|
||||
const int testOrder,
|
||||
const int coefficientOrder,
|
||||
const int geometryWeightOrder,
|
||||
const std::optional<int> baseOrder = std::nullopt
|
||||
) noexcept {
|
||||
return Query{
|
||||
.form = forms::form_descriptor<FormT>,
|
||||
.role = role,
|
||||
.domain = domain,
|
||||
.mapping = mapping,
|
||||
.trial_order = trialOrder,
|
||||
.test_order = testOrder,
|
||||
.coefficient_order = coefficientOrder,
|
||||
.geometry_weight_order = geometryWeightOrder,
|
||||
.trial_order_reduction = forms::FormTraits<FormT>::trial_order_reduction,
|
||||
.test_order_reduction = forms::FormTraits<FormT>::test_order_reduction,
|
||||
.base_order = baseOrder
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::quadrature::Query> : std::formatter<std::string> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::quadrature::Query& q, FormatContext& ctx) const {
|
||||
return std::formatter<std::string>::format(std::format("Query(form={}, role={}, domain={}, mapping={}, trial_order={}, test_order={}, coefficient_order={}, geometry_weight_order={}, trial_order_reduction={}, test_order_reduction={}, base_order={})",
|
||||
q.form,
|
||||
q.role,
|
||||
q.domain,
|
||||
q.mapping,
|
||||
q.trial_order,
|
||||
q.test_order,
|
||||
q.coefficient_order,
|
||||
q.geometry_weight_order,
|
||||
q.trial_order_reduction,
|
||||
q.test_order_reduction,
|
||||
(q.base_order.has_value() ? std::to_string(q.base_order.value()) : "nullopt")
|
||||
), ctx);
|
||||
}
|
||||
};
|
||||
342
src/include/serif/discretization/quadrature/rules.hpp
Normal file
342
src/include/serif/discretization/quadrature/rules.hpp
Normal file
@@ -0,0 +1,342 @@
|
||||
#pragma once
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <format>
|
||||
#include <utility>
|
||||
|
||||
#include "serif/discretization/forms/runtime.hpp"
|
||||
|
||||
namespace serif::discretization::quadrature {
|
||||
enum class QuadratureRole {
|
||||
discretization,
|
||||
preconditioner,
|
||||
diagnostic,
|
||||
projection
|
||||
};
|
||||
|
||||
enum class MappingKind {
|
||||
none,
|
||||
affine,
|
||||
general,
|
||||
kelvin
|
||||
};
|
||||
|
||||
enum class Mode {
|
||||
fast,
|
||||
production,
|
||||
reference,
|
||||
convergence
|
||||
};
|
||||
|
||||
struct RuleControl {
|
||||
std::optional<int> fixed_order;
|
||||
int boost = 0;
|
||||
};
|
||||
|
||||
struct FormRule final {
|
||||
forms::FormDescriptor form;
|
||||
RuleControl control;
|
||||
};
|
||||
|
||||
class RuleSet {
|
||||
public:
|
||||
template <forms::Form FormT>
|
||||
void set_form_control(
|
||||
const RuleControl control
|
||||
) {
|
||||
set_form_control(forms::form_descriptor<FormT>, control);
|
||||
}
|
||||
|
||||
void set_form_control(
|
||||
const forms::FormDescriptor &form,
|
||||
const RuleControl control
|
||||
) {
|
||||
for (auto &[formDescriptor, ruleControl] : m_formRules) {
|
||||
if (formDescriptor == form) {
|
||||
ruleControl = control;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_formRules.push_back(FormRule{.form = form, .control = control});
|
||||
}
|
||||
|
||||
[[nodiscard]] const RuleControl *find_form_control(
|
||||
const forms::FormDescriptor &form
|
||||
) const noexcept {
|
||||
for (const auto &[formDescriptor, ruleControl] : m_formRules) {
|
||||
if (formDescriptor == form) {
|
||||
return &ruleControl;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void set_role_control(
|
||||
const QuadratureRole role,
|
||||
const RuleControl control
|
||||
) noexcept {
|
||||
switch (role) {
|
||||
case QuadratureRole::discretization:
|
||||
m_discretizationControl = control;
|
||||
break;
|
||||
|
||||
case QuadratureRole::preconditioner:
|
||||
m_preconditionerControl = control;
|
||||
break;
|
||||
|
||||
case QuadratureRole::diagnostic:
|
||||
m_diagnosticControl = control;
|
||||
break;
|
||||
|
||||
case QuadratureRole::projection:
|
||||
m_projectionControl = control;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] const RuleControl &role_control(
|
||||
const QuadratureRole role
|
||||
) const noexcept {
|
||||
switch (role) {
|
||||
case QuadratureRole::discretization:
|
||||
return m_discretizationControl;
|
||||
|
||||
case QuadratureRole::preconditioner:
|
||||
return m_preconditionerControl;
|
||||
|
||||
case QuadratureRole::diagnostic:
|
||||
return m_diagnosticControl;
|
||||
|
||||
case QuadratureRole::projection:
|
||||
return m_projectionControl;
|
||||
}
|
||||
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
void set_fallback_control(
|
||||
const RuleControl control
|
||||
) noexcept {
|
||||
m_fallbackControl = control;
|
||||
}
|
||||
|
||||
[[nodiscard]] const RuleControl &fallback_control() const noexcept {
|
||||
return m_fallbackControl;
|
||||
}
|
||||
|
||||
auto begin() {
|
||||
return m_formRules.begin();
|
||||
}
|
||||
|
||||
auto end() {
|
||||
return m_formRules.end();
|
||||
}
|
||||
|
||||
auto begin() const {
|
||||
return m_formRules.begin();
|
||||
}
|
||||
|
||||
auto end() const {
|
||||
return m_formRules.end();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<FormRule> m_formRules;
|
||||
|
||||
RuleControl m_discretizationControl;
|
||||
RuleControl m_preconditionerControl;
|
||||
RuleControl m_diagnosticControl;
|
||||
RuleControl m_projectionControl;
|
||||
|
||||
RuleControl m_fallbackControl;
|
||||
};
|
||||
|
||||
struct RoleControls {
|
||||
RuleControl discretization;
|
||||
RuleControl preconditioner;
|
||||
RuleControl diagnostic;
|
||||
RuleControl projection;
|
||||
};
|
||||
|
||||
|
||||
struct Resolution {
|
||||
int base_order;
|
||||
int boost;
|
||||
int order;
|
||||
bool used_fixed_order;
|
||||
};
|
||||
|
||||
struct QuadratureTermOptions {
|
||||
std::optional<int> fixed_order;
|
||||
int additional_boost = 0;
|
||||
};
|
||||
|
||||
struct QuadratureManifestOptions {
|
||||
bool enabled = false;
|
||||
bool include_repeated_queries = false;
|
||||
std::optional<std::string> output_file;
|
||||
};
|
||||
|
||||
struct QuadratureValidationOptions {
|
||||
bool require_explicit_base_order = false;
|
||||
bool require_explicit_mfem_rule = false;
|
||||
bool reject_negative_boosts = true;
|
||||
bool report_unused_overrides = true;
|
||||
};
|
||||
|
||||
struct QuadratureRoleOptions {
|
||||
QuadratureTermOptions discretization;
|
||||
QuadratureTermOptions preconditioner;
|
||||
QuadratureTermOptions diagnostic;
|
||||
QuadratureTermOptions projection;
|
||||
};
|
||||
|
||||
struct QuadratureOptions {
|
||||
Mode mode = Mode::production;
|
||||
int global_boost = 0;
|
||||
std::optional<int> fallback_fixed_order;
|
||||
|
||||
QuadratureTermOptions gravity_hdiv_mass;
|
||||
QuadratureTermOptions gravity_divergence;
|
||||
QuadratureTermOptions gravity_source;
|
||||
QuadratureTermOptions gravity_force;
|
||||
QuadratureTermOptions gravity_boundary;
|
||||
QuadratureTermOptions centrifugal;
|
||||
QuadratureTermOptions density_projection;
|
||||
QuadratureTermOptions eos_closure;
|
||||
QuadratureTermOptions hydrostatic_equilibrium;
|
||||
QuadratureTermOptions isobaric_surface;
|
||||
QuadratureTermOptions mesh_extension;
|
||||
QuadratureTermOptions mass_conservation;
|
||||
QuadratureTermOptions mass_normalization;
|
||||
QuadratureTermOptions center_of_mass;
|
||||
QuadratureTermOptions quadrupole;
|
||||
QuadratureTermOptions gravitational_energy;
|
||||
QuadratureTermOptions pressure_integral;
|
||||
QuadratureTermOptions pressure_force;
|
||||
QuadratureTermOptions virial;
|
||||
QuadratureTermOptions error_norm;
|
||||
|
||||
QuadratureRoleOptions roles;
|
||||
|
||||
std::vector<int> convergence_boosts = {0, 2, 4};
|
||||
QuadratureManifestOptions manifest;
|
||||
QuadratureValidationOptions validation;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::quadrature::QuadratureRole> : std::formatter<std::string_view> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::quadrature::QuadratureRole& role, FormatContext& ctx) const {
|
||||
std::string_view roleStr;
|
||||
switch (role) {
|
||||
case serif::discretization::quadrature::QuadratureRole::preconditioner:
|
||||
roleStr = "preconditioner";
|
||||
break;
|
||||
case serif::discretization::quadrature::QuadratureRole::diagnostic:
|
||||
roleStr = "diagnostic";
|
||||
break;
|
||||
case serif::discretization::quadrature::QuadratureRole::projection:
|
||||
roleStr = "projection";
|
||||
break;
|
||||
default:
|
||||
roleStr = "unknown";
|
||||
break;
|
||||
}
|
||||
return std::formatter<std::string_view>::format(roleStr, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::quadrature::MappingKind> : std::formatter<std::string_view> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::quadrature::MappingKind& mk, FormatContext& ctx) const {
|
||||
std::string_view mappingKindStr;
|
||||
switch (mk) {
|
||||
case serif::discretization::quadrature::MappingKind::none:
|
||||
mappingKindStr = "none";
|
||||
break;
|
||||
case serif::discretization::quadrature::MappingKind::affine:
|
||||
mappingKindStr = "affine";
|
||||
break;
|
||||
case serif::discretization::quadrature::MappingKind::general:
|
||||
mappingKindStr = "general";
|
||||
break;
|
||||
case serif::discretization::quadrature::MappingKind::kelvin:
|
||||
mappingKindStr = "kelvin";
|
||||
break;
|
||||
default:
|
||||
mappingKindStr = "unknown";
|
||||
break;
|
||||
}
|
||||
return std::formatter<std::string_view>::format(mappingKindStr, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::quadrature::Mode> : std::formatter<std::string_view> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::quadrature::Mode& mode, FormatContext& ctx) const {
|
||||
std::string_view modeStr;
|
||||
switch (mode) {
|
||||
case serif::discretization::quadrature::Mode::fast:
|
||||
modeStr = "fast";
|
||||
break;
|
||||
case serif::discretization::quadrature::Mode::production:
|
||||
modeStr = "production";
|
||||
break;
|
||||
case serif::discretization::quadrature::Mode::reference:
|
||||
modeStr = "reference";
|
||||
break;
|
||||
case serif::discretization::quadrature::Mode::convergence:
|
||||
modeStr = "convergence";
|
||||
break;
|
||||
default:
|
||||
modeStr = "unknown";
|
||||
break;
|
||||
}
|
||||
return std::formatter<std::string_view>::format(modeStr, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::quadrature::RuleControl> : std::formatter<std::string_view> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::quadrature::RuleControl& rc, FormatContext& ctx) const {
|
||||
return std::formatter<std::string_view>::format(
|
||||
std::format("RuleControl(fixed_order={}, boost={})", rc.fixed_order.has_value() ? std::to_string(rc.fixed_order.value()) : "none", rc.boost),
|
||||
ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::quadrature::FormRule> : std::formatter<std::string_view> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::quadrature::FormRule& fr, FormatContext& ctx) const {
|
||||
return std::formatter<std::string_view>::format(
|
||||
std::format("FormRule(form={}, control={})", fr.form, fr.control),
|
||||
ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::formatter<serif::discretization::quadrature::RuleSet> : std::formatter<std::string_view> {
|
||||
template <typename FormatContext>
|
||||
auto format(const serif::discretization::quadrature::RuleSet& rs, FormatContext& ctx) const {
|
||||
std::string rulesStr;
|
||||
for (const auto& rule : rs) {
|
||||
if (!rulesStr.empty()) {
|
||||
rulesStr += ", ";
|
||||
}
|
||||
rulesStr += std::format("{}", rule);
|
||||
}
|
||||
return std::formatter<std::string_view>::format(
|
||||
std::format("RuleSet(formRules=[{}])", rulesStr),
|
||||
ctx);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user