Function for computing the slow RHS for the evolution equations for the density, potential temperature and momentum.
68 BL_PROFILE_REGION(
"erf_make_mom_sources()");
70 Box domain(geom.Domain());
71 const GpuArray<Real, AMREX_SPACEDIM> dxInv = geom.InvCellSizeArray();
105 if (solverChoice.
terrain_type == TerrainType::ImmersedForcing) {
107 amrex::Error(
" Currently forest canopy cannot be used with immersed forcing");
117 auto cosphi = solverChoice.
cosphi;
118 auto sinphi = solverChoice.
sinphi;
150 Real rhoUA_target{0};
151 Real rhoVA_target{0};
158 Table1D<Real> dptr_r_plane, dptr_u_plane, dptr_v_plane;
159 TableData<Real, 1> r_plane_tab, u_plane_tab, v_plane_tab;
162 enforce_massflux_x || enforce_massflux_y))
165 const int u_offset = 1;
166 const int v_offset = 1;
175 r_ave.compute_averages(
ZDir(), r_ave.field());
177 int ncell = r_ave.ncell_line();
178 Gpu::HostVector< Real> r_plane_h(ncell);
179 Gpu::DeviceVector< Real> r_plane_d(ncell);
181 r_ave.line_average(
Rho_comp, r_plane_h);
183 Gpu::copyAsync(Gpu::hostToDevice, r_plane_h.begin(), r_plane_h.end(), r_plane_d.begin());
185 Real* dptr_r = r_plane_d.data();
187 Box tdomain = domain; tdomain.grow(2,ng_c[2]);
188 r_plane_tab.resize({tdomain.smallEnd(2)}, {tdomain.bigEnd(2)});
190 dptr_r_plane = r_plane_tab.table();
191 ParallelFor(ncell, [=] AMREX_GPU_DEVICE (
int k) noexcept
193 dptr_r_plane(k-
offset) = dptr_r[k];
197 IntVect ng_u = S_data[
IntVars::xmom].nGrowVect(); ng_u[2] = u_offset;
200 IntVect ng_v = S_data[
IntVars::ymom].nGrowVect(); ng_v[2] = v_offset;
203 u_ave.compute_averages(
ZDir(), u_ave.field());
204 v_ave.compute_averages(
ZDir(), v_ave.field());
206 int u_ncell = u_ave.ncell_line();
207 int v_ncell = v_ave.ncell_line();
208 Gpu::HostVector< Real> u_plane_h(u_ncell), v_plane_h(v_ncell);
209 Gpu::DeviceVector< Real> u_plane_d(u_ncell), v_plane_d(v_ncell);
211 u_ave.line_average(0, u_plane_h);
212 v_ave.line_average(0, v_plane_h);
214 Gpu::copyAsync(Gpu::hostToDevice, u_plane_h.begin(), u_plane_h.end(), u_plane_d.begin());
215 Gpu::copyAsync(Gpu::hostToDevice, v_plane_h.begin(), v_plane_h.end(), v_plane_d.begin());
217 Real* dptr_u = u_plane_d.data();
218 Real* dptr_v = v_plane_d.data();
220 Box udomain = domain; udomain.grow(2,ng_u[2]);
221 Box vdomain = domain; vdomain.grow(2,ng_v[2]);
222 u_plane_tab.resize({udomain.smallEnd(2)}, {udomain.bigEnd(2)});
223 v_plane_tab.resize({vdomain.smallEnd(2)}, {vdomain.bigEnd(2)});
225 dptr_u_plane = u_plane_tab.table();
226 ParallelFor(u_ncell, [=] AMREX_GPU_DEVICE (
int k) noexcept
228 dptr_u_plane(k-u_offset) = dptr_u[k];
231 dptr_v_plane = v_plane_tab.table();
232 ParallelFor(v_ncell, [=] AMREX_GPU_DEVICE (
int k) noexcept
234 dptr_v_plane(k-v_offset) = dptr_v[k];
238 if (enforce_massflux_x || enforce_massflux_y) {
239 Real Lx = geom.ProbHi(0) - geom.ProbLo(0);
240 Real Ly = geom.ProbHi(1) - geom.ProbLo(1);
242 if (solverChoice.
mesh_type == MeshType::ConstantDz) {
244 rhoUA = std::accumulate(u_plane_h.begin() + u_offset + massflux_klo,
245 u_plane_h.begin() + u_offset + massflux_khi+1, 0.0);
246 rhoVA = std::accumulate(v_plane_h.begin() + v_offset + massflux_klo,
247 v_plane_h.begin() + v_offset + massflux_khi+1, 0.0);
248 rhoUA_target = std::accumulate(r_plane_h.begin() +
offset + massflux_klo,
249 r_plane_h.begin() +
offset + massflux_khi+1, 0.0);
250 rhoVA_target = rhoUA_target;
252 rhoUA *= geom.CellSize(2) * Ly;
253 rhoVA *= geom.CellSize(2) * Lx;
254 rhoUA_target *= geom.CellSize(2) * Ly;
255 rhoVA_target *= geom.CellSize(2) * Lx;
257 }
else if (solverChoice.
mesh_type == MeshType::StretchedDz) {
259 for (
int k=massflux_klo; k < massflux_khi; ++k) {
260 rhoUA += u_plane_h[k + u_offset] * stretched_dz_h[k];
261 rhoVA += v_plane_h[k + v_offset] * stretched_dz_h[k];
262 rhoUA_target += r_plane_h[k +
offset] * stretched_dz_h[k];
264 rhoVA_target = rhoUA_target;
273 rhoUA_target *= U_target;
274 rhoVA_target *= V_target;
276 Print() <<
"Integrated mass flux : " << rhoUA <<
" " << rhoVA
277 <<
" (target: " << rhoUA_target <<
" " << rhoVA_target <<
")"
285 for ( MFIter mfi(S_data[
IntVars::cons]); mfi.isValid(); ++mfi)
287 Box tbx = mfi.nodaltilebox(0);
288 Box tby = mfi.nodaltilebox(1);
289 Box tbz = mfi.nodaltilebox(2);
290 if (tbz.bigEnd(2) == domain.bigEnd(2)+1) tbz.growHi(2,-1);
292 const Array4<const Real>& cell_data = S_data[
IntVars::cons].array(mfi);
293 const Array4<const Real>& rho_u = S_data[
IntVars::xmom].array(mfi);
294 const Array4<const Real>& rho_v = S_data[
IntVars::ymom].array(mfi);
295 const Array4<const Real>& rho_w = S_data[
IntVars::zmom].array(mfi);
297 const Array4<const Real>& u =
xvel.array(mfi);
298 const Array4<const Real>& v =
yvel.array(mfi);
299 const Array4<const Real>& w = wvel.array(mfi);
301 const Array4< Real>& xmom_src_arr = xmom_src.array(mfi);
302 const Array4< Real>& ymom_src_arr = ymom_src.array(mfi);
303 const Array4< Real>& zmom_src_arr = zmom_src.array(mfi);
305 const Array4<const Real>& r0 = r_hse.const_array(mfi);
307 const Array4<const Real>& f_drag_arr = (forest_drag) ? forest_drag->const_array(mfi) :
308 Array4<const Real>{};
309 const Array4<const Real>& t_blank_arr = (terrain_blank) ? terrain_blank->const_array(mfi) :
310 Array4<const Real>{};
312 const Array4<const Real>& cphi_arr = (cosPhi_mf) ? cosPhi_mf->const_array(mfi) :
313 Array4<const Real>{};
314 const Array4<const Real>& sphi_arr = (sinPhi_mf) ? sinPhi_mf->const_array(mfi) :
315 Array4<const Real>{};
317 const Array4<const Real>& z_nd_arr = z_phys_nd->const_array(mfi);
318 const Array4<const Real>& z_cc_arr = z_phys_cc->const_array(mfi);
324 if (use_coriolis && is_slow_step) {
325 if(solverChoice.
init_type == InitType::HindCast) {
326 const Array4<const Real>& latlon_arr = (*forecast_state_at_lev)[4].array(mfi);
327 ParallelFor(tbx, tby, tbz,
328 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
330 Real rho_v_loc = 0.25 * (rho_v(i,j+1,k) + rho_v(i,j,k) + rho_v(i-1,j+1,k) + rho_v(i-1,j,k));
331 Real rho_w_loc = 0.25 * (rho_w(i,j,k+1) + rho_w(i,j,k) + rho_w(i,j-1,k+1) + rho_w(i,j-1,k));
332 Real latitude = latlon_arr(i,j,k,0);
333 Real sphi_loc = std::sin(latitude*
PI/180.0);
334 Real cphi_loc = std::cos(latitude*
PI/180.0);
335 xmom_src_arr(i, j, k) += coriolis_factor * (rho_v_loc * sphi_loc - rho_w_loc * cphi_loc);
337 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
338 Real rho_u_loc = 0.25 * (rho_u(i+1,j,k) + rho_u(i,j,k) + rho_u(i+1,j-1,k) + rho_u(i,j-1,k));
339 Real latitude = latlon_arr(i,j,k,0);
340 Real sphi_loc = std::sin(latitude*
PI/180.0);
341 ymom_src_arr(i, j, k) += -coriolis_factor * rho_u_loc * sphi_loc;
343 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
344 Real rho_u_loc = 0.25 * (rho_u(i+1,j,k) + rho_u(i,j,k) + rho_u(i+1,j,k-1) + rho_u(i,j,k-1));
345 Real latitude = latlon_arr(i,j,k,0);
346 Real cphi_loc = std::cos(latitude*
PI/180.0);
347 zmom_src_arr(i, j, k) += coriolis_factor * rho_u_loc * cphi_loc;
350 else if (var_coriolis && has_lat_lon) {
351 ParallelFor(tbx, tby, tbz,
352 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
354 Real rho_v_loc = 0.25 * (rho_v(i,j+1,k) + rho_v(i,j,k) + rho_v(i-1,j+1,k) + rho_v(i-1,j,k));
355 Real rho_w_loc = 0.25 * (rho_w(i,j,k+1) + rho_w(i,j,k) + rho_w(i,j-1,k+1) + rho_w(i,j-1,k));
356 Real sphi_loc = 0.5 * (sphi_arr(i,j,0) + sphi_arr(i-1,j,0));
357 Real cphi_loc = 0.5 * (cphi_arr(i,j,0) + cphi_arr(i-1,j,0));
358 xmom_src_arr(i, j, k) += coriolis_factor * (rho_v_loc * sphi_loc - rho_w_loc * cphi_loc);
360 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
361 Real rho_u_loc = 0.25 * (rho_u(i+1,j,k) + rho_u(i,j,k) + rho_u(i+1,j-1,k) + rho_u(i,j-1,k));
362 Real sphi_loc = 0.5 * (sphi_arr(i,j,0) + sphi_arr(i,j-1,0));
363 ymom_src_arr(i, j, k) += -coriolis_factor * rho_u_loc * sphi_loc;
365 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
366 Real rho_u_loc = 0.25 * (rho_u(i+1,j,k) + rho_u(i,j,k) + rho_u(i+1,j,k-1) + rho_u(i,j,k-1));
367 zmom_src_arr(i, j, k) += coriolis_factor * rho_u_loc * cphi_arr(i,j,0);
370 ParallelFor(tbx, tby, tbz,
371 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
373 Real rho_v_loc = 0.25 * (rho_v(i,j+1,k) + rho_v(i,j,k) + rho_v(i-1,j+1,k) + rho_v(i-1,j,k));
374 Real rho_w_loc = 0.25 * (rho_w(i,j,k+1) + rho_w(i,j,k) + rho_w(i,j-1,k+1) + rho_w(i,j-1,k));
375 xmom_src_arr(i, j, k) += coriolis_factor * (rho_v_loc * sinphi - rho_w_loc * cosphi);
377 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
378 Real rho_u_loc = 0.25 * (rho_u(i+1,j,k) + rho_u(i,j,k) + rho_u(i+1,j-1,k) + rho_u(i,j-1,k));
379 ymom_src_arr(i, j, k) += -coriolis_factor * rho_u_loc * sinphi;
381 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
382 Real rho_u_loc = 0.25 * (rho_u(i+1,j,k) + rho_u(i,j,k) + rho_u(i+1,j,k-1) + rho_u(i,j,k-1));
383 zmom_src_arr(i, j, k) += coriolis_factor * rho_u_loc * cosphi;
393 if ( (is_slow_step && !use_Rayleigh_fast_uv) || (!is_slow_step && use_Rayleigh_fast_uv)) {
394 if (rayleigh_damp_U) {
395 ParallelFor(tbx, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
398 Real uu = rho_u(i,j,k) / rho_on_u_face;
399 Real sinesq = d_sinesq_at_lev[k];
400 xmom_src_arr(i, j, k) -= dampcoef*sinesq * (uu -
ubar[k]) * rho_on_u_face;
404 if (rayleigh_damp_V) {
405 ParallelFor(tby, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
408 Real vv = rho_v(i,j,k) / rho_on_v_face;
409 Real sinesq = d_sinesq_at_lev[k];
410 ymom_src_arr(i, j, k) -= dampcoef*sinesq * (vv -
vbar[k]) * rho_on_v_face;
415 if ( (is_slow_step && !use_Rayleigh_fast_w) || (!is_slow_step && use_Rayleigh_fast_w)) {
416 if (rayleigh_damp_W) {
417 ParallelFor(tbz, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
420 Real ww = rho_w(i,j,k) / rho_on_w_face;
421 Real sinesq = d_sinesq_stag_at_lev[k];
422 zmom_src_arr(i, j, k) -= dampcoef*sinesq * (ww -
wbar[k]) * rho_on_w_face;
431 ParallelFor(tbx, tby, tbz,
432 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
435 xmom_src_arr(i, j, k) += rho_on_u_face * abl_geo_forcing[0];
437 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
440 ymom_src_arr(i, j, k) += rho_on_v_face * abl_geo_forcing[1];
442 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
445 zmom_src_arr(i, j, k) += rho_on_w_face * abl_geo_forcing[2];
452 if (geo_wind_profile && is_slow_step) {
453 ParallelFor(tbx, tby,
454 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
457 xmom_src_arr(i, j, k) -= coriolis_factor * rho_on_u_face * dptr_v_geos[k] * sinphi;
459 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
462 ymom_src_arr(i, j, k) += coriolis_factor * rho_on_v_face * dptr_u_geos[k] * sinphi;
472 ParallelFor(tbx, tby,
473 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
475 Real dzInv = 0.5*dxInv[2];
477 Real z_xf_lo = 0.25 * ( z_nd_arr(i,j,k ) + z_nd_arr(i,j+1,k )
478 + z_nd_arr(i,j,k-1) + z_nd_arr(i,j+1,k-1) );
479 Real z_xf_hi = 0.25 * ( z_nd_arr(i,j,k+1) + z_nd_arr(i,j+1,k+1)
480 + z_nd_arr(i,j,k+2) + z_nd_arr(i,j+1,k+2) );
481 dzInv = 1.0 / (z_xf_hi - z_xf_lo);
483 Real rho_on_u_face = 0.5 * ( cell_data(i,j,k,
nr) + cell_data(i-1,j,k,
nr) );
484 Real U_hi = dptr_u_plane(k+1) / dptr_r_plane(k+1);
485 Real U_lo = dptr_u_plane(k-1) / dptr_r_plane(k-1);
486 Real wbar_xf = 0.5 * (dptr_wbar_sub[k] + dptr_wbar_sub[k+1]);
487 xmom_src_arr(i, j, k) -= rho_on_u_face * wbar_xf * (U_hi - U_lo) * dzInv;
489 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
491 Real dzInv = 0.5*dxInv[2];
493 Real z_yf_lo = 0.25 * ( z_nd_arr(i,j,k ) + z_nd_arr(i+1,j,k )
494 + z_nd_arr(i,j,k-1) + z_nd_arr(i+1,j,k-1) );
495 Real z_yf_hi = 0.25 * ( z_nd_arr(i,j,k+1) + z_nd_arr(i+1,j,k+1)
496 + z_nd_arr(i,j,k+2) + z_nd_arr(i+1,j,k+2) );
497 dzInv = 1.0 / (z_yf_hi - z_yf_lo);
499 Real rho_on_v_face = 0.5 * ( cell_data(i,j,k,
nr) + cell_data(i,j-1,k,
nr) );
500 Real V_hi = dptr_v_plane(k+1) / dptr_r_plane(k+1);
501 Real V_lo = dptr_v_plane(k-1) / dptr_r_plane(k-1);
502 Real wbar_yf = 0.5 * (dptr_wbar_sub[k] + dptr_wbar_sub[k+1]);
503 ymom_src_arr(i, j, k) -= rho_on_v_face * wbar_yf * (V_hi - V_lo) * dzInv;
506 ParallelFor(tbx, tby,
507 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
509 Real dzInv = 0.5*dxInv[2];
511 Real z_xf_lo = 0.25 * ( z_nd_arr(i,j,k ) + z_nd_arr(i,j+1,k )
512 + z_nd_arr(i,j,k-1) + z_nd_arr(i,j+1,k-1) );
513 Real z_xf_hi = 0.25 * ( z_nd_arr(i,j,k+1) + z_nd_arr(i,j+1,k+1)
514 + z_nd_arr(i,j,k+2) + z_nd_arr(i,j+1,k+2) );
515 dzInv = 1.0 / (z_xf_hi - z_xf_lo);
517 Real U_hi = dptr_u_plane(k+1) / dptr_r_plane(k+1);
518 Real U_lo = dptr_u_plane(k-1) / dptr_r_plane(k-1);
519 Real wbar_xf = 0.5 * (dptr_wbar_sub[k] + dptr_wbar_sub[k+1]);
520 xmom_src_arr(i, j, k) -= wbar_xf * (U_hi - U_lo) * dzInv;
522 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
524 Real dzInv = 0.5*dxInv[2];
526 Real z_yf_lo = 0.25 * ( z_nd_arr(i,j,k ) + z_nd_arr(i+1,j,k )
527 + z_nd_arr(i,j,k-1) + z_nd_arr(i+1,j,k-1) );
528 Real z_yf_hi = 0.25 * ( z_nd_arr(i,j,k+1) + z_nd_arr(i+1,j,k+1)
529 + z_nd_arr(i,j,k+2) + z_nd_arr(i+1,j,k+2) );
530 dzInv = 1.0 / (z_yf_hi - z_yf_lo);
532 Real V_hi = dptr_v_plane(k+1) / dptr_r_plane(k+1);
533 Real V_lo = dptr_v_plane(k-1) / dptr_r_plane(k-1);
534 Real wbar_yf = 0.5 * (dptr_wbar_sub[k] + dptr_wbar_sub[k+1]);
535 ymom_src_arr(i, j, k) -= wbar_yf * (V_hi - V_lo) * dzInv;
554 for (
int nt = 1; nt < n_sounding_times; nt++) {
557 if (itime_n == n_sounding_times-1) {
560 itime_np1 = itime_n+1;
563 coeff_n =
Real(1.0) - coeff_np1;
568 const Real* u_inp_sound_n = input_sounding_data.
U_inp_sound_d[itime_n].dataPtr();
569 const Real* u_inp_sound_np1 = input_sounding_data.
U_inp_sound_d[itime_np1].dataPtr();
570 const Real* v_inp_sound_n = input_sounding_data.
V_inp_sound_d[itime_n].dataPtr();
571 const Real* v_inp_sound_np1 = input_sounding_data.
V_inp_sound_d[itime_np1].dataPtr();
572 ParallelFor(tbx, tby,
573 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
575 Real nudge_u = (coeff_n*u_inp_sound_n[k] + coeff_np1*u_inp_sound_np1[k]) - (dptr_u_plane(k)/dptr_r_plane(k));
577 xmom_src_arr(i, j, k) += cell_data(i, j, k,
nr) * nudge_u;
579 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
581 Real nudge_v = (coeff_n*v_inp_sound_n[k] + coeff_np1*v_inp_sound_np1[k]) - (dptr_v_plane(k)/dptr_r_plane(k));
583 ymom_src_arr(i, j, k) += cell_data(i, j, k,
nr) * nudge_v;
592 const Array4<const Real>& mf_ux = mapfac[MapFac::ux]->const_array(mfi);
593 const Array4<const Real>& mf_uy = mapfac[MapFac::uy]->const_array(mfi);
594 const Array4<const Real>& mf_vx = mapfac[MapFac::vx]->const_array(mfi);
595 const Array4<const Real>& mf_vy = mapfac[MapFac::vy]->const_array(mfi);
597 u, cell_data, xmom_src_arr, mf_ux, mf_uy);
599 v, cell_data, ymom_src_arr, mf_vx, mf_vy);
610 z_cc_arr, xmom_src_arr, ymom_src_arr,
611 rho_u, rho_v, d_sponge_ptrs_at_lev);
616 xmom_src_arr, ymom_src_arr, zmom_src_arr, rho_u, rho_v, rho_w,
617 r0, z_nd_arr, z_cc_arr);
622 const Array4<const Real>& rho_u_forecast_state = (*forecast_state_at_lev)[
IntVars::xmom].array(mfi);
623 const Array4<const Real>& rho_v_forecast_state = (*forecast_state_at_lev)[
IntVars::ymom].array(mfi);
624 const Array4<const Real>& rho_w_forecast_state = (*forecast_state_at_lev)[
IntVars::zmom].array(mfi);
625 const Array4<const Real>& cons_forecast_state = (*forecast_state_at_lev)[
IntVars::cons].array(mfi);
627 xmom_src_arr, ymom_src_arr, zmom_src_arr,
629 rho_u_forecast_state, rho_v_forecast_state, rho_w_forecast_state,
630 cons_forecast_state);
638 ((is_slow_step && !use_canopy_fast) || (!is_slow_step && use_canopy_fast))) {
639 ParallelFor(tbx, tby, tbz,
640 [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
642 const Real ux = u(i, j, k);
643 const Real uy = 0.25 * ( v(i, j , k ) + v(i-1, j , k )
644 + v(i, j+1, k ) + v(i-1, j+1, k ) );
645 const Real uz = 0.25 * ( w(i, j , k ) + w(i-1, j , k )
646 + w(i, j , k+1) + w(i-1, j , k+1) );
647 const Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
648 const Real f_drag = 0.5 * (f_drag_arr(i, j, k) + f_drag_arr(i-1, j, k));
649 xmom_src_arr(i, j, k) -= f_drag * ux * windspeed;
651 [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
653 const Real ux = 0.25 * ( u(i , j , k ) + u(i , j-1, k )
654 + u(i+1, j , k ) + u(i+1, j-1, k ) );
655 const Real uy = v(i, j, k);
656 const Real uz = 0.25 * ( w(i , j , k ) + w(i , j-1, k )
657 + w(i , j , k+1) + w(i , j-1, k+1) );
658 const amrex::Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
659 const Real f_drag = 0.5 * (f_drag_arr(i, j, k) + f_drag_arr(i, j-1, k));
660 ymom_src_arr(i, j, k) -= f_drag * uy * windspeed;
662 [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
664 const amrex::Real ux = 0.25 * ( u(i , j , k ) + u(i+1, j , k )
665 + u(i , j , k-1) + u(i+1, j , k-1) );
666 const amrex::Real uy = 0.25 * ( v(i , j , k ) + v(i , j+1, k )
667 + v(i , j , k-1) + v(i , j+1, k-1) );
669 const amrex::Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
670 const Real f_drag = 0.5 * (f_drag_arr(i, j, k) + f_drag_arr(i, j, k-1));
671 zmom_src_arr(i, j, k) -= f_drag * uz * windspeed;
677 if (solverChoice.
terrain_type == TerrainType::ImmersedForcing &&
678 ((is_slow_step && !use_ImmersedForcing_fast) || (!is_slow_step && use_ImmersedForcing_fast))) {
680 const Real* dx_arr = geom.CellSize();
681 const Real dx_x = dx_arr[0];
682 const Real dx_y = dx_arr[1];
683 const Real dx_z = dx_arr[2];
686 const Real drag_coefficient = alpha_m / std::pow(dx_x*dx_y*dx_z, 1./3.);
688 const Real U_s = 1.0;
699 ParallelFor(tbx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
701 const Real ux = u(i, j, k);
702 const Real uy = 0.25 * ( v(i, j , k ) + v(i-1, j , k )
703 + v(i, j+1, k ) + v(i-1, j+1, k ) );
704 const Real uz = 0.25 * ( w(i, j , k ) + w(i-1, j , k )
705 + w(i, j , k+1) + w(i-1, j , k+1) );
706 const Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
707 const Real t_blank = 0.5 * (t_blank_arr(i, j, k) + t_blank_arr(i-1, j, k));
708 const Real t_blank_above = 0.5 * (t_blank_arr(i, j, k+1) + t_blank_arr(i-1, j, k+1));
709 const Real CdM = std::min(drag_coefficient / (windspeed + tiny), 1000.0);
712 if ((t_blank > 0 && (t_blank_above == 0.0)) && l_use_most) {
714 const Real ux2r = u(i, j, k+1) ;
715 const Real uy2r = 0.25 * ( v(i, j , k+1) + v(i-1, j , k+1)
716 + v(i, j+1, k+1) + v(i-1, j+1, k+1) ) ;
717 const Real h_windspeed2r = std::sqrt(ux2r * ux2r + uy2r * uy2r);
721 const Real rho_xface_below = 0.5 * ( cell_data(i,j,k-1,
Rho_comp) + cell_data(i-1,j,k-1,
Rho_comp) );
723 const Real theta_surf = theta_xface_below;
727 Real ustar = h_windspeed2r * kappa / (std::log(1.5 * dx_z / z0) - psi_m);
728 Real tflux = (tflux_in != 1e-8) ? tflux_in : -(theta_xface - theta_surf) * ustar * kappa / (std::log(1.5 * dx_z / z0) - psi_h);
729 Real Olen = (Olen_in != 1e-8) ? Olen_in : -ustar * ustar * ustar * theta_xface / (kappa * ggg * tflux + tiny);
730 Real zeta = 1.5 * dx_z / Olen;
735 ustar = h_windspeed2r * kappa / (std::log(1.5 * dx_z / z0) - psi_m);
738 if (!(ustar > 0.0 && !std::isnan(ustar))) { ustar = 0.0; }
739 if (!(ustar < 2.0 && !std::isnan(ustar))) { ustar = 2.0; }
740 if (psi_m > std::log(0.5 * dx_z / z0)) { psi_m = std::log(0.5 * dx_z / z0); }
743 const Real uTarget = ustar / kappa * (std::log(0.5 * dx_z / z0) - psi_m);
744 Real uxTarget = uTarget * ux2r / (tiny + h_windspeed2r);
745 const Real bc_forcing_x = -(uxTarget - ux);
746 xmom_src_arr(i, j, k) -= (1-t_blank) * rho_xface * CdM * U_s * bc_forcing_x;
748 xmom_src_arr(i, j, k) -= t_blank * rho_xface * CdM * ux * windspeed;
751 ParallelFor(tby, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
753 const Real ux = 0.25 * ( u(i , j , k ) + u(i , j-1, k )
754 + u(i+1, j , k ) + u(i+1, j-1, k ) );
755 const Real uy = v(i, j, k);
756 const Real uz = 0.25 * ( w(i , j , k ) + w(i , j-1, k )
757 + w(i , j , k+1) + w(i , j-1, k+1) );
758 const Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
759 const Real t_blank = 0.5 * (t_blank_arr(i, j, k) + t_blank_arr(i, j-1, k));
760 const Real t_blank_above = 0.5 * (t_blank_arr(i, j, k+1) + t_blank_arr(i, j-1, k+1));
761 const Real CdM = std::min(drag_coefficient / (windspeed + tiny), 1000.0);
764 if ((t_blank > 0 && (t_blank_above == 0.0)) && l_use_most) {
766 const Real ux2r = 0.25 * ( u(i , j , k+1) + u(i , j-1, k+1)
767 + u(i+1, j , k+1) + u(i+1, j-1, k+1) );
768 const Real uy2r = v(i, j, k+1) ;
769 const Real h_windspeed2r = std::sqrt(ux2r * ux2r + uy2r * uy2r);
773 const Real rho_yface_below = 0.5 * ( cell_data(i,j,k-1,
Rho_comp) + cell_data(i,j-1,k-1,
Rho_comp) );
775 const Real theta_surf = theta_yface_below;
779 Real ustar = h_windspeed2r * kappa / (std::log(1.5 * dx_z / z0) - psi_m);
780 Real tflux = (tflux_in != 1e-8) ? tflux_in : -(theta_yface - theta_surf) * ustar * kappa / (std::log(1.5 * dx_z / z0) - psi_h);
781 Real Olen = (Olen_in != 1e-8) ? Olen_in : -ustar * ustar * ustar * theta_yface / (kappa * ggg * tflux + tiny);
782 Real zeta = 1.5 * dx_z / Olen;
787 ustar = h_windspeed2r * kappa / (std::log(1.5 * dx_z / z0) - psi_m);
790 if (!(ustar > 0.0 && !std::isnan(ustar))) { ustar = 0.0; }
791 if (!(ustar < 2.0 && !std::isnan(ustar))) { ustar = 2.0; }
792 if (psi_m > std::log(0.5 * dx_z / z0)) { psi_m = std::log(0.5 * dx_z / z0); }
795 const Real uTarget = ustar / kappa * (std::log(0.5 * dx_z / z0) - psi_m);
796 Real uyTarget = uTarget * uy2r / (tiny + h_windspeed2r);
797 const Real bc_forcing_y = -(uyTarget - uy);
798 ymom_src_arr(i, j, k) -= (1 - t_blank) * rho_yface * CdM * U_s * bc_forcing_y;
800 ymom_src_arr(i, j, k) -= t_blank * rho_yface * CdM * uy * windspeed;
803 ParallelFor(tbz, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
805 const Real ux = 0.25 * ( u(i , j , k ) + u(i+1, j , k )
806 + u(i , j , k-1) + u(i+1, j , k-1) );
807 const Real uy = 0.25 * ( v(i , j , k ) + v(i , j+1, k )
808 + v(i , j , k-1) + v(i , j+1, k-1) );
809 const Real uz = w(i, j, k);
810 const Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
811 const Real t_blank = 0.5 * (t_blank_arr(i, j, k) + t_blank_arr(i, j, k-1));
812 const Real CdM = std::min(drag_coefficient / (windspeed + tiny), 1000.0);
814 zmom_src_arr(i, j, k) -= t_blank * rho_zface * CdM * uz * windspeed;
821 if ((solverChoice.
buildings_type == BuildingsType::ImmersedForcing ) &&
822 ((is_slow_step && !use_ImmersedForcing_fast) || (!is_slow_step && use_ImmersedForcing_fast)))
825 const Real* dx_arr = geom.CellSize();
826 const Real dx_x = dx_arr[0];
827 const Real dx_y = dx_arr[1];
831 const Real min_t_blank = 0.005;
833 ParallelFor(tbx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
835 const Real ux = u(i, j, k);
836 const Real uy = 0.25 * ( v(i, j , k ) + v(i-1, j , k )
837 + v(i, j+1, k ) + v(i-1, j+1, k ) );
838 const Real uz = 0.25 * ( w(i, j , k ) + w(i-1, j , k )
839 + w(i, j , k+1) + w(i-1, j , k+1) );
840 const Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
842 Real t_blank = 0.5 * (t_blank_arr(i, j, k) + t_blank_arr(i-1, j, k));
843 if (t_blank < min_t_blank) { t_blank = 0.0; }
844 const Real dx_z = (z_cc_arr) ? (z_cc_arr(i,j,k) - z_cc_arr(i,j,k-1)) : dx_arr[2];
845 const Real drag_coefficient = alpha_m / std::pow(dx_x*dx_y*dx_z, 1./3.);
846 const Real CdM = std::min(drag_coefficient / (windspeed + tiny), 1000.0);
848 xmom_src_arr(i, j, k) -= t_blank * rho_xface * CdM * ux * windspeed;
850 ParallelFor(tby, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
852 const Real ux = 0.25 * ( u(i , j , k ) + u(i , j-1, k )
853 + u(i+1, j , k ) + u(i+1, j-1, k ) );
854 const Real uy = v(i, j, k);
855 const Real uz = 0.25 * ( w(i , j , k ) + w(i , j-1, k )
856 + w(i , j , k+1) + w(i , j-1, k+1) );
857 const Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
859 Real t_blank = 0.5 * (t_blank_arr(i, j, k) + t_blank_arr(i, j-1, k));
860 if (t_blank < min_t_blank) { t_blank = 0.0; }
861 const Real dx_z = (z_cc_arr) ? (z_cc_arr(i,j,k) - z_cc_arr(i,j,k-1)) : dx_arr[2];
862 const Real drag_coefficient = alpha_m / std::pow(dx_x*dx_y*dx_z, 1./3.);
863 const Real CdM = std::min(drag_coefficient / (windspeed + tiny), 1000.0);
865 ymom_src_arr(i, j, k) -= t_blank * rho_yface * CdM * uy * windspeed;
867 ParallelFor(tbz, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
869 const Real ux = 0.25 * ( u(i , j , k ) + u(i+1, j , k )
870 + u(i , j , k-1) + u(i+1, j , k-1) );
871 const Real uy = 0.25 * ( v(i , j , k ) + v(i , j+1, k )
872 + v(i , j , k-1) + v(i , j+1, k-1) );
873 const Real uz = w(i, j, k);
874 const Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
876 Real t_blank = 0.5 * (t_blank_arr(i, j, k) + t_blank_arr(i, j, k-1));
877 if (t_blank < min_t_blank) { t_blank = 0.0; }
878 const Real dx_z = (z_nd_arr) ? (z_nd_arr(i,j,k) - z_nd_arr(i,j,k-1)) : dx_arr[2];
879 const Real drag_coefficient = alpha_m / std::pow(dx_x*dx_y*dx_z, 1./3.);
880 const Real CdM = std::min(drag_coefficient / (windspeed + tiny), 1000.0);
882 zmom_src_arr(i, j, k) -= t_blank * rho_zface * CdM * uz * windspeed;
889 if (is_slow_step && (enforce_massflux_x || enforce_massflux_y)) {
892 ParallelFor(tbx, tby,
893 [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept {
894 xmom_src_arr(i, j, k) += tau_inv * (rhoUA_target - rhoUA);
896 [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept {
897 ymom_src_arr(i, j, k) += tau_inv * (rhoVA_target - rhoVA);
void ApplyBndryForcing_Forecast(const SolverChoice &solverChoice, const Geometry geom, const Box &tbx, const Box &tby, const Box &tbz, const Array4< const Real > &z_phys_nd, const Array4< Real > &rho_u_rhs, const Array4< Real > &rho_v_rhs, const Array4< Real > &rho_w_rhs, const Array4< const Real > &rho_u, const Array4< const Real > &rho_v, const Array4< const Real > &rho_w, const Array4< const Real > &rho_u_initial_state, const Array4< const Real > &rho_v_initial_state, const Array4< const Real > &rho_w_initial_state, const Array4< const Real > &cons_initial_state)
Definition: ERF_ApplyBndryForcing_Forecast.cpp:8
void ApplySpongeZoneBCsForMom(const SpongeChoice &spongeChoice, const Geometry geom, const Box &tbx, const Box &tby, const Box &tbz, const Array4< Real > &rho_u_rhs, const Array4< Real > &rho_v_rhs, const Array4< Real > &rho_w_rhs, const Array4< const Real > &rho_u, const Array4< const Real > &rho_v, const Array4< const Real > &rho_w, const Array4< const Real > &r0, const Array4< const Real > &z_phys_nd, const Array4< const Real > &z_phys_cc)
Definition: ERF_ApplySpongeZoneBCs.cpp:118
void ApplySpongeZoneBCsForMom_ReadFromFile(const SpongeChoice &spongeChoice, const Geometry geom, const Box &tbx, const Box &tby, const Array4< const Real > &cell_data, const Array4< const Real > &z_phys_cc, const Array4< Real > &rho_u_rhs, const Array4< Real > &rho_v_rhs, const Array4< const Real > &rho_u, const Array4< const Real > &rho_v, const Vector< Real * > d_sponge_ptrs_at_lev)
Definition: ERF_ApplySpongeZoneBCs_ReadFromFile.cpp:8
constexpr amrex::Real KAPPA
Definition: ERF_Constants.H:20
constexpr amrex::Real PI
Definition: ERF_Constants.H:6
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:21
@ ubar
Definition: ERF_DataStruct.H:96
@ wbar
Definition: ERF_DataStruct.H:96
@ vbar
Definition: ERF_DataStruct.H:96
DirectionSelector< 2 > ZDir
Definition: ERF_DirectionSelector.H:38
#define Rho_comp
Definition: ERF_IndexDefines.H:36
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
void NumericalDiffusion_Ymom(const Box &bx, const Real dt, const Real num_diff_coeff, const Array4< const Real > &prim_data, const Array4< const Real > &cell_data, const Array4< Real > &rhs, const Array4< const Real > &mfx_arr, const Array4< const Real > &mfy_arr)
Definition: ERF_NumericalDiffusion.cpp:151
void NumericalDiffusion_Xmom(const Box &bx, const Real dt, const Real num_diff_coeff, const Array4< const Real > &prim_data, const Array4< const Real > &cell_data, const Array4< Real > &rhs, const Array4< const Real > &mfx_arr, const Array4< const Real > &mfy_arr)
Definition: ERF_NumericalDiffusion.cpp:85
AMREX_FORCE_INLINE IntVect offset(const int face_dir, const int normal)
Definition: ERF_ReadBndryPlanes.cpp:28
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_PlaneAverage.H:14
@ r0_comp
Definition: ERF_IndexDefines.H:63
@ ymom
Definition: ERF_IndexDefines.H:160
@ cons
Definition: ERF_IndexDefines.H:158
@ zmom
Definition: ERF_IndexDefines.H:161
@ xmom
Definition: ERF_IndexDefines.H:159
@ nr
Definition: ERF_Morrison.H:45
@ xvel
Definition: ERF_IndexDefines.H:141
@ cons
Definition: ERF_IndexDefines.H:140
@ yvel
Definition: ERF_IndexDefines.H:142
real(c_double), parameter epsilon
Definition: ERF_module_model_constants.F90:12
bool rayleigh_damp_V
Definition: ERF_DampingStruct.H:85
amrex::Real rayleigh_dampcoef
Definition: ERF_DampingStruct.H:88
bool rayleigh_damp_W
Definition: ERF_DampingStruct.H:86
RayleighDampingType rayleigh_damping_type
Definition: ERF_DampingStruct.H:101
bool rayleigh_damp_U
Definition: ERF_DampingStruct.H:84
amrex::Real coriolis_factor
Definition: ERF_DataStruct.H:1066
static MeshType mesh_type
Definition: ERF_DataStruct.H:983
amrex::Real if_surf_temp_flux
Definition: ERF_DataStruct.H:1046
bool if_use_most
Definition: ERF_DataStruct.H:1050
DampingChoice dampingChoice
Definition: ERF_DataStruct.H:993
amrex::Real const_massflux_v
Definition: ERF_DataStruct.H:1136
amrex::Real if_z0
Definition: ERF_DataStruct.H:1045
amrex::Real cosphi
Definition: ERF_DataStruct.H:1067
amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > abl_geo_forcing
Definition: ERF_DataStruct.H:1109
bool hindcast_lateral_forcing
Definition: ERF_DataStruct.H:1145
int massflux_klo
Definition: ERF_DataStruct.H:1140
bool custom_w_subsidence
Definition: ERF_DataStruct.H:1073
bool nudging_from_input_sounding
Definition: ERF_DataStruct.H:1079
bool immersed_forcing_substep
Definition: ERF_DataStruct.H:1038
amrex::Real sinphi
Definition: ERF_DataStruct.H:1068
bool have_geo_wind_profile
Definition: ERF_DataStruct.H:1111
amrex::Real const_massflux_u
Definition: ERF_DataStruct.H:1135
amrex::Real if_Olen_in
Definition: ERF_DataStruct.H:1049
bool use_coriolis
Definition: ERF_DataStruct.H:1032
amrex::Real num_diff_coeff
Definition: ERF_DataStruct.H:1095
bool variable_coriolis
Definition: ERF_DataStruct.H:1114
amrex::Real if_Cd_momentum
Definition: ERF_DataStruct.H:1043
bool custom_forcing_prim_vars
Definition: ERF_DataStruct.H:1075
static BuildingsType buildings_type
Definition: ERF_DataStruct.H:974
static TerrainType terrain_type
Definition: ERF_DataStruct.H:971
SpongeChoice spongeChoice
Definition: ERF_DataStruct.H:994
static InitType init_type
Definition: ERF_DataStruct.H:965
bool has_lat_lon
Definition: ERF_DataStruct.H:1113
bool do_forest_drag
Definition: ERF_DataStruct.H:1132
amrex::Real const_massflux_tau
Definition: ERF_DataStruct.H:1137
int massflux_khi
Definition: ERF_DataStruct.H:1141
bool forest_substep
Definition: ERF_DataStruct.H:1039
int ave_plane
Definition: ERF_DataStruct.H:1116
std::string sponge_type
Definition: ERF_SpongeStruct.H:58
Definition: ERF_MOSTStress.H:41
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_psi_m(amrex::Real zeta) const
Definition: ERF_MOSTStress.H:91
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_psi_h(amrex::Real zeta) const
Definition: ERF_MOSTStress.H:105