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

#include <ERF_Morrison.H>

Inheritance diagram for Morrison:
Collaboration diagram for Morrison:

Public Member Functions

 Morrison ()
 
virtual ~Morrison ()=default
 
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, const amrex::MultiFab &) override
 
void Advance (const amrex::Real &dt_advance, const SolverChoice &sc) override
 
amrex::MultiFab * Qmoist_Ptr (const int &varIdx) override
 
int Qmoist_Size () override
 
int Qstate_Moist_Size () override
 
int Qstate_Moist_NumConc_Size () override
 
void Qmoist_Restart_Vars (const SolverChoice &, std::vector< int > &a_idx, std::vector< std::string > &a_names) const override
 
SurfacePrecipAccumulationSources Get_Surface_Precip_Accumulation_Ptrs (const int &) const override
 
void GetPlotVarNames (amrex::Vector< std::string > &a_vec) const override
 Populate a vector with names of all available Morrison plot variables. More...
 
void GetPlotVar (const std::string &a_name, amrex::MultiFab &a_mf) const override
 
void GetPlotVar (const std::string &a_name, amrex::MultiFab &a_mf, const int) const override
 
virtual void Update_Micro_Vars (amrex::MultiFab &)
 
virtual void Update_Micro_Vars (amrex::MultiFab &cons_in, const amrex::MultiFab *)
 
- Public Member Functions inherited from NullMoist
 NullMoist ()
 
virtual ~NullMoist ()=default
 
virtual void Update_Micro_Vars (amrex::MultiFab &cons_in, const amrex::MultiFab *)
 
virtual int Qstate_NonMoist_Size ()
 
virtual void SetCurrentLevel (const int &)
 
virtual void InitLevel (const int, const amrex::MultiFab &)
 
virtual int getDiagnosticsInterval () const
 
virtual void Set_RealWidth (const int)
 

Private Types

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

Private Attributes

int m_qmoist_size = 3
 
int n_qstate_moist_size = 11
 
int n_qstate_moist_numconc_size = 5
 
amrex::Vector< int > MicVarMap
 
amrex::Geometry m_geom
 
amrex::Real m_rdOcp
 
bool m_do_cond
 
MoistureType m_moisture_type = MoistureType::None
 
amrex::Real m_dzmin
 
amrex::MultiFab * m_z_phys_nd
 
amrex::MultiFab * m_detJ_cc
 
amrex::Array< FabPtr, MicVar_Morr::NumVarsmic_fab_vars
 

Member Typedef Documentation

◆ FabPtr

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

Constructor & Destructor Documentation

◆ Morrison()

Morrison::Morrison ( )
inline
65 {}

◆ ~Morrison()

virtual Morrison::~Morrison ( )
virtualdefault

Member Function Documentation

◆ Advance()

void Morrison::Advance ( const amrex::Real dt_advance,
const SolverChoice sc 
)
overridevirtual

Reimplemented from NullMoist.

166  {
167  // Expose for GPU
168  bool do_cond = m_do_cond;
169 
170  // Store timestep
171  Real dt = dt_advance;
172 
173  // Check if CPP or FORT answer is used
174  ParmParse pp("erf");
175  bool use_morr_cpp_answer = true;
176  pp.query("use_morr_cpp_answer", use_morr_cpp_answer);
177 
178  // Ensure that only one of these is true
179  bool run_morr_cpp = use_morr_cpp_answer;
180  bool run_morr_fort = !run_morr_cpp;
181 
182  std::string filename = std::string("output_cpp") + std::to_string(use_morr_cpp_answer) + ".txt";
183 
184  // Allow user to override constant droplet concentration from inputs file
185  // Constant droplet concentration (if INUM = 1)
186  Real m_ndcnst = Real(250.0); // Droplet number concentration (cm^-3)
187  pp.query("morrison_ndcnst", m_ndcnst);
188 
189  // Loop through the grids
190  //
191  // The Fortran bridge is a whole-FAB interface: it declares every array over the fab
192  // box and would stage a full-FAB copy of ~14 scratch arrays per tile. Iterate one
193  // box at a time on that path.
194  //
195  const IntVect morr_tile_size = run_morr_fort ? IntVect::TheZeroVector() : TileNoZ();
196  for (MFIter mfi(*mic_fab_vars[MicVar_Morr::qcl],morr_tile_size); mfi.isValid(); ++mfi)
197  {
198  auto box = mfi.tilebox();
199 
200  if (!box.ok()) { // Avoid going farther if the box is inverted (i.e., ilo > ihi or jlo > jhi).
201  continue;
202  }
203 
204  // Get array data from class member variables
205  auto const& theta_arr = mic_fab_vars[MicVar_Morr::theta]->array(mfi);
206 
207  auto const& qv_arr = mic_fab_vars[MicVar_Morr::qv]->array(mfi);
208 
209  auto const& qcl_arr = mic_fab_vars[MicVar_Morr::qcl]->array(mfi);
210  auto const& qpr_arr = mic_fab_vars[MicVar_Morr::qpr]->array(mfi);
211  auto const& qci_arr = mic_fab_vars[MicVar_Morr::qci]->array(mfi);
212  auto const& qps_arr = mic_fab_vars[MicVar_Morr::qps]->array(mfi);
213  auto const& qpg_arr = mic_fab_vars[MicVar_Morr::qpg]->array(mfi);
214 
215  auto const& nc_arr = mic_fab_vars[MicVar_Morr::nc]->array(mfi);
216  auto const& ni_arr = mic_fab_vars[MicVar_Morr::ni]->array(mfi);
217  auto const& nr_arr = mic_fab_vars[MicVar_Morr::nr]->array(mfi);
218  auto const& ns_arr = mic_fab_vars[MicVar_Morr::ns]->array(mfi);
219  auto const& ng_arr = mic_fab_vars[MicVar_Morr::ng]->array(mfi);
220 
221 #ifdef ERF_USE_MORR_FORT
222  auto const& rho_arr = mic_fab_vars[MicVar_Morr::rho]->array(mfi);
223 #endif
224  auto const& pres_arr = mic_fab_vars[MicVar_Morr::pres]->array(mfi);
225  auto const& rain_accum_arr = mic_fab_vars[MicVar_Morr::rain_accum]->array(mfi);
226  auto const& snow_accum_arr = mic_fab_vars[MicVar_Morr::snow_accum]->array(mfi);
227  auto const& graup_accum_arr = mic_fab_vars[MicVar_Morr::graup_accum]->array(mfi);
228  auto const& w_arr = mic_fab_vars[MicVar_Morr::omega]->array(mfi);
229 
230  // Get radar reflectivity array if radar diagnostics enabled
231  // auto const& refl_arr = m_do_radar_ref ? m_radar->array(mfi) : nullptr;
232  // auto const& refl_arr = m_radar->array(mfi);
233 
234  // Extract box dimensions
235  const int ilo = box.loVect()[0];
236  const int ihi = box.hiVect()[0];
237  const int jlo = box.loVect()[1];
238  const int jhi = box.hiVect()[1];
239  const int klo = box.loVect()[2];
240  const int khi = box.hiVect()[2];
241 
242  Box grown_box(box); grown_box.grow(3);
243 
244  // Every array handed to the Fortran bridge -- both the mic_fab_vars and the staging
245  // FABs below -- is declared there as DIMENSION(ims:ime,jms:jme,kms:kme), and those
246  // bounds are taken from mfi.fabbox(). So the staging FABs must be allocated on the
247  // fab box too; sizing them from a tilebox grown by a hard-coded 3 mis-declares the
248  // strides whenever ngrow_state != 3 or the MFIter tiles the box.
249  // Note fab_box always contains grown_box (ComputeGhostCells() >= 2, so the state
250  // carries at least 3 ghost cells), so this only ever widens the staged region.
251  const Box& fab_box = mfi.fabbox();
252 
253 #if defined(ERF_USE_MORR_FORT) && defined(AMREX_USE_GPU)
254  Arena* Arena_Used = The_Pinned_Arena();
255 #else
256  Arena* Arena_Used = The_Async_Arena();
257 #endif
258 
259  // Calculate Exner function (PII) to convert potential temperature to temperature
260  // PII = (P/P0)^(R/cp)
261  FArrayBox pii_fab(fab_box, 1, Arena_Used);
262  auto const& pii_arr = pii_fab.array();
263 
264  const Real p0 = Real(100000.0); // Reference pressure (Pa)
265 
266  const Real rdcp = m_rdOcp; // R/cp ratio
267 
268  // Calculate Exner function
269  ParallelFor(fab_box, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
270  // NOTE: the Morrison Fortran version uses Pa not hPa so we didn't divide p by 100
271  // so we don't need to multiply by 100 here
272  pii_arr(i,j,k) = std::pow((pres_arr(i,j,k)) / p0, rdcp);
273  });
274 
275  // Create arrays for height differences (dz)
276  FArrayBox dz_fab(fab_box, 1, Arena_Used);
277  auto const& dz_arr = dz_fab.array();
278 
279  // Calculate height differences
280  const Real dz_val = m_geom.CellSize(2);
281  const Array4<const Real> z_arr = (m_z_phys_nd) ? m_z_phys_nd->const_array(mfi) : Array4<const Real> {};
282  // z_phys_nd carries ComputeGhostCells()+2 ghost nodes, i.e. one more than the state,
283  // so the (i+1,j+1,k+1) reads stay in bounds over the whole fab box.
284  ParallelFor(fab_box, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
285  dz_arr(i,j,k) = (z_arr) ? Real(0.25) * ( (z_arr(i ,j ,k+1) - z_arr(i ,j ,k))
286  + (z_arr(i+1,j ,k+1) - z_arr(i+1,j ,k))
287  + (z_arr(i ,j+1,k+1) - z_arr(i ,j+1,k))
288  + (z_arr(i+1,j+1,k+1) - z_arr(i+1,j+1,k)) ) : dz_val;
289  });
290 
291  // The 2D Fortran arrays are declared DIMENSION(ims:ime,jms:jme), so this slab must
292  // carry the fab box extents in x and y.
293  Box fab_boxD(fab_box); fab_boxD.makeSlab(2,0);
294 
295  // Arrays to store precipitation rates
296  FArrayBox rainncv_fab(fab_boxD, 1, Arena_Used);
297  FArrayBox sr_fab(fab_boxD, 1, Arena_Used); // Ratio of snow to total precipitation
298  FArrayBox snowncv_fab(fab_boxD, 1, Arena_Used);
299  FArrayBox graupelncv_fab(fab_boxD, 1, Arena_Used);
300 
301  auto const& rainncv_arr = rainncv_fab.array();
302  auto const& sr_arr = sr_fab.array();
303  auto const& snowncv_arr = snowncv_fab.array();
304  auto const& graupelncv_arr = graupelncv_fab.array();
305 
306  // Initialize precipitation rate arrays to Real(0)
307  ParallelFor(fab_boxD, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
308  rainncv_arr(i,j,k) = Real(0);
309  sr_arr(i,j,k) = Real(0);
310  snowncv_arr(i,j,k) = Real(0);
311  graupelncv_arr(i,j,k) = Real(0);
312  });
313 
314  // Create terrain height array (not actually used by Morrison scheme)
315  FArrayBox ht_fab(Box(IntVect(ilo, jlo, 0), IntVect(ihi, jhi, 0)), 1, Arena_Used);
316  [[maybe_unused]] auto const& ht_arr = ht_fab.array();
317  // ParallelFor(Box(IntVect(ilo, jlo, 0), IntVect(ihi, jhi, 0)), [=] AMREX_GPU_DEVICE (int i, int j, int k) {
318  // ht_arr(i,j,k) = (z_arr) ? Real(0.25) * ( z_arr(i ,j ,k) + z_arr(i+1,j ,k)
319  // + z_arr(i ,j+1,k) + z_arr(i+1,j+1,k) ) : Real(0.); // Not used by Morrison scheme
320  //});
321 
322  // Microphysics options/switches
323  int m_iact = 2; // CCN activation option (1:std::power-law, 2: lognormal aerosol)
324  int m_inum = 1; // Droplet number option (0: predict, 1: constant)
325 
326  int m_iliq = 0; // Liquid-only option (0: include ice, 1: liquid only)
327  int m_inuc = 0; // Ice nucleation option (0: mid-latitude, 1: arctic)
328  // int m_ibase = 2; // Cloud base activation option
329  // int m_isub = 0; // Sub-grid vertical velocity option
330  int m_igraup = 0; // Graupel option (0: include graupel, 1: no graupel)
331  int m_ihail = 0; // Graupel/hail option (0: graupel, 1: hail)
332 
333  if(sc.moisture_type == MoistureType::Morrison_NoIce) {
334  m_iliq = 1; // Liquid-only option (0: include ice, 1: liquid only)
335  m_inuc = 0; // Ice nucleation option (0: mid-latitude, 1: arctic)
336  // m_ibase = 2; // Cloud base activation option
337  // m_isub = 0; // Sub-grid vertical velocity option
338  m_igraup = 1; // Graupel option (0: include graupel, 1: no graupel)
339  m_ihail = 0; // Graupel/hail option (0: graupel, 1: hail)
340  }
341  // bool m_do_radar_ref = false; // Radar reflectivity calculation flag
342 
343  // Physical constants
344  Real m_pi; // Pi constant
345  Real m_R; // Gas constant for dry air (J/kg/K)
346  Real m_Rd; // Gas constant for dry air (J/kg/K)
347  Real m_Rv; // Gas constant for water vapor (J/kg/K)
348  // Real m_cp; // Specific heat at constant pressure (J/kg/K)
349  Real m_g; // Gravitational acceleration (m/s^2)
350  Real m_ep_2; // Molecular weight ratio (Rd/Rv)
351 
352  // Reference density and species densities
353  Real m_rhosu; // Standard air density at 850 mb (kg/m^3)
354  Real m_rhow; // Density of liquid water (kg/m^3)
355  Real m_rhoi; // Bulk density of cloud ice (kg/m^3)
356  Real m_rhosn; // Bulk density of snow (kg/m^3)
357  Real m_rhog; // Bulk density of graupel/hail (kg/m^3)
358 
359  // Fall speed parameters (V=AD^B)
360  Real m_ai, m_bi; // Cloud ice fall speed parameters
361  // Real m_ac; // Cloud droplet fall speed parameters
362  Real m_bc; // Cloud droplet fall speed parameters
363  Real m_as, m_bs; // Snow fall speed parameters
364  Real m_ar, m_br; // Rain fall speed parameters
365  Real m_ag, m_bg; // Graupel/hail fall speed parameters
366 
367  // Microphysical parameters
368  Real m_aimm; // Parameter in Bigg immersion freezing
369  Real m_bimm; // Parameter in Bigg immersion freezing
370  Real m_ecr; // Collection efficiency between droplets/rain and snow/rain
371  Real m_dcs; // Threshold size for cloud ice autoconversion (m)
372  Real m_mi0; // Initial mass of nucleated ice crystal (kg)
373  Real m_mg0; // Mass of embryo graupel (kg)
374  Real m_f1s; // Ventilation parameter for snow
375  Real m_f2s; // Ventilation parameter for snow
376  Real m_f1r; // Ventilation parameter for rain
377  Real m_f2r; // Ventilation parameter for rain
378  Real m_qsmall; // Smallest allowed hydrometeor mixing ratio
379  Real m_eii; // Collection efficiency, ice-ice collisions
380  Real m_eci; // Collection efficiency, ice-droplet collisions
381  Real m_cpw; // Specific heat of liquid water (J/kg/K)
382  Real m_rin; // Radius of contact nuclei (m)
383  Real m_mmult; // Mass of splintered ice particle (kg)
384 
385  // Size distribution parameters
386  Real m_ci, m_di; // Cloud ice size distribution parameters
387  Real m_cs, m_ds; // Snow size distribution parameters
388  Real m_cg, m_dg; // Graupel size distribution parameters
389 
390  // Lambda limits for size distributions
391  Real m_lammaxi, m_lammini; // Cloud ice lambda limits
392  Real m_lammaxr, m_lamminr; // Rain lambda limits
393  Real m_lammaxs, m_lammins; // Snow lambda limits
394  Real m_lammaxg, m_lamming; // Graupel lambda limits
395 
396  // CCN spectra parameters (for IACT = 1)
397  // Real m_k1; // Exponent in CCN activation formula
398  // Real m_c1; // Coefficient in CCN activation formula (cm^-3)
399 
400  // Aerosol activation parameters (for IACT = 2)
401  // Real m_mw; // Molecular weight water (kg/mol)
402  // Real m_osm; // Osmotic coefficient
403  // Real m_vi; // Number of ions dissociated in solution
404  // Real m_epsm; // Aerosol soluble fraction
405  // Real m_rhoa; // Aerosol bulk density (kg/m^3)
406  // Real m_map; // Molecular weight aerosol (kg/mol)
407  // Real m_ma; // Molecular weight of air (kg/mol)
408  // Real m_rr; // Universal gas constant (J/mol/K)
409  // Real m_bact; // Activation parameter
410  // Real m_rm1; // Geometric mean radius, mode 1 (m)
411  // Real m_rm2; // Geometric mean radius, mode 2 (m)
412  Real m_nanew1; // Total aerosol concentration, mode 1 (m^-3)
413  Real m_nanew2; // Total aerosol concentration, mode 2 (m^-3)
414  // Real m_sig1; // Standard deviation of aerosol dist, mode 1
415  // Real m_sig2; // Standard deviation of aerosol dist, mode 2
416  // Real m_f11; // Correction factor for activation, mode 1
417  // Real m_f12; // Correction factor for activation, mode 1
418  // Real m_f21; // Correction factor for activation, mode 2
419  // Real m_f22; // Correction factor for activation, mode 2
420 
421  // Precomputed constants for efficiency
422  Real m_cons1, m_cons2, m_cons3, m_cons4, m_cons5;
423  Real m_cons6, m_cons7, m_cons8, m_cons9, m_cons10;
424  Real m_cons11, m_cons12, m_cons13, m_cons14, m_cons15;
425  Real m_cons16, m_cons17, m_cons18, m_cons19, m_cons20;
426  Real m_cons21, m_cons22, m_cons23, m_cons24, m_cons25;
427  Real m_cons26, m_cons27, m_cons28, m_cons29;
428  Real m_cons31, m_cons32, m_cons34, m_cons35;
429  Real m_cons36, m_cons37, m_cons38, m_cons39, m_cons40;
430  Real m_cons41;
431 
432  // Set microphysics control parameters
433  m_inum = 1; // Use constant droplet number concentration
434  m_ndcnst = Real(250.0); // Droplet number concentration (cm^-3)
435  // Mathematical constants
436  m_pi = Real(3.1415926535897932384626434);
437 
438  m_R = Real(287.0); // Gas constant for dry air (J/kg/K)
439  m_Rd = Real(287.0); // Gas constant for dry air (J/kg/K)
440  m_Rv = Real(461.6); // Gas constant for water vapor (J/kg/K)
441  // m_cp = Real(7.0)*Real(287.0)/Real(2); // Specific heat at constant pressure (J/kg/K)
442  m_g = Real(9.81); // Gravitational acceleration (m/s^2)
443  m_ep_2 = m_Rd / m_Rv; // Molecular weight ratio (Rd/Rv)
444 
445  // Reference density
446  m_rhosu = Real(85000.0)/(Real(287.15)*Real(273.15)); // Standard air density at 850 mb (kg/m^3)
447 
448  // Densities for different hydrometeor species
449  m_rhow = Real(997.0); // Density of liquid water (kg/m^3)
450  m_rhoi = Real(500.0); // Bulk density of cloud ice (kg/m^3)
451  m_rhosn = Real(100.0); // Bulk density of snow (kg/m^3)
452 
453  // Set density for graupel or hail based on configuration
454  if (m_ihail == 0) {
455  m_rhog = Real(400.0); // Bulk density of graupel (kg/m^3)
456  } else {
457  m_rhog = Real(900.0); // Bulk density of hail (kg/m^3)
458  }
459 
460  // Fall speed parameters (V=AD^B) for different hydrometeors
461  // Cloud ice
462  m_ai = Real(700.0);
463  m_bi = one;
464 
465  // Cloud droplets
466  // m_ac = Real(3.0E7);
467  m_bc = Real(2);
468 
469  // Snow
470  m_as = Real(11.72);
471  m_bs = Real(0.41);
472 
473  // Rain
474  m_ar = Real(841.99667);
475  m_br = Real(0.8);
476 
477  // Graupel/hail (dependent on configuration)
478  if (m_ihail == 0) {
479  // Graupel parameters
480  m_ag = Real(19.3);
481  m_bg = Real(0.37);
482  } else {
483  // Hail parameters (Matsun and Huggins 1980)
484  m_ag = Real(114.5);
485  m_bg = myhalf;
486  }
487 
488  // Microphysical parameters
489  m_aimm = Real(0.66); // Parameter in Bigg immersion freezing
490  m_bimm = Real(100.0); // Parameter in Bigg immersion freezing
491  m_ecr = one; // Collection efficiency between rain and snow/graupel
492  m_dcs = Real(125.0E-6); // Threshold size for cloud ice autoconversion (m)
493  m_mi0 = Real(4.0)/three*m_pi*m_rhoi*amrex::Math::powi<3>(Real(10.0E-6)); // Initial mass of nucleated ice crystal (kg)
494  m_mg0 = Real(1.6E-10); // Mass of embryo graupel (kg)
495 
496  // Ventilation parameters
497  m_f1s = Real(0.86); // Ventilation parameter for snow
498  m_f2s = Real(0.28); // Ventilation parameter for snow
499  m_f1r = Real(0.78); // Ventilation parameter for rain
500  m_f2r = Real(0.308); // Ventilation parameter for rain
501 
502  // Smallest allowed hydrometeor mixing ratio
503  m_qsmall = Real(1.0E-14);
504 
505  // Collection efficiencies
506  m_eii = Real(0.1); // Ice-ice collision efficiency
507  m_eci = Real(0.7); // Ice-droplet collision efficiency
508 
509  // Specific heat of liquid water (J/kg/K)
510  m_cpw = Real(4187.0);
511 
512  // Size distribution parameters
513  m_ci = m_rhoi * m_pi / Real(6.0);
514  m_di = three;
515  m_cs = m_rhosn * m_pi / Real(6.0);
516  m_ds = three;
517  m_cg = m_rhog * m_pi / Real(6.0);
518  m_dg = three;
519 
520  // Radius of contact nuclei (m)
521  m_rin = Real(0.1E-6);
522 
523  // Mass of splintered ice particle (kg)
524  m_mmult = Real(4.0)/three*m_pi*m_rhoi*amrex::Math::powi<3>(Real(5.0E-6));
525 
526  // Set lambda limits for size distributions
527  // Maximum and minimum values for lambda parameter in size distributions
528  m_lammaxi = one/Real(1.0E-6);
529  m_lammini = one/(Real(2)*m_dcs + Real(100.0E-6));
530  m_lammaxr = one/Real(20.0E-6);
531  m_lamminr = one/Real(2800.0E-6);
532  m_lammaxs = one/Real(10.0E-6);
533  m_lammins = one/Real(2000.0E-6);
534  m_lammaxg = one/Real(20.0E-6);
535  m_lamming = one/Real(2000.0E-6);
536 
537  // Set CCN parameters for different environments
538  if (m_iact == 1) {
539  // Maritime CCN spectrum parameters (modified from Rasmussen et al. 2002)
540  // NCCN = C*S^K, where S is supersaturation in %
541  // m_k1 = Real(0.4); // Exponent in CCN activation formula
542  // m_c1 = Real(120.0); // Coefficient in CCN activation formula (cm^-3)
543  }
544 
545  // Initialize aerosol activation parameters for lognormal distribution
546  if (m_iact == 2) {
547  // Parameters for ammonium sulfate
548  // m_mw = Real(0.018); // Molecular weight of water (kg/mol)
549  // m_osm = one; // Osmotic coefficient
550  // m_vi = three; // Number of ions dissociated in solution
551  // m_epsm = Real(0.7); // Aerosol soluble fraction
552  // m_rhoa = Real(1777.0); // Aerosol bulk density (kg/m^3)
553  // m_map = Real(0.132); // Molecular weight of aerosol (kg/mol)
554  // m_ma = Real(0.0284); // Molecular weight of air (kg/mol)
555  // m_rr = Real(8.3145); // Universal gas constant (J/mol/K)
556  // m_bact = m_vi * m_osm * m_epsm * m_mw * m_rhoa / (m_map * m_rhow);
557  // m_a_w = two * m_mw * Real(0.0761) / (m_rhow * m_r_v * Real(293.15)); // "A" parameter
558 
559  // Aerosol size distribution parameters for MPACE (Morrison et al. 2007, JGR)
560  // Mode 1
561  // m_rm1 = Real(0.052E-6); // Geometric mean radius, mode 1 (m)
562  // m_sig1 = Real(2.04); // Standard deviation of aerosol size distribution, mode 1
563  m_nanew1 = Real(72.2E6); // Total aerosol concentration, mode 1 (m^-3)
564  // m_f11 = myhalf * std::exp(Real(2.5) * amrex::Math::powi<2>(std::log(m_sig1)));
565  // m_f21 = one + fourth * std::log(m_sig1);
566 
567  // Mode 2
568  // m_rm2 = Real(1.3E-6); // Geometric mean radius, mode 2 (m)
569  // m_sig2 = Real(2.5); // Standard deviation of aerosol size distribution, mode 2
570  m_nanew2 = Real(1.8E6); // Total aerosol concentration, mode 2 (m^-3)
571  // m_f12 = myhalf * std::exp(Real(2.5) * amrex::Math::powi<2>(std::log(m_sig2)));
572  // m_f22 = one + fourth * std::log(m_sig2);
573  }
574 
575  // Precompute constants for efficiency
576  m_cons1 = gamma_function(one + m_ds) * m_cs;
577  m_cons2 = gamma_function(one + m_dg) * m_cg;
578  m_cons3 = gamma_function(Real(4.0) + m_bs) / Real(6.0);
579  m_cons4 = gamma_function(Real(4.0) + m_br) / Real(6.0);
580  m_cons5 = gamma_function(one + m_bs);
581  m_cons6 = gamma_function(one + m_br);
582  m_cons7 = gamma_function(Real(4.0) + m_bg) / Real(6.0);
583  m_cons8 = gamma_function(one + m_bg);
584  m_cons9 = gamma_function(Real(5.0)/Real(2) + m_br/Real(2));
585  m_cons10 = gamma_function(Real(5.0)/Real(2) + m_bs/Real(2));
586  m_cons11 = gamma_function(Real(5.0)/Real(2) + m_bg/Real(2));
587  m_cons12 = gamma_function(one + m_di) * m_ci;
588  m_cons13 = gamma_function(m_bs + three) * m_pi / Real(4.0) * m_eci;
589  m_cons14 = gamma_function(m_bg + three) * m_pi / Real(4.0) * m_eci;
590  m_cons15 = -Real(1108.0) * m_eii * std::pow(m_pi, (one-m_bs)/three) *
591  std::pow(m_rhosn, (-Real(2)-m_bs)/three) / (Real(4.0)*Real(720.0));
592  m_cons16 = gamma_function(m_bi + three) * m_pi / Real(4.0) * m_eci;
593  m_cons17 = Real(4.0) * Real(2) * three * m_rhosu * m_pi * m_eci * m_eci *
594  gamma_function(Real(2)*m_bs + Real(2)) / (Real(8.0)*(m_rhog-m_rhosn));
595  m_cons18 = m_rhosn * m_rhosn;
596  m_cons19 = m_rhow * m_rhow;
597  m_cons20 = Real(20.0) * m_pi * m_pi * m_rhow * m_bimm;
598  m_cons21 = Real(4.0) / (m_dcs * m_rhoi);
599  m_cons22 = m_pi * m_rhoi * amrex::Math::powi<3>(m_dcs) / Real(6.0);
600  m_cons23 = m_pi / Real(4.0) * m_eii * gamma_function(m_bs + three);
601  m_cons24 = m_pi / Real(4.0) * m_ecr * gamma_function(m_br + three);
602  m_cons25 = m_pi * m_pi / Real(24.0) * m_rhow * m_ecr * gamma_function(m_br + Real(6.0));
603  m_cons26 = m_pi / Real(6.0) * m_rhow;
604  m_cons27 = gamma_function(one + m_bi);
605  m_cons28 = gamma_function(Real(4.0) + m_bi) / Real(6.0);
606  m_cons29 = Real(4.0)/three * m_pi * m_rhow * amrex::Math::powi<3>(Real(25.0E-6));
607  m_cons31 = m_pi * m_pi * m_ecr * m_rhosn;
608  m_cons32 = m_pi / Real(2) * m_ecr;
609  m_cons34 = Real(5.0)/Real(2) + m_br/Real(2);
610  m_cons35 = Real(5.0)/Real(2) + m_bs/Real(2);
611  m_cons36 = Real(5.0)/Real(2) + m_bg/Real(2);
612  m_cons37 = Real(4.0) * m_pi * Real(1.38E-23) / (Real(6.0) * m_pi * m_rin);
613  m_cons38 = m_pi * m_pi / three * m_rhow;
614  m_cons39 = m_pi * m_pi / Real(36.0) * m_rhow * m_bimm;
615  m_cons40 = m_pi / Real(6.0) * m_bimm;
616  m_cons41 = m_pi * m_pi * m_ecr * m_rhow;
617 
618  // Set CCN parameters for different environments
619  if (m_iact == 1) {
620  // Maritime CCN spectrum parameters (modified from Rasmussen et al. 2002)
621  // NCCN = C*S^K, where S is supersaturation in %
622  // m_k1 = Real(0.4); // Exponent in CCN activation formula
623  // m_c1 = Real(120.0); // Coefficient in CCN activation formula (cm^-3)
624  }
625 
626  // Initialize aerosol activation parameters for IACT=2
627  if (m_iact == 2) {
628  // Parameters for ammonium sulfate
629  // m_mw = Real(0.018); // Molecular weight of water (kg/mol)
630  // m_osm = one; // Osmotic coefficient
631  // m_vi = three; // Number of ions dissociated in solution
632  // m_epsm = Real(0.7); // Aerosol soluble fraction
633  // m_rhoa = Real(1777.0); // Aerosol bulk density (kg/m^3)
634  // m_map = Real(0.132); // Molecular weight of aerosol (kg/mol)
635  // m_ma = Real(0.0284); // Molecular weight of air (kg/mol)
636  // m_rr = Real(8.3145); // Universal gas constant (J/mol/K)
637  // m_bact = m_vi * m_osm * m_epsm * m_mw * m_rhoa / (m_map * m_rhow);
638 
639  // Aerosol size distribution parameters for MPACE (Morrison et al. 2007, JGR)
640  // Mode 1
641  // m_rm1 = Real(0.052E-6); // Geometric mean radius, mode 1 (m)
642  // m_sig1 = Real(2.04); // Standard deviation of aerosol size distribution, mode 1
643  m_nanew1 = Real(72.2E6); // Total aerosol concentration, mode 1 (m^-3)
644  // m_f11 = myhalf * std::exp(Real(2.5) * amrex::Math::powi<2>(std::log(m_sig1)));
645  // m_f21 = one + fourth * std::log(m_sig1);
646 
647  // Mode 2
648  // m_rm2 = Real(1.3E-6); // Geometric mean radius, mode 2 (m)
649  // m_sig2 = Real(2.5); // Standard deviation of aerosol size distribution, mode 2
650  m_nanew2 = Real(1.8E6); // Total aerosol concentration, mode 2 (m^-3)
651  // m_f12 = myhalf * std::exp(Real(2.5) * amrex::Math::powi<2>(std::log(m_sig2)));
652  // m_f22 = one + fourth * std::log(m_sig2);
653  }
654  // Set microphysics control parameters
655  m_iact = 2; // Lognormal aerosol activation
656  m_inuc = 0; // Mid-latitude ice nucleation (Cooper)
657  if (sc.moisture_type == MoistureType::Morrison_NoIce) {
658  m_iliq = 1; // Include ice processes
659  m_igraup = 1; // Include graupel processes
660  } else {
661  m_iliq = 0; // Include ice processes
662  m_igraup = 0; // Include graupel processes
663  }
664  m_ihail = 0; // Use graupel (0) instead of hail (1)
665  // m_isub = 0; // Sub-grid vertical velocity option
666  // m_do_radar_ref = false; // Disable radar reflectivity by default
667  Box boxD(box); boxD.makeSlab(2,0);
668 
669  if(run_morr_cpp) {
670 
671  // One FAB to rule them all
672  FArrayBox morr_fab(grown_box, MORRInd::NumInds, Arena_Used);
673  morr_fab.template setVal<RunOn::Device>(0);
674  auto const& morr_arr = morr_fab.array();
675 
676  ////////////////////////////////////////////////////////////
677  // ParallelFor for testing partial C++ implementation
678  // NOTE: Currently all Array4 values are copied to locals
679  // This means we're not updating or outputting anything
680  ////////////////////////////////////////////////////////////
681  ParallelFor( box, [=] AMREX_GPU_DEVICE (int i, int j, int k)
682  {
683  // Tendencies and mixing ratios
684  morr_arr(i,j,k,MORRInd::qc3d) = qcl_arr(i,j,k); // CLOUD WATER MIXING RATIO
685  morr_arr(i,j,k,MORRInd::qi3d) = qci_arr(i,j,k); // CLOUD ICE MIXING RATIO
686  morr_arr(i,j,k,MORRInd::qni3d) = qps_arr(i,j,k); // SNOW MIXING RATIO
687  morr_arr(i,j,k,MORRInd::qr3d) = qpr_arr(i,j,k); // RAIN MIXING RATIO
688  morr_arr(i,j,k,MORRInd::qg3d) = qpg_arr(i,j,k); // GRAUPEL MIXING RATIO
689 
690  morr_arr(i,j,k,MORRInd::nc3d) = nc_arr(i,j,k); // CLOUD WATER NUMBER CONCENTRATION
691  morr_arr(i,j,k,MORRInd::ni3d) = ni_arr(i,j,k); // CLOUD ICE NUMBER CONCENTRATION
692  morr_arr(i,j,k,MORRInd::ns3d) = ns_arr(i,j,k); // SNOW NUMBER CONCENTRATION
693  morr_arr(i,j,k,MORRInd::nr3d) = nr_arr(i,j,k); // RAIN NUMBER CONCENTRATION
694  morr_arr(i,j,k,MORRInd::ng3d) = ng_arr(i,j,k); // GRAUPEL NUMBER CONCENTRATION
695 
696  morr_arr(i,j,k,MORRInd::t3d) = theta_arr(i,j,k) * pii_arr(i,j,k); // TEMPERATURE
697  morr_arr(i,j,k,MORRInd::qv3d) = qv_arr(i,j,k); // WATER VAPOR MIXING RATIO
698  morr_arr(i,j,k,MORRInd::pres) = pres_arr(i,j,k); // ATMOSPHERIC PRESSURE
699  morr_arr(i,j,k,MORRInd::dzq) = dz_arr(i,j,k); // DIFFERENCE IN HEIGHT ACROSS LEVEL
700  morr_arr(i,j,k,MORRInd::w3d) = w_arr(i,j,k); // GRID-SCALE VERTICAL VELOCITY
701 
702  // NOTE: There are no cumulus tendencies passed to Morrison
703  // and the FORTRAN version zeros these out.
704  morr_arr(i,j,k,MORRInd::qrcu1d) = Real(0); //morr_arr(i,j,k,MORRInd::qrcuten_arr); // RAIN FROM CUMULUS PARAMETERIZATION
705  morr_arr(i,j,k,MORRInd::qscu1d) = Real(0); //morr_arr(i,j,k,MORRInd::qscuten_arr); // SNOW FROM CUMULUS PARAMETERIZATION
706  morr_arr(i,j,k,MORRInd::qicu1d) = Real(0); //morr_arr(i,j,k,MORRInd::qicuten_arr); // ICE FROM CUMULUS PARAMETERIZATION
707  });
708 
709  ParallelFor( boxD, [=] AMREX_GPU_DEVICE (int i, int j, int )
710  {
711  int ltrue=0; // LTRUE: SWITCH = 0: NO HYDROMETEORS IN COLUMN, = 1: HYDROMETEORS IN COLUMN
712  int nstep; // NSTEP: Timestep counter
713  int iinum=m_inum; // iinum: Integer control variable
714 
715  for (int k=klo; k<=khi; k++) {
716  // Microphysical processes
717  // Real nsubc; // NSUBC: Loss of NC during evaporation
718  Real nsubi; // NSUBI: Loss of NI during sublimation
719  Real nsubs; // NSUBS: Loss of NS during sublimation
720  Real nsubr; // NSUBR: Loss of NR during evaporation
721  Real prd; // PRD: Deposition cloud ice
722  Real pre; // PRE: Evaporation of rain
723  Real prds; // PRDS: Deposition snow
724  Real nnuccc; // NNUCCC: Change N due to contact freezing droplets
725  Real mnuccc; // MNUCCC: Change Q due to contact freezing droplets
726  Real pra; // PRA: Accretion droplets by rain
727  Real prc; // PRC: Autoconversion droplets
728  Real pcc; // PCC: Condensation/evaporation droplets
729  Real nnuccd; // NNUCCD: Change N freezing aerosol (primary ice nucleation)
730  Real mnuccd; // MNUCCD: Change Q freezing aerosol (primary ice nucleation)
731  Real mnuccr; // MNUCCR: Change Q due to contact freezing rain
732  Real nnuccr; // NNUCCR: Change N due to contact freezing rain
733  Real npra; // NPRA: Change N due to droplet accretion by rain
734  Real nragg; // NRAGG: Self-collection/breakup of rain
735  Real nsagg; // NSAGG: Self-collection of snow
736  Real nprc; // NPRC: Change NC autoconversion droplets
737  Real nprc1; // NPRC1: Change NR autoconversion droplets
738  Real prai; // PRAI: Change Q accretion cloud ice by snow
739  Real prci; // PRCI: Change Q autoconversion cloud ice to snow
740  Real psacws; // PSACWS: Change Q droplet accretion by snow
741  Real npsacws; // NPSACWS: Change N droplet accretion by snow
742  Real psacwi; // PSACWI: Change Q droplet accretion by cloud ice
743  Real npsacwi; // NPSACWI: Change N droplet accretion by cloud ice
744  Real nprci; // NPRCI: Change N autoconversion cloud ice by snow
745  Real nprai; // NPRAI: Change N accretion cloud ice
746  Real nmults; // NMULTS: Ice multiplication due to riming droplets by snow
747  Real nmultr; // NMULTR: Ice multiplication due to riming rain by snow
748  Real qmults; // QMULTS: Change Q due to ice multiplication droplets/snow
749  Real qmultr; // QMULTR: Change Q due to ice multiplication rain/snow
750  Real pracs; // PRACS: Change Q rain-snow collection
751  Real npracs; // NPRACS: Change N rain-snow collection
752  // Real pccn; // PCCN: Change Q droplet activation
753  Real psmlt; // PSMLT: Change Q melting snow to rain
754  Real evpms; // EVPMS: Change Q melting snow evaporating
755  Real nsmlts; // NSMLTS: Change N melting snow
756  Real nsmltr; // NSMLTR: Change N melting snow to rain
757  Real piacr; // PIACR: Change QR, ice-rain collection
758  Real niacr; // NIACR: Change N, ice-rain collection
759  Real praci; // PRACI: Change QI, ice-rain collection
760  Real piacrs; // PIACRS: Change QR, ice rain collision, added to snow
761  Real niacrs; // NIACRS: Change N, ice rain collision, added to snow
762  Real pracis; // PRACIS: Change QI, ice rain collision, added to snow
763  Real eprd; // EPRD: Sublimation cloud ice
764  Real eprds; // EPRDS: Sublimation snow
765 
766  // Graupel processes
767  Real pracg; // PRACG: Change in Q collection rain by graupel
768  Real psacwg; // PSACWG: Change in Q collection droplets by graupel
769  Real pgsacw; // PGSACW: Conversion Q to graupel due to collection droplets by snow
770  Real pgracs; // PGRACS: Conversion Q to graupel due to collection rain by snow
771  Real prdg; // PRDG: Deposition of graupel
772  Real eprdg; // EPRDG: Sublimation of graupel
773  Real evpmg; // EVPMG: Change Q melting of graupel and evaporation
774  Real pgmlt; // PGMLT: Change Q melting of graupel
775  Real npracg; // NPRACG: Change N collection rain by graupel
776  Real npsacwg; // NPSACWG: Change N collection droplets by graupel
777  Real nscng; // NSCNG: Change N conversion to graupel due to collection droplets by snow
778  Real ngracs; // NGRACS: Change N conversion to graupel due to collection rain by snow
779  Real ngmltg; // NGMLTG: Change N melting graupel
780  Real ngmltr; // NGMLTR: Change N melting graupel to rain
781  Real nsubg; // NSUBG: Change N sublimation/deposition of graupel
782  Real psacr; // PSACR: Conversion due to collection of snow by rain
783  Real nmultg; // NMULTG: Ice multiplication due to accretion droplets by graupel
784  Real nmultrg; // NMULTRG: Ice multiplication due to accretion rain by graupel
785  Real qmultg; // QMULTG: Change Q due to ice multiplication droplets/graupel
786  Real qmultrg; // QMULTRG: Change Q due to ice multiplication rain/graupel
787 
788  // Time-varying atmospheric parameters
789  Real kap; // KAP: Thermal conductivity of air
790  Real evs; // EVS: Saturation vapor pressure
791  Real eis; // EIS: Ice saturation vapor pressure
792  Real qvs; // QVS: Saturation mixing ratio
793  Real qvi; // QVI: Ice saturation mixing ratio
794  Real qvqvs; // QVQVS: Saturation ratio
795  Real qvqvsi; // QVQVSI: Ice saturation ratio
796  Real dv; // DV: Diffusivity of water vapor in air
797  Real sc_schmidt; // SC: Schmidt number
798  Real ab; // AB: Correction to condensation rate due to latent heating
799  Real abi; // ABI: Correction to deposition rate due to latent heating
800 
801  // Dummy variables
802  Real dum; // DUM: General dummy variable
803  Real dum1; // DUM1: General dummy variable
804  Real dumt; // DUMT: Dummy variable for temperature
805  Real dumqv; // DUMQV: Dummy variable for water vapor
806  Real dumqss; // DUMQSS: Dummy saturation mixing ratio
807  Real dums; // DUMS: General dummy variable
808 
809  // Prognostic supersaturation
810  Real dqsdt; // DQSDT: Change of saturation mixing ratio with temperature
811  Real dqsidt; // DQSIDT: Change in ice saturation mixing ratio with temperature
812 
813  Real epsi; // EPSI: 1/phase relaxation time (see M2005), ice
814  Real epss; // EPSS: 1/phase relaxation time (see M2005), snow
815  Real epsr; // EPSR: 1/phase relaxation time (see M2005), rain
816  Real epsg; // EPSG: 1/phase relaxation time (see M2005), graupel
817  Real kc2; // KC2: Total ice nucleation rate
818  Real di0; // DC0: Characteristic diameter for ice
819  Real ds0; // DS0: Characteristic diameter for snow
820  Real dg0; // DG0: Characteristic diameter for graupel
821  Real dumqc; // DUMQC: Dummy variable for cloud water mixing ratio
822  Real ratio; // RATIO: General ratio variable
823  Real sum_dep; // SUM_DEP: Sum of deposition/sublimation
824  Real fudgef; // FUDGEF: Adjustment factor
825 
826  // Real dum2; // DUM2: General dummy variable
827  // Real dumqsi; // DUMQSI: Dummy ice saturation mixing ratio
828  // Real dc0; // DC0: Characteristic diameter for cloud droplets
829  // Real dumqr; // DUMQR: Dummy variable for rain mixing ratio
830 
831  // For WRF-CHEM
832  // Real c2prec; // C2PREC: Cloud to precipitation conversion
833  // Real csed; // CSED: Cloud sedimentation
834  // Real ised; // ISED: Ice sedimentation
835  // Real ssed; // SSED: Snow sedimentation
836  // Real gsed; // GSED: Graupel sedimentation
837  // Real rsed; // RSED: Rain sedimentation
838  // Real tqimelt; // tqimelt: Melting of cloud ice (tendency)
839 
840  // NC3DTEN LOCAL ARRAY INITIALIZED
841  morr_arr(i,j,k,MORRInd::nc3dten) = Real(0);
842 
843  // INITIALIZE VARIABLES FOR WRF-CHEM OUTPUT TO ZERO
844  // c2prec = Real(0);
845  // csed = Real(0);
846  // ised = Real(0);
847  // ssed = Real(0);
848  // gsed = Real(0);
849  // rsed = Real(0);
850 
851  // LATENT HEAT OF VAPORIZATION
852  morr_arr(i,j,k,MORRInd::xxlv) = Real(3.1484E6) - Real(2370.0) * morr_arr(i,j,k,MORRInd::t3d);
853  // LATENT HEAT OF SUBLIMATION
854  morr_arr(i,j,k,MORRInd::xxls) = Real(3.15E6) - Real(2370.0) * morr_arr(i,j,k,MORRInd::t3d) + Real(0.3337E6);
855 
856  // Assuming CP is a constant defined elsewhere (specific heat of dry air at constant pressure)
857  const Real CP = Real(1004.5); // J/kg/K
858  morr_arr(i,j,k,MORRInd::cpm) = CP * (one + Real(0.887) * morr_arr(i,j,k,MORRInd::qv3d));
859 
860  // SATURATION VAPOR PRESSURE AND MIXING RATIO
861  // hm, add fix for low pressure, 5/12/10
862  // Assuming POLYSVP is defined elsewhere
863  evs = std::min(Real(0.99) * morr_arr(i,j,k,MORRInd::pres), calc_saturation_vapor_pressure(morr_arr(i,j,k,MORRInd::t3d), 0)); // PA
864  eis = std::min(Real(0.99) * morr_arr(i,j,k,MORRInd::pres), calc_saturation_vapor_pressure(morr_arr(i,j,k,MORRInd::t3d), 1)); // PA
865  // MAKE SURE ICE SATURATION DOESN'T EXCEED WATER SAT. NEAR FREEZING
866  if (eis > evs) {
867  eis = evs; // temporary update: adjust ice saturation pressure
868  }
869 
870  // SATURATION MIXING RATIOS
871  qvs = m_ep_2 * evs / (morr_arr(i,j,k,MORRInd::pres) - evs); // budget equation: calculate water saturation mixing ratio
872  qvi = m_ep_2 * eis / (morr_arr(i,j,k,MORRInd::pres) - eis); // budget equation: calculate ice saturation mixing ratio
873 
874  // SATURATION RATIOS
875  qvqvs = morr_arr(i,j,k,MORRInd::qv3d) / qvs; // budget equation: calculate water saturation ratio
876  qvqvsi = morr_arr(i,j,k,MORRInd::qv3d) / qvi; // budget equation: calculate ice saturation ratio
877 
878  // AIR DENSITY
879  morr_arr(i,j,k,MORRInd::rho) = morr_arr(i,j,k,MORRInd::pres) / (m_R * morr_arr(i,j,k,MORRInd::t3d)); // budget equation: calculate air density
880 
881  ds0 = three; // Size distribution parameter for snow
882  di0 = three; // Size distribution parameter for cloud ice
883  dg0 = three; // Size distribution parameter for graupel
884 
885  // ADD NUMBER CONCENTRATION DUE TO CUMULUS TENDENCY
886  // ASSUME N0 ASSOCIATED WITH CUMULUS PARAM RAIN IS 10^7 M^-4
887  // ASSUME N0 ASSOCIATED WITH CUMULUS PARAM SNOW IS 2 X 10^7 M^-4
888  // FOR DETRAINED CLOUD ICE, ASSUME MEAN VOLUME DIAM OF 80 MICRON
889  if (morr_arr(i,j,k,MORRInd::qrcu1d) >= Real(1.0e-10)) {
890  dum = Real(1.8e5) * std::pow(morr_arr(i,j,k,MORRInd::qrcu1d) * dt / (m_pi * m_rhow * amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::rho))), fourth); // rate equation: calculate rain number concentration from cumulus
891  morr_arr(i,j,k,MORRInd::nr3d) += dum; // budget equation: update rain number concentration
892  }
893  if (morr_arr(i,j,k,MORRInd::qscu1d) >= Real(1.0e-10)) {
894  dum = Real(3.e5) * std::pow(morr_arr(i,j,k,MORRInd::qscu1d) * dt / (m_cons1 * amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::rho))), one / (ds0 + one)); // rate equation: calculate snow number concentration from cumulus
895  morr_arr(i,j,k,MORRInd::ns3d) += dum; // budget equation: update snow number concentration
896  }
897  if (morr_arr(i,j,k,MORRInd::qicu1d) >= Real(1.0e-10)) {
898  dum = morr_arr(i,j,k,MORRInd::qicu1d) * dt / (m_ci * std::pow(Real(80.0e-6), di0)); // rate equation: calculate cloud ice number concentration from cumulus
899  morr_arr(i,j,k,MORRInd::ni3d) += dum; // budget equation: update cloud ice number concentration
900  }
901 
902  // AT SUBSATURATION, REMOVE SMALL AMOUNTS OF CLOUD/PRECIP WATER
903  // hm modify 7/0/09 change limit to Real(1.e-8)
904  if (qvqvs < Real(0.9)) {
905  if (morr_arr(i,j,k,MORRInd::qr3d) < Real(1.0e-8)) {
906  morr_arr(i,j,k,MORRInd::qv3d) += morr_arr(i,j,k,MORRInd::qr3d); // budget equation: transfer rain to vapor
907  morr_arr(i,j,k,MORRInd::t3d) -= morr_arr(i,j,k,MORRInd::qr3d) * morr_arr(i,j,k,MORRInd::xxlv) / morr_arr(i,j,k,MORRInd::cpm); // budget equation: adjust temperature
908  morr_arr(i,j,k,MORRInd::qr3d) = Real(0); // temporary update: set rain to Real(0)
909  }
910  if (morr_arr(i,j,k,MORRInd::qc3d) < Real(1.0e-8)) {
911  morr_arr(i,j,k,MORRInd::qv3d) += morr_arr(i,j,k,MORRInd::qc3d); // budget equation: transfer cloud water to vapor
912  morr_arr(i,j,k,MORRInd::t3d) -= morr_arr(i,j,k,MORRInd::qc3d) * morr_arr(i,j,k,MORRInd::xxlv) / morr_arr(i,j,k,MORRInd::cpm); // budget equation: adjust temperature
913  morr_arr(i,j,k,MORRInd::qc3d) = Real(0); // temporary update: set cloud water to Real(0)
914  }
915  }
916  if (qvqvsi < Real(0.9)) {
917  if (morr_arr(i,j,k,MORRInd::qi3d) < Real(1.0e-8)) {
918  morr_arr(i,j,k,MORRInd::qv3d) += morr_arr(i,j,k,MORRInd::qi3d); // budget equation: transfer cloud ice to vapor
919  morr_arr(i,j,k,MORRInd::t3d) -= morr_arr(i,j,k,MORRInd::qi3d) * morr_arr(i,j,k,MORRInd::xxls) / morr_arr(i,j,k,MORRInd::cpm); // budget equation: adjust temperature
920  morr_arr(i,j,k,MORRInd::qi3d) = Real(0); // temporary update: set cloud ice to Real(0)
921  }
922  if (morr_arr(i,j,k,MORRInd::qni3d) < Real(1.0e-8)) {
923  morr_arr(i,j,k,MORRInd::qv3d) += morr_arr(i,j,k,MORRInd::qni3d); // budget equation: transfer snow to vapor
924  morr_arr(i,j,k,MORRInd::t3d) -= morr_arr(i,j,k,MORRInd::qni3d) * morr_arr(i,j,k,MORRInd::xxls) / morr_arr(i,j,k,MORRInd::cpm); // budget equation: adjust temperature
925  morr_arr(i,j,k,MORRInd::qni3d) = Real(0); // temporary update: set snow to Real(0)
926  }
927  if (morr_arr(i,j,k,MORRInd::qg3d) < Real(1.0e-8)) {
928  morr_arr(i,j,k,MORRInd::qv3d) += morr_arr(i,j,k,MORRInd::qg3d); // budget equation: transfer graupel to vapor
929  morr_arr(i,j,k,MORRInd::t3d) -= morr_arr(i,j,k,MORRInd::qg3d) * morr_arr(i,j,k,MORRInd::xxls) / morr_arr(i,j,k,MORRInd::cpm); // budget equation: adjust temperature
930  morr_arr(i,j,k,MORRInd::qg3d) = Real(0); // temporary update: set graupel to Real(0)
931  }
932  }
933  // HEAT OF FUSION
934  morr_arr(i,j,k,MORRInd::xlf) = morr_arr(i,j,k,MORRInd::xxls) - morr_arr(i,j,k,MORRInd::xxlv);
935 
936  // IF MIXING RATIO < QSMALL SET MIXING RATIO AND NUMBER CONC TO ZERO
937  // Note: QSMALL is not defined in the variable list, so I'll define it
938  const Real QSMALL = m_qsmall;
939 
940  if (morr_arr(i,j,k,MORRInd::qc3d) < QSMALL) {
941  morr_arr(i,j,k,MORRInd::qc3d) = Real(0);
942  morr_arr(i,j,k,MORRInd::nc3d) = Real(0);
943  morr_arr(i,j,k,MORRInd::effc) = Real(0);
944  }
945  if (morr_arr(i,j,k,MORRInd::qr3d) < QSMALL) {
946  morr_arr(i,j,k,MORRInd::qr3d) = Real(0);
947  morr_arr(i,j,k,MORRInd::nr3d) = Real(0);
948  morr_arr(i,j,k,MORRInd::effr) = Real(0);
949  }
950  if (morr_arr(i,j,k,MORRInd::qi3d) < QSMALL) {
951  morr_arr(i,j,k,MORRInd::qi3d) = Real(0);
952  morr_arr(i,j,k,MORRInd::ni3d) = Real(0);
953  morr_arr(i,j,k,MORRInd::effi) = Real(0);
954  }
955  if (morr_arr(i,j,k,MORRInd::qni3d) < QSMALL) {
956  morr_arr(i,j,k,MORRInd::qni3d) = Real(0);
957  morr_arr(i,j,k,MORRInd::ns3d) = Real(0);
958  morr_arr(i,j,k,MORRInd::effs) = Real(0);
959  }
960  if (morr_arr(i,j,k,MORRInd::qg3d) < QSMALL) {
961  morr_arr(i,j,k,MORRInd::qg3d) = Real(0);
962  morr_arr(i,j,k,MORRInd::ng3d) = Real(0);
963  morr_arr(i,j,k,MORRInd::effg) = Real(0);
964  }
965  // INITIALIZE SEDIMENTATION TENDENCIES FOR MIXING RATIO
966  morr_arr(i,j,k,MORRInd::qrsten) = Real(0); // temporary update: initialize QRSTEN
967  morr_arr(i,j,k,MORRInd::qisten) = Real(0); // temporary update: initialize QISTEN
968  morr_arr(i,j,k,MORRInd::qnisten) = Real(0); // temporary update: initialize QNISTEN
969  morr_arr(i,j,k,MORRInd::qcsten) = Real(0); // temporary update: initialize QCSTEN
970  morr_arr(i,j,k,MORRInd::qgsten) = Real(0); // temporary update: initialize QGSTEN
971 
972  // MICROPHYSICS PARAMETERS VARYING IN TIME/HEIGHT
973  morr_arr(i,j,k,MORRInd::mu) = Real(1.496e-6) * std::pow(morr_arr(i,j,k,MORRInd::t3d), Real(1.5)) / (morr_arr(i,j,k,MORRInd::t3d) + Real(120.0)); // budget equation: calculate air viscosity
974 
975  // Fall speed with density correction (Heymsfield and Benssemer 2006)
976  dum = std::pow(m_rhosu / morr_arr(i,j,k,MORRInd::rho), Real(0.54)); // temporary update: calculate density correction factor
977 
978  // AA revision 4/1/11: Ikawa and Saito 1991 air-density correction
979  morr_arr(i,j,k,MORRInd::ain) = std::pow(m_rhosu / morr_arr(i,j,k,MORRInd::rho), Real(0.35)) * m_ai; // budget equation: calculate ice fall speed parameter
980  morr_arr(i,j,k,MORRInd::arn) = dum * m_ar; // budget equation: calculate rain fall speed parameter
981  morr_arr(i,j,k,MORRInd::asn) = dum * m_as; // budget equation: calculate snow fall speed parameter
982 
983  // AA revision 4/1/11: temperature-dependent Stokes fall speed
984  morr_arr(i,j,k,MORRInd::acn) = m_g * m_rhow / (Real(18.0) * morr_arr(i,j,k,MORRInd::mu)); // budget equation: calculate cloud droplet fall speed parameter
985 
986  // HM ADD GRAUPEL 8/28/06
987  morr_arr(i,j,k,MORRInd::agn) = dum * m_ag; // budget equation: calculate graupel fall speed parameter
988  // hm 4/7/09 bug fix, initialize morr_arr(i,j,k,MORRInd::lami) to prevent later division by Real(0)
989  morr_arr(i,j,k,MORRInd::lami) = Real(0); // temporary update: initialize LAMI
990 
991  // If there is no cloud/precip water, and if subsaturated, then skip microphysics for this level
992  bool skipMicrophysics = false;
993  bool skipConcentrations = false;
994  if (morr_arr(i,j,k,MORRInd::qc3d) < QSMALL && morr_arr(i,j,k,MORRInd::qi3d) < QSMALL && morr_arr(i,j,k,MORRInd::qni3d) < QSMALL && morr_arr(i,j,k,MORRInd::qr3d) < QSMALL && morr_arr(i,j,k,MORRInd::qg3d) < QSMALL) {
995  if ((morr_arr(i,j,k,MORRInd::t3d) < Real(273.15) && qvqvsi < Real(0.999)) || (morr_arr(i,j,k,MORRInd::t3d) >= Real(273.15) && qvqvs < Real(0.999))) {
996  skipMicrophysics = true;// goto label_200;
997  }
998  }
999 
1000  if(!skipMicrophysics) {
1001 
1002  // Thermal conductivity for air
1003  kap = Real(1.414e3) * morr_arr(i,j,k,MORRInd::mu); // budget equation: calculate thermal conductivity
1004 
1005  // Diffusivity of water vapor
1006  dv = Real(8.794e-5) * std::pow(morr_arr(i,j,k,MORRInd::t3d), Real(1.81)) / morr_arr(i,j,k,MORRInd::pres); // budget equation: calculate vapor diffusivity
1007 
1008  // Schmidt number
1009  sc_schmidt = morr_arr(i,j,k,MORRInd::mu) / (morr_arr(i,j,k,MORRInd::rho) * dv); // budget equation: calculate Schmidt number
1010 
1011  // Psychometric corrections
1012  // Rate of change sat. mix. ratio with temperature
1013  dum = (m_Rv * amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::t3d))); // temporary update: calculate temperature factor
1014  dqsdt = morr_arr(i,j,k,MORRInd::xxlv) * qvs / dum; // budget equation: calculate DQSDT
1015  dqsidt = morr_arr(i,j,k,MORRInd::xxls) * qvi / dum; // budget equation: calculate DQSIDT
1016  abi = one + dqsidt * morr_arr(i,j,k,MORRInd::xxls) / morr_arr(i,j,k,MORRInd::cpm); // budget equation: calculate ABI
1017  ab = one + dqsdt * morr_arr(i,j,k,MORRInd::xxlv) / morr_arr(i,j,k,MORRInd::cpm); // budget equation: calculate AB
1018 
1019  // CASE FOR TEMPERATURE ABOVE FREEZING
1020  if (morr_arr(i,j,k,MORRInd::t3d) >= Real(273.15)) {
1021  //......................................................................
1022  // ALLOW FOR CONSTANT DROPLET NUMBER
1023  // INUM = 0, PREDICT DROPLET NUMBER
1024  // INUM = 1, SET CONSTANT DROPLET NUMBER
1025 
1026  if (m_inum == 1) {
1027  // CONVERT NDCNST FROM CM-3 TO KG-1
1028  // Note: NDCNST constant would need to be defined elsewhere
1029  morr_arr(i,j,k,MORRInd::nc3d) = m_ndcnst * Real(1.0e6) / morr_arr(i,j,k,MORRInd::rho); // Set cloud droplet number concentration
1030  }
1031 
1032  // GET SIZE DISTRIBUTION PARAMETERS
1033  // MELT VERY SMALL SNOW AND GRAUPEL MIXING RATIOS, ADD TO RAIN
1034  if (morr_arr(i,j,k,MORRInd::qni3d) < Real(1.0e-6)) {
1035  morr_arr(i,j,k,MORRInd::qr3d) = morr_arr(i,j,k,MORRInd::qr3d) + morr_arr(i,j,k,MORRInd::qni3d); // Transfer snow to rain
1036  morr_arr(i,j,k,MORRInd::nr3d) = morr_arr(i,j,k,MORRInd::nr3d) + morr_arr(i,j,k,MORRInd::ns3d); // Transfer snow number to rain
1037  morr_arr(i,j,k,MORRInd::t3d) = morr_arr(i,j,k,MORRInd::t3d) - morr_arr(i,j,k,MORRInd::qni3d) * morr_arr(i,j,k,MORRInd::xlf) / morr_arr(i,j,k,MORRInd::cpm); // Adjust temperature
1038  morr_arr(i,j,k,MORRInd::qni3d) = Real(0); // Set snow to Real(0)
1039  morr_arr(i,j,k,MORRInd::ns3d) = Real(0); // Set snow number to Real(0)
1040  }
1041 
1042  if (morr_arr(i,j,k,MORRInd::qg3d) < Real(1.0e-6)) {
1043  morr_arr(i,j,k,MORRInd::qr3d) = morr_arr(i,j,k,MORRInd::qr3d) + morr_arr(i,j,k,MORRInd::qg3d); // Transfer graupel to rain
1044  morr_arr(i,j,k,MORRInd::nr3d) = morr_arr(i,j,k,MORRInd::nr3d) + morr_arr(i,j,k,MORRInd::ng3d); // Transfer graupel number to rain
1045  morr_arr(i,j,k,MORRInd::t3d) = morr_arr(i,j,k,MORRInd::t3d) - morr_arr(i,j,k,MORRInd::qg3d) * morr_arr(i,j,k,MORRInd::xlf) / morr_arr(i,j,k,MORRInd::cpm); // Adjust temperature
1046  morr_arr(i,j,k,MORRInd::qg3d) = Real(0); // Set graupel to Real(0)
1047  morr_arr(i,j,k,MORRInd::ng3d) = Real(0); // Set graupel number to Real(0)
1048  }
1049  // Skip to label 300 if concentrations are below thresholds
1050  if (morr_arr(i,j,k,MORRInd::qc3d) < m_qsmall && morr_arr(i,j,k,MORRInd::qni3d) < Real(1.0e-8) && morr_arr(i,j,k,MORRInd::qr3d) < m_qsmall && morr_arr(i,j,k,MORRInd::qg3d) < Real(1.0e-8)) {
1051  skipConcentrations=true;// goto label_300;
1052  }
1053  if(!skipConcentrations) {
1054  morr_arr(i,j,k,MORRInd::ns3d) = amrex::max(Real(0),morr_arr(i,j,k,MORRInd::ns3d));
1055  morr_arr(i,j,k,MORRInd::nc3d) = amrex::max(Real(0),morr_arr(i,j,k,MORRInd::nc3d));
1056  morr_arr(i,j,k,MORRInd::nr3d) = amrex::max(Real(0),morr_arr(i,j,k,MORRInd::nr3d));
1057  morr_arr(i,j,k,MORRInd::ng3d) = amrex::max(Real(0),morr_arr(i,j,k,MORRInd::ng3d));
1058 
1059  // ========================================================================
1060  // USING WRF APPROACH FOR SIZE DISTRIBUTION PARAMETERS
1061  // ========================================================================
1062  // Rain
1063  if (morr_arr(i,j,k,MORRInd::qr3d) >= m_qsmall) {
1064  // Calculate lambda parameter using cons26 (pi*rhow/6)
1065  morr_arr(i,j,k,MORRInd::lamr) = std::pow(m_pi * m_rhow * morr_arr(i,j,k,MORRInd::nr3d) / morr_arr(i,j,k,MORRInd::qr3d), one/three);
1066  morr_arr(i,j,k,MORRInd::n0r) = morr_arr(i,j,k,MORRInd::nr3d)*morr_arr(i,j,k,MORRInd::lamr);
1067 
1068  // Check for slope and adjust vars
1069  if (morr_arr(i,j,k,MORRInd::lamr) < m_lamminr) {
1070  morr_arr(i,j,k,MORRInd::lamr) = m_lamminr;
1071  morr_arr(i,j,k,MORRInd::n0r) = std::pow(morr_arr(i,j,k,MORRInd::lamr), Real(4.0)) * morr_arr(i,j,k,MORRInd::qr3d) / (m_pi * m_rhow);
1072  morr_arr(i,j,k,MORRInd::nr3d) = morr_arr(i,j,k,MORRInd::n0r) / morr_arr(i,j,k,MORRInd::lamr); // Update number concentration
1073  } else if (morr_arr(i,j,k,MORRInd::lamr) > m_lammaxr) {
1074  morr_arr(i,j,k,MORRInd::lamr) = m_lammaxr;
1075  morr_arr(i,j,k,MORRInd::n0r) = std::pow(morr_arr(i,j,k,MORRInd::lamr), Real(4.0)) * morr_arr(i,j,k,MORRInd::qr3d) / (m_pi * m_rhow);
1076  morr_arr(i,j,k,MORRInd::nr3d) = morr_arr(i,j,k,MORRInd::n0r) / morr_arr(i,j,k,MORRInd::lamr); // Update number concentration
1077  }
1078  }
1079 
1080  // Cloud droplets
1081  if (morr_arr(i,j,k,MORRInd::qc3d) >= m_qsmall) {
1082  // Calculate air density factor (moist air density)
1083  dum = morr_arr(i,j,k,MORRInd::pres)/(Real(287.15)*morr_arr(i,j,k,MORRInd::t3d));
1084 
1085  // MARTIN ET AL. (1994) FORMULA FOR PGAM (WRF implementation)
1086  morr_arr(i,j,k,MORRInd::pgam) = Real(0.0005714)*(morr_arr(i,j,k,MORRInd::nc3d)/Real(1.0e6)*dum) + Real(0.2714);
1087  morr_arr(i,j,k,MORRInd::pgam) = one/(morr_arr(i,j,k,MORRInd::pgam)*morr_arr(i,j,k,MORRInd::pgam)) - one;
1088  morr_arr(i,j,k,MORRInd::pgam) = amrex::max(morr_arr(i,j,k,MORRInd::pgam), Real(2));
1089  morr_arr(i,j,k,MORRInd::pgam) = amrex::min(morr_arr(i,j,k,MORRInd::pgam), Real(10.0));
1090 
1091  // Calculate gamma function values
1092  Real gamma_pgam_plus_1 = gamma_function(morr_arr(i,j,k,MORRInd::pgam) + one);
1093  Real gamma_pgam_plus_4 = gamma_function(morr_arr(i,j,k,MORRInd::pgam) + Real(4.0));
1094 
1095  // Calculate lambda parameter
1096  morr_arr(i,j,k,MORRInd::lamc) = std::pow((m_cons26 * morr_arr(i,j,k,MORRInd::nc3d) * gamma_pgam_plus_4) / (morr_arr(i,j,k,MORRInd::qc3d) * gamma_pgam_plus_1), one/three);
1097 
1098  // Lambda bounds from WRF - 60 micron max diameter, 1 micron min diameter
1099  Real lambda_min = (morr_arr(i,j,k,MORRInd::pgam) + one)/Real(60.0e-6);
1100  Real lambda_max = (morr_arr(i,j,k,MORRInd::pgam) + one)/Real(1.0e-6);
1101 
1102  // Check bounds and update number concentration if needed
1103  if (morr_arr(i,j,k,MORRInd::lamc) < lambda_min) {
1104  morr_arr(i,j,k,MORRInd::lamc) = lambda_min;
1105  // Update cloud droplet number using the same formula as in WRF
1106  morr_arr(i,j,k,MORRInd::nc3d) = std::exp(three*std::log(morr_arr(i,j,k,MORRInd::lamc)) + std::log(morr_arr(i,j,k,MORRInd::qc3d)) +
1107  std::log(gamma_pgam_plus_1) - std::log(gamma_pgam_plus_4))/ m_cons26;
1108  } else if (morr_arr(i,j,k,MORRInd::lamc) > lambda_max) {
1109  morr_arr(i,j,k,MORRInd::lamc) = lambda_max;
1110  // Update cloud droplet number using the same formula as in WRF
1111  morr_arr(i,j,k,MORRInd::nc3d) = std::exp(three*std::log(morr_arr(i,j,k,MORRInd::lamc)) + std::log(morr_arr(i,j,k,MORRInd::qc3d)) +
1112  std::log(gamma_pgam_plus_1) - std::log(gamma_pgam_plus_4))/ m_cons26;
1113  }
1114 
1115  // Calculate intercept parameter
1116  morr_arr(i,j,k,MORRInd::cdist1) = morr_arr(i,j,k,MORRInd::nc3d) / gamma_pgam_plus_1;
1117  }
1118 
1119  // Snow
1120  if (morr_arr(i,j,k,MORRInd::qni3d) >= m_qsmall) {
1121  // Calculate lambda parameter
1122  morr_arr(i,j,k,MORRInd::lams) = std::pow(m_cons1 * morr_arr(i,j,k,MORRInd::ns3d) / morr_arr(i,j,k,MORRInd::qni3d), one/ds0);
1123 
1124  // Calculate intercept parameter
1125  morr_arr(i,j,k,MORRInd::n0s) = morr_arr(i,j,k,MORRInd::ns3d) * morr_arr(i,j,k,MORRInd::lams);
1126 
1127  // Check for slope and adjust vars
1128  if (morr_arr(i,j,k,MORRInd::lams) < m_lammins) {
1129  morr_arr(i,j,k,MORRInd::lams) = m_lammins;
1130  morr_arr(i,j,k,MORRInd::n0s) = std::pow(morr_arr(i,j,k,MORRInd::lams), Real(4.0)) * morr_arr(i,j,k,MORRInd::qni3d) / m_cons1;
1131  morr_arr(i,j,k,MORRInd::ns3d) = morr_arr(i,j,k,MORRInd::n0s) / morr_arr(i,j,k,MORRInd::lams); // Update number concentration
1132  } else if (morr_arr(i,j,k,MORRInd::lams) > m_lammaxs) {
1133  morr_arr(i,j,k,MORRInd::lams) = m_lammaxs;
1134  morr_arr(i,j,k,MORRInd::n0s) = std::pow(morr_arr(i,j,k,MORRInd::lams), Real(4.0)) * morr_arr(i,j,k,MORRInd::qni3d) / m_cons1;
1135  morr_arr(i,j,k,MORRInd::ns3d) = morr_arr(i,j,k,MORRInd::n0s) / morr_arr(i,j,k,MORRInd::lams); // Update number concentration
1136  }
1137  }
1138 
1139  // Graupel
1140  if (morr_arr(i,j,k,MORRInd::qg3d) >= m_qsmall) {
1141  // Calculate lambda parameter
1142  morr_arr(i,j,k,MORRInd::lamg) = std::pow(m_cons2 * morr_arr(i,j,k,MORRInd::ng3d) / morr_arr(i,j,k,MORRInd::qg3d), one/dg0);
1143 
1144  // Calculate intercept parameter
1145  morr_arr(i,j,k,MORRInd::n0g) = morr_arr(i,j,k,MORRInd::ng3d) * morr_arr(i,j,k,MORRInd::lamg);
1146 
1147  // Check for slope and adjust vars
1148  if (morr_arr(i,j,k,MORRInd::lamg) < m_lamming) {
1149  morr_arr(i,j,k,MORRInd::lamg) = m_lamming;
1150  morr_arr(i,j,k,MORRInd::n0g) = std::pow(morr_arr(i,j,k,MORRInd::lamg), Real(4.0)) * morr_arr(i,j,k,MORRInd::qg3d) / m_cons2;
1151  morr_arr(i,j,k,MORRInd::ng3d) = morr_arr(i,j,k,MORRInd::n0g) / morr_arr(i,j,k,MORRInd::lamg); // Update number concentration
1152  } else if (morr_arr(i,j,k,MORRInd::lamg) > m_lammaxg) {
1153  morr_arr(i,j,k,MORRInd::lamg) = m_lammaxg;
1154  morr_arr(i,j,k,MORRInd::n0g) = std::pow(morr_arr(i,j,k,MORRInd::lamg), Real(4.0)) * morr_arr(i,j,k,MORRInd::qg3d) / m_cons2;
1155  morr_arr(i,j,k,MORRInd::ng3d) = morr_arr(i,j,k,MORRInd::n0g) / morr_arr(i,j,k,MORRInd::lamg); // Update number concentration
1156  }
1157  }
1158  ////////////////////// First instance of ZERO OUT PROCESS RATES
1159  // Zero out process rates
1160  prc = Real(0); // Cloud water to rain conversion rate (PRC)
1161  nprc = Real(0); // Change in cloud droplet number due to autoconversion (NPRC)
1162  nprc1 = Real(0); // Change in rain number due to autoconversion (NPRC1)
1163  pra = Real(0); // Accretion of cloud water by rain (PRA)
1164  npra = Real(0); // Change in cloud droplet number due to accretion by rain (NPRA)
1165  nragg = Real(0); // Self-collection/breakup of rain (NRAGG)
1166  nsmlts = Real(0); // Loss of snow number during melting (NSMLTS)
1167  nsmltr = Real(0); // Change in rain number due to snow melting (NSMLTR)
1168  evpms = Real(0); // Melting snow evaporation rate (EVPMS)
1169  pcc = Real(0); // Condensation/evaporation of cloud water (PCC)
1170  pre = Real(0); // Evaporation of rain (PRE)
1171  // nsubc = Real(0); // Loss of cloud droplet number during evaporation (NSUBC)
1172  nsubr = Real(0); // Loss of rain number during evaporation (NSUBR)
1173  pracg = Real(0); // Collection of rain by graupel (PRACG)
1174  npracg = Real(0); // Change in number due to collection of rain by graupel (NPRACG)
1175  psmlt = Real(0); // Melting of snow (PSMLT)
1176  pgmlt = Real(0); // Melting of graupel (PGMLT)
1177  evpmg = Real(0); // Evaporation of melting graupel (EVPMG)
1178  pracs = Real(0); // Collection of snow by rain (PRACS)
1179  npracs = Real(0); // Change in number due to collection of snow by rain (NPRACS)
1180  ngmltg = Real(0); // Loss of graupel number during melting (NGMLTG)
1181  ngmltr = Real(0); // Change in rain number due to graupel melting (NGMLTR)
1182 
1183  // CALCULATION OF MICROPHYSICAL PROCESS RATES, T > Real(273.15) K
1184 
1185  // AUTOCONVERSION OF CLOUD LIQUID WATER TO RAIN
1186  // FORMULA FROM BEHENG (1994)
1187  // USING NUMERICAL SIMULATION OF STOCHASTIC COLLECTION EQUATION
1188  // AND INITIAL CLOUD DROPLET SIZE DISTRIBUTION SPECIFIED
1189  // AS A GAMMA DISTRIBUTION
1190 
1191  // USE MINIMUM VALUE OF Real(1.E-6) TO PREVENT FLOATING POINT ERROR
1192 
1193  if (morr_arr(i,j,k,MORRInd::qc3d) >= Real(1.0e-6)) {
1194  // HM ADD 12/13/06, REPLACE WITH NEWER FORMULA
1195  // FROM KHAIROUTDINOV AND KOGAN 2000, MWR
1196  prc = Real(1350.0) * std::pow(morr_arr(i,j,k,MORRInd::qc3d), Real(2.47)) *
1197  std::pow((morr_arr(i,j,k,MORRInd::nc3d)/Real(1.0e6)*morr_arr(i,j,k,MORRInd::rho)), -Real(1.79));
1198 
1199  // note: nprc1 is change in Nr,
1200  // nprc is change in Nc
1201  nprc1 = prc / m_cons29;
1202  nprc = prc / (morr_arr(i,j,k,MORRInd::qc3d) / morr_arr(i,j,k,MORRInd::nc3d));
1203 
1204  // hm bug fix 3/20/12
1205  nprc = std::min(nprc, morr_arr(i,j,k,MORRInd::nc3d) / dt);
1206  nprc1 = std::min(nprc1, nprc);
1207  }
1208 
1209  // HM ADD 12/13/06, COLLECTION OF SNOW BY RAIN ABOVE FREEZING
1210  // FORMULA FROM IKAWA AND SAITO (1991)
1211 
1212  if (morr_arr(i,j,k,MORRInd::qr3d) >= Real(1.0e-8) && morr_arr(i,j,k,MORRInd::qni3d) >= Real(1.0e-8)) {
1213  Real ums_local = morr_arr(i,j,k,MORRInd::asn) * m_cons3 / std::pow(morr_arr(i,j,k,MORRInd::lams), m_bs);
1214  Real umr_local = morr_arr(i,j,k,MORRInd::arn) * m_cons4 / std::pow(morr_arr(i,j,k,MORRInd::lamr), m_br);
1215  Real uns_local = morr_arr(i,j,k,MORRInd::asn) * m_cons5 / std::pow(morr_arr(i,j,k,MORRInd::lams), m_bs);
1216  Real unr_local = morr_arr(i,j,k,MORRInd::arn) * m_cons6 / std::pow(morr_arr(i,j,k,MORRInd::lamr), m_br);
1217 
1218  // SET REALISTIC LIMITS ON FALLSPEEDS
1219  // bug fix, 10/08/09
1220  dum = std::pow(m_rhosu/morr_arr(i,j,k,MORRInd::rho), Real(0.54));
1221  ums_local = std::min(ums_local, Real(1.2)*dum);
1222  uns_local = std::min(uns_local, Real(1.2)*dum);
1223  umr_local = std::min(umr_local, Real(9.1)*dum);
1224  unr_local = std::min(unr_local, Real(9.1)*dum);
1225 
1226 
1227  // hm fix, 2/12/13
1228  // for above freezing conditions to get accelerated melting of snow,
1229  // we need collection of rain by snow (following Lin et al. 1983)
1230  ////////////////////////Might needstd::pow expanding
1231  pracs = m_cons41 * (std::sqrt(amrex::Math::powi<2>(Real(1.2)*umr_local-Real(0.95)*ums_local) +
1232  Real(0.08)*ums_local*umr_local) * morr_arr(i,j,k,MORRInd::rho) *
1233  morr_arr(i,j,k,MORRInd::n0r) * morr_arr(i,j,k,MORRInd::n0s) / amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr)) *
1234  (Real(5.0)/(amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr)) * morr_arr(i,j,k,MORRInd::lams)) +
1235  Real(2)/(amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lamr)) * amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lams))) +
1236  myhalf/(morr_arr(i,j,k,MORRInd::lamr) * amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lams)))));
1237  }
1238  // ADD COLLECTION OF GRAUPEL BY RAIN ABOVE FREEZING
1239  // ASSUME ALL RAIN COLLECTION BY GRAUPEL ABOVE FREEZING IS SHED
1240  // ASSUME SHED DROPS ARE 1 MM IN SIZE
1241 
1242  if (morr_arr(i,j,k,MORRInd::qr3d) >= Real(1.0e-8) && morr_arr(i,j,k,MORRInd::qg3d) >= Real(1.0e-8)) {
1243 
1244  Real umg_local = morr_arr(i,j,k,MORRInd::agn) * m_cons7 / std::pow(morr_arr(i,j,k,MORRInd::lamg), m_bg);
1245  Real umr_local = morr_arr(i,j,k,MORRInd::arn) * m_cons4 / std::pow(morr_arr(i,j,k,MORRInd::lamr), m_br);
1246  Real ung_local = morr_arr(i,j,k,MORRInd::agn) * m_cons8 / std::pow(morr_arr(i,j,k,MORRInd::lamg), m_bg);
1247  Real unr_local = morr_arr(i,j,k,MORRInd::arn) * m_cons6 / std::pow(morr_arr(i,j,k,MORRInd::lamr), m_br);
1248 
1249  // SET REALISTIC LIMITS ON FALLSPEEDS
1250  // bug fix, 10/08/09
1251  dum = std::pow(m_rhosu/morr_arr(i,j,k,MORRInd::rho), Real(0.54));
1252  umg_local = std::min(umg_local, Real(20.0)*dum);
1253  ung_local = std::min(ung_local, Real(20.0)*dum);
1254  umr_local = std::min(umr_local, Real(9.1)*dum);
1255  unr_local = std::min(unr_local, Real(9.1)*dum);
1256 
1257  // PRACG IS MIXING RATIO OF RAIN PER SEC COLLECTED BY GRAUPEL/HAIL
1258  pracg = m_cons41 * (std::sqrt(amrex::Math::powi<2>(Real(1.2)*umr_local-Real(0.95)*umg_local) +
1259  Real(0.08)*umg_local*umr_local) * morr_arr(i,j,k,MORRInd::rho) *
1260  morr_arr(i,j,k,MORRInd::n0r) * morr_arr(i,j,k,MORRInd::n0g) / amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr)) *
1261  (Real(5.0)/(amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr)) * morr_arr(i,j,k,MORRInd::lamg)) +
1262  Real(2)/(amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lamr)) * amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lamg))) +
1263  myhalf/(morr_arr(i,j,k,MORRInd::lamr) * amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamg)))));
1264 
1265  // ASSUME 1 MM DROPS ARE SHED, GET NUMBER SHED PER SEC
1266  dum = pracg/Real(5.2e-7);
1267 
1268  npracg = m_cons32 * morr_arr(i,j,k,MORRInd::rho) * (std::sqrt(Real(1.7)*amrex::Math::powi<2>(unr_local-ung_local) +
1269  Real(0.3)*unr_local*ung_local) * morr_arr(i,j,k,MORRInd::n0r) * morr_arr(i,j,k,MORRInd::n0g) *
1270  (one/(amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr)) * morr_arr(i,j,k,MORRInd::lamg)) +
1271  one/(amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lamr)) * amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lamg))) +
1272  one/(morr_arr(i,j,k,MORRInd::lamr) * amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamg)))));
1273  // hm 7/15/13, remove limit so that the number of collected drops can smaller than
1274  // number of shed drops
1275  npracg = npracg - dum;
1276  }
1277  // ACCRETION OF CLOUD LIQUID WATER BY RAIN
1278  // CONTINUOUS COLLECTION EQUATION WITH
1279  // GRAVITATIONAL COLLECTION KERNEL, DROPLET FALL SPEED NEGLECTED
1280 
1281  if (morr_arr(i,j,k,MORRInd::qr3d) >= Real(1.0e-8) && morr_arr(i,j,k,MORRInd::qc3d) >= Real(1.0e-8)) {
1282  // 12/13/06 HM ADD, REPLACE WITH NEWER FORMULA FROM
1283  // KHAIROUTDINOV AND KOGAN 2000, MWR
1284  dum = morr_arr(i,j,k,MORRInd::qc3d) * morr_arr(i,j,k,MORRInd::qr3d);
1285  pra = Real(67.0) * std::pow(dum, Real(1.15));
1286  npra = pra / (morr_arr(i,j,k,MORRInd::qc3d) / morr_arr(i,j,k,MORRInd::nc3d));
1287  }
1288 
1289  // SELF-COLLECTION OF RAIN DROPS
1290  // FROM BEHENG(1994)
1291  // FROM NUMERICAL SIMULATION OF THE STOCHASTIC COLLECTION EQUATION
1292  // AS DESCRIBED ABOVE FOR AUTOCONVERSION
1293 
1294  if (morr_arr(i,j,k,MORRInd::qr3d) >= Real(1.0e-8)) {
1295  // include breakup add 10/09/09
1296  dum1 = Real(300.0e-6);
1297  if (one/morr_arr(i,j,k,MORRInd::lamr) < dum1) {
1298  dum = one;
1299  } else {
1300  dum = Real(2) - std::exp(Real(2300.0) * (one/morr_arr(i,j,k,MORRInd::lamr) - dum1));
1301  }
1302  nragg = -Real(5.78) * dum * morr_arr(i,j,k,MORRInd::nr3d) * morr_arr(i,j,k,MORRInd::qr3d) * morr_arr(i,j,k,MORRInd::rho);
1303  }
1304  // CALCULATE EVAP OF RAIN (RUTLEDGE AND HOBBS 1983)
1305  if (morr_arr(i,j,k,MORRInd::qr3d) >= m_qsmall) {
1306  epsr = Real(2) * m_pi * morr_arr(i,j,k,MORRInd::n0r) * morr_arr(i,j,k,MORRInd::rho) * dv *
1307  (m_f1r/(morr_arr(i,j,k,MORRInd::lamr)*morr_arr(i,j,k,MORRInd::lamr)) +
1308  m_f2r * std::sqrt(morr_arr(i,j,k,MORRInd::arn)*morr_arr(i,j,k,MORRInd::rho)/morr_arr(i,j,k,MORRInd::mu)) *
1309  std::pow(sc_schmidt, one/three) * m_cons9 /
1310  std::pow(morr_arr(i,j,k,MORRInd::lamr), m_cons34));
1311  } else {
1312  epsr = Real(0);
1313  }
1314  // NO CONDENSATION ONTO RAIN, ONLY EVAP ALLOWED
1315  if (morr_arr(i,j,k,MORRInd::qv3d) < qvs) {
1316  pre = epsr * (morr_arr(i,j,k,MORRInd::qv3d) - qvs) / ab;
1317  pre = std::min(pre, Real(0));
1318  } else {
1319  pre = Real(0);
1320  }
1321  // MELTING OF SNOW
1322  // SNOW MAY PERSIST ABOVE FREEZING, FORMULA FROM RUTLEDGE AND HOBBS, 1984
1323  // IF WATER SUPERSATURATION, SNOW MELTS TO FORM RAIN
1324 
1325  if (morr_arr(i,j,k,MORRInd::qni3d) >= Real(1.0e-8)) {
1326  // fix 053011
1327  // HM, MODIFY FOR V3.2, ADD ACCELERATED MELTING DUE TO COLLISION WITH RAIN
1328  dum = -m_cpw/morr_arr(i,j,k,MORRInd::xlf) * (morr_arr(i,j,k,MORRInd::t3d) - Real(273.15)) * pracs;
1329 
1330  // hm fix 1/20/15
1331  psmlt = Real(2) * m_pi * morr_arr(i,j,k,MORRInd::n0s) * kap * (Real(273.15) - morr_arr(i,j,k,MORRInd::t3d)) /
1332  morr_arr(i,j,k,MORRInd::xlf) * (m_f1s/(morr_arr(i,j,k,MORRInd::lams)*morr_arr(i,j,k,MORRInd::lams)) +
1333  m_f2s * std::sqrt(morr_arr(i,j,k,MORRInd::asn)*morr_arr(i,j,k,MORRInd::rho)/morr_arr(i,j,k,MORRInd::mu)) *
1334  std::pow(sc_schmidt, one/three) * m_cons10 /
1335  std::pow(morr_arr(i,j,k,MORRInd::lams), m_cons35)) + dum;
1336 
1337  // IN WATER SUBSATURATION, SNOW MELTS AND EVAPORATES
1338  if (qvqvs < one) {
1339  epss = Real(2) * m_pi * morr_arr(i,j,k,MORRInd::n0s) * morr_arr(i,j,k,MORRInd::rho) * dv *
1340  (m_f1s/(morr_arr(i,j,k,MORRInd::lams)*morr_arr(i,j,k,MORRInd::lams)) +
1341  m_f2s * std::sqrt(morr_arr(i,j,k,MORRInd::asn)*morr_arr(i,j,k,MORRInd::rho)/morr_arr(i,j,k,MORRInd::mu)) *
1342  std::pow(sc_schmidt, one/three) * m_cons10 /
1343  std::pow(morr_arr(i,j,k,MORRInd::lams), m_cons35));
1344 
1345  // hm fix 8/4/08
1346  evpms = (morr_arr(i,j,k,MORRInd::qv3d) - qvs) * epss / ab;
1347  evpms = std::max(evpms, psmlt);
1348  psmlt = psmlt - evpms;
1349  }
1350  }
1351  // MELTING OF GRAUPEL
1352  // GRAUPEL MAY PERSIST ABOVE FREEZING, FORMULA FROM RUTLEDGE AND HOBBS, 1984
1353  // IF WATER SUPERSATURATION, GRAUPEL MELTS TO FORM RAIN
1354 
1355  if (morr_arr(i,j,k,MORRInd::qg3d) >= Real(1.0e-8)) {
1356  // fix 053011
1357  // HM, MODIFY FOR V3.2, ADD ACCELERATED MELTING DUE TO COLLISION WITH RAIN
1358 
1359  dum = -m_cpw/morr_arr(i,j,k,MORRInd::xlf) * (morr_arr(i,j,k,MORRInd::t3d) - Real(273.15)) * pracg;
1360 
1361  // hm fix 1/20/15
1362  pgmlt = Real(2) * m_pi * morr_arr(i,j,k,MORRInd::n0g) * kap * (Real(273.15) - morr_arr(i,j,k,MORRInd::t3d)) /
1363  morr_arr(i,j,k,MORRInd::xlf) * (m_f1s/(morr_arr(i,j,k,MORRInd::lamg)*morr_arr(i,j,k,MORRInd::lamg)) +
1364  m_f2s * std::sqrt(morr_arr(i,j,k,MORRInd::agn)*morr_arr(i,j,k,MORRInd::rho)/morr_arr(i,j,k,MORRInd::mu)) *
1365  std::pow(sc_schmidt, one/three) * m_cons11 /
1366  std::pow(morr_arr(i,j,k,MORRInd::lamg), m_cons36)) + dum;
1367 
1368  // IN WATER SUBSATURATION, GRAUPEL MELTS AND EVAPORATES
1369  if (qvqvs < one) {
1370  epsg = Real(2) * m_pi * morr_arr(i,j,k,MORRInd::n0g) * morr_arr(i,j,k,MORRInd::rho) * dv *
1371  (m_f1s/(morr_arr(i,j,k,MORRInd::lamg)*morr_arr(i,j,k,MORRInd::lamg)) +
1372  m_f2s * std::sqrt(morr_arr(i,j,k,MORRInd::agn)*morr_arr(i,j,k,MORRInd::rho)/morr_arr(i,j,k,MORRInd::mu)) *
1373  std::pow(sc_schmidt, one/three) * m_cons11 /
1374  std::pow(morr_arr(i,j,k,MORRInd::lamg), m_cons36));
1375 
1376  // hm fix 8/4/08
1377  evpmg = (morr_arr(i,j,k,MORRInd::qv3d) - qvs) * epsg / ab;
1378  evpmg = std::max(evpmg, pgmlt);
1379  pgmlt = pgmlt - evpmg;
1380  }
1381  }
1382  // HM, V3.2
1383  // RESET PRACG AND PRACS TO ZERO, THIS IS DONE BECAUSE THERE IS NO
1384  // TRANSFER OF MASS FROM SNOW AND GRAUPEL TO RAIN DIRECTLY FROM COLLECTION
1385  // ABOVE FREEZING, IT IS ONLY USED FOR ENHANCEMENT OF MELTING AND SHEDDING
1386 
1387  pracg = Real(0);
1388  pracs = Real(0);
1389  // CONSERVATION OF QC
1390  dum = (prc + pra) * dt;
1391 
1392  if (dum > morr_arr(i,j,k,MORRInd::qc3d) && morr_arr(i,j,k,MORRInd::qc3d) >= m_qsmall) {
1393  ratio = morr_arr(i,j,k,MORRInd::qc3d) / dum;
1394  prc = prc * ratio;
1395  pra = pra * ratio;
1396  }
1397 
1398  // CONSERVATION OF SNOW
1399  dum = (-psmlt - evpms + pracs) * dt;
1400 
1401  if (dum > morr_arr(i,j,k,MORRInd::qni3d) && morr_arr(i,j,k,MORRInd::qni3d) >= m_qsmall) {
1402  // NO SOURCE TERMS FOR SNOW AT T > FREEZING
1403  ratio = morr_arr(i,j,k,MORRInd::qni3d) / dum;
1404  psmlt = psmlt * ratio;
1405  evpms = evpms * ratio;
1406  pracs = pracs * ratio;
1407  }
1408 
1409  // CONSERVATION OF GRAUPEL
1410  dum = (-pgmlt - evpmg + pracg) * dt;
1411 
1412  if (dum > morr_arr(i,j,k,MORRInd::qg3d) && morr_arr(i,j,k,MORRInd::qg3d) >= m_qsmall) {
1413  // NO SOURCE TERM FOR GRAUPEL ABOVE FREEZING
1414  ratio = morr_arr(i,j,k,MORRInd::qg3d) / dum;
1415  pgmlt = pgmlt * ratio;
1416  evpmg = evpmg * ratio;
1417  pracg = pracg * ratio;
1418  }
1419 
1420  // CONSERVATION OF QR
1421  // HM 12/13/06, ADDED CONSERVATION OF RAIN SINCE PRE IS NEGATIVE
1422 
1423  dum = (-pracs - pracg - pre - pra - prc + psmlt + pgmlt) * dt;
1424 
1425  if (dum > morr_arr(i,j,k,MORRInd::qr3d) && morr_arr(i,j,k,MORRInd::qr3d) >= m_qsmall) {
1426  ratio = (morr_arr(i,j,k,MORRInd::qr3d)/dt + pracs + pracg + pra + prc - psmlt - pgmlt) / (-pre);
1427  pre = pre * ratio;
1428  }
1429  // Update tendencies
1430  morr_arr(i,j,k,MORRInd::qv3dten) = morr_arr(i,j,k,MORRInd::qv3dten) + (-pre - evpms - evpmg);
1431 
1432  morr_arr(i,j,k,MORRInd::t3dten) = morr_arr(i,j,k,MORRInd::t3dten) + (pre * morr_arr(i,j,k,MORRInd::xxlv) +
1433  (evpms + evpmg) * morr_arr(i,j,k,MORRInd::xxls) +
1434  (psmlt + pgmlt - pracs - pracg) * morr_arr(i,j,k,MORRInd::xlf)) / morr_arr(i,j,k,MORRInd::cpm);
1435 
1436  morr_arr(i,j,k,MORRInd::qc3dten) = morr_arr(i,j,k,MORRInd::qc3dten) + (-pra - prc);
1437  morr_arr(i,j,k,MORRInd::qr3dten) = morr_arr(i,j,k,MORRInd::qr3dten) + (pre + pra + prc - psmlt - pgmlt + pracs + pracg);
1438  morr_arr(i,j,k,MORRInd::qni3dten) = morr_arr(i,j,k,MORRInd::qni3dten) + (psmlt + evpms - pracs);
1439  morr_arr(i,j,k,MORRInd::qg3dten) = morr_arr(i,j,k,MORRInd::qg3dten) + (pgmlt + evpmg - pracg);
1440 
1441  // fix 053011
1442  // HM, bug fix 5/12/08, npracg is subtracted from nr not ng
1443  morr_arr(i,j,k,MORRInd::nc3dten) = morr_arr(i,j,k,MORRInd::nc3dten) + (-npra - nprc);
1444  morr_arr(i,j,k,MORRInd::nr3dten) = morr_arr(i,j,k,MORRInd::nr3dten) + (nprc1 + nragg - npracg);
1445 
1446  // HM ADD, WRF-CHEM, ADD TENDENCIES FOR C2PREC
1447  // c2prec = pra + prc;
1448 
1449  if (pre < Real(0)) {
1450  dum = pre * dt / morr_arr(i,j,k,MORRInd::qr3d);
1451  dum = std::max(-one, dum);
1452  nsubr = dum * morr_arr(i,j,k,MORRInd::nr3d) / dt;
1453  }
1454 
1455  if (evpms + psmlt < Real(0)) {
1456  dum = (evpms + psmlt) * dt / morr_arr(i,j,k,MORRInd::qni3d);
1457  dum = std::max(-one, dum);
1458  nsmlts = dum * morr_arr(i,j,k,MORRInd::ns3d) / dt;
1459  }
1460 
1461  if (psmlt < Real(0)) {
1462  dum = psmlt * dt / morr_arr(i,j,k,MORRInd::qni3d);
1463  dum = std::max(-one, dum);
1464  nsmltr = dum * morr_arr(i,j,k,MORRInd::ns3d) / dt;
1465  }
1466 
1467  if (evpmg + pgmlt < Real(0)) {
1468  dum = (evpmg + pgmlt) * dt / morr_arr(i,j,k,MORRInd::qg3d);
1469  dum = std::max(-one, dum);
1470  ngmltg = dum * morr_arr(i,j,k,MORRInd::ng3d) / dt;
1471  }
1472 
1473  if (pgmlt < Real(0)) {
1474  dum = pgmlt * dt / morr_arr(i,j,k,MORRInd::qg3d);
1475  dum = std::max(-one, dum);
1476  ngmltr = dum * morr_arr(i,j,k,MORRInd::ng3d) / dt;
1477  }
1478 
1479  morr_arr(i,j,k,MORRInd::ns3dten) = morr_arr(i,j,k,MORRInd::ns3dten) + nsmlts;
1480  morr_arr(i,j,k,MORRInd::ng3dten) = morr_arr(i,j,k,MORRInd::ng3dten) + ngmltg;
1481  morr_arr(i,j,k,MORRInd::nr3dten) = morr_arr(i,j,k,MORRInd::nr3dten) + (nsubr - nsmltr - ngmltr);
1482 
1483  }
1484  //Right after 300 CONTINUE
1485 // label_300:
1486  if (do_cond) {
1487  // Calculate saturation adjustment to condense extra vapor above water saturation
1488  dumt = morr_arr(i,j,k,MORRInd::t3d) + dt * morr_arr(i,j,k,MORRInd::t3dten);
1489  dumqv = morr_arr(i,j,k,MORRInd::qv3d) + dt * morr_arr(i,j,k,MORRInd::qv3dten);
1490 
1491  // Fix for low pressure (added 5/12/10)
1492  dum = std::min(Real(0.99) * morr_arr(i,j,k,MORRInd::pres), calc_saturation_vapor_pressure(dumt, 0));
1493  dumqss = m_ep_2 * dum / (morr_arr(i,j,k,MORRInd::pres) - dum);
1494  dumqc = morr_arr(i,j,k,MORRInd::qc3d) + dt * morr_arr(i,j,k,MORRInd::qc3dten);
1495  dumqc = std::max(dumqc, Real(0));
1496 
1497  // Saturation adjustment for liquid
1498  dums = dumqv - dumqss;
1499  pcc = dums / (one + amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::xxlv)) * dumqss / (morr_arr(i,j,k,MORRInd::cpm) * m_Rv * amrex::Math::powi<2>(dumt))) / dt;
1500  if (pcc * dt + dumqc < Real(0)) {
1501  pcc = -dumqc / dt;
1502  }
1503 
1504  // Update tendencies
1505  morr_arr(i,j,k,MORRInd::qv3dten) -= pcc;
1506  morr_arr(i,j,k,MORRInd::t3dten) += pcc * morr_arr(i,j,k,MORRInd::xxlv) / morr_arr(i,j,k,MORRInd::cpm);
1507  morr_arr(i,j,k,MORRInd::qc3dten) += pcc;
1508  }
1509  } else { //cold
1510  //......................................................................
1511  // ALLOW FOR CONSTANT DROPLET NUMBER
1512  // INUM = 0, PREDICT DROPLET NUMBER
1513  // INUM = 1, SET CONSTANT DROPLET NUMBER
1514 
1515  if (m_inum == 1) {
1516  // CONVERT NDCNST FROM CM-3 TO KG-1
1517  // Note: NDCNST constant would need to be defined elsewhere
1518  morr_arr(i,j,k,MORRInd::nc3d) = m_ndcnst * Real(1.0e6) / morr_arr(i,j,k,MORRInd::rho); // Set cloud droplet number concentration
1519  }
1520 
1521  morr_arr(i,j,k,MORRInd::ni3d) = amrex::max(Real(0),morr_arr(i,j,k,MORRInd::ni3d));
1522  morr_arr(i,j,k,MORRInd::ns3d) = amrex::max(Real(0),morr_arr(i,j,k,MORRInd::ns3d));
1523  morr_arr(i,j,k,MORRInd::nc3d) = amrex::max(Real(0),morr_arr(i,j,k,MORRInd::nc3d));
1524  morr_arr(i,j,k,MORRInd::nr3d) = amrex::max(Real(0),morr_arr(i,j,k,MORRInd::nr3d));
1525  morr_arr(i,j,k,MORRInd::ng3d) = amrex::max(Real(0),morr_arr(i,j,k,MORRInd::ng3d));
1526 
1527  // ========================================================================
1528  // USING WRF APPROACH FOR SIZE DISTRIBUTION PARAMETERS
1529  // ========================================================================
1530  // Rain
1531  if (morr_arr(i,j,k,MORRInd::qr3d) >= m_qsmall) {
1532  // Calculate lambda parameter using cons26 (pi*rhow/6)
1533  morr_arr(i,j,k,MORRInd::lamr) = std::pow(m_pi * m_rhow * morr_arr(i,j,k,MORRInd::nr3d) / morr_arr(i,j,k,MORRInd::qr3d), one/three);
1534 
1535  // Check for slope and adjust vars
1536  if (morr_arr(i,j,k,MORRInd::lamr) < m_lamminr) {
1537  morr_arr(i,j,k,MORRInd::lamr) = m_lamminr;
1538  morr_arr(i,j,k,MORRInd::n0r) = std::pow(morr_arr(i,j,k,MORRInd::lamr), Real(4.0)) * morr_arr(i,j,k,MORRInd::qr3d) / (m_pi * m_rhow);
1539  morr_arr(i,j,k,MORRInd::nr3d) = morr_arr(i,j,k,MORRInd::n0r) / morr_arr(i,j,k,MORRInd::lamr); // Update number concentration
1540  } else if (morr_arr(i,j,k,MORRInd::lamr) > m_lammaxr) {
1541  morr_arr(i,j,k,MORRInd::lamr) = m_lammaxr;
1542  morr_arr(i,j,k,MORRInd::n0r) = std::pow(morr_arr(i,j,k,MORRInd::lamr), Real(4.0)) * morr_arr(i,j,k,MORRInd::qr3d) / (m_pi * m_rhow);
1543  morr_arr(i,j,k,MORRInd::nr3d) = morr_arr(i,j,k,MORRInd::n0r) / morr_arr(i,j,k,MORRInd::lamr); // Update number concentration
1544  } else {
1545  // Calculate intercept parameter using WRF formula
1546  morr_arr(i,j,k,MORRInd::n0r) = std::pow(morr_arr(i,j,k,MORRInd::lamr), Real(4.0)) * morr_arr(i,j,k,MORRInd::qr3d) / (m_pi * m_rhow);
1547  }
1548  }
1549 
1550 
1551  // Cloud droplets
1552  if (morr_arr(i,j,k,MORRInd::qc3d) >= m_qsmall) {
1553  // Calculate air density factor (moist air density)
1554  dum = morr_arr(i,j,k,MORRInd::pres)/(Real(287.15)*morr_arr(i,j,k,MORRInd::t3d));
1555 
1556  // MARTIN ET AL. (1994) FORMULA FOR PGAM (WRF implementation)
1557  morr_arr(i,j,k,MORRInd::pgam) = Real(0.0005714)*(morr_arr(i,j,k,MORRInd::nc3d)/Real(1.0e6)*dum) + Real(0.2714);
1558  morr_arr(i,j,k,MORRInd::pgam) = one/(amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::pgam))) - one;
1559  morr_arr(i,j,k,MORRInd::pgam) = amrex::max(morr_arr(i,j,k,MORRInd::pgam), Real(2));
1560  morr_arr(i,j,k,MORRInd::pgam) = amrex::min(morr_arr(i,j,k,MORRInd::pgam), Real(10.0));
1561 
1562  // Calculate gamma function values
1563  Real gamma_pgam_plus_1 = gamma_function(morr_arr(i,j,k,MORRInd::pgam) + one);
1564  Real gamma_pgam_plus_4 = gamma_function(morr_arr(i,j,k,MORRInd::pgam) + Real(4.0));
1565 
1566  // Calculate lambda parameter
1567  morr_arr(i,j,k,MORRInd::lamc) = std::pow((m_cons26 * morr_arr(i,j,k,MORRInd::nc3d) * gamma_pgam_plus_4) / (morr_arr(i,j,k,MORRInd::qc3d) * gamma_pgam_plus_1), one/three);
1568 
1569  // Lambda bounds from WRF - 60 micron max diameter, 1 micron min diameter
1570  Real lambda_min = (morr_arr(i,j,k,MORRInd::pgam) + one)/Real(60.0e-6);
1571  Real lambda_max = (morr_arr(i,j,k,MORRInd::pgam) + one)/Real(1.0e-6);
1572 
1573  // Check bounds and update number concentration if needed
1574  if (morr_arr(i,j,k,MORRInd::lamc) < lambda_min) {
1575  morr_arr(i,j,k,MORRInd::lamc) = lambda_min;
1576  // Update cloud droplet number using the same formula as in WRF
1577  morr_arr(i,j,k,MORRInd::nc3d) = std::exp(three*std::log(morr_arr(i,j,k,MORRInd::lamc)) + std::log(morr_arr(i,j,k,MORRInd::qc3d)) +
1578  std::log(gamma_pgam_plus_1) - std::log(gamma_pgam_plus_4))/ m_cons26;
1579  } else if (morr_arr(i,j,k,MORRInd::lamc) > lambda_max) {
1580  morr_arr(i,j,k,MORRInd::lamc) = lambda_max;
1581  // Update cloud droplet number using the same formula as in WRF
1582  morr_arr(i,j,k,MORRInd::nc3d) = std::exp(three*std::log(morr_arr(i,j,k,MORRInd::lamc)) + std::log(morr_arr(i,j,k,MORRInd::qc3d)) +
1583  std::log(gamma_pgam_plus_1) - std::log(gamma_pgam_plus_4))/ m_cons26;
1584  }
1585 
1586  // Calculate intercept parameter
1587  morr_arr(i,j,k,MORRInd::cdist1) = morr_arr(i,j,k,MORRInd::nc3d) / gamma_pgam_plus_1;
1588  }
1589 
1590  // Snow
1591  if (morr_arr(i,j,k,MORRInd::qni3d) >= m_qsmall) {
1592  // Calculate lambda parameter
1593  morr_arr(i,j,k,MORRInd::lams) = std::pow(m_cons1 * morr_arr(i,j,k,MORRInd::ns3d) / morr_arr(i,j,k,MORRInd::qni3d), one/ds0);
1594 
1595  // Calculate intercept parameter
1596  morr_arr(i,j,k,MORRInd::n0s) = morr_arr(i,j,k,MORRInd::ns3d) * morr_arr(i,j,k,MORRInd::lams);
1597 
1598  // Check for slope and adjust vars
1599  if (morr_arr(i,j,k,MORRInd::lams) < m_lammins) {
1600  morr_arr(i,j,k,MORRInd::lams) = m_lammins;
1601  morr_arr(i,j,k,MORRInd::n0s) = std::pow(morr_arr(i,j,k,MORRInd::lams), Real(4.0)) * morr_arr(i,j,k,MORRInd::qni3d) / m_cons1;
1602  morr_arr(i,j,k,MORRInd::ns3d) = morr_arr(i,j,k,MORRInd::n0s) / morr_arr(i,j,k,MORRInd::lams); // Update number concentration
1603  } else if (morr_arr(i,j,k,MORRInd::lams) > m_lammaxs) {
1604  morr_arr(i,j,k,MORRInd::lams) = m_lammaxs;
1605  morr_arr(i,j,k,MORRInd::n0s) = std::pow(morr_arr(i,j,k,MORRInd::lams), Real(4.0)) * morr_arr(i,j,k,MORRInd::qni3d) / m_cons1;
1606  morr_arr(i,j,k,MORRInd::ns3d) = morr_arr(i,j,k,MORRInd::n0s) / morr_arr(i,j,k,MORRInd::lams); // Update number concentration
1607  }
1608  }
1609 
1610  // Cloud ice
1611  if (morr_arr(i,j,k,MORRInd::qi3d) >= m_qsmall) {
1612  // Calculate lambda parameter
1613  morr_arr(i,j,k,MORRInd::lami) = std::pow(m_cons12 * morr_arr(i,j,k,MORRInd::ni3d) / morr_arr(i,j,k,MORRInd::qi3d), one/three);
1614 
1615  // Calculate intercept parameter (initial calculation)
1616  morr_arr(i,j,k,MORRInd::n0i) = morr_arr(i,j,k,MORRInd::ni3d) * morr_arr(i,j,k,MORRInd::lami);
1617 
1618  // Check for slope (apply bounds)
1619  if (morr_arr(i,j,k,MORRInd::lami) < m_lammini) {
1620  morr_arr(i,j,k,MORRInd::lami) = m_lammini;
1621  // Recalculate morr_arr(i,j,k,MORRInd::n0i) when lambda is adjusted
1622  morr_arr(i,j,k,MORRInd::n0i) = std::pow(morr_arr(i,j,k,MORRInd::lami), Real(4.0)) * morr_arr(i,j,k,MORRInd::qi3d) / m_cons12;
1623  // Update ni3d when lambda is adjusted
1624  morr_arr(i,j,k,MORRInd::ni3d) = morr_arr(i,j,k,MORRInd::n0i) / morr_arr(i,j,k,MORRInd::lami);
1625  } else if (morr_arr(i,j,k,MORRInd::lami) > m_lammaxi) {
1626  morr_arr(i,j,k,MORRInd::lami) = m_lammaxi;
1627  // Recalculate morr_arr(i,j,k,MORRInd::n0i) when lambda is adjusted
1628  morr_arr(i,j,k,MORRInd::n0i) = std::pow(morr_arr(i,j,k,MORRInd::lami), Real(4.0)) * morr_arr(i,j,k,MORRInd::qi3d) / m_cons12;
1629  // Update ni3d when lambda is adjusted
1630  morr_arr(i,j,k,MORRInd::ni3d) = morr_arr(i,j,k,MORRInd::n0i) / morr_arr(i,j,k,MORRInd::lami);
1631  }
1632  }
1633  // Graupel
1634  if (morr_arr(i,j,k,MORRInd::qg3d) >= m_qsmall) {
1635  // Calculate lambda parameter
1636  morr_arr(i,j,k,MORRInd::lamg) = std::pow(m_cons2 * morr_arr(i,j,k,MORRInd::ng3d) / morr_arr(i,j,k,MORRInd::qg3d), one/dg0);
1637 
1638  // Calculate intercept parameter
1639  morr_arr(i,j,k,MORRInd::n0g) = morr_arr(i,j,k,MORRInd::ng3d) * morr_arr(i,j,k,MORRInd::lamg);
1640 
1641  // Check for slope and adjust vars
1642  if (morr_arr(i,j,k,MORRInd::lamg) < m_lamming) {
1643  morr_arr(i,j,k,MORRInd::lamg) = m_lamming;
1644  morr_arr(i,j,k,MORRInd::n0g) = std::pow(morr_arr(i,j,k,MORRInd::lamg), Real(4.0)) * morr_arr(i,j,k,MORRInd::qg3d) / m_cons2;
1645  morr_arr(i,j,k,MORRInd::ng3d) = morr_arr(i,j,k,MORRInd::n0g) / morr_arr(i,j,k,MORRInd::lamg); // Update number concentration
1646  } else if (morr_arr(i,j,k,MORRInd::lamg) > m_lammaxg) {
1647  morr_arr(i,j,k,MORRInd::lamg) = m_lammaxg;
1648  morr_arr(i,j,k,MORRInd::n0g) = std::pow(morr_arr(i,j,k,MORRInd::lamg), Real(4.0)) * morr_arr(i,j,k,MORRInd::qg3d) / m_cons2;
1649  morr_arr(i,j,k,MORRInd::ng3d) = morr_arr(i,j,k,MORRInd::n0g) / morr_arr(i,j,k,MORRInd::lamg); // Update number concentration
1650  }
1651  }
1652  ////////////////////// Second instance of ZERO OUT PROCESS RATES
1653  // Zero out process rates
1654  mnuccc = Real(0); // Change Q due to contact freezing droplets (MNUCCC)
1655  nnuccc = Real(0); // Change N due to contact freezing droplets (NNUCCC)
1656  prc = Real(0); // Autoconversion droplets (PRC)
1657  nprc = Real(0); // Change NC autoconversion droplets (NPRC)
1658  nprc1 = Real(0); // Change NR autoconversion droplets (NPRC1)
1659  nsagg = Real(0); // Self-collection of snow (NSAGG)
1660  psacws = Real(0); // Change Q droplet accretion by snow (PSACWS)
1661  npsacws = Real(0); // Change N droplet accretion by snow (NPSACWS)
1662  psacwi = Real(0); // Change Q droplet accretion by cloud ice (PSACWI)
1663  npsacwi = Real(0); // Change N droplet accretion by cloud ice (NPSACWI)
1664  pracs = Real(0); // Change Q rain-snow collection (PRACS)
1665  npracs = Real(0); // Change N rain-snow collection (NPRACS)
1666  nmults = Real(0); // Ice multiplication due to riming droplets by snow (NMULTS)
1667  qmults = Real(0); // Change Q due to ice multiplication droplets/snow (QMULTS)
1668  nmultr = Real(0); // Ice multiplication due to riming rain by snow (NMULTR)
1669  qmultr = Real(0); // Change Q due to ice multiplication rain/snow (QMULTR)
1670  nmultg = Real(0); // Ice multiplication due to accretion droplets by graupel (NMULTG)
1671  qmultg = Real(0); // Change Q due to ice multiplication droplets/graupel (QMULTG)
1672  nmultrg = Real(0); // Ice multiplication due to accretion rain by graupel (NMULTRG)
1673  qmultrg = Real(0); // Change Q due to ice multiplication rain/graupel (QMULTRG)
1674  mnuccr = Real(0); // Change Q due to contact freezing rain (MNUCCR)
1675  nnuccr = Real(0); // Change N due to contact freezing rain (NNUCCR)
1676  pra = Real(0); // Accretion droplets by rain (PRA)
1677  npra = Real(0); // Change N due to droplet accretion by rain (NPRA)
1678  nragg = Real(0); // Self-collection/breakup of rain (NRAGG)
1679  prci = Real(0); // Change Q autoconversion cloud ice to snow (PRCI)
1680  nprci = Real(0); // Change N autoconversion cloud ice by snow (NPRCI)
1681  prai = Real(0); // Change Q accretion cloud ice by snow (PRAI)
1682  nprai = Real(0); // Change N accretion cloud ice (NPRAI)
1683  nnuccd = Real(0); // Change N freezing aerosol (primary ice nucleation) (NNUCCD)
1684  mnuccd = Real(0); // Change Q freezing aerosol (primary ice nucleation) (MNUCCD)
1685  pcc = Real(0); // Condensation/evaporation droplets (PCC)
1686  pre = Real(0); // Evaporation of rain (PRE)
1687  prd = Real(0); // Deposition cloud ice (PRD)
1688  prds = Real(0); // Deposition snow (PRDS)
1689  eprd = Real(0); // Sublimation cloud ice (EPRD)
1690  eprds = Real(0); // Sublimation snow (EPRDS)
1691  // nsubc = Real(0); // Loss of NC during evaporation (NSUBC)
1692  nsubi = Real(0); // Loss of NI during sublimation (NSUBI)
1693  nsubs = Real(0); // Loss of NS during sublimation (NSUBS)
1694  nsubr = Real(0); // Loss of NR during evaporation (NSUBR)
1695  piacr = Real(0); // Change QR, ice-rain collection (PIACR)
1696  niacr = Real(0); // Change N, ice-rain collection (NIACR)
1697  praci = Real(0); // Change QI, ice-rain collection (PRACI)
1698  piacrs = Real(0); // Change QR, ice rain collision, added to snow (PIACRS)
1699  niacrs = Real(0); // Change N, ice rain collision, added to snow (NIACRS)
1700  pracis = Real(0); // Change QI, ice rain collision, added to snow (PRACIS)
1701 
1702  // Graupel processes
1703  pracg = Real(0); // Change in Q collection rain by graupel (PRACG)
1704  psacr = Real(0); // Conversion due to collection of snow by rain (PSACR)
1705  psacwg = Real(0); // Change in Q collection droplets by graupel (PSACWG)
1706  pgsacw = Real(0); // Conversion Q to graupel due to collection droplets by snow (PGSACW)
1707  pgracs = Real(0); // Conversion Q to graupel due to collection rain by snow (PGRACS)
1708  prdg = Real(0); // Deposition of graupel (PRDG)
1709  eprdg = Real(0); // Sublimation of graupel (EPRDG)
1710  npracg = Real(0); // Change N collection rain by graupel (NPRACG)
1711  npsacwg = Real(0); // Change N collection droplets by graupel (NPSACWG)
1712  nscng = Real(0); // Change N conversion to graupel due to collection droplets by snow (NSCNG)
1713  ngracs = Real(0); // Change N conversion to graupel due to collection rain by snow (NGRACS)
1714  nsubg = Real(0); // Change N sublimation/deposition of graupel (NSUBG)
1715 
1716  ////////////////////// CALCULATION OF MICROPHYSICAL PROCESS RATES
1717  // FREEZING OF CLOUD DROPLETS - ONLY ALLOWED BELOW -4C
1718  if (morr_arr(i,j,k,MORRInd::qc3d) >= m_qsmall && morr_arr(i,j,k,MORRInd::t3d) < Real(269.15)) {
1719  // NUMBER OF CONTACT NUCLEI (M^-3) FROM MEYERS ET AL., 1992
1720  // FACTOR OF 1000 IS TO CONVERT FROM L^-1 TO M^-3
1721  // MEYERS CURVE
1722  Real nacnt = std::exp(-Real(2.80) + Real(0.262) * (Real(273.15) - morr_arr(i,j,k,MORRInd::t3d))) * Real(1000.0);
1723 
1724  // MEAN FREE PATH
1725  dum = Real(7.37) * morr_arr(i,j,k,MORRInd::t3d) / (Real(288.0) * Real(10.0) * morr_arr(i,j,k,MORRInd::pres)) / Real(100.0);
1726 
1727  // EFFECTIVE DIFFUSIVITY OF CONTACT NUCLEI
1728  // BASED ON BROWNIAN DIFFUSION
1729  Real dap = m_cons37 * morr_arr(i,j,k,MORRInd::t3d) * (one + dum / m_rin) / morr_arr(i,j,k,MORRInd::mu);
1730 
1731  // CONTACT FREEZING
1732  mnuccc = m_cons38 * dap * nacnt * std::exp(std::log(morr_arr(i,j,k,MORRInd::cdist1)) +
1733  std::log(gamma_function(morr_arr(i,j,k,MORRInd::pgam) + Real(5.0))) - Real(4.0) * std::log(morr_arr(i,j,k,MORRInd::lamc)));
1734  nnuccc = Real(2) * m_pi * dap * nacnt * morr_arr(i,j,k,MORRInd::cdist1) *
1735  gamma_function(morr_arr(i,j,k,MORRInd::pgam) + Real(2)) / morr_arr(i,j,k,MORRInd::lamc);
1736 
1737  // IMMERSION FREEZING (BIGG 1953)
1738  // hm 7/15/13 fix for consistency w/ original formula
1739  mnuccc = mnuccc + m_cons39 *
1740  std::exp(std::log(morr_arr(i,j,k,MORRInd::cdist1)) + std::log(gamma_function(Real(7.0) + morr_arr(i,j,k,MORRInd::pgam))) - Real(6.0) * std::log(morr_arr(i,j,k,MORRInd::lamc))) *
1741  (std::exp(m_aimm * (Real(273.15) - morr_arr(i,j,k,MORRInd::t3d))) - one);
1742 
1743  nnuccc = nnuccc +
1744  m_cons40 * std::exp(std::log(morr_arr(i,j,k,MORRInd::cdist1)) + std::log(gamma_function(morr_arr(i,j,k,MORRInd::pgam) + Real(4.0))) - three * std::log(morr_arr(i,j,k,MORRInd::lamc))) *
1745  (std::exp(m_aimm * (Real(273.15) - morr_arr(i,j,k,MORRInd::t3d))) - one);
1746 
1747  // PUT IN A CATCH HERE TO PREVENT DIVERGENCE BETWEEN NUMBER CONC. AND
1748  // MIXING RATIO, SINCE STRICT CONSERVATION NOT CHECKED FOR NUMBER CONC
1749  nnuccc = std::min(nnuccc, morr_arr(i,j,k,MORRInd::nc3d) / dt);
1750  }
1751 
1752  // AUTOCONVERSION OF CLOUD LIQUID WATER TO RAIN
1753  // FORMULA FROM BEHENG (1994)
1754  // USING NUMERICAL SIMULATION OF STOCHASTIC COLLECTION EQUATION
1755  // AND INITIAL CLOUD DROPLET SIZE DISTRIBUTION SPECIFIED
1756  // AS A GAMMA DISTRIBUTION
1757 
1758  // USE MINIMUM VALUE OF Real(1.E-6) TO PREVENT FLOATING POINT ERROR
1759  if (morr_arr(i,j,k,MORRInd::qc3d) >= Real(1.0e-6)) {
1760  // hm add 12/13/06, replace with newer formula
1761  // from khairoutdinov and kogan 2000, mwr
1762  prc = Real(1350.0) * std::pow(morr_arr(i,j,k,MORRInd::qc3d), Real(2.47)) *
1763  std::pow((morr_arr(i,j,k,MORRInd::nc3d) / Real(1.0e6) * morr_arr(i,j,k,MORRInd::rho)), -Real(1.79));
1764 
1765  // note: nprc1 is change in nr,
1766  // nprc is change in nc
1767  nprc1 = prc / m_cons29;
1768  nprc = prc / (morr_arr(i,j,k,MORRInd::qc3d) / morr_arr(i,j,k,MORRInd::nc3d));
1769 
1770  // hm bug fix 3/20/12
1771  nprc = std::min(nprc, morr_arr(i,j,k,MORRInd::nc3d) / dt);
1772  nprc1 = std::min(nprc1, nprc);
1773  }
1774  // SNOW AGGREGATION FROM PASSARELLI, 1978, USED BY REISNER, 1998
1775  // THIS IS HARD-WIRED FOR BS = Real(0.4) FOR NOW
1776  if (morr_arr(i,j,k,MORRInd::qni3d) >= Real(1.0e-8)) {
1777  nsagg = m_cons15 * morr_arr(i,j,k,MORRInd::asn) * std::pow(morr_arr(i,j,k,MORRInd::rho), ((Real(2) + m_bs) / three)) *
1778  std::pow(morr_arr(i,j,k,MORRInd::qni3d), ((Real(2) + m_bs) / three)) *
1779  std::pow((morr_arr(i,j,k,MORRInd::ns3d) * morr_arr(i,j,k,MORRInd::rho)), ((Real(4.0) - m_bs) / three)) / morr_arr(i,j,k,MORRInd::rho);
1780  }
1781 
1782  // ACCRETION OF CLOUD DROPLETS ONTO SNOW/GRAUPEL
1783  // HERE USE CONTINUOUS COLLECTION EQUATION WITH
1784  // SIMPLE GRAVITATIONAL COLLECTION KERNEL IGNORING
1785 
1786  // SNOW
1787  if (morr_arr(i,j,k,MORRInd::qni3d) >= Real(1.0e-8) && morr_arr(i,j,k,MORRInd::qc3d) >= m_qsmall) {
1788  psacws = m_cons13 * morr_arr(i,j,k,MORRInd::asn) * morr_arr(i,j,k,MORRInd::qc3d) * morr_arr(i,j,k,MORRInd::rho) *
1789  morr_arr(i,j,k,MORRInd::n0s) / std::pow(morr_arr(i,j,k,MORRInd::lams), (m_bs + three));
1790 
1791  npsacws = m_cons13 * morr_arr(i,j,k,MORRInd::asn) * morr_arr(i,j,k,MORRInd::nc3d) * morr_arr(i,j,k,MORRInd::rho) *
1792  morr_arr(i,j,k,MORRInd::n0s) / std::pow(morr_arr(i,j,k,MORRInd::lams), (m_bs + three));
1793  }
1794 
1795  // COLLECTION OF CLOUD WATER BY GRAUPEL
1796  if (morr_arr(i,j,k,MORRInd::qg3d) >= Real(1.0e-8) && morr_arr(i,j,k,MORRInd::qc3d) >= m_qsmall) {
1797  psacwg = m_cons14 * morr_arr(i,j,k,MORRInd::agn) * morr_arr(i,j,k,MORRInd::qc3d) * morr_arr(i,j,k,MORRInd::rho) *
1798  morr_arr(i,j,k,MORRInd::n0g) / std::pow(morr_arr(i,j,k,MORRInd::lamg), (m_bg + three));
1799 
1800  npsacwg = m_cons14 * morr_arr(i,j,k,MORRInd::agn) * morr_arr(i,j,k,MORRInd::nc3d) * morr_arr(i,j,k,MORRInd::rho) *
1801  morr_arr(i,j,k,MORRInd::n0g) / std::pow(morr_arr(i,j,k,MORRInd::lamg), (m_bg + three));
1802  }
1803  // hm, add 12/13/06
1804  // CLOUD ICE COLLECTING DROPLETS, ASSUME THAT CLOUD ICE MEAN DIAM > 100 MICRON
1805  // BEFORE RIMING CAN OCCUR
1806  // ASSUME THAT RIME COLLECTED ON CLOUD ICE DOES NOT LEAD
1807  // TO HALLET-MOSSOP SPLINTERING
1808  if (morr_arr(i,j,k,MORRInd::qi3d) >= Real(1.0e-8) && morr_arr(i,j,k,MORRInd::qc3d) >= m_qsmall) {
1809  // PUT IN SIZE DEPENDENT COLLECTION EFFICIENCY BASED ON STOKES LAW
1810  // FROM THOMPSON ET AL. 2004, MWR
1811  if (one / morr_arr(i,j,k,MORRInd::lami) >= Real(100.0e-6)) {
1812  psacwi = m_cons16 * morr_arr(i,j,k,MORRInd::ain) * morr_arr(i,j,k,MORRInd::qc3d) * morr_arr(i,j,k,MORRInd::rho) *
1813  morr_arr(i,j,k,MORRInd::n0i) / std::pow(morr_arr(i,j,k,MORRInd::lami), (m_bi + three));
1814 
1815  npsacwi = m_cons16 * morr_arr(i,j,k,MORRInd::ain) * morr_arr(i,j,k,MORRInd::nc3d) * morr_arr(i,j,k,MORRInd::rho) *
1816  morr_arr(i,j,k,MORRInd::n0i) / std::pow(morr_arr(i,j,k,MORRInd::lami), (m_bi + three));
1817  }
1818  }
1819 
1820  // ACCRETION OF RAIN WATER BY SNOW
1821  // FORMULA FROM IKAWA AND SAITO, 1991, USED BY REISNER ET AL, 1998
1822  if (morr_arr(i,j,k,MORRInd::qr3d) >= Real(1.0e-8) && morr_arr(i,j,k,MORRInd::qni3d) >= Real(1.0e-8)) {
1823  Real ums_local = morr_arr(i,j,k,MORRInd::asn) * m_cons3 / std::pow(morr_arr(i,j,k,MORRInd::lams), m_bs);
1824  Real umr_local = morr_arr(i,j,k,MORRInd::arn) * m_cons4 / std::pow(morr_arr(i,j,k,MORRInd::lamr), m_br);
1825  Real uns_local = morr_arr(i,j,k,MORRInd::asn) * m_cons5 / std::pow(morr_arr(i,j,k,MORRInd::lams), m_bs);
1826  Real unr_local = morr_arr(i,j,k,MORRInd::arn) * m_cons6 / std::pow(morr_arr(i,j,k,MORRInd::lamr), m_br);
1827 
1828  // SET REASLISTIC LIMITS ON FALLSPEEDS
1829  // bug fix, 10/08/09
1830  dum = std::pow(m_rhosu / morr_arr(i,j,k,MORRInd::rho), Real(0.54));
1831  ums_local = std::min(ums_local, Real(1.2) * dum);
1832  uns_local = std::min(uns_local, Real(1.2) * dum);
1833  umr_local = std::min(umr_local, Real(9.1) * dum);
1834  unr_local = std::min(unr_local, Real(9.1) * dum);
1835 
1836  pracs = m_cons41 * (std::sqrt(amrex::Math::powi<2>(Real(1.2) * umr_local - Real(0.95) * ums_local) +
1837  Real(0.08) * ums_local * umr_local) * morr_arr(i,j,k,MORRInd::rho) * morr_arr(i,j,k,MORRInd::n0r) * morr_arr(i,j,k,MORRInd::n0s) /
1838  amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr)) * (Real(5.0) / (amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr)) * morr_arr(i,j,k,MORRInd::lams)) +
1839  Real(2) / (amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lamr)) * amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lams))) +
1840  myhalf / (morr_arr(i,j,k,MORRInd::lamr) * amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lams)))));
1841 
1842  npracs = m_cons32 * morr_arr(i,j,k,MORRInd::rho) * std::sqrt(Real(1.7) * amrex::Math::powi<2>(unr_local - uns_local) +
1843  Real(0.3) * unr_local * uns_local) * morr_arr(i,j,k,MORRInd::n0r) * morr_arr(i,j,k,MORRInd::n0s) *
1844  (one / (amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr)) * morr_arr(i,j,k,MORRInd::lams)) +
1845  one / (amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lamr)) * amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lams))) +
1846  one / (morr_arr(i,j,k,MORRInd::lamr) * amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lams))));
1847 
1848  // MAKE SURE PRACS DOESN'T EXCEED TOTAL RAIN MIXING RATIO
1849  // AS THIS MAY OTHERWISE RESULT IN TOO MUCH TRANSFER OF WATER DURING
1850  // RIME-SPLINTERING
1851  pracs = std::min(pracs, morr_arr(i,j,k,MORRInd::qr3d) / dt);
1852 
1853  // COLLECTION OF SNOW BY RAIN - NEEDED FOR GRAUPEL CONVERSION CALCULATIONS
1854  // ONLY CALCULATE IF SNOW AND RAIN MIXING RATIOS EXCEED Real(0.1) G/KG
1855  // hm modify for wrfv3.1
1856  if (morr_arr(i,j,k,MORRInd::qni3d) >= Real(0.1e-3) && morr_arr(i,j,k,MORRInd::qr3d) >= Real(0.1e-3)) {
1857  psacr = m_cons31 * (std::sqrt(amrex::Math::powi<2>(Real(1.2) * umr_local - Real(0.95) * ums_local) +
1858  Real(0.08) * ums_local * umr_local) * morr_arr(i,j,k,MORRInd::rho) * morr_arr(i,j,k,MORRInd::n0r) * morr_arr(i,j,k,MORRInd::n0s) /
1859  amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lams)) * (Real(5.0) / (amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lams)) * morr_arr(i,j,k,MORRInd::lamr)) +
1860  Real(2) / (amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lams)) * amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lamr))) +
1861  myhalf / (morr_arr(i,j,k,MORRInd::lams) * amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr)))));
1862  }
1863  }
1864 
1865  // COLLECTION OF RAINWATER BY GRAUPEL, FROM IKAWA AND SAITO 1990,
1866  // USED BY REISNER ET AL 1998
1867  if (morr_arr(i,j,k,MORRInd::qr3d) >= Real(1.0e-8) && morr_arr(i,j,k,MORRInd::qg3d) >= Real(1.0e-8)) {
1868  Real umg_local = morr_arr(i,j,k,MORRInd::agn) * m_cons7 / std::pow(morr_arr(i,j,k,MORRInd::lamg), m_bg);
1869  Real umr_local = morr_arr(i,j,k,MORRInd::arn) * m_cons4 / std::pow(morr_arr(i,j,k,MORRInd::lamr), m_br);
1870  Real ung_local = morr_arr(i,j,k,MORRInd::agn) * m_cons8 / std::pow(morr_arr(i,j,k,MORRInd::lamg), m_bg);
1871  Real unr_local = morr_arr(i,j,k,MORRInd::arn) * m_cons6 / std::pow(morr_arr(i,j,k,MORRInd::lamr), m_br);
1872 
1873  // SET REASLISTIC LIMITS ON FALLSPEEDS
1874  // bug fix, 10/08/09
1875  dum = std::pow(m_rhosu / morr_arr(i,j,k,MORRInd::rho), Real(0.54));
1876  umg_local = std::min(umg_local, Real(20.0) * dum);
1877  ung_local = std::min(ung_local, Real(20.0) * dum);
1878  umr_local = std::min(umr_local, Real(9.1) * dum);
1879  unr_local = std::min(unr_local, Real(9.1) * dum);
1880 
1881  pracg = m_cons41 * (std::sqrt(amrex::Math::powi<2>(Real(1.2) * umr_local - Real(0.95) * umg_local) +
1882  Real(0.08) * umg_local * umr_local) * morr_arr(i,j,k,MORRInd::rho) * morr_arr(i,j,k,MORRInd::n0r) * morr_arr(i,j,k,MORRInd::n0g) /
1883  amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr)) * (Real(5.0) / (amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr)) * morr_arr(i,j,k,MORRInd::lamg)) +
1884  Real(2) / (amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lamr)) * amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lamg))) +
1885  myhalf / (morr_arr(i,j,k,MORRInd::lamr) * amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamg)))));
1886 
1887  npracg = m_cons32 * morr_arr(i,j,k,MORRInd::rho) * std::sqrt(Real(1.7) * amrex::Math::powi<2>(unr_local - ung_local) +
1888  Real(0.3) * unr_local * ung_local) * morr_arr(i,j,k,MORRInd::n0r) * morr_arr(i,j,k,MORRInd::n0g) *
1889  (one / (amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr)) * morr_arr(i,j,k,MORRInd::lamg)) +
1890  one / (amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lamr)) * amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::lamg))) +
1891  one / (morr_arr(i,j,k,MORRInd::lamr) * amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamg))));
1892 
1893  // MAKE SURE PRACG DOESN'T EXCEED TOTAL RAIN MIXING RATIO
1894  // AS THIS MAY OTHERWISE RESULT IN TOO MUCH TRANSFER OF WATER DURING
1895  // RIME-SPLINTERING
1896  pracg = std::min(pracg, morr_arr(i,j,k,MORRInd::qr3d) / dt);
1897  }
1898 
1899  // RIME-SPLINTERING - SNOW
1900  // HALLET-MOSSOP (1974)
1901  // NUMBER OF SPLINTERS FORMED IS BASED ON MASS OF RIMED WATER
1902  // hm add threshold snow and droplet mixing ratio for rime-splintering
1903  // to limit rime-splintering in stratiform clouds
1904  // these thresholds correspond with graupel thresholds in rh 1984
1905  //v1.4
1906  if (morr_arr(i,j,k,MORRInd::qni3d) >= Real(0.1e-3)) {
1907  if (morr_arr(i,j,k,MORRInd::qc3d) >= Real(0.5e-3) || morr_arr(i,j,k,MORRInd::qr3d) >= Real(0.1e-3)) {
1908  if (psacws > Real(0) || pracs > Real(0)) {
1909  if (morr_arr(i,j,k,MORRInd::t3d) < Real(270.16) && morr_arr(i,j,k,MORRInd::t3d) > Real(265.16)) {
1910  Real fmult = Real(0);
1911 
1912  if (morr_arr(i,j,k,MORRInd::t3d) > Real(270.16)) {
1913  fmult = Real(0);
1914  } else if (morr_arr(i,j,k,MORRInd::t3d) <= Real(270.16) && morr_arr(i,j,k,MORRInd::t3d) > Real(268.16)) {
1915  fmult = (Real(270.16) - morr_arr(i,j,k,MORRInd::t3d)) / Real(2);
1916  } else if (morr_arr(i,j,k,MORRInd::t3d) >= Real(265.16) && morr_arr(i,j,k,MORRInd::t3d) <= Real(268.16)) {
1917  fmult = (morr_arr(i,j,k,MORRInd::t3d) - Real(265.16)) / three;
1918  } else if (morr_arr(i,j,k,MORRInd::t3d) < Real(265.16)) {
1919  fmult = Real(0);
1920  }
1921 
1922  // 1000 IS TO CONVERT FROM KG TO G
1923  // SPLINTERING FROM DROPLETS ACCRETED ONTO SNOW
1924  if (psacws > Real(0)) {
1925  nmults = Real(35.0e4) * psacws * fmult * Real(1000.0);
1926  qmults = nmults * m_mmult;
1927 
1928  // CONSTRAIN SO THAT TRANSFER OF MASS FROM SNOW TO ICE CANNOT BE MORE MASS
1929  // THAN WAS RIMED ONTO SNOW
1930  qmults = std::min(qmults, psacws);
1931  psacws = psacws - qmults;
1932  }
1933 
1934  // RIMING AND SPLINTERING FROM ACCRETED RAINDROPS
1935  if (pracs > Real(0)) {
1936  nmultr = Real(35.0e4) * pracs * fmult * Real(1000.0);
1937  qmultr = nmultr * m_mmult;
1938 
1939  // CONSTRAIN SO THAT TRANSFER OF MASS FROM SNOW TO ICE CANNOT BE MORE MASS
1940  // THAN WAS RIMED ONTO SNOW
1941  qmultr = std::min(qmultr, pracs);
1942  pracs = pracs - qmultr;
1943  }
1944  }
1945  }
1946  }
1947  }
1948 
1949  // RIME-SPLINTERING - GRAUPEL
1950  // HALLET-MOSSOP (1974)
1951  // NUMBER OF SPLINTERS FORMED IS BASED ON MASS OF RIMED WATER
1952  // hm add threshold snow mixing ratio for rime-splintering
1953  // to limit rime-splintering in stratiform clouds
1954  // v1.4
1955  if (morr_arr(i,j,k,MORRInd::qg3d) >= Real(0.1e-3)) {
1956  if (morr_arr(i,j,k,MORRInd::qc3d) >= Real(0.5e-3) || morr_arr(i,j,k,MORRInd::qr3d) >= Real(0.1e-3)) {
1957  if (psacwg > Real(0) || pracg > Real(0)) {
1958  if (morr_arr(i,j,k,MORRInd::t3d) < Real(270.16) && morr_arr(i,j,k,MORRInd::t3d) > Real(265.16)) {
1959  Real fmult = Real(0);
1960 
1961  if (morr_arr(i,j,k,MORRInd::t3d) > Real(270.16)) {
1962  fmult = Real(0);
1963  } else if (morr_arr(i,j,k,MORRInd::t3d) <= Real(270.16) && morr_arr(i,j,k,MORRInd::t3d) > Real(268.16)) {
1964  fmult = (Real(270.16) - morr_arr(i,j,k,MORRInd::t3d)) / Real(2);
1965  } else if (morr_arr(i,j,k,MORRInd::t3d) >= Real(265.16) && morr_arr(i,j,k,MORRInd::t3d) <= Real(268.16)) {
1966  fmult = (morr_arr(i,j,k,MORRInd::t3d) - Real(265.16)) / three;
1967  } else if (morr_arr(i,j,k,MORRInd::t3d) < Real(265.16)) {
1968  fmult = Real(0);
1969  }
1970 
1971  // 1000 IS TO CONVERT FROM KG TO G
1972  // SPLINTERING FROM DROPLETS ACCRETED ONTO GRAUPEL
1973  if (psacwg > Real(0)) {
1974  nmultg = Real(35.0e4) * psacwg * fmult * Real(1000.0);
1975  qmultg = nmultg * m_mmult;
1976 
1977  // CONSTRAIN SO THAT TRANSFER OF MASS FROM GRAUPEL TO ICE CANNOT BE MORE MASS
1978  // THAN WAS RIMED ONTO GRAUPEL
1979  qmultg = std::min(qmultg, psacwg);
1980  psacwg = psacwg - qmultg;
1981  }
1982 
1983  // RIMING AND SPLINTERING FROM ACCRETED RAINDROPS
1984  if (pracg > Real(0)) {
1985  nmultrg = Real(35.0e4) * pracg * fmult * Real(1000.0);
1986  qmultrg = nmultrg * m_mmult;
1987 
1988  // CONSTRAIN SO THAT TRANSFER OF MASS FROM GRAUPEL TO ICE CANNOT BE MORE MASS
1989  // THAN WAS RIMED ONTO GRAUPEL
1990  qmultrg = std::min(qmultrg, pracg);
1991  pracg = pracg - qmultrg;
1992  }
1993  }
1994  }
1995  }
1996  }
1997 
1998  // CONVERSION OF RIMED CLOUD WATER ONTO SNOW TO GRAUPEL/HAIL
1999  if (psacws > Real(0)) {
2000  // ONLY ALLOW CONVERSION IF QNI > Real(0.1) AND QC > myhalf G/KG FOLLOWING RUTLEDGE AND HOBBS (1984)
2001  if (morr_arr(i,j,k,MORRInd::qni3d) >= Real(0.1e-3) && morr_arr(i,j,k,MORRInd::qc3d) >= Real(0.5e-3)) {
2002  // PORTION OF RIMING CONVERTED TO GRAUPEL (REISNER ET AL. 1998, ORIGINALLY IS1991)
2003  pgsacw = std::min(psacws, m_cons17 * dt * morr_arr(i,j,k,MORRInd::n0s) * morr_arr(i,j,k,MORRInd::qc3d) * morr_arr(i,j,k,MORRInd::qc3d) *
2004  morr_arr(i,j,k,MORRInd::asn) * morr_arr(i,j,k,MORRInd::asn) /
2005  (morr_arr(i,j,k,MORRInd::rho) * std::pow(morr_arr(i,j,k,MORRInd::lams), (Real(2) * m_bs + Real(2)))));
2006 
2007  // MIX RAT CONVERTED INTO GRAUPEL AS EMBRYO (REISNER ET AL. 1998, ORIG M1990)
2008  dum = std::max(m_rhosn / (m_rhog - m_rhosn) * pgsacw, Real(0));
2009 
2010  // NUMBER CONCENTRAITON OF EMBRYO GRAUPEL FROM RIMING OF SNOW
2011  nscng = dum / m_mg0 * morr_arr(i,j,k,MORRInd::rho);
2012  // LIMIT MAX NUMBER CONVERTED TO SNOW NUMBER
2013  nscng = std::min(nscng, morr_arr(i,j,k,MORRInd::ns3d) / dt);
2014 
2015  // PORTION OF RIMING LEFT FOR SNOW
2016  psacws = psacws - pgsacw;
2017  }
2018  }
2019 
2020  // CONVERSION OF RIMED RAINWATER ONTO SNOW CONVERTED TO GRAUPEL
2021  if (pracs > Real(0)) {
2022  // ONLY ALLOW CONVERSION IF QNI > Real(0.1) AND QR > Real(0.1) G/KG FOLLOWING RUTLEDGE AND HOBBS (1984)
2023  if (morr_arr(i,j,k,MORRInd::qni3d) >= Real(0.1e-3) && morr_arr(i,j,k,MORRInd::qr3d) >= Real(0.1e-3)) {
2024  // PORTION OF COLLECTED RAINWATER CONVERTED TO GRAUPEL (REISNER ET AL. 1998)
2025  dum = m_cons18 * amrex::Math::powi<3>(Real(4.0) / morr_arr(i,j,k,MORRInd::lams)) * amrex::Math::powi<3>(Real(4.0) / morr_arr(i,j,k,MORRInd::lams)) /
2026  (m_cons18 * amrex::Math::powi<3>(Real(4.0) / morr_arr(i,j,k,MORRInd::lams)) * amrex::Math::powi<3>(Real(4.0) / morr_arr(i,j,k,MORRInd::lams)) +
2027  m_cons19 * amrex::Math::powi<3>(Real(4.0) / morr_arr(i,j,k,MORRInd::lamr)) * amrex::Math::powi<3>(Real(4.0) / morr_arr(i,j,k,MORRInd::lamr)));
2028  dum = std::min(dum, Real(1));
2029  dum = std::max(dum, Real(0));
2030 
2031  pgracs = (one - dum) * pracs;
2032  ngracs = (one - dum) * npracs;
2033 
2034  // LIMIT MAX NUMBER CONVERTED TO MIN OF EITHER RAIN OR SNOW NUMBER CONCENTRATION
2035  ngracs = std::min(ngracs, morr_arr(i,j,k,MORRInd::nr3d) / dt);
2036  ngracs = std::min(ngracs, morr_arr(i,j,k,MORRInd::ns3d) / dt);
2037 
2038  // AMOUNT LEFT FOR SNOW PRODUCTION
2039  pracs = pracs - pgracs;
2040  npracs = npracs - ngracs;
2041 
2042  // CONVERSION TO GRAUPEL DUE TO COLLECTION OF SNOW BY RAIN
2043  psacr = psacr * (one - dum);
2044  }
2045  }
2046 
2047  // FREEZING OF RAIN DROPS
2048  // FREEZING ALLOWED BELOW -4 C
2049  if (morr_arr(i,j,k,MORRInd::t3d) < Real(269.15) && morr_arr(i,j,k,MORRInd::qr3d) >= m_qsmall) {
2050  // IMMERSION FREEZING (BIGG 1953)
2051  // hm fix 7/15/13 for consistency w/ original formula
2052  mnuccr = m_cons20 * morr_arr(i,j,k,MORRInd::nr3d) * (std::exp(m_aimm * (Real(273.15) - morr_arr(i,j,k,MORRInd::t3d))) - one) /
2053  amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr)) / amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr));
2054 
2055  nnuccr = m_pi * morr_arr(i,j,k,MORRInd::nr3d) * m_bimm * (std::exp(m_aimm * (Real(273.15) - morr_arr(i,j,k,MORRInd::t3d))) - one) /
2056  amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr));
2057 
2058  // PREVENT DIVERGENCE BETWEEN MIXING RATIO AND NUMBER CONC
2059  nnuccr = std::min(nnuccr, morr_arr(i,j,k,MORRInd::nr3d) / dt);
2060  }
2061 
2062  // ACCRETION OF CLOUD LIQUID WATER BY RAIN
2063  // CONTINUOUS COLLECTION EQUATION WITH
2064  // GRAVITATIONAL COLLECTION KERNEL, DROPLET FALL SPEED NEGLECTED
2065  if (morr_arr(i,j,k,MORRInd::qr3d) >= Real(1.0e-8) && morr_arr(i,j,k,MORRInd::qc3d) >= Real(1.0e-8)) {
2066  // 12/13/06 hm add, replace with newer formula from
2067  // khairoutdinov and kogan 2000, mwr
2068  dum = morr_arr(i,j,k,MORRInd::qc3d) * morr_arr(i,j,k,MORRInd::qr3d);
2069  pra = Real(67.0) * std::pow(dum, Real(1.15));
2070  npra = pra / (morr_arr(i,j,k,MORRInd::qc3d) / morr_arr(i,j,k,MORRInd::nc3d));
2071  }
2072 
2073  // SELF-COLLECTION OF RAIN DROPS
2074  // FROM BEHENG(1994)
2075  // FROM NUMERICAL SIMULATION OF THE STOCHASTIC COLLECTION EQUATION
2076  // AS DESCRINED ABOVE FOR AUTOCONVERSION
2077  if (morr_arr(i,j,k,MORRInd::qr3d) >= Real(1.0e-8)) {
2078  // include breakup add 10/09/09
2079  dum1 = Real(300.0e-6);
2080  if (one / morr_arr(i,j,k,MORRInd::lamr) < dum1) {
2081  dum = one;
2082  } else if (one / morr_arr(i,j,k,MORRInd::lamr) >= dum1) {
2083  dum = Real(2) - std::exp(Real(2300.0) * (one / morr_arr(i,j,k,MORRInd::lamr) - dum1));
2084  }
2085  nragg = -Real(5.78) * dum * morr_arr(i,j,k,MORRInd::nr3d) * morr_arr(i,j,k,MORRInd::qr3d) * morr_arr(i,j,k,MORRInd::rho);
2086  }
2087 
2088  // AUTOCONVERSION OF CLOUD ICE TO SNOW
2089  // FOLLOWING HARRINGTON ET AL. (1995) WITH MODIFICATION
2090  // HERE IT IS ASSUMED THAT AUTOCONVERSION CAN ONLY OCCUR WHEN THE
2091  // ICE IS GROWING, I.E. IN CONDITIONS OF ICE SUPERSATURATION
2092  if (morr_arr(i,j,k,MORRInd::qi3d) >= Real(1.0e-8) && qvqvsi >= one) {
2093  nprci = m_cons21 * (morr_arr(i,j,k,MORRInd::qv3d) - qvi) * morr_arr(i,j,k,MORRInd::rho) *
2094  morr_arr(i,j,k,MORRInd::n0i) * std::exp(-morr_arr(i,j,k,MORRInd::lami) * m_dcs) * dv / abi;
2095  prci = m_cons22 * nprci;
2096  nprci = std::min(nprci, morr_arr(i,j,k,MORRInd::ni3d) / dt);
2097  }
2098 
2099  // ACCRETION OF CLOUD ICE BY SNOW
2100  // FOR THIS CALCULATION, IT IS ASSUMED THAT THE VS >> VI
2101  // AND DS >> DI FOR CONTINUOUS COLLECTION
2102  if (morr_arr(i,j,k,MORRInd::qni3d) >= Real(1.0e-8) && morr_arr(i,j,k,MORRInd::qi3d) >= m_qsmall) {
2103  prai = m_cons23 * morr_arr(i,j,k,MORRInd::asn) * morr_arr(i,j,k,MORRInd::qi3d) * morr_arr(i,j,k,MORRInd::rho) * morr_arr(i,j,k,MORRInd::n0s) /
2104  std::pow(morr_arr(i,j,k,MORRInd::lams), (m_bs + three));
2105  nprai = m_cons23 * morr_arr(i,j,k,MORRInd::asn) * morr_arr(i,j,k,MORRInd::ni3d) *
2106  morr_arr(i,j,k,MORRInd::rho) * morr_arr(i,j,k,MORRInd::n0s) /
2107  std::pow(morr_arr(i,j,k,MORRInd::lams), (m_bs + three));
2108  nprai = std::min(nprai, morr_arr(i,j,k,MORRInd::ni3d) / dt);
2109  }
2110 
2111  // hm, add 12/13/06, collision of rain and ice to produce snow or graupel
2112  // follows reisner et al. 1998
2113  // assumed fallspeed and size of ice crystal << than for rain
2114  if (morr_arr(i,j,k,MORRInd::qr3d) >= Real(1.0e-8) && morr_arr(i,j,k,MORRInd::qi3d) >= Real(1.0e-8) && morr_arr(i,j,k,MORRInd::t3d) <= Real(273.15)) {
2115  // allow graupel formation from rain-ice collisions only if rain mixing ratio > Real(0.1) g/kg,
2116  // otherwise add to snow
2117  if (morr_arr(i,j,k,MORRInd::qr3d) >= Real(0.1e-3)) {
2118  niacr = m_cons24 * morr_arr(i,j,k,MORRInd::ni3d) * morr_arr(i,j,k,MORRInd::n0r)* morr_arr(i,j,k,MORRInd::arn) /
2119  std::pow(morr_arr(i,j,k,MORRInd::lamr), (m_br + three)) * morr_arr(i,j,k,MORRInd::rho);
2120  piacr = m_cons25 * morr_arr(i,j,k,MORRInd::ni3d) * morr_arr(i,j,k,MORRInd::n0r) * morr_arr(i,j,k,MORRInd::arn) /
2121  std::pow(morr_arr(i,j,k,MORRInd::lamr), (m_br + three)) / amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr)) * morr_arr(i,j,k,MORRInd::rho);
2122  praci = m_cons24 * morr_arr(i,j,k,MORRInd::qi3d) * morr_arr(i,j,k,MORRInd::n0r) * morr_arr(i,j,k,MORRInd::arn) /
2123  std::pow(morr_arr(i,j,k,MORRInd::lamr), (m_br + three)) * morr_arr(i,j,k,MORRInd::rho);
2124  niacr = std::min(niacr, morr_arr(i,j,k,MORRInd::nr3d) / dt);
2125  niacr = std::min(niacr, morr_arr(i,j,k,MORRInd::ni3d) / dt);
2126  } else {
2127  niacrs = m_cons24 * morr_arr(i,j,k,MORRInd::ni3d) * morr_arr(i,j,k,MORRInd::n0r) * morr_arr(i,j,k,MORRInd::arn) /
2128  std::pow(morr_arr(i,j,k,MORRInd::lamr), (m_br + three)) * morr_arr(i,j,k,MORRInd::rho);
2129  piacrs = m_cons25 * morr_arr(i,j,k,MORRInd::ni3d) * morr_arr(i,j,k,MORRInd::n0r) * morr_arr(i,j,k,MORRInd::arn) /
2130  std::pow(morr_arr(i,j,k,MORRInd::lamr), (m_br + three)) / amrex::Math::powi<3>(morr_arr(i,j,k,MORRInd::lamr)) * morr_arr(i,j,k,MORRInd::rho);
2131  pracis = m_cons24 * morr_arr(i,j,k,MORRInd::qi3d) * morr_arr(i,j,k,MORRInd::n0r) * morr_arr(i,j,k,MORRInd::arn) /
2132  std::pow(morr_arr(i,j,k,MORRInd::lamr), (m_br + three)) * morr_arr(i,j,k,MORRInd::rho);
2133  niacrs = std::min(niacrs, morr_arr(i,j,k,MORRInd::nr3d) / dt);
2134  niacrs = std::min(niacrs, morr_arr(i,j,k,MORRInd::ni3d) / dt);
2135  }
2136  }
2137 
2138  // NUCLEATION OF CLOUD ICE FROM HOMOGENEOUS AND HETEROGENEOUS FREEZING ON AEROSOL
2139  if (m_inuc == 0) {
2140  // ADD THRESHOLD ACCORDING TO GREG THOMSPON
2141  if ((qvqvs >= Real(0.999) && morr_arr(i,j,k,MORRInd::t3d) <= Real(265.15)) || qvqvsi >= Real(1.08)) {
2142  // hm, modify dec. 5, 2006, replace with cooper curve
2143  kc2 = Real(0.005) * std::exp(Real(0.304) * (Real(273.15) - morr_arr(i,j,k,MORRInd::t3d))) * Real(1000.0); // CONVERT FROM L-1 TO M-3
2144  // LIMIT TO 500 L-1
2145  kc2 = std::min(kc2, Real(500.0e3));
2146  kc2 = std::max(kc2 / morr_arr(i,j,k,MORRInd::rho), Real(0)); // CONVERT TO KG-1
2147 
2148  if (kc2 > morr_arr(i,j,k,MORRInd::ni3d) + morr_arr(i,j,k,MORRInd::ns3d) + morr_arr(i,j,k,MORRInd::ng3d)) {
2149  nnuccd = (kc2 - morr_arr(i,j,k,MORRInd::ni3d) - morr_arr(i,j,k,MORRInd::ns3d) - morr_arr(i,j,k,MORRInd::ng3d)) / dt;
2150  mnuccd = nnuccd * m_mi0;
2151  }
2152  }
2153  } else if (m_inuc == 1) {
2154  if (morr_arr(i,j,k,MORRInd::t3d) < Real(273.15) && qvqvsi > one) {
2155  kc2 = Real(0.16) * Real(1000.0) / morr_arr(i,j,k,MORRInd::rho); // CONVERT FROM L-1 TO KG-1
2156  if (kc2 > morr_arr(i,j,k,MORRInd::ni3d) + morr_arr(i,j,k,MORRInd::ns3d) + morr_arr(i,j,k,MORRInd::ng3d)) {
2157  nnuccd = (kc2 - morr_arr(i,j,k,MORRInd::ni3d) - morr_arr(i,j,k,MORRInd::ns3d) - morr_arr(i,j,k,MORRInd::ng3d)) / dt;
2158  mnuccd = nnuccd * m_mi0;
2159  }
2160  }
2161  }
2162 
2163  // CALCULATE EVAP/SUB/DEP TERMS FOR QI,QNI,QR
2164  // NO VENTILATION FOR CLOUD ICE
2165  epsi = Real(0);
2166  if (morr_arr(i,j,k,MORRInd::qi3d) >= m_qsmall) {
2167  epsi = Real(2) * m_pi * morr_arr(i,j,k,MORRInd::n0i) * morr_arr(i,j,k,MORRInd::rho) * dv / (morr_arr(i,j,k,MORRInd::lami) * morr_arr(i,j,k,MORRInd::lami));
2168  }
2169 
2170  // VENTILATION FOR SNOW
2171  epss = Real(0);
2172  if (morr_arr(i,j,k,MORRInd::qni3d) >= m_qsmall) {
2173  epss = Real(2) * m_pi * morr_arr(i,j,k,MORRInd::n0s) * morr_arr(i,j,k,MORRInd::rho) * dv *
2174  (m_f1s / (morr_arr(i,j,k,MORRInd::lams) * morr_arr(i,j,k,MORRInd::lams)) +
2175  m_f2s * std::pow(morr_arr(i,j,k,MORRInd::asn) * morr_arr(i,j,k,MORRInd::rho) / morr_arr(i,j,k,MORRInd::mu), myhalf) *
2176  std::pow(sc_schmidt, (one / three)) * m_cons10 /
2177  std::pow(morr_arr(i,j,k,MORRInd::lams), m_cons35));
2178  }
2179 
2180  // Ventilation for graupel
2181  epsg = Real(0);
2182  if (morr_arr(i,j,k,MORRInd::qg3d) >= m_qsmall) {
2183  epsg = Real(2) * m_pi * morr_arr(i,j,k,MORRInd::n0g) * morr_arr(i,j,k,MORRInd::rho) * dv *
2184  (m_f1s / (morr_arr(i,j,k,MORRInd::lamg) * morr_arr(i,j,k,MORRInd::lamg)) +
2185  m_f2s * std::pow(morr_arr(i,j,k,MORRInd::agn) * morr_arr(i,j,k,MORRInd::rho) / morr_arr(i,j,k,MORRInd::mu), myhalf) *
2186  std::pow(sc_schmidt, (one / three)) * m_cons11 /
2187  std::pow(morr_arr(i,j,k,MORRInd::lamg), m_cons36));
2188  }
2189 
2190  // VENTILATION FOR RAIN
2191  epsr = Real(0);
2192  if (morr_arr(i,j,k,MORRInd::qr3d) >= m_qsmall) {
2193  epsr = Real(2) * m_pi * morr_arr(i,j,k,MORRInd::n0r) * morr_arr(i,j,k,MORRInd::rho) * dv *
2194  (m_f1r / (morr_arr(i,j,k,MORRInd::lamr) * morr_arr(i,j,k,MORRInd::lamr)) +
2195  m_f2r * std::pow(morr_arr(i,j,k,MORRInd::arn) * morr_arr(i,j,k,MORRInd::rho) / morr_arr(i,j,k,MORRInd::mu), myhalf) *
2196  std::pow(sc_schmidt, (one / three)) * m_cons9 /
2197  std::pow(morr_arr(i,j,k,MORRInd::lamr), m_cons34));
2198  }
2199 
2200  // ONLY INCLUDE REGION OF ICE SIZE DIST < DCS
2201  // DUM IS FRACTION OF D*N(D) < DCS
2202  // LOGIC BELOW FOLLOWS THAT OF HARRINGTON ET AL. 1995 (JAS)
2203  if (morr_arr(i,j,k,MORRInd::qi3d) >= m_qsmall) {
2204  dum = (one - std::exp(-morr_arr(i,j,k,MORRInd::lami) * m_dcs) * (one + morr_arr(i,j,k,MORRInd::lami) * m_dcs));
2205  prd = epsi * (morr_arr(i,j,k,MORRInd::qv3d) - qvi) / abi * dum;
2206  } else {
2207  dum = Real(0);
2208  }
2209 
2210  // ADD DEPOSITION IN TAIL OF ICE SIZE DIST TO SNOW IF SNOW IS PRESENT
2211  if (morr_arr(i,j,k,MORRInd::qni3d) >= m_qsmall) {
2212  prds = epss * (morr_arr(i,j,k,MORRInd::qv3d) - qvi) / abi +
2213  epsi * (morr_arr(i,j,k,MORRInd::qv3d) - qvi) / abi * (one - dum);
2214  } else {
2215  // OTHERWISE ADD TO CLOUD ICE
2216  prd = prd + epsi * (morr_arr(i,j,k,MORRInd::qv3d) - qvi) / abi * (one - dum);
2217  }
2218 
2219  // VAPOR DPEOSITION ON GRAUPEL
2220  prdg = epsg * (morr_arr(i,j,k,MORRInd::qv3d) - qvi) / abi;
2221 
2222  // NO CONDENSATION ONTO RAIN, ONLY EVAP
2223  if (morr_arr(i,j,k,MORRInd::qv3d) < qvs) {
2224  pre = epsr * (morr_arr(i,j,k,MORRInd::qv3d) - qvs) / ab;
2225  pre = std::min(pre, Real(0));
2226  } else {
2227  pre = Real(0);
2228  }
2229 
2230  // MAKE SURE NOT PUSHED INTO ICE SUPERSAT/SUBSAT
2231  // FORMULA FROM REISNER 2 SCHEME
2232  dum = (morr_arr(i,j,k,MORRInd::qv3d) - qvi) / dt;
2233 
2234  fudgef = Real(0.9999);
2235  sum_dep = prd + prds + mnuccd + prdg;
2236 
2237  if ((dum > Real(0) && sum_dep > dum * fudgef) ||
2238  (dum < Real(0) && sum_dep < dum * fudgef)) {
2239  mnuccd = fudgef * mnuccd * dum / sum_dep;
2240  prd = fudgef * prd * dum / sum_dep;
2241  prds = fudgef * prds * dum / sum_dep;
2242  prdg = fudgef * prdg * dum / sum_dep;
2243  }
2244 
2245  // IF CLOUD ICE/SNOW/GRAUPEL VAP DEPOSITION IS NEG, THEN ASSIGN TO SUBLIMATION PROCESSES
2246  if (prd < Real(0)) {
2247  eprd = prd;
2248  prd = Real(0);
2249  }
2250  if (prds < Real(0)) {
2251  eprds = prds;
2252  prds = Real(0);
2253  }
2254  if (prdg < Real(0)) {
2255  eprdg = prdg;
2256  prdg = Real(0);
2257  }
2258  // CONSERVATION OF WATER
2259  // THIS IS ADOPTED LOOSELY FROM RESINER CODE. HOWEVER, HERE WE
2260  // ONLY ADJUST PROCESSES THAT ARE NEGATIVE, RATHER THAN ALL PROCESSES.
2261 
2262  // IF MIXING RATIOS LESS THAN QSMALL, THEN NO DEPLETION OF WATER
2263  // THROUGH MICROPHYSICAL PROCESSES, SKIP CONSERVATION
2264 
2265  // NOTE: CONSERVATION CHECK NOT APPLIED TO NUMBER CONCENTRATION SPECIES. ADDITIONAL CATCH
2266  // BELOW WILL PREVENT NEGATIVE NUMBER CONCENTRATION
2267  // FOR EACH MICROPHYSICAL PROCESS WHICH PROVIDES A SOURCE FOR NUMBER, THERE IS A CHECK
2268  // TO MAKE SURE THAT CAN'T EXCEED TOTAL NUMBER OF DEPLETED SPECIES WITH THE TIME
2269  // STEP
2270 
2271  // ****SENSITIVITY - NO ICE
2272  if (m_iliq == 1) {
2273  mnuccc = Real(0);
2274  nnuccc = Real(0);
2275  mnuccr = Real(0);
2276  nnuccr = Real(0);
2277  mnuccd = Real(0);
2278  nnuccd = Real(0);
2279  }
2280 
2281  // ****SENSITIVITY - NO GRAUPEL
2282  if (m_igraup == 1) {
2283  pracg = Real(0);
2284  psacr = Real(0);
2285  psacwg = Real(0);
2286  prdg = Real(0);
2287  eprdg = Real(0);
2288  evpmg = Real(0);
2289  pgmlt = Real(0);
2290  npracg = Real(0);
2291  npsacwg = Real(0);
2292  nscng = Real(0);
2293  ngracs = Real(0);
2294  nsubg = Real(0);
2295  ngmltg = Real(0);
2296  ngmltr = Real(0);
2297 
2298  // fix 053011
2299  piacrs = piacrs + piacr;
2300  piacr = Real(0);
2301 
2302  // fix 070713
2303  pracis = pracis + praci;
2304  praci = Real(0);
2305  psacws = psacws + pgsacw;
2306  pgsacw = Real(0);
2307  pracs = pracs + pgracs;
2308  pgracs = Real(0);
2309  }
2310 
2311  // CONSERVATION OF QC
2312  dum = (prc + pra + mnuccc + psacws + psacwi + qmults + psacwg + pgsacw + qmultg) * dt;
2313 
2314  if (dum > morr_arr(i,j,k,MORRInd::qc3d) && morr_arr(i,j,k,MORRInd::qc3d) >= m_qsmall) {
2315  ratio = morr_arr(i,j,k,MORRInd::qc3d) / dum;
2316 
2317  prc = prc * ratio;
2318  pra = pra * ratio;
2319  mnuccc = mnuccc * ratio;
2320  psacws = psacws * ratio;
2321  psacwi = psacwi * ratio;
2322  qmults = qmults * ratio;
2323  qmultg = qmultg * ratio;
2324  psacwg = psacwg * ratio;
2325  pgsacw = pgsacw * ratio;
2326  }
2327 
2328  // CONSERVATION OF QI
2329  dum = (-prd - mnuccc + prci + prai - qmults - qmultg - qmultr - qmultrg
2330  - mnuccd + praci + pracis - eprd - psacwi) * dt;
2331 
2332  if (dum > morr_arr(i,j,k,MORRInd::qi3d) && morr_arr(i,j,k,MORRInd::qi3d) >= m_qsmall) {
2333  ratio = (morr_arr(i,j,k,MORRInd::qi3d) / dt + prd + mnuccc + qmults + qmultg + qmultr + qmultrg +
2334  mnuccd + psacwi) /
2335  (prci + prai + praci + pracis - eprd);
2336 
2337  prci = prci * ratio;
2338  prai = prai * ratio;
2339  praci = praci * ratio;
2340  pracis = pracis * ratio;
2341  eprd = eprd * ratio;
2342  }
2343 
2344  // CONSERVATION OF QR
2345  dum = ((pracs - pre) + (qmultr + qmultrg - prc) + (mnuccr - pra) +
2346  piacr + piacrs + pgracs + pracg) * dt;
2347 
2348  if (dum > morr_arr(i,j,k,MORRInd::qr3d) && morr_arr(i,j,k,MORRInd::qr3d) >= m_qsmall) {
2349  ratio = (morr_arr(i,j,k,MORRInd::qr3d) / dt + prc + pra) /
2350  (-pre + qmultr + qmultrg + pracs + mnuccr + piacr + piacrs + pgracs + pracg);
2351 
2352  pre = pre * ratio;
2353  pracs = pracs * ratio;
2354  qmultr = qmultr * ratio;
2355  qmultrg = qmultrg * ratio;
2356  mnuccr = mnuccr * ratio;
2357  piacr = piacr * ratio;
2358  piacrs = piacrs * ratio;
2359  pgracs = pgracs * ratio;
2360  pracg = pracg * ratio;
2361  }
2362 
2363  // CONSERVATION OF QNI
2364  if (m_igraup == 0) {
2365  dum = (-prds - psacws - prai - prci - pracs - eprds + psacr - piacrs - pracis) * dt;
2366 
2367  if (dum > morr_arr(i,j,k,MORRInd::qni3d) && morr_arr(i,j,k,MORRInd::qni3d) >= m_qsmall) {
2368  ratio = (morr_arr(i,j,k,MORRInd::qni3d) / dt + prds + psacws + prai + prci + pracs + piacrs + pracis) /
2369  (-eprds + psacr);
2370 
2371  eprds = eprds * ratio;
2372  psacr = psacr * ratio;
2373  }
2374  } else if (m_igraup == 1) {
2375  // FOR NO GRAUPEL, NEED TO INCLUDE FREEZING OF RAIN FOR SNOW
2376  dum = (-prds - psacws - prai - prci - pracs - eprds + psacr - piacrs - pracis - mnuccr) * dt;
2377 
2378  if (dum > morr_arr(i,j,k,MORRInd::qni3d) && morr_arr(i,j,k,MORRInd::qni3d) >= m_qsmall) {
2379  ratio = (morr_arr(i,j,k,MORRInd::qni3d) / dt + prds + psacws + prai + prci + pracs + piacrs + pracis + mnuccr) /
2380  (-eprds + psacr);
2381 
2382  eprds = eprds * ratio;
2383  psacr = psacr * ratio;
2384  }
2385  }
2386 
2387  // CONSERVATION OF QG
2388  dum = (-psacwg - pracg - pgsacw - pgracs - prdg - mnuccr - eprdg - piacr - praci - psacr) * dt;
2389 
2390  if (dum > morr_arr(i,j,k,MORRInd::qg3d) && morr_arr(i,j,k,MORRInd::qg3d) >= m_qsmall) {
2391  ratio = (morr_arr(i,j,k,MORRInd::qg3d) / dt + psacwg + pracg + pgsacw + pgracs + prdg + mnuccr + psacr +
2392  piacr + praci) / (-eprdg);
2393 
2394  eprdg = eprdg * ratio;
2395  }
2396 
2397  // TENDENCIES
2398  morr_arr(i,j,k,MORRInd::qv3dten) = morr_arr(i,j,k,MORRInd::qv3dten) + (-pre - prd - prds - mnuccd - eprd - eprds - prdg - eprdg);
2399 
2400  // bug fix hm, 3/1/11, include piacr and piacrs
2401  morr_arr(i,j,k,MORRInd::t3dten) = morr_arr(i,j,k,MORRInd::t3dten) + (pre * morr_arr(i,j,k,MORRInd::xxlv) +
2402  (prd + prds + mnuccd + eprd + eprds + prdg + eprdg) * morr_arr(i,j,k,MORRInd::xxls) +
2403  (psacws + psacwi + mnuccc + mnuccr + qmults + qmultg + qmultr + qmultrg + pracs +
2404  psacwg + pracg + pgsacw + pgracs + piacr + piacrs) * morr_arr(i,j,k,MORRInd::xlf)) / morr_arr(i,j,k,MORRInd::cpm);
2405 
2406  morr_arr(i,j,k,MORRInd::qc3dten) = morr_arr(i,j,k,MORRInd::qc3dten) +
2407  (-pra - prc - mnuccc + pcc -
2408  psacws - psacwi - qmults - qmultg - psacwg - pgsacw);
2409 
2410  morr_arr(i,j,k,MORRInd::qi3dten) = morr_arr(i,j,k,MORRInd::qi3dten) +
2411  (prd + eprd + psacwi + mnuccc - prci -
2412  prai + qmults + qmultg + qmultr + qmultrg + mnuccd - praci - pracis);
2413 
2414  morr_arr(i,j,k,MORRInd::qr3dten) = morr_arr(i,j,k,MORRInd::qr3dten) +
2415  (pre + pra + prc - pracs - mnuccr - qmultr - qmultrg -
2416  piacr - piacrs - pracg - pgracs);
2417  if (m_igraup == 0) {
2418  morr_arr(i,j,k,MORRInd::qni3dten) = morr_arr(i,j,k,MORRInd::qni3dten) +
2419  (prai + psacws + prds + pracs + prci + eprds - psacr + piacrs + pracis);
2420 
2421  morr_arr(i,j,k,MORRInd::ns3dten) = morr_arr(i,j,k,MORRInd::ns3dten) + (nsagg + nprci - nscng - ngracs + niacrs);
2422 
2423  morr_arr(i,j,k,MORRInd::qg3dten) = morr_arr(i,j,k,MORRInd::qg3dten) + (pracg + psacwg + pgsacw + pgracs +
2424  prdg + eprdg + mnuccr + piacr + praci + psacr);
2425 
2426  morr_arr(i,j,k,MORRInd::ng3dten) = morr_arr(i,j,k,MORRInd::ng3dten) + (nscng + ngracs + nnuccr + niacr);
2427  } else if (m_igraup == 1) {
2428  // FOR NO GRAUPEL, NEED TO INCLUDE FREEZING OF RAIN FOR SNOW
2429  morr_arr(i,j,k,MORRInd::qni3dten) = morr_arr(i,j,k,MORRInd::qni3dten) +
2430  (prai + psacws + prds + pracs + prci + eprds - psacr + piacrs + pracis + mnuccr);
2431 
2432  morr_arr(i,j,k,MORRInd::ns3dten) = morr_arr(i,j,k,MORRInd::ns3dten) + (nsagg + nprci - nscng - ngracs + niacrs + nnuccr);
2433  }
2434 
2435  morr_arr(i,j,k,MORRInd::nc3dten) = morr_arr(i,j,k,MORRInd::nc3dten) + (-nnuccc - npsacws -
2436  npra - nprc - npsacwi - npsacwg);
2437 
2438  morr_arr(i,j,k,MORRInd::ni3dten) = morr_arr(i,j,k,MORRInd::ni3dten) +
2439  (nnuccc - nprci - nprai + nmults + nmultg + nmultr + nmultrg +
2440  nnuccd - niacr - niacrs);
2441 
2442  morr_arr(i,j,k,MORRInd::nr3dten) = morr_arr(i,j,k,MORRInd::nr3dten) + (nprc1 - npracs - nnuccr +
2443  nragg - niacr - niacrs - npracg - ngracs);
2444 
2445  // hm add, wrf-chem, add tendencies for c2prec
2446  // c2prec = pra + prc + psacws + qmults + qmultg + psacwg + pgsacw + mnuccc + psacwi;
2447 
2448  if (do_cond) {
2449  // CALCULATE SATURATION ADJUSTMENT TO CONDENSE EXTRA VAPOR ABOVE
2450  // WATER SATURATION
2451  dumt = morr_arr(i,j,k,MORRInd::t3d) + dt * morr_arr(i,j,k,MORRInd::t3dten);
2452  dumqv = morr_arr(i,j,k,MORRInd::qv3d) + dt * morr_arr(i,j,k,MORRInd::qv3dten);
2453 
2454  // hm, add fix for low pressure, 5/12/10
2455  dum = std::min(Real(0.99) * morr_arr(i,j,k,MORRInd::pres), calc_saturation_vapor_pressure(dumt, 0));
2456  dumqss = m_ep_2 * dum / (morr_arr(i,j,k,MORRInd::pres) - dum);
2457 
2458  dumqc = morr_arr(i,j,k,MORRInd::qc3d) + dt * morr_arr(i,j,k,MORRInd::qc3dten);
2459  dumqc = std::max(dumqc, Real(0));
2460 
2461  // SATURATION ADJUSTMENT FOR LIQUID
2462  dums = dumqv - dumqss;
2463 
2464  pcc = dums / (one + amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::xxlv)) * dumqss / (morr_arr(i,j,k,MORRInd::cpm) * m_Rv * amrex::Math::powi<2>(dumt))) / dt;
2465 
2466  if (pcc * dt + dumqc < Real(0)) {
2467  pcc = -dumqc / dt;
2468  }
2469 
2470  morr_arr(i,j,k,MORRInd::qv3dten) = morr_arr(i,j,k,MORRInd::qv3dten) - pcc;
2471  morr_arr(i,j,k,MORRInd::t3dten) = morr_arr(i,j,k,MORRInd::t3dten) + pcc * morr_arr(i,j,k,MORRInd::xxlv) / morr_arr(i,j,k,MORRInd::cpm);
2472  morr_arr(i,j,k,MORRInd::qc3dten) = morr_arr(i,j,k,MORRInd::qc3dten) + pcc;
2473  }
2474  // SUBLIMATE, MELT, OR EVAPORATE NUMBER CONCENTRATION
2475  // THIS FORMULATION ASSUMES 1:1 RATIO BETWEEN MASS LOSS AND
2476  // LOSS OF NUMBER CONCENTRATION
2477  if (eprd < Real(0)) {
2478  dum = eprd * dt / morr_arr(i,j,k,MORRInd::qi3d);
2479  dum = std::max(-one, dum);
2480  nsubi = dum * morr_arr(i,j,k,MORRInd::ni3d) / dt;
2481  }
2482 
2483  if (eprds < Real(0)) {
2484  dum = eprds * dt / morr_arr(i,j,k,MORRInd::qni3d);
2485  dum = std::max(-one, dum);
2486  nsubs = dum * morr_arr(i,j,k,MORRInd::ns3d) / dt;
2487  }
2488 
2489  if (pre < Real(0)) {
2490  dum = pre * dt / morr_arr(i,j,k,MORRInd::qr3d);
2491  dum = std::max(-one, dum);
2492  nsubr = dum * morr_arr(i,j,k,MORRInd::nr3d) / dt;
2493  }
2494 
2495  if (eprdg < Real(0)) {
2496  dum = eprdg * dt / morr_arr(i,j,k,MORRInd::qg3d);
2497  dum = std::max(-one, dum);
2498  nsubg = dum * morr_arr(i,j,k,MORRInd::ng3d) / dt;
2499  }
2500 
2501  // UPDATE TENDENCIES
2502  morr_arr(i,j,k,MORRInd::ni3dten) = morr_arr(i,j,k,MORRInd::ni3dten) + nsubi;
2503  morr_arr(i,j,k,MORRInd::ns3dten) = morr_arr(i,j,k,MORRInd::ns3dten) + nsubs;
2504  morr_arr(i,j,k,MORRInd::ng3dten) = morr_arr(i,j,k,MORRInd::ng3dten) + nsubg;
2505  morr_arr(i,j,k,MORRInd::nr3dten) = morr_arr(i,j,k,MORRInd::nr3dten) + nsubr;
2506  }
2507  ltrue = 1;
2508  }
2509  // label_200:
2510  } // k
2511 
2512  for(int k=klo; k<=khi; k++) {
2513  // INITIALIZE PRECIP AND SNOW RATES
2514  morr_arr(i,j,k,MORRInd::precrt) = Real(0);
2515  morr_arr(i,j,k,MORRInd::snowrt) = Real(0);
2516  // hm added 7/13/13
2517  morr_arr(i,j,k,MORRInd::snowprt) = Real(0);
2518  morr_arr(i,j,k,MORRInd::grplprt) = Real(0);
2519  } // k
2520 
2521  nstep = 1;
2522 
2523  if (ltrue != 0) {
2524  //goto 400
2525  // CALCULATE SEDIMENTATION
2526  // THE NUMERICS HERE FOLLOW FROM REISNER ET AL. (1998)
2527  // FALLOUT TERMS ARE CALCULATED ON SPLIT TIME STEPS TO ENSURE NUMERICAL
2528  // STABILITY, I.E. COURANT# < 1
2529  // Loop from top to bottom (KTE to KTS)
2530  for(int k=khi; k>=klo; k--) {
2531 
2532  Real dum; // DUM: General dummy variable
2533 
2534  Real di0; // DI0: Characteristic diameter for ice
2535  Real ds0; // DS0: Characteristic diameter for snow
2536  Real dg0; // DG0: Characteristic diameter for graupel
2537  Real lammax; // LAMMAX: Maximum value for slope parameter
2538  Real lammin; // LAMMIN: Minimum value for slope parameter
2539 
2540  ds0 = three; // Size distribution parameter for snow
2541  di0 = three; // Size distribution parameter for cloud ice
2542  dg0 = three; // Size distribution parameter for graupel
2543 
2544  // Update prognostic variables with tendencies
2545  morr_arr(i,j,k,MORRInd::dumi) = morr_arr(i,j,k,MORRInd::qi3d) + morr_arr(i,j,k,MORRInd::qi3dten) * dt;
2546  morr_arr(i,j,k,MORRInd::dumqs) = morr_arr(i,j,k,MORRInd::qni3d) + morr_arr(i,j,k,MORRInd::qni3dten) * dt;
2547  morr_arr(i,j,k,MORRInd::dumr) = morr_arr(i,j,k,MORRInd::qr3d) + morr_arr(i,j,k,MORRInd::qr3dten) * dt;
2548  morr_arr(i,j,k,MORRInd::dumfni) = morr_arr(i,j,k,MORRInd::ni3d) + morr_arr(i,j,k,MORRInd::ni3dten) * dt;
2549  morr_arr(i,j,k,MORRInd::dumfns) = morr_arr(i,j,k,MORRInd::ns3d) + morr_arr(i,j,k,MORRInd::ns3dten) * dt;
2550  morr_arr(i,j,k,MORRInd::dumfnr) = morr_arr(i,j,k,MORRInd::nr3d) + morr_arr(i,j,k,MORRInd::nr3dten) * dt;
2551  morr_arr(i,j,k,MORRInd::dumc) = morr_arr(i,j,k,MORRInd::qc3d) + morr_arr(i,j,k,MORRInd::qc3dten) * dt;
2552  morr_arr(i,j,k,MORRInd::dumfnc) = morr_arr(i,j,k,MORRInd::nc3d) + morr_arr(i,j,k,MORRInd::nc3dten) * dt;
2553  morr_arr(i,j,k,MORRInd::dumg) = morr_arr(i,j,k,MORRInd::qg3d) + morr_arr(i,j,k,MORRInd::qg3dten) * dt;
2554  morr_arr(i,j,k,MORRInd::dumfng) = morr_arr(i,j,k,MORRInd::ng3d) + morr_arr(i,j,k,MORRInd::ng3dten) * dt;
2555 
2556  // SWITCH FOR CONSTANT DROPLET NUMBER
2557  if (iinum == 1) {
2558  morr_arr(i,j,k,MORRInd::dumfnc) = morr_arr(i,j,k,MORRInd::nc3d);
2559  }
2560 
2561  // MAKE SURE NUMBER CONCENTRATIONS ARE POSITIVE
2562  morr_arr(i,j,k,MORRInd::dumfni) = amrex::max(Real(0), morr_arr(i,j,k,MORRInd::dumfni));
2563  morr_arr(i,j,k,MORRInd::dumfns) = amrex::max(Real(0), morr_arr(i,j,k,MORRInd::dumfns));
2564  morr_arr(i,j,k,MORRInd::dumfnc) = amrex::max(Real(0), morr_arr(i,j,k,MORRInd::dumfnc));
2565  morr_arr(i,j,k,MORRInd::dumfnr) = amrex::max(Real(0), morr_arr(i,j,k,MORRInd::dumfnr));
2566  morr_arr(i,j,k,MORRInd::dumfng) = amrex::max(Real(0), morr_arr(i,j,k,MORRInd::dumfng));
2567 
2568  // CLOUD ICE
2569  if (morr_arr(i,j,k,MORRInd::dumi) >= m_qsmall) {
2570  morr_arr(i,j,k,MORRInd::dlami) = std::pow(m_cons12 * morr_arr(i,j,k,MORRInd::dumfni) / morr_arr(i,j,k,MORRInd::dumi), one/di0);
2571  morr_arr(i,j,k,MORRInd::dlami) = amrex::max(morr_arr(i,j,k,MORRInd::dlami), m_lammini);
2572  morr_arr(i,j,k,MORRInd::dlami) = amrex::min(morr_arr(i,j,k,MORRInd::dlami), m_lammaxi);
2573  }
2574 
2575  // RAIN
2576  if (morr_arr(i,j,k,MORRInd::dumr) >= m_qsmall) {
2577  morr_arr(i,j,k,MORRInd::dlamr) = std::pow(m_pi * m_rhow * morr_arr(i,j,k,MORRInd::dumfnr) / morr_arr(i,j,k,MORRInd::dumr), one/three);
2578  morr_arr(i,j,k,MORRInd::dlamr) = amrex::max(morr_arr(i,j,k,MORRInd::dlamr), m_lamminr);
2579  morr_arr(i,j,k,MORRInd::dlamr) = amrex::min(morr_arr(i,j,k,MORRInd::dlamr), m_lammaxr);
2580  }
2581 
2582  // CLOUD DROPLETS
2583  if (morr_arr(i,j,k,MORRInd::dumc) >= m_qsmall) {
2584  dum = morr_arr(i,j,k,MORRInd::pres) / (Real(287.15) * morr_arr(i,j,k,MORRInd::t3d));
2585  morr_arr(i,j,k,MORRInd::pgam) = Real(0.0005714) * (morr_arr(i,j,k,MORRInd::nc3d) / Real(1.0e6) * dum) + Real(0.2714);
2586  morr_arr(i,j,k,MORRInd::pgam) = one / (morr_arr(i,j,k,MORRInd::pgam) * morr_arr(i,j,k,MORRInd::pgam)) - one;
2587  morr_arr(i,j,k,MORRInd::pgam) = amrex::max(morr_arr(i,j,k,MORRInd::pgam), Real(2));
2588  morr_arr(i,j,k,MORRInd::pgam) = amrex::min(morr_arr(i,j,k,MORRInd::pgam), Real(10.0));
2589 
2590  morr_arr(i,j,k,MORRInd::dlamc) = std::pow(m_cons26 * morr_arr(i,j,k,MORRInd::dumfnc) * gamma_function(morr_arr(i,j,k,MORRInd::pgam) + Real(4.0)) /
2591  (morr_arr(i,j,k,MORRInd::dumc) * gamma_function(morr_arr(i,j,k,MORRInd::pgam) + one)), one/three);
2592  lammin = (morr_arr(i,j,k,MORRInd::pgam) + one) / Real(60.0e-6);
2593  lammax = (morr_arr(i,j,k,MORRInd::pgam) + one) / Real(1.0e-6);
2594  morr_arr(i,j,k,MORRInd::dlamc) = amrex::max(morr_arr(i,j,k,MORRInd::dlamc), lammin);
2595  morr_arr(i,j,k,MORRInd::dlamc) = amrex::min(morr_arr(i,j,k,MORRInd::dlamc), lammax);
2596  }
2597 
2598  // SNOW
2599  if (morr_arr(i,j,k,MORRInd::dumqs) >= m_qsmall) {
2600  morr_arr(i,j,k,MORRInd::dlams) = std::pow(m_cons1 * morr_arr(i,j,k,MORRInd::dumfns) / morr_arr(i,j,k,MORRInd::dumqs), one/ds0);
2601  morr_arr(i,j,k,MORRInd::dlams) = amrex::max(morr_arr(i,j,k,MORRInd::dlams), m_lammins);
2602  morr_arr(i,j,k,MORRInd::dlams) = amrex::min(morr_arr(i,j,k,MORRInd::dlams), m_lammaxs);
2603  }
2604 
2605  // GRAUPEL
2606  if (morr_arr(i,j,k,MORRInd::dumg) >= m_qsmall) {
2607  morr_arr(i,j,k,MORRInd::dlamg) = std::pow(m_cons2 * morr_arr(i,j,k,MORRInd::dumfng) / morr_arr(i,j,k,MORRInd::dumg), one/dg0);
2608  morr_arr(i,j,k,MORRInd::dlamg) = amrex::max(morr_arr(i,j,k,MORRInd::dlamg), m_lamming);
2609  morr_arr(i,j,k,MORRInd::dlamg) = amrex::min(morr_arr(i,j,k,MORRInd::dlamg), m_lammaxg);
2610  }
2611 
2612  // Calculate number-weighted and mass-weighted terminal fall speeds
2613  // CLOUD WATER
2614  if (morr_arr(i,j,k,MORRInd::dumc) >= m_qsmall) {
2615  morr_arr(i,j,k,MORRInd::unc) = morr_arr(i,j,k,MORRInd::acn) * gamma_function(one + m_bc + morr_arr(i,j,k,MORRInd::pgam)) /
2616  (std::pow(morr_arr(i,j,k,MORRInd::dlamc), m_bc) * gamma_function(morr_arr(i,j,k,MORRInd::pgam) + one));
2617  morr_arr(i,j,k,MORRInd::umc) = morr_arr(i,j,k,MORRInd::acn) * gamma_function(Real(4.) + m_bc + morr_arr(i,j,k,MORRInd::pgam)) /
2618  (std::pow(morr_arr(i,j,k,MORRInd::dlamc), m_bc) * gamma_function(morr_arr(i,j,k,MORRInd::pgam) + Real(4.)));
2619  } else {
2620  morr_arr(i,j,k,MORRInd::umc) = Real(0);
2621  morr_arr(i,j,k,MORRInd::unc) = Real(0);
2622  }
2623 
2624  // CLOUD ICE
2625  if (morr_arr(i,j,k,MORRInd::dumi) >= m_qsmall) {
2626  morr_arr(i,j,k,MORRInd::uni) = morr_arr(i,j,k,MORRInd::ain) * m_cons27 / std::pow(morr_arr(i,j,k,MORRInd::dlami), m_bi);
2627  morr_arr(i,j,k,MORRInd::umi) = morr_arr(i,j,k,MORRInd::ain) * m_cons28 / std::pow(morr_arr(i,j,k,MORRInd::dlami), m_bi);
2628  } else {
2629  morr_arr(i,j,k,MORRInd::umi) = Real(0);
2630  morr_arr(i,j,k,MORRInd::uni) = Real(0);
2631  }
2632 
2633  // RAIN
2634  if (morr_arr(i,j,k,MORRInd::dumr) >= m_qsmall) {
2635  morr_arr(i,j,k,MORRInd::unr) = morr_arr(i,j,k,MORRInd::arn) * m_cons6 / std::pow(morr_arr(i,j,k,MORRInd::dlamr), m_br);
2636  morr_arr(i,j,k,MORRInd::umr) = morr_arr(i,j,k,MORRInd::arn) * m_cons4 / std::pow(morr_arr(i,j,k,MORRInd::dlamr), m_br);
2637  } else {
2638  morr_arr(i,j,k,MORRInd::umr) = Real(0);
2639  morr_arr(i,j,k,MORRInd::unr) = Real(0);
2640  }
2641 
2642  // SNOW
2643  if (morr_arr(i,j,k,MORRInd::dumqs) >= m_qsmall) {
2644  morr_arr(i,j,k,MORRInd::ums) = morr_arr(i,j,k,MORRInd::asn) * m_cons3 / std::pow(morr_arr(i,j,k,MORRInd::dlams), m_bs);
2645  morr_arr(i,j,k,MORRInd::uns) = morr_arr(i,j,k,MORRInd::asn) * m_cons5 / std::pow(morr_arr(i,j,k,MORRInd::dlams), m_bs);
2646  } else {
2647  morr_arr(i,j,k,MORRInd::ums) = Real(0);
2648  morr_arr(i,j,k,MORRInd::uns) = Real(0);
2649  }
2650 
2651  // GRAUPEL
2652  if (morr_arr(i,j,k,MORRInd::dumg) >= m_qsmall) {
2653  morr_arr(i,j,k,MORRInd::umg) = morr_arr(i,j,k,MORRInd::agn) * m_cons7 / std::pow(morr_arr(i,j,k,MORRInd::dlamg), m_bg);
2654  morr_arr(i,j,k,MORRInd::ung) = morr_arr(i,j,k,MORRInd::agn) * m_cons8 / std::pow(morr_arr(i,j,k,MORRInd::dlamg), m_bg);
2655  } else {
2656  morr_arr(i,j,k,MORRInd::umg) = Real(0);
2657  morr_arr(i,j,k,MORRInd::ung) = Real(0);
2658  }
2659 
2660  // SET REALISTIC LIMITS ON FALLSPEED
2661  // Bug fix, 10/08/09
2662  dum = std::pow(m_rhosu / morr_arr(i,j,k,MORRInd::rho), Real(0.54));
2663  morr_arr(i,j,k,MORRInd::ums) = std::min(morr_arr(i,j,k,MORRInd::ums), Real(1.2) * dum);
2664  morr_arr(i,j,k,MORRInd::uns) = std::min(morr_arr(i,j,k,MORRInd::uns), Real(1.2) * dum);
2665 
2666  // Fix 053011
2667  // Fix for correction by AA 4/6/11
2668  morr_arr(i,j,k,MORRInd::umi) = std::min(morr_arr(i,j,k,MORRInd::umi), Real(1.2) * std::pow(m_rhosu / morr_arr(i,j,k,MORRInd::rho), Real(0.35)));
2669  morr_arr(i,j,k,MORRInd::uni) = std::min(morr_arr(i,j,k,MORRInd::uni), Real(1.2) * std::pow(m_rhosu / morr_arr(i,j,k,MORRInd::rho), Real(0.35)));
2670  morr_arr(i,j,k,MORRInd::umr) = std::min(morr_arr(i,j,k,MORRInd::umr), Real(9.1) * dum);
2671  morr_arr(i,j,k,MORRInd::unr) = std::min(morr_arr(i,j,k,MORRInd::unr), Real(9.1) * dum);
2672  morr_arr(i,j,k,MORRInd::umg) = std::min(morr_arr(i,j,k,MORRInd::umg), Real(20.) * dum);
2673  morr_arr(i,j,k,MORRInd::ung) = std::min(morr_arr(i,j,k,MORRInd::ung), Real(20.) * dum);
2674 
2675  // Set fall speed values
2676  morr_arr(i,j,k,MORRInd::fr) = morr_arr(i,j,k,MORRInd::umr); // RAIN FALL SPEED
2677  morr_arr(i,j,k,MORRInd::fi) = morr_arr(i,j,k,MORRInd::umi); // CLOUD ICE FALL SPEED
2678  morr_arr(i,j,k,MORRInd::fni) = morr_arr(i,j,k,MORRInd::uni); // CLOUD ICE NUMBER FALL SPEED
2679  morr_arr(i,j,k,MORRInd::fs) = morr_arr(i,j,k,MORRInd::ums); // SNOW FALL SPEED
2680  morr_arr(i,j,k,MORRInd::fns) = morr_arr(i,j,k,MORRInd::uns); // SNOW NUMBER FALL SPEED
2681  morr_arr(i,j,k,MORRInd::fnr) = morr_arr(i,j,k,MORRInd::unr); // RAIN NUMBER FALL SPEED
2682  morr_arr(i,j,k,MORRInd::fc) = morr_arr(i,j,k,MORRInd::umc); // CLOUD WATER FALL SPEED
2683  morr_arr(i,j,k,MORRInd::fnc) = morr_arr(i,j,k,MORRInd::unc); // CLOUD NUMBER FALL SPEED
2684  morr_arr(i,j,k,MORRInd::fg) = morr_arr(i,j,k,MORRInd::umg); // GRAUPEL FALL SPEED
2685  morr_arr(i,j,k,MORRInd::fng) = morr_arr(i,j,k,MORRInd::ung); // GRAUPEL NUMBER FALL SPEED
2686 
2687  // V3.3 MODIFY FALLSPEED BELOW LEVEL OF PRECIP
2688  if (morr_arr(i,j,k,MORRInd::fr) < Real(1.e-10)) {
2689  morr_arr(i,j,k,MORRInd::fr) = morr_arr(i,j,k+1,MORRInd::fr);
2690  }
2691  if (morr_arr(i,j,k,MORRInd::fi) < Real(1.e-10)) {
2692  morr_arr(i,j,k,MORRInd::fi) = morr_arr(i,j,k+1,MORRInd::fi);
2693  }
2694  if (morr_arr(i,j,k,MORRInd::fni) < Real(1.e-10)) {
2695  morr_arr(i,j,k,MORRInd::fni) = morr_arr(i,j,k+1,MORRInd::fni);
2696  }
2697  if (morr_arr(i,j,k,MORRInd::fs) < Real(1.e-10)) {
2698  morr_arr(i,j,k,MORRInd::fs) = morr_arr(i,j,k+1,MORRInd::fs);
2699  }
2700  if (morr_arr(i,j,k,MORRInd::fns) < Real(1.e-10)) {
2701  morr_arr(i,j,k,MORRInd::fns) = morr_arr(i,j,k+1,MORRInd::fns);
2702  }
2703  if (morr_arr(i,j,k,MORRInd::fnr) < Real(1.e-10)) {
2704  morr_arr(i,j,k,MORRInd::fnr) = morr_arr(i,j,k+1,MORRInd::fnr);
2705  }
2706  if (morr_arr(i,j,k,MORRInd::fc) < Real(1.e-10)) {
2707  morr_arr(i,j,k,MORRInd::fc) = morr_arr(i,j,k+1,MORRInd::fc);
2708  }
2709  if (morr_arr(i,j,k,MORRInd::fnc) < Real(1.e-10)) {
2710  morr_arr(i,j,k,MORRInd::fnc) = morr_arr(i,j,k+1,MORRInd::fnc);
2711  }
2712  if (morr_arr(i,j,k,MORRInd::fg) < Real(1.e-10)) {
2713  morr_arr(i,j,k,MORRInd::fg) = morr_arr(i,j,k+1,MORRInd::fg);
2714  }
2715  if (morr_arr(i,j,k,MORRInd::fng) < Real(1.e-10)) {
2716  morr_arr(i,j,k,MORRInd::fng) = morr_arr(i,j,k+1,MORRInd::fng);
2717  }
2718 
2719  // CALCULATE NUMBER OF SPLIT TIME STEPS
2720  // Find maximum fall speed at this point
2721  morr_arr(i,j,k,MORRInd::rgvm) = std::max({morr_arr(i,j,k,MORRInd::fr), morr_arr(i,j,k,MORRInd::fi), morr_arr(i,j,k,MORRInd::fs), morr_arr(i,j,k,MORRInd::fc),
2722  morr_arr(i,j,k,MORRInd::fni), morr_arr(i,j,k,MORRInd::fnr), morr_arr(i,j,k,MORRInd::fns), morr_arr(i,j,k,MORRInd::fnc),
2723  morr_arr(i,j,k,MORRInd::fg), morr_arr(i,j,k,MORRInd::fng)});
2724 
2725  // Calculate number of steps (dt and nstep would need to be defined elsewhere)
2726  nstep = std::max(static_cast<int>(morr_arr(i,j,k,MORRInd::rgvm) * dt / morr_arr(i,j,k,MORRInd::dzq) + one), nstep);
2727  // MULTIPLY VARIABLES BY RHO
2728  morr_arr(i,j,k,MORRInd::dumr) = morr_arr(i,j,k,MORRInd::dumr) * morr_arr(i,j,k,MORRInd::rho); // Rain water content * density
2729  morr_arr(i,j,k,MORRInd::dumi) = morr_arr(i,j,k,MORRInd::dumi) * morr_arr(i,j,k,MORRInd::rho); // Cloud ice content * density
2730  morr_arr(i,j,k,MORRInd::dumfni) = morr_arr(i,j,k,MORRInd::dumfni) * morr_arr(i,j,k,MORRInd::rho); // Cloud ice number * density
2731  morr_arr(i,j,k,MORRInd::dumqs) = morr_arr(i,j,k,MORRInd::dumqs) * morr_arr(i,j,k,MORRInd::rho); // Snow content * density
2732  morr_arr(i,j,k,MORRInd::dumfns) = morr_arr(i,j,k,MORRInd::dumfns) * morr_arr(i,j,k,MORRInd::rho); // Snow number * density
2733  morr_arr(i,j,k,MORRInd::dumfnr) = morr_arr(i,j,k,MORRInd::dumfnr) * morr_arr(i,j,k,MORRInd::rho); // Rain number * density
2734  morr_arr(i,j,k,MORRInd::dumc) = morr_arr(i,j,k,MORRInd::dumc) * morr_arr(i,j,k,MORRInd::rho); // Cloud water content * density
2735  morr_arr(i,j,k,MORRInd::dumfnc) = morr_arr(i,j,k,MORRInd::dumfnc) * morr_arr(i,j,k,MORRInd::rho); // Cloud droplet number * density
2736  morr_arr(i,j,k,MORRInd::dumg) = morr_arr(i,j,k,MORRInd::dumg) * morr_arr(i,j,k,MORRInd::rho); // Graupel content * density
2737  morr_arr(i,j,k,MORRInd::dumfng) = morr_arr(i,j,k,MORRInd::dumfng) * morr_arr(i,j,k,MORRInd::rho); // Graupel number * density
2738  } // k
2739 
2740  // Main time stepping loop for sedimentation
2741  for (int n = 1; n <= nstep; n++) {
2742  // Calculate initial fallout for each hydrometeor type for all levels
2743  for (int k = klo; k <= khi; k++) {
2744  morr_arr(i,j,k,MORRInd::faloutr) = morr_arr(i,j,k,MORRInd::fr) * morr_arr(i,j,k,MORRInd::dumr);
2745  morr_arr(i,j,k,MORRInd::falouti) = morr_arr(i,j,k,MORRInd::fi) * morr_arr(i,j,k,MORRInd::dumi);
2746  morr_arr(i,j,k,MORRInd::faloutni) = morr_arr(i,j,k,MORRInd::fni) * morr_arr(i,j,k,MORRInd::dumfni);
2747  morr_arr(i,j,k,MORRInd::falouts) = morr_arr(i,j,k,MORRInd::fs) * morr_arr(i,j,k,MORRInd::dumqs);
2748  morr_arr(i,j,k,MORRInd::faloutns) = morr_arr(i,j,k,MORRInd::fns) * morr_arr(i,j,k,MORRInd::dumfns);
2749  morr_arr(i,j,k,MORRInd::faloutnr) = morr_arr(i,j,k,MORRInd::fnr) * morr_arr(i,j,k,MORRInd::dumfnr);
2750  morr_arr(i,j,k,MORRInd::faloutc) = morr_arr(i,j,k,MORRInd::fc) * morr_arr(i,j,k,MORRInd::dumc);
2751  morr_arr(i,j,k,MORRInd::faloutnc) = morr_arr(i,j,k,MORRInd::fnc) * morr_arr(i,j,k,MORRInd::dumfnc);
2752  morr_arr(i,j,k,MORRInd::faloutg) = morr_arr(i,j,k,MORRInd::fg) * morr_arr(i,j,k,MORRInd::dumg);
2753  morr_arr(i,j,k,MORRInd::faloutng) = morr_arr(i,j,k,MORRInd::fng) * morr_arr(i,j,k,MORRInd::dumfng);
2754  } //k
2755 
2756  // Process top of model level
2757  int k = khi;
2758 
2759  // Calculate tendencies at top level
2760  morr_arr(i,j,k,MORRInd::faltndr) = morr_arr(i,j,k,MORRInd::faloutr) / morr_arr(i,j,k,MORRInd::dzq);
2761  morr_arr(i,j,k,MORRInd::faltndi) = morr_arr(i,j,k,MORRInd::falouti) / morr_arr(i,j,k,MORRInd::dzq);
2762  morr_arr(i,j,k,MORRInd::faltndni) = morr_arr(i,j,k,MORRInd::faloutni) / morr_arr(i,j,k,MORRInd::dzq);
2763  morr_arr(i,j,k,MORRInd::faltnds) = morr_arr(i,j,k,MORRInd::falouts) / morr_arr(i,j,k,MORRInd::dzq);
2764  morr_arr(i,j,k,MORRInd::faltndns) = morr_arr(i,j,k,MORRInd::faloutns) / morr_arr(i,j,k,MORRInd::dzq);
2765  morr_arr(i,j,k,MORRInd::faltndnr) = morr_arr(i,j,k,MORRInd::faloutnr) / morr_arr(i,j,k,MORRInd::dzq);
2766  morr_arr(i,j,k,MORRInd::faltndc) = morr_arr(i,j,k,MORRInd::faloutc) / morr_arr(i,j,k,MORRInd::dzq);
2767  morr_arr(i,j,k,MORRInd::faltndnc) = morr_arr(i,j,k,MORRInd::faloutnc) / morr_arr(i,j,k,MORRInd::dzq);
2768  morr_arr(i,j,k,MORRInd::faltndg) = morr_arr(i,j,k,MORRInd::faloutg) / morr_arr(i,j,k,MORRInd::dzq);
2769  morr_arr(i,j,k,MORRInd::faltndng) = morr_arr(i,j,k,MORRInd::faloutng) / morr_arr(i,j,k,MORRInd::dzq);
2770 
2771  // Add fallout terms to Eulerian tendencies (scaled by time step and density)
2772  morr_arr(i,j,k,MORRInd::qrsten) = morr_arr(i,j,k,MORRInd::qrsten) - morr_arr(i,j,k,MORRInd::faltndr) / nstep / morr_arr(i,j,k,MORRInd::rho);
2773  morr_arr(i,j,k,MORRInd::qisten) = morr_arr(i,j,k,MORRInd::qisten) - morr_arr(i,j,k,MORRInd::faltndi) / nstep / morr_arr(i,j,k,MORRInd::rho);
2774  morr_arr(i,j,k,MORRInd::ni3dten) = morr_arr(i,j,k,MORRInd::ni3dten) - morr_arr(i,j,k,MORRInd::faltndni) / nstep / morr_arr(i,j,k,MORRInd::rho);
2775  morr_arr(i,j,k,MORRInd::qnisten) = morr_arr(i,j,k,MORRInd::qnisten) - morr_arr(i,j,k,MORRInd::faltnds) / nstep / morr_arr(i,j,k,MORRInd::rho);
2776  morr_arr(i,j,k,MORRInd::ns3dten) = morr_arr(i,j,k,MORRInd::ns3dten) - morr_arr(i,j,k,MORRInd::faltndns) / nstep / morr_arr(i,j,k,MORRInd::rho);
2777  morr_arr(i,j,k,MORRInd::nr3dten) = morr_arr(i,j,k,MORRInd::nr3dten) - morr_arr(i,j,k,MORRInd::faltndnr) / nstep / morr_arr(i,j,k,MORRInd::rho);
2778  morr_arr(i,j,k,MORRInd::qcsten) = morr_arr(i,j,k,MORRInd::qcsten) - morr_arr(i,j,k,MORRInd::faltndc) / nstep / morr_arr(i,j,k,MORRInd::rho);
2779  morr_arr(i,j,k,MORRInd::nc3dten) = morr_arr(i,j,k,MORRInd::nc3dten) - morr_arr(i,j,k,MORRInd::faltndnc) / nstep / morr_arr(i,j,k,MORRInd::rho);
2780  morr_arr(i,j,k,MORRInd::qgsten) = morr_arr(i,j,k,MORRInd::qgsten) - morr_arr(i,j,k,MORRInd::faltndg) / nstep / morr_arr(i,j,k,MORRInd::rho);
2781  morr_arr(i,j,k,MORRInd::ng3dten) = morr_arr(i,j,k,MORRInd::ng3dten) - morr_arr(i,j,k,MORRInd::faltndng) / nstep / morr_arr(i,j,k,MORRInd::rho);
2782 
2783  // Update temporary working variables
2784  morr_arr(i,j,k,MORRInd::dumr) = morr_arr(i,j,k,MORRInd::dumr) - morr_arr(i,j,k,MORRInd::faltndr) * dt / nstep;
2785  morr_arr(i,j,k,MORRInd::dumi) = morr_arr(i,j,k,MORRInd::dumi) - morr_arr(i,j,k,MORRInd::faltndi) * dt / nstep;
2786  morr_arr(i,j,k,MORRInd::dumfni) = morr_arr(i,j,k,MORRInd::dumfni) - morr_arr(i,j,k,MORRInd::faltndni) * dt / nstep;
2787  morr_arr(i,j,k,MORRInd::dumqs) = morr_arr(i,j,k,MORRInd::dumqs) - morr_arr(i,j,k,MORRInd::faltnds) * dt / nstep;
2788  morr_arr(i,j,k,MORRInd::dumfns) = morr_arr(i,j,k,MORRInd::dumfns) - morr_arr(i,j,k,MORRInd::faltndns) * dt / nstep;
2789  morr_arr(i,j,k,MORRInd::dumfnr) = morr_arr(i,j,k,MORRInd::dumfnr) - morr_arr(i,j,k,MORRInd::faltndnr) * dt / nstep;
2790  morr_arr(i,j,k,MORRInd::dumc) = morr_arr(i,j,k,MORRInd::dumc) - morr_arr(i,j,k,MORRInd::faltndc) * dt / nstep;
2791  morr_arr(i,j,k,MORRInd::dumfnc) = morr_arr(i,j,k,MORRInd::dumfnc) - morr_arr(i,j,k,MORRInd::faltndnc) * dt / nstep;
2792  morr_arr(i,j,k,MORRInd::dumg) = morr_arr(i,j,k,MORRInd::dumg) - morr_arr(i,j,k,MORRInd::faltndg) * dt / nstep;
2793  morr_arr(i,j,k,MORRInd::dumfng) = morr_arr(i,j,k,MORRInd::dumfng) - morr_arr(i,j,k,MORRInd::faltndng) * dt / nstep;
2794 
2795  // Process remaining levels from top to bottom
2796  for (k = khi-1; k >= klo; k--) {
2797  // Calculate tendencies based on difference between levels
2798  morr_arr(i,j,k,MORRInd::faltndr) = (morr_arr(i,j,k+1,MORRInd::faloutr) - morr_arr(i,j,k,MORRInd::faloutr)) / morr_arr(i,j,k,MORRInd::dzq);
2799  morr_arr(i,j,k,MORRInd::faltndi) = (morr_arr(i,j,k+1,MORRInd::falouti) - morr_arr(i,j,k,MORRInd::falouti)) / morr_arr(i,j,k,MORRInd::dzq);
2800  morr_arr(i,j,k,MORRInd::faltndni) = (morr_arr(i,j,k+1,MORRInd::faloutni) - morr_arr(i,j,k,MORRInd::faloutni)) / morr_arr(i,j,k,MORRInd::dzq);
2801  morr_arr(i,j,k,MORRInd::faltnds) = (morr_arr(i,j,k+1,MORRInd::falouts) - morr_arr(i,j,k,MORRInd::falouts)) / morr_arr(i,j,k,MORRInd::dzq);
2802  morr_arr(i,j,k,MORRInd::faltndns) = (morr_arr(i,j,k+1,MORRInd::faloutns) - morr_arr(i,j,k,MORRInd::faloutns)) / morr_arr(i,j,k,MORRInd::dzq);
2803  morr_arr(i,j,k,MORRInd::faltndnr) = (morr_arr(i,j,k+1,MORRInd::faloutnr) - morr_arr(i,j,k,MORRInd::faloutnr)) / morr_arr(i,j,k,MORRInd::dzq);
2804  morr_arr(i,j,k,MORRInd::faltndc) = (morr_arr(i,j,k+1,MORRInd::faloutc) - morr_arr(i,j,k,MORRInd::faloutc)) / morr_arr(i,j,k,MORRInd::dzq);
2805  morr_arr(i,j,k,MORRInd::faltndnc) = (morr_arr(i,j,k+1,MORRInd::faloutnc) - morr_arr(i,j,k,MORRInd::faloutnc)) / morr_arr(i,j,k,MORRInd::dzq);
2806  morr_arr(i,j,k,MORRInd::faltndg) = (morr_arr(i,j,k+1,MORRInd::faloutg) - morr_arr(i,j,k,MORRInd::faloutg)) / morr_arr(i,j,k,MORRInd::dzq);
2807  morr_arr(i,j,k,MORRInd::faltndng) = (morr_arr(i,j,k+1,MORRInd::faloutng) - morr_arr(i,j,k,MORRInd::faloutng)) / morr_arr(i,j,k,MORRInd::dzq);
2808 
2809  // Add fallout terms to Eulerian tendencies (positive here, as mass flows in from above)
2810  morr_arr(i,j,k,MORRInd::qrsten) = morr_arr(i,j,k,MORRInd::qrsten) + morr_arr(i,j,k,MORRInd::faltndr) / nstep / morr_arr(i,j,k,MORRInd::rho);
2811  morr_arr(i,j,k,MORRInd::qisten) = morr_arr(i,j,k,MORRInd::qisten) + morr_arr(i,j,k,MORRInd::faltndi) / nstep / morr_arr(i,j,k,MORRInd::rho);
2812  morr_arr(i,j,k,MORRInd::ni3dten) = morr_arr(i,j,k,MORRInd::ni3dten) + morr_arr(i,j,k,MORRInd::faltndni) / nstep / morr_arr(i,j,k,MORRInd::rho);
2813  morr_arr(i,j,k,MORRInd::qnisten) = morr_arr(i,j,k,MORRInd::qnisten) + morr_arr(i,j,k,MORRInd::faltnds) / nstep / morr_arr(i,j,k,MORRInd::rho);
2814  morr_arr(i,j,k,MORRInd::ns3dten) = morr_arr(i,j,k,MORRInd::ns3dten) + morr_arr(i,j,k,MORRInd::faltndns) / nstep / morr_arr(i,j,k,MORRInd::rho);
2815  morr_arr(i,j,k,MORRInd::nr3dten) = morr_arr(i,j,k,MORRInd::nr3dten) + morr_arr(i,j,k,MORRInd::faltndnr) / nstep / morr_arr(i,j,k,MORRInd::rho);
2816  morr_arr(i,j,k,MORRInd::qcsten) = morr_arr(i,j,k,MORRInd::qcsten) + morr_arr(i,j,k,MORRInd::faltndc) / nstep / morr_arr(i,j,k,MORRInd::rho);
2817  morr_arr(i,j,k,MORRInd::nc3dten) = morr_arr(i,j,k,MORRInd::nc3dten) + morr_arr(i,j,k,MORRInd::faltndnc) / nstep / morr_arr(i,j,k,MORRInd::rho);
2818  morr_arr(i,j,k,MORRInd::qgsten) = morr_arr(i,j,k,MORRInd::qgsten) + morr_arr(i,j,k,MORRInd::faltndg) / nstep / morr_arr(i,j,k,MORRInd::rho);
2819  morr_arr(i,j,k,MORRInd::ng3dten) = morr_arr(i,j,k,MORRInd::ng3dten) + morr_arr(i,j,k,MORRInd::faltndng) / nstep / morr_arr(i,j,k,MORRInd::rho);
2820  // Update temporary working variables
2821  morr_arr(i,j,k,MORRInd::dumr) = morr_arr(i,j,k,MORRInd::dumr) + morr_arr(i,j,k,MORRInd::faltndr) * dt / nstep;
2822  morr_arr(i,j,k,MORRInd::dumi) = morr_arr(i,j,k,MORRInd::dumi) + morr_arr(i,j,k,MORRInd::faltndi) * dt / nstep;
2823  morr_arr(i,j,k,MORRInd::dumfni) = morr_arr(i,j,k,MORRInd::dumfni) + morr_arr(i,j,k,MORRInd::faltndni) * dt / nstep;
2824  morr_arr(i,j,k,MORRInd::dumqs) = morr_arr(i,j,k,MORRInd::dumqs) + morr_arr(i,j,k,MORRInd::faltnds) * dt / nstep;
2825  morr_arr(i,j,k,MORRInd::dumfns) = morr_arr(i,j,k,MORRInd::dumfns) + morr_arr(i,j,k,MORRInd::faltndns) * dt / nstep;
2826  morr_arr(i,j,k,MORRInd::dumfnr) = morr_arr(i,j,k,MORRInd::dumfnr) + morr_arr(i,j,k,MORRInd::faltndnr) * dt / nstep;
2827  morr_arr(i,j,k,MORRInd::dumc) = morr_arr(i,j,k,MORRInd::dumc) + morr_arr(i,j,k,MORRInd::faltndc) * dt / nstep;
2828  morr_arr(i,j,k,MORRInd::dumfnc) = morr_arr(i,j,k,MORRInd::dumfnc) + morr_arr(i,j,k,MORRInd::faltndnc) * dt / nstep;
2829  morr_arr(i,j,k,MORRInd::dumg) = morr_arr(i,j,k,MORRInd::dumg) + morr_arr(i,j,k,MORRInd::faltndg) * dt / nstep;
2830  morr_arr(i,j,k,MORRInd::dumfng) = morr_arr(i,j,k,MORRInd::dumfng) + morr_arr(i,j,k,MORRInd::faltndng) * dt / nstep;
2831  }
2832  // Get precipitation and snowfall accumulation during the time step
2833  // Factor of 1000 converts from m to mm, but division by density
2834  // of liquid water cancels this factor of 1000
2835  int kts=klo;
2836  morr_arr(i,j,klo,MORRInd::precrt) += (morr_arr(i,j,kts,MORRInd::faloutr) + morr_arr(i,j,kts,MORRInd::faloutc) + morr_arr(i,j,kts,MORRInd::falouts) +
2837  morr_arr(i,j,kts,MORRInd::falouti) + morr_arr(i,j,kts,MORRInd::faloutg)) * dt / nstep;
2838  morr_arr(i,j,klo,MORRInd::snowrt) += (morr_arr(i,j,kts,MORRInd::falouts) + morr_arr(i,j,kts,MORRInd::falouti) + morr_arr(i,j,kts,MORRInd::faloutg)) * dt / nstep;
2839 
2840  // Added 7/13/13
2841  morr_arr(i,j,klo,MORRInd::snowprt) += (morr_arr(i,j,kts,MORRInd::falouti) + morr_arr(i,j,kts,MORRInd::falouts)) * dt / nstep;
2842  morr_arr(i,j,klo,MORRInd::grplprt) += morr_arr(i,j,kts,MORRInd::faloutg) * dt / nstep;
2843  }
2844 
2845  for(int k=klo; k<=khi; k++) {
2846  Real evs; // EVS: Saturation vapor pressure
2847  Real eis; // EIS: Ice saturation vapor pressure
2848  Real qvs; // QVS: Saturation mixing ratio
2849  Real qvi; // QVI: Ice saturation mixing ratio
2850  Real qvqvs; // QVQVS: Saturation ratio
2851  Real qvqvsi; // QVQVSI: Ice saturation ratio
2852 
2853  // ADD ON SEDIMENTATION TENDENCIES FOR MIXING RATIO TO REST OF TENDENCIES
2854  morr_arr(i,j,k,MORRInd::qr3dten) = morr_arr(i,j,k,MORRInd::qr3dten) + morr_arr(i,j,k,MORRInd::qrsten);
2855  morr_arr(i,j,k,MORRInd::qi3dten) = morr_arr(i,j,k,MORRInd::qi3dten) + morr_arr(i,j,k,MORRInd::qisten);
2856  morr_arr(i,j,k,MORRInd::qc3dten) = morr_arr(i,j,k,MORRInd::qc3dten) + morr_arr(i,j,k,MORRInd::qcsten);
2857  morr_arr(i,j,k,MORRInd::qg3dten) = morr_arr(i,j,k,MORRInd::qg3dten) + morr_arr(i,j,k,MORRInd::qgsten);
2858  morr_arr(i,j,k,MORRInd::qni3dten) = morr_arr(i,j,k,MORRInd::qni3dten) + morr_arr(i,j,k,MORRInd::qnisten);
2859  // PUT ALL CLOUD ICE IN SNOW CATEGORY IF MEAN DIAMETER EXCEEDS 2 * dcs
2860  // bug fix
2861  if (morr_arr(i,j,k,MORRInd::qi3d) >= m_qsmall && morr_arr(i,j,k,MORRInd::t3d) < Real(273.15) && morr_arr(i,j,k,MORRInd::lami) >= Real(1.e-10)) {
2862  if (one/morr_arr(i,j,k,MORRInd::lami) >= Real(2)*m_dcs) {
2863  morr_arr(i,j,k,MORRInd::qni3dten) = morr_arr(i,j,k,MORRInd::qni3dten) + morr_arr(i,j,k,MORRInd::qi3d)/dt + morr_arr(i,j,k,MORRInd::qi3dten);
2864  morr_arr(i,j,k,MORRInd::ns3dten) = morr_arr(i,j,k,MORRInd::ns3dten) + morr_arr(i,j,k,MORRInd::ni3d)/dt + morr_arr(i,j,k,MORRInd::ni3dten);
2865  morr_arr(i,j,k,MORRInd::qi3dten) = -morr_arr(i,j,k,MORRInd::qi3d)/dt;
2866  morr_arr(i,j,k,MORRInd::ni3dten) = -morr_arr(i,j,k,MORRInd::ni3d)/dt;
2867  }
2868  }
2869 
2870  // Add tendencies to ensure consistency between mixing ratio and number concentration
2871  morr_arr(i,j,k,MORRInd::qc3d) = morr_arr(i,j,k,MORRInd::qc3d) + morr_arr(i,j,k,MORRInd::qc3dten)*dt;
2872  morr_arr(i,j,k,MORRInd::qi3d) = morr_arr(i,j,k,MORRInd::qi3d) + morr_arr(i,j,k,MORRInd::qi3dten)*dt;
2873  morr_arr(i,j,k,MORRInd::qni3d) = morr_arr(i,j,k,MORRInd::qni3d) + morr_arr(i,j,k,MORRInd::qni3dten)*dt;
2874  morr_arr(i,j,k,MORRInd::qr3d) = morr_arr(i,j,k,MORRInd::qr3d) + morr_arr(i,j,k,MORRInd::qr3dten)*dt;
2875  morr_arr(i,j,k,MORRInd::nc3d) = morr_arr(i,j,k,MORRInd::nc3d) + morr_arr(i,j,k,MORRInd::nc3dten)*dt;
2876  morr_arr(i,j,k,MORRInd::ni3d) = morr_arr(i,j,k,MORRInd::ni3d) + morr_arr(i,j,k,MORRInd::ni3dten)*dt;
2877  morr_arr(i,j,k,MORRInd::ns3d) = morr_arr(i,j,k,MORRInd::ns3d) + morr_arr(i,j,k,MORRInd::ns3dten)*dt;
2878  morr_arr(i,j,k,MORRInd::nr3d) = morr_arr(i,j,k,MORRInd::nr3d) + morr_arr(i,j,k,MORRInd::nr3dten)*dt;
2879  if (m_igraup == 0) {
2880  morr_arr(i,j,k,MORRInd::qg3d) = morr_arr(i,j,k,MORRInd::qg3d) + morr_arr(i,j,k,MORRInd::qg3dten)*dt;
2881  morr_arr(i,j,k,MORRInd::ng3d) = morr_arr(i,j,k,MORRInd::ng3d) + morr_arr(i,j,k,MORRInd::ng3dten)*dt;
2882  }
2883 
2884  // ADD TEMPERATURE AND WATER VAPOR TENDENCIES FROM MICROPHYSICS
2885  morr_arr(i,j,k,MORRInd::t3d) = morr_arr(i,j,k,MORRInd::t3d) + morr_arr(i,j,k,MORRInd::t3dten)*dt;
2886  morr_arr(i,j,k,MORRInd::qv3d) = morr_arr(i,j,k,MORRInd::qv3d) + morr_arr(i,j,k,MORRInd::qv3dten)*dt;
2887  // SATURATION VAPOR PRESSURE AND MIXING RATIO
2888  // hm, add fix for low pressure, 5/12/10
2889  // Assuming POLYSVP is defined elsewhere
2890  evs = std::min(Real(0.99) * morr_arr(i,j,k,MORRInd::pres), calc_saturation_vapor_pressure(morr_arr(i,j,k,MORRInd::t3d), 0)); // PA
2891  eis = std::min(Real(0.99) * morr_arr(i,j,k,MORRInd::pres), calc_saturation_vapor_pressure(morr_arr(i,j,k,MORRInd::t3d), 1)); // PA
2892 
2893  // MAKE SURE ICE SATURATION DOESN'T EXCEED WATER SAT. NEAR FREEZING
2894  if (eis > evs) {
2895  eis = evs; // temporary update: adjust ice saturation pressure
2896  }
2897 
2898  // SATURATION MIXING RATIOS
2899  qvs = m_ep_2 * evs / (morr_arr(i,j,k,MORRInd::pres) - evs); // budget equation: calculate water saturation mixing ratio
2900  qvi = m_ep_2 * eis / (morr_arr(i,j,k,MORRInd::pres) - eis); // budget equation: calculate ice saturation mixing ratio
2901 
2902  // SATURATION RATIOS
2903  qvqvs = morr_arr(i,j,k,MORRInd::qv3d) / qvs; // budget equation: calculate water saturation ratio
2904  qvqvsi = morr_arr(i,j,k,MORRInd::qv3d) / qvi; // budget equation: calculate ice saturation ratio
2905  // AT SUBSATURATION, REMOVE SMALL AMOUNTS OF CLOUD/PRECIP WATER
2906  if (qvqvs < Real(0.9)) {
2907  if (morr_arr(i,j,k,MORRInd::qr3d) < Real(1.0e-8)) {
2908  morr_arr(i,j,k,MORRInd::qv3d) += morr_arr(i,j,k,MORRInd::qr3d);
2909  morr_arr(i,j,k,MORRInd::t3d) -= morr_arr(i,j,k,MORRInd::qr3d) * morr_arr(i,j,k,MORRInd::xxlv) / morr_arr(i,j,k,MORRInd::cpm);
2910  morr_arr(i,j,k,MORRInd::qr3d) = Real(0);
2911  }
2912  if (morr_arr(i,j,k,MORRInd::qc3d) < Real(1.0e-8)) {
2913  morr_arr(i,j,k,MORRInd::qv3d) += morr_arr(i,j,k,MORRInd::qc3d);
2914  morr_arr(i,j,k,MORRInd::t3d) -= morr_arr(i,j,k,MORRInd::qc3d) * morr_arr(i,j,k,MORRInd::xxlv) / morr_arr(i,j,k,MORRInd::cpm);
2915  morr_arr(i,j,k,MORRInd::qc3d) = Real(0);
2916  }
2917  }
2918  if (qvqvsi < Real(0.9)) {
2919  if (morr_arr(i,j,k,MORRInd::qi3d) < Real(1.0e-8)) {
2920  morr_arr(i,j,k,MORRInd::qv3d) += morr_arr(i,j,k,MORRInd::qi3d);
2921  morr_arr(i,j,k,MORRInd::t3d) -= morr_arr(i,j,k,MORRInd::qi3d) * morr_arr(i,j,k,MORRInd::xxls) / morr_arr(i,j,k,MORRInd::cpm);
2922  morr_arr(i,j,k,MORRInd::qi3d) = Real(0);
2923  }
2924  if (morr_arr(i,j,k,MORRInd::qni3d) < Real(1.0e-8)) {
2925  morr_arr(i,j,k,MORRInd::qv3d) += morr_arr(i,j,k,MORRInd::qni3d);
2926  morr_arr(i,j,k,MORRInd::t3d) -= morr_arr(i,j,k,MORRInd::qni3d) * morr_arr(i,j,k,MORRInd::xxls) / morr_arr(i,j,k,MORRInd::cpm);
2927  morr_arr(i,j,k,MORRInd::qni3d) = Real(0);
2928  }
2929  if (morr_arr(i,j,k,MORRInd::qg3d) < Real(1.0e-8)) {
2930  morr_arr(i,j,k,MORRInd::qv3d) += morr_arr(i,j,k,MORRInd::qg3d);
2931  morr_arr(i,j,k,MORRInd::t3d) -= morr_arr(i,j,k,MORRInd::qg3d) * morr_arr(i,j,k,MORRInd::xxls) / morr_arr(i,j,k,MORRInd::cpm);
2932  morr_arr(i,j,k,MORRInd::qg3d) = Real(0);
2933  }
2934  }
2935  // IF MIXING RATIO < QSMALL SET MIXING RATIO AND NUMBER CONC TO ZERO
2936  if (morr_arr(i,j,k,MORRInd::qc3d) < m_qsmall) {
2937  morr_arr(i,j,k,MORRInd::qc3d) = Real(0);
2938  morr_arr(i,j,k,MORRInd::nc3d) = Real(0);
2939  morr_arr(i,j,k,MORRInd::effc) = Real(0);
2940  }
2941  if (morr_arr(i,j,k,MORRInd::qr3d) < m_qsmall) {
2942  morr_arr(i,j,k,MORRInd::qr3d) = Real(0);
2943  morr_arr(i,j,k,MORRInd::nr3d) = Real(0);
2944  morr_arr(i,j,k,MORRInd::effr) = Real(0);
2945  }
2946  if (morr_arr(i,j,k,MORRInd::qi3d) < m_qsmall) {
2947  morr_arr(i,j,k,MORRInd::qi3d) = Real(0);
2948  morr_arr(i,j,k,MORRInd::ni3d) = Real(0);
2949  morr_arr(i,j,k,MORRInd::effi) = Real(0);
2950  }
2951  if (morr_arr(i,j,k,MORRInd::qni3d) < m_qsmall) {
2952  morr_arr(i,j,k,MORRInd::qni3d) = Real(0);
2953  morr_arr(i,j,k,MORRInd::ns3d) = Real(0);
2954  morr_arr(i,j,k,MORRInd::effs) = Real(0);
2955  }
2956  if (morr_arr(i,j,k,MORRInd::qg3d) < m_qsmall) {
2957  morr_arr(i,j,k,MORRInd::qg3d) = Real(0);
2958  morr_arr(i,j,k,MORRInd::ng3d) = Real(0);
2959  morr_arr(i,j,k,MORRInd::effg) = Real(0);
2960  }
2961  /*
2962  // Skip calculations if there is no cloud/precipitation water
2963  if ((morr_arr(i,j,k,MORRInd::qc3d) < m_qsmall && // CLOUD WATER MIXING RATIO (KG/KG)
2964  morr_arr(i,j,k,MORRInd::qi3d) < m_qsmall && // CLOUD ICE MIXING RATIO (KG/KG)
2965  morr_arr(i,j,k,MORRInd::qni3d) < m_qsmall && // SNOW MIXING RATIO (KG/KG)
2966  morr_arr(i,j,k,MORRInd::qr3d) < m_qsmall && // RAIN MIXING RATIO (KG/KG)
2967  morr_arr(i,j,k,MORRInd::qg3d) < m_qsmall)) { // GRAUPEL MIX RATIO (KG/KG)
2968  goto label_500;
2969  } else {*/
2970  if (!(morr_arr(i,j,k,MORRInd::qc3d) < m_qsmall && // CLOUD WATER MIXING RATIO (KG/KG)
2971  morr_arr(i,j,k,MORRInd::qi3d) < m_qsmall && // CLOUD ICE MIXING RATIO (KG/KG)
2972  morr_arr(i,j,k,MORRInd::qni3d) < m_qsmall && // SNOW MIXING RATIO (KG/KG)
2973  morr_arr(i,j,k,MORRInd::qr3d) < m_qsmall && // RAIN MIXING RATIO (KG/KG)
2974  morr_arr(i,j,k,MORRInd::qg3d) < m_qsmall)) { // GRAUPEL MIX RATIO (KG/KG)
2975  // CALCULATE INSTANTANEOUS PROCESSES
2976 
2977  // ADD MELTING OF CLOUD ICE TO FORM RAIN
2978  if (morr_arr(i,j,k,MORRInd::qi3d) >= m_qsmall && morr_arr(i,j,k,MORRInd::t3d) >= Real(273.15)) {
2979  morr_arr(i,j,k,MORRInd::qr3d) = morr_arr(i,j,k,MORRInd::qr3d) + morr_arr(i,j,k,MORRInd::qi3d);
2980  morr_arr(i,j,k,MORRInd::t3d) = morr_arr(i,j,k,MORRInd::t3d) - morr_arr(i,j,k,MORRInd::qi3d) * morr_arr(i,j,k,MORRInd::xlf) / morr_arr(i,j,k,MORRInd::cpm);
2981  morr_arr(i,j,k,MORRInd::qi3d) = Real(0);
2982  morr_arr(i,j,k,MORRInd::nr3d) = morr_arr(i,j,k,MORRInd::nr3d) + morr_arr(i,j,k,MORRInd::ni3d);
2983  morr_arr(i,j,k,MORRInd::ni3d) = Real(0);
2984  }
2985  // ****SENSITIVITY - NO ICE
2986  if ((m_iliq != 1)) {
2987 
2988  // HOMOGENEOUS FREEZING OF CLOUD WATER
2989  if (morr_arr(i,j,k,MORRInd::t3d) <= Real(233.15) && morr_arr(i,j,k,MORRInd::qc3d) >= m_qsmall) {
2990  morr_arr(i,j,k,MORRInd::qi3d) = morr_arr(i,j,k,MORRInd::qi3d) + morr_arr(i,j,k,MORRInd::qc3d);
2991  morr_arr(i,j,k,MORRInd::t3d) = morr_arr(i,j,k,MORRInd::t3d) + morr_arr(i,j,k,MORRInd::qc3d) * morr_arr(i,j,k,MORRInd::xlf) / morr_arr(i,j,k,MORRInd::cpm);
2992  morr_arr(i,j,k,MORRInd::qc3d) = Real(0);
2993  morr_arr(i,j,k,MORRInd::ni3d) = morr_arr(i,j,k,MORRInd::ni3d) + morr_arr(i,j,k,MORRInd::nc3d);
2994  morr_arr(i,j,k,MORRInd::nc3d) = Real(0);
2995  }
2996  // HOMOGENEOUS FREEZING OF RAIN
2997  if (m_igraup == 0) {
2998  if (morr_arr(i,j,k,MORRInd::t3d) <= Real(233.15) && morr_arr(i,j,k,MORRInd::qr3d) >= m_qsmall) {
2999  morr_arr(i,j,k,MORRInd::qg3d) = morr_arr(i,j,k,MORRInd::qg3d) + morr_arr(i,j,k,MORRInd::qr3d);
3000  morr_arr(i,j,k,MORRInd::t3d) = morr_arr(i,j,k,MORRInd::t3d) + morr_arr(i,j,k,MORRInd::qr3d) * morr_arr(i,j,k,MORRInd::xlf) / morr_arr(i,j,k,MORRInd::cpm);
3001  morr_arr(i,j,k,MORRInd::qr3d) = Real(0);
3002  morr_arr(i,j,k,MORRInd::ng3d) = morr_arr(i,j,k,MORRInd::ng3d) + morr_arr(i,j,k,MORRInd::nr3d);
3003  morr_arr(i,j,k,MORRInd::nr3d) = Real(0);
3004  }
3005  } else if (m_igraup == 1) {
3006  if (morr_arr(i,j,k,MORRInd::t3d) <= Real(233.15) && morr_arr(i,j,k,MORRInd::qr3d) >= m_qsmall) {
3007  morr_arr(i,j,k,MORRInd::qni3d) = morr_arr(i,j,k,MORRInd::qni3d) + morr_arr(i,j,k,MORRInd::qr3d);
3008  morr_arr(i,j,k,MORRInd::t3d) = morr_arr(i,j,k,MORRInd::t3d) + morr_arr(i,j,k,MORRInd::qr3d) * morr_arr(i,j,k,MORRInd::xlf) / morr_arr(i,j,k,MORRInd::cpm);
3009  morr_arr(i,j,k,MORRInd::qr3d) = Real(0);
3010  morr_arr(i,j,k,MORRInd::ns3d) = morr_arr(i,j,k,MORRInd::ns3d) + morr_arr(i,j,k,MORRInd::nr3d);
3011  morr_arr(i,j,k,MORRInd::nr3d) = Real(0);
3012  }
3013  }
3014 
3015  }/* else {
3016  Real dontdoanything=m_iliq;//printf("m_iliq: %d\n",m_iliq);// goto label_778;
3017  }*/
3018 
3019 // label_778:
3020  // MAKE SURE NUMBER CONCENTRATIONS AREN'T NEGATIVE
3021  morr_arr(i,j,k,MORRInd::ni3d) = std::max(Real(0), morr_arr(i,j,k,MORRInd::ni3d));
3022  morr_arr(i,j,k,MORRInd::ns3d) = std::max(Real(0), morr_arr(i,j,k,MORRInd::ns3d));
3023  morr_arr(i,j,k,MORRInd::nc3d) = std::max(Real(0), morr_arr(i,j,k,MORRInd::nc3d));
3024  morr_arr(i,j,k,MORRInd::nr3d) = std::max(Real(0), morr_arr(i,j,k,MORRInd::nr3d));
3025  morr_arr(i,j,k,MORRInd::ng3d) = std::max(Real(0), morr_arr(i,j,k,MORRInd::ng3d));
3026 
3027  // CLOUD ICE
3028  if (morr_arr(i,j,k,MORRInd::qi3d) >= m_qsmall) {
3029  morr_arr(i,j,k,MORRInd::lami) = std::pow(m_cons12 * morr_arr(i,j,k,MORRInd::ni3d) / morr_arr(i,j,k,MORRInd::qi3d), one/m_di);
3030  // CHECK FOR SLOPE
3031  // ADJUST VARS
3032  if (morr_arr(i,j,k,MORRInd::lami) < m_lammini) {
3033  morr_arr(i,j,k,MORRInd::lami) = m_lammini;
3034  morr_arr(i,j,k,MORRInd::n0i) = amrex::Math::powi<4>(morr_arr(i,j,k,MORRInd::lami)) * morr_arr(i,j,k,MORRInd::qi3d) / m_cons12;
3035  morr_arr(i,j,k,MORRInd::ni3d) = morr_arr(i,j,k,MORRInd::n0i) / morr_arr(i,j,k,MORRInd::lami);
3036  } else if (morr_arr(i,j,k,MORRInd::lami) > m_lammaxi) {
3037  morr_arr(i,j,k,MORRInd::lami) = m_lammaxi;
3038  morr_arr(i,j,k,MORRInd::n0i) = amrex::Math::powi<4>(morr_arr(i,j,k,MORRInd::lami)) * morr_arr(i,j,k,MORRInd::qi3d) / m_cons12;
3039  morr_arr(i,j,k,MORRInd::ni3d) = morr_arr(i,j,k,MORRInd::n0i) / morr_arr(i,j,k,MORRInd::lami);
3040  }
3041  }
3042 
3043  // RAIN
3044  if (morr_arr(i,j,k,MORRInd::qr3d) >= m_qsmall) {
3045  morr_arr(i,j,k,MORRInd::lamr) = std::pow(m_pi * m_rhow * morr_arr(i,j,k,MORRInd::nr3d) / morr_arr(i,j,k,MORRInd::qr3d), one/three);
3046 
3047  // CHECK FOR SLOPE
3048  // ADJUST VARS
3049  if (morr_arr(i,j,k,MORRInd::lamr) < m_lamminr) {
3050  morr_arr(i,j,k,MORRInd::lamr) = m_lamminr;
3051  morr_arr(i,j,k,MORRInd::n0r) = amrex::Math::powi<4>(morr_arr(i,j,k,MORRInd::lamr)) * morr_arr(i,j,k,MORRInd::qr3d) / (m_pi * m_rhow);
3052  morr_arr(i,j,k,MORRInd::nr3d) = morr_arr(i,j,k,MORRInd::n0r) / morr_arr(i,j,k,MORRInd::lamr);
3053  } else if (morr_arr(i,j,k,MORRInd::lamr) > m_lammaxr) {
3054  morr_arr(i,j,k,MORRInd::lamr) = m_lammaxr;
3055  morr_arr(i,j,k,MORRInd::n0r) = amrex::Math::powi<4>(morr_arr(i,j,k,MORRInd::lamr)) * morr_arr(i,j,k,MORRInd::qr3d) / (m_pi * m_rhow);
3056  morr_arr(i,j,k,MORRInd::nr3d) = morr_arr(i,j,k,MORRInd::n0r) / morr_arr(i,j,k,MORRInd::lamr);
3057  }
3058  }
3059 
3060  // CLOUD DROPLETS
3061  // MARTIN ET AL. (1994) FORMULA FOR PGAM
3062  if (morr_arr(i,j,k,MORRInd::qc3d) >= m_qsmall) {
3063  Real dum = morr_arr(i,j,k,MORRInd::pres) / (Real(287.15) * morr_arr(i,j,k,MORRInd::t3d));
3064  morr_arr(i,j,k,MORRInd::pgam) = Real(0.0005714) * (morr_arr(i,j,k,MORRInd::nc3d) / Real(1.0e6) * dum) + Real(0.2714);
3065  morr_arr(i,j,k,MORRInd::pgam) = one/(amrex::Math::powi<2>(morr_arr(i,j,k,MORRInd::pgam))) - one;
3066  morr_arr(i,j,k,MORRInd::pgam) = std::max(morr_arr(i,j,k,MORRInd::pgam), Real(2));
3067  morr_arr(i,j,k,MORRInd::pgam) = std::min(morr_arr(i,j,k,MORRInd::pgam), Real(10.0));
3068 
3069  // CALCULATE LAMC
3070  morr_arr(i,j,k,MORRInd::lamc) = std::pow(m_cons26 * morr_arr(i,j,k,MORRInd::nc3d) * gamma_function(morr_arr(i,j,k,MORRInd::pgam) + Real(4.0)) /
3071  (morr_arr(i,j,k,MORRInd::qc3d) * gamma_function(morr_arr(i,j,k,MORRInd::pgam) + one)), one/three);
3072 
3073  // LAMMIN, 60 MICRON DIAMETER
3074  // LAMMAX, 1 MICRON
3075  Real lammin = (morr_arr(i,j,k,MORRInd::pgam) + one) / Real(60.0e-6);
3076  Real lammax = (morr_arr(i,j,k,MORRInd::pgam) + one) / Real(1.0e-6);
3077 
3078  if (morr_arr(i,j,k,MORRInd::lamc) < lammin) {
3079  morr_arr(i,j,k,MORRInd::lamc) = lammin;
3080  morr_arr(i,j,k,MORRInd::nc3d) = std::exp(three * std::log(morr_arr(i,j,k,MORRInd::lamc)) + std::log(morr_arr(i,j,k,MORRInd::qc3d)) +
3081  std::log(gamma_function(morr_arr(i,j,k,MORRInd::pgam) + one)) - std::log(gamma_function(morr_arr(i,j,k,MORRInd::pgam) + Real(4.0)))) / m_cons26;
3082  } else if (morr_arr(i,j,k,MORRInd::lamc) > lammax) {
3083  morr_arr(i,j,k,MORRInd::lamc) = lammax;
3084  morr_arr(i,j,k,MORRInd::nc3d) = std::exp(three * std::log(morr_arr(i,j,k,MORRInd::lamc)) + std::log(morr_arr(i,j,k,MORRInd::qc3d)) +
3085  std::log(gamma_function(morr_arr(i,j,k,MORRInd::pgam) + one)) - std::log(gamma_function(morr_arr(i,j,k,MORRInd::pgam) + Real(4.0)))) / m_cons26;
3086  }
3087  }
3088 
3089  // SNOW
3090  if (morr_arr(i,j,k,MORRInd::qni3d) >= m_qsmall) {
3091  morr_arr(i,j,k,MORRInd::lams) = std::pow(m_cons1 * morr_arr(i,j,k,MORRInd::ns3d) / morr_arr(i,j,k,MORRInd::qni3d), one/m_ds);
3092 
3093  // CHECK FOR SLOPE
3094  // ADJUST VARS
3095  if (morr_arr(i,j,k,MORRInd::lams) < m_lammins) {
3096  morr_arr(i,j,k,MORRInd::lams) = m_lammins;
3097  morr_arr(i,j,k,MORRInd::n0s) = amrex::Math::powi<4>(morr_arr(i,j,k,MORRInd::lams)) * morr_arr(i,j,k,MORRInd::qni3d) / m_cons1;
3098  morr_arr(i,j,k,MORRInd::ns3d) = morr_arr(i,j,k,MORRInd::n0s) / morr_arr(i,j,k,MORRInd::lams);
3099  } else if (morr_arr(i,j,k,MORRInd::lams) > m_lammaxs) {
3100  morr_arr(i,j,k,MORRInd::lams) = m_lammaxs;
3101  morr_arr(i,j,k,MORRInd::n0s) = amrex::Math::powi<4>(morr_arr(i,j,k,MORRInd::lams)) * morr_arr(i,j,k,MORRInd::qni3d) / m_cons1;
3102  morr_arr(i,j,k,MORRInd::ns3d) = morr_arr(i,j,k,MORRInd::n0s) / morr_arr(i,j,k,MORRInd::lams);
3103  }
3104  }
3105 
3106  // GRAUPEL
3107  if (morr_arr(i,j,k,MORRInd::qg3d) >= m_qsmall) {
3108  morr_arr(i,j,k,MORRInd::lamg) = std::pow(m_cons2 * morr_arr(i,j,k,MORRInd::ng3d) / morr_arr(i,j,k,MORRInd::qg3d), one/m_dg);
3109 
3110  // CHECK FOR SLOPE
3111  // ADJUST VARS
3112  if (morr_arr(i,j,k,MORRInd::lamg) < m_lamming) {
3113  morr_arr(i,j,k,MORRInd::lamg) = m_lamming;
3114  morr_arr(i,j,k,MORRInd::n0g) = amrex::Math::powi<4>(morr_arr(i,j,k,MORRInd::lamg)) * morr_arr(i,j,k,MORRInd::qg3d) / m_cons2;
3115  morr_arr(i,j,k,MORRInd::ng3d) = morr_arr(i,j,k,MORRInd::n0g) / morr_arr(i,j,k,MORRInd::lamg);
3116  } else if (morr_arr(i,j,k,MORRInd::lamg) > m_lammaxg) {
3117  morr_arr(i,j,k,MORRInd::lamg) = m_lammaxg;
3118  morr_arr(i,j,k,MORRInd::n0g) = amrex::Math::powi<4>(morr_arr(i,j,k,MORRInd::lamg)) * morr_arr(i,j,k,MORRInd::qg3d) / m_cons2;
3119  morr_arr(i,j,k,MORRInd::ng3d) = morr_arr(i,j,k,MORRInd::n0g) / morr_arr(i,j,k,MORRInd::lamg);
3120  }
3121  }
3122  }
3123 
3124 // label_500:
3125  // CALCULATE EFFECTIVE RADIUS
3126  if (morr_arr(i,j,k,MORRInd::qi3d) >= m_qsmall) {
3127  morr_arr(i,j,k,MORRInd::effi) = three / morr_arr(i,j,k,MORRInd::lami) / Real(2) * Real(1.0e6);
3128  } else {
3129  morr_arr(i,j,k,MORRInd::effi) = Real(25.0);
3130  }
3131 
3132  if (morr_arr(i,j,k,MORRInd::qni3d) >= m_qsmall) {
3133  morr_arr(i,j,k,MORRInd::effs) = three / morr_arr(i,j,k,MORRInd::lams) / Real(2) * Real(1.0e6);
3134  } else {
3135  morr_arr(i,j,k,MORRInd::effs) = Real(25.0);
3136  }
3137 
3138  if (morr_arr(i,j,k,MORRInd::qr3d) >= m_qsmall) {
3139  morr_arr(i,j,k,MORRInd::effr) = three / morr_arr(i,j,k,MORRInd::lamr) / Real(2) * Real(1.0e6);
3140  } else {
3141  morr_arr(i,j,k,MORRInd::effr) = Real(25.0);
3142  }
3143 
3144  if (morr_arr(i,j,k,MORRInd::qc3d) >= m_qsmall) {
3145  morr_arr(i,j,k,MORRInd::effc) = gamma_function(morr_arr(i,j,k,MORRInd::pgam) + Real(4.0)) / gamma_function(morr_arr(i,j,k,MORRInd::pgam) + three) / morr_arr(i,j,k,MORRInd::lamc) / Real(2) * Real(1.0e6);
3146  } else {
3147  morr_arr(i,j,k,MORRInd::effc) = Real(25.0);
3148  }
3149 
3150  if (morr_arr(i,j,k,MORRInd::qg3d) >= m_qsmall) {
3151  morr_arr(i,j,k,MORRInd::effg) = three / morr_arr(i,j,k,MORRInd::lamg) / Real(2) * Real(1.0e6);
3152  } else {
3153  morr_arr(i,j,k,MORRInd::effg) = Real(25.0);
3154  }
3155 
3156  // HM ADD 1/10/06, ADD UPPER BOUND ON ICE NUMBER, THIS IS NEEDED
3157  // TO PREVENT VERY LARGE ICE NUMBER DUE TO HOMOGENEOUS FREEZING
3158  // OF DROPLETS, ESPECIALLY WHEN INUM = 1, SET MAX AT 10 CM-3
3159  // HM, 12/28/12, LOWER MAXIMUM ICE CONCENTRATION TO ADDRESS PROBLEM
3160  // OF EXCESSIVE AND PERSISTENT ANVIL
3161  // NOTE: THIS MAY CHANGE/REDUCE SENSITIVITY TO AEROSOL/CCN CONCENTRATION
3162  morr_arr(i,j,k,MORRInd::ni3d) = std::min(morr_arr(i,j,k,MORRInd::ni3d), Real(0.3e6) / morr_arr(i,j,k,MORRInd::rho));
3163 
3164  // ADD BOUND ON DROPLET NUMBER - CANNOT EXCEED AEROSOL CONCENTRATION
3165  if (iinum == 0 && m_iact == 2) {
3166  morr_arr(i,j,k,MORRInd::nc3d) = std::min(morr_arr(i,j,k,MORRInd::nc3d), (m_nanew1 + m_nanew2) / morr_arr(i,j,k,MORRInd::rho));
3167  }
3168 
3169  // SWITCH FOR CONSTANT DROPLET NUMBER
3170  if (iinum == 1) {
3171  // CHANGE NDCNST FROM CM-3 TO KG-1
3172  morr_arr(i,j,k,MORRInd::nc3d) = m_ndcnst * Real(1.0e6) / morr_arr(i,j,k,MORRInd::rho);
3173  }
3174  }
3175 
3176  }/* else {
3177  goto label_400;
3178  }
3179  label_400:*/
3180  //End of _micro
3181 
3182  if(use_morr_cpp_answer) {
3183  for (int k=klo; k<=khi; k++) {
3184  // Transfer 1D variables back to 3D arrays
3185  qcl_arr(i,j,k) = morr_arr(i,j,k,MORRInd::qc3d);
3186  qci_arr(i,j,k) = morr_arr(i,j,k,MORRInd::qi3d);
3187  qps_arr(i,j,k) = morr_arr(i,j,k,MORRInd::qni3d);
3188  qpr_arr(i,j,k) = morr_arr(i,j,k,MORRInd::qr3d);
3189  ni_arr(i,j,k) = morr_arr(i,j,k,MORRInd::ni3d);
3190  ns_arr(i,j,k) = morr_arr(i,j,k,MORRInd::ns3d);
3191  nr_arr(i,j,k) = morr_arr(i,j,k,MORRInd::nr3d);
3192  qpg_arr(i,j,k) = morr_arr(i,j,k,MORRInd::qg3d);
3193  ng_arr(i,j,k) = morr_arr(i,j,k,MORRInd::ng3d);
3194 
3195  // Temperature and potential temperature conversion
3196  theta_arr(i,j,k) = morr_arr(i,j,k,MORRInd::t3d) / pii_arr(i,j,k); // Convert temp back to potential temp
3197  qv_arr(i,j,k) = morr_arr(i,j,k,MORRInd::qv3d);
3198 
3199  //Deleted wrf-check, effc, and precr type data as not used by ERF
3200  /*
3201  // NEED gpu-compatible summation for rain_accum, check SAM or Kessler for better example
3202  rain_accum_arr(i,j,k) = rain_accum_arr(i,j,k) + morr_arr(i,j,k,MORRInd::precrt);
3203  snow_accum_arr(i,j,k) = snow_accum_arr(i,j,k) + morr_arr(i,j,k,MORRInd::snowprt);
3204  graup_accum_arr(i,j,k) = graup_accum_arr(i,j,k) + morr_arr(i,j,k,MORRInd::grplprt);
3205  */
3206 
3207  rainncv_arr(i,j,0) = morr_arr(i,j,klo,MORRInd::precrt);
3208  snowncv_arr(i,j,0) = morr_arr(i,j,klo,MORRInd::snowprt);
3209  graupelncv_arr(i,j,0) = morr_arr(i,j,klo,MORRInd::grplprt);
3210  sr_arr(i,j,0) = morr_arr(i,j,klo,MORRInd::snowrt) / (morr_arr(i,j,klo,MORRInd::precrt) + Real(1.e-12));
3211  } // k
3212 
3213  // Update precipitation accumulation variables
3214  // These are outside the k-loop in the original code
3215  rain_accum_arr(i,j,klo) = rain_accum_arr(i,j,klo) + morr_arr(i,j,klo,MORRInd::precrt);
3216  snow_accum_arr(i,j,klo) = snow_accum_arr(i,j,klo) + morr_arr(i,j,klo,MORRInd::snowprt);
3217  graup_accum_arr(i,j,klo) = graup_accum_arr(i,j,klo) + morr_arr(i,j,klo,MORRInd::grplprt);
3218 
3219  } // cpp
3220  });
3221 
3222  }
3223 
3224  if (run_morr_fort) {
3225 #ifdef ERF_USE_MORR_FORT
3226 #include "ERF_Morrison_Advance_F.H"
3227 #endif
3228  } // run_morr_fort
3229 
3230  }
3231  }
constexpr amrex::Real three
Definition: ERF_Constants.H:11
constexpr amrex::Real one
Definition: ERF_Constants.H:9
constexpr amrex::Real fourth
Definition: ERF_Constants.H:14
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:13
ParmParse pp("prob")
const int khi
Definition: ERF_InitCustomPert_Bubble.H:21
auto qv_arr
Definition: ERF_InitCustomPert_MultiSpeciesBubble.H:210
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Real gamma_function(Real x)
Definition: ERF_MorrisonGammaFunction.H:300
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_saturation_vapor_pressure(const amrex::Real T, const int type)
Definition: ERF_MorrisonVaporPressure.H:36
Arena * Arena_Used
Definition: ERF_Morrison_Advance_F.H:23
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
auto rho_arr
Definition: ERF_UpdateWSubsidence_SineMassFlux.H:3
amrex::Geometry m_geom
Definition: ERF_Morrison.H:198
amrex::MultiFab * m_z_phys_nd
Definition: ERF_Morrison.H:209
amrex::Real m_rdOcp
Definition: ERF_Morrison.H:201
amrex::Array< FabPtr, MicVar_Morr::NumVars > mic_fab_vars
Definition: ERF_Morrison.H:213
bool m_do_cond
Definition: ERF_Morrison.H:202
@ qisten
Definition: ERF_AdvanceMorrison.cpp:76
@ dumfnc
Definition: ERF_AdvanceMorrison.cpp:134
@ qi3dten
Definition: ERF_AdvanceMorrison.cpp:48
@ agn
Definition: ERF_AdvanceMorrison.cpp:97
@ pres
Definition: ERF_AdvanceMorrison.cpp:65
@ precrt
Definition: ERF_AdvanceMorrison.cpp:82
@ dumc
Definition: ERF_AdvanceMorrison.cpp:133
@ falouti
Definition: ERF_AdvanceMorrison.cpp:113
@ ni3d
Definition: ERF_AdvanceMorrison.cpp:58
@ dumi
Definition: ERF_AdvanceMorrison.cpp:98
@ faloutnc
Definition: ERF_AdvanceMorrison.cpp:141
@ snowprt
Definition: ERF_AdvanceMorrison.cpp:84
@ lamg
Definition: ERF_AdvanceMorrison.cpp:40
@ xxls
Definition: ERF_AdvanceMorrison.cpp:154
@ n0s
Definition: ERF_AdvanceMorrison.cpp:43
@ fns
Definition: ERF_AdvanceMorrison.cpp:123
@ grplprt
Definition: ERF_AdvanceMorrison.cpp:85
@ dumfns
Definition: ERF_AdvanceMorrison.cpp:119
@ qni3d
Definition: ERF_AdvanceMorrison.cpp:56
@ ung
Definition: ERF_AdvanceMorrison.cpp:137
@ faloutng
Definition: ERF_AdvanceMorrison.cpp:127
@ qc3dten
Definition: ERF_AdvanceMorrison.cpp:47
@ w3d
Definition: ERF_AdvanceMorrison.cpp:67
@ rgvm
Definition: ERF_AdvanceMorrison.cpp:111
@ arn
Definition: ERF_AdvanceMorrison.cpp:94
@ lami
Definition: ERF_AdvanceMorrison.cpp:37
@ qscu1d
Definition: ERF_AdvanceMorrison.cpp:80
@ qcsten
Definition: ERF_AdvanceMorrison.cpp:78
@ fc
Definition: ERF_AdvanceMorrison.cpp:139
@ fnr
Definition: ERF_AdvanceMorrison.cpp:148
@ pgam
Definition: ERF_AdvanceMorrison.cpp:46
@ qrcu1d
Definition: ERF_AdvanceMorrison.cpp:79
@ fng
Definition: ERF_AdvanceMorrison.cpp:110
@ ng3dten
Definition: ERF_AdvanceMorrison.cpp:71
@ dlami
Definition: ERF_AdvanceMorrison.cpp:151
@ faloutni
Definition: ERF_AdvanceMorrison.cpp:114
@ faloutnr
Definition: ERF_AdvanceMorrison.cpp:146
@ NumInds
Definition: ERF_AdvanceMorrison.cpp:158
@ dumfni
Definition: ERF_AdvanceMorrison.cpp:100
@ n0g
Definition: ERF_AdvanceMorrison.cpp:45
@ dlams
Definition: ERF_AdvanceMorrison.cpp:149
@ n0i
Definition: ERF_AdvanceMorrison.cpp:42
@ effs
Definition: ERF_AdvanceMorrison.cpp:88
@ faltndg
Definition: ERF_AdvanceMorrison.cpp:131
@ cpm
Definition: ERF_AdvanceMorrison.cpp:156
@ qr3dten
Definition: ERF_AdvanceMorrison.cpp:50
@ t3d
Definition: ERF_AdvanceMorrison.cpp:63
@ dumqs
Definition: ERF_AdvanceMorrison.cpp:118
@ qg3d
Definition: ERF_AdvanceMorrison.cpp:72
@ lamr
Definition: ERF_AdvanceMorrison.cpp:39
@ qr3d
Definition: ERF_AdvanceMorrison.cpp:57
@ nc3d
Definition: ERF_AdvanceMorrison.cpp:68
@ qg3dten
Definition: ERF_AdvanceMorrison.cpp:70
@ nr3dten
Definition: ERF_AdvanceMorrison.cpp:53
@ dzq
Definition: ERF_AdvanceMorrison.cpp:66
@ dumfnr
Definition: ERF_AdvanceMorrison.cpp:145
@ uns
Definition: ERF_AdvanceMorrison.cpp:121
@ faltndng
Definition: ERF_AdvanceMorrison.cpp:132
@ effc
Definition: ERF_AdvanceMorrison.cpp:86
@ qnisten
Definition: ERF_AdvanceMorrison.cpp:77
@ faloutg
Definition: ERF_AdvanceMorrison.cpp:126
@ t3dten
Definition: ERF_AdvanceMorrison.cpp:61
@ qv3d
Definition: ERF_AdvanceMorrison.cpp:64
@ ni3dten
Definition: ERF_AdvanceMorrison.cpp:51
@ uni
Definition: ERF_AdvanceMorrison.cpp:103
@ umi
Definition: ERF_AdvanceMorrison.cpp:104
@ qni3dten
Definition: ERF_AdvanceMorrison.cpp:49
@ faloutr
Definition: ERF_AdvanceMorrison.cpp:112
@ dumr
Definition: ERF_AdvanceMorrison.cpp:99
@ faloutns
Definition: ERF_AdvanceMorrison.cpp:125
@ effi
Definition: ERF_AdvanceMorrison.cpp:87
@ faltndni
Definition: ERF_AdvanceMorrison.cpp:117
@ unc
Definition: ERF_AdvanceMorrison.cpp:135
@ umc
Definition: ERF_AdvanceMorrison.cpp:136
@ qv3dten
Definition: ERF_AdvanceMorrison.cpp:62
@ faltndns
Definition: ERF_AdvanceMorrison.cpp:129
@ nc3dten
Definition: ERF_AdvanceMorrison.cpp:69
@ dumg
Definition: ERF_AdvanceMorrison.cpp:101
@ dlamc
Definition: ERF_AdvanceMorrison.cpp:152
@ rho
Definition: ERF_AdvanceMorrison.cpp:91
@ effr
Definition: ERF_AdvanceMorrison.cpp:89
@ faltndnc
Definition: ERF_AdvanceMorrison.cpp:143
@ xxlv
Definition: ERF_AdvanceMorrison.cpp:155
@ faltndc
Definition: ERF_AdvanceMorrison.cpp:142
@ faltndnr
Definition: ERF_AdvanceMorrison.cpp:147
@ fni
Definition: ERF_AdvanceMorrison.cpp:108
@ umr
Definition: ERF_AdvanceMorrison.cpp:105
@ faloutc
Definition: ERF_AdvanceMorrison.cpp:140
@ ain
Definition: ERF_AdvanceMorrison.cpp:93
@ effg
Definition: ERF_AdvanceMorrison.cpp:90
@ faltnds
Definition: ERF_AdvanceMorrison.cpp:128
@ xlf
Definition: ERF_AdvanceMorrison.cpp:157
@ asn
Definition: ERF_AdvanceMorrison.cpp:95
@ fr
Definition: ERF_AdvanceMorrison.cpp:106
@ fnc
Definition: ERF_AdvanceMorrison.cpp:144
@ fi
Definition: ERF_AdvanceMorrison.cpp:107
@ dumfng
Definition: ERF_AdvanceMorrison.cpp:102
@ faltndr
Definition: ERF_AdvanceMorrison.cpp:115
@ lams
Definition: ERF_AdvanceMorrison.cpp:38
@ fs
Definition: ERF_AdvanceMorrison.cpp:122
@ qicu1d
Definition: ERF_AdvanceMorrison.cpp:81
@ qrsten
Definition: ERF_AdvanceMorrison.cpp:75
@ qgsten
Definition: ERF_AdvanceMorrison.cpp:74
@ cdist1
Definition: ERF_AdvanceMorrison.cpp:41
@ dlamg
Definition: ERF_AdvanceMorrison.cpp:153
@ mu
Definition: ERF_AdvanceMorrison.cpp:92
@ lamc
Definition: ERF_AdvanceMorrison.cpp:36
@ ns3dten
Definition: ERF_AdvanceMorrison.cpp:52
@ ns3d
Definition: ERF_AdvanceMorrison.cpp:59
@ dlamr
Definition: ERF_AdvanceMorrison.cpp:150
@ ng3d
Definition: ERF_AdvanceMorrison.cpp:73
@ qi3d
Definition: ERF_AdvanceMorrison.cpp:55
@ acn
Definition: ERF_AdvanceMorrison.cpp:96
@ falouts
Definition: ERF_AdvanceMorrison.cpp:124
@ faltndi
Definition: ERF_AdvanceMorrison.cpp:116
@ fg
Definition: ERF_AdvanceMorrison.cpp:109
@ qc3d
Definition: ERF_AdvanceMorrison.cpp:54
@ umg
Definition: ERF_AdvanceMorrison.cpp:138
@ unr
Definition: ERF_AdvanceMorrison.cpp:130
@ ums
Definition: ERF_AdvanceMorrison.cpp:120
@ n0r
Definition: ERF_AdvanceMorrison.cpp:44
@ snowrt
Definition: ERF_AdvanceMorrison.cpp:83
@ nr3d
Definition: ERF_AdvanceMorrison.cpp:60
@ qv
Definition: ERF_Morrison.H:35
@ ng
Definition: ERF_Morrison.H:49
@ nc
Definition: ERF_Morrison.H:45
@ qpg
Definition: ERF_Morrison.H:42
@ pres
Definition: ERF_Morrison.H:31
@ nr
Definition: ERF_Morrison.H:46
@ qcl
Definition: ERF_Morrison.H:36
@ theta
Definition: ERF_Morrison.H:29
@ ni
Definition: ERF_Morrison.H:47
@ ns
Definition: ERF_Morrison.H:48
@ omega
Definition: ERF_Morrison.H:54
@ qps
Definition: ERF_Morrison.H:41
@ graup_accum
Definition: ERF_Morrison.H:53
@ rho
Definition: ERF_Morrison.H:28
@ qpr
Definition: ERF_Morrison.H:40
@ qci
Definition: ERF_Morrison.H:37
@ rain_accum
Definition: ERF_Morrison.H:51
@ snow_accum
Definition: ERF_Morrison.H:52
@ psacr
Definition: ERF_WSM6.H:222
@ praci
Definition: ERF_WSM6.H:218
@ psmlt
Definition: ERF_WSM6.H:228
@ pgmlt
Definition: ERF_WSM6.H:229
@ piacr
Definition: ERF_WSM6.H:216
@ pracs
Definition: ERF_WSM6.H:219
real(c_double), parameter p0
Definition: ERF_module_model_constants.F90:40
MoistureType moisture_type
Moisture or microphysics model.
Definition: ERF_DataStruct.H:1604
Here is the call graph for this function:

◆ Copy_Micro_to_State()

void Morrison::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.

18 {
19  // Get the temperature, density, theta, qt and qp from input
20  for ( MFIter mfi(cons,TilingIfNotGPU()); mfi.isValid(); ++mfi) {
21  const auto& box3d = mfi.tilebox();
22 
23  auto states_arr = cons.array(mfi);
24 
25  auto rho_arr = mic_fab_vars[MicVar_Morr::rho]->array(mfi);
26  auto theta_arr = mic_fab_vars[MicVar_Morr::theta]->array(mfi);
27 
28  auto qv_arr = mic_fab_vars[MicVar_Morr::qv]->array(mfi);
29  auto qc_arr = mic_fab_vars[MicVar_Morr::qcl]->array(mfi);
30  auto qi_arr = mic_fab_vars[MicVar_Morr::qci]->array(mfi);
31 
32  auto qpr_arr = mic_fab_vars[MicVar_Morr::qpr]->array(mfi);
33  auto qps_arr = mic_fab_vars[MicVar_Morr::qps]->array(mfi);
34  auto qpg_arr = mic_fab_vars[MicVar_Morr::qpg]->array(mfi);
35 
36  auto nc_arr = mic_fab_vars[MicVar_Morr::nc]->array(mfi);
37  auto ni_arr = mic_fab_vars[MicVar_Morr::ni]->array(mfi);
38  auto nr_arr = mic_fab_vars[MicVar_Morr::nr]->array(mfi);
39  auto ns_arr = mic_fab_vars[MicVar_Morr::ns]->array(mfi);
40  auto ng_arr = mic_fab_vars[MicVar_Morr::ng]->array(mfi);
41 
42  // get potential total density, temperature, qt, qp
43  ParallelFor( box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
44  {
45  states_arr(i,j,k,RhoTheta_comp) = rho_arr(i,j,k)*theta_arr(i,j,k);
46 
47  states_arr(i,j,k,RhoQ1_comp) = rho_arr(i,j,k)*std::max(Real(0),qv_arr(i,j,k));
48  states_arr(i,j,k,RhoQ2_comp) = rho_arr(i,j,k)*std::max(Real(0),qc_arr(i,j,k));
49  states_arr(i,j,k,RhoQ3_comp) = rho_arr(i,j,k)*std::max(Real(0),qi_arr(i,j,k));
50 
51  states_arr(i,j,k,RhoQ4_comp) = rho_arr(i,j,k)*std::max(Real(0),qpr_arr(i,j,k));
52  states_arr(i,j,k,RhoQ5_comp) = rho_arr(i,j,k)*std::max(Real(0),qps_arr(i,j,k));
53  states_arr(i,j,k,RhoQ6_comp) = rho_arr(i,j,k)*std::max(Real(0),qpg_arr(i,j,k));
54 
55  states_arr(i,j,k,RhoQ7_comp) = rho_arr(i,j,k)*std::max(Real(0),nc_arr(i,j,k));
56  states_arr(i,j,k,RhoQ8_comp) = rho_arr(i,j,k)*std::max(Real(0),ni_arr(i,j,k));
57  states_arr(i,j,k,RhoQ9_comp) = rho_arr(i,j,k)*std::max(Real(0),nr_arr(i,j,k));
58  states_arr(i,j,k,RhoQ10_comp) = rho_arr(i,j,k)*std::max(Real(0),ns_arr(i,j,k));
59  states_arr(i,j,k,RhoQ11_comp) = rho_arr(i,j,k)*std::max(Real(0),ng_arr(i,j,k));
60  });
61  }
62 
63  // Fill interior ghost cells and periodic boundaries
64  cons.FillBoundary(m_geom.periodicity());
65 }
#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 RhoQ11_comp
Definition: ERF_IndexDefines.H:52
#define RhoQ9_comp
Definition: ERF_IndexDefines.H:50
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:42
#define RhoQ6_comp
Definition: ERF_IndexDefines.H:47
#define RhoQ8_comp
Definition: ERF_IndexDefines.H:49
#define RhoQ5_comp
Definition: ERF_IndexDefines.H:46
#define RhoQ7_comp
Definition: ERF_IndexDefines.H:48
#define RhoQ10_comp
Definition: ERF_IndexDefines.H:51
@ cons
Definition: ERF_IndexDefines.H:176

Referenced by Update_State_Vars().

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

◆ Copy_State_to_Micro()

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

Initializes the Microphysics module.

Parameters
[in]cons_inConserved variables input

Reimplemented from NullMoist.

74 {
75  // Get the temperature, density, theta, qt and qp from input
76  for ( MFIter mfi(cons_in); mfi.isValid(); ++mfi) {
77  const auto& box3d = mfi.growntilebox();
78 
79  auto states_array = cons_in.array(mfi);
80 
81  // Non-precipitating
82  auto qv_array = mic_fab_vars[MicVar_Morr::qv]->array(mfi);
83  auto qc_array = mic_fab_vars[MicVar_Morr::qcl]->array(mfi);
84  auto qi_array = mic_fab_vars[MicVar_Morr::qci]->array(mfi);
85  auto qn_array = mic_fab_vars[MicVar_Morr::qn]->array(mfi);
86  auto qt_array = mic_fab_vars[MicVar_Morr::qt]->array(mfi);
87 
88  // Precipitating
89  auto qpr_array = mic_fab_vars[MicVar_Morr::qpr]->array(mfi);
90  auto qps_array = mic_fab_vars[MicVar_Morr::qps]->array(mfi);
91  auto qpg_array = mic_fab_vars[MicVar_Morr::qpg]->array(mfi);
92  auto qp_array = mic_fab_vars[MicVar_Morr::qp]->array(mfi);
93 
94  auto nc_array = mic_fab_vars[MicVar_Morr::nc]->array(mfi);
95  auto ni_array = mic_fab_vars[MicVar_Morr::ni]->array(mfi);
96  auto nr_array = mic_fab_vars[MicVar_Morr::nr]->array(mfi);
97  auto ns_array = mic_fab_vars[MicVar_Morr::ns]->array(mfi);
98  auto ng_array = mic_fab_vars[MicVar_Morr::ng]->array(mfi);
99 
100  auto rho_array = mic_fab_vars[MicVar_Morr::rho]->array(mfi);
101  auto theta_array = mic_fab_vars[MicVar_Morr::theta]->array(mfi);
102  auto tabs_array = mic_fab_vars[MicVar_Morr::tabs]->array(mfi);
103  auto pres_array = mic_fab_vars[MicVar_Morr::pres]->array(mfi);
104 
105  // Get pressure, theta, temperature, density, and qt, qp
106  ParallelFor( box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
107  {
108  rho_array(i,j,k) = states_array(i,j,k,Rho_comp);
109  theta_array(i,j,k) = states_array(i,j,k,RhoTheta_comp)/states_array(i,j,k,Rho_comp);
110 
111  qv_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ1_comp)/states_array(i,j,k,Rho_comp));
112  qc_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ2_comp)/states_array(i,j,k,Rho_comp));
113  qi_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ3_comp)/states_array(i,j,k,Rho_comp));
114  qn_array(i,j,k) = qc_array(i,j,k) + qi_array(i,j,k);
115  qt_array(i,j,k) = qv_array(i,j,k) + qn_array(i,j,k);
116 
117  qpr_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ4_comp)/states_array(i,j,k,Rho_comp));
118  qps_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ5_comp)/states_array(i,j,k,Rho_comp));
119  qpg_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ6_comp)/states_array(i,j,k,Rho_comp));
120 
121  qp_array(i,j,k) = qpr_array(i,j,k) + qps_array(i,j,k) + qpg_array(i,j,k);
122 
123  nc_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ7_comp) /states_array(i,j,k,Rho_comp));
124  ni_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ8_comp) /states_array(i,j,k,Rho_comp));
125  nr_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ9_comp) /states_array(i,j,k,Rho_comp));
126  ns_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ10_comp)/states_array(i,j,k,Rho_comp));
127  ng_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ11_comp)/states_array(i,j,k,Rho_comp));
128 
129  tabs_array(i,j,k) = getTgivenRandRTh(states_array(i,j,k,Rho_comp),
130  states_array(i,j,k,RhoTheta_comp),
131  qv_array(i,j,k));
132 
133  // NOTE: the Morrison Fortran version uses Pa not hPa so we don't divideby 100!
134  pres_array(i,j,k) = getPgivenRTh(states_array(i,j,k,RhoTheta_comp), qv_array(i,j,k)); // * Real(0.01);
135  });
136  }
137 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getTgivenRandRTh(const amrex::Real rho, const amrex::Real rhotheta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:46
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:36
@ tabs
Definition: ERF_Morrison.H:30
@ qp
Definition: ERF_Morrison.H:39
@ qn
Definition: ERF_Morrison.H:34
@ qt
Definition: ERF_Morrison.H:33

Referenced by Update_Micro_Vars().

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

◆ Define()

void Morrison::Define ( SolverChoice sc)
inlineoverridevirtual

Reimplemented from NullMoist.

73  {
75  m_rdOcp = sc.rdOcp;
76  m_do_cond = (!sc.uses_shoc_family());
77  }
MoistureType m_moisture_type
Definition: ERF_Morrison.H:203
amrex::Real rdOcp
Ratio of dry-air gas constant to c_p.
Definition: ERF_DataStruct.H:1477
bool uses_shoc_family() const noexcept
Query whether any SHOC-family PBL scheme is active.
Definition: ERF_DataStruct.H:1566
Here is the call graph for this function:

◆ Get_Surface_Precip_Accumulation_Ptrs()

SurfacePrecipAccumulationSources Morrison::Get_Surface_Precip_Accumulation_Ptrs ( const int &  ) const
inlineoverridevirtual

Reimplemented from NullMoist.

157  {
159  sources.total = {mic_fab_vars[MicVar_Morr::rain_accum].get(), rhor / amrex::Real(1000.0)};
160 
161  if (m_moisture_type == MoistureType::Morrison) {
162  sources.snow = {mic_fab_vars[MicVar_Morr::snow_accum].get(), rhor / amrex::Real(1000.0)};
163  sources.graupel = {mic_fab_vars[MicVar_Morr::graup_accum].get(), rhor / amrex::Real(1000.0)};
164  }
165 
166  return sources;
167  }
constexpr amrex::Real rhor
Definition: ERF_Constants.H:71
Definition: ERF_SurfacePrecipitation.H:21
SurfacePrecipAccumulationSource snow
Definition: ERF_SurfacePrecipitation.H:24
SurfacePrecipAccumulationSource total
Definition: ERF_SurfacePrecipitation.H:22
SurfacePrecipAccumulationSource graupel
Definition: ERF_SurfacePrecipitation.H:25

◆ GetPlotVar() [1/2]

void Morrison::GetPlotVar ( const std::string &  a_name,
amrex::MultiFab &  a_mf 
) const
overridevirtual

Reimplemented from NullMoist.

Referenced by GetPlotVar().

Here is the caller graph for this function:

◆ GetPlotVar() [2/2]

void Morrison::GetPlotVar ( const std::string &  a_name,
amrex::MultiFab &  a_mf,
const int   
) const
inlineoverridevirtual

Reimplemented from NullMoist.

180  {
181  GetPlotVar(a_name, a_mf);
182  }
void GetPlotVar(const std::string &a_name, amrex::MultiFab &a_mf) const override
Here is the call graph for this function:

◆ GetPlotVarNames()

void Morrison::GetPlotVarNames ( amrex::Vector< std::string > &  a_vec) const
overridevirtual

Populate a vector with names of all available Morrison plot variables.

This function returns the names of all Morrison microphysics variables that can be written to plotfiles. These names correspond to the diagnostic fields defined in the plot_entries table.

Parameters
[out]a_vecVector to be populated with plot variable names
Note
The returned vector will contain 19 variable names, including both prognostic quantities (mixing ratios, number concentrations) and diagnostic quantities (temperature, pressure, derived moisture totals).

Reimplemented from NullMoist.

102 {
103  a_vec.clear();
104  a_vec.reserve(sizeof(plot_entries) / sizeof(plot_entries[0]));
105  for (const auto& entry : plot_entries) {
106  a_vec.emplace_back(entry.name);
107  }
108 }

◆ Init()

void Morrison::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.

27 {
28  [[maybe_unused]] amrex::Real dt = dt_advance;
29  m_geom = geom;
30 
31  m_z_phys_nd = z_phys_nd.get();
32  m_detJ_cc = detJ_cc.get();
33 
34  MicVarMap.resize(m_qmoist_size);
36 
37 #if defined(ERF_USE_MORR_FORT) && defined(AMREX_USE_GPU)
38  Arena* Arena_Used = The_Managed_Arena();
39 #else
40  Arena* Arena_Used = The_Arena();
41 #endif
42 
43  // initialize microphysics variables
44  for (auto ivar = 0; ivar < MicVar_Morr::NumVars; ++ivar) {
45  mic_fab_vars[ivar] = std::make_shared<MultiFab>(cons_in.boxArray(), cons_in.DistributionMap(),
46  1, cons_in.nGrowVect(),
47  MFInfo().SetArena(Arena_Used));
48  mic_fab_vars[ivar]->setVal(0.);
49  }
50 
51 #ifdef ERF_USE_MORR_FORT
52  bool use_cpp = true;
53  amrex::ParmParse pp("erf");
54  pp.query("use_morr_cpp_answer", use_cpp);
55 
56  if (!use_cpp) {
57  MoistureType moisture_type;
58  pp.query_enum_case_insensitive("moisture_model",moisture_type);
59  int morr_noice = (moisture_type == MoistureType::Morrison_NoIce);
60  int morr_rimed_ice = 0; // This is used to set something called "ihail"
61  morr_two_moment_init_c(morr_rimed_ice, morr_noice);
62  }
63 #endif
64 }
void morr_two_moment_init_c(int morr_rimed_ice, int morr_noice)
amrex::Vector< int > MicVarMap
Definition: ERF_Morrison.H:195
amrex::MultiFab * m_detJ_cc
Definition: ERF_Morrison.H:210
int m_qmoist_size
Definition: ERF_Morrison.H:186
@ NumVars
Definition: ERF_Morrison.H:55
Here is the call graph for this function:

◆ Qmoist_Ptr()

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

Reimplemented from NullMoist.

125  {
127  return mic_fab_vars[MicVarMap[varIdx]].get();
128  }
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
Here is the call graph for this function:

◆ Qmoist_Restart_Vars()

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

Reimplemented from NullMoist.

143  {
144  a_idx.clear();
145  a_names.clear();
146 
147  // The ordering here needs to match that in
148  // MicVarMap = {MicVar_Morr::rain_accum, MicVar_Morr::snow_accum, MicVar_Morr::graup_accum};
149  //
150  a_idx.push_back(0); a_names.push_back("RainAccum");
151  a_idx.push_back(1); a_names.push_back("SnowAccum");
152  a_idx.push_back(2); a_names.push_back("GraupAccum");
153  }

◆ Qmoist_Size()

int Morrison::Qmoist_Size ( )
inlineoverridevirtual

Reimplemented from NullMoist.

131 { return Morrison::m_qmoist_size; }

◆ Qstate_Moist_NumConc_Size()

int Morrison::Qstate_Moist_NumConc_Size ( )
inlineoverridevirtual

Reimplemented from NullMoist.

int n_qstate_moist_numconc_size
Definition: ERF_Morrison.H:192

◆ Qstate_Moist_Size()

int Morrison::Qstate_Moist_Size ( )
inlineoverridevirtual

Reimplemented from NullMoist.

int n_qstate_moist_size
Definition: ERF_Morrison.H:189

◆ Set_dzmin()

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

Reimplemented from NullMoist.

91  {
92  m_dzmin = dz_min;
93  }
amrex::Real m_dzmin
Definition: ERF_Morrison.H:206

◆ Update_Micro_Vars() [1/3]

virtual void NullMoist::Update_Micro_Vars
inline
35 { }

◆ Update_Micro_Vars() [2/3]

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

Reimplemented from NullMoist.

107  {
108  this->Copy_State_to_Micro(cons_in);
109  }
void Copy_State_to_Micro(const amrex::MultiFab &cons_in) override
Definition: ERF_InitMorrison.cpp:73
Here is the call graph for this function:

◆ Update_Micro_Vars() [3/3]

virtual void NullMoist::Update_Micro_Vars
inline
42  {
43  Update_Micro_Vars(cons_in);
44  }
virtual void Update_Micro_Vars(amrex::MultiFab &)
Definition: ERF_NullMoist.H:35

◆ Update_State_Vars()

void Morrison::Update_State_Vars ( amrex::MultiFab &  cons_in,
const amrex::MultiFab &   
)
inlineoverridevirtual

Reimplemented from NullMoist.

114  {
115  this->Copy_Micro_to_State(cons_in);
116  }
void Copy_Micro_to_State(amrex::MultiFab &cons_in) override
Definition: ERF_UpdateMorrison.cpp:17
Here is the call graph for this function:

Member Data Documentation

◆ m_detJ_cc

amrex::MultiFab* Morrison::m_detJ_cc
private

◆ m_do_cond

bool Morrison::m_do_cond
private

Referenced by Define().

◆ m_dzmin

amrex::Real Morrison::m_dzmin
private

Referenced by Set_dzmin().

◆ m_geom

amrex::Geometry Morrison::m_geom
private

◆ m_moisture_type

MoistureType Morrison::m_moisture_type = MoistureType::None
private

◆ m_qmoist_size

int Morrison::m_qmoist_size = 3
private

Referenced by Qmoist_Ptr(), and Qmoist_Size().

◆ m_rdOcp

amrex::Real Morrison::m_rdOcp
private

Referenced by Define().

◆ m_z_phys_nd

amrex::MultiFab* Morrison::m_z_phys_nd
private

◆ mic_fab_vars

amrex::Array<FabPtr, MicVar_Morr::NumVars> Morrison::mic_fab_vars
private

◆ MicVarMap

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

Referenced by Qmoist_Ptr().

◆ n_qstate_moist_numconc_size

int Morrison::n_qstate_moist_numconc_size = 5
private

◆ n_qstate_moist_size

int Morrison::n_qstate_moist_size = 11
private

Referenced by Qstate_Moist_Size().


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