ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
MicrophysicsColumns Class Reference

#include <ERF_MicrophysicsColumns.H>

Collaboration diagram for MicrophysicsColumns:

Public Types

using FabPtr = std::shared_ptr< amrex::MultiFab >
 

Public Member Functions

void define (const amrex::BoxArray &ba, const amrex::Box &domain)
 Build from a level's grids; call from the scheme's Init (which also runs on regrid) More...
 
bool needs_gather () const
 True when some column is split between boxes, so the fields must be gathered. More...
 
bool boxes_span_domain () const
 True when every box spans the domain in z (required by the Fortran bridges) More...
 
template<std::size_t N>
void gather (std::array< FabPtr, N > &vars, std::array< FabPtr, N > &saved) const
 Swap each non-null field for a copy on the column layout; the originals go to saved. More...
 
template<std::size_t N>
void scatter (std::array< FabPtr, N > &vars, std::array< FabPtr, N > &saved) const
 Copy the column-layout fields back into the originals and restore them. More...
 
FabPtr gather_one (const amrex::MultiFab &src) const
 Copy of a field (cell-centered or z-face; with its ghost cells) on the column layout. More...
 
std::unique_ptr< amrex::MultiFab > gather_nodal (const amrex::MultiFab *src) const
 Copy of a nodal field (e.g. z_phys_nd) on the column layout, or null for null input. More...
 
std::unique_ptr< amrex::iMultiFab > gather_2d (const amrex::iMultiFab *src) const
 Copy of a 2D (z-flattened) integer field (e.g. lmask) on the column layout, or null. More...
 

Private Attributes

bool m_needs_gather = false
 
bool m_boxes_span_domain = true
 
amrex::BoxArray m_col_ba
 
amrex::DistributionMapping m_col_dm
 

Detailed Description

Morrison, WSM6 and WDM6 sediment each column inside one per-column kernel over the k range of the box they are handed: the box top is treated as the top of the column (no inflow) and the box bottom as its ground (outflow booked as surface precipitation). That is only right when no column is split between boxes.

This class records, for one level's grids, whether any column is split between boxes stacked in z, and if so builds a "column layout": a BoxArray covering exactly the same cells in which every contiguous vertical run of covered cells lies inside one box. A scheme then copies its fields onto that layout, runs its unchanged column kernels, and copies the result back. The kernels only read and write their own column, so this gives the same arithmetic as a run whose grids were never split in z.

A run that does not reach the domain bottom (e.g. a refined patch aloft) has no ground, so the schemes accumulate surface precipitation only where klo is the domain bottom.

Member Typedef Documentation

◆ FabPtr

using MicrophysicsColumns::FabPtr = std::shared_ptr<amrex::MultiFab>

Member Function Documentation

◆ boxes_span_domain()

bool MicrophysicsColumns::boxes_span_domain ( ) const
inline

True when every box spans the domain in z (required by the Fortran bridges)

44 { return m_boxes_span_domain; }
bool m_boxes_span_domain
Definition: ERF_MicrophysicsColumns.H:78

◆ define()

void MicrophysicsColumns::define ( const amrex::BoxArray &  ba,
const amrex::Box &  domain 
)

Build from a level's grids; call from the scheme's Init (which also runs on regrid)

10 {
11  m_boxes_span_domain = true;
12  for (int i = 0; i < ba.size(); ++i) {
13  if (ba[i].smallEnd(2) != domain.smallEnd(2) || ba[i].bigEnd(2) != domain.bigEnd(2)) {
14  m_boxes_span_domain = false;
15  break;
16  }
17  }
18 
19  // The z-flattened footprint of every box. A column is split between boxes exactly
20  // when two footprints overlap, since the boxes themselves are disjoint.
21  BoxList fl;
22  for (int i = 0; i < ba.size(); ++i) {
23  Box f(ba[i]); f.setRange(2,0);
24  fl.push_back(f);
25  }
26  const BoxArray fba(std::move(fl));
27 
28  m_needs_gather = false;
29  for (int i = 0; i < fba.size() && !m_needs_gather; ++i) {
30  m_needs_gather = (fba.intersections(fba[i]).size() > 1);
31  }
32 
33  m_col_ba = BoxArray();
34  m_col_dm = DistributionMapping();
35  if (!m_needs_gather) { return; }
36 
37  // Cut each footprint along the x and y edges of every footprint that overlaps it.
38  // Each resulting piece lies either wholly inside or wholly outside every footprint,
39  // so all of its columns are covered by the same boxes. A piece is emitted only by
40  // the lowest-numbered footprint containing it, so the pieces are disjoint.
41  BoxList col;
42  for (int i = 0; i < fba.size(); ++i) {
43  const Box& F = fba[i];
44  const auto overlaps = fba.intersections(F);
45 
46  Vector<int> xs, ys;
47  for (const auto& [j, bx] : overlaps) {
48  xs.push_back(bx.smallEnd(0)); xs.push_back(bx.bigEnd(0)+1);
49  ys.push_back(bx.smallEnd(1)); ys.push_back(bx.bigEnd(1)+1);
50  }
51  std::sort(xs.begin(), xs.end()); xs.erase(std::unique(xs.begin(), xs.end()), xs.end());
52  std::sort(ys.begin(), ys.end()); ys.erase(std::unique(ys.begin(), ys.end()), ys.end());
53 
54  for (int a = 0; a+1 < xs.size(); ++a) {
55  for (int b = 0; b+1 < ys.size(); ++b) {
56  const Box p(IntVect(xs[a], ys[b], 0), IntVect(xs[a+1]-1, ys[b+1]-1, 0));
57 
58  Vector<std::pair<int,int>> zruns;
59  bool owner = true;
60  for (const auto& [j, bx] : overlaps) {
61  if (fba[j].contains(p)) {
62  if (j < i) { owner = false; break; }
63  zruns.emplace_back(ba[j].smallEnd(2), ba[j].bigEnd(2));
64  }
65  }
66  if (!owner) { continue; }
67 
68  // Merge the z ranges of the boxes over this piece into contiguous runs
69  std::sort(zruns.begin(), zruns.end());
70  int lo = zruns[0].first, hi = zruns[0].second;
71  for (int n = 1; n <= zruns.size(); ++n) {
72  if (n < zruns.size() && zruns[n].first == hi+1) {
73  hi = zruns[n].second;
74  continue;
75  }
76  col.push_back(Box(IntVect(p.smallEnd(0), p.smallEnd(1), lo),
77  IntVect(p.bigEnd(0), p.bigEnd(1), hi)));
78  if (n < zruns.size()) { lo = zruns[n].first; hi = zruns[n].second; }
79  }
80  }
81  }
82  }
83 
84  // Merge the pieces, then chop them in x and y (never in z) to no more than the
85  // largest box of the original grids, so the layout still spreads over the ranks.
86  col.simplify();
87  IntVect chunk(1, 1, domain.length(2));
88  for (int i = 0; i < ba.size(); ++i) {
89  chunk[0] = std::max(chunk[0], ba[i].length(0));
90  chunk[1] = std::max(chunk[1], ba[i].length(1));
91  }
92  col.maxSize(chunk);
93 
94  m_col_ba = BoxArray(std::move(col));
95  AMREX_ALWAYS_ASSERT(m_col_ba.numPts() == ba.numPts());
96  m_col_dm = DistributionMapping(m_col_ba);
97 }
const Real length
Definition: ERF_InitCustomPert_AnelasticWallDiffusion.H:16
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
bool m_needs_gather
Definition: ERF_MicrophysicsColumns.H:77
amrex::BoxArray m_col_ba
Definition: ERF_MicrophysicsColumns.H:79
amrex::DistributionMapping m_col_dm
Definition: ERF_MicrophysicsColumns.H:80
@ p
Definition: ERF_WSM6.H:301
Here is the call graph for this function:

◆ gather()

template<std::size_t N>
void MicrophysicsColumns::gather ( std::array< FabPtr, N > &  vars,
std::array< FabPtr, N > &  saved 
) const
inline

Swap each non-null field for a copy on the column layout; the originals go to saved.

49  {
50  for (std::size_t n = 0; n < N; ++n) {
51  saved[n] = vars[n];
52  if (vars[n]) { vars[n] = gather_one(*vars[n]); }
53  }
54  }
FabPtr gather_one(const amrex::MultiFab &src) const
Copy of a field (cell-centered or z-face; with its ghost cells) on the column layout.
Definition: ERF_MicrophysicsColumns.cpp:100
Here is the call graph for this function:

◆ gather_2d()

std::unique_ptr< iMultiFab > MicrophysicsColumns::gather_2d ( const amrex::iMultiFab *  src) const

Copy of a 2D (z-flattened) integer field (e.g. lmask) on the column layout, or null.

129 {
130  if (!src) { return nullptr; }
131  BoxList bl = m_col_ba.boxList();
132  for (auto& b : bl) { b.setRange(2,0); }
133  auto dst = std::make_unique<iMultiFab>(BoxArray(std::move(bl)), m_col_dm,
134  src->nComp(), src->nGrowVect());
135  dst->setVal(0);
136  dst->ParallelCopy(*src, 0, 0, src->nComp(), IntVect(0), src->nGrowVect());
137  return dst;
138 }

◆ gather_nodal()

std::unique_ptr< MultiFab > MicrophysicsColumns::gather_nodal ( const amrex::MultiFab *  src) const

Copy of a nodal field (e.g. z_phys_nd) on the column layout, or null for null input.

117 {
118  if (!src) { return nullptr; }
119  auto dst = std::make_unique<MultiFab>(convert(m_col_ba, src->ixType()), m_col_dm,
120  src->nComp(), src->nGrowVect(),
121  MFInfo().SetArena(src->arena()));
122  dst->setVal(0.0);
123  dst->ParallelCopy(*src, 0, 0, src->nComp(), IntVect(0), src->nGrowVect());
124  return dst;
125 }

◆ gather_one()

MicrophysicsColumns::FabPtr MicrophysicsColumns::gather_one ( const amrex::MultiFab &  src) const

Copy of a field (cell-centered or z-face; with its ghost cells) on the column layout.

101 {
102  // The kernels stage arrays over the FAB box, so give the copy the same ghost cells and
103  // zero them first: ghost cells no source box covers would otherwise be uninitialized.
104  // Copy only from the source's valid cells. Its ghost cells may be stale (the
105  // accumulators' are never refreshed), and where a source box's ghost region overlaps
106  // another source box's valid cells, a copy that read ghost cells could take either.
107  auto dst = std::make_shared<MultiFab>(convert(m_col_ba, src.ixType()), m_col_dm,
108  src.nComp(), src.nGrowVect(),
109  MFInfo().SetArena(src.arena()));
110  dst->setVal(0.0);
111  dst->ParallelCopy(src, 0, 0, src.nComp(), IntVect(0), src.nGrowVect());
112  return dst;
113 }

Referenced by gather().

Here is the caller graph for this function:

◆ needs_gather()

bool MicrophysicsColumns::needs_gather ( ) const
inline

True when some column is split between boxes, so the fields must be gathered.

41 { return m_needs_gather; }

◆ scatter()

template<std::size_t N>
void MicrophysicsColumns::scatter ( std::array< FabPtr, N > &  vars,
std::array< FabPtr, N > &  saved 
) const
inline

Copy the column-layout fields back into the originals and restore them.

59  {
60  for (std::size_t n = 0; n < N; ++n) {
61  if (saved[n]) { saved[n]->ParallelCopy(*vars[n], 0, 0, vars[n]->nComp()); }
62  vars[n] = saved[n];
63  saved[n].reset();
64  }
65  }

Member Data Documentation

◆ m_boxes_span_domain

bool MicrophysicsColumns::m_boxes_span_domain = true
private

Referenced by boxes_span_domain().

◆ m_col_ba

amrex::BoxArray MicrophysicsColumns::m_col_ba
private

◆ m_col_dm

amrex::DistributionMapping MicrophysicsColumns::m_col_dm
private

◆ m_needs_gather

bool MicrophysicsColumns::m_needs_gather = false
private

Referenced by needs_gather().


The documentation for this class was generated from the following files: