834 lines
36 KiB
C++
834 lines
36 KiB
C++
module;
|
|
|
|
#include <array>
|
|
#include <cmath>
|
|
#include <cstdint>
|
|
#include <utility>
|
|
|
|
#include <mfem.hpp>
|
|
|
|
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."
|
|
);
|
|
}
|
|
|
|
using StellarRootForm = mean_field::utils::blocks::surface_deformed_stellar_equilibrium_form;
|
|
|
|
[[nodiscard]] std::array<
|
|
int,
|
|
StellarRootForm::value_block_count>
|
|
make_value_sizes(
|
|
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
|
|
) {
|
|
return {densityMap.reduced_size(), surfaceDeformationParameterCount, gravityFluxMap.reduced_size(),
|
|
gravityPotentialMap.reduced_size(), enthalpyMap.reduced_size(), 1};
|
|
}
|
|
|
|
[[nodiscard]] std::array<
|
|
int,
|
|
StellarRootForm::residual_block_count>
|
|
make_residual_sizes(
|
|
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
|
|
) {
|
|
return {gravityFluxMap.reduced_size(), gravityPotentialMap.reduced_size(), densityMap.reduced_size(),
|
|
surfaceDeformationParameterCount, enthalpyMap.reduced_size(), 1};
|
|
}
|
|
|
|
[[nodiscard]] mfem::Array<int> 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<int> 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<int> make_gravity_residual_offsets(
|
|
const mean_field::field::FieldDofMap &gravityFluxMap,
|
|
const mean_field::field::FieldDofMap &gravityPotentialMap
|
|
) {
|
|
mfem::Array<int> offsets(3);
|
|
offsets[0] = 0;
|
|
offsets[1] = gravityFluxMap.reduced_size();
|
|
offsets[2] = offsets[1] + gravityPotentialMap.reduced_size();
|
|
return offsets;
|
|
}
|
|
|
|
void assign_gravity_block(
|
|
mfem::Vector &gravityState,
|
|
const mfem::Array<int> &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<int> &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;
|
|
|
|
std::array<int, StellarRootForm::value_block_count> valueSizes;
|
|
std::array<int, StellarRootForm::residual_block_count> residualSizes;
|
|
mfem::Array<int> gravityStateOffsets;
|
|
mfem::Array<int> 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
|
|
)
|
|
),
|
|
valueSizes(make_value_sizes(
|
|
densityMap,
|
|
domainDeformation.parameterCount(),
|
|
gravityFluxMap,
|
|
gravityPotentialMap,
|
|
enthalpyMap
|
|
)),
|
|
residualSizes(make_residual_sizes(
|
|
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,
|
|
models::CompiledFixedMass fixedMassConstraint,
|
|
const PressureSurfaceConstraintView surfaceConstraint,
|
|
deformation::PreparedDomainDeformationRuntime domainDeformation
|
|
)
|
|
: PreparedStellarEquilibriumOperator(
|
|
f,
|
|
domainMapper,
|
|
equationOfState,
|
|
std::move(fixedMassConstraint),
|
|
surfaceConstraint,
|
|
MakeConstructionData(
|
|
f,
|
|
std::move(domainDeformation)
|
|
)
|
|
) {
|
|
}
|
|
|
|
PreparedStellarEquilibriumOperator::PreparedStellarEquilibriumOperator(
|
|
fem::FEM &f,
|
|
const mapping::DomainMapper &domainMapper,
|
|
const eos::Polytrope &equationOfState,
|
|
models::CompiledFixedMass fixedMassConstraint,
|
|
const PressureSurfaceConstraintView surfaceConstraint,
|
|
ConstructionData constructionData
|
|
)
|
|
: mfem::Operator(
|
|
StellarEquilibriumLayout(
|
|
constructionData.valueSizes,
|
|
constructionData.residualSizes
|
|
)
|
|
.residual_offsets()
|
|
.Last(),
|
|
StellarEquilibriumLayout(
|
|
constructionData.valueSizes,
|
|
constructionData.residualSizes
|
|
)
|
|
.value_offsets()
|
|
.Last()
|
|
),
|
|
m_rootManifest(
|
|
constructionData.valueSizes,
|
|
constructionData.residualSizes,
|
|
fixedMassConstraint.targetMass().value(),
|
|
surfaceConstraint.descriptor().targetPressure,
|
|
constructionData.pressureSurfaceRows.size()
|
|
),
|
|
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_fixedMassConstraint(std::move(fixedMassConstraint)) {
|
|
|
|
MFEM_VERIFY(
|
|
Width() == m_rootManifest.layout().value_offsets().Last() &&
|
|
Height() == m_rootManifest.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<std::uint64_t>(reinterpret_cast<std::uintptr_t>(&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;
|
|
|
|
const auto rootState = m_rootManifest.stateView(state);
|
|
|
|
const mfem::Vector reducedDensity = rootState.block(utils::blocks::density_field.mass_term);
|
|
const mfem::Vector surfaceDeformationParameters =
|
|
rootState.block(utils::blocks::surface_deformation_field.parameters_term);
|
|
const mfem::Vector gravityGradient = rootState.block(utils::blocks::gravity_field.gradient_term);
|
|
const mfem::Vector gravityPotential = rootState.block(utils::blocks::gravity_field.poisson_term);
|
|
const mfem::Vector reducedEnthalpy = rootState.block(utils::blocks::enthalpy_field.specific_term);
|
|
const mfem::Vector bernoulli =
|
|
rootState.block(utils::blocks::fixed_total_mass_constraint.mass_normalization_term);
|
|
|
|
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(
|
|
m_fixedMassConstraint, 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() {
|
|
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;
|
|
const auto residualView = m_rootManifest.residualView(m_cachedResidual);
|
|
|
|
MFEM_VERIFY(
|
|
gravity.Size() == residualView.block(utils::blocks::gravity_field.gradient_term).Size() +
|
|
residualView.block(utils::blocks::gravity_field.poisson_term).Size(),
|
|
"The gravity residual has the wrong size."
|
|
);
|
|
|
|
mfem::Vector gravityGradient(
|
|
gravity.GetData(), residualView.block(utils::blocks::gravity_field.gradient_term).Size()
|
|
);
|
|
mfem::Vector gravityPotential(
|
|
gravity.GetData() + gravityGradient.Size(),
|
|
residualView.block(utils::blocks::gravity_field.poisson_term).Size()
|
|
);
|
|
|
|
residualView.assign(utils::blocks::gravity_field.gradient_term, gravityGradient);
|
|
residualView.assign(utils::blocks::gravity_field.poisson_term, gravityPotential);
|
|
residualView.assign(utils::blocks::density_field.mass_term, closure);
|
|
residualView.assign(utils::blocks::surface_deformation_field.shape_equilibrium_term, surfaceShape);
|
|
residualView.assign(utils::blocks::enthalpy_field.specific_term, hydrostatic);
|
|
residualView.assign(utils::blocks::fixed_total_mass_constraint.mass_normalization_term, mass);
|
|
|
|
++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."
|
|
);
|
|
|
|
const auto rootDirection = m_rootManifest.directionView(direction);
|
|
|
|
const mfem::Vector reducedDensityDirection = rootDirection.block(utils::blocks::density_field.mass_term);
|
|
const mfem::Vector surfaceDeformationDirection =
|
|
rootDirection.block(utils::blocks::surface_deformation_field.parameters_term);
|
|
const mfem::Vector gravityGradientDirection = rootDirection.block(utils::blocks::gravity_field.gradient_term);
|
|
const mfem::Vector gravityPotentialDirection = rootDirection.block(utils::blocks::gravity_field.poisson_term);
|
|
const mfem::Vector reducedEnthalpyDirection = rootDirection.block(utils::blocks::enthalpy_field.specific_term);
|
|
const mfem::Vector bernoulliDirection =
|
|
rootDirection.block(utils::blocks::fixed_total_mass_constraint.mass_normalization_term);
|
|
|
|
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;
|
|
const auto actionView = m_rootManifest.residualView(action);
|
|
|
|
MFEM_VERIFY(
|
|
gravityAction.Size() == actionView.block(utils::blocks::gravity_field.gradient_term).Size() +
|
|
actionView.block(utils::blocks::gravity_field.poisson_term).Size(),
|
|
"The gravity Jacobian action has the wrong size."
|
|
);
|
|
|
|
mfem::Vector gravityGradientAction(
|
|
gravityAction.GetData(), actionView.block(utils::blocks::gravity_field.gradient_term).Size()
|
|
);
|
|
mfem::Vector gravityPotentialAction(
|
|
gravityAction.GetData() + gravityGradientAction.Size(),
|
|
actionView.block(utils::blocks::gravity_field.poisson_term).Size()
|
|
);
|
|
|
|
actionView.assign(utils::blocks::gravity_field.gradient_term, gravityGradientAction);
|
|
actionView.assign(utils::blocks::gravity_field.poisson_term, gravityPotentialAction);
|
|
actionView.assign(utils::blocks::density_field.mass_term, closureAction);
|
|
actionView.assign(utils::blocks::surface_deformation_field.shape_equilibrium_term, m_surfaceShapeAction);
|
|
actionView.assign(utils::blocks::enthalpy_field.specific_term, hydrostaticAction);
|
|
actionView.assign(utils::blocks::fixed_total_mass_constraint.mass_normalization_term, massAction);
|
|
|
|
++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_fixedMassConstraint.targetMass().value();
|
|
}
|
|
|
|
const StellarEquilibriumLayout &PreparedStellarEquilibriumOperator::GetLayout() const noexcept {
|
|
return m_rootManifest.layout();
|
|
}
|
|
|
|
const StellarEquilibriumRootManifest &PreparedStellarEquilibriumOperator::GetRootManifest() const noexcept {
|
|
return m_rootManifest;
|
|
}
|
|
|
|
RootStateView<utils::blocks::surface_deformed_stellar_equilibrium_form>
|
|
PreparedStellarEquilibriumOperator::GetRootStateView(const mfem::Vector &state) const {
|
|
return m_rootManifest.stateView(state);
|
|
}
|
|
|
|
ResidualView<utils::blocks::surface_deformed_stellar_equilibrium_form>
|
|
PreparedStellarEquilibriumOperator::GetResidualView(mfem::Vector &residual) const {
|
|
return m_rootManifest.residualView(residual);
|
|
}
|
|
|
|
RootConstraintReport PreparedStellarEquilibriumOperator::GetFixedMassReport() const {
|
|
VerifyPrepared();
|
|
return m_rootManifest.fixedMassReport(m_massNormalizationOperator.GetCurrentMass());
|
|
}
|
|
|
|
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
|