92 int klo = geom.Domain().smallEnd(2);
93 int khi = geom.Domain().bigEnd(2);
94 const int izmin = klo;
95 const int izmax =
khi;
97 const Real dz = geom.CellSize(2);
98 const Real dz_inv = geom.InvCellSize(2);
99 const auto&
dxInv = geom.InvCellSizeArray();
102 #pragma omp parallel if (Gpu::notInLaunchRegion())
104 for (MFIter mfi(eddyViscosity,
TileNoZ()); mfi.isValid(); ++mfi) {
107 const Box& gbx = mfi.growntilebox(IntVect(1,1,0));
109 gbx.bigEnd(2) ==
khi );
127 const Box xybx = PerpendicularBox<ZDir>(gbx, IntVect{0, 0, 0});
128 FArrayBox pbl_height_corrector(xybx, 1, The_Async_Arena());
129 IArrayBox pbl_index(xybx, 1, The_Async_Arena());
130 IArrayBox pbl_index_zero_ri(xybx, 1, The_Async_Arena());
131 FArrayBox hgamt_fab(xybx, 1, The_Async_Arena());
132 FArrayBox hgamq_fab(xybx, 1, The_Async_Arena());
133 FArrayBox hgamu_fab(xybx, 1, The_Async_Arena());
134 FArrayBox hgamv_fab(xybx, 1, The_Async_Arena());
135 FArrayBox wstar_fab(xybx, 1, The_Async_Arena());
136 FArrayBox vpert_fab(xybx, 1, The_Async_Arena());
137 FArrayBox entr_fab(xybx, 1, The_Async_Arena());
138 IArrayBox cloud_top_fab(xybx, 1, The_Async_Arena());
139 FArrayBox wstar3_down_fab(xybx, 1, The_Async_Arena());
140 FArrayBox sflux_fab(xybx, 1, The_Async_Arena());
141 FArrayBox wstar3_fab(xybx, 1, The_Async_Arena());
142 FArrayBox zol1_fab(xybx, 1, The_Async_Arena());
143 FArrayBox sfcflg_fab(xybx, 1, The_Async_Arena());
147 vpert_fab.setVal<RunOn::Device>(
zero);
148 sflux_fab.setVal<RunOn::Device>(
zero);
149 wstar3_fab.setVal<RunOn::Device>(
zero);
150 wstar3_down_fab.setVal<RunOn::Device>(
zero);
151 sfcflg_fab.setVal<RunOn::Device>(
zero);
152 hgamt_fab.setVal<RunOn::Device>(
zero);
153 hgamq_fab.setVal<RunOn::Device>(
zero);
154 hgamu_fab.setVal<RunOn::Device>(
zero);
155 hgamv_fab.setVal<RunOn::Device>(
zero);
156 wstar_fab.setVal<RunOn::Device>(
zero);
157 entr_fab.setVal<RunOn::Device>(
zero);
158 pbl_height_corrector.setVal<RunOn::Device>(
zero);
159 const auto& pblh_corr_arr = pbl_height_corrector.array();
160 const auto& pbli_arr = pbl_index.array();
161 const auto& pbli_zero_arr = pbl_index_zero_ri.array();
162 const auto& hgamt_arr = hgamt_fab.array();
163 const auto& hgamq_arr = hgamq_fab.array();
164 const auto& hgamu_arr = hgamu_fab.array();
165 const auto& hgamv_arr = hgamv_fab.array();
166 const auto& wstar_arr = wstar_fab.array();
167 const auto& vpert_arr = vpert_fab.array();
168 const auto& entr_arr = entr_fab.array();
169 const auto& cloud_top_arr = cloud_top_fab.array();
170 const auto& wstar3_down_arr = wstar3_down_fab.array();
171 const auto& sflux_arr = sflux_fab.array();
172 const auto& wstar3_arr = wstar3_fab.array();
173 const auto& zol1_arr = zol1_fab.array();
174 const auto& sfcflg_arr = sfcflg_fab.array();
177 const auto& cell_data = cons_in.const_array(mfi);
178 const auto& uvel =
xvel.const_array(mfi);
179 const auto& vvel =
yvel.const_array(mfi);
183 const auto& u_star_arr = SurfLayer->get_u_star(level)->const_array(mfi);
184 const auto& t_star_arr = SurfLayer->get_t_star(level)->const_array(mfi);
185 const auto& q_star_arr = SurfLayer->get_q_star(level)->const_array(mfi);
186 const auto& l_obuk_arr = SurfLayer->get_olen(level)->const_array(mfi);
187 const auto& t10av_arr = SurfLayer->get_mac_avg(level, 2)->const_array(mfi);
188 const auto& q10av_arr = SurfLayer->get_mac_avg(level, 3)->const_array(mfi);
189 const auto& ws10av_arr = SurfLayer->get_mac_avg(level, 5)->const_array(mfi);
190 const auto& z0_arr = SurfLayer->get_z0(level)->const_array(mfi);
193 const auto& lmask_arr = (SurfLayer->get_lmask(level)) ?
194 SurfLayer->get_lmask(level)->const_array(mfi) :
196 const Array4<Real const> z_nd_arr = z_phys_nd->array(mfi);
199 const Array4<Real const> qheat_arr = (qheating_rates !=
nullptr)
200 ? qheating_rates->const_array(mfi)
201 : Array4<Real const>{};
202 const bool has_qheating_rates = (qheating_rates !=
nullptr);
214 FArrayBox rib_base_fab(gbx, 1, The_Async_Arena());
215 FArrayBox rib_enhan_fab(gbx, 1, The_Async_Arena());
216 const auto& rib_base_arr = rib_base_fab.array();
217 const auto& rib_enhan_arr = rib_enhan_fab.array();
219 BL_PROFILE_VAR(
"YSUNew_Rib_Precompute", prof_rib_precomp);
220 ParallelFor(gbx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
226 const amrex::Real t_enh = t_layer_v + vpert_arr(i,j,0);
227 const amrex::Real z_sfc = (use_terrain_fitted_coords)
229 const amrex::Real zval = (use_terrain_fitted_coords)
234 ?
GetThetavl(i,j,k,cell_data,moisture_indices)
235 :
GetThetav(i,j,k,cell_data,moisture_indices);
237 ?
GetThetavl(i,j,klo,cell_data,moisture_indices)
238 :
GetThetav(i,j,klo,cell_data,moisture_indices);
239 const amrex::Real ws2_raw =
fourth * ((uvel(i,j,k)+uvel(i+1,j,k))*(uvel(i,j,k)+uvel(i+1,j,k))
240 + (vvel(i,j,k)+vvel(i,j+1,k))*(vvel(i,j,k)+vvel(i,j+1,k)));
242 rib_base_arr(i,j,k) =
CONST_GRAV * zrel * (theta_v - t_layer_v) / (ws2 * theta_v_klo);
243 rib_enhan_arr(i,j,k) =
CONST_GRAV * zrel * (theta_v - t_enh) / (ws2 * theta_v_klo);
245 BL_PROFILE_VAR_STOP(prof_rib_precomp);
258 BL_PROFILE_VAR(
"YSUNew_SurfFlux_Precompute", prof_sflux_precomp);
259 ParallelFor(xybx, [=, zero_d=
zero] AMREX_GPU_DEVICE(
int i,
int j,
int) noexcept
262 const Real t_layer = t10av_arr(i, j, 0);
265 const Real rhox = rho_sfc;
275 const Real ustar = u_star_arr(i, j, 0);
276 const Real tstar = t_star_arr(i, j, 0);
278 const Real hfx = -rhox * cp_air * ustar * tstar;
279 const Real qfx = -rhox * ustar * qstar;
280 const Real sflux = hfx / (rhox * cp_air) + qfx / rhox * ep1 * t_layer;
281 sflux_arr(i, j, 0) = sflux;
286 const bool sfcflg = (sflux >
zero);
287 sfcflg_arr(i, j, 0) = sfcflg ?
one :
zero;
296 const Real bfx0 = amrex::max(sflux, zero_d);
297 const Real wstar3 = govrth * bfx0 * pblh_guess;
298 wstar3_arr(i, j, 0) = wstar3;
303 const Real ust3 = ustar * ustar * ustar;
306 wscale = amrex::min(wscale, ustar *
amrex::Real(16.0));
307 wscale = amrex::max(wscale, ustar /
amrex::Real(5.0));
308 wstar_arr(i, j, 0) = wscale;
313 Real obuk_val = l_obuk_arr(i, j, 0);
316 const Real zl1 = (use_terrain_fitted_coords)
319 Real zol1 = zl1 / obuk_val;
326 zol1_arr(i, j, 0) = zol1;
328 BL_PROFILE_VAR_STOP(prof_sflux_precomp);
340 BL_PROFILE_VAR(
"YSUNew_PBLH_Passes", prof_pblh);
341 ParallelFor(xybx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int) noexcept
347 bool over_land = (!lmask_arr) || (lmask_arr(i, j, 0) == 1);
351 const Real z0 = z0_arr(i, j, 0);
352 const Real ws_layer = ws10av_arr(i, j, 0);
354 Ribcr = amrex::min(
Real(0.16) * std::pow(
Real(1.0e-7) * Rossby, -
Real(0.18)),
Real(0.3));
362 Real Rib = rib_base_arr(i,j,klo);
363 bool above_critical = (Rib >= Ribcr);
366 for (
int kk = klo+1; !above_critical && kk <=
khi; ++kk) {
367 if (rib_base_arr(i,j,kk) >= Ribcr) {
369 above_critical =
true;
374 pbli_arr(i, j, 0) = kpbl;
376 BL_PROFILE_VAR_STOP(prof_pblh);
461 constexpr
Real GAMCRQ =
Real(2.e-3);
464 ParallelFor(xybx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int) noexcept
470 bool over_land = (!lmask_arr) || (lmask_arr(i, j, 0) == 1);
474 const Real z0 = z0_arr(i, j, 0);
475 const Real ws_layer = ws10av_arr(i, j, 0);
477 Ribcr = amrex::min(
Real(0.16) * std::pow(
Real(1.0e-7) * Rossby, -
Real(0.18)),
Real(0.3));
487 const amrex::Real z_sfc_col = (use_terrain_fitted_coords)
495 Real Rib = rib_enhan_arr(i,j,klo);
496 zval0 = (use_terrain_fitted_coords)
500 bool above_critical = (Rib >= Ribcr);
503 for (
int kk = klo+1; !above_critical && kk <=
khi; ++kk) {
504 if (rib_enhan_arr(i,j,kk) >= Ribcr) { kpbl = kk; above_critical =
true;
break; }
505 zval0 = (use_terrain_fitted_coords)
508 Rib0 = rib_enhan_arr(i,j,kk);
513 const Real z_sfc = (use_terrain_fitted_coords)
516 const Real dz_terrain = (use_terrain_fitted_coords)
519 const Real z_max = (use_terrain_fitted_coords)
522 const Real pblh_max =
Real(0.9) * z_max;
528 pblh_min = amrex::max(z_sfc_col +
Real(0.5)*dz0,
Real(10.0));
530 pblh_min = amrex::max(z_sfc +
Real(0.5) * dz_terrain,
Real(10.0));
534 if (kpbl <
khi && rib_enhan_arr(i,j,kpbl) >= Ribcr) {
535 const Real zval = (use_terrain_fitted_coords)
538 Rib = rib_enhan_arr(i,j,kpbl);
539 Real pblh_interp = zval0 + (zval - zval0) / (Rib - Rib0) * (Ribcr - Rib0);
540 pblh_corr_arr(i, j, 0) = amrex::max(amrex::min(pblh_interp, pblh_max), pblh_min);
542 pblh_corr_arr(i, j, 0) = pblh_min;
544 pbli_arr(i, j, 0) = kpbl;
547 hgamt_arr(i, j, 0) =
zero;
548 hgamq_arr(i, j, 0) =
zero;
549 wstar_arr(i, j, 0) =
zero;
593 ParallelFor(xybx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int) noexcept
595 cloud_top_arr(i, j, 0) = -1;
598 int kpbl = pbli_arr(i, j, 0);
599 for (
int kk = kpbl - 1; kk >= klo; --kk) {
601 if (moisture_indices.
qc >= 0)
602 qc_kk = cell_data(i, j, kk, moisture_indices.
qc) / cell_data(i, j, kk,
Rho_comp);
603 if (moisture_indices.
qi >= 0)
604 qi_kk = cell_data(i, j, kk, moisture_indices.
qi) / cell_data(i, j, kk,
Rho_comp);
606 if (qc_kk + qi_kk > ysu_qcloud_threshold) {
607 cloud_top_arr(i, j, 0) = kk;
614 ParallelFor(xybx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int) noexcept
616 cloud_top_arr(i, j, 0) = -1;
622 const Real t_layer = t10av_arr(i, j, 0);
623 Real obuk_val = l_obuk_arr(i, j, 0);
632 const Real HOL = sf * pblh_corr_arr(i, j, 0) / obuk_val;
633 const Real HOL_bounded = amrex::max(amrex::min(HOL,
Real(100.0)),
Real(-100.0));
635 const Real phiM = (obuk_val > 0)
636 ? (1 + 5 * HOL_bounded)
638 amrex::max(1 - 16 * HOL_bounded,
Real(0.01)),
640 const Real phiM_safe = amrex::max(phiM,
Real(0.01));
646 Real wscale = u_star_arr(i, j, 0) / phiM_safe;
647 wscale = amrex::max(wscale, u_star_arr(i, j, 0) /
Real(5.0));
648 wscale = amrex::min(wscale,
Real(16.0) * u_star_arr(i, j, 0));
653 if (enable_ysu_topdown && cloud_top_arr(i, j, 0) >= klo) {
654 int k_cloud_top = cloud_top_arr(i, j, 0);
662 if (has_qheating_rates) {
665 for (
int kk = klo; kk <= k_cloud_top; ++kk) {
667 ? (z_nd_arr(i, j, kk+1) - z_nd_arr(i, j, kk))
671 LRAD += -qheat_arr(i, j, kk, 1) * ldz;
678 / cell_data(i, j, k_cloud_top,
Rho_comp);
680 wstar3_down = amrex::max(CONST_GRAV_d / t_local * LRAD
682 * pblh_corr_arr(i, j, 0), zero_d);
684 wstar3_down_arr(i, j, 0) = wstar3_down;
687 const Real bfx0_corr = amrex::max(sflux_arr(i, j, 0), zero_d);
688 const Real t_dry = t10av_arr(i, j, 0);
689 const Real wstar3_corr = (
CONST_GRAV / t_dry) * bfx0_corr * pblh_corr_arr(i, j, 0);
690 wstar3_arr(i, j, 0) = wstar3_corr;
693 const Real ust3 = u_star_arr(i,j,0) * u_star_arr(i,j,0) * u_star_arr(i,j,0);
695 wscale_corr = amrex::min(wscale_corr, u_star_arr(i,j,0) *
amrex::Real(16.0));
696 wscale_corr = amrex::max(wscale_corr, u_star_arr(i,j,0) /
amrex::Real(5.0));
697 wstar_arr(i, j, 0) = wscale_corr;
703 bool SFCFLG = (sfcflg_arr(i, j, 0) >
zero);
705 const Real hfx_col = -rho_sfc *
amrex::Real(1004.0) * u_star_arr(i,j,0) * t_star_arr(i,j,0);
706 const Real gamfac = const_b / (rho_sfc * wscale_corr);
707 const Real HGAMT = (SFCFLG && enable_ysu_countergradient)
708 ? amrex::min(gamfac * hfx_col /
amrex::Real(1004.0), GAMCRT)
713 const Real qfx_col = -rho_sfc * u_star_arr(i,j,0) * q_star_arr(i,j,0);
714 const Real HGAMQ_raw = (SFCFLG &&
use_moisture && enable_ysu_countergradient)
717 Real HGAMQ = amrex::min(amrex::max(HGAMQ_raw, zero_d), GAMCRQ);
720 if (lmask_arr && SFCFLG &&
use_moisture && enable_ysu_countergradient) {
721 bool is_land = (lmask_arr(i,j,0) == 1);
722 if (!is_land) HGAMQ =
zero;
726 if (enable_ysu_sat_limiter && moisture_indices.
qv >= 0 && SFCFLG &&
use_moisture && enable_ysu_countergradient) {
727 Real qv_klo = cell_data(i, j, klo, moisture_indices.
qv) / cell_data(i, j, klo,
Rho_comp);
734 Real rh_klo = (qsat_klo >
Real(1.0e-10)) ? (qv_klo / qsat_klo) :
zero;
735 if (rh_klo >
Real(0.95)) {
736 Real rh_scaling = amrex::max(zero_d, (
one - rh_klo) /
Real(0.05));
743 if (pbli_arr(i, j, 0) <= klo + 1) {
744 hgamt_arr(i, j, 0) =
zero;
745 hgamq_arr(i, j, 0) =
zero;
746 hgamu_arr(i, j, 0) =
zero;
747 hgamv_arr(i, j, 0) =
zero;
748 vpert_arr(i, j, 0) =
zero;
750 const Real pblh = pblh_corr_arr(i, j, 0);
751 hgamt_arr(i, j, 0) = (enable_ysu_countergradient) ? HGAMT / pblh :
zero;
752 hgamq_arr(i, j, 0) = (enable_ysu_countergradient &&
use_moisture) ? HGAMQ / pblh :
zero;
758 hgamu_arr(i, j, 0) =
zero;
759 hgamv_arr(i, j, 0) =
zero;
760 if (SFCFLG && enable_ysu_countergradient) {
761 const Real wspd_sfc = ws10av_arr(i, j, 0);
762 const Real ustar = u_star_arr(i, j, 0);
763 wscale = wstar_arr(i, j, 0);
764 const Real wstar3 = wstar3_arr(i, j, 0);
766 const Real wscale4 = amrex::max(wscale * wscale * wscale * wscale,
773 const Real u_klo =
myhalf * (uvel(i, j, klo) + uvel(i+1, j, klo));
774 const Real v_klo =
myhalf * (vvel(i, j, klo) + vvel(i, j+1, klo));
775 hgamu_arr(i, j, 0) = brint * u_klo;
776 hgamv_arr(i, j, 0) = brint * v_klo;
785 if (enable_ysu_countergradient) {
788 const Real zl1_col = (use_terrain_fitted_coords)
792 const Real height_lim = amrex::min(zl1_col / (sfcfrac_h * pblh), one_d);
795 const Real VPERT_capped = enable_ysu_unbounded_vpert
797 : amrex::min(VPERT_raw, GAMCRT);
798 vpert_arr(i, j, 0) = amrex::max(VPERT_capped, zero_d) * height_lim;
800 vpert_arr(i, j, 0) =
zero;
818 BL_PROFILE_VAR(
"YSUNew_Rib_Recompute", prof_rib_recomp);
819 ParallelFor(gbx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
825 const amrex::Real t_enh = t_layer_v + vpert_arr(i,j,0);
826 const amrex::Real z_sfc = (use_terrain_fitted_coords)
828 const amrex::Real zval = (use_terrain_fitted_coords)
833 ?
GetThetavl(i,j,k,cell_data,moisture_indices)
834 :
GetThetav(i,j,k,cell_data,moisture_indices);
836 ?
GetThetavl(i,j,klo,cell_data,moisture_indices)
837 :
GetThetav(i,j,klo,cell_data,moisture_indices);
838 const amrex::Real ws2_raw =
fourth * ((uvel(i,j,k)+uvel(i+1,j,k))*(uvel(i,j,k)+uvel(i+1,j,k))
839 + (vvel(i,j,k)+vvel(i,j+1,k))*(vvel(i,j,k)+vvel(i,j+1,k)));
842 rib_enhan_arr(i,j,k) =
CONST_GRAV * zrel * (theta_v - t_enh) / (ws2 * theta_v_klo);
844 BL_PROFILE_VAR_STOP(prof_rib_recomp);
853 ParallelFor(xybx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int) noexcept
858 bool over_land = (!lmask_arr) || (lmask_arr(i, j, 0) == 1);
862 const Real z0 = z0_arr(i, j, 0);
863 const Real ws_layer = ws10av_arr(i, j, 0);
865 Ribcr = amrex::min(
Real(0.16) * std::pow(
Real(1.0e-7) * Rossby, -
Real(0.18)),
Real(0.3));
872 Real Rib = rib_enhan_arr(i,j,klo);
873 zval0 = (use_terrain_fitted_coords)
877 bool above_critical = (Rib >= Ribcr);
879 for (
int kk = klo+1; !above_critical && kk <=
khi; ++kk) {
880 if (rib_enhan_arr(i,j,kk) >= Ribcr) { kpbl = kk; above_critical =
true;
break; }
881 zval0 = (use_terrain_fitted_coords)
884 Rib0 = rib_enhan_arr(i,j,kk);
889 const Real z_sfc = (use_terrain_fitted_coords)
892 const Real dz_terrain = (use_terrain_fitted_coords)
895 const Real z_max = (use_terrain_fitted_coords)
898 const Real pblh_max =
Real(0.9) * z_max;
904 const amrex::Real z_sfc_col = (use_terrain_fitted_coords)
907 pblh_min = amrex::max(z_sfc_col +
Real(0.5)*dz0,
Real(10.0));
909 pblh_min = amrex::max(z_sfc +
Real(0.5) * dz_terrain,
Real(10.0));
913 if (kpbl <
khi && rib_enhan_arr(i,j,kpbl) >= Ribcr) {
914 const Real zval = (use_terrain_fitted_coords)
917 Rib = rib_enhan_arr(i,j,kpbl);
918 Real pblh_interp = zval0 + (zval - zval0) / (Rib - Rib0) * (Ribcr - Rib0);
919 pblh_corr_arr(i, j, 0) = amrex::max(amrex::min(pblh_interp, pblh_max), pblh_min);
921 pblh_corr_arr(i, j, 0) = pblh_min;
923 pbli_arr(i, j, 0) = kpbl;
934 ParallelFor(xybx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int) noexcept
936 const int kpblold = pbli_arr(i,j,0);
937 bool definebrup =
false;
940 const Real thermalli =
GetThetavl(i, j, klo, cell_data, moisture_indices);
943 for (
int kk = kpblold; kk <
khi; ++kk) {
945 const Real ws2_raw =
fourth * ((uvel(i,j,kk)+uvel(i+1,j,kk))*(uvel(i,j,kk)+uvel(i+1,j,kk))
946 + (vvel(i,j,kk)+vvel(i,j+1,kk))*(vvel(i,j,kk)+vvel(i,j+1,kk)));
950 const Real z_sfc = (use_terrain_fitted_coords)
953 const Real zval_kk = (use_terrain_fitted_coords)
959 const Real thlix_kk =
GetThetavl(i, j, kk, cell_data, moisture_indices);
960 const Real thlix_klo =
GetThetavl(i, j, klo, cell_data, moisture_indices);
963 const Real bruptmp =
CONST_GRAV * zrel_kk * (thlix_kk - thermalli) / (ws2 * thlix_klo);
966 const bool stable = (bruptmp >=
zero);
969 pbli_arr(i,j,0) = kk;
980 pbli_arr(i,j,0) = amrex::min(pbli_arr(i,j,0), izmax);
1007 ParallelFor(xybx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int) noexcept
1011 int kpbl_zero = klo;
1012 Real Rib = rib_enhan_arr(i,j,klo);
1013 bool above_critical = (Rib >= Ribcr_zero);
1016 for (
int kk = klo+1; !above_critical && kk <=
khi; ++kk) {
1017 if (rib_enhan_arr(i,j,kk) >= Ribcr_zero) { kpbl_zero = kk; above_critical =
true;
break; }
1020 pbli_zero_arr(i, j, 0) = kpbl_zero;
1022 BL_PROFILE_VAR_STOP(prof_pblh);
1031 ParallelFor(xybx, [=, zero_d=
zero] AMREX_GPU_DEVICE(
int i,
int j,
int) noexcept
1033 entr_arr(i,j,0) =
zero;
1034 if (!enable_ysu_entrainment)
return;
1036 const int kpbl = pbli_arr(i,j,0);
1038 const Real pblh = pblh_corr_arr(i,j,0);
1039 const Real wscale = wstar_arr(i,j,0);
1040 const Real ustar = u_star_arr(i,j,0);
1041 const Real ustar3 = ustar * ustar * ustar;
1045 const Real wstar3_col = wstar3_arr(i,j,0);
1052 ?
GetThetavl(i, j, klo, cell_data, moisture_indices)
1053 :
GetThetav(i, j, klo, cell_data, moisture_indices);
1058 const int kpbl_p1 = amrex::min(kpbl + 1, izmax);
1060 ?
GetThetavl(i, j, kpbl, cell_data, moisture_indices)
1061 :
GetThetav(i, j, kpbl, cell_data, moisture_indices);
1063 ?
GetThetavl(i, j, kpbl_p1, cell_data, moisture_indices)
1064 :
GetThetav(i, j, kpbl_p1, cell_data, moisture_indices);
1065 const Real dthvx = amrex::max(thvx_kpbl_p1 - thvx_kpbl,
amrex::Real(1.0e-2));
1069 const Real we = amrex::max(bfxpbl / dthvx, -std::sqrt(wm2));
1072 const Real met_h = (use_terrain_fitted_coords)
1074 const Real dz_kpbl = met_h / dz_inv;
1084 Real K_entr_final = (we <
zero) ? rho_kpbl * (-we) * dz_kpbl :
zero;
1087 const int k_below = amrex::max(kpbl - 1, klo);
1089 Real qc_below = (moisture_indices.
qc >= 0)
1090 ? cell_data(i, j, k_below, moisture_indices.
qc) / rho_k :
zero;
1091 Real qi_below = (moisture_indices.
qi >= 0)
1092 ? cell_data(i, j, k_below, moisture_indices.
qi) / rho_k :
zero;
1096 if ((qc_below + qi_below) > cloud_thresh_entr && kpbl >= klo + 2) {
1104 const int k_p2 = amrex::min(kpbl + 1, izmax);
1105 const Real thlix_kbelow =
GetThetavl(i, j, k_below, cell_data, moisture_indices);
1106 const Real thlix_kp2 =
GetThetavl(i, j, k_p2, cell_data, moisture_indices);
1109 const Real dthvx_li = amrex::max(thlix_kp2 - thlix_kbelow,
amrex::Real(0.1));
1115 * xlv_over_cp * qc_below / dthvx_li,
1120 const Real we_cloud = amrex::max(bfxpbl / dthvx_li, -std::sqrt(wm2));
1124 const Real bfx0_cloud = amrex::max(sflux_arr(i, j, 0), zero_d);
1125 const Real bfxpbl_cloud = -ent_eff * bfx0_cloud;
1126 const Real we_cloud_top = amrex::max(bfxpbl_cloud / dthvx_li,
1130 we_final = we_cloud + we_cloud_top;
1133 K_entr_final = (we_final <
zero) ? rho_kpbl * (-we_final) * dz_kpbl :
zero;
1140 entr_arr(i,j,0) = amrex::min(K_entr_final, K_cap);
1144 const int kpbl_current = pbli_arr(i, j, 0);
1148 if (moisture_indices.
qc >= 0)
1149 qc_kpbl = cell_data(i, j, kpbl_current, moisture_indices.
qc) / cell_data(i, j, kpbl_current,
Rho_comp);
1150 if (moisture_indices.
qi >= 0)
1151 qi_kpbl = cell_data(i, j, kpbl_current, moisture_indices.
qi) / cell_data(i, j, kpbl_current,
Rho_comp);
1154 if ((qc_kpbl + qi_kpbl) > ysu_qcloud_threshold) {
1155 pbli_arr(i, j, 0) = amrex::min(kpbl_current + 1, izmax);
1162 FArrayBox K_down_fab(gbx, 1, The_Async_Arena());
1163 K_down_fab.setVal<RunOn::Device>(
zero);
1164 const auto& K_down_arr = K_down_fab.array();
1166 if (enable_ysu_topdown) {
1167 ParallelFor(gbx, [=, zero_d=
zero] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
1169 K_down_arr(i,j,k) =
zero;
1170 if (k >= pbli_arr(i,j,0))
return;
1174 const amrex::Real zval = (use_terrain_fitted_coords)
1177 const amrex::Real z_sfc = (use_terrain_fitted_coords)
1185 const amrex::Real wstar3_down_col = wstar3_down_arr(i,j,0);
1187 ? std::cbrt(wstar3_down_col)
1189 const amrex::Real zfac_up = amrex::max(zrel / pblh_rel, zero_d);
1190 K_down_arr(i,j,k) =
rho * wstar_down_eff *
KAPPA
1191 * amrex::max(pblh_rel - zrel, zero_d)
1192 * zfac_up * zfac_up;
1198 const Array4<Real>& K_turb = eddyViscosity.array(mfi);
1209 BL_PROFILE_VAR(
"YSUNew_Kprofile", prof_kprof);
1210 ParallelFor(gbx, [=, wstar3_arr_cap=wstar3_arr, zol1_arr_cap=zol1_arr, sfcflg_arr_cap=sfcflg_arr,
1211 zero_d=
zero, one_d=
one, two_d=
two] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
1213 Real obuk_val = l_obuk_arr(i, j, 0);
1218 const Real zval = (use_terrain_fitted_coords)
1222 const Real met_h_zeta = (use_terrain_fitted_coords)
1224 const Real dz_terrain = met_h_zeta / dz_inv;
1245 constexpr
Real qc_threshold =
Real(1.0e-5);
1250 if (moisture_indices.
qc >= 0) {
1251 qc_mix = cell_data(i, j, k, moisture_indices.
qc) /
rho;
1253 if (moisture_indices.
qi >= 0) {
1254 qi_mix = cell_data(i, j, k, moisture_indices.
qi) /
rho;
1257 const Real total_qcloud = qc_mix + qi_mix;
1258 const bool has_cloud = (total_qcloud > qc_threshold);
1267 if (k < pbli_extent) {
1288 bool SFCFLG = (sfcflg_arr_cap(i, j, 0) >
zero);
1294 const Real HOL = sf * pblh_corr_arr(i, j, 0) / obuk_val;
1295 const Real HOL_bounded = amrex::max(amrex::min(HOL,
Real(100.0)),
Real(-100.0));
1298 const Real phiM = (obuk_val > 0)
1299 ? (1 + 5 * HOL_bounded)
1301 amrex::max(1 - 16 * HOL_bounded,
Real(0.01)),
1308 const Real phit = (obuk_val > 0)
1309 ? (1 + 5 * HOL_bounded)
1311 amrex::max(1 - 16 * HOL_bounded,
Real(0.01)),
1320 Real phit_cloud = phit;
1321 Real phiM_cloud = phiM;
1322 if (has_cloud && obuk_val >
zero) {
1326 Real reduction_factor =
one -
Real(0.15) * amrex::min(total_qcloud / qc_threshold, one_d);
1328 phiM_cloud =
one +
Real(5.0) * reduction_factor * sf * pblh_corr_arr(i, j, 0) / obuk_val;
1329 phit_cloud =
one +
Real(5.0) * reduction_factor * sf * pblh_corr_arr(i, j, 0) / obuk_val;
1330 }
else if (has_cloud && obuk_val <=
zero) {
1334 Real cloud_boost =
Real(1.0) +
Real(0.05) * amrex::min(total_qcloud / qc_threshold, one_d);
1337 phiM_cloud = std::pow(
1338 amrex::max(one_d -
Real(16.0) * HOL_bounded / cloud_boost,
Real(0.01)),
1340 phit_cloud = std::pow(
1341 amrex::max(one_d -
Real(16.0) * HOL_bounded / cloud_boost,
Real(0.01)),
1346 const Real phiM_eff = phiM_cloud;
1347 const Real phit_eff = phit_cloud;
1360 const Real conpr = bfac *
KAPPA * sfcfrac;
1363 const Real zq_kp1_prandtl = zval +
myhalf * dz_terrain;
1367 const Real prfac = SFCFLG ? conpr :
zero;
1372 const Real wstar3_col = wstar3_arr_cap(i, j, 0);
1373 const Real ust3 = u_star_arr(i, j, 0) * u_star_arr(i, j, 0) * u_star_arr(i, j, 0);
1376 const Real wstar3_2 = wstar3_down_arr(i, j, 0);
1380 const Real wstar_tot3 = wstar3_col + wstar3_2;
1388 const Real pblh = pblh_corr_arr(i, j, 0);
1389 const Real sfclayer = sfcfrac * pblh;
1390 const Real zdiff = amrex::max(zq_kp1_prandtl - sfclayer, zero_d);
1391 const Real prnumfac =
amrex::Real(-3.0) * zdiff * zdiff / (pblh * pblh);
1397 Real prnum0 = (phit_eff / phiM_eff) + prfac;
1398 prnum0 = amrex::min(amrex::max(prnum0, prmin_wrf), prmax_wrf);
1402 Real prnum0_heat = prnum0 / (
one + prfac2 *
KAPPA * sfcfrac);
1403 prnum0_heat = amrex::min(amrex::max(prnum0_heat, prmin_wrf), prmax_wrf);
1404 const Real Prt =
one + (prnum0_heat -
one) * std::exp(prnumfac);
1408 const Real prnum_q =
one + (prnum0 -
one) * std::exp(prnumfac);
1425 const Real zq_kp1 = zval +
myhalf * dz_terrain;
1433 const Real zl1 = (use_terrain_fitted_coords)
1440 const Real pblh_rel = amrex::max(pblh_corr_arr(i, j, 0) - zl1,
amrex::Real(1.0e-4));
1441 const Real zfac = amrex::min(
1442 amrex::max(one_d - (zq_kp1 - zl1) / pblh_rel, zfacmin), one_d);
1446 const Real ust3_wscale = u_star_arr(i, j, 0) * u_star_arr(i, j, 0) * u_star_arr(i, j, 0);
1450 wscalek_val = std::cbrt(ust3_wscale +
amrex::Real(8.0) *
KAPPA * wstar3_col * (
one - zfac));
1454 constexpr
Real ckz_pbl =
Real(0.001);
1455 const Real K_base = ckz_pbl * dz_terrain *
rho;
1468 if (enable_ysu_topdown && k < pbli_arr(i, j, 0)) {
1479 const Real zq_kp1_stable = zval +
myhalf * dz_terrain;
1482 const Real zl1_stable = (use_terrain_fitted_coords)
1488 const Real pblh_rel_stable = amrex::max(pblh_corr_arr(i, j, 0) - zl1_stable,
amrex::Real(1.0e-4));
1489 const Real zfac_stable = amrex::min(
1490 amrex::max(one_d - (zq_kp1_stable - zl1_stable) / pblh_rel_stable, zfacmin_stable), one_d);
1494 const Real zol1_stable = zol1_arr_cap(i, j, 0);
1495 const Real zol_ratio = zq_kp1_stable / zl1_stable;
1496 const Real phim_stable_arg = zol1_stable * zol_ratio;
1498 const Real wscalek_stable = amrex::max(
1499 u_star_arr(i, j, 0) / amrex::max(phim_stable,
amrex::Real(0.01)),
1503 constexpr
Real ckz_pbl_stable =
Real(0.001);
1504 const Real K_base_stable = ckz_pbl_stable * dz_terrain *
rho;
1506 K_turb(i, j, k,
EddyDiff::Mom_v) = K_base_stable +
rho * wscalek_stable *
KAPPA * zq_kp1_stable * std::pow(zfac_stable, pfac_stable);
1511 const Real prnum_stable =
one + (prnum0 -
one) * std::exp(prnumfac);
1520 }
else if (k >= pbli_extent) {
1525 const Real lambda_min =
Real(30.0);
1526 const Real lambda_max =
Real(300.0);
1527 const Real lambdadz = amrex::min(amrex::max(
Real(0.1) * dz_terrain, lambda_min), lambda_max);
1528 const Real lscale = (lambdadz *
KAPPA * zval) / (lambdadz +
KAPPA * zval);
1529 Real dthetadz, dudz, dvdz;
1530 ComputeVerticalDerivativesPBL(i, j, k, uvel, vvel, cell_data, izmin, izmax, pbl_derivative_dz_inv(i,j,k),
1531 c_ext_dir_on_zlo, c_ext_dir_on_zhi, u_ext_dir_on_zlo,
1532 u_ext_dir_on_zhi, v_ext_dir_on_zlo, v_ext_dir_on_zhi, dthetadz,
1533 dudz, dvdz, moisture_indices);
1536 const Real dudz_safe = (k < izmax) ? dudz :
zero;
1537 const Real dvdz_safe = (k < izmax) ? dvdz :
zero;
1541 const Real wind_shear = dudz_safe * dudz_safe + dvdz_safe * dvdz_safe;
1542 const Real wind_shear_safe = std::max(wind_shear,
Real(1.0e-8));
1548 const Real theta_v =
GetThetav(i, j, k, cell_data, moisture_indices);
1549 const Real dtheta_v_dz = dthetadz;
1562 Real grad_Ri =
CONST_GRAV / theta_v * dtheta_v_dz / wind_shear_safe;
1563 grad_Ri = std::max(std::min(grad_Ri,
Real(100.0)), -
Real(100.0));
1571 Real qc_k = (moisture_indices.
qc >= 0) ? cell_data(i,j,k, moisture_indices.
qc)/rho_k :
zero;
1572 Real qc_kp1 = (moisture_indices.
qc >= 0) ? cell_data(i,j,k+1,moisture_indices.
qc)/rho_kp1 :
zero;
1573 Real qi_k = (moisture_indices.
qi >= 0) ? cell_data(i,j,k, moisture_indices.
qi)/rho_k :
zero;
1574 Real qi_kp1 = (moisture_indices.
qi >= 0) ? cell_data(i,j,k+1,moisture_indices.
qi)/rho_kp1 :
zero;
1577 if ((qc_k + qi_k) > cloud_thresh && (qc_kp1 + qi_kp1) > cloud_thresh) {
1584 const Real qv_k_mri = (moisture_indices.
qv >= 0)
1585 ? cell_data(i,j,k, moisture_indices.
qv) / rho_k :
zero;
1586 const Real qv_kp1_mri = (moisture_indices.
qv >= 0)
1587 ? cell_data(i,j,k+1,moisture_indices.
qv) / rho_kp1 :
zero;
1592 const Real qmean =
myhalf * (qv_k_mri + qv_kp1_mri);
1598 const Real chi =
xlv *
xlv * qmean / (
cp * rv * tmean * tmean);
1621 const Real grad_Ri_safe = amrex::max(grad_Ri, -
Real(100.0));
1622 const Real fm = (grad_Ri_safe > 0)
1624 : 1 - 8 * grad_Ri_safe / (1 +
Real(1.746) * std::sqrt(amrex::max(-grad_Ri_safe, zero_d)));
1625 const Real ft = (grad_Ri_safe > 0)
1627 : 1 - 8 * grad_Ri_safe / (1 +
Real(1.286) * std::sqrt(amrex::max(-grad_Ri_safe, zero_d)));
1628 const Real rl2wsp =
rho * lscale * lscale * std::sqrt(wind_shear);
1632 if (grad_Ri_safe > 0) {
1651 if (k == pbli_arr(i,j,0)) {
1677 Real rhoKmin, rhoKmax;
1683 constexpr
Real Kmax =
Real(1000.0);
1684 rhoKmin = ckz * dz_terrain *
rho;
1685 rhoKmax =
rho * Kmax;
1692 rhoKmin =
rho * Kmin;
1693 rhoKmax =
rho * Kmax;
1696 #ifdef ERF_USE_WINDFARM
1710 if (k < pbli_extent) {
1725 std::min(K_turb(i, j, k,
EddyDiff::Q_v), rhoKmax), rhoKmin);
1730 if (k < pbli_extent) {
1744 BL_PROFILE_VAR_STOP(prof_kprof);
1745 amrex::Print()<<
" Turbulent Viscosity at cell "<<K_turb(2, 2, 2,
EddyDiff::Mom_v)<<
" "<<pblh_corr_arr(2, 2, 0)<<std::endl;
1747 ParallelFor(xybx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int ) noexcept
constexpr amrex::Real epsv
Definition: ERF_Constants.H:53
constexpr amrex::Real KAPPA
Definition: ERF_Constants.H:63
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 zero
Definition: ERF_Constants.H:8
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:13
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:64
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getTgivenRandRTh(const amrex::Real rho, const amrex::Real rhotheta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:46
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getPgivenRTh(const amrex::Real rhotheta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:81
#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
Real z0
Definition: ERF_InitCustomPertVels_ScalarAdvDiff.H:8
const bool use_moisture
Definition: ERF_InitCustomPert_Bomex.H:14
const int khi
Definition: ERF_InitCustomPert_Bubble.H:21
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
rho
Definition: ERF_InitCustomPert_Bubble.H:107
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsatw(amrex::Real t, amrex::Real p, amrex::Real &qsatw)
Definition: ERF_MicrophysicsUtils.H:228
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real GetThetav(const int &i, const int &j, const int &k, const amrex::Array4< amrex::Real const > &cell_data, const MoistureComponentIndices &moisture_indices)
Definition: ERF_MoistUtils.H:72
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real GetThetavl(int i, int j, int k, const amrex::Array4< amrex::Real const > &cell_data, const MoistureComponentIndices &moisture_indices)
Definition: ERF_MoistUtils.H:92
ParallelFor(grown_box, [=] AMREX_GPU_DEVICE(int i, int j, int k) { qrcuten_arr(i, j, k)=Real(0);qscuten_arr(i, j, k)=Real(0);qicuten_arr(i, j, k)=Real(0);})
AMREX_GPU_DEVICE AMREX_FORCE_INLINE void ComputeVerticalDerivativesPBL(int i, int j, int k, const amrex::Array4< const amrex::Real > &uvel, const amrex::Array4< const amrex::Real > &vvel, const amrex::Array4< const amrex::Real > &cell_data, const int izmin, const int izmax, const PBLDerivativeDzInv &dz_inv, const bool c_ext_dir_on_zlo, const bool c_ext_dir_on_zhi, const bool u_ext_dir_on_zlo, const bool u_ext_dir_on_zhi, const bool v_ext_dir_on_zlo, const bool v_ext_dir_on_zhi, amrex::Real &dthetadz, amrex::Real &dudz, amrex::Real &dvdz, const MoistureComponentIndices &moisture_indices)
Definition: ERF_PBLModels.H:254
TurbChoice turbChoice
Definition: ERF_SetupVertDiff.H:6
amrex::Real Real
Definition: ERF_ShocInterface.H:19
AMREX_FORCE_INLINE AMREX_GPU_DEVICE amrex::Real Compute_h_zeta_AtCellCenter(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:55
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_Zrel_AtCellCenter(const int &i, const int &j, const int &k, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:389
AMREX_FORCE_INLINE amrex::IntVect TileNoZ()
Definition: ERF_TileNoZ.H:11
@ yvel_bc
Definition: ERF_IndexDefines.H:103
@ cons_bc
Definition: ERF_IndexDefines.H:86
@ xvel_bc
Definition: ERF_IndexDefines.H:102
@ ext_dir
Definition: ERF_IndexDefines.H:248
@ Theta_v
Definition: ERF_IndexDefines.H:211
@ Turb_lengthscale
Definition: ERF_IndexDefines.H:215
@ HGAMU_v
Definition: ERF_IndexDefines.H:218
@ Q_v
Definition: ERF_IndexDefines.H:214
@ Mom_v
Definition: ERF_IndexDefines.H:210
@ HGAMQ_v
Definition: ERF_IndexDefines.H:217
@ HGAMT_v
Definition: ERF_IndexDefines.H:216
@ HGAMV_v
Definition: ERF_IndexDefines.H:219
@ xvel
Definition: ERF_IndexDefines.H:176
@ yvel
Definition: ERF_IndexDefines.H:177
@ dz
Definition: ERF_AdvanceWSM6.cpp:104
real(c_double), parameter cp
Definition: ERF_module_model_constants.F90:22
real(c_double), parameter xlv
Definition: ERF_module_model_constants.F90:57
real(kind=kind_phys), parameter, public alpha
Definition: ERF_module_mp_wsm6.F90:44
int qi
Definition: ERF_DataStruct.H:109
int qv
Definition: ERF_DataStruct.H:107
int qc
Definition: ERF_DataStruct.H:108
Definition: ERF_PBLModels.H:416
bool enable_ysu_countergradient
Definition: ERF_TurbStruct.H:610
bool pbl_mrf_use_zero_ri_extent
Definition: ERF_TurbStruct.H:636
amrex::Real pbl_mrf_const_b
Definition: ERF_TurbStruct.H:629
amrex::Real ysu_qcloud_threshold
Definition: ERF_TurbStruct.H:622
bool pbl_ysunew_highres_bounds
Definition: ERF_TurbStruct.H:625
bool enable_ysu_topdown
Definition: ERF_TurbStruct.H:616
bool enable_mrf_unbounded_vpert
Definition: ERF_TurbStruct.H:635
amrex::Real pbl_mrf_sf
Definition: ERF_TurbStruct.H:630
bool enable_ysu_sat_limiter
Definition: ERF_TurbStruct.H:614
amrex::Real pbl_ysu_land_Ribcr
Definition: ERF_TurbStruct.H:604
bool enable_ysu_entrainment
Definition: ERF_TurbStruct.H:618
bool enable_ysu_cloud_pblh
Definition: ERF_TurbStruct.H:620
bool enable_ysu_terrain_pblh_floor
Definition: ERF_TurbStruct.H:612
amrex::Real pbl_ysu_coriolis_freq
Definition: ERF_TurbStruct.H:595
bool enable_ysu_liquid_theta
Definition: ERF_TurbStruct.H:608
bool ysu_moistvars
Definition: ERF_TurbStruct.H:624