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

◆ 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:276
amrex::MultiFab * m_z_phys_nd
Definition: ERF_Morrison.H:299
amrex::MultiFab * m_detJ_cc
Definition: ERF_Morrison.H:300
int m_qmoist_size
Definition: ERF_Morrison.H:267
int zlo
Definition: ERF_Morrison.H:285
amrex::BoxArray m_gtoe
Definition: ERF_Morrison.H:282
int zhi
Definition: ERF_Morrison.H:285
@ 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
149  {
150  // Solution tolerance
151  amrex::Real tol = 1.0e-4;
152 
153  // Saturation moisture fractions
154  amrex::Real omn, domn;
155  amrex::Real qsat, dqsat;
156  amrex::Real qsatw, dqsatw;
157  amrex::Real qsati, dqsati;
158 
159  // Newton iteration vars
160  int niter;
161  amrex::Real fff, dfff, dtabs;
162  amrex::Real lstar, dlstar;
163  amrex::Real lstarw, lstari;
164  amrex::Real delta_qv, delta_qc, delta_qi;
165 
166  // Initial guess for temperature & pressure
167  amrex::Real tabs = tabs_array(i,j,k);
168  amrex::Real pres = pres_array(i,j,k);
169 
170  niter = 0;
171  dtabs = 1;
172  //==================================================
173  // Newton iteration to qv=qsat (cloud phase only)
174  //==================================================
175  do {
176  // Latent heats and their derivatives wrt to T
177  lstarw = fac_cond;
178  lstari = fac_fus;
179  domn = 0.0;
180 
181  // Saturation moisture fractions
182  erf_qsatw(tabs, pres, qsatw);
183  erf_qsati(tabs, pres, qsati);
184  erf_dtqsatw(tabs, pres, dqsatw);
185  erf_dtqsati(tabs, pres, dqsati);
186 
187  // Cloud ice not permitted (condensation & fusion)
188  if(tabs >= tbgmax) {
189  omn = 1.0;
190  }
191  // Cloud water not permitted (sublimation & fusion)
192  else if(tabs <= tbgmin) {
193  omn = 0.0;
194  lstarw = fac_sub;
195  }
196  // Mixed cloud phase (condensation & fusion)
197  else {
198  omn = an*tabs-bn;
199  domn = an;
200  }
201 
202  // Linear combination of each component
203  qsat = omn * qsatw + (1.0-omn) * qsati;
204  dqsat = omn * dqsatw + (1.0-omn) * dqsati
205  + domn * qsatw - domn * qsati;
206  lstar = omn * lstarw + (1.0-omn) * lstari;
207  dlstar = domn * lstarw - domn * lstari;
208 
209  // Function for root finding:
210  // 0 = -T_new + T_old + L_eff/C_p * (qv - qsat)
211  fff = -tabs + tabs_array(i,j,k) + lstar*(qv_array(i,j,k) - qsat);
212 
213  // Derivative of function (T_new iterated on)
214  dfff = -1.0 + dlstar*(qv_array(i,j,k) - qsat) - lstar*dqsat;
215 
216  // Update the temperature
217  dtabs = -fff/dfff;
218  tabs += dtabs;
219 
220  // Update iteration
221  niter = niter+1;
222  } while(std::abs(dtabs) > tol && niter < 20);
223 
224  // Update qsat from last iteration (dq = dq/dt * dt)
225  qsat += dqsat*dtabs;
226 
227  // Changes in each component
228  delta_qv = qv_array(i,j,k) - qsat;
229  delta_qc = std::max(-qc_array(i,j,k), delta_qv * omn);
230  delta_qi = std::max(-qi_array(i,j,k), delta_qv * (1.0-omn));
231 
232  // Partition the change in non-precipitating q
233  qv_array(i,j,k) = qsat;
234  qc_array(i,j,k) += delta_qc;
235  qi_array(i,j,k) += delta_qi;
236  qn_array(i,j,k) = qc_array(i,j,k) + qi_array(i,j,k);
237  qt_array(i,j,k) = qv_array(i,j,k) + qn_array(i,j,k);
238 
239  // Return to temperature
240  return tabs;
241  }
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.

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

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

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

◆ Qmoist_Size()

int Morrison::Qmoist_Size ( )
inlineoverridevirtual

Reimplemented from NullMoist.

128 { 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:270

◆ Update_Micro_Vars()

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

Reimplemented from NullMoist.

101  {
102  this->Copy_State_to_Micro(cons_in);
103  this->Compute_Coefficients();
104  }
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.

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

bool Morrison::m_do_cond
private

Referenced by Define().

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