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_Lmask (amrex::iMultiFab *)
 Import ERF's land/water mask. Only schemes whose physics branches on land vs water need to override this. More...
 
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.

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

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:39
@ 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:1948
bool uses_shoc_family() const noexcept
Query whether any SHOC-family PBL scheme is active.
Definition: ERF_DataStruct.H:2063
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:34
SurfacePrecipAccumulationSource snow
Definition: ERF_SurfacePrecipitation.H:37
SurfacePrecipAccumulationSource total
Definition: ERF_SurfacePrecipitation.H:35
SurfacePrecipAccumulationSource graupel
Definition: ERF_SurfacePrecipitation.H:38

◆ 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.queryAdd("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
36 { }

◆ 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
43  {
44  Update_Micro_Vars(cons_in);
45  }
virtual void Update_Micro_Vars(amrex::MultiFab &)
Definition: ERF_NullMoist.H:36

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