ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 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 Qmoist_Restart_Vars (const SolverChoice &, std::vector< int > &a_idx, std::vector< std::string > &a_names) const override
 
- Public Member Functions inherited from NullMoist
 NullMoist ()
 
virtual ~NullMoist ()=default
 
virtual int Qstate_NonMoist_Size ()
 
virtual void GetPlotVarNames (amrex::Vector< std::string > &a_vec) const
 
virtual void GetPlotVar (const std::string &, amrex::MultiFab &) const
 

Static Public Member Functions

AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real NewtonIterSat (int &i, int &j, int &k, const 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
 
amrex::BoxArray m_gtoe
 
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_gOcp
 
amrex::Real m_rdOcp
 
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
 
amrex::TableData< amrex::Real, 1 > gamaz
 
amrex::TableData< amrex::Real, 1 > zmid
 

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

◆ Compute_Coefficients()

void Morrison::Compute_Coefficients ( )
153 {
154  auto dz = m_geom.CellSize(2);
155  auto lowz = m_geom.ProbLo(2);
156 
157  auto accrrc_t = accrrc.table();
158  auto accrsi_t = accrsi.table();
159  auto accrsc_t = accrsc.table();
160  auto coefice_t = coefice.table();
161  auto evaps1_t = evaps1.table();
162  auto evaps2_t = evaps2.table();
163  auto accrgi_t = accrgi.table();
164  auto accrgc_t = accrgc.table();
165  auto evapg1_t = evapg1.table();
166  auto evapg2_t = evapg2.table();
167  auto evapr1_t = evapr1.table();
168  auto evapr2_t = evapr2.table();
169 
170  auto rho1d_t = rho1d.table();
171  auto pres1d_t = pres1d.table();
172  auto tabs1d_t = tabs1d.table();
173 
174  auto gamaz_t = gamaz.table();
175  auto zmid_t = zmid.table();
176 
177  Real gam3 = erf_gammafff(3.0 );
178  Real gamr1 = erf_gammafff(3.0+b_rain );
179  Real gamr2 = erf_gammafff((5.0+b_rain)/2.0);
180  Real gams1 = erf_gammafff(3.0+b_snow );
181  Real gams2 = erf_gammafff((5.0+b_snow)/2.0);
182  Real gamg1 = erf_gammafff(3.0+b_grau );
183  Real gamg2 = erf_gammafff((5.0+b_grau)/2.0);
184 
185  // calculate the plane average variables
189  rho_ave.compute_averages(ZDir(), rho_ave.field());
190  theta_ave.compute_averages(ZDir(), theta_ave.field());
191  qv_ave.compute_averages(ZDir(), qv_ave.field());
192 
193  // get host variable rho, and rhotheta
194  int ncell = rho_ave.ncell_line();
195 
196  Gpu::HostVector<Real> rho_h(ncell), theta_h(ncell), qv_h(ncell);
197  rho_ave.line_average(0, rho_h);
198  theta_ave.line_average(0, theta_h);
199  qv_ave.line_average(0, qv_h);
200 
201  // copy data to device
202  Gpu::DeviceVector<Real> rho_d(ncell), theta_d(ncell), qv_d(ncell);
203  Gpu::copyAsync(Gpu::hostToDevice, rho_h.begin(), rho_h.end(), rho_d.begin());
204  Gpu::copyAsync(Gpu::hostToDevice, theta_h.begin(), theta_h.end(), theta_d.begin());
205  Gpu::copyAsync(Gpu::hostToDevice, qv_h.begin(), qv_h.end(), qv_d.begin());
206  Gpu::streamSynchronize();
207 
208  Real* rho_dptr = rho_d.data();
209  Real* theta_dptr = theta_d.data();
210  Real* qv_dptr = qv_d.data();
211 
212  Real gOcp = m_gOcp;
213 
214  ParallelFor(nlev, [=] AMREX_GPU_DEVICE (int k) noexcept
215  {
216  Real RhoTheta = rho_dptr[k]*theta_dptr[k];
217  Real pressure = getPgivenRTh(RhoTheta, qv_dptr[k]);
218  rho1d_t(k) = rho_dptr[k];
219  pres1d_t(k) = pressure*0.01;
220  // NOTE: Limit the temperature to the melting point of ice to avoid a divide by
221  // 0 condition when computing the cold evaporation coefficients. This should
222  // not affect results since evporation requires snow/graupel to be present
223  // and thus T<273.16
224  tabs1d_t(k) = std::min(getTgivenRandRTh(rho_dptr[k], RhoTheta, qv_dptr[k]),273.16);
225  zmid_t(k) = lowz + (k+0.5)*dz;
226  gamaz_t(k) = gOcp*zmid_t(k);
227  });
228 
229  if(round(gam3) != 2) {
230  std::cout << "cannot compute gamma-function in Microphysics::Init" << std::endl;
231  std::exit(-1);
232  }
233 
234  // Populate all the coefficients
235  ParallelFor(nlev, [=] AMREX_GPU_DEVICE (int k) noexcept
236  {
237  Real Prefactor;
238  Real pratio = sqrt(1.29 / rho1d_t(k));
239  //Real rrr1 = 393.0/(tabs1d_t(k)+120.0)*std::pow((tabs1d_t(k)/273.0),1.5);
240  //Real rrr2 = std::pow((tabs1d_t(k)/273.0),1.94)*(1000.0/pres1d_t(k));
241  Real estw = 100.0*erf_esatw(tabs1d_t(k));
242  Real esti = 100.0*erf_esati(tabs1d_t(k));
243 
244  // accretion by snow:
245  Real coef1 = 0.25 * PI * nzeros * a_snow * gams1 * pratio/pow((PI * rhos * nzeros/rho1d_t(k) ) , ((3.0+b_snow)/4.0));
246  Real coef2 = exp(0.025*(tabs1d_t(k) - 273.15));
247  accrsi_t(k) = coef1 * coef2 * esicoef;
248  accrsc_t(k) = coef1 * esccoef;
249  coefice_t(k) = coef2;
250 
251  // evaporation of snow:
252  coef1 = (lsub/(tabs1d_t(k)*R_v)-1.0)*lsub/(therco*tabs1d_t(k));
253  coef2 = R_v * R_d / (diffelq * esti);
254  Prefactor = 2.0 * PI * nzeros / (rho1d_t(k) * (coef1 + coef2));
255  Prefactor *= (2.0/PI); // Shape factor snow
256  evaps1_t(k) = Prefactor * 0.65 * sqrt(rho1d_t(k) / (PI * rhos * nzeros));
257  evaps2_t(k) = Prefactor * 0.44 * sqrt(a_snow * rho1d_t(k) / muelq) * gams2
258  * sqrt(pratio) * pow(rho1d_t(k) / (PI * rhos * nzeros) , ((5.0+b_snow)/8.0));
259 
260  // accretion by graupel:
261  coef1 = 0.25*PI*nzerog*a_grau*gamg1*pratio/pow((PI*rhog*nzerog/rho1d_t(k)) , ((3.0+b_grau)/4.0));
262  coef2 = exp(0.025*(tabs1d_t(k) - 273.15));
263  accrgi_t(k) = coef1 * coef2 * egicoef;
264  accrgc_t(k) = coef1 * egccoef;
265 
266  // evaporation of graupel:
267  coef1 = (lsub/(tabs1d_t(k)*R_v)-1.0)*lsub/(therco*tabs1d_t(k));
268  coef2 = R_v * R_d / (diffelq * esti);
269  Prefactor = 2.0 * PI * nzerog / (rho1d_t(k) * (coef1 + coef2)); // Shape factor for graupel is 1
270  evapg1_t(k) = Prefactor * 0.78 * sqrt(rho1d_t(k) / (PI * rhog * nzerog));
271  evapg2_t(k) = Prefactor * 0.31 * sqrt(a_grau * rho1d_t(k) / muelq) * gamg2
272  * sqrt(pratio) * pow(rho1d_t(k) / (PI * rhog * nzerog) , ((5.0+b_grau)/8.0));
273 
274  // accretion by rain:
275  accrrc_t(k) = 0.25 * PI * nzeror * a_rain * gamr1 * pratio/pow((PI * rhor * nzeror / rho1d_t(k)) , ((3.0+b_rain)/4.))* erccoef;
276 
277  // evaporation of rain:
278  coef1 = (lcond/(tabs1d_t(k)*R_v)-1.0)*lcond/(therco*tabs1d_t(k));
279  coef2 = R_v * R_d / (diffelq * estw);
280  Prefactor = 2.0 * PI * nzeror / (rho1d_t(k) * (coef1 + coef2)); // Shape factor for rain is 1
281  evapr1_t(k) = Prefactor * 0.78 * sqrt(rho1d_t(k) / (PI * rhor * nzeror));
282  evapr2_t(k) = Prefactor * 0.31 * sqrt(a_rain * rho1d_t(k) / muelq) * gamr2
283  * sqrt(pratio) * pow(rho1d_t(k) / (PI * rhor * nzeror) , ((5.0+b_rain)/8.0));
284  });
285 }
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:65
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esati(amrex::Real t)
Definition: ERF_MicrophysicsUtils.H:24
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:313
amrex::TableData< amrex::Real, 1 > pres1d
Definition: ERF_Morrison.H:319
amrex::TableData< amrex::Real, 1 > zmid
Definition: ERF_Morrison.H:326
amrex::Real m_gOcp
Definition: ERF_Morrison.H:293
amrex::TableData< amrex::Real, 1 > accrgi
Definition: ERF_Morrison.H:310
amrex::TableData< amrex::Real, 1 > accrgc
Definition: ERF_Morrison.H:311
amrex::TableData< amrex::Real, 1 > tabs1d
Definition: ERF_Morrison.H:320
int nlev
Definition: ERF_Morrison.H:284
amrex::TableData< amrex::Real, 1 > gamaz
Definition: ERF_Morrison.H:325
amrex::TableData< amrex::Real, 1 > coefice
Definition: ERF_Morrison.H:307
amrex::TableData< amrex::Real, 1 > accrsi
Definition: ERF_Morrison.H:305
amrex::TableData< amrex::Real, 1 > accrrc
Definition: ERF_Morrison.H:304
amrex::TableData< amrex::Real, 1 > evapg1
Definition: ERF_Morrison.H:312
amrex::TableData< amrex::Real, 1 > evapr1
Definition: ERF_Morrison.H:314
amrex::TableData< amrex::Real, 1 > evaps1
Definition: ERF_Morrison.H:308
amrex::TableData< amrex::Real, 1 > evaps2
Definition: ERF_Morrison.H:309
amrex::TableData< amrex::Real, 1 > rho1d
Definition: ERF_Morrison.H:318
amrex::TableData< amrex::Real, 1 > evapr2
Definition: ERF_Morrison.H:315
amrex::TableData< amrex::Real, 1 > accrsc
Definition: ERF_Morrison.H:306
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.

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

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

◆ Qmoist_Ptr()

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

Reimplemented from NullMoist.

118  {
119  AMREX_ALWAYS_ASSERT(varIdx < m_qmoist_size);
120  return mic_fab_vars[MicVarMap[varIdx]].get();
121  }

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

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

◆ Qmoist_Size()

int Morrison::Qmoist_Size ( )
inlineoverridevirtual

Reimplemented from NullMoist.

127 { 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:269

◆ Update_Micro_Vars()

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

Reimplemented from NullMoist.

100  {
101  this->Copy_State_to_Micro(cons_in);
102  this->Compute_Coefficients();
103  }
void Copy_State_to_Micro(const amrex::MultiFab &cons_in) override
Definition: ERF_InitMorrison.cpp:98
void Compute_Coefficients()
Definition: ERF_InitMorrison.cpp:152
Here is the call graph for this function:

◆ Update_State_Vars()

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

Reimplemented from NullMoist.

107  {
108  this->Copy_Micro_to_State(cons_in);
109  }
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

◆ gamaz

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

◆ m_axis

int Morrison::m_axis
private

Referenced by Define().

◆ m_detJ_cc

amrex::MultiFab* Morrison::m_detJ_cc
private

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

amrex::Real Morrison::m_gOcp
private

Referenced by Define().

◆ m_gtoe

amrex::BoxArray Morrison::m_gtoe
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_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

◆ zmid

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

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