/* 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 TestGpuSparseMatrixOperations #include #include #include #include #include #include #include #include #include #include using NumericTypes = boost::mpl::list; BOOST_AUTO_TEST_CASE_TEMPLATE(FlattenAndInvertDiagonalWith3By3Blocks, T, NumericTypes) { const size_t blocksize = 3; const size_t N = 2; const int nonZeroes = 3; using M = Dune::FieldMatrix; using SpMatrix = Dune::BCRSMatrix; /* create this sparse matrix | |1 2 3| | 1 0 0| | | |5 2 3| | 0 1 0| | | |2 1 1| | 0 0 1| | | | | |0 0 0| |-1 0 0| | | |0 0 0| | 0 -1 0| | | |0 0 0| | 0 0 -1| | The diagonal elements inverted, and put in a vector should look like this | |-1/4 1/4 0| | | | 1/4 -4/5 3| | | | 1/4 3/4 -2| | | | | | -1 0 0| | | | 0 -1 0| | | | 0 0 -1| | */ SpMatrix B(N, N, nonZeroes, SpMatrix::row_wise); for (auto row = B.createbegin(); row != B.createend(); ++row) { row.insert(row.index()); if (row.index() == 0) { row.insert(row.index() + 1); } } B[0][0][0][0] = 1.0; B[0][0][0][1] = 2.0; B[0][0][0][2] = 3.0; B[0][0][1][0] = 5.0; B[0][0][1][1] = 2.0; B[0][0][1][2] = 3.0; B[0][0][2][0] = 2.0; B[0][0][2][1] = 1.0; B[0][0][2][2] = 1.0; B[0][1][0][0] = 1.0; B[0][1][1][1] = 1.0; B[0][1][2][2] = 1.0; B[1][1][0][0] = -1.0; B[1][1][1][1] = -1.0; B[1][1][2][2] = -1.0; Opm::gpuistl::GpuSparseMatrix m = Opm::gpuistl::GpuSparseMatrix::fromMatrix(B); Opm::gpuistl::GpuVector dInvDiag(blocksize * blocksize * N); Opm::gpuistl::detail::JAC::invertDiagonalAndFlatten( m.getNonZeroValues().data(), m.getRowIndices().data(), m.getColumnIndices().data(), N, dInvDiag.data()); std::vector expectedInvDiag {-1.0 / 4.0, 1.0 / 4.0, 0.0, 1.0 / 4.0, -5.0 / 4.0, 3.0, 1.0 / 4.0, 3.0 / 4.0, -2.0, -1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, -1.0}; std::vector computedInvDiag = dInvDiag.asStdVector(); BOOST_REQUIRE_EQUAL(expectedInvDiag.size(), computedInvDiag.size()); for (size_t i = 0; i < expectedInvDiag.size(); ++i) { BOOST_CHECK_CLOSE(expectedInvDiag[i], computedInvDiag[i], 1e-7); } } BOOST_AUTO_TEST_CASE_TEMPLATE(FlattenAndInvertDiagonalWith2By2Blocks, T, NumericTypes) { const size_t blocksize = 2; const size_t N = 2; const int nonZeroes = 3; using M = Dune::FieldMatrix; using SpMatrix = Dune::BCRSMatrix; /* create this sparse matrix | | 1 2| | 1 0| | | |1/2 2| | 0 1| | | | | | 0 0| |-1 0| | | | 0 0| | 0 -1| | The diagonal elements inverted, and put in a vector should look like this | | 2 - 2| | | |-1/2 1| | | | | | -1 0| | | | 0 -1| | */ SpMatrix B(N, N, nonZeroes, SpMatrix::row_wise); for (auto row = B.createbegin(); row != B.createend(); ++row) { row.insert(row.index()); if (row.index() == 0) { row.insert(row.index() + 1); } } B[0][0][0][0] = 1.0; B[0][0][0][1] = 2.0; B[0][0][1][0] = 1.0 / 2.0; B[0][0][1][1] = 2.0; B[0][1][0][0] = 1.0; B[0][1][1][1] = 1.0; B[1][1][0][0] = -1.0; B[1][1][1][1] = -1.0; Opm::gpuistl::GpuSparseMatrix m = Opm::gpuistl::GpuSparseMatrix::fromMatrix(B); Opm::gpuistl::GpuVector dInvDiag(blocksize * blocksize * N); Opm::gpuistl::detail::JAC::invertDiagonalAndFlatten( m.getNonZeroValues().data(), m.getRowIndices().data(), m.getColumnIndices().data(), N, dInvDiag.data()); std::vector expectedInvDiag {2.0, -2.0, -1.0 / 2.0, 1.0, -1.0, 0.0, 0.0, -1.0}; std::vector computedInvDiag = dInvDiag.asStdVector(); BOOST_REQUIRE_EQUAL(expectedInvDiag.size(), computedInvDiag.size()); for (size_t i = 0; i < expectedInvDiag.size(); ++i) { BOOST_CHECK_CLOSE(expectedInvDiag[i], computedInvDiag[i], 1e-7); } }