ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_SuperDropletPCRiming.H
Go to the documentation of this file.
1 #ifndef SUPERDROPLET_PC_RIMING_H_
2 #define SUPERDROPLET_PC_RIMING_H_
3 
4 #include <cmath>
5 #include <algorithm>
6 
7 #include <AMReX_REAL.H>
8 #include <AMReX_GpuQualifiers.H>
9 #include <AMReX_Math.H>
10 
11 #include "ERF_Constants.H"
12 #include "ERF_MicrophysicsUtils.H"
14 
15 #ifdef ERF_USE_PARTICLES
16 
17 /*! \brief Riming microphysics helpers (dynamic viscosity, Rasmussen-Heymsfield
18  * impact velocity, ice surface temperature, and Heymsfield-Pflaum rime density).
19  * Factored out of ERF_SuperDropletPCCoalescence.cpp into this header, and made
20  * host+device, so they can be exercised by unit tests. */
21 namespace SDRiming
22 {
23  using amrex::Real;
24  using amrex::ParticleReal;
25 
26  /*! \brief Compute dynamic viscosity */
27  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
28  auto viscCoeff ( const ParticleReal a_T /*!< temperature */ )
29  {
30  auto T_degC = a_T - ParticleReal(tmelt); // [K] => [degC]
31  ParticleReal visc_coeff = ParticleReal(zero);
32  if( T_degC >= ParticleReal(zero) ) {
33  visc_coeff = ( ParticleReal(1.7180) + ParticleReal(4.9E-3)*T_degC ) * ParticleReal(1.E-5);
34  } else {
35  visc_coeff = ( ParticleReal(1.7180) + ParticleReal(4.9E-3)*T_degC - ParticleReal(1.2E-5)*T_degC*T_degC ) * ParticleReal(1.E-5);
36  }
37  return visc_coeff;
38  }
39 
40  /*! \brief Impact velocity ratio from Rasmussen and Heymsfield (1985)
41  *
42  * Computes the ratio of impact velocity to relative velocity for ice-droplet
43  * collisions as a function of Reynolds and Stokes numbers.
44  *
45  * Reference: Rasmussen, R. M., and A. J. Heymsfield, 1985: A generalized
46  * form for impact velocities used to determine graupel accretional densities.
47  * J. Atmos. Sci., 42, 2275-2279.
48  * https://doi.org/10.1175/1520-0469(1985)042<2275:AGFFIV>2.0.CO;2
49  *
50  * Polynomial fit: v_impact/v_rel = A0 + A1*w + A2*w^2 + A3*w^3 + A4*w^4
51  * where w = log10(St)
52  */
53  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
54  auto impactVelocity_RasmussenHeymsfield1985( const ParticleReal a_Re, /*!< Reynolds number */
55  const ParticleReal a_St /*!< Stokes number */ )
56  {
57  // the fits only apply for St >= 0.1; log10(0) raises FE_DIVBYZERO under fpe_trap_zero
58  ParticleReal w(zero), w2(zero), w3(zero), w4(zero);
59  if (a_St >= ParticleReal(0.1)) {
60  w = std::log10(a_St);
61  w2 = w*w;
62  w3 = w2*w;
63  w4 = w3*w;
64  }
65  ParticleReal retval = ParticleReal(zero);
66  if(a_Re < (ParticleReal(10.0)+ParticleReal(30.0))*ParticleReal(myhalf)) {
67  if (a_St < ParticleReal(0.4)) {
68  retval = ParticleReal(zero);
69  } else if (a_St<ParticleReal(10.0)) {
70  retval = ParticleReal(0.1701) + ParticleReal(0.7246)*w + ParticleReal(0.2257)*w2 - ParticleReal(1.13)*w3 + ParticleReal(0.5756)*w4;
71  } else {
72  retval = ParticleReal(0.57);
73  }
74  } else if (a_Re < (ParticleReal(30.0)+ParticleReal(100.0))*ParticleReal(myhalf)) {
75  if (a_St < ParticleReal(0.1)) {
76  retval = ParticleReal(zero);
77  } else if (a_St < ParticleReal(10.0)) {
78  retval = ParticleReal(0.2927) + ParticleReal(0.5085)*w - ParticleReal(0.03453)*w2 - ParticleReal(0.2184)*w3 + ParticleReal(0.03595)*w4;
79  } else {
80  retval = ParticleReal(0.59);
81  }
82  } else if (a_Re < (ParticleReal(100.0)+ParticleReal(300.0))*ParticleReal(myhalf)) {
83  if (a_St < ParticleReal(0.1)) {
84  retval = ParticleReal(zero);
85  } else if (a_St < ParticleReal(10.0)) {
86  retval = ParticleReal(0.3272) + ParticleReal(0.4907)*w - ParticleReal(0.09452)*w2 - ParticleReal(0.1906)*w3 + ParticleReal(0.07105)*w4;
87  } else {
88  retval = ParticleReal(0.61);
89  }
90  } else {
91  if (a_St < ParticleReal(0.1)) {
92  retval = ParticleReal(zero);
93  } else if (a_St < ParticleReal(10.0)) {
94  retval = ParticleReal(0.356) + ParticleReal(0.4738)*w - ParticleReal(0.1233)*w2 - ParticleReal(0.1618)*w3 + ParticleReal(0.08087)*w4;
95  } else {
96  retval = ParticleReal(0.63);
97  }
98  }
99  retval = std::max(retval,ParticleReal(zero));
100  return retval;
101  }
102 
103  /*! \brief Ice surface temperature */
104  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
105  ParticleReal iceSurfaceTemperature( const ParticleReal a_T, /*!< temperature */
106  const ParticleReal a_P, /*!< pressure */
107  const ParticleReal a_qv, /*!< vapour fraction */
108  const ParticleReal a_D, /*!< diffusivity coeff */
109  const SDMassChangeUtils_SV::dMdt<ParticleReal>& a_dmdt /*!< mass change utilities */)
110  {
111  // erf_qsati takes pressure in mbar and erf_esati returns mbar; a_P arrives in Pa
112  Real qsat_r = Real(zero); erf_qsati(a_T, a_P/Real(100.0), qsat_r);
113  ParticleReal qsat = ParticleReal(qsat_r);
114  auto sup_sat = a_qv/qsat - ParticleReal(one);
115  auto drho = sup_sat / (a_D * a_dmdt.Fk_plus_Fd(a_T, ParticleReal(erf_esati(a_T)*Real(100.0)), a_D));
116  auto dT = (a_dmdt.L * a_D / a_dmdt.K) * drho;
117  return a_T + dT;
118  }
119 
120  /*! \brief Rime density parameterization from Heymsfield and Pflaum (1985)
121  *
122  * Computes the density of rime accreted onto ice particles based on the
123  * dimensionless impact parameter Y = -r[um] * v_impact / T_surf[degC].
124  *
125  * Reference: Heymsfield, A. J., and J. C. Pflaum, 1985: A quantitative
126  * assessment of the accuracy of techniques for calculating graupel growth.
127  * J. Atmos. Sci., 42, 2264-2274.
128  *
129  * Two regimes based on surface temperature and Y parameter:
130  * - Low-density (T_surf <= -5 degC or Y < 1.6): rho = 0.30*Y^0.44 [Eq. 8]
131  * - High-density (otherwise): rho = exp(-0.03115 - 1.703*Y + 0.9116*Y^2 - 0.1224*Y^3) [Eq. 9]
132  *
133  * Output bounded to 0.1 <= rho_rime <= 0.91 g/cm^3 (100-910 kg/m^3)
134  */
135  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
136  auto rimeDensity_HeymsfieldPflaum1985( const ParticleReal a_radius, /*!< droplet radius [m] */
137  const ParticleReal a_a, /*!< ice particle equatorial radius [m] */
138  const ParticleReal a_c, /*!< ice particle polar radius [m] */
139  const ParticleReal a_vz_w, /*!< vertical velocity of water droplet [m/s] */
140  const ParticleReal a_vz_i, /*!< vertical velocity of ice particle [m/s] */
141  const ParticleReal a_rho_w, /*!< water density [kg/m^3] */
142  const ParticleReal a_D, /*!< diffusivity coefficient [m^2/s] */
143  const SDMassChangeUtils_SV::dMdt<ParticleReal>& a_dmdt, /*!< mass change utilities */
144  const ParticleReal a_T, /*!< temperature [K] */
145  const ParticleReal a_rhom, /*!< moist air density [kg/m^3] */
146  const ParticleReal a_P, /*!< pressure [Pa] */
147  const ParticleReal a_qv /*!< water vapor mixing ratio [kg/kg] */)
148  {
149  auto r_um = a_radius * ParticleReal(1.0e6);
150  auto mu = viscCoeff(a_T);
151 
152  auto maxD = ParticleReal(two) * std::max(a_a,a_c);
153  auto Re = a_rhom * maxD * std::abs(a_vz_i) / mu;
154  auto eqr_i = std::cbrt(a_a*a_a*a_c);
155  auto St = ParticleReal(two)*std::abs(a_vz_i)*a_radius*a_radius*a_rho_w/(ParticleReal(9.0)*mu*eqr_i);
156 
157  auto v_impact_ratio = impactVelocity_RasmussenHeymsfield1985(Re,St);
158  auto v_impact = std::abs(a_vz_i - a_vz_w) * v_impact_ratio;
159 
160  auto T_surf = std::min(ParticleReal(-0.01), iceSurfaceTemperature(a_T,a_P,a_qv,a_D,a_dmdt) - ParticleReal(tmelt));
161  auto var_Y = -r_um * v_impact/T_surf;
162 
163  ParticleReal rho_rime = ParticleReal(zero);
164  if ((T_surf <= ParticleReal(-5.0)) || (var_Y < ParticleReal(1.6))) {
165  rho_rime = ParticleReal(0.30) * std::pow(var_Y, ParticleReal(0.44));
166  } else {
167  var_Y = std::min(var_Y,ParticleReal(3.5));
168  rho_rime = std::exp(ParticleReal(-0.03115) - ParticleReal(1.7030)*var_Y + ParticleReal(0.9116)*var_Y*var_Y - ParticleReal(0.1224)*var_Y*var_Y*var_Y);
169  }
170  rho_rime = std::min(ParticleReal(0.91),std::max(rho_rime,ParticleReal(0.1))) * ParticleReal(1000.0);
171  return rho_rime;
172  }
173 
174 } // namespace SDRiming
175 
176 #endif
177 #endif
constexpr amrex::Real two
Definition: ERF_Constants.H:10
constexpr amrex::Real one
Definition: ERF_Constants.H:9
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
constexpr amrex::Real tmelt
Definition: ERF_Constants.H:130
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:13
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esati(amrex::Real t)
Definition: ERF_MicrophysicsUtils.H:31
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsati(amrex::Real t, amrex::Real p, amrex::Real &qsati)
Definition: ERF_MicrophysicsUtils.H:218
Real w
Definition: ERF_Plotfile2DInterpolator.cpp:22
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ mu
Definition: ERF_AdvanceMorrison.cpp:92