Function for computing the slow RHS for the evolution equations for the density, potential temperature and momentum.
114 BL_PROFILE_REGION(
"erf_make_mom_sources()");
116 Real time =
static_cast<Real>(time_d);
118 Box domain(geom.Domain());
119 const GpuArray<Real, AMREX_SPACEDIM>
dxInv = geom.InvCellSizeArray();
122 xmom_src.setVal(0.0);
123 ymom_src.setVal(0.0);
124 zmom_src.setVal(0.0);
153 if (solverChoice.
terrain_type == TerrainType::ImmersedForcing) {
155 amrex::Error(
" Currently forest canopy cannot be used with immersed forcing");
165 auto cosphi = solverChoice.
cosphi;
166 auto sinphi = solverChoice.
sinphi;
197 Real rhoUA_target{0};
198 Real rhoVA_target{0};
205 Table1D<Real> dptr_r_plane, dptr_u_plane, dptr_v_plane;
206 TableData<Real, 1> r_plane_tab, u_plane_tab, v_plane_tab;
209 enforce_massflux_x || enforce_massflux_y))
215 const int u_offset = 1;
216 const int v_offset = 1;
225 r_ave.compute_averages(
ZDir(), r_ave.field());
227 int ncell = r_ave.ncell_line();
228 Gpu::HostVector< Real> r_plane_h(ncell);
229 Gpu::DeviceVector< Real> r_plane_d(ncell);
231 r_ave.line_average(
Rho_comp, r_plane_h);
233 Gpu::copyAsync(Gpu::hostToDevice, r_plane_h.begin(), r_plane_h.end(), r_plane_d.begin());
235 Real* dptr_r = r_plane_d.data();
237 Box tdomain = domain; tdomain.grow(2,ng_c[2]);
238 r_plane_tab.resize({tdomain.smallEnd(2)}, {tdomain.bigEnd(2)});
240 dptr_r_plane = r_plane_tab.table();
241 ParallelFor(ncell, [=] AMREX_GPU_DEVICE (
int k) noexcept
243 dptr_r_plane(k-
offset) = dptr_r[k];
247 IntVect ng_u = S_data[
IntVars::xmom].nGrowVect(); ng_u[2] = u_offset;
250 IntVect ng_v = S_data[
IntVars::ymom].nGrowVect(); ng_v[2] = v_offset;
253 u_ave.compute_averages(
ZDir(), u_ave.field());
254 v_ave.compute_averages(
ZDir(), v_ave.field());
256 int u_ncell = u_ave.ncell_line();
257 int v_ncell = v_ave.ncell_line();
258 Gpu::HostVector< Real> u_plane_h(u_ncell), v_plane_h(v_ncell);
259 Gpu::DeviceVector< Real> u_plane_d(u_ncell), v_plane_d(v_ncell);
261 u_ave.line_average(0, u_plane_h);
262 v_ave.line_average(0, v_plane_h);
264 Gpu::copyAsync(Gpu::hostToDevice, u_plane_h.begin(), u_plane_h.end(), u_plane_d.begin());
265 Gpu::copyAsync(Gpu::hostToDevice, v_plane_h.begin(), v_plane_h.end(), v_plane_d.begin());
267 Real* dptr_u = u_plane_d.data();
268 Real* dptr_v = v_plane_d.data();
270 Box udomain = domain; udomain.grow(2,ng_u[2]);
271 Box vdomain = domain; vdomain.grow(2,ng_v[2]);
272 u_plane_tab.resize({udomain.smallEnd(2)}, {udomain.bigEnd(2)});
273 v_plane_tab.resize({vdomain.smallEnd(2)}, {vdomain.bigEnd(2)});
275 dptr_u_plane = u_plane_tab.table();
276 ParallelFor(u_ncell, [=] AMREX_GPU_DEVICE (
int k) noexcept
278 dptr_u_plane(k-u_offset) = dptr_u[k];
281 dptr_v_plane = v_plane_tab.table();
282 ParallelFor(v_ncell, [=] AMREX_GPU_DEVICE (
int k) noexcept
284 dptr_v_plane(k-v_offset) = dptr_v[k];
288 if (enforce_massflux_x || enforce_massflux_y) {
289 Real Lx = geom.ProbHi(0) - geom.ProbLo(0);
290 Real Ly = geom.ProbHi(1) - geom.ProbLo(1);
292 if (solverChoice.
mesh_type == MeshType::ConstantDz) {
294 rhoUA = std::accumulate(u_plane_h.begin() + u_offset + massflux_klo,
295 u_plane_h.begin() + u_offset + massflux_khi+1,
zero);
296 rhoVA = std::accumulate(v_plane_h.begin() + v_offset + massflux_klo,
297 v_plane_h.begin() + v_offset + massflux_khi+1,
zero);
298 rhoUA_target = std::accumulate(r_plane_h.begin() +
offset + massflux_klo,
299 r_plane_h.begin() +
offset + massflux_khi+1,
zero);
300 rhoVA_target = rhoUA_target;
302 rhoUA *= geom.CellSize(2) * Ly;
303 rhoVA *= geom.CellSize(2) * Lx;
304 rhoUA_target *= geom.CellSize(2) * Ly;
305 rhoVA_target *= geom.CellSize(2) * Lx;
307 }
else if (solverChoice.
mesh_type == MeshType::StretchedDz) {
309 for (
int k=massflux_klo; k < massflux_khi; ++k) {
310 rhoUA += u_plane_h[k + u_offset] * stretched_dz_h[k];
311 rhoVA += v_plane_h[k + v_offset] * stretched_dz_h[k];
312 rhoUA_target += r_plane_h[k +
offset] * stretched_dz_h[k];
314 rhoVA_target = rhoUA_target;
323 rhoUA_target *= U_target;
324 rhoVA_target *= V_target;
326 Print() <<
"Integrated mass flux : " << rhoUA <<
" " << rhoVA
327 <<
" (target: " << rhoUA_target <<
" " << rhoVA_target <<
")"
335 for ( MFIter mfi(S_data[
IntVars::cons]); mfi.isValid(); ++mfi)
337 Box tbx = mfi.nodaltilebox(0);
338 Box tby = mfi.nodaltilebox(1);
339 Box tbz = mfi.nodaltilebox(2);
340 if (tbz.bigEnd(2) == domain.bigEnd(2)+1) tbz.growHi(2,-1);
342 const Array4<const Real>& cell_data = S_data[
IntVars::cons].array(mfi);
343 const Array4<const Real>& rho_u = S_data[
IntVars::xmom].array(mfi);
344 const Array4<const Real>& rho_v = S_data[
IntVars::ymom].array(mfi);
345 const Array4<const Real>& rho_w = S_data[
IntVars::zmom].array(mfi);
347 const Array4<const Real>& u =
xvel.array(mfi);
348 const Array4<const Real>& v =
yvel.array(mfi);
349 const Array4<const Real>&
w = wvel.array(mfi);
351 const Array4< Real>& xmom_src_arr = xmom_src.array(mfi);
352 const Array4< Real>& ymom_src_arr = ymom_src.array(mfi);
353 const Array4< Real>& zmom_src_arr = zmom_src.array(mfi);
355 const Array4<const Real>&
r0 = r_hse.const_array(mfi);
357 const Array4<const Real>& f_drag_arr = (forest_drag) ? forest_drag->const_array(mfi) :
358 Array4<const Real>{};
359 const Array4<const Real>& t_blank_arr = (terrain_blank) ? terrain_blank->const_array(mfi) :
360 Array4<const Real>{};
362 const Array4<const Real>& cphi_arr = (cosPhi_mf) ? cosPhi_mf->const_array(mfi) :
363 Array4<const Real>{};
364 const Array4<const Real>& sphi_arr = (sinPhi_mf) ? sinPhi_mf->const_array(mfi) :
365 Array4<const Real>{};
367 const Array4<const Real>& z_nd_arr = z_phys_nd->const_array(mfi);
368 const Array4<const Real>& z_cc_arr = z_phys_cc->const_array(mfi);
374 if (use_coriolis && is_slow_step) {
375 if(solverChoice.
init_type == InitType::HindCast) {
376 const Array4<const Real>& latlon_arr = (*forecast_state_at_lev)[4].array(mfi);
378 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
381 Real v_loc =
fourth * (v(i,j+1,k) + v(i,j,k) + v(i-1,j+1,k) + v(i-1,j,k));
382 Real w_loc =
fourth * (
w(i,j,k+1) +
w(i,j,k) +
w(i-1,j,k+1) +
w(i-1,j,k));
383 Real latitude = latlon_arr(i,j,k,0);
384 Real sphi_loc = std::sin(latitude*
PI/
Real(180.0));
385 Real cphi_loc = std::cos(latitude*
PI/
Real(180.0));
386 xmom_src_arr(i, j, k) += coriolis_factor * rho_on_u_face * (v_loc * sphi_loc - w_loc * cphi_loc);
388 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
390 Real u_loc =
fourth * (u(i+1,j,k) + u(i,j,k) + u(i+1,j-1,k) + u(i,j-1,k));
391 Real latitude = latlon_arr(i,j,k,0);
392 Real sphi_loc = std::sin(latitude*
PI/
Real(180.0));
393 ymom_src_arr(i, j, k) += -coriolis_factor * rho_on_v_face * u_loc * sphi_loc;
395 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
397 Real u_loc =
fourth * (u(i+1,j,k) + u(i,j,k) + u(i+1,j,k-1) + u(i,j,k-1));
398 Real latitude = latlon_arr(i,j,k,0);
399 Real cphi_loc = std::cos(latitude*
PI/
Real(180.0));
400 zmom_src_arr(i, j, k) += coriolis_factor * rho_on_w_face * u_loc * cphi_loc;
403 else if (var_coriolis && (sinPhi_mf) && (cosPhi_mf)) {
405 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
408 Real v_loc =
fourth * (v(i,j+1,k) + v(i,j,k) + v(i-1,j+1,k) + v(i-1,j,k));
409 Real w_loc =
fourth * (
w(i,j,k+1) +
w(i,j,k) +
w(i-1,j,k+1) +
w(i-1,j,k));
410 Real sphi_loc =
myhalf * (sphi_arr(i,j,0) + sphi_arr(i-1,j,0));
411 Real cphi_loc =
myhalf * (cphi_arr(i,j,0) + cphi_arr(i-1,j,0));
412 xmom_src_arr(i, j, k) += coriolis_factor * rho_on_u_face * (v_loc * sphi_loc - w_loc * cphi_loc);
414 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
416 Real u_loc =
fourth * (u(i+1,j,k) + u(i,j,k) + u(i+1,j-1,k) + u(i,j-1,k));
417 Real sphi_loc =
myhalf * (sphi_arr(i,j,0) + sphi_arr(i,j-1,0));
418 ymom_src_arr(i, j, k) += -coriolis_factor * rho_on_v_face * u_loc * sphi_loc;
420 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
422 Real u_loc =
fourth * (u(i+1,j,k) + u(i,j,k) + u(i+1,j,k-1) + u(i,j,k-1));
423 zmom_src_arr(i, j, k) += coriolis_factor * rho_on_w_face * u_loc * cphi_arr(i,j,0);
427 Array4<const Real> u_volfrac = (ebfact.
get_u_const_factory())->getVolFrac().const_array(mfi);
428 Array4<const Real> v_volfrac = (ebfact.
get_v_const_factory())->getVolFrac().const_array(mfi);
429 Array4<const Real> w_volfrac = (ebfact.
get_w_const_factory())->getVolFrac().const_array(mfi);
430 ParallelFor(tbx, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
433 Real v_vol = v_volfrac(i,j+1,k) + v_volfrac(i,j,k) + v_volfrac(i-1,j+1,k) + v_volfrac(i-1,j,k);
434 Real w_vol = w_volfrac(i,j,k+1) + w_volfrac(i,j,k) + w_volfrac(i-1,j,k+1) + w_volfrac(i-1,j,k);
437 v_loc = ( v_volfrac(i ,j+1,k) * v(i ,j+1,k) + v_volfrac(i ,j,k) * v(i ,j,k)
438 + v_volfrac(i-1,j+1,k) * v(i-1,j+1,k) + v_volfrac(i-1,j,k) * v(i-1,j,k)) / v_vol;
441 w_loc = ( w_volfrac(i ,j,k+1) *
w(i ,j,k+1) + w_volfrac(i ,j,k) *
w(i ,j,k)
442 + w_volfrac(i-1,j,k+1) *
w(i-1,j,k+1) + w_volfrac(i-1,j,k) *
w(i-1,j,k)) / w_vol;
444 xmom_src_arr(i, j, k) += coriolis_factor * rho_on_u_face * (v_loc * sinphi - w_loc * cosphi);
446 ParallelFor(tby, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
448 Real u_vol = u_volfrac(i+1,j,k) + u_volfrac(i,j,k) + u_volfrac(i+1,j-1,k) + u_volfrac(i,j-1,k);
451 u_loc = ( u_volfrac(i+1,j ,k) * u(i+1,j ,k) + u_volfrac(i,j ,k) * u(i,j ,k)
452 + u_volfrac(i+1,j-1,k) * u(i+1,j-1,k) + u_volfrac(i,j-1,k) * u(i,j-1,k)) / u_vol;
454 ymom_src_arr(i, j, k) += -coriolis_factor * rho_on_v_face * u_loc * sinphi;
456 ParallelFor(tbz, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
458 Real u_vol = u_volfrac(i+1,j,k) + u_volfrac(i,j,k) + u_volfrac(i+1,j,k-1) + u_volfrac(i,j,k-1);
461 u_loc = ( u_volfrac(i+1,j,k ) * u(i+1,j,k ) + u_volfrac(i,j,k) * u(i,j,k )
462 + u_volfrac(i+1,j,k-1) * u(i+1,j,k-1) + u_volfrac(i,j,k-1) * u(i,j,k-1)) / u_vol;
464 zmom_src_arr(i, j, k) += coriolis_factor * rho_on_w_face * u_loc * cosphi;
468 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
470 Real v_loc =
fourth * (v(i,j+1,k) + v(i,j,k) + v(i-1,j+1,k) + v(i-1,j,k));
471 Real w_loc =
fourth * (
w(i,j,k+1) +
w(i,j,k) +
w(i-1,j,k+1) +
w(i-1,j,k));
473 xmom_src_arr(i, j, k) += rho_on_u_face * ( coriolis_factor * (v_loc * sinphi - w_loc * cosphi) );
475 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
477 Real u_loc =
fourth * (u(i+1,j,k) + u(i,j,k) + u(i+1,j-1,k) + u(i,j-1,k));
478 ymom_src_arr(i, j, k) += rho_on_v_face * ( -coriolis_factor * u_loc * sinphi );
480 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
481 Real u_loc =
fourth * (u(i+1,j,k) + u(i,j,k) + u(i+1,j,k-1) + u(i,j,k-1));
483 zmom_src_arr(i, j, k) += rho_on_w_face * ( coriolis_factor * u_loc * cosphi );
494 if ( (is_slow_step && !use_Rayleigh_fast_uv) || (!is_slow_step && use_Rayleigh_fast_uv)) {
495 if (rayleigh_damp_U) {
496 ParallelFor(tbx, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
499 Real uu = rho_u(i,j,k) / rho_on_u_face;
500 Real sinesq = d_sinesq_at_lev[k];
501 xmom_src_arr(i, j, k) -= dampcoef*sinesq * (uu -
ubar[k]) * rho_on_u_face;
505 if (rayleigh_damp_V) {
506 ParallelFor(tby, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
509 Real vv = rho_v(i,j,k) / rho_on_v_face;
510 Real sinesq = d_sinesq_at_lev[k];
511 ymom_src_arr(i, j, k) -= dampcoef*sinesq * (vv -
vbar[k]) * rho_on_v_face;
516 if ( (is_slow_step && !use_Rayleigh_fast_w) || (!is_slow_step && use_Rayleigh_fast_w)) {
517 if (rayleigh_damp_W) {
518 ParallelFor(tbz, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
521 Real ww = rho_w(i,j,k) / rho_on_w_face;
522 Real sinesq = d_sinesq_stag_at_lev[k];
523 zmom_src_arr(i, j, k) -= dampcoef*sinesq * (
ww -
wbar[k]) * rho_on_w_face;
533 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
536 xmom_src_arr(i, j, k) += rho_on_u_face * abl_geo_forcing[0];
538 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
541 ymom_src_arr(i, j, k) += rho_on_v_face * abl_geo_forcing[1];
543 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
546 zmom_src_arr(i, j, k) += rho_on_w_face * abl_geo_forcing[2];
553 if (geo_wind_profile && is_slow_step) {
555 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
558 xmom_src_arr(i, j, k) -= coriolis_factor * rho_on_u_face * dptr_v_geos[k] * sinphi;
560 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
563 ymom_src_arr(i, j, k) += coriolis_factor * rho_on_v_face * dptr_u_geos[k] * sinphi;
574 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
578 Real z_xf_lo =
fourth * ( z_nd_arr(i,j,k ) + z_nd_arr(i,j+1,k )
579 + z_nd_arr(i,j,k-1) + z_nd_arr(i,j+1,k-1) );
580 Real z_xf_hi =
fourth * ( z_nd_arr(i,j,k+1) + z_nd_arr(i,j+1,k+1)
581 + z_nd_arr(i,j,k+2) + z_nd_arr(i,j+1,k+2) );
582 dzInv =
one / (z_xf_hi - z_xf_lo);
584 Real rho_on_u_face =
myhalf * ( cell_data(i,j,k,
nr) + cell_data(i-1,j,k,
nr) );
585 Real U_hi = dptr_u_plane(k+1) / dptr_r_plane(k+1);
586 Real U_lo = dptr_u_plane(k-1) / dptr_r_plane(k-1);
587 Real wbar_xf =
myhalf * (dptr_wbar_sub[k] + dptr_wbar_sub[k+1]);
588 xmom_src_arr(i, j, k) -= rho_on_u_face * wbar_xf * (U_hi - U_lo) * dzInv;
590 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
594 Real z_yf_lo =
fourth * ( z_nd_arr(i,j,k ) + z_nd_arr(i+1,j,k )
595 + z_nd_arr(i,j,k-1) + z_nd_arr(i+1,j,k-1) );
596 Real z_yf_hi =
fourth * ( z_nd_arr(i,j,k+1) + z_nd_arr(i+1,j,k+1)
597 + z_nd_arr(i,j,k+2) + z_nd_arr(i+1,j,k+2) );
598 dzInv =
one / (z_yf_hi - z_yf_lo);
600 Real rho_on_v_face =
myhalf * ( cell_data(i,j,k,
nr) + cell_data(i,j-1,k,
nr) );
601 Real V_hi = dptr_v_plane(k+1) / dptr_r_plane(k+1);
602 Real V_lo = dptr_v_plane(k-1) / dptr_r_plane(k-1);
603 Real wbar_yf =
myhalf * (dptr_wbar_sub[k] + dptr_wbar_sub[k+1]);
604 ymom_src_arr(i, j, k) -= rho_on_v_face * wbar_yf * (V_hi - V_lo) * dzInv;
608 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
612 Real z_xf_lo =
fourth * ( z_nd_arr(i,j,k ) + z_nd_arr(i,j+1,k )
613 + z_nd_arr(i,j,k-1) + z_nd_arr(i,j+1,k-1) );
614 Real z_xf_hi =
fourth * ( z_nd_arr(i,j,k+1) + z_nd_arr(i,j+1,k+1)
615 + z_nd_arr(i,j,k+2) + z_nd_arr(i,j+1,k+2) );
616 dzInv =
one / (z_xf_hi - z_xf_lo);
618 Real U_hi = dptr_u_plane(k+1) / dptr_r_plane(k+1);
619 Real U_lo = dptr_u_plane(k-1) / dptr_r_plane(k-1);
620 Real wbar_xf =
myhalf * (dptr_wbar_sub[k] + dptr_wbar_sub[k+1]);
621 xmom_src_arr(i, j, k) -= wbar_xf * (U_hi - U_lo) * dzInv;
623 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
627 Real z_yf_lo =
fourth * ( z_nd_arr(i,j,k ) + z_nd_arr(i+1,j,k )
628 + z_nd_arr(i,j,k-1) + z_nd_arr(i+1,j,k-1) );
629 Real z_yf_hi =
fourth * ( z_nd_arr(i,j,k+1) + z_nd_arr(i+1,j,k+1)
630 + z_nd_arr(i,j,k+2) + z_nd_arr(i+1,j,k+2) );
631 dzInv =
one / (z_yf_hi - z_yf_lo);
633 Real V_hi = dptr_v_plane(k+1) / dptr_r_plane(k+1);
634 Real V_lo = dptr_v_plane(k-1) / dptr_r_plane(k-1);
635 Real wbar_yf =
myhalf * (dptr_wbar_sub[k] + dptr_wbar_sub[k+1]);
636 ymom_src_arr(i, j, k) -= wbar_yf * (V_hi - V_lo) * dzInv;
655 for (
int nt = 1; nt < n_sounding_times; nt++) {
658 if (itime_n == n_sounding_times-1) {
661 itime_np1 = itime_n+1;
664 coeff_n =
one - coeff_np1;
669 const Real* u_inp_sound_n = input_sounding_data.
U_inp_sound_d[itime_n].dataPtr();
670 const Real* u_inp_sound_np1 = input_sounding_data.
U_inp_sound_d[itime_np1].dataPtr();
671 const Real* v_inp_sound_n = input_sounding_data.
V_inp_sound_d[itime_n].dataPtr();
672 const Real* v_inp_sound_np1 = input_sounding_data.
V_inp_sound_d[itime_np1].dataPtr();
674 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
676 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));
678 xmom_src_arr(i, j, k) += cell_data(i, j, k,
nr) * nudge_u;
680 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
682 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));
684 ymom_src_arr(i, j, k) += cell_data(i, j, k,
nr) * nudge_v;
693 const Array4<const Real>& mf_ux = mapfac[MapFac::ux]->const_array(mfi);
694 const Array4<const Real>& mf_uy = mapfac[MapFac::uy]->const_array(mfi);
695 const Array4<const Real>& mf_vx = mapfac[MapFac::vx]->const_array(mfi);
696 const Array4<const Real>& mf_vy = mapfac[MapFac::vy]->const_array(mfi);
698 u, cell_data, xmom_src_arr, mf_ux, mf_uy);
700 v, cell_data, ymom_src_arr, mf_vx, mf_vy);
711 z_cc_arr, xmom_src_arr, ymom_src_arr,
712 rho_u, rho_v, d_sponge_ptrs_at_lev);
717 xmom_src_arr, ymom_src_arr, zmom_src_arr, rho_u, rho_v, rho_w,
718 r0, z_nd_arr, z_cc_arr);
723 const Array4<const Real>& rho_u_forecast_state = (*forecast_state_at_lev)[
IntVars::xmom].array(mfi);
724 const Array4<const Real>& rho_v_forecast_state = (*forecast_state_at_lev)[
IntVars::ymom].array(mfi);
725 const Array4<const Real>& rho_w_forecast_state = (*forecast_state_at_lev)[
IntVars::zmom].array(mfi);
726 const Array4<const Real>& cons_forecast_state = (*forecast_state_at_lev)[
IntVars::cons].array(mfi);
728 xmom_src_arr, ymom_src_arr, zmom_src_arr,
730 rho_u_forecast_state, rho_v_forecast_state, rho_w_forecast_state,
731 cons_forecast_state);
739 ((is_slow_step && !use_canopy_fast) || (!is_slow_step && use_canopy_fast))) {
741 [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
743 const Real ux = u(i, j, k);
744 const Real uy =
fourth * ( v(i, j , k ) + v(i-1, j , k )
745 + v(i, j+1, k ) + v(i-1, j+1, k ) );
746 const Real uz =
fourth * (
w(i, j , k ) +
w(i-1, j , k )
747 +
w(i, j , k+1) +
w(i-1, j , k+1) );
748 const Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
749 const Real f_drag =
myhalf * (f_drag_arr(i, j, k) + f_drag_arr(i-1, j, k));
750 xmom_src_arr(i, j, k) -= f_drag * ux * windspeed;
752 [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
754 const Real ux =
fourth * ( u(i , j , k ) + u(i , j-1, k )
755 + u(i+1, j , k ) + u(i+1, j-1, k ) );
756 const Real uy = v(i, j, k);
757 const Real uz =
fourth * (
w(i , j , k ) +
w(i , j-1, k )
758 +
w(i , j , k+1) +
w(i , j-1, k+1) );
759 const amrex::Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
760 const Real f_drag =
myhalf * (f_drag_arr(i, j, k) + f_drag_arr(i, j-1, k));
761 ymom_src_arr(i, j, k) -= f_drag * uy * windspeed;
763 [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
766 + u(i , j , k-1) + u(i+1, j , k-1) );
768 + v(i , j , k-1) + v(i , j+1, k-1) );
770 const amrex::Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
771 const Real f_drag =
myhalf * (f_drag_arr(i, j, k) + f_drag_arr(i, j, k-1));
772 zmom_src_arr(i, j, k) -= f_drag * uz * windspeed;
778 if (solverChoice.
terrain_type == TerrainType::ImmersedForcing &&
779 ((is_slow_step && !use_ImmersedForcing_fast) || (!is_slow_step && use_ImmersedForcing_fast))) {
781 const Real* dx_arr = geom.CellSize();
782 const Real dx_x = dx_arr[0];
783 const Real dx_y = dx_arr[1];
799 ParallelFor(tbx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
801 const Real ux = u(i, j, k);
802 const Real uy =
fourth * ( v(i, j , k ) + v(i-1, j , k )
803 + v(i, j+1, k ) + v(i-1, j+1, k ) );
804 const Real uz =
fourth * (
w(i, j , k ) +
w(i-1, j , k )
805 +
w(i, j , k+1) +
w(i-1, j , k+1) );
806 const Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
807 const Real t_blank =
myhalf * (t_blank_arr(i, j, k) + t_blank_arr(i-1, j, k));
808 const Real t_blank_above =
myhalf * (t_blank_arr(i, j, k+1) + t_blank_arr(i-1, j, k+1));
810 const Real dx_z = (z_cc_arr) ? (z_cc_arr(i,j,k) - z_cc_arr(i,j,k-1)) : dx_arr[2];
811 const Real drag_coefficient = alpha_m / std::pow(dx_x*dx_y*dx_z,
one/
three);
812 const Real CdM = std::min(drag_coefficient / (windspeed + tiny), drag_coefficient);
816 if ((t_blank > 0 && (t_blank_above ==
zero)) && l_use_most) {
818 const Real ux2r = u(i, j, k+1) ;
819 const Real uy2r =
fourth * ( v(i, j , k+1) + v(i-1, j , k+1)
820 + v(i, j+1, k+1) + v(i-1, j+1, k+1) ) ;
821 const Real h_windspeed2r = std::sqrt(ux2r * ux2r + uy2r * uy2r);
827 const Real theta_surf = theta_xface_below;
831 Real ustar = h_windspeed2r * kappa / (std::log(
Real(1.5) * dx_z /
z0) - psi_m);
832 Real tflux = (tflux_in !=
Real(1e-8)) ? tflux_in : -(theta_xface - theta_surf) * ustar * kappa / (std::log(
Real(1.5) * dx_z /
z0) - psi_h);
833 Real Olen = (Olen_in !=
Real(1e-8)) ? Olen_in : -ustar * ustar * ustar * theta_xface / (kappa * ggg * tflux + tiny);
839 ustar = h_windspeed2r * kappa / (std::log(
Real(1.5) * dx_z /
z0) - psi_m);
842 if (!(ustar >
zero && !std::isnan(ustar))) { ustar =
zero; }
843 if (!(ustar <
two && !std::isnan(ustar))) { ustar =
two; }
844 if (psi_m > std::log(
myhalf * dx_z /
z0)) { psi_m = std::log(
myhalf * dx_z /
z0); }
847 const Real uTarget = ustar / kappa * (std::log(
myhalf * dx_z /
z0) - psi_m);
848 Real uxTarget = uTarget * ux2r / (tiny + h_windspeed2r);
849 const Real bc_forcing_x = -(uxTarget - ux);
850 const Real lambda = (1-t_blank) * CdM * U_s;
851 const Real fac = l_implicit_drag ? lambda / (
one + lambda*dt) : lambda;
852 xmom_src_arr(i, j, k) -= fac * rho_xface * bc_forcing_x;
854 const Real lambda = t_blank * CdM * windspeed;
855 const Real fac = l_implicit_drag ? lambda / (
one + lambda*dt) : lambda;
856 xmom_src_arr(i, j, k) -= fac * rho_xface * ux;
859 ParallelFor(tby, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
861 const Real ux =
fourth * ( u(i , j , k ) + u(i , j-1, k )
862 + u(i+1, j , k ) + u(i+1, j-1, k ) );
863 const Real uy = v(i, j, k);
864 const Real uz =
fourth * (
w(i , j , k ) +
w(i , j-1, k )
865 +
w(i , j , k+1) +
w(i , j-1, k+1) );
866 const Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
867 const Real t_blank =
myhalf * (t_blank_arr(i, j, k) + t_blank_arr(i, j-1, k));
868 const Real t_blank_above =
myhalf * (t_blank_arr(i, j, k+1) + t_blank_arr(i, j-1, k+1));
870 const Real dx_z = (z_cc_arr) ? (z_cc_arr(i,j,k) - z_cc_arr(i,j,k-1)) : dx_arr[2];
871 const Real drag_coefficient = alpha_m / std::pow(dx_x*dx_y*dx_z,
one/
three);
872 const Real CdM = std::min(drag_coefficient / (windspeed + tiny), drag_coefficient);
876 if ((t_blank > 0 && (t_blank_above ==
zero)) && l_use_most) {
878 const Real ux2r =
fourth * ( u(i , j , k+1) + u(i , j-1, k+1)
879 + u(i+1, j , k+1) + u(i+1, j-1, k+1) );
880 const Real uy2r = v(i, j, k+1) ;
881 const Real h_windspeed2r = std::sqrt(ux2r * ux2r + uy2r * uy2r);
887 const Real theta_surf = theta_yface_below;
891 Real ustar = h_windspeed2r * kappa / (std::log(
Real(1.5) * dx_z /
z0) - psi_m);
892 Real tflux = (tflux_in !=
Real(1e-8)) ? tflux_in : -(theta_yface - theta_surf) * ustar * kappa / (std::log(
Real(1.5) * dx_z /
z0) - psi_h);
893 Real Olen = (Olen_in !=
Real(1e-8)) ? Olen_in : -ustar * ustar * ustar * theta_yface / (kappa * ggg * tflux + tiny);
899 ustar = h_windspeed2r * kappa / (std::log(
Real(1.5) * dx_z /
z0) - psi_m);
902 if (!(ustar >
zero && !std::isnan(ustar))) { ustar =
zero; }
903 if (!(ustar <
two && !std::isnan(ustar))) { ustar =
two; }
904 if (psi_m > std::log(
myhalf * dx_z /
z0)) { psi_m = std::log(
myhalf * dx_z /
z0); }
907 const Real uTarget = ustar / kappa * (std::log(
myhalf * dx_z /
z0) - psi_m);
908 Real uyTarget = uTarget * uy2r / (tiny + h_windspeed2r);
909 const Real bc_forcing_y = -(uyTarget - uy);
910 const Real lambda = (1 - t_blank) * CdM * U_s;
911 const Real fac = l_implicit_drag ? lambda / (
one + lambda*dt) : lambda;
912 ymom_src_arr(i, j, k) -= fac * rho_yface * bc_forcing_y;
914 const Real lambda = t_blank * CdM * windspeed;
915 const Real fac = l_implicit_drag ? lambda / (
one + lambda*dt) : lambda;
916 ymom_src_arr(i, j, k) -= fac * rho_yface * uy;
919 ParallelFor(tbz, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
921 const Real ux =
fourth * ( u(i , j , k ) + u(i+1, j , k )
922 + u(i , j , k-1) + u(i+1, j , k-1) );
923 const Real uy =
fourth * ( v(i , j , k ) + v(i , j+1, k )
924 + v(i , j , k-1) + v(i , j+1, k-1) );
925 const Real uz =
w(i, j, k);
926 const Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
927 const Real t_blank =
myhalf * (t_blank_arr(i, j, k) + t_blank_arr(i, j, k-1));
929 const Real dx_z = (z_cc_arr) ? (z_cc_arr(i,j,k) - z_cc_arr(i,j,k-1)) : dx_arr[2];
930 const Real drag_coefficient = alpha_m / std::pow(dx_x*dx_y*dx_z,
one/
three);
931 const Real CdM = std::min(drag_coefficient / (windspeed + tiny), drag_coefficient);
934 const Real lambda = t_blank * CdM * windspeed;
935 const Real fac = l_implicit_drag ? lambda / (
one + lambda*dt) : lambda;
936 zmom_src_arr(i, j, k) -= fac * rho_zface * uz;
944 const Real* dx_arr = geom.CellSize();
945 const Real dx_x = dx_arr[0];
946 const Real dx_y = dx_arr[1];
947 const Real delta_xy = std::pow(dx_x*dx_y,
myhalf);
948 if ((solverChoice.
buildings_type == BuildingsType::ImmersedForcing ) &&
949 ((is_slow_step && !use_ImmersedForcing_fast) || (!is_slow_step && use_ImmersedForcing_fast)) &&
954 const Real min_t_blank =
Real(1.e-4);
970 ParallelFor(tbx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
972 const Real ux = u(i, j, k );
973 const Real uy =
fourth * ( v(i, j , k ) + v(i-1, j , k )
974 + v(i, j+1, k ) + v(i-1, j+1, k ) );
975 const Real uz =
fourth * (
w(i, j , k ) +
w(i-1, j , k )
976 +
w(i, j , k+1) +
w(i-1, j , k+1) );
977 const amrex::Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
982 Real t_blank =
myhalf * (t_blank_arr(i, j , k ) + t_blank_arr(i-1, j , k ));
983 Real t_blank_below =
myhalf * (t_blank_arr(i, j , k-1) + t_blank_arr(i-1, j , k-1));
984 Real t_blank_above =
myhalf * (t_blank_arr(i, j , k+1) + t_blank_arr(i-1, j , k+1));
985 Real t_blank_north =
myhalf * (t_blank_arr(i, j+1, k ) + t_blank_arr(i-1, j+1, k ));
986 Real t_blank_south =
myhalf * (t_blank_arr(i, j-1, k ) + t_blank_arr(i-1, j-1, k ));
987 if (t_blank < min_t_blank) { t_blank =
zero; }
988 if (k == 0) { t_blank_below =
zero; }
989 if (t_blank_below < min_t_blank) { t_blank_below =
zero; }
990 if (t_blank_above < min_t_blank) { t_blank_above =
zero; }
991 if (t_blank_north < min_t_blank) { t_blank_north =
zero; }
992 if (t_blank_south < min_t_blank) { t_blank_south =
zero; }
994 t_blank = std::round(t_blank *
Real(10000.0)) /
Real(10000.0);
995 t_blank_below = std::round(t_blank_below *
Real(10000.0)) /
Real(10000.0);
996 t_blank_above = std::round(t_blank_above *
Real(10000.0)) /
Real(10000.0);
997 t_blank_north = std::round(t_blank_north *
Real(10000.0)) /
Real(10000.0);
998 t_blank_south = std::round(t_blank_south *
Real(10000.0)) /
Real(10000.0);
1000 const Real dx_z = (z_cc_arr) ? (z_cc_arr(i,j,k) - z_cc_arr(i,j,k-1)) : dx_arr[2];
1001 const Real drag_coefficient = alpha_m / std::pow(dx_x*dx_y*dx_z,
one/
three);
1002 const Real CdM = std::min(drag_coefficient / (windspeed + tiny), drag_coefficient);
1004 const Real roof_mask = (t_blank >
zero && t_blank < t_blank_below && t_blank_above ==
zero && l_use_most) ?
one :
zero;
1005 const Real south_mask = (t_blank >
zero && t_blank <= t_blank_north && t_blank_south ==
zero && l_use_most) ?
one :
zero;
1006 const Real north_mask = (t_blank >
zero && t_blank <= t_blank_south && t_blank_north ==
zero && l_use_most) ?
one :
zero;
1007 const Real wall_mask = (t_blank >
zero && t_blank <
one && !l_use_most) ?
one :
zero;
1008 const Real interior_mask = (t_blank == 1.0) ?
one :
zero;
1013 Real rho_xface_inside = rho_xface;
1014 Real theta_surf = theta_xface;
1019 u1_cellaway = u(i, j, k+1) ;
1020 u2_cellaway =
fourth * ( v(i, j , k+1) + v(i-1, j , k+1)
1021 + v(i, j+1, k+1) + v(i-1, j+1, k+1) ) ;
1024 u_target =
compute_if_most_target_vel(u1_cellaway, u2_cellaway, dx_z,
z0, t_blank, theta_xface, theta_surf, tflux_in, Olen_in, l_stability_correction);
1025 bc_forcing_x = -(u_target - ux);
1026 drag += bc_forcing_x * roof_mask * rho_xface * CdM * U_s;
1029 u1_cellaway = u(i, j-1, k );
1030 u2_cellaway =
fourth * (
w(i, j-1, k ) +
w(i-1, j-1, k )
1031 +
w(i, j-1, k+1) +
w(i-1, j-1, k+1) ) ;
1034 u_target =
compute_if_most_target_vel(u1_cellaway, u2_cellaway, dx_z,
z0, t_blank, theta_xface, theta_surf, tflux_in, Olen_in, l_stability_correction);
1035 bc_forcing_x = -(u_target - ux);
1036 drag += bc_forcing_x * south_mask * rho_xface * CdM * U_s;
1039 u1_cellaway = u(i, j+1, k ) ;
1040 u2_cellaway =
fourth * (
w(i, j+1, k ) +
w(i-1, j+1, k )
1041 +
w(i, j+1, k+1) +
w(i-1, j+1, k+1) ) ;
1044 u_target =
compute_if_most_target_vel(u1_cellaway, u2_cellaway, dx_z,
z0, t_blank, theta_xface, theta_surf, tflux_in, Olen_in, l_stability_correction);
1045 bc_forcing_x = -(u_target - ux);
1046 drag += bc_forcing_x * north_mask * rho_xface * CdM * U_s;
1049 drag += wall_mask * t_blank * rho_xface * CdM * ux * windspeed;
1052 drag += interior_mask * rho_xface * CdM * ux * windspeed;
1054 if (l_implicit_drag) {
1056 const Real lambda = CdM * ( (roof_mask + south_mask + north_mask) * U_s
1057 + wall_mask * t_blank * windspeed
1058 + interior_mask * windspeed );
1059 xmom_src_arr(i,j,k) -= drag / (
one + lambda*dt);
1060 }
else if (is_slow_step && !use_ImmersedForcing_fast) {
1062 Real d_drag = dt * -drag;
1063 Real wsmax_change = damp_alpha * amrex::max(amrex::Math::abs(ux), ws_floor);
1064 if (amrex::Math::abs(ux) < 0.1){
1065 wsmax_change =
one * amrex::max(amrex::Math::abs(ux), ws_floor);
1067 d_drag = amrex::min(amrex::max(d_drag, -wsmax_change), wsmax_change);
1068 xmom_src_arr(i,j,k) += d_drag / dt;
1070 xmom_src_arr(i, j, k) -= drag;
1073 ParallelFor(tby, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
1075 const Real ux =
fourth * ( u(i , j , k ) + u(i , j-1, k )
1076 + u(i+1, j , k ) + u(i+1, j-1, k ) );
1077 const Real uy = v(i, j, k);
1078 const Real uz =
fourth * (
w(i , j , k ) +
w(i , j-1, k )
1079 +
w(i , j , k+1) +
w(i , j-1, k+1) );
1080 const amrex::Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
1085 Real t_blank =
myhalf * (t_blank_arr(i , j , k ) + t_blank_arr(i-1, j , k ));
1086 Real t_blank_below =
myhalf * (t_blank_arr(i , j , k-1) + t_blank_arr(i-1, j , k-1));
1087 Real t_blank_above =
myhalf * (t_blank_arr(i , j , k+1) + t_blank_arr(i-1, j , k+1));
1088 Real t_blank_east =
myhalf * (t_blank_arr(i+1, j , k ) + t_blank_arr(i+1, j-1, k ));
1089 Real t_blank_west =
myhalf * (t_blank_arr(i-1, j , k ) + t_blank_arr(i-1, j-1, k ));
1090 if (t_blank < min_t_blank) { t_blank =
zero; }
1091 if (k == 0) { t_blank_below =
zero; }
1092 if (t_blank_below < min_t_blank) { t_blank_below =
zero; }
1093 if (t_blank_above < min_t_blank) { t_blank_above =
zero; }
1094 if (t_blank_east < min_t_blank) { t_blank_east =
zero; }
1095 if (t_blank_west < min_t_blank) { t_blank_west =
zero; }
1097 t_blank = std::round(t_blank *
Real(10000.0)) /
Real(10000.0);
1098 t_blank_below = std::round(t_blank_below *
Real(10000.0)) /
Real(10000.0);
1099 t_blank_above = std::round(t_blank_above *
Real(10000.0)) /
Real(10000.0);
1100 t_blank_east = std::round(t_blank_east *
Real(10000.0)) /
Real(10000.0);
1101 t_blank_west = std::round(t_blank_west *
Real(10000.0)) /
Real(10000.0);
1103 const Real dx_z = (z_cc_arr) ? (z_cc_arr(i,j,k) - z_cc_arr(i,j,k-1)) : dx_arr[2];
1104 const Real drag_coefficient = alpha_m / std::pow(dx_x*dx_y*dx_z,
one/
three);
1105 const Real CdM = std::min(drag_coefficient / (windspeed + tiny), drag_coefficient);
1107 const Real roof_mask = (t_blank >
zero && t_blank < t_blank_below && t_blank_above ==
zero && l_use_most) ?
one :
zero;
1108 const Real west_mask = (t_blank >
zero && t_blank <= t_blank_east && t_blank_west ==
zero && l_use_most) ?
one :
zero;
1109 const Real east_mask = (t_blank >
zero && t_blank <= t_blank_west && t_blank_east ==
zero && l_use_most) ?
one :
zero;
1110 const Real wall_mask = (t_blank >
zero && t_blank <
one && !l_use_most) ?
one :
zero;
1111 const Real interior_mask = (t_blank == 1.0) ?
one :
zero;
1116 Real rho_yface_inside = rho_yface;
1117 Real theta_surf = theta_yface;
1122 u1_cellaway =
fourth * ( u(i , j , k+1) + u(i , j-1, k+1)
1123 + u(i+1, j , k+1) + u(i+1, j-1, k+1) );
1124 u2_cellaway = v(i, j, k+1);
1127 u_target =
compute_if_most_target_vel(u1_cellaway, u2_cellaway, dx_z,
z0, t_blank, theta_yface, theta_surf, tflux_in, Olen_in, l_stability_correction);
1128 bc_forcing_y = -(u_target - uy);
1129 drag += bc_forcing_y * roof_mask * rho_yface * CdM * U_s;
1132 u1_cellaway = v(i-1, j , k );
1133 u2_cellaway =
fourth * (
w(i-1, j , k ) +
w(i-1, j-1, k )
1134 +
w(i-1, j , k+1) +
w(i-1, j-1, k+1) );
1137 u_target =
compute_if_most_target_vel(u1_cellaway, u2_cellaway, dx_x,
z0, t_blank, theta_yface, theta_surf, tflux_in, Olen_in, l_stability_correction);
1138 bc_forcing_y = -(u_target - uy);
1139 drag += bc_forcing_y * west_mask * rho_yface * CdM * U_s;
1142 u1_cellaway = v(i+1, j , k );
1143 u2_cellaway =
fourth * (
w(i+1, j , k ) +
w(i+1, j-1, k )
1144 +
w(i+1, j , k+1) +
w(i+1, j-1, k+1) );
1147 u_target =
compute_if_most_target_vel(u1_cellaway, u2_cellaway, dx_x,
z0, t_blank, theta_yface, theta_surf, tflux_in, Olen_in, l_stability_correction);
1148 bc_forcing_y = -(u_target - uy);
1149 drag += bc_forcing_y * east_mask * rho_yface * CdM * U_s;
1152 drag += wall_mask * t_blank * rho_yface * CdM * uy * windspeed;
1155 drag += interior_mask * rho_yface * CdM * uy * windspeed;
1157 if (l_implicit_drag) {
1159 const Real lambda = CdM * ( (roof_mask + west_mask + east_mask) * U_s
1160 + wall_mask * t_blank * windspeed
1161 + interior_mask * windspeed );
1162 ymom_src_arr(i,j,k) -= drag / (
one + lambda*dt);
1163 }
else if (is_slow_step && !use_ImmersedForcing_fast) {
1165 Real d_drag = dt * -drag;
1166 Real wsmax_change = damp_alpha * amrex::max(amrex::Math::abs(uy), ws_floor);
1167 if (amrex::Math::abs(uy) < 0.1){
1168 wsmax_change =
one * amrex::max(amrex::Math::abs(uy), ws_floor);
1170 d_drag = amrex::min(amrex::max(d_drag, -wsmax_change), wsmax_change);
1171 ymom_src_arr(i,j,k) += d_drag / dt;
1173 ymom_src_arr(i, j, k) -= drag;
1176 ParallelFor(tbz, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
1178 const Real ux =
fourth * ( u(i , j , k ) + u(i+1, j , k )
1179 + u(i , j , k-1) + u(i+1, j , k-1) );
1180 const Real uy =
fourth * ( v(i, j , k ) + v(i, j+1, k )
1181 + v(i, j , k-1) + v(i, j+1, k-1) );
1182 const Real uz =
w(i, j, k);
1183 const amrex::Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
1188 Real t_blank =
myhalf * (t_blank_arr(i ,j , k) + t_blank_arr(i , j , k-1));
1189 Real t_blank_below =
myhalf * (t_blank_arr(i ,j , k-1) + t_blank_arr(i , j , k-2));
1190 Real t_blank_above =
myhalf * (t_blank_arr(i ,j , k) + t_blank_arr(i , j , k+1));
1191 Real t_blank_north =
myhalf * (t_blank_arr(i ,j+1, k) + t_blank_arr(i , j+1, k-1));
1192 Real t_blank_south =
myhalf * (t_blank_arr(i ,j-1, k) + t_blank_arr(i , j-1, k-1));
1193 Real t_blank_east =
myhalf * (t_blank_arr(i+1,j , k) + t_blank_arr(i+1, j , k-1));
1194 Real t_blank_west =
myhalf * (t_blank_arr(i-1,j , k) + t_blank_arr(i-1, j , k-1));
1195 if (t_blank < min_t_blank) { t_blank =
zero; }
1196 if (k == 0) { t_blank_below =
zero; }
1197 if (t_blank_below < min_t_blank) { t_blank_below =
zero; }
1198 if (t_blank_above < min_t_blank) { t_blank_above =
zero; }
1199 if (t_blank_north < min_t_blank) { t_blank_north =
zero; }
1200 if (t_blank_south < min_t_blank) { t_blank_south =
zero; }
1201 if (t_blank_east < min_t_blank) { t_blank_east =
zero; }
1202 if (t_blank_west < min_t_blank) { t_blank_west =
zero; }
1204 t_blank = std::round(t_blank *
Real(10000.0)) /
Real(10000.0);
1205 t_blank_below = std::round(t_blank_below *
Real(10000.0)) /
Real(10000.0);
1206 t_blank_above = std::round(t_blank_above *
Real(10000.0)) /
Real(10000.0);
1207 t_blank_north = std::round(t_blank_north *
Real(10000.0)) /
Real(10000.0);
1208 t_blank_south = std::round(t_blank_south *
Real(10000.0)) /
Real(10000.0);
1209 t_blank_east = std::round(t_blank_east *
Real(10000.0)) /
Real(10000.0);
1210 t_blank_west = std::round(t_blank_west *
Real(10000.0)) /
Real(10000.0);
1212 const Real dx_z = (z_cc_arr) ? (z_cc_arr(i,j,k) - z_cc_arr(i,j,k-1)) : dx_arr[2];
1213 const Real drag_coefficient = alpha_m / std::pow(dx_x*dx_y*dx_z,
one/
three);
1214 const Real CdM = std::min(drag_coefficient / (windspeed + tiny), drag_coefficient);
1216 const Real south_mask = (t_blank >
zero && t_blank <= t_blank_north && t_blank_south == zero && l_use_most && k >= 1) ?
one :
zero;
1217 const Real north_mask = (t_blank >
zero && t_blank <= t_blank_south && t_blank_north == zero && l_use_most && k >= 1) ?
one :
zero;
1218 const Real west_mask = (t_blank >
zero && t_blank <= t_blank_east && t_blank_west == zero && l_use_most && k >= 1) ?
one :
zero;
1219 const Real east_mask = (t_blank >
zero && t_blank <= t_blank_west && t_blank_east == zero && l_use_most && k >= 1) ?
one :
zero;
1220 const Real wall_mask = (t_blank >
zero && t_blank <
one && !l_use_most) ?
one :
zero;
1221 const Real interior_mask = (t_blank == 1.0) ?
one :
zero;
1226 Real rho_zface_inside = rho_zface;
1227 Real theta_surf = theta_zface;
1232 u1_cellaway =
fourth * ( u(i , j-1, k ) + u(i+1, j-1, k )
1233 + u(i , j-1, k-1) + u(i+1, j-1, k-1) );
1234 u2_cellaway =
w(i, j-1, k);
1237 u_target =
compute_if_most_target_vel(u1_cellaway, u2_cellaway, dx_y,
z0, t_blank, theta_zface, theta_surf, tflux_in, Olen_in, l_stability_correction);
1238 bc_forcing_z = -(u_target - uz);
1239 drag += bc_forcing_z * south_mask * rho_zface * CdM * U_s;
1242 u1_cellaway =
fourth * ( u(i , j+1, k ) + u(i+1, j+1, k )
1243 + u(i , j+1, k-1) + u(i+1, j+1, k-1) );
1244 u2_cellaway =
w(i, j+1, k);
1247 u_target =
compute_if_most_target_vel(u1_cellaway, u2_cellaway, dx_y,
z0, t_blank, theta_zface, theta_surf, tflux_in, Olen_in, l_stability_correction);
1248 bc_forcing_z = -(u_target - uz);
1249 drag += bc_forcing_z * north_mask * rho_zface * CdM * U_s;
1252 u1_cellaway =
fourth * ( v(i-1, j , k ) + v(i-1, j+1, k )
1253 + v(i-1, j , k-1) + v(i-1, j+1, k-1) );
1254 u2_cellaway =
w(i-1, j, k);
1257 u_target =
compute_if_most_target_vel(u1_cellaway, u2_cellaway, dx_x,
z0, t_blank, theta_zface, theta_surf, tflux_in, Olen_in, l_stability_correction);
1258 bc_forcing_z = -(u_target - uz);
1259 drag += bc_forcing_z * west_mask * rho_zface * CdM * U_s;
1262 u1_cellaway =
fourth * ( v(i+1, j , k ) + v(i+1, j+1, k )
1263 + v(i+1, j , k-1) + v(i+1, j+1, k-1) );
1264 u2_cellaway =
w(i+1, j, k);
1267 u_target =
compute_if_most_target_vel(u1_cellaway, u2_cellaway, dx_x,
z0, t_blank, theta_zface, theta_surf, tflux_in, Olen_in, l_stability_correction);
1268 bc_forcing_z = -(u_target - uz);
1269 drag += bc_forcing_z * east_mask * rho_zface * CdM * U_s;
1272 drag += wall_mask * t_blank * rho_zface * CdM * uz * windspeed;
1275 drag += interior_mask * rho_zface * CdM * uz * windspeed;
1277 if (l_implicit_drag) {
1279 const Real lambda = CdM * ( (south_mask + north_mask + west_mask + east_mask) * U_s
1280 + wall_mask * t_blank * windspeed
1281 + interior_mask * windspeed );
1282 zmom_src_arr(i,j,k) -= drag / (
one + lambda*dt);
1283 }
else if (is_slow_step && !use_ImmersedForcing_fast) {
1285 Real d_drag = dt * -drag;
1286 Real wsmax_change = damp_alpha * amrex::max(amrex::Math::abs(uz), ws_floor);
1287 if (amrex::Math::abs(uz) < 0.1){
1288 wsmax_change =
one * amrex::max(amrex::Math::abs(uz), ws_floor);
1290 d_drag = amrex::min(amrex::max(d_drag, -wsmax_change), wsmax_change);
1291 zmom_src_arr(i,j,k) += d_drag / dt;
1293 zmom_src_arr(i, j, k) -= drag;
1301 if (is_slow_step && (enforce_massflux_x || enforce_massflux_y)) {
1305 [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept {
1306 xmom_src_arr(i, j, k) += tau_inv * (rhoUA_target - rhoUA);
1308 [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept {
1309 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:169
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 three
Definition: ERF_Constants.H:11
constexpr amrex::Real two
Definition: ERF_Constants.H:10
constexpr amrex::Real one
Definition: ERF_Constants.H:9
constexpr amrex::Real fourth
Definition: ERF_Constants.H:14
constexpr amrex::Real PI
Definition: ERF_Constants.H:42
@ ubar
Definition: ERF_DataStruct.H:152
@ wbar
Definition: ERF_DataStruct.H:152
@ vbar
Definition: ERF_DataStruct.H:152
DirectionSelector< 2 > ZDir
Definition: ERF_DirectionSelector.H:38
#define Rho_comp
Definition: ERF_IndexDefines.H:36
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
amrex::GpuArray< Real, AMREX_SPACEDIM > dxInv
Definition: ERF_InitCustomPertVels_ParticleTests.H:17
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real compute_if_most_target_vel(const amrex::Real u1_2r, const amrex::Real u2_2r, const amrex::Real delta, const amrex::Real z0, const amrex::Real t_blank, const amrex::Real theta_xface, const amrex::Real theta_surf, const amrex::Real tflux_in, const amrex::Real Olen_in, const bool stability_correction)
Definition: ERF_MakeMomSources.cpp:18
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);})
void NumericalDiffusion_Ymom(const Box &bx, const double 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 double 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
Real w
Definition: ERF_Plotfile2DInterpolator.cpp:22
AMREX_FORCE_INLINE IntVect offset(const int face_dir, const int normal)
Definition: ERF_ReadBndryPlanes.cpp:31
Definition: ERF_PlaneAverage.H:14
eb_aux_ const * get_w_const_factory() const noexcept
Return the ERF auxiliary z-face EB factory.
Definition: ERF_EB.H:123
eb_aux_ const * get_v_const_factory() const noexcept
Return the ERF auxiliary y-face EB factory.
Definition: ERF_EB.H:121
eb_aux_ const * get_u_const_factory() const noexcept
Return the ERF auxiliary x-face EB factory.
Definition: ERF_EB.H:119
@ r0_comp
Definition: ERF_IndexDefines.H:73
@ ymom
Definition: ERF_IndexDefines.H:196
@ cons
Definition: ERF_IndexDefines.H:194
@ zmom
Definition: ERF_IndexDefines.H:197
@ xmom
Definition: ERF_IndexDefines.H:195
@ nr
Definition: ERF_Morrison.H:46
@ xvel
Definition: ERF_IndexDefines.H:177
@ cons
Definition: ERF_IndexDefines.H:176
@ yvel
Definition: ERF_IndexDefines.H:178
@ ww
Definition: ERF_AdvanceWSM6.cpp:105
real(kind=kind_phys), parameter, private r0
Definition: ERF_module_mp_wsm6.F90:21
RayleighDampingType rayleigh_damping_type
Selected Rayleigh damping time-integration treatment.
Definition: ERF_DampingStruct.H:111
amrex::Real rayleigh_dampcoef
Rayleigh damping inverse time scale [1/s].
Definition: ERF_DampingStruct.H:98
bool rayleigh_damp_U
Whether Rayleigh damping is applied to x-momentum.
Definition: ERF_DampingStruct.H:94
bool rayleigh_damp_V
Whether Rayleigh damping is applied to y-momentum.
Definition: ERF_DampingStruct.H:95
bool rayleigh_damp_W
Whether Rayleigh damping is applied to vertical momentum.
Definition: ERF_DampingStruct.H:96
amrex::Real const_massflux_v
Target constant mass flux in the y direction.
Definition: ERF_DataStruct.H:1651
static InitType init_type
Initial-condition source selected for the run.
Definition: ERF_DataStruct.H:1362
amrex::Real coriolis_factor
Twice the planetary rotation rate used for Coriolis forcing.
Definition: ERF_DataStruct.H:1485
bool variable_coriolis
Whether spatially varying Coriolis forcing is enabled.
Definition: ERF_DataStruct.H:1616
amrex::Real if_Cd_momentum
Immersed-forcing drag coefficient for momentum.
Definition: ERF_DataStruct.H:1452
amrex::Real if_Olen_in
Input Obukhov length for immersed-forcing MOST [m].
Definition: ERF_DataStruct.H:1462
int ave_plane
Averaging plane index used by diagnostics.
Definition: ERF_DataStruct.H:1618
amrex::Real const_massflux_u
Target constant mass flux in the x direction.
Definition: ERF_DataStruct.H:1650
amrex::Real if_z0
Immersed-forcing roughness length [m].
Definition: ERF_DataStruct.H:1458
bool forest_substep
Whether canopy source terms are applied only during substeps.
Definition: ERF_DataStruct.H:1449
amrex::Real num_diff_coeff
Numerical diffusion coefficient after input scaling.
Definition: ERF_DataStruct.H:1601
bool hindcast_lateral_forcing
Whether hindcast lateral forcing is enabled.
Definition: ERF_DataStruct.H:1660
bool use_coriolis
Whether Coriolis forcing is enabled.
Definition: ERF_DataStruct.H:1442
static MeshType mesh_type
Vertical mesh representation.
Definition: ERF_DataStruct.H:1377
SpongeChoice spongeChoice
Sponge-layer options.
Definition: ERF_DataStruct.H:1392
bool have_geo_wind_profile
Whether a geostrophic wind profile has been configured.
Definition: ERF_DataStruct.H:1614
DampingChoice dampingChoice
Damping-related options.
Definition: ERF_DataStruct.H:1391
amrex::Real if_damp_alpha
Immersed-forcing damping coefficient.
Definition: ERF_DataStruct.H:1466
amrex::Real if_ws_floor
Wind-speed floor for immersed-forcing MOST [m/s].
Definition: ERF_DataStruct.H:1465
bool do_forest_drag
Whether forest canopy drag is enabled.
Definition: ERF_DataStruct.H:1647
int massflux_khi
Upper vertical index for constant-mass-flux forcing.
Definition: ERF_DataStruct.H:1656
static TerrainType terrain_type
Terrain or immersed-boundary representation.
Definition: ERF_DataStruct.H:1368
amrex::Real cosphi
Cosine of the latitude used for Coriolis forcing.
Definition: ERF_DataStruct.H:1486
static BuildingsType buildings_type
Building representation.
Definition: ERF_DataStruct.H:1371
int massflux_klo
Lower vertical index for constant-mass-flux forcing.
Definition: ERF_DataStruct.H:1655
amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > abl_geo_forcing
Applied geostrophic-wind forcing vector.
Definition: ERF_DataStruct.H:1612
amrex::Real if_surf_temp_flux
Immersed-forcing surface temperature flux [K m/s].
Definition: ERF_DataStruct.H:1459
bool custom_w_subsidence
Whether custom vertical subsidence is enabled.
Definition: ERF_DataStruct.H:1492
bool immersed_forcing_substep
Whether immersed-forcing source terms are applied only during substeps.
Definition: ERF_DataStruct.H:1448
bool if_use_most
Whether immersed-forcing MOST is enabled.
Definition: ERF_DataStruct.H:1463
amrex::Real const_massflux_tau
Relaxation time scale for constant-mass-flux forcing.
Definition: ERF_DataStruct.H:1652
amrex::Real sinphi
Sine of the latitude used for Coriolis forcing.
Definition: ERF_DataStruct.H:1487
bool if_implicit_drag
Definition: ERF_DataStruct.H:1456
bool do_mom_advection
Whether custom vertical subsidence is applied to momentum.
Definition: ERF_DataStruct.H:1494
bool if_stability_correction
Whether immersed-forcing stability corrections are enabled.
Definition: ERF_DataStruct.H:1464
bool custom_forcing_prim_vars
Whether custom forcing operates on primitive variables.
Definition: ERF_DataStruct.H:1496
bool nudging_from_input_sounding
Whether solution fields are nudged toward input sounding data.
Definition: ERF_DataStruct.H:1502
static SpongeType sponge_type
Selected sponge damping model.
Definition: ERF_SpongeStruct.H:100