ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_ParFunctions.H
Go to the documentation of this file.
1 #ifndef ERF_ParFunctions_H
2 #define ERF_ParFunctions_H
3 
4 #include <limits>
5 #include <memory>
6 
7 #include <AMReX_MultiFab.H>
8 #include <AMReX_ParallelDescriptor.H>
9 #include <AMReX_Reduce.H>
10 
11 /**
12  * Reduce a multifab of heights to a vector of max values at each height: v[k] is the largest
13  * valid value of mf at index k over all boxes of the level. A box contributes only the k it
14  * holds, since the boxes of a level need not span the column (a refined region that does not
15  * reach the top or the ground, or grids split in z). A k that no box holds gets the nominal
16  * height of the level from zlevels_stag (the face height if mf is nodal in z, the mean of the
17  * two faces otherwise), so every entry of v is a height and no caller has to test for a k
18  * that is not covered.
19  *
20  * @param[out] v max of mf per k
21  * @param[in] mf heights (z_phys_cc or z_phys_nd of a level)
22  * @param[in] zlevels_stag nominal heights of the z faces of the level
23  */
24 AMREX_FORCE_INLINE
25 void reduce_to_max_per_height (amrex::Vector<amrex::Real>& v,
26  std::unique_ptr<amrex::MultiFab>& mf,
27  const amrex::Vector<amrex::Real>& zlevels_stag)
28 {
29  const int nk = static_cast<int>(v.size());
30  const bool nodal_z = mf->ixType().nodeCentered(2);
31  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(static_cast<int>(zlevels_stag.size()) >= (nodal_z ? nk : nk+1),
32  "reduce_to_max_per_height: zlevels_stag is shorter than the column");
33 
34  // the identity of ReduceOpMax: the value of a k that no box holds
35  constexpr amrex::Real not_covered = std::numeric_limits<amrex::Real>::lowest();
36 
37  for (int k = 0; k < nk; k++) {
38  amrex::ReduceOps<amrex::ReduceOpMax> reduce_op;
39  amrex::ReduceData<amrex::Real> reduce_data(reduce_op);
40  using ReduceTuple = typename decltype(reduce_data)::Type;
41  for (amrex::MFIter mfi(*mf); mfi.isValid(); ++mfi) {
42  amrex::Box bx = mfi.validbox();
43  if (k < bx.smallEnd(2) || k > bx.bigEnd(2)) { continue; }
44  bx.setSmall(2, k);
45  bx.setBig(2, k);
46  const amrex::Array4<amrex::Real const> a = mf->const_array(mfi);
47  reduce_op.eval(bx, reduce_data,
48  [=] AMREX_GPU_DEVICE (int i, int j, int kk) noexcept -> ReduceTuple
49  {
50  return { a(i,j,kk) };
51  });
52  }
53  v[k] = amrex::get<0>(reduce_data.value(reduce_op));
54  }
55  amrex::ParallelDescriptor::ReduceRealMax(v.data(), nk);
56 
57  for (int k = 0; k < nk; k++) {
58  if (v[k] == not_covered) {
59  v[k] = nodal_z ? zlevels_stag[k]
60  : amrex::Real(0.5) * (zlevels_stag[k] + zlevels_stag[k+1]);
61  }
62  }
63 }
64 
65 #endif /* ERF_ParFunctions.H */
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(m_cloud_chamber_config.active, "Cloud Chamber: initializer reached without a parsed configuration")
AMREX_FORCE_INLINE void reduce_to_max_per_height(amrex::Vector< amrex::Real > &v, std::unique_ptr< amrex::MultiFab > &mf, const amrex::Vector< amrex::Real > &zlevels_stag)
Definition: ERF_ParFunctions.H:25
amrex::Real Real
Definition: ERF_ShocInterface.H:19