Add native spherical harmonic surface coordinates to coupled equilibrium

This commit is contained in:
2026-09-19 08:51:42 -04:00
parent 2171b8b76a
commit 7b0eb8d92d
23 changed files with 3131 additions and 57 deletions

View File

@@ -17,6 +17,8 @@ module;
export module mean_field:preconditioning.material_surface;
import :deformation.surface_metric;
export import :operators.prepared_stellar_equilibrium;
export import :operators.stellar_equilibrium_problem;
export import :preconditioning.backend_implementations;
@@ -1440,6 +1442,14 @@ export namespace mean_field::preconditioning {
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
const fem::FEM &finiteElements = operation.GetHydrostaticOperator().GetFEM();
if (!operation.GetDomainDeformation().hasNodalRadialParameters()) {
// The inverse acts on the parameter dual, not an ambient
// nodal trace. Keep the existing diagonal approximation but
// form it in the prescription's actual coordinate space.
return deformation::assembleSurfaceParameterMassDiagonal(
finiteElements, operation.GetDomainDeformation()
);
}
MFEM_VERIFY(
finiteElements.mesh != nullptr && finiteElements.surfaceDeformationFes != nullptr,
"The material/free-surface Riesz surrogate requires the surface finite-element space."
@@ -1492,10 +1502,26 @@ export namespace mean_field::preconditioning {
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
const fem::FEM &finiteElements = m_operation->GetHydrostaticOperator().GetFEM();
const field::ScalarBoundaryDofMap surfaceMap =
field::make_stellar_surface_scalar_dof_map<DomainSchema>(*finiteElements.surfaceDeformationFes);
if (surfaceMap.local_size() != m_surfaceDiagonal.Size()) {
throw std::logic_error("Surface Riesz calibration received an incompatible boundary coordinate map.");
const bool nodal = m_operation->GetDomainDeformation().hasNodalRadialParameters();
field::ScalarBoundaryDofMap surfaceMap;
if (nodal) {
surfaceMap =
field::make_stellar_surface_scalar_dof_map<DomainSchema>(*finiteElements.surfaceDeformationFes);
if (surfaceMap.local_size() != m_surfaceDiagonal.Size()) {
throw std::logic_error(
"Surface Riesz calibration received an incompatible boundary coordinate map."
);
}
} else {
int ranks = 0;
if (MPI_Comm_size(Communicator(*m_operation), &ranks) != MPI_SUCCESS || ranks != 1) {
throw std::invalid_argument(
"Surface parameter calibration currently requires one MPI rank for nonnodal coordinates."
);
}
if (m_surfaceDiagonal.Size() != m_operation->GetDomainDeformation().parameterCount()) {
throw std::logic_error("Surface Riesz calibration received an incompatible parameter metric.");
}
}
mfem::Vector probe(m_surfaceDiagonal.Size());
@@ -1513,7 +1539,11 @@ export namespace mean_field::preconditioning {
double localDenominator = 0.0;
for (int sample = 0; sample < calibration.probeCount; ++sample) {
for (int index = 0; index < probe.Size(); ++index) {
std::uint64_t value = static_cast<std::uint64_t>(surfaceMap.global_boundary_dof(index));
// Preserve nodal probes exactly. Nonnodal serial probes
// use the immutable ordered parameter index instead of
// pretending that each coefficient owns a boundary node.
std::uint64_t value =
static_cast<std::uint64_t>(nodal ? surfaceMap.global_boundary_dof(index) : index);
value += 0x9e3779b97f4a7c15ULL * static_cast<std::uint64_t>(sample + 1);
value = (value ^ (value >> 30U)) * 0xbf58476d1ce4e5b9ULL;
value = (value ^ (value >> 27U)) * 0x94d049bb133111ebULL;
@@ -1871,6 +1901,12 @@ export namespace mean_field::preconditioning {
[[nodiscard]] static field::ScalarBoundaryDofMap
SurfaceMap(const operators::PreparedStellarEquilibriumOperator &operation) {
if (!operation.GetDomainDeformation().hasNodalRadialParameters()) {
throw std::invalid_argument(
"SurfaceH1MassStiffness requires nodal radial parameters; a parameter-space H1 surrogate "
"has not been implemented for this surface prescription."
);
}
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
const fem::FEM &finiteElements = operation.GetHydrostaticOperator().GetFEM();
return field::make_stellar_surface_scalar_dof_map<DomainSchema>(*finiteElements.surfaceDeformationFes);