Snapshot optimized solver and audit diagnostics before numerical experiments

This commit is contained in:
2026-09-16 14:34:06 -04:00
parent 75cc638739
commit 80cc3d83d7
64 changed files with 11969 additions and 267 deletions

View File

@@ -1,6 +1,7 @@
module;
#include <concepts>
#include <mpi.h>
#include <cstdint>
#include <expected>
#include <memory>
@@ -22,9 +23,45 @@ export import :utils.domain;
namespace mean_field::normalization::detail {
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
[[nodiscard]] inline bool CanAssembleExactPartialDiagonal(mfem::ParFiniteElementSpace &space, bool hdiv) {
// For hanging nodes, diag(P^T A P) contains cross terms. MFEM's PA
// diagonal is approximate there, so retain assembled exact diagonals.
int eligible = space.GetMesh()->Conforming() && !space.IsVariableOrder() && space.GetVDim() == 1;
for (int e = 0; eligible && e < space.GetNE(); ++e) {
const auto *fe = space.GetFE(e);
eligible = fe->GetGeomType() == mfem::Geometry::CUBE &&
(hdiv ? dynamic_cast<const mfem::RT_HexahedronElement *>(fe) != nullptr :
dynamic_cast<const mfem::NodalTensorFiniteElement *>(fe) != nullptr);
}
int allEligible = 0;
if (MPI_Allreduce(&eligible, &allEligible, 1, MPI_INT, MPI_MIN, space.GetComm()) != MPI_SUCCESS)
throw std::runtime_error("Could not choose a collective normalization assembly path.");
return allEligible != 0;
}
[[nodiscard]] inline mfem::Vector AssembleMassDiagonal(
mfem::ParBilinearForm &mass, mfem::ParFiniteElementSpace &space, bool partial
) {
if (partial) {
mass.SetAssemblyLevel(mfem::AssemblyLevel::PARTIAL);
mass.Assemble();
mfem::Vector diagonal(space.GetTrueVSize());
mass.AssembleDiagonal(diagonal);
return diagonal;
}
mass.Assemble();
mass.Finalize();
std::unique_ptr<mfem::HypreParMatrix> matrix(mass.ParallelAssemble());
if (!matrix) throw std::runtime_error("Reference Riesz mass assembly failed.");
mfem::Vector diagonal;
matrix->GetDiag(diagonal);
return diagonal;
}
[[nodiscard]] inline mfem::Vector AssembleScalarMassDiagonal(
mfem::ParFiniteElementSpace &space,
mfem::Array<int> *domainMarker = nullptr
mfem::Array<int> *domainMarker = nullptr,
bool reference = false
) {
mfem::ParBilinearForm mass(&space);
if (domainMarker == nullptr) {
@@ -32,34 +69,80 @@ namespace mean_field::normalization::detail {
} else {
mass.AddDomainIntegrator(new mfem::MassIntegrator(), *domainMarker);
}
mass.Assemble();
mass.Finalize();
std::unique_ptr<mfem::HypreParMatrix> matrix(mass.ParallelAssemble());
if (matrix == nullptr) {
throw std::runtime_error("Reference scalar Riesz mass assembly failed.");
}
mfem::Vector diagonal;
matrix->GetDiag(diagonal);
return diagonal;
return AssembleMassDiagonal(mass, space, !reference && CanAssembleExactPartialDiagonal(space, false));
}
[[nodiscard]] inline mfem::Vector AssembleHDivMassDiagonal(mfem::ParFiniteElementSpace &space) {
[[nodiscard]] inline mfem::Vector AssembleHDivMassDiagonal(mfem::ParFiniteElementSpace &space, bool reference = false) {
mfem::ParBilinearForm mass(&space);
mass.AddDomainIntegrator(new mfem::VectorFEMassIntegrator());
mass.Assemble();
mass.Finalize();
std::unique_ptr<mfem::HypreParMatrix> matrix(mass.ParallelAssemble());
if (matrix == nullptr) {
throw std::runtime_error("Reference H(div) Riesz mass assembly failed.");
return AssembleMassDiagonal(mass, space, !reference && CanAssembleExactPartialDiagonal(space, true));
}
[[nodiscard]] inline bool CanAssembleDirectBoundaryDiagonal(
mfem::ParFiniteElementSpace &space, int attribute
) {
int eligible = !space.Nonconforming() && !space.IsVariableOrder() && space.GetVDim() == 1 &&
dynamic_cast<const mfem::H1_FECollection *>(space.FEColl()) != nullptr;
mfem::Array<int> dofs;
for (int b = 0; eligible && b < space.GetNBE(); ++b) {
if (space.GetBdrAttribute(b) != attribute) continue;
// A general DOF transformation would require transforming the
// full element matrix before extracting its diagonal.
eligible = space.GetBdrElementVDofs(b, dofs) == nullptr;
}
mfem::Vector diagonal;
matrix->GetDiag(diagonal);
return diagonal;
int allEligible = 0;
if (MPI_Allreduce(&eligible, &allEligible, 1, MPI_INT, MPI_MIN, space.GetComm()) != MPI_SUCCESS)
throw std::runtime_error("Could not choose a collective surface normalization assembly path.");
return allEligible != 0;
}
[[nodiscard]] inline mfem::Vector AssembleDirectBoundaryDiagonal(
mfem::ParFiniteElementSpace &space, int attribute
) {
mfem::Vector localDiagonal(space.GetVSize());
localDiagonal = 0.0;
mfem::Array<int> dofs;
mfem::Vector shape, elementDiagonal;
// GetNBE includes tagged internal interfaces. MFEM's boundary PA face
// restriction uses FaceType::Boundary and omits the star/vacuum interface.
for (int b = 0; b < space.GetNBE(); ++b) {
if (space.GetBdrAttribute(b) != attribute) continue;
const auto &element = *space.GetBE(b);
auto &transformation = *space.GetBdrElementTransformation(b);
space.GetBdrElementVDofs(b, dofs);
shape.SetSize(element.GetDof());
elementDiagonal.SetSize(element.GetDof());
elementDiagonal = 0.0;
// Identical rule and physical shapes to MassIntegrator's default
// element assembly; only the diagonal of w * shape * shape^T is formed.
const auto &rule = mfem::MassIntegrator::GetRule(element, element, transformation);
for (int q = 0; q < rule.GetNPoints(); ++q) {
const auto &point = rule.IntPoint(q);
transformation.SetIntPoint(&point);
element.CalcPhysShape(transformation, shape);
const double weight = transformation.Weight() * point.weight;
for (int i = 0; i < element.GetDof(); ++i)
elementDiagonal(i) += weight * shape(i) * shape(i);
}
for (int i = 0; i < dofs.Size(); ++i) {
const int dof = dofs[i] < 0 ? -1 - dofs[i] : dofs[i];
localDiagonal(dof) += elementDiagonal(i); // orientation signs are squared
}
}
mfem::Vector trueDiagonal(space.GetTrueVSize());
// Conforming H1 prolongation only copies scalar DOFs, so summing the
// local diagonal gives diag(P^T A P) exactly, including shared DOFs.
if (const auto *prolongation = space.GetProlongationMatrix())
prolongation->MultTranspose(localDiagonal, trueDiagonal);
else
trueDiagonal = localDiagonal;
return trueDiagonal;
}
[[nodiscard]] inline mfem::Vector AssembleSurfaceMassDiagonal(
const fem::FEM &finiteElements,
const field::ScalarBoundaryDofMap &surfaceMap
const field::ScalarBoundaryDofMap &surfaceMap,
bool reference = false
) {
mfem::Array<int> marker(finiteElements.mesh->bdr_attributes.Max());
marker = 0;
@@ -69,16 +152,12 @@ namespace mean_field::normalization::detail {
}
marker[attribute - 1] = 1;
if (!reference && CanAssembleDirectBoundaryDiagonal(*finiteElements.surfaceDeformationFes, attribute))
return surfaceMap.gather(AssembleDirectBoundaryDiagonal(*finiteElements.surfaceDeformationFes, attribute));
mfem::ParBilinearForm mass(finiteElements.surfaceDeformationFes.get());
mass.AddBoundaryIntegrator(new mfem::MassIntegrator(), marker);
mass.Assemble();
mass.Finalize();
std::unique_ptr<mfem::HypreParMatrix> matrix(mass.ParallelAssemble());
if (matrix == nullptr) {
throw std::runtime_error("Reference surface Riesz mass assembly failed.");
}
mfem::Vector ambientDiagonal;
matrix->GetDiag(ambientDiagonal);
auto ambientDiagonal = AssembleMassDiagonal(mass, *finiteElements.surfaceDeformationFes, false);
return surfaceMap.gather(ambientDiagonal);
}
@@ -100,6 +179,19 @@ namespace mean_field::normalization::detail {
} // namespace mean_field::normalization::detail
export namespace mean_field::normalization {
// Isolated verification/profiling entry points. reference=true retains the
// full assembled true-DOF diagonal; production uses exact PA for supported
// volume spaces and direct marked-boundary quadrature for supported surfaces.
[[nodiscard]] inline mfem::Vector AssembleReferenceScalarMassDiagonal(
mfem::ParFiniteElementSpace &space, mfem::Array<int> *domainMarker = nullptr, bool reference = false
) { return detail::AssembleScalarMassDiagonal(space, domainMarker, reference); }
[[nodiscard]] inline mfem::Vector AssembleReferenceHDivMassDiagonal(
mfem::ParFiniteElementSpace &space, bool reference = false
) { return detail::AssembleHDivMassDiagonal(space, reference); }
[[nodiscard]] inline mfem::Vector AssembleReferenceSurfaceMassDiagonal(
const fem::FEM &finiteElements, const field::ScalarBoundaryDofMap &surfaceMap, bool reference = false
) { return detail::AssembleSurfaceMassDiagonal(finiteElements, surfaceMap, reference); }
/*
* Runtime preparation paired with the compile-time normalization plan.
* The operator compiler is the authority for which blocks a specification