The test suite is extensive. Note that LLMs were used to aid in the development of the test suite. All LLM generated code was manually reviewed.
59 lines
2.4 KiB
C++
59 lines
2.4 KiB
C++
#include <array>
|
|
#include <initializer_list>
|
|
#include <memory>
|
|
#include <catch2/catch_approx.hpp>
|
|
#include <catch2/catch_test_macros.hpp>
|
|
#include "mfem/linalg/densemat.hpp"
|
|
#include "serif/backend/mfem/solver/preconditioner/coupling.hpp"
|
|
#include "serif/backend/mfem/solver/preconditioner/inverse/diagonal.hpp"
|
|
|
|
namespace
|
|
{
|
|
namespace backend = serif::solver::preconditioner::backend::mfem;
|
|
using Order = serif::solver::preconditioner::strategies::coupling::CouplingOrder;
|
|
|
|
/** @brief Express the original small physical couplings in row-major order. */
|
|
std::shared_ptr<mfem::DenseMatrix> matrix(const int rows, const int columns, const std::initializer_list<double> entries)
|
|
{
|
|
REQUIRE(entries.size() == static_cast<std::size_t>(rows * columns));
|
|
auto result = std::make_shared<mfem::DenseMatrix>(rows, columns);
|
|
auto entry = entries.begin();
|
|
for (int row = 0; row < rows; ++row)
|
|
{
|
|
for (int column = 0; column < columns; ++column)
|
|
{
|
|
(*result)(row, column) = *entry++;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/** @brief Prepare the original signed scalar inverse without another test-only numerical implementation. */
|
|
backend::Inverse scalar_inverse(const double diagonal)
|
|
{
|
|
const auto inverse = backend::try_diagonal_inverse(std::array{diagonal});
|
|
REQUIRE(inverse);
|
|
return *inverse;
|
|
}
|
|
} // namespace
|
|
|
|
TEST_CASE("Generic coupling preserves the original material-gravity factorization tolerances", "[preconditioner][parity][unit]")
|
|
{
|
|
const auto material = scalar_inverse(2.0);
|
|
const auto gravity = scalar_inverse(5.0);
|
|
const backend::TwoBlockCouplings cross{.first_from_second = matrix(1, 1, {7.0}), .second_from_first = matrix(1, 1, {3.0})};
|
|
const std::array orders{Order::independent, Order::second_then_first, Order::lower_diagonal_upper};
|
|
const std::array<std::array<double, 2>, 3> expected{{{5.5, 2.6}, {-3.6, 2.6}, {7.95, -0.7}}};
|
|
mfem::Vector rhs(2), result(2);
|
|
rhs[0] = 11.0;
|
|
rhs[1] = 13.0;
|
|
for (std::size_t policy = 0; policy < orders.size(); ++policy)
|
|
{
|
|
const auto inverse = backend::try_coupled_inverse(material, gravity, cross, orders[policy]);
|
|
REQUIRE(inverse);
|
|
inverse->action->Mult(rhs, result);
|
|
CHECK(result[0] == Catch::Approx(expected[policy][0]).margin(2.0e-14));
|
|
CHECK(result[1] == Catch::Approx(expected[policy][1]).margin(2.0e-14));
|
|
}
|
|
}
|