Files
MeanField/libmeanfield/impl/operators/prepared_central_density_stellar_equilibrium.cpp

224 lines
9.8 KiB
C++

module;
#include <array>
#include <cmath>
#include <cstdint>
#include <memory>
#include <utility>
#include <mfem.hpp>
module mean_field;
import :operators.prepared_central_density_stellar_equilibrium;
namespace {
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
using PhysicalForm = mean_field::utils::blocks::surface_deformed_stellar_equilibrium_form;
using BorderedForm = mean_field::operators::CentralDensityStellarEquilibriumForm;
[[nodiscard]] std::array<
int,
BorderedForm::value_block_count>
make_value_sizes(const mean_field::operators::StellarEquilibriumLayout &physicalLayout) {
std::array<int, BorderedForm::value_block_count> sizes{};
for (int block = 0; block < PhysicalForm::value_block_count; ++block) {
sizes[block] = physicalLayout.value_offsets()[block + 1] - physicalLayout.value_offsets()[block];
}
sizes[PhysicalForm::value_block_count] = 1;
return sizes;
}
[[nodiscard]] std::array<
int,
BorderedForm::residual_block_count>
make_residual_sizes(const mean_field::operators::StellarEquilibriumLayout &physicalLayout) {
std::array<int, BorderedForm::residual_block_count> sizes{};
for (int block = 0; block < PhysicalForm::residual_block_count; ++block) {
sizes[block] = physicalLayout.residual_offsets()[block + 1] - physicalLayout.residual_offsets()[block];
}
sizes[PhysicalForm::residual_block_count] = 1;
return sizes;
}
[[nodiscard]] mean_field::operators::CentralDensityDependencies
make_phase_dependencies(const mean_field::operators::StellarEquilibriumDependencies &dependencies) {
return {.enthalpy = {.identity = dependencies.enthalpy.identity, .revision = dependencies.enthalpy.revision}};
}
void validate_finite_scalar(
const double value,
const char *message
) {
MFEM_VERIFY(std::isfinite(value), message);
}
} // namespace
namespace mean_field::operators {
field::FieldPointDofMap PreparedCentralDensityStellarEquilibriumOperator::MakeCenterDofMap(const fem::FEM &f) {
MFEM_VERIFY(
f.mesh != nullptr && f.enthalpyFes != nullptr,
"The central-density phase requires the mesh and enthalpy finite-element space."
);
const field::FieldDofMap enthalpyMap = field::make_field_dof_map<field::Enthalpy, DomainSchema>(*f.enthalpyFes);
mfem::Vector origin(f.mesh->SpaceDimension());
origin = 0.0;
return field::make_field_point_dof_map<field::Enthalpy>(*f.enthalpyFes, enthalpyMap, origin, 1.0e-12);
}
PreparedCentralDensityStellarEquilibriumOperator::PreparedCentralDensityStellarEquilibriumOperator(
fem::FEM &f,
std::unique_ptr<PreparedStellarEquilibriumOperator> physicalOperator,
models::CompiledFixedCentralDensity centralDensity,
field::FieldPointDofMap centerDof
)
: mfem::Operator(
physicalOperator->Height() + 1,
physicalOperator->Width() + 1
),
m_physicalOperator(std::move(physicalOperator)),
m_centralDensity(std::move(centralDensity)),
m_phaseConstraint(
std::move(centerDof),
f.mesh->GetComm()
),
m_rootManifest(
make_value_sizes(m_physicalOperator->GetLayout()),
make_residual_sizes(m_physicalOperator->GetLayout()),
m_physicalOperator->GetTargetMass(),
m_physicalOperator->GetSurfaceConstraintOperator().GetPhysicalCondition().targetPressure,
m_physicalOperator->GetSurfaceConstraintOperator().GetSurfaceRows().size(),
CentralDensityManifestInput{
.targetDensity = m_centralDensity.targetDensity().value(),
.targetEnthalpy = m_centralDensity.targetEnthalpy().value(),
.centerDofCount = 1
}
) {
MFEM_VERIFY(
Width() == m_rootManifest.layout().value_offsets().Last() &&
Height() == m_rootManifest.layout().residual_offsets().Last(),
"The central-density bordered root has inconsistent dimensions."
);
}
PreparedCentralDensityStellarEquilibriumReport PreparedCentralDensityStellarEquilibriumOperator::Prepare(
const mfem::Vector &state,
const StellarEquilibriumDependencies &dependencies,
const physics::RigidRotation &rotation
) {
MFEM_VERIFY(state.Size() == Width(), "The central-density bordered root received a state with the wrong size.");
const auto stateView = m_rootManifest.stateView(state);
const mfem::Vector enthalpy = stateView.block(utils::blocks::enthalpy_field.specific_term);
const mfem::Vector border = stateView.block(utils::blocks::fixed_central_density_phase.central_value_term);
validate_finite_scalar(border(0), "The central-density bordered root received a non-finite border value.");
mfem::Vector physicalState(const_cast<mfem::real_t *>(state.GetData()), m_physicalOperator->Width());
m_isPrepared = false;
PreparedCentralDensityStellarEquilibriumReport report;
report.physical = m_physicalOperator->Prepare(physicalState, dependencies, rotation);
report.phase =
m_phaseConstraint.Prepare(m_centralDensity, enthalpy, border(0), make_phase_dependencies(dependencies));
if (report.physical.assembledResidual || report.phase.DidAnyWork() || m_cachedResidual.Size() != Height()) {
AssembleResidual();
report.assembledResidual = true;
}
m_isPrepared = true;
return report;
}
void PreparedCentralDensityStellarEquilibriumOperator::AssembleResidual() {
mfem::Vector physicalResidual;
m_physicalOperator->BuildResidual(physicalResidual);
m_cachedResidual.SetSize(Height());
m_cachedResidual = 0.0;
mfem::Vector physicalDestination(m_cachedResidual.GetData(), physicalResidual.Size());
physicalDestination = physicalResidual;
const auto residualView = m_rootManifest.residualView(m_cachedResidual);
mfem::Vector enthalpyResidual = residualView.block(utils::blocks::enthalpy_field.specific_term);
mfem::Vector phaseResidual = residualView.block(utils::blocks::fixed_central_density_phase.central_value_term);
m_phaseConstraint.AddResidual(enthalpyResidual, phaseResidual);
}
void PreparedCentralDensityStellarEquilibriumOperator::BuildResidual(mfem::Vector &residual) const {
VerifyPrepared();
residual = m_cachedResidual;
}
void PreparedCentralDensityStellarEquilibriumOperator::Mult(
const mfem::Vector &direction,
mfem::Vector &action
) const {
VerifyPrepared();
MFEM_VERIFY(
direction.Size() == Width(), "The central-density bordered root received a direction with the wrong size."
);
const auto directionView = m_rootManifest.directionView(direction);
const mfem::Vector enthalpyDirection = directionView.block(utils::blocks::enthalpy_field.specific_term);
const mfem::Vector borderDirection =
directionView.block(utils::blocks::fixed_central_density_phase.central_value_term);
validate_finite_scalar(
borderDirection(0), "The central-density bordered root received a non-finite border direction."
);
mfem::Vector physicalDirection(const_cast<mfem::real_t *>(direction.GetData()), m_physicalOperator->Width());
mfem::Vector physicalAction;
m_physicalOperator->Mult(physicalDirection, physicalAction);
action.SetSize(Height());
action = 0.0;
mfem::Vector physicalDestination(action.GetData(), physicalAction.Size());
physicalDestination = physicalAction;
const auto actionView = m_rootManifest.residualView(action);
mfem::Vector enthalpyAction = actionView.block(utils::blocks::enthalpy_field.specific_term);
mfem::Vector phaseAction = actionView.block(utils::blocks::fixed_central_density_phase.central_value_term);
m_phaseConstraint.ApplyJacobian(
{.enthalpyVariation = enthalpyDirection, .borderVariation = borderDirection(0)},
{.enthalpyAction = enthalpyAction, .phaseAction = phaseAction}
);
}
bool PreparedCentralDensityStellarEquilibriumOperator::IsPrepared() const noexcept {
return m_isPrepared && m_physicalOperator->IsPrepared() && m_phaseConstraint.IsPrepared();
}
const CentralDensityStellarEquilibriumLayout &
PreparedCentralDensityStellarEquilibriumOperator::GetLayout() const noexcept {
return m_rootManifest.layout();
}
const CentralDensityStellarEquilibriumRootManifest &
PreparedCentralDensityStellarEquilibriumOperator::GetRootManifest() const noexcept {
return m_rootManifest;
}
const PreparedStellarEquilibriumOperator &
PreparedCentralDensityStellarEquilibriumOperator::GetPhysicalOperator() const noexcept {
return *m_physicalOperator;
}
const PreparedCentralDensityConstraint &
PreparedCentralDensityStellarEquilibriumOperator::GetCentralDensityConstraint() const noexcept {
return m_phaseConstraint;
}
RootConstraintReport PreparedCentralDensityStellarEquilibriumOperator::GetFixedMassReport() const {
VerifyPrepared();
return m_physicalOperator->GetFixedMassReport();
}
CentralDensityConstraintReport PreparedCentralDensityStellarEquilibriumOperator::GetCentralDensityReport() const {
VerifyPrepared();
return m_phaseConstraint.GetConstraintReport();
}
void PreparedCentralDensityStellarEquilibriumOperator::VerifyPrepared() const {
MFEM_VERIFY(IsPrepared(), "The central-density bordered root must be prepared before application.");
}
} // namespace mean_field::operators