diff --git a/src/getgb2.F90 b/src/getgb2.F90 index 49626ef7..931747a4 100644 --- a/src/getgb2.F90 +++ b/src/getgb2.F90 @@ -145,11 +145,19 @@ subroutine getgb2l2(lugb, idxver, cindex, gfld, iret) type(gribfield) :: gfld integer, intent(out) :: iret end subroutine getgb2l2 + subroutine getgb2r2(lugb, idxver, cindex, gfld, iret) + use grib_mod + implicit none + integer, intent(in) :: lugb, idxver + character(len=1), intent(in) :: cindex(*) + type(gribfield) :: gfld + integer, intent(out) :: iret + end subroutine getgb2r2 end interface ! Determine whether index buffer needs to be initialized. irgi = 0 - idxver = 1 + idxver = 2 call getidx2(lugb, lugi, idxver, cbuf, nlen, nnum, irgi) if (irgi .gt. 1) then iret = 96 @@ -170,7 +178,7 @@ end subroutine getgb2l2 ! Read and unpack grib record. if (unpack) then - call getgb2r(lugb, cbuf(lpos), gfld, iret) + call getgb2r2(lugb, idxver, cbuf(lpos), gfld, iret) endif k = jk end subroutine getgb2 diff --git a/src/getgb2r.F90 b/src/getgb2r.F90 index f086e140..2d96f54b 100644 --- a/src/getgb2r.F90 +++ b/src/getgb2r.F90 @@ -1,18 +1,76 @@ !> @file -!> @brief Read and unpack sections 6 and 7 from a GRIB2 message. +!> @brief Read and unpack sections 6 and 7 from a GRIB2 message using +!> an index record. !> @author Stephen Gilbert @date 2002-01-11 -!> Read and unpack sections 6 and 7 from a GRIB2 message. +!> Read and unpack sections 6 and 7 from a GRIB2 message using a +!> version 1 index record. !> -!> It assumes that the metadata for this field already exists in -!> derived type @ref grib_mod::gribfield. Specifically, it requires -!> gfld\%ibmap, gfld\%ngrdpts, gfld\%idrtnum, gfld\%idrtmpl, and -!> gfld\%ndpts. +!> This function is maintained for backward compatibility. New code +!> should use getgb2r2(), which can handle both version 1 and version +!> 2 index records. !> -!> It decodes information for the selected grib field and returns it -!> in a derived type variable, gfld, of type @ref -!> grib_mod::gribfield. Users of this routine will need to include the -!> line "use grib_mod" in their calling routine. +!> Metadata for the field must already exists in derived type @ref +!> grib_mod::gribfield. Specifically, it requires gfld\%ibmap, +!> gfld\%ngrdpts, gfld\%idrtnum, gfld\%idrtmpl, and gfld\%ndpts. +!> +!> The field data is returned in derived type variable, gfld, of type +!> @ref grib_mod::gribfield. Users of this routine will need to +!> include the line "use grib_mod" in their calling routine. +!> +!> This subprogram is intended for private use by getgb2() +!> routines only. +!> +!> Derived type gribfield contains pointers to many arrays of +!> data. Users must free this memory by calling gf_free(). +!> +!> @param[in] lugb integer unit of the unblocked grib data file. +!> File must be opened with [baopen() or baopenr()] +!> (https://noaa-emc.github.io/NCEPLIBS-bacio/) before calling +!> this routine. +!> @param[in] cindex version 1 index record of the field (see +!> subroutine ix2gb2() for description of an index record.) +!> @param[out] gfld derived type @ref grib_mod::gribfield. +!> @param[out] iret Return code: +!> - 0 all ok +!> - 97 error reading grib file +!> - other gf_getfld grib2 unpacker return code +!> +!> @author Stephen Gilbert, Ed Hartnett @date 2002-01-11 +subroutine getgb2r(lugb, cindex, gfld, iret) + use grib_mod + implicit none + + integer, intent(in) :: lugb + character(len=1), intent(in) :: cindex(*) + type(gribfield) :: gfld + integer, intent(out) :: iret + + interface + subroutine getgb2r2(lugb, idxver, cindex, gfld, iret) + use grib_mod + implicit none + integer, intent(in) :: lugb, idxver + character(len=1), intent(in) :: cindex(*) + type(gribfield) :: gfld + integer, intent(out) :: iret + end subroutine getgb2r2 + end interface + + call getgb2r2(lugb, 1, cindex, gfld, iret) + +end subroutine getgb2r + +!> Read and unpack sections 6 and 7 from a GRIB2 message using a +!> version 1 or version 2 index record. +!> +!> Metadata for the field must already exists in derived type @ref +!> grib_mod::gribfield. Specifically, it requires gfld\%ibmap, +!> gfld\%ngrdpts, gfld\%idrtnum, gfld\%idrtmpl, and gfld\%ndpts. +!> +!> The field data is returned in derived type variable, gfld, of type +!> @ref grib_mod::gribfield. Users of this routine will need to +!> include the line "use grib_mod" in their calling routine. !> !> This subprogram is intended for private use by getgb2() !> routines only. @@ -23,33 +81,39 @@ !> @note Do not engage the same logical unit from more than one !> processor. !> -!> @param[in] LUGB integer unit of the unblocked grib data file. +!> @param[in] lugb integer unit of the unblocked grib data file. !> File must be opened with [baopen() or baopenr()] !> (https://noaa-emc.github.io/NCEPLIBS-bacio/) before calling !> this routine. -!> @param[in] CINDEX index record of the grib field (see -!> subroutine ixgb2() for description of an index record.) -!> @param[out] GFLD derived type @ref grib_mod::gribfield. -!> @param[out] IRET integer return code +!> @param[in] idxver Index version, 1 for legacy, 2 if file may be > +!> 2 GB. +!> @param[in] cindex version 1 or 2 index record of the grib field +!> (see subroutine ixgb2() for description of an index record.) +!> @param[out] gfld derived type @ref grib_mod::gribfield. +!> @param[out] iret Return code: !> - 0 all ok !> - 97 error reading grib file !> - other gf_getfld grib2 unpacker return code !> -!> @author Stephen Gilbert @date 2002-01-11 -SUBROUTINE GETGB2R(LUGB, CINDEX, GFLD, IRET) +!> @author Ed Hartnett, Stephen Gilbert @date Feb 14, 2024 +subroutine getgb2r2(lugb, idxver, cindex, gfld, iret) use grib_mod implicit none - INTEGER, INTENT(IN) :: LUGB - CHARACTER(LEN=1), INTENT(IN) :: CINDEX(*) - TYPE(GRIBFIELD) :: GFLD - INTEGER, INTENT(OUT) :: IRET + integer, intent(in) :: lugb, idxver + character(len=1), intent(in) :: cindex(*) + type(gribfield) :: gfld + integer, intent(out) :: iret - INTEGER :: LSKIP, SKIP6, SKIP7 - CHARACTER(LEN=1):: CSIZE(4) - CHARACTER(LEN=1), ALLOCATABLE :: CTEMP(:) + integer :: lskip, skip6, skip7 + character(len=1):: csize(4) + character(len=1), allocatable :: ctemp(:) real, pointer, dimension(:) :: newfld integer :: n, lread, j, iskip, iofst, ilen, ierr, idum + integer :: inc + integer (kind = 8) :: lskip8, lread8, ilen8, iskip8 + integer :: INT1_BITS, INT2_BITS, INT4_BITS, INT8_BITS + parameter(INT1_BITS = 8, INT2_BITS = 16, INT4_BITS = 32, INT8_BITS = 64) interface subroutine gf_unpack6(cgrib, lcgrib, iofst, ngpts, ibmap, bmap, ierr) @@ -72,63 +136,75 @@ end subroutine gf_unpack7 end interface ! Get info. - NULLIFY(gfld%bmap, gfld%fld) - IRET = 0 - CALL G2_GBYTEC(CINDEX, LSKIP, 4*8, 4*8) - CALL G2_GBYTEC(CINDEX, SKIP6, 24*8, 4*8) - CALL G2_GBYTEC(CINDEX, SKIP7, 28*8, 4*8) + nullify(gfld%bmap, gfld%fld) + iret = 0 + inc = 0 + if (idxver .eq. 1) then + call g2_gbytec(cindex, lskip, INT4_BITS, INT4_BITS) + lskip8 = lskip + else + inc = 4 + call g2_gbytec8(cindex, lskip8, INT4_BITS, INT8_BITS) + lskip = int(lskip8, kind(4)) + endif + call g2_gbytec(cindex, skip6, (24 + inc) * INT1_BITS, INT4_BITS) + call g2_gbytec(cindex, skip7, (28 + inc) * INT1_BITS, INT4_BITS) ! Read and unpack bit_map, if present. - IF (gfld%ibmap .eq. 0 .OR. gfld%ibmap .eq. 254) THEN - ISKIP = LSKIP + SKIP6 + if (gfld%ibmap .eq. 0 .or. gfld%ibmap .eq. 254) then + iskip = lskip + skip6 + iskip8 = lskip8 + skip6 - ! Get length of section. - CALL BAREAD(LUGB, ISKIP, 4, LREAD, CSIZE) - CALL G2_GBYTEC(CSIZE, ILEN, 0, 32) - ALLOCATE(CTEMP(ILEN)) - - ! Read in section. - CALL BAREAD(LUGB, ISKIP, ILEN, LREAD, CTEMP) - IF (ILEN .NE. LREAD) THEN - IRET = 97 - DEALLOCATE(CTEMP) - RETURN - ENDIF - IOFST = 0 - CALL GF_UNPACK6(CTEMP, ILEN, IOFST, gfld%ngrdpts, idum, gfld%bmap, ierr) - IF (IERR .NE. 0) THEN - IRET = 98 - DEALLOCATE(CTEMP) - RETURN - ENDIF - DEALLOCATE(CTEMP) - ENDIF + ! get length of section. + call bareadl(lugb, iskip8, 4_8, lread8, csize) + call g2_gbytec(csize, ilen, 0, 32) + allocate(ctemp(ilen)) + ilen8 = ilen + + ! read in section. + call bareadl(lugb, iskip8, ilen8, lread8, ctemp) + if (ilen8 .ne. lread8) then + iret = 97 + deallocate(ctemp) + return + endif + iofst = 0 + call gf_unpack6(ctemp, ilen, iofst, gfld%ngrdpts, idum, gfld%bmap, ierr) + if (ierr .ne. 0) then + iret = 98 + deallocate(ctemp) + return + endif + deallocate(ctemp) + endif ! Read and unpack data field. - ISKIP = LSKIP + SKIP7 + iskip = lskip + skip7 + iskip8 = lskip8 + skip7 ! Get length of section. - CALL BAREAD(LUGB, ISKIP, 4, LREAD, CSIZE) - CALL G2_GBYTEC(CSIZE, ILEN, 0, 32) + call bareadl(lugb, iskip8, 4_8, lread8, csize) + call g2_gbytec(csize, ilen, 0, 32) if (ilen .lt. 6) ilen = 6 - ALLOCATE(CTEMP(ILEN)) + allocate(ctemp(ilen)) + ilen8 = ilen ! Read in section. - CALL BAREAD(LUGB, ISKIP, ILEN, LREAD, CTEMP) - IF (ILEN .NE. LREAD) THEN - IRET = 97 - DEALLOCATE(CTEMP) - RETURN - ENDIF - IOFST = 0 - CALL GF_UNPACK7(CTEMP, ILEN, IOFST, gfld%igdtnum, gfld%igdtmpl, & + call bareadl(lugb, iskip8, ilen8, lread8, ctemp) + if (ilen8 .ne. lread8) then + iret = 97 + deallocate(ctemp) + return + endif + iofst = 0 + call gf_unpack7(ctemp, ilen, iofst, gfld%igdtnum, gfld%igdtmpl, & gfld%idrtnum, gfld%idrtmpl, gfld%ndpts, gfld%fld, ierr) - IF (IERR .NE. 0) THEN - IRET = 98 - DEALLOCATE(CTEMP) - RETURN - ENDIF - DEALLOCATE(CTEMP) + if (ierr .ne. 0) then + iret = 98 + deallocate(ctemp) + return + endif + deallocate(ctemp) ! If bitmap is used with this field, expand data field ! to grid, if possible. @@ -149,4 +225,4 @@ end subroutine gf_unpack7 else gfld%expanded = .true. endif -END SUBROUTINE GETGB2R +end subroutine getgb2r2 diff --git a/src/getgb2rp.F90 b/src/getgb2rp.F90 index 10dfaf86..f1b91f82 100644 --- a/src/getgb2rp.F90 +++ b/src/getgb2rp.F90 @@ -3,8 +3,11 @@ !> field. !> @author Stephen Gilbert @date 2003-12-31 -!> Extract a grib message from a file given the index of the requested -!> field. +!> Extract a grib message from a file given the index (index format 1) +!> of the requested field. +!> +!> This subroutine is maintained for backward compatibility. New code +!> should use getgb2rp2(). !> !> The GRIB message returned can contain only the requested field !> (extract=.true.), or the complete GRIB message originally @@ -22,7 +25,7 @@ !> (https://noaa-emc.github.io/NCEPLIBS-bacio/) before calling this !> routine. !> @param[in] cindex Index record of the grib field (see docunentation of -!> subroutine ixgb2() for description of an index record.) +!> subroutine ix2gb2() for description of an index record.) !> @param[in] extract Logical value indicating whether to return a !> GRIB2 message with just the requested field, or the entire !> GRIB2 message containing the requested field. @@ -34,135 +37,225 @@ !> - 0 No error. !> - 97 Error reading grib file. !> -!> @author Stephen Gilbert @date 2003-12-31 +!> @author Stephen Gilbert, Ed Hartnett @date 2003-12-31 subroutine getgb2rp(lugb, cindex, extract, gribm, leng, iret) implicit none integer, intent(in) :: lugb character(len = 1), intent(in) :: cindex(*) logical, intent(in) :: extract + character(len = 1), pointer, dimension(:) :: gribm + integer, intent(out) :: leng, iret + + interface + subroutine getgb2rp2(lugb, idxver, cindex, extract, gribm, leng, iret) + integer, intent(in) :: lugb, idxver + character(len = 1), intent(in) :: cindex(*) + logical, intent(in) :: extract + character(len = 1), pointer, dimension(:) :: gribm + integer, intent(out) :: leng, iret + end subroutine getgb2rp2 + end interface + + call getgb2rp2(lugb, 1, cindex, extract, gribm, leng, iret) + +end subroutine getgb2rp + +!> Extract a grib message from a file given the version 1 or 2 index +!> of the requested field. +!> +!> The GRIB message returned can contain only the requested field +!> (extract=.true.), or the complete GRIB message originally +!> containing the desired field can be returned (extract=.false.) even +!> if other fields were included in the GRIB message. +!> +!> If the GRIB field is not found, then the return code will be +!> nonzero. +!> +!> @param[in] lugb integer unit of the unblocked grib data file. file +!> must be opened with [baopen() or baopenr()] +!> (https://noaa-emc.github.io/NCEPLIBS-bacio/) before calling this +!> routine. +!> @param[in] idxver Version of index, use 1 for legacy, 2 if files +!> may be > 2 GB. +!> @param[in] cindex Index record of the grib field (see docunentation of +!> subroutine ixgb2() for description of an index record.) +!> @param[in] extract Logical value indicating whether to return a +!> GRIB2 message with just the requested field, or the entire +!> GRIB2 message containing the requested field. +!> - .true. = return grib2 message containing only the requested field. +!> - .false. = return entire grib2 message containing the requested field. +!> @param[out] gribm Returned grib message. +!> @param[out] leng Length of returned grib message in bytes. +!> @param[out] iret Return code: +!> - 0 No error. +!> - 97 Error reading grib file. +!> +!> @author Edward Hartnett, Stephen Gilbert @date Feb 13, 2024 +subroutine getgb2rp2(lugb, idxver, cindex, extract, gribm, leng, iret) + implicit none + + integer, intent(in) :: lugb, idxver + character(len = 1), intent(in) :: cindex(*) + logical, intent(in) :: extract integer, intent(out) :: leng, iret character(len = 1), pointer, dimension(:) :: gribm integer, parameter :: zero = 0 character(len = 1), allocatable, dimension(:) :: csec2, csec6, csec7 character(len = 4) :: ctemp - integer :: lencur, lread, len0, ibmap, ipos, iskip - integer :: len7, len8, len3, len4, len5, len6, len1, len2 + integer :: lencur, len0, ibmap = 0, ipos, iskip + integer :: len7 = 0, len8 = 0, len3 = 0, len4 = 0, len5 = 0, len6 = 0, len1 = 0, len2 = 0 integer :: iskp2, iskp6, iskp7 + integer :: INT1_BITS, INT2_BITS, INT4_BITS, INT8_BITS + parameter(INT1_BITS = 8, INT2_BITS = 16, INT4_BITS = 32, INT8_BITS = 64) + integer :: mypos, inc = 0 + integer (kind = 8) :: lread8, iskip8, leng8, len2_8, len7_8, len6_8 iret = 0 ! Extract grib message from file. - IF (EXTRACT) THEN - LEN0 = 16 - LEN8 = 4 - CALL G2_GBYTEC(CINDEX, ISKIP, 4*8, 4*8) ! BYTES TO SKIP IN FILE - CALL G2_GBYTEC(CINDEX, ISKP2, 8*8, 4*8) ! BYTES TO SKIP FOR section 2 + mypos = INT4_BITS + if (extract) then + len0 = 16 + len8 = 4 + if (idxver .eq. 1) then + call g2_gbytec(cindex, iskip, mypos, INT4_BITS) ! bytes to skip in file + mypos = mypos + INT4_BITS + iskip8 = iskip + else + inc = 4 + call g2_gbytec8(cindex, iskip8, mypos, INT8_BITS) ! bytes to skip in file + mypos = mypos + INT8_BITS + iskip = int(iskip8, kind(4)) + endif + call g2_gbytec(cindex, iskp2, mypos, INT4_BITS) ! bytes to skip for section 2 + mypos = mypos + INT4_BITS if (iskp2 .gt. 0) then - CALL BAREAD(LUGB, ISKIP + ISKP2, 4, LREAD, ctemp) - CALL G2_GBYTEC(Ctemp, LEN2, 0, 4*8) ! LENGTH OF SECTION 2 - ALLOCATE(csec2(len2)) - CALL BAREAD(LUGB, ISKIP + ISKP2, LEN2, LREAD, csec2) + call bareadl(lugb, iskip8 + iskp2, 4_8, lread8, ctemp) + call g2_gbytec(ctemp, len2, 0, INT4_BITS) ! length of section 2 + allocate(csec2(len2)) + len2_8 = len2 + call bareadl(lugb, iskip8 + iskp2, len2_8, lread8, csec2) else - LEN2 = 0 + len2 = 0 + endif + mypos = mypos + 32 * INT1_BITS ! skip ahead in the cindex + call g2_gbytec(cindex, len1, mypos, INT4_BITS) ! length of section 1 + ipos = 44 + len1 + mypos = mypos + len1 * INT1_BITS ! skip ahead in the cindex + call g2_gbytec(cindex, len3, mypos, INT4_BITS) ! length of section 3 + ipos = ipos + len3 + mypos = mypos + len3 * INT1_BITS ! skip ahead in the cindex + call g2_gbytec(cindex, len4, mypos, INT4_BITS) ! length of section 4 + ipos = ipos + len4 + mypos = mypos + len4 * INT1_BITS ! skip ahead in the cindex + call g2_gbytec(cindex, len5, mypos, INT4_BITS) ! length of section 5 + ipos = ipos + len5 + mypos = mypos + len5 * INT1_BITS ! skip ahead in the cindex + call g2_gbytec(cindex, len6, mypos, INT4_BITS) ! length of section 6 + ipos = ipos + 5 + mypos = mypos + len6 * INT1_BITS ! skip ahead in the cindex + call g2_gbytec(cindex, ibmap, mypos, INT1_BITS) ! bitmap indicator + if (ibmap .eq. 254) then + call g2_gbytec(cindex, iskp6, (24 + inc) * INT1_BITS, INT4_BITS) ! bytes to skip for section 6 + !call baread(lugb, iskip + iskp6, 4, lread, ctemp) + call bareadl(lugb, iskip8 + iskp6, 4_8, lread8, ctemp) + call g2_gbytec(ctemp, len6, 0, INT4_BITS) ! length of section 6 endif - CALL G2_GBYTEC(CINDEX, LEN1, 44*8, 4*8) ! LENGTH OF SECTION 1 - IPOS = 44 + LEN1 - CALL G2_GBYTEC(CINDEX, LEN3, IPOS*8, 4*8) ! LENGTH OF SECTION 3 - IPOS = IPOS + LEN3 - CALL G2_GBYTEC(CINDEX, LEN4, IPOS*8, 4*8) ! LENGTH OF SECTION 4 - IPOS = IPOS + LEN4 - CALL G2_GBYTEC(CINDEX, LEN5, IPOS*8, 4*8) ! LENGTH OF SECTION 5 - IPOS = IPOS + LEN5 - CALL G2_GBYTEC(CINDEX, LEN6, IPOS*8, 4*8) ! LENGTH OF SECTION 6 - IPOS = IPOS + 5 - CALL G2_GBYTEC(CINDEX, IBMAP, IPOS*8, 1*8) ! Bitmap indicator - IF (IBMAP .eq. 254) THEN - CALL G2_GBYTEC(CINDEX, ISKP6, 24*8, 4*8) ! BYTES TO SKIP FOR section 6 - CALL BAREAD(LUGB, ISKIP + ISKP6, 4, LREAD, ctemp) - CALL G2_GBYTEC(Ctemp, LEN6, 0, 4*8) ! LENGTH OF SECTION 6 - ENDIF - - ! READ IN SECTION 7 from file - CALL G2_GBYTEC(CINDEX, ISKP7, 28*8, 4*8) ! BYTES TO SKIP FOR section 7 - CALL BAREAD(LUGB, ISKIP + ISKP7, 4, LREAD, ctemp) - CALL G2_GBYTEC(Ctemp, LEN7, 0, 4*8) ! LENGTH OF SECTION 7 - ALLOCATE(csec7(len7)) - CALL BAREAD(LUGB, ISKIP + ISKP7, LEN7, LREAD, csec7) - - LENG = LEN0 + LEN1 + LEN2 + LEN3 + LEN4 + LEN5 + LEN6 + LEN7 + LEN8 - IF (.NOT. ASSOCIATED(GRIBM)) ALLOCATE(GRIBM(LENG)) + + ! read in section 7 from file + call g2_gbytec(cindex, iskp7, (28 + inc) * INT1_BITS, INT4_BITS) ! bytes to skip for section 7 + !call baread(lugb, iskip + iskp7, 4, lread, ctemp) + call bareadl(lugb, iskip8 + iskp7, 4_8, lread8, ctemp) + call g2_gbytec(ctemp, len7, 0, INT4_BITS) ! length of section 7 + allocate(csec7(len7)) + !call baread(lugb, iskip + iskp7, len7, lread, csec7) + len7_8 = len7 + call bareadl(lugb, iskip8 + iskp7, len7_8, lread8, csec7) + + leng = len0 + len1 + len2 + len3 + len4 + len5 + len6 + len7 + len8 + if (.not. associated(gribm)) allocate(gribm(leng)) ! Create Section 0 - GRIBM(1) = 'G' - GRIBM(2) = 'R' - GRIBM(3) = 'I' - GRIBM(4) = 'B' - GRIBM(5) = CHAR(0) - GRIBM(6) = CHAR(0) - GRIBM(7) = CINDEX(42) - GRIBM(8) = CINDEX(41) - GRIBM(9) = CHAR(0) - GRIBM(10) = CHAR(0) - GRIBM(11) = CHAR(0) - GRIBM(12) = CHAR(0) - CALL G2_SBYTEC(GRIBM, LENG, 12*8, 4*8) + gribm(1) = 'G' + gribm(2) = 'R' + gribm(3) = 'I' + gribm(4) = 'B' + gribm(5) = char(0) + gribm(6) = char(0) + gribm(7) = cindex(42 + inc) + gribm(8) = cindex(41 + inc) + gribm(9) = char(0) + gribm(10) = char(0) + gribm(11) = char(0) + gribm(12) = char(0) + call g2_sbytec(gribm, leng, 12*8, INT4_BITS) ! Copy Section 1 - GRIBM(17:16 + LEN1) = CINDEX(45:44 + LEN1) - lencur = 16 + LEN1 - ipos = 44 + len1 + gribm(17:16 + len1) = cindex(45 + inc:44 + inc + len1) + lencur = 16 + inc + len1 + ipos = 44 + inc + len1 ! Copy Section 2, if necessary if (iskp2 .gt. 0) then - GRIBM(lencur + 1:lencur + LEN2) = csec2(1:LEN2) - lencur = lencur + LEN2 + gribm(lencur + 1:lencur + len2) = csec2(1:len2) + lencur = lencur + len2 endif ! Copy Sections 3 through 5 - GRIBM(lencur + 1:lencur + LEN3 + LEN4 + LEN5) = CINDEX(ipos + 1:ipos + LEN3 + LEN4 + LEN5) - lencur = lencur + LEN3 + LEN4 + LEN5 - ipos = ipos + LEN3 + LEN4 + LEN5 + gribm(lencur + 1:lencur + len3 + len4 + len5) = cindex(ipos + 1:ipos + len3 + len4 + len5) + lencur = lencur + len3 + len4 + len5 + ipos = ipos + len3 + len4 + len5 ! Copy Section 6 - if (LEN6 .eq. 6 .AND. IBMAP .ne. 254) then - GRIBM(lencur + 1:lencur + LEN6) = CINDEX(ipos + 1:ipos + LEN6) - lencur = lencur + LEN6 + if (len6 .eq. 6 .and. ibmap .ne. 254) then + gribm(lencur + 1:lencur + len6) = cindex(ipos + 1:ipos + len6) + lencur = lencur + len6 else - CALL G2_GBYTEC(CINDEX, ISKP6, 24*8, 4*8) ! BYTES TO SKIP FOR section 6 - CALL BAREAD(LUGB, ISKIP + ISKP6, 4, LREAD, ctemp) - CALL G2_GBYTEC(Ctemp, LEN6, 0, 4*8) ! LENGTH OF SECTION 6 - ALLOCATE(csec6(len6)) - CALL BAREAD(LUGB, ISKIP + ISKP6, LEN6, LREAD, csec6) - GRIBM(lencur + 1:lencur + LEN6) = csec6(1:LEN6) - lencur = lencur + LEN6 - IF (allocated(csec6)) DEALLOCATE(csec6) + call g2_gbytec(cindex, iskp6, (24 + inc) * 8, INT4_BITS) ! bytes to skip for section 6 + call bareadl(lugb, iskip8 + iskp6, 4_8, lread8, ctemp) + call g2_gbytec(ctemp, len6, 0, INT4_BITS) ! length of section 6 + allocate(csec6(len6)) + len6_8 = len6 + call bareadl(lugb, iskip8 + iskp6, len6_8, lread8, csec6) + gribm(lencur + 1:lencur + len6) = csec6(1:len6) + lencur = lencur + len6 + if (allocated(csec6)) deallocate(csec6) endif ! Copy Section 7 - GRIBM(lencur + 1:lencur + LEN7) = csec7(1:LEN7) - lencur = lencur + LEN7 + gribm(lencur + 1:lencur + len7) = csec7(1:len7) + lencur = lencur + len7 ! Section 8 - GRIBM(lencur + 1) = '7' - GRIBM(lencur + 2) = '7' - GRIBM(lencur + 3) = '7' - GRIBM(lencur + 4) = '7' + gribm(lencur + 1) = '7' + gribm(lencur + 2) = '7' + gribm(lencur + 3) = '7' + gribm(lencur + 4) = '7' ! clean up - IF (allocated(csec2)) DEALLOCATE(csec2) - IF (allocated(csec7)) deallocate(csec7) - ELSE ! DO NOT extract field from message : Get entire message - CALL G2_GBYTEC(CINDEX, ISKIP, 4*8, 4*8) ! BYTES TO SKIP IN FILE - CALL G2_GBYTEC(CINDEX, LENG, 36*8, 4*8) ! LENGTH OF GRIB MESSAGE - IF (.NOT. ASSOCIATED(GRIBM)) ALLOCATE(GRIBM(LENG)) - CALL BAREAD(LUGB, ISKIP, LENG, LREAD, GRIBM) - IF (LENG .NE. LREAD ) THEN - DEALLOCATE(GRIBM) - NULLIFY(GRIBM) - IRET = 97 - RETURN - ENDIF - ENDIF -END SUBROUTINE GETGB2RP + if (allocated(csec2)) deallocate(csec2) + if (allocated(csec7)) deallocate(csec7) + else ! do not extract field from message : get entire message + if (idxver .eq. 1) then + call g2_gbytec(cindex, iskip, mypos, INT4_BITS) ! bytes to skip in file + mypos = mypos + INT4_BITS + iskip8 = iskip + else + call g2_gbytec8(cindex, iskip8, mypos, INT8_BITS) ! bytes to skip in file + mypos = mypos + INT8_BITS + endif + mypos = mypos + 7 * INT4_BITS + call g2_gbytec(cindex, leng, mypos, INT4_BITS) ! length of grib message + if (.not. associated(gribm)) allocate(gribm(leng)) + leng8 = leng + call bareadl(lugb, iskip8, leng8, lread8, gribm) + if (leng8 .ne. lread8) then + deallocate(gribm) + nullify(gribm) + iret = 97 + return + endif + endif +end subroutine getgb2rp2 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ae4f14cc..68ca6536 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -113,6 +113,7 @@ if(FTP_TEST_FILES) create_test(test_getg2ir ${kind}) create_test(test_getidx ${kind}) create_test(test_getgb2rp ${kind}) + create_test(test_getgb2rp_2 ${kind}) create_test(test_getgb2s ${kind}) create_test(test_getgb2p ${kind}) create_test(test_getgb2r ${kind}) @@ -162,7 +163,8 @@ foreach(kind ${kinds}) create_test(test_mkieee ${kind}) create_test(test_getlocal ${kind}) create_test(test_index_gdas ${kind} index_rec.F90) - create_test(test_getgb2p_gdas ${kind}) + create_test(test_getgb2p_gdas ${kind}) + set_tests_properties(test_getgb2p_gdas_${kind} PROPERTIES LABELS noMemcheck) create_test(test_realloc ${kind}) create_test(test_simpack ${kind}) create_test(test_gbytec ${kind}) diff --git a/tests/test_getgb2p_gdas.F90 b/tests/test_getgb2p_gdas.F90 index 84727d31..28a77a5f 100644 --- a/tests/test_getgb2p_gdas.F90 +++ b/tests/test_getgb2p_gdas.F90 @@ -20,7 +20,7 @@ program test_getgb2p_gdas parameter(GDAS_FILE = 'gdaswave.t00z.wcoast.0p16.f000.grib2') character(*) :: GDAS_INDEX_FILE parameter(GDAS_INDEX_FILE = 'ref_gdaswave.t00z.wcoast.0p16.f000.grb2index') - integer :: e, iret + integer :: e, iret = 0 ! Interfaces are needed due to pointers in the parameter lists. interface diff --git a/tests/test_getgb2rp_2.F90 b/tests/test_getgb2rp_2.F90 new file mode 100644 index 00000000..0129a17e --- /dev/null +++ b/tests/test_getgb2rp_2.F90 @@ -0,0 +1,77 @@ +! This is a test program for NCEPLIBS-g2. +! +! This program tests getg2rp.F90 +! +! Ed Hartnett 7/26/22 +program test_getgb2rp + use bacio_module + implicit none + + integer :: lugi + character(len=1), pointer, dimension(:) :: cbuf(:) + integer :: lugb = 3 + integer :: nlen, nnum, iret + logical :: extract + integer :: leng + character(len=1), pointer, dimension(:) :: gribm + integer :: idxver = 1 + + ! Interfaces are needed due to pointers in the parameter lists. + interface + subroutine getidx2(lugb, lugi, idxver, cindex, nlen, nnum, iret) + integer, intent(in) :: lugb, lugi + integer, intent(inout) :: idxver + character(len = 1), pointer, dimension(:) :: cindex + integer, intent(out) :: nlen, nnum, iret + end subroutine getidx2 + end interface + + interface + subroutine getgb2rp(lugb, cindex, extract, gribm, leng, iret) + integer, intent(in) :: lugb + character(len=1), intent(in) :: cindex(*) + logical, intent(in) :: extract + character(len=1), pointer, dimension(:) :: gribm + integer, intent(out) :: leng, iret + end subroutine getgb2rp + end interface + + print *, 'Testing the getgb2rp() subroutine - expect and ignore error messages during test...' + + ! Open a real GRIB2 file. + print *, 'Indexing a real GRIB2 file WW3_Regional_US_West_Coast_20220718_0000.grib2...' + call baopenr(lugb, "data/WW3_Regional_US_West_Coast_20220718_0000.grib2", iret) + if (iret .ne. 0) stop 100 + + lugi = 0 + call getidx2(lugb, lugi, idxver, cbuf, nlen, nnum, iret) + if (iret .ne. 0) stop 101 + if (nlen .ne. 137600 .or. nnum .ne. 688) stop 102 + print *, 'nlen, nnum: ', nlen, nnum + + ! Extract the whole message. + extract = .false. + nullify(gribm) + call getgb2rp(lugb, cbuf, extract, gribm, leng, iret) + print *, 'leng ', leng + if (leng .ne. 11183) stop 110 + ! Deallocate buffer that got GRIB message. + deallocate(gribm) + + ! Extract just the field (same result). + extract = .true. + call getgb2rp(lugb, cbuf, extract, gribm, leng, iret) + print *, 'leng ', leng + if (leng .ne. 11183) stop 110 + ! Deallocate buffer that got GRIB message. + deallocate(gribm) + + ! Deallocate the buffer that holds index. + deallocate(cbuf) + + call baclose(lugb, iret) + if (iret .ne. 0) stop 199 + + print *, 'SUCCESS!...' + +end program test_getgb2rp