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_fac_cond
 
amrex::Real m_fac_fus
 
amrex::Real m_fac_sub
 
amrex::Real m_rdOcp
 
bool m_do_cond
 
amrex::Real m_dzmin
 
amrex::MultiFab * m_z_phys_nd
 
amrex::MultiFab * m_detJ_cc
 
amrex::Array< FabPtr, MicVar_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 = 0.5
 

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.

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

◆ Compute_Coefficients()

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

Referenced by Update_State_Vars().

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.

96 {
97  // Get the temperature, density, theta, qt and qp from input
98  for ( MFIter mfi(cons_in); mfi.isValid(); ++mfi) {
99  const auto& box3d = mfi.growntilebox();
100 
101  auto states_array = cons_in.array(mfi);
102 
103  // Non-precipitating
104  auto qv_array = mic_fab_vars[MicVar_Morr::qv]->array(mfi);
105  auto qc_array = mic_fab_vars[MicVar_Morr::qcl]->array(mfi);
106  auto qi_array = mic_fab_vars[MicVar_Morr::qci]->array(mfi);
107  auto qn_array = mic_fab_vars[MicVar_Morr::qn]->array(mfi);
108  auto qt_array = mic_fab_vars[MicVar_Morr::qt]->array(mfi);
109 
110  // Precipitating
111  auto qpr_array = mic_fab_vars[MicVar_Morr::qpr]->array(mfi);
112  auto qps_array = mic_fab_vars[MicVar_Morr::qps]->array(mfi);
113  auto qpg_array = mic_fab_vars[MicVar_Morr::qpg]->array(mfi);
114  auto qp_array = mic_fab_vars[MicVar_Morr::qp]->array(mfi);
115 
116  auto rho_array = mic_fab_vars[MicVar_Morr::rho]->array(mfi);
117  auto theta_array = mic_fab_vars[MicVar_Morr::theta]->array(mfi);
118  auto tabs_array = mic_fab_vars[MicVar_Morr::tabs]->array(mfi);
119  auto pres_array = mic_fab_vars[MicVar_Morr::pres]->array(mfi);
120 
121  // Get pressure, theta, temperature, density, and qt, qp
122  ParallelFor( box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
123  {
124  rho_array(i,j,k) = states_array(i,j,k,Rho_comp);
125  theta_array(i,j,k) = states_array(i,j,k,RhoTheta_comp)/states_array(i,j,k,Rho_comp);
126 
127  qv_array(i,j,k) = std::max(0.0,states_array(i,j,k,RhoQ1_comp)/states_array(i,j,k,Rho_comp));
128  qc_array(i,j,k) = std::max(0.0,states_array(i,j,k,RhoQ2_comp)/states_array(i,j,k,Rho_comp));
129  qi_array(i,j,k) = std::max(0.0,states_array(i,j,k,RhoQ3_comp)/states_array(i,j,k,Rho_comp));
130  qn_array(i,j,k) = qc_array(i,j,k) + qi_array(i,j,k);
131  qt_array(i,j,k) = qv_array(i,j,k) + qn_array(i,j,k);
132 
133  qpr_array(i,j,k) = std::max(0.0,states_array(i,j,k,RhoQ4_comp)/states_array(i,j,k,Rho_comp));
134  qps_array(i,j,k) = std::max(0.0,states_array(i,j,k,RhoQ5_comp)/states_array(i,j,k,Rho_comp));
135  qpg_array(i,j,k) = std::max(0.0,states_array(i,j,k,RhoQ6_comp)/states_array(i,j,k,Rho_comp));
136  qp_array(i,j,k) = qpr_array(i,j,k) + qps_array(i,j,k) + qpg_array(i,j,k);
137 
138  tabs_array(i,j,k) = getTgivenRandRTh(states_array(i,j,k,Rho_comp),
139  states_array(i,j,k,RhoTheta_comp),
140  qv_array(i,j,k));
141 
142  // NOTE: the Morrison Fortran version uses Pa not hPa so we don't divideby 100!
143  pres_array(i,j,k) = getPgivenRTh(states_array(i,j,k,RhoTheta_comp), qv_array(i,j,k)); // * 0.01;
144  });
145  }
146 }
#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_fac_cond = lcond / sc.c_p;
74  m_fac_fus = lfus / sc.c_p;
75  m_fac_sub = lsub / sc.c_p;
76  m_axis = sc.ave_plane;
77  m_rdOcp = sc.rdOcp;
78  m_do_cond = (!sc.use_shoc);
79  }
constexpr amrex::Real lfus
Definition: ERF_Constants.H:67
amrex::Real m_fac_cond
Definition: ERF_Morrison.H:307
amrex::Real m_fac_sub
Definition: ERF_Morrison.H:309
amrex::Real m_fac_fus
Definition: ERF_Morrison.H:308
amrex::Real rdOcp
Definition: ERF_DataStruct.H:1124
amrex::Real c_p
Definition: ERF_DataStruct.H:1123
bool use_shoc
Definition: ERF_DataStruct.H:1155
int ave_plane
Definition: ERF_DataStruct.H:1186

◆ 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  // Set class data members
47  for ( MFIter mfi(cons_in, TileNoZ()); mfi.isValid(); ++mfi) {
48  const auto& box3d = mfi.tilebox();
49 
50  const auto& lo = lbound(box3d);
51  const auto& hi = ubound(box3d);
52 
53  nlev = box3d.length(2);
54  zlo = lo.z;
55  zhi = hi.z;
56 
57  // parameters
58  accrrc.resize({zlo}, {zhi});
59  accrsi.resize({zlo}, {zhi});
60  accrsc.resize({zlo}, {zhi});
61  coefice.resize({zlo}, {zhi});
62  evaps1.resize({zlo}, {zhi});
63  evaps2.resize({zlo}, {zhi});
64  accrgi.resize({zlo}, {zhi});
65  accrgc.resize({zlo}, {zhi});
66  evapg1.resize({zlo}, {zhi});
67  evapg2.resize({zlo}, {zhi});
68  evapr1.resize({zlo}, {zhi});
69  evapr2.resize({zlo}, {zhi});
70 
71  // data (input)
72  rho1d.resize({zlo}, {zhi});
73  pres1d.resize({zlo}, {zhi});
74  tabs1d.resize({zlo}, {zhi});
75  }
76 
77 #ifdef ERF_USE_MORR_FORT
78  int morr_rimed_ice = 0; // This is used to set something called "ihail"
79  amrex::ParmParse pp("erf");
80  MoistureType moisture_type;
81  pp.query_enum_case_insensitive("moisture_model",moisture_type);
82  int morr_noice = (moisture_type == MoistureType::Morrison_NoIce);
83  Print()<<"Setting No Ice flag in fortran to "<<morr_noice<<std::endl;
84  morr_two_moment_init_c(morr_rimed_ice, morr_noice);
85 #endif
86 }
void morr_two_moment_init_c(int morr_rimed_ice, int morr_noice)
amrex::Vector< int > MicVarMap
Definition: ERF_Morrison.H:292
amrex::MultiFab * m_z_phys_nd
Definition: ERF_Morrison.H:317
amrex::MultiFab * m_detJ_cc
Definition: ERF_Morrison.H:318
int m_qmoist_size
Definition: ERF_Morrison.H:283
int zlo
Definition: ERF_Morrison.H:301
int zhi
Definition: ERF_Morrison.H:301
@ 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
158  {
159  // Solution tolerance
160  amrex::Real tol = 1.0e-4;
161 
162  // Saturation moisture fractions
163  amrex::Real omn, domn;
164  amrex::Real qsat, dqsat;
165  amrex::Real qsatw, dqsatw;
166  amrex::Real qsati, dqsati;
167 
168  // Newton iteration vars
169  int niter;
170  amrex::Real fff, dfff, dtabs;
171  amrex::Real lstar, dlstar;
172  amrex::Real lstarw, lstari;
173  amrex::Real delta_qv, delta_qc, delta_qi;
174 
175  // Initial guess for temperature & pressure
176  amrex::Real tabs = tabs_array(i,j,k);
177  amrex::Real pres = pres_array(i,j,k);
178 
179  niter = 0;
180  dtabs = 1;
181  //==================================================
182  // Newton iteration to qv=qsat (cloud phase only)
183  //==================================================
184  do {
185  // Latent heats and their derivatives wrt to T
186  lstarw = fac_cond;
187  lstari = fac_fus;
188  domn = 0.0;
189 
190  // Saturation moisture fractions
191  erf_qsatw(tabs, pres, qsatw);
192  erf_qsati(tabs, pres, qsati);
193  erf_dtqsatw(tabs, pres, dqsatw);
194  erf_dtqsati(tabs, pres, dqsati);
195 
196  // Cloud ice not permitted (condensation & fusion)
197  if(tabs >= tbgmax) {
198  omn = 1.0;
199  }
200  // Cloud water not permitted (sublimation & fusion)
201  else if(tabs <= tbgmin) {
202  omn = 0.0;
203  lstarw = fac_sub;
204  }
205  // Mixed cloud phase (condensation & fusion)
206  else {
207  omn = an*tabs-bn;
208  domn = an;
209  }
210 
211  // Linear combination of each component
212  qsat = omn * qsatw + (1.0-omn) * qsati;
213  dqsat = omn * dqsatw + (1.0-omn) * dqsati
214  + domn * qsatw - domn * qsati;
215  lstar = omn * lstarw + (1.0-omn) * lstari;
216  dlstar = domn * lstarw - domn * lstari;
217 
218  // Function for root finding:
219  // 0 = -T_new + T_old + L_eff/C_p * (qv - qsat)
220  fff = -tabs + tabs_array(i,j,k) + lstar*(qv_array(i,j,k) - qsat);
221 
222  // Derivative of function (T_new iterated on)
223  dfff = -1.0 + dlstar*(qv_array(i,j,k) - qsat) - lstar*dqsat;
224 
225  // Update the temperature
226  dtabs = -fff/dfff;
227  tabs += dtabs;
228 
229  // Update iteration
230  niter = niter+1;
231  } while(std::abs(dtabs) > tol && niter < 20);
232 
233  // Update qsat from last iteration (dq = dq/dt * dt)
234  qsat += dqsat*dtabs;
235 
236  // Changes in each component
237  delta_qv = qv_array(i,j,k) - qsat;
238  delta_qc = std::max(-qc_array(i,j,k), delta_qv * omn);
239  delta_qi = std::max(-qi_array(i,j,k), delta_qv * (1.0-omn));
240 
241  // Partition the change in non-precipitating q
242  qv_array(i,j,k) = qsat;
243  qc_array(i,j,k) += delta_qc;
244  qi_array(i,j,k) += delta_qi;
245  qn_array(i,j,k) = qc_array(i,j,k) + qi_array(i,j,k);
246  qt_array(i,j,k) = qv_array(i,j,k) + qn_array(i,j,k);
247 
248  // Return to temperature
249  return tabs;
250  }
constexpr amrex::Real tbgmax
Definition: ERF_Constants.H:32
constexpr amrex::Real tbgmin
Definition: ERF_Constants.H:31
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_dtqsatw(amrex::Real t, amrex::Real p, amrex::Real &dtqsatw)
Definition: ERF_MicrophysicsUtils.H:181
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_dtqsati(amrex::Real t, amrex::Real p, amrex::Real &dtqsati)
Definition: ERF_MicrophysicsUtils.H:173
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsatw(amrex::Real t, amrex::Real p, amrex::Real &qsatw)
Definition: ERF_MicrophysicsUtils.H:166
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsati(amrex::Real t, amrex::Real p, amrex::Real &qsati)
Definition: ERF_MicrophysicsUtils.H:155
Here is the call graph for this function:

◆ Qmoist_Ptr()

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

Reimplemented from NullMoist.

125  {
126  AMREX_ALWAYS_ASSERT(varIdx < m_qmoist_size);
127  return mic_fab_vars[MicVarMap[varIdx]].get();
128  }

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

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

◆ Qmoist_Size()

int Morrison::Qmoist_Size ( )
inlineoverridevirtual

Reimplemented from NullMoist.

134 { 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:286

◆ Set_dzmin()

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

Reimplemented from NullMoist.

93  {
94  m_dzmin = dz_min;
95  }
amrex::Real m_dzmin
Definition: ERF_Morrison.H:314

◆ Set_RealWidth()

void Morrison::Set_RealWidth ( const int  real_width)
inlineoverridevirtual

Reimplemented from NullMoist.

140 { m_real_width = real_width; }

◆ Update_Micro_Vars()

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

Reimplemented from NullMoist.

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

◆ Update_State_Vars()

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

Reimplemented from NullMoist.

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

Member Data Documentation

◆ 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 = 0.5
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_fac_cond

amrex::Real Morrison::m_fac_cond
private

Referenced by Define().

◆ m_fac_fus

amrex::Real Morrison::m_fac_fus
private

Referenced by Define().

◆ m_fac_sub

amrex::Real Morrison::m_fac_sub
private

Referenced by Define().

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