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

#include <ERF_Morrison.H>

Inheritance diagram for Morrison:
Collaboration diagram for Morrison:

Public Member Functions

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

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