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_GPU_HPP
21 #define OPM_HYPRE_CPU_TRANSFERS_GPU_HPP
22 
23 #include <opm/simulators/linalg/hypreinterface/HypreDataStructures.hpp>
24 #include <opm/simulators/linalg/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
52  setDuneVectorFromContinuousVector(VectorType& v,
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  linalg::HypreInterface::HostDataArrays& host_arrays,
70  const linalg::HypreInterface::DeviceDataArrays& device_arrays,
71  const linalg::HypreInterface::ParallelInfo& par_info)
72 {
73  const int N = static_cast<int>(host_arrays.indices.size());
74  using T = typename VectorType::field_type;
75 
76  // GPU backend with CPU input: use pre-allocated device arrays
77  if (par_info.owner_first) {
78  // Direct host-to-device transfer for owner-first ordering
79  const T* values = &(cpu_vec[0][0]);
80  hypre_TMemcpy(
81  device_arrays.vector_buffer_device, values, HYPRE_Real, N, HYPRE_MEMORY_DEVICE, HYPRE_MEMORY_HOST);
82  OPM_HYPRE_SAFE_CALL(HYPRE_IJVectorSetValues(
83  hypre_vec, N, device_arrays.indices_device, device_arrays.vector_buffer_device));
84  } else {
85  // Use continuous storage and device buffer for non-owner-first ordering
86  setContinuousVectorForHypre(
87  cpu_vec, host_arrays.continuous_vector_values, par_info.local_hypre_to_local_dune);
88  hypre_TMemcpy(device_arrays.vector_buffer_device,
89  host_arrays.continuous_vector_values.data(),
90  HYPRE_Real,
91  N,
92  HYPRE_MEMORY_DEVICE,
93  HYPRE_MEMORY_HOST);
94  OPM_HYPRE_SAFE_CALL(HYPRE_IJVectorSetValues(
95  hypre_vec, N, device_arrays.indices_device, device_arrays.vector_buffer_device));
96  }
97 }
98 
102 template <typename VectorType>
103 void
104 transferHypreToCpuVector(HYPRE_IJVector hypre_vec,
105  VectorType& cpu_vec,
106  linalg::HypreInterface::HostDataArrays& host_arrays,
107  const linalg::HypreInterface::DeviceDataArrays& device_arrays,
108  const linalg::HypreInterface::ParallelInfo& par_info)
109 {
110  const int N = static_cast<int>(host_arrays.indices.size());
111  using T = typename VectorType::field_type;
112 
113  // GPU backend with CPU input: use pre-allocated device arrays
114  if (par_info.owner_first) {
115  // Direct device-to-host transfer for owner-first ordering
116  T* values = &(cpu_vec[0][0]);
117  OPM_HYPRE_SAFE_CALL(HYPRE_IJVectorGetValues(
118  hypre_vec, N, device_arrays.indices_device, device_arrays.vector_buffer_device));
119  hypre_TMemcpy(
120  values, device_arrays.vector_buffer_device, HYPRE_Real, N, HYPRE_MEMORY_HOST, HYPRE_MEMORY_DEVICE);
121  } else {
122  // Use device buffer and then remap for non-owner-first ordering
123  OPM_HYPRE_SAFE_CALL(HYPRE_IJVectorGetValues(
124  hypre_vec, N, device_arrays.indices_device, device_arrays.vector_buffer_device));
125  hypre_TMemcpy(host_arrays.continuous_vector_values.data(),
126  device_arrays.vector_buffer_device,
127  HYPRE_Real,
128  N,
129  HYPRE_MEMORY_HOST,
130  HYPRE_MEMORY_DEVICE);
131  setDuneVectorFromContinuousVector(
132  cpu_vec, host_arrays.continuous_vector_values, par_info.local_hypre_to_local_dune);
133  }
134 }
135 
141 template <typename MatrixType>
142 void
143 updateMatrixFromCpuMatrix(const MatrixType& cpu_matrix,
144  HYPRE_IJMatrix hypre_matrix,
145  const linalg::HypreInterface::SparsityPattern& sparsity_pattern,
146  const linalg::HypreInterface::DeviceDataArrays& device_arrays)
147 {
148  const auto N = sparsity_pattern.rows.size();
149 
150  using T = typename MatrixType::field_type;
151  const T* values = &(cpu_matrix[0][0][0][0]);
152 
153  const auto nnz = cpu_matrix.nonzeroes(); // Total entries including ghost
154  hypre_TMemcpy(
155  device_arrays.matrix_buffer_device, values, HYPRE_Real, nnz, HYPRE_MEMORY_DEVICE, HYPRE_MEMORY_HOST);
156  OPM_HYPRE_SAFE_CALL(HYPRE_IJMatrixSetValues2(hypre_matrix,
157  N,
158  device_arrays.ncols_device,
159  device_arrays.rows_device,
160  device_arrays.row_indexes_device,
161  device_arrays.cols_device,
162  device_arrays.matrix_buffer_device));
163 }
164 
165 } // namespace Opm::gpuistl::HypreInterface
166 
167 #endif // OPM_HYPRE_CPU_TRANSFERS_GPU_HPP
Definition: HypreCpuTransfers.hpp:29