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) ! rh_matrix,Ze_non,Ze_ray,kr_matrix,g_atten_to_vol,dBZe) use m_mrgrnk use array_lib use math_lib use optics_lib use radar_simulator_types implicit none ! Purpose: ! Simulates a vertical profile of radar reflectivity ! Part of QuickBeam v1.04 by John Haynes & Roger Marchand ! ! Inputs: ! [freq] radar frequency (GHz), can be anything unless ! use_mie_table=1, in which case one of 94,35,13.8,9.6,3 ! [k2] |K|^2, the dielectric constant, set to -1 to use the ! frequency dependent default ! [do_ray] 1=do Rayleigh calcs, 0=not ! [use_gas_abs] 1=do gaseous abs calcs, 0=not, ! 2=use same as first profile (undocumented) ! [use_mie_table] 1=use Mie tables, 0=not ! [mt] Mie look up table ! [nhclass] number of hydrometeor types ! [hp] structure that defines hydrometeor types ! [nprof] number of hydrometeor profiles ! [ngate] number of vertical layers ! [nsizes] number of discrete particles in [D] ! [D] array of discrete particles (um) ! ! (The following 5 arrays must be in order from closest to the radar ! to farthest...) ! [hgt_matrix] height of hydrometeors (km) ! [hm_matrix] table of hydrometeor mixing rations (g/kg) ! [re_matrix] OPTIONAL table of hydrometeor effective radii (microns) ! [p_matrix] pressure profile (hPa) ! [t_matrix] temperature profile (C) ! [rh_matrix] relative humidity profile (%) ! ! Outputs: ! [Ze_non] radar reflectivity without attenuation (dBZ) ! [Ze_ray] Rayleigh reflectivity (dBZ) ! [h_atten_to_vol] attenuation by hydromets, radar to vol (dB) ! [g_atten_to_vol] gaseous atteunation, radar to vol (dB) ! [dBZe] effective radar reflectivity factor (dBZ) ! ! Optional: ! [g_to_vol_in] integrated atten due to gases, r>v (dB). ! If present then is used as gaseous absorption, independently of the ! value in use_gas_abs ! [g_to_vol_out] integrated atten due to gases, r>v (dB). ! If present then gaseous absorption for each profile is returned here. ! ! Created: ! 11/28/2005 John Haynes (haynes@atmos.colostate.edu) ! Modified: ! 09/2006 placed into subroutine form, scaling factors (Roger Marchand,JMH) ! 08/2007 added equivalent volume spheres, Z and N scalling most distrubtion types (Roger Marchand) ! 01/2008 'Do while' to determine if hydrometeor(s) present in volume ! changed for vectorization purposes (A. Bodas-Salcedo) ! ----- INPUTS ----- type(mie), intent(in) :: mt type(class_param), intent(inout) :: hp real*8, intent(in) :: freq,k2 integer, intent(in) :: do_ray,use_gas_abs,use_mie_table, & nhclass,nprof,ngate,nsizes real*8, dimension(nsizes), intent(in) :: D real*8, dimension(nprof,ngate), intent(in) :: hgt_matrix, p_matrix, & t_matrix,rh_matrix real*8, dimension(nhclass,nprof,ngate), intent(in) :: hm_matrix real*8, dimension(nhclass,nprof,ngate), intent(inout) :: re_matrix ! ----- OUTPUTS ----- real*8, dimension(nprof,ngate), intent(out) :: Ze_non,Ze_ray, & g_atten_to_vol,dBZe,h_atten_to_vol ! ----- OPTIONAL ----- real*8, optional, dimension(ngate,nprof) :: & g_to_vol_in,g_to_vol_out ! integrated atten due to gases, r>v (dB). This allows to output and then input ! the same gaseous absorption in different calls. Optional to allow compatibility ! with original version. A. Bodas April 2008. ! real*8, dimension(nprof,ngate) :: kr_matrix ! ----- INTERNAL ----- integer :: & phase, & ! 0=liquid, 1=ice ns ! number of discrete drop sizes integer*4, dimension(ngate) :: & hydro ! 1=hydrometeor in vol, 0=none real*8 :: & rho_a, & ! air density (kg m^-3) gases ! function: 2-way gas atten (dB/km) real*8, dimension(:), allocatable :: & Di, Deq, & ! discrete drop sizes (um) Ni, Ntemp, & ! discrete concentrations (cm^-3 um^-1) rhoi ! discrete densities (kg m^-3) real*8, dimension(ngate) :: & z_vol, & ! effective reflectivity factor (mm^6/m^3) z_ray, & ! reflectivity factor, Rayleigh only (mm^6/m^3) kr_vol, & ! attenuation coefficient hydro (dB/km) g_vol, & ! attenuation coefficient gases (dB/km) a_to_vol, & ! integrated atten due to hydometeors, r>v (dB) g_to_vol ! integrated atten due to gases, r>v (dB) integer,parameter :: KR8 = selected_real_kind(15,300) real*8, parameter :: xx = -1.0_KR8 real*8, dimension(:), allocatable :: xxa real*8 :: kr, ze, zr, pi, scale_factor, tc, Re, ld, tmp1, ze2, kr2,apm,bpm integer*4 :: tp, i, j, k, pr, itt, iff real*8 bin_length,step,base,step_list(25),base_list(25) integer*4 iRe_type,n,max_bin logical :: g_to_vol_in_present, g_to_vol_out_present ! Logicals to avoid calling present within the loops g_to_vol_in_present = present(g_to_vol_in) g_to_vol_out_present = present(g_to_vol_out) ! set up Re bins for z_scalling bin_length=50; max_bin=25 step_list(1)=1 base_list(1)=75 do j=2,max_bin step_list(j)=3*(j-1); if(step_list(j)>bin_length) then step_list(j)=bin_length; endif base_list(j)=base_list(j-1)+floor(bin_length/step_list(j-1)); enddo pi = acos(-1.0) if (use_mie_table == 1) iff = infind(mt%freq,freq,sort=1) ! // loop over each profile (nprof) do pr=1,nprof ! ----- calculations for each volume ----- z_vol(:) = 0 z_ray(:) = 0 kr_vol(:) = 0 hydro(:) = 0 ! // loop over eacho range gate (ngate) do k=1,ngate ! :: determine if hydrometeor(s) present in volume hydro(k) = 0 do j=1,nhclass ! Do while changed for vectorization purposes (A. B-S) if ((hm_matrix(j,pr,k) > 1E-12) .and. (hp%dtype(j) > 0)) then hydro(k) = 1 exit endif enddo if (hydro(k) == 1) then ! :: if there is hydrometeor in the volume rho_a = (p_matrix(pr,k)*100.)/(287*(t_matrix(pr,k)+273.15)) ! :: loop over hydrometeor type do tp=1,nhclass if (hm_matrix(tp,pr,k) <= 1E-12) cycle phase = hp%phase(tp) if(phase==0) then itt = infind(mt_ttl,t_matrix(pr,k)) else itt = infind(mt_tti,t_matrix(pr,k)) endif ! calculate Re if we have an exponential distribution with fixed No ... precipitation type particle if( hp%dtype(tp)==2 .and. abs(hp%p2(tp)+1) < 1E-8) then apm=hp%apm(tp) bpm=hp%bpm(tp) if ((hp%rho(tp) > 0) .and. (apm < 0)) then apm = (pi/6)*hp%rho(tp) bpm = 3. endif tmp1 = 1./(1.+bpm) ld = ((apm*gamma(1.+bpm)*hp%p1(tp))/(rho_a*hm_matrix(tp,pr,k)*1E-3))**tmp1 Re = 1.5E6/ld re_matrix(tp,pr,k) = Re; endif if(re_matrix(tp,pr,k).eq.0) then iRe_type=1 Re=0 else iRe_type=1 Re=re_matrix(tp,pr,k) n=floor(Re/bin_length) if(n==0) then if(Re<25) then step=0.5 base=0 else step=1 base=25 endif else if(n>max_bin) then n=max_bin endif step=step_list(n) base=base_list(n) endif iRe_type=floor(Re/step) if(iRe_type.lt.1) then iRe_type=1 endif Re=step*(iRe_type+0.5) iRe_type=iRe_type+base-floor(n*bin_length/step) ! make sure iRe_type is within bounds if(iRe_type.ge.nRe_types) then ! print *, tp, re_matrix(tp,pr,k), Re, iRe_type ! no scaling allowed Re=re_matrix(tp,pr,k) iRe_type=nRe_types hp%z_flag(tp,itt,iRe_type)=.false. hp%scaled(tp,iRe_type)=.false. endif endif ! use Ze_scaled, Zr_scaled, and kr_scaled ... if know them ! if not we will calculate Ze, Zr, and Kr from the distribution parameters if( .not. hp%z_flag(tp,itt,iRe_type) ) then ! :: create a distribution of hydrometeors within volume select case(hp%dtype(tp)) case(4) ns = 1 allocate(Di(ns),Ni(ns),rhoi(ns),xxa(ns),Deq(ns)) if (use_mie_table == 1) allocate(mt_qext(ns),mt_qbsca(ns),Ntemp(ns)) Di = hp%p1(tp) Ni = 0. case default ns = nsizes allocate(Di(ns),Ni(ns),rhoi(ns),xxa(ns),Deq(ns)) if (use_mie_table == 1) allocate(mt_qext(ns),mt_qbsca(ns),Ntemp(ns)) Di = D Ni = 0. end select ! :: create a DSD (using scaling factor if applicable) ! hp%scaled(tp,iRe_type)=.false. ! turn off N scaling call dsd(hm_matrix(tp,pr,k),Re,Di,Ni,ns,hp%dtype(tp),rho_a, & t_matrix(pr,k),hp%dmin(tp),hp%dmax(tp),hp%apm(tp),hp%bpm(tp), & hp%rho(tp),hp%p1(tp),hp%p2(tp),hp%p3(tp),hp%fc(tp,1:ns,iRe_type), & hp%scaled(tp,iRe_type)) ! :: calculate particle density ! if ((hp%rho_eff(tp,1,iRe_type) < 0) .and. (phase == 1)) then if (phase == 1) then if (hp%rho(tp) < 0) then ! MG Mie approach - adjust density of sphere with D = D_characteristic to match particle density ! hp%rho_eff(tp,1:ns,iRe_type) = (6/pi)*hp%apm(tp)*(Di*1E-6)**(hp%bpm(tp)-3) !MG Mie approach ! as the particle size gets small it is possible that the mass to size relationship of ! (given by power law in hclass.data) can produce impossible results ! where the mass is larger than a solid sphere of ice. ! This loop ensures that no ice particle can have more mass/density larger than an ice sphere. ! do i=1,ns ! if(hp%rho_eff(tp,i,iRe_type) > 917 ) then ! hp%rho_eff(tp,i,iRe_type) = 917 !endif !enddo ! alternative is to use equivalent volume spheres. hp%rho_eff(tp,1:ns,iRe_type) = 917 ! solid ice == equivalent volume approach Deq = ( ( 6/pi*hp%apm(tp)/917 ) ** (1.0/3.0) ) * & ( (Di*1E-6) ** (hp%bpm(tp)/3.0) ) * 1E6 ! Di now really Deq in microns. else ! hp%rho_eff(tp,1:ns,iRe_type) = hp%rho(tp) !MG Mie approach ! Equivalent volume sphere (solid ice rho_ice=917 kg/m^3). hp%rho_eff(tp,1:ns,iRe_type) = 917 Deq=Di * ((hp%rho(tp)/917)**(1.0/3.0)) endif ! if using equivalent volume spheres if (use_mie_table == 1) then Ntemp=Ni ! Find N(Di) from N(Deq) which we know do i=1,ns j=infind(Deq,Di(i)) Ni(i)=Ntemp(j) enddo else ! just use Deq and D variable input to mie code Di=Deq; endif endif rhoi = hp%rho_eff(tp,1:ns,iRe_type) ! :: calculate effective reflectivity factor of volume if (use_mie_table == 1) then if ((hp%dtype(tp) == 4) .and. (hp%idd(tp) < 0)) then hp%idd(tp) = infind(mt%D,Di(1)) endif if (phase == 0) then ! itt = infind(mt_ttl,t_matrix(pr,k)) select case(hp%dtype(tp)) case(4) mt_qext(1) = mt%qext(hp%idd(tp),itt,1,iff) mt_qbsca(1) = mt%qbsca(hp%idd(tp),itt,1,iff) case default mt_qext = mt%qext(:,itt,1,iff) mt_qbsca = mt%qbsca(:,itt,1,iff) end select call zeff(freq,Di,Ni,ns,k2,mt_ttl(itt),0,do_ray, & ze,zr,kr,mt_qext,mt_qbsca,xx) else ! itt = infind(mt_tti,t_matrix(pr,k)) select case(hp%dtype(tp)) case(4) if (hp%ifc(tp,1,iRe_type) < 0) then hp%ifc(tp,1,iRe_type) = infind(mt%f,rhoi(1)/917.) endif mt_qext(1) = & mt%qext(hp%idd(tp),itt+cnt_liq,hp%ifc(tp,1,iRe_type),iff) mt_qbsca(1) = & mt%qbsca(hp%idd(tp),itt+cnt_liq,hp%ifc(tp,1,iRe_type),iff) case default do i=1,ns if (hp%ifc(tp,i,iRe_type) < 0) then hp%ifc(tp,i,iRe_type) = infind(mt%f,rhoi(i)/917.) endif mt_qext(i) = mt%qext(i,itt+cnt_liq,hp%ifc(tp,i,iRe_type),iff) mt_qbsca(i) = mt%qbsca(i,itt+cnt_liq,hp%ifc(tp,i,iRe_type),iff) enddo end select call zeff(freq,Di,Ni,ns,k2,mt_tti(itt),1,do_ray, & ze,zr,kr,mt_qext,mt_qbsca,xx) endif else xxa = -9.9 call zeff(freq,Di,Ni,ns,k2,t_matrix(pr,k),phase,do_ray, & ze,zr,kr,xxa,xxa,rhoi) endif ! end of use mie table ! xxa = -9.9 !call zeff(freq,Di,Ni,ns,k2,t_matrix(pr,k),phase,do_ray, & ! ze2,zr,kr2,xxa,xxa,rhoi) ! if(abs(ze2-ze)/ze2 > 0.1) then ! if(abs(kr2-kr)/kr2 > 0.1) then ! write(*,*) pr,k,tp,ze2,ze2-ze,abs(ze2-ze)/ze2,itt+cnt_liq,iff ! write(*,*) pr,k,tp,ze2,kr2,kr2-kr,abs(kr2-kr)/kr2 ! stop !endif deallocate(Di,Ni,rhoi,xxa,Deq) if (use_mie_table == 1) deallocate(mt_qext,mt_qbsca,Ntemp) else ! can use z scaling if( hp%dtype(tp)==2 .and. abs(hp%p2(tp)+1) < 1E-8 ) then ze = hp%Ze_scaled(tp,itt,iRe_type) zr = hp%Zr_scaled(tp,itt,iRe_type) kr = hp%kr_scaled(tp,itt,iRe_type) else scale_factor=rho_a*hm_matrix(tp,pr,k) zr = hp%Zr_scaled(tp,itt,iRe_type) * scale_factor ze = hp%Ze_scaled(tp,itt,iRe_type) * scale_factor kr = hp%kr_scaled(tp,itt,iRe_type) * scale_factor endif endif ! end z_scaling ! kr=0 kr_vol(k) = kr_vol(k) + kr z_vol(k) = z_vol(k) + ze z_ray(k) = z_ray(k) + zr ! construct Ze_scaled, Zr_scaled, and kr_scaled ... if we can if( .not. hp%z_flag(tp,itt,iRe_type) .and. 1.eq.1 ) then if( ( (hp%dtype(tp)==1 .or. hp%dtype(tp)==5 .or. hp%dtype(tp)==2) .and. abs(hp%p1(tp)+1) < 1E-8 ) .or. & ( hp%dtype(tp)==3 .or. hp%dtype(tp)==4 ) & ) then scale_factor=rho_a*hm_matrix(tp,pr,k) hp%Ze_scaled(tp,itt,iRe_type) = ze/ scale_factor hp%Zr_scaled(tp,itt,iRe_type) = zr/ scale_factor hp%kr_scaled(tp,itt,iRe_type) = kr/ scale_factor hp%z_flag(tp,itt,iRe_type)=.True. elseif( hp%dtype(tp)==2 .and. abs(hp%p2(tp)+1) < 1E-8 ) then hp%Ze_scaled(tp,itt,iRe_type) = ze hp%Zr_scaled(tp,itt,iRe_type) = zr hp%kr_scaled(tp,itt,iRe_type) = kr hp%z_flag(tp,itt,iRe_type)=.True. endif endif enddo ! end loop of tp (hydrometeor type) else ! :: volume is hydrometeor-free kr_vol(k) = 0 z_vol(k) = -999 z_ray(k) = -999 endif ! :: attenuation due to hydrometeors between radar and volume a_to_vol(k) = 2*path_integral(kr_vol,hgt_matrix(pr,:),1,k-1) ! :: attenuation due to gaseous absorption between radar and volume if (g_to_vol_in_present) then g_to_vol(k) = g_to_vol_in(k,pr) else if ( (use_gas_abs == 1) .or. ((use_gas_abs == 2) .and. (pr == 1)) ) then g_vol(k) = gases(p_matrix(pr,k),t_matrix(pr,k)+273.15, & rh_matrix(pr,k),freq) g_to_vol(k) = path_integral(g_vol,hgt_matrix(pr,:),1,k-1) elseif (use_gas_abs == 0) then g_to_vol(k) = 0 endif endif ! kr_matrix(pr,:)=kr_vol ! :: store results in matrix for return to calling program h_atten_to_vol(pr,k)=a_to_vol(k) g_atten_to_vol(pr,k)=g_to_vol(k) if ((do_ray == 1) .and. (z_ray(k) > 0)) then Ze_ray(pr,k) = 10*log10(z_ray(k)) else Ze_ray(pr,k) = -999 endif if (z_vol(k) > 0) then dBZe(pr,k) = 10*log10(z_vol(k))-a_to_vol(k)-g_to_vol(k) Ze_non(pr,k) = 10*log10(z_vol(k)) else dBZe(pr,k) = -999 Ze_non(pr,k) = -999 endif enddo ! end loop of k (range gate) ! Output array with gaseous absorption if (g_to_vol_out_present) g_to_vol_out(:,pr) = g_to_vol enddo ! end loop over pr (profile) end subroutine radar_simulator