ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_PBLRibCrossing.H
Go to the documentation of this file.
1 #ifndef ERF_PBL_RIB_CROSSING_H_
2 #define ERF_PBL_RIB_CROSSING_H_
3 
4 #include <AMReX_REAL.H>
5 #include <AMReX_GpuQualifiers.H>
6 #include <AMReX_Algorithm.H>
7 
8 /**
9  * Result of a bulk Richardson number scan up one column.
10  */
11 struct RibCrossing {
12  int kpbl; //!< level where Rib first reaches Ribcr; khi when it never does
13  amrex::Real pblh; //!< PBL height, kept in [pblh_min, pblh_max]
14  bool crossed; //!< Rib reached Ribcr at or below khi
15 };
16 
17 /**
18  * Find the PBL height where the bulk Richardson number first reaches Ribcr,
19  * scanning one column from its surface cell ksrf up to the top cell khi
20  * (YSU, Hong et al. 2006; WRF bl_ysu.F90, the "brint" interpolation).
21  *
22  * - The scan looks for the first level k in (ksrf, khi] with Rib >= Ribcr.
23  * The surface value Rib(ksrf) only seeds the lower end of the first
24  * interval, as WRF's br does: a surface cell above Ribcr does not stop the
25  * scan by itself.
26  * - If Rib(ksrf) and Rib(ksrf+1) are both at or above Ribcr, the height is
27  * z(ksrf) and kpbl = ksrf (WRF: brint = 0); with the bounds below this is
28  * pblh_min.
29  * - Otherwise the height is interpolated linearly in Rib between k-1, the last
30  * level below Ribcr, and k. The two levels bracket Ribcr, so the Rib
31  * difference is positive.
32  * - No crossing up to khi: the height is the top of the scan, z(khi), and
33  * kpbl = khi (WRF: brint = 1). The pblh_max cap then applies.
34  *
35  * Every height is then kept in [pblh_min, pblh_max] in that order, so
36  * pblh_min wins when a shallow column has pblh_max < pblh_min.
37  *
38  * @param[in] ksrf first fluid cell of the column
39  * @param[in] khi top cell of the scan
40  * @param[in] Ribcr critical bulk Richardson number
41  * @param[in] rib_at callable, rib_at(k) gives the bulk Richardson number at level k
42  * @param[in] z_at callable, z_at(k) gives the height of level k
43  * @param[in] pblh_min lower bound on the height
44  * @param[in] pblh_max upper bound on the height
45  */
46 template <typename RibAt, typename ZAt>
47 AMREX_GPU_HOST_DEVICE
48 AMREX_FORCE_INLINE
50 find_rib_crossing (int ksrf, int khi, amrex::Real Ribcr,
51  RibAt const& rib_at, ZAt const& z_at,
52  amrex::Real pblh_min, amrex::Real pblh_max) noexcept
53 {
54  amrex::Real rib_lo = rib_at(ksrf);
55  amrex::Real z_lo = z_at(ksrf);
56  for (int k = ksrf + 1; k <= khi; ++k) {
57  const amrex::Real rib_k = rib_at(k);
58  const amrex::Real z_k = z_at(k);
59  if (rib_k >= Ribcr) {
60  if (rib_lo >= Ribcr) {
61  // only possible for k = ksrf + 1: both surface levels at or above Ribcr
62  return RibCrossing{ksrf, amrex::max(amrex::min(z_lo, pblh_max), pblh_min), true};
63  }
64  const amrex::Real pblh = z_lo + (z_k - z_lo) / (rib_k - rib_lo) * (Ribcr - rib_lo);
65  return RibCrossing{k, amrex::max(amrex::min(pblh, pblh_max), pblh_min), true};
66  }
67  rib_lo = rib_k;
68  z_lo = z_k;
69  }
70  return RibCrossing{khi, amrex::max(amrex::min(z_lo, pblh_max), pblh_min), false};
71 }
72 
73 #endif
const int khi
Definition: ERF_InitCustomPert_Bubble.H:25
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE RibCrossing find_rib_crossing(int ksrf, int khi, amrex::Real Ribcr, RibAt const &rib_at, ZAt const &z_at, amrex::Real pblh_min, amrex::Real pblh_max) noexcept
Definition: ERF_PBLRibCrossing.H:50
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_PBLRibCrossing.H:11
amrex::Real pblh
PBL height, kept in [pblh_min, pblh_max].
Definition: ERF_PBLRibCrossing.H:13
int kpbl
level where Rib first reaches Ribcr; khi when it never does
Definition: ERF_PBLRibCrossing.H:12
bool crossed
Rib reached Ribcr at or below khi.
Definition: ERF_PBLRibCrossing.H:14