ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_Rebalance.cpp File Reference
#include "ERF_HSEUtils.H"
#include "ERF_Utils.H"
Include dependency graph for ERF_Rebalance.cpp:

Functions

void rebalance_columns (MultiFab &rho, MultiFab &theta, const MultiFab &qv, const MultiFab &qt, const MultiFab *z_phys, const Geometry &geom, const bool &maintain_Th, bool use_sfc)
 

Function Documentation

◆ rebalance_columns()

void rebalance_columns ( MultiFab &  rho,
MultiFab &  theta,
const MultiFab &  qv,
const MultiFab &  qt,
const MultiFab *  z_phys,
const Geometry &  geom,
const bool &  maintain_Th,
bool  use_sfc 
)

Rebalance density and potential temperature columns to satisfy hydrostatic equilibrium.

Parameters
[in,out]rhoDensity field
[in,out]thetaPotential temperature field
[in]qvWater vapor mixing ratio
[in]qtTotal water mixing ratio
[in]z_physPhysical height field
[in]geomGrid geometry
[in]maintain_ThWhether to maintain the existing potential temperature profile
[in]use_sfcWhether to use a surface boundary condition for initialization
27 {
28 
29 #ifdef AMREX_USE_FLOAT
30  Real tol = Real(1.0e-6);
31 #else
32  Real tol = Real(1.0e-10);
33 #endif
34  Real grav = CONST_GRAV;
35 
36  // int ncomp = cons.nComp();
37  int k_dom_lo = geom.Domain().smallEnd(2);
38 
39  for (MFIter mfi(rho,TileNoZ()); mfi.isValid(); ++mfi) {
40  Box bx = mfi.tilebox();
41  int klo = bx.smallEnd(2);
42  int khi = bx.bigEnd(2);
43 
44  //
45  // This is a bottom-up integration: the value in cell k depends only on cells at
46  // or below k. A box that stops below the top of the domain is therefore perfectly
47  // well defined -- it produces exactly the values the full-height column would have
48  // had in the cells it does contain -- so we deliberately do NOT require
49  // khi == geom.Domain().bigEnd(2) here. That matters for a refined level whose
50  // patch covers only the lower part of the domain, which is the normal way to nest
51  // an LES region inside a mesoscale parent.
52  //
53  // What the integration does require is a valid starting value in its lowest cell.
54  // The use_sfc seeding below marches up from p_0 at z = 0, so it is only meaningful
55  // for a box that reaches the ground; a box whose klo is in the interior has no
56  // surface to start from. (With amr.refine_grid_layout_z = 0, which is the ERF
57  // default set in main.cpp, grids are never chopped in z and this always holds.)
58  //
59  // NOTE: TileNoZ() above guarantees that klo/khi are the *box's* z extent rather
60  // than a tile's, so each column is integrated exactly once.
61  //
62  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(!use_sfc || (klo == k_dom_lo),
63  "rebalance_columns with use_sfc requires boxes that "
64  "reach the bottom of the domain: the integration is "
65  "seeded from p_0 at the surface. Set erf.max_grid_size_z "
66  "large enough that the grids are not decomposed in z.");
67  bx.makeSlab(2,klo);
68 
69  const Array4< Real>& rho_arr = rho.array(mfi);
70  const Array4< Real>& th_arr = theta.array(mfi);
71  const Array4<const Real>& qv_arr = qv.const_array(mfi);
72  const Array4<const Real>& qt_arr = qt.const_array(mfi);
73 
74  const Array4<const Real>& z_arr = z_phys->const_array(mfi);
75 
76  ParallelFor(bx, [=,RdoCp_d=RdoCp] AMREX_GPU_DEVICE (int i, int j, int /*k*/) noexcept
77  {
78  // Integrate upward from the bottom of this box to its top
79  Real dz, F, C;
80  Real rho_tot_hi, rho_tot_lo;
81  Real z_lo, z_hi;
82  Real R_lo, R_hi;
83  Real qv_lo, qv_hi;
84  Real qt_lo, qt_hi;
85  Real Th_lo, Th_hi;
86  Real T_hi;
87  Real P_lo, P_hi;
88 
89  // Integrate from z=0
90  if (use_sfc) {
91  z_lo = zero; // corresponding to p_0
92  z_hi = Real(0.125) * (z_arr(i,j,klo ) + z_arr(i+1,j,klo ) + z_arr(i,j+1,klo ) + z_arr(i+1,j+1,klo )
93  +z_arr(i,j,klo+1) + z_arr(i+1,j,klo+1) + z_arr(i,j+1,klo+1) + z_arr(i+1,j+1,klo+1));
94  dz = z_hi - z_lo;
95 
96  // Establish known constant
97  qt_lo = qt_arr(i,j,klo);
98  qv_lo = qv_arr(i,j,klo);
99  Th_lo = th_arr(i,j,klo);
100  P_lo = p_0;
101  R_lo = getRhogivenThetaPress(Th_lo, P_lo, RdoCp_d, qv_lo);
102  rho_tot_lo = R_lo * (one + qt_lo);
103  C = -P_lo + myhalf*rho_tot_lo*grav*dz;
104 
105  // Initial guess and residual
106  qt_hi = qt_arr(i,j,klo);
107  qv_hi = qv_arr(i,j,klo);
108  Th_hi = th_arr(i,j,klo);
109  P_hi = p_0;
110  T_hi = getTgivenPandTh(P_hi, Th_hi, RdoCp_d);
111  R_hi = getRhogivenThetaPress(Th_hi, P_hi, RdoCp_d, qv_hi);
112  rho_tot_hi = R_hi * (one + qt_hi);
113  F = P_hi + myhalf*rho_tot_hi*grav*dz + C;
114 
115  // Do iterations
116  HSEutils::Newton_Raphson_hse(tol, RdoCp_d, dz,
117  grav, C, Th_hi, T_hi,
118  qt_hi, qv_hi,
119  P_hi, R_hi, F, maintain_Th);
120 
121  // Assign data
122  rho_arr(i,j,klo) = R_hi;
123  if (!maintain_Th) { th_arr(i,j,klo) = getThgivenTandP(T_hi, P_hi, RdoCp_d); }
124  P_lo = P_hi;
125  z_lo = z_hi;
126 
127  // Use SFC state at first CC
128  } else {
129  z_lo = Real(0.125) * (z_arr(i,j,klo ) + z_arr(i+1,j,klo ) + z_arr(i,j+1,klo ) + z_arr(i+1,j+1,klo )
130  +z_arr(i,j,klo+1) + z_arr(i+1,j,klo+1) + z_arr(i,j+1,klo+1) + z_arr(i+1,j+1,klo+1));
131  P_lo = getPgivenRTh(rho_arr(i,j,klo)*th_arr(i,j,klo),qv_arr(i,j,klo));
132  P_hi = P_lo;
133  }
134 
135  for (int k(klo+1); k<=khi; ++k)
136  {
137  z_hi = Real(0.125) * (z_arr(i,j,k ) + z_arr(i+1,j,k ) + z_arr(i,j+1,k ) + z_arr(i+1,j+1,k )
138  +z_arr(i,j,k+1) + z_arr(i+1,j,k+1) + z_arr(i,j+1,k+1) + z_arr(i+1,j+1,k+1));
139  dz = z_hi - z_lo;
140 
141  // Establish known constant
142  qt_lo = qt_arr(i,j,k-1);
143  qv_lo = qv_arr(i,j,k-1);
144  Th_lo = th_arr(i,j,k-1);
145  R_lo = getRhogivenThetaPress(Th_lo, P_lo, RdoCp_d, qv_lo);
146  rho_tot_lo = R_lo * (one + qt_lo);
147  C = -P_lo + myhalf*rho_tot_lo*grav*dz;
148 
149  // Initial guess and residual
150  qt_hi = qt_arr(i,j,k);
151  qv_hi = qv_arr(i,j,k);
152  Th_hi = th_arr(i,j,k);
153  T_hi = getTgivenPandTh(P_hi, Th_hi, RdoCp_d);
154  R_hi = getRhogivenThetaPress(Th_hi, P_hi, RdoCp_d, qv_hi);
155  rho_tot_hi = R_hi * (one + qt_hi);
156  F = P_hi + myhalf*rho_tot_hi*grav*dz + C;
157 
158  // Do iterations
159  HSEutils::Newton_Raphson_hse(tol, RdoCp_d, dz,
160  grav, C, Th_hi, T_hi,
161  qt_hi, qv_hi,
162  P_hi, R_hi, F, maintain_Th);
163 
164  // Assign data
165  rho_arr(i,j,k) = R_hi;
166  if (!maintain_Th) { th_arr(i,j,k) = getThgivenTandP(T_hi, P_hi, RdoCp_d); }
167  P_lo = P_hi;
168  z_lo = z_hi;
169  }
170  });
171  } // mfi
172 } // rebalance_columns
constexpr amrex::Real one
Definition: ERF_Constants.H:9
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:13
constexpr amrex::Real p_0
Definition: ERF_Constants.H:61
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:64
constexpr amrex::Real RdoCp
Definition: ERF_Constants.H:54
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getRhogivenThetaPress(const amrex::Real th, const amrex::Real p, const amrex::Real rdOcp, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:96
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getThgivenTandP(const amrex::Real T, const amrex::Real P, const amrex::Real rdOcp)
Definition: ERF_EOS.H:18
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getPgivenRTh(const amrex::Real rhotheta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:81
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getTgivenPandTh(const amrex::Real P, const amrex::Real th, const amrex::Real rdOcp)
Definition: ERF_EOS.H:32
const int khi
Definition: ERF_InitCustomPert_Bubble.H:21
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(m_cloud_chamber_config.active, "Cloud Chamber: initializer reached without a parsed configuration")
auto qv_arr
Definition: ERF_InitCustomPert_MultiSpeciesBubble.H:210
ParallelFor(fab_box, [=] AMREX_GPU_DEVICE(int i, int j, int k) { qrcuten_arr(i, j, k)=Real(0);qscuten_arr(i, j, k)=Real(0);qicuten_arr(i, j, k)=Real(0);})
amrex::Real Real
Definition: ERF_ShocInterface.H:19
AMREX_FORCE_INLINE amrex::IntVect TileNoZ()
Definition: ERF_TileNoZ.H:11
auto rho_arr
Definition: ERF_UpdateWSubsidence_SineMassFlux.H:3
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void Newton_Raphson_hse(const Real &m_tol, const Real &RdoCp, const Real &dz, const Real &g, const Real &C, const Real &Th, const Real &T, const Real &qt, const Real &qv, Real &P, Real &rd, Real &F, const bool &maintain_Th)
Definition: ERF_HSEUtils.H:44
@ theta
Definition: ERF_SLM.H:20
@ rho
Definition: ERF_Kessler.H:24
@ qt
Definition: ERF_Kessler.H:29
@ qv
Definition: ERF_Kessler.H:30
@ dz
Definition: ERF_AdvanceWDM6.cpp:270

Referenced by ERF::init_from_input_sounding().

Here is the call graph for this function:
Here is the caller graph for this function: