feat(libmeanfield): variadic refactor
also added normaliztion operator
This commit is contained in:
196
libmeanfield/interface/operators/prepared_angular_momentum.cppm
Normal file
196
libmeanfield/interface/operators/prepared_angular_momentum.cppm
Normal file
@@ -0,0 +1,196 @@
|
||||
module;
|
||||
|
||||
#include <compare>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:operators.prepared_angular_momentum;
|
||||
|
||||
export import :fem;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :model.compiled_fixed_angular_momentum;
|
||||
export import :operators.context.gravity_field;
|
||||
|
||||
export namespace mean_field::operators {
|
||||
struct AngularMomentumDependencyStamp final {
|
||||
std::uint64_t identity{0};
|
||||
std::uint64_t revision{0};
|
||||
|
||||
constexpr auto operator<=>(const AngularMomentumDependencyStamp &) const = default;
|
||||
};
|
||||
|
||||
struct AngularMomentumDependencies final {
|
||||
AngularMomentumDependencyStamp discretization;
|
||||
AngularMomentumDependencyStamp density;
|
||||
AngularMomentumDependencyStamp displacement;
|
||||
AngularMomentumDependencyStamp rotation;
|
||||
|
||||
constexpr auto operator<=>(const AngularMomentumDependencies &) const = default;
|
||||
};
|
||||
|
||||
struct PreparedAngularMomentumReport final {
|
||||
bool rebuiltStaticPlan{false};
|
||||
bool refreshedGeometry{false};
|
||||
bool refreshedDensity{false};
|
||||
bool updatedAngularVelocity{false};
|
||||
bool assembledResidual{false};
|
||||
|
||||
[[nodiscard]] bool DidAnyWork() const noexcept {
|
||||
return rebuiltStaticPlan || refreshedGeometry || refreshedDensity || updatedAngularVelocity ||
|
||||
assembledResidual;
|
||||
}
|
||||
|
||||
constexpr auto operator<=>(const PreparedAngularMomentumReport &) const = default;
|
||||
};
|
||||
|
||||
struct AngularMomentumConstraintReport final {
|
||||
double targetAngularMomentum;
|
||||
double achievedAngularMomentum;
|
||||
double momentOfInertia;
|
||||
double angularVelocity;
|
||||
double dimensionalResidual;
|
||||
double scaledResidual;
|
||||
};
|
||||
|
||||
struct PreparedAngularMomentumActionStatistics final {
|
||||
std::uint64_t densityApplications{0};
|
||||
std::uint64_t displacementApplications{0};
|
||||
std::uint64_t angularVelocityApplications{0};
|
||||
std::uint64_t completeApplications{0};
|
||||
|
||||
constexpr auto operator<=>(const PreparedAngularMomentumActionStatistics &) const = default;
|
||||
};
|
||||
|
||||
/*
|
||||
* Prepared scalar invariant
|
||||
*
|
||||
* R_J(rho, d, Omega) = Omega I_axis(rho, d) - J_target,
|
||||
* I_axis = integral rho |(x-x_0)_perp|^2 dV.
|
||||
*
|
||||
* The axis is normalized by CompiledFixedAngularMomentum. Density and
|
||||
* geometry are borrowed from the shared gravity context, so this row is
|
||||
* linearized at exactly the same mapped state as every physical equation.
|
||||
*/
|
||||
class PreparedAngularMomentumOperator final {
|
||||
public:
|
||||
using SpecificationType = models::FixedAngularMomentum;
|
||||
using CompiledConstraintType = models::CompiledFixedAngularMomentum;
|
||||
using Dependencies = AngularMomentumDependencies;
|
||||
using Report = PreparedAngularMomentumReport;
|
||||
|
||||
PreparedAngularMomentumOperator(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapper &domainMapper,
|
||||
const context::gravity_field::GravityFieldLinearizationContext &gravityContext,
|
||||
models::CompiledFixedAngularMomentum constraint
|
||||
);
|
||||
|
||||
PreparedAngularMomentumOperator(const PreparedAngularMomentumOperator &) = delete;
|
||||
PreparedAngularMomentumOperator &operator=(const PreparedAngularMomentumOperator &) = delete;
|
||||
PreparedAngularMomentumOperator(PreparedAngularMomentumOperator &&) = delete;
|
||||
PreparedAngularMomentumOperator &operator=(PreparedAngularMomentumOperator &&) = delete;
|
||||
|
||||
PreparedAngularMomentumReport Prepare(
|
||||
double angularVelocity,
|
||||
const AngularMomentumDependencies &dependencies
|
||||
);
|
||||
|
||||
void BuildResidual(mfem::Vector &residual) const;
|
||||
|
||||
void ApplyDensityJacobianAction(
|
||||
const mfem::Vector &densityVariation,
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
void ApplyDisplacementJacobianAction(
|
||||
const mfem::Vector &displacementVariation,
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
void ApplyAngularVelocityJacobianAction(
|
||||
double angularVelocityVariation,
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
void ApplyCompleteJacobianAction(
|
||||
const mfem::Vector &densityVariation,
|
||||
const mfem::Vector &displacementVariation,
|
||||
double angularVelocityVariation,
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
[[nodiscard]] bool IsPrepared() const noexcept;
|
||||
[[nodiscard]] double GetMomentOfInertia() const;
|
||||
[[nodiscard]] double GetAngularVelocity() const;
|
||||
[[nodiscard]] double GetCurrentAngularMomentum() const;
|
||||
[[nodiscard]] double GetTargetAngularMomentum() const noexcept;
|
||||
[[nodiscard]] physics::RigidRotation GetRotation() const;
|
||||
[[nodiscard]] AngularMomentumConstraintReport GetConstraintReport() const;
|
||||
[[nodiscard]] std::uint64_t GetPreparationCount() const noexcept;
|
||||
[[nodiscard]] std::uint64_t GetResidualApplicationCount() const noexcept;
|
||||
[[nodiscard]] const PreparedAngularMomentumActionStatistics &GetActionStatistics() const noexcept;
|
||||
[[nodiscard]] const models::CompiledFixedAngularMomentum &GetCompiledConstraint() const noexcept;
|
||||
|
||||
private:
|
||||
struct QuadraturePointData final {
|
||||
mfem::IntegrationPoint integrationPoint;
|
||||
mfem::Vector densityShape;
|
||||
mapping::VolumeMappingContext mappingContext;
|
||||
double density{0.0};
|
||||
double cylindricalRadiusSquared{0.0};
|
||||
};
|
||||
|
||||
struct ElementPAData final {
|
||||
int elementId{-1};
|
||||
mfem::Array<int> densityDofs;
|
||||
mfem::Array<int> displacementDofs;
|
||||
mfem::Array<int> compactificationDofs;
|
||||
mfem::DofTransformation *densityDofTransformation{nullptr};
|
||||
mfem::DofTransformation *displacementDofTransformation{nullptr};
|
||||
mfem::DofTransformation *compactificationDofTransformation{nullptr};
|
||||
mfem::Vector baseDisplacement;
|
||||
mfem::Vector compactification;
|
||||
std::vector<QuadraturePointData> quadraturePoints;
|
||||
};
|
||||
|
||||
void BuildStaticPlan();
|
||||
void RefreshGeometry(const mfem::Vector &displacement);
|
||||
void RefreshDensity(const mfem::Vector &density);
|
||||
void AssembleResidual();
|
||||
void VerifyPrepared() const;
|
||||
|
||||
[[nodiscard]] double EvaluateDensityMomentActionLocal(const mfem::Vector &densityVariation) const;
|
||||
[[nodiscard]] double EvaluateDisplacementMomentActionLocal(const mfem::Vector &displacementVariation) const;
|
||||
[[nodiscard]] double CylindricalRadiusSquared(const mfem::Vector &physicalPosition) const noexcept;
|
||||
[[nodiscard]] double CylindricalRadiusSquaredVariation(
|
||||
const mfem::Vector &physicalPosition,
|
||||
const mfem::Vector &physicalPositionVariation
|
||||
) const noexcept;
|
||||
[[nodiscard]] double GlobalSum(double localValue) const;
|
||||
|
||||
const fem::FEM &m_fem;
|
||||
const mapping::DomainMapper &m_domainMapper;
|
||||
const context::gravity_field::GravityFieldLinearizationContext &m_gravityContext;
|
||||
models::CompiledFixedAngularMomentum m_constraint;
|
||||
|
||||
std::vector<ElementPAData> m_elements;
|
||||
AngularMomentumDependencies m_preparedDependencies;
|
||||
mfem::Vector m_cachedResidual;
|
||||
mutable mfem::Vector m_densityVariationTrue;
|
||||
mutable mfem::Vector m_displacementVariationTrue;
|
||||
mutable mfem::Vector m_densityVariationLocal;
|
||||
mutable mfem::Vector m_displacementVariationLocal;
|
||||
mutable mfem::Vector m_elementDensityVariation;
|
||||
mutable mfem::Vector m_elementDisplacementVariation;
|
||||
|
||||
double m_momentOfInertia{0.0};
|
||||
double m_angularVelocity{0.0};
|
||||
double m_currentAngularMomentum{0.0};
|
||||
std::uint64_t m_preparationCount{0};
|
||||
mutable std::uint64_t m_residualApplicationCount{0};
|
||||
mutable PreparedAngularMomentumActionStatistics m_actionStatistics;
|
||||
bool m_isPrepared{false};
|
||||
};
|
||||
} // namespace mean_field::operators
|
||||
@@ -1,117 +0,0 @@
|
||||
module;
|
||||
|
||||
#include <concepts>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:operators.prepared_central_density_stellar_equilibrium;
|
||||
|
||||
export import :model.compiled_fixed_central_density;
|
||||
export import :operators.prepared_central_density;
|
||||
export import :operators.prepared_stellar_equilibrium;
|
||||
|
||||
export namespace mean_field::operators {
|
||||
using CentralDensityStellarEquilibriumSpecificationModel = model::StellarModel<
|
||||
models::
|
||||
SpecificationSet<eos::Polytrope, models::FixedTotalMass, surface::Isobaric, models::FixedCentralDensity>>;
|
||||
|
||||
using CentralDensityStellarEquilibriumForm = utils::blocks::central_density_bordered_stellar_equilibrium_form;
|
||||
using CentralDensityStellarEquilibriumJacobianForm =
|
||||
utils::blocks::central_density_bordered_stellar_equilibrium_jacobian_form;
|
||||
using CentralDensityStellarEquilibriumLayout = utils::blocks::form_layout<CentralDensityStellarEquilibriumForm>;
|
||||
using CentralDensityStellarEquilibriumSystemManifest = EquilibriumSystemManifest<
|
||||
CentralDensityStellarEquilibriumSpecificationModel,
|
||||
CentralDensityStellarEquilibriumForm,
|
||||
CentralDensityStellarEquilibriumJacobianForm>;
|
||||
|
||||
using CentralDensityStellarEquilibriumRootManifest = CentralDensityStellarEquilibriumSystemManifest;
|
||||
|
||||
struct PreparedCentralDensityStellarEquilibriumReport final {
|
||||
PreparedStellarEquilibriumReport physical;
|
||||
PreparedCentralDensityReport phase;
|
||||
bool assembledResidual{false};
|
||||
|
||||
[[nodiscard]] bool DidAnyWork() const noexcept {
|
||||
return physical.DidAnyWork() || phase.DidAnyWork() || assembledResidual;
|
||||
}
|
||||
};
|
||||
|
||||
class PreparedCentralDensityStellarEquilibriumOperator final : public mfem::Operator {
|
||||
public:
|
||||
PreparedCentralDensityStellarEquilibriumOperator(
|
||||
fem::FEM &f,
|
||||
const mapping::DomainMapper &domainMapper,
|
||||
const eos::Polytrope &equationOfState,
|
||||
models::CompiledFixedMass fixedMassConstraint,
|
||||
PressureSurfaceConstraintView surfaceConstraint,
|
||||
deformation::PreparedDomainDeformationRuntime domainDeformation,
|
||||
models::CompiledFixedCentralDensity centralDensity
|
||||
)
|
||||
: PreparedCentralDensityStellarEquilibriumOperator(
|
||||
f,
|
||||
std::make_unique<PreparedStellarEquilibriumOperator>(
|
||||
f,
|
||||
domainMapper,
|
||||
equationOfState,
|
||||
std::move(fixedMassConstraint),
|
||||
surfaceConstraint,
|
||||
std::move(domainDeformation)
|
||||
),
|
||||
std::move(centralDensity),
|
||||
MakeCenterDofMap(f)
|
||||
) {
|
||||
}
|
||||
|
||||
PreparedCentralDensityStellarEquilibriumOperator(const PreparedCentralDensityStellarEquilibriumOperator &) =
|
||||
delete;
|
||||
PreparedCentralDensityStellarEquilibriumOperator &
|
||||
operator=(const PreparedCentralDensityStellarEquilibriumOperator &) = delete;
|
||||
PreparedCentralDensityStellarEquilibriumOperator(PreparedCentralDensityStellarEquilibriumOperator &&) = delete;
|
||||
PreparedCentralDensityStellarEquilibriumOperator &
|
||||
operator=(PreparedCentralDensityStellarEquilibriumOperator &&) = delete;
|
||||
|
||||
PreparedCentralDensityStellarEquilibriumReport Prepare(
|
||||
const mfem::Vector &state,
|
||||
const StellarEquilibriumDependencies &dependencies,
|
||||
const physics::RigidRotation &rotation
|
||||
);
|
||||
|
||||
void BuildResidual(mfem::Vector &residual) const;
|
||||
|
||||
void Mult(
|
||||
const mfem::Vector &direction,
|
||||
mfem::Vector &action
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] bool IsPrepared() const noexcept;
|
||||
[[nodiscard]] const CentralDensityStellarEquilibriumLayout &GetLayout() const noexcept;
|
||||
[[nodiscard]] const CentralDensityStellarEquilibriumRootManifest &GetRootManifest() const noexcept;
|
||||
[[nodiscard]] const PreparedStellarEquilibriumOperator &GetPhysicalOperator() const noexcept;
|
||||
[[nodiscard]] const PreparedCentralDensityConstraint &GetCentralDensityConstraint() const noexcept;
|
||||
[[nodiscard]] RootConstraintReport GetFixedMassReport() const;
|
||||
[[nodiscard]] CentralDensityConstraintReport GetCentralDensityReport() const;
|
||||
|
||||
private:
|
||||
static field::FieldPointDofMap MakeCenterDofMap(const fem::FEM &f);
|
||||
|
||||
PreparedCentralDensityStellarEquilibriumOperator(
|
||||
fem::FEM &f,
|
||||
std::unique_ptr<PreparedStellarEquilibriumOperator> physicalOperator,
|
||||
models::CompiledFixedCentralDensity centralDensity,
|
||||
field::FieldPointDofMap centerDof
|
||||
);
|
||||
|
||||
void AssembleResidual();
|
||||
void VerifyPrepared() const;
|
||||
|
||||
std::unique_ptr<PreparedStellarEquilibriumOperator> m_physicalOperator;
|
||||
models::CompiledFixedCentralDensity m_centralDensity;
|
||||
PreparedCentralDensityConstraint m_phaseConstraint;
|
||||
CentralDensityStellarEquilibriumRootManifest m_rootManifest;
|
||||
mfem::Vector m_cachedResidual;
|
||||
bool m_isPrepared{false};
|
||||
};
|
||||
} // namespace mean_field::operators
|
||||
@@ -35,6 +35,7 @@ export namespace mean_field::operators {
|
||||
std::uint64_t enthalpyApplications{0};
|
||||
std::uint64_t gravityPotentialApplications{0};
|
||||
std::uint64_t bernoulliConstantApplications{0};
|
||||
std::uint64_t rotationAmplitudeApplications{0};
|
||||
std::uint64_t combinedApplications{0};
|
||||
|
||||
constexpr auto operator<=>(const PreparedHydrostaticAlgebraicJacobianStatistics &) const = default;
|
||||
@@ -118,6 +119,14 @@ export namespace mean_field::operators {
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
// Differentiates a multiplicative change Omega -> (1 + alpha) Omega
|
||||
// at the frozen rigid rotation. Since Psi_rotation is quadratic in
|
||||
// Omega, this contributes -2 alpha Psi_rotation to the hydrostatic row.
|
||||
void ApplyRotationAmplitudeJacobianAction(
|
||||
double fractionalAngularVelocityVariation,
|
||||
mfem::Vector &action
|
||||
) const;
|
||||
|
||||
void ApplyAlgebraicJacobianAction(
|
||||
const mfem::Vector &enthalpyVariation,
|
||||
const mfem::Vector &gravityPotentialVariation,
|
||||
|
||||
@@ -96,6 +96,20 @@ export namespace mean_field::operators {
|
||||
|
||||
class PreparedStellarEquilibriumOperator final : public mfem::Operator {
|
||||
public:
|
||||
/*
|
||||
* Privileged aggregate runtimes can inspect this complete numerical
|
||||
* core. Keep their allow-list on the concrete core itself: a custom
|
||||
* EOS may reuse this class, but it cannot extend the class's backend
|
||||
* privileges. Ordinary specifications use restricted nested physics
|
||||
* and never interact with this list.
|
||||
*/
|
||||
using BackendSpecifications = models::ModelTypeList<
|
||||
eos::Polytrope,
|
||||
surface::Isobaric,
|
||||
models::FixedTotalMass,
|
||||
models::FixedAngularMomentum,
|
||||
models::FixedCentralDensity>;
|
||||
|
||||
template <models::StellarModelType Model>
|
||||
requires std::same_as<
|
||||
typename std::remove_cvref_t<Model>::EquationOfStateType,
|
||||
@@ -174,6 +188,12 @@ export namespace mean_field::operators {
|
||||
[[nodiscard]] const PreparedHydrostaticEquilibriumOperator &GetHydrostaticOperator() const noexcept;
|
||||
[[nodiscard]] const PreparedDisplacementResidualOperator &GetDisplacementOperator() const noexcept;
|
||||
[[nodiscard]] const PreparedMassNormalizationOperator &GetMassNormalizationOperator() const noexcept;
|
||||
[[nodiscard]] double ApplyDensityVolumeIntegralDensityAction(
|
||||
const mfem::Vector &densityDirection
|
||||
) const;
|
||||
[[nodiscard]] double ApplyDensityVolumeIntegralSurfaceShapeAction(
|
||||
const mfem::Vector &surfaceShapeDirection
|
||||
) const;
|
||||
[[nodiscard]] const PreparedPressureSurfaceConstraint &GetSurfaceConstraintOperator() const noexcept;
|
||||
[[nodiscard]] const deformation::PreparedDomainDeformationRuntime &GetDomainDeformation() const noexcept;
|
||||
[[nodiscard]] const mfem::Vector &GetSurfaceDeformationParameters() const;
|
||||
@@ -234,5 +254,6 @@ export namespace mean_field::operators {
|
||||
mutable mfem::Vector m_fullMechanicalAction;
|
||||
mutable mfem::Vector m_surfaceShapeAction;
|
||||
mutable mfem::Vector m_pullbackDerivativeAction;
|
||||
mutable mfem::Vector m_densityVolumeIntegralAction;
|
||||
};
|
||||
} // namespace mean_field::operators
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,815 @@
|
||||
module;
|
||||
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
|
||||
export module mean_field:operators.stellar_equilibrium_compiler;
|
||||
|
||||
export import :model.compiled_fixed_angular_momentum;
|
||||
export import :model.compiled_fixed_central_density;
|
||||
export import :model.typed_stellar;
|
||||
export import :utils.blocks;
|
||||
|
||||
export namespace mean_field::operators {
|
||||
/*
|
||||
* A coupling is the symbolic statement that one Jacobian block may be
|
||||
* nonzero. Specifications contribute these statements independently of
|
||||
* the final row and column layout.
|
||||
*/
|
||||
template <typename ResidualBlock, typename ValueBlock>
|
||||
struct StellarEquilibriumJacobianCoupling final {
|
||||
using Residual = ResidualBlock;
|
||||
using Value = ValueBlock;
|
||||
|
||||
using ResidualBlockType = ResidualBlock;
|
||||
using ValueBlockType = ValueBlock;
|
||||
};
|
||||
|
||||
template <typename ResidualBlock, typename ValueBlock>
|
||||
using EquilibriumJacobianCoupling =
|
||||
StellarEquilibriumJacobianCoupling<ResidualBlock, ValueBlock>;
|
||||
|
||||
namespace detail {
|
||||
template <typename... Lists> struct ConcatenateBlockLists;
|
||||
|
||||
template <> struct ConcatenateBlockLists<> {
|
||||
using Type = utils::blocks::type_list<>;
|
||||
};
|
||||
|
||||
template <typename... Types>
|
||||
struct ConcatenateBlockLists<utils::blocks::type_list<Types...>> {
|
||||
using Type = utils::blocks::type_list<Types...>;
|
||||
};
|
||||
|
||||
template <typename... First, typename... Second, typename... Remaining>
|
||||
struct ConcatenateBlockLists<utils::blocks::type_list<First...>,
|
||||
utils::blocks::type_list<Second...>,
|
||||
Remaining...> {
|
||||
using Type = typename ConcatenateBlockLists<
|
||||
utils::blocks::type_list<First..., Second...>, Remaining...>::Type;
|
||||
};
|
||||
|
||||
template <typename... Lists>
|
||||
using ConcatenateBlockListsT = typename ConcatenateBlockLists<Lists...>::Type;
|
||||
|
||||
template <typename List, typename Type> struct AppendUniqueBlockType;
|
||||
|
||||
template <typename... Types, typename Type>
|
||||
struct AppendUniqueBlockType<utils::blocks::type_list<Types...>, Type> {
|
||||
using TypeValue = std::conditional_t<
|
||||
utils::blocks::contains_type_v<Type, utils::blocks::type_list<Types...>>,
|
||||
utils::blocks::type_list<Types...>,
|
||||
utils::blocks::type_list<Types..., Type>>;
|
||||
};
|
||||
|
||||
template <typename Accumulated, typename Remaining> struct UniqueBlockListImpl;
|
||||
|
||||
template <typename Accumulated>
|
||||
struct UniqueBlockListImpl<Accumulated, utils::blocks::type_list<>> {
|
||||
using Type = Accumulated;
|
||||
};
|
||||
|
||||
template <typename Accumulated, typename Head, typename... Tail>
|
||||
struct UniqueBlockListImpl<Accumulated,
|
||||
utils::blocks::type_list<Head, Tail...>> {
|
||||
using Type = typename UniqueBlockListImpl<
|
||||
typename AppendUniqueBlockType<Accumulated, Head>::TypeValue,
|
||||
utils::blocks::type_list<Tail...>>::Type;
|
||||
};
|
||||
|
||||
template <typename List>
|
||||
using UniqueBlockListT =
|
||||
typename UniqueBlockListImpl<utils::blocks::type_list<>, List>::Type;
|
||||
|
||||
template <typename... Lists>
|
||||
using UniqueConcatenateBlockListsT =
|
||||
UniqueBlockListT<ConcatenateBlockListsT<Lists...>>;
|
||||
|
||||
template <typename Candidate> struct IsValueBlockList : std::false_type {};
|
||||
|
||||
template <typename... Blocks>
|
||||
struct IsValueBlockList<utils::blocks::type_list<Blocks...>>
|
||||
: std::bool_constant<
|
||||
(std::derived_from<Blocks, utils::blocks::value_block_base> && ...) &&
|
||||
utils::blocks::types_are_unique_v<
|
||||
utils::blocks::type_list<Blocks...>>> {};
|
||||
|
||||
template <typename Candidate> struct IsResidualBlockList : std::false_type {};
|
||||
|
||||
template <typename... Blocks>
|
||||
struct IsResidualBlockList<utils::blocks::type_list<Blocks...>>
|
||||
: std::bool_constant<
|
||||
(std::derived_from<Blocks, utils::blocks::residual_block_base> &&
|
||||
...) &&
|
||||
utils::blocks::types_are_unique_v<
|
||||
utils::blocks::type_list<Blocks...>>> {};
|
||||
|
||||
template <typename GeneratedValues> struct GeneratedValueBlocksFor;
|
||||
|
||||
template <typename... GeneratedValues>
|
||||
struct GeneratedValueBlocksFor<models::ModelTypeList<GeneratedValues...>> {
|
||||
using Type = utils::blocks::type_list<
|
||||
utils::blocks::generated_value_block<GeneratedValues>...>;
|
||||
};
|
||||
|
||||
template <typename GeneratedResiduals> struct GeneratedResidualBlocksFor;
|
||||
|
||||
template <typename... GeneratedResiduals>
|
||||
struct GeneratedResidualBlocksFor<
|
||||
models::ModelTypeList<GeneratedResiduals...>> {
|
||||
using Type = utils::blocks::type_list<
|
||||
utils::blocks::generated_residual_block<GeneratedResiduals>...>;
|
||||
};
|
||||
|
||||
/*
|
||||
* One translation boundary turns physics-facing stellar names into backend
|
||||
* blocks. Existing backend block types pass through unchanged, which keeps
|
||||
* the advanced extension API open without making built-in physics declarations
|
||||
* depend on utils.blocks.
|
||||
*/
|
||||
template <typename DeclaredDependency>
|
||||
struct UnmappedStellarDependency final {};
|
||||
|
||||
template <typename Blocks, typename DeclaredDependency>
|
||||
struct SingleGeneratedBlock {
|
||||
using Type = UnmappedStellarDependency<DeclaredDependency>;
|
||||
static constexpr bool available = false;
|
||||
};
|
||||
|
||||
template <typename Block, typename DeclaredDependency>
|
||||
struct SingleGeneratedBlock<utils::blocks::type_list<Block>,
|
||||
DeclaredDependency> {
|
||||
using Type = Block;
|
||||
static constexpr bool available = true;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification, typename Dependency>
|
||||
struct StellarDependencyBlock {
|
||||
using Type = UnmappedStellarDependency<Dependency>;
|
||||
static constexpr bool mapped = false;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification, typename Block>
|
||||
requires(std::derived_from<Block, utils::blocks::value_block_base> ||
|
||||
std::derived_from<Block, utils::blocks::residual_block_base>)
|
||||
struct StellarDependencyBlock<Specification, Block> {
|
||||
using Type = Block;
|
||||
static constexpr bool mapped = true;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification>
|
||||
struct StellarDependencyBlock<Specification, models::stellar::state::Density> {
|
||||
using Type = utils::blocks::density::mass::value;
|
||||
static constexpr bool mapped = true;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification>
|
||||
struct StellarDependencyBlock<Specification,
|
||||
models::stellar::state::SurfaceShape> {
|
||||
using Type = utils::blocks::surface_deformation::parameters::value;
|
||||
static constexpr bool mapped = true;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification>
|
||||
struct StellarDependencyBlock<Specification,
|
||||
models::stellar::state::GravityGradient> {
|
||||
using Type = utils::blocks::gravity::gradient::value;
|
||||
static constexpr bool mapped = true;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification>
|
||||
struct StellarDependencyBlock<
|
||||
Specification, models::stellar::state::GravitationalPotential> {
|
||||
using Type = utils::blocks::gravity::poisson::value;
|
||||
static constexpr bool mapped = true;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification>
|
||||
struct StellarDependencyBlock<Specification,
|
||||
models::stellar::state::SpecificEnthalpy> {
|
||||
using Type = utils::blocks::enthalpy::specific::value;
|
||||
static constexpr bool mapped = true;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification>
|
||||
struct StellarDependencyBlock<
|
||||
Specification, models::stellar::state::OwnGeneratedCoordinate> {
|
||||
private:
|
||||
using GeneratedBlocks = typename GeneratedValueBlocksFor<
|
||||
typename models::SpecificationContribution<
|
||||
Specification>::GeneratedValues>::Type;
|
||||
using Selection = SingleGeneratedBlock<
|
||||
GeneratedBlocks, models::stellar::state::OwnGeneratedCoordinate>;
|
||||
|
||||
public:
|
||||
using Type = typename Selection::Type;
|
||||
static constexpr bool mapped = Selection::available;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification,
|
||||
models::ModelSpecification Owner>
|
||||
struct StellarDependencyBlock<
|
||||
Specification, models::stellar::state::GeneratedCoordinateOf<Owner>> {
|
||||
private:
|
||||
using GeneratedBlocks = typename GeneratedValueBlocksFor<
|
||||
typename models::SpecificationContribution<Owner>::GeneratedValues>::Type;
|
||||
using Dependency = models::stellar::state::GeneratedCoordinateOf<Owner>;
|
||||
using Selection = SingleGeneratedBlock<GeneratedBlocks, Dependency>;
|
||||
|
||||
public:
|
||||
using Type = typename Selection::Type;
|
||||
static constexpr bool mapped = Selection::available;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification>
|
||||
struct StellarDependencyBlock<
|
||||
Specification, models::stellar::equation::GravityGradientDefinition> {
|
||||
using Type = utils::blocks::gravity::gradient::residual;
|
||||
static constexpr bool mapped = true;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification>
|
||||
struct StellarDependencyBlock<Specification,
|
||||
models::stellar::equation::PoissonEquation> {
|
||||
using Type = utils::blocks::gravity::poisson::residual;
|
||||
static constexpr bool mapped = true;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification>
|
||||
struct StellarDependencyBlock<Specification,
|
||||
models::stellar::equation::DensityClosure> {
|
||||
using Type = utils::blocks::density::mass::residual;
|
||||
static constexpr bool mapped = true;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification>
|
||||
struct StellarDependencyBlock<
|
||||
Specification, models::stellar::equation::SurfaceShapeBalance> {
|
||||
using Type =
|
||||
utils::blocks::surface_deformation::shape_equilibrium::residual;
|
||||
static constexpr bool mapped = true;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification>
|
||||
struct StellarDependencyBlock<
|
||||
Specification, models::stellar::equation::HydrostaticBalance> {
|
||||
using Type = utils::blocks::enthalpy::specific::residual;
|
||||
static constexpr bool mapped = true;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification>
|
||||
struct StellarDependencyBlock<Specification,
|
||||
models::stellar::equation::OwnConstraint> {
|
||||
private:
|
||||
using GeneratedBlocks = typename GeneratedResidualBlocksFor<
|
||||
typename models::SpecificationContribution<
|
||||
Specification>::GeneratedResiduals>::Type;
|
||||
using Selection = SingleGeneratedBlock<
|
||||
GeneratedBlocks, models::stellar::equation::OwnConstraint>;
|
||||
|
||||
public:
|
||||
using Type = typename Selection::Type;
|
||||
static constexpr bool mapped = Selection::available;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification,
|
||||
models::ModelSpecification Owner>
|
||||
struct StellarDependencyBlock<
|
||||
Specification, models::stellar::equation::ConstraintOf<Owner>> {
|
||||
private:
|
||||
using GeneratedBlocks = typename GeneratedResidualBlocksFor<
|
||||
typename models::SpecificationContribution<Owner>::GeneratedResiduals>::Type;
|
||||
using Dependency = models::stellar::equation::ConstraintOf<Owner>;
|
||||
using Selection = SingleGeneratedBlock<GeneratedBlocks, Dependency>;
|
||||
|
||||
public:
|
||||
using Type = typename Selection::Type;
|
||||
static constexpr bool mapped = Selection::available;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification, typename Dependencies>
|
||||
struct CompileStellarDependencies {
|
||||
using Type = utils::blocks::type_list<
|
||||
UnmappedStellarDependency<Dependencies>>;
|
||||
static constexpr bool complete = false;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification, typename... Dependencies>
|
||||
struct CompileStellarDependencies<Specification,
|
||||
models::ModelTypeList<Dependencies...>> {
|
||||
using Type = utils::blocks::type_list<
|
||||
typename StellarDependencyBlock<Specification, Dependencies>::Type...>;
|
||||
static constexpr bool complete =
|
||||
(StellarDependencyBlock<Specification, Dependencies>::mapped && ...);
|
||||
};
|
||||
|
||||
template <typename Residual, typename Values> struct CoupleResidualToValues;
|
||||
|
||||
template <typename Residual, typename... Values>
|
||||
struct CoupleResidualToValues<Residual, utils::blocks::type_list<Values...>> {
|
||||
using Type = utils::blocks::type_list<
|
||||
StellarEquilibriumJacobianCoupling<Residual, Values>...>;
|
||||
};
|
||||
|
||||
template <typename Residuals, typename Values>
|
||||
struct CartesianJacobianCouplings;
|
||||
|
||||
template <typename... Residuals, typename Values>
|
||||
struct CartesianJacobianCouplings<utils::blocks::type_list<Residuals...>,
|
||||
Values> {
|
||||
using Type = ConcatenateBlockListsT<
|
||||
typename CoupleResidualToValues<Residuals, Values>::Type...>;
|
||||
};
|
||||
|
||||
template <typename Candidate> struct IsJacobianCoupling : std::false_type {};
|
||||
|
||||
template <typename Residual, typename Value>
|
||||
struct IsJacobianCoupling<StellarEquilibriumJacobianCoupling<Residual, Value>>
|
||||
: std::bool_constant<
|
||||
std::derived_from<Residual, utils::blocks::residual_block_base> &&
|
||||
std::derived_from<Value, utils::blocks::value_block_base>> {};
|
||||
|
||||
template <typename Candidate>
|
||||
struct IsJacobianCouplingList : std::false_type {};
|
||||
|
||||
template <typename... Couplings>
|
||||
struct IsJacobianCouplingList<utils::blocks::type_list<Couplings...>>
|
||||
: std::bool_constant<(IsJacobianCoupling<Couplings>::value && ...) &&
|
||||
utils::blocks::types_are_unique_v<
|
||||
utils::blocks::type_list<Couplings...>>> {};
|
||||
|
||||
template <typename Candidate> struct IsGeneratedValueBlock : std::false_type {};
|
||||
|
||||
template <typename Owner>
|
||||
struct IsGeneratedValueBlock<utils::blocks::generated_value_block<Owner>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename Candidate>
|
||||
struct IsGeneratedResidualBlock : std::false_type {};
|
||||
|
||||
template <typename Owner>
|
||||
struct IsGeneratedResidualBlock<utils::blocks::generated_residual_block<Owner>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename Coupling>
|
||||
inline constexpr bool isGeneratedBorderIncidentCoupling =
|
||||
IsGeneratedValueBlock<typename Coupling::Value>::value ||
|
||||
IsGeneratedResidualBlock<typename Coupling::Residual>::value;
|
||||
|
||||
template <typename Couplings> struct GeneratedBorderIncidentCouplings;
|
||||
|
||||
template <>
|
||||
struct GeneratedBorderIncidentCouplings<utils::blocks::type_list<>> {
|
||||
using Type = utils::blocks::type_list<>;
|
||||
};
|
||||
|
||||
template <typename Head, typename... Tail>
|
||||
struct GeneratedBorderIncidentCouplings<
|
||||
utils::blocks::type_list<Head, Tail...>> {
|
||||
private:
|
||||
using Remaining = typename GeneratedBorderIncidentCouplings<
|
||||
utils::blocks::type_list<Tail...>>::Type;
|
||||
|
||||
public:
|
||||
using Type = std::conditional_t<
|
||||
isGeneratedBorderIncidentCoupling<Head>,
|
||||
ConcatenateBlockListsT<utils::blocks::type_list<Head>, Remaining>,
|
||||
Remaining>;
|
||||
};
|
||||
|
||||
template <bool Registered, typename GeneratedValues,
|
||||
typename GeneratedResiduals, typename DependsOn, typename Affects>
|
||||
struct DeclarativeStellarEquilibriumSpecificationCompilation {
|
||||
using GeneratedValueBlocks = GeneratedValues;
|
||||
using GeneratedResidualBlocks = GeneratedResiduals;
|
||||
using DependsOnValueBlocks = DependsOn;
|
||||
using AffectedResidualBlocks = Affects;
|
||||
|
||||
/*
|
||||
* Preserve the two physical meanings in the declaration instead of
|
||||
* flattening their endpoints into independent unions:
|
||||
*
|
||||
* constraint equation <- everything named in Reads
|
||||
* changed equations <- Reads plus the generated coordinate
|
||||
*
|
||||
* The second group deliberately includes Affects x Reads. Nonlinear
|
||||
* constraints and multiplier forces generally contribute Hessian-like
|
||||
* state derivatives there. Linear contributions simply assemble zero on
|
||||
* those structurally permitted edges.
|
||||
*/
|
||||
using ConstraintInputValueBlocks = DependsOnValueBlocks;
|
||||
using ConstraintOutputResidualBlocks = GeneratedResidualBlocks;
|
||||
using ChangedEquationInputValueBlocks = UniqueConcatenateBlockListsT<
|
||||
DependsOnValueBlocks, GeneratedValueBlocks>;
|
||||
using ChangedEquationOutputResidualBlocks = AffectedResidualBlocks;
|
||||
|
||||
using ConstraintJacobianCouplings =
|
||||
typename CartesianJacobianCouplings<GeneratedResidualBlocks,
|
||||
DependsOnValueBlocks>::Type;
|
||||
using ChangedEquationJacobianCouplings =
|
||||
typename CartesianJacobianCouplings<AffectedResidualBlocks,
|
||||
ChangedEquationInputValueBlocks>::Type;
|
||||
|
||||
// Compatibility names retained for backend code that distinguishes the
|
||||
// generated row from the generated-coordinate column.
|
||||
using GeneratedRowJacobianCouplings = ConstraintJacobianCouplings;
|
||||
using AffectedRowJacobianCouplings =
|
||||
typename CartesianJacobianCouplings<AffectedResidualBlocks,
|
||||
GeneratedValueBlocks>::Type;
|
||||
using AffectedStateJacobianCouplings =
|
||||
typename CartesianJacobianCouplings<AffectedResidualBlocks,
|
||||
DependsOnValueBlocks>::Type;
|
||||
|
||||
using JacobianCouplings = UniqueConcatenateBlockListsT<
|
||||
ConstraintJacobianCouplings, ChangedEquationJacobianCouplings>;
|
||||
using IncidentJacobianCouplings =
|
||||
typename GeneratedBorderIncidentCouplings<JacobianCouplings>::Type;
|
||||
|
||||
// Correction is the Newton-facing name for a value coordinate.
|
||||
using GeneratedCorrectionBlocks = GeneratedValueBlocks;
|
||||
|
||||
static constexpr bool registered = Registered;
|
||||
static constexpr bool complete =
|
||||
registered && IsValueBlockList<GeneratedValueBlocks>::value &&
|
||||
IsResidualBlockList<GeneratedResidualBlocks>::value &&
|
||||
IsValueBlockList<DependsOnValueBlocks>::value &&
|
||||
IsResidualBlockList<AffectedResidualBlocks>::value &&
|
||||
IsJacobianCouplingList<JacobianCouplings>::value &&
|
||||
(GeneratedValueBlocks::size == GeneratedResidualBlocks::size) &&
|
||||
((GeneratedValueBlocks::size == 0 && DependsOnValueBlocks::size == 0 &&
|
||||
AffectedResidualBlocks::size == 0) ||
|
||||
(GeneratedValueBlocks::size > 0 && DependsOnValueBlocks::size > 0 &&
|
||||
AffectedResidualBlocks::size > 0));
|
||||
};
|
||||
|
||||
using EmptySpecificationCompilation =
|
||||
DeclarativeStellarEquilibriumSpecificationCompilation<
|
||||
false, utils::blocks::type_list<>, utils::blocks::type_list<>,
|
||||
utils::blocks::type_list<>, utils::blocks::type_list<>>;
|
||||
|
||||
template <models::ModelSpecification Specification>
|
||||
struct SelfDescribingSpecificationCompilationInputs {
|
||||
using Contribution = models::SpecificationContribution<Specification>;
|
||||
using DependsOn =
|
||||
CompileStellarDependencies<Specification, typename Contribution::DependsOn>;
|
||||
using Affects =
|
||||
CompileStellarDependencies<Specification, typename Contribution::Affects>;
|
||||
|
||||
using GeneratedValueBlocks = typename GeneratedValueBlocksFor<
|
||||
typename Contribution::GeneratedValues>::Type;
|
||||
using GeneratedResidualBlocks = typename GeneratedResidualBlocksFor<
|
||||
typename Contribution::GeneratedResiduals>::Type;
|
||||
using DependsOnValueBlocks = typename DependsOn::Type;
|
||||
using AffectedResidualBlocks = typename Affects::Type;
|
||||
|
||||
static constexpr bool registered =
|
||||
Contribution::hasDeclarativeDefinition && DependsOn::complete &&
|
||||
Affects::complete;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification Specification>
|
||||
struct SelfDescribingSpecificationCompilation
|
||||
: DeclarativeStellarEquilibriumSpecificationCompilation<
|
||||
SelfDescribingSpecificationCompilationInputs<Specification>::registered,
|
||||
typename SelfDescribingSpecificationCompilationInputs<
|
||||
Specification>::GeneratedValueBlocks,
|
||||
typename SelfDescribingSpecificationCompilationInputs<
|
||||
Specification>::GeneratedResidualBlocks,
|
||||
typename SelfDescribingSpecificationCompilationInputs<
|
||||
Specification>::DependsOnValueBlocks,
|
||||
typename SelfDescribingSpecificationCompilationInputs<
|
||||
Specification>::AffectedResidualBlocks> {};
|
||||
} // namespace detail
|
||||
|
||||
/*
|
||||
* Public, inspectable per-specification compilation metadata. The primary
|
||||
* is deliberately well formed and incomplete, so testing an arbitrary type
|
||||
* in a requires-expression never triggers a diagnostic.
|
||||
*/
|
||||
template <typename Specification>
|
||||
struct StellarEquilibriumSpecificationCompilation
|
||||
: detail::EmptySpecificationCompilation {};
|
||||
|
||||
template <models::ModelSpecification Specification>
|
||||
struct StellarEquilibriumSpecificationCompilation<Specification>
|
||||
: detail::SelfDescribingSpecificationCompilation<Specification> {};
|
||||
|
||||
namespace detail {
|
||||
template <typename Specification, typename = void>
|
||||
struct SpecificationCompilationIsComplete : std::false_type {};
|
||||
|
||||
template <typename Specification>
|
||||
struct SpecificationCompilationIsComplete<
|
||||
Specification,
|
||||
std::void_t<typename StellarEquilibriumSpecificationCompilation<
|
||||
Specification>::GeneratedValueBlocks,
|
||||
typename StellarEquilibriumSpecificationCompilation<
|
||||
Specification>::GeneratedResidualBlocks,
|
||||
typename StellarEquilibriumSpecificationCompilation<
|
||||
Specification>::DependsOnValueBlocks,
|
||||
typename StellarEquilibriumSpecificationCompilation<
|
||||
Specification>::AffectedResidualBlocks,
|
||||
typename StellarEquilibriumSpecificationCompilation<
|
||||
Specification>::JacobianCouplings,
|
||||
std::bool_constant<StellarEquilibriumSpecificationCompilation<
|
||||
Specification>::registered>,
|
||||
std::bool_constant<StellarEquilibriumSpecificationCompilation<
|
||||
Specification>::complete>>>
|
||||
: std::bool_constant<
|
||||
StellarEquilibriumSpecificationCompilation<
|
||||
Specification>::registered &&
|
||||
StellarEquilibriumSpecificationCompilation<Specification>::complete &&
|
||||
IsValueBlockList<typename StellarEquilibriumSpecificationCompilation<
|
||||
Specification>::GeneratedValueBlocks>::value &&
|
||||
IsResidualBlockList<
|
||||
typename StellarEquilibriumSpecificationCompilation<
|
||||
Specification>::GeneratedResidualBlocks>::value &&
|
||||
IsValueBlockList<typename StellarEquilibriumSpecificationCompilation<
|
||||
Specification>::DependsOnValueBlocks>::value &&
|
||||
IsResidualBlockList<
|
||||
typename StellarEquilibriumSpecificationCompilation<
|
||||
Specification>::AffectedResidualBlocks>::value &&
|
||||
IsJacobianCouplingList<
|
||||
typename StellarEquilibriumSpecificationCompilation<
|
||||
Specification>::JacobianCouplings>::value> {};
|
||||
} // namespace detail
|
||||
|
||||
template <typename Candidate>
|
||||
inline constexpr bool stellarEquilibriumSpecificationCompilationComplete =
|
||||
detail::SpecificationCompilationIsComplete<
|
||||
std::remove_cvref_t<Candidate>>::value;
|
||||
|
||||
template <typename Candidate>
|
||||
concept StellarEquilibriumSpecificationCompilable =
|
||||
stellarEquilibriumSpecificationCompilationComplete<Candidate>;
|
||||
|
||||
namespace detail {
|
||||
/*
|
||||
* This five-by-five physical core is independent of global constraints.
|
||||
* Even FixedTotalMass is compiled as a contribution, keeping C and R_M
|
||||
* visible in that specification's metadata.
|
||||
*/
|
||||
using StellarPhysicsValueBlocks = utils::blocks::type_list<
|
||||
utils::blocks::density::mass::value,
|
||||
utils::blocks::surface_deformation::parameters::value,
|
||||
utils::blocks::gravity::gradient::value,
|
||||
utils::blocks::gravity::poisson::value,
|
||||
utils::blocks::enthalpy::specific::value>;
|
||||
|
||||
using StellarPhysicsResidualBlocks = utils::blocks::type_list<
|
||||
utils::blocks::gravity::gradient::residual,
|
||||
utils::blocks::gravity::poisson::residual,
|
||||
utils::blocks::density::mass::residual,
|
||||
utils::blocks::surface_deformation::shape_equilibrium::residual,
|
||||
utils::blocks::enthalpy::specific::residual>;
|
||||
|
||||
using StellarPhysicsJacobianRows = utils::blocks::type_list<
|
||||
utils::blocks::block_row<
|
||||
utils::blocks::gravity::gradient::residual,
|
||||
utils::blocks::gravity::gradient::value,
|
||||
utils::blocks::gravity::poisson::value,
|
||||
utils::blocks::surface_deformation::parameters::value>,
|
||||
utils::blocks::block_row<
|
||||
utils::blocks::gravity::poisson::residual,
|
||||
utils::blocks::gravity::gradient::value,
|
||||
utils::blocks::density::mass::value,
|
||||
utils::blocks::surface_deformation::parameters::value>,
|
||||
utils::blocks::block_row<
|
||||
utils::blocks::density::mass::residual,
|
||||
utils::blocks::density::mass::value,
|
||||
utils::blocks::enthalpy::specific::value,
|
||||
utils::blocks::surface_deformation::parameters::value>,
|
||||
utils::blocks::block_row<
|
||||
utils::blocks::surface_deformation::shape_equilibrium::residual,
|
||||
utils::blocks::density::mass::value,
|
||||
utils::blocks::surface_deformation::parameters::value,
|
||||
utils::blocks::gravity::gradient::value,
|
||||
utils::blocks::enthalpy::specific::value>,
|
||||
utils::blocks::block_row<
|
||||
utils::blocks::enthalpy::specific::residual,
|
||||
utils::blocks::enthalpy::specific::value,
|
||||
utils::blocks::gravity::poisson::value,
|
||||
utils::blocks::surface_deformation::parameters::value>>;
|
||||
|
||||
template <typename Row> struct JacobianRowCouplings;
|
||||
|
||||
template <typename Residual, typename... Values>
|
||||
struct JacobianRowCouplings<utils::blocks::block_row<Residual, Values...>> {
|
||||
using Type = utils::blocks::type_list<
|
||||
StellarEquilibriumJacobianCoupling<Residual, Values>...>;
|
||||
};
|
||||
|
||||
template <typename Rows> struct FlattenJacobianRows;
|
||||
|
||||
template <typename... Rows>
|
||||
struct FlattenJacobianRows<utils::blocks::type_list<Rows...>> {
|
||||
using Type =
|
||||
ConcatenateBlockListsT<typename JacobianRowCouplings<Rows>::Type...>;
|
||||
};
|
||||
|
||||
using StellarPhysicsJacobianCouplings =
|
||||
typename FlattenJacobianRows<StellarPhysicsJacobianRows>::Type;
|
||||
|
||||
template <typename SpecificationSet>
|
||||
struct SpecificationSetCompilationsAreComplete;
|
||||
|
||||
template <models::ModelSpecification... Specifications>
|
||||
struct SpecificationSetCompilationsAreComplete<
|
||||
models::detail::SpecificationSetStorage<Specifications...>>
|
||||
: std::bool_constant<(
|
||||
stellarEquilibriumSpecificationCompilationComplete<Specifications> &&
|
||||
...)> {};
|
||||
|
||||
template <typename SpecificationSet, bool Complete>
|
||||
struct CollectStellarEquilibriumContributionsImpl {
|
||||
using GeneratedValueBlocks = utils::blocks::type_list<>;
|
||||
using GeneratedResidualBlocks = utils::blocks::type_list<>;
|
||||
using ContributionJacobianCouplings = utils::blocks::type_list<>;
|
||||
using IncidentJacobianCouplings = ContributionJacobianCouplings;
|
||||
|
||||
static constexpr bool complete = false;
|
||||
};
|
||||
|
||||
template <models::ModelSpecification... Specifications>
|
||||
struct CollectStellarEquilibriumContributionsImpl<
|
||||
models::detail::SpecificationSetStorage<Specifications...>, true> {
|
||||
using GeneratedValueBlocks = ConcatenateBlockListsT<
|
||||
typename StellarEquilibriumSpecificationCompilation<
|
||||
Specifications>::GeneratedValueBlocks...>;
|
||||
using GeneratedResidualBlocks = ConcatenateBlockListsT<
|
||||
typename StellarEquilibriumSpecificationCompilation<
|
||||
Specifications>::GeneratedResidualBlocks...>;
|
||||
using ContributionJacobianCouplings = UniqueConcatenateBlockListsT<
|
||||
typename StellarEquilibriumSpecificationCompilation<
|
||||
Specifications>::JacobianCouplings...>;
|
||||
using IncidentJacobianCouplings = UniqueConcatenateBlockListsT<
|
||||
typename StellarEquilibriumSpecificationCompilation<
|
||||
Specifications>::IncidentJacobianCouplings...>;
|
||||
|
||||
static constexpr bool complete = true;
|
||||
};
|
||||
|
||||
template <typename SpecificationSet>
|
||||
using CollectStellarEquilibriumContributions =
|
||||
CollectStellarEquilibriumContributionsImpl<
|
||||
SpecificationSet,
|
||||
SpecificationSetCompilationsAreComplete<SpecificationSet>::value>;
|
||||
|
||||
template <typename Residual, typename Couplings> struct ValuesCoupledToResidual;
|
||||
|
||||
template <typename Residual>
|
||||
struct ValuesCoupledToResidual<Residual, utils::blocks::type_list<>> {
|
||||
using Type = utils::blocks::type_list<>;
|
||||
};
|
||||
|
||||
template <typename Residual, typename HeadResidual, typename HeadValue,
|
||||
typename... Tail>
|
||||
struct ValuesCoupledToResidual<
|
||||
Residual,
|
||||
utils::blocks::type_list<
|
||||
StellarEquilibriumJacobianCoupling<HeadResidual, HeadValue>, Tail...>> {
|
||||
private:
|
||||
using Remaining =
|
||||
typename ValuesCoupledToResidual<Residual,
|
||||
utils::blocks::type_list<Tail...>>::Type;
|
||||
|
||||
public:
|
||||
using Type = std::conditional_t<
|
||||
std::same_as<Residual, HeadResidual>,
|
||||
ConcatenateBlockListsT<utils::blocks::type_list<HeadValue>, Remaining>,
|
||||
Remaining>;
|
||||
};
|
||||
|
||||
template <typename Residual, typename Values> struct MakeJacobianRow;
|
||||
|
||||
template <typename Residual, typename... Values>
|
||||
struct MakeJacobianRow<Residual, utils::blocks::type_list<Values...>> {
|
||||
using Type = utils::blocks::block_row<Residual, Values...>;
|
||||
};
|
||||
|
||||
template <typename Residuals, typename Couplings> struct SynthesizeJacobianRows;
|
||||
|
||||
template <typename... Residuals, typename Couplings>
|
||||
struct SynthesizeJacobianRows<utils::blocks::type_list<Residuals...>,
|
||||
Couplings> {
|
||||
using Type = utils::blocks::type_list<typename MakeJacobianRow<
|
||||
Residuals,
|
||||
typename ValuesCoupledToResidual<Residuals, Couplings>::Type>::Type...>;
|
||||
};
|
||||
|
||||
template <typename Couplings, typename ValueBlocks, typename ResidualBlocks>
|
||||
struct CouplingEndpointsBelongToForm : std::false_type {};
|
||||
|
||||
template <typename ValueBlocks, typename ResidualBlocks, typename... Couplings>
|
||||
struct CouplingEndpointsBelongToForm<utils::blocks::type_list<Couplings...>,
|
||||
ValueBlocks, ResidualBlocks>
|
||||
: std::bool_constant<((utils::blocks::contains_type_v<
|
||||
typename Couplings::Value, ValueBlocks> &&
|
||||
utils::blocks::contains_type_v<
|
||||
typename Couplings::Residual, ResidualBlocks>) &&
|
||||
...)> {};
|
||||
|
||||
template <typename Candidate> struct CompileStellarEquilibriumSystem {
|
||||
using GeneratedValueBlocks = utils::blocks::type_list<>;
|
||||
using GeneratedCorrectionBlocks = GeneratedValueBlocks;
|
||||
using GeneratedResidualBlocks = utils::blocks::type_list<>;
|
||||
using BaseJacobianCouplings = utils::blocks::type_list<>;
|
||||
using ContributionJacobianCouplings = utils::blocks::type_list<>;
|
||||
using IncidentJacobianCouplings = ContributionJacobianCouplings;
|
||||
using JacobianCouplings = utils::blocks::type_list<>;
|
||||
|
||||
static constexpr bool compilable = false;
|
||||
};
|
||||
|
||||
template <model::StellarModelType Model>
|
||||
struct CompileStellarEquilibriumSystem<Model> {
|
||||
using ModelType = std::remove_cvref_t<Model>;
|
||||
using Contributions = CollectStellarEquilibriumContributions<
|
||||
typename ModelType::SpecificationTypes>;
|
||||
|
||||
using GeneratedValueBlocks = typename Contributions::GeneratedValueBlocks;
|
||||
using GeneratedCorrectionBlocks = GeneratedValueBlocks;
|
||||
using GeneratedResidualBlocks =
|
||||
typename Contributions::GeneratedResidualBlocks;
|
||||
|
||||
using ValueBlocks =
|
||||
ConcatenateBlockListsT<StellarPhysicsValueBlocks, GeneratedValueBlocks>;
|
||||
using ResidualBlocks = ConcatenateBlockListsT<StellarPhysicsResidualBlocks,
|
||||
GeneratedResidualBlocks>;
|
||||
using FormType = utils::blocks::block_form<ValueBlocks, ResidualBlocks>;
|
||||
|
||||
using BaseJacobianCouplings = StellarPhysicsJacobianCouplings;
|
||||
using ContributionJacobianCouplings =
|
||||
typename Contributions::ContributionJacobianCouplings;
|
||||
using IncidentJacobianCouplings = ContributionJacobianCouplings;
|
||||
using JacobianCouplings =
|
||||
UniqueConcatenateBlockListsT<BaseJacobianCouplings,
|
||||
ContributionJacobianCouplings>;
|
||||
|
||||
// Pass two: materialize rows only after all contributed blocks are
|
||||
// present in the final form.
|
||||
using JacobianType =
|
||||
typename SynthesizeJacobianRows<ResidualBlocks, JacobianCouplings>::Type;
|
||||
|
||||
static constexpr bool compilable =
|
||||
Contributions::complete &&
|
||||
utils::blocks::block_form_is_valid_v<FormType> &&
|
||||
IsJacobianCouplingList<JacobianCouplings>::value &&
|
||||
CouplingEndpointsBelongToForm<JacobianCouplings, ValueBlocks,
|
||||
ResidualBlocks>::value &&
|
||||
utils::blocks::jacobian_form_is_valid_v<FormType, JacobianType>;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename Candidate>
|
||||
inline constexpr bool stellarEquilibriumSystemIsCompilable =
|
||||
detail::CompileStellarEquilibriumSystem<
|
||||
std::remove_cvref_t<Candidate>>::compilable;
|
||||
|
||||
/*
|
||||
* This compiler proves the symbolic block topology only. Keep the explicit
|
||||
* name available to extension authors and tests so that success here is not
|
||||
* mistaken for an assembled numerical runtime. The established spelling is
|
||||
* retained below as a compatibility alias.
|
||||
*/
|
||||
template <typename Candidate>
|
||||
inline constexpr bool stellarEquilibriumIsSymbolicallyCompilable =
|
||||
stellarEquilibriumSystemIsCompilable<Candidate>;
|
||||
|
||||
template <typename Candidate>
|
||||
concept StellarEquilibriumSymbolicallyCompilable =
|
||||
stellarEquilibriumIsSymbolicallyCompilable<Candidate>;
|
||||
|
||||
template <typename Candidate>
|
||||
concept StellarEquilibriumSystemCompilable =
|
||||
StellarEquilibriumSymbolicallyCompilable<Candidate>;
|
||||
|
||||
template <model::StellarModelType Model>
|
||||
requires StellarEquilibriumSystemCompilable<Model>
|
||||
struct CompiledStellarEquilibriumSystem final
|
||||
: detail::CompileStellarEquilibriumSystem<std::remove_cvref_t<Model>> {
|
||||
using Base =
|
||||
detail::CompileStellarEquilibriumSystem<std::remove_cvref_t<Model>>;
|
||||
|
||||
using FormType = typename Base::FormType;
|
||||
using JacobianType = typename Base::JacobianType;
|
||||
|
||||
// This classification is exposed only after the complete compiler concept
|
||||
// has succeeded; model declarations intentionally do not predict it.
|
||||
static constexpr models::EquilibriumSystemCompilation compilationClass =
|
||||
models::EquilibriumSystemCompilation::complete_equilibrium_system;
|
||||
|
||||
static_assert(utils::blocks::block_form_is_valid_v<FormType>);
|
||||
static_assert(utils::blocks::valid_jacobian_form<FormType, JacobianType>);
|
||||
};
|
||||
|
||||
template <model::StellarModelType Model>
|
||||
requires StellarEquilibriumSystemCompilable<Model>
|
||||
using CompiledStellarEquilibriumForm =
|
||||
typename CompiledStellarEquilibriumSystem<Model>::FormType;
|
||||
|
||||
template <model::StellarModelType Model>
|
||||
requires StellarEquilibriumSystemCompilable<Model>
|
||||
using CompiledStellarEquilibriumJacobianForm =
|
||||
typename CompiledStellarEquilibriumSystem<Model>::JacobianType;
|
||||
} // namespace mean_field::operators
|
||||
@@ -2,6 +2,8 @@ module;
|
||||
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
@@ -13,46 +15,126 @@ export import :deformation.domain_deformation;
|
||||
export import :equilibrium.stellar_discretization;
|
||||
export import :material.thermodynamic_equations;
|
||||
export import :model.typed_stellar;
|
||||
export import :operators.prepared_central_density_stellar_equilibrium;
|
||||
export import :normalization.operators;
|
||||
export import :operators.prepared_variadic_stellar_equilibrium;
|
||||
export import :surface.compiler;
|
||||
|
||||
export namespace mean_field::equilibrium {
|
||||
namespace detail {
|
||||
template <
|
||||
model::StellarModelType Model,
|
||||
bool SymbolicallyCompilable = operators::StellarEquilibriumSystemCompilable<Model>>
|
||||
struct StellarSurfaceCompilationAudit {
|
||||
static constexpr bool complete = false;
|
||||
};
|
||||
|
||||
template <model::StellarModelType Model>
|
||||
struct StellarSurfaceCompilationAudit<Model, true> {
|
||||
private:
|
||||
using ModelType = std::remove_cvref_t<Model>;
|
||||
using EquationOfState = typename ModelType::EquationOfStateType;
|
||||
using Form = operators::CompiledStellarEquilibriumForm<ModelType>;
|
||||
using AvailableEquations = material::StellarEquilibriumThermodynamicEquations;
|
||||
|
||||
static constexpr bool thermodynamicsCompilable =
|
||||
material::ThermodynamicEquationsCompilable<EquationOfState, Form, AvailableEquations>;
|
||||
|
||||
public:
|
||||
static constexpr bool complete = [] {
|
||||
if constexpr (!thermodynamicsCompilable) {
|
||||
return false;
|
||||
} else {
|
||||
using ThermodynamicEquations =
|
||||
material::CompiledThermodynamicEquationsT<EquationOfState, Form, AvailableEquations>;
|
||||
using Formulation = typename ThermodynamicEquations::PressureSurfaceFormulation;
|
||||
using CompiledSurface =
|
||||
surface::CompiledPressureSurfaceConstraintT<Formulation, EquationOfState>;
|
||||
return requires(const ModelType &model) {
|
||||
{
|
||||
surface::compilePressureSurfaceConstraint<Formulation>(
|
||||
model.surfaceCondition(),
|
||||
model.equationOfState()
|
||||
)
|
||||
} -> std::same_as<CompiledSurface>;
|
||||
};
|
||||
}
|
||||
}();
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <model::StellarModelType Model>
|
||||
inline constexpr bool hasStellarEquilibriumSurfaceCompilation =
|
||||
detail::StellarSurfaceCompilationAudit<std::remove_cvref_t<Model>>::complete;
|
||||
|
||||
template <typename Candidate>
|
||||
concept StellarEquilibriumModel = model::StellarModelType<Candidate> && requires {
|
||||
requires std::remove_cvref_t<Candidate>::template containsSpecification<eos::Polytrope>;
|
||||
requires std::remove_cvref_t<Candidate>::template containsSpecification<surface::Isobaric>;
|
||||
typename std::remove_cvref_t<Candidate>::EquationOfStateType;
|
||||
requires(
|
||||
std::remove_cvref_t<Candidate>::template specificationRoleCount<
|
||||
models::SpecificationRole::boundary_condition> == 1
|
||||
);
|
||||
requires std::remove_cvref_t<Candidate>::template containsSpecification<models::FixedTotalMass>;
|
||||
requires std::remove_cvref_t<Candidate>::specificationCount ==
|
||||
3 + static_cast<std::size_t>(
|
||||
std::remove_cvref_t<Candidate>::template containsSpecification<models::FixedCentralDensity>
|
||||
);
|
||||
requires operators::StellarEquilibriumSystemCompilable<std::remove_cvref_t<Candidate>>;
|
||||
requires hasStellarEquilibriumSurfaceCompilation<std::remove_cvref_t<Candidate>>;
|
||||
requires operators::CompilableRootManifestFor<
|
||||
std::remove_cvref_t<Candidate>,
|
||||
operators::CompiledStellarEquilibriumForm<std::remove_cvref_t<Candidate>>>;
|
||||
requires operators::hasStellarEquilibriumCoreRuntime<std::remove_cvref_t<Candidate>>;
|
||||
requires operators::hasCompleteStellarEquilibriumRuntime<std::remove_cvref_t<Candidate>>;
|
||||
requires operators::stellarEquilibriumRotationProviderCount<std::remove_cvref_t<Candidate>> <= 1;
|
||||
};
|
||||
|
||||
template <StellarEquilibriumModel Model> class StellarEquilibriumProblem final {
|
||||
namespace detail {
|
||||
template <typename Model, typename Discretization, typename = void>
|
||||
struct StellarEquilibriumModelDiscretizationStructureAudit : std::false_type { };
|
||||
|
||||
template <typename Model, typename Discretization>
|
||||
requires StellarEquilibriumModel<std::remove_cvref_t<Model>> &&
|
||||
StellarDiscretizationType<std::remove_cvref_t<Discretization>>
|
||||
struct StellarEquilibriumModelDiscretizationStructureAudit<
|
||||
Model,
|
||||
Discretization,
|
||||
std::void_t<
|
||||
typename std::remove_cvref_t<Discretization>::NormalizationPrescriptionType,
|
||||
typename std::remove_cvref_t<Model>::SpecificationTypes,
|
||||
operators::CompiledStellarEquilibriumForm<std::remove_cvref_t<Model>>,
|
||||
operators::StellarEquilibriumPhysicalCoreType<std::remove_cvref_t<Model>>>>
|
||||
: std::bool_constant<normalization::StellarNormalizationRuntimeAvailableFor<
|
||||
typename std::remove_cvref_t<Discretization>::NormalizationPrescriptionType,
|
||||
operators::CompiledStellarEquilibriumForm<std::remove_cvref_t<Model>>,
|
||||
operators::StellarEquilibriumPhysicalCoreType<std::remove_cvref_t<Model>>,
|
||||
typename std::remove_cvref_t<Model>::SpecificationTypes>> { };
|
||||
|
||||
struct StellarEquilibriumProblemFactory;
|
||||
} // namespace detail
|
||||
|
||||
template <
|
||||
StellarEquilibriumModel Model,
|
||||
StellarDiscretizationType Discretization = StellarDiscretization>
|
||||
requires detail::StellarEquilibriumModelDiscretizationStructureAudit<
|
||||
std::remove_cvref_t<Model>,
|
||||
std::remove_cvref_t<Discretization>>::value
|
||||
class StellarEquilibriumProblem final {
|
||||
public:
|
||||
using ModelType = std::remove_cvref_t<Model>;
|
||||
using DiscretizationType = std::remove_cvref_t<Discretization>;
|
||||
using NormalizationPrescriptionType = typename DiscretizationType::NormalizationPrescriptionType;
|
||||
|
||||
static constexpr bool hasFixedCentralDensity =
|
||||
ModelType::template containsSpecification<models::FixedCentralDensity>;
|
||||
static constexpr bool hasFixedAngularMomentum =
|
||||
ModelType::template containsSpecification<models::FixedAngularMomentum>;
|
||||
static constexpr std::size_t generatedRotationProviderCount =
|
||||
operators::stellarEquilibriumRotationProviderCount<ModelType>;
|
||||
static constexpr bool symbolicallySquare = ModelType::symbolicallySquare;
|
||||
|
||||
using PreparedOperatorType = std::conditional_t<
|
||||
hasFixedCentralDensity,
|
||||
operators::PreparedCentralDensityStellarEquilibriumOperator,
|
||||
operators::PreparedStellarEquilibriumOperator>;
|
||||
using FormType = std::conditional_t<
|
||||
hasFixedCentralDensity,
|
||||
operators::CentralDensityStellarEquilibriumForm,
|
||||
utils::blocks::surface_deformed_stellar_equilibrium_form>;
|
||||
using JacobianFormType = std::conditional_t<
|
||||
hasFixedCentralDensity,
|
||||
operators::CentralDensityStellarEquilibriumJacobianForm,
|
||||
utils::blocks::surface_deformed_stellar_equilibrium_jacobian_form>;
|
||||
using ManifestType = std::conditional_t<
|
||||
hasFixedCentralDensity,
|
||||
operators::CentralDensityStellarEquilibriumSystemManifest,
|
||||
operators::StellarEquilibriumSystemManifest>;
|
||||
using EquationOfStateType = eos::Polytrope;
|
||||
using PreparedOperatorType = operators::PreparedVariadicStellarEquilibriumOperator<ModelType>;
|
||||
using PhysicalCoreType = typename PreparedOperatorType::PhysicalCoreType;
|
||||
using FormType = operators::CompiledStellarEquilibriumForm<ModelType>;
|
||||
using JacobianFormType = operators::CompiledStellarEquilibriumJacobianForm<ModelType>;
|
||||
using ManifestType = operators::EquilibriumSystemManifest<ModelType, FormType, JacobianFormType>;
|
||||
using EquationOfStateType = model::EquationOfStateType<ModelType>;
|
||||
using SurfaceConditionType = model::SurfaceConditionType<ModelType>;
|
||||
using AvailableThermodynamicEquations = material::StellarEquilibriumThermodynamicEquations;
|
||||
using ThermodynamicEquationsType =
|
||||
material::CompiledThermodynamicEquationsT<EquationOfStateType, FormType, AvailableThermodynamicEquations>;
|
||||
@@ -60,44 +142,22 @@ export namespace mean_field::equilibrium {
|
||||
typename ThermodynamicEquationsType::PressureSurfaceFormulation,
|
||||
EquationOfStateType>;
|
||||
|
||||
StellarEquilibriumProblem(
|
||||
ModelType stellarModel,
|
||||
const StellarDiscretization discretization
|
||||
)
|
||||
requires(!hasFixedCentralDensity)
|
||||
: m_stellarModel(std::move(stellarModel)),
|
||||
m_discretization(discretization),
|
||||
m_compiledSurfaceConstraint(CompileSurfaceConstraint(m_stellarModel)),
|
||||
m_preparedOperator(
|
||||
m_discretization.finiteElementModel(),
|
||||
m_discretization.domainMapper(),
|
||||
m_stellarModel.template specification<eos::Polytrope>(),
|
||||
models::compileConstraint(m_stellarModel.template specification<models::FixedTotalMass>()),
|
||||
operators::PressureSurfaceConstraintView{m_compiledSurfaceConstraint},
|
||||
CompileDefaultDomainDeformation(m_discretization.finiteElementModel())
|
||||
) {
|
||||
VerifyProblem();
|
||||
}
|
||||
private:
|
||||
friend struct detail::StellarEquilibriumProblemFactory;
|
||||
|
||||
StellarEquilibriumProblem(
|
||||
ModelType stellarModel,
|
||||
const StellarDiscretization discretization
|
||||
DiscretizationType discretization
|
||||
)
|
||||
requires hasFixedCentralDensity
|
||||
: m_stellarModel(std::move(stellarModel)),
|
||||
m_discretization(discretization),
|
||||
m_compiledSurfaceConstraint(CompileSurfaceConstraint(m_stellarModel)),
|
||||
: m_stellarModel(std::make_shared<ModelType>(std::move(stellarModel))),
|
||||
m_discretization(std::move(discretization)),
|
||||
m_compiledSurfaceConstraint(CompileSurfaceConstraint(*m_stellarModel)),
|
||||
m_preparedOperator(
|
||||
m_discretization.finiteElementModel(),
|
||||
m_discretization.domainMapper(),
|
||||
m_stellarModel.template specification<eos::Polytrope>(),
|
||||
models::compileConstraint(m_stellarModel.template specification<models::FixedTotalMass>()),
|
||||
m_stellarModel,
|
||||
operators::PressureSurfaceConstraintView{m_compiledSurfaceConstraint},
|
||||
CompileDefaultDomainDeformation(m_discretization.finiteElementModel()),
|
||||
models::compileConstraint(
|
||||
m_stellarModel.template specification<models::FixedCentralDensity>(),
|
||||
m_stellarModel.template specification<eos::Polytrope>()
|
||||
)
|
||||
CompileDefaultDomainDeformation(m_discretization.finiteElementModel())
|
||||
) {
|
||||
VerifyProblem();
|
||||
}
|
||||
@@ -107,14 +167,19 @@ export namespace mean_field::equilibrium {
|
||||
StellarEquilibriumProblem(StellarEquilibriumProblem &&) = delete;
|
||||
StellarEquilibriumProblem &operator=(StellarEquilibriumProblem &&) = delete;
|
||||
|
||||
public:
|
||||
[[nodiscard]] const ModelType &GetStellarModel() const noexcept {
|
||||
return m_stellarModel;
|
||||
return *m_stellarModel;
|
||||
}
|
||||
|
||||
[[nodiscard]] const StellarDiscretization &GetDiscretization() const noexcept {
|
||||
[[nodiscard]] const DiscretizationType &GetDiscretization() const noexcept {
|
||||
return m_discretization;
|
||||
}
|
||||
|
||||
[[nodiscard]] const NormalizationPrescriptionType &GetNormalizationPrescription() const noexcept {
|
||||
return m_discretization.normalizationPrescription();
|
||||
}
|
||||
|
||||
[[nodiscard]] const CompiledSurfaceConstraintType &GetCompiledSurfaceConstraint() const noexcept {
|
||||
return m_compiledSurfaceConstraint;
|
||||
}
|
||||
@@ -127,6 +192,10 @@ export namespace mean_field::equilibrium {
|
||||
return m_preparedOperator;
|
||||
}
|
||||
|
||||
[[nodiscard]] const PhysicalCoreType &GetPhysicalOperator() const noexcept {
|
||||
return m_preparedOperator.GetPhysicalOperator();
|
||||
}
|
||||
|
||||
[[nodiscard]] const auto &GetManifest() const noexcept {
|
||||
return m_preparedOperator.GetRootManifest();
|
||||
}
|
||||
@@ -135,28 +204,20 @@ export namespace mean_field::equilibrium {
|
||||
return m_preparedOperator.IsPrepared();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint64_t GetPreparationGeneration() const noexcept {
|
||||
return m_preparationGeneration;
|
||||
}
|
||||
|
||||
[[nodiscard]] const operators::StellarEquilibriumDependencies &GetLinearizationDependencies() const {
|
||||
if constexpr (hasFixedCentralDensity) {
|
||||
return m_preparedOperator.GetPhysicalOperator().GetDependencies();
|
||||
} else {
|
||||
return m_preparedOperator.GetDependencies();
|
||||
}
|
||||
return GetPhysicalOperator().GetDependencies();
|
||||
}
|
||||
|
||||
[[nodiscard]] const operators::StellarEquilibriumDependencyStamp &GetGeometryDependency() const {
|
||||
if constexpr (hasFixedCentralDensity) {
|
||||
return m_preparedOperator.GetPhysicalOperator().GetGeneratedDisplacementDependency();
|
||||
} else {
|
||||
return m_preparedOperator.GetGeneratedDisplacementDependency();
|
||||
}
|
||||
return GetPhysicalOperator().GetGeneratedDisplacementDependency();
|
||||
}
|
||||
|
||||
[[nodiscard]] const field::FieldBoundaryDofMap &GetPressureSurfaceRows() const noexcept {
|
||||
if constexpr (hasFixedCentralDensity) {
|
||||
return m_preparedOperator.GetPhysicalOperator().GetSurfaceConstraintOperator().GetSurfaceRows();
|
||||
} else {
|
||||
return m_preparedOperator.GetSurfaceConstraintOperator().GetSurfaceRows();
|
||||
}
|
||||
return GetPhysicalOperator().GetSurfaceConstraintOperator().GetSurfaceRows();
|
||||
}
|
||||
|
||||
[[nodiscard]] int StateSize() const noexcept {
|
||||
@@ -175,8 +236,19 @@ export namespace mean_field::equilibrium {
|
||||
const mfem::Vector &state,
|
||||
const operators::StellarEquilibriumDependencies &dependencies,
|
||||
const physics::RigidRotation &rotation
|
||||
) {
|
||||
return m_preparedOperator.Prepare(state, dependencies, rotation);
|
||||
) requires(generatedRotationProviderCount == 0) {
|
||||
auto report = m_preparedOperator.Prepare(state, dependencies, rotation);
|
||||
++m_preparationGeneration;
|
||||
return report;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Prepare(
|
||||
const mfem::Vector &state,
|
||||
const operators::StellarEquilibriumDependencies &dependencies
|
||||
) requires(generatedRotationProviderCount == 1) {
|
||||
auto report = m_preparedOperator.Prepare(state, dependencies);
|
||||
++m_preparationGeneration;
|
||||
return report;
|
||||
}
|
||||
|
||||
void BuildResidual(mfem::Vector &residual) const {
|
||||
@@ -194,8 +266,8 @@ export namespace mean_field::equilibrium {
|
||||
[[nodiscard]] static CompiledSurfaceConstraintType CompileSurfaceConstraint(const ModelType &stellarModel) {
|
||||
return surface::compilePressureSurfaceConstraint<
|
||||
typename ThermodynamicEquationsType::PressureSurfaceFormulation>(
|
||||
stellarModel.template specification<surface::Isobaric>(),
|
||||
stellarModel.template specification<EquationOfStateType>()
|
||||
stellarModel.surfaceCondition(),
|
||||
stellarModel.equationOfState()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -224,34 +296,112 @@ export namespace mean_field::equilibrium {
|
||||
MFEM_VERIFY(m_discretization.isCurrent(), "The stellar equilibrium problem has a stale discretization.");
|
||||
}
|
||||
|
||||
ModelType m_stellarModel;
|
||||
StellarDiscretization m_discretization;
|
||||
std::shared_ptr<const ModelType> m_stellarModel;
|
||||
DiscretizationType m_discretization;
|
||||
CompiledSurfaceConstraintType m_compiledSurfaceConstraint;
|
||||
PreparedOperatorType m_preparedOperator;
|
||||
std::uint64_t m_preparationGeneration{0};
|
||||
};
|
||||
|
||||
template <StellarEquilibriumModel Model>
|
||||
template <typename Candidate> struct IsStellarEquilibriumProblem : std::false_type { };
|
||||
|
||||
template <StellarEquilibriumModel Model, StellarDiscretizationType Discretization>
|
||||
requires detail::StellarEquilibriumModelDiscretizationStructureAudit<
|
||||
std::remove_cvref_t<Model>,
|
||||
std::remove_cvref_t<Discretization>>::value
|
||||
struct IsStellarEquilibriumProblem<StellarEquilibriumProblem<Model, Discretization>> : std::true_type { };
|
||||
|
||||
template <typename Candidate>
|
||||
concept DiscretizedStellarEquilibriumProblem = IsStellarEquilibriumProblem<std::remove_cvref_t<Candidate>>::value;
|
||||
|
||||
namespace detail {
|
||||
template <
|
||||
typename Model,
|
||||
typename Discretization,
|
||||
bool StructurallyCompatible =
|
||||
StellarEquilibriumModelDiscretizationStructureAudit<
|
||||
std::remove_cvref_t<Model>,
|
||||
std::remove_cvref_t<Discretization>>::value>
|
||||
struct StellarEquilibriumModelDiscretizationOperationAudit : std::false_type { };
|
||||
|
||||
template <typename Model, typename Discretization>
|
||||
struct StellarEquilibriumModelDiscretizationOperationAudit<
|
||||
Model,
|
||||
Discretization,
|
||||
true> {
|
||||
private:
|
||||
using ModelType = std::remove_cvref_t<Model>;
|
||||
using DiscretizationType = std::remove_cvref_t<Discretization>;
|
||||
using Problem = StellarEquilibriumProblem<ModelType, DiscretizationType>;
|
||||
using Prescription = typename DiscretizationType::NormalizationPrescriptionType;
|
||||
|
||||
public:
|
||||
static constexpr bool value = [] {
|
||||
if constexpr (
|
||||
std::same_as<Prescription, normalization::Unnormalized> ||
|
||||
normalization::PhysicalRieszDiagonalPrescription<Prescription>) {
|
||||
return true;
|
||||
} else {
|
||||
return normalization::RuntimePreparedNormalizationOperation<Problem>;
|
||||
}
|
||||
}();
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/*
|
||||
* A model and a discretization are separate compile-time choices. Their
|
||||
* pairing is valid only when the normalization plan covers the inferred
|
||||
* form, the selected physical runtime supports it, and a third-party
|
||||
* runtime policy provides its exact preparation operation. Keeping this
|
||||
* as a detection-safe public factory boundary rejects incomplete policies
|
||||
* at discretize(), before a solver-facing problem can be constructed.
|
||||
*/
|
||||
template <typename Model, typename Discretization>
|
||||
concept StellarEquilibriumModelDiscretizationCompatible =
|
||||
detail::StellarEquilibriumModelDiscretizationOperationAudit<
|
||||
std::remove_cvref_t<Model>,
|
||||
std::remove_cvref_t<Discretization>>::value;
|
||||
|
||||
namespace detail {
|
||||
/* The structurally formed problem type is needed to probe the ADL
|
||||
* operation without a recursive concept. Its constructor remains
|
||||
* private, and this factory is the single construction authority after
|
||||
* the complete public compatibility contract has succeeded. */
|
||||
struct StellarEquilibriumProblemFactory final {
|
||||
template <StellarEquilibriumModel Model, StellarDiscretizationType Discretization>
|
||||
requires StellarEquilibriumModelDiscretizationCompatible<Model, Discretization>
|
||||
[[nodiscard]] static auto Create(
|
||||
Model &&stellarModel,
|
||||
Discretization discretization
|
||||
) {
|
||||
using ModelType = std::remove_cvref_t<Model>;
|
||||
using DiscretizationType = std::remove_cvref_t<Discretization>;
|
||||
return StellarEquilibriumProblem<ModelType, DiscretizationType>{
|
||||
std::forward<Model>(stellarModel),
|
||||
std::move(discretization)
|
||||
};
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <StellarEquilibriumModel Model, StellarDiscretizationType Discretization>
|
||||
requires StellarEquilibriumModelDiscretizationCompatible<Model, Discretization>
|
||||
[[nodiscard]] auto discretize(
|
||||
Model &&stellarModel,
|
||||
const StellarDiscretization discretization
|
||||
Discretization discretization
|
||||
) {
|
||||
using ModelType = std::remove_cvref_t<Model>;
|
||||
return StellarEquilibriumProblem<ModelType>{std::forward<Model>(stellarModel), discretization};
|
||||
return detail::StellarEquilibriumProblemFactory::Create(
|
||||
std::forward<Model>(stellarModel),
|
||||
std::move(discretization)
|
||||
);
|
||||
}
|
||||
|
||||
template <StellarEquilibriumModel Model>
|
||||
requires StellarEquilibriumModelDiscretizationCompatible<Model, StellarDiscretization>
|
||||
[[nodiscard]] auto discretize(
|
||||
Model &&stellarModel,
|
||||
fem::FEM &finiteElementModel
|
||||
) {
|
||||
return discretize(std::forward<Model>(stellarModel), StellarDiscretization{finiteElementModel});
|
||||
}
|
||||
|
||||
template <typename Candidate> struct IsStellarEquilibriumProblem : std::false_type { };
|
||||
|
||||
template <StellarEquilibriumModel Model>
|
||||
struct IsStellarEquilibriumProblem<StellarEquilibriumProblem<Model>> : std::true_type { };
|
||||
|
||||
template <typename Candidate>
|
||||
concept DiscretizedStellarEquilibriumProblem = IsStellarEquilibriumProblem<std::remove_cvref_t<Candidate>>::value;
|
||||
} // namespace mean_field::equilibrium
|
||||
|
||||
Reference in New Issue
Block a user