ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_PlanarBoundary.H
Go to the documentation of this file.
1 #ifndef ERF_PLANAR_BOUNDARY_H_
2 #define ERF_PLANAR_BOUNDARY_H_
3 
4 #include <AMReX_BoxArray.H>
5 #include <AMReX_DistributionMapping.H>
6 #include <AMReX_GpuQualifiers.H>
7 #include <AMReX_IndexType.H>
8 #include <AMReX_MultiFab.H>
9 #include <AMReX_Periodicity.H>
10 #include <AMReX_Vector.H>
11 
12 #include <algorithm>
13 #include <memory>
14 
15 /**
16  * Ghost-cell fill for planar (2D) MultiFabs built on the collapse of a 3D BoxArray
17  * along a surface-normal direction.
18  *
19  * The surface-layer fields and the MOST averages are defined on one 2D box per 3D box.
20  * When the 3D BoxArray is split in the normal direction, several 3D boxes collapse onto
21  * the same 2D box, so the planar BoxArray holds duplicate boxes with overlapping valid
22  * regions, and only the copy that belongs to the 3D box touching the surface is ever
23  * computed. A FillBoundary on such a MultiFab may fill a ghost cell from an
24  * uncomputed copy.
25  *
26  * define() records which planar boxes are those surface copies. fill() copies them into
27  * a buffer without duplicates and ParallelCopies the buffer onto every planar box, valid
28  * region and ghost cells alike. Unlike FillBoundary it therefore also overwrites the
29  * valid region of the uncomputed copies, so that any copy can be read afterwards. Without
30  * duplicates fill() is a plain FillBoundary.
31  *
32  * The buffer is kept for each target layout, index type, and number of components, so only
33  * the first fill of each kind allocates. For a face-centered MultiFab (the MOST velocity averages)
34  * neighbouring surface boxes share a face in the buffer. Both should hold the same value
35  * there, but nothing enforces it, so fill() gives the shared faces a single value before
36  * it copies: the lowest global box index wins, which does not depend on the decomposition
37  * or the rank count, and every copy of the field then agrees.
38  *
39  * A level none of whose boxes reaches the surface (a fine level away from the surface) has
40  * no computed copy to fill from, and fill() leaves the MultiFab as it is.
41  */
43 {
44 public:
45  /**
46  * Record the surface copies of a planar BoxArray.
47  *
48  * @param[in] ba3d 3D BoxArray the planar BoxArray was collapsed from
49  * @param[in] ba2d planar BoxArray, one box per box of ba3d and in the same order
50  * @param[in] dm DistributionMapping shared by ba3d and ba2d
51  * @param[in] surface_index index of the surface cell in the normal direction
52  * @param[in] is_low whether the surface is the low side of the domain
53  * @param[in] normal_dir normal direction of the surface
54  */
55  void define (const amrex::BoxArray& ba3d,
56  const amrex::BoxArray& ba2d,
57  const amrex::DistributionMapping& dm,
58  int surface_index,
59  bool is_low = true,
60  int normal_dir = 2);
61 
62  /**
63  * Fill every copy of a planar MultiFab, valid region and ghost cells, from the
64  * surface copies.
65  *
66  * @param[in,out] mf planar MultiFab on ba2d, of any index type and number of components
67  * @param[in] period periodicity of the level
68  */
69  void fill (amrex::MultiFab& mf, const amrex::Periodicity& period);
70 
71  /**
72  * Copy the computed surface copies of a planar MultiFab into a MultiFab without
73  * duplicates.
74  *
75  * define() gives each surface copy the rank of the planar box it is a copy of, so every
76  * box of dst is filled from a FAB of mf that lives on the same rank and the gather needs
77  * no communication. Reading the surface copies directly, rather than any copy of the
78  * field, means the caller need not have filled the duplicates with fill().
79  *
80  * @param[in] mf planar MultiFab on the planar BoxArray given to define
81  * @param[out] dst MultiFab on surface_boxes() converted to the index type of mf, and on
82  * surface_dm()
83  * @param[in] scomp first component to read from mf
84  * @param[in] dcomp first component to write in dst
85  * @param[in] ncomp number of components
86  */
87  void gather_surface (const amrex::MultiFab& mf, amrex::MultiFab& dst,
88  int scomp, int dcomp, int ncomp) const;
89 
90  //! Cell-centered surface copies of the planar boxes, without duplicates
91  [[nodiscard]] const amrex::BoxArray& surface_boxes () const { return m_ba_sfc; }
92 
93  //! Ranks owning the surface copies: each is on the rank of the planar box it is a copy of
94  [[nodiscard]] const amrex::DistributionMapping& surface_dm () const { return m_dm_sfc; }
95 
96  //! Index of each surface copy in the planar BoxArray
97  [[nodiscard]] const amrex::Vector<int>& surface_index () const { return m_src_index; }
98 
99  //! Whether a planar-box index is the computed copy that touches the surface
100  [[nodiscard]] AMREX_GPU_HOST
101  bool is_surface_copy (const int planar_index) const
102  {
103  return std::binary_search(m_src_index.begin(), m_src_index.end(), planar_index);
104  }
105 
106 private:
107  amrex::MultiFab& buffer (const amrex::MultiFab& mf);
108 
109  struct Buffer
110  {
111  amrex::IndexType ixtype;
112  int ncomp;
113  amrex::BoxArray ba;
114  amrex::DistributionMapping dm;
115  amrex::Vector<const amrex::MultiFab*> sources;
116  std::unique_ptr<amrex::MultiFab> mf;
117  };
118 
119  int m_nplanar{0}; // Number of boxes in the planar BoxArray
120  amrex::BoxArray m_ba_sfc; // Surface copies
121  amrex::DistributionMapping m_dm_sfc; // Ranks owning them
122  amrex::Vector<int> m_src_index; // Their index in the planar BoxArray
123  amrex::Vector<Buffer> m_buffers; // Gather buffers
124 };
125 
126 #endif
Definition: ERF_PlanarBoundary.H:43
void fill(amrex::MultiFab &mf, const amrex::Periodicity &period)
Definition: ERF_PlanarBoundary.cpp:65
amrex::DistributionMapping m_dm_sfc
Definition: ERF_PlanarBoundary.H:121
const amrex::DistributionMapping & surface_dm() const
Ranks owning the surface copies: each is on the rank of the planar box it is a copy of.
Definition: ERF_PlanarBoundary.H:94
amrex::MultiFab & buffer(const amrex::MultiFab &mf)
Definition: ERF_PlanarBoundary.cpp:135
amrex::Vector< int > m_src_index
Definition: ERF_PlanarBoundary.H:122
void define(const amrex::BoxArray &ba3d, const amrex::BoxArray &ba2d, const amrex::DistributionMapping &dm, int surface_index, bool is_low=true, int normal_dir=2)
Definition: ERF_PlanarBoundary.cpp:21
amrex::BoxArray m_ba_sfc
Definition: ERF_PlanarBoundary.H:120
int m_nplanar
Definition: ERF_PlanarBoundary.H:119
AMREX_GPU_HOST bool is_surface_copy(const int planar_index) const
Whether a planar-box index is the computed copy that touches the surface.
Definition: ERF_PlanarBoundary.H:101
amrex::Vector< Buffer > m_buffers
Definition: ERF_PlanarBoundary.H:123
void gather_surface(const amrex::MultiFab &mf, amrex::MultiFab &dst, int scomp, int dcomp, int ncomp) const
Definition: ERF_PlanarBoundary.cpp:109
const amrex::BoxArray & surface_boxes() const
Cell-centered surface copies of the planar boxes, without duplicates.
Definition: ERF_PlanarBoundary.H:91
const amrex::Vector< int > & surface_index() const
Index of each surface copy in the planar BoxArray.
Definition: ERF_PlanarBoundary.H:97
Definition: ERF_PlanarBoundary.H:110
amrex::BoxArray ba
Definition: ERF_PlanarBoundary.H:113
std::unique_ptr< amrex::MultiFab > mf
Definition: ERF_PlanarBoundary.H:116
amrex::IndexType ixtype
Definition: ERF_PlanarBoundary.H:111
int ncomp
Definition: ERF_PlanarBoundary.H:112
amrex::Vector< const amrex::MultiFab * > sources
Definition: ERF_PlanarBoundary.H:115
amrex::DistributionMapping dm
Definition: ERF_PlanarBoundary.H:114