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, amrex::Vector< amrex::MultiFab * > &lsm_input_ptrs, 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 updated_lsm) override
 
virtual void WriteDataLog (const double &time) override
 
const amrex::MultiFab * get_radlwdn ()
 
const amrex::MultiFab * get_radqrlw ()
 
- Public Member Functions inherited from IRadiation
virtual ~IRadiation ()=default
 
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
 
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:66
bool m_ice
Definition: ERF_RadiationSimple.H:64
bool m_have_qc
Definition: ERF_RadiationSimple.H:63
int m_qi_comp
Definition: ERF_RadiationSimple.H:67
int m_qv_comp
Definition: ERF_RadiationSimple.H:65
bool m_have_qv
Definition: ERF_RadiationSimple.H:62
int qi
cloud ice
Definition: ERF_DataStruct.H:208
int qv
water vapor
Definition: ERF_DataStruct.H:206
int qc
cloud liquid water
Definition: ERF_DataStruct.H:207
MoistureComponentIndices moisture_indices
Index map of the moisture data carried by the active scheme: conserved-state components for the speci...
Definition: ERF_DataStruct.H:2144

◆ ~RadiationSimple()

RadiationSimple::~RadiationSimple ( )
default

Member Function Documentation

◆ get_radlwdn()

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

◆ get_radqrlw()

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

◆ Init()

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

Implements IRadiation.

11 {
12  m_geom = geom;
13  m_ba = ba;
14 
15  DistributionMapping dm = cons_in->DistributionMap();
16  deltaq.define(ba, dm, 1, 0);
17  flux.define(ba, dm, 1, IntVect(0, 0, 1));
18  radlwdn = std::make_unique<amrex::MultiFab>(ba, dm, 1, 0);
19  radqrlw = std::make_unique<amrex::MultiFab>(ba, dm, 1, 0);
20 
21  deltaq.setVal(zero);
22  flux.setVal(zero);
23  radlwdn->setVal(zero);
24  radqrlw->setVal(zero);
25 }
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
amrex::MultiFab deltaq
Definition: ERF_RadiationSimple.H:72
amrex::Geometry m_geom
Definition: ERF_RadiationSimple.H:69
amrex::BoxArray m_ba
Definition: ERF_RadiationSimple.H:70
amrex::MultiFab flux
Definition: ERF_RadiationSimple.H:72

◆ 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,
amrex::Vector< amrex::MultiFab * > &  lsm_input_ptrs,
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  updated_lsm 
)
overridevirtual

Implements IRadiation.

44 {
45 
46  constexpr amrex::Real cp_spec = 1015.0;
47  constexpr amrex::Real coef = 70.0;
48  constexpr amrex::Real coef1 = 22.0;
49  constexpr amrex::Real f0=3.75e-6;
50  constexpr amrex::Real xk = 85.0;
51 
52  const Real fixed_dz = geom.CellSize(2);
53  const int nz = geom.Domain().length(2);
54 
55  flux.setVal(zero);
56  deltaq.setVal(zero);
57 
58  const bool have_qv = m_have_qv;
59  const bool have_qc = m_have_qc;
60  const bool ice = m_ice;
61  const int qv_comp = m_qv_comp;
62  const int qc_comp = m_qc_comp;
63  const int qi_comp = m_qi_comp;
64 
65  for (MFIter mfi(*cons_in, TileNoZ()); mfi.isValid(); ++mfi)
66  {
67  Box box = mfi.validbox();
68  box.makeSlab(2, 0);
69 
70  const Array4<const Real>& cons_arr = cons_in->const_array(mfi);
71  const Array4<const Real>& z_nd_arr = (z_phys) ? z_phys->const_array(mfi) : Array4<const Real>{};
72  const Array4<Real>& deltaq_arr = deltaq.array(mfi);
73  const Array4<Real>& flux_arr = flux.array(mfi);
74  const Array4<Real>& radlwdn_arr = radlwdn->array(mfi);
75  const Array4<Real>& radqrlw_arr = radqrlw->array(mfi);
76  const Array4<Real>& qheating_arr = qheating_rates->array(mfi);
77 
78  const Array4<Real>& radfluxes_arr = rad_fluxes->array(mfi);
79 
80  ParallelFor(box, [=] AMREX_GPU_DEVICE (int i, int j, int)
81  {
82  int itop = 0;
83  Real qzinf = 0.0; // holds accumulated optical depth between z and domain top
84  Real qzeroz = 0.0; // holds accumulated optical depth between surface and z
85 
86  for (int k = 0; k < nz; k++)
87  {
88  Real rho = cons_arr(i, j, k, Rho_comp);
89  Real qv = (have_qv) ? cons_arr(i, j, k, qv_comp) / rho : zero;
90  Real qc = (have_qc) ? cons_arr(i, j, k, qc_comp) / rho : zero;
91  Real qi = (ice) ? cons_arr(i, j, k, qi_comp) / rho : zero;
92 
93  Real dz = (z_nd_arr) ? Real(0.25) * ( (z_nd_arr(i ,j ,k+1) - z_nd_arr(i ,j ,k))
94  + (z_nd_arr(i+1,j ,k+1) - z_nd_arr(i+1,j ,k))
95  + (z_nd_arr(i ,j+1,k+1) - z_nd_arr(i ,j+1,k))
96  + (z_nd_arr(i+1,j+1,k+1) - z_nd_arr(i+1,j+1,k)) ) : fixed_dz;
97 
98  // optical depth only includes that due to liquid water
99  if (qc + qi > 0.0)
100  {
101  deltaq_arr(i, j, k) = xk * rho * (qc + qi) * dz;
102  }
103 
104  // inversion height is top of highest layer w/q>8g/kg
105  if (qv + qc + qi > 0.008)
106  {
107  itop = max(itop, k+1); // note zi(k+1) is inversion height
108  }
109 
110  // accumulate optical depth in qzinf
111  qzinf = qzinf + deltaq_arr(i, j, k);
112  }
113 
114  // note: qzinf now holds total optical depth of column (due to cloud)
115  // qzeroz is initialized to zero since first level is at surface
116 
117  // compute net upward longwave flux up to inversion height
118  for (int k = 0; k <= itop; k++)
119  {
120  flux_arr(i, j, k) = coef*exp(-qzinf) + coef1*exp(-qzeroz);
121  qzinf = qzinf - deltaq_arr(i, j, k);
122  qzeroz = qzeroz + deltaq_arr(i, j, k);
123  }
124 
125  // compute net upward longwave flux above inversion height
126  // this includes correction for clearsky fluxes which balances
127  // the prescribed subsidence heating above the inversion
128  Real z_itop = (z_nd_arr) ? z_nd_arr(i, j, itop) : itop * fixed_dz;
129  for (int k = itop + 1; k < nz; k++) {
130  Real rho_nd = 0.5 * (cons_arr(i, j, k - 1, Rho_comp) + cons_arr(i, j, k, Rho_comp)); // rho at interface
131  Real zi = (z_nd_arr) ? z_nd_arr(i, j, k) : k * fixed_dz;
132  flux_arr(i, j, k) = coef * exp(-qzinf) + coef1 * exp(-qzeroz)
133  + cp_spec * rho_nd * f0 * (0.25 * zi + 0.75 * z_itop)
134  * pow(zi - z_itop, 1.0 / 3.0);
135  qzinf = qzinf - deltaq_arr(i, j, k);
136  qzeroz = qzeroz + deltaq_arr(i, j, k);
137  }
138  Real rho_nd = 0.5 * (cons_arr(i, j, nz - 1, Rho_comp) + cons_arr(i, j, nz, Rho_comp));
139  Real zi = (z_nd_arr) ? z_nd_arr(i, j, nz) : nz * fixed_dz;
140  flux_arr(i, j, nz) = coef * exp(-qzinf) + coef1 * exp(-qzeroz)
141  + cp_spec * rho_nd * f0 * (0.25 * zi + 0.75 * z_itop)
142  * pow(zi - z_itop, 1.0 / 3.0);
143 
144  // note that our flux differs from the specification in that it
145  // uses the local density (rather than the interface density) in
146  // computing the correction to the flux above the inversion.
147  // Formulating things in this way ensures a rough balance between
148  // the subsidence heating and radiative cooling above the inversion.
149 
150  // compute radiative heating as divergence of net upward lw flux
151  for (int k = 0; k < nz; k++)
152  {
153  Real dz = (z_nd_arr) ? 0.25 * ( (z_nd_arr(i ,j ,k+1) - z_nd_arr(i ,j ,k))
154  + (z_nd_arr(i+1,j ,k+1) - z_nd_arr(i+1,j ,k))
155  + (z_nd_arr(i ,j+1,k+1) - z_nd_arr(i ,j+1,k))
156  + (z_nd_arr(i+1,j+1,k+1) - z_nd_arr(i+1,j+1,k)) ) : fixed_dz;
157 
158  Real cpmassl = cp_spec * cons_arr(i, j, k, Rho_comp) * dz; // thermal mass
159  Real FTHRL = -(flux_arr(i, j, k+1) - flux_arr(i, j, k)) / cpmassl;
160  // convert heating rate FTHRL for theta_d
161  Real pres = getPgivenRTh(cons_arr(i,j,k,RhoTheta_comp),cons_arr(i,j,k,RhoQ1_comp)/cons_arr(i,j,k,Rho_comp));
162  Real exner = getExnergivenP(pres, R_d/Cp_d);
163  FTHRL *= exner;
164  qheating_arr(i, j, k, 1) = FTHRL; // radiative heating for source term
165  radlwdn_arr(i, j, k) = flux_arr(i, j, k); // net lw flux
166  radqrlw_arr(i, j, k) = FTHRL; // net lw heating
167 
168  // write lw dn to ERF fluxes
169  radfluxes_arr(i, j, k, 3) = flux_arr(i, j, k); // net lw flux
170  }
171  });
172  }
173 }
constexpr amrex::Real Cp_d
Definition: ERF_Constants.H:49
constexpr amrex::Real R_d
Definition: ERF_Constants.H:47
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:39
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:40
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:45
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:27
@ rho
Definition: ERF_Kessler.H:24
@ qv
Definition: ERF_Kessler.H:30
@ qc
Definition: ERF_SatAdj.H:41
@ qi
Definition: ERF_WDM6.H:27
@ dz
Definition: ERF_AdvanceWDM6.cpp:270
@ zi
Definition: ERF_AdvanceWDM6.cpp:274
Here is the call graph for this function:

◆ WriteDataLog()

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

Implements IRadiation.

176 {
177  constexpr int datwidth = 14;
178  constexpr int datprecision = 9;
179  constexpr int timeprecision = 13;
180 
181  Gpu::HostVector<Real> h_avg_radlwdn, h_avg_radqrlw;
182 
183  auto domain = m_geom.Domain();
184  h_avg_radlwdn = sumToLine(*radlwdn, 0, 1, domain, 2);
185  h_avg_radqrlw = sumToLine(*radqrlw, 0, 1, domain, 2);
186 
187  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
188  int nz = domain.length(2);
189  for (int k = 0; k < nz; k++) {
190  h_avg_radlwdn[k] /= area_z;
191  h_avg_radqrlw[k] /= area_z;
192  }
193 
194  if (ParallelDescriptor::IOProcessor()) {
195  std::ostream& log = *datalog;
196 
197  if (log.good()) {
198  for (int k = 0; k < nz; k++)
199  {
200  Real z = k * m_geom.CellSize(2);
201  log << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
202  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
203  << h_avg_radlwdn[k] << " "
204  << h_avg_radqrlw[k] << std::endl;
205  }
206  // Write top face values
207  Real z = nz * m_geom.CellSize(2);
208  log << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
209  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
210  << 0.0 << " "
211  << 0.0 << std::endl;
212  }
213  }
214 }
std::unique_ptr< std::fstream > datalog
Definition: ERF_RadiationInterface.H:86

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_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: