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

#include <ERF_Morrison.H>

Inheritance diagram for Morrison:
Collaboration diagram for Morrison:

Public Member Functions

 Morrison ()
 
virtual ~Morrison ()=default
 
void Define (SolverChoice &sc) override
 
void Init (const amrex::MultiFab &cons_in, const amrex::BoxArray &grids, const amrex::Geometry &geom, const amrex::Real &dt_advance, std::unique_ptr< amrex::MultiFab > &z_phys_nd, std::unique_ptr< amrex::MultiFab > &detJ_cc) override
 
void Set_dzmin (const amrex::Real dz_min) override
 
void Copy_State_to_Micro (const amrex::MultiFab &cons_in) override
 
void Copy_Micro_to_State (amrex::MultiFab &cons_in) override
 
void Update_Micro_Vars (amrex::MultiFab &cons_in) override
 
void Update_State_Vars (amrex::MultiFab &cons_in) override
 
void Advance (const amrex::Real &dt_advance, const SolverChoice &sc) override
 
amrex::MultiFab * Qmoist_Ptr (const int &varIdx) override
 
void Compute_Coefficients ()
 
int Qmoist_Size () override
 
int Qstate_Moist_Size () override
 
void Qmoist_Restart_Vars (const SolverChoice &, std::vector< int > &a_idx, std::vector< std::string > &a_names) const override
 
void GetPlotVarNames (amrex::Vector< std::string > &a_vec) const override
 Populate a vector with names of all available Morrison plot variables. More...
 
void GetPlotVar (const std::string &a_name, amrex::MultiFab &a_mf) const override
 Extract a Morrison microphysics variable for plotting. More...
 
- Public Member Functions inherited from NullMoist
 NullMoist ()
 
virtual ~NullMoist ()=default
 
virtual int Qstate_NonMoist_Size ()
 

Static Public Member Functions

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

Private Types

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

Private Attributes

int m_qmoist_size = 8
 
int n_qstate_moist_size = 6
 
amrex::Vector< int > MicVarMap
 
amrex::Geometry m_geom
 
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_rdOcp
 
bool m_do_cond
 
amrex::Real m_dzmin
 
amrex::MultiFab * m_z_phys_nd
 
amrex::MultiFab * m_detJ_cc
 
amrex::Array< FabPtr, MicVar_Morr::NumVarsmic_fab_vars
 
amrex::TableData< amrex::Real, 1 > accrrc
 
amrex::TableData< amrex::Real, 1 > accrsi
 
amrex::TableData< amrex::Real, 1 > accrsc
 
amrex::TableData< amrex::Real, 1 > coefice
 
amrex::TableData< amrex::Real, 1 > evaps1
 
amrex::TableData< amrex::Real, 1 > evaps2
 
amrex::TableData< amrex::Real, 1 > accrgi
 
amrex::TableData< amrex::Real, 1 > accrgc
 
amrex::TableData< amrex::Real, 1 > evapg1
 
amrex::TableData< amrex::Real, 1 > evapg2
 
amrex::TableData< amrex::Real, 1 > evapr1
 
amrex::TableData< amrex::Real, 1 > evapr2
 
amrex::TableData< amrex::Real, 1 > rho1d
 
amrex::TableData< amrex::Real, 1 > pres1d
 
amrex::TableData< amrex::Real, 1 > tabs1d
 
amrex::TableData< amrex::Real, 1 > qt1d
 
amrex::TableData< amrex::Real, 1 > qv1d
 
amrex::TableData< amrex::Real, 1 > qn1d
 

Static Private Attributes

static constexpr amrex::Real CFL_MAX = 0.5
 

Member Typedef Documentation

◆ FabPtr

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

Constructor & Destructor Documentation

◆ Morrison()

Morrison::Morrison ( )
inline
64 {}

◆ ~Morrison()

virtual Morrison::~Morrison ( )
virtualdefault

Member Function Documentation

◆ Advance()

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

Reimplemented from NullMoist.

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

◆ Compute_Coefficients()

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

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

Referenced by Update_Micro_Vars().

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

◆ Define()

void Morrison::Define ( SolverChoice sc)
inlineoverridevirtual

Reimplemented from NullMoist.

72  {
73  m_fac_cond = lcond / sc.c_p;
74  m_fac_fus = lfus / sc.c_p;
75  m_fac_sub = lsub / sc.c_p;
76  m_axis = sc.ave_plane;
77  m_rdOcp = sc.rdOcp;
78  m_do_cond = (!sc.use_shoc);
79  }
constexpr amrex::Real lfus
Definition: ERF_Constants.H:67
amrex::Real m_fac_cond
Definition: ERF_Morrison.H:304
amrex::Real m_fac_sub
Definition: ERF_Morrison.H:306
amrex::Real m_fac_fus
Definition: ERF_Morrison.H:305
amrex::Real rdOcp
Definition: ERF_DataStruct.H:975
amrex::Real c_p
Definition: ERF_DataStruct.H:974
bool use_shoc
Definition: ERF_DataStruct.H:1004
int ave_plane
Definition: ERF_DataStruct.H:1035

◆ GetPlotVar()

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

Extract a Morrison microphysics variable for plotting.

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

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

Reimplemented from NullMoist.

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

◆ GetPlotVarNames()

void Morrison::GetPlotVarNames ( amrex::Vector< std::string > &  a_vec) const
overridevirtual

Populate a vector with names of all available Morrison plot variables.

This function returns the names of all Morrison microphysics variables that can be written to plotfiles. These names correspond to the diagnostic fields defined in the plot_entries table.

Parameters
[out]a_vecVector to be populated with plot variable names
Note
The returned vector will contain 19 variable names, including both prognostic quantities (mixing ratios, number concentrations) and diagnostic quantities (temperature, pressure, derived moisture totals).

Reimplemented from NullMoist.

102 {
103  a_vec.clear();
104  a_vec.reserve(sizeof(plot_entries) / sizeof(plot_entries[0]));
105  for (const auto& entry : plot_entries) {
106  a_vec.emplace_back(entry.name);
107  }
108 }

◆ Init()

void Morrison::Init ( const amrex::MultiFab &  cons_in,
const amrex::BoxArray &  grids,
const amrex::Geometry &  geom,
const amrex::Real dt_advance,
std::unique_ptr< amrex::MultiFab > &  z_phys_nd,
std::unique_ptr< amrex::MultiFab > &  detJ_cc 
)
overridevirtual

Initializes the Microphysics module.

Parameters
[in]cons_inConserved variables input
[in]qc_inCloud variables input
[in,out]qv_inVapor variables input
[in]qi_inIce variables input
[in]gridsThe boxes on which we will evolve the solution
[in]geomGeometry associated with these MultiFabs and grids
[in]dt_advanceTimestep for the advance

Reimplemented from NullMoist.

28 {
29  [[maybe_unused]] amrex::Real dt = dt_advance;
30  m_geom = geom;
31  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  }
77 
78 #ifdef ERF_USE_MORR_FORT
79  int morr_rimed_ice = 0; // This is used to set something called "ihail"
80  amrex::ParmParse pp("erf");
81  MoistureType moisture_type;
82  pp.query_enum_case_insensitive("moisture_model",moisture_type);
83  int morr_noice = (moisture_type == MoistureType::Morrison_NoIce);
84  Print()<<"Setting No Ice flag in fortran to "<<morr_noice<<std::endl;
85  morr_two_moment_init_c(morr_rimed_ice, morr_noice);
86 #endif
87 }
void morr_two_moment_init_c(int morr_rimed_ice, int morr_noice)
amrex::Vector< int > MicVarMap
Definition: ERF_Morrison.H:289
amrex::MultiFab * m_z_phys_nd
Definition: ERF_Morrison.H:314
amrex::MultiFab * m_detJ_cc
Definition: ERF_Morrison.H:315
int m_qmoist_size
Definition: ERF_Morrison.H:280
int zlo
Definition: ERF_Morrison.H:298
amrex::BoxArray m_gtoe
Definition: ERF_Morrison.H:295
int zhi
Definition: ERF_Morrison.H:298
@ NumVars
Definition: ERF_Morrison.H:54
Here is the call graph for this function:

◆ NewtonIterSat()

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

◆ Qmoist_Ptr()

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

Reimplemented from NullMoist.

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

◆ Qmoist_Restart_Vars()

void Morrison::Qmoist_Restart_Vars ( const SolverChoice ,
std::vector< int > &  a_idx,
std::vector< std::string > &  a_names 
) const
inlineoverridevirtual

Reimplemented from NullMoist.

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

◆ Qmoist_Size()

int Morrison::Qmoist_Size ( )
inlineoverridevirtual

Reimplemented from NullMoist.

134 { return Morrison::m_qmoist_size; }

◆ Qstate_Moist_Size()

int Morrison::Qstate_Moist_Size ( )
inlineoverridevirtual

Reimplemented from NullMoist.

int n_qstate_moist_size
Definition: ERF_Morrison.H:283

◆ Set_dzmin()

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

Reimplemented from NullMoist.

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

◆ Update_Micro_Vars()

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

Reimplemented from NullMoist.

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

◆ Update_State_Vars()

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

Reimplemented from NullMoist.

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

Member Data Documentation

◆ accrgc

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

◆ accrgi

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

◆ accrrc

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

◆ accrsc

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

◆ accrsi

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

◆ CFL_MAX

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

◆ coefice

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

◆ evapg1

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

◆ evapg2

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

◆ evapr1

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

◆ evapr2

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

◆ evaps1

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

◆ evaps2

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

◆ m_axis

int Morrison::m_axis
private

Referenced by Define().

◆ m_detJ_cc

amrex::MultiFab* Morrison::m_detJ_cc
private

◆ m_do_cond

bool Morrison::m_do_cond
private

Referenced by Define().

◆ m_dzmin

amrex::Real Morrison::m_dzmin
private

Referenced by Set_dzmin().

◆ m_fac_cond

amrex::Real Morrison::m_fac_cond
private

Referenced by Define().

◆ m_fac_fus

amrex::Real Morrison::m_fac_fus
private

Referenced by Define().

◆ m_fac_sub

amrex::Real Morrison::m_fac_sub
private

Referenced by Define().

◆ m_geom

amrex::Geometry Morrison::m_geom
private

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

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