opm-simulators
HypreCpuTransfers.hpp
1 /*
2  Copyright 2025 Equinor ASA
3 
4  This file is part of the Open Porous Media project (OPM).
5 
6  OPM is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  OPM is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with OPM. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #ifndef OPM_HYPRE_CPU_TRANSFERS_HPP
21 #define OPM_HYPRE_CPU_TRANSFERS_HPP
22 
23 #include <opm/simulators/linalg/gpuistl/hypreinterface/HypreDataStructures.hpp>
24 #include <opm/simulators/linalg/gpuistl/hypreinterface/HypreErrorHandling.hpp>
25 
26 #include <HYPRE.h>
27 #include <_hypre_utilities.h>
28 
30 {
31 
35  template <typename VectorType>
36  void
37  setContinuousVectorForHypre(const VectorType& v,
38  std::vector<HYPRE_Real>& continuous_vector_values,
39  const std::vector<int>& local_hypre_to_local_dune)
40  {
41  // Set v values solution vectors
42  for (size_t i = 0; i < local_hypre_to_local_dune.size(); ++i) {
43  continuous_vector_values[i] = v[local_hypre_to_local_dune[i]][0];
44  }
45  }
46 
50  template <typename VectorType>
51  void
53  const std::vector<HYPRE_Real>& continuous_vector_values,
54  const std::vector<int>& local_hypre_to_local_dune)
55  {
56  // Place values back in original positions
57  for (size_t i = 0; i < local_hypre_to_local_dune.size(); ++i) {
58  v[local_hypre_to_local_dune[i]][0] = continuous_vector_values[i];
59  }
60  }
61 
65 template <typename VectorType>
66 void
67 transferCpuVectorToHypre(const VectorType& cpu_vec,
68  HYPRE_IJVector hypre_vec,
69  HypreHostDataArrays& host_arrays,
70  [[maybe_unused]] const HypreDeviceDataArrays& device_arrays,
71  const ParallelInfo& par_info,
72  bool use_gpu_backend)
73 {
74  const int N = static_cast<int>(host_arrays.indices.size());
75  using T = typename VectorType::field_type;
76 
77  if (use_gpu_backend) {
78 #if HYPRE_USING_CUDA || HYPRE_USING_HIP
79  // GPU backend with CPU input: use pre-allocated device arrays
80  if (par_info.owner_first) {
81  // Direct host-to-device transfer for owner-first ordering
82  const T* values = &(cpu_vec[0][0]);
83  hypre_TMemcpy(
84  device_arrays.vector_buffer_device, values, HYPRE_Real, N, HYPRE_MEMORY_DEVICE, HYPRE_MEMORY_HOST);
85  OPM_HYPRE_SAFE_CALL(HYPRE_IJVectorSetValues(
86  hypre_vec, N, device_arrays.indices_device, device_arrays.vector_buffer_device));
87  } else {
88  // Use continuous storage and device buffer for non-owner-first ordering
90  cpu_vec, host_arrays.continuous_vector_values, par_info.local_hypre_to_local_dune);
91  hypre_TMemcpy(device_arrays.vector_buffer_device,
92  host_arrays.continuous_vector_values.data(),
93  HYPRE_Real,
94  N,
95  HYPRE_MEMORY_DEVICE,
96  HYPRE_MEMORY_HOST);
97  OPM_HYPRE_SAFE_CALL(HYPRE_IJVectorSetValues(
98  hypre_vec, N, device_arrays.indices_device, device_arrays.vector_buffer_device));
99  }
100 #endif // HYPRE_USING_CUDA || HYPRE_USING_HIP
101  } else {
102  // CPU backend with CPU input: use host arrays directly
103  if (par_info.owner_first) {
104  // Direct transfer for owner-first ordering
105  const T* values = &(cpu_vec[0][0]);
106  OPM_HYPRE_SAFE_CALL(
107  HYPRE_IJVectorSetValues(hypre_vec, N, const_cast<HYPRE_BigInt*>(host_arrays.indices.data()), values));
108  } else {
109  // Use continuous storage for non-owner-first ordering
111  cpu_vec, host_arrays.continuous_vector_values, par_info.local_hypre_to_local_dune);
112  OPM_HYPRE_SAFE_CALL(HYPRE_IJVectorSetValues(hypre_vec,
113  N,
114  const_cast<HYPRE_BigInt*>(host_arrays.indices.data()),
115  host_arrays.continuous_vector_values.data()));
116  }
117  }
118 
119  OPM_HYPRE_SAFE_CALL(HYPRE_IJVectorAssemble(hypre_vec));
120 }
121 
125 template <typename VectorType>
126 void
127 transferHypreToCpuVector(HYPRE_IJVector hypre_vec,
128  VectorType& cpu_vec,
129  HypreHostDataArrays& host_arrays,
130  [[maybe_unused]] const HypreDeviceDataArrays& device_arrays,
131  const ParallelInfo& par_info,
132  bool use_gpu_backend)
133 {
134  const int N = static_cast<int>(host_arrays.indices.size());
135  using T = typename VectorType::field_type;
136 
137  if (use_gpu_backend) {
138 #if HYPRE_USING_CUDA || HYPRE_USING_HIP
139  // GPU backend with CPU input: use pre-allocated device arrays
140  if (par_info.owner_first) {
141  // Direct device-to-host transfer for owner-first ordering
142  T* values = &(cpu_vec[0][0]);
143  OPM_HYPRE_SAFE_CALL(HYPRE_IJVectorGetValues(
144  hypre_vec, N, device_arrays.indices_device, device_arrays.vector_buffer_device));
145  hypre_TMemcpy(
146  values, device_arrays.vector_buffer_device, HYPRE_Real, N, HYPRE_MEMORY_HOST, HYPRE_MEMORY_DEVICE);
147  } else {
148  // Use device buffer and then remap for non-owner-first ordering
149  OPM_HYPRE_SAFE_CALL(HYPRE_IJVectorGetValues(
150  hypre_vec, N, device_arrays.indices_device, device_arrays.vector_buffer_device));
151  hypre_TMemcpy(host_arrays.continuous_vector_values.data(),
152  device_arrays.vector_buffer_device,
153  HYPRE_Real,
154  N,
155  HYPRE_MEMORY_HOST,
156  HYPRE_MEMORY_DEVICE);
158  cpu_vec, host_arrays.continuous_vector_values, par_info.local_hypre_to_local_dune);
159  }
160 #endif // HYPRE_USING_CUDA || HYPRE_USING_HIP
161  } else {
162  // CPU backend with CPU input: use host arrays directly
163  if (par_info.owner_first) {
164  // Direct transfer for owner-first ordering
165  T* values = &(cpu_vec[0][0]);
166  OPM_HYPRE_SAFE_CALL(
167  HYPRE_IJVectorGetValues(hypre_vec, N, const_cast<HYPRE_BigInt*>(host_arrays.indices.data()), values));
168  } else {
169  // Use continuous storage for non-owner-first ordering
170  OPM_HYPRE_SAFE_CALL(HYPRE_IJVectorGetValues(hypre_vec,
171  N,
172  const_cast<HYPRE_BigInt*>(host_arrays.indices.data()),
173  host_arrays.continuous_vector_values.data()));
175  cpu_vec, host_arrays.continuous_vector_values, par_info.local_hypre_to_local_dune);
176  }
177  }
178 }
179 
185 template <typename MatrixType>
186 void
187 updateMatrixFromCpuMatrix(const MatrixType& cpu_matrix,
188  HYPRE_IJMatrix hypre_matrix,
189  const SparsityPattern& sparsity_pattern,
190  const HypreHostDataArrays& host_arrays,
191  [[maybe_unused]] const HypreDeviceDataArrays& device_arrays,
192  bool use_gpu_backend)
193 {
194  const auto N = sparsity_pattern.rows.size();
195 
196  using T = typename MatrixType::field_type;
197  const T* values = &(cpu_matrix[0][0][0][0]);
198 
199  if (use_gpu_backend) {
200 #if HYPRE_USING_CUDA || HYPRE_USING_HIP
201  const auto nnz = cpu_matrix.nonzeroes(); // Total entries including ghost
202  hypre_TMemcpy(
203  device_arrays.matrix_buffer_device, values, HYPRE_Real, nnz, HYPRE_MEMORY_DEVICE, HYPRE_MEMORY_HOST);
204  OPM_HYPRE_SAFE_CALL(HYPRE_IJMatrixSetValues2(hypre_matrix,
205  N,
206  device_arrays.ncols_device,
207  device_arrays.rows_device,
208  device_arrays.row_indexes_device,
209  device_arrays.cols_device,
210  device_arrays.matrix_buffer_device));
211 #endif
212  } else {
213  OPM_HYPRE_SAFE_CALL(HYPRE_IJMatrixSetValues2(hypre_matrix,
214  N,
215  const_cast<HYPRE_Int*>(sparsity_pattern.ncols.data()),
216  const_cast<HYPRE_BigInt*>(sparsity_pattern.rows.data()),
217  const_cast<HYPRE_Int*>(host_arrays.row_indexes.data()),
218  const_cast<HYPRE_BigInt*>(sparsity_pattern.cols.data()),
219  values));
220  }
221 
222  OPM_HYPRE_SAFE_CALL(HYPRE_IJMatrixAssemble(hypre_matrix));
223 }
224 } // namespace Opm::gpuistl::HypreInterface
225 
226 #endif // OPM_HYPRE_CPU_TRANSFERS_HPP
std::vector< HYPRE_BigInt > indices
Global DOF indices for owned degrees of freedom.
Definition: HypreDataStructures.hpp:120
void setContinuousVectorForHypre(const VectorType &v, std::vector< HYPRE_Real > &continuous_vector_values, const std::vector< int > &local_hypre_to_local_dune)
Extract owned vector values in the order expected by HYPRE.
Definition: HypreCpuTransfers.hpp:37
Unified interface for Hypre operations with both CPU and GPU data structures.
Definition: HypreCpuTransfers.hpp:29
std::vector< HYPRE_Real > continuous_vector_values
Temporary buffer for vector values in non-owner-first ordering.
Definition: HypreDataStructures.hpp:128
Host arrays for HYPRE matrix and vector data transfers.
Definition: HypreDataStructures.hpp:106
GPU device memory arrays for HYPRE operations with GPU backend.
Definition: HypreDataStructures.hpp:137
void updateMatrixFromCpuMatrix(const MatrixType &cpu_matrix, HYPRE_IJMatrix hypre_matrix, const SparsityPattern &sparsity_pattern, const HypreHostDataArrays &host_arrays, [[maybe_unused]] const HypreDeviceDataArrays &device_arrays, bool use_gpu_backend)
Update Hypre matrix from CPU matrix Uses HYPRE_IJMatrixSetValues2 with pre-computed row_indexes...
Definition: HypreCpuTransfers.hpp:187
void setDuneVectorFromContinuousVector(VectorType &v, const std::vector< HYPRE_Real > &continuous_vector_values, const std::vector< int > &local_hypre_to_local_dune)
Distribute HYPRE vector values back to original vector positions.
Definition: HypreCpuTransfers.hpp:52
std::vector< HYPRE_Int > row_indexes
Pre-computed row start indexes for HYPRE_IJMatrixSetValues2.
Definition: HypreDataStructures.hpp:113
bool owner_first
Whether owned DOFs appear first in local Dune ordering.
Definition: HypreDataStructures.hpp:77
std::vector< HYPRE_BigInt > rows
Global row indices for owned rows (size: N_owned)
Definition: HypreDataStructures.hpp:91
void transferCpuVectorToHypre(const VectorType &cpu_vec, HYPRE_IJVector hypre_vec, HypreHostDataArrays &host_arrays, [[maybe_unused]] const HypreDeviceDataArrays &device_arrays, const ParallelInfo &par_info, bool use_gpu_backend)
Transfer CPU vector to Hypre vector.
Definition: HypreCpuTransfers.hpp:67
std::vector< HYPRE_Int > ncols
Non-zero entries per owned row (size: N_owned)
Definition: HypreDataStructures.hpp:88
void transferHypreToCpuVector(HYPRE_IJVector hypre_vec, VectorType &cpu_vec, HypreHostDataArrays &host_arrays, [[maybe_unused]] const HypreDeviceDataArrays &device_arrays, const ParallelInfo &par_info, bool use_gpu_backend)
Transfer Hypre vector to CPU vector.
Definition: HypreCpuTransfers.hpp:127
std::vector< int > local_hypre_to_local_dune
Mapping from local HYPRE indices to local Dune indices.
Definition: HypreDataStructures.hpp:59
std::vector< HYPRE_BigInt > cols
Global column indices in CSR format (size: nnz)
Definition: HypreDataStructures.hpp:94
Compressed Sparse Row (CSR) sparsity pattern for HYPRE matrix assembly.
Definition: HypreDataStructures.hpp:86
Parallel domain decomposition information for HYPRE-Dune interface.
Definition: HypreDataStructures.hpp:37