opm-simulators
HypreSetup.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_SETUP_HPP
21 #define OPM_HYPRE_SETUP_HPP
22 
23 #include <opm/simulators/linalg/PropertyTree.hpp>
24 #include <opm/simulators/linalg/gpuistl/detail/gpu_type_detection.hpp>
25 #include <opm/simulators/linalg/gpuistl/hypreinterface/HypreDataStructures.hpp>
26 #include <opm/simulators/linalg/gpuistl/hypreinterface/HypreErrorHandling.hpp>
27 
28 #include <dune/istl/owneroverlapcopy.hh>
29 #include <dune/istl/paamg/graph.hh>
30 #include <dune/istl/paamg/pinfo.hh>
31 #include <dune/istl/repartition.hh>
32 
33 #if HAVE_CUDA
34 #if USE_HIP
35 #include <opm/simulators/linalg/gpuistl_hip/GpuSparseMatrixWrapper.hpp>
36 #else
37 #include <opm/simulators/linalg/gpuistl/GpuSparseMatrixWrapper.hpp>
38 #endif
39 #endif // HAVE_CUDA
40 
41 #include <HYPRE.h>
42 #include <HYPRE_parcsr_ls.h>
43 #include <_hypre_utilities.h>
44 
45 #include <algorithm>
46 #include <cstddef>
47 #include <numeric>
48 
50 {
51 
52 // GPU-specific helper functions
53 template <typename T, bool ForceLegacy>
54 SparsityPattern setupSparsityPatternFromGpuMatrix(const GpuSparseMatrixWrapper<T, ForceLegacy>& gpu_matrix,
55  const ParallelInfo& par_info,
56  bool owner_first);
57 
58 template <typename T, bool ForceLegacy>
59 std::vector<HYPRE_Int> computeRowIndexesWithMappingGpu(const GpuSparseMatrixWrapper<T, ForceLegacy>& gpu_matrix,
60  const std::vector<int>& local_dune_to_local_hypre);
61 
62 // Serial helper functions
63 ParallelInfo setupHypreParallelInfoSerial(HYPRE_Int N);
64 
65 // Parallel helper functions
66 template <typename CommType, typename MatrixType>
67 ParallelInfo setupHypreParallelInfoParallel(const CommType& comm, const MatrixType& matrix);
68 
69 template <typename MatrixType>
70 SparsityPattern
71 setupSparsityPatternFromCpuMatrix(const MatrixType& matrix, const ParallelInfo& par_info, bool owner_first);
72 
73 template <typename MatrixType>
74 std::vector<HYPRE_Int> computeRowIndexesWithMappingCpu(const MatrixType& matrix,
75  const std::vector<HYPRE_Int>& ncols,
76  const std::vector<int>& local_dune_to_local_hypre,
77  bool owner_first);
78 
79 template <typename MatrixType>
80 std::vector<HYPRE_Int> computeRowIndexesWithMappingCpu(const MatrixType& matrix,
81  const std::vector<int>& local_dune_to_local_hypre);
88 inline void
89 initialize([[maybe_unused]] bool use_gpu_backend)
90 {
91  // Set memory location and execution policy
92 #if HYPRE_USING_CUDA || HYPRE_USING_HIP
93  if (use_gpu_backend) {
94  OPM_HYPRE_SAFE_CALL(HYPRE_SetMemoryLocation(HYPRE_MEMORY_DEVICE));
95  OPM_HYPRE_SAFE_CALL(HYPRE_SetExecutionPolicy(HYPRE_EXEC_DEVICE));
96  // use hypre's SpGEMM instead of vendor implementation
97  OPM_HYPRE_SAFE_CALL(HYPRE_SetSpGemmUseVendor(false));
98  // use cuRand for PMIS
99  OPM_HYPRE_SAFE_CALL(HYPRE_SetUseGpuRand(1));
100  OPM_HYPRE_SAFE_CALL(HYPRE_DeviceInitialize());
101  OPM_HYPRE_SAFE_CALL(HYPRE_PrintDeviceInfo());
102  } else
103 #endif
104  {
105  OPM_HYPRE_SAFE_CALL(HYPRE_SetMemoryLocation(HYPRE_MEMORY_HOST));
106  OPM_HYPRE_SAFE_CALL(HYPRE_SetExecutionPolicy(HYPRE_EXEC_HOST));
107  }
108 }
109 
116 inline HYPRE_Solver
118 {
119  HYPRE_Solver solver;
120  OPM_HYPRE_SAFE_CALL(HYPRE_BoomerAMGCreate(&solver));
121  return solver;
122 }
123 
132 inline void
133 setSolverParameters(HYPRE_Solver solver, const PropertyTree& prm, bool use_gpu_backend)
134 {
135  // Set parameters from property tree with defaults
136  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetPrintLevel(solver, prm.get<int>("print_level", 0)));
137  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetMaxIter(solver, prm.get<int>("max_iter", 1)));
138  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetStrongThreshold(solver, prm.get<double>("strong_threshold", 0.5)));
139  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetAggTruncFactor(solver, prm.get<double>("agg_trunc_factor", 0.3)));
140  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetInterpType(solver, prm.get<int>("interp_type", 6)));
141  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetMaxLevels(solver, prm.get<int>("max_levels", 15)));
142  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetTol(solver, prm.get<double>("tolerance", 0.0)));
143 
144  if (use_gpu_backend) {
145  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetRelaxType(solver, prm.get<int>("relax_type", 16)));
146  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetCoarsenType(solver, prm.get<int>("coarsen_type", 8)));
147  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetAggNumLevels(solver, prm.get<int>("agg_num_levels", 0)));
148  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetAggInterpType(solver, prm.get<int>("agg_interp_type", 6)));
149  // Keep transpose to avoid SpMTV
150  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetKeepTranspose(solver, true));
151  } else {
152  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetRelaxType(solver, prm.get<int>("relax_type", 13)));
153  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetCoarsenType(solver, prm.get<int>("coarsen_type", 10)));
154  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetAggNumLevels(solver, prm.get<int>("agg_num_levels", 1)));
155  HYPRE_SAFE_CALL(HYPRE_BoomerAMGSetAggInterpType(solver, prm.get<int>("agg_interp_type", 4)));
156  }
157 }
158 
168 template <typename CommType>
169 HYPRE_IJMatrix
170 createMatrix(HYPRE_Int N, HYPRE_Int dof_offset, const CommType& comm)
171 {
172  HYPRE_IJMatrix matrix;
173  MPI_Comm mpi_comm;
174  if constexpr (std::is_same_v<CommType, Dune::Amg::SequentialInformation>) {
175  mpi_comm = MPI_COMM_SELF;
176  } else {
177  mpi_comm = comm.communicator();
178  }
179  OPM_HYPRE_SAFE_CALL(
180  HYPRE_IJMatrixCreate(mpi_comm, dof_offset, dof_offset + (N - 1), dof_offset, dof_offset + (N - 1), &matrix));
181  OPM_HYPRE_SAFE_CALL(HYPRE_IJMatrixSetObjectType(matrix, HYPRE_PARCSR));
182  OPM_HYPRE_SAFE_CALL(HYPRE_IJMatrixInitialize(matrix));
183  return matrix;
184 }
185 
195 template <typename CommType>
196 HYPRE_IJVector
197 createVector(HYPRE_Int N, HYPRE_Int dof_offset, const CommType& comm)
198 {
199  HYPRE_IJVector vector;
200  MPI_Comm mpi_comm;
201  if constexpr (std::is_same_v<CommType, Dune::Amg::SequentialInformation>) {
202  mpi_comm = MPI_COMM_SELF;
203  } else {
204  mpi_comm = comm.communicator();
205  }
206  OPM_HYPRE_SAFE_CALL(HYPRE_IJVectorCreate(mpi_comm, dof_offset, dof_offset + (N - 1), &vector));
207  OPM_HYPRE_SAFE_CALL(HYPRE_IJVectorSetObjectType(vector, HYPRE_PARCSR));
208  OPM_HYPRE_SAFE_CALL(HYPRE_IJVectorInitialize(vector));
209  return vector;
210 }
211 
218 inline void
219 destroySolver(HYPRE_Solver solver)
220 {
221  if (solver) {
222  OPM_HYPRE_SAFE_CALL(HYPRE_BoomerAMGDestroy(solver));
223  }
224 }
225 
232 inline void
233 destroyMatrix(HYPRE_IJMatrix matrix)
234 {
235  if (matrix) {
236  OPM_HYPRE_SAFE_CALL(HYPRE_IJMatrixDestroy(matrix));
237  }
238 }
239 
246 inline void
247 destroyVector(HYPRE_IJVector vector)
248 {
249  if (vector) {
250  OPM_HYPRE_SAFE_CALL(HYPRE_IJVectorDestroy(vector));
251  }
252 }
253 
261 template <typename CommType, typename MatrixType>
263 setupHypreParallelInfo(const CommType& comm, const MatrixType& matrix)
264 {
265  if constexpr (std::is_same_v<CommType, Dune::Amg::SequentialInformation>) {
266  return setupHypreParallelInfoSerial(static_cast<HYPRE_Int>(matrix.N()));
267  } else {
268  return setupHypreParallelInfoParallel(comm, matrix);
269  }
270 }
271 
278 inline ParallelInfo
280 {
281  ParallelInfo info;
282  info.N_owned = N;
283 
284  info.local_dune_to_local_hypre.resize(N);
285  info.local_dune_to_global_hypre.resize(N);
286  info.local_hypre_to_local_dune.resize(N);
287 
288  std::iota(info.local_dune_to_local_hypre.begin(), info.local_dune_to_local_hypre.end(), 0);
289  std::iota(info.local_hypre_to_local_dune.begin(), info.local_hypre_to_local_dune.end(), 0);
290  std::iota(info.local_dune_to_global_hypre.begin(), info.local_dune_to_global_hypre.end(), 0);
291 
292  info.dof_offset = 0;
293  info.owner_first = true;
294 
295  return info;
296 }
297 
361 template <typename CommType, typename MatrixType>
362 inline ParallelInfo
363 setupHypreParallelInfoParallel(const CommType& comm, const MatrixType& matrix)
364 {
365  ParallelInfo info;
366  const auto& collective_comm = comm.communicator();
367 
368  // Initialize mapping arrays to not owned (-1) state
369  info.local_dune_to_local_hypre.resize(comm.indexSet().size(), -1);
370  info.local_dune_to_global_hypre.resize(comm.indexSet().size(), -1);
371 
372  // Handle edge case: ensure index set covers all matrix rows
373  if (!(matrix.N() == comm.indexSet().size())) {
374  // in OPM this will likely not be trigged
375  // ensure no holes in index sett
376  const_cast<CommType&>(comm).buildGlobalLookup(matrix.N()); // need?
377  Dune::Amg::MatrixGraph<MatrixType> graph(const_cast<MatrixType&>(matrix)); // do not know why not const ref is sufficient
378  Dune::fillIndexSetHoles(graph, const_cast<CommType&>(comm));
379  assert(matrix.N() == comm.indexSet().size());
380  }
381 
382  // STEP 1: Ownership Detection
383  // Scan Dune's index set to identify which DOFs this process owns
384  // Note: iteration order in index set is NOT sequential by local index
385  for (const auto& ind : comm.indexSet()) {
386  int local_ind = ind.local().local();
387  if (ind.local().attribute() == Dune::OwnerOverlapCopyAttributeSet::owner) {
388  // Mark as owned (temporarily use 1, will be replaced with proper local index)
389  info.local_dune_to_local_hypre[local_ind] = 1;
390  } else {
391  // Mark as ghost/non-owned
392  info.local_dune_to_local_hypre[local_ind] = -1;
393  }
394  }
395 
396  // STEP 2: Local Reordering & Owner-First Detection
397  // Create compact [0..N_owned-1] local HYPRE indexing for owned DOFs
398  // Simultaneously detect if owned DOFs appear before all ghost DOFs
399  bool owner_first = true;
400  bool visited_ghost = false; // Have we seen any ghost DOF yet?
401  std::size_t count = 0; // Counter for owned DOFs
402 
403  for (std::size_t i = 0; i < info.local_dune_to_local_hypre.size(); ++i) {
404  if (info.local_dune_to_local_hypre[i] < 0) {
405  visited_ghost = true;
406  } else {
407  // This is an owned DOF - assign its local HYPRE index
408  info.local_dune_to_local_hypre[i] = count;
409  // Store the inverse mapping
410  info.local_hypre_to_local_dune.push_back(i);
411 
412  // Check if we've seen ghost DOFs before this owner
413  owner_first = owner_first && !visited_ghost;
414  count += 1;
415  }
416  }
417 
418  // Owner first need other copying of data
419  info.owner_first = owner_first;
420  info.N_owned = count;
421 
422  // STEP 3: Global Offset Calculation
423  // Coordinate with other processes to determine global index ranges
424  // Each process owns a contiguous range of global indices
425  // Use HYPRE_Int to match the send buffer type exactly; on builds where
426  // HYPRE_Int is 64-bit (long long) using int here causes MPI_ERR_TRUNCATE.
427  std::vector<HYPRE_Int> dof_counts_per_process(collective_comm.size());
428  collective_comm.allgather(&info.N_owned, 1, dof_counts_per_process.data());
429 
430  // Calculate this process's global offset (sum of DOFs in processes with lower rank)
431  info.dof_offset = std::accumulate(dof_counts_per_process.begin(),
432  dof_counts_per_process.begin() + collective_comm.rank(),
433  HYPRE_Int{0});
434 
435  // STEP 4: Create Global Indices for Owned DOFs
436  // Convert local HYPRE indices to global HYPRE indices by adding offset
437  for (std::size_t i = 0; i < info.local_dune_to_local_hypre.size(); ++i) {
438  if (info.local_dune_to_local_hypre[i] >= 0) {
439  // Owned DOF: global index = local HYPRE index + this process's offset
441  } else {
442  info.local_dune_to_global_hypre[i] = -1;
443  }
444  }
445 
446  if (collective_comm.rank() > 0) {
447  assert(info.dof_offset > 0);
448  }
449 
450  // STEP 5: Exchange global indices for ghost DOFs
451  // After this call, ghost DOFs will have their correct global indices
452  comm.copyOwnerToAll(info.local_dune_to_global_hypre, info.local_dune_to_global_hypre);
453 
454  return info;
455 }
456 
465 template <typename MatrixType>
467 setupSparsityPattern(const MatrixType& matrix, const ParallelInfo& par_info, bool owner_first)
468 {
469 #if HYPRE_USING_CUDA || HYPRE_USING_HIP
470  if constexpr (is_gpu_type<MatrixType>::value) {
471  return setupSparsityPatternFromGpuMatrix(matrix, par_info, owner_first);
472  } else
473 #endif
474  {
475  return setupSparsityPatternFromCpuMatrix(matrix, par_info, owner_first);
476  }
477 }
478 
487 template <typename MatrixType>
489 setupSparsityPatternFromCpuMatrix(const MatrixType& matrix, const ParallelInfo& par_info, bool owner_first)
490 {
491  SparsityPattern pattern;
492 
493  // Determine the size for cols array based on owner_first
494  if (owner_first) {
495  std::size_t cols_size = 0;
496  // For owner_first=true case, we need to calculate how many owned entries there are
497  for (auto row = matrix.begin(); row != matrix.end(); ++row) {
498  const int rowIdx = row.index();
499  if (par_info.local_dune_to_local_hypre[rowIdx] >= 0) {
500  cols_size += row->size();
501  }
502  }
503  pattern.nnz = cols_size;
504  } else {
505  // Full matrix space case: all entries (including gaps)
506  pattern.nnz = matrix.nonzeroes();
507  }
508 
509  // Setup host arrays
510  pattern.ncols.resize(par_info.N_owned);
511  pattern.rows.resize(par_info.N_owned);
512  pattern.cols.resize(pattern.nnz);
513 
514  int pos = 0;
515  for (auto row = matrix.begin(); row != matrix.end(); ++row) {
516  const int rind = row.index();
517  const int local_rowIdx = par_info.local_dune_to_local_hypre[rind];
518 
519  // For owner_first=true: skip ghost rows entirely
520  // For owner_first=false: process all rows (owned + ghost)
521  if (owner_first && local_rowIdx < 0) {
522  continue;
523  }
524 
525  if (local_rowIdx >= 0) {
526  // This is an owned row - record its metadata
527  const int global_rowIdx = par_info.local_dune_to_global_hypre[rind];
528  pattern.rows[local_rowIdx] = global_rowIdx;
529  pattern.ncols[local_rowIdx] = row->size();
530  }
531 
532  // Add column indices for this row
533  for (auto col = row->begin(); col != row->end(); ++col) {
534  const int global_colIdx = par_info.local_dune_to_global_hypre[col.index()];
535  assert(global_colIdx >= 0);
536  pattern.cols[pos++] = global_colIdx;
537  }
538  }
539 
540  return pattern;
541 }
542 
543 #if HYPRE_USING_CUDA || HYPRE_USING_HIP
544 
552 template <typename T, bool ForceLegacy>
554 setupSparsityPatternFromGpuMatrix(const GpuSparseMatrixWrapper<T, ForceLegacy>& gpu_matrix,
555  const ParallelInfo& par_info,
556  bool owner_first)
557 {
558  SparsityPattern pattern;
559 
560  // Determine the size for cols array based on owner_first
561  if (owner_first) {
562  std::size_t cols_size = 0;
563  // For owner_first=true case, we need to calculate how many owned entries there are
564  auto host_row_ptrs = gpu_matrix.getRowIndices().asStdVector();
565  for (int rind = 0; rind < static_cast<int>(gpu_matrix.N()); ++rind) {
566  if (par_info.local_dune_to_local_hypre[rind] >= 0) {
567  const int row_start = host_row_ptrs[rind];
568  const int row_end = host_row_ptrs[rind + 1];
569  cols_size += (row_end - row_start);
570  }
571  }
572  pattern.nnz = cols_size;
573  } else {
574  // Full matrix space case: all entries (including ghost rows)
575  pattern.nnz = gpu_matrix.nonzeroes();
576  }
577 
578  // Setup host arrays
579  pattern.ncols.resize(par_info.N_owned);
580  pattern.rows.resize(par_info.N_owned);
581  pattern.cols.resize(pattern.nnz);
582 
583  // Get row pointers and column indices from GPU matrix (one-time host copy during setup)
584  auto host_row_ptrs = gpu_matrix.getRowIndices().asStdVector();
585  auto host_col_indices = gpu_matrix.getColumnIndices().asStdVector();
586 
587  int pos = 0;
588  for (int rind = 0; rind < static_cast<int>(gpu_matrix.N()); ++rind) {
589  const int local_rowIdx = par_info.local_dune_to_local_hypre[rind];
590 
591  // For owner_first=true: skip ghost rows entirely
592  // For owner_first=false: process all rows (owned + ghost)
593  if (owner_first && local_rowIdx < 0) {
594  continue;
595  }
596 
597  const int row_start = host_row_ptrs[rind];
598  const int row_end = host_row_ptrs[rind + 1];
599  const int num_cols = row_end - row_start;
600 
601  if (local_rowIdx >= 0) {
602  // This is an owned row - record its metadata
603  const int global_rowIdx = par_info.local_dune_to_global_hypre[rind];
604  pattern.rows[local_rowIdx] = global_rowIdx;
605  pattern.ncols[local_rowIdx] = num_cols;
606  }
607 
608  // Add column indices for this row
609  for (int col_idx = row_start; col_idx < row_end; ++col_idx) {
610  const int colIdx = host_col_indices[col_idx];
611  const int global_colIdx = par_info.local_dune_to_global_hypre[colIdx];
612  assert(global_colIdx >= 0);
613  pattern.cols[pos++] = global_colIdx;
614  }
615  }
616 
617  return pattern;
618 }
619 #endif // HYPRE_USING_CUDA || HYPRE_USING_HIP
620 
634 template <typename MatrixType>
635 std::vector<HYPRE_Int>
636 computeRowIndexes(const MatrixType& matrix,
637  const std::vector<HYPRE_Int>& ncols,
638  const std::vector<int>& local_dune_to_local_hypre,
639  bool owner_first)
640 {
641  if (owner_first) {
642  // Simple contiguous case: prefix sum of ncols
643  std::vector<HYPRE_Int> row_indexes(ncols.size());
644  row_indexes[0] = 0;
645  for (std::size_t i = 1; i < ncols.size(); ++i) {
646  row_indexes[i] = row_indexes[i - 1] + ncols[i - 1];
647  }
648  return row_indexes;
649  } else {
650  // We need to compute the row indexes with mapping since we have gaps in the data
651 #if HYPRE_USING_CUDA || HYPRE_USING_HIP
652  if constexpr (is_gpu_type<MatrixType>::value) {
653  return computeRowIndexesWithMappingGpu(matrix, local_dune_to_local_hypre);
654  } else
655 #endif // HYPRE_USING_CUDA || HYPRE_USING_HIP
656  {
657  return computeRowIndexesWithMappingCpu(matrix, local_dune_to_local_hypre);
658  }
659  }
660 }
661 
681 template <typename MatrixType>
682 std::vector<HYPRE_Int>
683 computeRowIndexesWithMappingCpu(const MatrixType& matrix, const std::vector<int>& local_dune_to_local_hypre)
684 {
685  const int N = std::count_if(
686  local_dune_to_local_hypre.begin(), local_dune_to_local_hypre.end(), [](int val) { return val >= 0; });
687  std::vector<HYPRE_Int> row_indexes(N);
688  int data_position = 0; // Current position in the FULL (including ghost) matrix data
689  // Manually compute row starting positions by iterating through all matrix rows
690  for (auto row = matrix.begin(); row != matrix.end(); ++row) {
691  const int dune_row_idx = row.index();
692  const int hypre_row_idx = local_dune_to_local_hypre[dune_row_idx];
693 
694  if (hypre_row_idx >= 0) {
695  // This is an owned row - record where its data starts in the FULL matrix
696  // Use hypre_row_idx as index (maps to Hypre ordering up to N_owned)
697  row_indexes[hypre_row_idx] = data_position;
698  }
699  // Always advance position (including ghost rows - this creates gaps for owned-only access)
700  data_position += row->size();
701  }
702  return row_indexes;
703 }
704 
705 #if HYPRE_USING_CUDA || HYPRE_USING_HIP
706 
717 template <typename T, bool ForceLegacy>
718 std::vector<HYPRE_Int>
719 computeRowIndexesWithMappingGpu(const GpuSparseMatrixWrapper<T, ForceLegacy>& gpu_matrix,
720  const std::vector<int>& local_dune_to_local_hypre)
721 {
722  const int N = std::count_if(
723  local_dune_to_local_hypre.begin(), local_dune_to_local_hypre.end(), [](int val) { return val >= 0; });
724  std::vector<HYPRE_Int> row_indexes(N);
725 
726  // Use pre-computed BSR row pointers (already contain row starting positions)
727  auto host_row_ptrs = gpu_matrix.getRowIndices().asStdVector();
728 
729  // Map each owned Hypre row to its starting position in the FULL (including ghost) GPU matrix
730  for (int dune_row_idx = 0; dune_row_idx < static_cast<int>(gpu_matrix.N()); ++dune_row_idx) {
731  const int hypre_row_idx = local_dune_to_local_hypre[dune_row_idx];
732 
733  if (hypre_row_idx >= 0) {
734  // This is an owned row - record where its data starts in the FULL GPU matrix
735  // Use hypre_row_idx as index (maps to Hypre ordering up to N_owned)
736  row_indexes[hypre_row_idx] = host_row_ptrs[dune_row_idx];
737  }
738  // Non-owned rows create natural gaps in the indexing
739  }
740  return row_indexes;
741 }
742 #endif // HYPRE_USING_CUDA || HYPRE_USING_HIP
743 
744 } // namespace Opm::gpuistl::HypreInterface
745 
746 #endif // OPM_HYPRE_SETUP_HPP
std::vector< int > local_dune_to_local_hypre
Mapping from local Dune indices to local HYPRE indices.
Definition: HypreDataStructures.hpp:44
Type trait to detect if a type is a GPU type.
Definition: gpu_type_detection.hpp:40
The GpuSparseMatrixWrapper Checks CUDA/HIP version and dispatches a version either using the old or t...
Definition: gpu_type_detection.hpp:32
T get(const std::string &key) const
Retrieve property value given hierarchical property key.
Definition: PropertyTree.cpp:59
std::size_t N() const
N returns the number of rows (which is equal to the number of columns)
Definition: GpuSparseMatrixWrapper.hpp:232
Unified interface for Hypre operations with both CPU and GPU data structures.
Definition: HypreCpuTransfers.hpp:29
GpuVector< int > & getRowIndices()
getRowIndices returns the row indices used to represent the BSR structure.
Definition: GpuSparseMatrixWrapper.hpp:271
HYPRE_Solver createAMGSolver()
Create Hypre BoomerAMG solver.
Definition: HypreSetup.hpp:117
std::size_t nonzeroes() const
nonzeroes behaves as the Dune::BCRSMatrix::nonzeros() function and returns the number of non zero blo...
Definition: GpuSparseMatrixWrapper.hpp:241
ParallelInfo setupHypreParallelInfoParallel(const CommType &comm, const MatrixType &matrix)
Create mappings between Dune and HYPRE indexing for parallel decomposition.
Definition: HypreSetup.hpp:363
void destroyMatrix(HYPRE_IJMatrix matrix)
Destroy Hypre matrix.
Definition: HypreSetup.hpp:233
void initialize([[maybe_unused]] bool use_gpu_backend)
Initialize the Hypre library and set memory/execution policy.
Definition: HypreSetup.hpp:89
HYPRE_IJMatrix createMatrix(HYPRE_Int N, HYPRE_Int dof_offset, const CommType &comm)
Create Hypre matrix.
Definition: HypreSetup.hpp:170
HYPRE_Int nnz
Number of non-zero entries in matrix.
Definition: HypreDataStructures.hpp:97
HYPRE_Int dof_offset
Global index offset for this process&#39;s owned DOFs.
Definition: HypreDataStructures.hpp:69
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
HYPRE_IJVector createVector(HYPRE_Int N, HYPRE_Int dof_offset, const CommType &comm)
Create Hypre vector.
Definition: HypreSetup.hpp:197
std::vector< int > local_dune_to_global_hypre
Mapping from local Dune indices to global HYPRE indices.
Definition: HypreDataStructures.hpp:51
ParallelInfo setupHypreParallelInfo(const CommType &comm, const MatrixType &matrix)
Setup parallel information for Hypre (automatically detects serial/parallel)
Definition: HypreSetup.hpp:263
SparsityPattern setupSparsityPatternFromCpuMatrix(const MatrixType &matrix, const ParallelInfo &par_info, bool owner_first)
Setup sparsity pattern from CPU matrix (BCRSMatrix)
Definition: HypreSetup.hpp:489
HYPRE_Int N_owned
Number of DOFs owned by this MPI process.
Definition: HypreDataStructures.hpp:62
ParallelInfo setupHypreParallelInfoSerial(HYPRE_Int N)
Setup parallel information for Hypre in serial case.
Definition: HypreSetup.hpp:279
std::vector< HYPRE_Int > ncols
Non-zero entries per owned row (size: N_owned)
Definition: HypreDataStructures.hpp:88
SparsityPattern setupSparsityPattern(const MatrixType &matrix, const ParallelInfo &par_info, bool owner_first)
Setup sparsity pattern from matrix (automatically detects CPU/GPU type)
Definition: HypreSetup.hpp:467
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
void destroyVector(HYPRE_IJVector vector)
Destroy Hypre vector.
Definition: HypreSetup.hpp:247
GpuVector< int > & getColumnIndices()
getColumnIndices returns the column indices used to represent the BSR structure.
Definition: GpuSparseMatrixWrapper.hpp:291
void setSolverParameters(HYPRE_Solver solver, const PropertyTree &prm, bool use_gpu_backend)
Set solver parameters from property tree.
Definition: HypreSetup.hpp:133
Compressed Sparse Row (CSR) sparsity pattern for HYPRE matrix assembly.
Definition: HypreDataStructures.hpp:86
Hierarchical collection of key/value pairs.
Definition: PropertyTree.hpp:38
std::vector< HYPRE_Int > computeRowIndexes(const MatrixType &matrix, const std::vector< HYPRE_Int > &ncols, const std::vector< int > &local_dune_to_local_hypre, bool owner_first)
Compute row indexes for HYPRE_IJMatrixSetValues2.
Definition: HypreSetup.hpp:636
Parallel domain decomposition information for HYPRE-Dune interface.
Definition: HypreDataStructures.hpp:37
void destroySolver(HYPRE_Solver solver)
Destroy Hypre solver.
Definition: HypreSetup.hpp:219