Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_HypreSolver.H
Go to the documentation of this file.
1
5#ifndef AMREX_HYPRE_SOLVER_H_
6#define AMREX_HYPRE_SOLVER_H_
7
8#include <AMReX_Geometry.H>
9#include <AMReX_iMultiFab.H>
10#include <AMReX_HypreIJIface.H>
11#include <AMReX_BLProfiler.H>
12
13#include "HYPRE.h"
14#include "_hypre_utilities.h"
15
16#include <string>
17
18namespace amrex
19{
20
29template <int MSS>
31{
32public:
33
60 template <class Marker, class Filler>
61 HypreSolver (Vector<IndexType> const& a_index_type,
62 IntVect const& a_nghost,
63 Geometry const& a_geom,
64 BoxArray const& a_grids,
65 DistributionMapping const& a_dmap, // NOLINT(modernize-pass-by-value)
66 Marker && a_marker,
67 Filler && a_filler,
68 int a_verbose = 0,
69 std::string a_options_namespace = "hypre");
70
80 template <FabArrayType MF>
81 requires (std::same_as<typename MF::value_type, HYPRE_Real>)
82 void solve (Vector<MF *> const& a_soln,
83 Vector<MF const*> const& a_rhs,
84 HYPRE_Real rel_tol, HYPRE_Real abs_tol, int max_iter);
85
87 int getNumIters () const { return m_hypre_ij->getNumIters(); }
88
90 HYPRE_Real getFinalResidualNorm () const {
91 return m_hypre_ij->getFinalResidualNorm();
92 }
93
95 HYPRE_IJMatrix getA () const { return m_hypre_ij->A(); }
97 HYPRE_IJVector getb () const { return m_hypre_ij->b(); }
99 HYPRE_IJVector getx () const { return m_hypre_ij->x(); }
100
101// public: // for cuda
102
106 template <class Marker>
107#ifdef AMREX_USE_CUDA
109#else
111#endif
112 void fill_local_id (Marker const& marker);
113
115 template <typename AI>
116 void fill_global_id ();
117
126 template <class Filler>
127 requires (IsCallable<Filler,int,int,int,int,int,
129 HYPRE_Int&, HYPRE_Int*,
130 HYPRE_Real*>::value)
131 void fill_matrix (Filler const& filler);
132
139 template <FabArrayType MF>
140 requires (std::same_as<typename MF::value_type, HYPRE_Real>)
141 void load_vectors (Vector<MF *> const& a_soln,
142 Vector<MF const*> const& a_rhs);
143
149 template <FabArrayType MF>
150 requires (std::same_as<typename MF::value_type, HYPRE_Real>)
151 void get_solution (Vector<MF*> const& a_soln);
152
153private:
154
155 int m_nvars;
156 Vector<IndexType> m_index_type;
157 IntVect m_nghost;
158 Geometry m_geom;
159 Vector<BoxArray> m_grids;
160 DistributionMapping m_dmap;
161
162 int m_verbose;
163 std::string m_options_namespace;
164
165 MPI_Comm m_comm = MPI_COMM_NULL;
166
168 Vector<iMultiFab> m_local_id;
171
172#ifdef AMREX_USE_GPU
174#endif
175
176 Vector<LayoutData<HYPRE_Int>> m_nrows_grid;
177 Vector<LayoutData<HYPRE_Int>> m_id_offset;
178 LayoutData<HYPRE_Int> m_nrows;
179 HYPRE_Int m_nrows_proc;
180
181 std::unique_ptr<HypreIJIface> m_hypre_ij;
182
183 // Non-owning references to HYPRE matrix, rhs, and solution data
184 HYPRE_IJMatrix m_A = nullptr;
185 HYPRE_IJVector m_b = nullptr;
186 HYPRE_IJVector m_x = nullptr;
187};
188
189template <int MSS>
190template <class Marker, class Filler>
192 IntVect const& a_nghost,
193 Geometry const& a_geom,
194 BoxArray const& a_grids,
195 DistributionMapping const& a_dmap, // NOLINT(modernize-pass-by-value)
196 Marker && a_marker,
197 Filler && a_filler,
198 int a_verbose,
199 std::string a_options_namespace)
200 : m_nvars (int(a_index_type.size())),
201 m_index_type (a_index_type),
202 m_nghost (a_nghost),
203 m_geom (a_geom),
204 m_dmap (a_dmap),
205 m_verbose (a_verbose),
206 m_options_namespace(std::move(a_options_namespace))
207{
208 BL_PROFILE("HypreSolver()");
209
210#ifdef AMREX_USE_MPI
211 m_comm = ParallelContext::CommunicatorSub(); // NOLINT(cppcoreguidelines-prefer-member-initializer)
212#endif
213
214 m_grids.resize(m_nvars);
215 m_local_id.resize(m_nvars);
216 m_global_id.resize(m_nvars);
217 m_nrows_grid.resize(m_nvars);
218 m_id_offset.resize(m_nvars);
219 Long nrows_max = 0;
220 for (int ivar = 0; ivar < m_nvars; ++ivar) {
221 m_grids [ivar] = amrex::convert(a_grids,m_index_type[ivar]);
222 m_local_id [ivar].define(m_grids[ivar], m_dmap, 1, 0);
223 m_global_id [ivar].define(m_grids[ivar], m_dmap, 1, m_nghost);
224 m_nrows_grid[ivar].define(m_grids[0], m_dmap);
225 m_id_offset [ivar].define(m_grids[0], m_dmap);
226 nrows_max += m_grids[ivar].numPts();
227 }
228 m_global_id_vec.define(m_grids[0], m_dmap);
229 m_nrows.define (m_grids[0], m_dmap);
230 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(nrows_max < static_cast<Long>(std::numeric_limits<HYPRE_Int>::max()-1),
231 "Need to configure Hypre with --enable-bigint");
232
233 m_owner_mask.resize(m_nvars);
234 for (int ivar = 0; ivar < m_nvars; ++ivar) {
235 m_owner_mask[ivar] = amrex::OwnerMask(m_local_id[ivar], m_geom.periodicity());
236 }
237
238#ifdef AMREX_USE_GPU
239 m_cell_offset.define(m_grids[0], m_dmap);
240#endif
241
242 fill_local_id(std::forward<Marker>(a_marker));
243
244 // At this point, m_local_id stores the ids local to each box.
245 // m_nrows_grid stores the number of unique points in each box.
246 // m_nrows_proc is the number of rowss for all variables on this MPI
247 // process. If a point is invalid, its id is invalid (i.e., a very
248 // negative number). Note that the data type of local_node_id is int,
249 // not HYPRE_Int for performance on GPU.
250
251 const int nprocs = ParallelContext::NProcsSub();
252 const int myproc = ParallelContext::MyProcSub();
253
254 Vector<HYPRE_Int> nrows_allprocs(nprocs);
255#ifdef AMREX_USE_MPI
256 if (nrows_allprocs.size() > 1) {
257 MPI_Allgather(&m_nrows_proc, sizeof(HYPRE_Int), MPI_CHAR,
258 nrows_allprocs.data(), sizeof(HYPRE_Int), MPI_CHAR, m_comm);
259 } else
260#endif
261 {
262 nrows_allprocs[0] = m_nrows_proc;
263 }
264
265 HYPRE_Int proc_begin = 0;
266 for (int i = 0; i < myproc; ++i) {
267 proc_begin += nrows_allprocs[i];
268 }
269
270 HYPRE_Int proc_end = proc_begin;
271 for (MFIter mfi(m_nrows_grid[0]); mfi.isValid(); ++mfi) {
272 for (int ivar = 0; ivar < m_nvars; ++ivar) {
273 m_id_offset[ivar][mfi] = proc_end;
274 proc_end += m_nrows_grid[ivar][mfi];
275 }
276 }
277 AMREX_ASSERT(proc_end == proc_begin + m_nrows_proc);
278
279 // To generate global ids for HYPRE, we need to remove duplicates on
280 // nodes shared by multiple Boxes with OverrideSync. So we need to use
281 // a type that supports atomicAdd. HYPRE_Int is either int or long
282 // long. The latter (i.e., long long) does not have native atomicAdd
283 // support in CUDA/HIP, whereas unsigned long long has.
284 using AtomicInt = std::conditional_t<sizeof(HYPRE_Int) == 4,
285 HYPRE_Int, unsigned long long>;
286 fill_global_id<AtomicInt>();
287
288 // Create and initialize A, b & x
289 HYPRE_Int ilower = proc_begin;
290 HYPRE_Int iupper = proc_end-1;
291 m_hypre_ij = std::make_unique<HypreIJIface>(m_comm, ilower, iupper, m_verbose);
292 m_hypre_ij->parse_inputs(m_options_namespace);
293
294 // Obtain non-owning references to the matrix, rhs, and solution data
295 m_A = m_hypre_ij->A();
296 m_b = m_hypre_ij->b();
297 m_x = m_hypre_ij->x();
298
299 fill_matrix(std::forward<Filler>(a_filler));
300}
301
302template <int MSS>
303template <class Marker>
304#ifdef AMREX_USE_CUDA
306#else
308#endif
309void HypreSolver<MSS>::fill_local_id (Marker const& marker)
310{
311 BL_PROFILE("HypreSolver::fill_local_id()");
312
313#ifdef AMREX_USE_GPU
314
315 for (MFIter mfi(m_local_id[0]); mfi.isValid(); ++mfi) {
316 int boxno = mfi.LocalIndex();
317 Long npts_tot = 0;
318 for (int ivar = 0; ivar < m_nvars; ++ivar) {
319 Box const& bx = amrex::convert(mfi.validbox(),m_index_type[ivar]);
320 npts_tot += bx.numPts();
321 }
322 m_cell_offset[mfi].resize(npts_tot);
323 npts_tot = 0;
324 int* p_cell_offset = m_cell_offset[mfi].data();
325 for (int ivar = 0; ivar < m_nvars; ++ivar) {
326 Box const& bx = amrex::convert(mfi.validbox(),m_index_type[ivar]);
327 auto const& lid = m_local_id[ivar].array(mfi);
328 auto const& owner = m_owner_mask[ivar]->const_array(mfi);
329 AMREX_ASSERT(bx.numPts() < static_cast<Long>(std::numeric_limits<int>::max()));
330 const auto npts = static_cast<int>(bx.numPts());
331 int npts_box = amrex::Scan::PrefixSum<int>(npts,
332 [=] AMREX_GPU_DEVICE (int offset) noexcept -> int
333 {
334 const Dim3 cell = bx.atOffset(offset).dim3();
335 int id = (owner ( cell.x,cell.y,cell.z ) &&
336 marker(boxno,cell.x,cell.y,cell.z,ivar)) ? 1 : 0;
337 lid(cell.x,cell.y,cell.z) = id;
338 return id;
339 },
340 [=] AMREX_GPU_DEVICE (int offset, int ps) noexcept
341 {
342 const Dim3 cell = bx.atOffset(offset).dim3();
343 if (lid(cell.x,cell.y,cell.z)) {
344 lid(cell.x,cell.y,cell.z) = ps;
345 p_cell_offset[ps] = offset;
346 } else {
347 lid(cell.x,cell.y,cell.z) = std::numeric_limits<int>::lowest();
348 }
349 },
351 m_nrows_grid[ivar][mfi] = npts_box;
352 npts_tot += npts_box;
353 p_cell_offset += npts_box;
354 }
355 m_cell_offset[mfi].resize(npts_tot);
356 }
357
358#else
359
360#ifdef AMREX_USE_OMP
361#pragma omp parallel
362#endif
363 for (MFIter mfi(m_local_id[0]); mfi.isValid(); ++mfi) {
364 int boxno = mfi.LocalIndex();
365 for (int ivar = 0; ivar < m_nvars; ++ivar) {
366 Box const& bx = amrex::convert(mfi.validbox(),m_index_type[ivar]);
367 auto const& lid = m_local_id[ivar].array(mfi);
368 auto const& owner = m_owner_mask[ivar]->const_array(mfi);
369 int id = 0;
370 const auto lo = amrex::lbound(bx);
371 const auto hi = amrex::ubound(bx);
372 for (int k = lo.z; k <= hi.z; ++k) {
373 for (int j = lo.y; j <= hi.y; ++j) {
374 for (int i = lo.x; i <= hi.x; ++i) {
375 if (owner(i,j,k) && marker(boxno,i,j,k,ivar)) {
376 lid(i,j,k) = id++;
377 } else {
378 lid(i,j,k) = std::numeric_limits<int>::lowest();
379 }
380 }}}
381 m_nrows_grid[ivar][mfi] = id;
382 }
383 }
384#endif
385
386 m_nrows_proc = 0;
387 for (MFIter mfi(m_nrows); mfi.isValid(); ++mfi) {
388 int nrows = 0;
389 for (int ivar = 0; ivar < m_nvars; ++ivar) {
390 nrows += m_nrows_grid[ivar][mfi];
391 }
392 m_nrows[mfi] = nrows;
393 m_nrows_proc += nrows;
394 }
395}
396
397template <int MSS>
398template <typename AI>
399void
401{
402 BL_PROFILE("HypreSolver::fill_global_id()");
403
404 Vector<FabArray<BaseFab<AI>>> global_id_raii;
405 Vector<FabArray<BaseFab<AI>>*> p_global_id;
406
407 if constexpr (std::is_same_v<HYPRE_Int,AI>) {
408 for (int ivar = 0; ivar < m_nvars; ++ivar) {
409 p_global_id.push_back(&(m_global_id[ivar]));
410 }
411 } else {
412 // Reserve so that the pointers taken below stay valid.
413 global_id_raii.reserve(m_nvars);
414 for (int ivar = 0; ivar < m_nvars; ++ivar) {
415 global_id_raii.emplace_back(m_global_id[ivar].boxArray(),
416 m_global_id[ivar].DistributionMap(),
417 1, m_global_id[ivar].nGrowVect());
418 p_global_id.push_back(&(global_id_raii[ivar]));
419 }
420 }
421
422#ifdef AMREX_USE_OMP
423#pragma omp parallel if (Gpu::notInLaunchRegion())
424#endif
425 for (MFIter mfi(m_global_id[0]); mfi.isValid(); ++mfi) {
426 auto& rows_vec = m_global_id_vec[mfi];
427 rows_vec.resize(m_nrows[mfi]);
428
429 HYPRE_Int nrows = 0;
430 for (int ivar = 0; ivar < m_nvars; ++ivar) {
431 HYPRE_Int const os = m_id_offset[ivar][mfi];
432 Box bx = mfi.validbox();
433 bx.convert(m_index_type[ivar]).grow(m_nghost);
434 Array4<AI> const& gid = p_global_id[ivar]->array(mfi);
435 auto const& lid = m_local_id[ivar].const_array(mfi);
436 HYPRE_Int* rows = rows_vec.data() + nrows;
437 nrows += m_nrows_grid[ivar][mfi];
438 amrex::ParallelFor(bx,[=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
439 {
440 if (lid.contains(i,j,k) && lid(i,j,k) >= 0) {
441 const auto id = lid(i,j,k) + os;
442 rows[lid(i,j,k)] = id;
443 gid(i,j,k) = static_cast<AI>(id);
444 } else {
445 gid(i,j,k) = static_cast<AI>
446 (std::numeric_limits<HYPRE_Int>::max());
447 }
448 });
449 }
450 }
451
452 for (int ivar = 0; ivar < m_nvars; ++ivar) {
453 amrex::OverrideSync(*p_global_id[ivar], *m_owner_mask[ivar],
454 m_geom.periodicity());
455 p_global_id[ivar]->FillBoundary(m_geom.periodicity());
456
457 if constexpr (!std::is_same<HYPRE_Int, AI>()) {
458 auto const& dst = m_global_id[ivar].arrays();
459 auto const& src = p_global_id[ivar]->const_arrays();
460 amrex::ParallelFor(m_global_id[ivar], m_global_id[ivar].nGrowVect(),
461 [=] AMREX_GPU_DEVICE (int b, int i, int j, int k)
462 {
463 dst[b](i,j,k) = static_cast<HYPRE_Int>(src[b](i,j,k));
464 });
465 }
466 }
467}
468
469#ifdef AMREX_USE_GPU
471namespace detail {
472template <typename T>
473void pack_matrix_gpu (Gpu::DeviceVector<HYPRE_Int>& cols_tmp,
477{
478 auto* p_cols_tmp = cols_tmp.data();
479 auto* p_mat_tmp = mat_tmp.data();
480 auto const* p_cols = cols.data();
481 auto const* p_mat = mat.data();
482 const auto N = Long(cols.size());
483 Scan::PrefixSum<T>(N,
484 [=] AMREX_GPU_DEVICE (Long i) -> T
485 {
486 return static_cast<T>(p_cols[i] >= 0);
487 },
488 [=] AMREX_GPU_DEVICE (Long i, T s)
489 {
490 if (p_cols[i] >= 0) {
491 p_cols_tmp[s] = p_cols[i];
492 p_mat_tmp[s] = p_mat[i];
493 }
494 },
496 std::swap(cols_tmp, cols);
497 std::swap(mat_tmp, mat);
498}
499}
501#endif
502
503template <int MSS>
504template <class Filler>
505requires (IsCallable<Filler,int,int,int,int,int,
506 Array4<HYPRE_Int const> const*,
507 HYPRE_Int&, HYPRE_Int*,
508 HYPRE_Real*>::value)
509void
510HypreSolver<MSS>::fill_matrix (Filler const& filler)
511{
512 BL_PROFILE("HypreSolver::fill_matrix()");
513
517
518 MFItInfo mfitinfo;
520 for (MFIter mfi(m_local_id[0],mfitinfo); mfi.isValid(); ++mfi)
521 {
522 int boxno = mfi.LocalIndex();
523 const HYPRE_Int nrows = m_nrows[mfi];
524 if (nrows > 0)
525 {
526 ncols_vec.clear();
527 ncols_vec.resize(nrows);
528 HYPRE_Int* ncols = ncols_vec.data();
529
530 cols_vec.clear();
531 cols_vec.resize(Long(nrows)*MSS, -1);
532 HYPRE_Int* cols = cols_vec.data();
533
534 mat_vec.clear();
535 mat_vec.resize(Long(nrows)*MSS);
536 HYPRE_Real* mat = mat_vec.data();
537
538 Vector<Array4<HYPRE_Int const>> gid_v(m_nvars);
539 for (int ivar = 0; ivar < m_nvars; ++ivar) {
540 gid_v[ivar] = m_global_id[ivar].const_array(mfi);
541 }
542
543#ifdef AMREX_USE_GPU
545 (gid_v.data(), gid_v.size());
546 auto const* pgid = gid_buf.data();
547 auto const* p_cell_offset = m_cell_offset[mfi].data();
548 Long ntot = 0;
549 for (int ivar = 0; ivar < m_nvars; ++ivar) {
550 const HYPRE_Int nrows_var = m_nrows_grid[ivar][mfi];
551 if (nrows_var > 0) {
552 Box const& bx = amrex::convert(mfi.validbox(),m_index_type[ivar]);
553 ntot += Reduce::Sum<Long>(nrows_var,
554 [=] AMREX_GPU_DEVICE (HYPRE_Int offset)
555 {
556 const Dim3 cell = bx.atOffset(p_cell_offset[offset]).dim3();
557 filler(boxno, cell.x, cell.y, cell.z, ivar, pgid,
558 ncols[offset], cols+Long(offset)*MSS,
559 mat+Long(offset)*MSS);
560 return ncols[offset];
561 });
562 p_cell_offset += nrows_var;
563 ncols += nrows_var;
564 cols += Long(nrows_var)*MSS;
565 mat += Long(nrows_var)*MSS;
566 }
567 }
568 Gpu::DeviceVector<HYPRE_Int> cols_tmp(ntot);
569 Gpu::DeviceVector<HYPRE_Real> mat_tmp(ntot);
570 if (ntot >= Long(std::numeric_limits<int>::max())) {
571 detail::pack_matrix_gpu<Long>(cols_tmp, mat_tmp, cols_vec, mat_vec);
572 } else {
573 detail::pack_matrix_gpu<int>(cols_tmp, mat_tmp, cols_vec, mat_vec);
574 }
575#else
576 auto* pgid = gid_v.data();
577 for (int ivar = 0; ivar < m_nvars; ++ivar) {
578 if (m_nrows_grid[ivar][mfi] > 0) {
579 auto const& lid = m_local_id[ivar].const_array(mfi);
580 amrex::Loop(amrex::convert(mfi.validbox(),m_index_type[ivar]),
581 [=,&ncols,&cols,&mat] (int i, int j, int k)
582 {
583 if (lid(i,j,k) >= 0) {
584 filler(boxno, i, j, k, ivar, pgid, *ncols, cols, mat);
585 cols += (*ncols);
586 mat += (*ncols);
587 ++ncols;
588 }
589 });
590 }
591 }
592#endif
593
594 const auto& rows_vec = m_global_id_vec[mfi];
595 HYPRE_Int const* rows = rows_vec.data();
596
598 HYPRE_IJMatrixSetValues(m_A, nrows, ncols_vec.data(), rows,
599 cols_vec.data(), mat_vec.data());
600 Gpu::hypreSynchronize();
601 }
602 }
603 HYPRE_IJMatrixAssemble(m_A);
604}
605
606template <int MSS>
607template <FabArrayType MF>
608requires (std::same_as<typename MF::value_type, HYPRE_Real>)
609void
611 Vector<MF const*> const& a_rhs,
612 HYPRE_Real rel_tol, HYPRE_Real abs_tol, int max_iter)
613{
614 BL_PROFILE("HypreSolver::solve()");
615
616 AMREX_ASSERT(a_soln.size() == m_nvars && a_rhs.size() == m_nvars);
617
618 HYPRE_IJVectorInitialize(m_b);
619 HYPRE_IJVectorInitialize(m_x);
620
621 load_vectors(a_soln, a_rhs);
622
623 HYPRE_IJVectorAssemble(m_x);
624 HYPRE_IJVectorAssemble(m_b);
625
626 m_hypre_ij->solve(rel_tol, abs_tol, max_iter);
627
628 get_solution(a_soln);
629}
630
631template <int MSS>
632template <FabArrayType MF>
633requires (std::same_as<typename MF::value_type, HYPRE_Real>)
634void
636 Vector<MF const*> const& a_rhs)
637{
638 BL_PROFILE("HypreSolver::load_vectors()");
639
640 MFItInfo mfitinfo;
642
645 for (MFIter mfi(*a_soln[0],mfitinfo); mfi.isValid(); ++mfi)
646 {
647 const HYPRE_Int nrows = m_nrows[mfi];
648 if (nrows > 0)
649 {
650 xvec.clear();
651 xvec.resize(nrows);
652 bvec.clear();
653 bvec.resize(nrows);
654 auto* xp = xvec.data();
655 auto* bp = bvec.data();
656
657 HYPRE_Int const* rows = m_global_id_vec[mfi].data();
658
659 HYPRE_Int offset = 0;
660 for (int ivar = 0; ivar < m_nvars; ++ivar) {
661 if (m_nrows_grid[ivar][mfi] > 0) {
662 auto const& xfab = a_soln[ivar]->const_array(mfi);
663 auto const& bfab = a_rhs [ivar]->const_array(mfi);
664 auto const& lid = m_local_id[ivar].const_array(mfi);
665 HYPRE_Real* x = xp + offset;
666 HYPRE_Real* b = bp + offset;
667 Box box = amrex::convert(mfi.validbox(),m_index_type[ivar]);
668 amrex::ParallelFor(box,[=] AMREX_GPU_DEVICE (int i, int j, int k)
669 {
670 if (lid(i,j,k) >= 0) {
671 x[lid(i,j,k)] = xfab(i,j,k);
672 b[lid(i,j,k)] = bfab(i,j,k);
673 }
674 });
675 offset += m_nrows_grid[ivar][mfi];
676 }
677 }
678
679 Gpu::streamSynchronize();
680 HYPRE_IJVectorSetValues(m_x, nrows, rows, xp);
681 HYPRE_IJVectorSetValues(m_b, nrows, rows, bp);
682 Gpu::hypreSynchronize();
683 }
684 }
685}
686
687template <int MSS>
688template <FabArrayType MF>
689requires (std::same_as<typename MF::value_type, HYPRE_Real>)
690void
692{
693 BL_PROFILE("HypreSolver::get_solution()");
694
695 MFItInfo mfitinfo;
697
699 for (MFIter mfi(*a_soln[0],mfitinfo); mfi.isValid(); ++mfi)
700 {
701 const HYPRE_Int nrows = m_nrows[mfi];
702 if (nrows > 0)
703 {
704 xvec.clear();
705 xvec.resize(nrows);
706 auto* xp = xvec.data();
707
708 HYPRE_Int const* rows = m_global_id_vec[mfi].data();
709
710 HYPRE_IJVectorGetValues(m_x, nrows, rows, xp);
711 Gpu::hypreSynchronize();
712
713 HYPRE_Int offset = 0;
714 for (int ivar = 0; ivar < m_nvars; ++ivar) {
715 if (m_nrows_grid[ivar][mfi] > 0) {
716 auto const& xfab = a_soln[ivar]->array(mfi);
717 auto const& lid = m_local_id[ivar].const_array(mfi);
718 HYPRE_Real* x = xp + offset;
719 Box box = amrex::convert(mfi.validbox(),m_index_type[ivar]);
720 amrex::ParallelFor(box,[=] AMREX_GPU_DEVICE (int i, int j, int k)
721 {
722 if (lid(i,j,k) >= 0) {
723 xfab(i,j,k) = x[lid(i,j,k)];
724 }
725 });
726 offset += m_nrows_grid[ivar][mfi];
727 }
728 }
729 Gpu::streamSynchronize();
730 }
731 }
732
733 for (int ivar = 0; ivar < m_nvars; ++ivar) {
734 amrex::OverrideSync(*a_soln[ivar], *m_owner_mask[ivar],
735 m_geom.periodicity());
736 }
737}
738
739}
740
741#endif
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:562
#define AMREX_ALWAYS_ASSERT_WITH_MESSAGE(EX, MSG)
Definition AMReX_BLassert.H:49
#define AMREX_ASSERT(EX)
Definition AMReX_BLassert.H:38
Problem-domain geometry: maps between index space and physical space.
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
Array4< int const > offset
Definition AMReX_HypreMLABecLap.cpp:1131
Reference-counted collection of Boxes.
Definition AMReX_BoxArray.H:681
__host__ __device__ BoxND & grow(int i) noexcept
Grow in all directions by i cells (negative shrinks).
Definition AMReX_Box.H:668
__host__ __device__ Long numPts() const noexcept
Return the number of points contained in the BoxND.
Definition AMReX_Box.H:385
__host__ __device__ BoxND & convert(IndexTypeND< dim > typ) noexcept
Convert the BoxND from the current type into the argument type. This may change the BoxND coordinates...
Definition AMReX_Box.H:1008
__host__ __device__ IntVectND< dim > atOffset(Long offset) const noexcept
Given the offset, compute IntVectND<dim>
Definition AMReX_Box.H:1105
Calculates the distribution of FABs to MPI processes.
Definition AMReX_DistributionMapping.H:51
Rectangular problem domain geometry.
Definition AMReX_Geometry.H:85
Periodicity periodicity() const noexcept
Return the Periodicity based on the length of the domain.
Definition AMReX_Geometry.H:424
Definition AMReX_GpuBuffer.H:24
T const * data() const noexcept
Definition AMReX_GpuBuffer.H:51
Solve Ax = b using HYPRE's generic IJ matrix format where A is a sparse matrix specified using the co...
Definition AMReX_HypreSolver.H:31
HypreSolver(Vector< IndexType > const &a_index_type, IntVect const &a_nghost, Geometry const &a_geom, BoxArray const &a_grids, DistributionMapping const &a_dmap, Marker &&a_marker, Filler &&a_filler, int a_verbose=0, std::string a_options_namespace="hypre")
Definition AMReX_HypreSolver.H:191
void load_vectors(Vector< MF * > const &a_soln, Vector< MF const * > const &a_rhs)
Copy AMReX RHS/initial guess data into the IJ vectors.
Definition AMReX_HypreSolver.H:635
int getNumIters() const
Number of iterations from the last solve().
Definition AMReX_HypreSolver.H:87
void solve(Vector< MF * > const &a_soln, Vector< MF const * > const &a_rhs, HYPRE_Real rel_tol, HYPRE_Real abs_tol, int max_iter)
Solve Ax=b after the constructor assembled the IJ matrix.
Definition AMReX_HypreSolver.H:610
HYPRE_IJVector getx() const
Access the IJ solution handle (non-owning).
Definition AMReX_HypreSolver.H:99
HYPRE_IJMatrix getA() const
Access the assembled IJ matrix handle (non-owning).
Definition AMReX_HypreSolver.H:95
void fill_matrix(Filler const &filler)
Fill each CSR row using the supplied filler functor.
Definition AMReX_HypreSolver.H:510
void fill_local_id(Marker const &marker)
Assign local ids to each owned DOF by invoking marker.
Definition AMReX_HypreSolver.H:309
void get_solution(Vector< MF * > const &a_soln)
Copy IJ solution entries back into AMReX storage.
Definition AMReX_HypreSolver.H:691
void fill_global_id()
Convert the local ids to globally unique ids visible to HYPRE.
Definition AMReX_HypreSolver.H:400
HYPRE_Real getFinalResidualNorm() const
Final residual norm from the last solve().
Definition AMReX_HypreSolver.H:90
HYPRE_IJVector getb() const
Access the assembled IJ RHS handle (non-owning).
Definition AMReX_HypreSolver.H:97
a one-thingy-per-box distributed object
Definition AMReX_LayoutData.H:13
void define(const BoxArray &a_grids, const DistributionMapping &a_dm)
Definition AMReX_LayoutData.H:24
Iterator for looping ever tiles and boxes of amrex::FabArray based containers.
Definition AMReX_MFIter.H:88
bool isValid() const noexcept
Is the iterator valid i.e. is it associated with a FAB?
Definition AMReX_MFIter.H:176
Dynamically allocated vector for trivially copyable data.
Definition AMReX_PODVector.H:308
size_type size() const noexcept
Definition AMReX_PODVector.H:654
void resize(size_type a_new_size, GrowthStrategy strategy=GrowthStrategy::Poisson)
Definition AMReX_PODVector.H:734
void clear() noexcept
Definition AMReX_PODVector.H:652
T * data() noexcept
Definition AMReX_PODVector.H:672
This class is a thin wrapper around std::vector. Unlike vector, Vector::operator[] provides bound che...
Definition AMReX_Vector.H:29
Long size() const noexcept
Definition AMReX_Vector.H:54
amrex_long Long
Definition AMReX_INT.H:30
__host__ __device__ Dim3 ubound(Array4< T > const &a) noexcept
Return the inclusive upper bounds of an Array4 in Dim3 form.
Definition AMReX_Array4.H:1365
__host__ __device__ Dim3 lbound(Array4< T > const &a) noexcept
Return the inclusive lower bounds of an Array4 in Dim3 form.
Definition AMReX_Array4.H:1351
__host__ __device__ BoxND< dim > convert(const BoxND< dim > &b, const IntVectND< dim > &typ) noexcept
Return a copy of b converted to the nodal flags typ.
Definition AMReX_Box.H:1630
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:310
MPI_Comm CommunicatorSub() noexcept
sub-communicator for current frame
Definition AMReX_ParallelContext.H:70
int MyProcSub() noexcept
my sub-rank in current frame
Definition AMReX_ParallelContext.H:76
int NProcsSub() noexcept
number of ranks in current frame
Definition AMReX_ParallelContext.H:74
static constexpr struct amrex::Scan::Type::Exclusive exclusive
static constexpr RetSum noRetSum
Definition AMReX_Scan.H:35
int MPI_Comm
Definition AMReX_ccse-mpi.H:51
static constexpr int MPI_COMM_NULL
Definition AMReX_ccse-mpi.H:59
Definition AMReX_Amr.cpp:50
BoxArray const & boxArray(FabArrayBase const &fa)
Convenience wrapper that forwards to fa.boxArray().
Definition AMReX_FabArrayBase.cpp:2870
void ParallelFor(TypeList< CTOs... > ctos, std::array< int, sizeof...(CTOs)> const &runtime_options, T N, F &&f)
Definition AMReX_CTOParallelForImpl.H:202
std::unique_ptr< iMultiFab > OwnerMask(FabArrayBase const &mf, const Periodicity &period, const IntVect &ngrow)
Definition AMReX_iMultiFab.cpp:699
IntVect nGrowVect(FabArrayBase const &fa)
Convenience wrapper that forwards to fa.nGrowVect().
Definition AMReX_FabArrayBase.cpp:2865
const int[]
Definition AMReX_BLProfiler.cpp:1665
__host__ __device__ void Loop(Dim3 lo, Dim3 hi, F const &f) noexcept
Definition AMReX_Loop.H:127
void OverrideSync(FabArray< FAB > &fa, FabArray< IFAB > const &msk, const Periodicity &period)
Synchronize shared nodal values using an owner mask.
Definition AMReX_FabArrayUtility.H:1648
A multidimensional array accessor.
Definition AMReX_Array4.H:289
A simple struct holding 3 int values for a 3D index.
Definition AMReX_Dim3.H:24
int x
Definition AMReX_Dim3.H:24
int z
Definition AMReX_Dim3.H:24
int y
Definition AMReX_Dim3.H:24
Test if a given type T is callable with arguments of type Args...
Definition AMReX_TypeTraits.H:214
Test if a given type T is callable with arguments of type Args...
Definition AMReX_TypeTraits.H:208
Definition AMReX_MFIter.H:20
MFItInfo & DisableDeviceSync() noexcept
Definition AMReX_MFIter.H:47
MFItInfo & UseDefaultStream() noexcept
Definition AMReX_MFIter.H:75