LMDZ
radar_simulator.F90
Go to the documentation of this file.
1  subroutine radar_simulator(freq,k2,do_ray,use_gas_abs,use_mie_table,mt, &
2  nhclass,hp,nprof,ngate,nsizes,d,hgt_matrix,hm_matrix,re_matrix,p_matrix,t_matrix, &
3  rh_matrix,ze_non,ze_ray,h_atten_to_vol,g_atten_to_vol,dbze, &
4  g_to_vol_in,g_to_vol_out)
5 
6 ! rh_matrix,Ze_non,Ze_ray,kr_matrix,g_atten_to_vol,dBZe)
7 
8  use m_mrgrnk
9  use array_lib
10  use math_lib
11  use optics_lib
13  implicit none
14 
15 ! Purpose:
16 ! Simulates a vertical profile of radar reflectivity
17 ! Part of QuickBeam v1.04 by John Haynes & Roger Marchand
18 !
19 ! Inputs:
20 ! [freq] radar frequency (GHz), can be anything unless
21 ! use_mie_table=1, in which case one of 94,35,13.8,9.6,3
22 ! [k2] |K|^2, the dielectric constant, set to -1 to use the
23 ! frequency dependent default
24 ! [do_ray] 1=do Rayleigh calcs, 0=not
25 ! [use_gas_abs] 1=do gaseous abs calcs, 0=not,
26 ! 2=use same as first profile (undocumented)
27 ! [use_mie_table] 1=use Mie tables, 0=not
28 ! [mt] Mie look up table
29 ! [nhclass] number of hydrometeor types
30 ! [hp] structure that defines hydrometeor types
31 ! [nprof] number of hydrometeor profiles
32 ! [ngate] number of vertical layers
33 ! [nsizes] number of discrete particles in [D]
34 ! [D] array of discrete particles (um)
35 !
36 ! (The following 5 arrays must be in order from closest to the radar
37 ! to farthest...)
38 ! [hgt_matrix] height of hydrometeors (km)
39 ! [hm_matrix] table of hydrometeor mixing rations (g/kg)
40 ! [re_matrix] OPTIONAL table of hydrometeor effective radii (microns)
41 ! [p_matrix] pressure profile (hPa)
42 ! [t_matrix] temperature profile (C)
43 ! [rh_matrix] relative humidity profile (%)
44 !
45 ! Outputs:
46 ! [Ze_non] radar reflectivity without attenuation (dBZ)
47 ! [Ze_ray] Rayleigh reflectivity (dBZ)
48 ! [h_atten_to_vol] attenuation by hydromets, radar to vol (dB)
49 ! [g_atten_to_vol] gaseous atteunation, radar to vol (dB)
50 ! [dBZe] effective radar reflectivity factor (dBZ)
51 !
52 ! Optional:
53 ! [g_to_vol_in] integrated atten due to gases, r>v (dB).
54 ! If present then is used as gaseous absorption, independently of the
55 ! value in use_gas_abs
56 ! [g_to_vol_out] integrated atten due to gases, r>v (dB).
57 ! If present then gaseous absorption for each profile is returned here.
58 !
59 ! Created:
60 ! 11/28/2005 John Haynes (haynes@atmos.colostate.edu)
61 ! Modified:
62 ! 09/2006 placed into subroutine form, scaling factors (Roger Marchand,JMH)
63 ! 08/2007 added equivalent volume spheres, Z and N scalling most distrubtion types (Roger Marchand)
64 ! 01/2008 'Do while' to determine if hydrometeor(s) present in volume
65 ! changed for vectorization purposes (A. Bodas-Salcedo)
66 
67 ! ----- INPUTS -----
68  type(mie), intent(in) :: mt
69  type(class_param), intent(inout) :: hp
70  real*8, intent(in) :: freq,k2
71  integer, intent(in) :: do_ray,use_gas_abs,use_mie_table, &
72  nhclass,nprof,ngate,nsizes
73  real*8, dimension(nsizes), intent(in) :: D
74  real*8, dimension(nprof,ngate), intent(in) :: hgt_matrix, p_matrix, &
75  t_matrix,rh_matrix
76  real*8, dimension(nhclass,nprof,ngate), intent(in) :: hm_matrix
77  real*8, dimension(nhclass,nprof,ngate), intent(inout) :: re_matrix
78 
79 ! ----- OUTPUTS -----
80  real*8, dimension(nprof,ngate), intent(out) :: Ze_non,Ze_ray, &
81  g_atten_to_vol,dBZe,h_atten_to_vol
82 
83 ! ----- OPTIONAL -----
84  real*8, optional, dimension(ngate,nprof) :: &
85  g_to_vol_in,g_to_vol_out ! integrated atten due to gases, r>v (dB). This allows to output and then input
86  ! the same gaseous absorption in different calls. Optional to allow compatibility
87  ! with original version. A. Bodas April 2008.
88 
89 ! real*8, dimension(nprof,ngate) :: kr_matrix
90 
91 ! ----- INTERNAL -----
92  integer :: &
93  phase, & ! 0=liquid, 1=ice
94  ns ! number of discrete drop sizes
95 
96  integer*4, dimension(ngate) :: &
97  hydro ! 1=hydrometeor in vol, 0=none
98  real*8 :: &
99  rho_a, & ! air density (kg m^-3)
100  gases ! function: 2-way gas atten (dB/km)
101 
102  real*8, dimension(:), allocatable :: &
103  Di, Deq, & ! discrete drop sizes (um)
104  Ni, Ntemp, & ! discrete concentrations (cm^-3 um^-1)
105  rhoi ! discrete densities (kg m^-3)
106 
107  real*8, dimension(ngate) :: &
108  z_vol, & ! effective reflectivity factor (mm^6/m^3)
109  z_ray, & ! reflectivity factor, Rayleigh only (mm^6/m^3)
110  kr_vol, & ! attenuation coefficient hydro (dB/km)
111  g_vol, & ! attenuation coefficient gases (dB/km)
112  a_to_vol, & ! integrated atten due to hydometeors, r>v (dB)
113  g_to_vol ! integrated atten due to gases, r>v (dB)
114 
115 
116  integer,parameter :: KR8 = selected_real_kind(15,300)
117  real*8, parameter :: xx = -1.0_kr8
118  real*8, dimension(:), allocatable :: xxa
119  real*8 :: kr, ze, zr, pi, scale_factor, tc, Re, ld, tmp1, ze2, kr2,apm,bpm
120  integer*4 :: tp, i, j, k, pr, itt, iff
121 
122  real*8 bin_length,step,base,step_list(25),base_list(25)
123  integer*4 iRe_type,n,max_bin
124 
125  logical :: g_to_vol_in_present, g_to_vol_out_present
126 
127  ! Logicals to avoid calling present within the loops
128  g_to_vol_in_present = present(g_to_vol_in)
129  g_to_vol_out_present = present(g_to_vol_out)
130 
131  ! set up Re bins for z_scalling
132  bin_length=50;
133  max_bin=25
134 
135  step_list(1)=1
136  base_list(1)=75
137  do j=2,max_bin
138  step_list(j)=3*(j-1);
139  if(step_list(j)>bin_length) then
140  step_list(j)=bin_length;
141  endif
142  base_list(j)=base_list(j-1)+floor(bin_length/step_list(j-1));
143  enddo
144 
145 
146  pi = acos(-1.0)
147  if (use_mie_table == 1) iff = infind(mt%freq,freq,sort=1)
148 
149 
150  ! // loop over each profile (nprof)
151  do pr=1,nprof
152 
153 ! ----- calculations for each volume -----
154  z_vol(:) = 0
155  z_ray(:) = 0
156  kr_vol(:) = 0
157  hydro(:) = 0
158 
159 ! // loop over eacho range gate (ngate)
160  do k=1,ngate
161 
162 ! :: determine if hydrometeor(s) present in volume
163  hydro(k) = 0
164  do j=1,nhclass ! Do while changed for vectorization purposes (A. B-S)
165  if ((hm_matrix(j,pr,k) > 1e-12) .and. (hp%dtype(j) > 0)) then
166  hydro(k) = 1
167  exit
168  endif
169  enddo
170 
171  if (hydro(k) == 1) then
172 ! :: if there is hydrometeor in the volume
173 
174  rho_a = (p_matrix(pr,k)*100.)/(287*(t_matrix(pr,k)+273.15))
175 
176 ! :: loop over hydrometeor type
177  do tp=1,nhclass
178 
179  if (hm_matrix(tp,pr,k) <= 1e-12) cycle
180 
181  phase = hp%phase(tp)
182  if(phase==0) then
183  itt = infind(mt_ttl,t_matrix(pr,k))
184  else
185  itt = infind(mt_tti,t_matrix(pr,k))
186  endif
187 
188  ! calculate Re if we have an exponential distribution with fixed No ... precipitation type particle
189  if( hp%dtype(tp)==2 .and. abs(hp%p2(tp)+1) < 1e-8) then
190 
191  apm=hp%apm(tp)
192  bpm=hp%bpm(tp)
193 
194  if ((hp%rho(tp) > 0) .and. (apm < 0)) then
195  apm = (pi/6)*hp%rho(tp)
196  bpm = 3.
197  endif
198 
199  tmp1 = 1./(1.+bpm)
200  ld = ((apm*gamma(1.+bpm)*hp%p1(tp))/(rho_a*hm_matrix(tp,pr,k)*1e-3))**tmp1
201 
202  re = 1.5e6/ld
203 
204  re_matrix(tp,pr,k) = re;
205 
206  endif
207 
208  if(re_matrix(tp,pr,k).eq.0) then
209 
210  ire_type=1
211  re=0
212  else
213  ire_type=1
214  re=re_matrix(tp,pr,k)
215 
216  n=floor(re/bin_length)
217  if(n==0) then
218  if(re<25) then
219  step=0.5
220  base=0
221  else
222  step=1
223  base=25
224  endif
225  else
226  if(n>max_bin) then
227  n=max_bin
228  endif
229 
230  step=step_list(n)
231  base=base_list(n)
232  endif
233 
234  ire_type=floor(re/step)
235 
236  if(ire_type.lt.1) then
237  ire_type=1
238  endif
239 
240  re=step*(ire_type+0.5)
241  ire_type=ire_type+base-floor(n*bin_length/step)
242 
243  ! make sure iRe_type is within bounds
244  if(ire_type.ge.nre_types) then
245 
246  ! print *, tp, re_matrix(tp,pr,k), Re, iRe_type
247 
248  ! no scaling allowed
249  re=re_matrix(tp,pr,k)
250 
251  ire_type=nre_types
252  hp%z_flag(tp,itt,ire_type)=.false.
253  hp%scaled(tp,ire_type)=.false.
254  endif
255  endif
256 
257  ! use Ze_scaled, Zr_scaled, and kr_scaled ... if know them
258  ! if not we will calculate Ze, Zr, and Kr from the distribution parameters
259  if( .not. hp%z_flag(tp,itt,ire_type) ) then
260 
261 ! :: create a distribution of hydrometeors within volume
262  select case(hp%dtype(tp))
263  case(4)
264  ns = 1
265  allocate(di(ns),ni(ns),rhoi(ns),xxa(ns),deq(ns))
266  if (use_mie_table == 1) allocate(mt_qext(ns),mt_qbsca(ns),ntemp(ns))
267  di = hp%p1(tp)
268  ni = 0.
269  case default
270  ns = nsizes
271  allocate(di(ns),ni(ns),rhoi(ns),xxa(ns),deq(ns))
272  if (use_mie_table == 1) allocate(mt_qext(ns),mt_qbsca(ns),ntemp(ns))
273  di = d
274  ni = 0.
275  end select
276 
277 ! :: create a DSD (using scaling factor if applicable)
278  ! hp%scaled(tp,iRe_type)=.false. ! turn off N scaling
279 
280  call dsd(hm_matrix(tp,pr,k),re,di,ni,ns,hp%dtype(tp),rho_a, &
281  t_matrix(pr,k),hp%dmin(tp),hp%dmax(tp),hp%apm(tp),hp%bpm(tp), &
282  hp%rho(tp),hp%p1(tp),hp%p2(tp),hp%p3(tp),hp%fc(tp,1:ns,ire_type), &
283  hp%scaled(tp,ire_type))
284 
285 ! :: calculate particle density
286  ! if ((hp%rho_eff(tp,1,iRe_type) < 0) .and. (phase == 1)) then
287  if (phase == 1) then
288  if (hp%rho(tp) < 0) then
289 
290  ! MG Mie approach - adjust density of sphere with D = D_characteristic to match particle density
291  ! hp%rho_eff(tp,1:ns,iRe_type) = (6/pi)*hp%apm(tp)*(Di*1E-6)**(hp%bpm(tp)-3) !MG Mie approach
292 
293  ! as the particle size gets small it is possible that the mass to size relationship of
294  ! (given by power law in hclass.data) can produce impossible results
295  ! where the mass is larger than a solid sphere of ice.
296  ! This loop ensures that no ice particle can have more mass/density larger than an ice sphere.
297  ! do i=1,ns
298  ! if(hp%rho_eff(tp,i,iRe_type) > 917 ) then
299  ! hp%rho_eff(tp,i,iRe_type) = 917
300  !endif
301  !enddo
302 
303  ! alternative is to use equivalent volume spheres.
304  hp%rho_eff(tp,1:ns,ire_type) = 917 ! solid ice == equivalent volume approach
305  deq = ( ( 6/pi*hp%apm(tp)/917 ) ** (1.0/3.0) ) * &
306  ( (di*1e-6) ** (hp%bpm(tp)/3.0) ) * 1e6 ! Di now really Deq in microns.
307 
308  else
309 
310  ! hp%rho_eff(tp,1:ns,iRe_type) = hp%rho(tp) !MG Mie approach
311 
312  ! Equivalent volume sphere (solid ice rho_ice=917 kg/m^3).
313  hp%rho_eff(tp,1:ns,ire_type) = 917
314  deq=di * ((hp%rho(tp)/917)**(1.0/3.0))
315 
316  endif
317 
318  ! if using equivalent volume spheres
319  if (use_mie_table == 1) then
320 
321  ntemp=ni
322 
323  ! Find N(Di) from N(Deq) which we know
324  do i=1,ns
325  j=infind(deq,di(i))
326  ni(i)=ntemp(j)
327  enddo
328  else
329  ! just use Deq and D variable input to mie code
330  di=deq;
331  endif
332 
333  endif
334  rhoi = hp%rho_eff(tp,1:ns,ire_type)
335 
336 ! :: calculate effective reflectivity factor of volume
337  if (use_mie_table == 1) then
338 
339  if ((hp%dtype(tp) == 4) .and. (hp%idd(tp) < 0)) then
340  hp%idd(tp) = infind(mt%D,di(1))
341  endif
342 
343  if (phase == 0) then
344 
345  ! itt = infind(mt_ttl,t_matrix(pr,k))
346  select case(hp%dtype(tp))
347  case(4)
348  mt_qext(1) = mt%qext(hp%idd(tp),itt,1,iff)
349  mt_qbsca(1) = mt%qbsca(hp%idd(tp),itt,1,iff)
350  case default
351  mt_qext = mt%qext(:,itt,1,iff)
352  mt_qbsca = mt%qbsca(:,itt,1,iff)
353  end select
354 
355  call zeff(freq,di,ni,ns,k2,mt_ttl(itt),0,do_ray, &
356  ze,zr,kr,mt_qext,mt_qbsca,xx)
357 
358  else
359 
360  ! itt = infind(mt_tti,t_matrix(pr,k))
361  select case(hp%dtype(tp))
362  case(4)
363  if (hp%ifc(tp,1,ire_type) < 0) then
364  hp%ifc(tp,1,ire_type) = infind(mt%f,rhoi(1)/917.)
365  endif
366  mt_qext(1) = &
367  mt%qext(hp%idd(tp),itt+cnt_liq,hp%ifc(tp,1,ire_type),iff)
368  mt_qbsca(1) = &
369  mt%qbsca(hp%idd(tp),itt+cnt_liq,hp%ifc(tp,1,ire_type),iff)
370  case default
371  do i=1,ns
372  if (hp%ifc(tp,i,ire_type) < 0) then
373  hp%ifc(tp,i,ire_type) = infind(mt%f,rhoi(i)/917.)
374  endif
375  mt_qext(i) = mt%qext(i,itt+cnt_liq,hp%ifc(tp,i,ire_type),iff)
376  mt_qbsca(i) = mt%qbsca(i,itt+cnt_liq,hp%ifc(tp,i,ire_type),iff)
377  enddo
378  end select
379 
380  call zeff(freq,di,ni,ns,k2,mt_tti(itt),1,do_ray, &
381  ze,zr,kr,mt_qext,mt_qbsca,xx)
382 
383  endif
384 
385  else
386 
387  xxa = -9.9
388  call zeff(freq,di,ni,ns,k2,t_matrix(pr,k),phase,do_ray, &
389  ze,zr,kr,xxa,xxa,rhoi)
390 
391 
392  endif ! end of use mie table
393 
394  ! xxa = -9.9
395  !call zeff(freq,Di,Ni,ns,k2,t_matrix(pr,k),phase,do_ray, &
396  ! ze2,zr,kr2,xxa,xxa,rhoi)
397 
398  ! if(abs(ze2-ze)/ze2 > 0.1) then
399  ! if(abs(kr2-kr)/kr2 > 0.1) then
400 
401  ! write(*,*) pr,k,tp,ze2,ze2-ze,abs(ze2-ze)/ze2,itt+cnt_liq,iff
402  ! write(*,*) pr,k,tp,ze2,kr2,kr2-kr,abs(kr2-kr)/kr2
403  ! stop
404 
405  !endif
406 
407  deallocate(di,ni,rhoi,xxa,deq)
408  if (use_mie_table == 1) deallocate(mt_qext,mt_qbsca,ntemp)
409 
410  else ! can use z scaling
411 
412  if( hp%dtype(tp)==2 .and. abs(hp%p2(tp)+1) < 1e-8 ) then
413 
414  ze = hp%Ze_scaled(tp,itt,ire_type)
415  zr = hp%Zr_scaled(tp,itt,ire_type)
416  kr = hp%kr_scaled(tp,itt,ire_type)
417 
418  else
419  scale_factor=rho_a*hm_matrix(tp,pr,k)
420 
421  zr = hp%Zr_scaled(tp,itt,ire_type) * scale_factor
422  ze = hp%Ze_scaled(tp,itt,ire_type) * scale_factor
423  kr = hp%kr_scaled(tp,itt,ire_type) * scale_factor
424  endif
425 
426  endif ! end z_scaling
427 
428  ! kr=0
429 
430  kr_vol(k) = kr_vol(k) + kr
431  z_vol(k) = z_vol(k) + ze
432  z_ray(k) = z_ray(k) + zr
433 
434  ! construct Ze_scaled, Zr_scaled, and kr_scaled ... if we can
435  if( .not. hp%z_flag(tp,itt,ire_type) .and. 1.eq.1 ) then
436 
437  if( ( (hp%dtype(tp)==1 .or. hp%dtype(tp)==5 .or. hp%dtype(tp)==2) .and. abs(hp%p1(tp)+1) < 1e-8 ) .or. &
438  ( hp%dtype(tp)==3 .or. hp%dtype(tp)==4 ) &
439  ) then
440 
441  scale_factor=rho_a*hm_matrix(tp,pr,k)
442 
443  hp%Ze_scaled(tp,itt,ire_type) = ze/ scale_factor
444  hp%Zr_scaled(tp,itt,ire_type) = zr/ scale_factor
445  hp%kr_scaled(tp,itt,ire_type) = kr/ scale_factor
446 
447  hp%z_flag(tp,itt,ire_type)=.true.
448 
449  elseif( hp%dtype(tp)==2 .and. abs(hp%p2(tp)+1) < 1e-8 ) then
450 
451  hp%Ze_scaled(tp,itt,ire_type) = ze
452  hp%Zr_scaled(tp,itt,ire_type) = zr
453  hp%kr_scaled(tp,itt,ire_type) = kr
454 
455  hp%z_flag(tp,itt,ire_type)=.true.
456  endif
457 
458  endif
459 
460  enddo ! end loop of tp (hydrometeor type)
461 
462  else
463 ! :: volume is hydrometeor-free
464 
465  kr_vol(k) = 0
466  z_vol(k) = -999
467  z_ray(k) = -999
468 
469  endif
470 
471 ! :: attenuation due to hydrometeors between radar and volume
472  a_to_vol(k) = 2*path_integral(kr_vol,hgt_matrix(pr,:),1,k-1)
473 
474 ! :: attenuation due to gaseous absorption between radar and volume
475  if (g_to_vol_in_present) then
476  g_to_vol(k) = g_to_vol_in(k,pr)
477  else
478  if ( (use_gas_abs == 1) .or. ((use_gas_abs == 2) .and. (pr == 1)) ) then
479  g_vol(k) = gases(p_matrix(pr,k),t_matrix(pr,k)+273.15, &
480  rh_matrix(pr,k),freq)
481  g_to_vol(k) = path_integral(g_vol,hgt_matrix(pr,:),1,k-1)
482  elseif (use_gas_abs == 0) then
483  g_to_vol(k) = 0
484  endif
485  endif
486 
487 ! kr_matrix(pr,:)=kr_vol
488 
489 ! :: store results in matrix for return to calling program
490  h_atten_to_vol(pr,k)=a_to_vol(k)
491  g_atten_to_vol(pr,k)=g_to_vol(k)
492  if ((do_ray == 1) .and. (z_ray(k) > 0)) then
493  ze_ray(pr,k) = 10*log10(z_ray(k))
494  else
495  ze_ray(pr,k) = -999
496  endif
497  if (z_vol(k) > 0) then
498  dbze(pr,k) = 10*log10(z_vol(k))-a_to_vol(k)-g_to_vol(k)
499  ze_non(pr,k) = 10*log10(z_vol(k))
500  else
501  dbze(pr,k) = -999
502  ze_non(pr,k) = -999
503  endif
504 
505  enddo ! end loop of k (range gate)
506  ! Output array with gaseous absorption
507  if (g_to_vol_out_present) g_to_vol_out(:,pr) = g_to_vol
508  enddo ! end loop over pr (profile)
509 
510  end subroutine radar_simulator
511 
real *8, dimension(:), allocatable, save mt_tti
subroutine zeff(freq, D, N, nsizes, k2, tt, ice, xr, z_eff, z_ray, kr, qe, qs, rho_e)
Definition: zeff.F90:2
real *8, dimension(:), allocatable, save mt_ttl
real *8 function gamma(x)
Definition: math_lib.F90:18
subroutine dsd(Q, Re, D, N, nsizes, dtype, rho_a, tc, dmin, dmax, apm, bpm, rho_c, p1, p2, p3, fc, scaled)
Definition: dsd.F90:3
real *8, dimension(:), allocatable, save mt_qbsca
real *8, dimension(:), allocatable, save mt_qext
!$Id itapm1 ENDIF!IM on interpole les champs sur les niveaux STD de pression!IM a chaque pas de temps de la physique c!positionnement de l argument logique a false c!pour ne pas recalculer deux fois la meme chose!c!a cet effet un appel a plevel_new a ete deplace c!a la fin de la serie d appels c!la boucle DO nlevSTD a ete internalisee c!dans d ou la creation de cette routine c c!CALL false
Definition: calcul_STDlev.h:26
real *8 function path_integral(f, s, i1, i2)
Definition: math_lib.F90:97
!$Id itapm1 ENDIF!IM on interpole les champs sur les niveaux STD de pression!IM a chaque pas de temps de la physique c!positionnement de l argument logique a false c!pour ne pas recalculer deux fois la meme chose!c!a cet effet un appel a plevel_new a ete deplace c!a la fin de la serie d appels c!la boucle DO nlevSTD a ete internalisee c!dans d ou la creation de cette routine c c!CALL ulevSTD CALL &zphi philevSTD CALL &zx_rh rhlevSTD!DO klev DO klon klev DO klon klev DO klon klev DO klon klev DO klon klev DO klon klev DO klon klev DO klon klev DO klon klev DO klon du jour ou toutes les read_climoz CALL true
subroutine radar_simulator(freq, k2, do_ray, use_gas_abs, use_mie_table, mt, nhclass, hp, nprof, ngate, nsizes, D, hgt_matrix, hm_matrix, re_matrix, p_matrix, t_matrix, rh_matrix, Ze_non, Ze_ray, h_atten_to_vol, g_atten_to_vol, dBZe, g_to_vol_in, g_to_vol_out)
subroutine sort(n, d)
Definition: sort.F:7
integer, parameter nre_types
integer *4 function infind(list, val, sort, dist)
Definition: array_lib.F90:17