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) override
 
void Advance (const amrex::Real &dt_advance, const SolverChoice &sc) override
 
amrex::MultiFab * Qmoist_Ptr (const int &varIdx) override
 
void Compute_Coefficients ()
 
int Qmoist_Size () override
 
int Qstate_Moist_Size () override
 
void Set_RealWidth (const int real_width) override
 
void Qmoist_Restart_Vars (const SolverChoice &, std::vector< int > &a_idx, std::vector< std::string > &a_names) const override
 
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
 Extract a Morrison microphysics variable for plotting. More...
 
- Public Member Functions inherited from NullMoist
 NullMoist ()
 
virtual ~NullMoist ()=default
 
virtual int Qstate_NonMoist_Size ()
 

Static Public Member Functions

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

Private Types

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

Private Attributes

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

Static Private Attributes

static constexpr amrex::Real CFL_MAX = myhalf
 

Member Typedef Documentation

◆ FabPtr

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

Constructor & Destructor Documentation

◆ Morrison()

Morrison::Morrison ( )
inline
64 {}

◆ ~Morrison()

virtual Morrison::~Morrison ( )
virtualdefault

Member Function Documentation

◆ Advance()

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

Reimplemented from NullMoist.

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

◆ Compute_Coefficients()

void Morrison::Compute_Coefficients ( )
145 {
146  auto accrrc_t = accrrc.table();
147  auto accrsi_t = accrsi.table();
148  auto accrsc_t = accrsc.table();
149  auto coefice_t = coefice.table();
150  auto evaps1_t = evaps1.table();
151  auto evaps2_t = evaps2.table();
152  auto accrgi_t = accrgi.table();
153  auto accrgc_t = accrgc.table();
154  auto evapg1_t = evapg1.table();
155  auto evapg2_t = evapg2.table();
156  auto evapr1_t = evapr1.table();
157  auto evapr2_t = evapr2.table();
158 
159  auto rho1d_t = rho1d.table();
160  auto pres1d_t = pres1d.table();
161  auto tabs1d_t = tabs1d.table();
162 
163  Real gam3 = erf_gammafff(three );
164  Real gamr1 = erf_gammafff(three+b_rain );
165  Real gamr2 = erf_gammafff((Real(5.0)+b_rain)/two);
166  Real gams1 = erf_gammafff(three+b_snow );
167  Real gams2 = erf_gammafff((Real(5.0)+b_snow)/two);
168  Real gamg1 = erf_gammafff(three+b_grau );
169  Real gamg2 = erf_gammafff((Real(5.0)+b_grau)/two);
170 
171  // calculate the plane average variables
175  rho_ave.compute_averages(ZDir(), rho_ave.field());
176  theta_ave.compute_averages(ZDir(), theta_ave.field());
177  qv_ave.compute_averages(ZDir(), qv_ave.field());
178 
179  // get host variable rho, and rhotheta
180  int ncell = rho_ave.ncell_line();
181 
182  Gpu::HostVector<Real> rho_h(ncell), theta_h(ncell), qv_h(ncell);
183  rho_ave.line_average(0, rho_h);
184  theta_ave.line_average(0, theta_h);
185  qv_ave.line_average(0, qv_h);
186 
187  // copy data to device
188  Gpu::DeviceVector<Real> rho_d(ncell), theta_d(ncell), qv_d(ncell);
189  Gpu::copyAsync(Gpu::hostToDevice, rho_h.begin(), rho_h.end(), rho_d.begin());
190  Gpu::copyAsync(Gpu::hostToDevice, theta_h.begin(), theta_h.end(), theta_d.begin());
191  Gpu::copyAsync(Gpu::hostToDevice, qv_h.begin(), qv_h.end(), qv_d.begin());
192  Gpu::streamSynchronize();
193 
194  Real* rho_dptr = rho_d.data();
195  Real* theta_dptr = theta_d.data();
196  Real* qv_dptr = qv_d.data();
197 
198  ParallelFor(nlev, [=] AMREX_GPU_DEVICE (int k) noexcept
199  {
200  Real RhoTheta = rho_dptr[k]*theta_dptr[k];
201  Real pressure = getPgivenRTh(RhoTheta, qv_dptr[k]);
202  rho1d_t(k) = rho_dptr[k];
203  pres1d_t(k) = pressure*Real(0.01);
204  // NOTE: Limit the temperature to the melting point of ice to avoid a divide by
205  // 0 condition when computing the cold evaporation coefficients. This should
206  // not affect results since evaporation requires snow/graupel to be present
207  // and thus T<Real(273.16)
208  tabs1d_t(k) = std::min(getTgivenRandRTh(rho_dptr[k], RhoTheta, qv_dptr[k]),Real(273.16));
209  });
210 
211  if(round(gam3) != 2) {
212  std::cout << "cannot compute gamma-function in Microphysics::Init" << std::endl;
213  std::exit(-1);
214  }
215 
216  // Populate all the coefficients
217  ParallelFor(nlev, [=] AMREX_GPU_DEVICE (int k) noexcept
218  {
219  Real Prefactor;
220  Real pratio = sqrt(Real(1.29) / rho1d_t(k));
221  //Real rrr1 = Real(393.0)/(tabs1d_t(k)+Real(120.0))*std::pow((tabs1d_t(k)/Real(273.0)),Real(1.5));
222  //Real rrr2 = std::pow((tabs1d_t(k)/Real(273.0)),Real(1.94))*(Real(1000.0)/pres1d_t(k));
223  Real estw = Real(100.0)*erf_esatw(tabs1d_t(k));
224  Real esti = Real(100.0)*erf_esati(tabs1d_t(k));
225 
226  // accretion by snow:
227  Real coef1 = fourth * PI * nzeros * a_snow * gams1 * pratio/pow((PI * rhos * nzeros/rho1d_t(k) ) , ((three+b_snow)/Real(4.0)));
228  Real coef2 = exp(Real(0.025)*(tabs1d_t(k) - Real(273.15)));
229  accrsi_t(k) = coef1 * coef2 * esicoef;
230  accrsc_t(k) = coef1 * esccoef;
231  coefice_t(k) = coef2;
232 
233  // evaporation of snow:
234  coef1 = (lsub/(tabs1d_t(k)*R_v)-one)*lsub/(therco*tabs1d_t(k));
235  coef2 = R_v * R_d / (diffelq * esti);
236  Prefactor = two * PI * nzeros / (rho1d_t(k) * (coef1 + coef2));
237  Prefactor *= (two/PI); // Shape factor snow
238  evaps1_t(k) = Prefactor * Real(0.65) * sqrt(rho1d_t(k) / (PI * rhos * nzeros));
239  evaps2_t(k) = Prefactor * Real(0.44) * sqrt(a_snow * rho1d_t(k) / muelq) * gams2
240  * sqrt(pratio) * pow(rho1d_t(k) / (PI * rhos * nzeros) , ((Real(5.0)+b_snow)/Real(8.0)));
241 
242  // accretion by graupel:
243  coef1 = fourth*PI*nzerog*a_grau*gamg1*pratio/pow((PI*rhog*nzerog/rho1d_t(k)) , ((three+b_grau)/Real(4.0)));
244  coef2 = exp(Real(0.025)*(tabs1d_t(k) - Real(273.15)));
245  accrgi_t(k) = coef1 * coef2 * egicoef;
246  accrgc_t(k) = coef1 * egccoef;
247 
248  // evaporation of graupel:
249  coef1 = (lsub/(tabs1d_t(k)*R_v)-one)*lsub/(therco*tabs1d_t(k));
250  coef2 = R_v * R_d / (diffelq * esti);
251  Prefactor = two * PI * nzerog / (rho1d_t(k) * (coef1 + coef2)); // Shape factor for graupel is 1
252  evapg1_t(k) = Prefactor * Real(0.78) * sqrt(rho1d_t(k) / (PI * rhog * nzerog));
253  evapg2_t(k) = Prefactor * Real(0.31) * sqrt(a_grau * rho1d_t(k) / muelq) * gamg2
254  * sqrt(pratio) * pow(rho1d_t(k) / (PI * rhog * nzerog) , ((Real(5.0)+b_grau)/Real(8.0)));
255 
256  // accretion by rain:
257  accrrc_t(k) = fourth * PI * nzeror * a_rain * gamr1 * pratio/pow((PI * rhor * nzeror / rho1d_t(k)) , ((three+b_rain)/Real(4.)))* erccoef;
258 
259  // evaporation of rain:
260  coef1 = (lcond/(tabs1d_t(k)*R_v)-one)*lcond/(therco*tabs1d_t(k));
261  coef2 = R_v * R_d / (diffelq * estw);
262  Prefactor = two * PI * nzeror / (rho1d_t(k) * (coef1 + coef2)); // Shape factor for rain is 1
263  evapr1_t(k) = Prefactor * Real(0.78) * sqrt(rho1d_t(k) / (PI * rhor * nzeror));
264  evapr2_t(k) = Prefactor * Real(0.31) * sqrt(a_rain * rho1d_t(k) / muelq) * gamr2
265  * sqrt(pratio) * pow(rho1d_t(k) / (PI * rhor * nzeror) , ((Real(5.0)+b_rain)/Real(8.0)));
266  });
267 }
constexpr amrex::Real rhog
Definition: ERF_Constants.H:40
constexpr amrex::Real R_v
Definition: ERF_Constants.H:21
constexpr amrex::Real muelq
Definition: ERF_Constants.H:85
constexpr amrex::Real nzerog
Definition: ERF_Constants.H:69
constexpr amrex::Real two
Definition: ERF_Constants.H:8
constexpr amrex::Real a_grau
Definition: ERF_Constants.H:52
constexpr amrex::Real lsub
Definition: ERF_Constants.H:78
constexpr amrex::Real esicoef
Definition: ERF_Constants.H:63
constexpr amrex::Real diffelq
Definition: ERF_Constants.H:83
constexpr amrex::Real therco
Definition: ERF_Constants.H:84
constexpr amrex::Real b_grau
Definition: ERF_Constants.H:53
constexpr amrex::Real egccoef
Definition: ERF_Constants.H:64
constexpr amrex::Real egicoef
Definition: ERF_Constants.H:65
constexpr amrex::Real b_rain
Definition: ERF_Constants.H:49
constexpr amrex::Real lcond
Definition: ERF_Constants.H:76
constexpr amrex::Real PI
Definition: ERF_Constants.H:16
constexpr amrex::Real nzeror
Definition: ERF_Constants.H:67
constexpr amrex::Real rhos
Definition: ERF_Constants.H:39
constexpr amrex::Real esccoef
Definition: ERF_Constants.H:62
constexpr amrex::Real rhor
Definition: ERF_Constants.H:38
constexpr amrex::Real a_rain
Definition: ERF_Constants.H:48
constexpr amrex::Real nzeros
Definition: ERF_Constants.H:68
constexpr amrex::Real R_d
Definition: ERF_Constants.H:20
constexpr amrex::Real a_snow
Definition: ERF_Constants.H:50
constexpr amrex::Real b_snow
Definition: ERF_Constants.H:51
constexpr amrex::Real erccoef
Definition: ERF_Constants.H:61
DirectionSelector< 2 > ZDir
Definition: ERF_DirectionSelector.H:38
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
pp get("wavelength", wavelength)
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esati(amrex::Real t)
Definition: ERF_MicrophysicsUtils.H:26
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_gammafff(amrex::Real x)
Definition: ERF_MicrophysicsUtils.H:15
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esatw(amrex::Real t, bool use_empirical=false)
Definition: ERF_MicrophysicsUtils.H:68
Vector< Real > rho_h(khi+1, zero)
Gpu::DeviceVector< Real > rho_d(khi+1, zero)
amrex::TableData< amrex::Real, 1 > evapg2
Definition: ERF_Morrison.H:327
amrex::TableData< amrex::Real, 1 > pres1d
Definition: ERF_Morrison.H:333
amrex::TableData< amrex::Real, 1 > accrgi
Definition: ERF_Morrison.H:324
amrex::TableData< amrex::Real, 1 > accrgc
Definition: ERF_Morrison.H:325
amrex::TableData< amrex::Real, 1 > tabs1d
Definition: ERF_Morrison.H:334
int nlev
Definition: ERF_Morrison.H:298
amrex::TableData< amrex::Real, 1 > coefice
Definition: ERF_Morrison.H:321
amrex::TableData< amrex::Real, 1 > accrsi
Definition: ERF_Morrison.H:319
amrex::TableData< amrex::Real, 1 > accrrc
Definition: ERF_Morrison.H:318
amrex::TableData< amrex::Real, 1 > evapg1
Definition: ERF_Morrison.H:326
amrex::TableData< amrex::Real, 1 > evapr1
Definition: ERF_Morrison.H:328
amrex::TableData< amrex::Real, 1 > evaps1
Definition: ERF_Morrison.H:322
amrex::TableData< amrex::Real, 1 > evaps2
Definition: ERF_Morrison.H:323
amrex::TableData< amrex::Real, 1 > rho1d
Definition: ERF_Morrison.H:332
amrex::TableData< amrex::Real, 1 > evapr2
Definition: ERF_Morrison.H:329
amrex::TableData< amrex::Real, 1 > accrsc
Definition: ERF_Morrison.H:320
Definition: ERF_PlaneAverage.H:14

Referenced by Update_Micro_Vars().

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

◆ Copy_Micro_to_State()

void 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  // get potential total density, temperature, qt, qp
37  ParallelFor( box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
38  {
39  states_arr(i,j,k,RhoTheta_comp) = rho_arr(i,j,k)*theta_arr(i,j,k);
40 
41  states_arr(i,j,k,RhoQ1_comp) = rho_arr(i,j,k)*std::max(Real(0),qv_arr(i,j,k));
42  states_arr(i,j,k,RhoQ2_comp) = rho_arr(i,j,k)*std::max(Real(0),qc_arr(i,j,k));
43  states_arr(i,j,k,RhoQ3_comp) = rho_arr(i,j,k)*std::max(Real(0),qi_arr(i,j,k));
44 
45  states_arr(i,j,k,RhoQ4_comp) = rho_arr(i,j,k)*std::max(Real(0),qpr_arr(i,j,k));
46  states_arr(i,j,k,RhoQ5_comp) = rho_arr(i,j,k)*std::max(Real(0),qps_arr(i,j,k));
47  states_arr(i,j,k,RhoQ6_comp) = rho_arr(i,j,k)*std::max(Real(0),qpg_arr(i,j,k));
48  });
49  }
50 
51  // Fill interior ghost cells and periodic boundaries
52  cons.FillBoundary(m_geom.periodicity());
53 }
#define RhoQ4_comp
Definition: ERF_IndexDefines.H:45
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
#define RhoQ2_comp
Definition: ERF_IndexDefines.H:43
#define RhoQ3_comp
Definition: ERF_IndexDefines.H:44
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:42
#define RhoQ6_comp
Definition: ERF_IndexDefines.H:47
#define RhoQ5_comp
Definition: ERF_IndexDefines.H:46
@ cons
Definition: ERF_IndexDefines.H:158

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.

91 {
92  // Get the temperature, density, theta, qt and qp from input
93  for ( MFIter mfi(cons_in); mfi.isValid(); ++mfi) {
94  const auto& box3d = mfi.growntilebox();
95 
96  auto states_array = cons_in.array(mfi);
97 
98  // Non-precipitating
99  auto qv_array = mic_fab_vars[MicVar_Morr::qv]->array(mfi);
100  auto qc_array = mic_fab_vars[MicVar_Morr::qcl]->array(mfi);
101  auto qi_array = mic_fab_vars[MicVar_Morr::qci]->array(mfi);
102  auto qn_array = mic_fab_vars[MicVar_Morr::qn]->array(mfi);
103  auto qt_array = mic_fab_vars[MicVar_Morr::qt]->array(mfi);
104 
105  // Precipitating
106  auto qpr_array = mic_fab_vars[MicVar_Morr::qpr]->array(mfi);
107  auto qps_array = mic_fab_vars[MicVar_Morr::qps]->array(mfi);
108  auto qpg_array = mic_fab_vars[MicVar_Morr::qpg]->array(mfi);
109  auto qp_array = mic_fab_vars[MicVar_Morr::qp]->array(mfi);
110 
111  auto rho_array = mic_fab_vars[MicVar_Morr::rho]->array(mfi);
112  auto theta_array = mic_fab_vars[MicVar_Morr::theta]->array(mfi);
113  auto tabs_array = mic_fab_vars[MicVar_Morr::tabs]->array(mfi);
114  auto pres_array = mic_fab_vars[MicVar_Morr::pres]->array(mfi);
115 
116  // Get pressure, theta, temperature, density, and qt, qp
117  ParallelFor( box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
118  {
119  rho_array(i,j,k) = states_array(i,j,k,Rho_comp);
120  theta_array(i,j,k) = states_array(i,j,k,RhoTheta_comp)/states_array(i,j,k,Rho_comp);
121 
122  qv_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ1_comp)/states_array(i,j,k,Rho_comp));
123  qc_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ2_comp)/states_array(i,j,k,Rho_comp));
124  qi_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ3_comp)/states_array(i,j,k,Rho_comp));
125  qn_array(i,j,k) = qc_array(i,j,k) + qi_array(i,j,k);
126  qt_array(i,j,k) = qv_array(i,j,k) + qn_array(i,j,k);
127 
128  qpr_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ4_comp)/states_array(i,j,k,Rho_comp));
129  qps_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ5_comp)/states_array(i,j,k,Rho_comp));
130  qpg_array(i,j,k) = std::max(Real(0),states_array(i,j,k,RhoQ6_comp)/states_array(i,j,k,Rho_comp));
131  qp_array(i,j,k) = qpr_array(i,j,k) + qps_array(i,j,k) + qpg_array(i,j,k);
132 
133  tabs_array(i,j,k) = getTgivenRandRTh(states_array(i,j,k,Rho_comp),
134  states_array(i,j,k,RhoTheta_comp),
135  qv_array(i,j,k));
136 
137  // NOTE: the Morrison Fortran version uses Pa not hPa so we don't divideby 100!
138  pres_array(i,j,k) = getPgivenRTh(states_array(i,j,k,RhoTheta_comp), qv_array(i,j,k)); // * Real(0.01);
139  });
140  }
141 }
#define Rho_comp
Definition: ERF_IndexDefines.H:36
@ qp
Definition: ERF_Morrison.H:38
@ qn
Definition: ERF_Morrison.H:33
@ qt
Definition: ERF_Morrison.H:32

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.

72  {
73  m_axis = sc.ave_plane;
74  m_rdOcp = sc.rdOcp;
75  m_do_cond = (!sc.use_shoc);
76  }
amrex::Real rdOcp
Definition: ERF_DataStruct.H:1156
bool use_shoc
Definition: ERF_DataStruct.H:1187
int ave_plane
Definition: ERF_DataStruct.H:1220

◆ GetPlotVar()

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

Extract a Morrison microphysics variable for plotting.

This function copies data from the Morrison internal state (mic_fab_vars) to the provided MultiFab for inclusion in a plotfile. The variable to extract is specified by name matching the plot_entries table.

Parameters
[in]a_nameName of the variable to extract (e.g., "micro_qc")
[out]a_mfMultiFab to receive the variable data
Exceptions
amrex::Abortif the requested variable name is not found in plot_entries
Note
The caller must ensure a_mf has the correct distribution and size matching the Morrison mic_fab_vars arrays. Only the first component of the source MultiFab is copied.
Warning
If omega has not been populated from the velocity field, it will contain its initialization value (zero).

Reimplemented from NullMoist.

132 {
133  const MultiFab* src = nullptr;
134 
135  for (const auto& entry : plot_entries) {
136  if (a_name == entry.name) {
137  src = mic_fab_vars[entry.index].get();
138  break;
139  }
140  }
141 
142  if (src == nullptr) {
143  amrex::Abort("Morrison::GetPlotVar: unknown plot variable " + a_name);
144  }
145 
146  MultiFab::Copy(a_mf, *src, 0, 0, 1, 0);
147 }

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

28 {
29  [[maybe_unused]] amrex::Real dt = dt_advance;
30  m_geom = geom;
31 
32  m_z_phys_nd = z_phys_nd.get();
33  m_detJ_cc = detJ_cc.get();
34 
35  MicVarMap.resize(m_qmoist_size);
38 
39  // initialize microphysics variables
40  for (auto ivar = 0; ivar < MicVar_Morr::NumVars; ++ivar) {
41  mic_fab_vars[ivar] = std::make_shared<MultiFab>(cons_in.boxArray(), cons_in.DistributionMap(),
42  1, cons_in.nGrowVect());
43  mic_fab_vars[ivar]->setVal(0.);
44  }
45 
46  // NOTE: For multi-level not all ranks will own a box.
47  // Furthermore, the plane average allocates space
48  // for the entire domain. We make this consistent.
49  nlev = m_geom.Domain().length(2);
50  zlo = m_geom.Domain().smallEnd(2);
51  zhi = m_geom.Domain().bigEnd(2);
52 
53  // parameters
54  accrrc.resize({zlo}, {zhi});
55  accrsi.resize({zlo}, {zhi});
56  accrsc.resize({zlo}, {zhi});
57  coefice.resize({zlo}, {zhi});
58  evaps1.resize({zlo}, {zhi});
59  evaps2.resize({zlo}, {zhi});
60  accrgi.resize({zlo}, {zhi});
61  accrgc.resize({zlo}, {zhi});
62  evapg1.resize({zlo}, {zhi});
63  evapg2.resize({zlo}, {zhi});
64  evapr1.resize({zlo}, {zhi});
65  evapr2.resize({zlo}, {zhi});
66 
67  // data (input)
68  rho1d.resize({zlo}, {zhi});
69  pres1d.resize({zlo}, {zhi});
70  tabs1d.resize({zlo}, {zhi});
71 
72 #ifdef ERF_USE_MORR_FORT
73  int morr_rimed_ice = 0; // This is used to set something called "ihail"
74  amrex::ParmParse pp("erf");
75  MoistureType moisture_type;
76  pp.query_enum_case_insensitive("moisture_model",moisture_type);
77  int morr_noice = (moisture_type == MoistureType::Morrison_NoIce);
78  Print()<<"Setting No Ice flag in fortran to "<<morr_noice<<std::endl;
79  morr_two_moment_init_c(morr_rimed_ice, morr_noice);
80 #endif
81 }
void morr_two_moment_init_c(int morr_rimed_ice, int morr_noice)
amrex::Vector< int > MicVarMap
Definition: ERF_Morrison.H:289
amrex::MultiFab * m_detJ_cc
Definition: ERF_Morrison.H:312
int m_qmoist_size
Definition: ERF_Morrison.H:280
int zlo
Definition: ERF_Morrison.H:298
int zhi
Definition: ERF_Morrison.H:298
@ NumVars
Definition: ERF_Morrison.H:54
Here is the call graph for this function:

◆ NewtonIterSat()

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

◆ Qmoist_Ptr()

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

Reimplemented from NullMoist.

122  {
124  return mic_fab_vars[MicVarMap[varIdx]].get();
125  }
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.

253  {
254  a_idx.clear();
255  a_names.clear();
256 
257  // The ordering here needs to match that in
258  // MicVarMap = {MicVar_Morr::nc, MicVar_Morr::nr, MicVar_Morr::ni, MicVar_Morr::ns, MicVar_Morr::ng,
259  // MicVar_Morr::rain_accum, MicVar_Morr::snow_accum, MicVar_Morr::graup_accum};
260  //
261  a_idx.push_back(0); a_names.push_back("Nc");
262  a_idx.push_back(1); a_names.push_back("Nr");
263  a_idx.push_back(2); a_names.push_back("Ni");
264  a_idx.push_back(3); a_names.push_back("Ns");
265  a_idx.push_back(4); a_names.push_back("Ng");
266  a_idx.push_back(5); a_names.push_back("RainAccum");
267  a_idx.push_back(6); a_names.push_back("SnowAccum");
268  a_idx.push_back(7); a_names.push_back("GraupAccum");
269  }

◆ Qmoist_Size()

int Morrison::Qmoist_Size ( )
inlineoverridevirtual

Reimplemented from NullMoist.

131 { return Morrison::m_qmoist_size; }

◆ Qstate_Moist_Size()

int Morrison::Qstate_Moist_Size ( )
inlineoverridevirtual

Reimplemented from NullMoist.

int n_qstate_moist_size
Definition: ERF_Morrison.H:283

◆ Set_dzmin()

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

Reimplemented from NullMoist.

90  {
91  m_dzmin = dz_min;
92  }
amrex::Real m_dzmin
Definition: ERF_Morrison.H:308

◆ Set_RealWidth()

void Morrison::Set_RealWidth ( const int  real_width)
inlineoverridevirtual

Reimplemented from NullMoist.

137 { m_real_width = real_width; }

◆ Update_Micro_Vars()

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

Reimplemented from NullMoist.

104  {
105  this->Copy_State_to_Micro(cons_in);
106  this->Compute_Coefficients();
107  }
void Copy_State_to_Micro(const amrex::MultiFab &cons_in) override
Definition: ERF_InitMorrison.cpp:90
void Compute_Coefficients()
Definition: ERF_InitMorrison.cpp:144
Here is the call graph for this function:

◆ Update_State_Vars()

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

Reimplemented from NullMoist.

111  {
112  this->Copy_Micro_to_State(cons_in);
113  }
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

◆ accrgc

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

◆ accrgi

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

◆ accrrc

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

◆ accrsc

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

◆ accrsi

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

◆ CFL_MAX

constexpr amrex::Real Morrison::CFL_MAX = myhalf
staticconstexprprivate

◆ coefice

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

◆ evapg1

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

◆ evapg2

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

◆ evapr1

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

◆ evapr2

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

◆ evaps1

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

◆ evaps2

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

◆ m_axis

int Morrison::m_axis
private

Referenced by Define().

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

int Morrison::m_qmoist_size = 8
private

Referenced by Qmoist_Ptr(), and Qmoist_Size().

◆ m_rdOcp

amrex::Real Morrison::m_rdOcp
private

Referenced by Define().

◆ m_real_width

int Morrison::m_real_width {0}
private

Referenced by Set_RealWidth().

◆ 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

Referenced by Qmoist_Ptr().

◆ MicVarMap

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

Referenced by Qmoist_Ptr().

◆ n_qstate_moist_size

int Morrison::n_qstate_moist_size = 6
private

Referenced by Qstate_Moist_Size().

◆ nlev

int Morrison::nlev
private

◆ pres1d

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

◆ qn1d

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

◆ qt1d

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

◆ qv1d

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

◆ rho1d

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

◆ tabs1d

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

◆ zhi

int Morrison::zhi
private

◆ zlo

int Morrison::zlo
private

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