!########################################################################
!########################################################################
!######### #########
!######### SUBROUTINE get_radial_data #########
!######### #########
!######### Developed by #########
!######### Center for Analysis and Prediction of Storms #########
!######### University of Oklahoma #########
!######### #########
!########################################################################
!########################################################################
SUBROUTINE get_radial_data(ival,msglen, & 1,4
isite, isite_lat,isite_lon,isite_elev, &
iyr,imonth,iday,ihr,iminit,isec, &
iprod,maxval1,ivcp,ifield,maxbins,maxradials, &
iazmuth,ielev,nbins,nradials,icatt,icats, &
maxval2,iyr1,imonth1,iday1,ihr1,iminit1, &
iyr2,imonth2,iday2,ihr2,iminit2,istm_spd,istm_dir, &
iheader,len_header,itrailer,len_trailer,icode)
!------------------------------------------------------------------------
!
! PURPOSE:
!
! Decodes a WSR-88D radial graphic product and return pertinent data.
!
! Note 1: To convert ifield() to physical units, use the transform:
!
! VALUE = ICATS(IFIELD())
!
! Note 2: Non-system subroutines used are:
! w3fs26
! i2byte
! i4byte
!
!------------------------------------------------------------------------
!
! AUTHOR:
!
! NWS Techniques Development Laboratory (April 1998).
!
! MODIFICATION HISTORY:
!
! Yunheng Wang (July 2001)
! Converted from FORTRAN 77 code.
!
! Eric Kemp, 30 July 2001
! Added USE statement to module n2aconst, minor changes.
!
! Eric Kemp, 9 August 2001
! Use variable type INTEGER*4 and similar types instead of using
! KIND statements. Also use dimension parameters from N2ACONST module.
!
! Eric Kemp, 17 August 2001
! Modified code to avoid use of INTEGER*4, INTEGER*1, etc, based on
! work by Yunheng Wang. Also, changed variable maxval to maxval1 to
! avoid conflict with Fortran 90 implicit function. Finally, added
! code to allocate array irad at runtime, with dimension added to
! module N2ACONST.
!
!------------------------------------------------------------------------
!
! USE modules
!
!------------------------------------------------------------------------
USE n2aconst
!------------------------------------------------------------------------
!
! Force explicit declarations.
!
!------------------------------------------------------------------------
IMPLICIT NONE
!------------------------------------------------------------------------
!
! Declare external functions.
!
!------------------------------------------------------------------------
INTEGER, EXTERNAL :: i2byte, i4byte
!------------------------------------------------------------------------
!
! Arguments
!
!------------------------------------------------------------------------
! INPUT:
! ival = Array containing the graphic product
!
!------------------------------------------------------------------------
! OUTPUT:
! msglen = length of input product, bytes
! isite = wsr-88d site id
! isite_lat,isite_lon = site lat/lon (deg e), deg x 1000
! isite_elev = site elevation, m msl
! iyr,imonth,iday = product volume scan date: year, month, day
! ihr,iminit,isec = product time, utc: hour, minute, second
! iprod = product code number (output) (eg 19 for z)
! maxval1 = maximum value in the field,
! for velocity products, the greatest inbound
! (negative) velocity.
! maxval2 = for velocity products, the greatest outbound
! (positive) velocity
! istm_spd,istm_dir = for storm-relative velocity products, the velocity
! subtracted from base velocity (deg and kt)
! iyr1,imonth1,iday1 = for variable-period precipitation accumulation
! products, starting date of accumulation pd, UTC
! ihr1,iminit1 = for variable-period precipitation accumulation
! products, starting time of accumulation pd, UTC
! iyr2,imonth2,iday2 = for variable-period precipitation accumulation
! products, ending date of accumulation pd, UTC
! ihr2,iminit2 = for variable-period precipitation accumulation
! products, ending time of accumulation pd, UTC
! ivcp = operating volume coverage pattern
! ifield(,) = returned values (data levels) for the field
! a byte variable, 0-15. dimensioned by maxbins,
! maxradials in calling routine.
!
! for reflectivity and rainfall:
! ifield(,)=0 means 'below minimum threshold',
! and the actual value is meaningless. other
! values of icats() may be 0 or negative.
!
! for velocity and spectrum width:
! category 0 means insufficient backscatter and
! that velocity and width cannot be determined.
! category 15 indicates range folding (velocity may
! be from either primary or second-trip echo) and
! again, velocity and width cannot be determined.
!
! iazmuth() = antenna azimuth directions (deg x 10) for
! each radial. dimensioned by maxradials
! in calling routine.
! ielev = antenna elevation angle, deg x 10
! nbins,nradials = number of range bins and radials in the graphic
! icatt() = category-interval values taken directly from
! product header. dimensioned by 16 or 0:15
! in calling program.
! icats() = category-interval values in physical units.
! dimensioned by 16 or 0:15 in calling program
! iheader() = byte array with copy of header. should be
! dimensioned 160 in calling routine
! len_header = actual number of bytes of information in iheader()
!
! itrailer() = character*1 array with text information attached
! at end of file (if any). should be dimensioned by
! 20 000 in calling routine
! len_trailer = actual number of bytes of data in itrailer().
! will be set 0 if no trailer exists
!
! icode = output return code, conditions as follows:
! 0 : data returned ok
! 2 : not a radial graphic product
! 3 : maxradials or maxbins is too small
! 4 : product length greater than msglen
!
!------------------------------------------------------------------------
INTEGER, INTENT(IN) :: msglen, maxbins, maxradials
INTEGER, INTENT(IN) :: ival(msglen)
INTEGER, INTENT(OUT) :: icode,ivcp,isite,isite_lat,isite_lon, &
isite_elev,iyr,imonth,iday,ihr,iminit,isec, &
iprod,nbins,nradials,maxval2,ihr1,iminit1, &
ihr2,iminit2,istm_spd,istm_dir,len_header, &
len_trailer
INTEGER, INTENT(OUT) :: iazmuth(maxradials)
INTEGER, INTENT(OUT) :: icatt(0:15)
INTEGER, INTENT(OUT) :: icats(0:15)
INTEGER, INTENT(OUT) :: iyr1,imonth1,iday1,iyr2,imonth2,iday2
INTEGER, INTENT(OUT) :: maxval1, ielev
INTEGER, INTENT(OUT) :: iheader(iheaderdim), &
ifield(maxbins,maxradials)
CHARACTER(LEN=1), INTENT(OUT) :: itrailer(itrailerdim)
!------------------------------------------------------------------------
!
! Misc. local variables
!
!------------------------------------------------------------------------
! LOCAL VARIABLES:
!
! irad(470) = byte vector hold one radial of data
! ival0,ival1 = integer*4 words used to hold lower and higher-order
! halves of 2-byte integer
! nex_date,jul_date = nexrad reference date, astronomical julian date,
! used to determine legal date (year-month-day)
! npos1,npos2 = positions of 1st and last bytes (relative to start
! of the file) in the current radial being decoded
! nruns = number of runs needed to store the present radial
!
!------------------------------------------------------------------------
INTEGER, ALLOCATABLE :: irad(:)
INTEGER :: ival0, ival1
INTEGER :: ipcode
INTEGER :: nex_date, jul_date, idaywk,idayyr, nex_time
INTEGER :: npos1, npos2, nruns
INTEGER :: n, k, len1, ibin, ibin1, ibin2, nbin0
INTEGER :: ilvl, nbyte, ival4, nrun_marker, nr, nc
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
ALLOCATE(irad(iraddim))
!------------------------------------------------------------------------
!
! Get product type, and check for radial-type packet code
! in bytes 137-138
!
!------------------------------------------------------------------------
iprod = i2byte(ival(1) ,ival(2))
ipcode = i2byte(ival(137),ival(138))
IF (ipcode /= ipradial) THEN
icode = 2
RETURN
END IF
isite = 256*ival(13) + ival(14)
ivcp = 256*ival(35) + ival(36)
!------------------------------------------------------------------------
!
! Check internal file-length specification. Note that if file
! length is shorter than message length we won't proceed.
!
!------------------------------------------------------------------------
len1 = i4byte(ival(9),ival(10),ival(11),ival(12))
IF (len1 > msglen) THEN
icode = 4
RETURN
END IF
!------------------------------------------------------------------------
!
! Get header and trailer lengths, initialize arrays.
!
!------------------------------------------------------------------------
len_header = 150
DO n=1,150
iheader(n) = ival(n)
END DO
len1 = 136 + i4byte(ival(133),ival(134),ival(135),ival(136))
len_trailer = msglen - len1
IF (len_trailer > 0) THEN
k = 0
DO n=len1+1, msglen
k = k + 1
itrailer(k) = ACHAR(ival(n))
END DO
END IF
IF (len_trailer < 0) len_trailer = 0
!------------------------------------------------------------------------
!
! Get volume scan date and time
!
!------------------------------------------------------------------------
nex_time = i4byte(ival(43),ival(44),ival(45),ival(46))
nex_date = i2byte(ival(41),ival(42))
jul_date = jul_1_1_70 + nex_date
CALL w3fs26
(jul_date,iyr,imonth,iday,idaywk,idayyr)
ihr = nex_time / 3600
iminit = (nex_time - (3600*ihr)) / 60
isec = nex_time - (3600*ihr) - (60*iminit)
!------------------------------------------------------------------------
!
! Get site lat/lon, elevation
!
!------------------------------------------------------------------------
isite_elev = i2byte(ival(29),ival(30))
isite_lat = i4byte(ival(21),ival(22),ival(23),ival(24))
isite_lon = i4byte(ival(25),ival(26),ival(27),ival(28))
!------------------------------------------------------------------------
!
! Find number of radials in the product, elevation angle
!
!------------------------------------------------------------------------
nbins = i2byte(ival(141),ival(142))
nradials = i2byte(ival(149),ival(150))
IF ((maxbins < nbins) .OR. (maxradials < nradials)) THEN
icode = 3
RETURN
END IF
ielev = i2byte(ival(59),ival(60))
!------------------------------------------------------------------------
!
! Assign category threshold values. Scale up values
! if indicated by comparison of icatt(0) to iscale5.
!
!------------------------------------------------------------------------
nc = 0
DO n=61,91,2
icatt(nc) = i2byte(ival(n),ival(n+1))
ival0 = ival(n+1)
IF (ival0 < 0) ival0 = ival0 + 256
ival1 = ival(n)
IF (MOD(ival1,2) == 0) THEN
icats(nc) = ival0
ELSE
icats(nc) = -1*ival0
END IF
nc = nc + 1
END DO
IF (icatt(0) >= iscale5) THEN
DO nc=1,15
icats(nc) = 5*icats(nc)
END DO
END IF
!------------------------------------------------------------------------
!
! Adjust '0' position category back to 0 ('background color')
!
!------------------------------------------------------------------------
icats(0) = 0
!------------------------------------------------------------------------
!
! Get maximum value(s). For velocity, maxval1 and maxval2
! are inbound and outbound, respectively.
!
!------------------------------------------------------------------------
ival0 = ival(94)
IF (ival0 < 0) ival0 = 256 + ival0
ival1 = ival(93)
IF (ival1 < 0) ival1 = 256 + ival1
maxval1 = i2byte(ival(93),ival(94))
maxval2 = i2byte(ival(95),ival(96))
!------------------------------------------------------------------------
!
! Get storm velocity for storm-relative products
!
!------------------------------------------------------------------------
istm_spd = i2byte(ival(101),ival(102))
istm_dir = i2byte(ival(103),ival(104))
!------------------------------------------------------------------------
!
! For user-selected or storm-total precip, derive
! starting and ending date-times for accumulation
!
!------------------------------------------------------------------------
IF ((iprod == 80) .OR. (iprod == 78) .OR. (iprod == 79) &
.OR. (iprod == 81)) THEN
nex_date = i2byte(ival(95),ival(96))
jul_date = jul_1_1_70 + nex_date
CALL w3fs26
(jul_date,iyr1,imonth1,iday1,idaywk,idayyr)
nex_time = i2byte(ival(97),ival(98))
ihr1 = nex_time / 60
iminit1 = nex_time - (60*ihr1)
nex_date = i2byte(ival(99),ival(100))
jul_date = jul_1_1_70 + nex_date
CALL w3fs26
(jul_date,iyr2,imonth2,iday2,idaywk,idayyr)
nex_time = i2byte(ival(101),ival(102))
ihr2 = nex_time / 60
iminit2 = nex_time - (60*ihr2)
END IF
!------------------------------------------------------------------------
!
! Initialize the output array with -127 values.
!
!------------------------------------------------------------------------
ifield(:,:) = -127
!------------------------------------------------------------------------
!
! Radial by radial, plug run-length encoded values into the
! output array. For each radial, file has number of 2-byte
! words describing the radial, not bytes as for raster products.
!
!------------------------------------------------------------------------
nr = 0
nrun_marker = 151
DO WHILE (nr < nradials)
nr = nr + 1
IF (nr > nradials) EXIT
ival0 = ival(nrun_marker+1)
ival1 = ival(nrun_marker)
IF (ival0 < 0) ival0 = 256 + ival0
IF (ival1 < 0) ival1 = 256 + ival0
nruns = 2*i2byte(ival(nrun_marker),ival(nrun_marker+1))
iazmuth(nr) = i2byte(ival(nrun_marker+2),ival(nrun_marker+3))
npos1 = nrun_marker + 6
npos2 = npos1 + nruns - 1
ibin1 = 1
!------------------------------------------------------------------------
!
! Extract run length from 4 high-order bits and run value
! from 4 low-order bits of this byte, then plug into radial
! array.
!
!------------------------------------------------------------------------
DO nbyte=npos1,npos2
ival4 = ival(nbyte)
IF (ival4 < 0) ival4 = 256 + ival4
nbin0 = ival4/16
IF (nbin0 <= 0) EXIT
ilvl = ival4 - (16*nbin0)
ibin2 = ibin1 + nbin0 - 1
IF (ibin2 > nbins) ibin2 = nbins
DO ibin=ibin1,ibin2
irad(ibin) = ilvl
END DO
ibin1 = ibin2 + 1
IF (ibin2 >= nbins) EXIT
END DO
!------------------------------------------------------------------------
!
! Present radial has been decoded. Now map it into the
! full array.
!
!------------------------------------------------------------------------
DO ibin=1,nbins
ifield(ibin,nr) = irad(ibin)
END DO
!------------------------------------------------------------------------
!
! Finished mapping this radial - go on to the next
!
!------------------------------------------------------------------------
nrun_marker = npos2 + 1
END DO
icode = 0
RETURN
END SUBROUTINE get_radial_data
!########################################################################
!########################################################################
!######### #########
!######### SUBROUTINE get_raster_data #########
!######### #########
!######### Developed by #########
!######### Center for Analysis and Prediction of Storms #########
!######### University of Oklahoma #########
!######### #########
!########################################################################
!########################################################################
SUBROUTINE get_raster_data(ival,msglen,isite, & 1,2
isite_lat,isite_lon,isite_elev, &
iyr,imonth,iday,ihr,iminit,isec, &
iprod,maxval1,ivcp,ifield,ncols,nrows,icatt, &
icats,ndims_p,iheader,len_header,itrailer, &
len_trailer,icode)
!------------------------------------------------------------------------
!
! PURPOSE:
!
! Decodes WSR-88D raster product and return all pertinent data.
!
! Note 1: To convert ifield() values to physical units, use the icats()
! array as follows:
! VALUE = ICATS(IFIELD())
!
! Note 2: This uses non-system subroutines:
! W3FS26
! I2BYTE
! I4BYTE
!
!------------------------------------------------------------------------
!
! AUTHOR:
!
! Eric Kemp, 30 July 2001.
! Based on HPUX FORTRAN 77 subroutine written by Kitzmiller of the
! NWS Techniques Development Laboratory (August 1997).
!
! MODIFICATION HISTORY:
!
! Eric Kemp, 9 August 2001
! Use variable type INTEGER*4 and similar types instead of using
! KIND statements. Also use dimension parameters from N2ACONST module.
!
! Eric Kemp, 17 August 2001
! Modified code to avoid use of INTEGER*4, INTEGER*1, etc., based on
! work by Yunheng Wang. Also, changed variable maxval to maxval1 to
! avoid conflict with Fortran 90 implicit function.
!
!------------------------------------------------------------------------
!
! Use statement.
!
!------------------------------------------------------------------------
USE n2aconst
!------------------------------------------------------------------------
!
! Force explicit declarations.
!
!------------------------------------------------------------------------
IMPLICIT NONE
!------------------------------------------------------------------------
!
! External functions
!
!------------------------------------------------------------------------
INTEGER, EXTERNAL :: i2byte, i4byte
!------------------------------------------------------------------------
!
! Declare arguments (original documentation):
!
! IVAL( ) = BYTE OR CHARACTER*1 ARRAY CONTAINING GRAPHIC
! MESSAGE, DIMENSIONED MSGLEN (INPUT)
! MSGLEN = LENGTH OF GRAPHIC MESSAGE IN BYTES (INPUT)
! NCOLS,NROWS = DIMENSIONS OF IFIELD() (INPUT)
! ICODE = RETURN CODE, CONDITIONS AS FOLLOWS:
! 0 : RETURN OK
! 2 : NOT A RECOGNIZED RASTER PRODUCT
! 3 : NCOLS/NROWS TOO SMALL FOR PRODUCT
! 4 : MSGLEN TOO SMALL TO STORE PRODUCT!
! ISITE = WSR-88D NUMERIC SITE ID (OUTPUT)
! ISITE_LAT,ISITE_LON = SITE LAT/LON (DEG E), DEG X 1000 (OUTPUT)
! ISITE_ELEV = SITE ELEVATION, M MSL (OUTPUT)
! IYR,IMONTH,IDAY = PRODUCT DATE (OUTPUT)
! IHR,IMINIT,ISEC = PRODUCT TIME, UTC (OUTPUT)
! IPROD = PRODUCT CODE NUMBER (OUTPUT) (EG 57 FOR VIL)
! MAXVAL1 = MAXIMUM VALUE IN THE RASTER FIELD (OUTPUT)
! IVCP = OPERATING VOLUME COVERAGE PATTERN (OUTPUT)
! IFIELD(NCOLS,NROWS) = RETURNED VALUES (DATA LEVELS) FOR THE
! FIELD (OUTPUT); A BYTE VARIABLE
! ICATT() = CATEGORY-INTERVAL VALUES DIRECT FROM
! PRODUCT HEADER (OUTPUT, INTEGER*2). SHOULD BE
! DIMENSIONED BY 16 OR 0:15 IN CALLING ROUTINE.
! ICATS() = CATEGORY-INTERVAL VALUES IN PHYSICAL UNITS
! (OUTPUT). SHOULD BE DIMENSIONED BY 16 OR 0:15
! IN CALLING ROUTINE.
! NDIMS_P = ACTUAL NUMBER OF ROWS AND COLUMNS IN OUTPUT
! PRODUCT (OUTPUT) (ROWS=COLUMNS IN 88D FILES)
! IHEADER() = BYTE ARRAY WITH COPY OF HEADER. SHOULD BE
! DIMENSIONED 160 IN CALLING ROUTINE (OUTPUT)
! LEN_HEADER = ACTUAL NUMBER OF BYTES OF INFORMATION IN IHEADER()
! ITRAILER() = CHARACTER*1 ARRAY WITH TEXT INFORMATION ATTACHED
! AT END OF FILE (IF ANY). SHOULD BE DIMENSIONED BY
! 20 000 IN CALLING ROUTINE (OUTPUT)
! LEN_TRAILER = ACTUAL NUMBER OF BYTES OF DATA IN ITRAILER().
! WILL BE SET 0 IF NO TRAILER EXISTS (OUTPUT)
!
!------------------------------------------------------------------------
INTEGER, INTENT(IN) :: msglen, nrows, ncols
INTEGER, INTENT(IN) :: ival(msglen)
INTEGER, INTENT(OUT) :: icode, ivcp, isite, isite_lat, &
isite_lon, isite_elev, &
iyr, imonth, iday, ihr, iminit, &
isec, iprod, maxval1, len_header, &
len_trailer, ndims_p
INTEGER, INTENT(OUT) :: icatt(0:15)
INTEGER, INTENT(OUT) :: icats(0:15)
INTEGER, INTENT(OUT) :: iheader(iheaderdim),ifield(ncols, nrows)
CHARACTER(LEN=1), INTENT(OUT) :: itrailer(itrailerdim)
!------------------------------------------------------------------------
!
! Declare internal variables
!
!------------------------------------------------------------------------
INTEGER :: ipcode
INTEGER :: msglen_int, len1, ival0, ival1
INTEGER :: n,k,nc
INTEGER :: nex_time, nex_date, jul_date, idaywk, idayyr
INTEGER :: nrow, nrun_marker
INTEGER :: nb
INTEGER :: npos1,npos2
INTEGER :: icol,icol1,icol2
INTEGER :: ival4,ncol0,ilvl
INTEGER :: nbyte
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!------------------------------------------------------------------------
!
! Check internal and system-indicated file length for consistency.
!
!------------------------------------------------------------------------
msglen_int = i4byte(ival(9),ival(10),ival(11),ival(12))
IF (msglen < msglen_int) THEN
icode = 4
RETURN
END IF
!------------------------------------------------------------------------
!
! Get product ID# and check for raster-type packet code. Header length
! is constant 158 bytes for raster products.
!
!------------------------------------------------------------------------
iprod = i2byte(ival(1),ival(2))
ipcode = i2byte(ival(137),ival(138))
IF ((ipcode /= ipraster1) .AND. (ipcode /= ipraster2)) THEN
icode = 2
RETURN
END IF
len_header = 158
isite = i2byte(ival(13),ival(14))
ivcp = i2byte(ival(35),ival(36))
!------------------------------------------------------------------------
!
! Set header and trailer arrays. Text trailer is included in 4-km
! composite reflectivity product (storm cell info).
!
!------------------------------------------------------------------------
DO n = 1,158
iheader(n) = ival(n)
END DO
len1 = 136 + i4byte(ival(133),ival(134),ival(135),ival(136))
len_trailer = msglen - len1
IF (len_trailer > 0) THEN
k = 0
DO n = len1+1,msglen
k = k + 1
itrailer(k) = ACHAR(ival(n))
END DO
END IF
IF (len_trailer < 0) len_trailer = 0
!------------------------------------------------------------------------
!
! Get volume scan date and time.
!
!------------------------------------------------------------------------
nex_time = i4byte(ival(43),ival(44),ival(45),ival(46))
nex_date = i2byte(ival(41),ival(42))
jul_date = jul_1_1_70 + nex_date
CALL w3fs26
(jul_date,iyr,imonth,iday,idaywk,idayyr)
ihr = nex_time / 3600
iminit = (nex_time - (3600*ihr))/60
isec = nex_time - (3600*ihr) - (60*iminit)
!------------------------------------------------------------------------
!
! Get site lat/lon, elevation
!
!------------------------------------------------------------------------
isite_elev = i2byte(ival(29),ival(30))
isite_lat = i4byte(ival(21),ival(22),ival(23),ival(24))
isite_lon = i4byte(ival(25),ival(26),ival(27),ival(28))
!------------------------------------------------------------------------
!
! Confirm number of rows in the product.
!
!------------------------------------------------------------------------
ndims_p = i2byte(ival(155),ival(156))
IF ((ncols < ndims_p) .OR. (nrows < ndims_p)) THEN
icode = 3
RETURN
END IF
!------------------------------------------------------------------------
!
! Assign category threshold values. Scale up the physical values if
! indicated.
!
!------------------------------------------------------------------------
nc = 0
DO n = 61, 91, 2
icatt(nc) = i2byte(ival(n),ival(n+1))
ival0 = ival(n+1)
IF (ival0 < 0) ival0 = ival0 + 256
ival1 = ival(n)
IF (MOD(ival1,2) == 0) THEN
icats(nc) = ival0
ELSE
icats(nc) = -1*ival0
END IF
nc = nc + 1
END DO
icats(0) = 0
IF (icatt(0) >= iscale5) THEN
DO nc = 1, 15
icats(nc) = 5*icats(nc)
END DO
END IF
maxval1 = i2byte(ival(93),ival(94))
!------------------------------------------------------------------------
!
! Row by row, plug run-length encoded values into the output array.
! Determine how many bytes store the current row of data, then parse
! out each byte as a run, plug the run of values into the grid.
!
!------------------------------------------------------------------------
nrow = 0
nrun_marker= 159
DO WHILE (nrow < ndims_p)
nrow = nrow + 1
nb = i2byte(ival(nrun_marker),ival(nrun_marker+1))
npos1 = nrun_marker + 2
npos2 = npos1 + nb - 1
icol1 = 1
DO nbyte=npos1,npos2
ival4 = ival(nbyte)
IF (ival4 < 0) ival4 = 256 + ival4
ncol0 = ival4/16
ilvl = ival4 - (16*ncol0)
icol2 = icol1 + ncol0 - 1
DO icol=icol1,icol2
ifield(icol,nrow) = ilvl
END DO
icol1 = icol2 + 1
END DO
nrun_marker = npos2 + 1
END DO
icode = 0
RETURN
END SUBROUTINE get_raster_data
!########################################################################
!########################################################################
!######### #########
!######### SUBROUTINE get_dpa_data #########
!######### #########
!######### Developed by #########
!######### Center for Analysis and Prediction of Storms #########
!######### University of Oklahoma #########
!######### #########
!########################################################################
!########################################################################
SUBROUTINE get_dpa_data(ival,msglen,isite, & 1,2
isite_lat,isite_lon,isite_elev, &
iyr,imonth,iday,ihr,iminit,isec, &
iprod,maxval1,ivcp,ifield,ncols,nrows, &
ncolsp,nrowsp,iheader,len_header,itrailer, &
len_trailer,icode)
!------------------------------------------------------------------------
!
! PURPOSE:
!
! Decodes a WSR-88D digital precip array (DPA) message and returns all
! pertinent data. The digital values ifield() are converted to
! rainfall (mm) through the formulae:
!
! dBa = -6.125 + ifield()*0.125
! rainfall (mm) = 10.**(dBa/10.)
!
! ifield() of 0 indicates zero rainfall.
! ifield() of 255 indicates missing data.
!
! Note: This subroutine uses nonsystem subroutines:
! W3FS26
! I2BYTE
! I4BYTE
!
!------------------------------------------------------------------------
!
! AUTHOR: Eric Kemp, 2 August 2001.
! Based on HPUX FORTRAN 77 code developed by Kitzmiller of the
! Techniques Development Laboratory (August 1997).
!
! MODIFICATION HISTORY:
!
! Eric Kemp, 9 August 2001
! Now uses dimension parameters from N2ACONST module.
!
! Eric Kemp, 17 August 2001
! Modified to avoid use of INTEGER*4, INTEGER*1, etc., based on work
! by Yunheng Wang. Also, changed variable maxval to maxval1 to avoid
! conflict with Fortran 90 implicit function.
!
!------------------------------------------------------------------------
!
! Use modules
!
!------------------------------------------------------------------------
USE n2aconst
!------------------------------------------------------------------------
!
! Force explicit declarations.
!
!------------------------------------------------------------------------
IMPLICIT NONE
!------------------------------------------------------------------------
!
! Arguments (original documentation)
!
! IVAL() = BYTE OR CHARACTER*1 ARRAY CONTAINING DPA
! MESSAGE. MUST BE DIMENSIONED .GE. MSGLEN
! (INPUT).
! MSGLEN = LENGTH OF INPUT MESSAGE IN BYTES (INPUT)
! ISITE = WSR-88D NUMERIC SITE ID (OUTPUT)
! ISITE_LAT,ISITE_LON = SITE LAT/LON (DEG E), DEG X 1000 (OUTPUT)
! ISITE_ELEV = SITE ELEVATION, M MSL (OUTPUT)
! IYR,IMONTH,IDAY = PRODUCT VOLUME DATE: YEAR,MONTH,DAY (OUTPUT)
! IHR,IMINIT,ISEC = PRODUCT TIME, UTC: HOUR,MINUTE,SECOND (OUTPUT)
!
! IPROD = PRODUCT CODE NUMBER (OUTPUT)
! MAXVAL1 = MAXIMUM VALUE IN THE RASTER FIELD (OUTPUT)
! IVCP = OPERATING VOLUME COVERAGE PATTERN (OUTPUT)
! IFIELD(,) = RETURNED VALUES (DATA LEVELS) FOR THE
! FIELD (OUTPUT); INTEGER*2 VARIABLE. SHOULD BE
! DIMENSIONED BY NCOLS,NROWS IN CALLING ROUTINE.
! NCOLS,NROWS = DIMENSIONS OF IFIELD(), AT LEAST 131 (INPUT)
! NCOLSP,NROWSP = ACTUAL NUMBER OF ROWS AND COLUMNS IN OUTPUT
! PRODUCT (OUTPUT) (ROWS=COLUMNS IN 88D FILES)
! IHEADER() = BYTE ARRAY WITH COPY OF HEADER. SHOULD BE
! DIMENSIONED 160 IN CALLING ROUTINE (OUTPUT)
! LEN_HEADER = ACTUAL NUMBER OF BYTES OF INFORMATION IN
! IHEADER() (OUTPUT)
! ITRAILER() = CHARACTER*1 ARRAY WITH TEXT INFORMATION ATTACHED
! AT END OF FILE (IF ANY). SHOULD BE DIMENSIONED
! BY 20 000 IN CALLING ROUTINE (OUTPUT)
! LEN_TRAILER = ACTUAL NUMBER OF BYTES OF DATA IN ITRAILER().
! WILL BE SET 0 IF NO TRAILER EXISTS (OUTPUT)
! ICODE = OUTPUT RETURN CODE, CONDITIONS AS FOLLOWS:
! 0 : DECODED PROPERLY
! 2 : NOT A RECOGNIZED DPA PRODUCT
! 3 : NCOLS/NROWS TOO SMALL FOR PRODUCT
! 4 : PRODUCT TOO LARGE FOR MSGLEN
!
!------------------------------------------------------------------------
INTEGER, INTENT(IN) :: msglen, ncols, nrows
INTEGER, INTENT(IN) :: ival(msglen)
INTEGER, INTENT(OUT) :: iheader(iheaderdim)
INTEGER, INTENT(OUT) :: ifield(ncols,nrows), icode
INTEGER, INTENT(OUT) :: isite, isite_lat, isite_lon, isite_elev, &
iyr, imonth, iday, ihr, iminit, isec, &
iprod, maxval1, ivcp, ncolsp, nrowsp, &
len_header, len_trailer
CHARACTER(LEN=1), INTENT(OUT) :: itrailer(itrailerdim)
!------------------------------------------------------------------------
!
! Declare external functions.
!
!------------------------------------------------------------------------
INTEGER, EXTERNAL :: i2byte, i4byte
!------------------------------------------------------------------------
!
! Internal variables
!
!------------------------------------------------------------------------
INTEGER :: ipcode
INTEGER :: msglen_int, nrow, nb, len1,nex_time, nex_date, jul_date
INTEGER :: idaywk, idayyr
INTEGER :: nrun_marker, npos1, npos2, icol, icol1, icol2, nbyte
INTEGER :: ncol0, ilvl, n, k
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!------------------------------------------------------------------------
!
! Check internal and system-indicated file length for consistency.
!
!------------------------------------------------------------------------
msglen_int = i4byte(ival(9),ival(10),ival(11),ival(12))
IF (msglen < msglen_int) THEN
icode = 4
RETURN
END IF
!------------------------------------------------------------------------
!
! Get product type, and check for raster-type packet code. Header
! length is constant 146 bytes for DPA product.
!
!------------------------------------------------------------------------
ipcode = i2byte(ival(137),ival(138))
iprod = i2byte(ival(1),ival(2))
IF (iprod /= 81) THEN
icode = 2
RETURN
END IF
len_header = 146
isite = i2byte(ival(13),ival(14))
ivcp = i2byte(ival(35),ival(36))
!------------------------------------------------------------------------
!
! Set header and trailer arrays. Text trailer is included in 4-km
! composite reflectivity product (storm cell info).
!
!------------------------------------------------------------------------
DO n = 1,146
iheader(n) = ival(n)
END DO
len1 = 136 + i4byte(ival(133),ival(134),ival(135),ival(136))
len_trailer = msglen - len1
IF (len_trailer > 0) THEN
k = 0
DO n = len1+1,msglen
k = k + 1
itrailer(k) = ACHAR(ival(n))
END DO
END IF
IF (len_trailer < 0) len_trailer = 0
!------------------------------------------------------------------------
!
! Get volume scan date and time
!
!------------------------------------------------------------------------
nex_time = i4byte(ival(43),ival(44),ival(45),ival(46))
nex_date = i2byte(ival(41),ival(42))
jul_date = jul_1_1_70 + nex_date
CALL w3fs26
(jul_date,iyr,imonth,iday,idaywk,idayyr)
ihr = nex_time / 3600
iminit = (nex_time - (3600*ihr))/60
isec = nex_time - (3600*ihr) - (60*iminit)
!------------------------------------------------------------------------
!
! Get site lat/lon, elevation.
!
!------------------------------------------------------------------------
isite_elev = i2byte(ival(29),ival(30))
isite_lat = i4byte(ival(21),ival(22),ival(23),ival(24))
isite_lon = i4byte(ival(25),ival(26),ival(27),ival(28))
!------------------------------------------------------------------------
!
! Get maximum value.
!
!------------------------------------------------------------------------
maxval1 = i2byte(ival(93),ival(94))
!------------------------------------------------------------------------
!
! Confirm number of rows and columns in the product.
!
!------------------------------------------------------------------------
ncolsp = i2byte(ival(143),ival(144))
IF (ncols < ncolsp) THEN
icode = 3
RETURN
END IF
nrowsp = i2byte(ival(145),ival(146))
IF (nrows < nrowsp) THEN
icode = 3
RETURN
END IF
!------------------------------------------------------------------------
!
! Row by row, plug run-length encoded values into the output array.
! Determine how many bytes store the current row of data, then parse
! out each byte as a run and plug the run of values into the grid.
!
! For DPA product, run length and value are stored in 2-byte words
! rather than one byte as in other gridded products.
!
!------------------------------------------------------------------------
ifield(:,:) = 255
nrow = 0
nrun_marker = 147
DO WHILE (nrow < nrowsp)
nrow = nrow + 1
nb = i2byte(ival(nrun_marker),ival(nrun_marker+1))
npos1 = nrun_marker + 2
npos2 = npos1 + nb - 1
icol1 = 1
DO nbyte = npos1,npos2,2
ncol0 = ival(nbyte)
ilvl = ival(nbyte+1)
icol2 = icol1 + ncol0 - 1
DO icol=icol1,icol2
ifield(icol,nrow) = ilvl
END DO
icol1 = icol2 + 1
END DO ! DO nbyte = npos1,npos2,2
nrun_marker = npos2 + 1
END DO ! DO WHILE
!------------------------------------------------------------------------
!
! The end.
!
!------------------------------------------------------------------------
icode = 0
RETURN
END SUBROUTINE get_dpa_data
!########################################################################
!########################################################################
!######### #########
!######### SUBROUTINE get_dhr_data #########
!######### #########
!######### Developed by #########
!######### Center for Analysis and Prediction of Storms #########
!######### University of Oklahoma #########
!######### #########
!########################################################################
!########################################################################
SUBROUTINE get_dhr_data(ival,msglen,isite, &,2
isite_lat,isite_lon,isite_elev, &
iyr,imonth,iday, &
ihr,iminit,iprod,maxval1,ivcp,ifield,maxradials, &
maxbins,iazmuth,nbins,nradials,icode)
!------------------------------------------------------------------------
!
! PURPOSE:
!
! Decodes WSR-88D digital hybrid scan (DHR) product.
!
! Note 1: Raw digital values 0-255 are converted to dBZ by relationship:
!
! dBZ = ((ifield-2.)/2.) - 32.
!
! Note 2: This subroutine uses non-system subroutines:
! W3FS26
! I2BYTE
! I4BYTE
!
!------------------------------------------------------------------------
!
! AUTHOR:
!
! Eric Kemp, 1 August 2001
! Based on HPUX FORTRAN 77 subroutine written by Kitzmiller of the
! Techniques Development Laboratory (June 1998).
!
! Eric Kemp, 17 August 2001
! Modified to avoid use of INTEGER*4, INTEGER*1, etc., based on work
! by Yunheng Wang. Also, changed variable maxval to maxval1 to avoid
! conflict with Fortran 90 implicit function.
!
!------------------------------------------------------------------------
!
! Use modules.
!
!------------------------------------------------------------------------
USE n2aconst
!------------------------------------------------------------------------
!
! Force explicit declarations
!
!------------------------------------------------------------------------
IMPLICIT NONE
!------------------------------------------------------------------------
!
! Declare arguments (original documentation)
!
!
! IVAL( ) = BYTE OR CHARACTER*1 VECTOR OF LENGTH MSGLEN,
! HOLDING THE DIGITAL HYBRID SCAN MESSAGE (INPUT)
! MSGLEN = LENGTH OF THE MESSAGE (SHOULD BE 85100) (INPUT)
! ISITE = WSR-88D SITE ID (OUTPUT)
! ISITE_LAT,ISITE_LON = SITE LAT/LON (DEG E), DEG X 1000 (OUTPUT)
! ISITE_ELEV = SITE ELEVATION, M MSL (OUTPUT)
! IYR,IMONTH,IDAY = PRODUCT VOLUME SCAN DATE: YEAR,MONTH, DAY (OUTPUT)
! IHR,IMINIT = PRODUCT TIME, UTC: HOUR,MINUTE,SECOND (OUTPUT)
!
! IPROD = PRODUCT CODE NUMBER (OUTPUT)
! MAXVAL1 = MAXIMUM DIGITAL VALUE IN PRODUCT (OUTPUT)
! IVCP = OPERATING VOLUME COVERAGE PATTERN (OUTPUT)
! IFIELD(,) = RETURNED VALUES (DATA LEVELS) FOR THE
! FIELD (OUTPUT); AN INTEGER*2 ARRAY. SHOULD BE
! DIMENSIONED BY MAXBINS,MAXRADIALS IN CALLING
! ROUTINE.
!
!
! MAXRADIALS,MAXBINS = DIMENSIONS FOR IFIELD(), IAZMUTH(), INDICATING
! NUMBER OF RADIALS AND NUMBER OF RANGE BINS
! SHOULD BE .GE. 360 AND 230, RESPECTIVELY (INPUT)
!
! IAZMUTH() = ANTENNA AZIMUTH DIRECTIONS (DEG X 10) FOR
! EACH RADIAL (OUTPUT). DIMENSIOND BY MAXRADIALS IN
! CALLING ROUTINE
! NBINS,NRADIALS = NUMBER OF RANGE BINS AND RADIALS IN THE
! GRAPHIC (OUTPUT)
! ICODE = OUTPUT RETURN CODE, CONDITIONS AS FOLLOWS:
! 0 : MESSAGE DECODED OK
! 2 : NOT A DHR (ID CODE 32) PRODUCT
! 3 : MAXRADIALS OR MAXBINS IS TOO SMALL
! 4 : PRODUCT LENGTH GREATER THAN MSGLEN
!
!------------------------------------------------------------------------
INTEGER, INTENT(IN) :: msglen,maxradials,maxbins
INTEGER, INTENT(IN) :: ival(msglen)
INTEGER, INTENT(OUT) :: ifield(maxbins,maxradials)
INTEGER, INTENT(OUT) :: icode,ivcp,isite,isite_lat,isite_lon, &
isite_elev,iyr,imonth,iday,ihr,iminit, &
iprod,nbins,nradials
INTEGER, INTENT(OUT) :: maxval1
INTEGER, INTENT(OUT) :: iazmuth(maxradials)
!------------------------------------------------------------------------
!
! Declare external functions.
!
!------------------------------------------------------------------------
INTEGER, EXTERNAL :: i2byte, i4byte
!------------------------------------------------------------------------
!
! INTERNAL VARIABLES:
!
! IVAL0,IVAL1 = INTEGER*4 WORDS USED TO HOLD LOWER AND
! HIGHER-ORDER HALVES OF 2-BYTE INTEGER
! JUL_1_1_70 = JULIAN DATE OF 1JAN1970, USED TO CONVERT NEXRAD
! INTERNAL DATE TO YR/MON/DAY (PARAMETER)
! NEXDATE,JUL_DATE = NEXRAD REFERENCE DATE, ASTRONOMICAL JULIAN DATE,
! USED TO DETERMINE LEGAL DATE (YEAR-MONTH-DAY)
! NPOS1,NPOS2 = POSITIONS OF 1ST AND LAST BYTES (RELATIVE TO START
! OF THE FILE) IN THE CURRENT RADIAL BEING DECODED
! NRUNS = NUMBER OF RUNS NEEDED TO STORE THE PRESENT RADIAL
!
!------------------------------------------------------------------------
INTEGER :: ival4
INTEGER :: nex_time,nex_date,jul_date,idaywk,idayyr,msglen_int
INTEGER :: npos1,npos2
INTEGER :: nr, nrun_marker
INTEGER :: nbyte,ibin
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!------------------------------------------------------------------------
!
! Get product type and check for product code 32 for DHR.
!
!------------------------------------------------------------------------
iprod = i2byte(ival(1),ival(2))
IF (iprod /= 32) THEN
icode = 2
RETURN
END IF
isite = 256*ival(13) + ival(14)
ivcp = 256*ival(35) + ival(36)
!------------------------------------------------------------------------
!
! Get volume scan date and time.
!
!------------------------------------------------------------------------
nex_time = i4byte(ival(43),ival(44),ival(45),ival(46))
nex_date = i2byte(ival(41),ival(42))
jul_date = jul_1_1_70 + nex_date
CALL w3fs26
(jul_date,iyr,imonth,iday,idaywk,idayyr)
ihr = nex_time / 3600
iminit = (nex_time - (3600*ihr)) / 60
!------------------------------------------------------------------------
!
! Get site lat/lon, elevation.
!
!------------------------------------------------------------------------
isite_elev = i2byte(ival(29),ival(30))
isite_lat = i4byte(ival(21),ival(22),ival(23),ival(24))
isite_lon = i4byte(ival(25),ival(26),ival(27),ival(28))
!------------------------------------------------------------------------
!
! Find number of radials in the product.
!
!------------------------------------------------------------------------
nbins = i2byte(ival(141),ival(142))
nradials = i2byte(ival(149),ival(150))
IF ( (maxbins < nbins) .OR. (maxradials < nradials) ) THEN
icode = 3
RETURN
END IF
!------------------------------------------------------------------------
!
! Check internal and user-indicated file length for consistency.
!
!------------------------------------------------------------------------
msglen_int = i4byte(ival(9),ival(10),ival(11),ival(12))
IF (msglen < msglen_int) THEN
icode = 4
RETURN
END IF
!------------------------------------------------------------------------
!
! Initialize the reflectivity array with 0 values.
!
!------------------------------------------------------------------------
ifield(:,:) = 0
!------------------------------------------------------------------------
!
! Radial by radial, read in the data. There is no run-length encoding
! for DHR product.
!
!------------------------------------------------------------------------
nr = 0
nrun_marker = 151
maxval1 = 0
DO WHILE (nr < nradials)
nr = nr + 1
iazmuth(nr) = i2byte(ival(nrun_marker+2),ival(nrun_marker+3))
npos1 = nrun_marker + 6
npos2 = npos1 + 229
ibin = 0
DO nbyte = npos1,npos2
ival4 = ival(nbyte)
IF (ival4 < 0) ival4 = 256 + ival4
ibin = ibin + 1
ifield(ibin,nr) = ival4
IF (ival4 > maxval1) maxval1 = ival4
END DO
!------------------------------------------------------------------------
!
! Finished mapping this radial -- go on to the next.
!
!------------------------------------------------------------------------
nrun_marker = npos2 + 1
END DO ! DO WHILE (nr < nradials)
!------------------------------------------------------------------------
!
! The end.
!
!------------------------------------------------------------------------
icode = 0
RETURN
END SUBROUTINE get_dhr_data
!########################################################################
!########################################################################
!######### #########
!######### FUNCTION i2byte #########
!######### #########
!######### Developed by #########
!######### Center for Analysis and Prediction of Storms #########
!######### University of Oklahoma #########
!######### #########
!########################################################################
!########################################################################
INTEGER FUNCTION i2byte(ival1,ival0),1
!------------------------------------------------------------------------
!
! PURPOSE:
!
! Combines the contents of two 1-byte words into a single 4-byte signed
! integer word.
!
!------------------------------------------------------------------------
!
! AUTHOR:
!
! MODIFICATIONS:
!
! Yunheng Wang (July 2001)
! Converted from a FORTRAN 77 code developed by NWS Techniques
! Development Laboratory in April 1998
!
! Eric Kemp, 30 July 2001
! Added USE statement for module n2aconst, minor changes.
!
! Eric Kemp, 9 August 2001
! Use variable type INTEGER*4 and similar types instead of using
! KIND statements.
!
! Eric Kemp, 17 August 2001
! Modified to avoid use of INTEGER*4, INTEGER*1, etc., based on work
! by Yunheng Wang.
!
!------------------------------------------------------------------------
!
! USE modules
!
!------------------------------------------------------------------------
USE n2aconst
!------------------------------------------------------------------------
!
! Force explicit declarations.
!
!------------------------------------------------------------------------
IMPLICIT NONE
!------------------------------------------------------------------------
!
! VARIABLES
! ival1 = high-order 8 bits of integer word (byte, INPUT)
! ival0 = low-order 8 bits of integer word (byte, INPUT)
! kval4b = signed sum of the two bytes ( OUTPUT)
!
!------------------------------------------------------------------------
INTEGER, INTENT(IN) :: ival1,ival0
!------------------------------------------------------------------------
!
! Misc. local variables
!
!------------------------------------------------------------------------
INTEGER :: ivalh, ivall
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
ivalh = ival1; ivall = ival0
IF (ival0 < 0) ivall = 256 + ival0
IF (ival1 < 0) ivalh = 256 + ival1
i2byte = ivall + (256*ivalh)
RETURN
END FUNCTION i2byte
!########################################################################
!########################################################################
!######### #########
!######### FUNCTION i4byte #########
!######### #########
!######### Developed by #########
!######### Center for Analysis and Prediction of Storms #########
!######### University of Oklahoma #########
!######### #########
!########################################################################
!########################################################################
INTEGER FUNCTION i4byte(ival3, ival2, ival1,ival0) ,1
!------------------------------------------------------------------------
!
! PURPOSE:
!
! Combines the contents of four 1-byte words into a single 4-byte signed
! integer word.
!
!------------------------------------------------------------------------
!
! AUTHOR:
!
! MODIFICATIONS:
!
! Yunheng Wang (July 2001)
! Converted from a FORTRAN 77 code developed by NWS Techniques
! Development Laboratory in April 1998.
!
! Eric Kemp, 30 July 2001.
! Added USE statement for module n2aconst, minor changes.
!
! Eric Kemp, 9 August 2001
! Use variable type INTEGER*4 and similar types instead of using
! KIND statements.
!
! Eric Kemp, 17 August 2001
! Modified to avoid use of INTEGER*4, INTEGER*1, etc., based on work
! by Yunheng Wang.
!
!------------------------------------------------------------------------
!
! Use modules
!
!------------------------------------------------------------------------
USE n2aconst
!------------------------------------------------------------------------
!
! Force explicit declarations.
!
!------------------------------------------------------------------------
IMPLICIT NONE
!------------------------------------------------------------------------
!
! VARIABLES:
! IVAL3 = HIGH-ORDER 8 BITS OF INTEGER WORD (byte, INPUT)
! IVAL2 = 2ND HIGHEST 8 BITS OF INTEGER WORD (byte, INPUT)
! IVAL1 = NEXT-TO-LOWEST 8 BITS OF INTEGER WORD (byte, INPUT)
! IVAL0 = LOW-ORDER 8 BITS OF INTEGER WORD (byte, INPUT)
!
!------------------------------------------------------------------------
INTEGER, INTENT(IN) :: ival0,ival1,ival2,ival3
!------------------------------------------------------------------------
!
! Misc. local variables
!
!------------------------------------------------------------------------
INTEGER :: ivalhh, ivalh, ivall, ivalll
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
ivalhh = ival3; ivalh = ival2
ivall = ival1; ivalll = ival0
IF (ival3 < 0) ivalhh = 256 + ival3
IF (ival2 < 0) ivalh = 256 + ival2
IF (ival1 < 0) ivall = 256 + ival1
IF (ival0 < 0) ivalll = 256 + ival0
i4byte = ivalll + (256*ivall) + (2**16)*ivalh + (2**24)*ivalhh
RETURN
END FUNCTION i4byte
!########################################################################
!########################################################################
!######### #########
!######### SUBROUTINE w3fs26 #########
!######### #########
!######### Developed by #########
!######### Center for Analysis and Prediction of Storms #########
!######### University of Oklahoma #########
!######### #########
!########################################################################
!########################################################################
SUBROUTINE w3fs26(jldayn,iyear,month,iday,idaywk,idayyr) 6,1
!------------------------------------------------------------------------
!
! PURPOSE:
!
! Computes year (4 digits), month, day, day of week, day
! of year from julian day number. This subroutine will work
! from 1583 a.d. to 3300 a.d.
!
!------------------------------------------------------------------------
!
! AUTHOR:
!
! MODIFICATIONS:
!
! Yunheng Wang (July 2001)
! Converted from a FORTRAN 77 code developed by Jones, R.E.
! in March. 29, 1987
!
! Eric Kemp, 30 July 2001
! Added USE statement for module n2aconst, minor changes.
!
! Eric Kemp, 9 August 2001
! Use variable type INTEGER*4 and similar types instead of using
! KIND statements.
!
! Eric Kemp, 17 August 2001
! Modified to avoid use of INTEGER*4, INTEGER*1, etc., based on work
! by Yunheng Wang.
!
!------------------------------------------------------------------------
!
! USE modules.
!
!------------------------------------------------------------------------
USE n2aconst
!------------------------------------------------------------------------
!
! Force explicit declarations.
!
!------------------------------------------------------------------------
IMPLICIT NONE
!------------------------------------------------------------------------
!
! INPUT:
!
! jldayn: julian day number
!
!------------------------------------------------------------------------
!
! OUTPUT:
!
! iyear: year (4 digits)
! month: month
! iday: day
! idaywk: day of week (1 is sunday, 7 is sat)
! idayyr: day of year (1 to 366)
!
!------------------------------------------------------------------------
INTEGER, INTENT(IN) :: jldayn
INTEGER, INTENT(OUT) :: iyear, month, iday, idaywk, idayyr
!------------------------------------------------------------------------
!
! Misc. local variables
!
!------------------------------------------------------------------------
INTEGER :: l, n, i, j
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!------------------------------------------------------------------------
!
! REMARKS:
!
! A julian day number can be computed by using one of the
! following statement functions. A day of week can be computed
! from the julian day number. A day of year can be computed from
! a julian day number and year.
!
! JULIAN DAY NUMBER:
!
! 1: iyear (4 digits)
!
! jdn(iyear,month,iday) = iday - 32075 &
! + 1461 * (iyear + 4800 + (month - 14) / 12) / 4 &
! + 367 * (month - 2 - (month -14) / 12 * 12) / 12 &
! - 3 * ((iyear + 4900 + (month - 14) / 12) / 100) / 4
!
! 2: iyr (4 digits) , idyr(1-366) day of year
!
! julian(iyr,idyr) = -31739 + 1461 * (iyr + 4799) / 4 &
! -3 * ((iyr + 4899) / 100) / 4 + idyr
!
! DAY OF WEEK FROM JULIAN DAY NUMBER: 1 is sunday, 7 is saturday.
!
! jdaywk(jldayn) = mod((jldayn + 1),7) + 1
!
! DAY OF YEAR FROM JULIAN DAY NUMBER AND 4 DIGIT YEAR:
!
! jdayyr(jldayn,iyear) = jldayn - &
! (-31739+1461*(iyear+4799)/4-3*((iyear+4899)/100)/4)
!
! The first function was in a letter to the editor communications
! of the acm volume 11 / number 10 / october, 1968. The 2nd
! function was derived from the first. This subroutine was also
! included in the same letter. Julian day number 1 is
! jan 1,4713 b.c. A julian day number can be used to replace a
! day of century, this will take care of the date problem in
! the year 2000, or reduce program changes to one line change
! of 1900 to 2000. Julian day numbers can be used for finding
! record numbers in an archive or day of week, or day of year.
!
!------------------------------------------------------------------------
l = jldayn + 68569
n = 4 * l / 146097
l = l - (146097 * n + 3) / 4
i = 4000 * (l + 1) / 1461001
l = l - 1461 * i / 4 + 31
j = 80 * l / 2447
iday = l - 2447 * j / 80
l = j / 11
month = j + 2 - 12 * l
iyear = 100 * (n - 49) + i + l
idaywk = MOD((jldayn + 1),7) + 1
idayyr = jldayn - &
(-31739 +1461 * (iyear+4799) / 4 - 3 * ((iyear+4899)/100)/4)
RETURN
END SUBROUTINE w3fs26