SUBROUTINE NX_PRTB ( bull, lenb, ibptr, rawptb, lenptb, + iptbdt, iret ) C************************************************************************ C* NX_PRTB * C* * C* This subroutine locates, decodes, and stores the part B data from * C* within a NeXRaD RCM bulletin. * C* * C* NX_PRTB ( BULL, LENB, IBPTR, RAWPTB, LENPTB, * C* IPTBDT, IRET ) * C* * C* Input parameters: * C* BULL CHAR* Bulletin * C* LENB INTEGER Length of BULL * C* IBPTR INTEGER Pointer within BULL * C* * C* Output parameters: * C* CIVALS (ICRPID) CHAR* Product source identifier * C* RIVALS (IRYEAR) REAL Part B year * C* RIVALS (IRMNTH) REAL Part B month * C* RIVALS (IRDAYS) REAL Part B day * C* RIVALS (IRHOUR) REAL Part B hour * C* RIVALS (IRMINU) REAL Part B minute * C* RIVALS (IRNPBW) REAL Number of part B wind levels * C* RIVALS (IRHGTM) REAL Height in meters * C* RIVALS (IRDRCT) REAL Wind direction in degrees * C* RIVALS (IRSKNT) REAL Wind speed in knots * C* RIVALS (IRRMSE) REAL Root mean square wind error * C* RAWPTB CHAR* Raw part B data as originally * C* encoded in BULL * C* LENPTB INTEGER Length of RAWPTB * C* IPTBDT (5) INTEGER Part B date-time * C* (YYYY, MM, DD, HH, MM ) * C* IRET INTEGER Return code * C* 0 = normal return * C* -1 = critical error in BULL * C* or reached end of BULL * C** * C* Log: * C* J. Ator/NCEP 04/98 * C* R. Hollern/NCEP 01/99 Initialize cflvl,rmse in DATA stmts * C* J. Ator/NCEP 06/00 bullx->bull, lenbx->lenb, ibxptr->ibptr * C* J. Ator/NCEP 06/01 Use UT_EMSG * C* J. Ator/NCEP 01/02 Declare field locally * C************************************************************************ INCLUDE 'GEMPRM.PRM' INCLUDE 'nxcmn.cmn' C* CHARACTER*(*) bull, rawptb C* INTEGER iptbdt (*) C* PARAMETER ( NCFLVL = 7 ) C* REAL rmse ( NCFLVL ) C* CHARACTER ptbdt*11, field*(MXLENF), + cflvl ( NCFLVL ) C* LOGICAL done C* DATA (cflvl(i), i = 1,NCFLVL ) + / 'A', 'B', 'C', 'D', 'E', 'F', 'G' / C* DATA (rmse(i), i = 1,NCFLVL ) + / 1.9, 3.9, 5.8, 7.8, 9.7, 11.7, 13.6 / C----------------------------------------------------------------------- C C* Initialize output variables. C iret = -1 lenptb = 0 DO ii = 1, 5 iptbdt (ii) = 0 END DO C C* Locate the start of the part B data. C IF ( ibptr .ge. lenb ) THEN RETURN END IF ipt1 = INDEX ( bull ( ibptr : lenb ), '/NEXRBB' ) IF ( ipt1 .eq. 0 ) THEN logmsg = 'could not find /NEXRBB indicator' CALL DC_WLOG ( 2, 'NX', -1, logmsg, ierwlg ) RETURN END IF isbxb = ibptr + ipt1 - 1 C C* Make sure that there is only one part B within this bulletin. C IF ( ( isbxb + 7 ) .ge. lenb ) THEN RETURN END IF ipt1 = INDEX ( bull ( ( isbxb + 7 ) : lenb ), '/NEXRBB' ) IF ( ipt1 .gt. 0 ) THEN logmsg = 'found two /NEXRBB indicators' CALL DC_WLOG ( 2, 'NX', -1, logmsg, ierwlg ) RETURN END IF C C* Locate the end of the part B data. C IF ( isbxb .ge. lenb ) THEN RETURN END IF ipt1 = INDEX ( bull ( isbxb : lenb ), '/ENDBB' ) IF ( ipt1 .eq. 0 ) THEN logmsg = 'could not find /ENDBB indicator' CALL DC_WLOG ( 2, 'NX', -1, logmsg, ierwlg ) RETURN END IF iebxb = isbxb + ipt1 + 4 C C* Remove all excess blanks from the portion of BULL which C* contains the part B data, and store the result in RAWPTB. C* C* Note that, currently, the maximum size string that can be C* passed into subroutine ST_RXBL is 160. C mxsl = 160 C ipt1 = isbxb DO WHILE ( ( iebxb - ipt1 + 1 ) .gt. mxsl ) ipt2 = ipt1 + mxsl - 1 CALL ST_RXBL ( bull ( ipt1 : ipt2 ), + rawptb ( ( lenptb + 1 ) : ), + lpb, ierrxl ) IF ( ierrxl .ne. 0 ) THEN CALL UT_EMSG ( 2, 'ST_RXBL', ierrxl ) RETURN END IF lenptb = lenptb + lpb ipt1 = ipt2 + 1 END DO IF ( ipt1 .le. iebxb ) THEN CALL ST_RXBL ( bull ( ipt1 : iebxb ), + rawptb ( ( lenptb + 1 ) : ), + lpb, ierrxl ) IF ( ierrxl .ne. 0 ) THEN CALL UT_EMSG ( 2, 'ST_RXBL', ierrxl ) RETURN END IF lenptb = lenptb + lpb END IF C C* Get, decode, and store the part B data from within RAWPTB, C* beginning with the byte directly following "/NEXRBB" and C* ending with the byte directly preceding "/ENDBB". C ipt1 = 8 ipt2 = lenptb - 6 C C* Get the product source identifier. C CALL NX_GFLD ( rawptb, ipt2, ipt1, field, lenf, ier ) IF ( ier .ne. 0 ) THEN RETURN ELSE IF ( lenf .ne. 4 ) THEN logmsg = 'product source identifer ' // field (1:lenf) CALL DC_WLOG ( 2, 'NX', -1, logmsg, ierwlg ) RETURN END IF C C* Store the product source identifier. C civals ( icrpid ) (1:4) = field (1:4) C C* Get the part B date-time. C CALL NX_GFLD ( rawptb, ipt2, ipt1, field, lenf, ier ) IF ( ier .ne. 0 ) THEN RETURN ELSE IF ( lenf .ne. 10 ) THEN logmsg = 'part B date-time ' // field (1:lenf) CALL DC_WLOG ( 2, 'NX', -1, logmsg, ierwlg ) RETURN END IF C C* Decode and store the part B date-time. C ptbdt (1:2) = field (5:6) ptbdt (3:4) = field (3:4) ptbdt (5:6) = field (1:2) ptbdt (7:7) = '/' ptbdt (8:11) = field (7:10) CALL TI_CTOI ( ptbdt, iptbdt, iercto ) IF ( iercto .ne. 0 ) THEN logmsg = 'part B date-time ' // field (1:10) CALL DC_WLOG ( 2, 'NX', -1, logmsg, ierwlg ) RETURN END IF rivals ( iryear ) = FLOAT ( iptbdt (1) ) rivals ( irmnth ) = FLOAT ( iptbdt (2) ) rivals ( irdays ) = FLOAT ( iptbdt (3) ) rivals ( irhour ) = FLOAT ( iptbdt (4) ) rivals ( irminu ) = FLOAT ( iptbdt (5) ) C C* Check whether the next field contains a 'VADNA' indicator. C iptsv = ipt1 CALL NX_GFLD ( rawptb, ipt2, ipt1, field, lenf, ier ) IF ( ier .ne. 0 ) THEN RETURN ELSE IF ( ( lenf .eq. 5 ) .and. + ( field (1:5) .eq. 'VADNA' ) ) THEN logmsg = 'found VADNA indicator' CALL DC_WLOG ( 2, 'NX', -1, logmsg, ierwlg ) RETURN END IF ipt1 = iptsv C C* Get, decode, and store the part B wind levels. C npbw = 0 done = .false. prevht = rivals ( irselv ) C DO WHILE ( .not. done ) C C* Get the next field; it should contain a wind level. C CALL NX_GFLD ( rawptb, ipt2, ipt1, field, lenf, ier ) IF ( ier .ne. 0 ) THEN done = .true. ELSE IF ( lenf .ne. 10 ) THEN logmsg = 'wind level ' // field (1:lenf) CALL DC_WLOG ( 2, 'NX', 2, logmsg, ierwlg ) ELSE C C* Decode the wind level. C CALL ST_INTG ( field (1:3), ihghf, ierh ) CALL ST_FIND ( field (4:4), cflvl, NCFLVL, irms, ierf ) CALL ST_INTG ( field (5:7), idrct, ierd ) CALL ST_INTG ( field (8:10), isknt, iers ) IF ( ( ierh .ne. 0 ) .or. ( irms .eq. 0 ) .or. + ( ierd .ne. 0 ) .or. ( iers .ne. 0 ) .or. + ( idrct .lt. 0 ) .or. ( idrct .gt. 360 ) ) THEN logmsg = 'wind level ' // field (1:10) CALL DC_WLOG ( 2, 'NX', 2, logmsg, ierwlg ) ELSE hgtf = FLOAT ( ihghf * 100 ) hgtm = PR_HGFM ( hgtf ) C C* The heights for the wind levels *must* all be in C* ascending order. If even one out-of-order height C* is encountered, then stop decoding and delete all C* previously stored wind levels for this bulletin. C IF ( prevht .gt. hgtm ) THEN logmsg = 'out-of-order height in ' // + field (1:10) CALL DC_WLOG ( 2, 'NX', -1, logmsg, ierwlg ) rivals ( irnpbw ) = 0 RETURN ELSE prevht = hgtm npbw = npbw + 1 IF ( npbw .gt. MXNPBW ) THEN WRITE ( UNIT = logmsg, FMT = '( 2A, I2 )' ) + field (1:10), ' = valid wind level #', npbw CALL DC_WLOG ( 2, 'NX', 2, logmsg, ierwlg ) ELSE C C* Store the wind level. C rivals ( irhgtm ( npbw ) ) = hgtm rivals ( irdrct ( npbw ) ) = FLOAT ( idrct ) rivals ( irsknt ( npbw ) ) = FLOAT ( isknt ) rivals ( irrmse ( npbw ) ) = rmse ( irms ) rivals ( irnpbw ) = npbw END IF END IF END IF END IF END DO C iret = 0 C* RETURN END