ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
Radiation Class Reference

#include <ERF_Radiation.H>

Collaboration diagram for Radiation:

Public Member Functions

 Radiation ()
 
 ~Radiation ()=default
 
void initialize (const amrex::MultiFab &cons_in, amrex::MultiFab *lsm_fluxes, amrex::MultiFab *lsm_zenith, amrex::MultiFab *qheating_rates, amrex::MultiFab *lat, amrex::MultiFab *lon, amrex::Vector< amrex::MultiFab * > qmoist, const amrex::BoxArray &grids, const amrex::Geometry &geom, const amrex::Real &dt_advance, const bool &do_sw_rad, const bool &do_lw_rad, const bool &do_aero_rad, const bool &do_snow_opt, const bool &is_cmip6_volcano)
 
void run ()
 
void on_complete ()
 
void radiation_driver_lw (int ncol, int nlev, const real3d &gas_vmr, const real2d &pmid, const real2d &pint, const real2d &tmid, const real2d &tint, const real3d &cld_tau_gpt, const real3d &aer_tau_bnd, FluxesByband &fluxes_clrsky, FluxesByband &fluxes_allsky, const real2d &qrl, const real2d &qrlc)
 
void radiation_driver_sw (int ncol, const real3d &gas_vmr, const real2d &pmid, const real2d &pint, const real2d &tmid, const real2d &albedo_dir, const real2d &albedo_dif, const real1d &coszrs, const real3d &cld_tau_gpt, const real3d &cld_ssa_gpt, const real3d &cld_asm_gpt, const real3d &aer_tau_bnd, const real3d &aer_ssa_bnd, const real3d &aer_asm_bnd, FluxesByband &fluxes_clrsky, FluxesByband &fluxes_allsky, const real2d &qrs, const real2d &qrsc)
 
void set_daynight_indices (const real1d &coszrs, const int1d &day_indices, const int1d &night_indices)
 
void get_gas_vmr (const std::vector< std::string > &gas_names, const real3d &gas_vmr)
 
void calculate_heating_rate (const real2d &flux_up, const real2d &flux_dn, const real2d &pint, const real2d &heating_rate)
 
void export_surface_fluxes (FluxesByband &fluxes, std::string band)
 
void yakl_to_mf (const real2d &data, amrex::MultiFab &mf)
 
void expand_yakl1d_to_mf (const real1d &data, amrex::MultiFab &mf)
 
void writePlotfile (const std::string &plot_prefix, const amrex::Real time, const int level_step)
 

Private Attributes

amrex::Geometry m_geom
 
amrex::BoxArray m_box
 
amrex::MultiFab * qrad_src = nullptr
 
amrex::MultiFab * m_lat = nullptr
 
amrex::MultiFab * m_lon = nullptr
 
amrex::MultiFab * m_lsm_fluxes = nullptr
 
amrex::MultiFab * m_lsm_zenith = nullptr
 
std::string moisture_type = "None"
 
bool has_qmoist
 
amrex::Vector< int > rank_offsets
 
amrex::Real uniform_angle = 78.463
 
int nlev
 
int zlo
 
int zhi
 
int ncol
 
int nlwgpts
 
int nswgpts
 
int nlwbands
 
int nswbands
 
bool do_short_wave_rad
 
bool do_long_wave_rad
 
bool do_snow_optics
 
bool do_aerosol_rad = true
 
Rrtmgp radiation
 
Optics optics
 
AerRadProps aer_rad
 
real1d net_flux
 
bool is_cmip6_volc
 
real dt
 
real1d fsns
 
real1d fsnt
 
real1d flns
 
real1d flnt
 
real1d fsds
 
const std::vector< std::string > active_gases
 
bool spectralflux = false
 
bool use_rad_dt_cosz = false
 
real fixed_total_solar_irradiance = -1.
 
bool rrtmgp_enable_temperature_warnings = true
 
bool dohirs = false
 
int ihirsfq = 1
 
real dt_avg = 0.0
 
std::string rrtmgp_data_path
 
std::string rrtmgp_coefficients_file_sw
 
std::string rrtmgp_coefficients_file_lw
 
std::string rrtmgp_coefficients_file_name_sw = "rrtmgp_coefficients_sw_20181204.nc"
 
std::string rrtmgp_coefficients_file_name_lw = "rrtmgp_coefficients_lw_20181204.nc"
 
real1d sw_band_midpoints
 
real1d lw_band_midpoints
 
int ngas
 
int naer
 
std::vector< std::string > gasnames
 
std::vector< std::string > aernames
 
int1d rrtmg_to_rrtmgp
 
real2d qrs
 
real2d qrl
 
real2d zi
 
real2d clear_rh
 
real2d qrsc
 
real2d qrlc
 
real2d qt
 
real2d qi
 
real2d qc
 
real2d qn
 
real2d tmid
 
real2d pmid
 
real2d pdel
 
real2d pint
 
real2d tint
 
real2d albedo_dir
 
real2d albedo_dif
 
real1d coszrs
 
real2d cld
 
real2d cldfsnow
 
real2d iclwp
 
real2d iciwp
 
real2d icswp
 
real2d dei
 
real2d des
 
real2d lambdac
 
real2d mu
 
real2d rei
 
real2d rel
 
real3d cld_tau_gpt_sw
 
real3d cld_ssa_gpt_sw
 
real3d cld_asm_gpt_sw
 
real3d cld_tau_bnd_sw
 
real3d cld_ssa_bnd_sw
 
real3d cld_asm_bnd_sw
 
real3d aer_tau_bnd_sw
 
real3d aer_ssa_bnd_sw
 
real3d aer_asm_bnd_sw
 
real3d cld_tau_bnd_lw
 
real3d aer_tau_bnd_lw
 
real3d cld_tau_gpt_lw
 
real3d liq_tau_bnd_sw
 
real3d ice_tau_bnd_sw
 
real3d snw_tau_bnd_sw
 
real3d liq_tau_bnd_lw
 
real3d ice_tau_bnd_lw
 
real3d snw_tau_bnd_lw
 
real3d gas_vmr
 
int1d gpoint_bands_sw
 
int1d gpoint_bands_lw
 
FluxesByband sw_fluxes_allsky
 
FluxesByband sw_fluxes_clrsky
 
real1d cld_tau_bnd_sw_1d
 
real1d cld_ssa_bnd_sw_1d
 
real1d cld_asm_bnd_sw_1d
 
real1d cld_tau_bnd_sw_o_1d
 
real1d cld_ssa_bnd_sw_o_1d
 
real1d cld_asm_bnd_sw_o_1d
 
real1d aer_tau_bnd_sw_1d
 
real1d aer_ssa_bnd_sw_1d
 
real1d aer_asm_bnd_sw_1d
 
real1d aer_tau_bnd_sw_o_1d
 
real1d aer_ssa_bnd_sw_o_1d
 
real1d aer_asm_bnd_sw_o_1d
 
FluxesByband lw_fluxes_allsky
 
FluxesByband lw_fluxes_clrsky
 

Static Private Attributes

static constexpr amrex::Real eccen = 0.0
 
static constexpr amrex::Real obliqr = 23.0 * PI / 180.0
 
static constexpr amrex::Real mvelpp = 103.0 * PI / 180.0 + PI
 
static constexpr amrex::Real lambm0 = -3.2503635878519378e-2
 

Constructor & Destructor Documentation

◆ Radiation()

Radiation::Radiation ( )
inline
38  {
39  // First, make sure yakl has been initialized
40  if (!yakl::isInitialized()) yakl::init();
41  }

◆ ~Radiation()

Radiation::~Radiation ( )
default

Member Function Documentation

◆ calculate_heating_rate()

void Radiation::calculate_heating_rate ( const real2d &  flux_up,
const real2d &  flux_dn,
const real2d &  pint,
const real2d &  heating_rate 
)
963 {
964  // NOTE: The pressure is in [pa] for RRTMGP to use.
965  // The fluxes are in [W/m^2] and gravity is [m/s^2].
966  // The heating rate is {dF/dP * g / Cp} with units [K/s]
967  real1d heatfac("heatfac",1);
968  yakl::memset(heatfac, 1.0/Cp_d);
969  parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev)
970  {
971  heating_rate(icol,ilev) = heatfac(1) * ( (flux_up(icol,ilev+1) - flux_dn(icol,ilev+1))
972  - (flux_up(icol,ilev ) - flux_dn(icol,ilev )) )
973  * CONST_GRAV/(pint(icol,ilev+1)-pint(icol,ilev));
974  /*
975  if (icol==1) {
976  amrex::Print() << "HR: " << ilev << ' '
977  << heating_rate(icol,ilev) << ' '
978  << (flux_up(icol,ilev+1) - flux_dn(icol,ilev+1)) << ' '
979  << (flux_up(icol,ilev ) - flux_dn(icol,ilev )) << ' '
980  << flux_up(icol,ilev+1) << ' '
981  << flux_dn(icol,ilev+1) << ' '
982  << (flux_up(icol,ilev+1) - flux_dn(icol,ilev+1))
983  - (flux_up(icol,ilev ) - flux_dn(icol,ilev )) << ' '
984  << (pint(icol,ilev+1)-pint(icol,ilev)) << ' '
985  << CONST_GRAV << "\n";
986  }
987  */
988  });
989 }
constexpr amrex::Real Cp_d
Definition: ERF_Constants.H:12
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:21
real2d pint
Definition: ERF_Radiation.H:252
int nlev
Definition: ERF_Radiation.H:136
int ncol
Definition: ERF_Radiation.H:139

◆ expand_yakl1d_to_mf()

void Radiation::expand_yakl1d_to_mf ( const real1d &  data,
amrex::MultiFab &  mf 
)
1106 {
1107  // copies the 1D yakl data to a 3D MF
1108  AMREX_ASSERT(data.get_dimensions()(1) == ncol);
1109  mf = amrex::MultiFab(m_box, qrad_src->DistributionMap(), 1, 0);
1110  if (!data.initialized())
1111  {
1112  // yakl array hasn't been created yet, so create an empty MF
1113  mf.setVal(0.0);
1114  return;
1115  }
1116 
1117  for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
1118  auto mf_arr = mf.array(mfi);
1119  const auto& box3d = mfi.tilebox();
1120  const int nx = box3d.length(0);
1121  const int offset = rank_offsets[mfi.LocalIndex()];
1122  amrex::ParallelFor(box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1123  {
1124  // map [i,j,k] 0-based to [icol, ilev] 1-based
1125  const int icol = (j-box3d.smallEnd(1))*nx + (i-box3d.smallEnd(0)) + 1 + offset;
1126  AMREX_ASSERT(icol <= static_cast<int>(data.get_dimensions()(1)));
1127  mf_arr(i, j, k) = data(icol);
1128  });
1129  }
1130 }
AMREX_FORCE_INLINE IntVect offset(const int face_dir, const int normal)
Definition: ERF_ReadBndryPlanes.cpp:28
amrex::BoxArray m_box
Definition: ERF_Radiation.H:108
amrex::Vector< int > rank_offsets
Definition: ERF_Radiation.H:124
amrex::MultiFab * qrad_src
Definition: ERF_Radiation.H:111
Here is the call graph for this function:

◆ export_surface_fluxes()

void Radiation::export_surface_fluxes ( FluxesByband &  fluxes,
std::string  band 
)
994 {
995  // No work to be done if we don't have valid pointers
996  if (!m_lsm_fluxes) return;
997 
998  if (band == "shortwave") {
999  real3d flux_dn_diffuse("flux_dn_diffuse", ncol, nlev+1, nswbands);
1000 
1001  // Calculate diffuse flux from total and direct
1002  // This only occurs at the bottom level (k index)
1003  parallel_for (SimpleBounds<3>(ncol, 1, nswbands), YAKL_LAMBDA (int icol, int ilev, int ibnd)
1004  {
1005  flux_dn_diffuse(icol,ilev,ibnd) = fluxes.bnd_flux_dn(icol,ilev,ibnd)
1006  - fluxes.bnd_flux_dn_dir(icol,ilev,ibnd);
1007  });
1008 
1009  // Populate the LSM data structure (this is a 2D MF)
1010  for (MFIter mfi(*(m_lsm_fluxes)); mfi.isValid(); ++mfi) {
1011  auto lsm_array = m_lsm_fluxes->array(mfi);
1012  const auto& box3d = mfi.tilebox();
1013  auto nx = box3d.length(0);
1014  const int offset = rank_offsets[mfi.LocalIndex()];
1015  amrex::ParallelFor(box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1016  {
1017  // Map (col,lev) to (i,j,k)
1018  auto icol = (j-box3d.smallEnd(1))*nx + (i-box3d.smallEnd(0)) + 1 + offset;
1019  auto ilev = k+1;
1020 
1021  // Direct fluxes
1022  Real sum1(0.0), sum2(0.0);
1023  for (int ibnd(1); ibnd<=9; ++ibnd) {
1024  sum1 += fluxes.bnd_flux_dn_dir(icol,ilev,ibnd);
1025  }
1026  for (int ibnd(11); ibnd<=14; ++ibnd) {
1027  sum2 += fluxes.bnd_flux_dn_dir(icol,ilev,ibnd);
1028  }
1029  sum1 += 0.5 * fluxes.bnd_flux_dn_dir(icol,ilev,10);
1030  sum2 += 0.5 * fluxes.bnd_flux_dn_dir(icol,ilev,10);
1031  lsm_array(i,j,k,0) = sum1;
1032  lsm_array(i,j,k,1) = sum2;
1033 
1034  // Diffuse fluxes
1035  sum1=0.0; sum2=0.0;
1036  for (int ibnd(1); ibnd<=9; ++ibnd) {
1037  sum1 += flux_dn_diffuse(icol,ilev,ibnd);
1038  }
1039  for (int ibnd(11); ibnd<=14; ++ibnd) {
1040  sum2 += flux_dn_diffuse(icol,ilev,ibnd);
1041  }
1042  sum1 += 0.5 * flux_dn_diffuse(icol,ilev,10);
1043  sum2 += 0.5 * flux_dn_diffuse(icol,ilev,10);
1044  lsm_array(i,j,k,2) = sum1;
1045  lsm_array(i,j,k,3) = sum2;
1046 
1047  // Net fluxes
1048  lsm_array(i,j,k,4) = fluxes.flux_net(icol,ilev);
1049  });
1050  }
1051  } else if (band == "longwave") {
1052  // Populate the LSM data structure (this is a 2D MF)
1053  for (MFIter mfi(*(m_lsm_fluxes)); mfi.isValid(); ++mfi) {
1054  auto lsm_array = m_lsm_fluxes->array(mfi);
1055  const auto& box3d = mfi.tilebox();
1056  auto nx = box3d.length(0);
1057  const int offset = rank_offsets[mfi.LocalIndex()];
1058  amrex::ParallelFor(box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1059  {
1060  // Map (col,lev) to (i,j,k)
1061  auto icol = (j-box3d.smallEnd(1))*nx + (i-box3d.smallEnd(0)) + 1 + offset;
1062  auto ilev = k+1;
1063 
1064  // Net fluxes
1065  lsm_array(i,j,k,5) = fluxes.flux_dn(icol,ilev);
1066  });
1067  }
1068  } else {
1069  amrex::Abort("Unknown radiation band type!");
1070  }
1071 }
int nswbands
Definition: ERF_Radiation.H:142
amrex::MultiFab * m_lsm_fluxes
Definition: ERF_Radiation.H:118
Here is the call graph for this function:

◆ get_gas_vmr()

void Radiation::get_gas_vmr ( const std::vector< std::string > &  gas_names,
const real3d &  gas_vmr 
)
856 {
857  // Mass mixing ratio
858  real2d mmr("mmr", ncol, nlev);
859 
860  // Gases and molecular weights. Note that we do NOT have CFCs yet (I think
861  // this is coming soon in RRTMGP). RRTMGP also allows for absorption due to
862  // CO and N2, which RRTMG did not have.
863  const std::vector<std::string> gas_species = {"H2O", "CO2", "O3", "N2O",
864  "CO" , "CH4", "O2", "N2"};
865  const std::vector<real> mol_weight_gas = {18.01528, 44.00950, 47.9982, 44.0128,
866  28.01010, 16.04246, 31.9980, 28.0134}; // g/mol
867  // Molar weight of air
868  //const real mol_weight_air = 28.97; // g/mol
869  // Defaults for gases that are not available (TODO: is this still accurate?)
870  const real co_vol_mix_ratio = 1.0e-7;
871  const real n2_vol_mix_ratio = 0.7906;
872 
873  // initialize
874  yakl::memset(gas_vmr, 0.);
875 
876  // For each gas species needed for RRTMGP, read the mass mixing ratio from the
877  // CAM rad_constituents interface, convert to volume mixing ratios, and
878  // subset for daytime-only indices if needed.
879  for (auto igas = 0; igas < gas_names.size(); ++igas) {
880 
881  std::cout << "gas_name: " << gas_names[igas] << "; igas: " << igas << std::endl;
882 
883  if (gas_names[igas] == "CO"){
884  // CO not available, use default
885  parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev)
886  {
887  gas_vmr(igas+1,icol,ilev) = co_vol_mix_ratio;
888  });
889  } else if (gas_names[igas] == "N2") {
890  // N2 not available, use default
891  parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev)
892  {
893  gas_vmr(igas+1,icol,ilev) = n2_vol_mix_ratio;
894  });
895  } else if (gas_names[igas] == "H2O") {
896  // Water vapor is represented as specific humidity in CAM, so we
897  // need to handle water a little differently
898  // rad_cnst_get_gas(icall, gas_species[igas], mmr);
899 
900  // Convert to volume mixing ratio by multiplying by the ratio of
901  // molecular weight of dry air to molecular weight of gas. Note that
902  // first specific humidity (held in the mass_mix_ratio array read
903  // from rad_constituents) is converted to an actual mass mixing ratio.
904  parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev)
905  {
906  gas_vmr(igas+1,icol,ilev) = qt(icol,ilev); //mmr(icol,ilev) / (
907  // 1. - mmr(icol,ilev))*mol_weight_air / mol_weight_gas[igas];
908  });
909  } else if (gas_names[igas] == "CO2") {
910  parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev)
911  {
912  gas_vmr(igas+1,icol,ilev) = 3.8868676125307193E-4;
913  });
914  } else if (gas_names[igas] == "O3") {
915  parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev)
916  {
917  gas_vmr(igas+1,icol,ilev) = 1.8868676125307193E-7;
918  });
919  } else if (gas_names[igas] == "N2O") {
920  parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev)
921  {
922  gas_vmr(igas+1,icol,ilev) = 3.8868676125307193E-7;
923  });
924  } else if (gas_names[igas] == "CH4") {
925  parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev)
926  {
927  gas_vmr(igas+1,icol,ilev) = 1.8868676125307193E-6;
928  });
929  } else if (gas_names[igas] == "O2") {
930  parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev)
931  {
932  gas_vmr(igas+1,icol,ilev) = 0.2095;
933  });
934  } else {
935  // Get mass mixing ratio from the rad_constituents interface
936  // rad_cnst_get_gas(icall, gas_species[igas], mmr);
937 
938  // Convert to volume mixing ratio by multiplying by the ratio of
939  // molecular weight of dry air to molecular weight of gas
940  parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev)
941  {
942  gas_vmr(igas+1,icol,ilev) = 1.0e-6; //mmr(icol,ilev)
943  // * mol_weight_air / mol_weight_gas[igas];
944  });
945  }
946  } // igas
947 }
real3d gas_vmr
Definition: ERF_Radiation.H:268
real2d qt
Definition: ERF_Radiation.H:250

◆ initialize()

void Radiation::initialize ( const amrex::MultiFab &  cons_in,
amrex::MultiFab *  lsm_fluxes,
amrex::MultiFab *  lsm_zenith,
amrex::MultiFab *  qheating_rates,
amrex::MultiFab *  lat,
amrex::MultiFab *  lon,
amrex::Vector< amrex::MultiFab * >  qmoist,
const amrex::BoxArray &  grids,
const amrex::Geometry &  geom,
const amrex::Real &  dt_advance,
const bool &  do_sw_rad,
const bool &  do_lw_rad,
const bool &  do_aero_rad,
const bool &  do_snow_opt,
const bool &  is_cmip6_volcano 
)
117 {
118  m_geom = geom;
119  m_box = grids;
120 
121  qrad_src = qheating_rates;
122 
123  auto dz = m_geom.CellSize(2);
124  auto lowz = m_geom.ProbLo(2);
125 
126  dt = dt_advance;
127 
128  do_short_wave_rad = do_sw_rad;
129  do_long_wave_rad = do_lw_rad;
130  do_aerosol_rad = do_aero_rad;
131  do_snow_optics = do_snow_opt;
132  is_cmip6_volc = is_cmip6_volcano;
133 
134  m_lat = lat;
135  m_lon = lon;
136 
137  m_lsm_fluxes = lsm_fluxes;
138  m_lsm_zenith = lsm_zenith;
139 
140  rrtmgp_data_path = getRadiationDataDir() + "/";
143 
144  ParmParse pp("erf");
145  pp.query("fixed_total_solar_irradiance", fixed_total_solar_irradiance);
146  pp.query("radiation_uniform_angle" , uniform_angle);
147  pp.query("moisture_model", moisture_type); // TODO: get from SolverChoice?
148  has_qmoist = (moisture_type != "None");
149 
150  nlev = geom.Domain().length(2);
151  ncol = 0;
152  rank_offsets.resize(cons_in.local_size());
153  for (MFIter mfi(cons_in, TileNoZ()); mfi.isValid(); ++mfi) {
154  const auto& box3d = mfi.tilebox();
155  int nx = box3d.length(0);
156  int ny = box3d.length(1);
157  rank_offsets[mfi.LocalIndex()] = ncol;
158  ncol += nx * ny;
159  }
160 
161  ngas = active_gases.size();
162 
163  // initialize cloud, aerosol, and radiation
167 
168  // initialize the radiation data
173 
174  rrtmg_to_rrtmgp = int1d("rrtmg_to_rrtmgp",14);
175  parallel_for(14, YAKL_LAMBDA (int i)
176  {
177  if (i == 1) {
178  rrtmg_to_rrtmgp(i) = 13;
179  } else {
180  rrtmg_to_rrtmgp(i) = i - 1;
181  }
182  });
183 
184  tmid = real2d("tmid", ncol, nlev);
185  pmid = real2d("pmid", ncol, nlev);
186  pdel = real2d("pdel", ncol, nlev);
187 
188  pint = real2d("pint", ncol, nlev+1);
189  tint = real2d("tint", ncol, nlev+1);
190 
191  qt = real2d("qt", ncol, nlev);
192  qc = real2d("qc", ncol, nlev);
193  qi = real2d("qi", ncol, nlev);
194  qn = real2d("qn", ncol, nlev);
195  zi = real2d("zi", ncol, nlev);
196 
197  // Get the temperature, density, theta, qt and qp from input
198  for (MFIter mfi(cons_in, TileNoZ()); mfi.isValid(); ++mfi) {
199  const auto& box3d = mfi.tilebox();
200  auto nx = box3d.length(0);
201 
202  auto states_array = cons_in.array(mfi);
203  auto qt_array = (has_qmoist) ? qmoist[0]->array(mfi) : Array4<Real> {};
204  auto qv_array = (has_qmoist) ? qmoist[1]->array(mfi) : Array4<Real> {};
205  auto qc_array = (has_qmoist) ? qmoist[2]->array(mfi) : Array4<Real> {};
206  auto qi_array = (has_qmoist && qmoist.size()>=8) ? qmoist[3]->array(mfi) : Array4<Real> {};
207  const int offset = rank_offsets[mfi.LocalIndex()];
208 
209  // Get pressure, theta, temperature, density, and qt, qp
210  ParallelFor(box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
211  {
212  auto icol = (j-box3d.smallEnd(1))*nx + (i-box3d.smallEnd(0)) + 1 + offset;
213  auto ilev = k+1;
214  Real qv = (qv_array) ? qv_array(i,j,k): 0.0;
215  qt(icol,ilev) = (qt_array) ? qt_array(i,j,k): 0.0;
216  qc(icol,ilev) = (qc_array) ? qc_array(i,j,k): 0.0;
217  qi(icol,ilev) = (qi_array) ? qi_array(i,j,k): 0.0;
218  qn(icol,ilev) = qc(icol,ilev) + qi(icol,ilev);
219  tmid(icol,ilev) = getTgivenRandRTh(states_array(i,j,k,Rho_comp),states_array(i,j,k,RhoTheta_comp),qv);
220  // NOTE: RRTMGP code expects pressure in pa
221  pmid(icol,ilev) = getPgivenRTh(states_array(i,j,k,RhoTheta_comp),qv);
222  });
223  }
224 
225  parallel_for(SimpleBounds<2>(ncol, nlev+1), YAKL_LAMBDA (int icol, int ilev)
226  {
227  if (ilev == 1) {
228  pint(icol, 1) = -0.5*pmid(icol, 2) + 1.5*pmid(icol, 1);
229  tint(icol, 1) = -0.5*tmid(icol, 2) + 1.5*tmid(icol, 1);
230  } else if (ilev <= nlev) {
231  pint(icol, ilev) = 0.5*(pmid(icol, ilev-1) + pmid(icol, ilev));
232  tint(icol, ilev) = 0.5*(tmid(icol, ilev-1) + tmid(icol, ilev));
233  } else {
234  pint(icol, nlev+1) = -0.5*pmid(icol, nlev-1) + 1.5*pmid(icol, nlev);
235  tint(icol, nlev+1) = -0.5*tmid(icol, nlev-1) + 1.5*tmid(icol, nlev);
236  }
237  });
238 
239  parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev)
240  {
241  zi(icol, ilev) = lowz + (ilev+0.5)*dz;
242  pdel(icol,ilev) = pint(icol,ilev+1) - pint(icol,ilev);
243  });
244 
245  albedo_dir = real2d("albedo_dir", nswbands, ncol);
246  albedo_dif = real2d("albedo_dif", nswbands, ncol);
247 
248  qrs = real2d("qrs", ncol, nlev); // shortwave radiative heating rate
249  qrl = real2d("qrl", ncol, nlev); // longwave radiative heating rate
250 
251  // Clear-sky heating rates are not on the physics buffer, and we have no
252  // reason to put them there, so declare these are regular arrays here
253  qrsc = real2d("qrsc", ncol, nlev);
254  qrlc = real2d("qrlc", ncol, nlev);
255 
256  int nmodes = 3;
257  int nrh = 1;
258  int top_lev = 1;
259  naer = 4;
260  std::vector<std::string> aero_names {"H2O", "N2", "O2", "O3"};
261  auto geom_radius = real2d("geom_radius", ncol, nlev);
262  yakl::memset(geom_radius, 0.1);
263 
265  ncol, nlev, nrh, top_lev, aero_names, zi,
266  pmid, pdel, tmid, qt, geom_radius);
267 
268  amrex::Print() << "LW coefficients file: " << rrtmgp_coefficients_file_lw
269  << "\nSW coefficients file: " << rrtmgp_coefficients_file_sw
270  << "\nFrequency (timesteps) of Shortwave Radiation calc: " << dt
271  << "\nFrequency (timesteps) of Longwave Radiation calc: " << dt
272  << "\nDo aerosol radiative calculations: " << do_aerosol_rad << std::endl;
273 
274 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getPgivenRTh(const amrex::Real rhotheta, const amrex::Real qv=0.)
Definition: ERF_EOS.H:84
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getTgivenRandRTh(const amrex::Real rho, const amrex::Real rhotheta, const amrex::Real qv=0.0)
Definition: ERF_EOS.H:46
#define Rho_comp
Definition: ERF_IndexDefines.H:36
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real pp(amrex::Real y)
Definition: ERF_MicrophysicsUtils.H:219
AMREX_FORCE_INLINE amrex::IntVect TileNoZ()
Definition: ERF_TileNoZ.H:11
void initialize(int ngas, int nmodes, int num_aeros, int nswbands, int nlwbands, int ncol, int nlev, int nrh, int top_lev, const std::vector< std::string > &aero_names, const real2d &zi, const real2d &pmid, const real2d &pdel, const real2d &temp, const real2d &qi, const real2d &geom_radius)
Definition: ERF_Optics.cpp:12
amrex::MultiFab * m_lon
Definition: ERF_Radiation.H:115
std::string rrtmgp_data_path
Definition: ERF_Radiation.H:218
real fixed_total_solar_irradiance
Definition: ERF_Radiation.H:196
std::string rrtmgp_coefficients_file_lw
Definition: ERF_Radiation.H:220
bool is_cmip6_volc
Definition: ERF_Radiation.H:169
std::string moisture_type
Definition: ERF_Radiation.H:121
real2d qrl
Definition: ERF_Radiation.H:238
real2d pmid
Definition: ERF_Radiation.H:251
real2d qrlc
Definition: ERF_Radiation.H:247
int1d rrtmg_to_rrtmgp
Definition: ERF_Radiation.H:234
int naer
Definition: ERF_Radiation.H:230
int nswgpts
Definition: ERF_Radiation.H:141
bool do_aerosol_rad
Definition: ERF_Radiation.H:151
real2d tint
Definition: ERF_Radiation.H:252
real2d zi
Definition: ERF_Radiation.H:241
const std::vector< std::string > active_gases
Definition: ERF_Radiation.H:181
real2d qi
Definition: ERF_Radiation.H:250
int nlwgpts
Definition: ERF_Radiation.H:141
std::string rrtmgp_coefficients_file_sw
Definition: ERF_Radiation.H:219
bool do_snow_optics
Definition: ERF_Radiation.H:147
real2d qn
Definition: ERF_Radiation.H:250
real dt
Definition: ERF_Radiation.H:171
std::string rrtmgp_coefficients_file_name_lw
Definition: ERF_Radiation.H:222
real2d qrs
Definition: ERF_Radiation.H:237
amrex::MultiFab * m_lsm_zenith
Definition: ERF_Radiation.H:119
Optics optics
Definition: ERF_Radiation.H:157
real2d albedo_dir
Definition: ERF_Radiation.H:253
real2d albedo_dif
Definition: ERF_Radiation.H:253
int nlwbands
Definition: ERF_Radiation.H:142
real2d qrsc
Definition: ERF_Radiation.H:246
real2d qc
Definition: ERF_Radiation.H:250
real2d tmid
Definition: ERF_Radiation.H:251
bool do_short_wave_rad
Definition: ERF_Radiation.H:145
real2d pdel
Definition: ERF_Radiation.H:251
bool has_qmoist
Definition: ERF_Radiation.H:122
Rrtmgp radiation
Definition: ERF_Radiation.H:154
amrex::Geometry m_geom
Definition: ERF_Radiation.H:105
std::string rrtmgp_coefficients_file_name_sw
Definition: ERF_Radiation.H:221
amrex::MultiFab * m_lat
Definition: ERF_Radiation.H:114
amrex::Real uniform_angle
Definition: ERF_Radiation.H:127
int ngas
Definition: ERF_Radiation.H:230
bool do_long_wave_rad
Definition: ERF_Radiation.H:146
int get_ngpt_lw()
Definition: ERF_RRTMGP.H:89
int get_nband_sw()
Definition: ERF_RRTMGP.H:77
int get_nband_lw()
Definition: ERF_RRTMGP.H:81
int get_ngpt_sw()
Definition: ERF_RRTMGP.H:85
void initialize(int num_gas, const std::vector< std::string > &active_gas_names, const char *rrtmgp_coefficients_file_sw, const char *rrtmgp_coefficients_file_lw)
Definition: ERF_InitRRTMGP.cpp:13
@ qv
Definition: ERF_Kessler.H:36
Here is the call graph for this function:

◆ on_complete()

void Radiation::on_complete ( )
1074 { }

◆ radiation_driver_lw()

void Radiation::radiation_driver_lw ( int  ncol,
int  nlev,
const real3d &  gas_vmr,
const real2d &  pmid,
const real2d &  pint,
const real2d &  tmid,
const real2d &  tint,
const real3d &  cld_tau_gpt,
const real3d &  aer_tau_bnd,
FluxesByband &  fluxes_clrsky,
FluxesByband &  fluxes_allsky,
const real2d &  qrl,
const real2d &  qrlc 
)
777 {
778  real3d cld_tau_gpt_rad("cld_tau_gpt_rad", ncol, nlev+1, nlwgpts);
779  real3d aer_tau_bnd_rad("aer_tau_bnd_rad", ncol, nlev+1, nlwgpts);
780 
781  // Surface emissivity needed for longwave
782  real2d surface_emissivity("surface_emissivity", nlwbands, ncol);
783 
784  // Temporary heating rates on radiation vertical grid
785  real3d gas_vmr_rad("gas_vmr_rad", ngas, ncol, nlev);
786 
787  // Set surface emissivity to 1 here. There is a note in the RRTMG
788  // implementation that this is treated in the land model, but the old
789  // RRTMG implementation also sets this to 1. This probably does not make
790  // a lot of difference either way, but if a more intelligent value
791  // exists or is assumed in the model we should use it here as well.
792  // TODO: set this more intelligently?
793  yakl::memset(surface_emissivity, 1.0);
794 
795  // Add an empty level above model top
796  yakl::memset(cld_tau_gpt_rad, 0.);
797  yakl::memset(aer_tau_bnd_rad, 0.);
798 
799  parallel_for(SimpleBounds<3>(ncol, nlev, nlwgpts), YAKL_LAMBDA (int icol, int ilev, int igpt)
800  {
801  cld_tau_gpt_rad(icol,ilev,igpt) = cld_tau_gpt(icol,ilev,igpt);
802  aer_tau_bnd_rad(icol,ilev,igpt) = aer_tau_bnd(icol,ilev,igpt);
803  });
804 
805  parallel_for(SimpleBounds<3>(ncol, nlev, ngas), YAKL_LAMBDA (int icol, int ilev, int igas)
806  {
807  gas_vmr_rad(igas,icol,ilev) = gas_vmr(igas,icol,ilev);
808  });
809 
810  // Do longwave radiative transfer calculations
812  gas_vmr_rad, pmid, tmid, pint, tint,
813  surface_emissivity, cld_tau_gpt_rad, aer_tau_bnd_rad,
814  fluxes_allsky.flux_up , fluxes_allsky.flux_dn , fluxes_allsky.flux_net ,
815  fluxes_allsky.bnd_flux_up, fluxes_allsky.bnd_flux_dn, fluxes_allsky.bnd_flux_net,
816  fluxes_clrsky.flux_up , fluxes_clrsky.flux_dn , fluxes_clrsky.flux_net ,
817  fluxes_clrsky.bnd_flux_up, fluxes_clrsky.bnd_flux_dn, fluxes_clrsky.bnd_flux_net);
818 
819  // Calculate heating rates
820  calculate_heating_rate(fluxes_allsky.flux_up,
821  fluxes_allsky.flux_dn,
822  pint, qrl);
823 
824  calculate_heating_rate(fluxes_allsky.flux_up,
825  fluxes_allsky.flux_dn,
826  pint, qrlc);
827 }
void calculate_heating_rate(const real2d &flux_up, const real2d &flux_dn, const real2d &pint, const real2d &heating_rate)
Definition: ERF_Radiation.cpp:959
void run_longwave_rrtmgp(int ngas, int ncol, int nlay, const real3d &gas_vmr, const real2d &pmid, const real2d &tmid, const real2d &pint, const real2d &tint, const real2d &emis_sfc, const real3d &cld_tau_gpt, const real3d &aer_tau_bnd, const real2d &allsky_flux_up, const real2d &allsky_flux_dn, const real2d &allsky_flux_net, const real3d &allsky_bnd_flux_up, const real3d &allsky_bnd_flux_dn, const real3d &allsky_bnd_flux_net, const real2d &clrsky_flux_up, const real2d &clrsky_flux_dn, const real2d &clrsky_flux_net, const real3d &clrsky_bnd_flux_up, const real3d &clrsky_bnd_flux_dn, const real3d &clrsky_bnd_flux_net)
Definition: ERF_RunLongWaveRRTMGP.cpp:10

◆ radiation_driver_sw()

void Radiation::radiation_driver_sw ( int  ncol,
const real3d &  gas_vmr,
const real2d &  pmid,
const real2d &  pint,
const real2d &  tmid,
const real2d &  albedo_dir,
const real2d &  albedo_dif,
const real1d &  coszrs,
const real3d &  cld_tau_gpt,
const real3d &  cld_ssa_gpt,
const real3d &  cld_asm_gpt,
const real3d &  aer_tau_bnd,
const real3d &  aer_ssa_bnd,
const real3d &  aer_asm_bnd,
FluxesByband &  fluxes_clrsky,
FluxesByband &  fluxes_allsky,
const real2d &  qrs,
const real2d &  qrsc 
)
589 {
590  // Incoming solar radiation, scaled for solar zenith angle
591  // and earth-sun distance
592  real2d solar_irradiance_by_gpt("solar_irradiance_by_gpt",ncol,nswgpts);
593 
594  // Gathered indices of day and night columns
595  // chunk_column_index = day_indices(daylight_column_index)
596  int1d day_indices("day_indices",ncol), night_indices("night_indices", ncol); // Indices of daylight coumns
597 
598  real1d coszrs_day("coszrs_day", ncol);
599  real2d albedo_dir_day("albedo_dir_day", nswbands, ncol), albedo_dif_day("albedo_dif_day", nswbands, ncol);
600  real2d pmid_day("pmid_day", ncol, nlev);
601  real2d tmid_day("tmid_day", ncol, nlev);
602  real2d pint_day("pint_day", ncol, nlev+1);
603 
604  real3d gas_vmr_day("gas_vmr_day", ngas, ncol, nlev);
605 
606  real3d cld_tau_gpt_day("cld_tau_gpt_day", ncol, nlev, nswgpts);
607  real3d cld_ssa_gpt_day("cld_ssa_gpt_day", ncol, nlev, nswgpts);
608  real3d cld_asm_gpt_day("cld_asm_gpt_day", ncol, nlev, nswgpts);
609  real3d aer_tau_bnd_day("aer_tau_bnd_day", ncol, nlev, nswbands);
610  real3d aer_ssa_bnd_day("aer_ssa_bnd_day", ncol, nlev, nswbands);
611  real3d aer_asm_bnd_day("aer_asm_bnd_day", ncol, nlev, nswbands);
612 
613  real3d cld_tau_gpt_rad("cld_tau_gpt_rad", ncol, nlev+1, nswgpts);
614  real3d cld_ssa_gpt_rad("cld_ssa_gpt_rad", ncol, nlev+1, nswgpts);
615  real3d cld_asm_gpt_rad("cld_asm_gpt_rad", ncol, nlev+1, nswgpts);
616  real3d aer_tau_bnd_rad("aer_tau_bnd_rad", ncol, nlev+1, nswgpts);
617  real3d aer_ssa_bnd_rad("aer_ssa_bnd_rad", ncol, nlev+1, nswgpts);
618  real3d aer_asm_bnd_rad("aer_asm_bnd_rad", ncol, nlev+1, nswgpts);
619 
620  // Scaling factor for total sky irradiance; used to account for orbital
621  // eccentricity, and could be used to scale total sky irradiance for different
622  // climates as well (i.e., paleoclimate simulations)
623  real tsi_scaling;
624  real solar_declination;
625 
627  // TODO: Integrate calendar day computation
628  int calday = 1;
629  // Get orbital eccentricity factor to scale total sky irradiance
630  shr_orb_decl(calday, eccen, mvelpp, lambm0, obliqr, solar_declination, tsi_scaling);
631  } else {
632  // For fixed TSI we divide by the default solar constant of 1360.9
633  // At some point we will want to replace this with a method that
634  // retrieves the solar constant
635  tsi_scaling = fixed_total_solar_irradiance / 1360.9;
636  }
637 
638  // Gather night/day column indices for subsetting SW inputs; we only want to
639  // do the shortwave radiative transfer during the daytime to save
640  // computational cost (and because RRTMGP will fail for cosine solar zenith
641  // angles less than or equal to zero)
642  set_daynight_indices(coszrs, day_indices, night_indices);
643  int1d nday("nday",1);
644  int1d nnight("nnight", 1);
645  yakl::memset(nday, 0);
646  yakl::memset(nnight, 0);
647  parallel_for(SimpleBounds<1>(ncol), YAKL_LAMBDA (int icol)
648  {
649  if (day_indices(icol) > 0) nday(1)++;
650  if (night_indices(icol) > 0) nnight(1)++;
651  });
652 
653  AMREX_ASSERT(nday(1) + nnight(1) == ncol);
654 
655  intHost1d num_day("num_day",1);
656  intHost1d num_night("num_night",1);
657  nday.deep_copy_to(num_day);
658  nnight.deep_copy_to(num_night);
659 
660  // If no daytime columns in this chunk, then we return zeros
661  if (num_day(1) == 0) {
662  // reset_fluxes(fluxes_allsky)
663  // reset_fluxes(fluxes_clrsky)
664  yakl::memset(qrs, 0.);
665  yakl::memset(qrsc, 0.);
666  return;
667  }
668 
669  // Compress to daytime-only arrays
670  parallel_for(SimpleBounds<2>(num_day(1), nlev), YAKL_LAMBDA (int iday, int ilev)
671  {
672  // 2D arrays
673  auto icol = day_indices(iday);
674  tmid_day(iday,ilev) = tmid(icol,ilev);
675  pmid_day(iday,ilev) = pmid(icol,ilev);
676  pint_day(iday,ilev) = pint(icol,ilev);
677  });
678  parallel_for(SimpleBounds<1>(num_day(1)), YAKL_LAMBDA (int iday)
679  {
680  // copy extra level for pmid
681  auto icol = day_indices(iday);
682  pint_day(iday,nlev+1) = pint(icol,nlev+1);
683 
684  coszrs_day(iday) = coszrs(icol);
685  AMREX_ASSERT(coszrs_day(iday) > 0.0);
686  });
687  parallel_for(SimpleBounds<3>(num_day(1), nlev, nswgpts), YAKL_LAMBDA (int iday, int ilev, int igpt)
688  {
689  auto icol = day_indices(iday);
690  cld_tau_gpt_day(iday,ilev,igpt) = cld_tau_gpt(icol,ilev,igpt);
691  cld_ssa_gpt_day(iday,ilev,igpt) = cld_ssa_gpt(icol,ilev,igpt);
692  cld_asm_gpt_day(iday,ilev,igpt) = cld_asm_gpt(icol,ilev,igpt);
693  });
694  parallel_for(SimpleBounds<2>(num_day(1), nswbands), YAKL_LAMBDA (int iday, int ibnd)
695  {
696  // albedo dims: [nswbands, ncol]
697  auto icol = day_indices(iday);
698  albedo_dir_day(ibnd,iday) = albedo_dir(ibnd,icol);
699  albedo_dif_day(ibnd,iday) = albedo_dif(ibnd,icol);
700  });
701 
702  parallel_for(SimpleBounds<3>(num_day(1), nlev, nswbands), YAKL_LAMBDA (int iday, int ilev, int ibnd)
703  {
704  auto icol = day_indices(iday);
705  aer_tau_bnd_day(iday,ilev,ibnd) = aer_tau_bnd(icol,ilev,ibnd);
706  aer_ssa_bnd_day(iday,ilev,ibnd) = aer_ssa_bnd(icol,ilev,ibnd);
707  aer_asm_bnd_day(iday,ilev,ibnd) = aer_asm_bnd(icol,ilev,ibnd);
708  });
709 
710  // Allocate shortwave fluxes (allsky and clearsky)
711  // NOTE: fluxes defined at interfaces, so initialize to have vertical
712  // dimension nlev_rad+1, while we initialized the RRTMGP input variables to
713  // have vertical dimension nlev_rad (defined at midpoints).
714  FluxesByband fluxes_clrsky_day, fluxes_allsky_day;
715  internal::initial_fluxes(num_day(1), nlev+1, nswbands, fluxes_allsky_day);
716  internal::initial_fluxes(num_day(1), nlev+1, nswbands, fluxes_clrsky_day);
717 
718  // Add an empty level above model top
719  // TODO: combine with day compression above
720  yakl::memset(cld_tau_gpt_rad, 0.);
721  yakl::memset(cld_ssa_gpt_rad, 0.);
722  yakl::memset(cld_asm_gpt_rad, 0.);
723 
724  yakl::memset(aer_tau_bnd_rad, 0.);
725  yakl::memset(aer_ssa_bnd_rad, 0.);
726  yakl::memset(aer_asm_bnd_rad, 0.);
727 
728  parallel_for(SimpleBounds<3>(num_day(1), nlev, nswgpts), YAKL_LAMBDA (int iday, int ilev, int igpt)
729  {
730  cld_tau_gpt_rad(iday,ilev,igpt) = cld_tau_gpt_day(iday,ilev,igpt);
731  cld_ssa_gpt_rad(iday,ilev,igpt) = cld_ssa_gpt_day(iday,ilev,igpt);
732  cld_asm_gpt_rad(iday,ilev,igpt) = cld_asm_gpt_day(iday,ilev,igpt);
733  });
734 
735  parallel_for(SimpleBounds<3>(num_day(1), nlev, ngas), YAKL_LAMBDA (int iday, int ilev, int igas)
736  {
737  auto icol = day_indices(iday);
738  gas_vmr_day(igas,iday,ilev) = gas_vmr(igas,icol,ilev);
739  });
740 
741  parallel_for(SimpleBounds<3>(num_day(1), nlev, nswbands), YAKL_LAMBDA (int iday, int ilev, int ibnd)
742  {
743  aer_tau_bnd_rad(iday,ilev,ibnd) = aer_tau_bnd_day(iday,ilev,ibnd);
744  aer_ssa_bnd_rad(iday,ilev,ibnd) = aer_ssa_bnd_day(iday,ilev,ibnd);
745  aer_asm_bnd_rad(iday,ilev,ibnd) = aer_asm_bnd_day(iday,ilev,ibnd);
746  });
747 
748  // Do shortwave radiative transfer calculations
749  radiation.run_shortwave_rrtmgp(ngas, num_day(1), nlev, gas_vmr_day, pmid_day,
750  tmid_day, pint_day, coszrs_day, albedo_dir_day, albedo_dif_day,
751  cld_tau_gpt_rad, cld_ssa_gpt_rad, cld_asm_gpt_rad, aer_tau_bnd_rad, aer_ssa_bnd_rad, aer_asm_bnd_rad,
752  fluxes_allsky_day.flux_up , fluxes_allsky_day.flux_dn , fluxes_allsky_day.flux_net , fluxes_allsky_day.flux_dn_dir ,
753  fluxes_allsky_day.bnd_flux_up, fluxes_allsky_day.bnd_flux_dn, fluxes_allsky_day.bnd_flux_net, fluxes_allsky_day.bnd_flux_dn_dir,
754  fluxes_clrsky_day.flux_up , fluxes_clrsky_day.flux_dn , fluxes_clrsky_day.flux_net , fluxes_clrsky_day.flux_dn_dir ,
755  fluxes_clrsky_day.bnd_flux_up, fluxes_clrsky_day.bnd_flux_dn, fluxes_clrsky_day.bnd_flux_net, fluxes_clrsky_day.bnd_flux_dn_dir,
756  tsi_scaling);
757 
758  // Expand fluxes from daytime-only arrays to full chunk arrays
759  internal::expand_day_fluxes(fluxes_allsky_day, fluxes_allsky, day_indices);
760  internal::expand_day_fluxes(fluxes_clrsky_day, fluxes_clrsky, day_indices);
761 
762  // Calculate heating rates
763  calculate_heating_rate(fluxes_allsky.flux_up,
764  fluxes_allsky.flux_dn,
765  pint, qrs);
766 
767  calculate_heating_rate(fluxes_clrsky.flux_up,
768  fluxes_allsky.flux_dn,
769  pint, qrsc);
770 }
AMREX_GPU_HOST AMREX_FORCE_INLINE void shr_orb_decl(const amrex::Real &calday, const amrex::Real &eccen, const amrex::Real &mvelpp, const amrex::Real &lambm0, const amrex::Real &obliqr, amrex::Real &delta, amrex::Real &eccf)
Definition: ERF_Orbit.H:52
static constexpr amrex::Real obliqr
Definition: ERF_Radiation.H:131
void set_daynight_indices(const real1d &coszrs, const int1d &day_indices, const int1d &night_indices)
Definition: ERF_Radiation.cpp:831
static constexpr amrex::Real eccen
Definition: ERF_Radiation.H:130
static constexpr amrex::Real lambm0
Definition: ERF_Radiation.H:133
real1d coszrs
Definition: ERF_Radiation.H:256
static constexpr amrex::Real mvelpp
Definition: ERF_Radiation.H:132
void run_shortwave_rrtmgp(int ngas, int ncol, int nlay, const real3d &gas_vmr, const real2d &pmid, const real2d &tmid, const real2d &pint, const real1d &coszrs, const real2d &albedo_dir, const real2d &albedo_dif, const real3d &cld_tau_gpt, const real3d &cld_ssa_gpt, const real3d &cld_asm_gpt, const real3d &aer_tau_bnd, const real3d &aer_ssa_bnd, const real3d &aer_asm_bnd, const real2d &allsky_flux_up, const real2d &allsky_flux_dn, const real2d &allsky_flux_net, const real2d &allsky_flux_dn_dir, const real3d &allsky_bnd_flux_up, const real3d &allsky_bnd_flux_dn, const real3d &allsky_bnd_flux_net, const real3d &allsky_bnd_flux_dn_dir, const real2d &clrsky_flux_up, const real2d &clrsky_flux_dn, const real2d &clrsky_flux_net, const real2d &clrsky_flux_dn_dir, const real3d &clrsky_bnd_flux_up, const real3d &clrsky_bnd_flux_dn, const real3d &clrsky_bnd_flux_net, const real3d &clrsky_bnd_flux_dn_dir, double tsi_scaling)
Definition: ERF_RunShortWaveRRTMGP.cpp:4
void expand_day_fluxes(const FluxesByband &daytime_fluxes, FluxesByband &expanded_fluxes, const int1d &day_indices)
Definition: ERF_Radiation.cpp:52
void initial_fluxes(int nz, int nlay, int nbands, FluxesByband &fluxes)
Definition: ERF_Radiation.cpp:39
Here is the call graph for this function:

◆ run()

void Radiation::run ( )
279 {
280  // Cosine solar zenith angle for all columns in chunk
281  coszrs = real1d("coszrs", ncol);
282 
283  // Pointers to fields on the physics buffer
284  cld = real2d("cld", ncol, nlev);
285  cldfsnow = real2d("cldfsnow", ncol, nlev);
286  iclwp = real2d("iclwp", ncol, nlev);
287  iciwp = real2d("iciwp", ncol, nlev);
288  icswp = real2d("icswp", ncol, nlev);
289  dei = real2d("dei", ncol, nlev);
290  des = real2d("des", ncol, nlev);
291  lambdac = real2d("lambdac", ncol, nlev);
292  mu = real2d("mu", ncol, nlev);
293  rei = real2d("rei", ncol, nlev);
294  rel = real2d("rel", ncol, nlev);
295 
296  // Cloud, snow, and aerosol optical properties
297  cld_tau_gpt_sw = real3d("cld_tau_gpt_sw", ncol, nlev, nswgpts);
298  cld_ssa_gpt_sw = real3d("cld_ssa_gpt_sw", ncol, nlev, nswgpts);
299  cld_asm_gpt_sw = real3d("cld_asm_gpt_sw", ncol, nlev, nswgpts);
300 
301  cld_tau_bnd_sw = real3d("cld_tau_bnd_sw", ncol, nlev, nswbands);
302  cld_ssa_bnd_sw = real3d("cld_ssa_bnd_sw", ncol, nlev, nswbands);
303  cld_asm_bnd_sw = real3d("cld_asm_bnd_sw", ncol, nlev, nswbands);
304 
305  aer_tau_bnd_sw = real3d("aer_tau_bnd_sw", ncol, nlev, nswbands);
306  aer_ssa_bnd_sw = real3d("aer_ssa_bnd_sw", ncol, nlev, nswbands);
307  aer_asm_bnd_sw = real3d("aer_asm_bnd_sw", ncol, nlev, nswbands);
308 
309  cld_tau_bnd_lw = real3d("cld_tau_bnd_lw", ncol, nlev, nlwbands);
310  aer_tau_bnd_lw = real3d("aer_tau_bnd_lw", ncol, nlev, nlwbands);
311 
312  cld_tau_gpt_lw = real3d("cld_tau_gpt_lw", ncol, nlev, nlwgpts);
313 
314  // NOTE: these are diagnostic only
315  liq_tau_bnd_sw = real3d("liq_tau_bnd_sw", ncol, nlev, nswbands);
316  ice_tau_bnd_sw = real3d("ice_tau_bnd_sw", ncol, nlev, nswbands);
317  snw_tau_bnd_sw = real3d("snw_tau_bnd_sw", ncol, nlev, nswbands);
318  liq_tau_bnd_lw = real3d("liq_tau_bnd_lw", ncol, nlev, nlwbands);
319  ice_tau_bnd_lw = real3d("ice_tau_bnd_lw", ncol, nlev, nlwbands);
320  snw_tau_bnd_lw = real3d("snw_tau_bnd_lw", ncol, nlev, nlwbands);
321 
322  // Gas volume mixing ratios
323  gas_vmr = real3d("gas_vmr", ngas, ncol, nlev);
324 
325  // Needed for shortwave aerosol;
326  //int nday, nnight; // Number of daylight columns
327  int1d day_indices("day_indices", ncol), night_indices("night_indices", ncol); // Indices of daylight coumns
328 
329  // Flag to carry (QRS,QRL)*dp across time steps.
330  // TODO: what does this mean?
331  bool conserve_energy = true;
332 
333  // For loops over diagnostic calls
334  //bool active_calls(0:N_DIAG)
335 
336  // Zero-array for cloud properties if not diagnosed by microphysics
337  real2d zeros("zeros", ncol, nlev);
338 
339  gpoint_bands_sw = int1d("gpoint_bands_sw", nswgpts);
340  gpoint_bands_lw = int1d("gpoint_bands_lw", nlwgpts);
341 
342  // Do shortwave stuff...
343  if (do_short_wave_rad) {
344  // Radiative fluxes
347 
348  // TODO: Integrate calendar day computation
349  int calday = 1;
350  // Get cosine solar zenith angle for current time step.
351  if (m_lat) {
354  } else {
357  }
358 
359  // Get albedo. This uses CAM routines internally and just provides a
360  // wrapper to improve readability of the code here.
362 
363  // Do shortwave cloud optics calculations
364  yakl::memset(cld_tau_gpt_sw, 0.);
365  yakl::memset(cld_ssa_gpt_sw, 0.);
366  yakl::memset(cld_asm_gpt_sw, 0.);
367 
368  // set cloud fraction to be 1, and snow fraction 0
369  yakl::memset(cldfsnow, 0.0);
370  yakl::memset(cld, 1.0);
371 
372  parallel_for (SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int i, int k)
373  {
374  iciwp(i,k) = std::min(qi(i,k)/std::max(1.0e-4,cld(i,k)),0.005)*pmid(i,k)/CONST_GRAV;
375  iclwp(i,k) = std::min(qt(i,k)/std::max(1.0e-4,cld(i,k)),0.005)*pmid(i,k)/CONST_GRAV;
376  icswp(i,k) = qn(i,k)/std::max(1.0e-4,cldfsnow(i,k))*pmid(i,k)/CONST_GRAV;
377  });
378 
380  rel, rei, dei, lambdac, mu, des);
381 
382  // calculate the cloud radiation
385  lambdac, mu, dei, des, rel, rei,
388 
389  // Now reorder bands to be consistent with RRTMGP
390  // We need to fix band ordering because the old input files assume RRTMG
391  // band ordering, but this has changed in RRTMGP.
392  // TODO: fix the input files themselves!
393  cld_tau_bnd_sw_1d = real1d("cld_tau_bnd_sw_1d", nswbands);
394  cld_ssa_bnd_sw_1d = real1d("cld_ssa_bnd_sw_1d", nswbands);
395  cld_asm_bnd_sw_1d = real1d("cld_asm_bnd_sw_1d", nswbands);
396  cld_tau_bnd_sw_o_1d = real1d("cld_tau_bnd_sw_1d", nswbands);
397  cld_ssa_bnd_sw_o_1d = real1d("cld_ssa_bnd_sw_1d", nswbands);
398  cld_asm_bnd_sw_o_1d = real1d("cld_asm_bnd_sw_1d", nswbands);
399 
400  parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilay)
401  {
402  for (auto ibnd = 1; ibnd <= nswbands; ++ibnd) {
403  cld_tau_bnd_sw_1d(ibnd) = cld_tau_bnd_sw(icol,ilay,ibnd);
404  cld_ssa_bnd_sw_1d(ibnd) = cld_ssa_bnd_sw(icol,ilay,ibnd);
405  cld_asm_bnd_sw_1d(ibnd) = cld_asm_bnd_sw(icol,ilay,ibnd);
406  }
410  for (auto ibnd = 1; ibnd <= nswbands; ++ibnd) {
411  cld_tau_bnd_sw(icol,ilay,ibnd) = cld_tau_bnd_sw_o_1d(ibnd);
412  cld_ssa_bnd_sw(icol,ilay,ibnd) = cld_ssa_bnd_sw_o_1d(ibnd);
413  cld_asm_bnd_sw(icol,ilay,ibnd) = cld_asm_bnd_sw_o_1d(ibnd);
414  }
415  });
416 
417  // And now do the MCICA sampling to get cloud optical properties by
418  // gpoint/cloud state
420 
422  pmid, cld, cldfsnow,
425 
426  // Aerosol needs night indices
427  // TODO: remove this dependency, it's just used to mask aerosol outputs
428  set_daynight_indices(coszrs, day_indices, night_indices);
429  int1d nday("nday",1);
430  int1d nnight("nnight",1);
431  yakl::memset(nday, 0);
432  yakl::memset(nnight, 0);
433  for (auto icol=1; icol<=ncol; ++icol) {
434  if (day_indices(icol) > 0) nday(1)++;
435  if (night_indices(icol) > 0) nnight(1)++;
436  }
437 
438  AMREX_ALWAYS_ASSERT(nday(1) + nnight(1) == ncol);
439 
440  // get aerosol optics
441  do_aerosol_rad = false; // TODO: this causes issues if enabled
442  {
443  // Get gas concentrations
445 
446  // Get aerosol optics
447  if (do_aerosol_rad) {
448  yakl::memset(aer_tau_bnd_sw, 0.);
449  yakl::memset(aer_ssa_bnd_sw, 0.);
450  yakl::memset(aer_asm_bnd_sw, 0.);
451 
452  clear_rh = real2d("clear_rh",ncol, nswbands);
453  yakl::memset(clear_rh, 0.01);
454 
455  optics.set_aerosol_optics_sw(0, ncol, nlev, nswbands, dt, night_indices,
457 
458  // Now reorder bands to be consistent with RRTMGP
459  // TODO: fix the input files themselves!
460  aer_tau_bnd_sw_1d = real1d("cld_tau_bnd_sw_1d", nswbands);
461  aer_ssa_bnd_sw_1d = real1d("cld_ssa_bnd_sw_1d", nswbands);
462  aer_asm_bnd_sw_1d = real1d("cld_asm_bnd_sw_1d", nswbands);
463  aer_tau_bnd_sw_o_1d = real1d("cld_tau_bnd_sw_1d", nswbands);
464  aer_ssa_bnd_sw_o_1d = real1d("cld_ssa_bnd_sw_1d", nswbands);
465  aer_asm_bnd_sw_o_1d = real1d("cld_asm_bnd_sw_1d", nswbands);
466 
467  parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilay)
468  {
469  for (auto ibnd = 1; ibnd <= nswbands; ++ibnd) {
470  aer_tau_bnd_sw_1d(ibnd) = aer_tau_bnd_sw(icol,ilay,ibnd);
471  aer_ssa_bnd_sw_1d(ibnd) = aer_ssa_bnd_sw(icol,ilay,ibnd);
472  aer_asm_bnd_sw_1d(ibnd) = aer_asm_bnd_sw(icol,ilay,ibnd);
473  }
477  for (auto ibnd = 1; ibnd <= nswbands; ++ibnd) {
478  aer_tau_bnd_sw(icol,ilay,ibnd) = aer_tau_bnd_sw_o_1d(ibnd);
479  aer_ssa_bnd_sw(icol,ilay,ibnd) = aer_ssa_bnd_sw_o_1d(ibnd);
480  aer_asm_bnd_sw(icol,ilay,ibnd) = aer_asm_bnd_sw_o_1d(ibnd);
481  }
482  });
483  } else {
484  yakl::memset(aer_tau_bnd_sw, 0.);
485  yakl::memset(aer_ssa_bnd_sw, 0.);
486  yakl::memset(aer_asm_bnd_sw, 0.);
487  }
488 
489  yakl::memset(cld_tau_gpt_sw, 0.);
490  yakl::memset(cld_ssa_gpt_sw, 0.);
491  yakl::memset(cld_asm_gpt_sw, 0.);
492 
493  // Call the shortwave radiation driver
499  }
500 
501  // Set surface fluxes that are used by the land model
503 
504  } else {
505  // Conserve energy
506  if (conserve_energy) {
507  parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev)
508  {
509  qrs(icol,ilev) = qrs(icol,ilev)/pdel(icol,ilev);
510  });
511  }
512  } // dosw
513 
514  // Do longwave stuff...
515  if (do_long_wave_rad) {
516  // Allocate longwave outputs; why is this not part of the fluxes_t object?
519 
520  // NOTE: fluxes defined at interfaces, so initialize to have vertical dimension nlev_rad+1
521  yakl::memset(cld_tau_gpt_lw, 0.);
522 
524  lambdac, mu, dei, des, rei,
526 
528 
530  pmid, cld, cldfsnow,
532 
533  // Get gas concentrations
535 
536  // Get aerosol optics
537  yakl::memset(aer_tau_bnd_lw, 0.);
538  if (do_aerosol_rad) {
540  }
541 
542  // Call the longwave radiation driver to calculate fluxes and heating rates
545 
546  // Set surface fluxes that are used by the land model
548 
549  }
550  else {
551  // Conserve energy (what does this mean exactly?)
552  if (conserve_energy) {
553  parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev)
554  {
555  qrl(icol,ilev) = qrl(icol,ilev)/pdel(icol,ilev);
556  });
557  }
558  } // dolw
559 
560  // Populate source term for theta dycore variable
561  for (MFIter mfi(*(qrad_src)); mfi.isValid(); ++mfi) {
562  auto qrad_src_array = qrad_src->array(mfi);
563  const auto& box3d = mfi.tilebox();
564  auto nx = box3d.length(0);
565  int const offset = rank_offsets[mfi.LocalIndex()];
566  amrex::ParallelFor(box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
567  {
568  // Map (col,lev) to (i,j,k)
569  auto icol = (j-box3d.smallEnd(1))*nx + (i-box3d.smallEnd(0)) + 1 + offset;
570  auto ilev = k+1;
571 
572  // TODO: We do not include the cloud source term qrsc/qrlc.
573  // Do these simply sum for a net source or do we pick one?
574 
575  // SW and LW sources
576  qrad_src_array(i,j,k,0) = qrs(icol,ilev);
577  qrad_src_array(i,j,k,1) = qrl(icol,ilev);
578  });
579  }
580 }
void set_albedo(const real1d &coszrs, real2d &albedo_dir, real2d &albedo_dif)
Definition: ERF_Albedo.cpp:5
YAKL_INLINE void m2005_effradius(const real2d &ql, const real2d &nl, const real2d &qi, const real2d &ni, const real2d &qs, const real2d &ns, const real2d &cld, const real2d &pres, const real2d &tk, const real2d &effl, const real2d &effi, const real2d &deffi, const real2d &lamcrad, const real2d &pgamrad, const real2d &des)
Definition: ERF_M2005EffRadius.H:25
void zenith(int &calday, amrex::MultiFab *clat, amrex::MultiFab *clon, const amrex::Vector< int > &rank_offsets, real1d &coszrs, int &ncol, const Real &eccen, const Real &mvelpp, const Real &lambm0, const Real &obliqr, amrex::Real uniform_angle)
Definition: ERF_Orbit.cpp:6
void aer_rad_props_lw(const bool &is_cmip6_volc, const int &list_idx, const real &dt, const real2d &zi, const real3d &odap_aer, const real2d &clear_rh)
Definition: ERF_AeroRadProps.cpp:304
void set_aerosol_optics_sw(int icall, int ncol, int nlev, int nswbands, real dt, const int1d &night_indices, bool is_cmip6_volc, const real3d &tau_out, const real3d &ssa_out, const real3d &asm_out, const real2d &clear_rh)
Definition: ERF_Optics.cpp:358
void sample_cloud_optics_lw(int ncol, int nlev, int ngpt, const int1d &gpt2bnd, const real2d &pmid, const real2d &cld, const real2d &cldfsnow, const real3d &tau_bnd, const real3d &tau_gpt)
Definition: ERF_Optics.cpp:324
void sample_cloud_optics_sw(int ncol, int nlev, int ngpt, const int1d &gpt2bnd, const real2d &pmid, const real2d &cld, const real2d &cldfsnow, const real3d &tau_bnd, const real3d &ssa_bnd, const real3d &asm_bnd, const real3d &tau_gpt, const real3d &ssa_gpt, const real3d &asm_gpt)
Definition: ERF_Optics.cpp:286
void get_cloud_optics_sw(int ncol, int nlev, int nbnd, bool do_snow, const real2d &cld, const real2d &cldfsnow, const real2d &iclwp, const real2d &iciwp, const real2d &icswp, const real2d &lambdac, const real2d &mu, const real2d &dei, const real2d &des, const real2d &rel, const real2d &rei, const real3d &tau_out, const real3d &ssa_out, const real3d &asm_out, const real3d &liq_tau_out, const real3d &ice_tau_out, const real3d &snw_tau_out)
Definition: ERF_Optics.cpp:32
void get_cloud_optics_lw(int ncol, int nlev, int nbnd, bool do_snow, const real2d &cld, const real2d &cldfsnow, const real2d &iclwp, const real2d &iciwp, const real2d &icswp, const real2d &lambdac, const real2d &mu, const real2d &dei, const real2d &des, const real2d &rei, const real3d &tau_out, const real3d &liq_tau_out, const real3d &ice_tau_out, const real3d &snw_tau_out)
Definition: ERF_Optics.cpp:182
real3d cld_tau_gpt_lw
Definition: ERF_Radiation.H:263
real2d clear_rh
Definition: ERF_Radiation.H:242
real3d aer_tau_bnd_sw
Definition: ERF_Radiation.H:261
real3d aer_ssa_bnd_sw
Definition: ERF_Radiation.H:261
real2d rei
Definition: ERF_Radiation.H:257
void get_gas_vmr(const std::vector< std::string > &gas_names, const real3d &gas_vmr)
Definition: ERF_Radiation.cpp:855
real3d liq_tau_bnd_lw
Definition: ERF_Radiation.H:266
real2d mu
Definition: ERF_Radiation.H:257
void export_surface_fluxes(FluxesByband &fluxes, std::string band)
Definition: ERF_Radiation.cpp:992
real3d cld_ssa_gpt_sw
Definition: ERF_Radiation.H:259
real3d aer_asm_bnd_sw
Definition: ERF_Radiation.H:261
real1d aer_ssa_bnd_sw_o_1d
Definition: ERF_Radiation.H:276
real1d aer_tau_bnd_sw_o_1d
Definition: ERF_Radiation.H:276
real1d cld_asm_bnd_sw_o_1d
Definition: ERF_Radiation.H:273
real1d cld_tau_bnd_sw_o_1d
Definition: ERF_Radiation.H:273
real1d aer_ssa_bnd_sw_1d
Definition: ERF_Radiation.H:275
real2d dei
Definition: ERF_Radiation.H:257
real3d snw_tau_bnd_lw
Definition: ERF_Radiation.H:266
real3d cld_tau_bnd_lw
Definition: ERF_Radiation.H:262
real2d des
Definition: ERF_Radiation.H:257
real1d cld_tau_bnd_sw_1d
Definition: ERF_Radiation.H:272
AerRadProps aer_rad
Definition: ERF_Radiation.H:160
real3d cld_asm_gpt_sw
Definition: ERF_Radiation.H:259
int1d gpoint_bands_sw
Definition: ERF_Radiation.H:269
real2d cld
Definition: ERF_Radiation.H:257
FluxesByband sw_fluxes_clrsky
Definition: ERF_Radiation.H:271
real3d cld_asm_bnd_sw
Definition: ERF_Radiation.H:260
real2d rel
Definition: ERF_Radiation.H:257
real1d aer_asm_bnd_sw_1d
Definition: ERF_Radiation.H:275
real2d iclwp
Definition: ERF_Radiation.H:257
real2d iciwp
Definition: ERF_Radiation.H:257
real3d ice_tau_bnd_lw
Definition: ERF_Radiation.H:266
real2d lambdac
Definition: ERF_Radiation.H:257
real3d ice_tau_bnd_sw
Definition: ERF_Radiation.H:265
FluxesByband sw_fluxes_allsky
Definition: ERF_Radiation.H:271
real3d cld_tau_gpt_sw
Definition: ERF_Radiation.H:259
void radiation_driver_sw(int ncol, const real3d &gas_vmr, const real2d &pmid, const real2d &pint, const real2d &tmid, const real2d &albedo_dir, const real2d &albedo_dif, const real1d &coszrs, const real3d &cld_tau_gpt, const real3d &cld_ssa_gpt, const real3d &cld_asm_gpt, const real3d &aer_tau_bnd, const real3d &aer_ssa_bnd, const real3d &aer_asm_bnd, FluxesByband &fluxes_clrsky, FluxesByband &fluxes_allsky, const real2d &qrs, const real2d &qrsc)
Definition: ERF_Radiation.cpp:582
real1d aer_tau_bnd_sw_1d
Definition: ERF_Radiation.H:275
real3d liq_tau_bnd_sw
Definition: ERF_Radiation.H:265
void radiation_driver_lw(int ncol, int nlev, const real3d &gas_vmr, const real2d &pmid, const real2d &pint, const real2d &tmid, const real2d &tint, const real3d &cld_tau_gpt, const real3d &aer_tau_bnd, FluxesByband &fluxes_clrsky, FluxesByband &fluxes_allsky, const real2d &qrl, const real2d &qrlc)
Definition: ERF_Radiation.cpp:772
real1d cld_ssa_bnd_sw_1d
Definition: ERF_Radiation.H:272
real1d cld_ssa_bnd_sw_o_1d
Definition: ERF_Radiation.H:273
real2d icswp
Definition: ERF_Radiation.H:257
FluxesByband lw_fluxes_clrsky
Definition: ERF_Radiation.H:278
real2d cldfsnow
Definition: ERF_Radiation.H:257
real1d aer_asm_bnd_sw_o_1d
Definition: ERF_Radiation.H:276
real3d cld_tau_bnd_sw
Definition: ERF_Radiation.H:260
real3d snw_tau_bnd_sw
Definition: ERF_Radiation.H:265
FluxesByband lw_fluxes_allsky
Definition: ERF_Radiation.H:278
real3d cld_ssa_bnd_sw
Definition: ERF_Radiation.H:260
int1d gpoint_bands_lw
Definition: ERF_Radiation.H:269
real3d aer_tau_bnd_lw
Definition: ERF_Radiation.H:262
real1d cld_asm_bnd_sw_1d
Definition: ERF_Radiation.H:272
void get_gpoint_bands_lw(int1d &gpoint_bands)
Definition: ERF_RRTMGP.H:106
void get_gpoint_bands_sw(int1d &gpoint_bands)
Definition: ERF_RRTMGP.H:101
void reordered(const real1d &array_in, const int1d &new_indexing, const real1d &array_out)
Definition: ERF_Radiation.cpp:91
Here is the call graph for this function:

◆ set_daynight_indices()

void Radiation::set_daynight_indices ( const real1d &  coszrs,
const int1d &  day_indices,
const int1d &  night_indices 
)
832 {
833  // Loop over columns and identify daytime columns as those where the cosine
834  // solar zenith angle exceeds zero. Note that we wrap the setting of
835  // day_indices in an if-then to make sure we are not accessing day_indices out
836  // of bounds, and stopping with an informative error message if we do for some reason.
837  int1d iday("iday", 1);
838  int1d inight("inight",1);
839  yakl::memset(iday, 0);
840  yakl::memset(inight, 0);
841  yakl::memset(day_indices, 0);
842  yakl::memset(night_indices, 0);
843  parallel_for(SimpleBounds<1>(ncol), YAKL_LAMBDA (int icol)
844  {
845  if (coszrs(icol) > 0.) {
846  iday(1) += 1;
847  day_indices(iday(1)) = icol;
848  } else {
849  inight(1) += 1;
850  night_indices(inight(1)) = icol;
851  }
852  });
853 }

◆ writePlotfile()

void Radiation::writePlotfile ( const std::string &  plot_prefix,
const amrex::Real  time,
const int  level_step 
)
1133 {
1134  // Note: Radiation::initialize() is not called until the first timestep, so skip over the initial file write at t=0
1135  if (!qrad_src)
1136  {
1137  return;
1138  }
1139 
1140  std::string plotfilename = amrex::Concatenate(plot_prefix + "_rad", level_step, 5);
1141 
1142  // list of real2d (3D) variables to plot
1143  amrex::Vector<real2d*> plotvars_2d;
1144  plotvars_2d.push_back(&cld);
1145  plotvars_2d.push_back(&cldfsnow);
1146  plotvars_2d.push_back(&iclwp);
1147  plotvars_2d.push_back(&iciwp);
1148  plotvars_2d.push_back(&icswp);
1149  plotvars_2d.push_back(&dei);
1150  plotvars_2d.push_back(&des);
1151  plotvars_2d.push_back(&lambdac);
1152  plotvars_2d.push_back(&mu);
1153  plotvars_2d.push_back(&rei);
1154  plotvars_2d.push_back(&rel);
1155 
1156  // SW allsky
1157  plotvars_2d.push_back(&sw_fluxes_allsky.flux_up);
1158  plotvars_2d.push_back(&sw_fluxes_allsky.flux_dn);
1159  plotvars_2d.push_back(&sw_fluxes_allsky.flux_net);
1160  plotvars_2d.push_back(&sw_fluxes_allsky.flux_dn_dir);
1161  // SW clearsky
1162  plotvars_2d.push_back(&sw_fluxes_clrsky.flux_up);
1163  plotvars_2d.push_back(&sw_fluxes_clrsky.flux_dn);
1164  plotvars_2d.push_back(&sw_fluxes_clrsky.flux_net);
1165  plotvars_2d.push_back(&sw_fluxes_clrsky.flux_dn_dir);
1166 
1167  // LW allsky
1168  plotvars_2d.push_back(&lw_fluxes_allsky.flux_up);
1169  plotvars_2d.push_back(&lw_fluxes_allsky.flux_dn);
1170  plotvars_2d.push_back(&lw_fluxes_allsky.flux_net);
1171  // LW clearsky
1172  plotvars_2d.push_back(&lw_fluxes_clrsky.flux_up);
1173  plotvars_2d.push_back(&lw_fluxes_clrsky.flux_dn);
1174  plotvars_2d.push_back(&lw_fluxes_clrsky.flux_net);
1175 
1176  plotvars_2d.push_back(&qrs);
1177  plotvars_2d.push_back(&qrl);
1178  plotvars_2d.push_back(&zi);
1179  plotvars_2d.push_back(&clear_rh);
1180  plotvars_2d.push_back(&qrsc);
1181  plotvars_2d.push_back(&qrlc);
1182  plotvars_2d.push_back(&qt);
1183  plotvars_2d.push_back(&qi);
1184  plotvars_2d.push_back(&qc);
1185  plotvars_2d.push_back(&qn);
1186  plotvars_2d.push_back(&tmid);
1187  plotvars_2d.push_back(&pmid);
1188  plotvars_2d.push_back(&pdel);
1189 
1190  //plotvars_2d.push_back(&pint); // NOTE these have nlev + 1
1191  //plotvars_2d.push_back(&tint);
1192 
1193  //plotvars_2d.push_back(&albedo_dir); // [nswbands, ncol]
1194  //plotvars_2d.push_back(&albedo_dif);
1195 
1196  // names of plotted variables
1197  amrex::Vector<std::string> varnames_2d;
1198  varnames_2d.push_back("cld");
1199  varnames_2d.push_back("cldfsnow");
1200  varnames_2d.push_back("iclwp");
1201  varnames_2d.push_back("iciwp");
1202  varnames_2d.push_back("icswp");
1203  varnames_2d.push_back("dei");
1204  varnames_2d.push_back("des");
1205  varnames_2d.push_back("lambdac");
1206  varnames_2d.push_back("mu");
1207  varnames_2d.push_back("rei");
1208  varnames_2d.push_back("rel");
1209 
1210  // SW allsky
1211  varnames_2d.push_back("sw_fluxes_allsky.flux_up");
1212  varnames_2d.push_back("sw_fluxes_allsky.flux_dn");
1213  varnames_2d.push_back("sw_fluxes_allsky.flux_net");
1214  varnames_2d.push_back("sw_fluxes_allsky.flux_dn_dir");
1215  // SW clearsky
1216  varnames_2d.push_back("sw_fluxes_clrsky.flux_up");
1217  varnames_2d.push_back("sw_fluxes_clrsky.flux_dn");
1218  varnames_2d.push_back("sw_fluxes_clrsky.flux_net");
1219  varnames_2d.push_back("sw_fluxes_clrsky.flux_dn_dir");
1220 
1221  // LW allsky
1222  varnames_2d.push_back("lw_fluxes_allsky.flux_up");
1223  varnames_2d.push_back("lw_fluxes_allsky.flux_dn");
1224  varnames_2d.push_back("lw_fluxes_allsky.flux_net");
1225  // LW clearsky
1226  varnames_2d.push_back("lw_fluxes_clrsky.flux_up");
1227  varnames_2d.push_back("lw_fluxes_clrsky.flux_dn");
1228  varnames_2d.push_back("lw_fluxes_clrsky.flux_net");
1229 
1230  varnames_2d.push_back("qrs");
1231  varnames_2d.push_back("qrl");
1232  varnames_2d.push_back("zi");
1233  varnames_2d.push_back("clear_rh");
1234  varnames_2d.push_back("qrsc");
1235  varnames_2d.push_back("qrlc");
1236  varnames_2d.push_back("qt");
1237  varnames_2d.push_back("qi");
1238  varnames_2d.push_back("qc");
1239  varnames_2d.push_back("qn");
1240  varnames_2d.push_back("tmid");
1241  varnames_2d.push_back("pmid");
1242  varnames_2d.push_back("pdel");
1243 
1244  //varnames_2d.push_back("pint"); // NOTE these have nlev + 1
1245  //varnames_2d.push_back("tint");
1246 
1247  //varnames_2d.push_back("albedo_dir");
1248  //varnames_2d.push_back("albedo_dif");
1249 
1250  // list 3D variables defined over bands (SW and LW)
1251  // these are 4D fields split into 3D so they can use the same AMReX plotfile
1252  amrex::Vector<real3d*> plotvars_3d;
1253  amrex::Vector<std::string> varnames_3d;
1254  plotvars_3d.push_back(&cld_tau_bnd_sw);
1255  plotvars_3d.push_back(&cld_ssa_bnd_sw);
1256  plotvars_3d.push_back(&cld_asm_bnd_sw);
1257  plotvars_3d.push_back(&aer_tau_bnd_sw);
1258  plotvars_3d.push_back(&aer_ssa_bnd_sw);
1259  plotvars_3d.push_back(&aer_asm_bnd_sw);
1260  plotvars_3d.push_back(&cld_tau_bnd_lw);
1261  plotvars_3d.push_back(&aer_tau_bnd_lw);
1262  // diagnostic variables:
1263  plotvars_3d.push_back(&liq_tau_bnd_sw);
1264  plotvars_3d.push_back(&ice_tau_bnd_sw);
1265  plotvars_3d.push_back(&snw_tau_bnd_sw);
1266  plotvars_3d.push_back(&liq_tau_bnd_lw);
1267  plotvars_3d.push_back(&ice_tau_bnd_lw);
1268  plotvars_3d.push_back(&snw_tau_bnd_lw);
1269 
1270  varnames_3d.push_back("cld_tau_bnd_sw");
1271  varnames_3d.push_back("cld_ssa_bnd_sw");
1272  varnames_3d.push_back("cld_asm_bnd_sw");
1273  varnames_3d.push_back("aer_tau_bnd_sw");
1274  varnames_3d.push_back("aer_ssa_bnd_sw");
1275  varnames_3d.push_back("aer_asm_bnd_sw");
1276  varnames_3d.push_back("cld_tau_bnd_lw");
1277  varnames_3d.push_back("aer_tau_bnd_lw");
1278  // diagnostic variables:
1279  varnames_3d.push_back("liq_tau_bnd_sw");
1280  varnames_3d.push_back("ice_tau_bnd_sw");
1281  varnames_3d.push_back("snw_tau_bnd_sw");
1282  varnames_3d.push_back("liq_tau_bnd_lw");
1283  varnames_3d.push_back("ice_tau_bnd_lw");
1284  varnames_3d.push_back("snw_tau_bnd_lw");
1285 
1286  AMREX_ASSERT(varnames_2d.size() == plotvars_2d.size());
1287  AMREX_ASSERT(varnames_3d.size() == plotvars_3d.size());
1288 
1289  int output_size = plotvars_2d.size() + 1; // 2D vars + coszrs
1290  // add in total output size of all 3D vars
1291  for (int i = 0; i < plotvars_3d.size(); i++)
1292  {
1293  output_size += plotvars_3d[i]->get_dimensions()(3);
1294  }
1295 
1296  // convert each YAKL array to a MF and combine into a single MF for plotting
1297  MultiFab fab(m_box, qrad_src->DistributionMap(), output_size, 0);
1298  // copy 2D vars first
1299  for (int i = 0; i < plotvars_2d.size(); i++)
1300  {
1301  amrex::MultiFab mf;
1302  yakl_to_mf(*plotvars_2d[i], mf);
1303  MultiFab::Copy(fab, mf, 0, i, 1, 0);
1304  }
1305 
1306  int dst = plotvars_2d.size(); // output component index
1307 
1308  // expand coszrs from 2D to 3D so it can be saved with the same file
1309  varnames_2d.push_back("coszrs");
1310  amrex::MultiFab coszrs_mf;
1311  expand_yakl1d_to_mf(coszrs, coszrs_mf);
1312  MultiFab::Copy(fab, coszrs_mf, 0, dst, 1, 0);
1313  dst++;
1314 
1315  // copy 3D vars
1316  for (int i = 0; i < plotvars_3d.size(); i++)
1317  {
1318  // split real3ds into real2d for each band for output
1319  // TODO: find a better way to do this
1320  const int var_nbands = plotvars_3d[i]->get_dimensions()(3); // either nswbands or nlwbands
1321  for (int bnd = 1; bnd <= var_nbands; bnd++)
1322  {
1323  // add variable name to 2d list
1324  varnames_2d.push_back(varnames_3d[i] + "_" + std::to_string(bnd));
1325 
1326  amrex::MultiFab mf;
1327  real2d band_var = plotvars_3d[i]->slice<2>(yakl::COLON, yakl::COLON, bnd);
1328  yakl_to_mf(band_var, mf);
1329  MultiFab::Copy(fab, mf, 0, dst, 1, 0);
1330 
1331  dst++;
1332  }
1333  }
1334  AMREX_ASSERT(dst == fab.nComp());
1335 
1336  // this should now match full output size with all 3D variables expanded
1337  AMREX_ASSERT(varnames_2d.size() == output_size);
1338 
1339 
1340  amrex::WriteSingleLevelPlotfile(plotfilename, fab, varnames_2d, m_geom, time, level_step);
1341 }
void expand_yakl1d_to_mf(const real1d &data, amrex::MultiFab &mf)
Definition: ERF_Radiation.cpp:1105
void yakl_to_mf(const real2d &data, amrex::MultiFab &mf)
Definition: ERF_Radiation.cpp:1076

◆ yakl_to_mf()

void Radiation::yakl_to_mf ( const real2d &  data,
amrex::MultiFab &  mf 
)
1077 {
1078  // creates a MF from a YAKL real2d mapping from [col, lev] to [x,y,z]
1079  // by reshaping the yakl array to the geometry of the output qsrc multifab
1080  mf = amrex::MultiFab(m_box, qrad_src->DistributionMap(), 1, 0);
1081  if (!data.initialized())
1082  {
1083  // yakl array hasn't been created yet, so create an empty MF
1084  mf.setVal(0.0);
1085  return;
1086  }
1087 
1088  for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
1089  auto mf_arr = mf.array(mfi);
1090  const auto& box3d = mfi.tilebox();
1091  const int nx = box3d.length(0);
1092  const int offset = rank_offsets[mfi.LocalIndex()];
1093  amrex::ParallelFor(box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1094  {
1095  // map [i,j,k] 0-based to [icol, ilev] 1-based
1096  const int icol = (j-box3d.smallEnd(1))*nx + (i-box3d.smallEnd(0)) + 1 + offset;
1097  const int ilev = k+1;
1098  AMREX_ASSERT(icol <= static_cast<int>(data.get_dimensions()(1)));
1099  AMREX_ASSERT(ilev <= static_cast<int>(data.get_dimensions()(2)));
1100  mf_arr(i, j, k) = data(icol, ilev);
1101  });
1102  }
1103 }
Here is the call graph for this function:

Member Data Documentation

◆ active_gases

const std::vector<std::string> Radiation::active_gases
private
Initial value:
= {
"H2O", "CO2", "O3", "N2O",
"CO" , "CH4", "O2", "N2" }

◆ aer_asm_bnd_sw

real3d Radiation::aer_asm_bnd_sw
private

◆ aer_asm_bnd_sw_1d

real1d Radiation::aer_asm_bnd_sw_1d
private

◆ aer_asm_bnd_sw_o_1d

real1d Radiation::aer_asm_bnd_sw_o_1d
private

◆ aer_rad

AerRadProps Radiation::aer_rad
private

◆ aer_ssa_bnd_sw

real3d Radiation::aer_ssa_bnd_sw
private

◆ aer_ssa_bnd_sw_1d

real1d Radiation::aer_ssa_bnd_sw_1d
private

◆ aer_ssa_bnd_sw_o_1d

real1d Radiation::aer_ssa_bnd_sw_o_1d
private

◆ aer_tau_bnd_lw

real3d Radiation::aer_tau_bnd_lw
private

◆ aer_tau_bnd_sw

real3d Radiation::aer_tau_bnd_sw
private

◆ aer_tau_bnd_sw_1d

real1d Radiation::aer_tau_bnd_sw_1d
private

◆ aer_tau_bnd_sw_o_1d

real1d Radiation::aer_tau_bnd_sw_o_1d
private

◆ aernames

std::vector<std::string> Radiation::aernames
private

◆ albedo_dif

real2d Radiation::albedo_dif
private

◆ albedo_dir

real2d Radiation::albedo_dir
private

◆ cld

real2d Radiation::cld
private

◆ cld_asm_bnd_sw

real3d Radiation::cld_asm_bnd_sw
private

◆ cld_asm_bnd_sw_1d

real1d Radiation::cld_asm_bnd_sw_1d
private

◆ cld_asm_bnd_sw_o_1d

real1d Radiation::cld_asm_bnd_sw_o_1d
private

◆ cld_asm_gpt_sw

real3d Radiation::cld_asm_gpt_sw
private

◆ cld_ssa_bnd_sw

real3d Radiation::cld_ssa_bnd_sw
private

◆ cld_ssa_bnd_sw_1d

real1d Radiation::cld_ssa_bnd_sw_1d
private

◆ cld_ssa_bnd_sw_o_1d

real1d Radiation::cld_ssa_bnd_sw_o_1d
private

◆ cld_ssa_gpt_sw

real3d Radiation::cld_ssa_gpt_sw
private

◆ cld_tau_bnd_lw

real3d Radiation::cld_tau_bnd_lw
private

◆ cld_tau_bnd_sw

real3d Radiation::cld_tau_bnd_sw
private

◆ cld_tau_bnd_sw_1d

real1d Radiation::cld_tau_bnd_sw_1d
private

◆ cld_tau_bnd_sw_o_1d

real1d Radiation::cld_tau_bnd_sw_o_1d
private

◆ cld_tau_gpt_lw

real3d Radiation::cld_tau_gpt_lw
private

◆ cld_tau_gpt_sw

real3d Radiation::cld_tau_gpt_sw
private

◆ cldfsnow

real2d Radiation::cldfsnow
private

◆ clear_rh

real2d Radiation::clear_rh
private

◆ coszrs

real1d Radiation::coszrs
private

◆ dei

real2d Radiation::dei
private

◆ des

real2d Radiation::des
private

◆ do_aerosol_rad

bool Radiation::do_aerosol_rad = true
private

◆ do_long_wave_rad

bool Radiation::do_long_wave_rad
private

◆ do_short_wave_rad

bool Radiation::do_short_wave_rad
private

◆ do_snow_optics

bool Radiation::do_snow_optics
private

◆ dohirs

bool Radiation::dohirs = false
private

◆ dt

real Radiation::dt
private

◆ dt_avg

real Radiation::dt_avg = 0.0
private

◆ eccen

constexpr amrex::Real Radiation::eccen = 0.0
staticconstexprprivate

◆ fixed_total_solar_irradiance

real Radiation::fixed_total_solar_irradiance = -1.
private

◆ flns

real1d Radiation::flns
private

◆ flnt

real1d Radiation::flnt
private

◆ fsds

real1d Radiation::fsds
private

◆ fsns

real1d Radiation::fsns
private

◆ fsnt

real1d Radiation::fsnt
private

◆ gas_vmr

real3d Radiation::gas_vmr
private

◆ gasnames

std::vector<std::string> Radiation::gasnames
private

◆ gpoint_bands_lw

int1d Radiation::gpoint_bands_lw
private

◆ gpoint_bands_sw

int1d Radiation::gpoint_bands_sw
private

◆ has_qmoist

bool Radiation::has_qmoist
private

◆ ice_tau_bnd_lw

real3d Radiation::ice_tau_bnd_lw
private

◆ ice_tau_bnd_sw

real3d Radiation::ice_tau_bnd_sw
private

◆ iciwp

real2d Radiation::iciwp
private

◆ iclwp

real2d Radiation::iclwp
private

◆ icswp

real2d Radiation::icswp
private

◆ ihirsfq

int Radiation::ihirsfq = 1
private

◆ is_cmip6_volc

bool Radiation::is_cmip6_volc
private

◆ lambdac

real2d Radiation::lambdac
private

◆ lambm0

constexpr amrex::Real Radiation::lambm0 = -3.2503635878519378e-2
staticconstexprprivate

◆ liq_tau_bnd_lw

real3d Radiation::liq_tau_bnd_lw
private

◆ liq_tau_bnd_sw

real3d Radiation::liq_tau_bnd_sw
private

◆ lw_band_midpoints

real1d Radiation::lw_band_midpoints
private

◆ lw_fluxes_allsky

FluxesByband Radiation::lw_fluxes_allsky
private

◆ lw_fluxes_clrsky

FluxesByband Radiation::lw_fluxes_clrsky
private

◆ m_box

amrex::BoxArray Radiation::m_box
private

◆ m_geom

amrex::Geometry Radiation::m_geom
private

◆ m_lat

amrex::MultiFab* Radiation::m_lat = nullptr
private

◆ m_lon

amrex::MultiFab* Radiation::m_lon = nullptr
private

◆ m_lsm_fluxes

amrex::MultiFab* Radiation::m_lsm_fluxes = nullptr
private

◆ m_lsm_zenith

amrex::MultiFab* Radiation::m_lsm_zenith = nullptr
private

◆ moisture_type

std::string Radiation::moisture_type = "None"
private

◆ mu

real2d Radiation::mu
private

◆ mvelpp

constexpr amrex::Real Radiation::mvelpp = 103.0 * PI / 180.0 + PI
staticconstexprprivate

◆ naer

int Radiation::naer
private

◆ ncol

int Radiation::ncol
private

◆ net_flux

real1d Radiation::net_flux
private

◆ ngas

int Radiation::ngas
private

◆ nlev

int Radiation::nlev
private

◆ nlwbands

int Radiation::nlwbands
private

◆ nlwgpts

int Radiation::nlwgpts
private

◆ nswbands

int Radiation::nswbands
private

◆ nswgpts

int Radiation::nswgpts
private

◆ obliqr

constexpr amrex::Real Radiation::obliqr = 23.0 * PI / 180.0
staticconstexprprivate

◆ optics

Optics Radiation::optics
private

◆ pdel

real2d Radiation::pdel
private

◆ pint

real2d Radiation::pint
private

◆ pmid

real2d Radiation::pmid
private

◆ qc

real2d Radiation::qc
private

◆ qi

real2d Radiation::qi
private

◆ qn

real2d Radiation::qn
private

◆ qrad_src

amrex::MultiFab* Radiation::qrad_src = nullptr
private

◆ qrl

real2d Radiation::qrl
private

◆ qrlc

real2d Radiation::qrlc
private

◆ qrs

real2d Radiation::qrs
private

◆ qrsc

real2d Radiation::qrsc
private

◆ qt

real2d Radiation::qt
private

◆ radiation

Rrtmgp Radiation::radiation
private

◆ rank_offsets

amrex::Vector<int> Radiation::rank_offsets
private

◆ rei

real2d Radiation::rei
private

◆ rel

real2d Radiation::rel
private

◆ rrtmg_to_rrtmgp

int1d Radiation::rrtmg_to_rrtmgp
private

◆ rrtmgp_coefficients_file_lw

std::string Radiation::rrtmgp_coefficients_file_lw
private

◆ rrtmgp_coefficients_file_name_lw

std::string Radiation::rrtmgp_coefficients_file_name_lw = "rrtmgp_coefficients_lw_20181204.nc"
private

◆ rrtmgp_coefficients_file_name_sw

std::string Radiation::rrtmgp_coefficients_file_name_sw = "rrtmgp_coefficients_sw_20181204.nc"
private

◆ rrtmgp_coefficients_file_sw

std::string Radiation::rrtmgp_coefficients_file_sw
private

◆ rrtmgp_data_path

std::string Radiation::rrtmgp_data_path
private

◆ rrtmgp_enable_temperature_warnings

bool Radiation::rrtmgp_enable_temperature_warnings = true
private

◆ snw_tau_bnd_lw

real3d Radiation::snw_tau_bnd_lw
private

◆ snw_tau_bnd_sw

real3d Radiation::snw_tau_bnd_sw
private

◆ spectralflux

bool Radiation::spectralflux = false
private

◆ sw_band_midpoints

real1d Radiation::sw_band_midpoints
private

◆ sw_fluxes_allsky

FluxesByband Radiation::sw_fluxes_allsky
private

◆ sw_fluxes_clrsky

FluxesByband Radiation::sw_fluxes_clrsky
private

◆ tint

real2d Radiation::tint
private

◆ tmid

real2d Radiation::tmid
private

◆ uniform_angle

amrex::Real Radiation::uniform_angle = 78.463
private

◆ use_rad_dt_cosz

bool Radiation::use_rad_dt_cosz = false
private

◆ zhi

int Radiation::zhi
private

◆ zi

real2d Radiation::zi
private

◆ zlo

int Radiation::zlo
private

The documentation for this class was generated from the following files: