mirror of
https://github.com/OPM/opm-simulators.git
synced 2026-10-24 22:57:42 -05:00
Introduce a wrapper that handles whether we should use the generic or old CUDA/HIP API based on what versions are present during compilation
124 lines
4.8 KiB
C++
124 lines
4.8 KiB
C++
/*
|
|
Copyright 2025 Equinor ASA
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "opm/simulators/linalg/PropertyTree.hpp"
|
|
#include <boost/test/tools/old/interface.hpp>
|
|
#include <config.h>
|
|
#include <cstddef>
|
|
#include <stdexcept>
|
|
|
|
#define BOOST_TEST_MODULE TestPreconditionerFactoryGPU
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
#include <cuda.h>
|
|
#include <cuda_runtime.h>
|
|
|
|
#include <opm/simulators/linalg/PreconditionerFactory.hpp>
|
|
#include <opm/simulators/linalg/PreconditionerFactory_impl.hpp>
|
|
|
|
using ScalarT = double;
|
|
constexpr static int Dim = 1;
|
|
|
|
using CommSeq = Dune::Amg::SequentialInformation;
|
|
|
|
using MatrixTypeCPU = Dune::BCRSMatrix<Dune::FieldMatrix<ScalarT, Dim, Dim>>;
|
|
using VectorCPU = Dune::BlockVector<Dune::FieldVector<ScalarT, 1>>;
|
|
using CpuOperatorType = Dune::MatrixAdapter<MatrixTypeCPU, VectorCPU, VectorCPU>;
|
|
using FactoryTypeCpu = Opm::PreconditionerFactory<CpuOperatorType, CommSeq>;
|
|
|
|
using GpuMatrixType = Opm::gpuistl::GpuSparseMatrixWrapper<ScalarT>;
|
|
using GpuVectorType = Opm::gpuistl::GpuVector<ScalarT>;
|
|
using GpuOperatorType = Dune::MatrixAdapter<GpuMatrixType, GpuVectorType, GpuVectorType>;
|
|
using FactoryTypeGpu = Opm::PreconditionerFactory<GpuOperatorType, CommSeq>;
|
|
|
|
BOOST_AUTO_TEST_CASE(TestMatrixAdapter)
|
|
{
|
|
const std::size_t N = 10;
|
|
const std::size_t nonZeroes = N * 3 - 2;
|
|
|
|
// The name of the preconditioner on the GPU directly (key) and
|
|
// the name of the wrapped preconditioner (value).
|
|
auto preconditionerPairs = std::map<std::string, std::string> {
|
|
{"ilu0", "gpuilu0"},
|
|
{"jac", "gpujac"},
|
|
{"opmilu0", "opmgpuilu0"},
|
|
{"dilu", "gpudilu"},
|
|
};
|
|
|
|
for (const auto& [gpuPreconditionerName, wrappedPreconditionerName] : preconditionerPairs) {
|
|
MatrixTypeCPU matrix(N, N, nonZeroes, MatrixTypeCPU::row_wise);
|
|
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);
|
|
}
|
|
}
|
|
|
|
for (std::size_t i = 0; i < N; ++i) {
|
|
matrix[i][i] = -2;
|
|
if (i < int(N) - 1) {
|
|
matrix[i][i + 1] = 1;
|
|
}
|
|
|
|
if (i > 0) {
|
|
matrix[i][i - 1] = 1;
|
|
}
|
|
}
|
|
GpuMatrixType gpuMatrix = GpuMatrixType::fromMatrix(matrix);
|
|
GpuOperatorType gpuOp(gpuMatrix);
|
|
|
|
CpuOperatorType cpuOp(matrix);
|
|
|
|
|
|
|
|
Opm::PropertyTree prm;
|
|
prm.put(std::string("type"), gpuPreconditionerName);
|
|
Opm::PropertyTree prmCPU;
|
|
prmCPU.put(std::string("type"), wrappedPreconditionerName);
|
|
|
|
|
|
auto preconditionerGPU = FactoryTypeGpu::create(gpuOp, prm);
|
|
auto preconditionerWrapped = FactoryTypeCpu::create(cpuOp, prmCPU);
|
|
|
|
|
|
// check for the standard basis {e_i}
|
|
// (e_i=(0,...,0, 1 (i-th place), 0, ..., 0))
|
|
for (std::size_t i = 0; i < N; ++i) {
|
|
VectorCPU inputVector(N);
|
|
inputVector[i][0] = 1.0;
|
|
VectorCPU outputVectorWrapped(N);
|
|
auto outputVectorGPU = Opm::gpuistl::GpuVector<ScalarT>(N);
|
|
auto inputVectorGPU = Opm::gpuistl::GpuVector<ScalarT>(inputVector);
|
|
preconditionerGPU->apply(outputVectorGPU, inputVectorGPU);
|
|
preconditionerWrapped->apply(outputVectorWrapped, inputVector);
|
|
|
|
auto outputVectorgGPUonCPU = outputVectorGPU.asDuneBlockVector<Dim>();
|
|
|
|
for (std::size_t component = 0; component < N; ++component) {
|
|
BOOST_TEST(outputVectorWrapped[component][0] == outputVectorgGPUonCPU[component][0],
|
|
"Component " << component << " of the output vector is not equal to the expected value."
|
|
<< "\nExpected: " << outputVectorWrapped[component][0]
|
|
<< ",\nbut got: " << outputVectorgGPUonCPU[component][0]
|
|
<< "\nfor preconditioner: " << gpuPreconditionerName
|
|
<< " and wrapped preconditioner: " << wrappedPreconditionerName);
|
|
}
|
|
}
|
|
}
|
|
}
|