feat(libmeanfield): centrifugal + pressure
This commit is contained in:
@@ -12,7 +12,8 @@ export namespace mean_field::analysis {
|
||||
const fem::FEM &fem,
|
||||
const mfem::GridFunction &gf,
|
||||
utils::DOMAINS domain = utils::DOMAINS::ALL,
|
||||
mapping::COORDINATE_SPACE coord_space = mapping::COORDINATE_SPACE::PHYSICAL
|
||||
mapping::COORDINATE_SPACE coord_space =
|
||||
mapping::COORDINATE_SPACE::PHYSICAL
|
||||
);
|
||||
|
||||
mfem::Vector get_com(
|
||||
@@ -32,10 +33,9 @@ export namespace mean_field::analysis {
|
||||
);
|
||||
|
||||
double get_mesh_volume(
|
||||
const fem::FEM& fem,
|
||||
mapping::COORDINATE_SPACE coordinate_space = mapping::COORDINATE_SPACE::PHYSICAL,
|
||||
const fem::FEM &fem,
|
||||
mapping::COORDINATE_SPACE coordinate_space =
|
||||
mapping::COORDINATE_SPACE::PHYSICAL,
|
||||
utils::DOMAINS domain = utils::DOMAINS::STELLAR
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
} // namespace mean_field::analysis
|
||||
|
||||
@@ -5,20 +5,19 @@ export module mean_field:boundary.contexts;
|
||||
|
||||
export namespace mean_field::boundary {
|
||||
struct BoundaryContext {
|
||||
mfem::Array<int> inf_bounds;
|
||||
mfem::Array<int> stellar_bounds;
|
||||
mfem::Array<int> inf_bounds;
|
||||
mfem::Array<int> stellar_bounds;
|
||||
};
|
||||
|
||||
enum class Boundaries : uint8_t {
|
||||
STELLAR_SURFACE = 1,
|
||||
INF_SURFACE = 2
|
||||
};
|
||||
enum class Boundaries : uint8_t { STELLAR_SURFACE = 1, INF_SURFACE = 2 };
|
||||
|
||||
int operator-(
|
||||
Boundaries b,
|
||||
const int a
|
||||
) {
|
||||
return static_cast<int>(static_cast<uint8_t>(b) - static_cast<uint8_t>(a));
|
||||
return static_cast<int>(
|
||||
static_cast<uint8_t>(b) - static_cast<uint8_t>(a)
|
||||
);
|
||||
}
|
||||
|
||||
struct Bounds {
|
||||
@@ -26,9 +25,6 @@ export namespace mean_field::boundary {
|
||||
double r_inf_ref;
|
||||
};
|
||||
|
||||
enum BoundsError : uint8_t {
|
||||
CANNOT_FIND_VACUUM
|
||||
};
|
||||
enum BoundsError : uint8_t { CANNOT_FIND_VACUUM };
|
||||
|
||||
|
||||
}
|
||||
} // namespace mean_field::boundary
|
||||
|
||||
@@ -1,95 +1,183 @@
|
||||
module;
|
||||
|
||||
#include <stroid/stroid.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <mfem.hpp>
|
||||
#include <stroid/stroid.h>
|
||||
|
||||
export module mean_field:fem;
|
||||
|
||||
export import :physics.contexts;
|
||||
export import :boundary.contexts;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :utils.misc;
|
||||
export import :utils.user;
|
||||
export import :quadrature.mfem;
|
||||
export import :field.mfem;
|
||||
|
||||
export namespace mean_field::fem {
|
||||
using GravityField = field::Field<field::Gravity>;
|
||||
using DisplacementField = field::Field<field::Displacement>;
|
||||
using DensityField = field::Field<field::Density>;
|
||||
using EnthalpyField = field::Field<field::Enthalpy>;
|
||||
|
||||
struct FEM {
|
||||
// =====================================================================
|
||||
// Mesh
|
||||
// =====================================================================
|
||||
|
||||
stroid::StroidMesh smesh;
|
||||
std::unique_ptr<mfem::ParMesh> mesh;
|
||||
|
||||
// =====================================
|
||||
// 2. Finite Element Collections
|
||||
// =====================================
|
||||
// H1 (Continuous): For Gravitational Potential (Phi) and Velocity (v)
|
||||
std::unique_ptr<mfem::FiniteElementCollection> H1_fec;
|
||||
// =====================================================================
|
||||
// Compile-time field descriptors
|
||||
// =====================================================================
|
||||
|
||||
// L2 (Discontinuous): For Density (rho) to fix O-grid boundary scalloping
|
||||
std::unique_ptr<mfem::FiniteElementCollection> L2_fec;
|
||||
GravityField gravityField;
|
||||
DisplacementField displacementField;
|
||||
DensityField densityField;
|
||||
EnthalpyField enthalpyField;
|
||||
|
||||
// H(div)/RT space for gravitational field
|
||||
std::unique_ptr<mfem::RT_FECollection> RT_fec;
|
||||
// =====================================================================
|
||||
// Gravity field
|
||||
//
|
||||
// Collection members are declared before their corresponding spaces so
|
||||
// that the spaces are destroyed first.
|
||||
// =====================================================================
|
||||
|
||||
std::unique_ptr<mfem::FiniteElementCollection> gravityPotentialFec;
|
||||
|
||||
// =====================================
|
||||
// 3. Finite Element Spaces
|
||||
// =====================================
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> H1_fes; // Scalar continuous (Gravity)
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> Vec_H1_fes; // Vector continuous (Velocity field)
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> L2_fes; // Scalar discontinuous (Density)
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> RT_fes; // H(div)/RT space for gravitational field
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> gravityPotentialFes;
|
||||
|
||||
// Preconditioning for Gravity
|
||||
std::unique_ptr<mfem::ParLORDiscretization> H1_lor_disc;
|
||||
const mfem::ParFiniteElementSpace *H1_lor_fes{nullptr};
|
||||
std::unique_ptr<mfem::FiniteElementCollection> gravityFluxFec;
|
||||
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> gravityFluxFes;
|
||||
|
||||
// =====================================================================
|
||||
// Displacement field
|
||||
// =====================================================================
|
||||
|
||||
std::unique_ptr<mfem::FiniteElementCollection> displacementFec;
|
||||
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> displacementFes;
|
||||
|
||||
std::unique_ptr<mfem::ParGridFunction> displacement;
|
||||
|
||||
// =====================================================================
|
||||
// Density field
|
||||
// =====================================================================
|
||||
|
||||
std::unique_ptr<mfem::FiniteElementCollection> densityFec;
|
||||
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> densityFes;
|
||||
|
||||
// =====================================================================
|
||||
// Specific-enthalpy field
|
||||
// =====================================================================
|
||||
|
||||
std::unique_ptr<mfem::FiniteElementCollection> enthalpyFec;
|
||||
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> enthalpyFes;
|
||||
|
||||
// =====================================================================
|
||||
// Compactification coordinate
|
||||
// =====================================================================
|
||||
|
||||
std::unique_ptr<mfem::H1_FECollection> compactificationFec;
|
||||
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> compactificationFes;
|
||||
|
||||
std::unique_ptr<mfem::ParGridFunction> compactificationCoordinate;
|
||||
|
||||
// =====================================================================
|
||||
// Domain mapping
|
||||
//
|
||||
// These are declared after displacement so that they are destroyed
|
||||
// before the displacement grid function to which mapping may refer.
|
||||
// DomainMapper is retained only for legacy integrators. New operators
|
||||
// use DomainMapperStateless exclusively.
|
||||
// =====================================================================
|
||||
|
||||
// =====================================
|
||||
// 4. Domain Mapping
|
||||
// =====================================
|
||||
std::unique_ptr<mapping::DomainMapper> mapping;
|
||||
|
||||
// =====================================
|
||||
// 5. Global System Tracking
|
||||
// =====================================
|
||||
// [ Velocity | Density | Mapping Parameters (Surface) ]
|
||||
mfem::Array<int> block_true_offsets;
|
||||
std::unique_ptr<mapping::DomainMapperStateless> domainMapperStateless;
|
||||
|
||||
mfem::Array<int> gravity_block_true_offsets;
|
||||
// =====================================================================
|
||||
// Block layouts
|
||||
//
|
||||
// These arrays are retained only for legacy code. Canonical operator
|
||||
// layouts are defined by the compile-time forms in :utils.blocks.
|
||||
//
|
||||
// Main system: [Displacement | Density]
|
||||
// Gravity system: [Flux | Potential]
|
||||
// =====================================================================
|
||||
|
||||
// Essential Boundary Conditions for the fluid (e.g., surface stress-free)
|
||||
mfem::Array<int> ess_v_tdofs;
|
||||
mfem::Array<int> blockTrueOffsets;
|
||||
mfem::Array<int> gravityBlockTrueOffsets;
|
||||
|
||||
// Elements entirely in the vacuum domain where fluid equations are not solved
|
||||
mfem::Array<int> vacuum_tdof_rho;
|
||||
mfem::Array<int> vacuum_tdof_v;
|
||||
// =====================================================================
|
||||
// Boundary conditions and domain masks
|
||||
// =====================================================================
|
||||
|
||||
mfem::Array<int> essentialDisplacementTdofs;
|
||||
mfem::Array<int> vacuumDensityTdofs;
|
||||
mfem::Array<int> vacuumEnthalpyTdofs;
|
||||
mfem::Array<int> vacuumDisplacementTdofs;
|
||||
|
||||
// =====================================================================
|
||||
// Global diagnostics
|
||||
// =====================================================================
|
||||
|
||||
// =====================================
|
||||
// 6. Multiphysics State & Integration
|
||||
// =====================================
|
||||
mfem::Vector com;
|
||||
mfem::DenseMatrix Q;
|
||||
|
||||
int int_order{3};
|
||||
std::unique_ptr<mfem::IntegrationRule> int_rule;
|
||||
// =====================================================================
|
||||
// Physics and boundary contexts
|
||||
// =====================================================================
|
||||
|
||||
physics::GravityContext gravity_context;
|
||||
boundary::BoundaryContext boundary_context;
|
||||
physics::GravityContext gravityContext;
|
||||
boundary::BoundaryContext boundaryContext;
|
||||
|
||||
std::unique_ptr<quadrature::RuleFactory> quadrature_factory;
|
||||
std::unique_ptr<quadrature::RuleFactory> quadratureFactory;
|
||||
|
||||
// =====================================================================
|
||||
// Validation
|
||||
// =====================================================================
|
||||
|
||||
// =====================================
|
||||
// 7. Utilities
|
||||
// =====================================
|
||||
[[nodiscard]] bool okay() const {
|
||||
return (mesh != nullptr) &&
|
||||
(H1_fec != nullptr) && (L2_fec != nullptr) && (RT_fec != nullptr) &&
|
||||
(H1_fes != nullptr) && (Vec_H1_fes != nullptr) && (L2_fes != nullptr) && (RT_fes != nullptr);
|
||||
return mesh != nullptr &&
|
||||
|
||||
gravityPotentialFec != nullptr &&
|
||||
gravityPotentialFes != nullptr &&
|
||||
gravityFluxFec != nullptr && gravityFluxFes != nullptr &&
|
||||
|
||||
displacementFec != nullptr && displacementFes != nullptr &&
|
||||
displacement != nullptr &&
|
||||
|
||||
densityFec != nullptr && densityFes != nullptr &&
|
||||
|
||||
enthalpyFec != nullptr && enthalpyFes != nullptr &&
|
||||
|
||||
compactificationFec != nullptr &&
|
||||
compactificationFes != nullptr &&
|
||||
compactificationCoordinate != nullptr &&
|
||||
|
||||
mapping != nullptr && domainMapperStateless != nullptr &&
|
||||
quadratureFactory != nullptr &&
|
||||
|
||||
blockTrueOffsets.Size() == 3 &&
|
||||
gravityBlockTrueOffsets.Size() == 3;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool has_mapping() const { return mapping != nullptr; }
|
||||
[[nodiscard]] bool has_mapping() const {
|
||||
return mapping != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
FEM setup_fem(const std::string &filename, const utils::Args &args, int extra_refine = 0);
|
||||
}
|
||||
|
||||
FEM setup_fem(
|
||||
const std::string &filename,
|
||||
const utils::Args &args,
|
||||
int extraRefine = 0
|
||||
);
|
||||
} // namespace mean_field::fem
|
||||
|
||||
356
libmeanfield/interface/field/field_base.cppm
Normal file
356
libmeanfield/interface/field/field_base.cppm
Normal file
@@ -0,0 +1,356 @@
|
||||
module;
|
||||
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
export module mean_field:field.base;
|
||||
|
||||
export namespace mean_field::field {
|
||||
template <typename... Ts> struct TypeList { };
|
||||
|
||||
template <typename T, typename ListT> struct TypeListContains;
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
struct TypeListContains<T, TypeList<Ts...>>
|
||||
: std::bool_constant<(std::same_as<T, Ts> || ...)> { };
|
||||
|
||||
template <typename T, typename ListT>
|
||||
inline constexpr bool typeListContains = TypeListContains<T, ListT>::value;
|
||||
|
||||
enum class StorageKind { finite_element, global_scalar };
|
||||
|
||||
inline constexpr int dynamicBlockSize = -1;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Function-space tags
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
struct L2 {
|
||||
static constexpr std::string_view name = "L2";
|
||||
};
|
||||
|
||||
struct H1 {
|
||||
static constexpr std::string_view name = "H1";
|
||||
};
|
||||
|
||||
struct RT {
|
||||
static constexpr std::string_view name = "RT";
|
||||
};
|
||||
|
||||
struct ND {
|
||||
static constexpr std::string_view name = "ND";
|
||||
};
|
||||
|
||||
template <typename SpaceT>
|
||||
concept SpaceTag = std::same_as<SpaceT, L2> || std::same_as<SpaceT, H1> ||
|
||||
std::same_as<SpaceT, RT> || std::same_as<SpaceT, ND>;
|
||||
|
||||
template <SpaceTag SpaceT, int RankV>
|
||||
inline constexpr bool spaceSupportsRank =
|
||||
(std::same_as<SpaceT, H1> && (RankV == 0 || RankV == 1)) ||
|
||||
(std::same_as<SpaceT, L2> && (RankV == 0 || RankV == 1)) ||
|
||||
(std::same_as<SpaceT, RT> && RankV == 1) ||
|
||||
(std::same_as<SpaceT, ND> && RankV == 1);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Discretization descriptors
|
||||
//
|
||||
// familyOrder is the order passed to the backend's FE collection
|
||||
// constructor. It is deliberately not called polynomialOrder because those
|
||||
// values differ for some spaces, notably Raviart-Thomas elements in MFEM.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
template <SpaceTag SpaceT, int FamilyOrderV> struct Disc {
|
||||
using Space = SpaceT;
|
||||
|
||||
static constexpr int familyOrder = FamilyOrderV;
|
||||
|
||||
static_assert(
|
||||
FamilyOrderV >= 0,
|
||||
"Finite-element family order must be non-negative."
|
||||
);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept DiscretizationTag = requires {
|
||||
typename T::Space;
|
||||
{ T::familyOrder } -> std::convertible_to<int>;
|
||||
} && SpaceTag<typename T::Space>;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Physical relations between quantities
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
struct FieldRelation {
|
||||
struct Independent { };
|
||||
|
||||
template <typename SourceT> struct Gradient {
|
||||
using Source = SourceT;
|
||||
};
|
||||
|
||||
template <typename SourceT> struct Divergence {
|
||||
using Source = SourceT;
|
||||
};
|
||||
|
||||
template <typename SourceT> struct Curl {
|
||||
using Source = SourceT;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T> struct IsGradient : std::false_type { };
|
||||
|
||||
template <typename T> struct IsDivergence : std::false_type { };
|
||||
|
||||
template <typename T> struct IsCurl : std::false_type { };
|
||||
|
||||
template <typename SourceT>
|
||||
struct IsGradient<FieldRelation::Gradient<SourceT>> : std::true_type { };
|
||||
|
||||
template <typename SourceT>
|
||||
struct IsDivergence<FieldRelation::Divergence<SourceT>> : std::true_type {
|
||||
};
|
||||
|
||||
template <typename SourceT>
|
||||
struct IsCurl<FieldRelation::Curl<SourceT>> : std::true_type { };
|
||||
|
||||
template <typename RelationT>
|
||||
concept ValidRelation =
|
||||
std::same_as<RelationT, FieldRelation::Independent> ||
|
||||
IsGradient<RelationT>::value || IsDivergence<RelationT>::value ||
|
||||
IsCurl<RelationT>::value;
|
||||
|
||||
template <typename RelationT> struct RelationTarget {
|
||||
using Type = void;
|
||||
};
|
||||
|
||||
template <typename SourceT>
|
||||
struct RelationTarget<FieldRelation::Gradient<SourceT>> {
|
||||
using Type = SourceT;
|
||||
};
|
||||
|
||||
template <typename SourceT>
|
||||
struct RelationTarget<FieldRelation::Divergence<SourceT>> {
|
||||
using Type = SourceT;
|
||||
};
|
||||
|
||||
template <typename SourceT>
|
||||
struct RelationTarget<FieldRelation::Curl<SourceT>> {
|
||||
using Type = SourceT;
|
||||
};
|
||||
|
||||
template <typename QuantityT>
|
||||
using RelationTargetT =
|
||||
typename RelationTarget<typename QuantityT::Relation>::Type;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Field quantities
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
template <int RankV, ValidRelation RelationT, DiscretizationTag DiscT>
|
||||
struct Quantity {
|
||||
using Relation = RelationT;
|
||||
using Discretization = DiscT;
|
||||
using Space = typename DiscT::Space;
|
||||
|
||||
static constexpr int rankValue = RankV;
|
||||
static constexpr int familyOrder = DiscT::familyOrder;
|
||||
|
||||
static constexpr StorageKind storageKind = StorageKind::finite_element;
|
||||
static constexpr int staticBlockSize = dynamicBlockSize;
|
||||
|
||||
static_assert(
|
||||
RankV >= 0,
|
||||
"A field quantity cannot have a negative tensor rank."
|
||||
);
|
||||
|
||||
static_assert(
|
||||
spaceSupportsRank<
|
||||
Space,
|
||||
RankV>,
|
||||
"This function space cannot represent a quantity of this rank."
|
||||
);
|
||||
};
|
||||
|
||||
template <ValidRelation RelationT, DiscretizationTag DiscT>
|
||||
using ScalarQ = Quantity<0, RelationT, DiscT>;
|
||||
|
||||
template <ValidRelation RelationT, DiscretizationTag DiscT>
|
||||
using VectorQ = Quantity<1, RelationT, DiscT>;
|
||||
|
||||
struct GlobalScalarQ {
|
||||
using Relation = FieldRelation::Independent;
|
||||
|
||||
static constexpr int rankValue = 0;
|
||||
static constexpr StorageKind storageKind = StorageKind::global_scalar;
|
||||
static constexpr int staticBlockSize = 1;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept FieldQuantity =
|
||||
requires {
|
||||
typename T::Relation;
|
||||
typename T::Discretization;
|
||||
typename T::Space;
|
||||
|
||||
{ T::rankValue } -> std::convertible_to<int>;
|
||||
{ T::familyOrder } -> std::convertible_to<int>;
|
||||
{ T::storageKind } -> std::convertible_to<StorageKind>;
|
||||
{ T::staticBlockSize } -> std::convertible_to<int>;
|
||||
} && SpaceTag<typename T::Space> &&
|
||||
T::storageKind == StorageKind::finite_element;
|
||||
|
||||
template <typename T>
|
||||
concept GlobalScalarQuantity =
|
||||
requires {
|
||||
typename T::Relation;
|
||||
|
||||
{ T::rankValue } -> std::convertible_to<int>;
|
||||
{ T::storageKind } -> std::convertible_to<StorageKind>;
|
||||
{ T::staticBlockSize } -> std::convertible_to<int>;
|
||||
} && T::rankValue == 0 &&
|
||||
T::storageKind == StorageKind::global_scalar && T::staticBlockSize == 1;
|
||||
|
||||
template <typename T>
|
||||
concept RegisteredQuantity = FieldQuantity<T> || GlobalScalarQuantity<T>;
|
||||
|
||||
template <typename QuantityT>
|
||||
concept DerivedQuantity = FieldQuantity<QuantityT> &&
|
||||
(!std::same_as<RelationTargetT<QuantityT>, void>);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Compile-time discretization constraints
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
template <FieldQuantity FluxT, FieldQuantity PotentialT>
|
||||
struct RtL2StablePair {
|
||||
static consteval void validate() {
|
||||
static_assert(
|
||||
std::same_as<typename FluxT::Space, RT>,
|
||||
"The flux in an RT/L2 pair must use Raviart-Thomas elements."
|
||||
);
|
||||
|
||||
static_assert(
|
||||
std::same_as<typename PotentialT::Space, L2>,
|
||||
"The potential in an RT/L2 pair must use L2 elements."
|
||||
);
|
||||
|
||||
static_assert(
|
||||
FluxT::rankValue == 1,
|
||||
"The flux in an RT/L2 pair must be vector-valued."
|
||||
);
|
||||
|
||||
static_assert(
|
||||
PotentialT::rankValue == 0,
|
||||
"The potential in an RT/L2 pair must be scalar-valued."
|
||||
);
|
||||
|
||||
static_assert(
|
||||
FluxT::familyOrder == PotentialT::familyOrder,
|
||||
"The MFEM RT and L2 family orders must match."
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... ConstraintTs>
|
||||
consteval bool validate_constraints(TypeList<ConstraintTs...>) {
|
||||
(ConstraintTs::validate(), ...);
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Operations applied to quantities inside weak forms
|
||||
//
|
||||
// These describe the mathematics. Backend-specific polynomial-order rules
|
||||
// are provided by field.mfem.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
struct FieldOperation {
|
||||
struct Value { };
|
||||
struct Gradient { };
|
||||
struct Divergence { };
|
||||
struct Curl { };
|
||||
struct NormalTrace { };
|
||||
};
|
||||
|
||||
template <typename OperationT>
|
||||
concept FieldOperationTag =
|
||||
std::same_as<OperationT, FieldOperation::Value> ||
|
||||
std::same_as<OperationT, FieldOperation::Gradient> ||
|
||||
std::same_as<OperationT, FieldOperation::Divergence> ||
|
||||
std::same_as<OperationT, FieldOperation::Curl> ||
|
||||
std::same_as<OperationT, FieldOperation::NormalTrace>;
|
||||
|
||||
template <
|
||||
RegisteredQuantity QuantityT,
|
||||
FieldOperationTag OperationT = FieldOperation::Value>
|
||||
struct Operand {
|
||||
using Quantity = QuantityT;
|
||||
using Operation = OperationT;
|
||||
|
||||
static_assert(
|
||||
FieldQuantity<QuantityT> || std::same_as<
|
||||
OperationT,
|
||||
FieldOperation::Value>,
|
||||
"Global scalar quantities support only the value operation."
|
||||
);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept FieldOperand =
|
||||
requires {
|
||||
typename T::Quantity;
|
||||
typename T::Operation;
|
||||
} && RegisteredQuantity<typename T::Quantity> &&
|
||||
FieldOperationTag<typename T::Operation>;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Weak-form descriptions
|
||||
//
|
||||
// PolicyKeyV associates the form with a runtime quadrature-policy key.
|
||||
//
|
||||
// DynamicOrderCountV is the number of polynomial-order contributions that
|
||||
// cannot yet be derived from registered quantities. For example, a source
|
||||
// coefficient supplied at runtime contributes one dynamic order.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
auto PolicyKeyV,
|
||||
std::size_t DynamicOrderCountV,
|
||||
FieldOperand... OperandTs>
|
||||
struct FormSpec {
|
||||
static constexpr auto policyKey = PolicyKeyV;
|
||||
static constexpr std::size_t dynamicOrderCount = DynamicOrderCountV;
|
||||
|
||||
using Operands = TypeList<OperandTs...>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept FieldForm = requires {
|
||||
typename T::Operands;
|
||||
|
||||
T::policyKey;
|
||||
|
||||
{ T::dynamicOrderCount } -> std::convertible_to<std::size_t>;
|
||||
};
|
||||
|
||||
template <typename ListT>
|
||||
struct IsRegisteredQuantityList : std::false_type { };
|
||||
|
||||
template <RegisteredQuantity... QuantityTs>
|
||||
struct IsRegisteredQuantityList<TypeList<QuantityTs...>> : std::true_type {
|
||||
};
|
||||
|
||||
template <typename ListT>
|
||||
inline constexpr bool isRegisteredQuantityList =
|
||||
IsRegisteredQuantityList<ListT>::value;
|
||||
|
||||
template <typename ListT> struct IsFieldFormList : std::false_type { };
|
||||
|
||||
template <FieldForm... FormTs>
|
||||
struct IsFieldFormList<TypeList<FormTs...>> : std::true_type { };
|
||||
|
||||
template <typename ListT>
|
||||
inline constexpr bool isFieldFormList = IsFieldFormList<ListT>::value;
|
||||
} // namespace mean_field::field
|
||||
380
libmeanfield/interface/field/field_mfem.cppm
Normal file
380
libmeanfield/interface/field/field_mfem.cppm
Normal file
@@ -0,0 +1,380 @@
|
||||
module;
|
||||
|
||||
#include <array>
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:field.mfem;
|
||||
|
||||
export import :field.registry;
|
||||
|
||||
namespace mean_field::field::detail {
|
||||
template <typename T> inline constexpr bool alwaysFalse = false;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// MFEM finite-element collection construction
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
template <typename SpaceT> struct FecFor;
|
||||
|
||||
template <> struct FecFor<L2> {
|
||||
static std::unique_ptr<mfem::FiniteElementCollection> make(
|
||||
int familyOrder,
|
||||
int dimension
|
||||
) {
|
||||
return std::make_unique<mfem::L2_FECollection>(
|
||||
familyOrder, dimension
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct FecFor<H1> {
|
||||
static std::unique_ptr<mfem::FiniteElementCollection> make(
|
||||
int familyOrder,
|
||||
int dimension
|
||||
) {
|
||||
return std::make_unique<mfem::H1_FECollection>(
|
||||
familyOrder, dimension
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct FecFor<RT> {
|
||||
static std::unique_ptr<mfem::FiniteElementCollection> make(
|
||||
int familyOrder,
|
||||
int dimension
|
||||
) {
|
||||
return std::make_unique<mfem::RT_FECollection>(
|
||||
familyOrder, dimension
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct FecFor<ND> {
|
||||
static std::unique_ptr<mfem::FiniteElementCollection> make(
|
||||
int familyOrder,
|
||||
int dimension
|
||||
) {
|
||||
return std::make_unique<mfem::ND_FECollection>(
|
||||
familyOrder, dimension
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// MFEM polynomial-order interpretation
|
||||
//
|
||||
// familyOrder is the collection constructor argument.
|
||||
//
|
||||
// For RT_p:
|
||||
// value order = p + 1
|
||||
// divergence order = p
|
||||
// normal-trace order = p
|
||||
//
|
||||
// This distinction is what allows Disc<RT, p> and Disc<L2, p> to form a
|
||||
// compatible pair while still giving different value-shape orders.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
template <typename OperandT> struct MfemOperandOrder;
|
||||
|
||||
template <RegisteredQuantity QuantityT, FieldOperationTag OperationT>
|
||||
struct MfemOperandOrder<Operand<QuantityT, OperationT>> {
|
||||
static constexpr int orderValue = []() consteval {
|
||||
if constexpr (GlobalScalarQuantity<QuantityT>) {
|
||||
static_assert(
|
||||
std::same_as<OperationT, FieldOperation::Value>,
|
||||
"Global scalars support only the value operation."
|
||||
);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
using Space = typename QuantityT::Space;
|
||||
constexpr int familyOrder = QuantityT::familyOrder;
|
||||
|
||||
if constexpr (std::same_as<OperationT, FieldOperation::Value>) {
|
||||
if constexpr (std::same_as<Space, RT>) {
|
||||
return familyOrder + 1;
|
||||
} else {
|
||||
return familyOrder;
|
||||
}
|
||||
} else if constexpr (
|
||||
std::same_as<OperationT, FieldOperation::Divergence>
|
||||
) {
|
||||
static_assert(
|
||||
std::same_as<Space, RT>,
|
||||
"Only RT quantities currently support the divergence "
|
||||
"polynomial-order rule."
|
||||
);
|
||||
|
||||
return familyOrder;
|
||||
} else if constexpr (
|
||||
std::same_as<OperationT, FieldOperation::Gradient>
|
||||
) {
|
||||
static_assert(
|
||||
std::same_as<Space, H1>,
|
||||
"Only H1 quantities currently support the gradient "
|
||||
"polynomial-order rule."
|
||||
);
|
||||
|
||||
return familyOrder > 0 ? familyOrder - 1 : 0;
|
||||
} else if constexpr (
|
||||
std::same_as<OperationT, FieldOperation::Curl>
|
||||
) {
|
||||
static_assert(
|
||||
std::same_as<Space, ND>,
|
||||
"Only ND quantities currently support the curl "
|
||||
"polynomial-order rule."
|
||||
);
|
||||
|
||||
return familyOrder > 0 ? familyOrder - 1 : 0;
|
||||
} else if constexpr (
|
||||
std::same_as<OperationT, FieldOperation::NormalTrace>
|
||||
) {
|
||||
static_assert(
|
||||
std::same_as<Space, RT>,
|
||||
"Only RT quantities currently support the normal-trace "
|
||||
"polynomial-order rule."
|
||||
);
|
||||
|
||||
return familyOrder;
|
||||
} else {
|
||||
static_assert(
|
||||
alwaysFalse<OperationT>,
|
||||
"Unsupported MFEM field operation."
|
||||
);
|
||||
}
|
||||
}
|
||||
}();
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Static polynomial-order contribution of an entire form
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
template <typename FormT> struct MfemFormOrder;
|
||||
|
||||
template <
|
||||
auto PolicyKeyV,
|
||||
std::size_t DynamicOrderCountV,
|
||||
FieldOperand... OperandTs>
|
||||
struct MfemFormOrder<
|
||||
FormSpec<PolicyKeyV, DynamicOrderCountV, OperandTs...>> {
|
||||
static constexpr int staticOrder =
|
||||
(MfemOperandOrder<OperandTs>::orderValue + ... + 0);
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// MFEM vector-dimension and ordering rules
|
||||
//
|
||||
// Vector H1/L2 fields are represented using multiple copies of a scalar
|
||||
// finite-element space. RT and ND elements are intrinsically vector-valued
|
||||
// and therefore use vdim = 1.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
template <FieldQuantity QuantityT> int get_vdim(int spaceDimension) {
|
||||
if (spaceDimension <= 0) {
|
||||
throw std::invalid_argument("Space dimension must be positive.");
|
||||
}
|
||||
|
||||
if constexpr (QuantityT::rankValue == 0) {
|
||||
return 1;
|
||||
} else if constexpr (
|
||||
std::same_as<typename QuantityT::Space, H1> ||
|
||||
std::same_as<typename QuantityT::Space, L2>
|
||||
) {
|
||||
return spaceDimension;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <FieldQuantity QuantityT>
|
||||
constexpr mfem::Ordering::Type get_ordering() {
|
||||
if constexpr (
|
||||
QuantityT::rankValue == 1 &&
|
||||
(std::same_as<typename QuantityT::Space, H1> ||
|
||||
std::same_as<typename QuantityT::Space, L2>)
|
||||
) {
|
||||
return mfem::Ordering::byVDIM;
|
||||
} else {
|
||||
return mfem::Ordering::byNODES;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Quantity-specific MFEM realization
|
||||
//
|
||||
// Backend choices that are part of a field definition live here rather
|
||||
// than leaking into FEM setup or call sites.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
template <FieldQuantity QuantityT> struct MfemQuantityTraits {
|
||||
static std::unique_ptr<mfem::FiniteElementCollection>
|
||||
make_fec(int dimension) {
|
||||
return FecFor<typename QuantityT::Space>::make(
|
||||
QuantityT::familyOrder, dimension
|
||||
);
|
||||
}
|
||||
|
||||
static constexpr mfem::Ordering::Type ordering =
|
||||
get_ordering<QuantityT>();
|
||||
};
|
||||
|
||||
template <> struct MfemQuantityTraits<Gravity::Flux> {
|
||||
static std::unique_ptr<mfem::FiniteElementCollection>
|
||||
make_fec(int dimension) {
|
||||
return std::make_unique<mfem::RT_FECollection>(
|
||||
Gravity::Flux::familyOrder, dimension,
|
||||
mfem::BasisType::GaussLobatto, mfem::BasisType::IntegratedGLL
|
||||
);
|
||||
}
|
||||
|
||||
static constexpr mfem::Ordering::Type ordering =
|
||||
mfem::Ordering::byNODES;
|
||||
};
|
||||
|
||||
template <> struct MfemQuantityTraits<Displacement::Vector> {
|
||||
static std::unique_ptr<mfem::FiniteElementCollection>
|
||||
make_fec(int dimension) {
|
||||
return FecFor<H1>::make(
|
||||
Displacement::Vector::familyOrder, dimension
|
||||
);
|
||||
}
|
||||
|
||||
static constexpr mfem::Ordering::Type ordering =
|
||||
mfem::Ordering::byNODES;
|
||||
};
|
||||
} // namespace mean_field::field::detail
|
||||
|
||||
export namespace mean_field::field {
|
||||
// -------------------------------------------------------------------------
|
||||
// User-facing field type
|
||||
//
|
||||
// The object itself is currently a zero-cost compile-time descriptor:
|
||||
//
|
||||
// Field<Gravity> gravityField;
|
||||
//
|
||||
// MFEM construction and typed quadrature-query generation are provided as
|
||||
// static operations. Runtime ownership can later be added without changing
|
||||
// Gravity, Displacement, or their form definitions.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
template <FieldTag TagT> class Field {
|
||||
public:
|
||||
using Tag = TagT;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// MFEM finite-element collection construction
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
template <FieldQuantity QuantityT>
|
||||
requires typeListContains<
|
||||
QuantityT,
|
||||
typename TagT::Quantities>
|
||||
static std::unique_ptr<mfem::FiniteElementCollection>
|
||||
make_fec(int dimension) {
|
||||
if (dimension <= 0) {
|
||||
throw std::invalid_argument("Mesh dimension must be positive.");
|
||||
}
|
||||
|
||||
return detail::MfemQuantityTraits<QuantityT>::make_fec(dimension);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// MFEM parallel finite-element space construction
|
||||
//
|
||||
// The finite-element collection must outlive the returned space.
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
template <FieldQuantity QuantityT>
|
||||
requires typeListContains<
|
||||
QuantityT,
|
||||
typename TagT::Quantities>
|
||||
static std::unique_ptr<mfem::ParFiniteElementSpace> make_fespace(
|
||||
mfem::ParMesh &mesh,
|
||||
mfem::FiniteElementCollection &finiteElementCollection
|
||||
) {
|
||||
return std::make_unique<mfem::ParFiniteElementSpace>(
|
||||
&mesh, &finiteElementCollection,
|
||||
detail::get_vdim<QuantityT>(mesh.SpaceDimension()),
|
||||
detail::MfemQuantityTraits<QuantityT>::ordering
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Typed quadrature-query construction
|
||||
//
|
||||
// geometryWeightOrder is supplied at runtime because it depends on the
|
||||
// actual element transformation.
|
||||
//
|
||||
// dynamicOrders contains the form-specific polynomial orders that are
|
||||
// not represented by registered compile-time quantities.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// Density::Form::CenterOfMass:
|
||||
// { positionOrder }
|
||||
//
|
||||
// Gravity source forms need no dynamic orders because density and
|
||||
// potential are both registered quantities.
|
||||
//
|
||||
// The completed base order is stored in Query::base_order, so Policy
|
||||
// does not need to understand divergence, RT conventions, or individual
|
||||
// field layouts.
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
template <FieldForm FormT>
|
||||
requires typeListContains<
|
||||
FormT,
|
||||
typename TagT::FormList>
|
||||
static constexpr quadrature::Query make_query(
|
||||
quadrature::QuadratureRole role,
|
||||
int geometryWeightOrder,
|
||||
std::array<
|
||||
int,
|
||||
FormT::dynamicOrderCount> dynamicOrders = {},
|
||||
utils::DOMAINS domain = utils::DOMAINS::ALL,
|
||||
quadrature::MappingKind mapping = quadrature::MappingKind::none
|
||||
) {
|
||||
if (geometryWeightOrder < 0) {
|
||||
throw std::invalid_argument(
|
||||
"Geometry weight order cannot be negative."
|
||||
);
|
||||
}
|
||||
|
||||
int baseOrder =
|
||||
detail::MfemFormOrder<FormT>::staticOrder + geometryWeightOrder;
|
||||
|
||||
for (const int dynamicOrder : dynamicOrders) {
|
||||
if (dynamicOrder < 0) {
|
||||
throw std::invalid_argument(
|
||||
"Dynamic polynomial orders cannot be negative."
|
||||
);
|
||||
}
|
||||
|
||||
baseOrder += dynamicOrder;
|
||||
}
|
||||
|
||||
return {
|
||||
.term = FormT::policyKey,
|
||||
.role = role,
|
||||
.domain = domain,
|
||||
.mapping = mapping,
|
||||
.trial_order = 0,
|
||||
.test_order = 0,
|
||||
.coefficient_order = 0,
|
||||
.geometry_weight_order = geometryWeightOrder,
|
||||
.base_order = baseOrder
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(FieldTag<Gravity>);
|
||||
static_assert(FieldTag<Displacement>);
|
||||
static_assert(FieldTag<Density>);
|
||||
static_assert(FieldTag<BarotropicConstant>);
|
||||
} // namespace mean_field::field
|
||||
379
libmeanfield/interface/field/field_registry.cppm
Normal file
379
libmeanfield/interface/field/field_registry.cppm
Normal file
@@ -0,0 +1,379 @@
|
||||
module;
|
||||
|
||||
#include <concepts>
|
||||
#include <string_view>
|
||||
|
||||
export module mean_field:field.registry;
|
||||
|
||||
export import :field.base;
|
||||
export import :quadrature.policy;
|
||||
|
||||
export namespace mean_field::field {
|
||||
// =========================================================================
|
||||
// Density
|
||||
// =========================================================================
|
||||
|
||||
struct Density {
|
||||
static constexpr std::string_view name = "density";
|
||||
static constexpr int scalarOrder = 2;
|
||||
|
||||
struct Scalar final
|
||||
: ScalarQ<FieldRelation::Independent, Disc<L2, scalarOrder>> {
|
||||
static constexpr std::string_view symbol = "ρ";
|
||||
};
|
||||
|
||||
using Quantities = TypeList<Scalar>;
|
||||
using Constraints = TypeList<>;
|
||||
|
||||
static constexpr bool constraintsAreValid =
|
||||
validate_constraints(Constraints{});
|
||||
|
||||
static_assert(constraintsAreValid);
|
||||
|
||||
struct Form {
|
||||
// Density-space mass matrix: (rho, q).
|
||||
using ProjectionMass = FormSpec<
|
||||
quadrature::Term::density_projection,
|
||||
0,
|
||||
Operand<Scalar>,
|
||||
Operand<Scalar>>;
|
||||
|
||||
// Projection RHS with one runtime coefficient order.
|
||||
using ProjectionSource = FormSpec<
|
||||
quadrature::Term::density_projection,
|
||||
1,
|
||||
Operand<Scalar>>;
|
||||
|
||||
// Density-space contribution to the barotropic EOS closure:
|
||||
// (rho, q_rho).
|
||||
using EosClosureMass = FormSpec<
|
||||
quadrature::Term::eos_closure,
|
||||
0,
|
||||
Operand<Scalar>,
|
||||
Operand<Scalar>>;
|
||||
|
||||
// Integral of density over the physical volume.
|
||||
using MassConservation = FormSpec<
|
||||
quadrature::Term::mass_conservation,
|
||||
0,
|
||||
Operand<Scalar>>;
|
||||
|
||||
// The same physical integral used as a nonlinear normalization
|
||||
// constraint. It has a distinct policy key so solver assembly and
|
||||
// diagnostics can be overintegrated independently.
|
||||
using MassNormalization = FormSpec<
|
||||
quadrature::Term::mass_normalization,
|
||||
0,
|
||||
Operand<Scalar>>;
|
||||
|
||||
// Integral of rho * x. The combined position-coefficient order is
|
||||
// supplied as one dynamic order.
|
||||
using CenterOfMass =
|
||||
FormSpec<quadrature::Term::center_of_mass, 1, Operand<Scalar>>;
|
||||
|
||||
// Integral of rho times the quadratic position tensor. The
|
||||
// combined tensor-coefficient order is supplied dynamically.
|
||||
using Quadrupole =
|
||||
FormSpec<quadrature::Term::quadrupole, 1, Operand<Scalar>>;
|
||||
|
||||
using ErrorNorm = FormSpec<
|
||||
quadrature::Term::error_norm,
|
||||
0,
|
||||
Operand<Scalar>,
|
||||
Operand<Scalar>>;
|
||||
};
|
||||
|
||||
using FormList = TypeList<
|
||||
Form::ProjectionMass,
|
||||
Form::ProjectionSource,
|
||||
Form::EosClosureMass,
|
||||
Form::MassConservation,
|
||||
Form::MassNormalization,
|
||||
Form::CenterOfMass,
|
||||
Form::Quadrupole,
|
||||
Form::ErrorNorm>;
|
||||
};
|
||||
|
||||
// =========================================================================
|
||||
// Gravity
|
||||
// =========================================================================
|
||||
|
||||
struct Gravity {
|
||||
static constexpr std::string_view name = "gravity";
|
||||
|
||||
static constexpr int potentialOrder = 2;
|
||||
static constexpr int fluxOrder = 2;
|
||||
|
||||
struct Potential final
|
||||
: ScalarQ<FieldRelation::Independent, Disc<L2, potentialOrder>> {
|
||||
static constexpr std::string_view symbol = "φ";
|
||||
};
|
||||
|
||||
struct Flux final
|
||||
: VectorQ<FieldRelation::Gradient<Potential>, Disc<RT, fluxOrder>> {
|
||||
static constexpr std::string_view symbol = "∇φ";
|
||||
};
|
||||
|
||||
using Quantities = TypeList<Potential, Flux>;
|
||||
|
||||
using Constraints = TypeList<RtL2StablePair<Flux, Potential>>;
|
||||
|
||||
static constexpr bool constraintsAreValid =
|
||||
validate_constraints(Constraints{});
|
||||
|
||||
static_assert(constraintsAreValid);
|
||||
|
||||
struct Form {
|
||||
using HDivMass = FormSpec<
|
||||
quadrature::Term::gravity_hdiv_mass,
|
||||
0,
|
||||
Operand<Flux>,
|
||||
Operand<Flux>>;
|
||||
|
||||
using DivergenceCoupling = FormSpec<
|
||||
quadrature::Term::gravity_divergence,
|
||||
0,
|
||||
Operand<Flux, FieldOperation::Divergence>,
|
||||
Operand<Potential>>;
|
||||
|
||||
using Boundary = FormSpec<
|
||||
quadrature::Term::gravity_boundary,
|
||||
0,
|
||||
Operand<Flux, FieldOperation::NormalTrace>,
|
||||
Operand<Flux, FieldOperation::NormalTrace>>;
|
||||
|
||||
// Density is a registered coefficient field and potential is the
|
||||
// test field, so the full polynomial order is compile-time data.
|
||||
using SourceLinear = FormSpec<
|
||||
quadrature::Term::gravity_source,
|
||||
0,
|
||||
Operand<Density::Scalar>,
|
||||
Operand<Potential>>;
|
||||
|
||||
// Mixed density-to-potential projection. Both trial and test
|
||||
// orders are registered quantities.
|
||||
using SourceProjection = FormSpec<
|
||||
quadrature::Term::gravity_source,
|
||||
0,
|
||||
Operand<Density::Scalar>,
|
||||
Operand<Potential>>;
|
||||
|
||||
using PotentialErrorNorm = FormSpec<
|
||||
quadrature::Term::error_norm,
|
||||
0,
|
||||
Operand<Potential>,
|
||||
Operand<Potential>>;
|
||||
|
||||
using FluxErrorNorm = FormSpec<
|
||||
quadrature::Term::error_norm,
|
||||
0,
|
||||
Operand<Flux>,
|
||||
Operand<Flux>>;
|
||||
};
|
||||
|
||||
using FormList = TypeList<
|
||||
Form::HDivMass,
|
||||
Form::DivergenceCoupling,
|
||||
Form::Boundary,
|
||||
Form::SourceLinear,
|
||||
Form::SourceProjection,
|
||||
Form::PotentialErrorNorm,
|
||||
Form::FluxErrorNorm>;
|
||||
};
|
||||
|
||||
// =========================================================================
|
||||
// Displacement
|
||||
// =========================================================================
|
||||
|
||||
struct Displacement {
|
||||
static constexpr std::string_view name = "displacement";
|
||||
static constexpr int vectorOrder = 3;
|
||||
|
||||
struct Vector final
|
||||
: VectorQ<FieldRelation::Independent, Disc<H1, vectorOrder>> {
|
||||
static constexpr std::string_view symbol = "d";
|
||||
};
|
||||
|
||||
using Quantities = TypeList<Vector>;
|
||||
using Constraints = TypeList<>;
|
||||
|
||||
static constexpr bool constraintsAreValid =
|
||||
validate_constraints(Constraints{});
|
||||
|
||||
static_assert(constraintsAreValid);
|
||||
|
||||
struct Form {
|
||||
// Harmonic or pseudoelastic interior mesh extension. For the
|
||||
// initial Laplacian model this is (grad d, grad w).
|
||||
using MeshExtension = FormSpec<
|
||||
quadrature::Term::mesh_extension,
|
||||
0,
|
||||
Operand<Vector, FieldOperation::Gradient>,
|
||||
Operand<Vector, FieldOperation::Gradient>>;
|
||||
|
||||
using ErrorNorm = FormSpec<
|
||||
quadrature::Term::error_norm,
|
||||
0,
|
||||
Operand<Vector>,
|
||||
Operand<Vector>>;
|
||||
};
|
||||
|
||||
using FormList = TypeList<Form::MeshExtension, Form::ErrorNorm>;
|
||||
};
|
||||
|
||||
struct BarotropicConstant {
|
||||
static constexpr std::string_view name = "barotropic_constant";
|
||||
|
||||
struct Scalar final : GlobalScalarQ {
|
||||
static constexpr std::string_view symbol = "C";
|
||||
};
|
||||
|
||||
using Quantities = TypeList<Scalar>;
|
||||
using Constraints = TypeList<>;
|
||||
using FormList = TypeList<>;
|
||||
|
||||
static constexpr bool constraintsAreValid =
|
||||
validate_constraints(Constraints{});
|
||||
|
||||
static_assert(constraintsAreValid);
|
||||
};
|
||||
|
||||
// =========================================================================
|
||||
// Specific enthalpy
|
||||
//
|
||||
// Pressure is deliberately not registered as an independent field. For a
|
||||
// barotrope it is derived from h through the EOS, while h supplies the
|
||||
// continuous H1 trace used to define the isobaric stellar surface.
|
||||
// =========================================================================
|
||||
|
||||
struct Enthalpy {
|
||||
static constexpr std::string_view name = "specific_enthalpy";
|
||||
static constexpr int scalarOrder = 3;
|
||||
|
||||
struct Scalar final
|
||||
: ScalarQ<FieldRelation::Independent, Disc<H1, scalarOrder>> {
|
||||
static constexpr std::string_view symbol = "h";
|
||||
};
|
||||
|
||||
using Quantities = TypeList<Scalar>;
|
||||
using Constraints = TypeList<>;
|
||||
|
||||
static constexpr bool constraintsAreValid =
|
||||
validate_constraints(Constraints{});
|
||||
|
||||
static_assert(constraintsAreValid);
|
||||
|
||||
struct Form {
|
||||
// EOS source contribution (rho(h), q_rho). The dynamic order is
|
||||
// the extra polynomial order introduced by the nonlinear EOS
|
||||
// beyond the registered order of h. For an n=3 polytrope this is
|
||||
// 2 * hOrder, making rho(h) cubic in h.
|
||||
using EosClosureSource = FormSpec<
|
||||
quadrature::Term::eos_closure,
|
||||
1,
|
||||
Operand<Scalar>,
|
||||
Operand<Density::Scalar>>;
|
||||
|
||||
// (h, q_h) contribution to
|
||||
// h + phi - Psi_rotation - C = 0.
|
||||
using EquilibriumEnthalpy = FormSpec<
|
||||
quadrature::Term::hydrostatic_equilibrium,
|
||||
0,
|
||||
Operand<Scalar>,
|
||||
Operand<Scalar>>;
|
||||
|
||||
// (phi, q_h) contribution to hydrostatic equilibrium.
|
||||
using EquilibriumGravity = FormSpec<
|
||||
quadrature::Term::hydrostatic_equilibrium,
|
||||
0,
|
||||
Operand<Gravity::Potential>,
|
||||
Operand<Scalar>>;
|
||||
|
||||
// (Psi_rotation, q_h). The rotation-potential order is supplied
|
||||
// dynamically because it belongs to runtime rotation data.
|
||||
using EquilibriumRotation = FormSpec<
|
||||
quadrature::Term::hydrostatic_equilibrium,
|
||||
1,
|
||||
Operand<Scalar>>;
|
||||
|
||||
// (C, q_h), where C is spatially constant.
|
||||
using EquilibriumConstant = FormSpec<
|
||||
quadrature::Term::hydrostatic_equilibrium,
|
||||
0,
|
||||
Operand<BarotropicConstant::Scalar>,
|
||||
Operand<Scalar>>;
|
||||
|
||||
// Boundary trace form available for weak enforcement, testing, or
|
||||
// a future multiplier formulation of h|Gamma_star = 0.
|
||||
using IsobaricSurface = FormSpec<
|
||||
quadrature::Term::isobaric_surface,
|
||||
0,
|
||||
Operand<Scalar>,
|
||||
Operand<Scalar>>;
|
||||
|
||||
// Integral of P(h). The dynamic order is the extra EOS order
|
||||
// beyond the registered order of h.
|
||||
using PressureIntegral = FormSpec<
|
||||
quadrature::Term::pressure_integral,
|
||||
1,
|
||||
Operand<Scalar>>;
|
||||
|
||||
// Weak pressure force in the displacement test space:
|
||||
//
|
||||
// -int P(h) I : grad(w) dV
|
||||
//
|
||||
// which is equivalent to -int P(h) div(w) dV. The dynamic order
|
||||
// is the extra EOS order beyond the registered order of h. For an
|
||||
// n=3 polytrope this is 3 * hOrder, making P(h) quartic in h.
|
||||
using PressureForce = FormSpec<
|
||||
quadrature::Term::pressure_force,
|
||||
1,
|
||||
Operand<Scalar>,
|
||||
Operand<Displacement::Vector, FieldOperation::Gradient>>;
|
||||
|
||||
using ErrorNorm = FormSpec<
|
||||
quadrature::Term::error_norm,
|
||||
0,
|
||||
Operand<Scalar>,
|
||||
Operand<Scalar>>;
|
||||
};
|
||||
|
||||
using FormList = TypeList<
|
||||
Form::EosClosureSource,
|
||||
Form::EquilibriumEnthalpy,
|
||||
Form::EquilibriumGravity,
|
||||
Form::EquilibriumRotation,
|
||||
Form::EquilibriumConstant,
|
||||
Form::IsobaricSurface,
|
||||
Form::PressureIntegral,
|
||||
Form::PressureForce,
|
||||
Form::ErrorNorm>;
|
||||
};
|
||||
|
||||
// =========================================================================
|
||||
// Field definition concept
|
||||
// =========================================================================
|
||||
|
||||
template <typename T>
|
||||
concept FieldTag =
|
||||
requires {
|
||||
typename T::Quantities;
|
||||
typename T::Constraints;
|
||||
typename T::FormList;
|
||||
|
||||
{ T::name } -> std::convertible_to<std::string_view>;
|
||||
} && isRegisteredQuantityList<typename T::Quantities> &&
|
||||
isFieldFormList<typename T::FormList>;
|
||||
|
||||
static_assert(FieldTag<Gravity>);
|
||||
static_assert(FieldTag<Displacement>);
|
||||
static_assert(FieldTag<Density>);
|
||||
static_assert(FieldTag<Enthalpy>);
|
||||
static_assert(FieldTag<BarotropicConstant>);
|
||||
|
||||
static_assert(DerivedQuantity<Gravity::Flux>);
|
||||
|
||||
static_assert(std::same_as<
|
||||
RelationTargetT<Gravity::Flux>,
|
||||
Gravity::Potential>);
|
||||
} // namespace mean_field::field
|
||||
@@ -25,4 +25,4 @@ export namespace mean_field::integrators {
|
||||
private:
|
||||
const mapping::DomainMapper &m_map;
|
||||
};
|
||||
}
|
||||
} // namespace mean_field::integrators
|
||||
@@ -1,14 +1,19 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
export module mean_field:integrators.centrifugal;
|
||||
import :mapping.domain_mapper;
|
||||
export import :mapping.domain_mapper;
|
||||
|
||||
export namespace mean_field::integrators {
|
||||
class CentrifugalForceIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
class CentrifugalForceIntegrator
|
||||
: public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
CentrifugalForceIntegrator(const mapping::DomainMapper& map, const mfem::Vector& omega);
|
||||
CentrifugalForceIntegrator(
|
||||
const mapping::DomainMapper &map,
|
||||
const mfem::Vector &omega
|
||||
);
|
||||
|
||||
void SetOmega(const mfem::Vector& omega);
|
||||
void SetOmega(const mfem::Vector &omega);
|
||||
void SetIntegrationRule(const mfem::IntegrationRule &ir);
|
||||
|
||||
void AssembleElementVector(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
@@ -25,8 +30,9 @@ export namespace mean_field::integrators {
|
||||
) override;
|
||||
|
||||
private:
|
||||
const mapping::DomainMapper& m_map;
|
||||
const mapping::DomainMapper &m_map;
|
||||
mfem::Vector m_omega;
|
||||
const mfem::IntegrationRule *m_ir = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace mean_field::integrators
|
||||
@@ -3,26 +3,32 @@ module;
|
||||
export module mean_field:integrators.coriolis;
|
||||
import :mapping.domain_mapper;
|
||||
|
||||
|
||||
export namespace mean_field::integrators {
|
||||
class CoriolisIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
CoriolisIntegrator(const mapping::DomainMapper& map, const mfem::Vector& omega);
|
||||
CoriolisIntegrator(
|
||||
const mapping::DomainMapper &map,
|
||||
const mfem::Vector &omega
|
||||
);
|
||||
|
||||
void AssembleElementVector(const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array<mfem::Vector *> &elvec) override;
|
||||
void AssembleElementVector(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array<mfem::Vector *> &elvec
|
||||
) override;
|
||||
|
||||
void AssembleElementGrad(const mfem::Array<const mfem::FiniteElement*> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats) override;
|
||||
void AssembleElementGrad(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||
) override;
|
||||
|
||||
private:
|
||||
const mapping::DomainMapper& m_map;
|
||||
const mapping::DomainMapper &m_map;
|
||||
mfem::Vector m_omega;
|
||||
mfem::DenseMatrix m_omega_mat;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace mean_field::integrators
|
||||
@@ -1,14 +1,29 @@
|
||||
module;
|
||||
#include <cstdint>
|
||||
#include <mfem.hpp>
|
||||
export module mean_field:integrators.gravity;
|
||||
import :mapping.domain_mapper;
|
||||
|
||||
export namespace mean_field::integrators {
|
||||
class GravityForceIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
GravityForceIntegrator(const mapping::DomainMapper& map, const mfem::GridFunction& phi);
|
||||
enum class GravityForceJacobianMode : std::uint8_t {
|
||||
minimal,
|
||||
field_coupled,
|
||||
exact
|
||||
};
|
||||
|
||||
void SetPotential(const mfem::GridFunction& phi);
|
||||
class GravityMomentumIntegrator
|
||||
: public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
explicit GravityMomentumIntegrator(
|
||||
const mapping::DomainMapper &map,
|
||||
GravityForceJacobianMode jacobian_mode =
|
||||
GravityForceJacobianMode::field_coupled
|
||||
);
|
||||
|
||||
void SetJacobianMode(GravityForceJacobianMode jacobian_mode);
|
||||
void SetIntegrationRule(const mfem::IntegrationRule &integration_rule);
|
||||
|
||||
[[nodiscard]] GravityForceJacobianMode GetJacobianMode() const;
|
||||
|
||||
void AssembleElementVector(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
@@ -16,7 +31,6 @@ export namespace mean_field::integrators {
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array<mfem::Vector *> &elvec
|
||||
) override;
|
||||
|
||||
void AssembleElementGrad(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
@@ -24,9 +38,9 @@ export namespace mean_field::integrators {
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||
) override;
|
||||
|
||||
|
||||
private:
|
||||
const mapping::DomainMapper& m_map;
|
||||
const mfem::GridFunction* m_phi;
|
||||
const mapping::DomainMapper &m_map;
|
||||
GravityForceJacobianMode m_jacobian_mode;
|
||||
const mfem::IntegrationRule *m_integration_rule{nullptr};
|
||||
};
|
||||
}
|
||||
} // namespace mean_field::integrators
|
||||
@@ -4,9 +4,10 @@ export module mean_field:integrators.mass_continuity;
|
||||
import :mapping.domain_mapper;
|
||||
|
||||
export namespace mean_field::integrators {
|
||||
class ContinuityVolumeIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
class ContinuityVolumeIntegrator
|
||||
: public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
explicit ContinuityVolumeIntegrator(const mapping::DomainMapper& map);
|
||||
explicit ContinuityVolumeIntegrator(const mapping::DomainMapper &map);
|
||||
|
||||
void AssembleElementVector(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
@@ -21,13 +22,14 @@ export namespace mean_field::integrators {
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||
) override;
|
||||
|
||||
private:
|
||||
const mapping::DomainMapper& m_map;
|
||||
const mapping::DomainMapper &m_map;
|
||||
};
|
||||
|
||||
class ContinuityFaceIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
explicit ContinuityFaceIntegrator(const mapping::DomainMapper& map);
|
||||
explicit ContinuityFaceIntegrator(const mapping::DomainMapper &map);
|
||||
|
||||
void AssembleFaceVector(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el1,
|
||||
@@ -44,19 +46,20 @@ export namespace mean_field::integrators {
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||
) override;
|
||||
|
||||
private:
|
||||
static bool skip_face(const mfem::FaceElementTransformations& Tr);
|
||||
static bool skip_face(const mfem::FaceElementTransformations &Tr);
|
||||
|
||||
static double compute_u_n(
|
||||
const mfem::Vector& v_dofs,
|
||||
const mfem::Vector& shape_v_minus,
|
||||
const mfem::Vector& n_unit,
|
||||
const mfem::Vector &v_dofs,
|
||||
const mfem::Vector &shape_v_minus,
|
||||
const mfem::Vector &n_unit,
|
||||
int dof_v_minus,
|
||||
int dim
|
||||
);
|
||||
|
||||
private:
|
||||
const mapping::DomainMapper& m_map;
|
||||
const mapping::DomainMapper &m_map;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace mean_field::integrators
|
||||
|
||||
@@ -1,36 +1,47 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
#include "xad_promote_polyfill.h"
|
||||
#include <XAD/XAD.hpp>
|
||||
#include <mfem.hpp>
|
||||
export module mean_field:integrators.pressure_gradient;
|
||||
import :mapping.domain_mapper;
|
||||
import :utils.misc;
|
||||
|
||||
export namespace mean_field::integrators {
|
||||
template <utils::is_xad EOS_T>
|
||||
class PressureGradientIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
class PressureGradientIntegrator
|
||||
: public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
PressureGradientIntegrator(const mapping::DomainMapper& map, utils::EOS_P<EOS_T> eos);
|
||||
PressureGradientIntegrator(
|
||||
const mapping::DomainMapper &map,
|
||||
utils::EOS_P<EOS_T> eos
|
||||
);
|
||||
|
||||
void AssembleElementVector(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array<mfem::Vector *> &elvec
|
||||
) override;
|
||||
void AssembleElementGrad(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||
) override;
|
||||
|
||||
void AssembleElementVector(const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array<mfem::Vector *> &elvec) override;
|
||||
void AssembleElementGrad(const mfem::Array<const mfem::FiniteElement*> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats) override;
|
||||
private:
|
||||
const mapping::DomainMapper& m_map;
|
||||
const mapping::DomainMapper &m_map;
|
||||
utils::EOS_P<EOS_T> m_eos;
|
||||
};
|
||||
|
||||
template <utils::is_xad EOS_T>
|
||||
PressureGradientIntegrator<EOS_T>::PressureGradientIntegrator(
|
||||
const mapping::DomainMapper& map,
|
||||
const mapping::DomainMapper &map,
|
||||
utils::EOS_P<EOS_T> eos
|
||||
) : m_map(map), m_eos(std::move(eos)) {}
|
||||
)
|
||||
: m_map(map),
|
||||
m_eos(std::move(eos)) {
|
||||
}
|
||||
|
||||
template <utils::is_xad EOS_T>
|
||||
void PressureGradientIntegrator<EOS_T>::AssembleElementVector(
|
||||
@@ -43,16 +54,16 @@ export namespace mean_field::integrators {
|
||||
return;
|
||||
}
|
||||
|
||||
const mfem::FiniteElement* fe_v = el[0];
|
||||
const mfem::FiniteElement* fe_rho = el[1];
|
||||
const mfem::FiniteElement *fe_v = el[0];
|
||||
const mfem::FiniteElement *fe_rho = el[1];
|
||||
|
||||
const int dof_v = fe_v->GetDof();
|
||||
const int dof_rho = fe_rho->GetDof();
|
||||
const int dim = Tr.GetSpaceDim();
|
||||
const int dof_v = fe_v->GetDof();
|
||||
const int dof_rho = fe_rho->GetDof();
|
||||
const int dim = Tr.GetSpaceDim();
|
||||
|
||||
const mfem::Vector& rho_dofs = *elfun[1];
|
||||
const mfem::Vector &rho_dofs = *elfun[1];
|
||||
|
||||
mfem::Vector& r_v = *elvec[0];
|
||||
mfem::Vector &r_v = *elvec[0];
|
||||
r_v.SetSize(dof_v * dim);
|
||||
r_v = 0.0;
|
||||
if (elvec[1]) {
|
||||
@@ -63,10 +74,11 @@ export namespace mean_field::integrators {
|
||||
mfem::DenseMatrix dshape_v_ref(dof_v, dim), dshape_v_phys(dof_v, dim);
|
||||
mfem::Vector shape_rho(dof_rho);
|
||||
|
||||
const mfem::IntegrationRule* ir = &mfem::IntRules.Get(fe_v->GetGeomType(), 2 * fe_v->GetOrder());
|
||||
const mfem::IntegrationRule *ir =
|
||||
&mfem::IntRules.Get(fe_v->GetGeomType(), 2 * fe_v->GetOrder());
|
||||
|
||||
for (int q = 0; q < ir->GetNPoints(); ++q) {
|
||||
const mfem::IntegrationPoint& ip = ir->IntPoint(q);
|
||||
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
||||
Tr.SetIntPoint(&ip);
|
||||
|
||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
||||
@@ -76,13 +88,15 @@ export namespace mean_field::integrators {
|
||||
fe_rho->CalcShape(ip, shape_rho);
|
||||
|
||||
double rho_val = 0.0;
|
||||
for (int i = 0; i < dof_rho; ++i) rho_val += rho_dofs(i) * shape_rho(i);
|
||||
for (int i = 0; i < dof_rho; ++i)
|
||||
rho_val += rho_dofs(i) * shape_rho(i);
|
||||
|
||||
// Guard against negative density from Newton solver overshoots
|
||||
if (rho_val < 1e-15) rho_val = 1e-15;
|
||||
if (rho_val < 1e-15)
|
||||
rho_val = 1e-15;
|
||||
|
||||
// Evaluate the exact Equation of State Pressure
|
||||
EOS_T x_rho = rho_val;
|
||||
EOS_T x_rho = rho_val;
|
||||
double P_val = m_eos(x_rho, EOS_T(0.0)).value();
|
||||
|
||||
for (int i = 0; i < dof_v; ++i) {
|
||||
@@ -95,36 +109,40 @@ export namespace mean_field::integrators {
|
||||
|
||||
template <utils::is_xad EOS_T>
|
||||
void PressureGradientIntegrator<EOS_T>::AssembleElementGrad(
|
||||
const mfem::Array<const mfem::FiniteElement*> &el,
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||
) {
|
||||
const mfem::FiniteElement* fe_v = el[0];
|
||||
const mfem::FiniteElement* fe_rho = el[1];
|
||||
const mfem::FiniteElement *fe_v = el[0];
|
||||
const mfem::FiniteElement *fe_rho = el[1];
|
||||
|
||||
const int dof_v = fe_v->GetDof();
|
||||
const int dof_rho = fe_rho->GetDof();
|
||||
const int dim = Tr.GetSpaceDim();
|
||||
const int dof_v = fe_v->GetDof();
|
||||
const int dof_rho = fe_rho->GetDof();
|
||||
const int dim = Tr.GetSpaceDim();
|
||||
|
||||
const mfem::Vector& rho_dofs = *elfun[1];
|
||||
const mfem::Vector &rho_dofs = *elfun[1];
|
||||
|
||||
mfem::DenseMatrix* dv_dv = elmats(0, 0);
|
||||
mfem::DenseMatrix* dv_drho = elmats(0, 1);
|
||||
mfem::DenseMatrix *dv_dv = elmats(0, 0);
|
||||
mfem::DenseMatrix *dv_drho = elmats(0, 1);
|
||||
|
||||
if (dv_dv) *dv_dv = 0.0;
|
||||
if (dv_drho) *dv_drho = 0.0;
|
||||
if (!dv_drho) return;
|
||||
if (dv_dv)
|
||||
*dv_dv = 0.0;
|
||||
if (dv_drho)
|
||||
*dv_drho = 0.0;
|
||||
if (!dv_drho)
|
||||
return;
|
||||
|
||||
mfem::DenseMatrix dshape_v_ref(dof_v, dim), dshape_v_phys(dof_v, dim);
|
||||
mfem::Vector shape_rho(dof_rho);
|
||||
|
||||
const mfem::IntegrationRule* ir = &mfem::IntRules.Get(fe_v->GetGeomType(), 2 * fe_v->GetOrder());
|
||||
const mfem::IntegrationRule *ir =
|
||||
&mfem::IntRules.Get(fe_v->GetGeomType(), 2 * fe_v->GetOrder());
|
||||
|
||||
for (int q = 0; q < ir->GetNPoints(); ++q) {
|
||||
using Scalar = EOS_T::value_type;
|
||||
xad::Tape<Scalar> tape;
|
||||
const mfem::IntegrationPoint& ip = ir->IntPoint(q);
|
||||
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
||||
Tr.SetIntPoint(&ip);
|
||||
|
||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
||||
@@ -140,29 +158,32 @@ export namespace mean_field::integrators {
|
||||
for (int i = 0; i < dof_rho; ++i) {
|
||||
x_rho += rho_dofs(i) * shape_rho(i);
|
||||
}
|
||||
if (x_rho < 1e-15) x_rho = EOS_T(1e-15);
|
||||
if (x_rho < 1e-15)
|
||||
x_rho = EOS_T(1e-15);
|
||||
EOS_T x_P = m_eos(x_rho, EOS_T(0.0));
|
||||
tape.registerOutput(x_P);
|
||||
x_P.setAdjoint(1.0);
|
||||
tape.computeAdjoints();
|
||||
double dP_drho = x_rho.getAdjoint();
|
||||
double dP_drho = x_rho.getAdjoint();
|
||||
|
||||
double debug_K = 1.5;
|
||||
double debug_n = 3.0;
|
||||
double analytic_dp = debug_K * (1.0 + 1.0 / debug_n) * std::pow(xad::value(x_rho), 1.0 / debug_n);
|
||||
double debug_K = 1.5;
|
||||
double debug_n = 3.0;
|
||||
double analytic_dp = debug_K * (1.0 + 1.0 / debug_n) *
|
||||
std::pow(xad::value(x_rho), 1.0 / debug_n);
|
||||
|
||||
double ad_err = std::abs(dP_drho - analytic_dp);
|
||||
double ad_err = std::abs(dP_drho - analytic_dp);
|
||||
|
||||
for (int i = 0; i < dof_v; ++i) {
|
||||
for (int c = 0; c < dim; ++c) {
|
||||
int row = i + c * dof_v;
|
||||
for (int j = 0; j < dof_rho; ++j) {
|
||||
int col = j;
|
||||
double term = dshape_v_phys(i, c) * dP_drho * shape_rho(j);
|
||||
double term =
|
||||
dshape_v_phys(i, c) * dP_drho * shape_rho(j);
|
||||
(*dv_drho)(row, col) -= term * weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace mean_field::integrators
|
||||
|
||||
@@ -4,9 +4,13 @@ export module mean_field:integrators.viscosity;
|
||||
import :mapping.domain_mapper;
|
||||
|
||||
export namespace mean_field::integrators {
|
||||
class ViscosityIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
class ViscosityIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
ViscosityIntegrator(const mapping::DomainMapper& map, double mu, int quad_boost);
|
||||
ViscosityIntegrator(
|
||||
const mapping::DomainMapper &map,
|
||||
double mu,
|
||||
int quad_boost
|
||||
);
|
||||
|
||||
void SetMu(const double mu);
|
||||
|
||||
@@ -23,10 +27,11 @@ export namespace mean_field::integrators {
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||
) override;
|
||||
|
||||
private:
|
||||
const mapping::DomainMapper& m_map;
|
||||
const mapping::DomainMapper &m_map;
|
||||
double m_mu;
|
||||
int m_quad_boost;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace mean_field::integrators
|
||||
|
||||
@@ -10,7 +10,7 @@ export namespace mean_field::mapping {
|
||||
public:
|
||||
MappedScalarCoefficient(
|
||||
const DomainMapper &map,
|
||||
mfem::Coefficient &coeff,
|
||||
Coefficient &coeff,
|
||||
COORDINATE_SPACE coord_space = COORDINATE_SPACE::PHYSICAL
|
||||
);
|
||||
|
||||
@@ -21,14 +21,14 @@ export namespace mean_field::mapping {
|
||||
|
||||
private:
|
||||
static double eval_at_point(
|
||||
mfem::Coefficient &c,
|
||||
Coefficient &c,
|
||||
mfem::ElementTransformation &T,
|
||||
const mfem::IntegrationPoint &ip
|
||||
);
|
||||
|
||||
private:
|
||||
const DomainMapper &m_map;
|
||||
mfem::Coefficient &m_coeff;
|
||||
Coefficient &m_coeff;
|
||||
COORDINATE_SPACE m_coord_space;
|
||||
};
|
||||
|
||||
@@ -42,29 +42,37 @@ export namespace mean_field::mapping {
|
||||
|
||||
MappedDiffusionCoefficient(
|
||||
const DomainMapper &map,
|
||||
mfem::MatrixCoefficient &sigma
|
||||
MatrixCoefficient &sigma
|
||||
);
|
||||
|
||||
void Eval(mfem::DenseMatrix &K, mfem::ElementTransformation &T, const mfem::IntegrationPoint &ip) override;
|
||||
void Eval(
|
||||
mfem::DenseMatrix &K,
|
||||
mfem::ElementTransformation &T,
|
||||
const mfem::IntegrationPoint &ip
|
||||
) override;
|
||||
|
||||
private:
|
||||
const DomainMapper &m_map;
|
||||
mfem::Coefficient *m_scalar;
|
||||
mfem::MatrixCoefficient *m_tensor;
|
||||
MatrixCoefficient *m_tensor;
|
||||
};
|
||||
|
||||
class MappedVectorCoefficient : public mfem::VectorCoefficient {
|
||||
public:
|
||||
MappedVectorCoefficient(
|
||||
const DomainMapper &map,
|
||||
mfem::VectorCoefficient &coeff
|
||||
VectorCoefficient &coeff
|
||||
);
|
||||
|
||||
void Eval(mfem::Vector &V, mfem::ElementTransformation &T, const mfem::IntegrationPoint &ip) override;
|
||||
void Eval(
|
||||
mfem::Vector &V,
|
||||
mfem::ElementTransformation &T,
|
||||
const mfem::IntegrationPoint &ip
|
||||
) override;
|
||||
|
||||
private:
|
||||
const DomainMapper &m_map;
|
||||
mfem::VectorCoefficient &m_coeff;
|
||||
VectorCoefficient &m_coeff;
|
||||
};
|
||||
|
||||
class PhysicalPositionFunctionCoefficient : public mfem::Coefficient {
|
||||
@@ -76,7 +84,10 @@ export namespace mean_field::mapping {
|
||||
Func f
|
||||
);
|
||||
|
||||
double Eval(mfem::ElementTransformation &T, const mfem::IntegrationPoint &ip) override;
|
||||
double Eval(
|
||||
mfem::ElementTransformation &T,
|
||||
const mfem::IntegrationPoint &ip
|
||||
) override;
|
||||
|
||||
private:
|
||||
Func m_f;
|
||||
@@ -85,11 +96,18 @@ export namespace mean_field::mapping {
|
||||
|
||||
class MappedHDivMassCoefficient final : public mfem::MatrixCoefficient {
|
||||
public:
|
||||
MappedHDivMassCoefficient(const DomainMapper& map, const int dim);
|
||||
MappedHDivMassCoefficient(
|
||||
const DomainMapper &map,
|
||||
const int dim
|
||||
);
|
||||
|
||||
void Eval(
|
||||
mfem::DenseMatrix &matrix,
|
||||
mfem::ElementTransformation &transformation,
|
||||
const mfem::IntegrationPoint &integration_point
|
||||
) override;
|
||||
|
||||
void Eval(mfem::DenseMatrix& matrix, mfem::ElementTransformation& transformation, const mfem::IntegrationPoint& integration_point) override;
|
||||
private:
|
||||
const DomainMapper& m_map;
|
||||
|
||||
const DomainMapper &m_map;
|
||||
};
|
||||
}
|
||||
} // namespace mean_field::mapping
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
export module mean_field:mapping.compactification;
|
||||
export import :mapping.types;
|
||||
|
||||
export namespace mean_field::mapping::compactification {
|
||||
struct ExteriorMapInput {
|
||||
const mfem::Vector &reference_position;
|
||||
const mfem::Vector &displaced_position;
|
||||
const mfem::DenseMatrix &displacement_jacobian;
|
||||
double compactification_coordinate;
|
||||
const mfem::Vector &compactification_coordinate_gradient;
|
||||
};
|
||||
|
||||
struct ExteriorMapResult {
|
||||
mfem::Vector physical_position;
|
||||
mfem::DenseMatrix mapping_jacobian;
|
||||
};
|
||||
|
||||
struct ExteriorMapDirection {
|
||||
const mfem::Vector &displaced_position_variation;
|
||||
const mfem::DenseMatrix &displacement_jacobian_variation;
|
||||
};
|
||||
|
||||
struct ExteriorMapVariation {
|
||||
mfem::Vector physical_position_variation;
|
||||
mfem::DenseMatrix mapping_jacobian_variation;
|
||||
};
|
||||
|
||||
class ExteriorDomainMap {
|
||||
public:
|
||||
virtual ~ExteriorDomainMap() = default;
|
||||
|
||||
[[nodiscard]] virtual MappingStatus Evaluate(
|
||||
const ExteriorMapInput &input,
|
||||
ExteriorMapResult &result
|
||||
) const = 0;
|
||||
[[nodiscard]] virtual MappingStatus EvaluateVariation(
|
||||
const ExteriorMapInput &input,
|
||||
const ExteriorMapResult &result,
|
||||
const ExteriorMapDirection &direction,
|
||||
ExteriorMapVariation &variation
|
||||
) const = 0;
|
||||
[[nodiscard]] virtual std::string_view GetName() const noexcept = 0;
|
||||
};
|
||||
} // namespace mean_field::mapping::compactification
|
||||
50
libmeanfield/interface/mapping/compactification/kelvin.cppm
Normal file
50
libmeanfield/interface/mapping/compactification/kelvin.cppm
Normal file
@@ -0,0 +1,50 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:mapping.kelvin;
|
||||
export import :mapping.compactification;
|
||||
export import :mapping.types;
|
||||
export import :mapping.compactification.options;
|
||||
|
||||
export namespace mean_field::mapping::compactification {
|
||||
|
||||
class KelvinCompactification final : public ExteriorDomainMap {
|
||||
public:
|
||||
explicit KelvinCompactification(
|
||||
options::KelvinCompactificationOptions options
|
||||
);
|
||||
|
||||
[[nodiscard]] MappingStatus Evaluate(
|
||||
const ExteriorMapInput &input,
|
||||
ExteriorMapResult &result
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] MappingStatus EvaluateVariation(
|
||||
const ExteriorMapInput &input,
|
||||
const ExteriorMapResult &result,
|
||||
const ExteriorMapDirection &direction,
|
||||
ExteriorMapVariation &variation
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] std::string_view GetName() const noexcept override;
|
||||
|
||||
[[nodiscard]] double GetReferenceStellarRadius() const noexcept;
|
||||
[[nodiscard]] double GetReferenceInfinityRadius() const noexcept;
|
||||
[[nodiscard]] double GetCoordinateTolerance() const noexcept;
|
||||
|
||||
private:
|
||||
struct RadialFactors {
|
||||
double coordinate;
|
||||
double computational_radius;
|
||||
double scale;
|
||||
double scale_derivative;
|
||||
};
|
||||
|
||||
[[nodiscard]] MappingStatus ComputeRadialFactors(
|
||||
double compactification_coordinate,
|
||||
RadialFactors &factors
|
||||
) const;
|
||||
|
||||
options::KelvinCompactificationOptions m_options;
|
||||
};
|
||||
} // namespace mean_field::mapping::compactification
|
||||
@@ -0,0 +1,9 @@
|
||||
export module mean_field:mapping.compactification.options;
|
||||
|
||||
export namespace mean_field::mapping::compactification::options {
|
||||
struct KelvinCompactificationOptions {
|
||||
double r_star_ref{1.0};
|
||||
double r_inf_ref{2.0};
|
||||
double coordinate_tolerance{1.0e-12};
|
||||
};
|
||||
} // namespace mean_field::mapping::compactification::options
|
||||
@@ -3,51 +3,302 @@ module;
|
||||
#include "mean_field.h"
|
||||
|
||||
export module mean_field:mapping.domain_mapper;
|
||||
export import :mapping.types;
|
||||
import :mapping.compactification;
|
||||
import :utils.user;
|
||||
|
||||
export namespace mean_field::mapping {
|
||||
enum class FaceElementSide : uint8_t { element_1, element_2 };
|
||||
|
||||
class ElementDisplacementData {
|
||||
public:
|
||||
ElementDisplacementData(
|
||||
const mfem::FiniteElement &element,
|
||||
const mfem::Vector &displacement_dofs,
|
||||
mfem::Ordering::Type ordering = mfem::Ordering::byNODES
|
||||
);
|
||||
|
||||
[[nodiscard]] const mfem::FiniteElement &GetElement() const noexcept;
|
||||
[[nodiscard]] const mfem::DenseMatrix &GetDofMatrix() const noexcept;
|
||||
[[nodiscard]] int GetDimension() const noexcept;
|
||||
[[nodiscard]] int GetDofCount() const noexcept;
|
||||
[[nodiscard]] mfem::Ordering::Type GetOrdering() const noexcept;
|
||||
|
||||
private:
|
||||
const mfem::FiniteElement *m_element;
|
||||
mfem::DenseMatrix m_dof_matrix;
|
||||
int m_dimension;
|
||||
mfem::Ordering::Type m_ordering;
|
||||
};
|
||||
|
||||
struct CompactificationPointData {
|
||||
double coordinate{0.0};
|
||||
mfem::Vector coordinate_gradient;
|
||||
};
|
||||
|
||||
[[nodiscard]] ElementDisplacementData
|
||||
ElementDisplacementDataFromElementVDofs(
|
||||
const mfem::FiniteElement &element,
|
||||
const mfem::Vector &displacement_dofs
|
||||
);
|
||||
|
||||
class ElementCompactificationData {
|
||||
public:
|
||||
ElementCompactificationData(
|
||||
const mfem::FiniteElement &element,
|
||||
const mfem::Vector &dofs
|
||||
);
|
||||
|
||||
[[nodiscard]] const mfem::FiniteElement &GetElement() const noexcept;
|
||||
[[nodiscard]] const mfem::Vector &GetDofs() const noexcept;
|
||||
[[nodiscard]] int GetDofCount() const noexcept;
|
||||
|
||||
private:
|
||||
const mfem::FiniteElement *m_element;
|
||||
mfem::Vector m_dofs;
|
||||
};
|
||||
|
||||
struct ElementMappingData {
|
||||
const ElementDisplacementData &displacement;
|
||||
const ElementCompactificationData &compactification;
|
||||
};
|
||||
|
||||
class DomainMapperStateless {
|
||||
public:
|
||||
class Workspace {
|
||||
public:
|
||||
explicit Workspace(int dimension = 3);
|
||||
|
||||
void SetDimension(int dimension);
|
||||
|
||||
[[nodiscard]] int GetDimension() const noexcept;
|
||||
|
||||
private:
|
||||
friend class DomainMapperStateless;
|
||||
|
||||
int m_dimension;
|
||||
|
||||
mfem::Vector m_shape;
|
||||
mfem::DenseMatrix m_mesh_dshape;
|
||||
mfem::Vector m_field_value;
|
||||
mfem::DenseMatrix m_field_jacobian;
|
||||
|
||||
mfem::Vector m_compactification_shape;
|
||||
mfem::DenseMatrix m_compactification_dshape;
|
||||
CompactificationPointData m_compactification_point;
|
||||
|
||||
mfem::Vector m_reference_normal;
|
||||
mfem::Vector m_mapped_normal;
|
||||
mfem::DenseMatrix m_full_element_jacobian;
|
||||
|
||||
mfem::Vector m_vector_temp;
|
||||
mfem::DenseMatrix m_matrix_temp_1;
|
||||
mfem::DenseMatrix m_matrix_temp_2;
|
||||
|
||||
compactification::ExteriorMapResult m_exterior_result;
|
||||
compactification::ExteriorMapVariation m_exterior_variation;
|
||||
};
|
||||
|
||||
public:
|
||||
DomainMapperStateless(
|
||||
utils::DomainMapperStatelessOptions options,
|
||||
std::unique_ptr<const compactification::ExteriorDomainMap>
|
||||
exterior_map
|
||||
);
|
||||
|
||||
DomainMapperStateless(const DomainMapperStateless &) = delete;
|
||||
DomainMapperStateless &
|
||||
operator=(const DomainMapperStateless &) = delete;
|
||||
DomainMapperStateless(DomainMapperStateless &&) = default;
|
||||
DomainMapperStateless &operator=(DomainMapperStateless &&) = default;
|
||||
|
||||
[[nodiscard]] MappingStatus EvaluatePoint(
|
||||
const ElementMappingData &element_data,
|
||||
mfem::ElementTransformation &transformation,
|
||||
const mfem::IntegrationPoint &integration_point,
|
||||
Workspace &workspace,
|
||||
MappingPointContext &context
|
||||
) const;
|
||||
|
||||
[[nodiscard]] MappingStatus EvaluateVolume(
|
||||
const ElementMappingData &element_data,
|
||||
mfem::ElementTransformation &transformation,
|
||||
const mfem::IntegrationPoint &integration_point,
|
||||
Workspace &workspace,
|
||||
VolumeMappingContext &context
|
||||
) const;
|
||||
|
||||
[[nodiscard]] MappingStatus EvaluateFace(
|
||||
const ElementMappingData &element_data,
|
||||
mfem::FaceElementTransformations &transformation,
|
||||
FaceElementSide side,
|
||||
const mfem::IntegrationPoint &integration_point,
|
||||
Workspace &workspace,
|
||||
FaceMappingContext &context
|
||||
) const;
|
||||
|
||||
[[nodiscard]] MappingStatus EvaluatePointVariation(
|
||||
const ElementMappingData &element_data,
|
||||
const ElementDisplacementData &direction,
|
||||
mfem::ElementTransformation &transformation,
|
||||
const mfem::IntegrationPoint &integration_point,
|
||||
const MappingPointContext &base_context,
|
||||
Workspace &workspace,
|
||||
MappingPointVariation &variation
|
||||
) const;
|
||||
|
||||
[[nodiscard]] MappingStatus EvaluateVolumeVariation(
|
||||
const ElementMappingData &element_data,
|
||||
const ElementDisplacementData &direction,
|
||||
mfem::ElementTransformation &transformation,
|
||||
const mfem::IntegrationPoint &integration_point,
|
||||
const VolumeMappingContext &base_context,
|
||||
Workspace &workspace,
|
||||
VolumeMappingVariation &variation
|
||||
) const;
|
||||
|
||||
[[nodiscard]] MappingStatus EvaluateFaceVariation(
|
||||
const ElementMappingData &element_data,
|
||||
const ElementDisplacementData &direction,
|
||||
mfem::FaceElementTransformations &transformation,
|
||||
FaceElementSide side,
|
||||
const mfem::IntegrationPoint &integration_point,
|
||||
const FaceMappingContext &base_context,
|
||||
Workspace &workspace,
|
||||
FaceMappingVariation &variation
|
||||
) const;
|
||||
|
||||
[[nodiscard]] bool IsCompactifiedElement(
|
||||
const mfem::ElementTransformation &transformation
|
||||
) const noexcept;
|
||||
[[nodiscard]] int GetDimension() const noexcept;
|
||||
[[nodiscard]] int GetVacuumElementAttribute() const noexcept;
|
||||
[[nodiscard]] const compactification::ExteriorDomainMap &
|
||||
GetExteriorMap() const noexcept;
|
||||
|
||||
private:
|
||||
void ValidateElementData(const ElementMappingData &element_data) const;
|
||||
|
||||
void EvaluateField(
|
||||
const ElementDisplacementData &field,
|
||||
mfem::ElementTransformation &transformation,
|
||||
const mfem::IntegrationPoint &integration_point,
|
||||
Workspace &workspace,
|
||||
mfem::Vector &value,
|
||||
mfem::DenseMatrix &jacobian
|
||||
) const;
|
||||
|
||||
[[nodiscard]] MappingStatus EvaluateCompactificationCoordinate(
|
||||
const ElementCompactificationData &compactification,
|
||||
mfem::ElementTransformation &transformation,
|
||||
const mfem::IntegrationPoint &integration_point,
|
||||
Workspace &workspace,
|
||||
CompactificationPointData &point_data
|
||||
) const;
|
||||
|
||||
[[nodiscard]] static mfem::ElementTransformation &
|
||||
SelectFaceElementTransformation(
|
||||
mfem::FaceElementTransformations &transformation,
|
||||
FaceElementSide side
|
||||
);
|
||||
|
||||
[[nodiscard]] static const mfem::IntegrationPoint &
|
||||
SelectFaceElementIntegrationPoint(
|
||||
mfem::FaceElementTransformations &transformation,
|
||||
FaceElementSide side
|
||||
);
|
||||
|
||||
utils::DomainMapperStatelessOptions m_options;
|
||||
std::unique_ptr<const compactification::ExteriorDomainMap>
|
||||
m_exterior_map;
|
||||
};
|
||||
class DomainMapper {
|
||||
public:
|
||||
struct VolumeQuadratureContext {
|
||||
mfem::DenseMatrix J_inv;
|
||||
double detJ;
|
||||
double weight;
|
||||
};
|
||||
|
||||
struct FaceQuadratureContext {
|
||||
mfem::Vector normal;
|
||||
double ds;
|
||||
double v_dot_n_scale;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit DomainMapper(const double r_star_ref, const double r_inf_ref);
|
||||
explicit DomainMapper(
|
||||
const double r_star_ref,
|
||||
const double r_inf_ref
|
||||
);
|
||||
|
||||
explicit DomainMapper(const mfem::GridFunction &d, const double r_star_ref, const double r_inf_ref);
|
||||
explicit DomainMapper(
|
||||
const mfem::GridFunction &d,
|
||||
const double r_star_ref,
|
||||
const double r_inf_ref
|
||||
);
|
||||
|
||||
[[nodiscard]] bool is_vacuum(const mfem::ElementTransformation &T) const;
|
||||
[[nodiscard]] bool
|
||||
is_vacuum(const mfem::ElementTransformation &T) const;
|
||||
|
||||
void SetDisplacement(const mfem::GridFunction &d);
|
||||
|
||||
[[nodiscard]] bool IsIdentity() const;
|
||||
[[nodiscard]] bool HasCompactification() const noexcept;
|
||||
[[nodiscard]] bool HasDisplacementField() const noexcept;
|
||||
[[nodiscard]] bool CalcIsIdentity() const;
|
||||
|
||||
void ResetDisplacement();
|
||||
|
||||
void ComputeJacobian(mfem::ElementTransformation &T, mfem::DenseMatrix &J) const;
|
||||
void ComputeJacobian(
|
||||
mfem::ElementTransformation &T,
|
||||
mfem::DenseMatrix &J
|
||||
) const;
|
||||
|
||||
double ComputeDetJ(mfem::ElementTransformation &T, const mfem::IntegrationPoint &ip) const;
|
||||
double ComputeDetJ(
|
||||
mfem::ElementTransformation &T,
|
||||
const mfem::IntegrationPoint &ip
|
||||
) const;
|
||||
|
||||
void ComputeMappedDiffusionTensor(mfem::ElementTransformation &T, mfem::DenseMatrix &D) const;
|
||||
void ComputeMappedDiffusionTensor(
|
||||
mfem::ElementTransformation &T,
|
||||
mfem::DenseMatrix &D
|
||||
) const;
|
||||
|
||||
void ComputeInverseJacobian(mfem::ElementTransformation &T, mfem::DenseMatrix &JInv) const;
|
||||
void ComputeInverseJacobian(
|
||||
mfem::ElementTransformation &T,
|
||||
mfem::DenseMatrix &JInv
|
||||
) const;
|
||||
|
||||
VolumeQuadratureContext GetQuadratureContext(mfem::ElementTransformation &T, const mfem::IntegrationPoint &ip) const;
|
||||
VolumeQuadratureContext GetQuadratureContext(
|
||||
mfem::ElementTransformation &T,
|
||||
const mfem::IntegrationPoint &ip
|
||||
) const;
|
||||
|
||||
FaceQuadratureContext GetFaceQuadratureContext(mfem::FaceElementTransformations &T, const mfem::IntegrationPoint &ip) const;
|
||||
FaceQuadratureContext GetFaceQuadratureContext(
|
||||
mfem::FaceElementTransformations &T,
|
||||
const mfem::IntegrationPoint &ip
|
||||
) const;
|
||||
|
||||
void GetPhysicalPoint(mfem::ElementTransformation &T, const mfem::IntegrationPoint &ip, mfem::Vector &x_phys) const;
|
||||
void GetPhysicalPoint(
|
||||
mfem::ElementTransformation &T,
|
||||
const mfem::IntegrationPoint &ip,
|
||||
mfem::Vector &x_phys
|
||||
) const;
|
||||
|
||||
void GetVectorValue(const int i, const mfem::IntegrationPoint &ip, mfem::Vector &val) const;
|
||||
void GetVectorValue(
|
||||
const int i,
|
||||
const mfem::IntegrationPoint &ip,
|
||||
mfem::Vector &val
|
||||
) const;
|
||||
|
||||
void MapHDivFluxToPhysical(
|
||||
mfem::ElementTransformation &transformation,
|
||||
const mfem::IntegrationPoint &integration_point,
|
||||
const mfem::Vector &reference_flux,
|
||||
mfem::Vector &physical_flux
|
||||
) const;
|
||||
|
||||
void MapPhysicalFluxToHDivReference(
|
||||
mfem::ElementTransformation &transformation,
|
||||
const mfem::IntegrationPoint &integration_point,
|
||||
const mfem::Vector &physical_flux,
|
||||
mfem::Vector &reference_flux
|
||||
) const;
|
||||
|
||||
void MapReferenceGradientToPhysical(
|
||||
mfem::ElementTransformation &transformation,
|
||||
const mfem::IntegrationPoint &integration_point,
|
||||
const mfem::Vector &reference_gradient,
|
||||
mfem::Vector &physical_gradient
|
||||
) const;
|
||||
[[nodiscard]] const mfem::GridFunction *GetDisplacement() const;
|
||||
|
||||
[[nodiscard]] double GetPhysInfRadius() const;
|
||||
@@ -63,9 +314,17 @@ export namespace mean_field::mapping {
|
||||
private:
|
||||
void InitAllScratchSpaces() const;
|
||||
|
||||
void ApplyKelvinMapping(const mfem::Vector &x_ref, mfem::Vector &x_phys) const;
|
||||
void ApplyKelvinMapping(
|
||||
const mfem::Vector &x_ref,
|
||||
mfem::Vector &x_phys
|
||||
) const;
|
||||
|
||||
void ComputeKelvinJacobian(const mfem::Vector &x_ref, const mfem::Vector &x_disp, const mfem::DenseMatrix &J_D, mfem::DenseMatrix &J) const;
|
||||
void ComputeKelvinJacobian(
|
||||
const mfem::Vector &x_ref,
|
||||
const mfem::Vector &x_disp,
|
||||
const mfem::DenseMatrix &J_D,
|
||||
mfem::DenseMatrix &J
|
||||
) const;
|
||||
|
||||
void InvalidateCache() const;
|
||||
|
||||
@@ -98,6 +357,8 @@ export namespace mean_field::mapping {
|
||||
mutable mfem::Vector m_x_ref;
|
||||
mutable mfem::Vector m_x_disp;
|
||||
mutable mfem::Vector m_d_val;
|
||||
|
||||
bool m_displacement_is_identity{true};
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace mean_field::mapping
|
||||
|
||||
87
libmeanfield/interface/mapping/transformations.cppm
Normal file
87
libmeanfield/interface/mapping/transformations.cppm
Normal file
@@ -0,0 +1,87 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
export module mean_field:mapping.transformations;
|
||||
export import :mapping.types;
|
||||
|
||||
export namespace mean_field::mapping {
|
||||
void MapHDivFluxToPhysical(
|
||||
const MappingPointContext &context,
|
||||
const mfem::Vector &reference_flux,
|
||||
mfem::Vector &physical_flux
|
||||
);
|
||||
void MapPhysicalFluxToHDivReference(
|
||||
const MappingPointContext &context,
|
||||
const mfem::Vector &physical_flux,
|
||||
mfem::Vector &reference_flux
|
||||
);
|
||||
|
||||
void MapReferenceGradientToPhysical(
|
||||
const MappingPointContext &context,
|
||||
const mfem::Vector &reference_gradient,
|
||||
mfem::Vector &physical_gradient
|
||||
);
|
||||
void MapPhysicalGradientToReference(
|
||||
const MappingPointContext &context,
|
||||
const mfem::Vector &physical_gradient,
|
||||
mfem::Vector &reference_gradient
|
||||
);
|
||||
|
||||
void MapReferenceVectorGradientToPhysical(
|
||||
const MappingPointContext &context,
|
||||
const mfem::DenseMatrix &reference_gradient,
|
||||
mfem::DenseMatrix &physical_gradient
|
||||
);
|
||||
void MapPhysicalVectorGradientToReference(
|
||||
const MappingPointContext &context,
|
||||
const mfem::DenseMatrix &physical_gradient,
|
||||
mfem::DenseMatrix &reference_gradient
|
||||
);
|
||||
|
||||
[[nodiscard]] double MapHDivDivergenceToPhysical(
|
||||
const MappingPointContext &context,
|
||||
double reference_divergence
|
||||
);
|
||||
|
||||
void ComputeHDivMassTensor(
|
||||
const MappingPointContext &context,
|
||||
mfem::DenseMatrix &mass_tensor
|
||||
);
|
||||
void ComputeScalarDiffusionTensor(
|
||||
const MappingPointContext &context,
|
||||
mfem::DenseMatrix &diffusion_tensor
|
||||
);
|
||||
|
||||
void MapHCurlFieldToPhysical(
|
||||
const MappingPointContext &context,
|
||||
const mfem::Vector &reference_field,
|
||||
mfem::Vector &physical_field
|
||||
);
|
||||
void MapPhysicalFieldToHCurlReference(
|
||||
const MappingPointContext &context,
|
||||
const mfem::Vector &physical_field,
|
||||
mfem::Vector &reference_field
|
||||
);
|
||||
void MapHCurlCurlToPhysical(
|
||||
const MappingPointContext &context,
|
||||
const mfem::Vector &reference_curl,
|
||||
mfem::Vector &physical_curl
|
||||
);
|
||||
void MapPhysicalCurlToHCurlReference(
|
||||
const MappingPointContext &context,
|
||||
const mfem::Vector &physical_curl,
|
||||
mfem::Vector &reference_curl
|
||||
);
|
||||
void ComputeHCurlMassTensor(
|
||||
const MappingPointContext &context,
|
||||
mfem::DenseMatrix &mass_tensor
|
||||
);
|
||||
void ComputeHCurlCurlTensor(
|
||||
const MappingPointContext &context,
|
||||
mfem::DenseMatrix &curl_tensor
|
||||
);
|
||||
void ComputeHDivMassTensorVariation(
|
||||
const MappingPointContext &context,
|
||||
const MappingPointVariation &variation,
|
||||
mfem::DenseMatrix &mass_tensor_variation
|
||||
);
|
||||
} // namespace mean_field::mapping
|
||||
@@ -1,10 +1,77 @@
|
||||
module;
|
||||
#include <cstdint>
|
||||
#include <mfem.hpp>
|
||||
export module mean_field:mapping.types;
|
||||
|
||||
namespace mean_field::mapping {
|
||||
enum class COORDINATE_SPACE : uint8_t {
|
||||
PHYSICAL,
|
||||
REFERENCE
|
||||
export namespace mean_field::mapping {
|
||||
enum class COORDINATE_SPACE : uint8_t { PHYSICAL, REFERENCE };
|
||||
|
||||
enum class MappingStatus : uint8_t {
|
||||
valid,
|
||||
invalid_dimension,
|
||||
non_finite_input,
|
||||
invalid_reference_radius,
|
||||
at_compactified_infinity,
|
||||
outside_reference_domain,
|
||||
non_finite_result,
|
||||
non_positive_determinant
|
||||
};
|
||||
}
|
||||
|
||||
struct VolumeQuadratureContext {
|
||||
mfem::DenseMatrix J_inv;
|
||||
double detJ;
|
||||
double weight;
|
||||
};
|
||||
|
||||
struct FaceQuadratureContext {
|
||||
mfem::Vector normal;
|
||||
double ds;
|
||||
double v_dot_n_scale;
|
||||
};
|
||||
|
||||
struct MappingPointContext {
|
||||
mfem::Vector reference_position;
|
||||
mfem::Vector displaced_position;
|
||||
mfem::Vector physical_position;
|
||||
mfem::DenseMatrix displacement_jacobian;
|
||||
mfem::DenseMatrix mapping_jacobian;
|
||||
mfem::DenseMatrix inverse_mapping_jacobian;
|
||||
double mapping_determinant{0.0};
|
||||
bool compactified{false};
|
||||
};
|
||||
|
||||
struct VolumeMappingContext {
|
||||
MappingPointContext mapping;
|
||||
VolumeQuadratureContext quadrature;
|
||||
};
|
||||
|
||||
struct FaceMappingContext {
|
||||
MappingPointContext mapping;
|
||||
FaceQuadratureContext quadrature;
|
||||
mfem::Vector reference_normal;
|
||||
double reference_surface_weight{0.0};
|
||||
double physical_surface_weight{0.0};
|
||||
};
|
||||
|
||||
struct MappingPointVariation {
|
||||
mfem::Vector displacement_variation;
|
||||
mfem::Vector physical_position_variation;
|
||||
mfem::DenseMatrix displacement_jacobian_variation;
|
||||
mfem::DenseMatrix mapping_jacobian_variation;
|
||||
mfem::DenseMatrix inverse_mapping_jacobian_variation;
|
||||
double mapping_determinant_variation{0.0};
|
||||
};
|
||||
|
||||
struct VolumeMappingVariation {
|
||||
MappingPointVariation mapping;
|
||||
mfem::DenseMatrix inverse_element_jacobian_variation;
|
||||
double weight_variation{0.0};
|
||||
};
|
||||
|
||||
struct FaceMappingVariation {
|
||||
MappingPointVariation mapping;
|
||||
mfem::Vector physical_normal_variation;
|
||||
double physical_surface_weight_variation{0.0};
|
||||
double normal_flux_scale_variation{0.0};
|
||||
};
|
||||
} // namespace mean_field::mapping
|
||||
@@ -5,11 +5,18 @@ export import :utils.misc;
|
||||
export import :utils.user;
|
||||
export import :utils.domain;
|
||||
export import :physics.gravity;
|
||||
export import :physics.solid_body;
|
||||
export import :physics.barotrope;
|
||||
export import :physics.contexts;
|
||||
export import :boundary.contexts;
|
||||
export import :analysis.integral;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :mapping.coefficients;
|
||||
export import :mapping.compactification;
|
||||
export import :mapping.kelvin;
|
||||
export import :mapping.transformations;
|
||||
export import :mapping.types;
|
||||
export import :mapping.compactification.options;
|
||||
export import :integrators.advection;
|
||||
export import :integrators.centrifugal;
|
||||
export import :integrators.gravity;
|
||||
@@ -19,3 +26,22 @@ export import :integrators.pressure_gradient;
|
||||
export import :integrators.viscosity;
|
||||
export import :quadrature.policy;
|
||||
export import :quadrature.mfem;
|
||||
export import :solver.fields;
|
||||
export import :utils.blocks;
|
||||
export import :operators.gravity_field;
|
||||
export import :operators.gravity_field_jacobian;
|
||||
export import :operators.kernels.gravity_field;
|
||||
export import :operators.prepared_gravity_source;
|
||||
export import :operators.prepared_hdiv_mass;
|
||||
export import :operators.context.gravity_field;
|
||||
export import :field.base;
|
||||
export import :field.registry;
|
||||
export import :field.mfem;
|
||||
export import :operators.kernels.barotropic_closure;
|
||||
export import :operators.prepared_barotropic_closure;
|
||||
export import :operators.context.barotropic_closure_linearization;
|
||||
export import :physics.rigid_rotation;
|
||||
export import :operators.kernels.hydrostatic_equilibrium;
|
||||
export import :operators.context.hydrostatic_equilibrium;
|
||||
export import :operators.prepared_hydrostatic_equilibrium;
|
||||
export import :operators.kernels.pressure_force;
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
module;
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:operators.context.barotropic_closure_linearization;
|
||||
|
||||
export import :fem;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :operators.prepared_barotropic_closure;
|
||||
export import :physics.barotrope;
|
||||
|
||||
export namespace mean_field::operators::context::barotropic {
|
||||
struct BarotropicClosureRevisions final {
|
||||
std::uint64_t density = 0;
|
||||
std::uint64_t enthalpy = 0;
|
||||
std::uint64_t displacement = 0;
|
||||
|
||||
[[nodiscard]] bool
|
||||
operator==(const BarotropicClosureRevisions &) const noexcept = default;
|
||||
};
|
||||
|
||||
class BarotropicClosureLinearizationContext final {
|
||||
public:
|
||||
BarotropicClosureLinearizationContext(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope
|
||||
);
|
||||
|
||||
void Prepare(
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
const BarotropicClosureRevisions &revisions
|
||||
);
|
||||
|
||||
[[nodiscard]] bool IsPrepared() const noexcept;
|
||||
|
||||
[[nodiscard]] bool MatchesRevisions(
|
||||
const BarotropicClosureRevisions &revisions
|
||||
) const noexcept;
|
||||
|
||||
[[nodiscard]] std::uint64_t GetPreparationCount() const noexcept;
|
||||
|
||||
[[nodiscard]] const BarotropicClosureRevisions &GetRevisions() const;
|
||||
|
||||
[[nodiscard]] const mfem::Vector &GetBaseDensityTrue() const;
|
||||
|
||||
[[nodiscard]] const mfem::Vector &GetBaseEnthalpyTrue() const;
|
||||
|
||||
[[nodiscard]] const mfem::Vector &GetDisplacementTrue() const;
|
||||
|
||||
[[nodiscard]]
|
||||
const PreparedBarotropicClosureOperator &GetOperator() const noexcept;
|
||||
|
||||
void BuildResidual(mfem::Vector &residual) const;
|
||||
|
||||
private:
|
||||
void VerifyPrepared() const;
|
||||
|
||||
const fem::FEM &m_f;
|
||||
|
||||
PreparedBarotropicClosureOperator m_operator;
|
||||
|
||||
mfem::Vector m_baseDensityTrue;
|
||||
mfem::Vector m_baseEnthalpyTrue;
|
||||
mfem::Vector m_displacementTrue;
|
||||
|
||||
BarotropicClosureRevisions m_revisions;
|
||||
|
||||
std::uint64_t m_preparationCount = 0;
|
||||
bool m_isPrepared = false;
|
||||
};
|
||||
} // namespace mean_field::operators::context::barotropic
|
||||
@@ -0,0 +1,157 @@
|
||||
module;
|
||||
#include <compare>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:operators.context.gravity_field;
|
||||
export import :fem;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :operators.prepared_gravity_source;
|
||||
export import :operators.prepared_hdiv_mass;
|
||||
|
||||
export namespace mean_field::operators::context::gravity_field {
|
||||
template <typename Tag> struct Revision {
|
||||
std::uint64_t value{0};
|
||||
|
||||
constexpr auto operator<=>(const Revision &) const = default;
|
||||
};
|
||||
|
||||
struct DiscretizationRevisionTag { };
|
||||
struct DisplacementRevisionTag { };
|
||||
struct DensityRevisionTag { };
|
||||
struct GravityGradientRevisionTag { };
|
||||
struct GravityPotentialRevisionTag { };
|
||||
|
||||
using DiscretizationRevision = Revision<DiscretizationRevisionTag>;
|
||||
using DisplacementRevision = Revision<DisplacementRevisionTag>;
|
||||
using DensityRevision = Revision<DensityRevisionTag>;
|
||||
using GravityGradientRevision = Revision<GravityGradientRevisionTag>;
|
||||
using GravityPotentialRevision = Revision<GravityPotentialRevisionTag>;
|
||||
|
||||
struct GravityFieldRevisions {
|
||||
DiscretizationRevision discretization;
|
||||
DisplacementRevision displacement;
|
||||
DensityRevision density;
|
||||
GravityGradientRevision gravity_gradient;
|
||||
GravityPotentialRevision gravity_potential;
|
||||
};
|
||||
|
||||
struct GravityFieldStateView {
|
||||
const mfem::Vector &density;
|
||||
const mfem::Vector &displacement;
|
||||
const mfem::Vector &gravity_gradient;
|
||||
const mfem::Vector &gravity_potential;
|
||||
};
|
||||
|
||||
struct GravityFieldGeometryPreparation {
|
||||
bool reconstructed_operators{false};
|
||||
bool rebuilt_mass_operator{false};
|
||||
bool rebuilt_source_operator{false};
|
||||
bool refreshed_variation_state{false};
|
||||
|
||||
[[nodiscard]] bool DidAnyWork() const noexcept {
|
||||
return reconstructed_operators || rebuilt_mass_operator ||
|
||||
rebuilt_source_operator || refreshed_variation_state;
|
||||
}
|
||||
};
|
||||
|
||||
class GravityFieldGeometryContext {
|
||||
public:
|
||||
GravityFieldGeometryContext(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domain_mapper
|
||||
);
|
||||
|
||||
GravityFieldGeometryContext(const GravityFieldGeometryContext &) =
|
||||
delete;
|
||||
GravityFieldGeometryContext &
|
||||
operator=(const GravityFieldGeometryContext &) = delete;
|
||||
GravityFieldGeometryContext(GravityFieldGeometryContext &&) = delete;
|
||||
GravityFieldGeometryContext &
|
||||
operator=(GravityFieldGeometryContext &&) = delete;
|
||||
|
||||
GravityFieldGeometryPreparation Prepare(
|
||||
const mfem::Vector &displacement_true,
|
||||
DiscretizationRevision discretization_revision,
|
||||
DisplacementRevision displacement_revision
|
||||
);
|
||||
|
||||
[[nodiscard]] const PreparedMappedHDivMassOperator &
|
||||
GetMassOperator() const;
|
||||
[[nodiscard]] const PreparedMappedGravitySourceOperator &
|
||||
GetSourceOperator() const;
|
||||
[[nodiscard]] const mfem::Vector &GetDisplacement() const;
|
||||
[[nodiscard]] DiscretizationRevision
|
||||
GetDiscretizationRevision() const noexcept;
|
||||
[[nodiscard]] DisplacementRevision
|
||||
GetDisplacementRevision() const noexcept;
|
||||
[[nodiscard]] bool IsPrepared() const noexcept;
|
||||
|
||||
private:
|
||||
const fem::FEM &m_fem;
|
||||
const mapping::DomainMapperStateless &m_domain_mapper;
|
||||
|
||||
std::unique_ptr<PreparedMappedHDivMassOperator> m_mass_operator;
|
||||
std::unique_ptr<PreparedMappedGravitySourceOperator> m_source_operator;
|
||||
|
||||
mfem::Vector m_displacement_true;
|
||||
|
||||
DiscretizationRevision m_discretization_revision;
|
||||
DisplacementRevision m_displacement_revision;
|
||||
|
||||
bool m_is_prepared{false};
|
||||
};
|
||||
|
||||
struct GravityFieldPreparationReport {
|
||||
GravityFieldGeometryPreparation geometry;
|
||||
bool updated_density{false};
|
||||
bool updated_gravity_gradient{false};
|
||||
|
||||
[[nodiscard]] bool DidAnyWork() const noexcept {
|
||||
return geometry.DidAnyWork() || updated_density ||
|
||||
updated_gravity_gradient;
|
||||
}
|
||||
};
|
||||
|
||||
class GravityFieldLinearizationContext {
|
||||
public:
|
||||
GravityFieldLinearizationContext(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domain_mapper
|
||||
);
|
||||
|
||||
GravityFieldLinearizationContext(
|
||||
const GravityFieldLinearizationContext &
|
||||
) = delete;
|
||||
GravityFieldLinearizationContext &
|
||||
operator=(const GravityFieldLinearizationContext &) = delete;
|
||||
GravityFieldLinearizationContext(GravityFieldLinearizationContext &&) =
|
||||
delete;
|
||||
GravityFieldLinearizationContext &
|
||||
operator=(GravityFieldLinearizationContext &&) = delete;
|
||||
|
||||
GravityFieldPreparationReport Prepare(
|
||||
const GravityFieldStateView &state,
|
||||
const GravityFieldRevisions &revisions
|
||||
);
|
||||
|
||||
[[nodiscard]] const GravityFieldGeometryContext &
|
||||
GetGeometryContext() const;
|
||||
[[nodiscard]] const mfem::Vector &GetDensity() const;
|
||||
[[nodiscard]] const mfem::Vector &GetGravityGradient() const;
|
||||
[[nodiscard]] const GravityFieldRevisions &GetRevisions() const;
|
||||
[[nodiscard]] bool IsPrepared() const noexcept;
|
||||
|
||||
private:
|
||||
const fem::FEM &m_fem;
|
||||
|
||||
GravityFieldGeometryContext m_geometry_context;
|
||||
|
||||
mfem::Vector m_density_true;
|
||||
mfem::Vector m_gravity_gradient_true;
|
||||
|
||||
GravityFieldRevisions m_revisions;
|
||||
bool m_is_prepared{false};
|
||||
};
|
||||
} // namespace mean_field::operators::context::gravity_field
|
||||
@@ -0,0 +1,154 @@
|
||||
module;
|
||||
|
||||
#include <compare>
|
||||
#include <cstdint>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:operators.context.hydrostatic_equilibrium;
|
||||
|
||||
export import :fem;
|
||||
export import :mapping.domain_mapper;
|
||||
|
||||
export namespace mean_field::operators::context::hydrostatic {
|
||||
template <typename Tag> struct DependencyStamp {
|
||||
std::uint64_t identity{0};
|
||||
std::uint64_t revision{0};
|
||||
|
||||
[[nodiscard]] constexpr bool
|
||||
CanFollow(const DependencyStamp &prepared) const noexcept {
|
||||
return identity != prepared.identity ||
|
||||
revision >= prepared.revision;
|
||||
}
|
||||
|
||||
constexpr auto operator<=>(const DependencyStamp &) const = default;
|
||||
};
|
||||
|
||||
struct DiscretizationDependencyTag { };
|
||||
struct EnthalpyDependencyTag { };
|
||||
struct GravityPotentialDependencyTag { };
|
||||
struct DisplacementDependencyTag { };
|
||||
struct RotationDependencyTag { };
|
||||
struct BernoulliConstantDependencyTag { };
|
||||
|
||||
using DiscretizationDependency =
|
||||
DependencyStamp<DiscretizationDependencyTag>;
|
||||
|
||||
using EnthalpyDependency = DependencyStamp<EnthalpyDependencyTag>;
|
||||
|
||||
using GravityPotentialDependency =
|
||||
DependencyStamp<GravityPotentialDependencyTag>;
|
||||
|
||||
using DisplacementDependency = DependencyStamp<DisplacementDependencyTag>;
|
||||
|
||||
using RotationDependency = DependencyStamp<RotationDependencyTag>;
|
||||
|
||||
using BernoulliConstantDependency =
|
||||
DependencyStamp<BernoulliConstantDependencyTag>;
|
||||
|
||||
struct HydrostaticEquilibriumDependencies {
|
||||
DiscretizationDependency discretization;
|
||||
EnthalpyDependency enthalpy;
|
||||
GravityPotentialDependency gravityPotential;
|
||||
DisplacementDependency displacement;
|
||||
RotationDependency rotation;
|
||||
BernoulliConstantDependency bernoulliConstant;
|
||||
|
||||
constexpr auto
|
||||
operator<=>(const HydrostaticEquilibriumDependencies &) const = default;
|
||||
};
|
||||
|
||||
struct HydrostaticEquilibriumStateView {
|
||||
const mfem::Vector &enthalpy;
|
||||
const mfem::Vector &gravityPotential;
|
||||
const mfem::Vector &displacement;
|
||||
double bernoulliConstant{0.0};
|
||||
};
|
||||
|
||||
struct HydrostaticPreparationReport {
|
||||
bool preparedStaticDependencies{false};
|
||||
bool preparedGeometryState{false};
|
||||
bool preparedRotationDependencies{false};
|
||||
bool preparedBaseState{false};
|
||||
|
||||
bool updatedEnthalpy{false};
|
||||
bool updatedGravityPotential{false};
|
||||
bool updatedDisplacement{false};
|
||||
bool updatedBernoulliConstant{false};
|
||||
|
||||
[[nodiscard]] bool DidAnyWork() const noexcept {
|
||||
return preparedStaticDependencies || preparedGeometryState ||
|
||||
preparedRotationDependencies || preparedBaseState;
|
||||
}
|
||||
};
|
||||
|
||||
struct HydrostaticPreparationStatistics {
|
||||
std::uint64_t staticPreparations{0};
|
||||
std::uint64_t geometryPreparations{0};
|
||||
std::uint64_t rotationPreparations{0};
|
||||
std::uint64_t baseStatePreparations{0};
|
||||
|
||||
constexpr auto
|
||||
operator<=>(const HydrostaticPreparationStatistics &) const = default;
|
||||
};
|
||||
|
||||
class HydrostaticEquilibriumContext {
|
||||
public:
|
||||
HydrostaticEquilibriumContext(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper
|
||||
);
|
||||
|
||||
HydrostaticEquilibriumContext(const HydrostaticEquilibriumContext &) =
|
||||
delete;
|
||||
|
||||
HydrostaticEquilibriumContext &
|
||||
operator=(const HydrostaticEquilibriumContext &) = delete;
|
||||
|
||||
HydrostaticEquilibriumContext(HydrostaticEquilibriumContext &&) =
|
||||
delete;
|
||||
|
||||
HydrostaticEquilibriumContext &
|
||||
operator=(HydrostaticEquilibriumContext &&) = delete;
|
||||
|
||||
HydrostaticPreparationReport Prepare(
|
||||
const HydrostaticEquilibriumStateView &state,
|
||||
const HydrostaticEquilibriumDependencies &dependencies
|
||||
);
|
||||
|
||||
[[nodiscard]] bool IsPrepared() const noexcept;
|
||||
|
||||
[[nodiscard]] bool MatchesDependencies(
|
||||
const HydrostaticEquilibriumDependencies &dependencies
|
||||
) const noexcept;
|
||||
|
||||
[[nodiscard]] const HydrostaticEquilibriumDependencies &
|
||||
GetDependencies() const;
|
||||
|
||||
[[nodiscard]] const HydrostaticPreparationStatistics &
|
||||
GetPreparationStatistics() const noexcept;
|
||||
|
||||
[[nodiscard]] const mfem::Vector &GetBaseEnthalpyTrue() const;
|
||||
|
||||
[[nodiscard]] const mfem::Vector &GetBaseGravityPotentialTrue() const;
|
||||
|
||||
[[nodiscard]] const mfem::Vector &GetDisplacementTrue() const;
|
||||
|
||||
[[nodiscard]] double GetBernoulliConstant() const;
|
||||
|
||||
private:
|
||||
void VerifyPrepared() const;
|
||||
|
||||
const fem::FEM &m_f;
|
||||
const mapping::DomainMapperStateless &m_domainMapper;
|
||||
|
||||
mfem::Vector m_baseEnthalpyTrue;
|
||||
mfem::Vector m_baseGravityPotentialTrue;
|
||||
mfem::Vector m_displacementTrue;
|
||||
double m_bernoulliConstant{0.0};
|
||||
|
||||
HydrostaticEquilibriumDependencies m_dependencies;
|
||||
HydrostaticPreparationStatistics m_statistics;
|
||||
bool m_isPrepared{false};
|
||||
};
|
||||
} // namespace mean_field::operators::context::hydrostatic
|
||||
147
libmeanfield/interface/operators/gravity_field.cppm
Normal file
147
libmeanfield/interface/operators/gravity_field.cppm
Normal file
@@ -0,0 +1,147 @@
|
||||
module;
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:operators.gravity_field;
|
||||
export import :fem;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :operators.gravity_field_jacobian;
|
||||
export import :operators.context.gravity_field;
|
||||
|
||||
export namespace mean_field::operators {
|
||||
enum class GravityResidualBlock : std::uint8_t {
|
||||
gradient_equation = 0,
|
||||
poisson_equation = 1,
|
||||
count = 2
|
||||
};
|
||||
|
||||
constexpr int
|
||||
gravity_residual_block_index(const GravityResidualBlock block) noexcept {
|
||||
return static_cast<int>(block);
|
||||
}
|
||||
|
||||
inline constexpr int gravity_residual_block_count =
|
||||
gravity_residual_block_index(GravityResidualBlock::count);
|
||||
|
||||
class GravityFieldOperator final : public mfem::Operator {
|
||||
public:
|
||||
GravityFieldOperator(
|
||||
fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domain_mapper,
|
||||
context::gravity_field::GravityFieldLinearizationContext
|
||||
&linearization_context,
|
||||
const mfem::Array<int> &state_true_offsets,
|
||||
GravityFieldJacobianOperator &jacobian
|
||||
);
|
||||
|
||||
context::gravity_field::GravityFieldPreparationReport Prepare(
|
||||
const mfem::Vector &state,
|
||||
const context::gravity_field::GravityFieldRevisions &revisions
|
||||
);
|
||||
|
||||
void Mult(
|
||||
const mfem::Vector &state,
|
||||
mfem::Vector &residual
|
||||
) const override;
|
||||
|
||||
Operator &GetGradient(const mfem::Vector &state) const override;
|
||||
|
||||
[[nodiscard]] const mfem::Array<int> &
|
||||
GetStateTrueOffsets() const noexcept;
|
||||
|
||||
[[nodiscard]] const mfem::Array<int> &
|
||||
GetResidualTrueOffsets() const noexcept;
|
||||
|
||||
[[nodiscard]] context::gravity_field::GravityFieldLinearizationContext &
|
||||
GetLinearizationContext() noexcept;
|
||||
|
||||
[[nodiscard]] const context::gravity_field::
|
||||
GravityFieldLinearizationContext &
|
||||
GetLinearizationContext() const noexcept;
|
||||
|
||||
void ApplyGravityUnknowns(
|
||||
const mfem::Vector &gravity_gradient,
|
||||
const mfem::Vector &gravity_potential,
|
||||
const context::gravity_field::GravityFieldGeometryContext
|
||||
&geometry_context,
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
void ApplyDensitySource(
|
||||
const mfem::Vector &density,
|
||||
const context::gravity_field::GravityFieldGeometryContext
|
||||
&geometry_context,
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
private:
|
||||
fem::FEM &m_fem;
|
||||
const mapping::DomainMapperStateless &m_domain_mapper;
|
||||
context::gravity_field::GravityFieldLinearizationContext
|
||||
&m_linearization_context;
|
||||
mfem::Array<int> m_state_true_offsets;
|
||||
mfem::Array<int> m_residual_true_offsets;
|
||||
GravityFieldJacobianOperator &m_jacobian;
|
||||
};
|
||||
|
||||
class ReducedGravityFieldOperator final : public mfem::Operator {
|
||||
public:
|
||||
ReducedGravityFieldOperator(
|
||||
GravityFieldOperator &gravity_field_operator,
|
||||
context::gravity_field::GravityFieldGeometryContext
|
||||
&gravity_field_geometry_context,
|
||||
const mfem::Vector &displacement
|
||||
);
|
||||
|
||||
ReducedGravityFieldOperator(const ReducedGravityFieldOperator &) =
|
||||
delete;
|
||||
ReducedGravityFieldOperator &
|
||||
operator=(const ReducedGravityFieldOperator &) = delete;
|
||||
ReducedGravityFieldOperator(ReducedGravityFieldOperator &&) = delete;
|
||||
ReducedGravityFieldOperator &
|
||||
operator=(ReducedGravityFieldOperator &&) = delete;
|
||||
|
||||
void SetDisplacement(const mfem::Vector &displacement);
|
||||
|
||||
[[nodiscard]] const mfem::Vector &GetDisplacement() const;
|
||||
|
||||
void BuildRightHandSide(
|
||||
const mfem::Vector &density,
|
||||
mfem::Vector &right_hand_side
|
||||
) const;
|
||||
|
||||
void Mult(
|
||||
const mfem::Vector &gravity_state,
|
||||
mfem::Vector &action
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] GravityFieldOperator &GetGravityFieldOperator() noexcept;
|
||||
|
||||
[[nodiscard]] const GravityFieldOperator &
|
||||
GetGravityFieldOperator() const noexcept;
|
||||
|
||||
[[nodiscard]] context::gravity_field::GravityFieldGeometryContext &
|
||||
GetGeometryContext() noexcept;
|
||||
|
||||
[[nodiscard]] const context::gravity_field::
|
||||
GravityFieldGeometryContext &
|
||||
GetGeometryContext() const noexcept;
|
||||
|
||||
[[nodiscard]] const mfem::Array<int> &
|
||||
GetGravityTrueOffsets() const noexcept;
|
||||
|
||||
private:
|
||||
void ValidateDisplacement(const mfem::Vector &displacement) const;
|
||||
|
||||
void ValidateDensity(const mfem::Vector &density) const;
|
||||
|
||||
void ValidateGravityState(const mfem::Vector &gravity_state) const;
|
||||
|
||||
private:
|
||||
GravityFieldOperator &m_gravity_field_operator;
|
||||
mfem::Array<int> m_gravity_true_offsets;
|
||||
context::gravity_field::GravityFieldGeometryContext
|
||||
&m_gravity_field_geometry_context;
|
||||
};
|
||||
} // namespace mean_field::operators
|
||||
38
libmeanfield/interface/operators/gravity_field_jacobian.cppm
Normal file
38
libmeanfield/interface/operators/gravity_field_jacobian.cppm
Normal file
@@ -0,0 +1,38 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:operators.gravity_field_jacobian;
|
||||
export import :fem;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :operators.context.gravity_field;
|
||||
|
||||
export namespace mean_field::operators {
|
||||
class GravityFieldJacobianOperator final : public mfem::Operator {
|
||||
public:
|
||||
GravityFieldJacobianOperator(
|
||||
fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domain_mapper,
|
||||
const context::gravity_field::GravityFieldLinearizationContext
|
||||
&linearization_context,
|
||||
const mfem::Array<int> &state_true_offsets,
|
||||
const mfem::Array<int> &residual_true_offsets
|
||||
);
|
||||
|
||||
void Mult(
|
||||
const mfem::Vector &direction,
|
||||
mfem::Vector &action
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] const context::gravity_field::
|
||||
GravityFieldLinearizationContext &
|
||||
GetLinearizationContext() const noexcept;
|
||||
|
||||
private:
|
||||
fem::FEM &m_fem;
|
||||
const mapping::DomainMapperStateless &m_domain_mapper;
|
||||
const context::gravity_field::GravityFieldLinearizationContext
|
||||
&m_linearization_context;
|
||||
mfem::Array<int> m_state_true_offsets;
|
||||
mfem::Array<int> m_residual_true_offsets;
|
||||
};
|
||||
} // namespace mean_field::operators
|
||||
@@ -0,0 +1,51 @@
|
||||
module;
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:operators.kernels.barotropic_closure;
|
||||
|
||||
export import :fem;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :physics.barotrope;
|
||||
|
||||
export namespace mean_field::operators::kernels {
|
||||
void apply_barotropic_closure(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope,
|
||||
const mfem::Vector &densityTrue,
|
||||
const mfem::Vector &enthalpyTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &residual
|
||||
);
|
||||
|
||||
void apply_barotropic_closure_density_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope,
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &action
|
||||
);
|
||||
|
||||
void apply_barotropic_closure_enthalpy_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &enthalpyVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &action
|
||||
);
|
||||
|
||||
void apply_barotropic_closure_displacement_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope,
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
mfem::Vector &action
|
||||
);
|
||||
} // namespace mean_field::operators::kernels
|
||||
@@ -0,0 +1,42 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
export module mean_field:operators.kernels.gravity_field;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :fem;
|
||||
|
||||
export namespace mean_field::operators::kernels {
|
||||
|
||||
void apply_mapped_hdiv_mass(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domain_mapper,
|
||||
const mfem::Vector &gravity_gradient_true,
|
||||
const mfem::Vector &displacement_true,
|
||||
mfem::Vector &action
|
||||
);
|
||||
|
||||
void apply_mapped_source(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domain_mapper,
|
||||
const mfem::Vector &density_true,
|
||||
const mfem::Vector &displacement_true,
|
||||
mfem::Vector &action
|
||||
);
|
||||
|
||||
void apply_mapped_hdiv_mass_variation(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domain_mapper,
|
||||
const mfem::Vector &gravity_gradient_true,
|
||||
const mfem::Vector &displacement_true,
|
||||
const mfem::Vector &displacement_variation_true,
|
||||
mfem::Vector &action
|
||||
);
|
||||
|
||||
void apply_mapped_source_variation(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domain_mapper,
|
||||
const mfem::Vector &density_true,
|
||||
const mfem::Vector &displacement_true,
|
||||
const mfem::Vector &displacement_variation_true,
|
||||
mfem::Vector &action_variation
|
||||
);
|
||||
} // namespace mean_field::operators::kernels
|
||||
@@ -0,0 +1,73 @@
|
||||
module;
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:operators.kernels.hydrostatic_equilibrium;
|
||||
|
||||
export import :fem;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :physics.rigid_rotation;
|
||||
|
||||
export namespace mean_field::operators::kernels {
|
||||
void apply_hydrostatic_equilibrium(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::RigidRotation &rotation,
|
||||
const mfem::Vector &enthalpyTrue,
|
||||
const mfem::Vector &potentialTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
double bernoulliConstant,
|
||||
mfem::Vector &residual
|
||||
);
|
||||
|
||||
void apply_hydrostatic_equilibrium_enthalpy_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &enthalpyVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &action
|
||||
);
|
||||
|
||||
void apply_hydrostatic_equilibrium_potential_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &potentialVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &action
|
||||
);
|
||||
|
||||
void apply_hydrostatic_equilibrium_constant_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
double constantVariation,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &action
|
||||
);
|
||||
|
||||
void apply_hydrostatic_equilibrium_displacement_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::RigidRotation &rotation,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &basePotentialTrue,
|
||||
const mfem::Vector &baseDisplacementTrue,
|
||||
double baseBernoulliConstant,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
mfem::Vector &action
|
||||
);
|
||||
|
||||
void apply_hydrostatic_equilibrium_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::RigidRotation &rotation,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &basePotentialTrue,
|
||||
const mfem::Vector &baseDisplacementTrue,
|
||||
double baseBernoulliConstant,
|
||||
const mfem::Vector &enthalpyVariationTrue,
|
||||
const mfem::Vector &potentialVariationTrue,
|
||||
double constantVariation,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
mfem::Vector &action
|
||||
);
|
||||
} // namespace mean_field::operators::kernels
|
||||
@@ -0,0 +1,20 @@
|
||||
module;
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:operators.kernels.pressure_force;
|
||||
|
||||
export import :fem;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :physics.barotrope;
|
||||
|
||||
export namespace mean_field::operators::kernels {
|
||||
void apply_pressure_force_residual(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope,
|
||||
const mfem::Vector &enthalpyTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &residualTrue
|
||||
);
|
||||
} // namespace mean_field::operators::kernels
|
||||
@@ -0,0 +1,90 @@
|
||||
module;
|
||||
|
||||
#include <cstdint>
|
||||
#include <mfem.hpp>
|
||||
#include <vector>
|
||||
|
||||
export module mean_field:operators.prepared_barotropic_closure;
|
||||
|
||||
export import :fem;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :physics.barotrope;
|
||||
|
||||
export namespace mean_field::operators {
|
||||
class PreparedBarotropicClosureOperator final : public mfem::Operator {
|
||||
public:
|
||||
PreparedBarotropicClosureOperator(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope
|
||||
);
|
||||
|
||||
void Prepare(
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &displacementTrue
|
||||
);
|
||||
|
||||
void Mult(
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &enthalpyVariationTrue,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
void Mult(
|
||||
const mfem::Vector &combinedVariation,
|
||||
mfem::Vector &action
|
||||
) const override;
|
||||
|
||||
void BuildResidual(mfem::Vector &residual) const;
|
||||
|
||||
[[nodiscard]] bool IsPrepared() const noexcept;
|
||||
|
||||
[[nodiscard]] std::uint64_t GetPreparationCount() const noexcept;
|
||||
|
||||
[[nodiscard]] int GetDensitySize() const noexcept;
|
||||
|
||||
[[nodiscard]] int GetEnthalpySize() const noexcept;
|
||||
|
||||
private:
|
||||
void VerifyPrepared() const;
|
||||
|
||||
void Mult(
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &enthalpyVariationTrue,
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
struct ElementPAData {
|
||||
mfem::Array<int> densityDofs;
|
||||
mfem::Array<int> enthalpyDofs;
|
||||
|
||||
mfem::DofTransformation *densityDofTransformation{nullptr};
|
||||
mfem::DofTransformation *enthalpyDofTransformation{nullptr};
|
||||
|
||||
mfem::DenseMatrix densityBasis;
|
||||
mfem::DenseMatrix enthalpyBasis;
|
||||
|
||||
mfem::Vector weightedResidual;
|
||||
mfem::Vector quadratureWeights;
|
||||
mfem::Vector weightedEnthalpyDerivative;
|
||||
};
|
||||
|
||||
const fem::FEM &m_fem;
|
||||
const mapping::DomainMapperStateless &m_domainMapper;
|
||||
const physics::PolytropicBarotrope &m_barotrope;
|
||||
|
||||
std::vector<ElementPAData> m_elements;
|
||||
|
||||
mfem::Vector m_baseDensityTrue;
|
||||
mfem::Vector m_baseEnthalpyTrue;
|
||||
mfem::Vector m_baseDisplacementTrue;
|
||||
|
||||
int m_densitySize{0};
|
||||
int m_enthalpySize{0};
|
||||
|
||||
std::uint64_t m_preparationCount{0};
|
||||
bool m_isPrepared{false};
|
||||
};
|
||||
} // namespace mean_field::operators
|
||||
@@ -0,0 +1,61 @@
|
||||
module;
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mfem.hpp>
|
||||
#include <vector>
|
||||
|
||||
export module mean_field:operators.prepared_gravity_source;
|
||||
export import :fem;
|
||||
export import :mapping.domain_mapper;
|
||||
|
||||
export namespace mean_field::operators {
|
||||
class PreparedMappedGravitySourceOperator final : public mfem::Operator {
|
||||
public:
|
||||
PreparedMappedGravitySourceOperator(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domain_mapper
|
||||
);
|
||||
|
||||
void Prepare(const mfem::Vector &displacement_true);
|
||||
void Mult(
|
||||
const mfem::Vector &density_true,
|
||||
mfem::Vector &action
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] bool IsPrepared() const noexcept;
|
||||
[[nodiscard]] std::uint64_t GetPreparationCount() const noexcept;
|
||||
|
||||
void MultTranspose(
|
||||
const mfem::Vector &potential_true,
|
||||
mfem::Vector &action
|
||||
) const override;
|
||||
|
||||
private:
|
||||
struct ElementPAData {
|
||||
int element_id{-1};
|
||||
|
||||
mfem::Array<int> density_dofs;
|
||||
mfem::Array<int> potential_dofs;
|
||||
|
||||
mfem::DofTransformation *density_dof_transformation{nullptr};
|
||||
mfem::DofTransformation *potential_dof_transformation{nullptr};
|
||||
|
||||
// Rows are quadrature points; columns are element DOFs.
|
||||
mfem::DenseMatrix density_basis;
|
||||
mfem::DenseMatrix potential_basis;
|
||||
|
||||
// Contains quadrature weight, mesh Jacobian, mapped Jacobian,
|
||||
// and 4*pi*G.
|
||||
mfem::Vector quadrature_data;
|
||||
};
|
||||
|
||||
const fem::FEM &m_fem;
|
||||
const mapping::DomainMapperStateless &m_domain_mapper;
|
||||
|
||||
mfem::Array<int> m_stellar_marker;
|
||||
std::vector<ElementPAData> m_elements;
|
||||
|
||||
std::uint64_t m_preparation_count{0};
|
||||
bool m_is_prepared{false};
|
||||
};
|
||||
} // namespace mean_field::operators
|
||||
40
libmeanfield/interface/operators/prepared_hdiv_mass.cppm
Normal file
40
libmeanfield/interface/operators/prepared_hdiv_mass.cppm
Normal file
@@ -0,0 +1,40 @@
|
||||
module;
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:operators.prepared_hdiv_mass;
|
||||
export import :fem;
|
||||
export import :mapping.domain_mapper;
|
||||
|
||||
export namespace mean_field::operators {
|
||||
class PreparedMappedHDivMassOperator final : public mfem::Operator {
|
||||
public:
|
||||
PreparedMappedHDivMassOperator(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domain_mapper
|
||||
);
|
||||
|
||||
void Prepare(const mfem::Vector &displacement_true);
|
||||
void Mult(
|
||||
const mfem::Vector &gravity_gradient_true,
|
||||
mfem::Vector &action
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] bool IsPrepared() const noexcept;
|
||||
[[nodiscard]] std::uint64_t GetPreparationCount() const noexcept;
|
||||
|
||||
private:
|
||||
const fem::FEM &m_fem;
|
||||
const mapping::DomainMapperStateless &m_domain_mapper;
|
||||
|
||||
mfem::Array<int> m_stellar_marker;
|
||||
mfem::Array<int> m_vacuum_marker;
|
||||
|
||||
std::unique_ptr<mfem::MatrixCoefficient> m_stellar_mass_coefficient;
|
||||
std::unique_ptr<mfem::MatrixCoefficient> m_vacuum_mass_coefficient;
|
||||
std::unique_ptr<mfem::ParBilinearForm> m_mass_form;
|
||||
std::uint64_t m_preparation_count{0};
|
||||
bool m_is_prepared{false};
|
||||
};
|
||||
} // namespace mean_field::operators
|
||||
@@ -0,0 +1,278 @@
|
||||
module;
|
||||
|
||||
#include <compare>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:operators.prepared_hydrostatic_equilibrium;
|
||||
|
||||
export import :fem;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :operators.context.hydrostatic_equilibrium;
|
||||
export import :physics.rigid_rotation;
|
||||
|
||||
export namespace mean_field::operators {
|
||||
struct PreparedHydrostaticEquilibriumReport {
|
||||
context::hydrostatic::HydrostaticPreparationReport contextReport;
|
||||
|
||||
bool updatedRotation{false};
|
||||
bool preparedAlgebraicJacobianBlocks{false};
|
||||
bool preparedDisplacementJacobianData{false};
|
||||
bool preparedResidual{false};
|
||||
|
||||
[[nodiscard]] bool DidAnyWork() const noexcept {
|
||||
return contextReport.DidAnyWork() || updatedRotation ||
|
||||
preparedAlgebraicJacobianBlocks ||
|
||||
preparedDisplacementJacobianData || preparedResidual;
|
||||
}
|
||||
};
|
||||
|
||||
struct PreparedHydrostaticAlgebraicJacobianStatistics {
|
||||
std::uint64_t preparations{0};
|
||||
std::uint64_t enthalpyApplications{0};
|
||||
std::uint64_t gravityPotentialApplications{0};
|
||||
std::uint64_t bernoulliConstantApplications{0};
|
||||
std::uint64_t combinedApplications{0};
|
||||
|
||||
constexpr auto operator<=>(
|
||||
const PreparedHydrostaticAlgebraicJacobianStatistics &
|
||||
) const = default;
|
||||
};
|
||||
|
||||
struct PreparedHydrostaticDisplacementJacobianStatistics {
|
||||
std::uint64_t preparations{0};
|
||||
std::uint64_t applications{0};
|
||||
|
||||
constexpr auto operator<=>(
|
||||
const PreparedHydrostaticDisplacementJacobianStatistics &
|
||||
) const = default;
|
||||
};
|
||||
|
||||
struct PreparedHydrostaticCompleteJacobianStatistics {
|
||||
std::uint64_t applications{0};
|
||||
|
||||
constexpr auto operator<=>(
|
||||
const PreparedHydrostaticCompleteJacobianStatistics &
|
||||
) const = default;
|
||||
};
|
||||
|
||||
enum class HydrostaticJacobianInputBlock : int {
|
||||
enthalpy = 0,
|
||||
gravityPotential = 1,
|
||||
bernoulliConstant = 2,
|
||||
displacement = 3
|
||||
};
|
||||
|
||||
class HydrostaticJacobianBlockLayout final {
|
||||
public:
|
||||
explicit HydrostaticJacobianBlockLayout(const fem::FEM &f);
|
||||
|
||||
[[nodiscard]] int Offset(HydrostaticJacobianInputBlock block) const;
|
||||
|
||||
[[nodiscard]] int Size(HydrostaticJacobianInputBlock block) const;
|
||||
|
||||
[[nodiscard]] int GetTotalSize() const noexcept;
|
||||
|
||||
[[nodiscard]] int GetResidualSize() const noexcept;
|
||||
|
||||
private:
|
||||
int m_enthalpySize{0};
|
||||
int m_gravityPotentialSize{0};
|
||||
int m_displacementSize{0};
|
||||
int m_totalSize{0};
|
||||
int m_residualSize{0};
|
||||
};
|
||||
|
||||
class PreparedHydrostaticEquilibriumOperator final {
|
||||
public:
|
||||
PreparedHydrostaticEquilibriumOperator(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper
|
||||
);
|
||||
|
||||
PreparedHydrostaticEquilibriumOperator(
|
||||
const PreparedHydrostaticEquilibriumOperator &
|
||||
) = delete;
|
||||
|
||||
PreparedHydrostaticEquilibriumOperator &
|
||||
operator=(const PreparedHydrostaticEquilibriumOperator &) = delete;
|
||||
|
||||
PreparedHydrostaticEquilibriumOperator(
|
||||
PreparedHydrostaticEquilibriumOperator &&
|
||||
) = delete;
|
||||
|
||||
PreparedHydrostaticEquilibriumOperator &
|
||||
operator=(PreparedHydrostaticEquilibriumOperator &&) = delete;
|
||||
|
||||
PreparedHydrostaticEquilibriumReport Prepare(
|
||||
const context::hydrostatic::HydrostaticEquilibriumStateView &state,
|
||||
const context::hydrostatic::HydrostaticEquilibriumDependencies
|
||||
&dependencies,
|
||||
const physics::RigidRotation &rotation
|
||||
);
|
||||
|
||||
void BuildResidual(mfem::Vector &residual) const;
|
||||
|
||||
void ApplyEnthalpyJacobianAction(
|
||||
const mfem::Vector &enthalpyVariation,
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
void ApplyGravityPotentialJacobianAction(
|
||||
const mfem::Vector &gravityPotentialVariation,
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
void ApplyBernoulliConstantJacobianAction(
|
||||
double bernoulliConstantVariation,
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
void ApplyAlgebraicJacobianAction(
|
||||
const mfem::Vector &enthalpyVariation,
|
||||
const mfem::Vector &gravityPotentialVariation,
|
||||
double bernoulliConstantVariation,
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
void ApplyDisplacementJacobianAction(
|
||||
const mfem::Vector &displacementVariation,
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
void ApplyCompleteJacobianAction(
|
||||
const mfem::Vector &enthalpyVariation,
|
||||
const mfem::Vector &gravityPotentialVariation,
|
||||
double bernoulliConstantVariation,
|
||||
const mfem::Vector &displacementVariation,
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
[[nodiscard]] bool IsPrepared() const noexcept;
|
||||
|
||||
[[nodiscard]] const context::hydrostatic::
|
||||
HydrostaticPreparationStatistics &
|
||||
GetContextPreparationStatistics() const noexcept;
|
||||
|
||||
[[nodiscard]] std::uint64_t
|
||||
GetResidualPreparationCount() const noexcept;
|
||||
|
||||
[[nodiscard]] std::uint64_t
|
||||
GetResidualApplicationCount() const noexcept;
|
||||
|
||||
[[nodiscard]] const PreparedHydrostaticAlgebraicJacobianStatistics &
|
||||
GetAlgebraicJacobianStatistics() const noexcept;
|
||||
|
||||
[[nodiscard]] const PreparedHydrostaticDisplacementJacobianStatistics &
|
||||
GetDisplacementJacobianStatistics() const noexcept;
|
||||
|
||||
[[nodiscard]] const PreparedHydrostaticCompleteJacobianStatistics &
|
||||
GetCompleteJacobianStatistics() const noexcept;
|
||||
|
||||
[[nodiscard]] std::size_t GetStellarElementCount() const noexcept;
|
||||
|
||||
[[nodiscard]] const fem::FEM &GetFEM() const noexcept;
|
||||
|
||||
private:
|
||||
struct ElementPAData {
|
||||
int elementId{-1};
|
||||
|
||||
mfem::Array<int> enthalpyDofs;
|
||||
mfem::Array<int> gravityPotentialDofs;
|
||||
mfem::Array<int> displacementDofs;
|
||||
|
||||
mfem::DofTransformation *enthalpyDofTransformation{nullptr};
|
||||
|
||||
mfem::DofTransformation *gravityPotentialDofTransformation{nullptr};
|
||||
|
||||
mfem::DofTransformation *displacementDofTransformation{nullptr};
|
||||
|
||||
const mfem::IntegrationRule *integrationRule{nullptr};
|
||||
|
||||
// Rows are quadrature points and columns are element DOFs.
|
||||
mfem::DenseMatrix enthalpyBasis;
|
||||
mfem::DenseMatrix gravityPotentialBasis;
|
||||
|
||||
// Rows are quadrature points and columns are physical components.
|
||||
mfem::DenseMatrix physicalPositions;
|
||||
|
||||
mfem::Vector quadratureWeights;
|
||||
std::vector<mapping::VolumeMappingContext> baseMappingContexts;
|
||||
|
||||
std::optional<mapping::ElementDisplacementData>
|
||||
baseDisplacementData;
|
||||
|
||||
std::optional<mapping::ElementCompactificationData>
|
||||
compactificationData;
|
||||
|
||||
mfem::Vector rotationPotential;
|
||||
mfem::DenseMatrix rotationGradient;
|
||||
mfem::Vector hydrostaticImbalance;
|
||||
mfem::Vector weightedResidual;
|
||||
|
||||
// Geometry-dependent algebraic Jacobian blocks.
|
||||
mfem::DenseMatrix enthalpyJacobian;
|
||||
mfem::DenseMatrix gravityPotentialJacobian;
|
||||
mfem::Vector bernoulliConstantJacobian;
|
||||
};
|
||||
|
||||
void PrepareStaticPlan();
|
||||
void PrepareGeometry();
|
||||
void PrepareAlgebraicJacobianBlocks();
|
||||
void PrepareRotation();
|
||||
void PrepareBaseState();
|
||||
void FinalizeDisplacementJacobianPreparation();
|
||||
void AssembleCachedResidual();
|
||||
void VerifyPrepared() const;
|
||||
|
||||
const fem::FEM &m_fem;
|
||||
const mapping::DomainMapperStateless &m_domainMapper;
|
||||
|
||||
context::hydrostatic::HydrostaticEquilibriumContext m_context;
|
||||
|
||||
std::optional<physics::RigidRotation> m_rotation;
|
||||
std::vector<ElementPAData> m_elements;
|
||||
mfem::Vector m_cachedResidual;
|
||||
|
||||
std::uint64_t m_residualPreparationCount{0};
|
||||
|
||||
mutable std::uint64_t m_residualApplicationCount{0};
|
||||
|
||||
mutable PreparedHydrostaticAlgebraicJacobianStatistics
|
||||
m_algebraicJacobianStatistics;
|
||||
|
||||
mutable PreparedHydrostaticDisplacementJacobianStatistics
|
||||
m_displacementJacobianStatistics;
|
||||
|
||||
mutable PreparedHydrostaticCompleteJacobianStatistics
|
||||
m_completeJacobianStatistics;
|
||||
|
||||
bool m_isPrepared{false};
|
||||
};
|
||||
|
||||
class PreparedHydrostaticEquilibriumJacobianOperator final
|
||||
: public mfem::Operator {
|
||||
public:
|
||||
PreparedHydrostaticEquilibriumJacobianOperator(
|
||||
const fem::FEM &f,
|
||||
const PreparedHydrostaticEquilibriumOperator &preparedOperator
|
||||
);
|
||||
|
||||
void Mult(
|
||||
const mfem::Vector &direction,
|
||||
mfem::Vector &action
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] const HydrostaticJacobianBlockLayout &
|
||||
GetLayout() const noexcept;
|
||||
|
||||
private:
|
||||
HydrostaticJacobianBlockLayout m_layout;
|
||||
|
||||
const PreparedHydrostaticEquilibriumOperator &m_preparedOperator;
|
||||
};
|
||||
} // namespace mean_field::operators
|
||||
173
libmeanfield/interface/physics/barotrope.cppm
Normal file
173
libmeanfield/interface/physics/barotrope.cppm
Normal file
@@ -0,0 +1,173 @@
|
||||
module;
|
||||
|
||||
#include <cmath>
|
||||
#include <format>
|
||||
#include <stdexcept>
|
||||
|
||||
export module mean_field:physics.barotrope;
|
||||
|
||||
export namespace mean_field::physics {
|
||||
class PolytropicBarotrope final {
|
||||
public:
|
||||
PolytropicBarotrope(
|
||||
const double polytropic_index,
|
||||
const double polytropic_constant
|
||||
)
|
||||
: m_polytropic_index(polytropic_index),
|
||||
m_polytropic_constant(polytropic_constant),
|
||||
m_enthalpy_scale((polytropic_index + 1.0) * polytropic_constant) {
|
||||
if (!std::isfinite(polytropic_index) || polytropic_index < 1.0) {
|
||||
throw std::invalid_argument(
|
||||
std::format(
|
||||
"The differentiable polytropic closure requires a "
|
||||
"finite polytropic index greater than or equal to one. "
|
||||
"Instead a value of {} has been provided",
|
||||
polytropic_index
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!std::isfinite(polytropic_constant) ||
|
||||
polytropic_constant <= 0.0) {
|
||||
throw std::invalid_argument(
|
||||
std::format(
|
||||
"The polytropic constant must be finite and positive. "
|
||||
"Instead a value of {} has been provided",
|
||||
polytropic_constant
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
[[nodiscard]] double polytropic_index() const noexcept {
|
||||
return m_polytropic_index;
|
||||
}
|
||||
|
||||
[[nodiscard]] double polytropic_constant() const noexcept {
|
||||
return m_polytropic_constant;
|
||||
}
|
||||
|
||||
[[nodiscard]] double enthalpy_scale() const noexcept {
|
||||
return m_enthalpy_scale;
|
||||
}
|
||||
|
||||
[[nodiscard]] double pressure_from_density(const double density) const {
|
||||
validate_nonnegativity(density, "density");
|
||||
if (density == 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return m_polytropic_constant *
|
||||
std::pow(density, 1.0 + 1.0 / m_polytropic_index);
|
||||
}
|
||||
|
||||
[[nodiscard]] double enthalpy_from_density(const double density) const {
|
||||
validate_nonnegativity(density, "density");
|
||||
if (density == 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return m_enthalpy_scale *
|
||||
std::pow(density, 1.0 / m_polytropic_index);
|
||||
}
|
||||
|
||||
[[nodiscard]] double
|
||||
density_from_enthalpy(const double enthalpy) const {
|
||||
validate_finite(enthalpy, "enthalpy");
|
||||
|
||||
if (enthalpy <= 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return std::pow(enthalpy / m_enthalpy_scale, m_polytropic_index);
|
||||
}
|
||||
|
||||
[[nodiscard]] double
|
||||
pressure_from_enthalpy(const double enthalpy) const {
|
||||
validate_finite(enthalpy, "enthalpy");
|
||||
|
||||
if (enthalpy <= 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return density_from_enthalpy(enthalpy) * enthalpy /
|
||||
(m_polytropic_index + 1.0);
|
||||
}
|
||||
|
||||
[[nodiscard]] double
|
||||
density_derivative_from_enthalpy(const double enthalpy) const {
|
||||
validate_finite(enthalpy, "enthalpy");
|
||||
if (enthalpy < 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if (enthalpy == 0.0) {
|
||||
return m_polytropic_index == 1.0 ? 1.0 / m_enthalpy_scale : 0.0;
|
||||
}
|
||||
|
||||
return m_polytropic_index / m_enthalpy_scale *
|
||||
std::pow(
|
||||
enthalpy / m_enthalpy_scale, m_polytropic_index - 1.0
|
||||
);
|
||||
}
|
||||
|
||||
[[nodiscard]] double
|
||||
pressure_derivative_from_enthalpy(const double enthalpy) const {
|
||||
validate_finite(enthalpy, "enthalpy");
|
||||
|
||||
if (enthalpy <= 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return density_from_enthalpy(enthalpy);
|
||||
}
|
||||
|
||||
[[nodiscard]] double
|
||||
pressure_derivative_from_density(const double density) const {
|
||||
validate_nonnegativity(density, "density");
|
||||
if (density == 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return m_polytropic_constant * (1.0 + 1.0 / m_polytropic_index) *
|
||||
std::pow(density, 1.0 / m_polytropic_index);
|
||||
}
|
||||
|
||||
private:
|
||||
static void validate_finite(
|
||||
const double value,
|
||||
const char *quantity
|
||||
) {
|
||||
if (!std::isfinite(value)) {
|
||||
throw std::domain_error(
|
||||
std::format(
|
||||
"The {} must be finite. Instead a value of {} has been "
|
||||
"provided",
|
||||
quantity, value
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void validate_nonnegativity(
|
||||
const double value,
|
||||
const char *quantity
|
||||
) {
|
||||
validate_finite(value, quantity);
|
||||
if (value < 0.0) {
|
||||
throw std::domain_error(
|
||||
std::format(
|
||||
"The {} must be non-negative. Instead a value of {} "
|
||||
"has been "
|
||||
"provided",
|
||||
quantity, value
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
double m_polytropic_index;
|
||||
double m_polytropic_constant;
|
||||
double m_enthalpy_scale;
|
||||
};
|
||||
} // namespace mean_field::physics
|
||||
@@ -1,4 +1,5 @@
|
||||
module;
|
||||
#include <memory>
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:physics.contexts;
|
||||
@@ -23,6 +24,6 @@ export namespace mean_field::physics {
|
||||
std::unique_ptr<mfem::HypreParMatrix> Schur;
|
||||
|
||||
std::unique_ptr<mfem::MatrixCoefficient> mapped_hdiv_mass_coeff;
|
||||
|
||||
std::unique_ptr<mfem::Operator> source_form;
|
||||
};
|
||||
}
|
||||
} // namespace mean_field::physics
|
||||
|
||||
@@ -10,7 +10,10 @@ export namespace mean_field::physics {
|
||||
mfem::ParGridFunction gradPhi;
|
||||
mfem::ParGridFunction phi;
|
||||
|
||||
explicit GravitySolution(fem::FEM& fem): gradPhi(fem.RT_fes.get()), phi(fem.L2_fes.get()) {}
|
||||
explicit GravitySolution(fem::FEM &fem)
|
||||
: gradPhi(fem.gravityFluxFes.get()),
|
||||
phi(fem.gravityPotentialFes.get()) {
|
||||
}
|
||||
};
|
||||
|
||||
GravitySolution grav_potential(
|
||||
@@ -20,6 +23,13 @@ export namespace mean_field::physics {
|
||||
bool phi_warm = false
|
||||
);
|
||||
|
||||
GravitySolution grav_potential_new(
|
||||
fem::FEM &f,
|
||||
const utils::Args &args,
|
||||
const mfem::GridFunction &rho,
|
||||
const mfem::GridFunction &displacement
|
||||
);
|
||||
|
||||
mfem::GridFunction get_potential(
|
||||
fem::FEM &fem,
|
||||
const utils::Args &args,
|
||||
@@ -40,6 +50,4 @@ export namespace mean_field::physics {
|
||||
);
|
||||
|
||||
void update_stiffness_matrix(fem::FEM &fem);
|
||||
}
|
||||
|
||||
|
||||
} // namespace mean_field::physics
|
||||
|
||||
127
libmeanfield/interface/physics/rigid_rotation.cppm
Normal file
127
libmeanfield/interface/physics/rigid_rotation.cppm
Normal file
@@ -0,0 +1,127 @@
|
||||
module;
|
||||
|
||||
#include <cmath>
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:physics.rigid_rotation;
|
||||
|
||||
export namespace mean_field::physics {
|
||||
class RigidRotation final {
|
||||
public:
|
||||
RigidRotation(
|
||||
const mfem::Vector &angularVelocity,
|
||||
const mfem::Vector ¢er
|
||||
)
|
||||
: m_angularVelocity(angularVelocity),
|
||||
m_center(center) {
|
||||
MFEM_VERIFY(
|
||||
m_angularVelocity.Size() == 3,
|
||||
"RigidRotation requires a three-dimensional "
|
||||
"angular-velocity vector."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_center.Size() == 3,
|
||||
"RigidRotation requires a three-dimensional center."
|
||||
);
|
||||
|
||||
for (int component = 0; component < 3; ++component) {
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(m_angularVelocity(component)),
|
||||
"RigidRotation received a non-finite "
|
||||
"angular-velocity component."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(m_center(component)),
|
||||
"RigidRotation received a non-finite center component."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] double
|
||||
potential(const mfem::Vector &physicalPosition) const {
|
||||
MFEM_VERIFY(
|
||||
physicalPosition.Size() == 3,
|
||||
"RigidRotation::potential requires a "
|
||||
"three-dimensional position."
|
||||
);
|
||||
|
||||
const double relativeX = physicalPosition(0) - m_center(0);
|
||||
|
||||
const double relativeY = physicalPosition(1) - m_center(1);
|
||||
|
||||
const double relativeZ = physicalPosition(2) - m_center(2);
|
||||
|
||||
const double crossX = m_angularVelocity(1) * relativeZ -
|
||||
m_angularVelocity(2) * relativeY;
|
||||
|
||||
const double crossY = m_angularVelocity(2) * relativeX -
|
||||
m_angularVelocity(0) * relativeZ;
|
||||
|
||||
const double crossZ = m_angularVelocity(0) * relativeY -
|
||||
m_angularVelocity(1) * relativeX;
|
||||
|
||||
return 0.5 * (crossX * crossX + crossY * crossY + crossZ * crossZ);
|
||||
}
|
||||
|
||||
[[nodiscard]] double potential_directional_derivative(
|
||||
const mfem::Vector &physicalPosition,
|
||||
const mfem::Vector &physicalPositionVariation
|
||||
) const {
|
||||
MFEM_VERIFY(
|
||||
physicalPosition.Size() == 3,
|
||||
"RigidRotation derivative requires a "
|
||||
"three-dimensional position."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
physicalPositionVariation.Size() == 3,
|
||||
"RigidRotation derivative requires a "
|
||||
"three-dimensional direction."
|
||||
);
|
||||
|
||||
double angularVelocitySquared = 0.0;
|
||||
double angularVelocityDotPosition = 0.0;
|
||||
|
||||
for (int component = 0; component < 3; ++component) {
|
||||
const double relativePosition =
|
||||
physicalPosition(component) - m_center(component);
|
||||
|
||||
angularVelocitySquared +=
|
||||
m_angularVelocity(component) * m_angularVelocity(component);
|
||||
|
||||
angularVelocityDotPosition +=
|
||||
m_angularVelocity(component) * relativePosition;
|
||||
}
|
||||
|
||||
double derivative = 0.0;
|
||||
|
||||
for (int component = 0; component < 3; ++component) {
|
||||
const double relativePosition =
|
||||
physicalPosition(component) - m_center(component);
|
||||
|
||||
const double gradientComponent =
|
||||
angularVelocitySquared * relativePosition -
|
||||
angularVelocityDotPosition * m_angularVelocity(component);
|
||||
|
||||
derivative +=
|
||||
gradientComponent * physicalPositionVariation(component);
|
||||
}
|
||||
|
||||
return derivative;
|
||||
}
|
||||
|
||||
[[nodiscard]] const mfem::Vector &angular_velocity() const noexcept {
|
||||
return m_angularVelocity;
|
||||
}
|
||||
|
||||
[[nodiscard]] const mfem::Vector ¢er() const noexcept {
|
||||
return m_center;
|
||||
}
|
||||
|
||||
private:
|
||||
mfem::Vector m_angularVelocity;
|
||||
mfem::Vector m_center;
|
||||
};
|
||||
} // namespace mean_field::physics
|
||||
@@ -5,5 +5,8 @@ export module mean_field:physics.solid_body;
|
||||
export import :fem;
|
||||
|
||||
export namespace mean_field::physics {
|
||||
double compute_moment_of_inertia(const fem::FEM &fem, const mfem::GridFunction &rho_ref);
|
||||
double compute_moment_of_inertia(
|
||||
const fem::FEM &fem,
|
||||
const mfem::GridFunction &rho_ref
|
||||
);
|
||||
}
|
||||
@@ -4,93 +4,116 @@ module;
|
||||
|
||||
export module mean_field:quadrature.mfem;
|
||||
export import :quadrature.policy;
|
||||
export import :integrators.centrifugal;
|
||||
import :field.mfem;
|
||||
|
||||
export namespace mean_field::quadrature {
|
||||
struct MfemRule {
|
||||
Resolution resolution;
|
||||
const mfem::IntegrationRule* integration_rule;
|
||||
const mfem::IntegrationRule *integration_rule;
|
||||
};
|
||||
|
||||
class RuleFactory {
|
||||
public:
|
||||
explicit RuleFactory(
|
||||
Policy policy
|
||||
);
|
||||
MfemRule get(
|
||||
const Query& query,
|
||||
mfem::Geometry::Type geometry
|
||||
) const;
|
||||
MfemRule get(
|
||||
Term term,
|
||||
explicit RuleFactory(Policy policy);
|
||||
MfemRule
|
||||
get(const Query &query,
|
||||
mfem::Geometry::Type geometry) const;
|
||||
MfemRule
|
||||
get(Term term,
|
||||
QuadratureRole role,
|
||||
mfem::Geometry::Type geometry,
|
||||
int base_order,
|
||||
utils::DOMAINS domain = utils::DOMAINS::ALL,
|
||||
MappingKind mapping = MappingKind::none
|
||||
) const;
|
||||
MappingKind mapping = MappingKind::none) const;
|
||||
|
||||
Resolution configure_gravity_hdiv_mass(
|
||||
mfem::VectorFEMassIntegrator& integrator,
|
||||
mfem::VectorFEMassIntegrator &integrator,
|
||||
QuadratureRole role,
|
||||
const mfem::FiniteElement& element,
|
||||
const mfem::ElementTransformation& transformation,
|
||||
const mfem::FiniteElement &element,
|
||||
const mfem::ElementTransformation &transformation,
|
||||
utils::DOMAINS domain = utils::DOMAINS::ALL,
|
||||
MappingKind mapping = MappingKind::none
|
||||
MappingKind mapping = MappingKind::none
|
||||
) const;
|
||||
|
||||
Resolution configure_gravity_divergence(
|
||||
mfem::VectorFEDivergenceIntegrator& integrator,
|
||||
mfem::VectorFEDivergenceIntegrator &integrator,
|
||||
QuadratureRole role,
|
||||
const mfem::FiniteElement& trial_element,
|
||||
const mfem::FiniteElement& test_element,
|
||||
const mfem::ElementTransformation& transformation,
|
||||
const mfem::FiniteElement &trial_element,
|
||||
const mfem::FiniteElement &test_element,
|
||||
const mfem::ElementTransformation &transformation,
|
||||
utils::DOMAINS domain = utils::DOMAINS::ALL,
|
||||
MappingKind mapping = MappingKind::none
|
||||
MappingKind mapping = MappingKind::none
|
||||
) const;
|
||||
|
||||
Resolution configure_gravity_boundary(
|
||||
mfem::VectorFEBoundaryFluxLFIntegrator& integrator,
|
||||
mfem::VectorFEBoundaryFluxLFIntegrator &integrator,
|
||||
QuadratureRole role,
|
||||
const mfem::FiniteElement& boundary_element,
|
||||
const mfem::FiniteElement &boundary_element,
|
||||
utils::DOMAINS domain = utils::DOMAINS::VACUUM,
|
||||
MappingKind mapping = MappingKind::none
|
||||
MappingKind mapping = MappingKind::none
|
||||
) const;
|
||||
|
||||
Resolution configure_gravity_source(
|
||||
mfem::DomainLFIntegrator& integrator,
|
||||
mfem::DomainLFIntegrator &integrator,
|
||||
QuadratureRole role,
|
||||
const mfem::FiniteElement& test_element,
|
||||
const mfem::ElementTransformation& transformation,
|
||||
const mfem::FiniteElement &test_element,
|
||||
const mfem::ElementTransformation &transformation,
|
||||
int coefficient_order,
|
||||
utils::DOMAINS domain = utils::DOMAINS::STELLAR,
|
||||
MappingKind mapping = MappingKind::none
|
||||
MappingKind mapping = MappingKind::none
|
||||
) const;
|
||||
|
||||
template<typename IntegratorType>
|
||||
Resolution configure_gravity_source(
|
||||
mfem::MixedScalarMassIntegrator &integrator,
|
||||
QuadratureRole role,
|
||||
const mfem::FiniteElement &trial_element,
|
||||
const mfem::FiniteElement &test_element,
|
||||
const mfem::ElementTransformation &transformation,
|
||||
int coefficient_order,
|
||||
utils::DOMAINS domain = utils::DOMAINS::STELLAR,
|
||||
MappingKind mapping = MappingKind::none
|
||||
) const;
|
||||
|
||||
Resolution configure_centrifugal(
|
||||
integrators::CentrifugalForceIntegrator &integrator,
|
||||
QuadratureRole role,
|
||||
const mfem::FiniteElement &density_element,
|
||||
const mfem::FiniteElement &velocity_element,
|
||||
const mfem::ElementTransformation &transformation,
|
||||
int position_order,
|
||||
utils::DOMAINS domain = utils::DOMAINS::STELLAR,
|
||||
MappingKind mapping = MappingKind::none
|
||||
) const;
|
||||
|
||||
template <typename IntegratorType>
|
||||
Resolution configure(
|
||||
IntegratorType& integrator,
|
||||
IntegratorType &integrator,
|
||||
Term term,
|
||||
QuadratureRole role,
|
||||
mfem::Geometry::Type geometry,
|
||||
int base_order,
|
||||
utils::DOMAINS domain = utils::DOMAINS::ALL,
|
||||
MappingKind mapping = MappingKind::none
|
||||
MappingKind mapping = MappingKind::none
|
||||
) const;
|
||||
|
||||
|
||||
private:
|
||||
Policy policy;
|
||||
};
|
||||
|
||||
RuleFactory::RuleFactory(Policy policy) : policy(std::move(policy)) {}
|
||||
RuleFactory::RuleFactory(Policy policy) : policy(std::move(policy)) {
|
||||
}
|
||||
|
||||
MfemRule RuleFactory::get(
|
||||
const Query& query,
|
||||
const Query &query,
|
||||
const mfem::Geometry::Type geometry
|
||||
) const {
|
||||
const Resolution resolution = policy.resolve(query);
|
||||
const mfem::IntegrationRule& integration_rule = mfem::IntRules.Get(geometry, resolution.order);
|
||||
return {.resolution = resolution, .integration_rule = &integration_rule};
|
||||
const mfem::IntegrationRule &integration_rule =
|
||||
mfem::IntRules.Get(geometry, resolution.order);
|
||||
return {
|
||||
.resolution = resolution, .integration_rule = &integration_rule
|
||||
};
|
||||
}
|
||||
|
||||
MfemRule RuleFactory::get(
|
||||
@@ -102,87 +125,197 @@ export namespace mean_field::quadrature {
|
||||
const MappingKind mapping
|
||||
) const {
|
||||
Query query{.term = term};
|
||||
query.domain = domain;
|
||||
query.mapping = mapping;
|
||||
query.role = role;
|
||||
query.domain = domain;
|
||||
query.mapping = mapping;
|
||||
query.role = role;
|
||||
query.base_order = base_order;
|
||||
return get(query, geometry);
|
||||
}
|
||||
|
||||
Resolution RuleFactory::configure_gravity_hdiv_mass(
|
||||
mfem::VectorFEMassIntegrator& integrator,
|
||||
mfem::VectorFEMassIntegrator &integrator,
|
||||
const QuadratureRole role,
|
||||
const mfem::FiniteElement& element,
|
||||
const mfem::ElementTransformation& transformation,
|
||||
const mfem::FiniteElement &element,
|
||||
const mfem::ElementTransformation &transformation,
|
||||
const utils::DOMAINS domain,
|
||||
const MappingKind mapping
|
||||
) const {
|
||||
const int base_order = 2 * element.GetOrder() + transformation.OrderW();
|
||||
return configure(integrator, Term::gravity_hdiv_mass, role, element.GetGeomType(), base_order, domain, mapping);
|
||||
using GravityField = field::Field<field::Gravity>;
|
||||
MFEM_VERIFY(
|
||||
element.GetOrder() == field::Gravity::Flux::familyOrder + 1,
|
||||
"The H(div) element order does not match the registered gravity "
|
||||
"flux."
|
||||
);
|
||||
const Query query =
|
||||
GravityField::make_query<field::Gravity::Form::HDivMass>(
|
||||
role, transformation.OrderW(), {}, domain, mapping
|
||||
);
|
||||
const auto [resolution, integration_rule] =
|
||||
get(query, element.GetGeomType());
|
||||
integrator.SetIntegrationRule(*integration_rule);
|
||||
return resolution;
|
||||
}
|
||||
|
||||
Resolution RuleFactory::configure_gravity_divergence(
|
||||
mfem::VectorFEDivergenceIntegrator& integrator,
|
||||
mfem::VectorFEDivergenceIntegrator &integrator,
|
||||
const QuadratureRole role,
|
||||
const mfem::FiniteElement& trial_element,
|
||||
const mfem::FiniteElement& test_element,
|
||||
const mfem::ElementTransformation& transformation,
|
||||
const mfem::FiniteElement &trial_element,
|
||||
const mfem::FiniteElement &test_element,
|
||||
const mfem::ElementTransformation &transformation,
|
||||
const utils::DOMAINS domain,
|
||||
const MappingKind mapping
|
||||
) const {
|
||||
const Query query = {
|
||||
.term = Term::gravity_divergence,
|
||||
.role = role,
|
||||
.domain = domain,
|
||||
.mapping = mapping,
|
||||
.trial_order = trial_element.GetOrder(),
|
||||
.test_order = test_element.GetOrder(),
|
||||
.geometry_weight_order = transformation.OrderW()
|
||||
};
|
||||
using GravityField = field::Field<field::Gravity>;
|
||||
MFEM_VERIFY(
|
||||
trial_element.GetOrder() == field::Gravity::Flux::familyOrder + 1,
|
||||
"The divergence trial element does not match the registered "
|
||||
"gravity flux."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
test_element.GetOrder() == field::Gravity::Potential::familyOrder,
|
||||
"The divergence test element does not match the registered "
|
||||
"gravity potential."
|
||||
);
|
||||
const Query query =
|
||||
GravityField::make_query<field::Gravity::Form::DivergenceCoupling>(
|
||||
role, transformation.OrderW(), {}, domain, mapping
|
||||
);
|
||||
|
||||
const auto [resolution, integration_rule] = get(query, trial_element.GetGeomType());
|
||||
const auto [resolution, integration_rule] =
|
||||
get(query, trial_element.GetGeomType());
|
||||
integrator.SetIntegrationRule(*integration_rule);
|
||||
return resolution;
|
||||
}
|
||||
|
||||
Resolution RuleFactory::configure_gravity_boundary(
|
||||
mfem::VectorFEBoundaryFluxLFIntegrator& integrator,
|
||||
mfem::VectorFEBoundaryFluxLFIntegrator &integrator,
|
||||
const QuadratureRole role,
|
||||
const mfem::FiniteElement& boundary_element,
|
||||
const mfem::FiniteElement &boundary_element,
|
||||
const utils::DOMAINS domain,
|
||||
const MappingKind mapping
|
||||
) const {
|
||||
const int base_order = 2 * boundary_element.GetOrder();
|
||||
return configure(integrator, Term::gravity_boundary, role, boundary_element.GetGeomType(), base_order, domain, mapping);
|
||||
}
|
||||
|
||||
Resolution RuleFactory::configure_gravity_source(
|
||||
mfem::DomainLFIntegrator& integrator,
|
||||
const QuadratureRole role,
|
||||
const mfem::FiniteElement& test_element,
|
||||
const mfem::ElementTransformation& transformation,
|
||||
const int coefficient_order,
|
||||
const utils::DOMAINS domain,
|
||||
const MappingKind mapping
|
||||
) const {
|
||||
const Query query = {
|
||||
.term = Term::gravity_source,
|
||||
.role = role,
|
||||
.domain = domain,
|
||||
.mapping = mapping,
|
||||
.test_order = test_element.GetOrder(),
|
||||
.coefficient_order = coefficient_order,
|
||||
.geometry_weight_order = transformation.OrderW()
|
||||
};
|
||||
|
||||
const auto [resolution, integration_rule] = get(query, test_element.GetGeomType());
|
||||
using GravityField = field::Field<field::Gravity>;
|
||||
MFEM_VERIFY(
|
||||
boundary_element.GetOrder() == field::Gravity::Flux::familyOrder,
|
||||
"The boundary element does not match the registered gravity-flux "
|
||||
"normal trace."
|
||||
);
|
||||
const Query query =
|
||||
GravityField::make_query<field::Gravity::Form::Boundary>(
|
||||
role, 0, {}, domain, mapping
|
||||
);
|
||||
const auto [resolution, integration_rule] =
|
||||
get(query, boundary_element.GetGeomType());
|
||||
integrator.SetIntegrationRule(*integration_rule);
|
||||
return resolution;
|
||||
}
|
||||
|
||||
template<typename IntegratorType>
|
||||
Resolution RuleFactory::configure_gravity_source(
|
||||
mfem::DomainLFIntegrator &integrator,
|
||||
const QuadratureRole role,
|
||||
const mfem::FiniteElement &test_element,
|
||||
const mfem::ElementTransformation &transformation,
|
||||
const int coefficient_order,
|
||||
const utils::DOMAINS domain,
|
||||
const MappingKind mapping
|
||||
) const {
|
||||
using GravityField = field::Field<field::Gravity>;
|
||||
MFEM_VERIFY(
|
||||
test_element.GetOrder() == field::Gravity::Potential::familyOrder,
|
||||
"The gravity-source test element does not match the registered "
|
||||
"gravity potential."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
coefficient_order == field::Density::Scalar::familyOrder,
|
||||
"The gravity-source coefficient order does not match the "
|
||||
"registered density field."
|
||||
);
|
||||
const Query query =
|
||||
GravityField::make_query<field::Gravity::Form::SourceLinear>(
|
||||
role, transformation.OrderW(), {}, domain, mapping
|
||||
);
|
||||
|
||||
const auto [resolution, integration_rule] =
|
||||
get(query, test_element.GetGeomType());
|
||||
integrator.SetIntegrationRule(*integration_rule);
|
||||
return resolution;
|
||||
}
|
||||
Resolution RuleFactory::configure_gravity_source(
|
||||
mfem::MixedScalarMassIntegrator &integrator,
|
||||
QuadratureRole role,
|
||||
const mfem::FiniteElement &trial_element,
|
||||
const mfem::FiniteElement &test_element,
|
||||
const mfem::ElementTransformation &transformation,
|
||||
int coefficient_order,
|
||||
utils::DOMAINS domain,
|
||||
MappingKind mapping
|
||||
) const {
|
||||
MFEM_VERIFY(
|
||||
trial_element.GetGeomType() == test_element.GetGeomType(),
|
||||
"Gravity source trial and test elements must use the same geometry."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
trial_element.GetGeomType() == transformation.GetGeometryType(),
|
||||
"Gravity source element and transformation geometries must agree."
|
||||
);
|
||||
|
||||
using GravityField = field::Field<field::Gravity>;
|
||||
MFEM_VERIFY(
|
||||
trial_element.GetOrder() == field::Density::Scalar::familyOrder,
|
||||
"The gravity-source trial element does not match the registered "
|
||||
"density field."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
test_element.GetOrder() == field::Gravity::Potential::familyOrder,
|
||||
"The gravity-source test element does not match the registered "
|
||||
"gravity potential."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
coefficient_order == 0,
|
||||
"The mapped gravity-source coefficient order must be zero; "
|
||||
"density order is supplied by the registered trial field."
|
||||
);
|
||||
const Query query =
|
||||
GravityField::make_query<field::Gravity::Form::SourceProjection>(
|
||||
role, transformation.OrderW(), {}, domain, mapping
|
||||
);
|
||||
|
||||
const auto [resolution, integration_rule] =
|
||||
get(query, transformation.GetGeometryType());
|
||||
integrator.SetIntRule(integration_rule);
|
||||
return resolution;
|
||||
}
|
||||
|
||||
Resolution RuleFactory::configure_centrifugal(
|
||||
integrators::CentrifugalForceIntegrator &integrator,
|
||||
const QuadratureRole role,
|
||||
const mfem::FiniteElement &density_element,
|
||||
const mfem::FiniteElement &velocity_element,
|
||||
const mfem::ElementTransformation &transformation,
|
||||
const int position_order,
|
||||
const utils::DOMAINS domain,
|
||||
const MappingKind mapping
|
||||
) const {
|
||||
const Query query = {
|
||||
.term = Term::centrifugal,
|
||||
.role = role,
|
||||
.domain = domain,
|
||||
.mapping = mapping,
|
||||
.trial_order = density_element.GetOrder(),
|
||||
.test_order = velocity_element.GetOrder(),
|
||||
.coefficient_order = position_order,
|
||||
.geometry_weight_order = transformation.OrderW()
|
||||
};
|
||||
|
||||
const auto [resolution, integration_rule] =
|
||||
get(query, velocity_element.GetGeomType());
|
||||
integrator.SetIntegrationRule(*integration_rule);
|
||||
return resolution;
|
||||
}
|
||||
|
||||
template <typename IntegratorType>
|
||||
Resolution RuleFactory::configure(
|
||||
IntegratorType& integrator,
|
||||
IntegratorType &integrator,
|
||||
const Term term,
|
||||
const QuadratureRole role,
|
||||
const mfem::Geometry::Type geometry,
|
||||
@@ -190,9 +323,10 @@ export namespace mean_field::quadrature {
|
||||
const utils::DOMAINS domain,
|
||||
const MappingKind mapping
|
||||
) const {
|
||||
const auto [resolution, integration_rule] = get(term, role, geometry, base_order, domain, mapping);
|
||||
const auto [resolution, integration_rule] =
|
||||
get(term, role, geometry, base_order, domain, mapping);
|
||||
integrator.SetIntegrationRule(*integration_rule);
|
||||
return resolution;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace mean_field::quadrature
|
||||
|
||||
@@ -2,7 +2,9 @@ module;
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
export module mean_field:quadrature.policy;
|
||||
export import :utils.misc;
|
||||
@@ -13,11 +15,19 @@ export namespace mean_field::quadrature {
|
||||
gravity_divergence,
|
||||
gravity_source,
|
||||
gravity_boundary,
|
||||
centrifugal,
|
||||
density_projection,
|
||||
eos_closure,
|
||||
hydrostatic_equilibrium,
|
||||
isobaric_surface,
|
||||
mesh_extension,
|
||||
mass_conservation,
|
||||
mass_normalization,
|
||||
center_of_mass,
|
||||
quadrupole,
|
||||
gravitational_energy,
|
||||
pressure_integral,
|
||||
pressure_force,
|
||||
virial,
|
||||
error_norm
|
||||
};
|
||||
@@ -29,19 +39,9 @@ export namespace mean_field::quadrature {
|
||||
projection
|
||||
};
|
||||
|
||||
enum class MappingKind {
|
||||
none,
|
||||
affine,
|
||||
general,
|
||||
kelvin
|
||||
};
|
||||
enum class MappingKind { none, affine, general, kelvin };
|
||||
|
||||
enum class Mode {
|
||||
fast,
|
||||
production,
|
||||
reference,
|
||||
convergence
|
||||
};
|
||||
enum class Mode { fast, production, reference, convergence };
|
||||
|
||||
struct RuleControl {
|
||||
std::optional<int> fixed_order;
|
||||
@@ -55,17 +55,24 @@ export namespace mean_field::quadrature {
|
||||
RuleControl projection;
|
||||
};
|
||||
|
||||
|
||||
struct RuleSet {
|
||||
RuleControl gravity_hdiv_mass;
|
||||
RuleControl gravity_divergence;
|
||||
RuleControl gravity_source;
|
||||
RuleControl gravity_boundary;
|
||||
RuleControl centrifugal;
|
||||
RuleControl density_projection;
|
||||
RuleControl eos_closure;
|
||||
RuleControl hydrostatic_equilibrium;
|
||||
RuleControl isobaric_surface;
|
||||
RuleControl mesh_extension;
|
||||
RuleControl mass_conservation;
|
||||
RuleControl mass_normalization;
|
||||
RuleControl center_of_mass;
|
||||
RuleControl quadrupole;
|
||||
RuleControl gravitational_energy;
|
||||
RuleControl pressure_integral;
|
||||
RuleControl pressure_force;
|
||||
RuleControl virial;
|
||||
RuleControl error_norm;
|
||||
RoleControls roles;
|
||||
@@ -74,12 +81,12 @@ export namespace mean_field::quadrature {
|
||||
|
||||
struct Query {
|
||||
Term term;
|
||||
QuadratureRole role = QuadratureRole::discretization;
|
||||
utils::DOMAINS domain = utils::DOMAINS::ALL;
|
||||
MappingKind mapping = MappingKind::none;
|
||||
int trial_order = 0;
|
||||
int test_order = 0;
|
||||
int coefficient_order = 0;
|
||||
QuadratureRole role = QuadratureRole::discretization;
|
||||
utils::DOMAINS domain = utils::DOMAINS::ALL;
|
||||
MappingKind mapping = MappingKind::none;
|
||||
int trial_order = 0;
|
||||
int test_order = 0;
|
||||
int coefficient_order = 0;
|
||||
int geometry_weight_order = 0;
|
||||
std::optional<int> base_order;
|
||||
};
|
||||
@@ -96,16 +103,16 @@ export namespace mean_field::quadrature {
|
||||
};
|
||||
|
||||
struct QuadratureManifestOptions {
|
||||
bool enabled = false;
|
||||
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;
|
||||
bool require_explicit_mfem_rule = false;
|
||||
bool reject_negative_boosts = true;
|
||||
bool report_unused_overrides = true;
|
||||
};
|
||||
|
||||
struct QuadratureRoleOptions {
|
||||
@@ -116,7 +123,7 @@ export namespace mean_field::quadrature {
|
||||
};
|
||||
|
||||
struct QuadratureOptions {
|
||||
Mode mode = Mode::production;
|
||||
Mode mode = Mode::production;
|
||||
int global_boost = 0;
|
||||
std::optional<int> fallback_fixed_order;
|
||||
|
||||
@@ -124,11 +131,19 @@ export namespace mean_field::quadrature {
|
||||
QuadratureTermOptions gravity_divergence;
|
||||
QuadratureTermOptions gravity_source;
|
||||
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;
|
||||
|
||||
@@ -139,44 +154,51 @@ export namespace mean_field::quadrature {
|
||||
QuadratureValidationOptions validation;
|
||||
};
|
||||
|
||||
RuleSet make_rule_set(Mode mode, int global_boost = 0);
|
||||
RuleSet make_rule_set(
|
||||
Mode mode,
|
||||
int global_boost = 0
|
||||
);
|
||||
|
||||
class Policy {
|
||||
public:
|
||||
explicit Policy(RuleSet rule_set);
|
||||
Resolution resolve(const Query& query) const;
|
||||
Resolution resolve(const Query &query) const;
|
||||
|
||||
private:
|
||||
const RuleControl& get_control(Term term) const;
|
||||
static int compute_base_order(const Query& query) ;
|
||||
const RuleControl& get_role_control(QuadratureRole role) const;
|
||||
const RuleControl &get_control(Term term) const;
|
||||
static int compute_base_order(const Query &query);
|
||||
const RuleControl &get_role_control(QuadratureRole role) const;
|
||||
|
||||
RuleSet rule_set;
|
||||
};
|
||||
|
||||
RuleSet make_rule_set(const Mode mode, const int global_boost) {
|
||||
RuleSet make_rule_set(
|
||||
const Mode mode,
|
||||
const int global_boost
|
||||
) {
|
||||
RuleSet rule_set;
|
||||
|
||||
switch (mode) {
|
||||
case Mode::fast:
|
||||
case Mode::production:
|
||||
case Mode::convergence:
|
||||
rule_set.fallback.boost = global_boost;
|
||||
break;
|
||||
case Mode::reference:
|
||||
rule_set.fallback.boost = global_boost + 8;
|
||||
break;
|
||||
case Mode::fast:
|
||||
case Mode::production:
|
||||
case Mode::convergence:
|
||||
rule_set.fallback.boost = global_boost;
|
||||
break;
|
||||
case Mode::reference:
|
||||
rule_set.fallback.boost = global_boost + 8;
|
||||
break;
|
||||
}
|
||||
|
||||
return rule_set;
|
||||
}
|
||||
|
||||
Policy::Policy(RuleSet rule_set) : rule_set(std::move(rule_set)) {}
|
||||
Policy::Policy(RuleSet rule_set) : rule_set(std::move(rule_set)) {
|
||||
}
|
||||
|
||||
Resolution Policy::resolve(const Query& query) const {
|
||||
const int base_order = compute_base_order(query);
|
||||
const RuleControl& term_control = get_control(query.term);
|
||||
const RuleControl& role_control = get_role_control(query.role);
|
||||
Resolution Policy::resolve(const Query &query) const {
|
||||
const int base_order = compute_base_order(query);
|
||||
const RuleControl &term_control = get_control(query.term);
|
||||
const RuleControl &role_control = get_role_control(query.role);
|
||||
std::optional<int> fixed_order;
|
||||
|
||||
if (term_control.fixed_order.has_value()) {
|
||||
@@ -189,49 +211,96 @@ export namespace mean_field::quadrature {
|
||||
|
||||
if (fixed_order.has_value()) {
|
||||
if (*fixed_order < 0) {
|
||||
throw std::invalid_argument("Quadrature fixed order cannot be negative.");
|
||||
throw std::invalid_argument(
|
||||
"Quadrature fixed order cannot be negative."
|
||||
);
|
||||
}
|
||||
|
||||
return {.base_order = base_order, .boost = 0, .order = *fixed_order, .used_fixed_order = true};
|
||||
return {
|
||||
.base_order = base_order,
|
||||
.boost = 0,
|
||||
.order = *fixed_order,
|
||||
.used_fixed_order = true
|
||||
};
|
||||
}
|
||||
|
||||
const int boost = rule_set.fallback.boost + role_control.boost + term_control.boost;
|
||||
const int boost =
|
||||
rule_set.fallback.boost + role_control.boost + term_control.boost;
|
||||
const int order = base_order + boost;
|
||||
|
||||
if (order < 0) {
|
||||
throw std::invalid_argument("Resolved quadrature order cannot be negative.");
|
||||
throw std::invalid_argument(
|
||||
"Resolved quadrature order cannot be negative."
|
||||
);
|
||||
}
|
||||
|
||||
return {.base_order = base_order, .boost = boost, .order = order, .used_fixed_order = false};
|
||||
return {
|
||||
.base_order = base_order,
|
||||
.boost = boost,
|
||||
.order = order,
|
||||
.used_fixed_order = false
|
||||
};
|
||||
}
|
||||
const RuleControl& Policy::get_control(const Term term) const {
|
||||
const RuleControl &Policy::get_control(const Term term) const {
|
||||
switch (term) {
|
||||
case Term::gravity_hdiv_mass: return rule_set.gravity_hdiv_mass;
|
||||
case Term::gravity_divergence: return rule_set.gravity_divergence;
|
||||
case Term::gravity_source: return rule_set.gravity_source;
|
||||
case Term::gravity_boundary: return rule_set.gravity_boundary;
|
||||
case Term::density_projection: return rule_set.density_projection;
|
||||
case Term::mass_conservation: return rule_set.mass_conservation;
|
||||
case Term::center_of_mass: return rule_set.center_of_mass;
|
||||
case Term::quadrupole: return rule_set.quadrupole;
|
||||
case Term::gravitational_energy: return rule_set.gravitational_energy;
|
||||
case Term::virial: return rule_set.virial;
|
||||
case Term::error_norm: return rule_set.error_norm;
|
||||
case Term::gravity_hdiv_mass:
|
||||
return rule_set.gravity_hdiv_mass;
|
||||
case Term::gravity_divergence:
|
||||
return rule_set.gravity_divergence;
|
||||
case Term::gravity_source:
|
||||
return rule_set.gravity_source;
|
||||
case Term::gravity_boundary:
|
||||
return rule_set.gravity_boundary;
|
||||
case Term::centrifugal:
|
||||
return rule_set.centrifugal;
|
||||
case Term::density_projection:
|
||||
return rule_set.density_projection;
|
||||
case Term::eos_closure:
|
||||
return rule_set.eos_closure;
|
||||
case Term::hydrostatic_equilibrium:
|
||||
return rule_set.hydrostatic_equilibrium;
|
||||
case Term::isobaric_surface:
|
||||
return rule_set.isobaric_surface;
|
||||
case Term::mesh_extension:
|
||||
return rule_set.mesh_extension;
|
||||
case Term::mass_conservation:
|
||||
return rule_set.mass_conservation;
|
||||
case Term::mass_normalization:
|
||||
return rule_set.mass_normalization;
|
||||
case Term::center_of_mass:
|
||||
return rule_set.center_of_mass;
|
||||
case Term::quadrupole:
|
||||
return rule_set.quadrupole;
|
||||
case Term::gravitational_energy:
|
||||
return rule_set.gravitational_energy;
|
||||
case Term::pressure_integral:
|
||||
return rule_set.pressure_integral;
|
||||
case Term::pressure_force:
|
||||
return rule_set.pressure_force;
|
||||
case Term::virial:
|
||||
return rule_set.virial;
|
||||
case Term::error_norm:
|
||||
return rule_set.error_norm;
|
||||
}
|
||||
|
||||
throw std::logic_error("Unknown quadrature term.");
|
||||
}
|
||||
|
||||
int Policy::compute_base_order(const Query& query) {
|
||||
int Policy::compute_base_order(const Query &query) {
|
||||
if (query.base_order.has_value()) {
|
||||
if (*query.base_order < 0) {
|
||||
throw std::invalid_argument("Quadrature base order cannot be negative.");
|
||||
throw std::invalid_argument(
|
||||
"Quadrature base order cannot be negative."
|
||||
);
|
||||
}
|
||||
return *query.base_order;
|
||||
}
|
||||
|
||||
if (query.trial_order < 0 || query.test_order < 0 || query.coefficient_order < 0 || query.geometry_weight_order < 0) {
|
||||
throw std::invalid_argument("Quadrature query orders cannot be negative.");
|
||||
if (query.trial_order < 0 || query.test_order < 0 ||
|
||||
query.coefficient_order < 0 || query.geometry_weight_order < 0) {
|
||||
throw std::invalid_argument(
|
||||
"Quadrature query orders cannot be negative."
|
||||
);
|
||||
}
|
||||
|
||||
int trial_order = query.trial_order;
|
||||
@@ -239,18 +308,24 @@ export namespace mean_field::quadrature {
|
||||
trial_order = std::max(0, trial_order - 1);
|
||||
}
|
||||
|
||||
return trial_order + query.test_order + query.coefficient_order + query.geometry_weight_order;
|
||||
return trial_order + query.test_order + query.coefficient_order +
|
||||
query.geometry_weight_order;
|
||||
}
|
||||
|
||||
const RuleControl& Policy::get_role_control(const QuadratureRole role) const {
|
||||
const RuleControl &
|
||||
Policy::get_role_control(const QuadratureRole role) const {
|
||||
switch (role) {
|
||||
case QuadratureRole::discretization: return rule_set.roles.discretization;
|
||||
case QuadratureRole::preconditioner: return rule_set.roles.preconditioner;
|
||||
case QuadratureRole::diagnostic: return rule_set.roles.diagnostic;
|
||||
case QuadratureRole::projection: return rule_set.roles.projection;
|
||||
case QuadratureRole::discretization:
|
||||
return rule_set.roles.discretization;
|
||||
case QuadratureRole::preconditioner:
|
||||
return rule_set.roles.preconditioner;
|
||||
case QuadratureRole::diagnostic:
|
||||
return rule_set.roles.diagnostic;
|
||||
case QuadratureRole::projection:
|
||||
return rule_set.roles.projection;
|
||||
}
|
||||
|
||||
throw std::logic_error("Unknown quadrature role.");
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace mean_field::quadrature
|
||||
|
||||
29
libmeanfield/interface/solver/fields.cppm
Normal file
29
libmeanfield/interface/solver/fields.cppm
Normal file
@@ -0,0 +1,29 @@
|
||||
module;
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
export module mean_field:solver.fields;
|
||||
|
||||
export namespace mean_field::solver {
|
||||
enum class FieldBlock : std::uint8_t {
|
||||
velocity = 0,
|
||||
density = 1,
|
||||
gravity_gradient = 2,
|
||||
gravity_potential = 3,
|
||||
displacement = 4,
|
||||
count = 5
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr int block_index(const FieldBlock field) noexcept {
|
||||
return static_cast<int>(field);
|
||||
}
|
||||
|
||||
inline constexpr int field_block_count = block_index(FieldBlock::count);
|
||||
|
||||
static_assert(block_index(FieldBlock::velocity) == 0);
|
||||
static_assert(block_index(FieldBlock::density) == 1);
|
||||
static_assert(block_index(FieldBlock::gravity_gradient) == 2);
|
||||
static_assert(block_index(FieldBlock::gravity_potential) == 3);
|
||||
static_assert(block_index(FieldBlock::displacement) == 4);
|
||||
static_assert(field_block_count == 5);
|
||||
} // namespace mean_field::solver
|
||||
493
libmeanfield/interface/utils/blocks.cppm
Normal file
493
libmeanfield/interface/utils/blocks.cppm
Normal file
@@ -0,0 +1,493 @@
|
||||
module;
|
||||
#include <array>
|
||||
#include <mfem.hpp>
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
export module mean_field:utils.blocks;
|
||||
|
||||
export namespace mean_field::utils::blocks {
|
||||
inline constexpr int dynamic_block_size = -1;
|
||||
|
||||
struct block { };
|
||||
|
||||
struct residual_block_base : block {
|
||||
static constexpr int static_block_size = dynamic_block_size;
|
||||
};
|
||||
|
||||
struct value_block_base : block {
|
||||
static constexpr int static_block_size = dynamic_block_size;
|
||||
};
|
||||
|
||||
struct term { };
|
||||
struct field { };
|
||||
|
||||
template <typename Residual, typename... Values> struct block_row { };
|
||||
template <int index_value>
|
||||
struct residual_block final : residual_block_base {
|
||||
static constexpr int index = index_value;
|
||||
|
||||
// ReSharper disable once CppNonExplicitConversionOperator
|
||||
constexpr operator int() const noexcept {
|
||||
return index;
|
||||
}
|
||||
};
|
||||
|
||||
template <int index_value> struct value_block final : value_block_base {
|
||||
static constexpr int index = index_value;
|
||||
|
||||
// ReSharper disable once CppNonExplicitConversionOperator
|
||||
constexpr operator int() const noexcept {
|
||||
return index;
|
||||
}
|
||||
};
|
||||
|
||||
struct density final : field {
|
||||
struct mass final : term {
|
||||
struct value final : value_block_base { };
|
||||
struct residual final : residual_block_base { };
|
||||
};
|
||||
|
||||
static inline constexpr mass mass_term{};
|
||||
};
|
||||
|
||||
struct displacement final : field {
|
||||
struct geometry final : term {
|
||||
struct value final : value_block_base { };
|
||||
struct residual final : residual_block_base { };
|
||||
};
|
||||
|
||||
static inline constexpr geometry geometry_term{};
|
||||
};
|
||||
|
||||
struct gravity final : field {
|
||||
struct gradient final : term {
|
||||
struct value final : value_block_base { };
|
||||
struct residual final : residual_block_base { };
|
||||
};
|
||||
|
||||
struct poisson final : term {
|
||||
struct value final : value_block_base { };
|
||||
struct residual final : residual_block_base { };
|
||||
};
|
||||
|
||||
static inline constexpr gradient gradient_term{};
|
||||
static inline constexpr poisson poisson_term{};
|
||||
};
|
||||
|
||||
struct enthalpy final : field {
|
||||
struct specific final : term {
|
||||
struct value final : value_block_base { };
|
||||
struct residual final : residual_block_base { };
|
||||
};
|
||||
|
||||
static inline constexpr specific specific_term{};
|
||||
};
|
||||
|
||||
struct barotropic_constant final : field {
|
||||
struct mass_normalization final : term {
|
||||
struct value final : value_block_base {
|
||||
static constexpr int static_block_size = 1;
|
||||
};
|
||||
|
||||
struct residual final : residual_block_base {
|
||||
static constexpr int static_block_size = 1;
|
||||
};
|
||||
};
|
||||
|
||||
static inline constexpr mass_normalization mass_normalization_term{};
|
||||
};
|
||||
|
||||
inline constexpr density density_field{};
|
||||
inline constexpr displacement displacement_field{};
|
||||
inline constexpr gravity gravity_field{};
|
||||
inline constexpr enthalpy enthalpy_field{};
|
||||
inline constexpr barotropic_constant barotropic_constant_field{};
|
||||
|
||||
template <typename... Types> struct type_list {
|
||||
static constexpr int size = sizeof...(Types);
|
||||
};
|
||||
|
||||
template <typename Query, typename List> struct contains_type;
|
||||
|
||||
template <typename Query>
|
||||
struct contains_type<Query, type_list<>> : std::false_type { };
|
||||
|
||||
template <typename Query, typename Head, typename... Tail>
|
||||
struct contains_type<Query, type_list<Head, Tail...>>
|
||||
: std::conditional_t<
|
||||
std::is_same_v<Query, Head>,
|
||||
std::true_type,
|
||||
contains_type<Query, type_list<Tail...>>> { };
|
||||
|
||||
template <typename Query, typename List>
|
||||
inline constexpr bool contains_type_v = contains_type<Query, List>::value;
|
||||
|
||||
template <typename Query, typename List> struct type_count;
|
||||
|
||||
template <typename Query>
|
||||
struct type_count<Query, type_list<>> : std::integral_constant<int, 0> { };
|
||||
|
||||
template <typename Query, typename Head, typename... Tail>
|
||||
struct type_count<Query, type_list<Head, Tail...>>
|
||||
: std::integral_constant<
|
||||
int,
|
||||
(std::is_same_v<Query, Head> ? 1 : 0) +
|
||||
type_count<Query, type_list<Tail...>>::value> { };
|
||||
|
||||
template <typename Query, typename List>
|
||||
inline constexpr int type_count_v = type_count<Query, List>::value;
|
||||
|
||||
template <typename List> struct types_are_unique;
|
||||
|
||||
template <typename... Types>
|
||||
struct types_are_unique<type_list<Types...>>
|
||||
: std::bool_constant<
|
||||
((type_count_v<Types, type_list<Types...>> == 1) && ...)> { };
|
||||
|
||||
template <typename List>
|
||||
inline constexpr bool types_are_unique_v = types_are_unique<List>::value;
|
||||
|
||||
template <typename Row> struct block_row_traits {
|
||||
using residual = void;
|
||||
using values = type_list<>;
|
||||
|
||||
static constexpr int value_count = 0;
|
||||
static constexpr bool is_block_row = false;
|
||||
};
|
||||
|
||||
template <typename Residual, typename... Values>
|
||||
struct block_row_traits<block_row<Residual, Values...>> {
|
||||
using residual = Residual;
|
||||
using values = type_list<Values...>;
|
||||
|
||||
static constexpr int value_count = sizeof...(Values);
|
||||
static constexpr bool is_block_row = true;
|
||||
};
|
||||
|
||||
template <typename Query, typename List> struct type_index;
|
||||
|
||||
template <typename Query, typename... Tail>
|
||||
struct type_index<Query, type_list<Query, Tail...>> {
|
||||
static constexpr int value = 0;
|
||||
};
|
||||
|
||||
template <typename Query, typename Head, typename... Tail>
|
||||
struct type_index<Query, type_list<Head, Tail...>> {
|
||||
static constexpr int value =
|
||||
1 + type_index<Query, type_list<Tail...>>::value;
|
||||
};
|
||||
|
||||
template <typename Query, typename List>
|
||||
inline constexpr int type_index_v = type_index<Query, List>::value;
|
||||
|
||||
template <typename ValueBlocks, typename ResidualBlocks> struct block_form {
|
||||
using value_blocks = ValueBlocks;
|
||||
using residual_blocks = ResidualBlocks;
|
||||
|
||||
static constexpr int value_block_count = ValueBlocks::size;
|
||||
static constexpr int residual_block_count = ResidualBlocks::size;
|
||||
};
|
||||
|
||||
template <typename Form> struct block_form_is_valid : std::false_type { };
|
||||
|
||||
template <typename... Values, typename... Residuals>
|
||||
struct block_form_is_valid<
|
||||
block_form<type_list<Values...>, type_list<Residuals...>>>
|
||||
: std::bool_constant<
|
||||
(std::is_base_of_v<value_block_base, Values> && ...) &&
|
||||
(std::is_base_of_v<residual_block_base, Residuals> && ...) &&
|
||||
types_are_unique_v<type_list<Values...>> &&
|
||||
types_are_unique_v<type_list<Residuals...>>> { };
|
||||
|
||||
template <typename Form>
|
||||
inline constexpr bool block_form_is_valid_v =
|
||||
block_form_is_valid<Form>::value;
|
||||
|
||||
template <typename Row, typename ValueBlocks, typename ResidualBlocks>
|
||||
struct block_row_is_valid : std::false_type { };
|
||||
|
||||
template <
|
||||
typename Residual,
|
||||
typename... Values,
|
||||
typename ValueBlocks,
|
||||
typename ResidualBlocks>
|
||||
struct block_row_is_valid<
|
||||
block_row<Residual, Values...>,
|
||||
ValueBlocks,
|
||||
ResidualBlocks>
|
||||
: std::bool_constant<
|
||||
std::is_base_of_v<residual_block_base, Residual> &&
|
||||
contains_type_v<Residual, ResidualBlocks> &&
|
||||
((std::is_base_of_v<value_block_base, Values> &&
|
||||
contains_type_v<Values, ValueBlocks>) &&
|
||||
...) &&
|
||||
types_are_unique_v<type_list<Values...>>> { };
|
||||
|
||||
template <typename Rows> struct row_residual_list;
|
||||
|
||||
template <typename... Rows> struct row_residual_list<type_list<Rows...>> {
|
||||
using type = type_list<typename block_row_traits<Rows>::residual...>;
|
||||
};
|
||||
|
||||
template <typename Rows>
|
||||
using row_residual_list_t = typename row_residual_list<Rows>::type;
|
||||
|
||||
template <typename Form, typename JacobianForm>
|
||||
struct jacobian_form_is_valid : std::false_type { };
|
||||
|
||||
template <typename... Values, typename... Residuals, typename... Rows>
|
||||
struct jacobian_form_is_valid<
|
||||
block_form<type_list<Values...>, type_list<Residuals...>>,
|
||||
type_list<Rows...>> {
|
||||
using form_type =
|
||||
block_form<type_list<Values...>, type_list<Residuals...>>;
|
||||
|
||||
using value_blocks = type_list<Values...>;
|
||||
using residual_blocks = type_list<Residuals...>;
|
||||
using rows = type_list<Rows...>;
|
||||
|
||||
static constexpr bool value =
|
||||
block_form_is_valid_v<form_type> &&
|
||||
(block_row_is_valid<Rows, value_blocks, residual_blocks>::value &&
|
||||
...) &&
|
||||
std::is_same_v<row_residual_list_t<rows>, residual_blocks>;
|
||||
};
|
||||
|
||||
template <typename Form, typename JacobianForm>
|
||||
inline constexpr bool jacobian_form_is_valid_v =
|
||||
jacobian_form_is_valid<Form, JacobianForm>::value;
|
||||
|
||||
template <typename Form, typename JacobianForm>
|
||||
concept valid_jacobian_form = jacobian_form_is_valid_v<Form, JacobianForm>;
|
||||
|
||||
template <typename Residual, typename Value, typename JacobianForm>
|
||||
struct has_jacobian_coupling;
|
||||
|
||||
template <typename Residual, typename Value>
|
||||
struct has_jacobian_coupling<Residual, Value, type_list<>>
|
||||
: std::false_type { };
|
||||
|
||||
template <
|
||||
typename Residual,
|
||||
typename Value,
|
||||
typename RowResidual,
|
||||
typename... RowValues,
|
||||
typename... RemainingRows>
|
||||
struct has_jacobian_coupling<
|
||||
Residual,
|
||||
Value,
|
||||
type_list<block_row<RowResidual, RowValues...>, RemainingRows...>>
|
||||
: std::conditional_t<
|
||||
std::is_same_v<Residual, RowResidual>,
|
||||
std::bool_constant<(std::is_same_v<Value, RowValues> || ...)>,
|
||||
has_jacobian_coupling<
|
||||
Residual,
|
||||
Value,
|
||||
type_list<RemainingRows...>>> { };
|
||||
|
||||
template <typename Residual, typename Value, typename JacobianForm>
|
||||
inline constexpr bool has_jacobian_coupling_v =
|
||||
has_jacobian_coupling<Residual, Value, JacobianForm>::value;
|
||||
|
||||
template <
|
||||
typename Form,
|
||||
typename Term>
|
||||
consteval auto get_value_block(const Term &) {
|
||||
using value_type = typename Term::value;
|
||||
constexpr int index =
|
||||
type_index_v<value_type, typename Form::value_blocks>;
|
||||
return value_block<index>{};
|
||||
}
|
||||
|
||||
template <
|
||||
typename Form,
|
||||
typename Term>
|
||||
consteval auto get_residual_block(const Term &) {
|
||||
using residual_type = typename Term::residual;
|
||||
constexpr int index =
|
||||
type_index_v<residual_type, typename Form::residual_blocks>;
|
||||
return residual_block<index>{};
|
||||
}
|
||||
|
||||
template <typename Form> class form_layout {
|
||||
public:
|
||||
form_layout(
|
||||
const std::array<
|
||||
int,
|
||||
Form::value_block_count> &value_sizes,
|
||||
const std::array<
|
||||
int,
|
||||
Form::residual_block_count> &residual_sizes
|
||||
) {
|
||||
build_offsets(
|
||||
m_value_offsets, value_sizes, typename Form::value_blocks{}
|
||||
);
|
||||
|
||||
build_offsets(
|
||||
m_residual_offsets, residual_sizes,
|
||||
typename Form::residual_blocks{}
|
||||
);
|
||||
}
|
||||
|
||||
template <int index> [[nodiscard]] int size(value_block<index>) const {
|
||||
return m_value_offsets[index + 1] - m_value_offsets[index];
|
||||
}
|
||||
|
||||
template <int index>
|
||||
[[nodiscard]] int size(residual_block<index>) const {
|
||||
return m_residual_offsets[index + 1] - m_residual_offsets[index];
|
||||
}
|
||||
|
||||
template <int index>
|
||||
[[nodiscard]] int offset(value_block<index>) const {
|
||||
return m_value_offsets[index];
|
||||
}
|
||||
|
||||
template <int index>
|
||||
[[nodiscard]] int offset(residual_block<index>) const {
|
||||
return m_residual_offsets[index];
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const mfem::Array<int> &value_offsets() const noexcept {
|
||||
return m_value_offsets;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const mfem::Array<int> &residual_offsets() const noexcept {
|
||||
return m_residual_offsets;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename BlockType>
|
||||
[[nodiscard]]
|
||||
static int resolve_block_size(const int requested_size) {
|
||||
if constexpr (BlockType::static_block_size == dynamic_block_size) {
|
||||
return requested_size;
|
||||
} else {
|
||||
if (requested_size != BlockType::static_block_size) {
|
||||
throw std::invalid_argument(
|
||||
"A statically sized block was given an "
|
||||
"incompatible runtime size."
|
||||
);
|
||||
}
|
||||
|
||||
return BlockType::static_block_size;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... BlockTypes>
|
||||
static void build_offsets(
|
||||
mfem::Array<int> &offsets,
|
||||
const std::array<
|
||||
int,
|
||||
sizeof...(BlockTypes)> &requested_sizes,
|
||||
type_list<BlockTypes...>
|
||||
) {
|
||||
offsets.SetSize(sizeof...(BlockTypes) + 1);
|
||||
offsets[0] = 0;
|
||||
|
||||
int block_index = 0;
|
||||
|
||||
((offsets[block_index + 1] =
|
||||
offsets[block_index] +
|
||||
resolve_block_size<BlockTypes>(requested_sizes[block_index]),
|
||||
++block_index),
|
||||
...);
|
||||
}
|
||||
|
||||
mfem::Array<int> m_value_offsets;
|
||||
mfem::Array<int> m_residual_offsets;
|
||||
};
|
||||
using gravity_field_form = block_form<
|
||||
type_list<
|
||||
density::mass::value,
|
||||
displacement::geometry::value,
|
||||
gravity::gradient::value,
|
||||
gravity::poisson::value>,
|
||||
type_list<gravity::gradient::residual, gravity::poisson::residual>>;
|
||||
|
||||
using gravity_jacobian_form = type_list<
|
||||
block_row<
|
||||
gravity::gradient::residual,
|
||||
gravity::gradient::value,
|
||||
gravity::poisson::value,
|
||||
displacement::geometry::value>,
|
||||
block_row<
|
||||
gravity::poisson::residual,
|
||||
gravity::gradient::value,
|
||||
density::mass::value,
|
||||
displacement::geometry::value>>;
|
||||
|
||||
// Columns:
|
||||
// [rho, d, g, Phi, h, C]
|
||||
//
|
||||
// Rows:
|
||||
// [R_g, R_Phi, R_rho, R_d, R_h, R_M]
|
||||
using barotropic_equilibrium_form = block_form<
|
||||
type_list<
|
||||
density::mass::value,
|
||||
displacement::geometry::value,
|
||||
gravity::gradient::value,
|
||||
gravity::poisson::value,
|
||||
enthalpy::specific::value,
|
||||
barotropic_constant::mass_normalization::value>,
|
||||
type_list<
|
||||
gravity::gradient::residual,
|
||||
gravity::poisson::residual,
|
||||
density::mass::residual,
|
||||
displacement::geometry::residual,
|
||||
enthalpy::specific::residual,
|
||||
barotropic_constant::mass_normalization::residual>>;
|
||||
|
||||
using barotropic_equilibrium_jacobian_form = type_list<
|
||||
// R_g(g, Phi, d)
|
||||
block_row<
|
||||
gravity::gradient::residual,
|
||||
gravity::gradient::value,
|
||||
gravity::poisson::value,
|
||||
displacement::geometry::value>,
|
||||
|
||||
// R_Phi(g, rho, d)
|
||||
block_row<
|
||||
gravity::poisson::residual,
|
||||
gravity::gradient::value,
|
||||
density::mass::value,
|
||||
displacement::geometry::value>,
|
||||
|
||||
// R_rho(rho, h, d)
|
||||
block_row<
|
||||
density::mass::residual,
|
||||
density::mass::value,
|
||||
enthalpy::specific::value,
|
||||
displacement::geometry::value>,
|
||||
|
||||
// R_d(d, h)
|
||||
block_row<
|
||||
displacement::geometry::residual,
|
||||
displacement::geometry::value,
|
||||
enthalpy::specific::value>,
|
||||
|
||||
// R_h(h, Phi, d, C)
|
||||
block_row<
|
||||
enthalpy::specific::residual,
|
||||
enthalpy::specific::value,
|
||||
gravity::poisson::value,
|
||||
displacement::geometry::value,
|
||||
barotropic_constant::mass_normalization::value>,
|
||||
|
||||
// R_M(rho, d)
|
||||
block_row<
|
||||
barotropic_constant::mass_normalization::residual,
|
||||
density::mass::value,
|
||||
displacement::geometry::value>>;
|
||||
|
||||
static_assert(valid_jacobian_form<
|
||||
gravity_field_form,
|
||||
gravity_jacobian_form>);
|
||||
|
||||
static_assert(valid_jacobian_form<
|
||||
barotropic_equilibrium_form,
|
||||
barotropic_equilibrium_jacobian_form>);
|
||||
} // namespace mean_field::utils::blocks
|
||||
@@ -21,4 +21,4 @@ export namespace mean_field::utils {
|
||||
mapping::COORDINATE_SPACE vspace = mapping::COORDINATE_SPACE::REFERENCE,
|
||||
mapping::COORDINATE_SPACE rspace = mapping::COORDINATE_SPACE::PHYSICAL
|
||||
);
|
||||
}
|
||||
} // namespace mean_field::utils
|
||||
@@ -1,7 +1,7 @@
|
||||
module;
|
||||
#include <string_view>
|
||||
#include <functional>
|
||||
#include <expected>
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
@@ -14,8 +14,10 @@ import :boundary.contexts;
|
||||
export namespace mean_field::utils {
|
||||
constexpr double APPROX_MAX_ACCEPTABLE_POTENTIAL_ERROR_SI_BURNING = 1e-4;
|
||||
|
||||
|
||||
bool is_vacuum(const mfem::ElementTransformation &Tr, mfem::Array<mfem::Vector*> elvec) {
|
||||
bool is_vacuum(
|
||||
const mfem::ElementTransformation &Tr,
|
||||
mfem::Array<mfem::Vector *> elvec
|
||||
) {
|
||||
if (Tr.Attribute == 3) {
|
||||
const int size_elvec = elvec.Size();
|
||||
for (int i = 0; i < size_elvec; i++) {
|
||||
@@ -28,45 +30,60 @@ export namespace mean_field::utils {
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr std::string_view ANSI_GREEN = "\033[32m";
|
||||
constexpr std::string_view ANSI_RED = "\033[31m";
|
||||
constexpr std::string_view ANSI_YELLOW = "\033[33m";
|
||||
constexpr std::string_view ANSI_BLUE = "\033[34m";
|
||||
constexpr std::string_view ANSI_MAGENTA = "\033[35m";
|
||||
constexpr std::string_view ANSI_CYAN = "\033[36m";
|
||||
constexpr std::string_view ANSI_RESET = "\033[0m";
|
||||
constexpr std::string_view ANSI_BCYAN = "\033[1;36m";
|
||||
bool is_vacuum(
|
||||
const mfem::ElementTransformation &Tr,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||
) {
|
||||
if (Tr.Attribute == 3) {
|
||||
const int cols = elmats.NumCols();
|
||||
const int rows = elmats.NumRows();
|
||||
for (int rowID = 0; rowID < rows; rowID++) {
|
||||
for (int colID = 0; colID < cols; colID++) {
|
||||
if (elmats(rowID, colID)) {
|
||||
*elmats(rowID, colID) = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr std::string_view ANSI_GREEN = "\033[32m";
|
||||
constexpr std::string_view ANSI_RED = "\033[31m";
|
||||
constexpr std::string_view ANSI_YELLOW = "\033[33m";
|
||||
constexpr std::string_view ANSI_BLUE = "\033[34m";
|
||||
constexpr std::string_view ANSI_MAGENTA = "\033[35m";
|
||||
constexpr std::string_view ANSI_CYAN = "\033[36m";
|
||||
constexpr std::string_view ANSI_RESET = "\033[0m";
|
||||
constexpr std::string_view ANSI_BCYAN = "\033[1;36m";
|
||||
|
||||
constexpr double G = 1.0;
|
||||
constexpr double MASS = 1.0;
|
||||
constexpr double RADIUS = 1.0;
|
||||
constexpr double G = 1.0;
|
||||
constexpr double MASS = 1.0;
|
||||
constexpr double RADIUS = 1.0;
|
||||
|
||||
[[maybe_unused]] constexpr char HOST[10] = "localhost";
|
||||
[[maybe_unused]] constexpr int PORT = 19916;
|
||||
[[maybe_unused]] constexpr int PORT = 19916;
|
||||
|
||||
template <typename T>
|
||||
concept is_xad = std::is_same_v<T, xad::AReal<long double>> ||
|
||||
std::is_same_v<T, xad::AReal<double>> ||
|
||||
std::is_same_v<T, xad::AReal<float>>;
|
||||
|
||||
template<typename T>
|
||||
concept is_xad =
|
||||
std::is_same_v<T, xad::AReal<long double> >
|
||||
|| std::is_same_v<T, xad::AReal<double> >
|
||||
|| std::is_same_v<T, xad::AReal<float> >;
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
concept is_real = std::is_floating_point_v<T> || is_xad<T>;
|
||||
|
||||
template<is_real T>
|
||||
using EOS_P = std::function<T(const T& rho, const T& temp)>;
|
||||
template <is_real T>
|
||||
using EOS_P = std::function<T(const T &rho, const T &temp)>;
|
||||
|
||||
enum class DOMAINS : uint8_t {
|
||||
CORE = 1 << 0,
|
||||
CORE = 1 << 0,
|
||||
ENVELOPE = 1 << 1,
|
||||
VACUUM = 1 << 2,
|
||||
STELLAR = CORE | ENVELOPE,
|
||||
ALL = CORE | ENVELOPE | VACUUM
|
||||
VACUUM = 1 << 2,
|
||||
STELLAR = CORE | ENVELOPE,
|
||||
ALL = CORE | ENVELOPE | VACUUM
|
||||
};
|
||||
|
||||
|
||||
DOMAINS operator|(
|
||||
DOMAINS lhs,
|
||||
DOMAINS rhs
|
||||
@@ -78,7 +95,7 @@ export namespace mean_field::utils {
|
||||
);
|
||||
|
||||
void populate_element_mask(
|
||||
const mfem::Mesh* mesh,
|
||||
const mfem::Mesh *mesh,
|
||||
DOMAINS domain,
|
||||
mfem::Array<int> &mask
|
||||
);
|
||||
@@ -89,13 +106,14 @@ export namespace mean_field::utils {
|
||||
mfem::Array<int> &ess_tdof
|
||||
);
|
||||
|
||||
std::expected<boundary::Bounds, boundary::BoundsError> discover_bounds(
|
||||
std::expected<
|
||||
boundary::Bounds,
|
||||
boundary::BoundsError>
|
||||
discover_bounds(
|
||||
const mfem::Mesh *mesh,
|
||||
int vacuum_attr
|
||||
);
|
||||
|
||||
int get_mesh_order(
|
||||
const mfem::Mesh &mesh
|
||||
);
|
||||
int get_mesh_order(const mfem::Mesh &mesh);
|
||||
|
||||
}
|
||||
} // namespace mean_field::utils
|
||||
|
||||
@@ -3,6 +3,8 @@ module;
|
||||
export module mean_field:utils.user;
|
||||
export import :quadrature.policy;
|
||||
|
||||
export import :mapping.compactification.options;
|
||||
|
||||
export namespace mean_field::utils {
|
||||
struct potential {
|
||||
double rtol;
|
||||
@@ -16,6 +18,11 @@ export namespace mean_field::utils {
|
||||
double L;
|
||||
};
|
||||
|
||||
struct DomainMapperStatelessOptions {
|
||||
int dimension{3};
|
||||
int vacuum_element_attribute{3};
|
||||
};
|
||||
|
||||
struct Args {
|
||||
std::string mesh_file;
|
||||
potential p{};
|
||||
@@ -24,13 +31,13 @@ export namespace mean_field::utils {
|
||||
double index{};
|
||||
double mass{};
|
||||
double c{};
|
||||
|
||||
int quad_boost{0};
|
||||
|
||||
DomainMapperStatelessOptions domain_mapper_options{};
|
||||
mapping::compactification::options::KelvinCompactificationOptions
|
||||
kelvin_options{};
|
||||
int max_iters{};
|
||||
double tol{};
|
||||
|
||||
quadrature::QuadratureOptions quadrature{};
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace mean_field::utils
|
||||
|
||||
Reference in New Issue
Block a user