feat(libmeanfield): centrifugal + pressure

This commit is contained in:
2026-08-04 14:24:55 -04:00
parent 9bc4f2758a
commit dc912fd15e
115 changed files with 260058 additions and 163261 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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