107 lines
4.4 KiB
C++
107 lines
4.4 KiB
C++
// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
|
|
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
|
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
|
//
|
|
// This file is part of the MFEM library. For more information and source code
|
|
// availability visit https://mfem.org.
|
|
//
|
|
// MFEM is free software; you can redistribute it and/or modify it under the
|
|
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
|
// CONTRIBUTING.md for details.
|
|
|
|
#include "mfem.hpp"
|
|
#include "unit_tests.hpp"
|
|
|
|
using namespace mfem;
|
|
|
|
#ifdef MFEM_USE_EXCEPTIONS
|
|
|
|
TEST_CASE("Operator", "[Operator]")
|
|
{
|
|
// Define diagonal sparse matrix
|
|
Vector diag(5);
|
|
diag = 12.34;
|
|
|
|
SparseMatrix A(diag);
|
|
|
|
CGSolver cg;
|
|
cg.SetOperator(A);
|
|
|
|
SECTION("ProductNotIterative")
|
|
{
|
|
// When cg is in a product (on the right), we require cg->iterative_mode to be false.
|
|
|
|
// First, test that the failing version throws an exception.
|
|
cg.iterative_mode = true;
|
|
REQUIRE_THROWS(ProductOperator(&A, &cg, false, false));
|
|
REQUIRE_THROWS(TripleProductOperator(&A, &cg, &cg, false, false,
|
|
false));
|
|
REQUIRE_THROWS(RAPOperator(A, cg, cg));
|
|
|
|
// Second, test that the correct version does not throw.
|
|
cg.iterative_mode = false;
|
|
REQUIRE_NOTHROW(ProductOperator(&A, &cg, false, false));
|
|
REQUIRE_NOTHROW(TripleProductOperator(&A, &cg, &cg, false, false,
|
|
false));
|
|
REQUIRE_NOTHROW(RAPOperator(A, cg, cg));
|
|
}
|
|
}
|
|
|
|
#endif // MFEM_USE_EXCEPTIONS
|
|
|
|
double constrained_mult_application(Operator &op, Array<int> &list,
|
|
const Vector &input, const Vector &truth, const bool transpose = false,
|
|
const Operator::DiagonalPolicy diag_policy = Operator::DiagonalPolicy::DIAG_ONE)
|
|
{
|
|
const ConstrainedOperator constrained_op(&op, list, false, diag_policy);
|
|
// Make sure test is well formed.
|
|
CHECK(op.Width() == input.Size());
|
|
CHECK(op.Height() == truth.Size());
|
|
Vector y(op.Height());
|
|
if (transpose)
|
|
{
|
|
constrained_op.MultTranspose(input,y);
|
|
}
|
|
else
|
|
{
|
|
constrained_op.Mult(input,y);
|
|
}
|
|
auto error = truth;
|
|
error -= y;
|
|
auto error_norm = error.Norml2() / truth.Norml2();
|
|
return error_norm;
|
|
}
|
|
|
|
TEST_CASE("ConstrainedOperator", "[ConstrainedOperator][Operator]")
|
|
{
|
|
INFO("Constrained Operator");
|
|
// Compare against manual calculation with random 5x5 matrix and input vector.
|
|
// Should leave first and fourth entries the same for DIAG_ONE, and zero them
|
|
// out for DIAG_ZERO.
|
|
DenseMatrix A(
|
|
{
|
|
{27.531558467881045, 89.30012682807859, 10.363408976942745, 78.97400291889993, 18.703638414621903 },
|
|
{79.33627624921924, 73.99743336818197, 85.27832370283267, 11.13213120570734, 27.59542336254316},
|
|
{26.474414966916925, 17.38636366801234, 41.423691595967114, 94.06135498225382, 18.379018138899884},
|
|
{45.83203742468528, 90.10126513894627, 3.8488872448446343, 41.03858238887901, 14.429143614063412},
|
|
{26.2225932381016, 3.8232081630501513, 17.820832452264256, 3.919068726019015, 92.66801110040682}
|
|
});
|
|
Array<int> list(2);
|
|
list[0] = 0;
|
|
list[1] = 3;
|
|
Vector x({62.06906909143156, 63.31143800813616, 59.6546764326512, 48.10287136113324, 0.4275152133050852});
|
|
// DIAG_ONE checks
|
|
Vector y_true({62.06906909143156, 9783.932185967293, 3579.7299142176153, 48.10287136113324, 1344.7657848396123});
|
|
Vector y_true_transpose({62.06906909143156, 5723.696294059853, 7877.828900340113, 48.10287136113324, 2883.1173002839714});
|
|
REQUIRE(constrained_mult_application(A, list, x, y_true) == MFEM_Approx(0.0));
|
|
REQUIRE(constrained_mult_application(A, list, x, y_true_transpose,
|
|
true) == MFEM_Approx(0.0));
|
|
// DIAG_ZERO checks
|
|
Vector y_true_zero({0.0, 9783.932185967293, 3579.7299142176153, 0.0, 1344.7657848396123});
|
|
Vector y_true_zero_transpose({0.0, 5723.696294059853, 7877.828900340113, 0.0, 2883.1173002839714});
|
|
REQUIRE(constrained_mult_application(A, list, x, y_true_zero, false,
|
|
Operator::DiagonalPolicy::DIAG_ZERO) == MFEM_Approx(0.0));
|
|
REQUIRE(constrained_mult_application(A, list, x, y_true_zero_transpose, true,
|
|
Operator::DiagonalPolicy::DIAG_ZERO) == MFEM_Approx(0.0));
|
|
}
|