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

#include <ERF_RadiationSimple.H>

Inheritance diagram for RadiationSimple:
Collaboration diagram for RadiationSimple:

Public Member Functions

 RadiationSimple (const int &, const SolverChoice &sc)
 
 ~RadiationSimple ()=default
 
virtual void Init (const amrex::Geometry &geom, const amrex::BoxArray &ba, amrex::MultiFab *cons_in) override
 
virtual void Run (int &level, int &step, double &time, const double &dt, const amrex::BoxArray &ba, amrex::Geometry &geom, amrex::MultiFab *cons_in, amrex::iMultiFab *lmask, amrex::MultiFab *t_surf, const amrex::Vector< const amrex::MultiFab * > &lsm_input_ptrs, const amrex::Vector< amrex::MultiFab * > &lsm_output_ptrs, amrex::MultiFab *qheating_rates, amrex::MultiFab *rad_fluxes, amrex::MultiFab *z_phys, amrex::MultiFab *lat, amrex::MultiFab *lon, const bool force_update, amrex::Real &declin, amrex::Real &calday) override
 
virtual void WriteDataLog (const double &time) override
 
bool is_nested_patch () const override
 
const amrex::MultiFab * get_radlwdn ()
 
const amrex::MultiFab * get_radqrlw ()
 
- Public Member Functions inherited from IRadiation
virtual ~IRadiation ()=default
 
virtual bool radiation_updated () const
 Reports whether the last radiation call updated its outputs. More...
 
virtual amrex::Vector< std::string > get_lsm_input_varnames ()
 
virtual amrex::Vector< std::string > get_lsm_output_varnames ()
 
void setupDataLog ()
 
void setDataLogFrequency (const int nstep)
 
bool hasDatalog ()
 

Private Attributes

bool m_have_qv = false
 
bool m_have_qc = false
 
bool m_ice = false
 
int m_qv_comp = -1
 
int m_qc_comp = -1
 
int m_qi_comp = -1
 
amrex::Geometry m_geom
 
amrex::BoxArray m_ba
 
bool m_partial_columns = false
 
amrex::MultiFab deltaq
 
amrex::MultiFab flux
 
std::unique_ptr< amrex::MultiFab > radlwdn
 
std::unique_ptr< amrex::MultiFab > radqrlw
 

Additional Inherited Members

- Protected Attributes inherited from IRadiation
std::unique_ptr< std::fstream > datalog = nullptr
 
std::string datalogname
 
int datalog_int = -1
 

Constructor & Destructor Documentation

◆ RadiationSimple()

RadiationSimple::RadiationSimple ( const int &  ,
const SolverChoice &  sc 
)
inline
18  {
19  // Every moist species we read is taken from the configured moisture-component
20  // mapping, so each scheme is indexed by its own layout rather than by an
21  // enumerated model list: every scheme carrying cloud ice (SAM, Morrison, WSM6,
22  // WDM6, ...) is picked up, and the warm-rain schemes are not.
26 
27  m_have_qv = (m_qv_comp >= 0);
28  m_have_qc = (m_qc_comp >= 0);
29  m_ice = (m_qi_comp >= 0);
30  }
int m_qc_comp
Definition: ERF_RadiationSimple.H:73
bool m_ice
Definition: ERF_RadiationSimple.H:71
bool m_have_qc
Definition: ERF_RadiationSimple.H:70
int m_qi_comp
Definition: ERF_RadiationSimple.H:74
int m_qv_comp
Definition: ERF_RadiationSimple.H:72
bool m_have_qv
Definition: ERF_RadiationSimple.H:69
int qi
cloud ice
Definition: ERF_DataStruct.H:264
int qv
water vapor
Definition: ERF_DataStruct.H:262
int qc
cloud liquid water
Definition: ERF_DataStruct.H:263
MoistureComponentIndices moisture_indices
Index map of the moisture data carried by the active scheme: conserved-state components for the speci...
Definition: ERF_DataStruct.H:2993

◆ ~RadiationSimple()

RadiationSimple::~RadiationSimple ( )
default

Member Function Documentation

◆ get_radlwdn()

const amrex::MultiFab* RadiationSimple::get_radlwdn ( )
inline
65 { return radlwdn.get(); }
std::unique_ptr< amrex::MultiFab > radlwdn
Definition: ERF_RadiationSimple.H:81

◆ get_radqrlw()

const amrex::MultiFab* RadiationSimple::get_radqrlw ( )
inline
66 { return radqrlw.get(); }
std::unique_ptr< amrex::MultiFab > radqrlw
Definition: ERF_RadiationSimple.H:82

◆ Init()

void RadiationSimple::Init ( const amrex::Geometry &  geom,
const amrex::BoxArray &  ba,
amrex::MultiFab *  cons_in 
)
overridevirtual

Implements IRadiation.

12 {
13  m_geom = geom;
14  m_ba = ba;
15 
16  // Set (or cleared) on every Init, so a level that spans the column again after a
17  // regrid resumes the sweep.
18  m_partial_columns = false;
19  for (int ib = 0; ib < ba.size(); ++ib) {
20  if (ba[ib].smallEnd(2) != geom.Domain().smallEnd(2) || ba[ib].bigEnd(2) != geom.Domain().bigEnd(2)) {
21  m_partial_columns = true;
22  break;
23  }
24  }
25 
26  DistributionMapping dm = cons_in->DistributionMap();
27  deltaq.define(ba, dm, 1, 0);
28  flux.define(ba, dm, 1, IntVect(0, 0, 1));
29  radlwdn = std::make_unique<amrex::MultiFab>(ba, dm, 1, 0);
30  radqrlw = std::make_unique<amrex::MultiFab>(ba, dm, 1, 0);
31 
32  deltaq.setVal(zero);
33  flux.setVal(zero);
34  radlwdn->setVal(zero);
35  radqrlw->setVal(zero);
36 }
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:36
amrex::MultiFab deltaq
Definition: ERF_RadiationSimple.H:80
amrex::Geometry m_geom
Definition: ERF_RadiationSimple.H:76
amrex::BoxArray m_ba
Definition: ERF_RadiationSimple.H:77
amrex::MultiFab flux
Definition: ERF_RadiationSimple.H:80
bool m_partial_columns
Definition: ERF_RadiationSimple.H:78

◆ is_nested_patch()

bool RadiationSimple::is_nested_patch ( ) const
inlineoverridevirtual

Reimplemented from IRadiation.

63 { return m_partial_columns; }

◆ Run()

void RadiationSimple::Run ( int &  level,
int &  step,
double &  time,
const double &  dt,
const amrex::BoxArray &  ba,
amrex::Geometry &  geom,
amrex::MultiFab *  cons_in,
amrex::iMultiFab *  lmask,
amrex::MultiFab *  t_surf,
const amrex::Vector< const amrex::MultiFab * > &  lsm_input_ptrs,
const amrex::Vector< amrex::MultiFab * > &  lsm_output_ptrs,
amrex::MultiFab *  qheating_rates,
amrex::MultiFab *  rad_fluxes,
amrex::MultiFab *  z_phys,
amrex::MultiFab *  lat,
amrex::MultiFab *  lon,
const bool  force_update,
amrex::Real &  declin,
amrex::Real &  calday 
)
overridevirtual

Implements IRadiation.

57 {
58  if (m_partial_columns) {
59  // Level 0 has no parent to interpolate from: grids split in z are unsupported here.
61  "RadiationSimple: every level-0 box must span the domain in z (do not split grids in z)");
62  return;
63  }
64 
65  constexpr amrex::Real cp_spec = 1015.0;
66  constexpr amrex::Real coef = 70.0;
67  constexpr amrex::Real coef1 = 22.0;
68  constexpr amrex::Real f0=3.75e-6;
69  constexpr amrex::Real xk = 85.0;
70 
71  const Real fixed_dz = geom.CellSize(2);
72  const int nz = geom.Domain().length(2);
73 
74  flux.setVal(zero);
75  deltaq.setVal(zero);
76 
77  const bool have_qv = m_have_qv;
78  const bool have_qc = m_have_qc;
79  const bool ice = m_ice;
80  const int qv_comp = m_qv_comp;
81  const int qc_comp = m_qc_comp;
82  const int qi_comp = m_qi_comp;
83 
84  for (MFIter mfi(*cons_in, TileNoZ()); mfi.isValid(); ++mfi)
85  {
86  Box box = mfi.tilebox();
87  box.makeSlab(2, 0);
88 
89  const Array4<const Real>& cons_arr = cons_in->const_array(mfi);
90  const Array4<const Real>& z_nd_arr = (z_phys) ? z_phys->const_array(mfi) : Array4<const Real>{};
91  const Array4<Real>& deltaq_arr = deltaq.array(mfi);
92  const Array4<Real>& flux_arr = flux.array(mfi);
93  const Array4<Real>& radlwdn_arr = radlwdn->array(mfi);
94  const Array4<Real>& radqrlw_arr = radqrlw->array(mfi);
95  const Array4<Real>& qheating_arr = qheating_rates->array(mfi);
96 
97  ParallelFor(box, [=] AMREX_GPU_DEVICE (int i, int j, int)
98  {
99  int itop = 0;
100  Real qzinf = 0.0; // holds accumulated optical depth between z and domain top
101  Real qzeroz = 0.0; // holds accumulated optical depth between surface and z
102 
103  for (int k = 0; k < nz; k++)
104  {
105  Real rho = cons_arr(i, j, k, Rho_comp);
106  Real qv = (have_qv) ? cons_arr(i, j, k, qv_comp) / rho : zero;
107  Real qc = (have_qc) ? cons_arr(i, j, k, qc_comp) / rho : zero;
108  Real qi = (ice) ? cons_arr(i, j, k, qi_comp) / rho : zero;
109 
110  Real dz = (z_nd_arr) ? Real(0.25) * ( (z_nd_arr(i ,j ,k+1) - z_nd_arr(i ,j ,k))
111  + (z_nd_arr(i+1,j ,k+1) - z_nd_arr(i+1,j ,k))
112  + (z_nd_arr(i ,j+1,k+1) - z_nd_arr(i ,j+1,k))
113  + (z_nd_arr(i+1,j+1,k+1) - z_nd_arr(i+1,j+1,k)) ) : fixed_dz;
114 
115  // optical depth only includes that due to liquid water
116  if (qc + qi > 0.0)
117  {
118  deltaq_arr(i, j, k) = xk * rho * (qc + qi) * dz;
119  }
120 
121  // inversion height is top of highest layer w/q>8g/kg
122  if (qv + qc + qi > 0.008)
123  {
124  itop = max(itop, k+1); // note zi(k+1) is inversion height
125  }
126 
127  // accumulate optical depth in qzinf
128  qzinf = qzinf + deltaq_arr(i, j, k);
129  }
130 
131  // note: qzinf now holds total optical depth of column (due to cloud)
132  // qzeroz is initialized to zero since first level is at surface
133 
134  // compute net upward longwave flux up to inversion height. When the
135  // moist layer reaches the top cell, itop = nz: the face at nz is then
136  // written below, where its above-inversion term vanishes (zi = z_itop),
137  // and deltaq has no cell at nz to read.
138  for (int k = 0; k <= amrex::min(itop, nz - 1); k++)
139  {
140  flux_arr(i, j, k) = coef*exp(-qzinf) + coef1*exp(-qzeroz);
141  qzinf = qzinf - deltaq_arr(i, j, k);
142  qzeroz = qzeroz + deltaq_arr(i, j, k);
143  }
144 
145  // compute net upward longwave flux above inversion height
146  // this includes correction for clearsky fluxes which balances
147  // the prescribed subsidence heating above the inversion
148  Real z_itop = (z_nd_arr) ? z_nd_arr(i, j, itop) : itop * fixed_dz;
149  for (int k = itop + 1; k < nz; k++) {
150  Real rho_nd = 0.5 * (cons_arr(i, j, k - 1, Rho_comp) + cons_arr(i, j, k, Rho_comp)); // rho at interface
151  Real zi = (z_nd_arr) ? z_nd_arr(i, j, k) : k * fixed_dz;
152  flux_arr(i, j, k) = coef * exp(-qzinf) + coef1 * exp(-qzeroz)
153  + cp_spec * rho_nd * f0 * (0.25 * zi + 0.75 * z_itop)
154  * pow(zi - z_itop, 1.0 / 3.0);
155  qzinf = qzinf - deltaq_arr(i, j, k);
156  qzeroz = qzeroz + deltaq_arr(i, j, k);
157  }
158  Real rho_nd = 0.5 * (cons_arr(i, j, nz - 1, Rho_comp) + cons_arr(i, j, nz, Rho_comp));
159  Real zi = (z_nd_arr) ? z_nd_arr(i, j, nz) : nz * fixed_dz;
160  flux_arr(i, j, nz) = coef * exp(-qzinf) + coef1 * exp(-qzeroz)
161  + cp_spec * rho_nd * f0 * (0.25 * zi + 0.75 * z_itop)
162  * pow(zi - z_itop, 1.0 / 3.0);
163 
164  // note that our flux differs from the specification in that it
165  // uses the local density (rather than the interface density) in
166  // computing the correction to the flux above the inversion.
167  // Formulating things in this way ensures a rough balance between
168  // the subsidence heating and radiative cooling above the inversion.
169 
170  // compute radiative heating as divergence of net upward lw flux
171  for (int k = 0; k < nz; k++)
172  {
173  Real dz = (z_nd_arr) ? 0.25 * ( (z_nd_arr(i ,j ,k+1) - z_nd_arr(i ,j ,k))
174  + (z_nd_arr(i+1,j ,k+1) - z_nd_arr(i+1,j ,k))
175  + (z_nd_arr(i ,j+1,k+1) - z_nd_arr(i ,j+1,k))
176  + (z_nd_arr(i+1,j+1,k+1) - z_nd_arr(i+1,j+1,k)) ) : fixed_dz;
177 
178  Real cpmassl = cp_spec * cons_arr(i, j, k, Rho_comp) * dz; // thermal mass
179  Real FTHRL = -(flux_arr(i, j, k+1) - flux_arr(i, j, k)) / cpmassl;
180  // convert heating rate FTHRL for theta_d
181  Real qv_k = (have_qv) ? cons_arr(i,j,k,qv_comp)/cons_arr(i,j,k,Rho_comp) : zero;
182  Real pres = getPgivenRTh(cons_arr(i,j,k,RhoTheta_comp), qv_k);
183  Real exner = getExnergivenP(pres, R_d/Cp_d);
184  FTHRL /= exner;
185  qheating_arr(i, j, k, 1) = FTHRL; // radiative heating for source term
186  radlwdn_arr(i, j, k) = flux_arr(i, j, k); // net lw flux
187  radqrlw_arr(i, j, k) = FTHRL; // net lw heating
188 
189  // The net flux is not written to rad_fluxes: that array holds
190  // (SW up, SW down, LW up, LW down), and this model computes
191  // none of those. It stays zero, and HasRadiation() is false.
192  }
193  });
194  }
195 }
constexpr amrex::Real Cp_d
Definition: ERF_Constants.H:51
constexpr amrex::Real R_d
Definition: ERF_Constants.H:49
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getExnergivenP(const amrex::Real P, const amrex::Real rdOcp)
Definition: ERF_EOS.H:141
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getPgivenRTh(const amrex::Real rhotheta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:81
#define Rho_comp
Definition: ERF_IndexDefines.H:53
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:54
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(axis >=0 &&axis< AMREX_SPACEDIM, "prob.axis must be 0, 1 or 2")
ParallelFor(fab_box, [=] AMREX_GPU_DEVICE(int i, int j, int k) { qrcuten_arr(i, j, k)=Real(0);qscuten_arr(i, j, k)=Real(0);qicuten_arr(i, j, k)=Real(0);})
amrex::Real Real
Definition: ERF_ShocInterface.H:19
AMREX_FORCE_INLINE amrex::IntVect TileNoZ()
Definition: ERF_TileNoZ.H:11
@ pres
Definition: ERF_Kessler.H:28
@ rho
Definition: ERF_Kessler.H:25
@ qv
Definition: ERF_Kessler.H:31
@ qi
Definition: ERF_Morrison.H:111
@ qc
Definition: ERF_Morrison.H:110
@ dz
Definition: ERF_AdvanceWDM6.cpp:273
@ zi
Definition: ERF_AdvanceWDM6.cpp:277
Here is the call graph for this function:

◆ WriteDataLog()

void RadiationSimple::WriteDataLog ( const double &  time)
overridevirtual

Implements IRadiation.

198 {
199  constexpr int datwidth = 14;
200  constexpr int datprecision = 9;
201  constexpr int timeprecision = 13;
202 
203  Gpu::HostVector<Real> h_avg_radlwdn, h_avg_radqrlw;
204 
205  auto domain = m_geom.Domain();
206  h_avg_radlwdn = sumToLine(*radlwdn, 0, 1, domain, 2);
207  h_avg_radqrlw = sumToLine(*radqrlw, 0, 1, domain, 2);
208 
209  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
210  int nz = domain.length(2);
211  for (int k = 0; k < nz; k++) {
212  h_avg_radlwdn[k] /= area_z;
213  h_avg_radqrlw[k] /= area_z;
214  }
215 
216  if (ParallelDescriptor::IOProcessor()) {
217  std::ostream& log = *datalog;
218 
219  if (log.good()) {
220  for (int k = 0; k < nz; k++)
221  {
222  Real z = k * m_geom.CellSize(2);
223  log << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
224  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
225  << h_avg_radlwdn[k] << " "
226  << h_avg_radqrlw[k] << std::endl;
227  }
228  // Write top face values
229  Real z = nz * m_geom.CellSize(2);
230  log << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
231  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
232  << 0.0 << " "
233  << 0.0 << std::endl;
234  }
235  }
236 }
std::unique_ptr< std::fstream > datalog
Definition: ERF_RadiationInterface.H:102

Member Data Documentation

◆ deltaq

amrex::MultiFab RadiationSimple::deltaq
private

◆ flux

amrex::MultiFab RadiationSimple::flux
private

◆ m_ba

amrex::BoxArray RadiationSimple::m_ba
private

◆ m_geom

amrex::Geometry RadiationSimple::m_geom
private

◆ m_have_qc

bool RadiationSimple::m_have_qc = false
private

Referenced by RadiationSimple().

◆ m_have_qv

bool RadiationSimple::m_have_qv = false
private

Referenced by RadiationSimple().

◆ m_ice

bool RadiationSimple::m_ice = false
private

Referenced by RadiationSimple().

◆ m_partial_columns

bool RadiationSimple::m_partial_columns = false
private

Referenced by is_nested_patch().

◆ m_qc_comp

int RadiationSimple::m_qc_comp = -1
private

Referenced by RadiationSimple().

◆ m_qi_comp

int RadiationSimple::m_qi_comp = -1
private

Referenced by RadiationSimple().

◆ m_qv_comp

int RadiationSimple::m_qv_comp = -1
private

Referenced by RadiationSimple().

◆ radlwdn

std::unique_ptr<amrex::MultiFab> RadiationSimple::radlwdn
private

Referenced by get_radlwdn().

◆ radqrlw

std::unique_ptr<amrex::MultiFab> RadiationSimple::radqrlw
private

Referenced by get_radqrlw().


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