/* Copyright 2022-2023 SINTEF AS This file is part of the Open Porous Media project (OPM). OPM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OPM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OPM. If not, see . */ #include #define BOOST_TEST_MODULE TestSolverAdapter #include #include #include #include #include static const constexpr int dim = 3; using Matrix = Dune::BCRSMatrix>; using Vector = Dune::BlockVector>; using Moperator = Dune::MatrixAdapter; using PrecondFactory = Opm::PreconditionerFactory; using SolverAdapter = Opm::gpuistl::SolverAdapter; namespace { auto createSolverAdapterWithMatrix(const size_t N = 10) { const int nonZeroes = N * 3 - 2; // We need to hold the matrix in memory somehow, but we don't want to deference // a pointer all the time (quality of life...): auto matrixPtr = std::make_shared(N, N, nonZeroes, Matrix::row_wise); auto& matrix = *matrixPtr; for (auto row = matrix.createbegin(); row != matrix.createend(); ++row) { // Add nonzeros for left neighbour, diagonal and right neighbour if (row.index() > 0) { row.insert(row.index() - 1); } row.insert(row.index()); if (row.index() < matrix.N() - 1) { row.insert(row.index() + 1); } } // This might not be the most elegant way of filling in a Dune sparse matrix, but it works. for (size_t i = 0; i < N; ++i) { for (int k = 0; k < dim; ++k) { matrix[i][i][k][k] = -2; } if (i < N - 1) { for (int k = 0; k < dim; ++k) { matrix[i][i + 1][k][k] = 1; } } if (i > 0) { for (int k = 0; k < dim; ++k) { matrix[i][i - 1][k][k] = 1; } } } auto op = std::make_shared(matrix); auto sp = std::make_shared>(); auto prm = Opm::PropertyTree(); prm.put("relaxation", 1.0); prm.put("type", "CUILU0"); auto prec = PrecondFactory::create(*op, prm); auto solverAdapter = std::make_shared(*op, *sp, prec, 1.0, 10, 0, Dune::Amg::SequentialInformation()); return std::make_tuple(matrixPtr, solverAdapter, op, sp); } } // namespace BOOST_AUTO_TEST_CASE(TestCreation) { BOOST_CHECK_NO_THROW(createSolverAdapterWithMatrix();); } BOOST_AUTO_TEST_CASE(TestSolve) { const size_t N = 10; auto [matrix, solverAdapter, op, sp] = createSolverAdapterWithMatrix(N); Vector xActual(N), xInitial(N), b(N); for (size_t i = 0; i < N; ++i) { for (size_t j = 0; j < dim; ++j) { xActual[i][j] = 1.0; xInitial[i][j] = 0.1 * i; } } matrix->mv(xActual, b); Dune::InverseOperatorResult res; solverAdapter->apply(xInitial, b, res); for (size_t i = 0; i < N; ++i) { for (size_t j = 0; j < dim; ++j) { // This should actually be up to rounding exact since ILU is just the inverse // for this matrix. BOOST_CHECK_CLOSE(xActual[i][j], xInitial[i][j], 1e-13); } } }