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

#include <ERF_SAM.H>

Inheritance diagram for SAM:
Collaboration diagram for SAM:

Public Member Functions

 SAM ()
 
virtual ~SAM ()=default
 
void Cloud (const SolverChoice &sc)
 
void IceFall (const SolverChoice &sc)
 
void Precip (const SolverChoice &sc)
 
void PrecipFall (const SolverChoice &sc)
 
void Define (SolverChoice &sc) override
 
void Init (const amrex::MultiFab &cons_in, const amrex::BoxArray &grids, const amrex::Geometry &geom, const amrex::Real &dt_advance, std::unique_ptr< amrex::MultiFab > &z_phys_nd, std::unique_ptr< amrex::MultiFab > &detJ_cc) override
 
void Set_dzmin (const amrex::Real dz_min) override
 
void Copy_State_to_Micro (const amrex::MultiFab &cons_in) override
 
void Copy_Micro_to_State (amrex::MultiFab &cons_in) override
 
void Update_Micro_Vars (amrex::MultiFab &cons_in) override
 
void Update_State_Vars (amrex::MultiFab &cons_in) override
 
void Advance (const amrex::Real &dt_advance, const SolverChoice &sc) override
 
amrex::MultiFab * Qmoist_Ptr (const int &varIdx) override
 
void Compute_Coefficients ()
 
int Qmoist_Size () override
 
int Qstate_Moist_Size () override
 
void Set_RealWidth (const int real_width) override
 
void Qmoist_Restart_Vars (const SolverChoice &, std::vector< int > &a_idx, std::vector< std::string > &a_names) const override
 
- Public Member Functions inherited from NullMoist
 NullMoist ()
 
virtual ~NullMoist ()=default
 
virtual int Qstate_NonMoist_Size ()
 
virtual void GetPlotVarNames (amrex::Vector< std::string > &a_vec) const
 
virtual void GetPlotVar (const std::string &, amrex::MultiFab &) const
 

Static Public Member Functions

AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real NewtonIterSat (int &i, int &j, int &k, const int &SAM_moisture_type, const amrex::Real &fac_cond, const amrex::Real &, const amrex::Real &fac_sub, const amrex::Real &an, const amrex::Real &bn, const amrex::Array4< amrex::Real > &tabs_array, const amrex::Array4< amrex::Real > &pres_array, const amrex::Array4< amrex::Real > &qv_array, const amrex::Array4< amrex::Real > &qc_array, const amrex::Array4< amrex::Real > &qi_array, const amrex::Array4< amrex::Real > &qn_array, const amrex::Array4< amrex::Real > &qt_array)
 

Private Types

using FabPtr = std::shared_ptr< amrex::MultiFab >
 

Private Attributes

int m_qmoist_size = 3
 
int n_qstate_moist_size = 6
 
amrex::Vector< int > MicVarMap
 
amrex::Geometry m_geom
 
int m_real_width {0}
 
amrex::Real dt
 
int nlev
 
int zlo
 
int zhi
 
int m_axis
 
amrex::Real m_fac_cond
 
amrex::Real m_fac_fus
 
amrex::Real m_fac_sub
 
amrex::Real m_rdOcp
 
bool m_do_cond
 
amrex::Real m_dzmin
 
amrex::MultiFab * m_z_phys_nd
 
amrex::MultiFab * m_detJ_cc
 
amrex::Array< FabPtr, MicVar::NumVarsmic_fab_vars
 
amrex::TableData< amrex::Real, 1 > accrrc
 
amrex::TableData< amrex::Real, 1 > accrsi
 
amrex::TableData< amrex::Real, 1 > accrsc
 
amrex::TableData< amrex::Real, 1 > coefice
 
amrex::TableData< amrex::Real, 1 > evaps1
 
amrex::TableData< amrex::Real, 1 > evaps2
 
amrex::TableData< amrex::Real, 1 > accrgi
 
amrex::TableData< amrex::Real, 1 > accrgc
 
amrex::TableData< amrex::Real, 1 > evapg1
 
amrex::TableData< amrex::Real, 1 > evapg2
 
amrex::TableData< amrex::Real, 1 > evapr1
 
amrex::TableData< amrex::Real, 1 > evapr2
 
amrex::TableData< amrex::Real, 1 > rho1d
 
amrex::TableData< amrex::Real, 1 > pres1d
 
amrex::TableData< amrex::Real, 1 > tabs1d
 
amrex::TableData< amrex::Real, 1 > qt1d
 
amrex::TableData< amrex::Real, 1 > qv1d
 
amrex::TableData< amrex::Real, 1 > qn1d
 

Static Private Attributes

static constexpr amrex::Real CFL_MAX = 0.5
 

Member Typedef Documentation

◆ FabPtr

using SAM::FabPtr = std::shared_ptr<amrex::MultiFab>
private

Constructor & Destructor Documentation

◆ SAM()

SAM::SAM ( )
inline
59 {}

◆ ~SAM()

virtual SAM::~SAM ( )
virtualdefault

Member Function Documentation

◆ Advance()

void SAM::Advance ( const amrex::Real dt_advance,
const SolverChoice sc 
)
inlineoverridevirtual

Reimplemented from NullMoist.

129  {
130  dt = dt_advance;
131 
132  this->Cloud(sc);
133  this->IceFall(sc);
134  this->Precip(sc);
135  this->PrecipFall(sc);
136  }
void Precip(const SolverChoice &sc)
Definition: ERF_Precip.cpp:10
void IceFall(const SolverChoice &sc)
Definition: ERF_IceFall.cpp:11
void Cloud(const SolverChoice &sc)
Definition: ERF_CloudSAM.cpp:12
void PrecipFall(const SolverChoice &sc)
Definition: ERF_PrecipFall.cpp:16
amrex::Real dt
Definition: ERF_SAM.H:306
Here is the call graph for this function:

◆ Cloud()

void SAM::Cloud ( const SolverChoice sc)

Split cloud components according to saturation pressures; source theta from latent heat.

13 {
14  if (!m_do_cond) { return; }
15 
16  constexpr Real an = 1.0/(tbgmax-tbgmin);
17  constexpr Real bn = tbgmin*an;
18 
19  Real fac_cond = m_fac_cond;
20  Real fac_sub = m_fac_sub;
21  Real fac_fus = m_fac_fus;
22  Real rdOcp = m_rdOcp;
23 
24  int SAM_moisture_type = 1;
25  if (sc.moisture_type == MoistureType::SAM_NoIce ||
26  sc.moisture_type == MoistureType::SAM_NoPrecip_NoIce) {
27  SAM_moisture_type = 2;
28  }
29 
30  auto domain = m_geom.Domain();
31  int i_lo = domain.smallEnd(0);
32  int i_hi = domain.bigEnd(0);
33  int j_lo = domain.smallEnd(1);
34  int j_hi = domain.bigEnd(1);
35 
36  for ( MFIter mfi(*(mic_fab_vars[MicVar::tabs]), TilingIfNotGPU()); mfi.isValid(); ++mfi) {
37  auto qt_array = mic_fab_vars[MicVar::qt]->array(mfi);
38  auto qn_array = mic_fab_vars[MicVar::qn]->array(mfi);
39  auto qv_array = mic_fab_vars[MicVar::qv]->array(mfi);
40  auto qcl_array = mic_fab_vars[MicVar::qcl]->array(mfi);
41  auto qci_array = mic_fab_vars[MicVar::qci]->array(mfi);
42 
43  auto rho_array = mic_fab_vars[MicVar::rho]->array(mfi);
44  auto tabs_array = mic_fab_vars[MicVar::tabs]->array(mfi);
45  auto theta_array = mic_fab_vars[MicVar::theta]->array(mfi);
46  auto pres_array = mic_fab_vars[MicVar::pres]->array(mfi);
47 
48  auto tbx = mfi.tilebox();
49  if (tbx.smallEnd(0) == i_lo) { tbx.growLo(0,-m_real_width); }
50  if (tbx.bigEnd(0) == i_hi) { tbx.growHi(0,-m_real_width); }
51  if (tbx.smallEnd(1) == j_lo) { tbx.growLo(1,-m_real_width); }
52  if (tbx.bigEnd(1) == j_hi) { tbx.growHi(1,-m_real_width); }
53 
54  ParallelFor(tbx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
55  {
56  // Saturation moisture fractions
57  Real omn;
58  Real qsat;
59  Real qsatw;
60  Real qsati;
61 
62  // Newton iteration vars
63  Real delta_qv, delta_qc, delta_qi;
64 
65  // NOTE: Conversion before iterations is necessary to
66  // convert cloud water to ice or vice versa.
67  // This ensures the omn splitting is enforced
68  // before the Newton iteration, which assumes it is.
69 
70  omn = 1.0;
71  if (SAM_moisture_type == 1){
72  // Cloud ice not permitted (melt to form water)
73  if (tabs_array(i,j,k) >= tbgmax) {
74  omn = 1.0;
75  delta_qi = qci_array(i,j,k);
76  qci_array(i,j,k) = 0.0;
77  qcl_array(i,j,k) += delta_qi;
78  tabs_array(i,j,k) -= fac_fus * delta_qi;
79  pres_array(i,j,k) = rho_array(i,j,k) * R_d * tabs_array(i,j,k)
80  * (1.0 + R_v/R_d * qv_array(i,j,k));
81  theta_array(i,j,k) = getThgivenTandP(tabs_array(i,j,k), pres_array(i,j,k), rdOcp);
82  pres_array(i,j,k) *= 0.01;
83  }
84  // Cloud water not permitted (freeze to form ice)
85  else if (tabs_array(i,j,k) <= tbgmin) {
86  omn = 0.0;
87  delta_qc = qcl_array(i,j,k);
88  qcl_array(i,j,k) = 0.0;
89  qci_array(i,j,k) += delta_qc;
90  tabs_array(i,j,k) += fac_fus * delta_qc;
91  pres_array(i,j,k) = rho_array(i,j,k) * R_d * tabs_array(i,j,k)
92  * (1.0 + R_v/R_d * qv_array(i,j,k));
93  theta_array(i,j,k) = getThgivenTandP(tabs_array(i,j,k), pres_array(i,j,k), rdOcp);
94  pres_array(i,j,k) *= 0.01;
95  }
96  // Mixed cloud phase (split according to omn)
97  else {
98  omn = an*tabs_array(i,j,k)-bn;
99  delta_qc = qcl_array(i,j,k) - qn_array(i,j,k) * omn;
100  delta_qi = qci_array(i,j,k) - qn_array(i,j,k) * (1.0 - omn);
101  qcl_array(i,j,k) = qn_array(i,j,k) * omn;
102  qci_array(i,j,k) = qn_array(i,j,k) * (1.0 - omn);
103  tabs_array(i,j,k) += fac_fus * delta_qc;
104  pres_array(i,j,k) = rho_array(i,j,k) * R_d * tabs_array(i,j,k)
105  * (1.0 + R_v/R_d * qv_array(i,j,k));
106  theta_array(i,j,k) = getThgivenTandP(tabs_array(i,j,k), pres_array(i,j,k), rdOcp);
107  pres_array(i,j,k) *= 0.01;
108  }
109  }
110  else if (SAM_moisture_type == 2)
111  {
112  // No ice. ie omn = 1.0
113  delta_qc = qcl_array(i,j,k) - qn_array(i,j,k);
114  delta_qi = 0.0;
115  qcl_array(i,j,k) = qn_array(i,j,k);
116  qci_array(i,j,k) = 0.0;
117  tabs_array(i,j,k) += fac_cond * delta_qc;
118  pres_array(i,j,k) = rho_array(i,j,k) * R_d * tabs_array(i,j,k)
119  * (1.0 + R_v/R_d * qv_array(i,j,k));
120  theta_array(i,j,k) = getThgivenTandP(tabs_array(i,j,k), pres_array(i,j,k), rdOcp);
121  pres_array(i,j,k) *= 0.01;
122  }
123 
124  // Saturation moisture fractions
125  erf_qsatw(tabs_array(i,j,k), pres_array(i,j,k), qsatw);
126  erf_qsati(tabs_array(i,j,k), pres_array(i,j,k), qsati);
127  qsat = omn * qsatw + (1.0-omn) * qsati;
128 
129  // We have enough total moisture to relax to equilibrium
130  if (qt_array(i,j,k) > qsat) {
131 
132  // Update temperature
133  tabs_array(i,j,k) = NewtonIterSat(i, j, k , SAM_moisture_type ,
134  fac_cond , fac_fus , fac_sub ,
135  an , bn ,
136  tabs_array, pres_array,
137  qv_array , qcl_array , qci_array,
138  qn_array , qt_array);
139 
140  // Update theta
141  theta_array(i,j,k) = getThgivenTandP(tabs_array(i,j,k), 100.0*pres_array(i,j,k), rdOcp);
142 
143  //
144  // We cannot blindly relax to qsat, but we can convert qc/qi -> qv.
145  // The concept here is that if we put all the moisture into qv and modify
146  // the temperature, we can then check if qv > qsat occurs (for final T/P/qv).
147  // If the reduction in T/qsat and increase in qv does trigger the
148  // aforementioned condition, we can do Newton iteration to drive qv = qsat.
149  //
150  } else {
151  // Changes in each component
152  delta_qv = qcl_array(i,j,k) + qci_array(i,j,k);
153  delta_qc = qcl_array(i,j,k);
154  delta_qi = qci_array(i,j,k);
155 
156  // Partition the change in non-precipitating q
157  qv_array(i,j,k) += delta_qv;
158  qcl_array(i,j,k) = 0.0;
159  qci_array(i,j,k) = 0.0;
160  qn_array(i,j,k) = 0.0;
161  qt_array(i,j,k) = qv_array(i,j,k);
162 
163  // Update temperature (endothermic since we evap/sublime)
164  tabs_array(i,j,k) -= fac_cond * delta_qc + fac_sub * delta_qi;
165 
166  // Update theta
167  theta_array(i,j,k) = getThgivenTandP(tabs_array(i,j,k), 100.0*pres_array(i,j,k), rdOcp);
168 
169  // Verify assumption that qv > qsat does not occur
170  erf_qsatw(tabs_array(i,j,k), pres_array(i,j,k), qsatw);
171  erf_qsati(tabs_array(i,j,k), pres_array(i,j,k), qsati);
172  qsat = omn * qsatw + (1.0-omn) * qsati;
173  if (qt_array(i,j,k) > qsat) {
174 
175  // Update temperature
176  tabs_array(i,j,k) = NewtonIterSat(i, j, k , SAM_moisture_type ,
177  fac_cond , fac_fus , fac_sub ,
178  an , bn ,
179  tabs_array, pres_array,
180  qv_array , qcl_array , qci_array,
181  qn_array , qt_array);
182 
183  // Update theta
184  theta_array(i,j,k) = getThgivenTandP(tabs_array(i,j,k), 100.0*pres_array(i,j,k), rdOcp);
185 
186  }
187  }
188  });
189  } // mfi
190 }
constexpr amrex::Real R_v
Definition: ERF_Constants.H:11
constexpr amrex::Real tbgmax
Definition: ERF_Constants.H:32
constexpr amrex::Real tbgmin
Definition: ERF_Constants.H:31
constexpr amrex::Real R_d
Definition: ERF_Constants.H:10
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getThgivenTandP(const amrex::Real T, const amrex::Real P, const amrex::Real rdOcp)
Definition: ERF_EOS.H:18
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsatw(amrex::Real t, amrex::Real p, amrex::Real &qsatw)
Definition: ERF_MicrophysicsUtils.H:166
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsati(amrex::Real t, amrex::Real p, amrex::Real &qsati)
Definition: ERF_MicrophysicsUtils.H:155
amrex::Real Real
Definition: ERF_ShocInterface.H:19
amrex::Array< FabPtr, MicVar::NumVars > mic_fab_vars
Definition: ERF_SAM.H:329
amrex::Real m_rdOcp
Definition: ERF_SAM.H:318
amrex::Real m_fac_fus
Definition: ERF_SAM.H:316
bool m_do_cond
Definition: ERF_SAM.H:319
amrex::Real m_fac_cond
Definition: ERF_SAM.H:315
amrex::Geometry m_geom
Definition: ERF_SAM.H:300
amrex::Real m_fac_sub
Definition: ERF_SAM.H:317
int m_real_width
Definition: ERF_SAM.H:303
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real NewtonIterSat(int &i, int &j, int &k, const int &SAM_moisture_type, const amrex::Real &fac_cond, const amrex::Real &, const amrex::Real &fac_sub, const amrex::Real &an, const amrex::Real &bn, const amrex::Array4< amrex::Real > &tabs_array, const amrex::Array4< amrex::Real > &pres_array, const amrex::Array4< amrex::Real > &qv_array, const amrex::Array4< amrex::Real > &qc_array, const amrex::Array4< amrex::Real > &qi_array, const amrex::Array4< amrex::Real > &qn_array, const amrex::Array4< amrex::Real > &qt_array)
Definition: ERF_SAM.H:160
@ pres
Definition: ERF_SAM.H:33
@ qci
Definition: ERF_SAM.H:39
@ qv
Definition: ERF_SAM.H:37
@ rho
Definition: ERF_SAM.H:30
@ qt
Definition: ERF_SAM.H:35
@ qn
Definition: ERF_SAM.H:36
@ theta
Definition: ERF_SAM.H:31
@ qcl
Definition: ERF_SAM.H:38
@ tabs
Definition: ERF_SAM.H:32
MoistureType moisture_type
Definition: ERF_DataStruct.H:1171

Referenced by Advance().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Compute_Coefficients()

void SAM::Compute_Coefficients ( )
137 {
138  auto accrrc_t = accrrc.table();
139  auto accrsi_t = accrsi.table();
140  auto accrsc_t = accrsc.table();
141  auto coefice_t = coefice.table();
142  auto evaps1_t = evaps1.table();
143  auto evaps2_t = evaps2.table();
144  auto accrgi_t = accrgi.table();
145  auto accrgc_t = accrgc.table();
146  auto evapg1_t = evapg1.table();
147  auto evapg2_t = evapg2.table();
148  auto evapr1_t = evapr1.table();
149  auto evapr2_t = evapr2.table();
150 
151  auto rho1d_t = rho1d.table();
152  auto pres1d_t = pres1d.table();
153  auto tabs1d_t = tabs1d.table();
154 
155  Real gam3 = erf_gammafff(3.0 );
156  Real gamr1 = erf_gammafff(3.0+b_rain );
157  Real gamr2 = erf_gammafff((5.0+b_rain)/2.0);
158  Real gams1 = erf_gammafff(3.0+b_snow );
159  Real gams2 = erf_gammafff((5.0+b_snow)/2.0);
160  Real gamg1 = erf_gammafff(3.0+b_grau );
161  Real gamg2 = erf_gammafff((5.0+b_grau)/2.0);
162 
163  // calculate the plane average variables
167  rho_ave.compute_averages(ZDir(), rho_ave.field());
168  theta_ave.compute_averages(ZDir(), theta_ave.field());
169  qv_ave.compute_averages(ZDir(), qv_ave.field());
170 
171  // get host variable rho, and rhotheta
172  int ncell = rho_ave.ncell_line();
173 
174  Gpu::HostVector<Real> rho_h(ncell), theta_h(ncell), qv_h(ncell);
175  rho_ave.line_average(0, rho_h);
176  theta_ave.line_average(0, theta_h);
177  qv_ave.line_average(0, qv_h);
178 
179  // copy data to device
180  Gpu::DeviceVector<Real> rho_d(ncell), theta_d(ncell), qv_d(ncell);
181  Gpu::copyAsync(Gpu::hostToDevice, rho_h.begin(), rho_h.end(), rho_d.begin());
182  Gpu::copyAsync(Gpu::hostToDevice, theta_h.begin(), theta_h.end(), theta_d.begin());
183  Gpu::copyAsync(Gpu::hostToDevice, qv_h.begin(), qv_h.end(), qv_d.begin());
184  Gpu::streamSynchronize();
185 
186  Real* rho_dptr = rho_d.data();
187  Real* theta_dptr = theta_d.data();
188  Real* qv_dptr = qv_d.data();
189 
190  ParallelFor(nlev, [=] AMREX_GPU_DEVICE (int k) noexcept
191  {
192  Real RhoTheta = rho_dptr[k]*theta_dptr[k];
193  Real pressure = getPgivenRTh(RhoTheta, qv_dptr[k]);
194  rho1d_t(k) = rho_dptr[k];
195  pres1d_t(k) = pressure*0.01;
196  // NOTE: Limit the temperature to the melting point of ice to avoid a divide by
197  // 0 condition when computing the cold evaporation coefficients. This should
198  // not affect results since evporation requires snow/graupel to be present
199  // and thus T<273.16
200  tabs1d_t(k) = std::min(getTgivenRandRTh(rho_dptr[k], RhoTheta, qv_dptr[k]),273.16);
201  });
202 
203  if(round(gam3) != 2) {
204  std::cout << "cannot compute gamma-function in Microphysics::Init" << std::endl;
205  std::exit(-1);
206  }
207 
208  // Populate all the coefficients
209  ParallelFor(nlev, [=] AMREX_GPU_DEVICE (int k) noexcept
210  {
211  Real Prefactor;
212  Real pratio = sqrt(1.29 / rho1d_t(k));
213  //Real rrr1 = 393.0/(tabs1d_t(k)+120.0)*std::pow((tabs1d_t(k)/273.0),1.5);
214  //Real rrr2 = std::pow((tabs1d_t(k)/273.0),1.94)*(1000.0/pres1d_t(k));
215  Real estw = 100.0*erf_esatw(tabs1d_t(k));
216  Real esti = 100.0*erf_esati(tabs1d_t(k));
217 
218  // accretion by snow:
219  Real coef1 = 0.25 * PI * nzeros * a_snow * gams1 * pratio/pow((PI * rhos * nzeros/rho1d_t(k) ) , ((3.0+b_snow)/4.0));
220  Real coef2 = exp(0.025*(tabs1d_t(k) - 273.15));
221  accrsi_t(k) = coef1 * coef2 * esicoef;
222  accrsc_t(k) = coef1 * esccoef;
223  coefice_t(k) = coef2;
224 
225  // evaporation of snow:
226  coef1 = (lsub/(tabs1d_t(k)*R_v)-1.0)*lsub/(therco*tabs1d_t(k));
227  coef2 = R_v * R_d / (diffelq * esti);
228  Prefactor = 2.0 * PI * nzeros / (rho1d_t(k) * (coef1 + coef2));
229  Prefactor *= (2.0/PI); // Shape factor snow
230  evaps1_t(k) = Prefactor * 0.65 * sqrt(rho1d_t(k) / (PI * rhos * nzeros));
231  evaps2_t(k) = Prefactor * 0.44 * sqrt(a_snow * rho1d_t(k) / muelq) * gams2
232  * sqrt(pratio) * pow(rho1d_t(k) / (PI * rhos * nzeros) , ((5.0+b_snow)/8.0));
233 
234  // accretion by graupel:
235  coef1 = 0.25*PI*nzerog*a_grau*gamg1*pratio/pow((PI*rhog*nzerog/rho1d_t(k)) , ((3.0+b_grau)/4.0));
236  coef2 = exp(0.025*(tabs1d_t(k) - 273.15));
237  accrgi_t(k) = coef1 * coef2 * egicoef;
238  accrgc_t(k) = coef1 * egccoef;
239 
240  // evaporation of graupel:
241  coef1 = (lsub/(tabs1d_t(k)*R_v)-1.0)*lsub/(therco*tabs1d_t(k));
242  coef2 = R_v * R_d / (diffelq * esti);
243  Prefactor = 2.0 * PI * nzerog / (rho1d_t(k) * (coef1 + coef2)); // Shape factor for graupel is 1
244  evapg1_t(k) = Prefactor * 0.78 * sqrt(rho1d_t(k) / (PI * rhog * nzerog));
245  evapg2_t(k) = Prefactor * 0.31 * sqrt(a_grau * rho1d_t(k) / muelq) * gamg2
246  * sqrt(pratio) * pow(rho1d_t(k) / (PI * rhog * nzerog) , ((5.0+b_grau)/8.0));
247 
248  // accretion by rain:
249  accrrc_t(k) = 0.25 * PI * nzeror * a_rain * gamr1 * pratio/pow((PI * rhor * nzeror / rho1d_t(k)) , ((3.0+b_rain)/4.))* erccoef;
250 
251  // evaporation of rain:
252  coef1 = (lcond/(tabs1d_t(k)*R_v)-1.0)*lcond/(therco*tabs1d_t(k));
253  coef2 = R_v * R_d / (diffelq * estw);
254  Prefactor = 2.0 * PI * nzeror / (rho1d_t(k) * (coef1 + coef2)); // Shape factor for rain is 1
255  evapr1_t(k) = Prefactor * 0.78 * sqrt(rho1d_t(k) / (PI * rhor * nzeror));
256  evapr2_t(k) = Prefactor * 0.31 * sqrt(a_rain * rho1d_t(k) / muelq) * gamr2
257  * sqrt(pratio) * pow(rho1d_t(k) / (PI * rhor * nzeror) , ((5.0+b_rain)/8.0));
258  });
259 }
constexpr amrex::Real rhog
Definition: ERF_Constants.H:30
constexpr amrex::Real muelq
Definition: ERF_Constants.H:75
constexpr amrex::Real nzerog
Definition: ERF_Constants.H:59
constexpr amrex::Real a_grau
Definition: ERF_Constants.H:42
constexpr amrex::Real lsub
Definition: ERF_Constants.H:68
constexpr amrex::Real esicoef
Definition: ERF_Constants.H:53
constexpr amrex::Real diffelq
Definition: ERF_Constants.H:73
constexpr amrex::Real therco
Definition: ERF_Constants.H:74
constexpr amrex::Real b_grau
Definition: ERF_Constants.H:43
constexpr amrex::Real egccoef
Definition: ERF_Constants.H:54
constexpr amrex::Real egicoef
Definition: ERF_Constants.H:55
constexpr amrex::Real b_rain
Definition: ERF_Constants.H:39
constexpr amrex::Real lcond
Definition: ERF_Constants.H:66
constexpr amrex::Real PI
Definition: ERF_Constants.H:6
constexpr amrex::Real nzeror
Definition: ERF_Constants.H:57
constexpr amrex::Real rhos
Definition: ERF_Constants.H:29
constexpr amrex::Real esccoef
Definition: ERF_Constants.H:52
constexpr amrex::Real rhor
Definition: ERF_Constants.H:28
constexpr amrex::Real a_rain
Definition: ERF_Constants.H:38
constexpr amrex::Real nzeros
Definition: ERF_Constants.H:58
constexpr amrex::Real a_snow
Definition: ERF_Constants.H:40
constexpr amrex::Real b_snow
Definition: ERF_Constants.H:41
constexpr amrex::Real erccoef
Definition: ERF_Constants.H:51
DirectionSelector< 2 > ZDir
Definition: ERF_DirectionSelector.H:38
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getPgivenRTh(const amrex::Real rhotheta, const amrex::Real qv=0.)
Definition: ERF_EOS.H:81
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
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esatw(amrex::Real t)
Definition: ERF_MicrophysicsUtils.H:68
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esati(amrex::Real t)
Definition: ERF_MicrophysicsUtils.H:26
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_gammafff(amrex::Real x)
Definition: ERF_MicrophysicsUtils.H:15
Definition: ERF_PlaneAverage.H:14
amrex::TableData< amrex::Real, 1 > rho1d
Definition: ERF_SAM.H:346
amrex::TableData< amrex::Real, 1 > evapr2
Definition: ERF_SAM.H:343
amrex::TableData< amrex::Real, 1 > evapg1
Definition: ERF_SAM.H:340
amrex::TableData< amrex::Real, 1 > accrgi
Definition: ERF_SAM.H:338
amrex::TableData< amrex::Real, 1 > evapg2
Definition: ERF_SAM.H:341
int m_axis
Definition: ERF_SAM.H:312
amrex::TableData< amrex::Real, 1 > evaps1
Definition: ERF_SAM.H:336
amrex::TableData< amrex::Real, 1 > accrsi
Definition: ERF_SAM.H:333
amrex::TableData< amrex::Real, 1 > accrrc
Definition: ERF_SAM.H:332
amrex::TableData< amrex::Real, 1 > pres1d
Definition: ERF_SAM.H:347
int nlev
Definition: ERF_SAM.H:309
amrex::TableData< amrex::Real, 1 > evapr1
Definition: ERF_SAM.H:342
amrex::TableData< amrex::Real, 1 > evaps2
Definition: ERF_SAM.H:337
amrex::TableData< amrex::Real, 1 > accrgc
Definition: ERF_SAM.H:339
amrex::TableData< amrex::Real, 1 > accrsc
Definition: ERF_SAM.H:334
amrex::TableData< amrex::Real, 1 > coefice
Definition: ERF_SAM.H:335
amrex::TableData< amrex::Real, 1 > tabs1d
Definition: ERF_SAM.H:348

Referenced by Update_Micro_Vars().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Copy_Micro_to_State()

void SAM::Copy_Micro_to_State ( amrex::MultiFab &  cons_in)
overridevirtual

Updates conserved and microphysics variables in the provided MultiFabs from the internal MultiFabs that store Microphysics module data.

Parameters
[out]consConserved variables
[out]qmoistqv, qc, qi, qr, qs, qg

Reimplemented from NullMoist.

16 {
17  // Get the temperature, density, theta, qt and qp from input
18  for ( MFIter mfi(cons,TilingIfNotGPU()); mfi.isValid(); ++mfi) {
19  const auto& box3d = mfi.tilebox();
20 
21  auto states_arr = cons.array(mfi);
22 
23  auto rho_arr = mic_fab_vars[MicVar::rho]->array(mfi);
24  auto theta_arr = mic_fab_vars[MicVar::theta]->array(mfi);
25 
26  auto qv_arr = mic_fab_vars[MicVar::qv]->array(mfi);
27  auto qc_arr = mic_fab_vars[MicVar::qcl]->array(mfi);
28  auto qi_arr = mic_fab_vars[MicVar::qci]->array(mfi);
29 
30  auto qpr_arr = mic_fab_vars[MicVar::qpr]->array(mfi);
31  auto qps_arr = mic_fab_vars[MicVar::qps]->array(mfi);
32  auto qpg_arr = mic_fab_vars[MicVar::qpg]->array(mfi);
33 
34  // get potential total density, temperature, qt, qp
35  ParallelFor( box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
36  {
37  states_arr(i,j,k,RhoTheta_comp) = rho_arr(i,j,k)*theta_arr(i,j,k);
38 
39  states_arr(i,j,k,RhoQ1_comp) = rho_arr(i,j,k)*std::max(0.0,qv_arr(i,j,k));
40  states_arr(i,j,k,RhoQ2_comp) = rho_arr(i,j,k)*std::max(0.0,qc_arr(i,j,k));
41  states_arr(i,j,k,RhoQ3_comp) = rho_arr(i,j,k)*std::max(0.0,qi_arr(i,j,k));
42 
43  states_arr(i,j,k,RhoQ4_comp) = rho_arr(i,j,k)*std::max(0.0,qpr_arr(i,j,k));
44  states_arr(i,j,k,RhoQ5_comp) = rho_arr(i,j,k)*std::max(0.0,qps_arr(i,j,k));
45  states_arr(i,j,k,RhoQ6_comp) = rho_arr(i,j,k)*std::max(0.0,qpg_arr(i,j,k));
46  });
47  }
48 
49  // Fill interior ghost cells and periodic boundaries
50  cons.FillBoundary(m_geom.periodicity());
51 }
#define RhoQ4_comp
Definition: ERF_IndexDefines.H:45
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
#define RhoQ2_comp
Definition: ERF_IndexDefines.H:43
#define RhoQ3_comp
Definition: ERF_IndexDefines.H:44
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:42
#define RhoQ6_comp
Definition: ERF_IndexDefines.H:47
#define RhoQ5_comp
Definition: ERF_IndexDefines.H:46
@ qpr
Definition: ERF_SAM.H:42
@ qpg
Definition: ERF_SAM.H:44
@ qps
Definition: ERF_SAM.H:43
@ cons
Definition: ERF_IndexDefines.H:140

Referenced by Update_State_Vars().

Here is the caller graph for this function:

◆ Copy_State_to_Micro()

void SAM::Copy_State_to_Micro ( const amrex::MultiFab &  cons_in)
overridevirtual

Initializes the Microphysics module.

Parameters
[in]cons_inConserved variables input

Reimplemented from NullMoist.

85 {
86  // Get the temperature, density, theta, qt and qp from input
87  for ( MFIter mfi(cons_in); mfi.isValid(); ++mfi) {
88  const auto& box3d = mfi.growntilebox();
89 
90  auto states_array = cons_in.array(mfi);
91 
92  // Non-precipitating
93  auto qv_array = mic_fab_vars[MicVar::qv]->array(mfi);
94  auto qc_array = mic_fab_vars[MicVar::qcl]->array(mfi);
95  auto qi_array = mic_fab_vars[MicVar::qci]->array(mfi);
96  auto qn_array = mic_fab_vars[MicVar::qn]->array(mfi);
97  auto qt_array = mic_fab_vars[MicVar::qt]->array(mfi);
98 
99  // Precipitating
100  auto qpr_array = mic_fab_vars[MicVar::qpr]->array(mfi);
101  auto qps_array = mic_fab_vars[MicVar::qps]->array(mfi);
102  auto qpg_array = mic_fab_vars[MicVar::qpg]->array(mfi);
103  auto qp_array = mic_fab_vars[MicVar::qp]->array(mfi);
104 
105  auto rho_array = mic_fab_vars[MicVar::rho]->array(mfi);
106  auto theta_array = mic_fab_vars[MicVar::theta]->array(mfi);
107  auto tabs_array = mic_fab_vars[MicVar::tabs]->array(mfi);
108  auto pres_array = mic_fab_vars[MicVar::pres]->array(mfi);
109 
110  // Get pressure, theta, temperature, density, and qt, qp
111  ParallelFor( box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
112  {
113  rho_array(i,j,k) = states_array(i,j,k,Rho_comp);
114  theta_array(i,j,k) = states_array(i,j,k,RhoTheta_comp)/states_array(i,j,k,Rho_comp);
115 
116  qv_array(i,j,k) = std::max(0.0,states_array(i,j,k,RhoQ1_comp)/states_array(i,j,k,Rho_comp));
117  qc_array(i,j,k) = std::max(0.0,states_array(i,j,k,RhoQ2_comp)/states_array(i,j,k,Rho_comp));
118  qi_array(i,j,k) = std::max(0.0,states_array(i,j,k,RhoQ3_comp)/states_array(i,j,k,Rho_comp));
119  qn_array(i,j,k) = qc_array(i,j,k) + qi_array(i,j,k);
120  qt_array(i,j,k) = qv_array(i,j,k) + qn_array(i,j,k);
121 
122  qpr_array(i,j,k) = std::max(0.0,states_array(i,j,k,RhoQ4_comp)/states_array(i,j,k,Rho_comp));
123  qps_array(i,j,k) = std::max(0.0,states_array(i,j,k,RhoQ5_comp)/states_array(i,j,k,Rho_comp));
124  qpg_array(i,j,k) = std::max(0.0,states_array(i,j,k,RhoQ6_comp)/states_array(i,j,k,Rho_comp));
125  qp_array(i,j,k) = qpr_array(i,j,k) + qps_array(i,j,k) + qpg_array(i,j,k);
126 
127  tabs_array(i,j,k) = getTgivenRandRTh(states_array(i,j,k,Rho_comp),
128  states_array(i,j,k,RhoTheta_comp),
129  qv_array(i,j,k));
130  pres_array(i,j,k) = getPgivenRTh(states_array(i,j,k,RhoTheta_comp), qv_array(i,j,k)) * 0.01;
131  });
132  }
133 }
#define Rho_comp
Definition: ERF_IndexDefines.H:36
@ qp
Definition: ERF_SAM.H:41

Referenced by Update_Micro_Vars().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Define()

void SAM::Define ( SolverChoice sc)
inlineoverridevirtual

Reimplemented from NullMoist.

79  {
80  m_fac_cond = lcond / sc.c_p;
81  m_fac_fus = lfus / sc.c_p;
82  m_fac_sub = lsub / sc.c_p;
83  m_axis = sc.ave_plane;
84  m_rdOcp = sc.rdOcp;
85  m_do_cond = (!sc.use_shoc);
86  }
constexpr amrex::Real lfus
Definition: ERF_Constants.H:67
amrex::Real rdOcp
Definition: ERF_DataStruct.H:1124
amrex::Real c_p
Definition: ERF_DataStruct.H:1123
bool use_shoc
Definition: ERF_DataStruct.H:1155
int ave_plane
Definition: ERF_DataStruct.H:1186

◆ IceFall()

void SAM::IceFall ( const SolverChoice sc)

Sedimentation of cloud ice (A32)

11  {
12 
13  if(sc.moisture_type == MoistureType::SAM_NoIce ||
14  sc.moisture_type == MoistureType::SAM_NoPrecip_NoIce)
15  return;
16 
17  Real dtn = dt;
18  Real coef = dtn/m_dzmin;
19 
20  auto domain = m_geom.Domain();
21  int k_lo = domain.smallEnd(2);
22  int k_hi = domain.bigEnd(2);
23 
26  auto qn = mic_fab_vars[MicVar::qn];
27  auto qt = mic_fab_vars[MicVar::qt];
30 
31  MultiFab fz;
32  IntVect ng = qcl->nGrowVect();
33  BoxArray ba = qcl->boxArray();
34  DistributionMapping dm = qcl->DistributionMap();
35  fz.define(convert(ba, IntVect(0,0,1)), dm, 1, ng);
36  fz.setVal(0.);
37 
38  for (MFIter mfi(fz, TileNoZ()); mfi.isValid(); ++mfi) {
39  auto qci_array = qci->array(mfi);
40  auto rho_array = rho->array(mfi);
41  auto fz_array = fz.array(mfi);
42 
43  const auto& box3d = mfi.tilebox();
44 
45  ParallelFor(box3d, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
46  {
47  Real rho_avg, qci_avg;
48  if (k==k_lo) {
49  rho_avg = rho_array(i,j,k);
50  qci_avg = qci_array(i,j,k);
51  } else if (k==k_hi+1) {
52  rho_avg = rho_array(i,j,k-1);
53  qci_avg = qci_array(i,j,k-1);
54  } else {
55  rho_avg = 0.5*(rho_array(i,j,k-1) + rho_array(i,j,k));
56  qci_avg = 0.5*(qci_array(i,j,k-1) + qci_array(i,j,k));
57  }
58  Real vt_ice = min( 0.4 , 8.66 * pow( (std::max(0.,qci_avg)+1.e-10) , 0.24) );
59 
60  // NOTE: Fz is the sedimentation flux from the advective operator.
61  // In the terrain-following coordinate system, the z-deriv in
62  // the divergence uses the normal velocity (Omega). However,
63  // there are no u/v components to the sedimentation velocity.
64  // Therefore, we simply end up with a division by detJ when
65  // evaluating the source term: dJinv * (flux_hi - flux_lo) * dzinv.
66  fz_array(i,j,k) = rho_avg*vt_ice*qci_avg;
67  });
68  }
69 
70  // Compute number of substeps from maximum terminal velocity
71  Real wt_max;
72  int n_substep;
73  auto const& ma_fz_arr = fz.const_arrays();
74  GpuTuple<Real> max = ParReduce(TypeList<ReduceOpMax>{},
75  TypeList<Real>{},
76  fz, IntVect(0),
77  [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept
78  -> GpuTuple<Real>
79  {
80  return { ma_fz_arr[box_no](i,j,k) };
81  });
82  wt_max = get<0>(max) + std::numeric_limits<Real>::epsilon();
83  n_substep = int( std::ceil(wt_max * coef / CFL_MAX) );
84  AMREX_ALWAYS_ASSERT(n_substep >= 1);
85  coef /= Real(n_substep);
86  dtn /= Real(n_substep);
87 
88  // Substep the vertical advection
89  for (int nsub(0); nsub<n_substep; ++nsub) {
90  for (MFIter mfi(*qci, TileNoZ()); mfi.isValid(); ++mfi) {
91  auto qci_array = qci->array(mfi);
92  auto qn_array = qn->array(mfi);
93  auto qt_array = qt->array(mfi);
94  auto rho_array = rho->array(mfi);
95  auto fz_array = fz.array(mfi);
96 
97  const auto dJ_array = (m_detJ_cc) ? m_detJ_cc->const_array(mfi) : Array4<const Real>{};
98 
99  const auto& tbx = mfi.tilebox();
100  const auto& tbz = mfi.tilebox(IntVect(0,0,1),IntVect(0));
101 
102  // Update vertical flux every substep
103  ParallelFor(tbz, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
104  {
105  Real rho_avg, qci_avg;
106  if (k==k_lo) {
107  rho_avg = rho_array(i,j,k);
108  qci_avg = qci_array(i,j,k);
109  } else if (k==k_hi+1) {
110  rho_avg = rho_array(i,j,k-1);
111  qci_avg = qci_array(i,j,k-1);
112  } else {
113  rho_avg = 0.5*(rho_array(i,j,k-1) + rho_array(i,j,k));
114  qci_avg = 0.5*(qci_array(i,j,k-1) + qci_array(i,j,k));
115  }
116  Real vt_ice = min( 0.4 , 8.66 * pow( (std::max(0.,qci_avg)+1.e-10) , 0.24) );
117 
118  // NOTE: Fz is the sedimentation flux from the advective operator.
119  // In the terrain-following coordinate system, the z-deriv in
120  // the divergence uses the normal velocity (Omega). However,
121  // there are no u/v components to the sedimentation velocity.
122  // Therefore, we simply end up with a division by detJ when
123  // evaluating the source term: dJinv * (flux_hi - flux_lo) * dzinv.
124  fz_array(i,j,k) = rho_avg*vt_ice*qci_avg;
125  });
126 
127  // Update precip every substep
128  ParallelFor(tbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
129  {
130  // Jacobian determinant
131  Real dJinv = (dJ_array) ? 1.0/dJ_array(i,j,k) : 1.0;
132 
133  //==================================================
134  // Cloud ice sedimentation (A32)
135  //==================================================
136  Real dqi = dJinv * (1.0/rho_array(i,j,k)) * ( fz_array(i,j,k+1) - fz_array(i,j,k) ) * coef;
137  dqi = std::max(-qci_array(i,j,k), dqi);
138 
139  // Add this increment to both non-precipitating and total water.
140  qci_array(i,j,k) += dqi;
141  qn_array(i,j,k) += dqi;
142  qt_array(i,j,k) += dqi;
143 
144  // NOTE: Sedimentation does not affect the potential temperature,
145  // but it does affect the liquid/ice static energy.
146  // No source to Theta occurs here.
147  });
148  } // mfi
149  } // nsub
150 }
AMREX_FORCE_INLINE amrex::IntVect TileNoZ()
Definition: ERF_TileNoZ.H:11
amrex::MultiFab * m_detJ_cc
Definition: ERF_SAM.H:326
static constexpr amrex::Real CFL_MAX
Definition: ERF_SAM.H:294
amrex::Real m_dzmin
Definition: ERF_SAM.H:322
@ qcl
Definition: ERF_Kessler.H:29
@ tabs
Definition: ERF_Kessler.H:24
@ rho
Definition: ERF_Kessler.H:22
@ qt
Definition: ERF_Kessler.H:27
@ ng
Definition: ERF_Morrison.H:48
@ qn
Definition: ERF_Morrison.H:33
@ qci
Definition: ERF_Morrison.H:36
real(c_double), parameter epsilon
Definition: ERF_module_model_constants.F90:12

Referenced by Advance().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Init()

void SAM::Init ( const amrex::MultiFab &  cons_in,
const amrex::BoxArray &  grids,
const amrex::Geometry &  geom,
const amrex::Real dt_advance,
std::unique_ptr< amrex::MultiFab > &  z_phys_nd,
std::unique_ptr< amrex::MultiFab > &  detJ_cc 
)
overridevirtual

Initializes the Microphysics module.

Parameters
[in]cons_inConserved variables input
[in]qc_inCloud variables input
[in,out]qv_inVapor variables input
[in]qi_inIce variables input
[in]gridsThe boxes on which we will evolve the solution
[in]geomGeometry associated with these MultiFabs and grids
[in]dt_advanceTimestep for the advance

Reimplemented from NullMoist.

28 {
29  dt = dt_advance;
30  m_geom = geom;
31 
32  m_z_phys_nd = z_phys_nd.get();
33  m_detJ_cc = detJ_cc.get();
34 
35  MicVarMap.resize(m_qmoist_size);
37 
38  // initialize microphysics variables
39  for (auto ivar = 0; ivar < MicVar::NumVars; ++ivar) {
40  mic_fab_vars[ivar] = std::make_shared<MultiFab>(cons_in.boxArray(), cons_in.DistributionMap(),
41  1, cons_in.nGrowVect());
42  mic_fab_vars[ivar]->setVal(0.);
43  }
44 
45  // Set class data members
46  for ( MFIter mfi(cons_in, TileNoZ()); mfi.isValid(); ++mfi) {
47  const auto& box3d = mfi.tilebox();
48 
49  const auto& lo = lbound(box3d);
50  const auto& hi = ubound(box3d);
51 
52  nlev = box3d.length(2);
53  zlo = lo.z;
54  zhi = hi.z;
55 
56  // parameters
57  accrrc.resize({zlo}, {zhi});
58  accrsi.resize({zlo}, {zhi});
59  accrsc.resize({zlo}, {zhi});
60  coefice.resize({zlo}, {zhi});
61  evaps1.resize({zlo}, {zhi});
62  evaps2.resize({zlo}, {zhi});
63  accrgi.resize({zlo}, {zhi});
64  accrgc.resize({zlo}, {zhi});
65  evapg1.resize({zlo}, {zhi});
66  evapg2.resize({zlo}, {zhi});
67  evapr1.resize({zlo}, {zhi});
68  evapr2.resize({zlo}, {zhi});
69 
70  // data (input)
71  rho1d.resize({zlo}, {zhi});
72  pres1d.resize({zlo}, {zhi});
73  tabs1d.resize({zlo}, {zhi});
74  }
75 }
int zlo
Definition: ERF_SAM.H:309
int m_qmoist_size
Definition: ERF_SAM.H:288
amrex::MultiFab * m_z_phys_nd
Definition: ERF_SAM.H:325
amrex::Vector< int > MicVarMap
Definition: ERF_SAM.H:297
int zhi
Definition: ERF_SAM.H:309
@ NumVars
Definition: ERF_SAM.H:49
@ snow_accum
Definition: ERF_SAM.H:47
@ rain_accum
Definition: ERF_SAM.H:46
@ graup_accum
Definition: ERF_SAM.H:48
Here is the call graph for this function:

◆ NewtonIterSat()

AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real SAM::NewtonIterSat ( int &  i,
int &  j,
int &  k,
const int &  SAM_moisture_type,
const amrex::Real fac_cond,
const amrex::Real ,
const amrex::Real fac_sub,
const amrex::Real an,
const amrex::Real bn,
const amrex::Array4< amrex::Real > &  tabs_array,
const amrex::Array4< amrex::Real > &  pres_array,
const amrex::Array4< amrex::Real > &  qv_array,
const amrex::Array4< amrex::Real > &  qc_array,
const amrex::Array4< amrex::Real > &  qi_array,
const amrex::Array4< amrex::Real > &  qn_array,
const amrex::Array4< amrex::Real > &  qt_array 
)
inlinestatic
174  {
175  // Solution tolerance
176  amrex::Real tol = 1.0e-4;
177 
178  // Saturation moisture fractions
179  amrex::Real omn, domn;
180  amrex::Real qsat, dqsat;
181  amrex::Real qsatw, dqsatw;
182  amrex::Real qsati, dqsati;
183 
184  // Newton iteration vars
185  int niter;
186  amrex::Real fff, dfff, dtabs;
187  amrex::Real lstar, dlstar;
188  amrex::Real lstarw, lstari;
189  amrex::Real delta_qv, delta_qc, delta_qi;
190 
191  // Initial guess for temperature & pressure
192  amrex::Real tabs = tabs_array(i,j,k);
193  amrex::Real pres = pres_array(i,j,k);
194 
195  niter = 0;
196  dtabs = 1;
197  //==================================================
198  // Newton iteration to qv=qsat (cloud phase only)
199  //==================================================
200  do {
201  // Latent heats and their derivatives wrt to T
202  lstarw = fac_cond;
203  lstari = fac_sub;
204  domn = 0.0;
205 
206  // Saturation moisture fractions
207  erf_qsatw(tabs, pres, qsatw);
208  erf_qsati(tabs, pres, qsati);
209  erf_dtqsatw(tabs, pres, dqsatw);
210  erf_dtqsati(tabs, pres, dqsati);
211 
212  if (SAM_moisture_type == 1) {
213  // Cloud ice not permitted (condensation & fusion)
214  if(tabs >= tbgmax) {
215  omn = 1.0;
216  }
217  // Cloud water not permitted (sublimation & fusion)
218  else if(tabs <= tbgmin) {
219  omn = 0.0;
220  }
221  // Mixed cloud phase (condensation & fusion)
222  else {
223  omn = an*tabs-bn;
224  domn = an;
225  }
226  } else if (SAM_moisture_type == 2) {
227  omn = 1.0;
228  domn = 0.0;
229  }
230 
231  // Linear combination of each component
232  qsat = omn * qsatw + (1.0-omn) * qsati;
233  dqsat = omn * dqsatw + (1.0-omn) * dqsati
234  + domn * qsatw - domn * qsati;
235  lstar = omn * lstarw + (1.0-omn) * lstari;
236  dlstar = domn * lstarw - domn * lstari;
237 
238  // Function for root finding:
239  // 0 = -T_new + T_old + L_eff/C_p * (qv - qsat)
240  fff = -tabs + tabs_array(i,j,k) + lstar*(qv_array(i,j,k) - qsat);
241 
242  // Derivative of function (T_new iterated on)
243  dfff = -1.0 + dlstar*(qv_array(i,j,k) - qsat) - lstar*dqsat;
244 
245  // Update the temperature
246  dtabs = -fff/dfff;
247  tabs += dtabs;
248 
249  // Update iteration
250  niter = niter+1;
251  } while(std::abs(dtabs) > tol && niter < 20);
252 
253  // Update qsat from last iteration (dq = dq/dt * dt)
254  qsat += dqsat*dtabs;
255 
256  // Changes in each component
257  delta_qv = qv_array(i,j,k) - qsat;
258  delta_qc = std::max(-qc_array(i,j,k), delta_qv * omn);
259  delta_qi = std::max(-qi_array(i,j,k), delta_qv * (1.0-omn));
260 
261  // Partition the change in non-precipitating q
262  qv_array(i,j,k) = qsat;
263  qc_array(i,j,k) += delta_qc;
264  qi_array(i,j,k) += delta_qi;
265  qn_array(i,j,k) = qc_array(i,j,k) + qi_array(i,j,k);
266  qt_array(i,j,k) = qv_array(i,j,k) + qn_array(i,j,k);
267 
268  // Return to temperature
269  return tabs;
270  }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_dtqsatw(amrex::Real t, amrex::Real p, amrex::Real &dtqsatw)
Definition: ERF_MicrophysicsUtils.H:181
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_dtqsati(amrex::Real t, amrex::Real p, amrex::Real &dtqsati)
Definition: ERF_MicrophysicsUtils.H:173
Here is the call graph for this function:

◆ Precip()

void SAM::Precip ( const SolverChoice sc)

Autoconversion (A30), Accretion (A28), Evaporation (A24)

11 {
12 
13  if (sc.moisture_type == MoistureType::SAM_NoPrecip_NoIce) return;
14 
15  Real powr1 = (3.0 + b_rain) / 4.0;
16  Real powr2 = (5.0 + b_rain) / 8.0;
17  Real pows1 = (3.0 + b_snow) / 4.0;
18  Real pows2 = (5.0 + b_snow) / 8.0;
19  Real powg1 = (3.0 + b_grau) / 4.0;
20  Real powg2 = (5.0 + b_grau) / 8.0;
21 
22  auto accrrc_t = accrrc.table();
23  auto accrsc_t = accrsc.table();
24  auto accrsi_t = accrsi.table();
25  auto accrgc_t = accrgc.table();
26  auto accrgi_t = accrgi.table();
27  auto coefice_t = coefice.table();
28  auto evapr1_t = evapr1.table();
29  auto evapr2_t = evapr2.table();
30  auto evaps1_t = evaps1.table();
31  auto evaps2_t = evaps2.table();
32  auto evapg1_t = evapg1.table();
33  auto evapg2_t = evapg2.table();
34 
35  Real fac_cond = m_fac_cond;
36  Real fac_sub = m_fac_sub;
37  Real fac_fus = m_fac_fus;
38  Real rdOcp = m_rdOcp;
39 
41 
42  Real dtn = dt;
43 
44  int SAM_moisture_type = 1;
45  if (sc.moisture_type == MoistureType::SAM_NoIce) {
46  SAM_moisture_type = 2;
47  }
48 
49  auto domain = m_geom.Domain();
50  int i_lo = domain.smallEnd(0);
51  int i_hi = domain.bigEnd(0);
52  int j_lo = domain.smallEnd(1);
53  int j_hi = domain.bigEnd(1);
54 
55  // get the temperature, density, theta, qt and qp from input
56  for ( MFIter mfi(*(mic_fab_vars[MicVar::tabs]),TilingIfNotGPU()); mfi.isValid(); ++mfi) {
57  auto theta_array = mic_fab_vars[MicVar::theta]->array(mfi);
58  auto tabs_array = mic_fab_vars[MicVar::tabs]->array(mfi);
59  auto pres_array = mic_fab_vars[MicVar::pres]->array(mfi);
60 
61  // Non-precipitating
62  auto qv_array = mic_fab_vars[MicVar::qv]->array(mfi);
63  auto qcl_array = mic_fab_vars[MicVar::qcl]->array(mfi);
64  auto qci_array = mic_fab_vars[MicVar::qci]->array(mfi);
65  auto qn_array = mic_fab_vars[MicVar::qn]->array(mfi);
66  auto qt_array = mic_fab_vars[MicVar::qt]->array(mfi);
67 
68  // Precipitating
69  auto qpr_array = mic_fab_vars[MicVar::qpr]->array(mfi);
70  auto qps_array = mic_fab_vars[MicVar::qps]->array(mfi);
71  auto qpg_array = mic_fab_vars[MicVar::qpg]->array(mfi);
72  auto qp_array = mic_fab_vars[MicVar::qp]->array(mfi);
73 
74  auto tbx = mfi.tilebox();
75  if (tbx.smallEnd(0) == i_lo) { tbx.growLo(0,-m_real_width); }
76  if (tbx.bigEnd(0) == i_hi) { tbx.growHi(0,-m_real_width); }
77  if (tbx.smallEnd(1) == j_lo) { tbx.growLo(1,-m_real_width); }
78  if (tbx.bigEnd(1) == j_hi) { tbx.growHi(1,-m_real_width); }
79 
80  ParallelFor(tbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
81  {
82  //------- Autoconversion/accretion
83  Real omn, omp, omg;
84  Real qsat, qsatw, qsati;
85 
86  Real qcc, qii, qpr, qps, qpg;
87  Real dprc, dpsc, dpgc;
88  Real dpsi, dpgi;
89 
90  Real dqc, dqca, dqi, dqia, dqp;
91  Real dqpr, dqps, dqpg;
92 
93  Real auto_r, autos;
94  Real accrcr, accrcs, accris, accrcg, accrig;
95 
96  // Work to be done for autoc/accr or evap
97  if (qn_array(i,j,k)+qp_array(i,j,k) > 0.0) {
98  if (SAM_moisture_type == 2) {
99  omn = 1.0;
100  omp = 1.0;
101  omg = 0.0;
102  } else {
103  omn = std::max(0.0,std::min(1.0,(tabs_array(i,j,k)-tbgmin)*a_bg));
104  omp = std::max(0.0,std::min(1.0,(tabs_array(i,j,k)-tprmin)*a_pr));
105  omg = std::max(0.0,std::min(1.0,(tabs_array(i,j,k)-tgrmin)*a_gr));
106  }
107 
108  qcc = qcl_array(i,j,k);
109  qii = qci_array(i,j,k);
110 
111  qpr = qpr_array(i,j,k);
112  qps = qps_array(i,j,k);
113  qpg = qpg_array(i,j,k);
114 
115  //==================================================
116  // Autoconversion (A30/A31) and accretion (A27)
117  //==================================================
118  if (qn_array(i,j,k) > 0.0) {
119  accrcr = 0.0;
120  accrcs = 0.0;
121  accris = 0.0;
122  accrcg = 0.0;
123  accrig = 0.0;
124 
125  if (qcc > qcw0) {
126  auto_r = alphaelq;
127  } else {
128  auto_r = 0.0;
129  }
130 
131  if (qii > qci0) {
132  autos = betaelq*coefice_t(k);
133  } else {
134  autos = 0.0;
135  }
136 
137  if (omp > 0.001) {
138  accrcr = accrrc_t(k);
139  }
140 
141  if (omp < 0.999 && omg < 0.999) {
142  accrcs = accrsc_t(k);
143  accris = accrsi_t(k);
144  }
145 
146  if (omp < 0.999 && omg > 0.001) {
147  accrcg = accrgc_t(k);
148  accrig = accrgi_t(k);
149  }
150 
151  // Autoconversion & accretion (sink for cloud comps)
152  dqca = dtn * auto_r * (qcc-qcw0);
153  dprc = dtn * accrcr * qcc * std::pow(qpr, powr1);
154  dpsc = dtn * accrcs * qcc * std::pow(qps, pows1);
155  dpgc = dtn * accrcg * qcc * std::pow(qpg, powg1);
156 
157  dqia = dtn * autos * (qii-qci0);
158  dpsi = dtn * accris * qii * std::pow(qps, pows1);
159  dpgi = dtn * accrig * qii * std::pow(qpg, powg1);
160 
161  // Rescale sinks to avoid negative cloud fractions
162  dqc = dqca + dprc + dpsc + dpgc;
163  dqi = dqia + dpsi + dpgi;
164  Real scalec = std::min(qcl_array(i,j,k),dqc) / (dqc + eps);
165  Real scalei = std::min(qci_array(i,j,k),dqi) / (dqi + eps);
166  dqca *= scalec; dprc *= scalec; dpsc *= scalec; dpgc *= scalec;
167  dqia *= scalei; dpsi *= scalei; dpgi *= scalei;
168  dqc = dqca + dprc + dpsc + dpgc;
169  dqi = dqia + dpsi + dpgi;
170 
171  // NOTE: Autoconversion of cloud water and ice are sources
172  // to qp, while accretion is a source to an individual
173  // precipitating component (e.g., qpr/qps/qpg). So we
174  // only split autoconversion with omega. The omega
175  // splitting does imply a latent heat source.
176 
177  // Partition formed precip componentss
178  dqpr = (dqca + dqia) * omp + dprc;
179  dqps = (dqca + dqia) * (1.0 - omp) * (1.0 - omg) + dpsc + dpsi;
180  dqpg = (dqca + dqia) * (1.0 - omp) * omg + dpgc + dpgi;
181 
182  // Update the primitive state variables
183  qcl_array(i,j,k) -= dqc;
184  qci_array(i,j,k) -= dqi;
185  qpr_array(i,j,k) += dqpr;
186  qps_array(i,j,k) += dqps;
187  qpg_array(i,j,k) += dqpg;
188 
189  // Update the primitive derived vars
190  qn_array(i,j,k) = qcl_array(i,j,k) + qci_array(i,j,k);
191  qt_array(i,j,k) = qv_array(i,j,k) + qn_array(i,j,k);
192  qp_array(i,j,k) = qpr_array(i,j,k) + qps_array(i,j,k) + qpg_array(i,j,k);
193 
194  // Update temperature
195  tabs_array(i,j,k) += fac_fus * ( dqca * (1.0 - omp) - dqia * omp );
196 
197  // Update theta
198  theta_array(i,j,k) = getThgivenTandP(tabs_array(i,j,k), 100.0*pres_array(i,j,k), rdOcp);
199  }
200 
201  //==================================================
202  // Evaporation (A24)
203  //==================================================
204  erf_qsatw(tabs_array(i,j,k),pres_array(i,j,k),qsatw);
205  erf_qsati(tabs_array(i,j,k),pres_array(i,j,k),qsati);
206  qsat = qsatw * omn + qsati * (1.0-omn);
207  if((qp_array(i,j,k) > 0.0) && (qv_array(i,j,k) < qsat)) {
208 
209  dqpr = evapr1_t(k)*sqrt(qpr) + evapr2_t(k)*pow(qpr,powr2);
210  dqps = evaps1_t(k)*sqrt(qps) + evaps2_t(k)*pow(qps,pows2);
211  dqpg = evapg1_t(k)*sqrt(qpg) + evapg2_t(k)*pow(qpg,powg2);
212 
213  // NOTE: This is always a sink for precipitating comps
214  // since qv<qsat and thus (1 - qv/qsat)>0. If we are
215  // in a super-saturated state (qv>qsat) the Newton
216  // iterations in Cloud() will have handled condensation.
217  dqpr *= dtn * (1.0 - qv_array(i,j,k)/qsat);
218  dqps *= dtn * (1.0 - qv_array(i,j,k)/qsat);
219  dqpg *= dtn * (1.0 - qv_array(i,j,k)/qsat);
220 
221  // Limit to avoid negative moisture fractions
222  dqpr = std::min(qpr_array(i,j,k),dqpr);
223  dqps = std::min(qps_array(i,j,k),dqps);
224  dqpg = std::min(qpg_array(i,j,k),dqpg);
225  dqp = dqpr + dqps + dqpg;
226 
227  // Update the primitive state variables
228  qv_array(i,j,k) += dqp;
229  qpr_array(i,j,k) -= dqpr;
230  qps_array(i,j,k) -= dqps;
231  qpg_array(i,j,k) -= dqpg;
232 
233  // Update the primitive derived vars
234  qt_array(i,j,k) = qv_array(i,j,k) + qn_array(i,j,k);
235  qp_array(i,j,k) = qpr_array(i,j,k) + qps_array(i,j,k) + qpg_array(i,j,k);
236 
237  // Update temperature
238  tabs_array(i,j,k) -= fac_cond * dqpr + fac_sub * (dqps + dqpg);
239 
240  // Update theta
241  theta_array(i,j,k) = getThgivenTandP(tabs_array(i,j,k), 100.0*pres_array(i,j,k), rdOcp);
242  }
243  }
244  });
245  }
246 }
constexpr amrex::Real a_bg
Definition: ERF_Constants.H:77
constexpr amrex::Real a_gr
Definition: ERF_Constants.H:79
constexpr amrex::Real qci0
Definition: ERF_Constants.H:47
constexpr amrex::Real betaelq
Definition: ERF_Constants.H:49
constexpr amrex::Real alphaelq
Definition: ERF_Constants.H:48
constexpr amrex::Real qcw0
Definition: ERF_Constants.H:46
constexpr amrex::Real tprmin
Definition: ERF_Constants.H:33
constexpr amrex::Real tgrmin
Definition: ERF_Constants.H:35
constexpr amrex::Real a_pr
Definition: ERF_Constants.H:78
@ qpg
Definition: ERF_Morrison.H:41
@ qps
Definition: ERF_Morrison.H:40
@ qpr
Definition: ERF_Morrison.H:39

Referenced by Advance().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ PrecipFall()

void SAM::PrecipFall ( const SolverChoice sc)

Precipitation fluxes P_{r/s/g} (A19)

Code modified from SAMXX, the C++ version of the SAM code.

Parameters
[in]hydro_typeType selection for the precipitation advection hydrodynamics scheme (0-3)
17 {
18  if(sc.moisture_type == MoistureType::SAM_NoPrecip_NoIce) return;
19 
20  Real rho_0 = 1.29;
21 
22  Real gamr3 = erf_gammafff(4.0+b_rain);
23  Real gams3 = erf_gammafff(4.0+b_snow);
24  Real gamg3 = erf_gammafff(4.0+b_grau);
25 
26  Real vrain = (a_rain*gamr3/6.0)*pow((PI*rhor*nzeror),-crain);
27  Real vsnow = (a_snow*gams3/6.0)*pow((PI*rhos*nzeros),-csnow);
28  Real vgrau = (a_grau*gamg3/6.0)*pow((PI*rhog*nzerog),-cgrau);
29 
30  Real dtn = dt;
31  Real coef = dtn/m_dzmin;
32 
33  auto domain = m_geom.Domain();
34  int k_lo = domain.smallEnd(2);
35  int k_hi = domain.bigEnd(2);
36 
40  auto qp = mic_fab_vars[MicVar::qp];
47 
48  auto ba = tabs->boxArray();
49  auto dm = tabs->DistributionMap();
50  auto ngrow = tabs->nGrowVect();
51 
52  MultiFab fz;
53  fz.define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow);
54 
55  int SAM_moisture_type = 1;
56  if (sc.moisture_type == MoistureType::SAM_NoIce) {
57  SAM_moisture_type = 2;
58  }
59 
60  // Precompute the vertical fluxes for CFL constraint
61  for (MFIter mfi(fz, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
62  auto qp_array = qp->array(mfi);
63  auto rho_array = rho->array(mfi);
64  auto tabs_array = tabs->array(mfi);
65  auto fz_array = fz.array(mfi);
66 
67  const auto& box3d = mfi.tilebox();
68 
69  ParallelFor(box3d, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
70  {
71  Real rho_avg, tab_avg, qp_avg;
72  if (k==k_lo) {
73  rho_avg = rho_array(i,j,k);
74  tab_avg = tabs_array(i,j,k);
75  qp_avg = qp_array(i,j,k);
76  } else if (k==k_hi+1) {
77  rho_avg = rho_array(i,j,k-1);
78  tab_avg = tabs_array(i,j,k-1);
79  qp_avg = qp_array(i,j,k-1);
80  } else {
81  rho_avg = 0.5*( rho_array(i,j,k-1) + rho_array(i,j,k));
82  tab_avg = 0.5*(tabs_array(i,j,k-1) + tabs_array(i,j,k));
83  qp_avg = 0.5*( qp_array(i,j,k-1) + qp_array(i,j,k));
84  }
85 
86  Real Pprecip = 0.0;
87  if(qp_avg > qp_threshold) {
88  Real omp, omg;
89  if (SAM_moisture_type == 2) {
90  omp = 1.0;
91  omg = 0.0;
92  } else {
93  omp = std::max(0.0,std::min(1.0,(tab_avg-tprmin)*a_pr));
94  omg = std::max(0.0,std::min(1.0,(tab_avg-tgrmin)*a_gr));
95  }
96  Real qrr = omp*qp_avg;
97  Real qss = (1.0-omp)*(1.0-omg)*qp_avg;
98  Real qgg = (1.0-omp)*(omg)*qp_avg;
99  Pprecip = omp*vrain*std::pow(rho_avg*qrr,1.0+crain)
100  + (1.0-omp)*( (1.0-omg)*vsnow*std::pow(rho_avg*qss,1.0+csnow)
101  + omg *vgrau*std::pow(rho_avg*qgg,1.0+cgrau) );
102  }
103 
104  // NOTE: Fz is the sedimentation flux from the advective operator.
105  // In the terrain-following coordinate system, the z-deriv in
106  // the divergence uses the normal velocity (Omega). However,
107  // there are no u/v components to the sedimentation velocity.
108  // Therefore, we simply end up with a division by detJ when
109  // evaluating the source term: dJinv * (flux_hi - flux_lo) * dzinv.
110  fz_array(i,j,k) = Pprecip * std::sqrt(rho_0/rho_avg);
111  });
112  }
113 
114  // Compute number of substeps from maximum terminal velocity
115  Real wt_max;
116  int n_substep;
117  auto const& ma_fz_arr = fz.const_arrays();
118  GpuTuple<Real> max = ParReduce(TypeList<ReduceOpMax>{},
119  TypeList<Real>{},
120  fz, IntVect(0),
121  [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept
122  -> GpuTuple<Real>
123  {
124  return { ma_fz_arr[box_no](i,j,k) };
125  });
126  wt_max = get<0>(max) + std::numeric_limits<Real>::epsilon();
127  n_substep = int( std::ceil(wt_max * coef / CFL_MAX) );
128  AMREX_ALWAYS_ASSERT(n_substep >= 1);
129  coef /= Real(n_substep);
130  dtn /= Real(n_substep);
131 
132  // Substep the vertical advection
133  for (int nsub(0); nsub<n_substep; ++nsub) {
134  for (MFIter mfi(*qp, TileNoZ()); mfi.isValid(); ++mfi) {
135  auto qpr_array = qpr->array(mfi);
136  auto qps_array = qps->array(mfi);
137  auto qpg_array = qpg->array(mfi);
138  auto qp_array = qp->array(mfi);
139  auto rho_array = rho->array(mfi);
140  auto tabs_array = tabs->array(mfi);
141  auto fz_array = fz.array(mfi);
142 
143  auto rain_accum_array = rain_accum->array(mfi);
144  auto snow_accum_array = snow_accum->array(mfi);
145  auto graup_accum_array = graup_accum->array(mfi);
146 
147  const auto dJ_array = (m_detJ_cc) ? m_detJ_cc->const_array(mfi) : Array4<const Real>{};
148 
149  const auto& tbx = mfi.tilebox();
150  const auto& tbz = mfi.tilebox(IntVect(0,0,1),IntVect(0));
151 
152  // Update vertical flux every substep
153  ParallelFor(tbz, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
154  {
155  Real rho_avg, tab_avg, qp_avg;
156  if (k==k_lo) {
157  rho_avg = rho_array(i,j,k);
158  tab_avg = tabs_array(i,j,k);
159  qp_avg = qp_array(i,j,k);
160  } else if (k==k_hi+1) {
161  rho_avg = rho_array(i,j,k-1);
162  tab_avg = tabs_array(i,j,k-1);
163  qp_avg = qp_array(i,j,k-1);
164  } else {
165  rho_avg = 0.5*( rho_array(i,j,k-1) + rho_array(i,j,k));
166  tab_avg = 0.5*(tabs_array(i,j,k-1) + tabs_array(i,j,k));
167  qp_avg = 0.5*( qp_array(i,j,k-1) + qp_array(i,j,k));
168  }
169 
170  Real Pprecip = 0.0;
171  if(qp_avg > qp_threshold) {
172  Real omp, omg;
173  if (SAM_moisture_type == 2) {
174  omp = 1.0;
175  omg = 0.0;
176  } else {
177  omp = std::max(0.0,std::min(1.0,(tab_avg-tprmin)*a_pr));
178  omg = std::max(0.0,std::min(1.0,(tab_avg-tgrmin)*a_gr));
179  }
180  Real qrr = omp*qp_avg;
181  Real qss = (1.0-omp)*(1.0-omg)*qp_avg;
182  Real qgg = (1.0-omp)*(omg)*qp_avg;
183  Pprecip = omp*vrain*std::pow(rho_avg*qrr,1.0+crain)
184  + (1.0-omp)*( (1.0-omg)*vsnow*std::pow(rho_avg*qss,1.0+csnow)
185  + omg *vgrau*std::pow(rho_avg*qgg,1.0+cgrau) );
186  }
187 
188  // NOTE: Fz is the sedimentation flux from the advective operator.
189  // In the terrain-following coordinate system, the z-deriv in
190  // the divergence uses the normal velocity (Omega). However,
191  // there are no u/v components to the sedimentation velocity.
192  // Therefore, we simply end up with a division by detJ when
193  // evaluating the source term: dJinv * (flux_hi - flux_lo) * dzinv.
194  fz_array(i,j,k) = Pprecip * std::sqrt(rho_0/rho_avg);
195 
196  if(k==k_lo){
197  Real omp, omg;
198  if (SAM_moisture_type == 2) {
199  omp = 1.0;
200  omg = 0.0;
201  } else {
202  omp = std::max(0.0,std::min(1.0,(tab_avg-tprmin)*a_pr));
203  omg = std::max(0.0,std::min(1.0,(tab_avg-tgrmin)*a_gr));
204  }
205  rain_accum_array(i,j,k) = rain_accum_array(i,j,k) + rho_avg*(omp*qp_avg)*vrain*dtn/rhor*1000.0; // Divide by rho_water and convert to mm
206  snow_accum_array(i,j,k) = snow_accum_array(i,j,k) + rho_avg*(1.0-omp)*(1.0-omg)*qp_avg*vrain*dtn/rhos*1000.0; // Divide by rho_snow and convert to mm
207  graup_accum_array(i,j,k) = graup_accum_array(i,j,k) + rho_avg*(1.0-omp)*(omg)*qp_avg*vrain*dtn/rhog*1000.0; // Divide by rho_graupel and convert to mm
208  }
209  });
210 
211  // Update precip every substep
212  ParallelFor(tbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
213  {
214  // Jacobian determinant
215  Real dJinv = (dJ_array) ? 1.0/dJ_array(i,j,k) : 1.0;
216 
217  //==================================================
218  // Precipitating sedimentation (A19)
219  //==================================================
220  Real dqp = dJinv * (1.0/rho_array(i,j,k)) * ( fz_array(i,j,k+1) - fz_array(i,j,k) ) * coef;
221  Real omp, omg;
222  if (SAM_moisture_type == 2) {
223  omp = 1.0;
224  omg = 0.0;
225  } else {
226  omp = std::max(0.0,std::min(1.0,(tabs_array(i,j,k)-tprmin)*a_pr));
227  omg = std::max(0.0,std::min(1.0,(tabs_array(i,j,k)-tgrmin)*a_gr));
228  }
229 
230  qpr_array(i,j,k) = std::max(0.0, qpr_array(i,j,k) + dqp*omp);
231  qps_array(i,j,k) = std::max(0.0, qps_array(i,j,k) + dqp*(1.0-omp)*(1.0-omg));
232  qpg_array(i,j,k) = std::max(0.0, qpg_array(i,j,k) + dqp*(1.0-omp)*omg);
233  qp_array(i,j,k) = qpr_array(i,j,k) + qps_array(i,j,k) + qpg_array(i,j,k);
234 
235  // NOTE: Sedimentation does not affect the potential temperature,
236  // but it does affect the liquid/ice static energy.
237  // No source to Theta occurs here.
238  });
239  } // mfi
240  } // nsub
241 }
constexpr amrex::Real csnow
Definition: ERF_Constants.H:82
constexpr amrex::Real cgrau
Definition: ERF_Constants.H:83
constexpr amrex::Real qp_threshold
Definition: ERF_Constants.H:60
constexpr amrex::Real crain
Definition: ERF_Constants.H:81
@ theta
Definition: ERF_MM5.H:20
@ qp
Definition: ERF_Kessler.H:31
@ rain_accum
Definition: ERF_Kessler.H:33
@ graup_accum
Definition: ERF_Morrison.H:52
@ snow_accum
Definition: ERF_Morrison.H:51

Referenced by Advance().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Qmoist_Ptr()

amrex::MultiFab* SAM::Qmoist_Ptr ( const int &  varIdx)
inlineoverridevirtual

Reimplemented from NullMoist.

140  {
141  AMREX_ALWAYS_ASSERT(varIdx < m_qmoist_size);
142  return mic_fab_vars[MicVarMap[varIdx]].get();
143  }

◆ Qmoist_Restart_Vars()

void SAM::Qmoist_Restart_Vars ( const SolverChoice ,
std::vector< int > &  a_idx,
std::vector< std::string > &  a_names 
) const
inlineoverridevirtual

Reimplemented from NullMoist.

276  {
277  a_idx.clear();
278  a_names.clear();
279 
280  // NOTE: These are the indices to access into qmoist (not mic_fab_vars)
281  a_idx.push_back(0); a_names.push_back("RainAccum");
282  a_idx.push_back(1); a_names.push_back("SnowAccum");
283  a_idx.push_back(2); a_names.push_back("GraupAccum");
284  }

◆ Qmoist_Size()

int SAM::Qmoist_Size ( )
inlineoverridevirtual

Reimplemented from NullMoist.

149 { return SAM::m_qmoist_size; }

◆ Qstate_Moist_Size()

int SAM::Qstate_Moist_Size ( )
inlineoverridevirtual

Reimplemented from NullMoist.

152 { return SAM::n_qstate_moist_size; }
int n_qstate_moist_size
Definition: ERF_SAM.H:291

◆ Set_dzmin()

void SAM::Set_dzmin ( const amrex::Real  dz_min)
inlineoverridevirtual

Reimplemented from NullMoist.

100  {
101  m_dzmin = dz_min;
102  }

◆ Set_RealWidth()

void SAM::Set_RealWidth ( const int  real_width)
inlineoverridevirtual

Reimplemented from NullMoist.

155 { m_real_width = real_width; }

◆ Update_Micro_Vars()

void SAM::Update_Micro_Vars ( amrex::MultiFab &  cons_in)
inlineoverridevirtual

Reimplemented from NullMoist.

114  {
115  this->Copy_State_to_Micro(cons_in);
116  this->Compute_Coefficients();
117  }
void Copy_State_to_Micro(const amrex::MultiFab &cons_in) override
Definition: ERF_InitSAM.cpp:84
void Compute_Coefficients()
Definition: ERF_InitSAM.cpp:136
Here is the call graph for this function:

◆ Update_State_Vars()

void SAM::Update_State_Vars ( amrex::MultiFab &  cons_in)
inlineoverridevirtual

Reimplemented from NullMoist.

121  {
122  this->Copy_Micro_to_State(cons_in);
123  }
void Copy_Micro_to_State(amrex::MultiFab &cons_in) override
Definition: ERF_UpdateSAM.cpp:15
Here is the call graph for this function:

Member Data Documentation

◆ accrgc

amrex::TableData<amrex::Real, 1> SAM::accrgc
private

◆ accrgi

amrex::TableData<amrex::Real, 1> SAM::accrgi
private

◆ accrrc

amrex::TableData<amrex::Real, 1> SAM::accrrc
private

◆ accrsc

amrex::TableData<amrex::Real, 1> SAM::accrsc
private

◆ accrsi

amrex::TableData<amrex::Real, 1> SAM::accrsi
private

◆ CFL_MAX

constexpr amrex::Real SAM::CFL_MAX = 0.5
staticconstexprprivate

◆ coefice

amrex::TableData<amrex::Real, 1> SAM::coefice
private

◆ dt

amrex::Real SAM::dt
private

Referenced by Advance().

◆ evapg1

amrex::TableData<amrex::Real, 1> SAM::evapg1
private

◆ evapg2

amrex::TableData<amrex::Real, 1> SAM::evapg2
private

◆ evapr1

amrex::TableData<amrex::Real, 1> SAM::evapr1
private

◆ evapr2

amrex::TableData<amrex::Real, 1> SAM::evapr2
private

◆ evaps1

amrex::TableData<amrex::Real, 1> SAM::evaps1
private

◆ evaps2

amrex::TableData<amrex::Real, 1> SAM::evaps2
private

◆ m_axis

int SAM::m_axis
private

Referenced by Define().

◆ m_detJ_cc

amrex::MultiFab* SAM::m_detJ_cc
private

◆ m_do_cond

bool SAM::m_do_cond
private

Referenced by Define().

◆ m_dzmin

amrex::Real SAM::m_dzmin
private

Referenced by Set_dzmin().

◆ m_fac_cond

amrex::Real SAM::m_fac_cond
private

Referenced by Define().

◆ m_fac_fus

amrex::Real SAM::m_fac_fus
private

Referenced by Define().

◆ m_fac_sub

amrex::Real SAM::m_fac_sub
private

Referenced by Define().

◆ m_geom

amrex::Geometry SAM::m_geom
private

◆ m_qmoist_size

int SAM::m_qmoist_size = 3
private

Referenced by Qmoist_Ptr(), and Qmoist_Size().

◆ m_rdOcp

amrex::Real SAM::m_rdOcp
private

Referenced by Define().

◆ m_real_width

int SAM::m_real_width {0}
private

Referenced by Set_RealWidth().

◆ m_z_phys_nd

amrex::MultiFab* SAM::m_z_phys_nd
private

◆ mic_fab_vars

amrex::Array<FabPtr, MicVar::NumVars> SAM::mic_fab_vars
private

Referenced by Qmoist_Ptr().

◆ MicVarMap

amrex::Vector<int> SAM::MicVarMap
private

Referenced by Qmoist_Ptr().

◆ n_qstate_moist_size

int SAM::n_qstate_moist_size = 6
private

Referenced by Qstate_Moist_Size().

◆ nlev

int SAM::nlev
private

◆ pres1d

amrex::TableData<amrex::Real, 1> SAM::pres1d
private

◆ qn1d

amrex::TableData<amrex::Real, 1> SAM::qn1d
private

◆ qt1d

amrex::TableData<amrex::Real, 1> SAM::qt1d
private

◆ qv1d

amrex::TableData<amrex::Real, 1> SAM::qv1d
private

◆ rho1d

amrex::TableData<amrex::Real, 1> SAM::rho1d
private

◆ tabs1d

amrex::TableData<amrex::Real, 1> SAM::tabs1d
private

◆ zhi

int SAM::zhi
private

◆ zlo

int SAM::zlo
private

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