Snapshot optimized solver and audit diagnostics before numerical experiments
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user