CCPP SciDoc v7.0.0  v7.0.0
Common Community Physics Package Developed at DTC
 
Loading...
Searching...
No Matches
module_mp_tempo_diags.F90
2 !! diagnostic output
3 use module_mp_tempo_params, only : wp, sp, dp, create_bins, r1, pi
4 use module_mp_tempo_utils, only : get_nuc, snow_moments
5
6 implicit none
7 private
8
9 public :: reflectivity_10cm, effective_radius, max_hail_diam, freezing_rain
10
11 contains
12
13 subroutine effective_radius(temp, l_qc, nc, ilamc, l_qi, ilami, l_qs, rs, &
14 re_qc, re_qi, re_qs)
15 !! effective radius values for cloud water, cloud ice and snow
16 !!
17 !! \‍(r_{e} = 0.5\frac{\int_0^\infty D^{3}n(D)dD}{\int_0^\infty D^2n(D)dD}\‍)
18 use module_mp_tempo_params, only : mu_i, t0
19
20 real(wp), dimension(:), intent(in) :: temp, nc, rs
21 real(dp), dimension(:), intent(in) :: ilamc, ilami
22 logical, dimension(:), intent(in) :: l_qc, l_qi, l_qs
23 real(wp), dimension(:), intent(out) :: re_qc, re_qi, re_qs
24 real(wp), dimension(15), parameter :: g_ratio = &
25 [24._wp,60._wp,120._wp,210._wp,336._wp,504._wp,720._wp,990._wp, &
26 1320._wp,1716._wp,2184._wp,2730._wp,3360._wp,4080._wp,4896._wp]
27 real(dp) :: smob, smoc
28 real(wp) :: tc0
29 integer :: k, nz, nu_c
30
31 nz = size(l_qc)
32 do k = 1, nz
33 re_qc(k) = 0._wp
34 re_qi(k) = 0._wp
35 re_qs(k) = 0._wp
36
41 if (l_qc(k)) then
42 nu_c = get_nuc(nc(k))
43 re_qc(k) = max(2.51e-6_wp, &
44 min(real(0.5_dp*(3._dp+real(nu_c, kind=dp))*ilamc(k), kind=wp), 50.e-6_wp))
45 endif
46 if (l_qi(k)) then
47 re_qi(k) = max(2.51e-6_wp, &
48 min(real(0.5_dp*(3._dp+real(mu_i, kind=dp))*ilami(k), kind=wp), 125.e-6_wp))
49 endif
50 if (l_qs(k)) then
51 tc0 = min(-0.1, temp(k)-t0)
52 call snow_moments(rs=rs(k), tc=tc0, smob=smob, smoc=smoc)
53 re_qs(k) = max(5.01e-6_wp, min(real(0.5_wp*(smoc/smob), kind=wp), 999.e-6_wp))
54 endif
55 enddo
56 end subroutine effective_radius
57
58
59 subroutine reflectivity_10cm(refl10cm_from_melting_flag, &
60 temp, l_qr, rr, nr, ilamr, l_qs, rs, smoc, smob, smoz, &
61 l_qg, rg, ng, idx, ilamg, dbz)
62 !! 10-cm radar reflectivity
63 !!
64 !! contributions from melting snow and graupel are optionally included
65 !!
66 !! \‍(Z_{e} = \int_0^\infty D^{6}n(D)dD\‍) and \‍(dbz = 10*log10(Z_{e}*1\times 10^{18})\‍)
67 use module_mp_tempo_params, only : pi, org2, cre, crg, am_s, am_g, cge, cgg, ogg2
68
69 logical, intent(in) :: refl10cm_from_melting_flag
70 logical, dimension(:), intent(in) :: l_qr, l_qs, l_qg
71 real(wp), dimension(:), intent(in) :: temp, rg, ng, rr, nr, rs
72 real(dp), dimension(:), intent(in) :: ilamr, smoc, smob, smoz, ilamg
73 integer, dimension(:), intent(in) :: idx
74 real(wp), dimension(:), intent(out) :: dbz
75 real(wp) :: ze_rain(size(temp)), ze_snow(size(temp)), ze_graupel(size(temp))
76 real(dp) :: n0_r, lamr, n0_g
77 integer :: k, nz, k_melt
78
79 nz = size(temp)
80 ze_rain = 1.e-22_wp
81 ze_snow = 1.e-22_wp
82 ze_graupel = 1.e-22_wp
83
84 if (refl10cm_from_melting_flag) then
85 k_melt = find_melting_level(temp, l_qr, l_qs, l_qg)
86 endif
87
88 do k = nz, 1, -1
89 dbz(k) = -35._wp
90
91 if (l_qr(k)) then
92 lamr = 1._dp/ilamr(k)
93 n0_r = nr(k)*org2*lamr**cre(2)
94 ze_rain(k) = n0_r*crg(4)*ilamr(k)**cre(4)
95 endif
96 if (l_qs(k)) then
97 ze_snow(k) = (0.176_wp/0.93_wp) * (6._wp/pi)*(6._wp/pi) * &
98 (am_s/900._wp)*(am_s/900._wp)*smoz(k)
99 ! include melting
100 if (refl10cm_from_melting_flag) then
101 if (k_melt > 2 .and. k < k_melt-1) then
102 ze_snow(k) = reflectivity_from_melting_snow(rs(k), &
103 smob(k), smoc(k), rr(k))
104 endif
105 endif
106 endif
107 if (l_qg(k)) then
108 n0_g = ng(k)*ogg2*(1._dp/ilamg(k))**cge(2,1)
109 ze_graupel(k) = (0.176_wp/0.93_wp) * (6._wp/pi)*(6._wp/pi) * &
110 (am_g(idx(k))/900._wp)*(am_g(idx(k))/900._wp) * n0_g*cgg(4,1)*ilamg(k)**cge(4,1)
111 ! include melting
112 if (refl10cm_from_melting_flag) then
113 if (k_melt > 2 .and. k < k_melt-1) then
114 ze_graupel(k) = reflectivity_from_melting_graupel(rg(k), ng(k), &
115 ilamg(k), idx(k), rr(k))
116 endif
117 endif
118 endif
119 dbz(k) = max(-35._wp, 10._wp*real(log10((ze_rain(k)+ze_snow(k)+ze_graupel(k))*1.e18_dp), kind=wp))
120 enddo
121 end subroutine reflectivity_10cm
122
123
124 function find_melting_level(temp, l_qr, l_qs, l_qg) result(k_melt)
125 !! finds the melting level
126 use module_mp_tempo_params, only : t0
127
128 real(wp), dimension(:), intent(in) :: temp
129 logical, dimension(:), intent(in) :: l_qr, l_qs, l_qg
130 integer :: k, nz
131 integer :: k_melt
132
133 nz = size(l_qr)
134 k_melt = 1
135 kloop: do k = nz-1, 1, -1
136 if ((temp(k) > t0) .and. l_qr(k) .and. (l_qs(k+1) .or. l_qg(k+1))) then
137 k_melt = max(k+1, k_melt)
138 exit kloop
139 endif
140 enddo kloop
141 end function find_melting_level
142
143
144 function complex_water_ray(lambda, t) result(refractive_index)
145 use module_mp_tempo_params, only : pi
146 !! complex refractive index of water
147 !! from [Ray (1972)](https://doi.org/10.1364/AO.11.001836)
148 !! calculated as function of temperature t [Celsius] (valid from -10 to 30)
149 !! and radar wavelength lambda [m] (valid from 0.001 to 1)
150 !!
151 !! original credit: Ulrich Blahak and G. Thompson
152 real(dp), intent(in) :: lambda, t
153 real(dp) :: epsinf,epss,epsr,epsi,alpha,lambdas,nenner
154 complex(dp), parameter :: i = (0._dp, 1._dp)
155 complex(dp) :: refractive_index
156
157 epsinf = 5.27137_dp + 0.02164740d0*t - 0.00131198_dp*t*t
158 epss = 78.54_dp * (1.0_dp - 4.579e-3_dp * (t - 25.0_dp) + &
159 1.190e-5_dp * (t - 25.0_dp)*(t - 25.0_dp) - 2.800e-8_dp * &
160 (t - 25.0_dp)*(t - 25.0_dp)*(t - 25.0_dp))
161 alpha = -16.8129_dp/(t+273.16_dp) + 0.0609265_dp
162 lambdas = 0.00033836_dp * exp(2513.98_dp/(t+273.16_dp)) * 1e-2_dp
163
164 nenner = 1._dp+2._dp*(lambdas/lambda)**(1_dp-alpha)*sin(alpha*pi*0.5_dp) + &
165 (lambdas/lambda)**(2._dp-2._dp*alpha)
166 epsr = epsinf + ((epss-epsinf) * ((lambdas/lambda)**(1_dp-alpha) * &
167 sin(alpha*pi*0.5_dp)+1._dp)) / nenner
168 epsi = ((epss-epsinf) * ((lambdas/lambda)**(1_dp-alpha) * &
169 cos(alpha*pi*0.5_dp)+0._dp)) / nenner + lambda*1.25664_dp/1.88496_dp
170
171 refractive_index = sqrt(cmplx(epsr,-epsi, kind=dp))
172 end function complex_water_ray
173
174
175 function complex_ice_maetzler(lambda, t) result(refractive_index)
176 !! complex refractive index of ice from
177 !! [Maetzler (1998)](https://doi.org/10.1007/978-94-011-5252-5_10)
178 !! calculated as function of temperature t [Celsius] (valid from -250 to 0)
179 !! and radar wavelength lambda [m] (valid from 0.0001 to 30)
180 !!
181 !! original credit: Ulrich Blahak and G. Thompson
182 real(dp), intent(in) :: lambda, t
183 real(dp) :: f,c,tk,b1,b2,b,deltabeta,betam,beta,theta,alfa
184 complex(dp) :: refractive_index
185
186 c = 2.99e8_dp
187 tk = t + 273.16_dp
188 f = c / lambda * 1e-9_dp
189 b1 = 0.0207_dp
190 b2 = 1.16e-11_dp
191 b = 335._dp
192 deltabeta = exp(-10.02_dp + 0.0364_dp*(tk-273.16_dp))
193 betam = (b1/tk) * (exp(b/tk) / ((exp(b/tk)-1._dp)**2_dp) ) + b2*f*f
194 beta = betam + deltabeta
195 theta = 300._dp / tk - 1._dp
196 alfa = (0.00504_dp + 0.0062_dp*theta) * exp(-22.1_dp*theta)
197
198 refractive_index = 3.1884_dp + 9.1e-4_dp*(tk-273.16_dp)
199 refractive_index = refractive_index+ cmplx(0.0_dp, (alfa/f + beta*f), kind=dp)
200 refractive_index = sqrt(conjg(refractive_index))
201 end function complex_ice_maetzler
202
203
204 function reflectivity_from_melting_graupel(rg, ng, ilamg, idx, rr) result(ze_graupel)
205 !! calculates radar reflectivity from melting graupel using binned approach
206 !!
207 !! original credit: Ulrich Blahak and G. Thompson
208 use module_mp_tempo_params, only : am_g, bm_g, obmg, ocmg, mu_g, ogg2, cge, &
209 gbins_radar, dgbins_radar, radar_bins
210
211 real(wp), intent(in) :: rg, ng, rr
212 real(dp), intent(in) :: ilamg
213 integer, intent(in) :: idx
214 real(dp), parameter :: melt_outside = 0.9_dp
215 real(dp), parameter :: lambda_radar = 0.10_dp ! in meters
216 complex(dp) :: m_w_0, m_i_0
217 real(dp), dimension(radar_bins+1) :: simpson
218 real(dp), dimension(3), parameter :: basis = [1._dp/3._dp, 4._dp/3._dp, 1._dp/3._dp]
219 real(dp) :: sr, fmelt, eta, lamg, backscatter, f_d, n0_g, mass, k_w
220 integer :: n
221 real(wp) :: ze_graupel
222
223 do n = 1, radar_bins+1
224 simpson(n) = 0._dp
225 enddo
226 do n = 1, radar_bins-1, 2
227 simpson(n) = simpson(n) + basis(1)
228 simpson(n+1) = simpson(n+1) + basis(2)
229 simpson(n+2) = simpson(n+2) + basis(3)
230 enddo
231
232 m_w_0 = complex_water_ray(lambda_radar, 0._dp)
233 m_i_0 = complex_ice_maetzler(lambda_radar, 0._dp)
234 k_w = (abs((m_w_0*m_w_0 - 1._dp) /(m_w_0*m_w_0 + 2._dp)))**2
235
236 sr = max(0.01_dp, min(1.0_dp - rg/max(rg + rr, r1), 0.99_dp))
237 fmelt = real(sr*sr, kind=dp)
238 eta = 0._dp
239 lamg = 1._dp/ilamg
240 n0_g = ng*ogg2*lamg**cge(2,1)
241
242 do n = 1, radar_bins
243 mass = am_g(idx) * gbins_radar(n)**bm_g
244 call rayleigh_soak_wetgraupel(x_g=mass, a_geo=real(ocmg(idx), kind=dp), b_geo=real(obmg, kind=dp), &
245 fmelt=fmelt, lambda_radar=lambda_radar, meltratio_outside=melt_outside, &
246 m_w=m_w_0, m_i=m_i_0, backscatter=backscatter)
247 f_d = n0_g*gbins_radar(n)**mu_g * exp(-lamg*gbins_radar(n))
248 eta = eta + f_d * backscatter * simpson(n) * dgbins_radar(n)
249 enddo
250 ze_graupel = lambda_radar*lambda_radar*lambda_radar*lambda_radar / &
251 (pi*pi*pi*pi*pi * k_w) * eta
252 end function reflectivity_from_melting_graupel
253
254
255 function reflectivity_from_melting_snow(rs, smob, smoc, rr) result(ze_snow)
256 !! calculates radar reflectivity from melting snow using binned approach
257 !!
258 !! original credit: Ulrich Blahak and G. Thompson
259 use module_mp_tempo_params, only : am_s, bm_s, lam0, lam1, obms, ocms, kap0, kap1, mu_s, &
260 sbins_radar, dsbins_radar, radar_bins
261
262 real(wp), intent(in) :: rs, rr
263 real(dp), intent(in) :: smob, smoc
264 real(dp), parameter :: melt_outside = 0.9_dp
265 real(dp), parameter :: lambda_radar = 0.10_dp ! in meters
266 complex(dp) :: m_w_0, m_i_0
267 real(dp), dimension(radar_bins+1) :: simpson
268 real(dp), dimension(3), parameter :: basis = [1._dp/3._dp, 4._dp/3._dp, 1._dp/3._dp]
269 real(dp) :: sr, fmelt, eta, backscatter, f_d, mass, k_w, om3, m0, mrat, slam1, slam2
270 integer :: n
271 real(wp) :: ze_snow
272
273 do n = 1, radar_bins+1
274 simpson(n) = 0._dp
275 enddo
276 do n = 1, radar_bins-1, 2
277 simpson(n) = simpson(n) + basis(1)
278 simpson(n+1) = simpson(n+1) + basis(2)
279 simpson(n+2) = simpson(n+2) + basis(3)
280 enddo
281
282 m_w_0 = complex_water_ray(lambda_radar, 0._dp)
283 m_i_0 = complex_ice_maetzler(lambda_radar, 0._dp)
284 k_w = (abs((m_w_0*m_w_0 - 1._dp) /(m_w_0*m_w_0 + 2._dp)))**2
285
286 sr = max(0.01_dp, min(1.0_dp - rs/(rs + rr), 0.99_dp))
287 fmelt = real(sr*sr, kind=dp)
288 eta = 0._dp
289
290 om3 = 1._dp/smoc
291 m0 = (smob*om3)
292 mrat = smob*m0*m0*m0
293 slam1 = m0 * lam0
294 slam2 = m0 * lam1
295 do n = 1, radar_bins
296 mass = am_s * sbins_radar(n)**bm_s
297
298 call rayleigh_soak_wetgraupel(x_g=mass, a_geo=real(ocms, kind=dp), b_geo=real(obms, kind=dp), &
299 fmelt=fmelt, lambda_radar=lambda_radar, meltratio_outside=melt_outside, &
300 m_w=m_w_0, m_i=m_i_0, backscatter=backscatter)
301 f_d = mrat*(kap0*exp(-slam1*sbins_radar(n)) + kap1*(m0*sbins_radar(n))**mu_s * exp(-slam2*sbins_radar(n)))
302 eta = eta + f_d * backscatter * simpson(n) * dsbins_radar(n)
303 enddo
304 ze_snow = lambda_radar*lambda_radar*lambda_radar*lambda_radar / &
305 (pi*pi*pi*pi*pi * k_w) * eta
306 end function reflectivity_from_melting_snow
307
308
309 subroutine rayleigh_soak_wetgraupel(x_g, a_geo, b_geo, fmelt, lambda_radar, &
310 meltratio_outside, m_w, m_i, backscatter)
311 !! calculates backscatter cross section of wet snow or graupel
312 !! using Maxwell-Garnett mixing formula and Rayleigh approximation
313 !!
314 !! original credit: Ulrich Blahak and G. Thompson
315
316 real(dp), intent(in) :: x_g, a_geo, b_geo, fmelt, lambda_radar, meltratio_outside
317 complex(dp), intent(in) :: m_w, m_i
318 real(dp), intent(out) :: backscatter
319 real(dp) :: fm, mra, x_w, d_g, vg, rhog, meltratio_outside_grenz, &
320 volg, fmgrenz, d_large, volwater, volice, volair, volmix1, volmix2, &
321 vol1, vol2, vol3
322 complex(dp) :: m_core, m_air, m_tmp, m1t, m2t, m3t, beta2, beta3
323
324 m_air = (1._dp, 0._dp)
325 fm = max(min(fmelt, 1._dp), 0._dp) ! limit melt fraction between 0 and 1
326 mra = max(min(meltratio_outside, 1._dp), 0._dp) ! ratio of (melt on outside) / (melt on indside)
327 mra = mra + (1._dp-mra)*fm ! force mra to 1 when fm = 1
328
329 x_w = x_g * fm
330 d_g = a_geo * x_g**b_geo
331 if (d_g >= r1) then
332 vg = pi/6._dp * d_g**3
333 rhog = max(min(x_g / vg, 900._dp), 10._dp)
334 vg = x_g / rhog
335 meltratio_outside_grenz = 1._dp - rhog / 1000._dp
336
337 if (mra <= meltratio_outside_grenz) then
338 volg = vg * (1._dp - mra * fm)
339 else
340 ! at some value of fm all air gets filled with meltwater
341 fmgrenz=(900._dp-rhog)/(mra*900._dp-rhog+900._dp*rhog/1000._dp)
342 if (fm <= fmgrenz) then
343 ! not all air is filled with meltwater
344 volg = (1.0_dp - mra * fm) * vg
345 else
346 ! all air is filled with meltwater
347 volg = (x_g - x_w) / 900._dp + x_w / 1000._dp
348 endif
349 endif
350
351 ! ice-air-water mixture volumes
352 d_large = (6._dp / pi * volg) ** (1._dp/3._dp)
353 volice = (x_g - x_w) / (volg * 900._dp)
354 volwater = x_w / (1000._dp * volg)
355 volair = 1.0_dp - volice - volwater
356
357 volmix1 = volice / max(volice+volwater,1e-10_dp)
358 volmix2 = 1._dp - volmix1
359
360 ! Maxwell-Garnett mixing for ice-water mixture
361 m1t = m_w**2
362 m2t = m_air**2
363 m3t = m_i**2
364 vol1 = volmix2
365 vol2 = 0._dp
366 vol3 = volmix1
367
368 beta2 = 2._dp*m1t/(m2t-m1t) * (m2t/(m2t-m1t)*log(m2t/m1t)-1._dp)
369 beta3 = 2._dp*m1t/(m3t-m1t) * (m3t/(m3t-m1t)*log(m3t/m1t)-1._dp)
370
371 m_tmp = sqrt(((1._dp-vol2-vol3)*m1t + vol2*beta2*m2t + vol3*beta3*m3t) / &
372 (1._dp-vol2-vol3+vol2*beta2+vol3*beta3))
373
374 ! Maxwell-Garnett mixing (including air)
375 m1t = m_tmp**2
376 m2t = m_air**2
377 m3t = (2._dp*m_air)**2
378 vol1 = (1._dp-volair)
379 vol2 = volair
380 vol3 = 0._dp
381
382 beta2 = 2._dp*m1t/(m2t-m1t) * (m2t/(m2t-m1t)*log(m2t/m1t)-1._dp)
383 beta3 = 2._dp*m1t/(m3t-m1t) * (m3t/(m3t-m1t)*log(m3t/m1t)-1._dp)
384
385 ! complex index of refraction for ice-air-water mixture
386 m_core = sqrt(((1._dp-vol2-vol3)*m1t + vol2*beta2*m2t + vol3*beta3*m3t) / &
387 (1._dp-vol2-vol3+vol2*beta2+vol3*beta3))
388
389 ! Rayleigh backscattering coefficient of melting particle
390 backscatter = (abs((m_core**2-1._dp)/(m_core**2+2._dp)))**2 * pi*pi*pi*pi*pi * d_large**6 / &
391 (lambda_radar*lambda_radar*lambda_radar*lambda_radar)
392 else
393 backscatter = 0._dp
394 endif
395 end subroutine rayleigh_soak_wetgraupel
396
397
398 subroutine max_hail_diam(rho, rg, ng, ilamg, idx, max_hail_diameter)
399 !! estimates maximmum hail diameter [mm] using a binned approach
400 !!
401 !! see [Jensen et al. (2023)](https://doi.org/10.1175/MWR-D-21-0319.1)
402 use module_mp_tempo_params, only : hbins, dhbins, rho_g, ogg2, cge, nhbins, mu_g
403
404 real(wp), dimension(:), intent(in) :: rho, rg, ng
405 real(dp), dimension(:), intent(in) :: ilamg
406 integer, dimension(:), intent(in) :: idx
407 real(wp), dimension(:), intent(out) :: max_hail_diameter
408 real(dp) :: lamg, n0_g, sum_nh, sum_t, f_d, hail_max
409 integer :: k, nz, n
410 real(dp), parameter :: threshold_conc = 0.0005
411
412 nz = size(rho)
413 do k = 1, nz
414 max_hail_diameter(k) = 0._wp
415 if(rg(k)/rho(k) >= 1.e-6_wp) then
416 if (rho_g(idx(k)) < 350._wp) cycle ! density too low to be hail/ice pellets
417 lamg = 1._dp / ilamg(k)
418 n0_g = ng(k)*ogg2*lamg**cge(2,1)
419
420 sum_nh = 0._dp
421 sum_t = 0._dp
422 do n = nhbins, 1, -1
423 f_d = n0_g*hbins(n)**mu_g * exp(-lamg*hbins(n)) * dhbins(n)
424 sum_nh = sum_nh + f_d
425 if (sum_nh > threshold_conc) exit
426 sum_t = sum_nh
427 enddo
428 if (n >= nhbins) then
429 hail_max = hbins(nhbins)
430 elseif (hbins(n+1) > 1.e-3_wp) then
431 hail_max = hbins(n) - (sum_nh-threshold_conc)/(sum_nh-sum_t) * (hbins(n)-hbins(n+1))
432 else
433 hail_max = 1.e-4_wp
434 endif
435 max_hail_diameter(k) = 1000._wp * hail_max ! convert to mm
436 endif
437 enddo
438 end subroutine max_hail_diam
439
440
441 subroutine freezing_rain(temp, rain_precip, cloud_precip, frz_rain)
442 !! estimates freezing rain/drizzle accumulation
443 use module_mp_tempo_params, only : t0
444
445 real(wp), intent(in) :: temp, rain_precip
446 real(wp), intent(in), optional :: cloud_precip
447 real(wp), intent(out) :: frz_rain
448
449 frz_rain = 0._wp
450 if ((temp-t0) < -0.5_wp) then
451 frz_rain = rain_precip
452 if (present(cloud_precip)) then
453 frz_rain = frz_rain + cloud_precip
454 endif
455 endif
456 end subroutine freezing_rain
457
458end module module_mp_tempo_diags