Snapshot optimized solver and audit diagnostics before numerical experiments
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
@@ -102,6 +103,43 @@ namespace {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Kelvin Prepared Jacobian Factors Match Full Variation", tags::unit &tags::mapping &tags::kelvin) {
|
||||
mapping::compactification::KelvinCompactification kelvin({.r_star_ref = 1.3, .r_inf_ref = 3.1});
|
||||
const auto position = make_vector(1.1, 0.2, -0.1);
|
||||
const auto coordinateGradient = make_vector(0.2, 0.03, -0.01);
|
||||
auto jacobian = make_identity();
|
||||
jacobian(0, 1) = 0.07;
|
||||
const auto direction = make_vector(-0.02, 0.07, 0.04);
|
||||
auto directionJacobian = make_identity();
|
||||
directionJacobian *= 0.03;
|
||||
directionJacobian(1, 2) = -0.05;
|
||||
for (const double coordinate : {0.0, 0.4, 0.93, 0.999}) {
|
||||
const mapping::compactification::ExteriorMapInput input{
|
||||
position, position, jacobian, coordinate, coordinateGradient};
|
||||
mapping::compactification::ExteriorMapResult base;
|
||||
REQUIRE(kelvin.Evaluate(input, base) == mapping::MappingStatus::valid);
|
||||
mapping::compactification::ExteriorMapVariation variation;
|
||||
REQUIRE(kelvin.EvaluateVariation(input, base, {direction, directionJacobian}, variation) == mapping::MappingStatus::valid);
|
||||
double scale = 0.0;
|
||||
mfem::Vector scaleGradient;
|
||||
REQUIRE(kelvin.EvaluateJacobianVariationFactors(coordinate, coordinateGradient, scale, scaleGradient) == mapping::MappingStatus::valid);
|
||||
for (int row = 0; row < 3; ++row) {
|
||||
for (int column = 0; column < 3; ++column) {
|
||||
const double expected = variation.mapping_jacobian_variation(row, column);
|
||||
CHECK_THAT(scale * directionJacobian(row, column) + direction(row) * scaleGradient(column),
|
||||
WithinAbs(expected, 1.0e-12 * std::max(1.0, std::abs(expected))));
|
||||
}
|
||||
}
|
||||
}
|
||||
double scale = 0.0;
|
||||
mfem::Vector gradient;
|
||||
CHECK(kelvin.EvaluateJacobianVariationFactors(1.0, coordinateGradient, scale, gradient) == mapping::MappingStatus::at_compactified_infinity);
|
||||
CHECK(kelvin.EvaluateJacobianVariationFactors(-0.1, coordinateGradient, scale, gradient) == mapping::MappingStatus::outside_reference_domain);
|
||||
auto invalid = coordinateGradient;
|
||||
invalid(1) = std::numeric_limits<double>::quiet_NaN();
|
||||
CHECK(kelvin.EvaluateJacobianVariationFactors(0.4, invalid, scale, gradient) == mapping::MappingStatus::non_finite_input);
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Kelvin Compactification Validates Its Configuration",
|
||||
tags::unit &tags::mapping &tags::kelvin
|
||||
@@ -719,4 +757,4 @@ TEST_CASE(
|
||||
|
||||
check_vector(first_a.physical_position, second_a.physical_position, tolerance);
|
||||
check_matrix(first_a.mapping_jacobian, second_a.mapping_jacobian, tolerance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2870,3 +2870,80 @@ TEST_CASE(
|
||||
CHECK_THROWS_AS(evaluator.Refresh(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(evaluator.EvaluatePoint(*transformation, integration_point, context), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST_CASE("Fixed Mesh Geometry Cache Reuses Factors And Invalidates On Mesh Updates", "[mapping][geometry-cache]") {
|
||||
SingleElementFixture fixture;
|
||||
mapping::DomainMapper mapper({.dimension = dimension, .vacuum_element_attribute = 3}, make_kelvin_compactification());
|
||||
mapping::DomainMapper::Workspace workspace(dimension);
|
||||
const auto &rule = mfem::IntRules.Get(mfem::Geometry::CUBE, 5);
|
||||
const auto &point = rule.IntPoint(0);
|
||||
auto zero = fixture.MakeZeroElementDofs();
|
||||
mapping::ElementDisplacementData displacement(fixture.GetElement(), zero);
|
||||
ElementMappingDataOwner data(displacement);
|
||||
auto compare = [&](const mfem::IntegrationPoint &ip) {
|
||||
auto &transformation = *fixture.mesh.GetElementTransformation(0);
|
||||
mapping::VolumeMappingContext fast, reference;
|
||||
mapper.SetGeometryCacheEnabled(true);
|
||||
REQUIRE(mapper.EvaluateVolume(data.Get(), transformation, ip, workspace, fast) == mapping::MappingStatus::valid);
|
||||
mapper.SetGeometryCacheEnabled(false);
|
||||
REQUIRE(mapper.EvaluateVolume(data.Get(), transformation, ip, workspace, reference) == mapping::MappingStatus::valid);
|
||||
check_vector(fast.mapping.physical_position, reference.mapping.physical_position);
|
||||
check_matrix(fast.mapping.mapping_jacobian, reference.mapping.mapping_jacobian);
|
||||
check_matrix(fast.quadrature.J_inv, reference.quadrature.J_inv);
|
||||
CHECK_THAT(fast.quadrature.weight, WithinAbs(reference.quadrature.weight, 1.0e-12));
|
||||
mapper.SetGeometryCacheEnabled(true);
|
||||
return fast.quadrature.weight;
|
||||
};
|
||||
const double originalWeight = compare(point);
|
||||
CHECK(mapper.GetGeometryCacheStatistics().misses == 1);
|
||||
compare(point);
|
||||
CHECK(mapper.GetGeometryCacheStatistics().hits == 1);
|
||||
auto changedPoint = point;
|
||||
changedPoint.x += 0.013;
|
||||
compare(changedPoint);
|
||||
CHECK(mapper.GetGeometryCacheStatistics().points == 2);
|
||||
changedPoint.weight *= 0.5;
|
||||
compare(changedPoint);
|
||||
CHECK(mapper.GetGeometryCacheStatistics().points == 2); // weights are supplied by the caller
|
||||
fixture.mesh.Transform([](const mfem::Vector &x, mfem::Vector &y) {
|
||||
y = x; y(0) *= 1.2; y(1) += 0.17;
|
||||
});
|
||||
const double newWeight = compare(point);
|
||||
CHECK(newWeight > originalWeight);
|
||||
CHECK(mapper.GetGeometryCacheStatistics().points == 1);
|
||||
CHECK(mapper.GetGeometryCacheStatistics().misses == 3);
|
||||
mapper.ClearGeometryCache();
|
||||
CHECK(mapper.GetGeometryCacheStatistics().points == 0);
|
||||
compare(point);
|
||||
CHECK(mapper.GetGeometryCacheStatistics().misses == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("Geometry Cache Does Not Freeze Displacement Or Compactification State", "[mapping][geometry-cache]") {
|
||||
SingleElementFixture fixture;
|
||||
mapping::DomainMapper mapper({.dimension = dimension, .vacuum_element_attribute = 3}, make_kelvin_compactification());
|
||||
mapping::DomainMapper::Workspace workspace(dimension);
|
||||
const auto &point = mfem::IntRules.Get(mfem::Geometry::CUBE, 3).IntPoint(0);
|
||||
for (double scale : {0.0, 0.02, -0.01}) {
|
||||
auto &transformation = *fixture.mesh.GetElementTransformation(0);
|
||||
auto dofs = fixture.MakeZeroElementDofs(); dofs = scale;
|
||||
mapping::ElementDisplacementData displacement(fixture.GetElement(), dofs);
|
||||
auto compactificationDofs = make_constant_compactification_dofs(fixture.GetElement(), 0.1 + scale);
|
||||
mapping::ElementCompactificationData compactification(fixture.GetElement(), compactificationDofs);
|
||||
mapping::ElementMappingData data{displacement, compactification};
|
||||
for (int attribute : {1, 3}) {
|
||||
transformation.Attribute = attribute;
|
||||
mapping::VolumeMappingContext fast, reference;
|
||||
mapper.SetGeometryCacheEnabled(true);
|
||||
const auto fastStatus = mapper.EvaluateVolume(data, transformation, point, workspace, fast);
|
||||
mapper.SetGeometryCacheEnabled(false);
|
||||
const auto referenceStatus = mapper.EvaluateVolume(data, transformation, point, workspace, reference);
|
||||
REQUIRE(fastStatus == referenceStatus);
|
||||
if (fastStatus == mapping::MappingStatus::valid) {
|
||||
check_vector(fast.mapping.physical_position, reference.mapping.physical_position);
|
||||
check_matrix(fast.mapping.mapping_jacobian, reference.mapping.mapping_jacobian);
|
||||
check_matrix(fast.quadrature.J_inv, reference.quadrature.J_inv);
|
||||
}
|
||||
}
|
||||
}
|
||||
CHECK(mapper.GetGeometryCacheStatistics().points == 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user