!########################################################################
!########################################################################
!######### #########
!######### SUBROUTINE adjust_refl #########
!######### #########
!######### Developed by #########
!######### Center for Analysis and Prediction of Storms #########
!######### University of Oklahoma #########
!######### #########
!########################################################################
!########################################################################
SUBROUTINE adjust_refl(nx,ny,nz,refl,zs,et_nids,vil_nids) 1,2
!------------------------------------------------------------------------
!
! PURPOSE:
!
! Adjusts the remapped 3D reflectivity field using NIDS echo top and VIL
! data. A linear function R = A*H + B is used as a first guess between
! the NIDS echo top product level and the top of the original remapped
! reflectivity field (R being reflectivity, A being a slope, H is height,
! and B is the intercept). However, a quadratic function R = (A*H*H) +
! (B*H) + C is used if "too much" reflectivity is inserted by the linear
! function.
!
!------------------------------------------------------------------------
!
! AUTHOR:
!
! Eric Kemp, 6 September 2001. Developed for WDT.
!
!------------------------------------------------------------------------
!
! Force explicit declarations.
!
!------------------------------------------------------------------------
IMPLICIT NONE
!------------------------------------------------------------------------
!
! Declare arguments
!
!------------------------------------------------------------------------
INTEGER, INTENT(IN) :: nx,ny,nz ! Dimensions of grid
REAL, INTENT(INOUT) :: refl(nx,ny,nz) ! 3D reflectivity (dBZ)
REAL, INTENT(IN) :: zs(nx,ny,nz) ! Height of scalar points (m MSL)
REAL, INTENT(IN) :: et_nids(nx,ny) ! NIDS Echo top (m MSL)
REAL, INTENT(IN) :: vil_nids(nx,ny) ! NIDS VIL (kg m**-2)
!------------------------------------------------------------------------
!
! Functions
!
!------------------------------------------------------------------------
REAL, EXTERNAL :: vil_88d
!------------------------------------------------------------------------
!
! Internal parameters
!
!------------------------------------------------------------------------
REAL, PARAMETER :: K_const = 3.44E-6
REAL, PARAMETER :: foursevenths = 4./7.
REAL, PARAMETER :: sevenfourths = 7./4.
INTEGER, PARAMETER :: iterationmax = 40
!------------------------------------------------------------------------
!
! Internal variables
!
!------------------------------------------------------------------------
REAL :: refl_adj(nx,ny,nz)
REAL :: et_refl(nx,ny)
INTEGER :: k_et_refl(nx,ny)
INTEGER :: k_et_nids(nx,ny)
REAL :: vil_refl(nx,ny)
REAL :: vil_residual(nx,ny)
REAL :: reflthresh
REAL :: Z, r
REAL :: slope, intercept
REAL :: Mtop, Mr, M
REAL :: reflthreshexp
REAL :: maxresidual,minresidual
INTEGER :: i,j,k
INTEGER :: iteration
REAL :: A, B, C
REAL :: N, N1, N2, N3, N4
REAL :: D, D1, D2, D3, D4
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!------------------------------------------------------------------------
!
! Calculate the echo top from the 3D reflectivity field. Also,
! determine k-levels of NIDS echo tops.
!
!------------------------------------------------------------------------
reflthresh = 18.5
CALL calc_et_refl
(nx,ny,nz,refl,reflthresh,zs,et_refl,k_et_refl)
CALL calc_k_et
(nx,ny,nz,zs,et_nids,k_et_nids)
refl_adj(:,:,:) = refl(:,:,:)
DO j = 1,ny-1
DO i = 1,nx-1
IF (et_nids(i,j) == 0.) THEN
! WRITE(6,*)'WARNING: No NIDS echo top.'
! WRITE(6,*)'i: ',i,' j: ',j
CYCLE ! Skip to next column
ELSE IF (vil_nids(i,j) == 0.) THEN
! WRITE(6,*)'WARNING: No NIDS VIL.'
! WRITE(6,*)'i: ',i,' j: ',j
CYCLE ! Skip to next column
ELSE IF (et_nids(i,j) == -9999. .OR. k_et_nids(i,j) == -9999) THEN
! WRITE(6,*)'WARNING: NIDS echo top value missing.'
! WRITE(6,*)'i: ',i,' j: ',j
CYCLE ! Skip to next column
ELSE IF (vil_nids(i,j) == -9999.) THEN
! WRITE(6,*)'WARNING: NIDS VIL value missing.'
! WRITE(6,*)'i: ',i,' j: ',j
CYCLE ! Skip to next column
ELSE IF (et_refl(i,j) == -9999. .OR. k_et_refl(i,j) == -9999) THEN
! WRITE(6,*)'WARNING: Estimated echo top value missing.'
! WRITE(6,*)'i: ',i,' j: ',j
CYCLE ! Skip to next column
ELSE IF (vil_refl(i,j) == -9999.) THEN
! WRITE(6,*)'WARNING: Estimated VIL value missing.'
! WRITE(6,*)'i: ',i,' j: ',j
CYCLE ! Skip to next column
ELSE IF (k_et_nids(i,j) == k_et_refl(i,j)) THEN
! WRITE(6,*)'NOTE: Echo top k levels are equal. Skipping...'
! WRITE(6,*)'i: ',i,' j: ',j
CYCLE ! Skip to next column
ELSE IF (k_et_nids(i,j) < k_et_refl(i,j)) THEN
! WRITE(6,*)'WARNING: NIDS echo top below estimated value.'
! WRITE(6,*)'i: ',i,' j: ',j
! WRITE(6,*)'et_nids: ',et_nids(i,j),' et_refl: ',et_refl(i,j)
CYCLE ! Skip to next column
END IF
reflthresh = 18.5
DO iteration = 1,iterationmax
vil_refl(i,j) = vil_88d(nz,refl_adj(i,j,:),zs(i,j,:))
IF ( (vil_refl(i,j) < (vil_nids(i,j) - 5.) ) .OR. &
(iteration == 1) ) THEN
!------------------------------------------------------------------------
!
! To use the linear function, we must first calculate the slope
! and intercept values. With some algebra and calculus, it can
! be shown that:
!
! slope = (Mtop - Mr)/(et_nids - et_refl), and
!
! intercept = Mr - (slope*et_refl)
!
! where Mtop is M at et_nids and Mr is M at et_refl. So, we need
! to calculate Mtop and Mr, and then slope and intercept.
!
!------------------------------------------------------------------------
Z = 10.**(refl(i,j,k_et_refl(i,j))*0.1)
Mr = K_const*(Z**foursevenths)
reflthreshexp = reflthresh*0.1
Z = 10.**(reflthreshexp)
Mtop = K_const*(Z**foursevenths)
slope = (Mtop - Mr)/(et_nids(i,j) - et_refl(i,j))
intercept = Mr - (slope*et_refl(i,j))
!------------------------------------------------------------------------
!
! Now apply the linear function to the refl_adj field between
! k_et_refl and k_ef_nids.
!
!------------------------------------------------------------------------
DO k = k_et_refl(i,j),k_et_nids(i,j)
M = (slope*zs(i,j,k)) + intercept
Z = (M/K_const)**sevenfourths
refl_adj(i,j,k) = 10.*ALOG10(Z)
END DO ! k loop
vil_refl(i,j) = vil_88d(nz,refl_adj(i,j,:),zs(i,j,:))
reflthresh = reflthresh + 1.5
IF (reflthresh > 55.) EXIT
ELSE IF (vil_refl(i,j) > (vil_nids(i,j) + 5.) ) THEN
reflthresh = 18.5
!------------------------------------------------------------------------
!
! To use the quadratic function, we must first calculate the A,
! B, and C coefficients. By performing much algebra and
! calculus, it can be shown that:
!
! A = N/D
!
! N = N1 + N2 + N3 + N4
!
! N1 = 6.*r*(et_nids - et_refl)
!
! N2 = -3.*(Mtop - Mr)*(et_nids*et_nids - et_refl*et_refl)
!
! N3 = 6.*et_refl*(Mtop - Mr)*(et_nids - et_refl)
!
! N4 = -6.*Mr*(et_nids - et_refl)**3.
!
! D = D1 + D2 + D3 + D4
!
! D1 = 2.*(et_nids**3 - et_refl**3.)*(et_nids-et_refl)
!
! D2 = -6.*(et_refl*et_refl)*(et_nids - et_refl)**2.
!
! D3 = -3.*(et_nids**2. - et_refl**2.)
!
! D4 = 6.*et_refl*(et_nids**2. - et_refl**2.)*
! (et_nids - et_refl)
!
! B = (Mtop - Mr - A*(et_nids**2. - et_refl**2.))/(et_nids-et_refl)
!
! C = Mr - (A*et_refl*et_refl) - (B*et_refl)
!
! where Mtop is M at et_nids, Mr is M at et_refl, and r is the
! residual VIL (NIDS VIL - reflectivity field VIL). So, we need
! to calculate Mtop, Mr, and r, and then A, B, and C
!
!------------------------------------------------------------------------
IF (iteration > 2) THEN
refl_adj(i,j,k_et_refl(i,j)) = &
refl_adj(i,j,k_et_refl(i,j)) - 1.5
END IF
Z = 10.**(refl_adj(i,j,k_et_refl(i,j))*0.1)
Mr = K_const*(Z**foursevenths)
reflthreshexp = reflthresh*0.1
Z = 10.**(reflthreshexp)
Mtop = K_const*(Z**foursevenths)
r = vil_nids(i,j) - vil_refl(i,j)
N1 = 6.*r*(et_nids(i,j) - et_refl(i,j))
N2 = -3.*(Mtop - Mr)*(et_nids(i,j)*et_nids(i,j) - &
et_refl(i,j)*et_refl(i,j))
N3 = 6.*et_refl(i,j)*(Mtop - Mr)*(et_nids(i,j) - et_refl(i,j))
N4 = -6.*Mr*(et_nids(i,j) - et_refl(i,j))**3.
N = N1 + N2 + N3 + N4
D1 = 2.*(et_nids(i,j)**3. - &
et_refl(i,j)**3.)*(et_nids(i,j)-et_refl(i,j))
D2 = -6.*(et_refl(i,j)*et_refl(i,j))* &
(et_nids(i,j)-et_refl(i,j))**2.
D3 = -3.*(et_nids(i,j)*et_nids(i,j) - &
et_refl(i,j)*et_refl(i,j))
D4 = 6.*et_refl(i,j)*(et_nids(i,j)*et_nids(i,j) - &
et_refl(i,j)*et_refl(i,j))*(et_nids(i,j) - et_refl(i,j))
D = D1 + D2 + D3 + D4
A = N/D
B = (Mtop - Mr - A*(et_nids(i,j)*et_nids(i,j) - &
et_refl(i,j)*et_refl(i,j)))/(et_nids(i,j) - et_refl(i,j))
C = Mr - (A*et_refl(i,j)*et_refl(i,j)) - (B*et_refl(i,j))
!------------------------------------------------------------------------
!
! Now apply the quadratic function to the refl_adj field between
! k_et_refl and k_ef_nids.
!
!------------------------------------------------------------------------
DO k = k_et_refl(i,j),k_et_nids(i,j)
M = (A*zs(i,j,k)*zs(i,j,k)) + (B*zs(i,j,k)) + C
Z = (M/K_const)**sevenfourths
refl_adj(i,j,k) = 10.*ALOG10(Z)
END DO ! k loop
END IF ! linear or quadratic
vil_refl(i,j) = vil_88d(nz,refl_adj(i,j,:),zs(i,j,:))
END DO ! iteration loop
!------------------------------------------------------------------------
!
! Move on to next column.
!
!------------------------------------------------------------------------
END DO ! i loop
END DO ! j loop
!------------------------------------------------------------------------
!
! Calculate new VIL and residual VIL from adjusted reflectivity field.
!
!------------------------------------------------------------------------
vil_residual(:,:) = -9999.
maxresidual = 0.
minresidual = 0.
DO j = 1,ny-1
DO i = 1,nx-1
IF (vil_nids(i,j) /= -9999. .AND. et_nids(i,j) /= -9999. .AND. &
vil_refl(i,j) /= -9999. .AND. et_refl(i,j) /= -9999. .AND. &
k_et_nids(i,j) /= -9999 .AND. k_et_refl(i,j) /= -9999 .AND. &
k_et_nids(i,j) > k_et_refl(i,j)) THEN
vil_residual(i,j) = vil_nids(i,j) - vil_refl(i,j)
IF (vil_residual(i,j) < minresidual) THEN
minresidual = vil_residual(i,j)
END IF
IF (vil_residual(i,j) > maxresidual) THEN
maxresidual = vil_residual(i,j)
END IF
END IF
END DO
END DO
WRITE(6,*)'Max Residual VIL: ',maxresidual
WRITE(6,*)'Min Residual VIL: ',minresidual
!------------------------------------------------------------------------
!
! Overwrite original reflectivity and exit.
!
!------------------------------------------------------------------------
refl(:,:,:) = refl_adj(:,:,:)
RETURN
END SUBROUTINE adjust_refl
!########################################################################
!########################################################################
!######### #########
!######### SUBROUTINE calc_et_refl #########
!######### #########
!######### Developed by #########
!######### Center for Analysis and Prediction of Storms #########
!######### University of Oklahoma #########
!######### #########
!########################################################################
!########################################################################
SUBROUTINE calc_et_refl(nx,ny,nz,refl,reflthresh,zs,et,k_et) 1
!------------------------------------------------------------------------
!
! PURPOSE:
!
! Determines echo tops for 3D reflectivity field using a dBZe threshold
! specified as an argument. Also returns the k-levels.
!
!------------------------------------------------------------------------
!
! AUTHOR:
!
! Eric Kemp, 31 August 2001. Developed for WDT.
!
!------------------------------------------------------------------------
!
! Force explicit declarations.
!
!------------------------------------------------------------------------
IMPLICIT NONE
!------------------------------------------------------------------------
!
! Declare arguments.
!
!------------------------------------------------------------------------
INTEGER, INTENT(IN) :: nx,ny,nz ! Dimensions of grid
REAL, INTENT(IN) :: refl(nx,ny,nz) ! 3D reflectivity (dBZ)
REAL, INTENT(IN) :: reflthresh ! Reflectivity threshold for
! echo top (dBZ)
REAL, INTENT(IN) :: zs(nx,ny,nz) ! Scalar heights (m MSL)
REAL, INTENT(INOUT) :: et(nx,ny) ! Echo top heights (m MSL)
INTEGER, INTENT(INOUT) :: k_et(nx,ny) ! k-level of echo top height.
!------------------------------------------------------------------------
!
! Declare internal variables
!
!------------------------------------------------------------------------
INTEGER :: i,j,k
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
et(:,:) = -9999.
k_et(:,:) = -9999
DO j = 1,ny-1
DO i = 1,nx-1
DO k = nz-1,2,-1
IF (refl(i,j,k) > reflthresh) THEN
et(i,j) = zs(i,j,k)
k_et(i,j) = k
EXIT ! Get out of k loop
END IF
END DO ! k loop
END DO ! i loop
END DO ! j loop
RETURN
END SUBROUTINE calc_et_refl
!########################################################################
!########################################################################
!######### #########
!######### SUBROUTINE calc_k_et #########
!######### #########
!######### Developed by #########
!######### Center for Analysis and Prediction of Storms #########
!######### University of Oklahoma #########
!######### #########
!########################################################################
!########################################################################
SUBROUTINE calc_k_et(nx,ny,nz,zs,et,k_et) 1
!------------------------------------------------------------------------
!
! PURPOSE:
!
! Determines the k-level of the (NIDS) echo tops. Developed for WDT.
!
!------------------------------------------------------------------------
!
! AUTHOR:
!
! Eric Kemp, 31 August 2001
!
!------------------------------------------------------------------------
!
! Force explicit declarations.
!
!------------------------------------------------------------------------
IMPLICIT NONE
!------------------------------------------------------------------------
!
! Declare arguments.
!
!------------------------------------------------------------------------
INTEGER, INTENT(IN) :: nx,ny,nz ! Dimensions of grid
REAL, INTENT(IN) :: zs(nx,ny,nz) ! Scalar heights (m MSL)
REAL, INTENT(IN) :: et(nx,ny) ! Echo top heights (m MSL)
INTEGER, INTENT(INOUT) :: k_et(nx,ny) ! k-level of echo tops
!------------------------------------------------------------------------
!
! Declare internal variables
!
!------------------------------------------------------------------------
INTEGER :: i,j,k
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
k_et(:,:) = -9999
DO j = 1,ny-1
DO i = 1,nx-1
DO k = nz-1,2,-1
IF (et(i,j) > zs(i,j,k)) THEN
k_et(i,j) = k
EXIT ! Get out of k loop
END IF
END DO ! k loop
END DO ! i loop
END DO ! j loop
RETURN
END SUBROUTINE calc_k_et
!########################################################################
!########################################################################
!######### #########
!######### FUNCTION vil_88d #########
!######### #########
!######### Developed by #########
!######### Center for Analysis and Prediction of Storms #########
!######### University of Oklahoma #########
!######### #########
!########################################################################
!########################################################################
REAL FUNCTION vil_88d(nz,refl,zs)
!------------------------------------------------------------------------
!
! PURPOSE:
!
! Calculates vertically integrated liquid from 3D reflectivity data
! following the WSR-88D algorithm.
!
!------------------------------------------------------------------------
!
! REFERENCES:
!
! Edwards, R., and R. L. Thompson, 1998: Nationwide comparisons of hail
! size with WSR-88D vertically integrated liquid water and derived
! thermodynamic sounding data. _Wea. Forecasting_, 12, 277-285.
! Greene, D. R., and R. A. Clark, 1972: Vertically integrated liquid
! water -- A new analysis tool. _Mon. Wea. Rev._, 100, 548-552.
! OSF, Undated Document: Vertically-integrated liquid water algorithm
! description. NX-DR-03-006/25, 7pp. Available on the Internet at
! http://120.125.144.136/~swimm/wsr88d/algorithms.htm
! Witt, A., and Coauthors, 1998: An enhanced hail detection algorithm
! for the WSR-88D. _Wea. Forecasting_, 13, 286-303.
!
!------------------------------------------------------------------------
!
! AUTHOR:
!
! Eric Kemp, 7 September 2001. Developed for WDT.
!
!------------------------------------------------------------------------
!
! Force explicit declarations
!
!------------------------------------------------------------------------
IMPLICIT NONE
!------------------------------------------------------------------------
!
! Declare arguments.
!
!------------------------------------------------------------------------
INTEGER, INTENT(IN) :: nz ! Dimension of column
REAL, INTENT(IN) :: refl(nz) ! Reflectivity in column (dBZ)
REAL, INTENT(IN) :: zs(nz) ! Scalar heights (m MSL)
!------------------------------------------------------------------------
!
! Declare internal parameters.
!
!------------------------------------------------------------------------
REAL, PARAMETER :: minrefl = 18.5 ! Minimum point reflectivity used
! in VIL algorithm.
REAL, PARAMETER :: maxrefl = 55. ! Maximum point reflectivity used
! in VIL algorithm.
REAL, PARAMETER :: maxreflexp = 55.*0.1 ! Exponent used for cases
! with reflectivity > maxrefl
REAL, PARAMETER :: K_const = 3.44E-6 ! Conversion factor for Z to M.
REAL, PARAMETER :: maxvil = 80. ! Maximum VIL permitted (kg m**-2)
REAL, PARAMETER :: foursevenths = 4./7.
!------------------------------------------------------------------------
!
! Declare internal variables.
!
!------------------------------------------------------------------------
REAL :: Z, M, dh, VIL
INTEGER :: k
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
VIL = 0.
DO k = 2,nz-1
!------------------------------------------------------------------------
!
! Calculate reflectivity factor Z in mm**6 m**-3. Logarithmic
! reflectivities less than 18.5 dBZ are set to zero, while
! those values above 55 dBZ are truncated.
!
!------------------------------------------------------------------------
IF (refl(k) < minrefl) THEN
Z = 0.
ELSE IF (refl(k) > maxrefl) THEN
Z = 10.**(maxreflexp)
ELSE
Z = 10.**(refl(k)*0.1)
END IF
!------------------------------------------------------------------------
!
! Now calculate liquid water content (M) in kg m**-3.
!
!------------------------------------------------------------------------
M = K_const*(Z**foursevenths)
!------------------------------------------------------------------------
!
! Calculate local dh.
!
!------------------------------------------------------------------------
dh = zs(k+1) - zs(k)
!------------------------------------------------------------------------
!
! Add to VIL.
!
!------------------------------------------------------------------------
VIL = VIL + (M*dh)
END DO
!------------------------------------------------------------------------
!
! Return value and exit.
!
!------------------------------------------------------------------------
vil_88d = MIN(VIL,maxvil)
RETURN
END FUNCTION vil_88d