15 auto domain =
m_geom.Domain();
16 int i_lo = domain.smallEnd(0);
17 int i_hi = domain.bigEnd(0);
18 int j_lo = domain.smallEnd(1);
19 int j_hi = domain.bigEnd(1);
20 int k_lo = domain.smallEnd(2);
21 int k_hi = domain.bigEnd(2);
25 auto ba =
tabs->boxArray();
26 auto dm =
tabs->DistributionMap();
27 fz.define(convert(ba, IntVect(0,0,1)), dm, 1, 0);
33 for ( MFIter mfi(*
tabs,TilingIfNotGPU()); mfi.isValid(); ++mfi) {
43 auto tbx = mfi.tilebox();
44 if (tbx.smallEnd(0) == i_lo) { tbx.growLo(0,-
m_real_width); }
45 if (tbx.bigEnd(0) == i_hi) { tbx.growHi(0,-
m_real_width); }
46 if (tbx.smallEnd(1) == j_lo) { tbx.growLo(1,-
m_real_width); }
47 if (tbx.bigEnd(1) == j_hi) { tbx.growHi(1,-
m_real_width); }
52 ParallelFor(tbx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
54 qv_array(i,j,k) = std::max(
Real(0), qv_array(i,j,k));
55 qc_array(i,j,k) = std::max(
Real(0), qc_array(i,j,k));
56 qp_array(i,j,k) = std::max(
Real(0), qp_array(i,j,k));
59 Real qcc, auto_r, accrr;
61 Real dq_clwater_to_rain, dq_rain_to_vapor, dq_clwater_to_vapor, dq_vapor_to_clwater;
63 Real pressure = pres_array(i,j,k);
64 erf_qsatw(tabs_array(i,j,k), pressure, qsat);
67 if (qsat <=
Real(0)) {
68 amrex::Warning(
"qsat computed as non-positive; setting to Real(0)!");
76 dq_clwater_to_rain =
Real(0);
77 dq_rain_to_vapor =
Real(0);
78 dq_vapor_to_clwater =
Real(0);
79 dq_clwater_to_vapor =
Real(0);
86 if ( (qv_array(i,j,k) > qsat) && do_cond ) {
87 dq_vapor_to_clwater = std::min(qv_array(i,j,k), (qv_array(i,j,k)-qsat)/(
Real(1) + fac));
92 if ( (qv_array(i,j,k) < qsat) && (qc_array(i,j,k) >
Real(0)) && do_cond ) {
93 dq_clwater_to_vapor = std::min(qc_array(i,j,k), (qsat - qv_array(i,j,k))/(
Real(1) + fac));
96 if (( qp_array(i,j,k) >
Real(0)) && (qv_array(i,j,k) < qsat) ) {
97 Real C =
Real(1.6) +
Real(124.9)*std::pow(
Real(0.001)*rho_array(i,j,k)*qp_array(i,j,k),
Real(0.2046));
98 dq_rain_to_vapor =
Real(1)/(
Real(0.001)*rho_array(i,j,k))*(
Real(1) - qv_array(i,j,k)/qsat)*C*std::pow(
Real(0.001)*rho_array(i,j,k)*qp_array(i,j,k),
Real(0.525))/
99 (
Real(5.4e5) +
Real(2.55e6)/(pressure*qsat))*dtn;
102 dq_rain_to_vapor = std::min({qp_array(i,j,k), dq_rain_to_vapor});
108 if (qc_array(i,j,k) >
Real(0)) {
109 qcc = qc_array(i,j,k);
117 accrr =
Real(2.2) * std::pow(qp_array(i,j,k) ,
Real(0.875));
118 dq_clwater_to_rain = dtn *(accrr*qcc + auto_r*(qcc -
qcw0));
121 dq_clwater_to_rain = std::min(dq_clwater_to_rain, qc_array(i,j,k));
124 qv_array(i,j,k) += -dq_vapor_to_clwater + dq_clwater_to_vapor + dq_rain_to_vapor;
125 qc_array(i,j,k) += dq_vapor_to_clwater - dq_clwater_to_vapor - dq_clwater_to_rain;
126 qp_array(i,j,k) += dq_clwater_to_rain - dq_rain_to_vapor;
128 Real theta_over_T = theta_array(i,j,k)/tabs_array(i,j,k);
129 theta_array(i,j,k) += theta_over_T * d_fac_cond * (dq_vapor_to_clwater - dq_clwater_to_vapor - dq_rain_to_vapor);
131 qv_array(i,j,k) = std::max(
Real(0), qv_array(i,j,k));
132 qc_array(i,j,k) = std::max(
Real(0), qc_array(i,j,k));
133 qp_array(i,j,k) = std::max(
Real(0), qp_array(i,j,k));
135 qt_array(i,j,k) = qv_array(i,j,k) + qc_array(i,j,k);
140 for ( MFIter mfi(fz, TilingIfNotGPU()); mfi.isValid(); ++mfi ){
144 auto fz_array = fz.array(mfi);
145 const Box& tbz = mfi.tilebox();
147 ParallelFor(tbz, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
149 Real rho_avg, qp_avg;
152 rho_avg = rho_array(i,j,k);
153 qp_avg = qp_array(i,j,k);
154 }
else if (k==k_hi+1) {
155 rho_avg = rho_array(i,j,k-1);
156 qp_avg = qp_array(i,j,k-1);
158 rho_avg =
myhalf*(rho_array(i,j,k-1) + rho_array(i,j,k));
159 qp_avg =
myhalf*(qp_array(i,j,k-1) + qp_array(i,j,k));
162 qp_avg = std::max(
Real(0), qp_avg);
172 fz_array(i,j,k) = rho_avg*V_terminal*qp_avg;
179 auto const& ma_fz_arr = fz.const_arrays();
180 GpuTuple<Real> max = ParReduce(TypeList<ReduceOpMax>{},
183 [=] AMREX_GPU_DEVICE (
int box_no,
int i,
int j,
int k) noexcept
186 return { ma_fz_arr[box_no](i,j,k) };
189 n_substep = int( std::ceil(wt_max * coef /
CFL_MAX) );
190 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(n_substep >= 1,
191 "Kessler: Number of precipitation substeps must be greater than 0!");
192 coef /=
Real(n_substep);
193 dtn /=
Real(n_substep);
196 for (
int nsub(0); nsub<n_substep; ++nsub) {
197 for ( MFIter mfi(*
tabs, TilingIfNotGPU()); mfi.isValid(); ++mfi ){
201 auto fz_array = fz.array(mfi);
203 const auto dJ_array = (
m_detJ_cc) ?
m_detJ_cc->const_array(mfi) : Array4<const Real>{};
205 const Box& tbx = mfi.tilebox();
206 const Box& tbz = mfi.tilebox(IntVect(0,0,1),IntVect(0));
209 ParallelFor(tbz, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
211 Real rho_avg, qp_avg;
213 rho_avg = rho_array(i,j,k);
214 qp_avg = qp_array(i,j,k);
215 }
else if (k==k_hi+1) {
216 rho_avg = rho_array(i,j,k-1);
217 qp_avg = qp_array(i,j,k-1);
219 rho_avg =
myhalf*(rho_array(i,j,k-1) + rho_array(i,j,k));
220 qp_avg =
myhalf*(qp_array(i,j,k-1) + qp_array(i,j,k));
223 qp_avg = std::max(
Real(0), qp_avg);
233 fz_array(i,j,k) = rho_avg*V_terminal*qp_avg;
236 rain_accum_array(i,j,k) = rain_accum_array(i,j,k) + rho_avg*qp_avg*V_terminal*dtn/
Real(1000.0)*
Real(1000.0);
241 ParallelFor(tbx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
244 Real dJinv = (dJ_array) ?
Real(1)/dJ_array(i,j,k) :
Real(1);
246 if(std::fabs(fz_array(i,j,k+1)) < 1e-14) fz_array(i,j,k+1) =
Real(0);
247 if(std::fabs(fz_array(i,j,k )) < 1e-14) fz_array(i,j,k ) =
Real(0);
248 Real dq_sed = dJinv * (
Real(1)/rho_array(i,j,k)) * (fz_array(i,j,k+1) - fz_array(i,j,k)) * coef;
249 if(std::fabs(dq_sed) < 1e-14) dq_sed =
Real(0);
251 qp_array(i,j,k) += dq_sed;
252 qp_array(i,j,k) = std::max(
Real(0), qp_array(i,j,k));
259 if (solverChoice.
moisture_type == MoistureType::Kessler_NoRain) {
260 if (!do_cond) {
return; }
262 for ( MFIter mfi(*
tabs,TilingIfNotGPU()); mfi.isValid(); ++mfi) {
270 auto tbx = mfi.tilebox();
271 if (tbx.smallEnd(0) == i_lo) { tbx.growLo(0,-
m_real_width); }
272 if (tbx.bigEnd(0) == i_hi) { tbx.growHi(0,-
m_real_width); }
273 if (tbx.smallEnd(1) == j_lo) { tbx.growLo(1,-
m_real_width); }
274 if (tbx.bigEnd(1) == j_hi) { tbx.growHi(1,-
m_real_width); }
279 ParallelFor(tbx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
281 qc_array(i,j,k) = std::max(
Real(0), qc_array(i,j,k));
285 Real dq_clwater_to_vapor, dq_vapor_to_clwater;
287 Real pressure = pres_array(i,j,k);
288 erf_qsatw(tabs_array(i,j,k), pressure, qsat);
295 dq_vapor_to_clwater =
Real(0);
296 dq_clwater_to_vapor =
Real(0);
303 if (qv_array(i,j,k) > qsat){
304 dq_vapor_to_clwater = std::min(qv_array(i,j,k), (qv_array(i,j,k)-qsat)/(
Real(1) + fac));
308 if (qv_array(i,j,k) < qsat && qc_array(i,j,k) >
Real(0)){
309 dq_clwater_to_vapor = std::min(qc_array(i,j,k), (qsat - qv_array(i,j,k))/(
Real(1) + fac));
312 qv_array(i,j,k) += -dq_vapor_to_clwater + dq_clwater_to_vapor;
313 qc_array(i,j,k) += dq_vapor_to_clwater - dq_clwater_to_vapor;
315 Real theta_over_T = theta_array(i,j,k)/tabs_array(i,j,k);
317 theta_array(i,j,k) += theta_over_T * d_fac_cond * (dq_vapor_to_clwater - dq_clwater_to_vapor);
319 qv_array(i,j,k) = std::max(
Real(0), qv_array(i,j,k));
320 qc_array(i,j,k) = std::max(
Real(0), qc_array(i,j,k));
322 qt_array(i,j,k) = qv_array(i,j,k) + qc_array(i,j,k);
constexpr amrex::Real Cp_d
Definition: ERF_Constants.H:22
constexpr amrex::Real alphaelq
Definition: ERF_Constants.H:58
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:11
constexpr amrex::Real qcw0
Definition: ERF_Constants.H:56
constexpr amrex::Real L_v
Definition: ERF_Constants.H:26
ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const auto prob_lo=geomdata.ProbLo();const auto dx=geomdata.CellSize();const Real x=(prob_lo[0]+(i+myhalf) *dx[0])/mf_m(i, j, 0);const Real z=z_cc(i, j, k);Real L=std::sqrt(std::pow((x - x_c)/x_r, 2)+std::pow((z - z_c)/z_r, 2));if(L<=one) { Real dT=T_pert *(std::cos(PI *L)+one)/two;Real Tbar_hse=p_hse(i, j, k)/(R_d *r_hse(i, j, k));Real theta_perturbed=(Tbar_hse+dT) *std::pow(p_0/p_hse(i, j, k), rdOcp);Real theta_0=(Tbar_hse) *std::pow(p_0/p_hse(i, j, k), rdOcp);if(const_rho) { state_pert(i, j, k, RhoTheta_comp)=r_hse(i, j, k) *(theta_perturbed - theta_0);} else { state_pert(i, j, k, Rho_comp)=getRhoThetagivenP(p_hse(i, j, k))/theta_perturbed - r_hse(i, j, k);} } })
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_dtqsatw(amrex::Real t, amrex::Real p, amrex::Real &dtqsatw)
Definition: ERF_MicrophysicsUtils.H:186
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsatw(amrex::Real t, amrex::Real p, amrex::Real &qsatw)
Definition: ERF_MicrophysicsUtils.H:171
amrex::Real Real
Definition: ERF_ShocInterface.H:19
amrex::Geometry m_geom
Definition: ERF_Kessler.H:151
amrex::MultiFab * m_detJ_cc
Definition: ERF_Kessler.H:174
amrex::Real m_dzmin
Definition: ERF_Kessler.H:160
amrex::Real m_fac_cond
Definition: ERF_Kessler.H:169
bool m_do_cond
Definition: ERF_Kessler.H:170
amrex::Array< FabPtr, MicVar_Kess::NumVars > mic_fab_vars
Definition: ERF_Kessler.H:177
static constexpr amrex::Real CFL_MAX
Definition: ERF_Kessler.H:145
int m_real_width
Definition: ERF_Kessler.H:154
@ qp
Definition: ERF_Kessler.H:31
@ qcl
Definition: ERF_Kessler.H:29
@ tabs
Definition: ERF_Kessler.H:24
@ pres
Definition: ERF_Kessler.H:25
@ rho
Definition: ERF_Kessler.H:22
@ theta
Definition: ERF_Kessler.H:23
@ qt
Definition: ERF_Kessler.H:27
@ rain_accum
Definition: ERF_Kessler.H:33
@ qv
Definition: ERF_Kessler.H:28
real(c_double), parameter epsilon
Definition: ERF_module_model_constants.F90:12
MoistureType moisture_type
Definition: ERF_DataStruct.H:1206