Files
MeanField/tests/mapping/prepared_cache.cpp
Emily Boudreaux 75cc638739 perf(allocations): reduced overall allocations by 95%, increaseed jacobian applicatin by 2x
This commit uses global pre allocated work space to dramatically reduce memory usage and allocation time
2026-09-10 06:50:56 -04:00

151 lines
5.8 KiB
C++

#include <catch2/catch_test_macros.hpp>
#include <mfem.hpp>
#include <stdexcept>
import mean_field;
namespace {
using mean_field::mapping::VolumeMappingContext;
void fill_vector(
mfem::Vector &vector,
const int dimension,
const double offset
) {
vector.SetSize(dimension);
for (int i = 0; i < dimension; ++i)
vector(i) = offset + i;
}
void fill_matrix(
mfem::DenseMatrix &matrix,
const int dimension,
const double offset
) {
matrix.SetSize(dimension);
for (int j = 0; j < dimension; ++j) {
for (int i = 0; i < dimension; ++i)
matrix(i, j) = offset + 10 * j + i;
}
}
VolumeMappingContext make_context(
const int dimension,
const double offset,
const bool compactified
) {
VolumeMappingContext context;
fill_vector(context.mapping.reference_position, dimension, offset + 1);
fill_vector(context.mapping.displaced_position, dimension, offset + 2);
fill_vector(context.mapping.physical_position, dimension, offset + 3);
fill_matrix(context.mapping.displacement_jacobian, dimension, offset + 4);
fill_matrix(context.mapping.mapping_jacobian, dimension, offset + 5);
fill_matrix(context.mapping.inverse_mapping_jacobian, dimension, offset + 6);
fill_matrix(context.quadrature.J_inv, dimension, offset + 7);
context.mapping.mapping_determinant = offset + 8;
context.mapping.compactified = compactified;
context.quadrature.detJ = offset + 9;
context.quadrature.weight = offset + 10;
return context;
}
void check_vector(
const mfem::Vector &actual,
const mfem::Vector &expected
) {
REQUIRE(actual.Size() == expected.Size());
for (int i = 0; i < expected.Size(); ++i)
CHECK(actual(i) == expected(i));
}
void check_matrix(
const mfem::DenseMatrix &actual,
const mfem::DenseMatrix &expected
) {
REQUIRE(actual.Height() == expected.Height());
REQUIRE(actual.Width() == expected.Width());
for (int j = 0; j < expected.Width(); ++j) {
for (int i = 0; i < expected.Height(); ++i)
CHECK(actual(i, j) == expected(i, j));
}
}
void check_context(
const VolumeMappingContext &actual,
const VolumeMappingContext &expected
) {
check_vector(actual.mapping.reference_position, expected.mapping.reference_position);
check_vector(actual.mapping.displaced_position, expected.mapping.displaced_position);
check_vector(actual.mapping.physical_position, expected.mapping.physical_position);
check_matrix(actual.mapping.displacement_jacobian, expected.mapping.displacement_jacobian);
check_matrix(actual.mapping.mapping_jacobian, expected.mapping.mapping_jacobian);
check_matrix(actual.mapping.inverse_mapping_jacobian, expected.mapping.inverse_mapping_jacobian);
check_matrix(actual.quadrature.J_inv, expected.quadrature.J_inv);
CHECK(actual.mapping.mapping_determinant == expected.mapping.mapping_determinant);
CHECK(actual.mapping.compactified == expected.mapping.compactified);
CHECK(actual.quadrature.detJ == expected.quadrature.detJ);
CHECK(actual.quadrature.weight == expected.quadrature.weight);
}
} // namespace
TEST_CASE(
"Flat Volume Mapping Cache Preserves Every Context Field",
"[mapping][prepared-cache]"
) {
for (const int dimension : {1, 2, 3}) {
CAPTURE(dimension);
mean_field::mapping::VolumeMappingCache cache;
cache.SetSize(2, dimension);
CHECK(cache.GetPointCount() == 2);
CHECK(cache.GetDimension() == dimension);
const auto first = make_context(dimension, 0.125, false);
const auto second = make_context(dimension, -30.25, true);
cache.Store(0, first);
cache.Store(1, second);
VolumeMappingContext workspace;
cache.Load(1, workspace);
check_context(workspace, second);
const double *inverse_buffer = workspace.quadrature.J_inv.HostRead();
const double *position_buffer = workspace.mapping.physical_position.HostRead();
cache.Load(0, workspace);
check_context(workspace, first);
CHECK(workspace.quadrature.J_inv.HostRead() == inverse_buffer);
CHECK(workspace.mapping.physical_position.HostRead() == position_buffer);
mfem::DenseMatrix inverse;
cache.LoadInverseJacobian(1, inverse);
check_matrix(inverse, second.quadrature.J_inv);
const auto copy = cache;
cache.Store(1, first);
copy.Load(1, workspace);
check_context(workspace, second);
cache.Load(1, workspace);
check_context(workspace, first);
cache.SetSize(1, 3);
const auto resized = make_context(3, 13.5, true);
cache.Store(0, resized);
cache.Load(0, workspace);
check_context(workspace, resized);
}
}
TEST_CASE(
"Flat Volume Mapping Cache Rejects Invalid Indices And Dimensions",
"[mapping][prepared-cache]"
) {
mean_field::mapping::VolumeMappingCache cache;
VolumeMappingContext workspace;
CHECK_THROWS_AS(cache.SetSize(-1, 3), std::invalid_argument);
CHECK_THROWS_AS(cache.SetSize(1, 0), std::invalid_argument);
CHECK_THROWS_AS(cache.SetSize(1, 4), std::invalid_argument);
cache.SetSize(1, 3);
CHECK_THROWS_AS(cache.Load(-1, workspace), std::out_of_range);
CHECK_THROWS_AS(cache.Load(1, workspace), std::out_of_range);
CHECK_THROWS_AS(cache.Store(0, make_context(2, 0.0, false)), std::invalid_argument);
cache.SetSize(0, 2);
CHECK(cache.GetPointCount() == 0);
CHECK_THROWS_AS(cache.Load(0, workspace), std::out_of_range);
}