ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_HostFabView.H
Go to the documentation of this file.
1 #ifndef ERF_HOST_FAB_VIEW_H
2 #define ERF_HOST_FAB_VIEW_H
3 
4 #include <AMReX_MultiFab.H>
5 #include <AMReX_FArrayBox.H>
6 #include <AMReX_Gpu.H>
7 
8 /**
9  * @file ERF_HostFabView.H
10  * @brief Host-readable view of one FAB of a MultiFab.
11  *
12  * AMReX leaves `the_arena_is_managed` at false by default, so under CUDA a
13  * MultiFab's data lives in device memory and an `Array4` obtained from it
14  * cannot be dereferenced on the host at all -- a plain `for` loop or
15  * `amrex::LoopOnCpu` over it faults, or silently reads garbage if the address
16  * happens to be mapped. `Gpu::streamSynchronize()` does not help: it orders
17  * kernels, it does not migrate memory.
18  *
19  * Most of the time the answer is to do the work in a kernel. This helper is for
20  * the cases where it genuinely cannot be: serial trajectory integration with a
21  * host RNG, scatter-accumulation into named bins, and gathering a field into a
22  * flat host vector ahead of an MPI reduce or a file write.
23  *
24  * On CPU builds the view is a plain alias for the device FAB, so host runs pay
25  * nothing for it.
26  *
27  * Typical use:
28  * @code
29  * for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
30  * const ERFHostFabView view(mf[mfi]);
31  * auto arr = view.array();
32  * amrex::LoopOnCpu(mfi.validbox(), [&](int i, int j, int k) {
33  * total += arr(i,j,k);
34  * });
35  * }
36  * @endcode
37  */
39 {
40 #ifdef AMREX_USE_GPU
41  amrex::FArrayBox fab;
42 
43  explicit ERFHostFabView (const amrex::FArrayBox& dev_fab)
44  : fab(dev_fab.box(), dev_fab.nComp(), amrex::The_Pinned_Arena())
45  {
46  // The staging FAB carries the device FAB's own box, so an Array4 taken
47  // from it is indexed with the same global (i,j,k).
48  amrex::Gpu::dtoh_memcpy_async(fab.dataPtr(), dev_fab.dataPtr(),
49  dev_fab.size() * sizeof(amrex::Real));
50  amrex::Gpu::streamSynchronize();
51  }
52 
53  [[nodiscard]] amrex::Array4<const amrex::Real> array () const
54  {
55  return fab.const_array();
56  }
57 #else
58  const amrex::FArrayBox* dev_fab;
59 
60  explicit ERFHostFabView (const amrex::FArrayBox& d) : dev_fab(&d) {}
61 
62  [[nodiscard]] amrex::Array4<const amrex::Real> array () const
63  {
64  return dev_fab->const_array();
65  }
66 #endif
67 };
68 
69 #endif /* ERF_HOST_FAB_VIEW_H */
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_HostFabView.H:39
ERFHostFabView(const amrex::FArrayBox &d)
Definition: ERF_HostFabView.H:60
const amrex::FArrayBox * dev_fab
Definition: ERF_HostFabView.H:58
amrex::Array4< const amrex::Real > array() const
Definition: ERF_HostFabView.H:62