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

Go to the source code of this file.

Functions

void erf_init_dens_hse_dry (amrex::MultiFab &rho_hse, std::unique_ptr< amrex::MultiFab > &, std::unique_ptr< amrex::MultiFab > &z_phys_cc, amrex::Geometry const &geom, const amrex::Vector< amrex::Real > &stretched_dz_h, bool is_constant_dz, bool is_stretched_dz) override
 Initialize density in hydrostatic equilibrium for dry cases. More...
 
void erf_init_dens_hse_moist (amrex::MultiFab &rho_hse, std::unique_ptr< amrex::MultiFab > &, amrex::Geometry const &geom) override
 Initialize density in hydrostatic equilibrium for moist cases. More...
 
void erf_init_const_dens_hse (amrex::MultiFab &rho_hse) override
 Initialize HSE density as a constant value. More...
 
void erf_init_const_dens_and_th_hse (amrex::MultiFab &rho_hse, amrex::MultiFab &p_hse, amrex::MultiFab &pi_hse, amrex::MultiFab &th_hse, amrex::MultiFab &qv_hse, amrex::Real l_rdOcp) override
 Initialize constant density and potential temperature in HSE. More...
 
void erf_init_const_dens_and_linear_th_hse (amrex::MultiFab &rho_hse, amrex::MultiFab &p_hse, amrex::MultiFab &pi_hse, amrex::MultiFab &th_hse, amrex::MultiFab &qv_hse, amrex::Real l_rdOcp, std::unique_ptr< amrex::MultiFab > &z_phys_cc) override
 Initialize constant density and linearly varying potential temperature in HSE. More...
 

Function Documentation

◆ erf_init_const_dens_and_linear_th_hse()

void erf_init_const_dens_and_linear_th_hse ( amrex::MultiFab &  rho_hse,
amrex::MultiFab &  p_hse,
amrex::MultiFab &  pi_hse,
amrex::MultiFab &  th_hse,
amrex::MultiFab &  qv_hse,
amrex::Real  l_rdOcp,
std::unique_ptr< amrex::MultiFab > &  z_phys_cc 
)
override

Initialize constant density and linearly varying potential temperature in HSE.

Parameters
[out]rho_hseMultiFab for HSE density.
[out]p_hseMultiFab for HSE pressure.
[out]pi_hseMultiFab for HSE internal energy.
[out]th_hseMultiFab for HSE potential temperature.
[out]qv_hseMultiFab for HSE water vapor mixing ratio.
[in]l_rdOcpConstant R_d/Cp.
[in]z_phys_ccCell-centered physical height MultiFab.
277 {
278  amrex::Real rho_0 = base_parms.rho_0;
279  amrex::Real T_0 = base_parms.T_0;
280 
281  amrex::ParmParse pp_prob("prob");
282  amrex::Real dtheta_dz = zero; pp_prob.query("dtheta_dz",dtheta_dz);
283 
284  rho_hse.setVal(rho_0);
285 
286  for ( amrex::MFIter mfi(th_hse, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi )
287  {
288  amrex::Array4<amrex::Real> th_hse_arr = th_hse.array(mfi);
289  amrex::Array4<amrex::Real> p_hse_arr = p_hse.array(mfi);
290  amrex::Array4<amrex::Real> pi_hse_arr = pi_hse.array(mfi);
291  amrex::Array4<amrex::Real const> z_arr = z_phys_cc->array(mfi);
292  const amrex::Box& gbx = mfi.growntilebox(1);
293  ParallelFor(gbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
294  {
295  th_hse_arr(i,j,k) = T_0 + dtheta_dz * (z_arr(i,j,k)- z_arr(i,j,0));
296  p_hse_arr(i,j,k) = getPgivenRTh(rho_0*th_hse_arr(i,j,k));
297  pi_hse_arr(i,j,k) = getExnergivenRTh(rho_0*th_hse_arr(i,j,k), l_rdOcp);
298  });
299  } // mfi
300 
301  // Default to zero background moisture
302  qv_hse.setVal(0.0);
303 }
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getExnergivenRTh(const amrex::Real rhotheta, const amrex::Real rdOcp, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:156
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
Real rho_0
Definition: ERF_InitCustomPert_ABL.H:18
Real T_0
Definition: ERF_InitCustomPert_ABL.H:19
ParmParse pp_prob("prob")
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
Here is the call graph for this function:

◆ erf_init_const_dens_and_th_hse()

void erf_init_const_dens_and_th_hse ( amrex::MultiFab &  rho_hse,
amrex::MultiFab &  p_hse,
amrex::MultiFab &  pi_hse,
amrex::MultiFab &  th_hse,
amrex::MultiFab &  qv_hse,
amrex::Real  l_rdOcp 
)
override

Initialize constant density and potential temperature in HSE.

Parameters
[out]rho_hseMultiFab for HSE density.
[out]p_hseMultiFab for HSE pressure.
[out]pi_hseMultiFab for HSE internal energy.
[out]th_hseMultiFab for HSE potential temperature.
[out]qv_hseMultiFab for HSE water vapor mixing ratio.
[in]l_rdOcpConstant R_d/Cp.
238 {
239  amrex::Real rho_0 = base_parms.rho_0;
240  amrex::Real T_0 = base_parms.T_0;
241 
242  amrex::ParmParse pp_prob("prob");
243  amrex::Real dtheta_dz = zero; pp_prob.query("dtheta_dz",dtheta_dz);
244 
245  rho_hse.setVal(rho_0);
246  th_hse.setVal(T_0);
247 
248  amrex::Real rt0 = rho_0 * T_0;
249 
250  amrex::Real p0 = getPgivenRTh(rt0);
251  p_hse.setVal(p0);
252 
253  amrex::Real pi0 = getExnergivenRTh(rt0, l_rdOcp);
254 
255  pi_hse.setVal(pi0);
256 
257  // Default to zero background moisture
258  qv_hse.setVal(0.0);
259 }
real(c_double), parameter p0
Definition: ERF_module_model_constants.F90:40
Here is the call graph for this function:

◆ erf_init_const_dens_hse()

void erf_init_const_dens_hse ( amrex::MultiFab &  rho_hse)
override

Initialize HSE density as a constant value.

Parameters
[out]rho_hseMultiFab to be filled with constant HSE density.
212 {
213  amrex::Real rho_0 = base_parms.rho_0;
214  for ( amrex::MFIter mfi(rho_hse, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi )
215  {
216  amrex::Array4<amrex::Real> rho_hse_arr = rho_hse.array(mfi);
217  const amrex::Box& gbx = mfi.growntilebox(1);
218  ParallelFor(gbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
219  {
220  rho_hse_arr(i,j,k) = rho_0;
221  });
222  }
223 }
Here is the call graph for this function:

◆ erf_init_dens_hse_dry()

void erf_init_dens_hse_dry ( amrex::MultiFab &  rho_hse,
std::unique_ptr< amrex::MultiFab > &  ,
std::unique_ptr< amrex::MultiFab > &  z_phys_cc,
amrex::Geometry const &  geom,
const amrex::Vector< amrex::Real > &  stretched_dz_h,
bool  is_constant_dz,
bool  is_stretched_dz 
)
override

Initialize density in hydrostatic equilibrium for dry cases.

Initialize hydrostatically balanced density

Calls init_isentropic_hse_terrain() or init_isentropic_hse() for cases with and without terrain, respectively. Hydrostatic equilibrium (HSE) is satisfied discretely. Note that these routines presume that qv==0 when evaluating the EOS. Both density and pressure in HSE are calculated but only the density is used at this point.

Parameters
[out]rho_hseMultiFab to be filled with HSE density.
z_phys_ndUnused nodal physical height MultiFab.
[in]z_phys_ccCell-centered physical height MultiFab.
[in]geomGeometry defining the domain.
[in]stretched_dz_hVector of stretched grid spacings.
[in]is_constant_dzWhether the grid spacing is constant.
[in]is_stretched_dzWhether the grid spacing is stretched.
31 {
32  const amrex::Real T_sfc = amrex::Real(300.);
33  const amrex::Real rho_sfc = p_0 / (R_d*T_sfc);
34  const amrex::Real Thetabar = T_sfc;
35 
36  if (!is_constant_dz && !is_stretched_dz) {
37 
38  const int domlo_z = geom.Domain().smallEnd(2);
39  const int domhi_z = geom.Domain().bigEnd(2);
40  if (domhi_z > 255) amrex::Abort("1D Arrays are hard-wired to only 256 high");
41 
42  for ( amrex::MFIter mfi(rho_hse, TileNoZ()); mfi.isValid(); ++mfi )
43  {
44  amrex::Array4<amrex::Real > rho_arr = rho_hse.array(mfi);
45  amrex::Array4<amrex::Real const> z_cc_arr = z_phys_cc->const_array(mfi);
46 
47  // Create a flat box with same horizontal extent but only one cell in vertical
48  const amrex::Box& tbz = mfi.nodaltilebox(2);
49  amrex::Box b2d = tbz; // Copy constructor
50  b2d.grow(0,1); b2d.grow(1,1); // Grow by one in the lateral directions
51  b2d.setRange(2,0);
52 
53  const int klo = tbz.smallEnd(2);
54  const int khi = tbz.bigEnd(2)-1;
55 
56  amrex::ParallelFor(b2d, [=] AMREX_GPU_DEVICE (int i, int j, int)
57  {
58  //
59  // The density we start each column's integration from. If this box does
60  // not reach the bottom of the domain then that is the density in the
61  // ghost cell below the box, which has been interpolated from the
62  // coarser level.
63  //
64  // NOTE: we must do this lookup here, inside the kernel, for two reasons:
65  // rho_arr is device memory, so reading it on the host is invalid in
66  // a GPU build, and -- more importantly -- each column has its own
67  // surface density, so we must not use the value at one corner of
68  // the box for every column.
69  //
70  const amrex::Real rho_local_sfc = (klo == 0) ? rho_sfc : rho_arr(i,j,klo-1);
71 
72  amrex::Array1D<amrex::Real,0,255> r;
73  amrex::Array1D<amrex::Real,0,255> p;
74  HSEutils::init_isentropic_hse_terrain(i,j,rho_local_sfc,Thetabar,&(r(0)),&(p(0)),z_cc_arr,klo,khi);
75 
76  for (int k = klo; k <= khi; k++) {
77  rho_arr(i,j,k) = r(k);
78  }
79 
80  // Impose Neumann conditions at bottom and top of domain boundary
81  if (klo == domlo_z) {
82  rho_arr(i,j,domlo_z-1) = rho_arr(i,j,domlo_z);
83  }
84  if (khi == domhi_z) {
85  rho_arr(i,j,domhi_z+1) = rho_arr(i,j,domhi_z);
86  }
87  });
88  } // mfi
89 
90  } else {
91 
92 
93  // Note that this integrates over the entire domain height,
94  // but only copies into each box as appropriate.
95  // There is no assumption that any one box spans the whole vertical height.
96  const int klo = geom.Domain().smallEnd(2);
97  const int khi = geom.Domain().bigEnd(2);
98 
99  // These are at cell centers (unstaggered)
100  amrex::Vector<amrex::Real> h_r(khi+2);
101  amrex::Vector<amrex::Real> h_p(khi+2);
102 
103  amrex::Gpu::DeviceVector<amrex::Real> d_r(khi+2);
104  amrex::Gpu::DeviceVector<amrex::Real> d_p(khi+2);
105 
106  if (is_constant_dz) {
107  const amrex::Real dz = geom.CellSize()[2];
108  HSEutils::init_isentropic_hse_constant_dz(rho_sfc,Thetabar,h_r.data(),h_p.data(),dz,klo,khi);
109  } else { // stretched_dz
110  HSEutils::init_isentropic_hse_stretched_dz(rho_sfc,Thetabar,h_r.data(),h_p.data(),stretched_dz_h.data(),klo,khi);
111  }
112 
113  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, h_r.begin(), h_r.end(), d_r.begin());
114  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, h_p.begin(), h_p.end(), d_p.begin());
115 
116  amrex::Real* r = d_r.data();
117 
118 #ifdef _OPENMP
119 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
120 #endif
121  for ( amrex::MFIter mfi(rho_hse, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi )
122  {
123  const amrex::Box& bx = mfi.growntilebox(1);
124  const amrex::Array4<amrex::Real> rho_hse_arr = rho_hse[mfi].array();
125  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
126  {
127  int kk = std::max(k,0);
128  rho_hse_arr(i,j,k) = r[kk];
129  });
130  } // mfi
131  }
132 }
constexpr amrex::Real p_0
Definition: ERF_Constants.H:61
constexpr amrex::Real R_d
Definition: ERF_Constants.H:47
const int khi
Definition: ERF_InitCustomPert_Bubble.H:21
Gpu::DeviceVector< Real > d_p(khi+2)
Vector< Real > h_r(khi+2)
Vector< Real > h_p(khi+2)
Gpu::DeviceVector< Real > d_r(khi+2)
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 init_isentropic_hse_stretched_dz(const amrex::Real &r_sfc, const amrex::Real &theta, amrex::Real *r, amrex::Real *p, const amrex::Real *stretched_dz, const int klo, const int khi)
Definition: ERF_HSEUtils.H:219
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void init_isentropic_hse_constant_dz(const amrex::Real &r_sfc, const amrex::Real &theta, amrex::Real *r, amrex::Real *p, const amrex::Real &dz, const int klo, const int khi)
Definition: ERF_HSEUtils.H:109
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void init_isentropic_hse_terrain(int i, int j, const amrex::Real &r_sfc, const amrex::Real &theta, amrex::Real *r, amrex::Real *p, const amrex::Array4< amrex::Real const > z_cc, const int &klo, const int &khi)
Definition: ERF_HSEUtils.H:331
@ dz
Definition: ERF_AdvanceWDM6.cpp:270
@ p
Definition: ERF_WSM6.H:191
Here is the call graph for this function:

◆ erf_init_dens_hse_moist()

void erf_init_dens_hse_moist ( amrex::MultiFab &  rho_hse,
std::unique_ptr< amrex::MultiFab > &  ,
amrex::Geometry const &  geom 
)
override

Initialize density in hydrostatic equilibrium for moist cases.

Parameters
[out]rho_hseMultiFab to be filled with HSE density.
z_phys_ndUnused nodal physical height MultiFab.
[in]geomGeometry defining the domain.
145 {
146  const amrex::Real dz = geom.CellSize()[2];
147  const int khi = geom.Domain().bigEnd()[2];
148 
149  // These are at cell centers (unstaggered)
150  amrex::Vector<amrex::Real> h_r(khi+2);
151  amrex::Vector<amrex::Real> h_p(khi+2);
152  amrex::Vector<amrex::Real> h_t(khi+2);
153  amrex::Vector<amrex::Real> h_q_v(khi+2);
154 
155  amrex::ParmParse pp("prob");
156  amrex::Real q_t = amrex::Real(0.02);
157  pp.query("qt_init",q_t);
158 
160  pp.query("eq_pot_temp",eq_pot_temp);
161 
162  bool use_empirical = false;
163  pp.query("use_empirical_psat",use_empirical);
164 
165  amrex::Real z_tr_1 = -one;
166  amrex::Real z_tr_2 = -one;
167  pp.query("height", z_tr_1);
168  pp.query("z_tr", z_tr_2);
169 
170  // We only set them to zero to make sure they are initialized
172 
173  bool T_from_theta = false;
174  pp.query("T_from_theta_in_moist_init", T_from_theta);
175 
176  if (T_from_theta) {
177  pp.get("theta_tr",theta_tr); pp.get("theta_0",theta_0);
178  pp.get("T_tr",T_tr);
179  }
180 
181  HSEutils::init_isentropic_hse_no_terrain( h_t.data(), h_r.data(), h_p.data(),
182  h_q_v.data(), dz, khi, q_t, eq_pot_temp, use_empirical,
183  T_from_theta, z_tr_1, z_tr_2,
184  theta_0, theta_tr, T_tr);
185 
186  amrex::Gpu::DeviceVector<amrex::Real> d_r(khi+2);
187  amrex::Gpu::copy(amrex::Gpu::hostToDevice, h_r.begin(), h_r.end(), d_r.begin());
188  amrex::Real* r = d_r.data();
189 
190 #ifdef _OPENMP
191 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
192 #endif
193  for ( amrex::MFIter mfi(rho_hse,amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
194  {
195  const amrex::Box& bx = mfi.growntilebox(1);
196  const amrex::Array4<amrex::Real> rho_hse_arr = rho_hse[mfi].array();
197  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
198  {
199  int kk = std::max(k,0);
200  rho_hse_arr(i,j,k) = r[kk];
201  });
202  } // mfi
203 }
constexpr amrex::Real one
Definition: ERF_Constants.H:9
ParmParse pp("prob")
Real eq_pot_temp
Definition: ERF_InitCustomPert_MultiSpeciesBubble.H:23
bool use_empirical
Definition: ERF_InitCustomPert_MultiSpeciesBubble.H:25
Vector< Real > h_t(khi+2)
Real T_tr
Definition: ERF_InitCustomPert_SquallLine.H:43
Real q_t
Definition: ERF_InitCustomPert_SquallLine.H:24
Vector< Real > h_q_v(khi+2)
Real theta_tr
Definition: ERF_InitCustomPert_SquallLine.H:47
Real theta_0
Definition: ERF_InitCustomPert_SquallLine.H:46
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE void init_isentropic_hse_no_terrain(Real *theta, Real *r, Real *p, Real *q_v, const Real &dz, const int &khi, const Real q_t, const Real eq_pot_temp, const bool use_empirical, const bool T_from_theta=false, const Real z_tr_1=-one, const Real z_tr_2=-one, const Real theta_0=amrex::Real(0), const Real theta_tr=amrex::Real(0), const Real T_tr=amrex::Real(0))
Definition: ERF_HSEUtils.H:675
Here is the call graph for this function: