module; #include #include #include #include #include module mean_field; import :operators.prepared_stellar_equilibrium; namespace { using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema; void verify_coupled_discretization(const mean_field::fem::FEM &f) { MFEM_VERIFY( f.mesh != nullptr && f.densityFes != nullptr && f.displacementFes != nullptr && f.gravityFluxFes != nullptr && f.gravityPotentialFes != nullptr && f.enthalpyFes != nullptr, "PreparedStellarEquilibriumOperator requires the complete coupled finite-element discretization." ); } [[nodiscard]] mean_field::operators::StellarEquilibriumLayout make_layout( const mean_field::field::FieldDofMap &densityMap, const int surfaceDeformationParameterCount, const mean_field::field::FieldDofMap &gravityFluxMap, const mean_field::field::FieldDofMap &gravityPotentialMap, const mean_field::field::FieldDofMap &enthalpyMap ) { using Form = mean_field::utils::blocks::surface_deformed_stellar_equilibrium_form; const std::array valueSizes{ densityMap.reduced_size(), surfaceDeformationParameterCount, gravityFluxMap.reduced_size(), gravityPotentialMap.reduced_size(), enthalpyMap.reduced_size(), 1 }; const std::array residualSizes{ gravityFluxMap.reduced_size(), gravityPotentialMap.reduced_size(), densityMap.reduced_size(), surfaceDeformationParameterCount, enthalpyMap.reduced_size(), 1 }; return {valueSizes, residualSizes}; } [[nodiscard]] mfem::Array make_gravity_state_offsets( const mean_field::field::FieldDofMap &densityMap, const mean_field::field::FieldDofMap &displacementMap, const mean_field::field::FieldDofMap &gravityFluxMap, const mean_field::field::FieldDofMap &gravityPotentialMap ) { mfem::Array offsets(5); offsets[0] = 0; offsets[1] = offsets[0] + densityMap.reduced_size(); offsets[2] = offsets[1] + displacementMap.reduced_size(); offsets[3] = offsets[2] + gravityFluxMap.reduced_size(); offsets[4] = offsets[3] + gravityPotentialMap.reduced_size(); return offsets; } [[nodiscard]] mfem::Array make_gravity_residual_offsets( const mean_field::field::FieldDofMap &gravityFluxMap, const mean_field::field::FieldDofMap &gravityPotentialMap ) { mfem::Array offsets(3); offsets[0] = 0; offsets[1] = gravityFluxMap.reduced_size(); offsets[2] = offsets[1] + gravityPotentialMap.reduced_size(); return offsets; } template [[nodiscard]] mfem::Vector make_value_view( const mfem::Vector &vector, const mean_field::operators::StellarEquilibriumLayout &layout, const mean_field::utils::blocks::value_block block ) { MFEM_VERIFY( vector.Size() == layout.value_offsets().Last(), "The coupled vector does not match the stellar-equilibrium value layout." ); return mfem::Vector(const_cast(vector.GetData()) + layout.offset(block), layout.size(block)); } template [[nodiscard]] mfem::Vector make_residual_view( mfem::Vector &vector, const mean_field::operators::StellarEquilibriumLayout &layout, const mean_field::utils::blocks::residual_block block ) { MFEM_VERIFY( vector.Size() == layout.residual_offsets().Last(), "The coupled vector does not match the stellar-equilibrium residual layout." ); return mfem::Vector(vector.GetData() + layout.offset(block), layout.size(block)); } template void assign_residual_block( mfem::Vector &coupledResidual, const mean_field::operators::StellarEquilibriumLayout &layout, const mean_field::utils::blocks::residual_block block, const mfem::Vector &blockResidual, const char *message ) { MFEM_VERIFY(layout.size(block) == blockResidual.Size(), message); mfem::Vector destination = make_residual_view(coupledResidual, layout, block); destination = blockResidual; } void assign_gravity_block( mfem::Vector &gravityState, const mfem::Array &offsets, const int blockIndex, const mfem::Vector &source, const char *message ) { MFEM_VERIFY(offsets.Size() == 5, "Gravity state offsets are invalid."); MFEM_VERIFY(blockIndex >= 0 && blockIndex + 1 < offsets.Size(), "Requested gravity-state block is invalid."); const int blockSize = offsets[blockIndex + 1] - offsets[blockIndex]; MFEM_VERIFY(blockSize == source.Size(), message); MFEM_VERIFY(gravityState.Size() == offsets.Last(), "Packed gravity state has the wrong size."); mfem::Vector destination(gravityState.GetData() + offsets[blockIndex], blockSize); destination = source; } void pack_gravity_vector( mfem::Vector &gravityState, const mfem::Array &offsets, const mfem::Vector &density, const mfem::Vector &displacement, const mfem::Vector &gravityGradient, const mfem::Vector &gravityPotential ) { MFEM_VERIFY(offsets.Size() == 5, "Packed gravity state requires four blocks."); if (gravityState.Size() != offsets.Last()) { gravityState.SetSize(offsets.Last()); } assign_gravity_block( gravityState, offsets, 0, density, "The full density vector has the wrong gravity-state size." ); assign_gravity_block( gravityState, offsets, 1, displacement, "The displacement vector has the wrong gravity-state size." ); assign_gravity_block( gravityState, offsets, 2, gravityGradient, "The gravity-gradient vector has the wrong gravity-state size." ); assign_gravity_block( gravityState, offsets, 3, gravityPotential, "The gravity-potential vector has the wrong gravity-state size." ); } void validate_finite_vector( const mfem::Vector &vector, const char *message ) { for (int index = 0; index < vector.Size(); ++index) { MFEM_VERIFY(std::isfinite(vector(index)), message); } } void validate_dependency_transition( const mean_field::operators::StellarEquilibriumDependencyStamp &prepared, const mean_field::operators::StellarEquilibriumDependencyStamp &requested, const char *message ) { MFEM_VERIFY(prepared.identity != requested.identity || requested.revision >= prepared.revision, message); MFEM_VERIFY( prepared.identity == requested.identity || prepared.revision != requested.revision, "A new stellar-equilibrium dependency identity must also carry a visibly different revision." ); } [[nodiscard]] mean_field::operators::context::gravity_field::GravityFieldRevisions make_gravity_revisions( const mean_field::operators::StellarEquilibriumDependencies &dependencies, const mean_field::operators::StellarEquilibriumDependencyStamp &generatedDisplacement ) { return { .discretization = {.value = dependencies.discretization.revision}, .displacement = {.value = generatedDisplacement.revision}, .density = {.value = dependencies.density.revision}, .gravity_gradient = {.value = dependencies.gravityGradient.revision}, .gravity_potential = {.value = dependencies.gravityPotential.revision} }; } [[nodiscard]] mean_field::operators::context::barotropic::BarotropicClosureDependencies make_barotropic_closure_dependencies( const mean_field::operators::StellarEquilibriumDependencies &dependencies, const mean_field::operators::StellarEquilibriumDependencyStamp &generatedDisplacement ) { return { .discretization = {.identity = dependencies.discretization.identity, .revision = dependencies.discretization.revision}, .density = {.identity = dependencies.density.identity, .revision = dependencies.density.revision}, .enthalpy = {.identity = dependencies.enthalpy.identity, .revision = dependencies.enthalpy.revision}, .displacement = {.identity = generatedDisplacement.identity, .revision = generatedDisplacement.revision} }; } [[nodiscard]] mean_field::operators::DisplacementResidualDependencies make_displacement_dependencies( const mean_field::operators::StellarEquilibriumDependencies &dependencies, const mean_field::operators::StellarEquilibriumDependencyStamp &generatedDisplacement ) { return { .discretization = {.identity = dependencies.discretization.identity, .revision = dependencies.discretization.revision}, .density = {.identity = dependencies.density.identity, .revision = dependencies.density.revision}, .displacement = {.identity = generatedDisplacement.identity, .revision = generatedDisplacement.revision}, .gravityGradient = {.identity = dependencies.gravityGradient.identity, .revision = dependencies.gravityGradient.revision}, .enthalpy = {.identity = dependencies.enthalpy.identity, .revision = dependencies.enthalpy.revision}, .rotation = {.identity = dependencies.rotation.identity, .revision = dependencies.rotation.revision} }; } [[nodiscard]] mean_field::operators::context::hydrostatic::HydrostaticEquilibriumDependencies make_hydrostatic_dependencies( const mean_field::operators::StellarEquilibriumDependencies &dependencies, const mean_field::operators::StellarEquilibriumDependencyStamp &generatedDisplacement ) { return { .discretization = {.identity = dependencies.discretization.identity, .revision = dependencies.discretization.revision}, .enthalpy = {.identity = dependencies.enthalpy.identity, .revision = dependencies.enthalpy.revision}, .gravityPotential = {.identity = dependencies.gravityPotential.identity, .revision = dependencies.gravityPotential.revision}, .displacement = {.identity = generatedDisplacement.identity, .revision = generatedDisplacement.revision}, .rotation = {.identity = dependencies.rotation.identity, .revision = dependencies.rotation.revision}, .bernoulliConstant = { .identity = dependencies.bernoulliConstant.identity, .revision = dependencies.bernoulliConstant.revision } }; } [[nodiscard]] mean_field::operators::MassNormalizationDependencies make_mass_dependencies( const mean_field::operators::StellarEquilibriumDependencies &dependencies, const mean_field::operators::StellarEquilibriumDependencyStamp &generatedDisplacement ) { return { .discretization = {.identity = dependencies.discretization.identity, .revision = dependencies.discretization.revision}, .density = {.identity = dependencies.density.identity, .revision = dependencies.density.revision}, .displacement = {.identity = generatedDisplacement.identity, .revision = generatedDisplacement.revision}, .targetMass = {.identity = dependencies.targetMass.identity, .revision = dependencies.targetMass.revision} }; } } // namespace namespace mean_field::operators { struct PreparedStellarEquilibriumOperator::ConstructionData { deformation::PreparedDomainDeformationRuntime domainDeformation; field::FieldDofMap densityMap; field::FieldDofMap displacementMap; field::FieldDofMap gravityFluxMap; field::FieldDofMap gravityPotentialMap; field::FieldDofMap enthalpyMap; field::FieldBoundaryDofMap pressureSurfaceRows; StellarEquilibriumLayout layout; mfem::Array gravityStateOffsets; mfem::Array gravityResidualOffsets; ConstructionData( fem::FEM &f, deformation::PreparedDomainDeformationRuntime preparedDomainDeformation ) : domainDeformation(std::move(preparedDomainDeformation)), densityMap( field::make_field_dof_map< field::Density, DomainSchema>(*f.densityFes) ), displacementMap( field::make_field_dof_map< field::Displacement, DomainSchema>(*f.displacementFes) ), gravityFluxMap( field::make_field_dof_map< field::Gravity, DomainSchema>(*f.gravityFluxFes) ), gravityPotentialMap( field::make_field_dof_map< field::Gravity, DomainSchema>(*f.gravityPotentialFes) ), enthalpyMap( field::make_field_dof_map< field::Enthalpy, DomainSchema>(*f.enthalpyFes) ), pressureSurfaceRows( field::make_field_boundary_dof_map< field::Enthalpy, utils::domain::StellarSurface, DomainSchema>( *f.enthalpyFes, enthalpyMap ) ), layout(make_layout( densityMap, domainDeformation.parameterCount(), gravityFluxMap, gravityPotentialMap, enthalpyMap )), gravityStateOffsets(make_gravity_state_offsets( densityMap, displacementMap, gravityFluxMap, gravityPotentialMap )), gravityResidualOffsets(make_gravity_residual_offsets( gravityFluxMap, gravityPotentialMap )) { } }; PreparedStellarEquilibriumOperator::ConstructionData PreparedStellarEquilibriumOperator::MakeConstructionData( fem::FEM &f, deformation::PreparedDomainDeformationRuntime domainDeformation ) { verify_coupled_discretization(f); return ConstructionData(f, std::move(domainDeformation)); } PreparedStellarEquilibriumOperator::PreparedStellarEquilibriumOperator( fem::FEM &f, const mapping::DomainMapper &domainMapper, const eos::Polytrope &equationOfState, const double targetMass, const PressureSurfaceConstraintView surfaceConstraint, deformation::PreparedDomainDeformationRuntime domainDeformation ) : PreparedStellarEquilibriumOperator( f, domainMapper, equationOfState, targetMass, surfaceConstraint, MakeConstructionData( f, std::move(domainDeformation) ) ) { } PreparedStellarEquilibriumOperator::PreparedStellarEquilibriumOperator( fem::FEM &f, const mapping::DomainMapper &domainMapper, const eos::Polytrope &equationOfState, const double targetMass, const PressureSurfaceConstraintView surfaceConstraint, ConstructionData constructionData ) : mfem::Operator( constructionData.layout.residual_offsets().Last(), constructionData.layout.value_offsets().Last() ), m_layout(constructionData.layout), m_gravityStateOffsets(constructionData.gravityStateOffsets), m_gravityContext( f, domainMapper ), m_gravityJacobianOperator( f, domainMapper, m_gravityContext, m_gravityStateOffsets, constructionData.gravityResidualOffsets ), m_gravityOperator( f, domainMapper, m_gravityContext, m_gravityStateOffsets, m_gravityJacobianOperator ), m_barotropicClosureOperator( f, domainMapper, equationOfState ), m_hydrostaticOperator( f, domainMapper ), m_displacementOperator( f, domainMapper, equationOfState, m_gravityContext ), m_massNormalizationOperator( f, domainMapper, m_gravityContext ), m_surfaceConstraintOperator( constructionData.pressureSurfaceRows, surfaceConstraint ), m_domainDeformation(std::move(constructionData.domainDeformation)), m_targetMass(targetMass) { MFEM_VERIFY( std::isfinite(m_targetMass) && m_targetMass > 0.0, "PreparedStellarEquilibriumOperator requires a finite, positive target mass." ); MFEM_VERIFY( Width() == m_layout.value_offsets().Last() && Height() == m_layout.residual_offsets().Last(), "PreparedStellarEquilibriumOperator has inconsistent block dimensions." ); MFEM_VERIFY( m_domainDeformation.volumeDisplacementSize() == constructionData.displacementMap.reduced_size(), "The domain-deformation output does not match the coupled displacement discretization." ); m_generatedDisplacementDependency.identity = static_cast(reinterpret_cast(&m_domainDeformation)); m_gravityState.SetSize(m_gravityStateOffsets.Last()); m_gravityDirection.SetSize(m_gravityStateOffsets.Last()); m_surfaceDeformationParameters.SetSize(m_domainDeformation.parameterCount()); m_generatedVolumeDisplacement.SetSize(m_domainDeformation.volumeDisplacementSize()); m_fullMechanicalResidual.SetSize(m_domainDeformation.volumeDisplacementSize()); m_volumeDisplacementDirection.SetSize(m_domainDeformation.volumeDisplacementSize()); m_fullMechanicalAction.SetSize(m_domainDeformation.volumeDisplacementSize()); m_surfaceShapeAction.SetSize(m_domainDeformation.parameterCount()); m_pullbackDerivativeAction.SetSize(m_domainDeformation.parameterCount()); m_gravityState = 0.0; m_gravityDirection = 0.0; m_surfaceDeformationParameters = 0.0; m_generatedVolumeDisplacement = 0.0; m_fullMechanicalResidual = 0.0; m_volumeDisplacementDirection = 0.0; m_fullMechanicalAction = 0.0; m_surfaceShapeAction = 0.0; m_pullbackDerivativeAction = 0.0; } PreparedStellarEquilibriumReport PreparedStellarEquilibriumOperator::Prepare( const mfem::Vector &state, const StellarEquilibriumDependencies &dependencies, const physics::RigidRotation &rotation ) { MFEM_VERIFY( state.Size() == Width(), "PreparedStellarEquilibriumOperator received a state with the wrong size." ); validate_finite_vector(state, "PreparedStellarEquilibriumOperator received a non-finite state."); const bool wasPrepared = m_isPrepared; if (wasPrepared) { validate_dependency_transition( m_preparedDependencies.discretization, dependencies.discretization, "The discretization revision cannot move backwards." ); validate_dependency_transition( m_preparedDependencies.density, dependencies.density, "The density revision cannot move backwards." ); validate_dependency_transition( m_preparedDependencies.surfaceDeformation, dependencies.surfaceDeformation, "The surface-deformation revision cannot move backwards." ); validate_dependency_transition( m_preparedDependencies.gravityGradient, dependencies.gravityGradient, "The gravity-gradient revision cannot move backwards." ); validate_dependency_transition( m_preparedDependencies.gravityPotential, dependencies.gravityPotential, "The gravity-potential revision cannot move backwards." ); validate_dependency_transition( m_preparedDependencies.enthalpy, dependencies.enthalpy, "The enthalpy revision cannot move backwards." ); validate_dependency_transition( m_preparedDependencies.bernoulliConstant, dependencies.bernoulliConstant, "The Bernoulli-constant revision cannot move backwards." ); validate_dependency_transition( m_preparedDependencies.rotation, dependencies.rotation, "The rotation revision cannot move backwards." ); validate_dependency_transition( m_preparedDependencies.targetMass, dependencies.targetMass, "The target-mass revision cannot move backwards." ); } m_isPrepared = false; using Form = utils::blocks::surface_deformed_stellar_equilibrium_form; constexpr auto densityValue = utils::blocks::get_value_block
(utils::blocks::density_field.mass_term); constexpr auto surfaceDeformationValue = utils::blocks::get_value_block(utils::blocks::surface_deformation_field.parameters_term); constexpr auto gravityGradientValue = utils::blocks::get_value_block(utils::blocks::gravity_field.gradient_term); constexpr auto gravityPotentialValue = utils::blocks::get_value_block(utils::blocks::gravity_field.poisson_term); constexpr auto enthalpyValue = utils::blocks::get_value_block(utils::blocks::enthalpy_field.specific_term); constexpr auto bernoulliValue = utils::blocks::get_value_block(utils::blocks::barotropic_constant_field.mass_normalization_term); const mfem::Vector reducedDensity = make_value_view(state, m_layout, densityValue); const mfem::Vector surfaceDeformationParameters = make_value_view(state, m_layout, surfaceDeformationValue); const mfem::Vector gravityGradient = make_value_view(state, m_layout, gravityGradientValue); const mfem::Vector gravityPotential = make_value_view(state, m_layout, gravityPotentialValue); const mfem::Vector reducedEnthalpy = make_value_view(state, m_layout, enthalpyValue); const mfem::Vector bernoulli = make_value_view(state, m_layout, bernoulliValue); const bool generatedGeometryChanged = !wasPrepared || dependencies.discretization != m_preparedDependencies.discretization || dependencies.surfaceDeformation != m_preparedDependencies.surfaceDeformation; PreparedStellarEquilibriumReport report; if (generatedGeometryChanged) { m_surfaceDeformationParameters = surfaceDeformationParameters; m_generatedGeometryReport = m_domainDeformation.buildValidatedVolumeDisplacement( m_surfaceDeformationParameters, m_generatedVolumeDisplacement ); ++m_generatedDisplacementDependency.revision; ++m_statistics.generatedGeometryBuilds; report.generatedVolumeDisplacement = true; } report.generatedGeometry = m_generatedGeometryReport; report.generatedDisplacement = m_generatedDisplacementDependency; pack_gravity_vector( m_gravityState, m_gravityStateOffsets, reducedDensity, m_generatedVolumeDisplacement, gravityGradient, gravityPotential ); report.gravity = m_gravityOperator.Prepare( m_gravityState, make_gravity_revisions(dependencies, m_generatedDisplacementDependency) ); report.barotropicClosure = m_barotropicClosureOperator.Prepare( {.density = reducedDensity, .enthalpy = reducedEnthalpy, .displacement = m_generatedVolumeDisplacement}, make_barotropic_closure_dependencies(dependencies, m_generatedDisplacementDependency) ); report.hydrostatic = m_hydrostaticOperator.Prepare( {.enthalpy = reducedEnthalpy, .gravityPotential = gravityPotential, .displacement = m_generatedVolumeDisplacement, .bernoulliConstant = bernoulli(0)}, make_hydrostatic_dependencies(dependencies, m_generatedDisplacementDependency), rotation ); report.displacement = m_displacementOperator.Prepare( {.enthalpy = reducedEnthalpy}, make_displacement_dependencies(dependencies, m_generatedDisplacementDependency), rotation ); report.massNormalization = m_massNormalizationOperator.Prepare( {.targetMass = m_targetMass}, make_mass_dependencies(dependencies, m_generatedDisplacementDependency) ); report.surfaceConstraint = m_surfaceConstraintOperator.Prepare( reducedEnthalpy, !wasPrepared || dependencies.enthalpy != m_preparedDependencies.enthalpy ); const bool dependenciesChanged = !wasPrepared || dependencies != m_preparedDependencies; if (dependenciesChanged || report.DidAnyChildWork()) { AssembleResidual(); report.assembledResidual = true; } m_preparedDependencies = dependencies; m_isPrepared = true; return report; } void PreparedStellarEquilibriumOperator::AssembleResidual() { using Form = utils::blocks::surface_deformed_stellar_equilibrium_form; constexpr auto gravityGradientResidual = utils::blocks::get_residual_block(utils::blocks::gravity_field.gradient_term); constexpr auto gravityPotentialResidual = utils::blocks::get_residual_block(utils::blocks::gravity_field.poisson_term); constexpr auto densityResidual = utils::blocks::get_residual_block(utils::blocks::density_field.mass_term); constexpr auto surfaceShapeResidual = utils::blocks::get_residual_block(utils::blocks::surface_deformation_field.shape_equilibrium_term); constexpr auto enthalpyResidual = utils::blocks::get_residual_block(utils::blocks::enthalpy_field.specific_term); constexpr auto massResidual = utils::blocks::get_residual_block(utils::blocks::barotropic_constant_field.mass_normalization_term); mfem::Vector gravity; mfem::Vector closure; mfem::Vector surfaceShape; mfem::Vector hydrostatic; mfem::Vector mass; m_gravityOperator.Mult(m_gravityState, gravity); m_barotropicClosureOperator.BuildResidual(closure); m_displacementOperator.BuildResidual(m_fullMechanicalResidual); surfaceShape.SetSize(m_domainDeformation.parameterCount()); m_domainDeformation.applyJacobianTranspose( m_surfaceDeformationParameters, m_fullMechanicalResidual, surfaceShape ); m_hydrostaticOperator.BuildResidual(hydrostatic); m_surfaceConstraintOperator.ApplyResidualRows(hydrostatic); m_massNormalizationOperator.BuildResidual(mass); m_cachedResidual.SetSize(Height()); m_cachedResidual = 0.0; MFEM_VERIFY( gravity.Size() == m_layout.size(gravityGradientResidual) + m_layout.size(gravityPotentialResidual), "The gravity residual has the wrong size." ); mfem::Vector gravityGradient(gravity.GetData(), m_layout.size(gravityGradientResidual)); mfem::Vector gravityPotential( gravity.GetData() + m_layout.size(gravityGradientResidual), m_layout.size(gravityPotentialResidual) ); assign_residual_block( m_cachedResidual, m_layout, gravityGradientResidual, gravityGradient, "The gravity-gradient residual has the wrong size." ); assign_residual_block( m_cachedResidual, m_layout, gravityPotentialResidual, gravityPotential, "The gravity-potential residual has the wrong size." ); assign_residual_block( m_cachedResidual, m_layout, densityResidual, closure, "The closure residual has the wrong size." ); assign_residual_block( m_cachedResidual, m_layout, surfaceShapeResidual, surfaceShape, "The surface-shape residual has the wrong size." ); assign_residual_block( m_cachedResidual, m_layout, enthalpyResidual, hydrostatic, "The hydrostatic residual has the wrong size." ); assign_residual_block( m_cachedResidual, m_layout, massResidual, mass, "The mass-normalization residual has the wrong size." ); ++m_statistics.residualAssemblies; } void PreparedStellarEquilibriumOperator::BuildResidual(mfem::Vector &residual) const { VerifyPrepared(); residual = m_cachedResidual; ++m_statistics.residualApplications; } void PreparedStellarEquilibriumOperator::Mult( const mfem::Vector &direction, mfem::Vector &action ) const { VerifyPrepared(); MFEM_VERIFY( direction.Size() == Width(), "PreparedStellarEquilibriumOperator received a Jacobian direction with the wrong size." ); validate_finite_vector( direction, "PreparedStellarEquilibriumOperator received a non-finite Jacobian direction." ); using Form = utils::blocks::surface_deformed_stellar_equilibrium_form; constexpr auto densityValue = utils::blocks::get_value_block(utils::blocks::density_field.mass_term); constexpr auto surfaceDeformationValue = utils::blocks::get_value_block(utils::blocks::surface_deformation_field.parameters_term); constexpr auto gravityGradientValue = utils::blocks::get_value_block(utils::blocks::gravity_field.gradient_term); constexpr auto gravityPotentialValue = utils::blocks::get_value_block(utils::blocks::gravity_field.poisson_term); constexpr auto enthalpyValue = utils::blocks::get_value_block(utils::blocks::enthalpy_field.specific_term); constexpr auto bernoulliValue = utils::blocks::get_value_block(utils::blocks::barotropic_constant_field.mass_normalization_term); constexpr auto gravityGradientResidual = utils::blocks::get_residual_block(utils::blocks::gravity_field.gradient_term); constexpr auto gravityPotentialResidual = utils::blocks::get_residual_block(utils::blocks::gravity_field.poisson_term); constexpr auto densityResidual = utils::blocks::get_residual_block(utils::blocks::density_field.mass_term); constexpr auto surfaceShapeResidual = utils::blocks::get_residual_block(utils::blocks::surface_deformation_field.shape_equilibrium_term); constexpr auto enthalpyResidual = utils::blocks::get_residual_block(utils::blocks::enthalpy_field.specific_term); constexpr auto massResidual = utils::blocks::get_residual_block(utils::blocks::barotropic_constant_field.mass_normalization_term); const mfem::Vector reducedDensityDirection = make_value_view(direction, m_layout, densityValue); const mfem::Vector surfaceDeformationDirection = make_value_view(direction, m_layout, surfaceDeformationValue); const mfem::Vector gravityGradientDirection = make_value_view(direction, m_layout, gravityGradientValue); const mfem::Vector gravityPotentialDirection = make_value_view(direction, m_layout, gravityPotentialValue); const mfem::Vector reducedEnthalpyDirection = make_value_view(direction, m_layout, enthalpyValue); const mfem::Vector bernoulliDirection = make_value_view(direction, m_layout, bernoulliValue); m_domainDeformation.applyJacobian( m_surfaceDeformationParameters, surfaceDeformationDirection, m_volumeDisplacementDirection ); pack_gravity_vector( m_gravityDirection, m_gravityStateOffsets, reducedDensityDirection, m_volumeDisplacementDirection, gravityGradientDirection, gravityPotentialDirection ); mfem::Vector gravityAction; mfem::Vector closureAction; mfem::Vector hydrostaticAction; mfem::Vector massAction; m_gravityJacobianOperator.Mult(m_gravityDirection, gravityAction); m_barotropicClosureOperator.Mult( reducedDensityDirection, reducedEnthalpyDirection, m_volumeDisplacementDirection, closureAction ); m_displacementOperator.ApplyCompleteJacobianAction( reducedDensityDirection, m_volumeDisplacementDirection, gravityGradientDirection, reducedEnthalpyDirection, m_fullMechanicalAction ); m_domainDeformation.applyJacobianTranspose( m_surfaceDeformationParameters, m_fullMechanicalAction, m_surfaceShapeAction ); m_domainDeformation.applyPullbackDerivative( m_surfaceDeformationParameters, surfaceDeformationDirection, m_fullMechanicalResidual, m_pullbackDerivativeAction ); m_surfaceShapeAction += m_pullbackDerivativeAction; m_hydrostaticOperator.ApplyCompleteJacobianAction( reducedEnthalpyDirection, gravityPotentialDirection, bernoulliDirection(0), m_volumeDisplacementDirection, hydrostaticAction ); m_surfaceConstraintOperator.ApplyJacobianRows(reducedEnthalpyDirection, hydrostaticAction); m_massNormalizationOperator.ApplyCompleteJacobianAction( reducedDensityDirection, m_volumeDisplacementDirection, massAction ); action.SetSize(Height()); action = 0.0; MFEM_VERIFY( gravityAction.Size() == m_layout.size(gravityGradientResidual) + m_layout.size(gravityPotentialResidual), "The gravity Jacobian action has the wrong size." ); mfem::Vector gravityGradientAction(gravityAction.GetData(), m_layout.size(gravityGradientResidual)); mfem::Vector gravityPotentialAction( gravityAction.GetData() + m_layout.size(gravityGradientResidual), m_layout.size(gravityPotentialResidual) ); assign_residual_block( action, m_layout, gravityGradientResidual, gravityGradientAction, "The gravity-gradient Jacobian action has the wrong size." ); assign_residual_block( action, m_layout, gravityPotentialResidual, gravityPotentialAction, "The gravity-potential Jacobian action has the wrong size." ); assign_residual_block( action, m_layout, densityResidual, closureAction, "The closure Jacobian action has the wrong size." ); assign_residual_block( action, m_layout, surfaceShapeResidual, m_surfaceShapeAction, "The surface-shape Jacobian action has the wrong size." ); assign_residual_block( action, m_layout, enthalpyResidual, hydrostaticAction, "The hydrostatic Jacobian action has the wrong size." ); assign_residual_block( action, m_layout, massResidual, massAction, "The mass-normalization Jacobian action has the wrong size." ); ++m_statistics.jacobianApplications; } bool PreparedStellarEquilibriumOperator::IsPrepared() const noexcept { return m_isPrepared && m_gravityContext.IsPrepared() && m_barotropicClosureOperator.IsPrepared() && m_hydrostaticOperator.IsPrepared() && m_displacementOperator.IsPrepared() && m_massNormalizationOperator.IsPrepared() && m_surfaceConstraintOperator.IsPrepared(); } double PreparedStellarEquilibriumOperator::GetTargetMass() const noexcept { return m_targetMass; } const StellarEquilibriumLayout &PreparedStellarEquilibriumOperator::GetLayout() const noexcept { return m_layout; } const StellarEquilibriumDependencies &PreparedStellarEquilibriumOperator::GetDependencies() const { VerifyPrepared(); return m_preparedDependencies; } const PreparedStellarEquilibriumStatistics &PreparedStellarEquilibriumOperator::GetStatistics() const noexcept { return m_statistics; } const context::gravity_field::GravityFieldLinearizationContext & PreparedStellarEquilibriumOperator::GetGravityContext() const noexcept { return m_gravityContext; } const GravityFieldOperator &PreparedStellarEquilibriumOperator::GetGravityOperator() const noexcept { return m_gravityOperator; } const GravityFieldJacobianOperator & PreparedStellarEquilibriumOperator::GetGravityJacobianOperator() const noexcept { return m_gravityJacobianOperator; } const PreparedBarotropicClosureOperator & PreparedStellarEquilibriumOperator::GetBarotropicClosureOperator() const noexcept { return m_barotropicClosureOperator; } const context::barotropic::BarotropicClosureLinearizationContext & PreparedStellarEquilibriumOperator::GetBarotropicClosureContext() const noexcept { return m_barotropicClosureOperator.GetContext(); } const PreparedHydrostaticEquilibriumOperator & PreparedStellarEquilibriumOperator::GetHydrostaticOperator() const noexcept { return m_hydrostaticOperator; } const PreparedDisplacementResidualOperator & PreparedStellarEquilibriumOperator::GetDisplacementOperator() const noexcept { return m_displacementOperator; } const PreparedMassNormalizationOperator & PreparedStellarEquilibriumOperator::GetMassNormalizationOperator() const noexcept { return m_massNormalizationOperator; } const PreparedPressureSurfaceConstraint & PreparedStellarEquilibriumOperator::GetSurfaceConstraintOperator() const noexcept { return m_surfaceConstraintOperator; } const deformation::PreparedDomainDeformationRuntime & PreparedStellarEquilibriumOperator::GetDomainDeformation() const noexcept { return m_domainDeformation; } const mfem::Vector &PreparedStellarEquilibriumOperator::GetSurfaceDeformationParameters() const { VerifyPrepared(); return m_surfaceDeformationParameters; } const mfem::Vector &PreparedStellarEquilibriumOperator::GetGeneratedVolumeDisplacement() const { VerifyPrepared(); return m_generatedVolumeDisplacement; } const mfem::Vector &PreparedStellarEquilibriumOperator::GetFullMechanicalResidual() const { VerifyPrepared(); return m_fullMechanicalResidual; } const StellarEquilibriumDependencyStamp & PreparedStellarEquilibriumOperator::GetGeneratedDisplacementDependency() const { VerifyPrepared(); return m_generatedDisplacementDependency; } void PreparedStellarEquilibriumOperator::VerifyPrepared() const { MFEM_VERIFY( IsPrepared(), "PreparedStellarEquilibriumOperator must be prepared before residual or Jacobian application." ); } } // namespace mean_field::operators