Function for computing the slow RHS for the evolution equations for the density, potential temperature and momentum.
77 BL_PROFILE_REGION(
"erf_make_mom_sources()");
79 Real time =
static_cast<Real>(time_d);
81 Box domain(geom.Domain());
82 const GpuArray<Real, AMREX_SPACEDIM>
dxInv = geom.InvCellSizeArray();
116 if (solverChoice.
terrain_type == TerrainType::ImmersedForcing) {
118 amrex::Error(
" Currently forest canopy cannot be used with immersed forcing");
128 auto cosphi = solverChoice.
cosphi;
129 auto sinphi = solverChoice.
sinphi;
160 Real rhoUA_target{0};
161 Real rhoVA_target{0};
167 Real massflux_area_x{0};
168 Real massflux_area_y{0};
173 Table1D<Real> dptr_r_plane, dptr_u_plane, dptr_v_plane;
174 TableData<Real, 1> r_plane_tab, u_plane_tab, v_plane_tab;
176 if (is_slow_step && (dptr_wbar_sub ||
179 enforce_massflux_x || enforce_massflux_y))
184 const bool planar_averages_valid =
185 solverChoice.
mesh_type != MeshType::VariableDz ||
188 planar_averages_valid,
189 "Fixed-index planar averages require a non-variable-dz mesh or "
190 "a validated flat fitted mesh (erf.flat_terrain = true).");
193 const int u_offset = 1;
194 const int v_offset = 1;
203 r_ave.compute_averages(
ZDir(), r_ave.field());
205 int ncell = r_ave.ncell_line();
206 Gpu::HostVector< Real> r_plane_h(ncell);
207 Gpu::DeviceVector< Real> r_plane_d(ncell);
209 r_ave.line_average(
Rho_comp, r_plane_h);
211 Gpu::copyAsync(Gpu::hostToDevice, r_plane_h.begin(), r_plane_h.end(), r_plane_d.begin());
213 Real* dptr_r = r_plane_d.data();
215 Box tdomain = domain; tdomain.grow(2,ng_c[2]);
216 r_plane_tab.resize({tdomain.smallEnd(2)}, {tdomain.bigEnd(2)});
218 dptr_r_plane = r_plane_tab.table();
219 ParallelFor(ncell, [=] AMREX_GPU_DEVICE (
int k) noexcept
221 dptr_r_plane(k-
offset) = dptr_r[k];
225 IntVect ng_u = S_data[
IntVars::xmom].nGrowVect(); ng_u[2] = u_offset;
228 IntVect ng_v = S_data[
IntVars::ymom].nGrowVect(); ng_v[2] = v_offset;
231 u_ave.compute_averages(
ZDir(), u_ave.field());
232 v_ave.compute_averages(
ZDir(), v_ave.field());
234 int u_ncell = u_ave.ncell_line();
235 int v_ncell = v_ave.ncell_line();
236 Gpu::HostVector< Real> u_plane_h(u_ncell), v_plane_h(v_ncell);
237 Gpu::DeviceVector< Real> u_plane_d(u_ncell), v_plane_d(v_ncell);
239 u_ave.line_average(0, u_plane_h);
240 v_ave.line_average(0, v_plane_h);
242 Gpu::copyAsync(Gpu::hostToDevice, u_plane_h.begin(), u_plane_h.end(), u_plane_d.begin());
243 Gpu::copyAsync(Gpu::hostToDevice, v_plane_h.begin(), v_plane_h.end(), v_plane_d.begin());
245 Real* dptr_u = u_plane_d.data();
246 Real* dptr_v = v_plane_d.data();
248 Box udomain = domain; udomain.grow(2,ng_u[2]);
249 Box vdomain = domain; vdomain.grow(2,ng_v[2]);
250 u_plane_tab.resize({udomain.smallEnd(2)}, {udomain.bigEnd(2)});
251 v_plane_tab.resize({vdomain.smallEnd(2)}, {vdomain.bigEnd(2)});
253 dptr_u_plane = u_plane_tab.table();
254 ParallelFor(u_ncell, [=] AMREX_GPU_DEVICE (
int k) noexcept
256 dptr_u_plane(k-u_offset) = dptr_u[k];
259 dptr_v_plane = v_plane_tab.table();
260 ParallelFor(v_ncell, [=] AMREX_GPU_DEVICE (
int k) noexcept
262 dptr_v_plane(k-v_offset) = dptr_v[k];
266 if (enforce_massflux_x || enforce_massflux_y) {
267 Real Lx = geom.ProbHi(0) - geom.ProbLo(0);
268 Real Ly = geom.ProbHi(1) - geom.ProbLo(1);
270 if (solverChoice.
mesh_type == MeshType::ConstantDz) {
272 rhoUA = std::accumulate(u_plane_h.begin() + u_offset + massflux_klo,
273 u_plane_h.begin() + u_offset + massflux_khi+1,
zero);
274 rhoVA = std::accumulate(v_plane_h.begin() + v_offset + massflux_klo,
275 v_plane_h.begin() + v_offset + massflux_khi+1,
zero);
276 rhoUA_target = std::accumulate(r_plane_h.begin() +
offset + massflux_klo,
277 r_plane_h.begin() +
offset + massflux_khi+1,
zero);
278 rhoVA_target = rhoUA_target;
280 rhoUA *= geom.CellSize(2) * Ly;
281 rhoVA *= geom.CellSize(2) * Lx;
282 rhoUA_target *= geom.CellSize(2) * Ly;
283 rhoVA_target *= geom.CellSize(2) * Lx;
285 const Real H = geom.CellSize(2) *
static_cast<Real>(massflux_khi - massflux_klo + 1);
286 massflux_area_x =
H * Ly;
287 massflux_area_y =
H * Lx;
289 }
else if (solverChoice.
mesh_type == MeshType::StretchedDz) {
292 for (
int k=massflux_klo; k < massflux_khi; ++k) {
293 rhoUA += u_plane_h[k + u_offset] * stretched_dz_h[k];
294 rhoVA += v_plane_h[k + v_offset] * stretched_dz_h[k];
295 rhoUA_target += r_plane_h[k +
offset] * stretched_dz_h[k];
296 H += stretched_dz_h[k];
298 rhoVA_target = rhoUA_target;
305 massflux_area_x =
H * Ly;
306 massflux_area_y =
H * Lx;
310 rhoUA_target *= U_target;
311 rhoVA_target *= V_target;
313 Print() <<
"Integrated mass flux : " << rhoUA <<
" " << rhoVA
314 <<
" (target: " << rhoUA_target <<
" " << rhoVA_target <<
")"
322 for ( MFIter mfi(S_data[
IntVars::cons]); mfi.isValid(); ++mfi)
324 Box tbx = mfi.nodaltilebox(0);
325 Box tby = mfi.nodaltilebox(1);
326 Box tbz = mfi.nodaltilebox(2);
327 if (tbz.bigEnd(2) == domain.bigEnd(2)+1) tbz.growHi(2,-1);
329 const Array4<const Real>& cell_data = S_data[
IntVars::cons].array(mfi);
330 const Array4<const Real>& rho_u = S_data[
IntVars::xmom].array(mfi);
331 const Array4<const Real>& rho_v = S_data[
IntVars::ymom].array(mfi);
332 const Array4<const Real>& rho_w = S_data[
IntVars::zmom].array(mfi);
334 const Array4<const Real>& u =
xvel.array(mfi);
335 const Array4<const Real>& v =
yvel.array(mfi);
336 const Array4<const Real>&
w = wvel.array(mfi);
338 const Array4< Real>& xmom_src_arr = xmom_src.array(mfi);
339 const Array4< Real>& ymom_src_arr = ymom_src.array(mfi);
340 const Array4< Real>& zmom_src_arr = zmom_src.array(mfi);
342 const Array4<const Real>&
r0 = r_hse.const_array(mfi);
344 const Array4<const Real>& f_drag_arr = (forest_drag) ? forest_drag->const_array(mfi) :
345 Array4<const Real>{};
346 const Array4<const Real>& t_blank_arr = (terrain_blank) ? terrain_blank->const_array(mfi) :
347 Array4<const Real>{};
348 const Array4<const Real>& t_blank_xface_arr = (terrain_blank_xface) ? terrain_blank_xface->const_array(mfi) :
349 Array4<const Real>{};
350 const Array4<const Real>& t_blank_yface_arr = (terrain_blank_yface) ? terrain_blank_yface->const_array(mfi) :
351 Array4<const Real>{};
352 const Array4<const Real>& t_blank_zface_arr = (terrain_blank_zface) ? terrain_blank_zface->const_array(mfi) :
353 Array4<const Real>{};
355 const Array4<const Real>& cphi_arr = (cosPhi_mf) ? cosPhi_mf->const_array(mfi) :
356 Array4<const Real>{};
357 const Array4<const Real>& sphi_arr = (sinPhi_mf) ? sinPhi_mf->const_array(mfi) :
358 Array4<const Real>{};
360 const Array4<const Real>& z_nd_arr = z_phys_nd->const_array(mfi);
361 const Array4<const Real>& z_cc_arr = z_phys_cc->const_array(mfi);
367 if (use_coriolis && is_slow_step) {
368 if(solverChoice.
init_type == InitType::HindCast) {
369 const Array4<const Real>& latlon_arr = (*forecast_state_at_lev)[4].array(mfi);
371 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
374 Real v_loc =
fourth * (v(i,j+1,k) + v(i,j,k) + v(i-1,j+1,k) + v(i-1,j,k));
375 Real w_loc =
fourth * (
w(i,j,k+1) +
w(i,j,k) +
w(i-1,j,k+1) +
w(i-1,j,k));
376 Real latitude = latlon_arr(i,j,k,0);
377 Real sphi_loc = std::sin(latitude*
PI/
Real(180.0));
378 Real cphi_loc = std::cos(latitude*
PI/
Real(180.0));
379 xmom_src_arr(i, j, k) += coriolis_factor * rho_on_u_face * (v_loc * sphi_loc - w_loc * cphi_loc);
381 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
383 Real u_loc =
fourth * (u(i+1,j,k) + u(i,j,k) + u(i+1,j-1,k) + u(i,j-1,k));
384 Real latitude = latlon_arr(i,j,k,0);
385 Real sphi_loc = std::sin(latitude*
PI/
Real(180.0));
386 ymom_src_arr(i, j, k) += -coriolis_factor * rho_on_v_face * u_loc * sphi_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,k-1) + u(i,j,k-1));
391 Real latitude = latlon_arr(i,j,k,0);
392 Real cphi_loc = std::cos(latitude*
PI/
Real(180.0));
393 zmom_src_arr(i, j, k) += coriolis_factor * rho_on_w_face * u_loc * cphi_loc;
396 else if (var_coriolis && (sinPhi_mf) && (cosPhi_mf)) {
398 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
401 Real v_loc =
fourth * (v(i,j+1,k) + v(i,j,k) + v(i-1,j+1,k) + v(i-1,j,k));
402 Real w_loc =
fourth * (
w(i,j,k+1) +
w(i,j,k) +
w(i-1,j,k+1) +
w(i-1,j,k));
403 Real sphi_loc =
myhalf * (sphi_arr(i,j,0) + sphi_arr(i-1,j,0));
404 Real cphi_loc =
myhalf * (cphi_arr(i,j,0) + cphi_arr(i-1,j,0));
405 xmom_src_arr(i, j, k) += coriolis_factor * rho_on_u_face * (v_loc * sphi_loc - w_loc * cphi_loc);
407 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
409 Real u_loc =
fourth * (u(i+1,j,k) + u(i,j,k) + u(i+1,j-1,k) + u(i,j-1,k));
410 Real sphi_loc =
myhalf * (sphi_arr(i,j,0) + sphi_arr(i,j-1,0));
411 ymom_src_arr(i, j, k) += -coriolis_factor * rho_on_v_face * u_loc * sphi_loc;
413 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
415 Real u_loc =
fourth * (u(i+1,j,k) + u(i,j,k) + u(i+1,j,k-1) + u(i,j,k-1));
416 zmom_src_arr(i, j, k) += coriolis_factor * rho_on_w_face * u_loc * cphi_arr(i,j,0);
420 Array4<const Real> u_volfrac = (ebfact.
get_u_const_factory())->getVolFrac().const_array(mfi);
421 Array4<const Real> v_volfrac = (ebfact.
get_v_const_factory())->getVolFrac().const_array(mfi);
422 Array4<const Real> w_volfrac = (ebfact.
get_w_const_factory())->getVolFrac().const_array(mfi);
423 ParallelFor(tbx, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
426 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);
427 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);
430 v_loc = ( v_volfrac(i ,j+1,k) * v(i ,j+1,k) + v_volfrac(i ,j,k) * v(i ,j,k)
431 + 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;
434 w_loc = ( w_volfrac(i ,j,k+1) *
w(i ,j,k+1) + w_volfrac(i ,j,k) *
w(i ,j,k)
435 + 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;
437 xmom_src_arr(i, j, k) += coriolis_factor * rho_on_u_face * (v_loc * sinphi - w_loc * cosphi);
439 ParallelFor(tby, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
441 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);
444 u_loc = ( u_volfrac(i+1,j ,k) * u(i+1,j ,k) + u_volfrac(i,j ,k) * u(i,j ,k)
445 + 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;
447 ymom_src_arr(i, j, k) += -coriolis_factor * rho_on_v_face * u_loc * sinphi;
449 ParallelFor(tbz, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
451 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);
454 u_loc = ( u_volfrac(i+1,j,k ) * u(i+1,j,k ) + u_volfrac(i,j,k) * u(i,j,k )
455 + 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;
457 zmom_src_arr(i, j, k) += coriolis_factor * rho_on_w_face * u_loc * cosphi;
461 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
463 Real v_loc =
fourth * (v(i,j+1,k) + v(i,j,k) + v(i-1,j+1,k) + v(i-1,j,k));
464 Real w_loc =
fourth * (
w(i,j,k+1) +
w(i,j,k) +
w(i-1,j,k+1) +
w(i-1,j,k));
466 xmom_src_arr(i, j, k) += rho_on_u_face * ( coriolis_factor * (v_loc * sinphi - w_loc * cosphi) );
468 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
470 Real u_loc =
fourth * (u(i+1,j,k) + u(i,j,k) + u(i+1,j-1,k) + u(i,j-1,k));
471 ymom_src_arr(i, j, k) += rho_on_v_face * ( -coriolis_factor * u_loc * sinphi );
473 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) {
474 Real u_loc =
fourth * (u(i+1,j,k) + u(i,j,k) + u(i+1,j,k-1) + u(i,j,k-1));
476 zmom_src_arr(i, j, k) += rho_on_w_face * ( coriolis_factor * u_loc * cosphi );
487 if ( (is_slow_step && !use_Rayleigh_fast_uv) || (!is_slow_step && use_Rayleigh_fast_uv)) {
488 if (rayleigh_damp_U) {
489 ParallelFor(tbx, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
492 Real uu = rho_u(i,j,k) / rho_on_u_face;
493 Real sinesq = d_sinesq_at_lev[k];
494 xmom_src_arr(i, j, k) -= dampcoef*sinesq * (uu -
ubar[k]) * rho_on_u_face;
498 if (rayleigh_damp_V) {
499 ParallelFor(tby, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
502 Real vv = rho_v(i,j,k) / rho_on_v_face;
503 Real sinesq = d_sinesq_at_lev[k];
504 ymom_src_arr(i, j, k) -= dampcoef*sinesq * (vv -
vbar[k]) * rho_on_v_face;
509 if ( (is_slow_step && !use_Rayleigh_fast_w) || (!is_slow_step && use_Rayleigh_fast_w)) {
510 if (rayleigh_damp_W) {
511 ParallelFor(tbz, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
514 Real ww = rho_w(i,j,k) / rho_on_w_face;
515 Real sinesq = d_sinesq_stag_at_lev[k];
516 zmom_src_arr(i, j, k) -= dampcoef*sinesq * (
ww -
wbar[k]) * rho_on_w_face;
526 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
529 xmom_src_arr(i, j, k) += rho_on_u_face * abl_geo_forcing[0];
531 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
534 ymom_src_arr(i, j, k) += rho_on_v_face * abl_geo_forcing[1];
536 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
539 zmom_src_arr(i, j, k) += rho_on_w_face * abl_geo_forcing[2];
546 if (geo_wind_profile && is_slow_step) {
549 const bool geo_hindcast_lat = (solverChoice.
init_type == InitType::HindCast) &&
550 (forecast_state_at_lev !=
nullptr);
551 const bool geo_var_sinphi = !geo_hindcast_lat && var_coriolis && (sinPhi_mf !=
nullptr);
552 const Array4<const Real> geo_latlon_arr = (geo_hindcast_lat) ?
553 (*forecast_state_at_lev)[4].const_array(mfi) : Array4<const Real>{};
555 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
557 Real sphi_loc = (geo_hindcast_lat) ? std::sin(geo_latlon_arr(i,j,k,0)*
PI/
Real(180.0)) :
558 (geo_var_sinphi) ?
myhalf * (sphi_arr(i,j,0) + sphi_arr(i-1,j,0)) : sinphi;
560 xmom_src_arr(i, j, k) -= coriolis_factor * rho_on_u_face * dptr_v_geos[k] * sphi_loc;
562 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
564 Real sphi_loc = (geo_hindcast_lat) ? std::sin(geo_latlon_arr(i,j,k,0)*
PI/
Real(180.0)) :
565 (geo_var_sinphi) ?
myhalf * (sphi_arr(i,j,0) + sphi_arr(i,j-1,0)) : sinphi;
567 ymom_src_arr(i, j, k) += coriolis_factor * rho_on_v_face * dptr_u_geos[k] * sphi_loc;
579 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
583 Real z_xf_lo =
fourth * ( z_nd_arr(i,j,k ) + z_nd_arr(i,j+1,k )
584 + z_nd_arr(i,j,k-1) + z_nd_arr(i,j+1,k-1) );
585 Real z_xf_hi =
fourth * ( z_nd_arr(i,j,k+1) + z_nd_arr(i,j+1,k+1)
586 + z_nd_arr(i,j,k+2) + z_nd_arr(i,j+1,k+2) );
587 dzInv =
one / (z_xf_hi - z_xf_lo);
589 Real rho_on_u_face =
myhalf * ( cell_data(i,j,k,
nr) + cell_data(i-1,j,k,
nr) );
590 Real U_hi = dptr_u_plane(k+1) / dptr_r_plane(k+1);
591 Real U_lo = dptr_u_plane(k-1) / dptr_r_plane(k-1);
592 Real wbar_xf =
myhalf * (dptr_wbar_sub[k] + dptr_wbar_sub[k+1]);
593 xmom_src_arr(i, j, k) -= rho_on_u_face * wbar_xf * (U_hi - U_lo) * dzInv;
595 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
599 Real z_yf_lo =
fourth * ( z_nd_arr(i,j,k ) + z_nd_arr(i+1,j,k )
600 + z_nd_arr(i,j,k-1) + z_nd_arr(i+1,j,k-1) );
601 Real z_yf_hi =
fourth * ( z_nd_arr(i,j,k+1) + z_nd_arr(i+1,j,k+1)
602 + z_nd_arr(i,j,k+2) + z_nd_arr(i+1,j,k+2) );
603 dzInv =
one / (z_yf_hi - z_yf_lo);
605 Real rho_on_v_face =
myhalf * ( cell_data(i,j,k,
nr) + cell_data(i,j-1,k,
nr) );
606 Real V_hi = dptr_v_plane(k+1) / dptr_r_plane(k+1);
607 Real V_lo = dptr_v_plane(k-1) / dptr_r_plane(k-1);
608 Real wbar_yf =
myhalf * (dptr_wbar_sub[k] + dptr_wbar_sub[k+1]);
609 ymom_src_arr(i, j, k) -= rho_on_v_face * wbar_yf * (V_hi - V_lo) * dzInv;
616 auto lsf_arr = lsf_tendencies->const_array(mfi);
618 const int kmin = domain.smallEnd(2) + 1;
619 const int kmax = domain.bigEnd(2) - 1;
621 ParallelFor(tbx, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
623 if (k >= kmin && k <= kmax) {
625 if (lsf_arr(i, j, k, 2) >= 0.0)
638 + z_nd_arr(i,j,
k1+1) + z_nd_arr(i,j+1,
k1+1) );
639 Real z_uf_2 =
fourth * ( z_nd_arr(i,j,k2 ) + z_nd_arr(i,j+1,k2 )
640 + z_nd_arr(i,j,k2+1) + z_nd_arr(i,j+1,k2+1) );
641 dzInv =
one / (z_uf_1 - z_uf_2);
644 amrex::Real utend = -(dzInv * lsf_arr(i, j, k, 2)) * ( u(i, j,
k1) - u(i, j, k2) );
645 xmom_src_arr(i, j, k) += utend * rho_on_u_face;
649 ParallelFor(tby, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
651 if (k >= kmin && k <= kmax) {
653 if (lsf_arr(i, j, k, 2) >= 0.0)
666 + z_nd_arr(i,j,
k1+1) + z_nd_arr(i+1,j,
k1+1) );
667 Real z_vf_2 =
fourth * ( z_nd_arr(i,j,k2 ) + z_nd_arr(i+1,j,k2 )
668 + z_nd_arr(i,j,k2+1) + z_nd_arr(i+1,j,k2+1) );
669 dzInv =
one / (z_vf_1 - z_vf_2);
672 amrex::Real vtend = -(dzInv * lsf_arr(i, j, k, 2)) * ( v(i, j,
k1) - v(i, j, k2) );
673 ymom_src_arr(i, j, k) += vtend * rho_on_v_face;
691 Real uv_coeff_n = 1.0;
692 Real uv_coeff_np1 = 0.0;
694 const Real *u_nudge_n, *u_nudge_np1, *v_nudge_n, *v_nudge_np1;
701 for (
int nt = 1; nt < n_sounding_times; nt++) {
704 if (itime_n == n_sounding_times-1) {
707 itime_np1 = itime_n+1;
710 uv_coeff_n =
Real(1.0) - uv_coeff_np1;
712 u_nudge_n = input_sounding_data.
U_inp_sound_d[itime_n].dataPtr() + 1;
713 u_nudge_np1 = input_sounding_data.
U_inp_sound_d[itime_np1].dataPtr() + 1;
714 v_nudge_n = input_sounding_data.
V_inp_sound_d[itime_n].dataPtr() + 1;
715 v_nudge_np1 = input_sounding_data.
V_inp_sound_d[itime_np1].dataPtr() + 1;
724 u_nudge_n = lsf_data.
u_int_lsf_d[itime_curr].dataPtr();
725 u_nudge_np1 = lsf_data.
u_int_lsf_d[itime_next].dataPtr();
726 v_nudge_n = lsf_data.
v_int_lsf_d[itime_curr].dataPtr();
727 v_nudge_np1 = lsf_data.
v_int_lsf_d[itime_next].dataPtr();
730 ParallelFor(tbx, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
732 Real z = z_cc_arr(i,j,k);
733 if (l_lsf || (z >= u_z1 && z <= u_z2)) {
734 Real unudge = -((dptr_u_plane(k)/dptr_r_plane(k)) - (uv_coeff_n*u_nudge_n[k] + uv_coeff_np1*u_nudge_np1[k]));
735 xmom_src_arr(i, j, k) += tau * unudge * dptr_r_plane(k);
739 ParallelFor(tby, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept
741 Real z = z_cc_arr(i,j,k);
742 if (l_lsf || (z >= u_z1 && z <= u_z2)) {
743 Real vnudge = -((dptr_v_plane(k)/dptr_r_plane(k)) - (uv_coeff_n*v_nudge_n[k] + uv_coeff_np1*v_nudge_np1[k]));
744 ymom_src_arr(i, j, k) += tau * vnudge * dptr_r_plane(k);
754 const Array4<const Real>& mf_ux = mapfac[MapFac::ux]->const_array(mfi);
755 const Array4<const Real>& mf_uy = mapfac[MapFac::uy]->const_array(mfi);
756 const Array4<const Real>& mf_vx = mapfac[MapFac::vx]->const_array(mfi);
757 const Array4<const Real>& mf_vy = mapfac[MapFac::vy]->const_array(mfi);
759 u, cell_data, xmom_src_arr, mf_ux, mf_uy);
761 v, cell_data, ymom_src_arr, mf_vx, mf_vy);
772 z_cc_arr, xmom_src_arr, ymom_src_arr,
773 rho_u, rho_v, d_sponge_ptrs_at_lev);
778 xmom_src_arr, ymom_src_arr, zmom_src_arr, rho_u, rho_v, rho_w,
779 r0, z_nd_arr, z_cc_arr);
784 const Array4<const Real>& rho_u_forecast_state = (*forecast_state_at_lev)[
IntVars::xmom].array(mfi);
785 const Array4<const Real>& rho_v_forecast_state = (*forecast_state_at_lev)[
IntVars::ymom].array(mfi);
786 const Array4<const Real>& rho_w_forecast_state = (*forecast_state_at_lev)[
IntVars::zmom].array(mfi);
787 const Array4<const Real>& cons_forecast_state = (*forecast_state_at_lev)[
IntVars::cons].array(mfi);
789 xmom_src_arr, ymom_src_arr, zmom_src_arr,
791 rho_u_forecast_state, rho_v_forecast_state, rho_w_forecast_state,
792 cons_forecast_state);
805 ((is_slow_step && !use_canopy_fast) || (!is_slow_step && use_canopy_fast))) {
807 [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
809 const Real ux = u(i, j, k);
810 const Real uy =
fourth * ( v(i, j , k ) + v(i-1, j , k )
811 + v(i, j+1, k ) + v(i-1, j+1, k ) );
812 const Real uz =
fourth * (
w(i, j , k ) +
w(i-1, j , k )
813 +
w(i, j , k+1) +
w(i-1, j , k+1) );
814 const Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
815 const Real f_drag =
myhalf * (f_drag_arr(i, j, k) + f_drag_arr(i-1, j, k));
817 xmom_src_arr(i, j, k) -= rho_on_u_face * f_drag * ux * windspeed;
819 [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
821 const Real ux =
fourth * ( u(i , j , k ) + u(i , j-1, k )
822 + u(i+1, j , k ) + u(i+1, j-1, k ) );
823 const Real uy = v(i, j, k);
824 const Real uz =
fourth * (
w(i , j , k ) +
w(i , j-1, k )
825 +
w(i , j , k+1) +
w(i , j-1, k+1) );
826 const amrex::Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
827 const Real f_drag =
myhalf * (f_drag_arr(i, j, k) + f_drag_arr(i, j-1, k));
829 ymom_src_arr(i, j, k) -= rho_on_v_face * f_drag * uy * windspeed;
831 [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
834 + u(i , j , k-1) + u(i+1, j , k-1) );
836 + v(i , j , k-1) + v(i , j+1, k-1) );
838 const amrex::Real windspeed = std::sqrt(ux * ux + uy * uy + uz * uz);
839 const Real f_drag =
myhalf * (f_drag_arr(i, j, k) + f_drag_arr(i, j, k-1));
841 zmom_src_arr(i, j, k) -= rho_on_w_face * f_drag * uz * windspeed;
847 if (solverChoice.
terrain_type == TerrainType::ImmersedForcing &&
848 ((is_slow_step && !use_ImmersedForcing_fast) || (!is_slow_step && use_ImmersedForcing_fast))) {
852 xmom_src_arr, geom, solverChoice, dt, time);
854 ymom_src_arr, geom, solverChoice, dt, time);
857 z_cc_arr, xmom_src_arr, geom, solverChoice, dt);
859 z_cc_arr, ymom_src_arr, geom, solverChoice, dt);
862 z_cc_arr, zmom_src_arr, geom, solverChoice, dt);
869 ((is_slow_step && !use_ImmersedForcing_fast) || (!is_slow_step && use_ImmersedForcing_fast))) {
872 z_cc_arr, xmom_src_arr, geom, solverChoice, dt);
874 z_cc_arr, ymom_src_arr, geom, solverChoice, dt);
876 z_cc_arr, zmom_src_arr, geom, solverChoice, dt);
882 if (is_slow_step && (enforce_massflux_x || enforce_massflux_y)) {
889 constexpr
Real tiny_area = std::numeric_limits<Real>::min();
890 Real dRUA = (massflux_area_x >
zero) ? (rhoUA_target - rhoUA) / amrex::max(massflux_area_x, tiny_area) :
zero;
891 Real dRVA = (massflux_area_y >
zero) ? (rhoVA_target - rhoVA) / amrex::max(massflux_area_y, tiny_area) :
zero;
895 if (enforce_massflux_x) {
896 ParallelFor(tbx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept {
897 xmom_src_arr(i, j, k) += tau_inv * dRUA;
900 if (enforce_massflux_y) {
901 ParallelFor(tby, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept {
902 ymom_src_arr(i, j, k) += tau_inv * dRVA;
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)
Apply sponge zone damping to momentum variables.
Definition: ERF_ApplySpongeZoneBCs.cpp:211
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:23
@ ubar
Definition: ERF_DataStruct.H:207
@ wbar
Definition: ERF_DataStruct.H:207
@ vbar
Definition: ERF_DataStruct.H:207
DirectionSelector< 2 > ZDir
Definition: ERF_DirectionSelector.H:55
void ImmersedForcingBuildings_Ymom(const Box &tby, const Array4< const Real > &u, const Array4< const Real > &v, const Array4< const Real > &w, const Array4< const Real > &cell_data, const Array4< const Real > &t_blank_arr, const Array4< const Real > &t_blank_yface_arr, const Array4< const Real > &z_cc_arr, const Array4< Real > &ymom_src_arr, const Geometry &geom, const SolverChoice &solverChoice, const Real fac)
Definition: ERF_ImmersedForcing.cpp:823
void ImmersedForcingTerrain_Xmom_FractionStress(const Box &tbx, const Array4< const Real > &u, const Array4< const Real > &v, const Array4< const Real > &w, const Array4< const Real > &cell_data, const Array4< const Real > &t_blank_arr, const Array4< const Real > &t_blank_xface_arr, const Array4< Real > &xmom_src_arr, const Geometry &geom, const SolverChoice &solverChoice, const Real fac, const Real time)
Definition: ERF_ImmersedForcing.cpp:454
void ImmersedForcingTerrain_Ymom(const Box &tby, const Array4< const Real > &u, const Array4< const Real > &v, const Array4< const Real > &w, const Array4< const Real > &cell_data, const Array4< const Real > &t_blank_arr, const Array4< const Real > &t_blank_yface_arr, const Array4< const Real > &z_cc_arr, const Array4< Real > &ymom_src_arr, const Geometry &geom, const SolverChoice &solverChoice, const Real fac)
Definition: ERF_ImmersedForcing.cpp:203
void ImmersedForcingTerrain_Ymom_FractionStress(const Box &tby, const Array4< const Real > &u, const Array4< const Real > &v, const Array4< const Real > &w, const Array4< const Real > &cell_data, const Array4< const Real > &t_blank_arr, const Array4< const Real > &t_blank_yface_arr, const Array4< Real > &ymom_src_arr, const Geometry &geom, const SolverChoice &solverChoice, const Real fac, const Real time)
Definition: ERF_ImmersedForcing.cpp:471
void ImmersedForcingBuildings_Xmom(const Box &tbx, const Array4< const Real > &u, const Array4< const Real > &v, const Array4< const Real > &w, const Array4< const Real > &cell_data, const Array4< const Real > &t_blank_arr, const Array4< const Real > &t_blank_xface_arr, const Array4< const Real > &z_cc_arr, const Array4< Real > &xmom_src_arr, const Geometry &geom, const SolverChoice &solverChoice, const Real fac)
Definition: ERF_ImmersedForcing.cpp:630
void ImmersedForcingTerrain_Xmom(const Box &tbx, const Array4< const Real > &u, const Array4< const Real > &v, const Array4< const Real > &w, const Array4< const Real > &cell_data, const Array4< const Real > &t_blank_arr, const Array4< const Real > &t_blank_xface_arr, const Array4< const Real > &z_cc_arr, const Array4< Real > &xmom_src_arr, const Geometry &geom, const SolverChoice &solverChoice, const Real fac)
Definition: ERF_ImmersedForcing.cpp:81
void ImmersedForcingBuildings_Zmom(const Box &tbz, const Array4< const Real > &u, const Array4< const Real > &v, const Array4< const Real > &w, const Array4< const Real > &cell_data, const Array4< const Real > &t_blank_arr, const Array4< const Real > &t_blank_zface_arr, const Array4< const Real > &z_cc_arr, const Array4< Real > &zmom_src_arr, const Geometry &geom, const SolverChoice &solverChoice, const Real fac)
Definition: ERF_ImmersedForcing.cpp:1014
void ImmersedForcingTerrain_Zmom(const Box &tbz, const Array4< const Real > &u, const Array4< const Real > &v, const Array4< const Real > &w, const Array4< const Real > &cell_data, const Array4< const Real > &t_blank_arr, const Array4< const Real > &t_blank_zface_arr, const Array4< const Real > &z_cc_arr, const Array4< Real > &zmom_src_arr, const Geometry &geom, const SolverChoice &solverChoice, const Real fac)
Definition: ERF_ImmersedForcing.cpp:573
#define Rho_comp
Definition: ERF_IndexDefines.H:53
amrex::GpuArray< Real, AMREX_SPACEDIM > dxInv
Definition: ERF_InitCustomPertVels_ParticleTests.H:17
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(axis >=0 &&axis< AMREX_SPACEDIM, "prob.axis must be 0, 1 or 2")
Real H
Definition: ERF_InitCustomPert_MovingTerrain.H:8
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);})
constexpr amrex::Real one
Definition: ERF_NumericalConstants.H:37
constexpr amrex::Real fourth
Definition: ERF_NumericalConstants.H:42
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:36
constexpr amrex::Real myhalf
Definition: ERF_NumericalConstants.H:41
constexpr amrex::Real PI
Definition: ERF_NumericalConstants.H:46
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:23
AMREX_FORCE_INLINE IntVect offset(const int face_dir, const int normal)
Definition: ERF_ReadBndryPlanes.cpp:36
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_PlaneAverage.H:14
amrex::EBFArrayBoxFactory const * get_w_const_factory() const noexcept
Return the native AMReX z-face EB factory.
Definition: ERF_EB.H:148
amrex::EBFArrayBoxFactory const * get_u_const_factory() const noexcept
Return the native AMReX x-face EB factory.
Definition: ERF_EB.H:144
amrex::EBFArrayBoxFactory const * get_v_const_factory() const noexcept
Return the native AMReX y-face EB factory.
Definition: ERF_EB.H:146
@ r0_comp
Definition: ERF_IndexDefines.H:97
@ ymom
Definition: ERF_IndexDefines.H:274
@ cons
Definition: ERF_IndexDefines.H:272
@ zmom
Definition: ERF_IndexDefines.H:275
@ xmom
Definition: ERF_IndexDefines.H:273
@ nr
Definition: ERF_Morrison.H:48
@ xvel
Definition: ERF_IndexDefines.H:255
@ cons
Definition: ERF_IndexDefines.H:254
@ yvel
Definition: ERF_IndexDefines.H:256
@ ww
Definition: ERF_AdvanceWSM6.cpp:107
real(c_double), private k1
Definition: ERF_module_mp_morr_two_moment.F90:213
real(kind=kind_phys), parameter, private r0
Definition: ERF_module_mp_wdm6.F90:75
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
void get_forcing_time_coeffs(const amrex::Real &time, int &curr, int &next, amrex::Real &coeff_curr, amrex::Real &coeff_next) const
Determine interpolation coefficients to apply tendencies for the given time.
Definition: ERF_LargeScaleForcingData.H:337
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > v_int_lsf_d
Definition: ERF_LargeScaleForcingData.H:459
amrex::Real tau_lsf
Definition: ERF_LargeScaleForcingData.H:409
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > u_int_lsf_d
Definition: ERF_LargeScaleForcingData.H:459
amrex::Real const_massflux_v
Target constant mass flux in the y direction.
Definition: ERF_DataStruct.H:3044
static InitType init_type
Initial-condition source selected for the run.
Definition: ERF_DataStruct.H:2583
amrex::Real coriolis_factor
Twice the planetary rotation rate used for Coriolis forcing.
Definition: ERF_DataStruct.H:2745
static bool flat_terrain
Permit fixed-index planar averages after validating a flat fitted mesh.
Definition: ERF_DataStruct.H:2592
bool if_fraction_stress
erf.if_wall_form = fraction_stress: the wall stress of ERF_ImmersedWallCell.H in the wall cell of eac...
Definition: ERF_DataStruct.H:2714
bool variable_coriolis
Whether spatially varying Coriolis forcing is enabled.
Definition: ERF_DataStruct.H:2988
int ave_plane
Averaging plane index used by diagnostics.
Definition: ERF_DataStruct.H:2990
amrex::Real const_massflux_u
Target constant mass flux in the x direction.
Definition: ERF_DataStruct.H:3043
bool use_building_immersed_forcing(const amrex::Geometry &geom) const noexcept
Definition: ERF_DataStruct.H:2808
bool forest_substep
Whether canopy source terms are applied only during substeps.
Definition: ERF_DataStruct.H:2696
amrex::Real num_diff_coeff
Numerical diffusion coefficient after input scaling.
Definition: ERF_DataStruct.H:2939
bool hindcast_lateral_forcing
Whether hindcast lateral forcing is enabled.
Definition: ERF_DataStruct.H:3053
amrex::Real nudging_u_z2
Definition: ERF_DataStruct.H:2769
bool use_coriolis
Whether Coriolis forcing is enabled.
Definition: ERF_DataStruct.H:2689
static MeshType mesh_type
Vertical mesh representation.
Definition: ERF_DataStruct.H:2604
SpongeChoice spongeChoice
Sponge-layer options.
Definition: ERF_DataStruct.H:2619
bool have_geo_wind_profile
Whether a geostrophic wind profile has been configured.
Definition: ERF_DataStruct.H:2986
DampingChoice dampingChoice
Damping-related options.
Definition: ERF_DataStruct.H:2618
amrex::Real nudging_u_z1
Definition: ERF_DataStruct.H:2768
bool do_forest_drag
Whether forest canopy drag is enabled.
Definition: ERF_DataStruct.H:3033
int massflux_khi
Upper vertical index for constant-mass-flux forcing.
Definition: ERF_DataStruct.H:3049
bool large_scale_forcing
Definition: ERF_DataStruct.H:2779
static TerrainType terrain_type
Terrain or immersed-boundary representation.
Definition: ERF_DataStruct.H:2589
amrex::Real cosphi
Cosine of the latitude used for Coriolis forcing.
Definition: ERF_DataStruct.H:2746
int massflux_klo
Lower vertical index for constant-mass-flux forcing.
Definition: ERF_DataStruct.H:3048
amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > abl_geo_forcing
Applied geostrophic-wind forcing vector.
Definition: ERF_DataStruct.H:2984
bool custom_w_subsidence
Whether custom vertical subsidence is enabled.
Definition: ERF_DataStruct.H:2752
bool immersed_forcing_substep
Whether immersed-forcing source terms are applied only during substeps.
Definition: ERF_DataStruct.H:2695
amrex::Real const_massflux_tau
Relaxation time scale for constant-mass-flux forcing.
Definition: ERF_DataStruct.H:3045
amrex::Real sinphi
Sine of the latitude used for Coriolis forcing.
Definition: ERF_DataStruct.H:2747
bool do_mom_advection
Whether custom vertical subsidence is applied to momentum.
Definition: ERF_DataStruct.H:2754
bool nudging_u
Definition: ERF_DataStruct.H:2775
bool nudging_from_input_sounding
Whether solution fields are nudged toward input sounding data.
Definition: ERF_DataStruct.H:2762
static SpongeType sponge_type
Selected sponge damping model.
Definition: ERF_SpongeStruct.H:100