opm-simulators
Loading...
Searching...
No Matches
HyprePreconditioner.hpp
1/*
2 Copyright 2024 SINTEF AS
3 Copyright 2024-2025 Equinor ASA
4
5 This file is part of the Open Porous Media project (OPM).
6
7 OPM is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 OPM is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with OPM. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#ifndef OPM_HYPRE_PRECONDITIONER_HEADER_INCLUDED
22#define OPM_HYPRE_PRECONDITIONER_HEADER_INCLUDED
23
24#include <opm/common/ErrorMacros.hpp>
25#include <opm/common/TimingMacros.hpp>
26#include <opm/simulators/linalg/PreconditionerWithUpdate.hpp>
27#include <opm/simulators/linalg/PropertyTree.hpp>
28#include <opm/simulators/linalg/gpuistl/HypreInterface.hpp>
29#include <opm/simulators/linalg/gpuistl/detail/gpu_type_detection.hpp>
30
31#include <dune/common/fmatrix.hh>
32#include <dune/istl/bcrsmatrix.hh>
33
34#include <HYPRE.h>
35#include <HYPRE_krylov.h>
36#include <HYPRE_parcsr_ls.h>
37#include <_hypre_utilities.h>
38
39#include <numeric>
40#include <vector>
41
42namespace Hypre
43{
44
45namespace HypreInterface = Opm::gpuistl::HypreInterface;
46
65template <class M, class X, class Y, class Comm>
67{
68public:
70 using matrix_type = M;
72 using matrix_field_type = typename M::field_type;
74 using domain_type = X;
76 using range_type = Y;
78 using vector_field_type = typename X::field_type;
79
89 HyprePreconditioner(const M& A, const Opm::PropertyTree prm, const Comm& comm)
90 : A_(A)
91 , comm_(comm)
92 {
93 OPM_TIMEBLOCK(prec_construct);
94 int size;
95 int rank;
96 MPI_Comm mpi_comm;
97 if constexpr (std::is_same_v<Comm, Dune::Amg::SequentialInformation>) {
98 mpi_comm = MPI_COMM_SELF;
99 } else {
100 mpi_comm = comm.communicator();
101 }
102 MPI_Comm_size(mpi_comm, &size);
103 MPI_Comm_rank(mpi_comm, &rank);
104 if (size > 1) {
105 assert(size == comm.communicator().size());
106 assert(rank == comm.communicator().rank());
107 }
108 // Set use_gpu_backend_ to user value if specified, otherwise match input type
109 use_gpu_backend_ = prm.get<bool>("use_gpu", Opm::gpuistl::is_gpu_type<M>::value);
110
111 // Initialize Hypre library with backend configuration
112 HypreInterface::initialize(use_gpu_backend_);
113
114 // Create solver
115 solver_ = HypreInterface::createAMGSolver();
116 HypreInterface::setSolverParameters(solver_, prm, use_gpu_backend_);
117
118 // Setup parallel info and mappings
119 par_info_ = HypreInterface::setupHypreParallelInfo(comm_, A_);
120
121 // Setup sparsity pattern
122 sparsity_pattern_ = HypreInterface::setupSparsityPattern(A_, par_info_, par_info_.owner_first);
123
124 // Setup host arrays
125 host_arrays_.row_indexes = HypreInterface::computeRowIndexes(
126 A_, sparsity_pattern_.ncols, par_info_.local_dune_to_local_hypre, par_info_.owner_first);
127
128 // Create indices for vector operations - simple sequential indices for owned DOFs
129 host_arrays_.indices.resize(par_info_.N_owned);
130 std::iota(host_arrays_.indices.begin(), host_arrays_.indices.end(), par_info_.dof_offset);
131
132 // Setup continuous vector values buffer - only needed for non-owner-first
133 if (!par_info_.owner_first) {
134 host_arrays_.continuous_vector_values.resize(par_info_.N_owned);
135 }
136
137 // Allocate device arrays if using GPU backend
138 if (use_gpu_backend_) {
139#if HYPRE_USING_CUDA || HYPRE_USING_HIP
140 device_arrays_.ncols_device = hypre_CTAlloc(HYPRE_Int, par_info_.N_owned, HYPRE_MEMORY_DEVICE);
141 device_arrays_.rows_device = hypre_CTAlloc(HYPRE_BigInt, par_info_.N_owned, HYPRE_MEMORY_DEVICE);
142 device_arrays_.cols_device = hypre_CTAlloc(HYPRE_BigInt, sparsity_pattern_.nnz, HYPRE_MEMORY_DEVICE);
143 device_arrays_.row_indexes_device = hypre_CTAlloc(HYPRE_Int, par_info_.N_owned, HYPRE_MEMORY_DEVICE);
144 device_arrays_.indices_device = hypre_CTAlloc(HYPRE_BigInt, par_info_.N_owned, HYPRE_MEMORY_DEVICE);
145 device_arrays_.vector_buffer_device = hypre_CTAlloc(HYPRE_Real, par_info_.N_owned, HYPRE_MEMORY_DEVICE);
147 // For CPU input and GPU backend we need to allocate space for transfering the matrix values
148 // Note that the buffer must be allocated with the number of nonzeroes in the matrix, not the
149 // sparsity_pattern.nnz because we need to copy the entire matrix values from the host to the device.
150 device_arrays_.matrix_buffer_device = hypre_CTAlloc(HYPRE_Real, A_.nonzeroes(), HYPRE_MEMORY_DEVICE);
151 }
152 // Copy data to device
153 hypre_TMemcpy(device_arrays_.ncols_device, sparsity_pattern_.ncols.data(), HYPRE_Int, par_info_.N_owned, HYPRE_MEMORY_DEVICE, HYPRE_MEMORY_HOST);
154 hypre_TMemcpy(device_arrays_.rows_device, sparsity_pattern_.rows.data(), HYPRE_BigInt, par_info_.N_owned, HYPRE_MEMORY_DEVICE, HYPRE_MEMORY_HOST);
155 hypre_TMemcpy(device_arrays_.cols_device, sparsity_pattern_.cols.data(), HYPRE_BigInt, sparsity_pattern_.nnz, HYPRE_MEMORY_DEVICE, HYPRE_MEMORY_HOST);
156 hypre_TMemcpy(device_arrays_.row_indexes_device, host_arrays_.row_indexes.data(), HYPRE_Int, par_info_.N_owned, HYPRE_MEMORY_DEVICE, HYPRE_MEMORY_HOST);
157 hypre_TMemcpy(device_arrays_.indices_device, host_arrays_.indices.data(), HYPRE_BigInt, par_info_.N_owned, HYPRE_MEMORY_DEVICE, HYPRE_MEMORY_HOST);
158#endif
159 }
160
161 // Create Hypre matrix and vectors
162 A_hypre_ = HypreInterface::createMatrix(par_info_.N_owned, par_info_.dof_offset, comm_);
163 x_hypre_ = HypreInterface::createVector(par_info_.N_owned, par_info_.dof_offset, comm_);
164 b_hypre_ = HypreInterface::createVector(par_info_.N_owned, par_info_.dof_offset, comm_);
165
166 // Perform initial update
167 update();
168 }
169
176 {
177 // Clean up device arrays if allocated
178 if (use_gpu_backend_) {
179#if HYPRE_USING_CUDA || HYPRE_USING_HIP
180 if (device_arrays_.ncols_device) {
181 hypre_TFree(device_arrays_.ncols_device, HYPRE_MEMORY_DEVICE);
182 }
183 if (device_arrays_.rows_device) {
184 hypre_TFree(device_arrays_.rows_device, HYPRE_MEMORY_DEVICE);
185 }
186 if (device_arrays_.cols_device) {
187 hypre_T