currently the barotope and the pressure force operator are migrated to the new support system
722 lines
31 KiB
C++
722 lines
31 KiB
C++
#include <array>
|
|
#include <catch2/catch_test_macros.hpp>
|
|
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
|
#include <cmath>
|
|
#include <limits>
|
|
#include <mfem.hpp>
|
|
#include <stdexcept>
|
|
|
|
import mean_field;
|
|
import test_helpers;
|
|
|
|
using namespace mean_field;
|
|
using Catch::Matchers::WithinAbs;
|
|
|
|
namespace {
|
|
constexpr int dimension = 3;
|
|
|
|
mfem::Vector make_vector(
|
|
const double x,
|
|
const double y,
|
|
const double z
|
|
) {
|
|
mfem::Vector vector(dimension);
|
|
vector(0) = x;
|
|
vector(1) = y;
|
|
vector(2) = z;
|
|
return vector;
|
|
}
|
|
|
|
mfem::DenseMatrix make_identity() {
|
|
mfem::DenseMatrix matrix(dimension);
|
|
matrix = 0.0;
|
|
for (int i = 0; i < dimension; ++i)
|
|
matrix(i, i) = 1.0;
|
|
return matrix;
|
|
}
|
|
|
|
void check_vector(
|
|
const mfem::Vector &actual,
|
|
const mfem::Vector &expected,
|
|
const double tolerance
|
|
) {
|
|
REQUIRE(actual.Size() == expected.Size());
|
|
for (int i = 0; i < actual.Size(); ++i)
|
|
CHECK_THAT(actual(i), WithinAbs(expected(i), tolerance));
|
|
}
|
|
|
|
void check_matrix(
|
|
const mfem::DenseMatrix &actual,
|
|
const mfem::DenseMatrix &expected,
|
|
const double tolerance
|
|
) {
|
|
REQUIRE(actual.Height() == expected.Height());
|
|
REQUIRE(actual.Width() == expected.Width());
|
|
|
|
for (int i = 0; i < actual.Height(); ++i) {
|
|
for (int j = 0; j < actual.Width(); ++j)
|
|
CHECK_THAT(actual(i, j), WithinAbs(expected(i, j), tolerance));
|
|
}
|
|
}
|
|
|
|
struct AnalyticFactors {
|
|
double computational_radius;
|
|
double scale;
|
|
double scale_derivative;
|
|
};
|
|
|
|
AnalyticFactors compute_analytic_factors(
|
|
const double r_star,
|
|
const double r_inf,
|
|
const double coordinate
|
|
) {
|
|
const double radial_extent = r_inf - r_star;
|
|
const double computational_radius = r_star + coordinate * radial_extent;
|
|
const double scale = r_star / (computational_radius * (1.0 - coordinate));
|
|
const double scale_derivative = scale * (1.0 / (1.0 - coordinate) - radial_extent / computational_radius);
|
|
return {.computational_radius = computational_radius, .scale = scale, .scale_derivative = scale_derivative};
|
|
}
|
|
|
|
mapping::MappingStatus evaluate_affine_map(
|
|
const mapping::compactification::ExteriorDomainMap &exterior_map,
|
|
const mfem::Vector &reference_position,
|
|
const mfem::DenseMatrix &affine_jacobian,
|
|
const mfem::Vector &offset,
|
|
const double compactification_coordinate,
|
|
const mfem::Vector &compactification_coordinate_gradient,
|
|
mapping::compactification::ExteriorMapResult &result
|
|
) {
|
|
mfem::Vector displaced_position(dimension);
|
|
affine_jacobian.Mult(reference_position, displaced_position);
|
|
displaced_position += offset;
|
|
|
|
const mapping::compactification::ExteriorMapInput input{
|
|
.reference_position = reference_position,
|
|
.displaced_position = displaced_position,
|
|
.displacement_jacobian = affine_jacobian,
|
|
.compactification_coordinate = compactification_coordinate,
|
|
.compactification_coordinate_gradient = compactification_coordinate_gradient
|
|
};
|
|
|
|
return exterior_map.Evaluate(input, result);
|
|
}
|
|
} // namespace
|
|
|
|
TEST_CASE(
|
|
"Kelvin Compactification Validates Its Configuration",
|
|
tags::unit &tags::mapping &tags::kelvin
|
|
) {
|
|
CHECK_NOTHROW(mapping::compactification::KelvinCompactification({.r_star_ref = 1.0, .r_inf_ref = 4.0}));
|
|
CHECK_THROWS_AS(
|
|
mapping::compactification::KelvinCompactification({.r_star_ref = 0.0, .r_inf_ref = 4.0}), std::invalid_argument
|
|
);
|
|
CHECK_THROWS_AS(
|
|
mapping::compactification::KelvinCompactification({.r_star_ref = -1.0, .r_inf_ref = 4.0}), std::invalid_argument
|
|
);
|
|
CHECK_THROWS_AS(
|
|
mapping::compactification::KelvinCompactification({.r_star_ref = 2.0, .r_inf_ref = 2.0}), std::invalid_argument
|
|
);
|
|
CHECK_THROWS_AS(
|
|
mapping::compactification::KelvinCompactification({.r_star_ref = 3.0, .r_inf_ref = 2.0}), std::invalid_argument
|
|
);
|
|
CHECK_THROWS_AS(
|
|
mapping::compactification::KelvinCompactification(
|
|
{.r_star_ref = 1.0, .r_inf_ref = std::numeric_limits<double>::infinity()}
|
|
),
|
|
std::invalid_argument
|
|
);
|
|
CHECK_THROWS_AS(
|
|
mapping::compactification::KelvinCompactification(
|
|
{.r_star_ref = 1.0, .r_inf_ref = 4.0, .coordinate_tolerance = -1.0e-12}
|
|
),
|
|
std::invalid_argument
|
|
);
|
|
CHECK_THROWS_AS(
|
|
mapping::compactification::KelvinCompactification(
|
|
{.r_star_ref = 1.0, .r_inf_ref = 4.0, .coordinate_tolerance = 1.0}
|
|
),
|
|
std::invalid_argument
|
|
);
|
|
CHECK_THROWS_AS(
|
|
mapping::compactification::KelvinCompactification(
|
|
{.r_star_ref = 1.0, .r_inf_ref = 4.0, .coordinate_tolerance = std::numeric_limits<double>::quiet_NaN()}
|
|
),
|
|
std::invalid_argument
|
|
);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Kelvin Compactification Reports Its Configuration",
|
|
tags::unit &tags::mapping &tags::kelvin
|
|
) {
|
|
constexpr double coordinate_tolerance = 3.0e-11;
|
|
mapping::compactification::KelvinCompactification compactification(
|
|
{.r_star_ref = 1.25, .r_inf_ref = 5.5, .coordinate_tolerance = coordinate_tolerance}
|
|
);
|
|
|
|
CHECK(compactification.GetName() == "KelvinCompactification");
|
|
CHECK_THAT(compactification.GetReferenceStellarRadius(), WithinAbs(1.25, 0.0));
|
|
CHECK_THAT(compactification.GetReferenceInfinityRadius(), WithinAbs(5.5, 0.0));
|
|
CHECK_THAT(compactification.GetCoordinateTolerance(), WithinAbs(coordinate_tolerance, 0.0));
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Kelvin Compactification Uses The Exterior Coordinate Rather Than "
|
|
"Euclidean Radius",
|
|
tags::unit &tags::mapping &tags::kelvin
|
|
) {
|
|
constexpr double tolerance = 0.0;
|
|
constexpr double coordinate = 0.37;
|
|
|
|
mapping::compactification::KelvinCompactification compactification({.r_star_ref = 1.0, .r_inf_ref = 4.0});
|
|
const mfem::DenseMatrix displacement_jacobian = make_identity();
|
|
const mfem::Vector displaced_position = make_vector(1.4, -0.2, 0.3);
|
|
const mfem::Vector coordinate_gradient = make_vector(0.2, -0.1, 0.05);
|
|
const mfem::Vector reference_a = make_vector(0.2, 0.1, -0.1);
|
|
const mfem::Vector reference_b = make_vector(12.0, -7.0, 4.0);
|
|
|
|
const mapping::compactification::ExteriorMapInput input_a{
|
|
reference_a, displaced_position, displacement_jacobian, coordinate, coordinate_gradient
|
|
};
|
|
const mapping::compactification::ExteriorMapInput input_b{
|
|
reference_b, displaced_position, displacement_jacobian, coordinate, coordinate_gradient
|
|
};
|
|
|
|
mapping::compactification::ExteriorMapResult result_a;
|
|
mapping::compactification::ExteriorMapResult result_b;
|
|
|
|
REQUIRE(compactification.Evaluate(input_a, result_a) == mapping::MappingStatus::valid);
|
|
REQUIRE(compactification.Evaluate(input_b, result_b) == mapping::MappingStatus::valid);
|
|
|
|
check_vector(result_a.physical_position, result_b.physical_position, tolerance);
|
|
check_matrix(result_a.mapping_jacobian, result_b.mapping_jacobian, tolerance);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Kelvin Compactification Matches Its Analytic Radial Map",
|
|
tags::unit &tags::mapping &tags::kelvin
|
|
) {
|
|
constexpr double r_star = 1.0;
|
|
constexpr double r_inf = 4.0;
|
|
constexpr double radial_extent = r_inf - r_star;
|
|
constexpr double tolerance = 2.0e-12;
|
|
|
|
mapping::compactification::KelvinCompactification compactification({.r_star_ref = r_star, .r_inf_ref = r_inf});
|
|
const mfem::DenseMatrix identity = make_identity();
|
|
const mfem::Vector coordinate_gradient = make_vector(1.0 / radial_extent, 0.0, 0.0);
|
|
|
|
for (const double computational_radius : std::array{1.0, 1.25, 2.0, 3.0, 3.75}) {
|
|
CAPTURE(computational_radius);
|
|
|
|
const double coordinate = (computational_radius - r_star) / radial_extent;
|
|
const mfem::Vector reference_position = make_vector(computational_radius, 0.0, 0.0);
|
|
const mfem::Vector displaced_position(reference_position);
|
|
const mapping::compactification::ExteriorMapInput input{
|
|
reference_position, displaced_position, identity, coordinate, coordinate_gradient
|
|
};
|
|
mapping::compactification::ExteriorMapResult result;
|
|
|
|
REQUIRE(compactification.Evaluate(input, result) == mapping::MappingStatus::valid);
|
|
|
|
const double expected_radius = r_star * radial_extent / (r_inf - computational_radius);
|
|
const double expected_radial_derivative = r_star * radial_extent / std::pow(r_inf - computational_radius, 2.0);
|
|
const double expected_tangential_scale = expected_radius / computational_radius;
|
|
|
|
const mfem::Vector expected_position = make_vector(expected_radius, 0.0, 0.0);
|
|
mfem::DenseMatrix expected_jacobian(dimension);
|
|
expected_jacobian = 0.0;
|
|
expected_jacobian(0, 0) = expected_radial_derivative;
|
|
expected_jacobian(1, 1) = expected_tangential_scale;
|
|
expected_jacobian(2, 2) = expected_tangential_scale;
|
|
|
|
check_vector(result.physical_position, expected_position, tolerance);
|
|
check_matrix(result.mapping_jacobian, expected_jacobian, tolerance);
|
|
CHECK(result.mapping_jacobian.Det() > 0.0);
|
|
}
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Kelvin Compactification Matches Its Full Cartesian Formula",
|
|
tags::unit &tags::mapping &tags::kelvin
|
|
) {
|
|
constexpr double r_star = 1.0;
|
|
constexpr double r_inf = 4.0;
|
|
constexpr double coordinate = 0.42;
|
|
constexpr double tolerance = 1.0e-12;
|
|
|
|
mapping::compactification::KelvinCompactification compactification({.r_star_ref = r_star, .r_inf_ref = r_inf});
|
|
const mfem::Vector reference_position = make_vector(0.8, 0.4, -0.2);
|
|
const mfem::Vector displaced_position = make_vector(1.1, 0.5, -0.1);
|
|
const mfem::Vector coordinate_gradient = make_vector(0.20, -0.10, 0.05);
|
|
|
|
mfem::DenseMatrix displacement_jacobian(dimension);
|
|
displacement_jacobian(0, 0) = 1.10;
|
|
displacement_jacobian(0, 1) = 0.05;
|
|
displacement_jacobian(0, 2) = 0.00;
|
|
displacement_jacobian(1, 0) = -0.02;
|
|
displacement_jacobian(1, 1) = 0.95;
|
|
displacement_jacobian(1, 2) = 0.03;
|
|
displacement_jacobian(2, 0) = 0.01;
|
|
displacement_jacobian(2, 1) = -0.04;
|
|
displacement_jacobian(2, 2) = 1.05;
|
|
|
|
const mapping::compactification::ExteriorMapInput input{
|
|
reference_position, displaced_position, displacement_jacobian, coordinate, coordinate_gradient
|
|
};
|
|
mapping::compactification::ExteriorMapResult result;
|
|
|
|
REQUIRE(compactification.Evaluate(input, result) == mapping::MappingStatus::valid);
|
|
|
|
const AnalyticFactors factors = compute_analytic_factors(r_star, r_inf, coordinate);
|
|
mfem::Vector expected_position(displaced_position);
|
|
expected_position *= factors.scale;
|
|
|
|
mfem::DenseMatrix expected_jacobian(displacement_jacobian);
|
|
expected_jacobian *= factors.scale;
|
|
|
|
for (int i = 0; i < dimension; ++i) {
|
|
for (int j = 0; j < dimension; ++j)
|
|
expected_jacobian(i, j) += displaced_position(i) * factors.scale_derivative * coordinate_gradient(j);
|
|
}
|
|
|
|
check_vector(result.physical_position, expected_position, tolerance);
|
|
check_matrix(result.mapping_jacobian, expected_jacobian, tolerance);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Kelvin Compactification Jacobian Matches Coordinate Finite Differences",
|
|
tags::unit &tags::mapping &tags::kelvin
|
|
) {
|
|
constexpr double base_coordinate = 0.38;
|
|
constexpr double difference_step = 1.0e-6;
|
|
constexpr double tolerance = 3.0e-9;
|
|
|
|
mapping::compactification::KelvinCompactification compactification({.r_star_ref = 1.0, .r_inf_ref = 4.0});
|
|
|
|
mfem::DenseMatrix affine_jacobian(dimension);
|
|
affine_jacobian(0, 0) = 1.05;
|
|
affine_jacobian(0, 1) = 0.02;
|
|
affine_jacobian(0, 2) = 0.00;
|
|
affine_jacobian(1, 0) = -0.01;
|
|
affine_jacobian(1, 1) = 0.98;
|
|
affine_jacobian(1, 2) = 0.03;
|
|
affine_jacobian(2, 0) = 0.02;
|
|
affine_jacobian(2, 1) = 0.00;
|
|
affine_jacobian(2, 2) = 1.02;
|
|
|
|
const mfem::Vector offset = make_vector(0.04, -0.03, 0.02);
|
|
const mfem::Vector reference_position = make_vector(1.4, 0.3, -0.2);
|
|
const mfem::Vector coordinate_gradient = make_vector(0.11, -0.07, 0.05);
|
|
|
|
mapping::compactification::ExteriorMapResult base_result;
|
|
REQUIRE(
|
|
evaluate_affine_map(
|
|
compactification, reference_position, affine_jacobian, offset, base_coordinate, coordinate_gradient,
|
|
base_result
|
|
) == mapping::MappingStatus::valid
|
|
);
|
|
|
|
for (int coordinate = 0; coordinate < dimension; ++coordinate) {
|
|
mfem::Vector reference_plus(reference_position);
|
|
mfem::Vector reference_minus(reference_position);
|
|
reference_plus(coordinate) += difference_step;
|
|
reference_minus(coordinate) -= difference_step;
|
|
|
|
const double compactification_plus = base_coordinate + difference_step * coordinate_gradient(coordinate);
|
|
const double compactification_minus = base_coordinate - difference_step * coordinate_gradient(coordinate);
|
|
|
|
mapping::compactification::ExteriorMapResult result_plus;
|
|
mapping::compactification::ExteriorMapResult result_minus;
|
|
|
|
REQUIRE(
|
|
evaluate_affine_map(
|
|
compactification, reference_plus, affine_jacobian, offset, compactification_plus, coordinate_gradient,
|
|
result_plus
|
|
) == mapping::MappingStatus::valid
|
|
);
|
|
REQUIRE(
|
|
evaluate_affine_map(
|
|
compactification, reference_minus, affine_jacobian, offset, compactification_minus, coordinate_gradient,
|
|
result_minus
|
|
) == mapping::MappingStatus::valid
|
|
);
|
|
|
|
for (int component = 0; component < dimension; ++component) {
|
|
const double finite_difference =
|
|
(result_plus.physical_position(component) - result_minus.physical_position(component)) /
|
|
(2.0 * difference_step);
|
|
CHECK_THAT(finite_difference, WithinAbs(base_result.mapping_jacobian(component, coordinate), tolerance));
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Kelvin Compactification Variation Matches State Finite Differences",
|
|
tags::unit &tags::mapping &tags::kelvin
|
|
) {
|
|
constexpr double coordinate = 0.46;
|
|
constexpr double difference_step = 1.0e-6;
|
|
constexpr double tolerance = 2.0e-10;
|
|
|
|
mapping::compactification::KelvinCompactification compactification({.r_star_ref = 1.0, .r_inf_ref = 4.0});
|
|
const mfem::Vector reference_position = make_vector(1.3, -0.2, 0.4);
|
|
const mfem::Vector displaced_position = make_vector(1.4, -0.1, 0.35);
|
|
const mfem::Vector coordinate_gradient = make_vector(0.12, -0.04, 0.08);
|
|
const mfem::Vector position_direction = make_vector(0.03, -0.05, 0.02);
|
|
|
|
mfem::DenseMatrix displacement_jacobian = make_identity();
|
|
displacement_jacobian(0, 1) = 0.04;
|
|
displacement_jacobian(1, 2) = -0.03;
|
|
displacement_jacobian(2, 0) = 0.02;
|
|
|
|
mfem::DenseMatrix jacobian_direction(dimension);
|
|
jacobian_direction(0, 0) = 0.02;
|
|
jacobian_direction(0, 1) = -0.01;
|
|
jacobian_direction(0, 2) = 0.03;
|
|
jacobian_direction(1, 0) = 0.01;
|
|
jacobian_direction(1, 1) = -0.02;
|
|
jacobian_direction(1, 2) = 0.00;
|
|
jacobian_direction(2, 0) = -0.01;
|
|
jacobian_direction(2, 1) = 0.02;
|
|
jacobian_direction(2, 2) = 0.01;
|
|
|
|
const mapping::compactification::ExteriorMapInput input{
|
|
reference_position, displaced_position, displacement_jacobian, coordinate, coordinate_gradient
|
|
};
|
|
const mapping::compactification::ExteriorMapDirection direction{position_direction, jacobian_direction};
|
|
|
|
mapping::compactification::ExteriorMapResult base_result;
|
|
mapping::compactification::ExteriorMapVariation variation;
|
|
|
|
REQUIRE(compactification.Evaluate(input, base_result) == mapping::MappingStatus::valid);
|
|
REQUIRE(
|
|
compactification.EvaluateVariation(input, base_result, direction, variation) == mapping::MappingStatus::valid
|
|
);
|
|
|
|
mfem::Vector displaced_plus(displaced_position);
|
|
mfem::Vector displaced_minus(displaced_position);
|
|
displaced_plus.Add(difference_step, position_direction);
|
|
displaced_minus.Add(-difference_step, position_direction);
|
|
|
|
mfem::DenseMatrix jacobian_plus(displacement_jacobian);
|
|
mfem::DenseMatrix jacobian_minus(displacement_jacobian);
|
|
jacobian_plus.Add(difference_step, jacobian_direction);
|
|
jacobian_minus.Add(-difference_step, jacobian_direction);
|
|
|
|
const mapping::compactification::ExteriorMapInput input_plus{
|
|
reference_position, displaced_plus, jacobian_plus, coordinate, coordinate_gradient
|
|
};
|
|
const mapping::compactification::ExteriorMapInput input_minus{
|
|
reference_position, displaced_minus, jacobian_minus, coordinate, coordinate_gradient
|
|
};
|
|
|
|
mapping::compactification::ExteriorMapResult result_plus;
|
|
mapping::compactification::ExteriorMapResult result_minus;
|
|
|
|
REQUIRE(compactification.Evaluate(input_plus, result_plus) == mapping::MappingStatus::valid);
|
|
REQUIRE(compactification.Evaluate(input_minus, result_minus) == mapping::MappingStatus::valid);
|
|
|
|
for (int i = 0; i < dimension; ++i) {
|
|
const double position_finite_difference =
|
|
(result_plus.physical_position(i) - result_minus.physical_position(i)) / (2.0 * difference_step);
|
|
CHECK_THAT(position_finite_difference, WithinAbs(variation.physical_position_variation(i), tolerance));
|
|
|
|
for (int j = 0; j < dimension; ++j) {
|
|
const double jacobian_finite_difference =
|
|
(result_plus.mapping_jacobian(i, j) - result_minus.mapping_jacobian(i, j)) / (2.0 * difference_step);
|
|
CHECK_THAT(jacobian_finite_difference, WithinAbs(variation.mapping_jacobian_variation(i, j), tolerance));
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Kelvin Compactification Preserves Rotational Covariance",
|
|
tags::unit &tags::mapping &tags::kelvin
|
|
) {
|
|
constexpr double coordinate = 0.31;
|
|
constexpr double tolerance = 1.0e-12;
|
|
|
|
mapping::compactification::KelvinCompactification compactification({.r_star_ref = 1.0, .r_inf_ref = 4.0});
|
|
const mfem::Vector reference_position = make_vector(1.3, 0.4, -0.2);
|
|
const mfem::Vector displaced_position = make_vector(1.4, 0.2, -0.1);
|
|
const mfem::Vector coordinate_gradient = make_vector(0.16, -0.08, 0.03);
|
|
|
|
mfem::DenseMatrix displacement_jacobian = make_identity();
|
|
displacement_jacobian(0, 1) = 0.05;
|
|
displacement_jacobian(1, 0) = -0.02;
|
|
displacement_jacobian(2, 1) = 0.03;
|
|
|
|
const mapping::compactification::ExteriorMapInput input{
|
|
reference_position, displaced_position, displacement_jacobian, coordinate, coordinate_gradient
|
|
};
|
|
mapping::compactification::ExteriorMapResult result;
|
|
REQUIRE(compactification.Evaluate(input, result) == mapping::MappingStatus::valid);
|
|
|
|
mfem::DenseMatrix rotation(dimension);
|
|
rotation = 0.0;
|
|
rotation(0, 1) = -1.0;
|
|
rotation(1, 0) = 1.0;
|
|
rotation(2, 2) = 1.0;
|
|
|
|
mfem::Vector rotated_reference(dimension);
|
|
mfem::Vector rotated_displaced(dimension);
|
|
mfem::Vector rotated_coordinate_gradient(dimension);
|
|
rotation.Mult(reference_position, rotated_reference);
|
|
rotation.Mult(displaced_position, rotated_displaced);
|
|
rotation.Mult(coordinate_gradient, rotated_coordinate_gradient);
|
|
|
|
mfem::DenseMatrix temporary(dimension);
|
|
mfem::DenseMatrix rotated_displacement_jacobian(dimension);
|
|
mfem::Mult(rotation, displacement_jacobian, temporary);
|
|
mfem::MultABt(temporary, rotation, rotated_displacement_jacobian);
|
|
|
|
const mapping::compactification::ExteriorMapInput rotated_input{
|
|
rotated_reference, rotated_displaced, rotated_displacement_jacobian, coordinate, rotated_coordinate_gradient
|
|
};
|
|
mapping::compactification::ExteriorMapResult rotated_result;
|
|
REQUIRE(compactification.Evaluate(rotated_input, rotated_result) == mapping::MappingStatus::valid);
|
|
|
|
mfem::Vector expected_position(dimension);
|
|
rotation.Mult(result.physical_position, expected_position);
|
|
|
|
mfem::DenseMatrix expected_jacobian(dimension);
|
|
mfem::Mult(rotation, result.mapping_jacobian, temporary);
|
|
mfem::MultABt(temporary, rotation, expected_jacobian);
|
|
|
|
check_vector(rotated_result.physical_position, expected_position, tolerance);
|
|
check_matrix(rotated_result.mapping_jacobian, expected_jacobian, tolerance);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Kelvin Compactification Is Continuous At The Mesh Defined Stellar Surface",
|
|
tags::unit &tags::mapping &tags::kelvin
|
|
) {
|
|
constexpr double tolerance = 1.0e-14;
|
|
|
|
mapping::compactification::KelvinCompactification compactification({.r_star_ref = 1.0, .r_inf_ref = 4.0});
|
|
const mfem::Vector reference_position = make_vector(-0.5260553366425769, 0.5260553366425769, -0.6553163792879153);
|
|
const mfem::Vector displaced_position = make_vector(-0.55, 0.51, -0.63);
|
|
const mfem::Vector coordinate_gradient = make_vector(-0.18, 0.18, -0.22);
|
|
const mfem::DenseMatrix displacement_jacobian = make_identity();
|
|
|
|
REQUIRE(reference_position.Norml2() < 1.0);
|
|
|
|
const mapping::compactification::ExteriorMapInput input{
|
|
reference_position, displaced_position, displacement_jacobian, 0.0, coordinate_gradient
|
|
};
|
|
mapping::compactification::ExteriorMapResult result;
|
|
|
|
REQUIRE(compactification.Evaluate(input, result) == mapping::MappingStatus::valid);
|
|
check_vector(result.physical_position, displaced_position, tolerance);
|
|
CHECK(result.mapping_jacobian.Det() > 0.0);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Kelvin Compactification Has Correct Infinity And Coordinate Bound "
|
|
"Behavior",
|
|
tags::unit &tags::mapping &tags::kelvin
|
|
) {
|
|
constexpr double r_star = 1.0;
|
|
constexpr double r_inf = 4.0;
|
|
constexpr double radial_extent = r_inf - r_star;
|
|
constexpr double coordinate_tolerance = 1.0e-12;
|
|
constexpr double tolerance = 2.0e-11;
|
|
|
|
mapping::compactification::KelvinCompactification compactification(
|
|
{.r_star_ref = r_star, .r_inf_ref = r_inf, .coordinate_tolerance = coordinate_tolerance}
|
|
);
|
|
const mfem::DenseMatrix identity = make_identity();
|
|
const mfem::Vector coordinate_gradient = make_vector(1.0 / radial_extent, 0.0, 0.0);
|
|
|
|
for (const double coordinate : std::array{0.0, 0.25, 0.75, 0.95, 0.99, 0.999}) {
|
|
CAPTURE(coordinate);
|
|
|
|
const double computational_radius = r_star + coordinate * radial_extent;
|
|
const mfem::Vector reference_position = make_vector(computational_radius, 0.0, 0.0);
|
|
const mapping::compactification::ExteriorMapInput input{
|
|
reference_position, reference_position, identity, coordinate, coordinate_gradient
|
|
};
|
|
mapping::compactification::ExteriorMapResult result;
|
|
|
|
REQUIRE(compactification.Evaluate(input, result) == mapping::MappingStatus::valid);
|
|
CHECK_THAT(result.physical_position.Norml2() * (1.0 - coordinate), WithinAbs(r_star, tolerance));
|
|
}
|
|
|
|
const mfem::Vector reference_position = make_vector(r_inf, 0.0, 0.0);
|
|
mapping::compactification::ExteriorMapResult result;
|
|
|
|
CHECK(
|
|
compactification.Evaluate(
|
|
{reference_position, reference_position, identity, 1.0, coordinate_gradient}, result
|
|
) == mapping::MappingStatus::at_compactified_infinity
|
|
);
|
|
CHECK(
|
|
compactification.Evaluate(
|
|
{reference_position, reference_position, identity, 1.0 - 0.5 * coordinate_tolerance, coordinate_gradient},
|
|
result
|
|
) == mapping::MappingStatus::at_compactified_infinity
|
|
);
|
|
CHECK(
|
|
compactification.Evaluate(
|
|
{reference_position, reference_position, identity, 1.0 + 0.5 * coordinate_tolerance, coordinate_gradient},
|
|
result
|
|
) == mapping::MappingStatus::at_compactified_infinity
|
|
);
|
|
CHECK(
|
|
compactification.Evaluate(
|
|
{reference_position, reference_position, identity, 1.0 + 2.0 * coordinate_tolerance, coordinate_gradient},
|
|
result
|
|
) == mapping::MappingStatus::outside_reference_domain
|
|
);
|
|
CHECK(
|
|
compactification.Evaluate(
|
|
{reference_position, reference_position, identity, -2.0 * coordinate_tolerance, coordinate_gradient}, result
|
|
) == mapping::MappingStatus::outside_reference_domain
|
|
);
|
|
|
|
const mfem::Vector surface_position = make_vector(0.97, 0.0, 0.0);
|
|
CHECK(
|
|
compactification.Evaluate(
|
|
{surface_position, surface_position, identity, -0.5 * coordinate_tolerance, coordinate_gradient}, result
|
|
) == mapping::MappingStatus::valid
|
|
);
|
|
check_vector(result.physical_position, surface_position, tolerance);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Kelvin Compactification Rejects Invalid Inputs And Inverted Maps",
|
|
tags::unit &tags::mapping &tags::kelvin
|
|
) {
|
|
mapping::compactification::KelvinCompactification compactification({.r_star_ref = 1.0, .r_inf_ref = 4.0});
|
|
|
|
const mfem::Vector reference_position = make_vector(2.0, 0.0, 0.0);
|
|
const mfem::Vector displaced_position(reference_position);
|
|
const mfem::Vector coordinate_gradient = make_vector(1.0 / 3.0, 0.0, 0.0);
|
|
const mfem::Vector zero_gradient = make_vector(0.0, 0.0, 0.0);
|
|
const mfem::DenseMatrix identity = make_identity();
|
|
mapping::compactification::ExteriorMapResult result;
|
|
|
|
mfem::Vector wrong_dimension(2);
|
|
wrong_dimension = 1.0;
|
|
CHECK(
|
|
compactification.Evaluate(
|
|
{wrong_dimension, displaced_position, identity, 1.0 / 3.0, coordinate_gradient}, result
|
|
) == mapping::MappingStatus::invalid_dimension
|
|
);
|
|
CHECK(
|
|
compactification.Evaluate(
|
|
{reference_position, displaced_position, identity, 1.0 / 3.0, wrong_dimension}, result
|
|
) == mapping::MappingStatus::invalid_dimension
|
|
);
|
|
|
|
mfem::Vector non_finite_position(reference_position);
|
|
non_finite_position(1) = std::numeric_limits<double>::quiet_NaN();
|
|
CHECK(
|
|
compactification.Evaluate(
|
|
{non_finite_position, displaced_position, identity, 1.0 / 3.0, coordinate_gradient}, result
|
|
) == mapping::MappingStatus::non_finite_input
|
|
);
|
|
|
|
mfem::Vector non_finite_gradient(coordinate_gradient);
|
|
non_finite_gradient(2) = std::numeric_limits<double>::infinity();
|
|
CHECK(
|
|
compactification.Evaluate(
|
|
{reference_position, displaced_position, identity, 1.0 / 3.0, non_finite_gradient}, result
|
|
) == mapping::MappingStatus::non_finite_input
|
|
);
|
|
CHECK(
|
|
compactification.Evaluate(
|
|
{reference_position, displaced_position, identity, std::numeric_limits<double>::quiet_NaN(),
|
|
coordinate_gradient},
|
|
result
|
|
) == mapping::MappingStatus::non_finite_input
|
|
);
|
|
|
|
mfem::DenseMatrix singular_displacement_jacobian(dimension);
|
|
singular_displacement_jacobian = 0.0;
|
|
CHECK(
|
|
compactification.Evaluate(
|
|
{reference_position, displaced_position, singular_displacement_jacobian, 1.0 / 3.0, zero_gradient}, result
|
|
) == mapping::MappingStatus::non_positive_determinant
|
|
);
|
|
|
|
mfem::DenseMatrix inverted_displacement_jacobian = make_identity();
|
|
inverted_displacement_jacobian(0, 0) = -1.0;
|
|
CHECK(
|
|
compactification.Evaluate(
|
|
{reference_position, displaced_position, inverted_displacement_jacobian, 1.0 / 3.0, zero_gradient}, result
|
|
) == mapping::MappingStatus::non_positive_determinant
|
|
);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Kelvin Compactification Variation Rejects Invalid Inputs",
|
|
tags::unit &tags::mapping &tags::kelvin
|
|
) {
|
|
mapping::compactification::KelvinCompactification compactification({.r_star_ref = 1.0, .r_inf_ref = 4.0});
|
|
const mfem::Vector reference_position = make_vector(2.0, 0.0, 0.0);
|
|
const mfem::Vector displaced_position(reference_position);
|
|
const mfem::Vector coordinate_gradient = make_vector(1.0 / 3.0, 0.0, 0.0);
|
|
const mfem::DenseMatrix identity = make_identity();
|
|
const mapping::compactification::ExteriorMapInput input{
|
|
reference_position, displaced_position, identity, 1.0 / 3.0, coordinate_gradient
|
|
};
|
|
|
|
mapping::compactification::ExteriorMapResult result;
|
|
REQUIRE(compactification.Evaluate(input, result) == mapping::MappingStatus::valid);
|
|
|
|
const mfem::Vector valid_position_direction = make_vector(0.01, -0.02, 0.03);
|
|
const mfem::DenseMatrix valid_jacobian_direction = make_identity();
|
|
mapping::compactification::ExteriorMapVariation variation;
|
|
|
|
mfem::Vector wrong_dimension(2);
|
|
wrong_dimension = 0.0;
|
|
CHECK(
|
|
compactification.EvaluateVariation(input, result, {wrong_dimension, valid_jacobian_direction}, variation) ==
|
|
mapping::MappingStatus::invalid_dimension
|
|
);
|
|
|
|
mfem::DenseMatrix wrong_jacobian_dimension(2);
|
|
wrong_jacobian_dimension = 0.0;
|
|
CHECK(
|
|
compactification.EvaluateVariation(
|
|
input, result, {valid_position_direction, wrong_jacobian_dimension}, variation
|
|
) == mapping::MappingStatus::invalid_dimension
|
|
);
|
|
|
|
mfem::Vector non_finite_direction(valid_position_direction);
|
|
non_finite_direction(0) = std::numeric_limits<double>::quiet_NaN();
|
|
CHECK(
|
|
compactification.EvaluateVariation(
|
|
input, result, {non_finite_direction, valid_jacobian_direction}, variation
|
|
) == mapping::MappingStatus::non_finite_input
|
|
);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Kelvin Compactification Evaluations Are Independent",
|
|
tags::unit &tags::mapping &tags::kelvin
|
|
) {
|
|
constexpr double tolerance = 0.0;
|
|
|
|
mapping::compactification::KelvinCompactification compactification({.r_star_ref = 1.0, .r_inf_ref = 4.0});
|
|
const mfem::DenseMatrix identity = make_identity();
|
|
const mfem::Vector gradient_a = make_vector(0.12, 0.03, -0.02);
|
|
const mfem::Vector gradient_b = make_vector(-0.04, 0.15, 0.01);
|
|
const mfem::Vector reference_a = make_vector(1.5, 0.2, 0.1);
|
|
const mfem::Vector reference_b = make_vector(2.5, -0.3, 0.4);
|
|
|
|
const mapping::compactification::ExteriorMapInput input_a{reference_a, reference_a, identity, 0.25, gradient_a};
|
|
const mapping::compactification::ExteriorMapInput input_b{reference_b, reference_b, identity, 0.70, gradient_b};
|
|
|
|
mapping::compactification::ExteriorMapResult first_a;
|
|
mapping::compactification::ExteriorMapResult result_b;
|
|
mapping::compactification::ExteriorMapResult second_a;
|
|
|
|
REQUIRE(compactification.Evaluate(input_a, first_a) == mapping::MappingStatus::valid);
|
|
REQUIRE(compactification.Evaluate(input_b, result_b) == mapping::MappingStatus::valid);
|
|
REQUIRE(compactification.Evaluate(input_a, second_a) == mapping::MappingStatus::valid);
|
|
|
|
check_vector(first_a.physical_position, second_a.physical_position, tolerance);
|
|
check_matrix(first_a.mapping_jacobian, second_a.mapping_jacobian, tolerance);
|
|
} |