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

@@ -13,6 +13,7 @@
#include <catch2/catch_approx.hpp>
#include <catch2/catch_test_macros.hpp>
#include <mfem.hpp>
#include <mpi.h>
import mean_field;
import test_helpers;
@@ -997,3 +998,83 @@ TEST_CASE(
CHECK(physicalInverse.IsCurrent());
CHECK(scaledInverse.IsCurrent());
}
TEST_CASE("Direct Reference Mass Diagonals Match Full True DOF Assembly", "[normalization][diagonal][assembly]") {
using namespace mean_field;
auto args = test_utils::setup_args();
auto f = fem::setup_fem(args.mesh_file, args, 0);
REQUIRE(f.okay());
auto compare = [](const mfem::Vector &a, const mfem::Vector &b) {
REQUIRE(a.Size() == b.Size());
mfem::Vector difference(a); difference -= b;
CHECK(difference.Norml2() <= 2.0e-11 * std::max(1.0, b.Norml2()));
};
compare(normalization::AssembleReferenceHDivMassDiagonal(*f.gravityFluxFes),
normalization::AssembleReferenceHDivMassDiagonal(*f.gravityFluxFes, true));
for (auto *space : {f.gravityPotentialFes.get(), f.densityFes.get(), f.enthalpyFes.get()}) {
compare(normalization::AssembleReferenceScalarMassDiagonal(*space),
normalization::AssembleReferenceScalarMassDiagonal(*space, nullptr, true));
mfem::Array<int> marker(f.mesh->attributes.Max());
marker = 0; marker[f.mesh->GetAttribute(0)-1] = 1;
compare(normalization::AssembleReferenceScalarMassDiagonal(*space, &marker),
normalization::AssembleReferenceScalarMassDiagonal(*space, &marker, true));
}
auto surfaceMap = field::make_stellar_surface_scalar_dof_map(*f.surfaceDeformationFes);
// The stellar surface is a tagged internal interface, which an exterior-only
// boundary face restriction would omit even though volume diagonals pass.
using Schema = utils::domain::CoreEnvelopeVacuumDomainSchema;
constexpr int surfaceAttribute = Schema::boundary_attribute<utils::domain::StellarSurface>();
int localFaceCounts[2] = {0, 0}, globalFaceCounts[2] = {0, 0};
for (int b = 0; b < f.mesh->GetNBE(); ++b) {
if (f.mesh->GetBdrAttribute(b) != surfaceAttribute) continue;
++localFaceCounts[0];
const int face = f.mesh->GetBdrElementFaceIndex(b);
if (f.mesh->GetFaceInformation(face).IsOfFaceType(mfem::FaceType::Interior))
++localFaceCounts[1];
}
REQUIRE(MPI_Allreduce(localFaceCounts, globalFaceCounts, 2, MPI_INT, MPI_SUM,
f.surfaceDeformationFes->GetComm()) == MPI_SUCCESS);
REQUIRE(globalFaceCounts[0] > 0);
REQUIRE(globalFaceCounts[1] == globalFaceCounts[0]);
const auto surface = normalization::AssembleReferenceSurfaceMassDiagonal(f, surfaceMap);
const auto referenceSurface = normalization::AssembleReferenceSurfaceMassDiagonal(f, surfaceMap, true);
REQUIRE(surface.Size() == referenceSurface.Size());
for (int i = 0; i < surface.Size(); ++i) {
CAPTURE(i, surface(i), referenceSurface(i));
CHECK(std::isfinite(surface(i)));
CHECK(surface(i) > 0.0);
CHECK(std::isfinite(referenceSurface(i)));
CHECK(referenceSurface(i) > 0.0);
}
mfem::Vector difference(surface);
difference -= referenceSurface;
const double errorNorm = difference.Norml2(), referenceNorm = referenceSurface.Norml2();
const double localSquares[2] = {errorNorm * errorNorm, referenceNorm * referenceNorm};
double globalSquares[2] = {0.0, 0.0};
REQUIRE(MPI_Allreduce(localSquares, globalSquares, 2, MPI_DOUBLE, MPI_SUM,
f.surfaceDeformationFes->GetComm()) == MPI_SUCCESS);
REQUIRE(globalSquares[1] > 0.0);
CHECK(std::sqrt(globalSquares[0] / globalSquares[1]) <= 2.0e-11);
}
TEST_CASE("Nonconforming Reference Diagonals Retain Exact Assembled Cross Terms", "[normalization][diagonal][nonconforming]") {
using namespace mean_field;
auto serial = mfem::Mesh::MakeCartesian3D(2, 1, 1, mfem::Element::HEXAHEDRON);
serial.EnsureNCMesh();
mfem::Array<int> refine(1); refine[0] = 0;
serial.GeneralRefinement(refine);
REQUIRE(serial.Nonconforming());
mfem::ParMesh mesh(MPI_COMM_WORLD, serial);
mfem::H1_FECollection h1(2, 3);
mfem::RT_FECollection rt(1, 3);
mfem::ParFiniteElementSpace scalar(&mesh, &h1), flux(&mesh, &rt);
auto actual = normalization::AssembleReferenceScalarMassDiagonal(scalar);
auto expected = normalization::AssembleReferenceScalarMassDiagonal(scalar, nullptr, true);
actual -= expected;
CHECK(actual.Norml2() == 0.0);
actual = normalization::AssembleReferenceHDivMassDiagonal(flux);
expected = normalization::AssembleReferenceHDivMassDiagonal(flux, true);
actual -= expected;
CHECK(actual.Norml2() == 0.0);
}