One radiation call at one level.
314 BL_PROFILE(
"TwoStreamRadiation::advance()");
317 if (!
active()) {
return; }
323 "TwoStreamRadiation::advance: call_site must be pre_dycore or post_dycore");
325 "TwoStreamRadiation::advance called on a level define_level has not built");
329 m_alb_sw[lev]->boxArray().size() == cons_old.boxArray().size() &&
330 m_alb_sw[lev]->DistributionMap() == cons_old.DistributionMap(),
331 "TwoStreamRadiation: the 2D surface fields and the 3D state are laid out differently");
332 if (qheating !=
nullptr) {
334 qheating->boxArray() == cons_old.boxArray() &&
335 qheating->DistributionMap() == cons_old.DistributionMap(),
336 "TwoStreamRadiation: qheating must be the 2-component (SW, LW) field on the state's grids");
342 "TwoStreamRadiation: seb_enable is set but the SEB fields were not allocated");
346 "TwoStreamRadiation: the force-restore update needs a positive, finite dt_step");
359 if (call_site ==
"pre_dycore") {
360 ReduceOps<ReduceOpMin, ReduceOpMin> state_ops;
361 ReduceData<amrex::Real, amrex::Real> state_data(state_ops);
362 using StateTuple =
typename decltype(state_data)::Type;
363 for (MFIter mfi(cons_old, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
364 const auto& arr = cons_old.const_array(mfi);
365 state_ops.eval(mfi.tilebox(), state_data,
366 [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) -> StateTuple {
367 constexpr
amrex::Real neg_inf = -std::numeric_limits<amrex::Real>::infinity();
370 return {amrex::Math::isfinite(
rho) ?
rho : neg_inf,
371 amrex::Math::isfinite(rth) ? rth : neg_inf};
374 auto state_tuple = state_data.value(state_ops);
375 amrex::Real mins[2] = {amrex::get<0>(state_tuple), amrex::get<1>(state_tuple)};
376 ParallelDescriptor::ReduceRealMin(mins, 2);
379 if (!std::isfinite(rho_min) || !std::isfinite(rth_min)) {
380 amrex::Abort(
"TwoStreamRadiation: the state handed to the column sweep at level " +
381 std::to_string(lev) +
", step " + std::to_string(nstep) +
382 " has a non-finite density or rho*theta");
384 if (!(rho_min > 0.0) || !(rth_min > 0.0)) {
385 amrex::Abort(
"TwoStreamRadiation: the state handed to the column sweep at level " +
386 std::to_string(lev) +
", step " + std::to_string(nstep) +
387 " has a non-positive density (min " + std::to_string(rho_min) +
388 ") or rho*theta (min " + std::to_string(rth_min) +
")");
396 const bool do_sweep = (call_site !=
"post_dycore");
402 m_diag = std::make_unique<RadiationDiagnostics>(
424 amrex::Real seb_residual_mean = std::numeric_limits<amrex::Real>::quiet_NaN();
425 amrex::Real seb_residual_max = std::numeric_limits<amrex::Real>::quiet_NaN();
428 amrex::Real t_s_mean = std::numeric_limits<amrex::Real>::quiet_NaN();
429 amrex::Real t_s_max = std::numeric_limits<amrex::Real>::quiet_NaN();
430 amrex::Real q_s_mean = std::numeric_limits<amrex::Real>::quiet_NaN();
431 amrex::Real q_s_max = std::numeric_limits<amrex::Real>::quiet_NaN();
434 const MultiFab& state_cons = cons_old;
437 if (state_cons.nComp() > 0 ) {
445 if (do_sweep) { set_solar_state(ts_params, rad_choice,
m_orbit, epoch_time, have_datetime, lev, nstep); }
454 amrex::Long n_columns_total = 0;
458 amrex::Long n_seb_columns = 0;
468 MultiFab* qheating_mf = qheating;
475 const bool sw_flux_from_rad = rad_choice.
seb_enable &&
477 !lsm_has_field(lsm, lev,
"sav");
478 const bool lw_flux_from_rad = rad_choice.
seb_enable &&
480 !lsm_has_field(lsm, lev,
"fira");
497 if (!sw_flux_from_rad) {
501 if (!lw_flux_from_rad) {
514 fill_or_copy_seb_field(
m_q_sfc[lev].
get(), lsm, lev,
"noahmp_water_vapor_mixing_ratio_2m_vegetated", rad_choice.
seb_q_sfc_default);
529 const Box& rad_domain = geom.Domain();
531 for (MFIter mfi(state_cons,
false); mfi.isValid(); ++mfi)
533 const Box& bx = mfi.validbox();
541 bx.smallEnd(2) == rad_domain.smallEnd(2) &&
542 bx.bigEnd(2) == rad_domain.bigEnd(2),
543 "TwoStream radiation requires grids that span the domain in z; "
544 "set amr.max_grid_size_z to at least amr.n_cell in z");
545 const auto& state_arr = state_cons.const_array(mfi);
548 const amrex::Real dz_uniform_lev = geom.CellSize(2);
552 Array4<const amrex::Real> z_phys_nd_arr;
553 if (z_phys_nd !=
nullptr) {
554 z_phys_nd_arr = z_phys_nd->const_array(mfi);
560 Array4<amrex::Real> scratch_arr = scratch_fab.array();
570 bool has_hetero_alb_sw =
false;
571 Array4<const amrex::Real> hetero_alb_sw_arr;
573 std::string varname_alb =
"sfc_alb_dir_vis";
578 hetero_alb_sw_arr = lsm_ptr->const_array(mfi);
579 has_hetero_alb_sw =
true;
582 hetero_alb_sw_arr =
m_alb_sw[lev]->const_array(mfi);
583 has_hetero_alb_sw =
true;
588 bool has_hetero_emiss_lw =
false;
589 Array4<const amrex::Real> hetero_emiss_lw_arr;
591 std::string varname_emiss =
"sfc_emis";
596 hetero_emiss_lw_arr = lsm_ptr->const_array(mfi);
597 has_hetero_emiss_lw =
true;
600 hetero_emiss_lw_arr =
m_emiss_lw[lev]->const_array(mfi);
601 has_hetero_emiss_lw =
true;
612 bool has_lsm_t_sfc =
false;
613 Array4<const amrex::Real> lsm_t_sfc_arr;
614 bool has_seb_t_sfc =
false;
615 Array4<const amrex::Real> seb_t_sfc_arr;
616 bool has_surface_layer =
false;
617 Array4<const amrex::Real> surface_layer_theta_arr;
619 std::string varname_t_sfc =
"t_sfc";
624 lsm_t_sfc_arr = lsm_ptr->const_array(mfi);
625 has_lsm_t_sfc =
true;
633 seb_t_sfc_arr =
m_t_sfc[lev]->const_array(mfi);
634 has_seb_t_sfc =
true;
636 if (t_surf !=
nullptr) {
637 surface_layer_theta_arr = t_surf->const_array(mfi);
638 has_surface_layer =
true;
645 const bool has_latlon = (lat_m !=
nullptr) && (lon_m !=
nullptr);
646 Array4<const amrex::Real> lat_arr, lon_arr;
648 lat_arr = lat_m->const_array(mfi);
649 lon_arr = lon_m->const_array(mfi);
658 const bool write_fluxes = (rad_fluxes !=
nullptr);
659 Array4<amrex::Real> rad_flux_clear_arr;
660 FArrayBox rad_flux_cloudy_fab;
661 Array4<amrex::Real> rad_flux_cloudy_arr;
663 rad_flux_clear_arr = rad_fluxes->array(mfi);
664 if (cloud_fraction > 0.0) {
666 rad_flux_cloudy_arr = rad_flux_cloudy_fab.array();
672 Array4<amrex::Real> sw_sfc_out;
673 Array4<amrex::Real> lw_sfc_out;
674 if (sw_flux_from_rad) sw_sfc_out =
m_sw_flux_sfc[lev]->array(mfi);
675 if (lw_flux_from_rad) lw_sfc_out =
m_lw_flux_sfc[lev]->array(mfi);
679 const auto&
lo = bx.loVect();
680 const auto&
hi = bx.hiVect();
681 Box xy_box(IntVect(
lo[0],
lo[1], 0), IntVect(
hi[0],
hi[1], 0));
684 amrex::Long n_cols =
static_cast<amrex::Long
>(bx.length(0)) *
685 static_cast<amrex::Long
>(bx.length(1));
686 n_columns_total += n_cols;
692 FArrayBox qheating_fallback_fab;
693 Array4<amrex::Real> qheating_clear_arr;
694 if (qheating_mf !=
nullptr) {
695 qheating_clear_arr = qheating_mf->array(mfi);
697 qheating_fallback_fab.resize(bx, 2);
698 qheating_clear_arr = qheating_fallback_fab.array();
703 FArrayBox qheating_cloudy_fab;
704 Array4<amrex::Real> qheating_cloudy_arr;
705 if (cloud_fraction > 0.0) {
706 qheating_cloudy_fab.resize(bx, 2);
707 qheating_cloudy_arr = qheating_cloudy_fab.array();
720 ReduceOps<ReduceOpMax, ReduceOpSum, ReduceOpSum, ReduceOpSum, ReduceOpSum, ReduceOpSum> reduce_ops;
721 ReduceData<amrex::Real, amrex::Real, amrex::Real, amrex::Real, amrex::Real, amrex::Real> reduce_data(reduce_ops);
723 using ReduceTuple =
typename decltype(reduce_data)::Type;
726 reduce_ops.eval(xy_box, reduce_data,
727 [=] AMREX_GPU_DEVICE (
int i,
int j,
int ) -> ReduceTuple
738 i, j, bx, dz_uniform_lev, state_arr, ts_params,
false,
740 max_heating_clear, sw_flux_clear, sw_up_clear, lw_net_clear, lw_up_clear,
742 z_phys_nd_arr, scratch_arr,
743 has_hetero_alb_sw, &hetero_alb_sw_arr,
744 has_hetero_emiss_lw, &hetero_emiss_lw_arr,
745 has_lsm_t_sfc, &lsm_t_sfc_arr,
746 has_seb_t_sfc, &seb_t_sfc_arr,
747 has_surface_layer, &surface_layer_theta_arr,
748 has_latlon, &lat_arr, &lon_arr,
749 write_fluxes ? &rad_flux_clear_arr :
nullptr);
760 if (cloud_fraction > 0.0) {
768 i, j, bx, dz_uniform_lev, state_arr, ts_params,
true,
770 max_heating_cloudy, sw_flux_cloudy, sw_up_cloudy, lw_net_cloudy, lw_up_cloudy,
772 z_phys_nd_arr, scratch_arr,
773 has_hetero_alb_sw, &hetero_alb_sw_arr,
774 has_hetero_emiss_lw, &hetero_emiss_lw_arr,
775 has_lsm_t_sfc, &lsm_t_sfc_arr,
776 has_seb_t_sfc, &seb_t_sfc_arr,
777 has_surface_layer, &surface_layer_theta_arr,
778 has_latlon, &lat_arr, &lon_arr,
779 write_fluxes ? &rad_flux_cloudy_arr :
nullptr);
782 sw_flux_col = (1.0 - cloud_fraction) * sw_flux_clear +
783 cloud_fraction * sw_flux_cloudy;
784 sw_up_col = (1.0 - cloud_fraction) * sw_up_clear +
785 cloud_fraction * sw_up_cloudy;
786 lw_net_col = (1.0 - cloud_fraction) * lw_net_clear +
787 cloud_fraction * lw_net_cloudy;
788 lw_up_col = (1.0 - cloud_fraction) * lw_up_clear +
789 cloud_fraction * lw_up_cloudy;
790 max_heating_col = std::max(max_heating_clear, max_heating_cloudy);
795 int kmin = bx.smallEnd(2);
796 int kmax = bx.bigEnd(2);
797 for (
int k = kmin; k <= kmax; ++k) {
798 for (
int comp = 0; comp < 2; ++comp) {
799 amrex::Real q_clear_val = qheating_clear_arr(i, j, k, comp);
800 amrex::Real q_cloudy_val = qheating_cloudy_arr(i, j, k, comp);
801 qheating_clear_arr(i, j, k, comp) =
802 (1.0 - cloud_fraction) * q_clear_val +
803 cloud_fraction * q_cloudy_val;
808 for (
int k = kmin; k <= kmax + 1; ++k) {
809 for (
int comp = 0; comp < 4; ++comp) {
810 rad_flux_clear_arr(i, j, k, comp) =
811 (1.0 - cloud_fraction) * rad_flux_clear_arr(i, j, k, comp) +
812 cloud_fraction * rad_flux_cloudy_arr(i, j, k, comp);
820 if (sw_flux_from_rad) sw_sfc_out(i, j, 0) = sw_flux_col;
821 if (lw_flux_from_rad) lw_sfc_out(i, j, 0) = -lw_net_col;
825 return {max_heating_col, sw_flux_col, sw_up_col, lw_net_col, lw_up_col, sw_toa_clear};
830 amrex::Gpu::synchronize();
831 auto reduce_tuple = reduce_data.value(reduce_ops);
832 max_heating_box = amrex::get<0>(reduce_tuple);
833 sw_sum_box = amrex::get<1>(reduce_tuple);
834 sw_up_sum_box = amrex::get<2>(reduce_tuple);
835 lw_sum_box = amrex::get<3>(reduce_tuple);
836 lw_up_sum_box = amrex::get<4>(reduce_tuple);
837 sw_toa_sum_box = amrex::get<5>(reduce_tuple);
840 max_heating_global = std::max(max_heating_global, max_heating_box);
841 sw_surface_sum += sw_sum_box;
842 sw_up_toa_sum += sw_up_sum_box;
843 lw_net_sum += lw_sum_box;
844 lw_up_toa_sum += lw_up_sum_box;
845 sw_toa_sum += sw_toa_sum_box;
852 amrex::Real sums[5] = {sw_surface_sum, sw_up_toa_sum, lw_net_sum, lw_up_toa_sum, sw_toa_sum};
853 ParallelDescriptor::ReduceRealSum(sums, 5);
854 sw_surface_sum = sums[0]; sw_up_toa_sum = sums[1];
855 lw_net_sum = sums[2]; lw_up_toa_sum = sums[3];
856 sw_toa_sum = sums[4];
857 ParallelDescriptor::ReduceLongSum(n_columns_total);
858 ParallelDescriptor::ReduceRealMax(max_heating_global);
864 if (do_sweep && qheating_mf !=
nullptr &&
865 (qheating_mf->contains_nan(0, 2, 0) || qheating_mf->contains_inf(0, 2, 0))) {
866 amrex::Abort(
"TwoStreamRadiation: non-finite heating rate after the column sweep at level " +
867 std::to_string(lev) +
", step " + std::to_string(nstep));
872 static bool warned_seb_misconfig =
false;
873 if (!warned_seb_misconfig && ParallelDescriptor::IOProcessor()) {
874 Print() <<
"WARNING: erf.radiation.seb_diagnostic_enable=true but "
875 "seb_enable=false; SEB residual diagnostics will report NaN. "
876 "Set erf.radiation.seb_enable=true to enable SEB field "
878 warned_seb_misconfig =
true;
883 seb_residual_max = 0.0;
887 for (MFIter mfi(state_cons,
false); mfi.isValid(); ++mfi) {
888 const Box& bx = mfi.validbox();
889 const auto&
lo = bx.loVect();
890 const auto&
hi = bx.hiVect();
891 Box xy_box(IntVect(
lo[0],
lo[1], 0), IntVect(
hi[0],
hi[1], 0));
894 Array4<const amrex::Real> sw_flux_arr =
m_sw_flux_sfc[lev]->const_array(mfi);
895 Array4<const amrex::Real> lw_flux_arr =
m_lw_flux_sfc[lev]->const_array(mfi);
896 Array4<const amrex::Real> hfx_arr =
m_hfx_sfc[lev]->const_array(mfi);
897 Array4<const amrex::Real> lh_arr =
m_lh_sfc[lev]->const_array(mfi);
898 Array4<const amrex::Real> grdflx_arr =
m_grdflx_sfc[lev]->const_array(mfi);
901 amrex::Long n_cols_box =
static_cast<amrex::Long
>(bx.length(0)) *
902 static_cast<amrex::Long
>(bx.length(1));
907 ReduceOps<ReduceOpSum, ReduceOpMax> seb_reduce_ops;
908 ReduceData<amrex::Real, amrex::Real> seb_reduce_data(seb_reduce_ops);
910 using SEBReduceTuple =
typename decltype(seb_reduce_data)::Type;
912 seb_reduce_ops.eval(xy_box, seb_reduce_data,
913 [=] AMREX_GPU_DEVICE (
int i,
int j,
int ) -> SEBReduceTuple {
924 return {residual, std::abs(residual)};
929 amrex::Gpu::synchronize();
930 auto seb_reduce_tuple = seb_reduce_data.value(seb_reduce_ops);
931 residual_sum_box = amrex::get<0>(seb_reduce_tuple);
932 residual_max_box = amrex::get<1>(seb_reduce_tuple);
935 seb_residual_sum += residual_sum_box;
936 seb_residual_max = std::max(seb_residual_max, residual_max_box);
937 n_seb_columns += n_cols_box;
939 ParallelDescriptor::ReduceRealSum(seb_residual_sum);
940 ParallelDescriptor::ReduceRealMax(seb_residual_max);
941 ParallelDescriptor::ReduceLongSum(n_seb_columns);
947 call_site ==
"post_dycore") {
949 std::string varname_t_sfc_prog =
"t_sfc";
950 int lsm_idx_t_sfc = lsm.
Get_DataIdx(lev, varname_t_sfc_prog);
951 bool noahmp_active = (lsm_idx_t_sfc >= 0);
953 if (!noahmp_active) {
958 amrex::Real t_s_max_val = -std::numeric_limits<amrex::Real>::max();
960 amrex::Real q_s_max_val = -std::numeric_limits<amrex::Real>::max();
961 amrex::Long n_prog_columns = 0;
967 for (MFIter mfi(state_cons,
false); mfi.isValid(); ++mfi) {
968 const Box& bx = mfi.validbox();
969 const auto&
lo = bx.loVect();
970 const auto&
hi = bx.hiVect();
971 Box xy_box(IntVect(
lo[0],
lo[1], 0), IntVect(
hi[0],
hi[1], 0));
974 Array4<const amrex::Real> sw_flux_arr =
m_sw_flux_sfc[lev]->const_array(mfi);
975 Array4<const amrex::Real> lw_flux_arr =
m_lw_flux_sfc[lev]->const_array(mfi);
976 Array4<const amrex::Real> hfx_arr =
m_hfx_sfc[lev]->const_array(mfi);
977 Array4<const amrex::Real> lh_arr =
m_lh_sfc[lev]->const_array(mfi);
978 Array4<const amrex::Real> grdflx_arr =
m_grdflx_sfc[lev]->const_array(mfi);
979 Array4<const amrex::Real> t_deep_arr =
m_t_deep[lev]->const_array(mfi);
980 Array4<const amrex::Real> q_deep_arr =
m_q_deep[lev]->const_array(mfi);
983 Array4<amrex::Real> t_s_arr =
m_t_sfc[lev]->array(mfi);
984 Array4<amrex::Real> q_s_arr =
m_q_sfc[lev]->array(mfi);
986 amrex::Long n_cols_box =
static_cast<amrex::Long
>(bx.length(0)) *
987 static_cast<amrex::Long
>(bx.length(1));
989 amrex::Real t_s_max_box = -std::numeric_limits<amrex::Real>::max();
991 amrex::Real q_s_max_box = -std::numeric_limits<amrex::Real>::max();
994 ReduceOps<ReduceOpSum, ReduceOpMax, ReduceOpSum, ReduceOpMax> prog_reduce_ops;
995 ReduceData<amrex::Real, amrex::Real, amrex::Real, amrex::Real> prog_reduce_data(prog_reduce_ops);
997 using ProgReduceTuple =
typename decltype(prog_reduce_data)::Type;
999 prog_reduce_ops.eval(xy_box, prog_reduce_data,
1008 AMREX_GPU_DEVICE (
int i,
int j,
int ) -> ProgReduceTuple {
1031 amrex::Real t_s_new = t_s_old + dt_step * dT_s_dt;
1032 amrex::Real q_s_new = q_s_old + dt_step * dq_s_dt;
1035 t_s_new = amrex::max(t_min, amrex::min(t_max, t_s_new));
1036 q_s_new = amrex::max(q_min, amrex::min(q_max, q_s_new));
1039 t_s_arr(i, j, 0) = t_s_new;
1040 q_s_arr(i, j, 0) = q_s_new;
1043 return {t_s_new, std::abs(t_s_new), q_s_new, std::abs(q_s_new)};
1047 amrex::Gpu::synchronize();
1048 auto prog_reduce_tuple = prog_reduce_data.value(prog_reduce_ops);
1049 t_s_sum_box = amrex::get<0>(prog_reduce_tuple);
1050 t_s_max_box = amrex::get<1>(prog_reduce_tuple);
1051 q_s_sum_box = amrex::get<2>(prog_reduce_tuple);
1052 q_s_max_box = amrex::get<3>(prog_reduce_tuple);
1055 t_s_sum += t_s_sum_box;
1056 t_s_max_val = std::max(t_s_max_val, t_s_max_box);
1057 q_s_sum += q_s_sum_box;
1058 q_s_max_val = std::max(q_s_max_val, q_s_max_box);
1059 n_prog_columns += n_cols_box;
1065 if (
m_t_sfc[lev]->contains_nan(0, 1, 0) ||
m_q_sfc[lev]->contains_nan(0, 1, 0)) {
1066 amrex::Abort(
"TwoStreamRadiation: non-finite surface temperature or moisture "
1067 "after the force-restore update at level " + std::to_string(lev) +
1068 ", step " + std::to_string(nstep));
1073 ParallelDescriptor::ReduceRealSum(sums, 2);
1074 t_s_sum = sums[0]; q_s_sum = sums[1];
1075 ParallelDescriptor::ReduceRealMax(t_s_max_val);
1076 ParallelDescriptor::ReduceRealMax(q_s_max_val);
1077 ParallelDescriptor::ReduceLongSum(n_prog_columns);
1081 if (n_prog_columns > 0) {
1082 t_s_mean = t_s_sum /
static_cast<amrex::Real>(n_prog_columns);
1083 t_s_max = t_s_max_val;
1084 q_s_mean = q_s_sum /
static_cast<amrex::Real>(n_prog_columns);
1085 q_s_max = q_s_max_val;
1087 t_s_mean = std::numeric_limits<amrex::Real>::quiet_NaN();
1088 t_s_max = std::numeric_limits<amrex::Real>::quiet_NaN();
1089 q_s_mean = std::numeric_limits<amrex::Real>::quiet_NaN();
1090 q_s_max = std::numeric_limits<amrex::Real>::quiet_NaN();
1095 t_s_mean = std::numeric_limits<amrex::Real>::quiet_NaN();
1096 t_s_max = std::numeric_limits<amrex::Real>::quiet_NaN();
1097 q_s_mean = std::numeric_limits<amrex::Real>::quiet_NaN();
1098 q_s_max = std::numeric_limits<amrex::Real>::quiet_NaN();
1109 if (n_columns_total > 0) {
1111 SW_surface = sw_surface_sum * inv_n;
1112 SW_TOA = sw_toa_sum * inv_n;
1113 SW_up_TOA = sw_up_toa_sum * inv_n;
1114 LW_net_surface = lw_net_sum * inv_n;
1115 LW_up_TOA = lw_up_toa_sum * inv_n;
1117 heating_rate_max = max_heating_global;
1118 m_flux_diag[lev] = FluxDiag{SW_surface, SW_TOA, SW_up_TOA,
1119 LW_net_surface, LW_up_TOA,
1123 SW_surface = cached.SW_surface;
1124 SW_TOA = cached.SW_TOA;
1125 SW_up_TOA = cached.SW_up_TOA;
1126 LW_net_surface = cached.LW_net_surface;
1127 LW_up_TOA = cached.LW_up_TOA;
1128 heating_rate_max = cached.heating_rate_max;
1133 seb_residual_mean = seb_residual_sum /
static_cast<amrex::Real>(n_seb_columns);
1136 seb_residual_mean = std::numeric_limits<amrex::Real>::quiet_NaN();
1137 seb_residual_max = std::numeric_limits<amrex::Real>::quiet_NaN();
1143 if (rad_choice.
verbosity >= 1 && ParallelDescriptor::IOProcessor()) {
1144 Print() <<
"Radiation diagnostics at step " << nstep <<
":\n"
1145 <<
" SW TOA = " << SW_TOA <<
" W/m^2\n"
1146 <<
" SW surface = " << SW_surface <<
" W/m^2\n"
1147 <<
" SW up (TOA) = " << SW_up_TOA <<
" W/m^2\n"
1148 <<
" LW net (surface) = " << LW_net_surface <<
" W/m^2\n"
1149 <<
" LW up (TOA) = " << LW_up_TOA <<
" W/m^2\n"
1150 <<
" Max heating rate = " << heating_rate_max <<
" K/s\n";
1152 Print() <<
" SEB residual (mean) = " << seb_residual_mean <<
" W/m^2\n"
1153 <<
" SEB residual (max) = " << seb_residual_max <<
" W/m^2\n";
1156 Print() <<
" Surface temperature (mean) = " << t_s_mean <<
" K\n"
1157 <<
" Surface temperature (max) = " << t_s_max <<
" K\n"
1158 <<
" Surface moisture (mean) = " << q_s_mean <<
" kg/kg\n"
1159 <<
" Surface moisture (max) = " << q_s_max <<
" kg/kg\n";
1163 rad_diag.
append(nstep, time, call_site, SW_surface, SW_TOA,
1164 SW_up_TOA, LW_net_surface, LW_up_TOA, heating_rate_max,
1165 seb_residual_mean, seb_residual_max,
1166 t_s_mean, t_s_max, q_s_mean, q_s_max);
#define Rho_comp
Definition: ERF_IndexDefines.H:39
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:40
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(m_cloud_chamber_config.active, "Cloud Chamber: initializer reached without a parsed configuration")
pp get("wavelength", wavelength)
amrex::Real Real
Definition: ERF_ShocInterface.H:19
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real diagnose_seb_residual(amrex::Real sw_net, amrex::Real lw_net, amrex::Real hfx, amrex::Real lh, amrex::Real grdflx)
Diagnose the surface energy balance residual.
Definition: ERF_SimplifiedSEB.H:64
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real prognostic_dqs_dt(amrex::Real le, amrex::Real q_s, amrex::Real q_deep, amrex::Real d_s, amrex::Real tau_q)
Compute prognostic surface moisture tendency using force-restore formulation.
Definition: ERF_SimplifiedSEB.H:164
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real prognostic_dTs_dt(amrex::Real seb_residual, amrex::Real t_s, amrex::Real t_deep, amrex::Real c_s, amrex::Real tau)
Compute prognostic surface temperature tendency using force-restore formulation.
Definition: ERF_SimplifiedSEB.H:110
TwoStreamParams make_two_stream_params(const RadChoice &rc, const amrex::Real rdOcp)
Copy the column-kernel parameters out of a RadChoice.
Definition: ERF_TwoStreamColumn.H:127
amrex::Box two_stream_scratch_box(const amrex::Box &bx)
Box of the scratch FArrayBox a sweep over box bx needs.
Definition: ERF_TwoStreamColumn.H:612
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void vertical_two_stream_sweep(int i, int j, const amrex::Box &bx, amrex::Real dz_uniform, const amrex::Array4< const amrex::Real > &state_arr, const TwoStreamParams &rad_choice, bool cloudy, const amrex::Array4< amrex::Real > &qheating_arr, amrex::Real &max_heating_rate, amrex::Real &sw_surface_flux, amrex::Real &sw_up_toa, amrex::Real &lw_net_surface, amrex::Real &lw_up_toa, amrex::Real &sw_down_toa, const amrex::Array4< const amrex::Real > &z_phys_nd, const amrex::Array4< amrex::Real > &scratch, bool has_hetero_alb_sw=false, const amrex::Array4< const amrex::Real > *hetero_alb_sw=nullptr, bool has_hetero_emiss_lw=false, const amrex::Array4< const amrex::Real > *hetero_emiss_lw=nullptr, bool has_lsm_t_sfc=false, const amrex::Array4< const amrex::Real > *lsm_t_sfc=nullptr, bool has_seb_t_sfc=false, const amrex::Array4< const amrex::Real > *seb_t_sfc=nullptr, bool has_surface_layer=false, const amrex::Array4< const amrex::Real > *surface_layer_theta=nullptr, bool has_latlon=false, const amrex::Array4< const amrex::Real > *lat_arr=nullptr, const amrex::Array4< const amrex::Real > *lon_arr=nullptr, const amrex::Array4< amrex::Real > *rad_flux_out=nullptr)
GPU-safe per-column vertical integration kernel for two-stream radiation, computing either the clear-...
Definition: ERF_TwoStreamColumn.H:886
int Get_DataIdx(const int &lev, std::string &varname)
Definition: ERF_LandSurface.H:152
amrex::MultiFab * Get_Data_Ptr(const int &lev, const int &varIdx)
Definition: ERF_LandSurface.H:108
CSV logger and debug-print manager for radiation module.
Definition: ERF_RadiationDiagnostics.H:70
void append(int step, amrex::Real time, std::string const &call_site, amrex::Real sw_surface, amrex::Real sw_toa, amrex::Real sw_up_toa, amrex::Real lw_net_surface, amrex::Real lw_up_toa, amrex::Real heating_rate_max, amrex::Real seb_residual_mean=std::numeric_limits< amrex::Real >::quiet_NaN(), amrex::Real seb_residual_max=std::numeric_limits< amrex::Real >::quiet_NaN(), amrex::Real t_s_mean=std::numeric_limits< amrex::Real >::quiet_NaN(), amrex::Real t_s_max=std::numeric_limits< amrex::Real >::quiet_NaN(), amrex::Real q_s_mean=std::numeric_limits< amrex::Real >::quiet_NaN(), amrex::Real q_s_max=std::numeric_limits< amrex::Real >::quiet_NaN())
Append a diagnostic row to the CSV file.
Definition: ERF_RadiationDiagnostics.cpp:75
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_q_sfc
Definition: ERF_TwoStreamRadiation.H:166
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_grdflx_sfc
Definition: ERF_TwoStreamRadiation.H:165
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_lw_flux_sfc
Definition: ERF_TwoStreamRadiation.H:162
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_q_deep
Definition: ERF_TwoStreamRadiation.H:168
amrex::Real m_rdOcp
Definition: ERF_TwoStreamRadiation.H:148
amrex::Vector< FluxDiag > m_flux_diag
Definition: ERF_TwoStreamRadiation.H:170
bool active() const
True once a level has been defined with the model selected.
Definition: ERF_TwoStreamRadiation.H:50
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_emiss_lw
Definition: ERF_TwoStreamRadiation.H:157
std::unique_ptr< RadiationDiagnostics > m_diag
Definition: ERF_TwoStreamRadiation.H:153
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_t_sfc
Definition: ERF_TwoStreamRadiation.H:158
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_lh_sfc
Definition: ERF_TwoStreamRadiation.H:164
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_alb_sw
Definition: ERF_TwoStreamRadiation.H:156
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_sw_flux_sfc
Definition: ERF_TwoStreamRadiation.H:161
OrbitalCache m_orbit
Definition: ERF_TwoStreamRadiation.H:149
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_t_deep
Definition: ERF_TwoStreamRadiation.H:167
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_hfx_sfc
Definition: ERF_TwoStreamRadiation.H:163
@ rho
Definition: ERF_Kessler.H:25
constexpr int NCOMP
Definition: ERF_TwoStreamColumn.H:608
Container holding radiation-related choices and parameters.
Definition: ERF_RadStruct.H:70
std::string diag_file
Output file path for radiation diagnostics CSV. Paths are relative to the simulation working director...
Definition: ERF_RadStruct.H:206
amrex::Real surface_albedo_sw
Shortwave surface albedo fallback [0, 1] for per-column heterogeneous-surface-property resolution....
Definition: ERF_RadStruct.H:340
amrex::Real surface_emissivity_lw
Longwave surface emissivity fallback [0, 1] for per-column heterogeneous-surface-property resolution....
Definition: ERF_RadStruct.H:355
amrex::Real seb_grdflx_default
Fallback SEB ground heat flux [W/m^2].
Definition: ERF_RadStruct.H:396
amrex::Real diag_dedup_tol
Tolerance for time equality in duplicate guard [s]. Times within this tolerance are considered equal....
Definition: ERF_RadStruct.H:257
amrex::Real seb_restore_timescale_s
Force-restore timescale for surface temperature [s]. Relaxation time constant toward T_deep in progno...
Definition: ERF_RadStruct.H:446
std::string diag_callsite_mode
Call-site filtering mode: "both" (pre+post rows), "pre_only", or "post_only".
Definition: ERF_RadStruct.H:250
bool diag_regtest_line_enable
Enable RADIATION_DIAG: line emission. Controls regtest-parsing diagnostics line. Default true.
Definition: ERF_RadStruct.H:237
amrex::Real seb_lh_default
Fallback SEB latent heat flux [W/m^2].
Definition: ERF_RadStruct.H:391
amrex::Real seb_moisture_restore_timescale_s
Force-restore timescale for surface moisture [s]. Relaxation time constant toward q_deep in prognosti...
Definition: ERF_RadStruct.H:462
amrex::Real seb_lw_flux_default
Fallback SEB surface net longwave flux [W/m^2].
Definition: ERF_RadStruct.H:381
amrex::Real seb_q_sfc_default
Fallback SEB surface moisture [kg/kg].
Definition: ERF_RadStruct.H:401
bool diag_csv_enable
Enable CSV file append behavior. When false, no file writes; other enabled streams may still print....
Definition: ERF_RadStruct.H:244
amrex::Real seb_t_deep_default
Fallback SEB deep soil temperature [K].
Definition: ERF_RadStruct.H:406
amrex::Real seb_prognostic_t_max_k
Maximum clamping bound for prognostic surface temperature [K]. After each Euler update,...
Definition: ERF_RadStruct.H:479
amrex::Real rad_t_sfc
erf.rad_t_sfc: surface temperature [K] used as the longwave boundary condition wherever no land-surfa...
Definition: ERF_RadStruct.H:135
bool seb_prognostic_enable
Enable prognostic SEB surface temperature and moisture evolution. When true, integrates SEB residual ...
Definition: ERF_RadStruct.H:430
bool seb_use_radiation_fluxes
Take the SEB's net surface shortwave and longwave fluxes from the two-stream sweep itself (per column...
Definition: ERF_RadStruct.H:371
amrex::Real seb_prognostic_t_min_k
Minimum clamping bound for prognostic surface temperature [K]. After each Euler update,...
Definition: ERF_RadStruct.H:471
amrex::Real cloud_fraction
Cloud fraction in [0, 1] used to blend clear-sky and cloudy-column fluxes: F = (1 - cloud_fraction) *...
Definition: ERF_RadStruct.H:292
amrex::Real seb_prognostic_q_max
Maximum clamping bound for prognostic surface moisture [kg/kg]. After each Euler update,...
Definition: ERF_RadStruct.H:495
amrex::Real seb_moisture_layer_depth_m
Effective surface moisture layer depth [m]. Used in force-restore prognostic q_s equation: dq_s/dt = ...
Definition: ERF_RadStruct.H:454
amrex::Real seb_hfx_default
Fallback SEB sensible heat flux [W/m^2].
Definition: ERF_RadStruct.H:386
bool diag_tagged_enable
Enable tagged [RAD][...] debug lines. Controls emission of bracketed-tag debug output....
Definition: ERF_RadStruct.H:230
amrex::Real seb_q_deep_default
Fallback SEB deep soil moisture [kg/kg].
Definition: ERF_RadStruct.H:411
amrex::Real seb_sw_flux_default
Fallback SEB surface net shortwave flux [W/m^2].
Definition: ERF_RadStruct.H:376
bool diag_enable
Master switch for radiation diagnostics emission. When false, no diagnostics output (stdout/tagged/re...
Definition: ERF_RadStruct.H:216
amrex::Real seb_prognostic_q_min
Minimum clamping bound for prognostic surface moisture [kg/kg]. After each Euler update,...
Definition: ERF_RadStruct.H:487
bool seb_enable
Master switch for simplified SEB infrastructure. When false (default), no SEB MultiFabs are allocated...
Definition: ERF_RadStruct.H:361
bool diag_stdout_enable
Enable human-readable stdout diagnostics block. Controls tagged [RAD][...] debug line emission (when ...
Definition: ERF_RadStruct.H:223
int verbosity
Debug verbosity level (0=off, 1+=debug output). Gated debug prints only emit when this is >= 1.
Definition: ERF_RadStruct.H:200
amrex::Real seb_surface_heat_capacity
Effective surface heat capacity [J/(m^2*K)]. Used in force-restore prognostic T_s equation: dT_s/dt =...
Definition: ERF_RadStruct.H:438
bool seb_diagnostic_enable
Enable diagnostic SEB residual computation and reporting. When true, computes and reports SEB residua...
Definition: ERF_RadStruct.H:421
Trivially copyable subset of RadChoice used by the column kernels.
Definition: ERF_TwoStreamColumn.H:57