module; #include #include #include #include #include #include #include #include #include #include export module mean_field:operators.prepared_stellar_equilibrium; export import :eos.polytrope; export import :fem; export import :field.mfem; export import :mapping.domain_mapper; export import :model.stellar; export import :model.typed_stellar; export import :operators.context.gravity_field; export import :operators.gravity_field; export import :operators.gravity_field_jacobian; export import :operators.prepared_barotropic_closure; export import :operators.prepared_displacement_residual; export import :operators.prepared_hydrostatic_equilibrium; export import :operators.prepared_mass_normalization; export import :operators.prepared_surface_constraint; export import :operators.root_manifest; export import :physics.rigid_rotation; export import :utils.blocks; export namespace mean_field::operators { struct StellarEquilibriumDependencyStamp final { std::uint64_t identity{0}; std::uint64_t revision{0}; constexpr auto operator<=>(const StellarEquilibriumDependencyStamp &) const = default; }; struct StellarEquilibriumDependencies final { StellarEquilibriumDependencyStamp discretization; StellarEquilibriumDependencyStamp density; StellarEquilibriumDependencyStamp surfaceDeformation; StellarEquilibriumDependencyStamp gravityGradient; StellarEquilibriumDependencyStamp gravityPotential; StellarEquilibriumDependencyStamp enthalpy; StellarEquilibriumDependencyStamp bernoulliConstant; StellarEquilibriumDependencyStamp rotation; StellarEquilibriumDependencyStamp targetMass; constexpr auto operator<=>(const StellarEquilibriumDependencies &) const = default; }; struct PreparedStellarEquilibriumReport final { context::gravity_field::GravityFieldPreparationReport gravity; PreparedBarotropicClosureReport barotropicClosure; PreparedHydrostaticEquilibriumReport hydrostatic; PreparedDisplacementResidualReport displacement; PreparedMassNormalizationReport massNormalization; PreparedSurfaceConstraintReport surfaceConstraint; deformation::DomainDeformationGeometryReport generatedGeometry; StellarEquilibriumDependencyStamp generatedDisplacement; bool generatedVolumeDisplacement{false}; bool assembledResidual{false}; [[nodiscard]] bool DidAnyChildWork() const noexcept { return gravity.DidAnyWork() || barotropicClosure.DidAnyWork() || hydrostatic.DidAnyWork() || displacement.DidAnyWork() || massNormalization.DidAnyWork() || surfaceConstraint.DidAnyWork(); } [[nodiscard]] bool DidAnyWork() const noexcept { return DidAnyChildWork() || generatedVolumeDisplacement || assembledResidual; } }; enum class StellarEquilibriumPreparationRejectionReason : std::uint8_t { inverted_geometry, non_finite_geometry, thermodynamic_domain, non_finite_thermodynamics, inadmissible_physics, non_finite_physics }; enum class StellarEquilibriumPreparationStage : std::uint8_t { unspecified, generated_geometry, gravity, barotropic_closure, hydrostatic_equilibrium, displacement_residual, pressure_force, gravity_displacement_force, rotational_displacement_force, displacement_composition, mass_normalization, model_specification }; /* * A candidate state that cannot define a physical mapped domain is an * expected line-search outcome, not an exceptional program failure. Keep * this payload fixed-size so every trial can report it without allocating. */ struct StellarEquilibriumPreparationRejection final { StellarEquilibriumPreparationRejectionReason reason{ StellarEquilibriumPreparationRejectionReason::inverted_geometry }; StellarEquilibriumPreparationStage stage{StellarEquilibriumPreparationStage::unspecified}; double minimumJacobianDeterminant{std::numeric_limits::quiet_NaN()}; eos::EvaluationErrorCode thermodynamicErrorCode{eos::EvaluationErrorCode::nonfinite_result}; }; template using StellarEquilibriumPreparationResult = std::expected; [[noreturn]] inline void throwStellarEquilibriumPreparationRejection(const StellarEquilibriumPreparationRejection &rejection) { switch (rejection.reason) { case StellarEquilibriumPreparationRejectionReason::non_finite_geometry: throw std::domain_error("The prepared domain deformation has non-finite mapped geometry."); case StellarEquilibriumPreparationRejectionReason::thermodynamic_domain: throw eos::EvaluationError( rejection.thermodynamicErrorCode, "The stellar state lies outside the equation-of-state domain." ); case StellarEquilibriumPreparationRejectionReason::non_finite_thermodynamics: throw eos::EvaluationError( rejection.thermodynamicErrorCode, "The stellar state produced non-finite thermodynamic data." ); case StellarEquilibriumPreparationRejectionReason::inadmissible_physics: throw std::domain_error("The stellar state is physically inadmissible."); case StellarEquilibriumPreparationRejectionReason::non_finite_physics: throw std::domain_error("The stellar state produced non-finite physical data."); case StellarEquilibriumPreparationRejectionReason::inverted_geometry: throw std::domain_error("The prepared domain deformation inverts at least one volume element."); } throw std::logic_error("Unknown stellar-equilibrium candidate-rejection reason."); } struct PreparedStellarEquilibriumStatistics final { std::uint64_t residualAssemblies{0}; std::uint64_t residualApplications{0}; std::uint64_t jacobianApplications{0}; std::uint64_t generatedGeometryBuilds{0}; constexpr auto operator<=>(const PreparedStellarEquilibriumStatistics &) const = default; }; using StellarEquilibriumLayout = utils::blocks::form_layout; using StellarEquilibriumSpecificationModel = model::StellarModel>; using StellarEquilibriumSystemManifest = EquilibriumSystemManifest< StellarEquilibriumSpecificationModel, utils::blocks::surface_deformed_stellar_equilibrium_form, utils::blocks::surface_deformed_stellar_equilibrium_jacobian_form>; using StellarEquilibriumRootManifest = StellarEquilibriumSystemManifest; 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 requires std::same_as< typename std::remove_cvref_t::EquationOfStateType, eos::Polytrope> && SingleFieldPressureSurfaceConstraintFor< typename std::remove_cvref_t::SurfaceConstraintType, field::Enthalpy> && std::is_lvalue_reference_v PreparedStellarEquilibriumOperator( fem::FEM &f, const mapping::DomainMapper &domainMapper, Model &&stellarModel ) : PreparedStellarEquilibriumOperator( f, domainMapper, stellarModel.equationOfState(), models::compileConstraint(models::FixedTotalMass{dimensions::MassValue{stellarModel.targetMass()}}), PressureSurfaceConstraintView{stellarModel.compiledSurfaceConstraint()}, deformation::PreparedDomainDeformationRuntime{stellarModel.compileDomainDeformation(f)} ) { } /* * Authoritative construction path for a compiled equilibrium system. * The caller owns the EOS and compiled surface constraint for this * operator's lifetime; the remaining compiled contributions are * transferred into the operator. */ PreparedStellarEquilibriumOperator( fem::FEM &f, const mapping::DomainMapper &domainMapper, const eos::Polytrope &equationOfState, models::CompiledFixedMass fixedMassConstraint, PressureSurfaceConstraintView surfaceConstraint, deformation::PreparedDomainDeformationRuntime domainDeformation ); PreparedStellarEquilibriumOperator(const PreparedStellarEquilibriumOperator &) = delete; PreparedStellarEquilibriumOperator &operator=(const PreparedStellarEquilibriumOperator &) = delete; PreparedStellarEquilibriumOperator(PreparedStellarEquilibriumOperator &&) = delete; PreparedStellarEquilibriumOperator &operator=(PreparedStellarEquilibriumOperator &&) = delete; PreparedStellarEquilibriumReport Prepare( const mfem::Vector &state, const StellarEquilibriumDependencies &dependencies, const physics::RigidRotation &rotation ); [[nodiscard]] StellarEquilibriumPreparationResult TryPrepare( 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]] double GetTargetMass() const noexcept; [[nodiscard]] const StellarEquilibriumLayout &GetLayout() const noexcept; [[nodiscard]] const StellarEquilibriumRootManifest &GetRootManifest() const noexcept; [[nodiscard]] RootStateView GetRootStateView(const mfem::Vector &state) const; [[nodiscard]] ResidualView GetResidualView(mfem::Vector &residual) const; [[nodiscard]] RootConstraintReport GetFixedMassReport() const; [[nodiscard]] const StellarEquilibriumDependencies &GetDependencies() const; [[nodiscard]] const PreparedStellarEquilibriumStatistics &GetStatistics() const noexcept; [[nodiscard]] const context::gravity_field::GravityFieldLinearizationContext & GetGravityContext() const noexcept; [[nodiscard]] const GravityFieldOperator &GetGravityOperator() const noexcept; [[nodiscard]] const GravityFieldJacobianOperator &GetGravityJacobianOperator() const noexcept; [[nodiscard]] const PreparedBarotropicClosureOperator &GetBarotropicClosureOperator() const noexcept; [[nodiscard]] const context::barotropic::BarotropicClosureLinearizationContext & GetBarotropicClosureContext() const noexcept; [[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; [[nodiscard]] const mfem::Vector &GetGeneratedVolumeDisplacement() const; [[nodiscard]] const mfem::Vector &GetFullMechanicalResidual() const; [[nodiscard]] const StellarEquilibriumDependencyStamp &GetGeneratedDisplacementDependency() const; private: struct ConstructionData; static ConstructionData MakeConstructionData( fem::FEM &f, deformation::PreparedDomainDeformationRuntime domainDeformation ); PreparedStellarEquilibriumOperator( fem::FEM &f, const mapping::DomainMapper &domainMapper, const eos::Polytrope &equationOfState, models::CompiledFixedMass fixedMassConstraint, PressureSurfaceConstraintView surfaceConstraint, ConstructionData constructionData ); void AssembleResidual(); void VerifyPrepared() const; StellarEquilibriumRootManifest m_rootManifest; MPI_Comm m_communicator{MPI_COMM_NULL}; mfem::Array m_gravityStateOffsets; context::gravity_field::GravityFieldLinearizationContext m_gravityContext; GravityFieldJacobianOperator m_gravityJacobianOperator; GravityFieldOperator m_gravityOperator; PreparedBarotropicClosureOperator m_barotropicClosureOperator; PreparedHydrostaticEquilibriumOperator m_hydrostaticOperator; PreparedDisplacementResidualOperator m_displacementOperator; PreparedMassNormalizationOperator m_massNormalizationOperator; PreparedPressureSurfaceConstraint m_surfaceConstraintOperator; deformation::PreparedDomainDeformationRuntime m_domainDeformation; StellarEquilibriumDependencies m_preparedDependencies; StellarEquilibriumDependencyStamp m_generatedDisplacementDependency; deformation::DomainDeformationGeometryReport m_generatedGeometryReport; mfem::Vector m_surfaceDeformationParameters; mfem::Vector m_generatedVolumeDisplacement; mfem::Vector m_fullMechanicalResidual; mfem::Vector m_cachedResidual; models::CompiledFixedMass m_fixedMassConstraint; mutable PreparedStellarEquilibriumStatistics m_statistics; bool m_isPrepared{false}; mfem::Vector m_gravityState; mutable mfem::Vector m_gravityDirection; mutable mfem::Vector m_volumeDisplacementDirection; mutable mfem::Vector m_fullMechanicalAction; mutable mfem::Vector m_surfaceShapeAction; mutable mfem::Vector m_pullbackDerivativeAction; mutable mfem::Vector m_densityVolumeIntegralAction; }; } // namespace mean_field::operators