feat(field-support): added field support system, mid migration

currently the barotope and the pressure force operator are migrated to the new support system
This commit is contained in:
2026-08-23 10:13:53 -04:00
parent dc912fd15e
commit 0f3ca8050b
137 changed files with 29975 additions and 16389 deletions

View File

@@ -0,0 +1,114 @@
module;
#include <concepts>
#include <memory>
#include <type_traits>
#include <utility>
export module mean_field:model.stellar;
export import :eos.base;
export import :model.structure.base;
export import :surface.base;
export namespace mean_field::models {
template <typename Candidate>
concept StructurePrescription =
std::derived_from<std::remove_cvref_t<Candidate>, mean_field::models::structure::StructureBase>;
template <typename Candidate>
concept SurfacePrescription = std::derived_from<std::remove_cvref_t<Candidate>, mean_field::surface::SurfaceBase>;
/*
* Public ownership facade for a physical structure prescription and its
* stellar-surface prescription.
*
* The concrete prescriptions are allocated once at construction. Their
* stable addresses allow future prepared operators and contexts to borrow
* references without making ownership part of the user-facing API.
*/
class StellarModel final {
public:
template <
StructurePrescription StructureType,
SurfacePrescription SurfaceType>
explicit StellarModel(
StructureType &&structurePrescription,
SurfaceType &&surfacePrescription
)
: StellarModel(
std::make_unique<std::remove_cvref_t<StructureType>>(
std::forward<StructureType>(structurePrescription)
),
std::make_unique<std::remove_cvref_t<SurfaceType>>(std::forward<SurfaceType>(surfacePrescription))
) {
}
~StellarModel() = default;
StellarModel(const StellarModel &) = delete;
StellarModel &operator=(const StellarModel &) = delete;
StellarModel(StellarModel &&) noexcept = default;
StellarModel &operator=(StellarModel &&) noexcept = default;
[[nodiscard]] const mean_field::models::structure::StructureBase &structurePrescription() const noexcept {
return *m_structurePrescription;
}
[[nodiscard]] const mean_field::surface::SurfaceBase &surfacePrescription() const noexcept {
return *m_surfacePrescription;
}
[[nodiscard]] const mean_field::eos::EquationOfState &equationOfState() const noexcept {
return m_structurePrescription->equationOfState();
}
[[nodiscard]] double targetMass() const noexcept {
return m_structurePrescription->targetMass();
}
[[nodiscard]] mean_field::models::structure::StructureSeed
makeInitialSeed(const mean_field::models::structure::StructureSeedRequest &request) const {
return m_structurePrescription->makeInitialSeed(request);
}
[[nodiscard]] const mean_field::surface::ResolvedSurfaceCondition &resolvedSurfaceCondition() const noexcept {
return m_resolvedSurfaceCondition;
}
private:
explicit StellarModel(
std::unique_ptr<mean_field::models::structure::StructureBase> structurePrescription,
std::unique_ptr<mean_field::surface::SurfaceBase> surfacePrescription
)
: m_structurePrescription(std::move(structurePrescription)),
m_surfacePrescription(std::move(surfacePrescription)),
m_resolvedSurfaceCondition(validateAndResolve(
*m_structurePrescription,
*m_surfacePrescription
)) {
}
[[nodiscard]] static mean_field::surface::ResolvedSurfaceCondition validateAndResolve(
const mean_field::models::structure::StructureBase &structurePrescription,
const mean_field::surface::SurfaceBase &surfacePrescription
) {
structurePrescription.validate();
const mean_field::eos::EquationOfState &equationOfState = structurePrescription.equationOfState();
surfacePrescription.validate(equationOfState);
return surfacePrescription.resolve(equationOfState);
}
std::unique_ptr<mean_field::models::structure::StructureBase> m_structurePrescription;
std::unique_ptr<mean_field::surface::SurfaceBase> m_surfacePrescription;
mean_field::surface::ResolvedSurfaceCondition m_resolvedSurfaceCondition;
};
} // namespace mean_field::models

View File

@@ -0,0 +1,68 @@
module;
#include <vector>
#include <mfem.hpp>
export module mean_field:model.structure.polytropic;
export import :eos.polytrope;
export import :model.structure.base;
import :utils.misc;
export namespace mean_field::models::structure {
class PolytropicStructure final : public StructureBase {
public:
explicit PolytropicStructure(
eos::Polytrope equationOfState,
double targetMass
);
[[nodiscard]] const eos::EquationOfState &equationOfState() const noexcept override;
[[nodiscard]] double targetMass() const noexcept override;
[[nodiscard]] StructureSeed makeInitialSeed(const StructureSeedRequest &request) const override;
void validate() const override;
private:
struct LaneEmdenPoint {
double coordinate{0.0};
double value{0.0};
double derivative{0.0};
};
struct LaneEmdenDerivative {
double value{0.0};
double derivative{0.0};
};
static void validateSeedRequest(const StructureSeedRequest &request);
[[nodiscard]] static LaneEmdenDerivative evaluateLaneEmdenRhs(
double coordinate,
double value,
double derivative,
double polytropicIndex
);
[[nodiscard]] static LaneEmdenPoint takeLaneEmdenStep(
const LaneEmdenPoint &point,
double step,
double polytropicIndex
);
[[nodiscard]] static std::vector<LaneEmdenPoint> solveLaneEmden(double polytropicIndex);
[[nodiscard]] static double interpolateLaneEmdenValue(
const std::vector<LaneEmdenPoint> &solution,
double coordinate,
std::size_t &lowerIndex
);
eos::Polytrope m_equationOfState;
double m_targetMass;
};
} // namespace mean_field::models::structure

View File

@@ -0,0 +1,37 @@
module;
#include <mfem.hpp>
export module mean_field:model.structure.base;
export import :eos.base;
export namespace mean_field::models::structure {
struct StructureSeed {
mfem::Vector radius;
mfem::Vector density;
mfem::Vector enthalpy;
double stellarRadius;
double centralDensity;
double centralEnthalpy;
};
struct StructureSeedRequest {
double centralDensity;
int radialSampleCount{512};
};
class StructureBase {
public:
virtual ~StructureBase() = default;
[[nodiscard]] virtual const eos::EquationOfState &equationOfState() const noexcept = 0;
[[nodiscard]] virtual double targetMass() const noexcept = 0;
[[nodiscard]] virtual StructureSeed makeInitialSeed(const StructureSeedRequest &request) const = 0;
virtual void validate() const = 0;
protected:
StructureBase() = default;
};
} // namespace mean_field::models::structure

View File

@@ -0,0 +1,146 @@
module;
#include <mfem.hpp>
export module mean_field:model.structure_profile;
export import :fem;
export namespace mean_field::models {
constexpr double DEFAULT_COLATITUDE_DEGREES = 90;
constexpr double DEFAULT_LONGITUDE_DEGREES = 0;
struct RadialDirection {
double coLatitudeDegrees{DEFAULT_COLATITUDE_DEGREES};
double longitudeDegrees{DEFAULT_LONGITUDE_DEGREES};
[[nodiscard]] mfem::Vector toUnitCartesian() const;
};
struct RadialProfile {
double coLatitudeDegrees;
double longitudeDegrees;
mfem::Vector radius;
mfem::Vector param;
};
struct SliceProfile {
double radius;
std::array<double, 2> normal;
mfem::GridFunction param;
};
class StructureProfile {
public:
explicit StructureProfile(
const fem::FEM &fem,
mfem::Vector state
);
// Profiles
mfem::GridFunction pressureProfile();
mfem::GridFunction densityProfile();
mfem::GridFunction gravitationalPotentialProfile();
mfem::GridFunction gravitationalFieldProfile();
mfem::GridFunction enthalpyProfile();
mfem::GridFunction entropyProfile();
mfem::GridFunction temperatureProfile();
mfem::GridFunction internalEnergyProfile();
// Local Evaluation
double pressureAt(const mfem::Vector &position);
double densityAt(const mfem::Vector &position);
double gravitationalPotentialAt(const mfem::Vector &position);
mfem::Vector gravitationalFieldAt(const mfem::Vector &position);
double enthalpyAt(const mfem::Vector &position);
double entropyAt(const mfem::Vector &position);
double temperatureAt(const mfem::Vector &position);
double internalEnergyAt(const mfem::Vector &position);
// Radial helpers
mfem::Vector radius(RadialDirection direction = {});
RadialProfile radialPressureProfile(RadialDirection direction = {});
RadialProfile radialDensityProfile(RadialDirection direction = {});
RadialProfile radialGravitationalPotentialProfile(RadialDirection direction = {});
RadialProfile radialGravitationalFieldProfile(RadialDirection direction = {});
RadialProfile radialEnthalpyProfile(RadialDirection direction = {});
RadialProfile radialEntropyProfile(RadialDirection direction = {});
RadialProfile radialTemperatureProfile(RadialDirection direction = {});
RadialProfile radialInternalEnergyProfile(RadialDirection direction = {});
// Ellipsoidal Slices
SliceProfile slicePressureProfile(
double radius,
const std::array<
double,
2> &normal
);
SliceProfile sliceDensityProfile(
double radius,
const std::array<
double,
2> &normal
);
SliceProfile sliceGravitationalPotentialProfile(
double radius,
const std::array<
double,
2> &normal
);
SliceProfile sliceGravitationalFieldProfile(
double radius,
const std::array<
double,
2> &normal
);
SliceProfile sliceEnthalpyProfile(
double radius,
const std::array<
double,
2> &normal
);
SliceProfile sliceEntropyProfile(
double radius,
const std::array<
double,
2> &normal
);
SliceProfile sliceTemperatureProfile(
double radius,
const std::array<
double,
2> &normal
);
SliceProfile sliceInternalEnergyProfile(
double radius,
const std::array<
double,
2> &normal
);
// Integral Constraints
double totalMass();
double virialRatio();
// Diagnostics
bool isBound();
// IO
void radialToCSV(
const std::string &filename,
RadialDirection direction = {}
);
void radialToBIN(
const std::string &filename,
RadialDirection direction = {}
);
void toBIN(const std::string &filename);
private:
const fem::FEM &m_fem;
const mfem::Vector m_state;
};
StructureProfile StructureProfileFromBIN(const std::string &filename);
} // namespace mean_field::models