From 65bf7b381a1f55b125605f187599f39ee6996b62 Mon Sep 17 00:00:00 2001 From: AlysonStahl-NOAA <166434581+AlysonStahl-NOAA@users.noreply.github.com> Date: Fri, 14 Jun 2024 01:18:36 -0600 Subject: [PATCH] Clean up utils directory (#715) * consolidated files for degrib2 * temporarily disable test * combined some files for cnvgrib * merge mkfldsep into tocgrib * subroutines for degrib2 used separately in test, combined into their own file --------- Co-authored-by: Edward Hartnett <38856240+edwardhartnett@users.noreply.github.com> --- test_utils/CMakeLists.txt | 3 +- utils/CMakeLists.txt | 6 +- utils/cnv12.F90 | 1509 ++++++++++++++++++++++++++++ utils/cnv21.F90 | 1335 ++++++++++++++++++++++++ utils/gds2gdt.F90 | 392 -------- utils/gdt2gds.F90 | 378 ------- utils/makepds.F90 | 528 ---------- utils/makepdsens.F90 | 156 --- utils/pds2pdt.F90 | 490 --------- utils/pds2pdtens.F90 | 640 ------------ utils/{prlevel.F90 => prgrib2.F90} | 147 ++- utils/prvtime.F90 | 147 --- utils/putgbexn.F90 | 222 ---- utils/setbit.F90 | 69 -- utils/tocgrib.F90 | 93 ++ 15 files changed, 3085 insertions(+), 3030 deletions(-) delete mode 100644 utils/gds2gdt.F90 delete mode 100644 utils/gdt2gds.F90 delete mode 100644 utils/makepds.F90 delete mode 100644 utils/makepdsens.F90 delete mode 100644 utils/pds2pdt.F90 delete mode 100644 utils/pds2pdtens.F90 rename utils/{prlevel.F90 => prgrib2.F90} (76%) delete mode 100644 utils/prvtime.F90 delete mode 100644 utils/putgbexn.F90 delete mode 100644 utils/setbit.F90 diff --git a/test_utils/CMakeLists.txt b/test_utils/CMakeLists.txt index 168e5fa83..2f35ca9b1 100644 --- a/test_utils/CMakeLists.txt +++ b/test_utils/CMakeLists.txt @@ -5,8 +5,7 @@ if(BUILD_4) # This fortran test is for the internals of degrib2. - add_executable(test_degrib2_int test_degrib2_int.F90 ${CMAKE_SOURCE_DIR}/utils/prlevel.F90 - ${CMAKE_SOURCE_DIR}/utils/prvtime.F90) + add_executable(test_degrib2_int test_degrib2_int.F90 ${CMAKE_SOURCE_DIR}/utils/prgrib2.F90) target_link_libraries(test_degrib2_int PUBLIC ${PROJECT_NAME}_4) add_test(NAME test_degrib2_int COMMAND test_degrib2_int) endif() diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index b18bc4441..c68d607ae 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -31,14 +31,12 @@ if (BUILD_D) endif() if (BUILD_4) - add_executable(cnvgrib cnv12.F90 cnv22.F90 gds2gdt.F90 makepdsens.F90 - pds2pdtens.F90 putgbexn.F90 cnv21.F90 cnvgrib.F90 gdt2gds.F90 - makepds.F90 pds2pdt.F90 setbit.F90) + add_executable(cnvgrib cnv12.F90 cnv22.F90 cnv21.F90 cnvgrib.F90) target_link_libraries(cnvgrib PUBLIC ${PROJECT_NAME}_4) target_link_libraries(cnvgrib PRIVATE bacio::bacio w3emc::w3emc_4 ${JASPER_LIBRARIES} PNG::PNG ${ZLIB_LIBRARY}) - add_executable(degrib2 degrib2.F90 prlevel.F90 prvtime.F90) + add_executable(degrib2 prgrib2.F90 degrib2.F90) target_link_libraries(degrib2 PUBLIC ${PROJECT_NAME}_4) target_link_libraries(degrib2 PRIVATE bacio::bacio w3emc::w3emc_4 ${JASPER_LIBRARIES} PNG::PNG ${ZLIB_LIBRARY}) diff --git a/utils/cnv12.F90 b/utils/cnv12.F90 index 80dd8304d..69302e41e 100644 --- a/utils/cnv12.F90 +++ b/utils/cnv12.F90 @@ -367,3 +367,1512 @@ subroutine cnv12(ifl1, ifl2, ipack, usemiss, imiss, uvvect, table_ver) return end subroutine cnv12 + +!> This routine converts a GRIB1 GDS (in format specfied in +!> w3fi63.f) to necessary info for a GRIB2 Grid Definition Section. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-17 | Gilbert | Initial. +!> 2004-04-27 | Gilbert | Added support for Gaussian grids. +!> 2007-04-16 | Vuong | Added Curvilinear Orthogonal grids. +!> 2007-05-29 | Vuong | Added Rotate Lat/Lon E-grid (203) +!> 2010-05-10 | Vuong | Added Rotate Lat/Lon for Non-E Stagger grid (205) +!> 2011-05-04 | Vuong | Corrected Arakawa Lat/Lon of grid points for Non-E Stagger grid (205) +!> +!> @param[in] kgds GRIB1 GDS info as returned by w3fi63.f. +!> @param[out] igds Contains information read from the appropriate GRIB +!> Grid Definition Section 3 for the field being returned. Must be +!> dimensioned >= 5. +!> - igds(1) Source of grid definition (see Code Table 3.0) +!> - igds(2) Number of grid points in the defined grid. +!> - igds(3) Number of octets needed for each additional grid points +!> definition. Used to define number of points in each row (or column) +!> for non-regular grids. = 0, if using regular grid. +!> - igds(4) Interpretation of list for optional points definition. (Code Table 3.11) +!> - igds(5) Grid Definition Template Number (Code Table 3.1) +!> @param[out] igdstmpl Grid Definition Template values for GDT 3.igds(5) +!> @param[out] idefnum The number of entries in array +!> ideflist. i.e. number of rows (or columns) for which optional grid +!> points are defined. +!> @param[out] ideflist Optional integer array containing the number of +!> grid points contained in each row (or column). +!> @param[out] iret Error return value: +!> - 0 Successful +!> - 1 Unrecognized GRIB1 grid data representation type +!> +!> @author Stephen Gilbert @date 2003-06-17 +subroutine gds2gdt(kgds,igds,igdstmpl,idefnum,ideflist,iret) + + integer,intent(in) :: kgds(*) + integer,intent(out) :: igds(*),igdstmpl(*),ideflist(*) + integer,intent(out) :: idefnum,iret + + iret=0 + if (kgds(1).eq.0) then ! Lat/Lon grid + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=0 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) !Ni + igdstmpl(9)=kgds(3) !Nj + igdstmpl(10)=0 + igdstmpl(11)=0 + igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point + if (kgds(5).lt.0) then ! Lon of 1st grid point + igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E + else + igdstmpl(13)=kgds(5)*1000 + endif + igdstmpl(14)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(14)=48 + if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 + igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point + if (kgds(8).lt.0) then ! Lon of last grid point + igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E + else + igdstmpl(16)=kgds(8)*1000 + endif + igdstmpl(17)=kgds(9)*1000 ! Di + igdstmpl(18)=kgds(10)*1000 ! Dj + igdstmpl(19)=kgds(11) ! Scanning mode + if (kgds(20).ne.255) then ! irregular grid (eg WAFS) + igds(2)=kgds(21) ! num of grid points + !idefnum=kgds(19) + if (kgds(2).eq.65535) idefnum=kgds(3) + if (kgds(3).eq.65535) idefnum=kgds(2) + imax=0 + do j=1,idefnum + ideflist(j)=kgds(21+j) + if (ideflist(j).gt.imax) imax=ideflist(j) + enddo + igds(3)=1 ! octets for further grid definition + if (imax.gt.255) igds(3)=2 + if (imax.gt.65535) igds(3)=3 + if (imax.gt.16777215) igds(3)=4 + igds(4)=1 ! interpretation of optional list + igdstmpl(8)=-1 + igdstmpl(17)=-1 + endif + elseif (kgds(1).eq.1) then ! Mercator grid + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=10 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) ! Ni + igdstmpl(9)=kgds(3) ! Nj + igdstmpl(10)=kgds(4)*1000 ! Lat of 1st grid point + if (kgds(5).lt.0) then ! Lon of 1st grid point + igdstmpl(11)=(360000+kgds(5))*1000 ! convert W to E + else + igdstmpl(11)=kgds(5)*1000 + endif + igdstmpl(12)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(12)=48 + if (btest(kgds(6),3)) igdstmpl(12)=igdstmpl(12)+8 + igdstmpl(13)=kgds(9)*1000 ! Lat intersects earth + igdstmpl(14)=kgds(7)*1000 ! Lat of last grid point + if (kgds(8).lt.0) then ! Lon of last grid point + igdstmpl(15)=(360000+kgds(8))*1000 ! convert W to E + else + igdstmpl(15)=kgds(8)*1000 + endif + igdstmpl(16)=kgds(11) ! Scanning mode + igdstmpl(17)=0 ! Orientation of grid + igdstmpl(18)=kgds(12)*1000 ! Di + igdstmpl(19)=kgds(13)*1000 ! Dj + elseif (kgds(1).eq.3) then ! Lambert Conformal Grid + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=30 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) ! Nx + igdstmpl(9)=kgds(3) ! Ny + igdstmpl(10)=kgds(4)*1000 ! Lat of 1st grid point + if (kgds(5).lt.0) then ! Lon of 1st grid point + igdstmpl(11)=(360000+kgds(5))*1000 ! convert W to E + else + igdstmpl(11)=kgds(5)*1000 + endif + igdstmpl(12)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(12)=48 + if (btest(kgds(6),3)) igdstmpl(12)=igdstmpl(12)+8 + igdstmpl(13)=kgds(12)*1000 ! Lat where Dx and Dy specified + if (kgds(7).lt.0) then ! Lon of orientation + igdstmpl(14)=(360000+kgds(7))*1000 ! convert W to E + else + igdstmpl(14)=kgds(7)*1000 + endif + igdstmpl(15)=kgds(8)*1000 ! Dx + igdstmpl(16)=kgds(9)*1000 ! Dy + igdstmpl(17)=kgds(10) ! Projection Center Flag + igdstmpl(18)=kgds(11) ! Scanning mode + igdstmpl(19)=kgds(12)*1000 ! Latin 1 + igdstmpl(20)=kgds(13)*1000 ! Latin 2 + igdstmpl(21)=kgds(14)*1000 ! Lat of S. Pole of projection + if (kgds(15).lt.0) then ! Lon of S. Pole of projection + igdstmpl(22)=(360000+kgds(15))*1000 ! convert W to E + else + igdstmpl(22)=kgds(15)*1000 + endif + elseif (kgds(1).eq.4) then ! Gaussian Lat/Lon grid + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=40 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) !Ni + igdstmpl(9)=kgds(3) !Nj + igdstmpl(10)=0 + igdstmpl(11)=0 + igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point + if (kgds(5).lt.0) then ! Lon of 1st grid point + igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E + else + igdstmpl(13)=kgds(5)*1000 + endif + igdstmpl(14)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(14)=48 + if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 + igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point + if (kgds(8).lt.0) then ! Lon of last grid point + igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E + else + igdstmpl(16)=kgds(8)*1000 + endif + igdstmpl(17)=kgds(9)*1000 ! Di + igdstmpl(18)=kgds(10) ! D - Number of parallels + igdstmpl(19)=kgds(11) ! Scanning mode + elseif (kgds(1).eq.5) then ! Polar Stereographic Grid + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=20 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) ! Nx + igdstmpl(9)=kgds(3) ! Ny + igdstmpl(10)=kgds(4)*1000 ! Lat of 1st grid point + if (kgds(5).lt.0) then ! Lon of 1st grid point + igdstmpl(11)=(360000+kgds(5))*1000 ! convert W to E + else + igdstmpl(11)=kgds(5)*1000 + endif + igdstmpl(12)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(12)=48 + if (btest(kgds(6),3)) igdstmpl(12)=igdstmpl(12)+8 + igdstmpl(13)=60000000 ! Lat where Dx and Dy specified + if (btest(kgds(10),7)) igdstmpl(13)=-60000000 + if (kgds(7).lt.0) then ! Lon of orientation + igdstmpl(14)=(360000+kgds(7))*1000 ! convert W to E + else + igdstmpl(14)=kgds(7)*1000 + endif + igdstmpl(15)=kgds(8)*1000 ! Dx + igdstmpl(16)=kgds(9)*1000 ! Dy + igdstmpl(17)=kgds(10) ! Projection Center Flag + igdstmpl(18)=kgds(11) ! Scanning mode + elseif (kgds(1).eq.204) then ! Curivilinear Orthogonal Grid (Used by RTOFS) + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=204 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) !Ni - No of points along x-grid direction + igdstmpl(9)=kgds(3) !Nj - No of points along y-grid direction + igdstmpl(10)=0 + igdstmpl(11)=0 + igdstmpl(12)=0 + igdstmpl(13)=0 + igdstmpl(14)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(14)=48 + if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 + igdstmpl(15)=0 + igdstmpl(16)=0 + igdstmpl(17)=0 + igdstmpl(18)=0 + igdstmpl(19)=kgds(11) ! Scanning mode + elseif (kgds(1).eq.203) then ! Rot Lat/Lon grid (Arakawa) + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=32768 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) !Ni + igdstmpl(9)=kgds(3) !Nj + igdstmpl(10)=0 + igdstmpl(11)=0 + igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point + if (kgds(5).lt.0) then ! Lon of 1st grid point + igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E + else + igdstmpl(13)=kgds(5)*1000 + endif + igdstmpl(14)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(14)=48 + if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 + igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point + if (kgds(8).lt.0) then ! Lon of last grid point + igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E + else + igdstmpl(16)=kgds(8)*1000 + endif + igdstmpl(17)=kgds(9)*1000 ! Di + igdstmpl(18)=kgds(10)*1000 ! Dj + igdstmpl(19)=kgds(11) ! Scanning mode + elseif (kgds(1).eq.205) then ! Rot Lat/Lon for Non-E Stagger grid (Arakawa) + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=32769 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) !Ni + igdstmpl(9)=kgds(3) !Nj + igdstmpl(10)=0 + igdstmpl(11)=0 + igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point + if (kgds(5).lt.0) then ! Lon of 1st grid point + igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E + else + igdstmpl(13)=kgds(5)*1000 + endif + igdstmpl(14)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(14)=48 + if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 + igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point + if (kgds(8).lt.0) then ! Lon of last grid point + igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E + else + igdstmpl(16)=kgds(8)*1000 + endif + igdstmpl(17)=kgds(9)*1000 ! Di + igdstmpl(18)=kgds(10)*1000 ! Dj + igdstmpl(19)=kgds(11) ! Scanning mode + igdstmpl(20)=kgds(12)*1000 + igdstmpl(21)=kgds(13)*1000 + else + Print *,'gds2gdt: Unrecognized GRIB1 Grid type = ',kgds(1) + iret=1 + endif + return +end subroutine gds2gdt + +!> This routine converts a GRIB1 PDS (Section 1) info to a GRIB2 PDS +!> (Section 4) info with appropriate Product Definition Template. +!> +!> @note Use pds2pdtens for ensemble related PDS. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-12 | Gilbert | Initial. +!> 2005-04-19 | Gilbert | Changed scaling factor used with potential vorticity surfaces. +!> 2007-02-07 | Gilbert | fixed end date calculation +!> 2007-03-26 | Gordon | Added check for ECMWF data to reference ECMWF Conversion tables. +!> 2007-05-14 | Boi Vuong | Added Time Range Indicator 51 (Climatological Mean Value) +!> 2009-05-20 | Boi Vuong | Added check for WAFS to use PDT 4.8 for Max Wind +!> 2009-12-14 | Boi Vuong | Added check for WAFS to use PDT 4.15 for Icing, Turbulence and Cumulonimbus +!> 2010-02-18 | Boi Vuong | Added Time Range Indicator 7 +!> 2010-08-10 | Boi Vuong | Removed check for WAFS to use PDT 4.8 for Max Wind +!> 2011-10-24 | Boi Vuong | Added check for parameters (MAXUW, MAXVW, to set type of statistical processing (MIN and MAX) +!> +!> @param[in] kpds GRIB1 PDS info as specified in W3FI63. +!> @param[out] ipdsnum GRIB2 Product Definition Template Number +!> @param[out] ipdstmpl GRIB2 Product Definition Template entries for PDT 4.ipdsnum +!> @param[out] numcoord number of vertical discretisation values (not implemented) +!> @param[out] coordlist rtical discretisation values (not implemented) +!> @param[out] iret Error return value: +!> - 0 Successful +!> - 1 Unrecognized GRIB1 Time Range Indicator +!> +!> @author Stephen Gilbert @date 2003-06-12 +subroutine pds2pdt(kpds,ipdsnum,ipdstmpl,numcoord,coordlist, & + iret) + + use params + use params_ecmwf + + integer,intent(in) :: kpds(*) + integer,intent(out) :: ipdstmpl(*) + real,intent(out) :: coordlist(*) + integer,intent(out) :: ipdsnum,numcoord,iret + + integer :: idat(8),jdat(8) + real :: rinc(5) + logical :: ecmwf + + iret=0 + numcoord=0 + ecmwf=.false. + + if (kpds(1).eq.98) ecmwf=.true. + ! + ! Special check for WAFS products for parameters (Max Icing, TP and CAT) + ! to PDT 4.15 + ! + if ((kpds(2).eq.96 .AND. kpds(3).eq.45 .AND. & + kpds(16).eq.10) .AND. & + (kpds(19).eq.140 .AND. (kpds(5).ge.168 .AND. & + kpds(5).le.173))) then + ipdsnum=15 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + if (ecmwf) then ! treat ecmwf data conversion seperately + call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & + ipdstmpl(1),ipdstmpl(2)) + else + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + endif + ipdstmpl(3)=2 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + if (kpds(5).eq.168.or.kpds(5).eq.170.or. & ! statistical process WAFS-ICAO + kpds(5).eq.172) ipdstmpl(16)=0 ! for Mean Icing, CT, CAT + if (kpds(5).eq.169.or.kpds(5).eq.171.or. & ! statistical process WAFS-ICAO + kpds(5).eq.173) ipdstmpl(16)=2 ! for MAX Icing, CT, CAT + ipdstmpl(17)=3 ! Neighbor interpolation + ! Output values is set to nearest input values + ipdstmpl(18)=1 ! Number of data point (grid 45) + elseif (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then + ipdsnum=0 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + if (ecmwf) then ! treat ecmwf data conversion seperately + call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & + ipdstmpl(1),ipdstmpl(2)) + else + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + endif + if (kpds(16).eq.1) then + ipdstmpl(3)=0 + else + ipdstmpl(3)=2 + endif + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + !if (kpds(16).eq.10) then + ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) + !else + ipdstmpl(9)=kpds(14) + !endif + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + if (kpds(2).eq.96 .AND. kpds(3).eq.45 .AND. & + kpds(16).eq.10) then + if (kpds(5).eq.174) ipdstmpl(10) = 10 + if (kpds(5).eq.179) ipdstmpl(10) = 11 + if (kpds(5).eq.180) ipdstmpl(10) = 12 + end if + elseif (kpds(16).ge.2.AND.kpds(16).le.5) then + ipdsnum=8 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + if (ecmwf) then ! treat ecmwf data conversion seperately + call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & + ipdstmpl(1),ipdstmpl(2)) + else + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + endif + ipdstmpl(3)=2 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0.0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(16)=jdat(1) ! year of end time + ipdstmpl(17)=jdat(2) ! month of end time + ipdstmpl(18)=jdat(3) ! day of end time + ipdstmpl(19)=jdat(5) ! hour of end time + ipdstmpl(20)=jdat(6) ! minute of end time + ipdstmpl(21)=jdat(7) ! second of end time + ipdstmpl(22)=1 ! # of time ranges + ipdstmpl(23)=kpds(20) ! # of values missing + if (kpds(16).eq.2) then ! statistical process + ipdstmpl(24)=255 + elseif (kpds(16).eq.3) then + ipdstmpl(24)=0 + elseif (kpds(16).eq.4) then + ipdstmpl(24)=1 + elseif (kpds(16).eq.5) then + ipdstmpl(24)=4 + endif + ipdstmpl(25)=2 + if (kpds(19).eq.129 .AND. & + (kpds(5).eq.235 .or. kpds(5).eq.236 .or. & + kpds(5).eq.237 .or. kpds(5).eq.238 .or. & + kpds(5).eq.239 .or. kpds(5).eq.253 .or. & + kpds(5).eq.254 )) then + ipdstmpl(24)=2 + endif + ipdstmpl(26)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(26)=13 + ipdstmpl(27)=kpds(15)-kpds(14) + ipdstmpl(28)=255 + ipdstmpl(29)=0 + elseif (kpds(16).eq.7) then + ipdsnum=8 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + if (ecmwf) then ! treat ecmwf data conversion seperately + call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & + ipdstmpl(1),ipdstmpl(2)) + else + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + endif + ipdstmpl(3)=2 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)= - kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0.0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(16)=jdat(1) ! year of end time + ipdstmpl(17)=jdat(2) ! month of end time + ipdstmpl(18)=jdat(3) ! day of end time + ipdstmpl(19)=jdat(5) ! hour of end time + ipdstmpl(20)=jdat(6) ! minute of end time + ipdstmpl(21)=jdat(7) ! second of end time + ipdstmpl(22)=1 ! # of time ranges + ipdstmpl(23)=kpds(20) ! # of values missing + ipdstmpl(24)=0 + ipdstmpl(25)=2 + ipdstmpl(26)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(26)=13 + ipdstmpl(27)=kpds(15) + kpds(14) + ipdstmpl(28)=255 + ipdstmpl(29)=0 + elseif (kpds(16).eq.51) then + ipdsnum=8 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + if (ecmwf) then ! treat ecmwf data conversion seperately + call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & + ipdstmpl(1),ipdstmpl(2)) + else + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + endif + ipdstmpl(3)=2 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0.0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(16)=jdat(1) ! year of end time + ipdstmpl(17)=jdat(2) ! month of end time + ipdstmpl(18)=jdat(3) ! day of end time + ipdstmpl(19)=jdat(5) ! hour of end time + ipdstmpl(20)=jdat(6) ! minute of end time + ipdstmpl(21)=jdat(7) ! second of end time + ipdstmpl(22)=1 ! # of time ranges + ipdstmpl(23)=kpds(20) ! # of values missing + ipdstmpl(24)=51 ! Climatological Mean + ipdstmpl(25)=2 + ipdstmpl(26)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(26)=13 + ipdstmpl(27)=kpds(15)-kpds(14) + ipdstmpl(28)=255 + ipdstmpl(29)=0 + else + Print *,' Unrecognized Time Range Indicator = ',kpds(16) + Print *,'pds2pdt: Couldn:t construct PDS Template ' + iret=1 + endif + + return +end subroutine pds2pdt + +!> This routine converts a GRIB1 Level type and Level value to GRIB2 +!> values and fills in the appropriate PDT values for the level/layer +!> information. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-12 | Gilbert | Initial. +!> 2011-01-13 | Boi Vuong | Added level/layer values from 235 to 239 +!> +!> @param[in] ltype GRIB1 level type (PDS octet 10) +!> @param[in] lval GRIB1 level/layer value(s) (PDS octets 11 and 12) +!> @param[out] ipdstmpl GRIB2 Product Definition Template values. +!> +!> @author Stephen Gilbert @date 2003-06-12 +subroutine cnvlevel(ltype,lval,ipdstmpl) + + integer,intent(in) :: ltype,lval + integer,intent(inout) :: ipdstmpl(*) + + ipdstmpl(10)=ltype + ipdstmpl(11)=0 + ipdstmpl(12)=0 + ipdstmpl(13)=255 + ipdstmpl(14)=0 + ipdstmpl(15)=0 + + if (ltype.eq.100) then + ipdstmpl(12)=lval*100 + elseif (ltype.eq.101) then + ipdstmpl(10)=100 + ipdstmpl(12)=(lval/256)*1000 + ipdstmpl(13)=100 + ipdstmpl(15)=mod(lval,256)*1000 + elseif (ltype.eq.102) then + ipdstmpl(10)=101 + elseif (ltype.eq.103) then + ipdstmpl(10)=102 + ipdstmpl(12)=lval + elseif (ltype.eq.104) then + ipdstmpl(10)=102 + ipdstmpl(12)=lval/256 + ipdstmpl(13)=102 + ipdstmpl(15)=mod(lval,256) + elseif (ltype.eq.105) then + ipdstmpl(10)=103 + ipdstmpl(12)=lval + elseif (ltype.eq.106) then + ipdstmpl(10)=103 + ipdstmpl(12)=(lval/256)*100 + ipdstmpl(13)=103 + ipdstmpl(15)=mod(lval,256)*100 + elseif (ltype.eq.107) then + ipdstmpl(10)=104 + ipdstmpl(11)=4 + ipdstmpl(12)=lval + elseif (ltype.eq.108) then + ipdstmpl(10)=104 + ipdstmpl(11)=2 + ipdstmpl(12)=lval/256 + ipdstmpl(13)=104 + ipdstmpl(14)=2 + ipdstmpl(15)=mod(lval,256) + elseif (ltype.eq.109) then + ipdstmpl(10)=105 + ipdstmpl(12)=lval + elseif (ltype.eq.110) then + ipdstmpl(10)=105 + ipdstmpl(12)=lval/256 + ipdstmpl(13)=105 + ipdstmpl(15)=mod(lval,256) + elseif (ltype.eq.111) then + ipdstmpl(10)=106 + ipdstmpl(11)=2 + ipdstmpl(12)=lval + elseif (ltype.eq.112) then + ipdstmpl(10)=106 + ipdstmpl(11)=2 + ipdstmpl(12)=lval/256 + ipdstmpl(13)=106 + ipdstmpl(14)=2 + ipdstmpl(15)=mod(lval,256) + elseif (ltype.eq.113) then + ipdstmpl(10)=107 + ipdstmpl(12)=lval + elseif (ltype.eq.114) then + ipdstmpl(10)=107 + ipdstmpl(12)=475+(lval/256) + ipdstmpl(13)=107 + ipdstmpl(15)=475+mod(lval,256) + elseif (ltype.eq.115) then + ipdstmpl(10)=108 + ipdstmpl(12)=lval*100 + elseif (ltype.eq.116) then + ipdstmpl(10)=108 + ipdstmpl(12)=(lval/256)*100 + ipdstmpl(13)=108 + ipdstmpl(15)=mod(lval,256)*100 + elseif (ltype.eq.117) then + ipdstmpl(10)=109 + ipdstmpl(11)=9 + ipdstmpl(12)=lval + if ( btest(lval,15) ) then + ipdstmpl(12)=-1*mod(lval,32768) + endif + elseif (ltype.eq.119) then + ipdstmpl(10)=111 + ipdstmpl(11)=4 + ipdstmpl(12)=lval + elseif (ltype.eq.120) then + ipdstmpl(10)=111 + ipdstmpl(11)=2 + ipdstmpl(12)=lval/256 + ipdstmpl(13)=111 + ipdstmpl(14)=2 + ipdstmpl(15)=mod(lval,256) + elseif (ltype.eq.121) then + ipdstmpl(10)=100 + ipdstmpl(12)=(1100+(lval/256))*100 + ipdstmpl(13)=100 + ipdstmpl(15)=(1100+mod(lval,256))*100 + elseif (ltype.eq.125) then + ipdstmpl(10)=103 + ipdstmpl(11)=2 + ipdstmpl(12)=lval + elseif (ltype.eq.126) then + ipdstmpl(10)=100 + ipdstmpl(12)=lval + elseif (ltype.eq.128) then + ipdstmpl(10)=104 + ipdstmpl(11)=3 + ipdstmpl(12)=1100+(lval/256) + ipdstmpl(13)=104 + ipdstmpl(14)=3 + ipdstmpl(15)=1100+mod(lval,256) + elseif (ltype.eq.141) then + ipdstmpl(10)=100 + ipdstmpl(12)=(lval/256)*100 + ipdstmpl(13)=100 + ipdstmpl(15)=(1100+mod(lval,256))*100 + elseif (ltype.eq.160) then + ipdstmpl(10)=160 + ipdstmpl(12)=lval + elseif (ltype.gt.99.AND.ltype.lt.200) then + print *,'cnvlevel: GRIB1 Level ',ltype,' not recognized.' + ipdstmpl(10)=255 + elseif (ltype.eq.235) then + ipdstmpl(10)=ltype + ipdstmpl(12)=lval + elseif (ltype.eq.236) then + ipdstmpl(10)=ltype + ipdstmpl(12)=lval/256 + ipdstmpl(13)=ltype + ipdstmpl(15)=mod(lval,256) + elseif (ltype.ge.237.AND.ltype.le.239) then + ipdstmpl(10)=ltype + ipdstmpl(12)=lval + endif + + return +end subroutine cnvlevel + +!> This routine converts a GRIB1 PDS (Section 1) that includes NCEP +!> ensemble PDS extensions to a GRIB2 PDS (Section 4) info with +!> appropriate Product Definition Template. +!> +!> @note Use routine pds2pdt for non ensemble related PDS. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-12 | Gilbert | Initial. +!> 2007-02-07 | Gilbert | fixed end date calculation +!> 2007-05-14 | Boi Vuong | Added Time Range Indicator 51 (Climatological Mean Value) +!> +!> @param[in] kpds GRIB1 PDS info as specified in W3FI63. +!> @param[in] kens Ensemble identification from PDS octets 41-45. +!> @param[in] kprob Ensemble probability info from PDS octets 46 & 47. +!> @param[in] xprob Ensemble probability info from PDS octets 48-55. +!> @param[in] kclust Ensemble cluster info from PDS octets 61-76. +!> @param[in] kmember- semble membership info from PDS octest 77-86. +!> @param[out] ipdsnum GRIB2 Product Definition Template Number. +!> @param[out] ipdstmpl GRIB2 Product Definition Template entries for PDT 4.ipdsnum. +!> @param[out] numcoord number of vertical discretisation values (not implemented). +!> @param[out] coordlist- rtical discretisation values (not implemented). +!> @param[out] iret Error return value: +!> - 0 = Successful +!> - 1 = Unrecognized GRIB1 Time Range Indicator for ensembles +!> - 2 = Unrecognized GRIB1 Ensemble type +!> - 10 = Unrecognized GRIB1 Time Range Indicator for probabilities +!> +!> @author Stephen Gilbert @date 2003-06-12 +subroutine pds2pdtens(kpds,kens,kprob,xprob,kclust,kmember, & + ipdsnum,ipdstmpl,numcoord,coordlist, & + iret) + + use params + + integer,intent(in) :: kpds(*),kens(*),kprob(*),kclust(*) + integer,intent(in) :: kmember(*) + real,intent(in) :: xprob(*) + integer,intent(out) :: ipdstmpl(*) + real,intent(out) :: coordlist(*) + integer,intent(out) :: ipdsnum,numcoord,iret + + integer :: idat(8),jdat(8) + real :: rinc(5) + + iret=0 + numcoord=0 + if (kens(2).eq.1.or.kens(2).eq.2.or.kens(2).eq.3) then + ! individual ensemble fcst... + if (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then + ! At specific point in time... + ipdsnum=1 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=4 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + !if (kpds(16).eq.10) then + ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) + !else + ipdstmpl(9)=kpds(14) + !endif + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + if (kens(2).eq.1) then + ! if (kens(3).eq.1) ipdstmpl(16)=0 + ! if (kens(3).eq.2) ipdstmpl(16)=1 + ipdstmpl(16)=kens(3)-1 + ipdstmpl(17)=0 + elseif (kens(2).eq.2) then + ipdstmpl(16)=2 + ipdstmpl(17)=kens(3) + elseif (kens(2).eq.3) then + ipdstmpl(16)=3 + ipdstmpl(17)=kens(3) + endif + ipdstmpl(18)=10 + elseif (kpds(16).ge.2.AND.kpds(16).le.5) then + ! over time range... + ipdsnum=11 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=4 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + !ipdstmpl(9)=kpds(15) + if (kens(2).eq.1) then + ! if (kens(3).eq.1) ipdstmpl(16)=0 + ! if (kens(3).eq.2) ipdstmpl(16)=1 + ipdstmpl(16)=kens(3)-1 + ipdstmpl(17)=0 + elseif (kens(2).eq.2) then + ipdstmpl(16)=2 + ipdstmpl(17)=kens(3) + elseif (kens(2).eq.3) then + ipdstmpl(16)=3 + ipdstmpl(17)=kens(3) + endif + ipdstmpl(18)=10 + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(19)=jdat(1) ! year of end time + ipdstmpl(20)=jdat(2) ! month of end time + ipdstmpl(21)=jdat(3) ! day of end time + ipdstmpl(22)=jdat(5) ! hour of end time + ipdstmpl(23)=jdat(6) ! minute of end time + ipdstmpl(24)=jdat(7) ! second of end time + ipdstmpl(25)=1 + ipdstmpl(26)=0 + if (kpds(16).eq.2) then + ipdstmpl(27)=255 + if (kpds(5).eq.15) ipdstmpl(27)=2 + if (kpds(5).eq.16) ipdstmpl(27)=3 + elseif (kpds(16).eq.3) then + ipdstmpl(27)=0 + elseif (kpds(16).eq.4) then + ipdstmpl(27)=1 + elseif (kpds(16).eq.5) then + ipdstmpl(27)=4 + endif + ipdstmpl(28)=2 + ipdstmpl(29)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(29)=13 + ipdstmpl(30)=kpds(15)-kpds(14) + ipdstmpl(31)=255 + ipdstmpl(32)=0 + elseif (kpds(16).eq.51) then + ! over time range... + ipdsnum=11 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=4 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + !ipdstmpl(9)=kpds(15) + if (kens(2).eq.1) then + ! if (kens(3).eq.1) ipdstmpl(16)=0 + ! if (kens(3).eq.2) ipdstmpl(16)=1 + ipdstmpl(16)=kens(3)-1 + ipdstmpl(17)=0 + elseif (kens(2).eq.2) then + ipdstmpl(16)=2 + ipdstmpl(17)=kens(3) + elseif (kens(2).eq.3) then + ipdstmpl(16)=3 + ipdstmpl(17)=kens(3) + endif + ipdstmpl(18)=10 + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(19)=jdat(1) ! year of end time + ipdstmpl(20)=jdat(2) ! month of end time + ipdstmpl(21)=jdat(3) ! day of end time + ipdstmpl(22)=jdat(5) ! hour of end time + ipdstmpl(23)=jdat(6) ! minute of end time + ipdstmpl(24)=jdat(7) ! second of end time + ipdstmpl(25)=1 + ipdstmpl(26)=0 + ipdstmpl(27)=51 + ipdstmpl(28)=2 + ipdstmpl(29)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(29)=13 + ipdstmpl(30)=kpds(15)-kpds(14) + ipdstmpl(31)=255 + ipdstmpl(32)=0 + else + Print *,' Unrecognized Time Range Ind for ensembles = ', & + kpds(16),kens(2) + Print *,'pds2pdtens: Couldn:t construct PDS Template ' + iret=1 + endif + + elseif (kens(2).eq.5) then ! WHOLE or CLUSTERENSEMBLE type + if (kpds(5).eq.191.OR.kpds(5).eq.192) then ! probs + if (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then + ! At specific point in time... + ipdsnum=5 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kprob(1),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=5 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + !if (kpds(16).eq.10) then + ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) + !else + ipdstmpl(9)=kpds(14) + !endif + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + ipdstmpl(16)=0 !? + ipdstmpl(17)=kclust(1) !? + ipdstmpl(18)=kprob(2)-1 + if (ipdstmpl(18).eq.0.OR.ipdstmpl(18).eq.2) then + ipdstmpl(19)=3 + ipdstmpl(20)=nint(xprob(1)*1000.0) + else + ipdstmpl(19)=0 + ipdstmpl(20)=0 + endif + if (ipdstmpl(18).eq.1.OR.ipdstmpl(18).eq.2) then + ipdstmpl(21)=3 + ipdstmpl(22)=nint(xprob(2)*1000.0) + else + ipdstmpl(21)=0 + ipdstmpl(22)=0 + endif + elseif (kpds(16).ge.2.AND.kpds(16).le.5) then + ! over time range... + ipdsnum=9 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kprob(1),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=5 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + !ipdstmpl(9)=kpds(15) + ipdstmpl(16)=0 !? + ipdstmpl(17)=kclust(1) !? + ipdstmpl(18)=kprob(2)-1 + if (ipdstmpl(18).eq.0.OR.ipdstmpl(18).eq.2) then + ipdstmpl(19)=3 + ipdstmpl(20)=nint(xprob(1)*1000.0) + else + ipdstmpl(19)=0 + ipdstmpl(20)=0 + endif + if (ipdstmpl(18).eq.1.OR.ipdstmpl(18).eq.2) then + ipdstmpl(21)=3 + ipdstmpl(22)=nint(xprob(2)*1000.0) + else + ipdstmpl(21)=0 + ipdstmpl(22)=0 + endif + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(23)=jdat(1) ! year of end time + ipdstmpl(24)=jdat(2) ! month of end time + ipdstmpl(25)=jdat(3) ! day of end time + ipdstmpl(26)=jdat(5) ! hour of end time + ipdstmpl(27)=jdat(6) ! minute of end time + ipdstmpl(28)=jdat(7) ! second of end time + ipdstmpl(29)=1 + ipdstmpl(30)=0 + if (kpds(16).eq.2) then + ipdstmpl(31)=255 + if (kpds(5).eq.15) ipdstmpl(31)=2 + if (kpds(5).eq.16) ipdstmpl(31)=3 + elseif (kpds(16).eq.3) then + ipdstmpl(31)=0 + elseif (kpds(16).eq.4) then + ipdstmpl(31)=1 + elseif (kpds(16).eq.5) then + ipdstmpl(31)=4 + endif + ipdstmpl(32)=2 + ipdstmpl(33)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(33)=13 + ipdstmpl(34)=kpds(15)-kpds(14) + ipdstmpl(35)=255 + ipdstmpl(36)=0 + elseif (kpds(16).eq.51) then + ! over time range... + ipdsnum=9 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kprob(1),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=5 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + !ipdstmpl(9)=kpds(15) + ipdstmpl(16)=0 !? + ipdstmpl(17)=kclust(1) !? + ipdstmpl(18)=kprob(2)-1 + if (ipdstmpl(18).eq.0.OR.ipdstmpl(18).eq.2) then + ipdstmpl(19)=3 + ipdstmpl(20)=nint(xprob(1)*1000.0) + else + ipdstmpl(19)=0 + ipdstmpl(20)=0 + endif + if (ipdstmpl(18).eq.1.OR.ipdstmpl(18).eq.2) then + ipdstmpl(21)=3 + ipdstmpl(22)=nint(xprob(2)*1000.0) + else + ipdstmpl(21)=0 + ipdstmpl(22)=0 + endif + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(23)=jdat(1) ! year of end time + ipdstmpl(24)=jdat(2) ! month of end time + ipdstmpl(25)=jdat(3) ! day of end time + ipdstmpl(26)=jdat(5) ! hour of end time + ipdstmpl(27)=jdat(6) ! minute of end time + ipdstmpl(28)=jdat(7) ! second of end time + ipdstmpl(29)=1 + ipdstmpl(30)=0 + ipdstmpl(31)=51 + ipdstmpl(32)=2 + ipdstmpl(33)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(33)=13 + ipdstmpl(34)=kpds(15)-kpds(14) + ipdstmpl(35)=255 + ipdstmpl(36)=0 + else + Print *,' Unrecognized Time Range Ind for Probs = ', & + kpds(16),kens(2) + Print *,'pds2pdtens: Couldn:t construct PDS Template ' + iret=10 + endif + else ! Non-probablility Whole Ens Fcst + if (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then + ! At specific point in time... + ipdsnum=2 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=4 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + !if (kpds(16).eq.10) then + ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) + !else + ipdstmpl(9)=kpds(14) + !endif + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + if (kens(4).eq.1) then + ipdstmpl(16)=0 + elseif (kens(4).eq.2) then + ipdstmpl(16)=1 + elseif (kens(4).eq.11) then + ipdstmpl(16)=2 + elseif (kens(4).eq.12) then + ipdstmpl(16)=3 + endif + ipdstmpl(17)=kclust(1) + elseif (kpds(16).ge.2.AND.kpds(16).le.5) then + ! over time range... + ipdsnum=12 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=4 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + !ipdstmpl(9)=kpds(15) + if (kens(4).eq.1) then + ipdstmpl(16)=0 + elseif (kens(4).eq.2) then + ipdstmpl(16)=1 + elseif (kens(4).eq.11) then + ipdstmpl(16)=2 + elseif (kens(4).eq.12) then + ipdstmpl(16)=3 + endif + ipdstmpl(17)=kclust(1) + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(18)=jdat(1) ! year of end time + ipdstmpl(19)=jdat(2) ! month of end time + ipdstmpl(20)=jdat(3) ! day of end time + ipdstmpl(21)=jdat(5) ! hour of end time + ipdstmpl(22)=jdat(6) ! minute of end time + ipdstmpl(23)=jdat(7) ! second of end time + ipdstmpl(24)=1 + ipdstmpl(25)=0 + if (kpds(16).eq.2) then + ipdstmpl(26)=255 + if (kpds(5).eq.15) ipdstmpl(26)=2 + if (kpds(5).eq.16) ipdstmpl(26)=3 + elseif (kpds(16).eq.3) then + ipdstmpl(26)=0 + elseif (kpds(16).eq.4) then + ipdstmpl(26)=1 + elseif (kpds(16).eq.5) then + ipdstmpl(26)=4 + endif + ipdstmpl(27)=2 + ipdstmpl(28)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(28)=13 + ipdstmpl(29)=kpds(15)-kpds(14) + ipdstmpl(30)=255 + ipdstmpl(31)=0 + elseif (kpds(16).eq.51) then + ! over time range... + ipdsnum=12 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=4 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + !ipdstmpl(9)=kpds(15) + if (kens(4).eq.1) then + ipdstmpl(16)=0 + elseif (kens(4).eq.2) then + ipdstmpl(16)=1 + elseif (kens(4).eq.11) then + ipdstmpl(16)=2 + elseif (kens(4).eq.12) then + ipdstmpl(16)=3 + endif + ipdstmpl(17)=kclust(1) + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(18)=jdat(1) ! year of end time + ipdstmpl(19)=jdat(2) ! month of end time + ipdstmpl(20)=jdat(3) ! day of end time + ipdstmpl(21)=jdat(5) ! hour of end time + ipdstmpl(22)=jdat(6) ! minute of end time + ipdstmpl(23)=jdat(7) ! second of end time + ipdstmpl(24)=1 + ipdstmpl(25)=0 + ipdstmpl(26)=51 + ipdstmpl(27)=2 + ipdstmpl(28)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(28)=13 + ipdstmpl(29)=kpds(15)-kpds(14) + ipdstmpl(30)=255 + ipdstmpl(31)=0 + endif + endif + else + Print *,' Unrecognized Ensemble type = ',kens(2) + Print *,'pds2pdtens: Couldn:t construct PDS Template ' + iret=2 + endif + + return +end subroutine pds2pdtens diff --git a/utils/cnv21.F90 b/utils/cnv21.F90 index 96653ad74..ce2a811fc 100644 --- a/utils/cnv21.F90 +++ b/utils/cnv21.F90 @@ -190,3 +190,1338 @@ subroutine cnv21(ifl1,ifl2) return end subroutine cnv21 + +!> This routine creates a GRIB1 PDS (Section 1) from appropriate +!> information from a GRIB2 Product Definition Template. +!> +!> @note Use pds2pdtens for ensemble related PDS. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-12 | Gilbert | Initial. +!> 2005-04-19 | Gilbert | Changed scaling factor used with potential vorticity surfaces. +!> 2007-05-08 | VUONG | Add Product Definition Template entries 120-124, 131, 88, 45, 47. +!> 2007-05-14 | Boi Vuong | Added Time Range Indicator 51 (Climatological Mean Value) +!> 2007-10-24 | Boi Vuong | Added level 8 (Nominal top of atmosphere) +!> 2009-05-19 | Boi Vuong | Added levels 10(Entire Atmosphere), 11(Cumulonimbus Base),12(Cumulonimbus Top) and level 126(Isobaric Pa) +!> 2009-12-14 | Boi Vuong | Added check for WAFS to use PDT 4.15 for Icing, Turbulence and Cumulonimbus +!> 2010-08-10 | Boi Vuong | Added check for FNMOC to use TMP as TMAX and TMIN - Removed check WAFS MAX wind level +!> 2011-10-24 | Boi Vuong | Added check for NAM (NMM-B) parameters to set statistical processing as MAX and MIN +!> 2012-03-29 | Boi Vuong | Added check Time Range for APCP in FNMOC +!> 2014-05-20 | Boi Vuong | Added check Time Range after F252 +!> 2014-11-14 | Boi Vuong | Added check Time Range for 15-hr or 18-hr or 21-hr or 24-hr Accumulation for APCP after F240 +!> 2018-07-26 | Boi Vuong | Added check Time Range for continuous accumulated APCP after F252 when convert from grib2 to grib1 +!> +!> @param[in] idisc GRIB2 discipline from Section 0. +!> @param[in] idsect GRIB2 Section 1 info. +!> - idsect(1) Id of orginating centre (Common Code Table C-1) +!> - idsect(2) Id of orginating sub-centre (local table) +!> - idsect(3) GRIB Master Tables Version Number (Code Table 1.0) +!> - idsect(4) GRIB Local Tables Version Number (Code Table 1.1) +!> - idsect(5) Significance of Reference Time (Code Table 1.2) +!> - idsect(6) Reference Time - Year (4 digits) +!> - idsect(7) Reference Time - Month +!> - idsect(8) Reference Time - Day +!> - idsect(9) Reference Time - Hour +!> - idsect(10) Reference Time - Minute +!> - idsect(11) Reference Time - Second +!> - idsect(12) Production status of data (Code Table 1.3) +!> - idsect(13) Type of processed data (Code Table 1.4) +!> @param[in] ipdsnum GRIB2 Product Definition Template Number +!> @param[in] ipdstmpl GRIB2 Product Definition Template entries for PDT 4.ipdsnum +!> @param[in] ibmap GRIB2 bitmap indicator from octet 6, Section 6. +!> @param[in] idrsnum GRIB2 Data Representation Template Number +!> @param[in] idrstmpl GRIB2 Data Representation Template entries +!> @param[out] kpds GRIB1 PDS info as specified in W3FI63. +!> - 1 id of center +!> - 2 generating process id number +!> - 3 grid definition +!> - 4 gds/bms flag (right adj copy of octet 8) +!> - 5 indicator of parameter +!> - 6 type of level +!> - 7 height/pressure , etc of level +!> - 8 year including (century-1) +!> - 9 month of year +!> - 10 day of month +!> - 11 hour of day +!> - 12 minute of hour +!> - 13 indicator of forecast time unit +!> - 14 time range 1 +!> - 15 time range 2 +!> - 16 time range flag +!> - 17 number included in average +!> - 18 version nr of grib specification +!> - 19 version nr of parameter table +!> - 20 nr missing from average/accumulation +!> - 21 century of reference time of data +!> - 22 units decimal scale factor +!> - 23 subcenter number +!> @param[out] iret Error return value: +!> - 0 Successful +!> - 1 Don't know what to do with pre-defined bitmap. +!> - 2 Unrecognized GRIB2 PDT 4.ipdsnum +!> +!> @author Stephen Gilbert @date 2003-06-12 +subroutine makepds(idisc,idsect,ipdsnum,ipdstmpl,ibmap, & + idrsnum,idrstmpl,kpds,iret) + + use params + + integer,intent(in) :: idsect(*),ipdstmpl(*),idrstmpl(*) + integer,intent(in) :: ipdsnum,idisc,idrsnum,ibmap + integer,intent(out) :: kpds(*) + integer,intent(out) :: iret + + iret=0 + ipos=0 + kpds(1:24)=0 + if ( (ipdsnum.lt.0).OR.(ipdsnum.gt.15) ) then + print *,'makepds: Don:t know GRIB2 PDT 4.',ipdsnum + iret=2 + return + endif + + kpds(1)=idsect(1) + kpds(2)=ipdstmpl(5) + kpds(3)=255 + kpds(4)=128 + if ( ibmap.ne.255 ) kpds(4)=kpds(4)+64 + if ( ibmap.ge.1.AND.ibmap.le.253 ) then + print *,'makepds: Don:t know about predefined bit-map ',ibmap + iret=1 + return + endif + call param_g2_to_g1(idisc,ipdstmpl(1),ipdstmpl(2),kpds(5), & + kpds(19)) + ! + ! Special parameters for ICAO WAFS (Max Icing, TP and CAT) + ! + If (ipdstmpl(16).eq.2.and.ipdstmpl(1).eq.19.and. & + ipdstmpl(2).eq.20) kpds(5) = 169 + If (ipdstmpl(16).eq.2.and.ipdstmpl(1).eq.19.and. & + ipdstmpl(2).eq.21) kpds(5) = 171 + If (ipdstmpl(16).eq.2.and.ipdstmpl(1).eq.19.and. & + ipdstmpl(2).eq.22) kpds(5) = 173 + ! + ! Special parameters for NAM (NMMB) + ! + If (idisc.eq.0.and.ipdstmpl(1).eq.2) then + if (ipdstmpl(2).eq.220) then + kpds(5) = 237 + kpds(19) = 129 + end if + if (ipdstmpl(2).eq.221) then + kpds(5) = 238 + kpds(19) = 129 + end if + if (ipdstmpl(2).eq.222) then + kpds(5) = 253 + kpds(19) = 129 + end if + if (ipdstmpl(2).eq.223) then + kpds(5) = 254 + kpds(19) = 129 + end if + endif + ! + If (idisc.eq.0.and.ipdstmpl(2).eq.16 & + .and.ipdstmpl(3).eq.198) then + kpds(5) = 235 + kpds(19) = 129 + endif + ! + If (idisc.eq.0.and.ipdstmpl(2).eq.7 & + .and.ipdstmpl(3).eq.199) then + kpds(5) = 236 + kpds(19) = 129 + endif + ! + ! Special parameters for ICAO Height at CB Base and Top + ! in GRIB1 Table 140 + ! + If (ipdstmpl(1).eq.3.and.ipdstmpl(2).eq.3) then + If (ipdstmpl(10).eq.11) then + kpds(19) = 140 + kpds(5) = 179 + end if + If (ipdstmpl(10).eq.12) then + kpds(19) = 140 + kpds(5) = 180 + end if + end if + ! + call levelcnv(ipdstmpl,kpds(6),kpds(7)) ! level + kpds(8)=mod(idsect(6),100) + if ( kpds(8).eq.0 ) kpds(8)=100 + kpds(9)=idsect(7) ! Year + kpds(10)=idsect(8) ! Month + kpds(11)=idsect(9) ! Day + kpds(12)=idsect(10) ! Hour + if ( ipdstmpl(8).ne.13 ) then + kpds(13)=ipdstmpl(8) ! Time Unit + else + kpds(13)=254 + endif + kpds(14)=ipdstmpl(9) ! P1 + if ( ipdsnum.le.7 ) then ! P2 + kpds(15)=0 + kpds(16)=0 + kpds(20)=0 + if ( kpds(14).eq.0 ) kpds(16)=1 + if ( kpds(14).gt.255 ) kpds(16)=10 + if ( ipdstmpl(5).eq.77.OR.ipdstmpl(5).eq.81.OR. & + ipdstmpl(5).eq.96.OR.ipdstmpl(5).eq.80.OR. & + ipdstmpl(5).eq.82.OR.ipdstmpl(5).eq.120.OR. & + ipdstmpl(5).eq.47.OR.ipdstmpl(5).eq.11 ) then + kpds(16)=10 + end if + if (ipdstmpl(5).eq.84.AND.kpds(5).eq.154)kpds(16) = 10 + ! + ! NOAA Wave Watch III and Coastal Ocean Circulation + ! and Alaska Waters Regional Wave Model + ! + if ( ipdstmpl(5).eq.88.OR.ipdstmpl(5).eq.121 & + .OR.ipdstmpl(5).eq.122.OR.ipdstmpl(5).eq.123 & + .OR.ipdstmpl(5).eq.124.OR.ipdstmpl(5).eq.125 & + .OR.ipdstmpl(5).eq.131.OR.ipdstmpl(5).eq.45 & + .OR.ipdstmpl(5).eq.11 ) then + kpds(16) = 0 + ! + ! Level Surface set to 1 + ! + if (kpds(5).eq.80.OR.kpds(5).eq.82.OR. & + kpds(5).eq.88.OR.kpds(5).eq.49.OR. & + kpds(5).eq.50) kpds(7)=1 ! Level Surface + if (ipdstmpl(5).eq.122.OR.ipdstmpl(5).eq.124.OR. & + ipdstmpl(5).eq.131.OR.ipdstmpl(5).eq.123.OR. & + ipdstmpl(5).eq.125.OR.ipdstmpl(5).eq.88.OR. & + ipdstmpl(5).eq.121) kpds(7)=1 + if (idsect(1).eq.54.AND.ipdstmpl(5).eq.45) kpds(16) = 10 + endif + else + selectcase (ipdsnum) + case(8) + ipos=24 + case(9) + ipos=31 + case(10) + ipos=25 + case(11) + ipos=27 + case(12) + ipos=26 + case(13) + ipos=40 + case(14) + ipos=39 + end select + kpds(15)=ipdstmpl(ipos+3)+kpds(14) ! P2 + selectcase (ipdstmpl(ipos)) + case (255) + kpds(16)=2 + case (0) + kpds(16)=3 + case (1) + kpds(16)=4 + case (2) + kpds(16)=2 + case (3) + kpds(16)=2 + case (4) + kpds(16)=5 + case (51) + kpds(16)=51 + end select + kpds(20)=ipdstmpl(ipos-1) + endif + if (ipdstmpl(9) .ge. 252) then + if (ipdstmpl(ipos+3).eq.3) then + kpds(13)= 10 ! Forecast time unit is 3-hour + kpds(14)=ipdstmpl(9)/3 ! Time range P1 + kpds(15)=ipdstmpl(ipos+3)/3+kpds(14) ! Time range P2 + else if (ipdstmpl(ipos+3).eq.6) then + kpds(13)= 11 ! Forecast time unit is 6-hour + kpds(14)=ipdstmpl(9)/6 ! Time range P1 + kpds(15)=ipdstmpl(ipos+3)/6+kpds(14) ! Time range P2 + else if (ipdstmpl(ipos+3).eq.12) then + kpds(13)= 12 ! Forecast time unit is 12-hour + kpds(14)=ipdstmpl(9)/12 ! Time range P1 + kpds(15)=ipdstmpl(ipos+3)/12+kpds(14) ! Time range P2 + end if + end if + if (ipdsnum .eq. 8 .AND. ipdstmpl(9) .eq. 0) then + if (ipdstmpl(ipos+3).ge.252) then + kpds(13)= 10 ! Forecast time unit is hour + kpds(14)=ipdstmpl(9)/3 ! Time range P1 + kpds(15)=ipdstmpl(ipos+3)/3+kpds(14) ! Time range P2 + end if + end if + ! + ! Checking total preciptation for 15-hr or 18-hr or 21-hr or 24-hr accumulation + ! after forecast hour F240 + ! + if (ipdstmpl(9) .ge. 240 )then + if ( ipdstmpl(ipos+3).eq.15 .OR. ipdstmpl(ipos+3).eq.18 & + .OR. ipdstmpl(ipos+3).eq.21 .OR. & + ipdstmpl(ipos+3).eq.24 ) then + kpds(13)= 10 ! Forecast time unit is 3-hour + kpds(14)=ipdstmpl(9)/3 ! Time range P1 + kpds(15)=ipdstmpl(ipos+3)/3+kpds(14) ! Time range P2 + end if + end if + ! + ! Checking Unit of Time Range for FNMOC (APCP) + ! + if (ipdstmpl(4).eq.58 .AND. ipdsnum.eq.11 .AND. & + (ipdstmpl(1).eq.1 .AND.ipdstmpl(2).eq.8) & + .AND. (ipdstmpl(10).eq.1)) then + if (ipdstmpl(9) .ge. 252) then + kpds(13)= 11 ! Forecast time unit is 6-hour + kpds(14)=ipdstmpl(9)/6 ! Time range P1 + kpds(15)=ipdstmpl(ipos+3)/6+kpds(14) ! Time range P2 + else + kpds(13)= 1 ! Forecast time unit is 1-hour + kpds(14)=ipdstmpl(9) ! Time range P1 + end if + end if + ! + ! Special case for FNMOC (TMAX and TMIN) + ! + if (ipdstmpl(4).eq.58 .AND. ipdsnum.eq.11 .AND. & + (ipdstmpl(1).eq.0 & + .AND.ipdstmpl(2).eq.0).AND.(ipdstmpl(10).eq.103)) then + kpds(16) = 2 + ! For Maximum Temperature + If (ipdstmpl(27).eq.2 .AND. ipdstmpl(1).eq.0 .AND. & + ipdstmpl(2).eq.0) kpds(5) = 15 + ! For Minimum Temperature + If (ipdstmpl(27).eq.3 .AND. ipdstmpl(1).eq.0 .AND. & + ipdstmpl(2).eq.0) kpds(5) = 16 + end if + ! + ! Special case for WAFS (Mean/MAx IP,CTP and CAT) + ! + if (ipdstmpl(5).eq.96.AND.((ipdstmpl(1).eq.19) & + .AND.(ipdstmpl(2).eq.20.or.ipdstmpl(2).eq.21.or. & + ipdstmpl(2).eq.22)).AND.(ipdstmpl(10).eq.100)) then + kpds(16) = 10 + end if + ! + kpds(17)=0 + kpds(18)=1 ! GRIB edition + kpds(21)=(idsect(6)/100)+1 ! Century + if ( kpds(8).eq.100 ) kpds(21)=idsect(6)/100 + kpds(22)=idrstmpl(3) ! Decimal scale factor + kpds(23)=idsect(2) ! Sub-center + return +end subroutine makepds + +!> This routine converts Level/layer information from a GRIB2 Product +!> Definition Template to GRIB1 Level type and Level value. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-12 | Gilbert | Initial +!> 2007-10-24 | Boi Vuong | Added level 8 (Nominal top of atmosphere) +!> 2011-01-13 | Boi Vuong | Added level/layer values from 235 to 239 +!> +!> @param[in] ipdstmpl GRIB2 Product Definition Template values +!> @param[out] ltype GRIB1 level type (PDS octet 10) +!> @param[out] lval GRIB1 level/layer value(s) (PDS octets 11 and 12) +!> +!> @author Stephen Gilbert @date 2003-06-12 +subroutine levelcnv(ipdstmpl,ltype,lval) + integer,intent(in) :: ipdstmpl(*) + integer,intent(out) :: ltype,lval + + ltype=255 + lval=0 + ltype1=ipdstmpl(10) + ltype2=ipdstmpl(13) + + if ( ltype1.eq.10.AND.ltype2.eq.255 ) then + ltype=200 + lval=0 + elseif ( ltype1.eq.11.AND.ltype2.eq.255 ) then + ltype=216 + lval=0 + elseif ( ltype1.eq.12.AND.ltype2.eq.255 ) then + ltype=217 + lval=0 + elseif ( ltype1.lt.100.AND.ltype2.eq.255 ) then + ltype=ltype1 + lval=0 + elseif ( ltype1.eq.1.AND.ltype2.eq.8 ) then + ltype=ltype1 + lval=0 + elseif ( ltype1.eq.10.AND.ltype2.eq.255 ) then + ltype=200 + lval=0 + elseif ( ltype1.eq.235.AND.ltype2.eq.255 ) then + ltype=235 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1) + elseif ( ltype1.ge.200.AND.ltype2.eq.255 ) then + ltype=ltype1 + lval=0 + elseif (ltype1.eq.100.AND.ltype2.eq.255 ) then + ltype=100 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1/100.) + elseif (ltype1.eq.100.AND.ltype2.eq.100 ) then + ltype=101 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1/1000.) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2/1000.) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.101.AND.ltype2.eq.255 ) then + ltype=102 + lval=0 + elseif (ltype1.eq.102.AND.ltype2.eq.255 ) then + ltype=103 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1) + elseif (ltype1.eq.102.AND.ltype2.eq.102 ) then + ltype=104 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.103.AND.ltype2.eq.255 ) then + ltype=105 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1) + elseif (ltype1.eq.103.AND.ltype2.eq.103 ) then + ltype=106 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1/100.) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2/100.) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.104.AND.ltype2.eq.255 ) then + ltype=107 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1*10000.) + elseif (ltype1.eq.104.AND.ltype2.eq.104 ) then + ltype=108 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1*100.) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2*100.) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.105.AND.ltype2.eq.255 ) then + ltype=109 + lval=ipdstmpl(12) + elseif (ltype1.eq.105.AND.ltype2.eq.105 ) then + ltype=110 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.106.AND.ltype2.eq.255 ) then + ltype=111 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1*100.) + elseif (ltype1.eq.106.AND.ltype2.eq.106 ) then + ltype=112 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1*100.) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2*100.) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.107.AND.ltype2.eq.255 ) then + ltype=113 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1) + elseif (ltype1.eq.107.AND.ltype2.eq.107 ) then + ltype=114 + rscal1=10.**(-ipdstmpl(11)) + lval1=475-nint(real(ipdstmpl(12))*rscal1) + rscal2=10.**(-ipdstmpl(14)) + lval2=475-nint(real(ipdstmpl(15))*rscal2) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.108.AND.ltype2.eq.255 ) then + ltype=115 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1/100.) + elseif (ltype1.eq.108.AND.ltype2.eq.108 ) then + ltype=116 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1/100.) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2/100.) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.109.AND.ltype2.eq.255 ) then + ltype=117 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1*1000000000.) + elseif (ltype1.eq.111.AND.ltype2.eq.255 ) then + ltype=119 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1*10000.) + elseif (ltype1.eq.111.AND.ltype2.eq.111 ) then + ltype=120 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1*100.) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2*100.) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.160.AND.ltype2.eq.255 ) then + ltype=160 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1) + elseif ((ltype1.ge.236.AND.ltype1.le.239).AND. & + (ltype2.ge.236.AND.ltype2.le.239)) then + ltype=ltype1 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2) + lval=(lval1*256)+lval2 + else + print *,'levelcnv: GRIB2 Levels ',ltype1,ltype2, & + ' not recognized.' + ltype=255 + endif + + ! High resolution stuff + ! elseif (ltype.eq.121) then + ! ipdstmpl(10)=100 + ! ipdstmpl(12)=(1100+(lval/256))*100 + ! ipdstmpl(13)=100 + ! ipdstmpl(15)=(1100+mod(lval,256))*100 + ! elseif (ltype.eq.125) then + ! ipdstmpl(10)=103 + ! ipdstmpl(11)=-2 + ! ipdstmpl(12)=lval + ! elseif (ltype.eq.128) then + ! ipdstmpl(10)=104 + ! ipdstmpl(11)=-3 + ! ipdstmpl(12)=1100+(lval/256) + ! ipdstmpl(13)=104 + ! ipdstmpl(14)=-3 + ! ipdstmpl(15)=1100+mod(lval,256) + ! elseif (ltype.eq.141) then + ! ipdstmpl(10)=100 + ! ipdstmpl(12)=(lval/256)*100 + ! ipdstmpl(13)=100 + ! ipdstmpl(15)=(1100+mod(lval,256))*100 + + return +end subroutine levelcnv + +!> This routine creates the GRIB1 NCEP Ensemble PDS extension +!> information from appropriate information from a GRIB2 Product +!> Definition Template. +!> +!> @note Use pds2pdtens for ensemble related PDS. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-12 | Gilbert | Initial +!> 2007-05-14 | Boi Vuong | Corrected scale factor probabilities +!> 2010-07-26 | Boi Vuong | Added two type of ensemblers (4 and 192) +!> +!> @param[in] ipdsnum GRIB2 Product Definition Template Number +!> @param[in] ipdstmpl GRIB2 Product Definition Template entries for +!> PDT 4.ipdsnum +!> @param[inout] kpds GRIB1 PDS info as specified in W3FI63. +!> - 1 id of center +!> - 2 generating process id number +!> - 3 grid definition +!> - 4 gds/bms flag (right adj copy of octet 8) +!> - 5 indicator of parameter +!> - 6 type of level +!> - 7 height/pressure , etc of level +!> - 8 year including (century-1) +!> - 9 month of year +!> - 10 day of month +!> - 11 hour of day +!> - 12 minute of hour +!> - 13 indicator of forecast time unit +!> - 14 time range 1 +!> - 15 time range 2 +!> - 16 time range flag +!> - 17 number included in average +!> - 18 version nr of grib specification +!> - 19 version nr of parameter table +!> - 20 nr missing from average/accumulation +!> - 21 century of reference time of data +!> - 22 units decimal scale factor +!> - 23 subcenter number +!> @param[out] kens Ensemble identification for PDS octets 41-45 +!> @param[out] kprob Ensemble probability info for PDS octets 46 47 +!> @param[out] xprob Ensemble probability info for PDS octets 48-55 +!> @param[out] kclust Ensemble cluster info for PDS octets 61-76 +!> @param[out] kmembr Ensemble membership info for PDS octest 77-86 +!> @param[out] iret Error return value: +!> - 0 Successful +!> - 2 Unrecognized GRIB2 PDT 4.ipdsnum +!> +!> @author Stephen Gilbert @date 2003-06-12 +subroutine makepdsens(ipdsnum,ipdstmpl,kpds,kens,kprob, & + xprob,kclust,kmembr,iret) + use params + + integer,intent(in) :: ipdstmpl(*) + integer,intent(in) :: ipdsnum + integer,intent(inout) :: kpds(*) + integer,intent(out) :: kens(5),kprob(2) + integer,intent(out) :: kclust(16),kmembr(80) + real,intent(out) :: xprob(2) + integer,intent(out) :: iret + + iret=0 + kpds(23)=2 ! subcenter = ensemble + + kens(1:5)=0 + kprob(1:2)=0 + xprob(1:2)=0. + kclust(1:16)=0 + kmembr(1:80)=0 + ! + ! Individual Ensemble Fcst + ! + if (ipdsnum.eq.1.OR.ipdsnum.eq.11) then + kens(1)=1 + selectcase (ipdstmpl(16)) + case(0) + kens(2)=1 + kens(3)=1 + case(1) + kens(2)=1 + kens(3)=2 + case(2) + kens(2)=2 + kens(3)=ipdstmpl(17) + case(3) + kens(2)=3 + kens(3)=ipdstmpl(17) + case(4) + kens(2)=3 + kens(3)=ipdstmpl(17) + case(192) + kens(2)=3 + kens(3)=ipdstmpl(17) + end select + kens(4)=1 + kens(5)=255 + ! + ! Probability Fcst + ! + elseif (ipdsnum.eq.5.OR.ipdsnum.eq.9) then + kens(1)=1 + kens(2)=5 + kens(3)=0 + kens(4)=0 + kens(5)=255 + kprob(1)=kpds(5) + kpds(5)=191 + kprob(2)=ipdstmpl(18)+1 + if (kprob(2).eq.1) then + rscale=10.**ipdstmpl(19) + xprob(1)=real(ipdstmpl(20))/rscale + xprob(2)=0.0 + elseif (kprob(2).eq.2) then + xprob(1)=0.0 + rscale=10.**ipdstmpl(21) + xprob(2)=real(ipdstmpl(22))/rscale + elseif (kprob(2).eq.3) then + rscale=10.**ipdstmpl(19) + xprob(1)=real(ipdstmpl(20))/rscale + rscale=10.**ipdstmpl(21) + xprob(2)=real(ipdstmpl(22))/rscale + endif + kclust(1)=ipdstmpl(17) + ! + ! Derived Ensemble Fcst + ! + elseif (ipdsnum.eq.2.OR.ipdsnum.eq.12) then + kens(1)=1 + kens(2)=5 + kens(3)=0 + selectcase (ipdstmpl(16)) + case(0) + kens(4)=1 + case(1) + kens(4)=2 + case(2) + kens(4)=11 + case(3) + kens(4)=12 + end select + !kens(5)=89 + kens(5)=0 + kclust(1)=ipdstmpl(17) + else + print *,'makepdsens: Don:t know GRIB2 PDT 4.',ipdsnum + iret=2 + endif + + return +end subroutine makepdsens + +!> This routine converts grid information from a GRIB2 Grid Description +!> Section as well as its Grid Definition Template to GRIB1 GDS info. In +!> addition, a check is made to determine if the grid is an NCEP +!> predefined grid. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-17 | Gilbert | Initial. +!> 2004-04-27 | Gilbert | Added support for gaussian grids. +!> 2007-04-16 | Vuong | Added Curvilinear Orthogonal grids. +!> 2007-05-29 | Vuong | Added Rotate Lat/Lon E-grid (203) +!> +!> @param[in] igds Contains information read from the appropriate GRIB +!> Grid Definition Section 3 for the field being returned. Must be +!> dimensioned >= 5. +!> - igds(1) Source of grid definition (see Code Table 3.0) +!> - igds(2) Number of grid points in the defined grid. +!> - igds(3) Number of octets needed for each additional grid points +!> definition. Used to define number of points in each row (or column) +!> for non-regular grids. = 0, if using regular grid. +!> - igds(4) Interpretation of list for optional points +!> definition. (Code Table 3.11). +!> - igds(5) Grid Definition Template Number (Code Table 3.1) +!> @param[in] igdstmpl Grid Definition Template values for GDT 3.igds(5) +!> @param[in] idefnum The number of entries in array +!> ideflist. i.e. number of rows (or columns) for which optional grid +!> points are defined. +!> @param[in] ideflist Optional integer array containing the number of +!> grid points contained in each row (or column). +!> @param[out] kgds GRIB1 GDS as described in w3fi63 format. +!> @param[out] igrid NCEP predefined GRIB1 grid number +!> set to 255, if not NCEP grid +!> @param[out] iret Error return value: +!> - 0 Successful +!> - 1 Unrecognized GRIB2 GDT number 3.igds(5). +!> +!> @author Stephen Gilbert @date 2003-06-17 & +subroutine gdt2gds(igds,igdstmpl,idefnum,ideflist,kgds, & + igrid,iret) + + ! + integer,intent(in) :: idefnum + integer,intent(in) :: igds(*),igdstmpl(*),ideflist(*) + integer,intent(out) :: kgds(*),igrid,iret + + integer :: kgds72(200),kgds71(200),idum(200),jdum(200) + + iret=0 + if (igds(5).eq.0) then ! Lat/Lon grid + kgds(1)=0 + kgds(2)=igdstmpl(8) ! Ni + kgds(3)=igdstmpl(9) ! Nj + kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point + kgds(5)=igdstmpl(13)/1000 ! Long of 1st grid point + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 + kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point + kgds(8)=igdstmpl(16)/1000 ! Long of last grid point + kgds(9)=igdstmpl(17)/1000 ! Di + kgds(10)=igdstmpl(18)/1000 ! Dj + kgds(11)=igdstmpl(19) ! Scanning mode + kgds(12)=0 + kgds(13)=0 + kgds(14)=0 + kgds(15)=0 + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + ! + ! Process irreg grid stuff, if necessary + ! + if (idefnum.ne.0) then + if (igdstmpl(8).eq.-1) then + kgds(2)=65535 + kgds(9)=65535 + endif + if (igdstmpl(9).eq.-1) then + kgds(3)=65535 + kgds(10)=65535 + endif + kgds(19)=0 + kgds(20)=33 + if (kgds(1).eq.1.OR.kgds(1).eq.3) kgds(20)=43 + kgds(21)=igds(2) ! num of grid points + do j=1,idefnum + kgds(21+j)=ideflist(j) + enddo + endif + elseif (igds(5).eq.10) then ! Mercator grid + kgds(1)=1 ! Grid Definition Template number + kgds(2)=igdstmpl(8) ! Ni + kgds(3)=igdstmpl(9) ! Nj + kgds(4)=igdstmpl(10)/1000 ! Lat of 1st grid point + kgds(5)=igdstmpl(11)/1000 ! Long of 1st grid point + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(12),4).OR.btest(igdstmpl(12),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(12),3)) kgds(6)=kgds(6)+8 + kgds(7)=igdstmpl(14)/1000 ! Lat of last grid point + kgds(8)=igdstmpl(15)/1000 ! Long of last grid point + kgds(9)=igdstmpl(13)/1000 ! Lat intersects earth + kgds(10)=0 + kgds(11)=igdstmpl(16) ! Scanning mode + kgds(12)=igdstmpl(18)/1000 ! Di + kgds(13)=igdstmpl(19)/1000 ! Dj + kgds(14)=0 + kgds(15)=0 + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + elseif (igds(5).eq.30) then ! Lambert Conformal Grid + kgds(1)=3 + kgds(2)=igdstmpl(8) ! Nx + kgds(3)=igdstmpl(9) ! Ny + kgds(4)=igdstmpl(10)/1000 ! Lat of 1st grid point + kgds(5)=igdstmpl(11)/1000 ! Long of 1st grid point + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(12),4).OR.btest(igdstmpl(12),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(12),3)) kgds(6)=kgds(6)+8 + kgds(7)=igdstmpl(14)/1000 ! Lon of orientation + kgds(8)=igdstmpl(15)/1000 ! Dx + kgds(9)=igdstmpl(16)/1000 ! Dy + kgds(10)=igdstmpl(17) ! Projection Center Flag + kgds(11)=igdstmpl(18) ! Scanning mode + kgds(12)=igdstmpl(19)/1000 ! Lat in 1 + kgds(13)=igdstmpl(20)/1000 ! Lat in 2 + kgds(14)=igdstmpl(21)/1000 ! Lat of S. Pole of projection + kgds(15)=igdstmpl(22)/1000 ! Lon of S. Pole of projection + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + elseif (igds(5).eq.40) then ! Gaussian Lat/Lon grid + kgds(1)=4 + kgds(2)=igdstmpl(8) ! Ni + kgds(3)=igdstmpl(9) ! Nj + kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point + kgds(5)=igdstmpl(13)/1000 ! Long of 1st grid point + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 + kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point + kgds(8)=igdstmpl(16)/1000 ! Long of last grid point + kgds(9)=igdstmpl(17)/1000 ! Di + kgds(10)=igdstmpl(18) ! N - Number of parallels + kgds(11)=igdstmpl(19) ! Scanning mode + kgds(12)=0 + kgds(13)=0 + kgds(14)=0 + kgds(15)=0 + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + elseif (igds(5).eq.20) then ! Polar Stereographic Grid + kgds(1)=5 + kgds(2)=igdstmpl(8) ! Nx + kgds(3)=igdstmpl(9) ! Ny + kgds(4)=igdstmpl(10)/1000 ! Lat of 1st grid point + kgds(5)=igdstmpl(11)/1000 ! Long of 1st grid point + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(12),4).OR.btest(igdstmpl(12),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(12),3)) kgds(6)=kgds(6)+8 + kgds(7)=igdstmpl(14)/1000 ! Lon of orientation + kgds(8)=igdstmpl(15)/1000 ! Dx + kgds(9)=igdstmpl(16)/1000 ! Dy + kgds(10)=igdstmpl(17) ! Projection Center Flag + kgds(11)=igdstmpl(18) ! Scanning mode + kgds(12)=0 + kgds(13)=0 + kgds(14)=0 + kgds(15)=0 + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + elseif (igds(5).eq.204) then ! Curvilinear Orthogonal + kgds(1)=204 + kgds(2)=igdstmpl(8) ! Ni + kgds(3)=igdstmpl(9) ! Nj + kgds(4)=0 + kgds(5)=0 + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 + kgds(7)=0 + kgds(8)=0 + kgds(9)=0 + kgds(10)=0 + kgds(11)=igdstmpl(19) ! Scanning mode + kgds(12)=0 + kgds(13)=0 + kgds(14)=0 + kgds(15)=0 + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + ! + ! Process irreg grid stuff, if necessary + ! + if (idefnum.ne.0) then + if (igdstmpl(8).eq.-1) then + kgds(2)=65535 + kgds(9)=65535 + endif + if (igdstmpl(9).eq.-1) then + kgds(3)=65535 + kgds(10)=65535 + endif + kgds(19)=0 + kgds(20)=33 + if (kgds(1).eq.1.OR.kgds(1).eq.3) kgds(20)=43 + kgds(21)=igds(2) ! num of grid points + do j=1,idefnum + kgds(21+j)=ideflist(j) + enddo + endif + elseif (igds(5).eq.32768) then ! Rotate Lat/Lon grid + kgds(1)=203 ! Arakawa Staggerred E/B grid + kgds(2)=igdstmpl(8) ! Ni + kgds(3)=igdstmpl(9) ! Nj + kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point + kgds(5)=igdstmpl(13)/1000 ! Lon of 1st grid point + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 + kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point + kgds(8)=igdstmpl(16)/1000 ! Lon of last grid point + kgds(9)=igdstmpl(17)/1000 ! Di + kgds(10)=igdstmpl(18)/1000 ! Dj + kgds(11)=igdstmpl(19) ! Scanning mode + kgds(12)=0 + kgds(13)=0 + kgds(14)=0 + kgds(15)=0 + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + ! + ! Process irreg grid stuff, if necessary + ! + if (idefnum.ne.0) then + if (igdstmpl(8).eq.-1) then + kgds(2)=65535 + kgds(9)=65535 + endif + if (igdstmpl(9).eq.-1) then + kgds(3)=65535 + kgds(10)=65535 + endif + kgds(19)=0 + kgds(20)=33 + if (kgds(1).eq.1.OR.kgds(1).eq.3) kgds(20)=43 + kgds(21)=igds(2) ! num of grid points + do j=1,idefnum + kgds(21+j)=ideflist(j) + enddo + endif + elseif (igds(5).eq.32769) then ! Rotate Lat/Lon grid + kgds(1)=205 ! Arakawa Staggerred for Non-E Stagger grid + kgds(2)=igdstmpl(8) ! Ni + kgds(3)=igdstmpl(9) ! Nj + kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point + kgds(5)=igdstmpl(13)/1000 ! Lon of 1st grid point + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 + kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point + kgds(8)=igdstmpl(16)/1000 ! Lon of last grid point + kgds(9)=igdstmpl(17)/1000 ! Di + kgds(10)=igdstmpl(18)/1000 ! Dj + kgds(11)=igdstmpl(19) ! Scanning mode + kgds(12)=igdstmpl(20)/1000 + kgds(13)=igdstmpl(21)/1000 + kgds(14)=0 + kgds(15)=0 + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + else + Print *,'gdt2gds: Unrecognized GRIB2 GDT = 3.',igds(5) + iret=1 + kgds(1:22)=0 + return + endif + ! + ! Can we determine NCEP grid number ? + ! + igrid=255 + do j=254,1,-1 + !do j=225,225 + kgds71=0 + kgds72=0 + call w3fi71(j,kgds71,ierr) + if (ierr.ne.0) cycle + ! convert W to E for longitudes + if (kgds71(3).eq.0) then ! lat/lon + if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) + if (kgds71(10).lt.0) kgds71(10)=360000+kgds71(10) + elseif (kgds71(3).eq.1) then ! mercator + if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) + if (kgds71(10).lt.0) kgds71(10)=360000+kgds71(10) + elseif (kgds71(3).eq.3) then ! lambert conformal + if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) + if (kgds71(9).lt.0) kgds71(9)=360000+kgds71(9) + if (kgds71(18).lt.0) kgds71(18)=360000+kgds71(18) + elseif (kgds71(3).eq.4) then ! Guassian lat/lon + if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) + if (kgds71(10).lt.0) kgds71(10)=360000+kgds71(10) + elseif (kgds71(3).eq.5) then ! polar stereographic + if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) + if (kgds71(9).lt.0) kgds71(9)=360000+kgds71(9) + endif + call r63w72(idum,kgds,jdum,kgds72) + if (kgds72(3).eq.3) kgds72(14)=0 ! lambert conformal fix + if (kgds72(3).eq.1) kgds72(15:18)=0 ! mercator fix + if (kgds72(3).eq.5) kgds72(14:18)=0 ! polar str fix + ! print *,' kgds71(',j,')= ', kgds71(1:30) + ! print *,' kgds72 = ', kgds72(1:30) + if (all(kgds71.eq.kgds72)) then + igrid=j + return + endif + enddo + + return +end subroutine gdt2gds + +!> Pack and write a grib message. This subprogram is nearly the inverse +!> of getgbe. +!> +!> @note Subprogram can be called from a multiprocessing environment. +!> Do not engage the same logical unit from more than one processor. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 94-04-01 | Iredell | Initial. +!> 95-10-31 | Iredell | Removed saves and prints +!> 97-02-11 | Y. Zhu | Included probability and cluster arguments +!> 2002-03-18 | Gilbert | Modified from putgbex to account for binary scale factors. +!> +!> @param[in] lugb teger unit of the unblocked grib data file +!> @param[in] kf teger number of data points +!> @param[in] kpds teger (200) pds parameters +!> - 1 id of center +!> - 2 generating process id number +!> - 3 grid definition +!> - 4 gds/bms flag (right adj copy of octet 8) +!> - 5 indicator of parameter +!> - 6 type of level +!> - 7 height/pressure , etc of level +!> - 8 year including (century-1) +!> - 9 month of year +!> - 10 day of month +!> - 11 hour of day +!> - 12 minute of hour +!> - 13 indicator of forecast time unit +!> - 14 time range 1 +!> - 15 time range 2 +!> - 16 time range flag +!> - 17 number included in average +!> - 18 version nr of grib specification +!> - 19 version nr of parameter table +!> - 20 nr missing from average/accumulation +!> - 21 century of reference time of data +!> - 22 units decimal scale factor +!> - 23 subcenter number +!> - 24 pds byte 29, for nmc ensemble products, 128 if forecast field +!> error, 64 if bias corrected fcst field, 32 if smoothed field, +!> warning: can be combination of more than 1. +!> - 25 pds byte 30, not used +!> @param[in] kgds teger (200) gds parameters +!> - 1 data representation type +!> - 19 number of vertical coordinate parameters +!> - 20 octet number of the list of vertical coordinate parameters or +!> octet number of the list of numbers of points in each row or 255 if +!> neither are present. +!> - 21 for grids with pl, number of points in grid +!> - 22 number of words in each row latitude/longitude grids +!> - 2 n(i) nr points on latitude circle +!> - 3 n(j) nr points on longitude meridian +!> - 4 la(1) latitude of origin +!> - 5 lo(1) longitude of origin +!> - 6 resolution flag (right adj copy of octet 17) +!> - 7 la(2) latitude of extreme point +!> - 8 lo(2) longitude of extreme point +!> - 9 di longitudinal direction of increment +!> - 10 dj latitudinal direction increment +!> - 11 scanning mode flag (right adj copy of octet 28) +!> Gaussian grids: +!> - 2 n(i) nr points on latitude circle +!> - 3 n(j) nr points on longitude meridian +!> - 4 la(1) latitude of origin +!> - 5 lo(1) longitude of origin +!> - 6 resolution flag (right adj copy of octet 17) +!> - 7 la(2) latitude of extreme point +!> - 8 lo(2) longitude of extreme point +!> - 9 di longitudinal direction of increment +!> - 10 n - nr of circles pole to equator +!> - 11 scanning mode flag (right adj copy of octet 28) +!> - 12 nv - nr of vert coord parameters +!> - 13 pv - octet nr of list of vert coord parameters or pl - location +!> of the list of numbers of points in each row (if no vert coord +!> parameters are present or 255 if neither are present +!> Polar Stereographic grids: +!> - 2 n(i) nr points along lat circle +!> - 3 n(j) nr points along lon circle +!> - 4 la(1) latitude of origin +!> - 5 lo(1) longitude of origin +!> - 6 resolution flag (right adj copy of octet 17) +!> - 7 lov grid orientation +!> - 8 dx - x direction increment +!> - 9 dy - y direction increment +!> - 10 projection center flag +!> - 11 scanning mode (right adj copy of octet 28) +!> Spherical Harmonic Coefficients: +!> - 2 j pentagonal resolution parameter +!> - 3 k pentagonal resolution parameter +!> - 4 m pentagonal resolution parameter +!> - 5 representation type +!> - 6 coefficient storage mode +!> Mercator grids: +!> - 2 n(i) nr points on latitude circle +!> - 3 n(j) nr points on longitude meridian +!> - 4 la(1) latitude of origin +!> - 5 lo(1) longitude of origin +!> - 6 resolution flag (right adj copy of octet 17) +!> - 7 la(2) latitude of last grid point +!> - 8 lo(2) longitude of last grid point +!> - 9 latit - latitude of projection intersection +!> - 10 reserved +!> - 11 scanning mode flag (right adj copy of octet 28) +!> - 12 longitudinal dir grid length +!> - 13 latitudinal dir grid length +!> Lambert Conformal Grids: +!> - 2 nx nr points along x-axis +!> - 3 ny nr points along y-axis +!> - 4 la1 lat of origin (lower left) +!> - 5 lo1 lon of origin (lower left) +!> - 6 resolution (right adj copy of octet 17) +!> - 7 lov - orientation of grid +!> - 8 dx - x-dir increment +!> - 9 dy - y-dir increment +!> - 10 projection center flag +!> - 11 scanning mode flag (right adj copy of octet 28) +!> - 12 latin 1 - first lat from pole of secant cone inter +!> - 13 latin 2 - second lat from pole of secant cone inter +!> @param[in] kens teger (200) ensemble pds parms +!> - 1 application identifier +!> - 2 ensemble type +!> - 3 ensemble identifier +!> - 4 product identifier +!> - 5 smoothing flag +!> @param[in] kprob teger (2) probability ensemble parms +!> @param[in] xprob al (2) probability ensemble parms +!> @param[in] kclust teger (16) cluster ensemble parms +!> @param[in] kmembr teger (8) cluster ensemble parms +!> @param[in] ibs teger binary scale factor (0 to ignore) +!> @param[in] nbits teger number of bits in which to pack (0 to ignore) +!> @param[in] lb gical*1 (kf) bitmap if present +!> @param[in] f al (kf) data +!> @param[out] iret teger return code +!> - 0 Success +!> - Other W3FI72 GRIB packer return code +!> +!> @author Mark Iredell @date 94-04-01 +SUBROUTINE PUTGBEXN(LUGB,KF,KPDS,KGDS,KENS, & + KPROB,XPROB,KCLUST,KMEMBR,IBS,NBITS,LB,F,IRET) + + INTEGER KPDS(200),KGDS(200),KENS(200) + INTEGER KPROB(2),KCLUST(16),KMEMBR(80) + REAL XPROB(2) + LOGICAL*1 LB(KF) + REAL F(KF) + ! PARAMETER(MAXBIT=16) + PARAMETER(MAXBIT=24) + INTEGER IBM(KF),IPDS(200),IGDS(200),IBDS(200) + CHARACTER PDS(400),GRIB(1000+KF*(MAXBIT+1)/8) + + ! GET W3FI72 PARAMETERS + !print *,'SAGT: start putgbexn' + CALL R63W72(KPDS,KGDS,IPDS,IGDS) + IBDS=0 + + ! COUNT VALID DATA + KBM=KF + IF(IPDS(7).NE.0) THEN + KBM=0 + DO I=1,KF + IF(LB(I)) THEN + IBM(I)=1 + KBM=KBM+1 + ELSE + IBM(I)=0 + ENDIF + ENDDO + IF(KBM.EQ.KF) IPDS(7)=0 + ENDIF + + ! GET NUMBER OF BITS AND ROUND DATA + IF(NBITS.GT.0) THEN + NBIT=NBITS + ELSE + IF(KBM.EQ.0) THEN + DO I=1,KF + F(I)=0. + ENDDO + NBIT=0 + ELSE + !print *,'SAGT:',IPDS(7),IBS,IPDS(25),KF + !print *,'SAGT:',count(ibm.eq.0),count(ibm.eq.1) + CALL SETBIT(IPDS(7),-IBS,IPDS(25),KF,IBM,F,FMIN,FMAX,NBIT) + NBIT=MIN(NBIT,MAXBIT) + ENDIF + ENDIF + + ! CREATE PRODUCT DEFINITION SECTION + CALL W3FI68(IPDS,PDS) + IF(IPDS(24).EQ.2) THEN + ILAST=45 + IF (IPDS(8).EQ.191.OR.IPDS(8).EQ.192) ILAST=55 + IF (KENS(2).EQ.5) ILAST=76 + IF (KENS(2).EQ.5) ILAST=86 + IF (KENS(2).EQ.4) ILAST=86 + CALL PDSENS(KENS,KPROB,XPROB,KCLUST,KMEMBR,ILAST,PDS) + ENDIF + + ! PACK AND WRITE GRIB DATA + igflag=1 + igrid=kpds(3) + if (igrid.ne.255) igflag=0 + !print *,minval(f(1:kf)),maxval(f(1:kf)) + !print *,nbit,kf + !print *,(ipds(j),j=1,28) + !write(6,fmt='(28z2)') (pds(j),j=1,28) + !print *,(kgds(j),j=1,28) + !print *,(igds(j),j=1,28) + icomp=0 + CALL W3FI72(0,F,0,NBIT,1,IPDS,PDS, & + igflag,igrid,IGDS,ICOMP,0,IBM,KF,IBDS, & + KFO,GRIB,LGRIB,IRET) + IF(IRET.EQ.0) CALL WRYTE(LUGB,LGRIB,GRIB) + + RETURN +END SUBROUTINE PUTGBEXN + +!> The number of bits required to pack a given field for particular +!> binary and decimal scalings is computed. The minimum and maximum +!> rounded field values are also returned. GRIB bitmap masking for +!> valid data is optionally used. +!> +!> @param[in] ibm integer bitmap flag (=0 for no bitmap). +!> @param[in] ibs integer binary scaling (e.g. ibs=3 to round field to +!> nearest eighth value). +!> @param[in] ids integer decimal scaling (e.g. ids=3 to round field to +!> nearest milli-value) (note that ids and ibs can both be nonzero, +!> e.g. ids=1 and ibs=1 rounds to the nearest twentieth). +!> @param[in] len integer length of the field and bitmap. +!> @param[in] mg integer (len) bitmap if ibm=1 (0 to skip, 1 to keep). +!> @param[in] g real (len) field. +!> @param[out] gmin real minimum valid rounded field value. +!> @param[out] gmax real maximum valid rounded field value. +!> @param[out] nbit integer number of bits to pack. +!> +!> @author Mark Iredell @date 92-10-31 +SUBROUTINE SETBIT(IBM,IBS,IDS,LEN,MG,G,GMIN,GMAX,NBIT) + + DIMENSION MG(LEN),G(LEN) + + ! ROUND FIELD AND DETERMINE EXTREMES WHERE BITMAP IS ON + S=2.**IBS*10.**IDS + IF(IBM.EQ.0) THEN + GMAX=G(1) + GMIN=G(1) + DO I=2,LEN + GMAX=MAX(GMAX,G(I)) + GMIN=MIN(GMIN,G(I)) + ENDDO + ELSE + I1=1 + DO WHILE(I1.LE.LEN.AND.MG(I1).EQ.0) + I1=I1+1 + ENDDO + IF(I1.LE.LEN) THEN + DO I=1,I1-1 + G(I)=0. + ENDDO + GMAX=G(I1) + GMIN=G(I1) + DO I=I1+1,LEN + IF(MG(I).NE.0) THEN + GMAX=MAX(GMAX,G(I)) + GMIN=MIN(GMIN,G(I)) + ELSE + G(I)=0. + ENDIF + ENDDO + ELSE + DO I=1,LEN + G(I)=0. + ENDDO + GMAX=0. + GMIN=0. + ENDIF + ENDIF + + ! COMPUTE NUMBER OF BITS + NBIT=LOG((GMAX-GMIN)*S+0.9)/LOG(2.)+1. + + RETURN +END SUBROUTINE SETBIT diff --git a/utils/gds2gdt.F90 b/utils/gds2gdt.F90 deleted file mode 100644 index 773e64cd3..000000000 --- a/utils/gds2gdt.F90 +++ /dev/null @@ -1,392 +0,0 @@ -!> @file -!> @brief Convert a GRIB1 GDS to necessary info for a GRIB2 Grid -!> Definition Section. -!> @author Stephen Gilbert @date 2003-06-17 - -!> This routine converts a GRIB1 GDS (in format specfied in -!> w3fi63.f) to necessary info for a GRIB2 Grid Definition Section. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-17 | Gilbert | Initial. -!> 2004-04-27 | Gilbert | Added support for Gaussian grids. -!> 2007-04-16 | Vuong | Added Curvilinear Orthogonal grids. -!> 2007-05-29 | Vuong | Added Rotate Lat/Lon E-grid (203) -!> 2010-05-10 | Vuong | Added Rotate Lat/Lon for Non-E Stagger grid (205) -!> 2011-05-04 | Vuong | Corrected Arakawa Lat/Lon of grid points for Non-E Stagger grid (205) -!> -!> @param[in] kgds GRIB1 GDS info as returned by w3fi63.f. -!> @param[out] igds Contains information read from the appropriate GRIB -!> Grid Definition Section 3 for the field being returned. Must be -!> dimensioned >= 5. -!> - igds(1) Source of grid definition (see Code Table 3.0) -!> - igds(2) Number of grid points in the defined grid. -!> - igds(3) Number of octets needed for each additional grid points -!> definition. Used to define number of points in each row (or column) -!> for non-regular grids. = 0, if using regular grid. -!> - igds(4) Interpretation of list for optional points definition. (Code Table 3.11) -!> - igds(5) Grid Definition Template Number (Code Table 3.1) -!> @param[out] igdstmpl Grid Definition Template values for GDT 3.igds(5) -!> @param[out] idefnum The number of entries in array -!> ideflist. i.e. number of rows (or columns) for which optional grid -!> points are defined. -!> @param[out] ideflist Optional integer array containing the number of -!> grid points contained in each row (or column). -!> @param[out] iret Error return value: -!> - 0 Successful -!> - 1 Unrecognized GRIB1 grid data representation type -!> -!> @author Stephen Gilbert @date 2003-06-17 -subroutine gds2gdt(kgds,igds,igdstmpl,idefnum,ideflist,iret) - - integer,intent(in) :: kgds(*) - integer,intent(out) :: igds(*),igdstmpl(*),ideflist(*) - integer,intent(out) :: idefnum,iret - - iret=0 - if (kgds(1).eq.0) then ! Lat/Lon grid - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=0 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) !Ni - igdstmpl(9)=kgds(3) !Nj - igdstmpl(10)=0 - igdstmpl(11)=0 - igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point - if (kgds(5).lt.0) then ! Lon of 1st grid point - igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E - else - igdstmpl(13)=kgds(5)*1000 - endif - igdstmpl(14)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(14)=48 - if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 - igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point - if (kgds(8).lt.0) then ! Lon of last grid point - igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E - else - igdstmpl(16)=kgds(8)*1000 - endif - igdstmpl(17)=kgds(9)*1000 ! Di - igdstmpl(18)=kgds(10)*1000 ! Dj - igdstmpl(19)=kgds(11) ! Scanning mode - if (kgds(20).ne.255) then ! irregular grid (eg WAFS) - igds(2)=kgds(21) ! num of grid points - !idefnum=kgds(19) - if (kgds(2).eq.65535) idefnum=kgds(3) - if (kgds(3).eq.65535) idefnum=kgds(2) - imax=0 - do j=1,idefnum - ideflist(j)=kgds(21+j) - if (ideflist(j).gt.imax) imax=ideflist(j) - enddo - igds(3)=1 ! octets for further grid definition - if (imax.gt.255) igds(3)=2 - if (imax.gt.65535) igds(3)=3 - if (imax.gt.16777215) igds(3)=4 - igds(4)=1 ! interpretation of optional list - igdstmpl(8)=-1 - igdstmpl(17)=-1 - endif - elseif (kgds(1).eq.1) then ! Mercator grid - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=10 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) ! Ni - igdstmpl(9)=kgds(3) ! Nj - igdstmpl(10)=kgds(4)*1000 ! Lat of 1st grid point - if (kgds(5).lt.0) then ! Lon of 1st grid point - igdstmpl(11)=(360000+kgds(5))*1000 ! convert W to E - else - igdstmpl(11)=kgds(5)*1000 - endif - igdstmpl(12)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(12)=48 - if (btest(kgds(6),3)) igdstmpl(12)=igdstmpl(12)+8 - igdstmpl(13)=kgds(9)*1000 ! Lat intersects earth - igdstmpl(14)=kgds(7)*1000 ! Lat of last grid point - if (kgds(8).lt.0) then ! Lon of last grid point - igdstmpl(15)=(360000+kgds(8))*1000 ! convert W to E - else - igdstmpl(15)=kgds(8)*1000 - endif - igdstmpl(16)=kgds(11) ! Scanning mode - igdstmpl(17)=0 ! Orientation of grid - igdstmpl(18)=kgds(12)*1000 ! Di - igdstmpl(19)=kgds(13)*1000 ! Dj - elseif (kgds(1).eq.3) then ! Lambert Conformal Grid - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=30 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) ! Nx - igdstmpl(9)=kgds(3) ! Ny - igdstmpl(10)=kgds(4)*1000 ! Lat of 1st grid point - if (kgds(5).lt.0) then ! Lon of 1st grid point - igdstmpl(11)=(360000+kgds(5))*1000 ! convert W to E - else - igdstmpl(11)=kgds(5)*1000 - endif - igdstmpl(12)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(12)=48 - if (btest(kgds(6),3)) igdstmpl(12)=igdstmpl(12)+8 - igdstmpl(13)=kgds(12)*1000 ! Lat where Dx and Dy specified - if (kgds(7).lt.0) then ! Lon of orientation - igdstmpl(14)=(360000+kgds(7))*1000 ! convert W to E - else - igdstmpl(14)=kgds(7)*1000 - endif - igdstmpl(15)=kgds(8)*1000 ! Dx - igdstmpl(16)=kgds(9)*1000 ! Dy - igdstmpl(17)=kgds(10) ! Projection Center Flag - igdstmpl(18)=kgds(11) ! Scanning mode - igdstmpl(19)=kgds(12)*1000 ! Latin 1 - igdstmpl(20)=kgds(13)*1000 ! Latin 2 - igdstmpl(21)=kgds(14)*1000 ! Lat of S. Pole of projection - if (kgds(15).lt.0) then ! Lon of S. Pole of projection - igdstmpl(22)=(360000+kgds(15))*1000 ! convert W to E - else - igdstmpl(22)=kgds(15)*1000 - endif - elseif (kgds(1).eq.4) then ! Gaussian Lat/Lon grid - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=40 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) !Ni - igdstmpl(9)=kgds(3) !Nj - igdstmpl(10)=0 - igdstmpl(11)=0 - igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point - if (kgds(5).lt.0) then ! Lon of 1st grid point - igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E - else - igdstmpl(13)=kgds(5)*1000 - endif - igdstmpl(14)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(14)=48 - if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 - igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point - if (kgds(8).lt.0) then ! Lon of last grid point - igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E - else - igdstmpl(16)=kgds(8)*1000 - endif - igdstmpl(17)=kgds(9)*1000 ! Di - igdstmpl(18)=kgds(10) ! D - Number of parallels - igdstmpl(19)=kgds(11) ! Scanning mode - elseif (kgds(1).eq.5) then ! Polar Stereographic Grid - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=20 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) ! Nx - igdstmpl(9)=kgds(3) ! Ny - igdstmpl(10)=kgds(4)*1000 ! Lat of 1st grid point - if (kgds(5).lt.0) then ! Lon of 1st grid point - igdstmpl(11)=(360000+kgds(5))*1000 ! convert W to E - else - igdstmpl(11)=kgds(5)*1000 - endif - igdstmpl(12)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(12)=48 - if (btest(kgds(6),3)) igdstmpl(12)=igdstmpl(12)+8 - igdstmpl(13)=60000000 ! Lat where Dx and Dy specified - if (btest(kgds(10),7)) igdstmpl(13)=-60000000 - if (kgds(7).lt.0) then ! Lon of orientation - igdstmpl(14)=(360000+kgds(7))*1000 ! convert W to E - else - igdstmpl(14)=kgds(7)*1000 - endif - igdstmpl(15)=kgds(8)*1000 ! Dx - igdstmpl(16)=kgds(9)*1000 ! Dy - igdstmpl(17)=kgds(10) ! Projection Center Flag - igdstmpl(18)=kgds(11) ! Scanning mode - elseif (kgds(1).eq.204) then ! Curivilinear Orthogonal Grid (Used by RTOFS) - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=204 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) !Ni - No of points along x-grid direction - igdstmpl(9)=kgds(3) !Nj - No of points along y-grid direction - igdstmpl(10)=0 - igdstmpl(11)=0 - igdstmpl(12)=0 - igdstmpl(13)=0 - igdstmpl(14)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(14)=48 - if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 - igdstmpl(15)=0 - igdstmpl(16)=0 - igdstmpl(17)=0 - igdstmpl(18)=0 - igdstmpl(19)=kgds(11) ! Scanning mode - elseif (kgds(1).eq.203) then ! Rot Lat/Lon grid (Arakawa) - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=32768 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) !Ni - igdstmpl(9)=kgds(3) !Nj - igdstmpl(10)=0 - igdstmpl(11)=0 - igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point - if (kgds(5).lt.0) then ! Lon of 1st grid point - igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E - else - igdstmpl(13)=kgds(5)*1000 - endif - igdstmpl(14)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(14)=48 - if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 - igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point - if (kgds(8).lt.0) then ! Lon of last grid point - igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E - else - igdstmpl(16)=kgds(8)*1000 - endif - igdstmpl(17)=kgds(9)*1000 ! Di - igdstmpl(18)=kgds(10)*1000 ! Dj - igdstmpl(19)=kgds(11) ! Scanning mode - elseif (kgds(1).eq.205) then ! Rot Lat/Lon for Non-E Stagger grid (Arakawa) - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=32769 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) !Ni - igdstmpl(9)=kgds(3) !Nj - igdstmpl(10)=0 - igdstmpl(11)=0 - igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point - if (kgds(5).lt.0) then ! Lon of 1st grid point - igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E - else - igdstmpl(13)=kgds(5)*1000 - endif - igdstmpl(14)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(14)=48 - if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 - igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point - if (kgds(8).lt.0) then ! Lon of last grid point - igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E - else - igdstmpl(16)=kgds(8)*1000 - endif - igdstmpl(17)=kgds(9)*1000 ! Di - igdstmpl(18)=kgds(10)*1000 ! Dj - igdstmpl(19)=kgds(11) ! Scanning mode - igdstmpl(20)=kgds(12)*1000 - igdstmpl(21)=kgds(13)*1000 - else - Print *,'gds2gdt: Unrecognized GRIB1 Grid type = ',kgds(1) - iret=1 - endif - return -end subroutine gds2gdt diff --git a/utils/gdt2gds.F90 b/utils/gdt2gds.F90 deleted file mode 100644 index 0513ba15d..000000000 --- a/utils/gdt2gds.F90 +++ /dev/null @@ -1,378 +0,0 @@ -!> @file -!> @brief Convert grid information from a GRIB2 Grid Description -!> Section to GRIB1 GDS info. -!> @author Stephen Gilbert @date 2003-06-17 - -!> This routine converts grid information from a GRIB2 Grid Description -!> Section as well as its Grid Definition Template to GRIB1 GDS info. In -!> addition, a check is made to determine if the grid is an NCEP -!> predefined grid. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-17 | Gilbert | Initial. -!> 2004-04-27 | Gilbert | Added support for gaussian grids. -!> 2007-04-16 | Vuong | Added Curvilinear Orthogonal grids. -!> 2007-05-29 | Vuong | Added Rotate Lat/Lon E-grid (203) -!> -!> @param[in] igds Contains information read from the appropriate GRIB -!> Grid Definition Section 3 for the field being returned. Must be -!> dimensioned >= 5. -!> - igds(1) Source of grid definition (see Code Table 3.0) -!> - igds(2) Number of grid points in the defined grid. -!> - igds(3) Number of octets needed for each additional grid points -!> definition. Used to define number of points in each row (or column) -!> for non-regular grids. = 0, if using regular grid. -!> - igds(4) Interpretation of list for optional points -!> definition. (Code Table 3.11). -!> - igds(5) Grid Definition Template Number (Code Table 3.1) -!> @param[in] igdstmpl Grid Definition Template values for GDT 3.igds(5) -!> @param[in] idefnum The number of entries in array -!> ideflist. i.e. number of rows (or columns) for which optional grid -!> points are defined. -!> @param[in] ideflist Optional integer array containing the number of -!> grid points contained in each row (or column). -!> @param[out] kgds GRIB1 GDS as described in w3fi63 format. -!> @param[out] igrid NCEP predefined GRIB1 grid number -!> set to 255, if not NCEP grid -!> @param[out] iret Error return value: -!> - 0 Successful -!> - 1 Unrecognized GRIB2 GDT number 3.igds(5). -!> -!> @author Stephen Gilbert @date 2003-06-17 & -subroutine gdt2gds(igds,igdstmpl,idefnum,ideflist,kgds, & - igrid,iret) - - ! - integer,intent(in) :: idefnum - integer,intent(in) :: igds(*),igdstmpl(*),ideflist(*) - integer,intent(out) :: kgds(*),igrid,iret - - integer :: kgds72(200),kgds71(200),idum(200),jdum(200) - - iret=0 - if (igds(5).eq.0) then ! Lat/Lon grid - kgds(1)=0 - kgds(2)=igdstmpl(8) ! Ni - kgds(3)=igdstmpl(9) ! Nj - kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point - kgds(5)=igdstmpl(13)/1000 ! Long of 1st grid point - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 - kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point - kgds(8)=igdstmpl(16)/1000 ! Long of last grid point - kgds(9)=igdstmpl(17)/1000 ! Di - kgds(10)=igdstmpl(18)/1000 ! Dj - kgds(11)=igdstmpl(19) ! Scanning mode - kgds(12)=0 - kgds(13)=0 - kgds(14)=0 - kgds(15)=0 - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - ! - ! Process irreg grid stuff, if necessary - ! - if (idefnum.ne.0) then - if (igdstmpl(8).eq.-1) then - kgds(2)=65535 - kgds(9)=65535 - endif - if (igdstmpl(9).eq.-1) then - kgds(3)=65535 - kgds(10)=65535 - endif - kgds(19)=0 - kgds(20)=33 - if (kgds(1).eq.1.OR.kgds(1).eq.3) kgds(20)=43 - kgds(21)=igds(2) ! num of grid points - do j=1,idefnum - kgds(21+j)=ideflist(j) - enddo - endif - elseif (igds(5).eq.10) then ! Mercator grid - kgds(1)=1 ! Grid Definition Template number - kgds(2)=igdstmpl(8) ! Ni - kgds(3)=igdstmpl(9) ! Nj - kgds(4)=igdstmpl(10)/1000 ! Lat of 1st grid point - kgds(5)=igdstmpl(11)/1000 ! Long of 1st grid point - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(12),4).OR.btest(igdstmpl(12),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(12),3)) kgds(6)=kgds(6)+8 - kgds(7)=igdstmpl(14)/1000 ! Lat of last grid point - kgds(8)=igdstmpl(15)/1000 ! Long of last grid point - kgds(9)=igdstmpl(13)/1000 ! Lat intersects earth - kgds(10)=0 - kgds(11)=igdstmpl(16) ! Scanning mode - kgds(12)=igdstmpl(18)/1000 ! Di - kgds(13)=igdstmpl(19)/1000 ! Dj - kgds(14)=0 - kgds(15)=0 - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - elseif (igds(5).eq.30) then ! Lambert Conformal Grid - kgds(1)=3 - kgds(2)=igdstmpl(8) ! Nx - kgds(3)=igdstmpl(9) ! Ny - kgds(4)=igdstmpl(10)/1000 ! Lat of 1st grid point - kgds(5)=igdstmpl(11)/1000 ! Long of 1st grid point - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(12),4).OR.btest(igdstmpl(12),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(12),3)) kgds(6)=kgds(6)+8 - kgds(7)=igdstmpl(14)/1000 ! Lon of orientation - kgds(8)=igdstmpl(15)/1000 ! Dx - kgds(9)=igdstmpl(16)/1000 ! Dy - kgds(10)=igdstmpl(17) ! Projection Center Flag - kgds(11)=igdstmpl(18) ! Scanning mode - kgds(12)=igdstmpl(19)/1000 ! Lat in 1 - kgds(13)=igdstmpl(20)/1000 ! Lat in 2 - kgds(14)=igdstmpl(21)/1000 ! Lat of S. Pole of projection - kgds(15)=igdstmpl(22)/1000 ! Lon of S. Pole of projection - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - elseif (igds(5).eq.40) then ! Gaussian Lat/Lon grid - kgds(1)=4 - kgds(2)=igdstmpl(8) ! Ni - kgds(3)=igdstmpl(9) ! Nj - kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point - kgds(5)=igdstmpl(13)/1000 ! Long of 1st grid point - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 - kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point - kgds(8)=igdstmpl(16)/1000 ! Long of last grid point - kgds(9)=igdstmpl(17)/1000 ! Di - kgds(10)=igdstmpl(18) ! N - Number of parallels - kgds(11)=igdstmpl(19) ! Scanning mode - kgds(12)=0 - kgds(13)=0 - kgds(14)=0 - kgds(15)=0 - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - elseif (igds(5).eq.20) then ! Polar Stereographic Grid - kgds(1)=5 - kgds(2)=igdstmpl(8) ! Nx - kgds(3)=igdstmpl(9) ! Ny - kgds(4)=igdstmpl(10)/1000 ! Lat of 1st grid point - kgds(5)=igdstmpl(11)/1000 ! Long of 1st grid point - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(12),4).OR.btest(igdstmpl(12),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(12),3)) kgds(6)=kgds(6)+8 - kgds(7)=igdstmpl(14)/1000 ! Lon of orientation - kgds(8)=igdstmpl(15)/1000 ! Dx - kgds(9)=igdstmpl(16)/1000 ! Dy - kgds(10)=igdstmpl(17) ! Projection Center Flag - kgds(11)=igdstmpl(18) ! Scanning mode - kgds(12)=0 - kgds(13)=0 - kgds(14)=0 - kgds(15)=0 - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - elseif (igds(5).eq.204) then ! Curvilinear Orthogonal - kgds(1)=204 - kgds(2)=igdstmpl(8) ! Ni - kgds(3)=igdstmpl(9) ! Nj - kgds(4)=0 - kgds(5)=0 - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 - kgds(7)=0 - kgds(8)=0 - kgds(9)=0 - kgds(10)=0 - kgds(11)=igdstmpl(19) ! Scanning mode - kgds(12)=0 - kgds(13)=0 - kgds(14)=0 - kgds(15)=0 - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - ! - ! Process irreg grid stuff, if necessary - ! - if (idefnum.ne.0) then - if (igdstmpl(8).eq.-1) then - kgds(2)=65535 - kgds(9)=65535 - endif - if (igdstmpl(9).eq.-1) then - kgds(3)=65535 - kgds(10)=65535 - endif - kgds(19)=0 - kgds(20)=33 - if (kgds(1).eq.1.OR.kgds(1).eq.3) kgds(20)=43 - kgds(21)=igds(2) ! num of grid points - do j=1,idefnum - kgds(21+j)=ideflist(j) - enddo - endif - elseif (igds(5).eq.32768) then ! Rotate Lat/Lon grid - kgds(1)=203 ! Arakawa Staggerred E/B grid - kgds(2)=igdstmpl(8) ! Ni - kgds(3)=igdstmpl(9) ! Nj - kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point - kgds(5)=igdstmpl(13)/1000 ! Lon of 1st grid point - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 - kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point - kgds(8)=igdstmpl(16)/1000 ! Lon of last grid point - kgds(9)=igdstmpl(17)/1000 ! Di - kgds(10)=igdstmpl(18)/1000 ! Dj - kgds(11)=igdstmpl(19) ! Scanning mode - kgds(12)=0 - kgds(13)=0 - kgds(14)=0 - kgds(15)=0 - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - ! - ! Process irreg grid stuff, if necessary - ! - if (idefnum.ne.0) then - if (igdstmpl(8).eq.-1) then - kgds(2)=65535 - kgds(9)=65535 - endif - if (igdstmpl(9).eq.-1) then - kgds(3)=65535 - kgds(10)=65535 - endif - kgds(19)=0 - kgds(20)=33 - if (kgds(1).eq.1.OR.kgds(1).eq.3) kgds(20)=43 - kgds(21)=igds(2) ! num of grid points - do j=1,idefnum - kgds(21+j)=ideflist(j) - enddo - endif - elseif (igds(5).eq.32769) then ! Rotate Lat/Lon grid - kgds(1)=205 ! Arakawa Staggerred for Non-E Stagger grid - kgds(2)=igdstmpl(8) ! Ni - kgds(3)=igdstmpl(9) ! Nj - kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point - kgds(5)=igdstmpl(13)/1000 ! Lon of 1st grid point - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 - kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point - kgds(8)=igdstmpl(16)/1000 ! Lon of last grid point - kgds(9)=igdstmpl(17)/1000 ! Di - kgds(10)=igdstmpl(18)/1000 ! Dj - kgds(11)=igdstmpl(19) ! Scanning mode - kgds(12)=igdstmpl(20)/1000 - kgds(13)=igdstmpl(21)/1000 - kgds(14)=0 - kgds(15)=0 - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - else - Print *,'gdt2gds: Unrecognized GRIB2 GDT = 3.',igds(5) - iret=1 - kgds(1:22)=0 - return - endif - ! - ! Can we determine NCEP grid number ? - ! - igrid=255 - do j=254,1,-1 - !do j=225,225 - kgds71=0 - kgds72=0 - call w3fi71(j,kgds71,ierr) - if (ierr.ne.0) cycle - ! convert W to E for longitudes - if (kgds71(3).eq.0) then ! lat/lon - if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) - if (kgds71(10).lt.0) kgds71(10)=360000+kgds71(10) - elseif (kgds71(3).eq.1) then ! mercator - if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) - if (kgds71(10).lt.0) kgds71(10)=360000+kgds71(10) - elseif (kgds71(3).eq.3) then ! lambert conformal - if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) - if (kgds71(9).lt.0) kgds71(9)=360000+kgds71(9) - if (kgds71(18).lt.0) kgds71(18)=360000+kgds71(18) - elseif (kgds71(3).eq.4) then ! Guassian lat/lon - if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) - if (kgds71(10).lt.0) kgds71(10)=360000+kgds71(10) - elseif (kgds71(3).eq.5) then ! polar stereographic - if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) - if (kgds71(9).lt.0) kgds71(9)=360000+kgds71(9) - endif - call r63w72(idum,kgds,jdum,kgds72) - if (kgds72(3).eq.3) kgds72(14)=0 ! lambert conformal fix - if (kgds72(3).eq.1) kgds72(15:18)=0 ! mercator fix - if (kgds72(3).eq.5) kgds72(14:18)=0 ! polar str fix - ! print *,' kgds71(',j,')= ', kgds71(1:30) - ! print *,' kgds72 = ', kgds72(1:30) - if (all(kgds71.eq.kgds72)) then - igrid=j - return - endif - enddo - - return -end subroutine gdt2gds diff --git a/utils/makepds.F90 b/utils/makepds.F90 deleted file mode 100644 index ca82c3502..000000000 --- a/utils/makepds.F90 +++ /dev/null @@ -1,528 +0,0 @@ -!> @file -!> @brief Create a GRIB1 PDS (Section 1). -!> @author Stephen Gilbert @date 2003-06-12 - -!> This routine creates a GRIB1 PDS (Section 1) from appropriate -!> information from a GRIB2 Product Definition Template. -!> -!> @note Use pds2pdtens for ensemble related PDS. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-12 | Gilbert | Initial. -!> 2005-04-19 | Gilbert | Changed scaling factor used with potential vorticity surfaces. -!> 2007-05-08 | VUONG | Add Product Definition Template entries 120-124, 131, 88, 45, 47. -!> 2007-05-14 | Boi Vuong | Added Time Range Indicator 51 (Climatological Mean Value) -!> 2007-10-24 | Boi Vuong | Added level 8 (Nominal top of atmosphere) -!> 2009-05-19 | Boi Vuong | Added levels 10(Entire Atmosphere), 11(Cumulonimbus Base),12(Cumulonimbus Top) and level 126(Isobaric Pa) -!> 2009-12-14 | Boi Vuong | Added check for WAFS to use PDT 4.15 for Icing, Turbulence and Cumulonimbus -!> 2010-08-10 | Boi Vuong | Added check for FNMOC to use TMP as TMAX and TMIN - Removed check WAFS MAX wind level -!> 2011-10-24 | Boi Vuong | Added check for NAM (NMM-B) parameters to set statistical processing as MAX and MIN -!> 2012-03-29 | Boi Vuong | Added check Time Range for APCP in FNMOC -!> 2014-05-20 | Boi Vuong | Added check Time Range after F252 -!> 2014-11-14 | Boi Vuong | Added check Time Range for 15-hr or 18-hr or 21-hr or 24-hr Accumulation for APCP after F240 -!> 2018-07-26 | Boi Vuong | Added check Time Range for continuous accumulated APCP after F252 when convert from grib2 to grib1 -!> -!> @param[in] idisc GRIB2 discipline from Section 0. -!> @param[in] idsect GRIB2 Section 1 info. -!> - idsect(1) Id of orginating centre (Common Code Table C-1) -!> - idsect(2) Id of orginating sub-centre (local table) -!> - idsect(3) GRIB Master Tables Version Number (Code Table 1.0) -!> - idsect(4) GRIB Local Tables Version Number (Code Table 1.1) -!> - idsect(5) Significance of Reference Time (Code Table 1.2) -!> - idsect(6) Reference Time - Year (4 digits) -!> - idsect(7) Reference Time - Month -!> - idsect(8) Reference Time - Day -!> - idsect(9) Reference Time - Hour -!> - idsect(10) Reference Time - Minute -!> - idsect(11) Reference Time - Second -!> - idsect(12) Production status of data (Code Table 1.3) -!> - idsect(13) Type of processed data (Code Table 1.4) -!> @param[in] ipdsnum GRIB2 Product Definition Template Number -!> @param[in] ipdstmpl GRIB2 Product Definition Template entries for PDT 4.ipdsnum -!> @param[in] ibmap GRIB2 bitmap indicator from octet 6, Section 6. -!> @param[in] idrsnum GRIB2 Data Representation Template Number -!> @param[in] idrstmpl GRIB2 Data Representation Template entries -!> @param[out] kpds GRIB1 PDS info as specified in W3FI63. -!> - 1 id of center -!> - 2 generating process id number -!> - 3 grid definition -!> - 4 gds/bms flag (right adj copy of octet 8) -!> - 5 indicator of parameter -!> - 6 type of level -!> - 7 height/pressure , etc of level -!> - 8 year including (century-1) -!> - 9 month of year -!> - 10 day of month -!> - 11 hour of day -!> - 12 minute of hour -!> - 13 indicator of forecast time unit -!> - 14 time range 1 -!> - 15 time range 2 -!> - 16 time range flag -!> - 17 number included in average -!> - 18 version nr of grib specification -!> - 19 version nr of parameter table -!> - 20 nr missing from average/accumulation -!> - 21 century of reference time of data -!> - 22 units decimal scale factor -!> - 23 subcenter number -!> @param[out] iret Error return value: -!> - 0 Successful -!> - 1 Don't know what to do with pre-defined bitmap. -!> - 2 Unrecognized GRIB2 PDT 4.ipdsnum -!> -!> @author Stephen Gilbert @date 2003-06-12 -subroutine makepds(idisc,idsect,ipdsnum,ipdstmpl,ibmap, & - idrsnum,idrstmpl,kpds,iret) - - use params - - integer,intent(in) :: idsect(*),ipdstmpl(*),idrstmpl(*) - integer,intent(in) :: ipdsnum,idisc,idrsnum,ibmap - integer,intent(out) :: kpds(*) - integer,intent(out) :: iret - - iret=0 - ipos=0 - kpds(1:24)=0 - if ( (ipdsnum.lt.0).OR.(ipdsnum.gt.15) ) then - print *,'makepds: Don:t know GRIB2 PDT 4.',ipdsnum - iret=2 - return - endif - - kpds(1)=idsect(1) - kpds(2)=ipdstmpl(5) - kpds(3)=255 - kpds(4)=128 - if ( ibmap.ne.255 ) kpds(4)=kpds(4)+64 - if ( ibmap.ge.1.AND.ibmap.le.253 ) then - print *,'makepds: Don:t know about predefined bit-map ',ibmap - iret=1 - return - endif - call param_g2_to_g1(idisc,ipdstmpl(1),ipdstmpl(2),kpds(5), & - kpds(19)) - ! - ! Special parameters for ICAO WAFS (Max Icing, TP and CAT) - ! - If (ipdstmpl(16).eq.2.and.ipdstmpl(1).eq.19.and. & - ipdstmpl(2).eq.20) kpds(5) = 169 - If (ipdstmpl(16).eq.2.and.ipdstmpl(1).eq.19.and. & - ipdstmpl(2).eq.21) kpds(5) = 171 - If (ipdstmpl(16).eq.2.and.ipdstmpl(1).eq.19.and. & - ipdstmpl(2).eq.22) kpds(5) = 173 - ! - ! Special parameters for NAM (NMMB) - ! - If (idisc.eq.0.and.ipdstmpl(1).eq.2) then - if (ipdstmpl(2).eq.220) then - kpds(5) = 237 - kpds(19) = 129 - end if - if (ipdstmpl(2).eq.221) then - kpds(5) = 238 - kpds(19) = 129 - end if - if (ipdstmpl(2).eq.222) then - kpds(5) = 253 - kpds(19) = 129 - end if - if (ipdstmpl(2).eq.223) then - kpds(5) = 254 - kpds(19) = 129 - end if - endif - ! - If (idisc.eq.0.and.ipdstmpl(2).eq.16 & - .and.ipdstmpl(3).eq.198) then - kpds(5) = 235 - kpds(19) = 129 - endif - ! - If (idisc.eq.0.and.ipdstmpl(2).eq.7 & - .and.ipdstmpl(3).eq.199) then - kpds(5) = 236 - kpds(19) = 129 - endif - ! - ! Special parameters for ICAO Height at CB Base and Top - ! in GRIB1 Table 140 - ! - If (ipdstmpl(1).eq.3.and.ipdstmpl(2).eq.3) then - If (ipdstmpl(10).eq.11) then - kpds(19) = 140 - kpds(5) = 179 - end if - If (ipdstmpl(10).eq.12) then - kpds(19) = 140 - kpds(5) = 180 - end if - end if - ! - call levelcnv(ipdstmpl,kpds(6),kpds(7)) ! level - kpds(8)=mod(idsect(6),100) - if ( kpds(8).eq.0 ) kpds(8)=100 - kpds(9)=idsect(7) ! Year - kpds(10)=idsect(8) ! Month - kpds(11)=idsect(9) ! Day - kpds(12)=idsect(10) ! Hour - if ( ipdstmpl(8).ne.13 ) then - kpds(13)=ipdstmpl(8) ! Time Unit - else - kpds(13)=254 - endif - kpds(14)=ipdstmpl(9) ! P1 - if ( ipdsnum.le.7 ) then ! P2 - kpds(15)=0 - kpds(16)=0 - kpds(20)=0 - if ( kpds(14).eq.0 ) kpds(16)=1 - if ( kpds(14).gt.255 ) kpds(16)=10 - if ( ipdstmpl(5).eq.77.OR.ipdstmpl(5).eq.81.OR. & - ipdstmpl(5).eq.96.OR.ipdstmpl(5).eq.80.OR. & - ipdstmpl(5).eq.82.OR.ipdstmpl(5).eq.120.OR. & - ipdstmpl(5).eq.47.OR.ipdstmpl(5).eq.11 ) then - kpds(16)=10 - end if - if (ipdstmpl(5).eq.84.AND.kpds(5).eq.154)kpds(16) = 10 - ! - ! NOAA Wave Watch III and Coastal Ocean Circulation - ! and Alaska Waters Regional Wave Model - ! - if ( ipdstmpl(5).eq.88.OR.ipdstmpl(5).eq.121 & - .OR.ipdstmpl(5).eq.122.OR.ipdstmpl(5).eq.123 & - .OR.ipdstmpl(5).eq.124.OR.ipdstmpl(5).eq.125 & - .OR.ipdstmpl(5).eq.131.OR.ipdstmpl(5).eq.45 & - .OR.ipdstmpl(5).eq.11 ) then - kpds(16) = 0 - ! - ! Level Surface set to 1 - ! - if (kpds(5).eq.80.OR.kpds(5).eq.82.OR. & - kpds(5).eq.88.OR.kpds(5).eq.49.OR. & - kpds(5).eq.50) kpds(7)=1 ! Level Surface - if (ipdstmpl(5).eq.122.OR.ipdstmpl(5).eq.124.OR. & - ipdstmpl(5).eq.131.OR.ipdstmpl(5).eq.123.OR. & - ipdstmpl(5).eq.125.OR.ipdstmpl(5).eq.88.OR. & - ipdstmpl(5).eq.121) kpds(7)=1 - if (idsect(1).eq.54.AND.ipdstmpl(5).eq.45) kpds(16) = 10 - endif - else - selectcase (ipdsnum) - case(8) - ipos=24 - case(9) - ipos=31 - case(10) - ipos=25 - case(11) - ipos=27 - case(12) - ipos=26 - case(13) - ipos=40 - case(14) - ipos=39 - end select - kpds(15)=ipdstmpl(ipos+3)+kpds(14) ! P2 - selectcase (ipdstmpl(ipos)) - case (255) - kpds(16)=2 - case (0) - kpds(16)=3 - case (1) - kpds(16)=4 - case (2) - kpds(16)=2 - case (3) - kpds(16)=2 - case (4) - kpds(16)=5 - case (51) - kpds(16)=51 - end select - kpds(20)=ipdstmpl(ipos-1) - endif - if (ipdstmpl(9) .ge. 252) then - if (ipdstmpl(ipos+3).eq.3) then - kpds(13)= 10 ! Forecast time unit is 3-hour - kpds(14)=ipdstmpl(9)/3 ! Time range P1 - kpds(15)=ipdstmpl(ipos+3)/3+kpds(14) ! Time range P2 - else if (ipdstmpl(ipos+3).eq.6) then - kpds(13)= 11 ! Forecast time unit is 6-hour - kpds(14)=ipdstmpl(9)/6 ! Time range P1 - kpds(15)=ipdstmpl(ipos+3)/6+kpds(14) ! Time range P2 - else if (ipdstmpl(ipos+3).eq.12) then - kpds(13)= 12 ! Forecast time unit is 12-hour - kpds(14)=ipdstmpl(9)/12 ! Time range P1 - kpds(15)=ipdstmpl(ipos+3)/12+kpds(14) ! Time range P2 - end if - end if - if (ipdsnum .eq. 8 .AND. ipdstmpl(9) .eq. 0) then - if (ipdstmpl(ipos+3).ge.252) then - kpds(13)= 10 ! Forecast time unit is hour - kpds(14)=ipdstmpl(9)/3 ! Time range P1 - kpds(15)=ipdstmpl(ipos+3)/3+kpds(14) ! Time range P2 - end if - end if - ! - ! Checking total preciptation for 15-hr or 18-hr or 21-hr or 24-hr accumulation - ! after forecast hour F240 - ! - if (ipdstmpl(9) .ge. 240 )then - if ( ipdstmpl(ipos+3).eq.15 .OR. ipdstmpl(ipos+3).eq.18 & - .OR. ipdstmpl(ipos+3).eq.21 .OR. & - ipdstmpl(ipos+3).eq.24 ) then - kpds(13)= 10 ! Forecast time unit is 3-hour - kpds(14)=ipdstmpl(9)/3 ! Time range P1 - kpds(15)=ipdstmpl(ipos+3)/3+kpds(14) ! Time range P2 - end if - end if - ! - ! Checking Unit of Time Range for FNMOC (APCP) - ! - if (ipdstmpl(4).eq.58 .AND. ipdsnum.eq.11 .AND. & - (ipdstmpl(1).eq.1 .AND.ipdstmpl(2).eq.8) & - .AND. (ipdstmpl(10).eq.1)) then - if (ipdstmpl(9) .ge. 252) then - kpds(13)= 11 ! Forecast time unit is 6-hour - kpds(14)=ipdstmpl(9)/6 ! Time range P1 - kpds(15)=ipdstmpl(ipos+3)/6+kpds(14) ! Time range P2 - else - kpds(13)= 1 ! Forecast time unit is 1-hour - kpds(14)=ipdstmpl(9) ! Time range P1 - end if - end if - ! - ! Special case for FNMOC (TMAX and TMIN) - ! - if (ipdstmpl(4).eq.58 .AND. ipdsnum.eq.11 .AND. & - (ipdstmpl(1).eq.0 & - .AND.ipdstmpl(2).eq.0).AND.(ipdstmpl(10).eq.103)) then - kpds(16) = 2 - ! For Maximum Temperature - If (ipdstmpl(27).eq.2 .AND. ipdstmpl(1).eq.0 .AND. & - ipdstmpl(2).eq.0) kpds(5) = 15 - ! For Minimum Temperature - If (ipdstmpl(27).eq.3 .AND. ipdstmpl(1).eq.0 .AND. & - ipdstmpl(2).eq.0) kpds(5) = 16 - end if - ! - ! Special case for WAFS (Mean/MAx IP,CTP and CAT) - ! - if (ipdstmpl(5).eq.96.AND.((ipdstmpl(1).eq.19) & - .AND.(ipdstmpl(2).eq.20.or.ipdstmpl(2).eq.21.or. & - ipdstmpl(2).eq.22)).AND.(ipdstmpl(10).eq.100)) then - kpds(16) = 10 - end if - ! - kpds(17)=0 - kpds(18)=1 ! GRIB edition - kpds(21)=(idsect(6)/100)+1 ! Century - if ( kpds(8).eq.100 ) kpds(21)=idsect(6)/100 - kpds(22)=idrstmpl(3) ! Decimal scale factor - kpds(23)=idsect(2) ! Sub-center - return -end subroutine makepds - - -!> This routine converts Level/layer information from a GRIB2 Product -!> Definition Template to GRIB1 Level type and Level value. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-12 | Gilbert | Initial -!> 2007-10-24 | Boi Vuong | Added level 8 (Nominal top of atmosphere) -!> 2011-01-13 | Boi Vuong | Added level/layer values from 235 to 239 -!> -!> @param[in] ipdstmpl GRIB2 Product Definition Template values -!> @param[out] ltype GRIB1 level type (PDS octet 10) -!> @param[out] lval GRIB1 level/layer value(s) (PDS octets 11 and 12) -!> -!> @author Stephen Gilbert @date 2003-06-12 -subroutine levelcnv(ipdstmpl,ltype,lval) - integer,intent(in) :: ipdstmpl(*) - integer,intent(out) :: ltype,lval - - ltype=255 - lval=0 - ltype1=ipdstmpl(10) - ltype2=ipdstmpl(13) - - if ( ltype1.eq.10.AND.ltype2.eq.255 ) then - ltype=200 - lval=0 - elseif ( ltype1.eq.11.AND.ltype2.eq.255 ) then - ltype=216 - lval=0 - elseif ( ltype1.eq.12.AND.ltype2.eq.255 ) then - ltype=217 - lval=0 - elseif ( ltype1.lt.100.AND.ltype2.eq.255 ) then - ltype=ltype1 - lval=0 - elseif ( ltype1.eq.1.AND.ltype2.eq.8 ) then - ltype=ltype1 - lval=0 - elseif ( ltype1.eq.10.AND.ltype2.eq.255 ) then - ltype=200 - lval=0 - elseif ( ltype1.eq.235.AND.ltype2.eq.255 ) then - ltype=235 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1) - elseif ( ltype1.ge.200.AND.ltype2.eq.255 ) then - ltype=ltype1 - lval=0 - elseif (ltype1.eq.100.AND.ltype2.eq.255 ) then - ltype=100 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1/100.) - elseif (ltype1.eq.100.AND.ltype2.eq.100 ) then - ltype=101 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1/1000.) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2/1000.) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.101.AND.ltype2.eq.255 ) then - ltype=102 - lval=0 - elseif (ltype1.eq.102.AND.ltype2.eq.255 ) then - ltype=103 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1) - elseif (ltype1.eq.102.AND.ltype2.eq.102 ) then - ltype=104 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.103.AND.ltype2.eq.255 ) then - ltype=105 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1) - elseif (ltype1.eq.103.AND.ltype2.eq.103 ) then - ltype=106 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1/100.) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2/100.) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.104.AND.ltype2.eq.255 ) then - ltype=107 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1*10000.) - elseif (ltype1.eq.104.AND.ltype2.eq.104 ) then - ltype=108 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1*100.) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2*100.) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.105.AND.ltype2.eq.255 ) then - ltype=109 - lval=ipdstmpl(12) - elseif (ltype1.eq.105.AND.ltype2.eq.105 ) then - ltype=110 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.106.AND.ltype2.eq.255 ) then - ltype=111 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1*100.) - elseif (ltype1.eq.106.AND.ltype2.eq.106 ) then - ltype=112 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1*100.) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2*100.) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.107.AND.ltype2.eq.255 ) then - ltype=113 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1) - elseif (ltype1.eq.107.AND.ltype2.eq.107 ) then - ltype=114 - rscal1=10.**(-ipdstmpl(11)) - lval1=475-nint(real(ipdstmpl(12))*rscal1) - rscal2=10.**(-ipdstmpl(14)) - lval2=475-nint(real(ipdstmpl(15))*rscal2) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.108.AND.ltype2.eq.255 ) then - ltype=115 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1/100.) - elseif (ltype1.eq.108.AND.ltype2.eq.108 ) then - ltype=116 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1/100.) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2/100.) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.109.AND.ltype2.eq.255 ) then - ltype=117 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1*1000000000.) - elseif (ltype1.eq.111.AND.ltype2.eq.255 ) then - ltype=119 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1*10000.) - elseif (ltype1.eq.111.AND.ltype2.eq.111 ) then - ltype=120 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1*100.) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2*100.) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.160.AND.ltype2.eq.255 ) then - ltype=160 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1) - elseif ((ltype1.ge.236.AND.ltype1.le.239).AND. & - (ltype2.ge.236.AND.ltype2.le.239)) then - ltype=ltype1 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2) - lval=(lval1*256)+lval2 - else - print *,'levelcnv: GRIB2 Levels ',ltype1,ltype2, & - ' not recognized.' - ltype=255 - endif - - ! High resolution stuff - ! elseif (ltype.eq.121) then - ! ipdstmpl(10)=100 - ! ipdstmpl(12)=(1100+(lval/256))*100 - ! ipdstmpl(13)=100 - ! ipdstmpl(15)=(1100+mod(lval,256))*100 - ! elseif (ltype.eq.125) then - ! ipdstmpl(10)=103 - ! ipdstmpl(11)=-2 - ! ipdstmpl(12)=lval - ! elseif (ltype.eq.128) then - ! ipdstmpl(10)=104 - ! ipdstmpl(11)=-3 - ! ipdstmpl(12)=1100+(lval/256) - ! ipdstmpl(13)=104 - ! ipdstmpl(14)=-3 - ! ipdstmpl(15)=1100+mod(lval,256) - ! elseif (ltype.eq.141) then - ! ipdstmpl(10)=100 - ! ipdstmpl(12)=(lval/256)*100 - ! ipdstmpl(13)=100 - ! ipdstmpl(15)=(1100+mod(lval,256))*100 - - return -end subroutine levelcnv diff --git a/utils/makepdsens.F90 b/utils/makepdsens.F90 deleted file mode 100644 index 7767afc45..000000000 --- a/utils/makepdsens.F90 +++ /dev/null @@ -1,156 +0,0 @@ -!> @file -!> @brief Create GRIB1 NCEP Ensemble PDS extension information from a -!> GRIB2 Product Definition Template. -!> @author Stephen Gilbert @date 2003-06-12 - -!> This routine creates the GRIB1 NCEP Ensemble PDS extension -!> information from appropriate information from a GRIB2 Product -!> Definition Template. -!> -!> @note Use pds2pdtens for ensemble related PDS. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-12 | Gilbert | Initial -!> 2007-05-14 | Boi Vuong | Corrected scale factor probabilities -!> 2010-07-26 | Boi Vuong | Added two type of ensemblers (4 and 192) -!> -!> @param[in] ipdsnum GRIB2 Product Definition Template Number -!> @param[in] ipdstmpl GRIB2 Product Definition Template entries for -!> PDT 4.ipdsnum -!> @param[inout] kpds GRIB1 PDS info as specified in W3FI63. -!> - 1 id of center -!> - 2 generating process id number -!> - 3 grid definition -!> - 4 gds/bms flag (right adj copy of octet 8) -!> - 5 indicator of parameter -!> - 6 type of level -!> - 7 height/pressure , etc of level -!> - 8 year including (century-1) -!> - 9 month of year -!> - 10 day of month -!> - 11 hour of day -!> - 12 minute of hour -!> - 13 indicator of forecast time unit -!> - 14 time range 1 -!> - 15 time range 2 -!> - 16 time range flag -!> - 17 number included in average -!> - 18 version nr of grib specification -!> - 19 version nr of parameter table -!> - 20 nr missing from average/accumulation -!> - 21 century of reference time of data -!> - 22 units decimal scale factor -!> - 23 subcenter number -!> @param[out] kens Ensemble identification for PDS octets 41-45 -!> @param[out] kprob Ensemble probability info for PDS octets 46 47 -!> @param[out] xprob Ensemble probability info for PDS octets 48-55 -!> @param[out] kclust Ensemble cluster info for PDS octets 61-76 -!> @param[out] kmembr Ensemble membership info for PDS octest 77-86 -!> @param[out] iret Error return value: -!> - 0 Successful -!> - 2 Unrecognized GRIB2 PDT 4.ipdsnum -!> -!> @author Stephen Gilbert @date 2003-06-12 -subroutine makepdsens(ipdsnum,ipdstmpl,kpds,kens,kprob, & - xprob,kclust,kmembr,iret) - use params - - integer,intent(in) :: ipdstmpl(*) - integer,intent(in) :: ipdsnum - integer,intent(inout) :: kpds(*) - integer,intent(out) :: kens(5),kprob(2) - integer,intent(out) :: kclust(16),kmembr(80) - real,intent(out) :: xprob(2) - integer,intent(out) :: iret - - iret=0 - kpds(23)=2 ! subcenter = ensemble - - kens(1:5)=0 - kprob(1:2)=0 - xprob(1:2)=0. - kclust(1:16)=0 - kmembr(1:80)=0 - ! - ! Individual Ensemble Fcst - ! - if (ipdsnum.eq.1.OR.ipdsnum.eq.11) then - kens(1)=1 - selectcase (ipdstmpl(16)) - case(0) - kens(2)=1 - kens(3)=1 - case(1) - kens(2)=1 - kens(3)=2 - case(2) - kens(2)=2 - kens(3)=ipdstmpl(17) - case(3) - kens(2)=3 - kens(3)=ipdstmpl(17) - case(4) - kens(2)=3 - kens(3)=ipdstmpl(17) - case(192) - kens(2)=3 - kens(3)=ipdstmpl(17) - end select - kens(4)=1 - kens(5)=255 - ! - ! Probability Fcst - ! - elseif (ipdsnum.eq.5.OR.ipdsnum.eq.9) then - kens(1)=1 - kens(2)=5 - kens(3)=0 - kens(4)=0 - kens(5)=255 - kprob(1)=kpds(5) - kpds(5)=191 - kprob(2)=ipdstmpl(18)+1 - if (kprob(2).eq.1) then - rscale=10.**ipdstmpl(19) - xprob(1)=real(ipdstmpl(20))/rscale - xprob(2)=0.0 - elseif (kprob(2).eq.2) then - xprob(1)=0.0 - rscale=10.**ipdstmpl(21) - xprob(2)=real(ipdstmpl(22))/rscale - elseif (kprob(2).eq.3) then - rscale=10.**ipdstmpl(19) - xprob(1)=real(ipdstmpl(20))/rscale - rscale=10.**ipdstmpl(21) - xprob(2)=real(ipdstmpl(22))/rscale - endif - kclust(1)=ipdstmpl(17) - ! - ! Derived Ensemble Fcst - ! - elseif (ipdsnum.eq.2.OR.ipdsnum.eq.12) then - kens(1)=1 - kens(2)=5 - kens(3)=0 - selectcase (ipdstmpl(16)) - case(0) - kens(4)=1 - case(1) - kens(4)=2 - case(2) - kens(4)=11 - case(3) - kens(4)=12 - end select - !kens(5)=89 - kens(5)=0 - kclust(1)=ipdstmpl(17) - else - print *,'makepdsens: Don:t know GRIB2 PDT 4.',ipdsnum - iret=2 - endif - - return -end subroutine makepdsens diff --git a/utils/pds2pdt.F90 b/utils/pds2pdt.F90 deleted file mode 100644 index df59351ea..000000000 --- a/utils/pds2pdt.F90 +++ /dev/null @@ -1,490 +0,0 @@ -!> @file -!> @brief Convert a GRIB1 PDS (Section 1) info to a GRIB2 PDS (Section -!> 4) info. -!> @author Stephen Gilbert @date 2003-06-12 - -!> This routine converts a GRIB1 PDS (Section 1) info to a GRIB2 PDS -!> (Section 4) info with appropriate Product Definition Template. -!> -!> @note Use pds2pdtens for ensemble related PDS. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-12 | Gilbert | Initial. -!> 2005-04-19 | Gilbert | Changed scaling factor used with potential vorticity surfaces. -!> 2007-02-07 | Gilbert | fixed end date calculation -!> 2007-03-26 | Gordon | Added check for ECMWF data to reference ECMWF Conversion tables. -!> 2007-05-14 | Boi Vuong | Added Time Range Indicator 51 (Climatological Mean Value) -!> 2009-05-20 | Boi Vuong | Added check for WAFS to use PDT 4.8 for Max Wind -!> 2009-12-14 | Boi Vuong | Added check for WAFS to use PDT 4.15 for Icing, Turbulence and Cumulonimbus -!> 2010-02-18 | Boi Vuong | Added Time Range Indicator 7 -!> 2010-08-10 | Boi Vuong | Removed check for WAFS to use PDT 4.8 for Max Wind -!> 2011-10-24 | Boi Vuong | Added check for parameters (MAXUW, MAXVW, to set type of statistical processing (MIN and MAX) -!> -!> @param[in] kpds GRIB1 PDS info as specified in W3FI63. -!> @param[out] ipdsnum GRIB2 Product Definition Template Number -!> @param[out] ipdstmpl GRIB2 Product Definition Template entries for PDT 4.ipdsnum -!> @param[out] numcoord number of vertical discretisation values (not implemented) -!> @param[out] coordlist rtical discretisation values (not implemented) -!> @param[out] iret Error return value: -!> - 0 Successful -!> - 1 Unrecognized GRIB1 Time Range Indicator -!> -!> @author Stephen Gilbert @date 2003-06-12 -subroutine pds2pdt(kpds,ipdsnum,ipdstmpl,numcoord,coordlist, & - iret) - - use params - use params_ecmwf - - integer,intent(in) :: kpds(*) - integer,intent(out) :: ipdstmpl(*) - real,intent(out) :: coordlist(*) - integer,intent(out) :: ipdsnum,numcoord,iret - - integer :: idat(8),jdat(8) - real :: rinc(5) - logical :: ecmwf - - iret=0 - numcoord=0 - ecmwf=.false. - - if (kpds(1).eq.98) ecmwf=.true. - ! - ! Special check for WAFS products for parameters (Max Icing, TP and CAT) - ! to PDT 4.15 - ! - if ((kpds(2).eq.96 .AND. kpds(3).eq.45 .AND. & - kpds(16).eq.10) .AND. & - (kpds(19).eq.140 .AND. (kpds(5).ge.168 .AND. & - kpds(5).le.173))) then - ipdsnum=15 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - if (ecmwf) then ! treat ecmwf data conversion seperately - call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & - ipdstmpl(1),ipdstmpl(2)) - else - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - endif - ipdstmpl(3)=2 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - if (kpds(5).eq.168.or.kpds(5).eq.170.or. & ! statistical process WAFS-ICAO - kpds(5).eq.172) ipdstmpl(16)=0 ! for Mean Icing, CT, CAT - if (kpds(5).eq.169.or.kpds(5).eq.171.or. & ! statistical process WAFS-ICAO - kpds(5).eq.173) ipdstmpl(16)=2 ! for MAX Icing, CT, CAT - ipdstmpl(17)=3 ! Neighbor interpolation - ! Output values is set to nearest input values - ipdstmpl(18)=1 ! Number of data point (grid 45) - elseif (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then - ipdsnum=0 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - if (ecmwf) then ! treat ecmwf data conversion seperately - call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & - ipdstmpl(1),ipdstmpl(2)) - else - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - endif - if (kpds(16).eq.1) then - ipdstmpl(3)=0 - else - ipdstmpl(3)=2 - endif - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - !if (kpds(16).eq.10) then - ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) - !else - ipdstmpl(9)=kpds(14) - !endif - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - if (kpds(2).eq.96 .AND. kpds(3).eq.45 .AND. & - kpds(16).eq.10) then - if (kpds(5).eq.174) ipdstmpl(10) = 10 - if (kpds(5).eq.179) ipdstmpl(10) = 11 - if (kpds(5).eq.180) ipdstmpl(10) = 12 - end if - elseif (kpds(16).ge.2.AND.kpds(16).le.5) then - ipdsnum=8 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - if (ecmwf) then ! treat ecmwf data conversion seperately - call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & - ipdstmpl(1),ipdstmpl(2)) - else - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - endif - ipdstmpl(3)=2 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0.0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(16)=jdat(1) ! year of end time - ipdstmpl(17)=jdat(2) ! month of end time - ipdstmpl(18)=jdat(3) ! day of end time - ipdstmpl(19)=jdat(5) ! hour of end time - ipdstmpl(20)=jdat(6) ! minute of end time - ipdstmpl(21)=jdat(7) ! second of end time - ipdstmpl(22)=1 ! # of time ranges - ipdstmpl(23)=kpds(20) ! # of values missing - if (kpds(16).eq.2) then ! statistical process - ipdstmpl(24)=255 - elseif (kpds(16).eq.3) then - ipdstmpl(24)=0 - elseif (kpds(16).eq.4) then - ipdstmpl(24)=1 - elseif (kpds(16).eq.5) then - ipdstmpl(24)=4 - endif - ipdstmpl(25)=2 - if (kpds(19).eq.129 .AND. & - (kpds(5).eq.235 .or. kpds(5).eq.236 .or. & - kpds(5).eq.237 .or. kpds(5).eq.238 .or. & - kpds(5).eq.239 .or. kpds(5).eq.253 .or. & - kpds(5).eq.254 )) then - ipdstmpl(24)=2 - endif - ipdstmpl(26)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(26)=13 - ipdstmpl(27)=kpds(15)-kpds(14) - ipdstmpl(28)=255 - ipdstmpl(29)=0 - elseif (kpds(16).eq.7) then - ipdsnum=8 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - if (ecmwf) then ! treat ecmwf data conversion seperately - call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & - ipdstmpl(1),ipdstmpl(2)) - else - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - endif - ipdstmpl(3)=2 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)= - kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0.0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(16)=jdat(1) ! year of end time - ipdstmpl(17)=jdat(2) ! month of end time - ipdstmpl(18)=jdat(3) ! day of end time - ipdstmpl(19)=jdat(5) ! hour of end time - ipdstmpl(20)=jdat(6) ! minute of end time - ipdstmpl(21)=jdat(7) ! second of end time - ipdstmpl(22)=1 ! # of time ranges - ipdstmpl(23)=kpds(20) ! # of values missing - ipdstmpl(24)=0 - ipdstmpl(25)=2 - ipdstmpl(26)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(26)=13 - ipdstmpl(27)=kpds(15) + kpds(14) - ipdstmpl(28)=255 - ipdstmpl(29)=0 - elseif (kpds(16).eq.51) then - ipdsnum=8 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - if (ecmwf) then ! treat ecmwf data conversion seperately - call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & - ipdstmpl(1),ipdstmpl(2)) - else - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - endif - ipdstmpl(3)=2 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0.0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(16)=jdat(1) ! year of end time - ipdstmpl(17)=jdat(2) ! month of end time - ipdstmpl(18)=jdat(3) ! day of end time - ipdstmpl(19)=jdat(5) ! hour of end time - ipdstmpl(20)=jdat(6) ! minute of end time - ipdstmpl(21)=jdat(7) ! second of end time - ipdstmpl(22)=1 ! # of time ranges - ipdstmpl(23)=kpds(20) ! # of values missing - ipdstmpl(24)=51 ! Climatological Mean - ipdstmpl(25)=2 - ipdstmpl(26)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(26)=13 - ipdstmpl(27)=kpds(15)-kpds(14) - ipdstmpl(28)=255 - ipdstmpl(29)=0 - else - Print *,' Unrecognized Time Range Indicator = ',kpds(16) - Print *,'pds2pdt: Couldn:t construct PDS Template ' - iret=1 - endif - - return -end subroutine pds2pdt - -!> This routine converts a GRIB1 Level type and Level value to GRIB2 -!> values and fills in the appropriate PDT values for the level/layer -!> information. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-12 | Gilbert | Initial. -!> 2011-01-13 | Boi Vuong | Added level/layer values from 235 to 239 -!> -!> @param[in] ltype GRIB1 level type (PDS octet 10) -!> @param[in] lval GRIB1 level/layer value(s) (PDS octets 11 and 12) -!> @param[out] ipdstmpl GRIB2 Product Definition Template values. -!> -!> @author Stephen Gilbert @date 2003-06-12 -subroutine cnvlevel(ltype,lval,ipdstmpl) - - integer,intent(in) :: ltype,lval - integer,intent(inout) :: ipdstmpl(*) - - ipdstmpl(10)=ltype - ipdstmpl(11)=0 - ipdstmpl(12)=0 - ipdstmpl(13)=255 - ipdstmpl(14)=0 - ipdstmpl(15)=0 - - if (ltype.eq.100) then - ipdstmpl(12)=lval*100 - elseif (ltype.eq.101) then - ipdstmpl(10)=100 - ipdstmpl(12)=(lval/256)*1000 - ipdstmpl(13)=100 - ipdstmpl(15)=mod(lval,256)*1000 - elseif (ltype.eq.102) then - ipdstmpl(10)=101 - elseif (ltype.eq.103) then - ipdstmpl(10)=102 - ipdstmpl(12)=lval - elseif (ltype.eq.104) then - ipdstmpl(10)=102 - ipdstmpl(12)=lval/256 - ipdstmpl(13)=102 - ipdstmpl(15)=mod(lval,256) - elseif (ltype.eq.105) then - ipdstmpl(10)=103 - ipdstmpl(12)=lval - elseif (ltype.eq.106) then - ipdstmpl(10)=103 - ipdstmpl(12)=(lval/256)*100 - ipdstmpl(13)=103 - ipdstmpl(15)=mod(lval,256)*100 - elseif (ltype.eq.107) then - ipdstmpl(10)=104 - ipdstmpl(11)=4 - ipdstmpl(12)=lval - elseif (ltype.eq.108) then - ipdstmpl(10)=104 - ipdstmpl(11)=2 - ipdstmpl(12)=lval/256 - ipdstmpl(13)=104 - ipdstmpl(14)=2 - ipdstmpl(15)=mod(lval,256) - elseif (ltype.eq.109) then - ipdstmpl(10)=105 - ipdstmpl(12)=lval - elseif (ltype.eq.110) then - ipdstmpl(10)=105 - ipdstmpl(12)=lval/256 - ipdstmpl(13)=105 - ipdstmpl(15)=mod(lval,256) - elseif (ltype.eq.111) then - ipdstmpl(10)=106 - ipdstmpl(11)=2 - ipdstmpl(12)=lval - elseif (ltype.eq.112) then - ipdstmpl(10)=106 - ipdstmpl(11)=2 - ipdstmpl(12)=lval/256 - ipdstmpl(13)=106 - ipdstmpl(14)=2 - ipdstmpl(15)=mod(lval,256) - elseif (ltype.eq.113) then - ipdstmpl(10)=107 - ipdstmpl(12)=lval - elseif (ltype.eq.114) then - ipdstmpl(10)=107 - ipdstmpl(12)=475+(lval/256) - ipdstmpl(13)=107 - ipdstmpl(15)=475+mod(lval,256) - elseif (ltype.eq.115) then - ipdstmpl(10)=108 - ipdstmpl(12)=lval*100 - elseif (ltype.eq.116) then - ipdstmpl(10)=108 - ipdstmpl(12)=(lval/256)*100 - ipdstmpl(13)=108 - ipdstmpl(15)=mod(lval,256)*100 - elseif (ltype.eq.117) then - ipdstmpl(10)=109 - ipdstmpl(11)=9 - ipdstmpl(12)=lval - if ( btest(lval,15) ) then - ipdstmpl(12)=-1*mod(lval,32768) - endif - elseif (ltype.eq.119) then - ipdstmpl(10)=111 - ipdstmpl(11)=4 - ipdstmpl(12)=lval - elseif (ltype.eq.120) then - ipdstmpl(10)=111 - ipdstmpl(11)=2 - ipdstmpl(12)=lval/256 - ipdstmpl(13)=111 - ipdstmpl(14)=2 - ipdstmpl(15)=mod(lval,256) - elseif (ltype.eq.121) then - ipdstmpl(10)=100 - ipdstmpl(12)=(1100+(lval/256))*100 - ipdstmpl(13)=100 - ipdstmpl(15)=(1100+mod(lval,256))*100 - elseif (ltype.eq.125) then - ipdstmpl(10)=103 - ipdstmpl(11)=2 - ipdstmpl(12)=lval - elseif (ltype.eq.126) then - ipdstmpl(10)=100 - ipdstmpl(12)=lval - elseif (ltype.eq.128) then - ipdstmpl(10)=104 - ipdstmpl(11)=3 - ipdstmpl(12)=1100+(lval/256) - ipdstmpl(13)=104 - ipdstmpl(14)=3 - ipdstmpl(15)=1100+mod(lval,256) - elseif (ltype.eq.141) then - ipdstmpl(10)=100 - ipdstmpl(12)=(lval/256)*100 - ipdstmpl(13)=100 - ipdstmpl(15)=(1100+mod(lval,256))*100 - elseif (ltype.eq.160) then - ipdstmpl(10)=160 - ipdstmpl(12)=lval - elseif (ltype.gt.99.AND.ltype.lt.200) then - print *,'cnvlevel: GRIB1 Level ',ltype,' not recognized.' - ipdstmpl(10)=255 - elseif (ltype.eq.235) then - ipdstmpl(10)=ltype - ipdstmpl(12)=lval - elseif (ltype.eq.236) then - ipdstmpl(10)=ltype - ipdstmpl(12)=lval/256 - ipdstmpl(13)=ltype - ipdstmpl(15)=mod(lval,256) - elseif (ltype.ge.237.AND.ltype.le.239) then - ipdstmpl(10)=ltype - ipdstmpl(12)=lval - endif - - return -end subroutine cnvlevel diff --git a/utils/pds2pdtens.F90 b/utils/pds2pdtens.F90 deleted file mode 100644 index a7df0a770..000000000 --- a/utils/pds2pdtens.F90 +++ /dev/null @@ -1,640 +0,0 @@ -!> @file -!> @brief Convert a GRIB1 PDS (Section 1) that includes NCEP -!> ensemble PDS extensions to a GRIB2 PDS (Section 4) info. -!> @author Stephen Gilbert @date 2003-06-12 - -!> This routine converts a GRIB1 PDS (Section 1) that includes NCEP -!> ensemble PDS extensions to a GRIB2 PDS (Section 4) info with -!> appropriate Product Definition Template. -!> -!> @note Use routine pds2pdt for non ensemble related PDS. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-12 | Gilbert | Initial. -!> 2007-02-07 | Gilbert | fixed end date calculation -!> 2007-05-14 | Boi Vuong | Added Time Range Indicator 51 (Climatological Mean Value) -!> -!> @param[in] kpds GRIB1 PDS info as specified in W3FI63. -!> @param[in] kens Ensemble identification from PDS octets 41-45. -!> @param[in] kprob Ensemble probability info from PDS octets 46 & 47. -!> @param[in] xprob Ensemble probability info from PDS octets 48-55. -!> @param[in] kclust Ensemble cluster info from PDS octets 61-76. -!> @param[in] kmember- semble membership info from PDS octest 77-86. -!> @param[out] ipdsnum GRIB2 Product Definition Template Number. -!> @param[out] ipdstmpl GRIB2 Product Definition Template entries for PDT 4.ipdsnum. -!> @param[out] numcoord number of vertical discretisation values (not implemented). -!> @param[out] coordlist- rtical discretisation values (not implemented). -!> @param[out] iret Error return value: -!> - 0 = Successful -!> - 1 = Unrecognized GRIB1 Time Range Indicator for ensembles -!> - 2 = Unrecognized GRIB1 Ensemble type -!> - 10 = Unrecognized GRIB1 Time Range Indicator for probabilities -!> -!> @author Stephen Gilbert @date 2003-06-12 -subroutine pds2pdtens(kpds,kens,kprob,xprob,kclust,kmember, & - ipdsnum,ipdstmpl,numcoord,coordlist, & - iret) - - - use params - - integer,intent(in) :: kpds(*),kens(*),kprob(*),kclust(*) - integer,intent(in) :: kmember(*) - real,intent(in) :: xprob(*) - integer,intent(out) :: ipdstmpl(*) - real,intent(out) :: coordlist(*) - integer,intent(out) :: ipdsnum,numcoord,iret - - integer :: idat(8),jdat(8) - real :: rinc(5) - - iret=0 - numcoord=0 - if (kens(2).eq.1.or.kens(2).eq.2.or.kens(2).eq.3) then - ! individual ensemble fcst... - if (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then - ! At specific point in time... - ipdsnum=1 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=4 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - !if (kpds(16).eq.10) then - ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) - !else - ipdstmpl(9)=kpds(14) - !endif - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - if (kens(2).eq.1) then - ! if (kens(3).eq.1) ipdstmpl(16)=0 - ! if (kens(3).eq.2) ipdstmpl(16)=1 - ipdstmpl(16)=kens(3)-1 - ipdstmpl(17)=0 - elseif (kens(2).eq.2) then - ipdstmpl(16)=2 - ipdstmpl(17)=kens(3) - elseif (kens(2).eq.3) then - ipdstmpl(16)=3 - ipdstmpl(17)=kens(3) - endif - ipdstmpl(18)=10 - elseif (kpds(16).ge.2.AND.kpds(16).le.5) then - ! over time range... - ipdsnum=11 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=4 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - !ipdstmpl(9)=kpds(15) - if (kens(2).eq.1) then - ! if (kens(3).eq.1) ipdstmpl(16)=0 - ! if (kens(3).eq.2) ipdstmpl(16)=1 - ipdstmpl(16)=kens(3)-1 - ipdstmpl(17)=0 - elseif (kens(2).eq.2) then - ipdstmpl(16)=2 - ipdstmpl(17)=kens(3) - elseif (kens(2).eq.3) then - ipdstmpl(16)=3 - ipdstmpl(17)=kens(3) - endif - ipdstmpl(18)=10 - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(19)=jdat(1) ! year of end time - ipdstmpl(20)=jdat(2) ! month of end time - ipdstmpl(21)=jdat(3) ! day of end time - ipdstmpl(22)=jdat(5) ! hour of end time - ipdstmpl(23)=jdat(6) ! minute of end time - ipdstmpl(24)=jdat(7) ! second of end time - ipdstmpl(25)=1 - ipdstmpl(26)=0 - if (kpds(16).eq.2) then - ipdstmpl(27)=255 - if (kpds(5).eq.15) ipdstmpl(27)=2 - if (kpds(5).eq.16) ipdstmpl(27)=3 - elseif (kpds(16).eq.3) then - ipdstmpl(27)=0 - elseif (kpds(16).eq.4) then - ipdstmpl(27)=1 - elseif (kpds(16).eq.5) then - ipdstmpl(27)=4 - endif - ipdstmpl(28)=2 - ipdstmpl(29)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(29)=13 - ipdstmpl(30)=kpds(15)-kpds(14) - ipdstmpl(31)=255 - ipdstmpl(32)=0 - elseif (kpds(16).eq.51) then - ! over time range... - ipdsnum=11 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=4 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - !ipdstmpl(9)=kpds(15) - if (kens(2).eq.1) then - ! if (kens(3).eq.1) ipdstmpl(16)=0 - ! if (kens(3).eq.2) ipdstmpl(16)=1 - ipdstmpl(16)=kens(3)-1 - ipdstmpl(17)=0 - elseif (kens(2).eq.2) then - ipdstmpl(16)=2 - ipdstmpl(17)=kens(3) - elseif (kens(2).eq.3) then - ipdstmpl(16)=3 - ipdstmpl(17)=kens(3) - endif - ipdstmpl(18)=10 - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(19)=jdat(1) ! year of end time - ipdstmpl(20)=jdat(2) ! month of end time - ipdstmpl(21)=jdat(3) ! day of end time - ipdstmpl(22)=jdat(5) ! hour of end time - ipdstmpl(23)=jdat(6) ! minute of end time - ipdstmpl(24)=jdat(7) ! second of end time - ipdstmpl(25)=1 - ipdstmpl(26)=0 - ipdstmpl(27)=51 - ipdstmpl(28)=2 - ipdstmpl(29)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(29)=13 - ipdstmpl(30)=kpds(15)-kpds(14) - ipdstmpl(31)=255 - ipdstmpl(32)=0 - else - Print *,' Unrecognized Time Range Ind for ensembles = ', & - kpds(16),kens(2) - Print *,'pds2pdtens: Couldn:t construct PDS Template ' - iret=1 - endif - - elseif (kens(2).eq.5) then ! WHOLE or CLUSTERENSEMBLE type - if (kpds(5).eq.191.OR.kpds(5).eq.192) then ! probs - if (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then - ! At specific point in time... - ipdsnum=5 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kprob(1),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=5 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - !if (kpds(16).eq.10) then - ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) - !else - ipdstmpl(9)=kpds(14) - !endif - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - ipdstmpl(16)=0 !? - ipdstmpl(17)=kclust(1) !? - ipdstmpl(18)=kprob(2)-1 - if (ipdstmpl(18).eq.0.OR.ipdstmpl(18).eq.2) then - ipdstmpl(19)=3 - ipdstmpl(20)=nint(xprob(1)*1000.0) - else - ipdstmpl(19)=0 - ipdstmpl(20)=0 - endif - if (ipdstmpl(18).eq.1.OR.ipdstmpl(18).eq.2) then - ipdstmpl(21)=3 - ipdstmpl(22)=nint(xprob(2)*1000.0) - else - ipdstmpl(21)=0 - ipdstmpl(22)=0 - endif - elseif (kpds(16).ge.2.AND.kpds(16).le.5) then - ! over time range... - ipdsnum=9 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kprob(1),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=5 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - !ipdstmpl(9)=kpds(15) - ipdstmpl(16)=0 !? - ipdstmpl(17)=kclust(1) !? - ipdstmpl(18)=kprob(2)-1 - if (ipdstmpl(18).eq.0.OR.ipdstmpl(18).eq.2) then - ipdstmpl(19)=3 - ipdstmpl(20)=nint(xprob(1)*1000.0) - else - ipdstmpl(19)=0 - ipdstmpl(20)=0 - endif - if (ipdstmpl(18).eq.1.OR.ipdstmpl(18).eq.2) then - ipdstmpl(21)=3 - ipdstmpl(22)=nint(xprob(2)*1000.0) - else - ipdstmpl(21)=0 - ipdstmpl(22)=0 - endif - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(23)=jdat(1) ! year of end time - ipdstmpl(24)=jdat(2) ! month of end time - ipdstmpl(25)=jdat(3) ! day of end time - ipdstmpl(26)=jdat(5) ! hour of end time - ipdstmpl(27)=jdat(6) ! minute of end time - ipdstmpl(28)=jdat(7) ! second of end time - ipdstmpl(29)=1 - ipdstmpl(30)=0 - if (kpds(16).eq.2) then - ipdstmpl(31)=255 - if (kpds(5).eq.15) ipdstmpl(31)=2 - if (kpds(5).eq.16) ipdstmpl(31)=3 - elseif (kpds(16).eq.3) then - ipdstmpl(31)=0 - elseif (kpds(16).eq.4) then - ipdstmpl(31)=1 - elseif (kpds(16).eq.5) then - ipdstmpl(31)=4 - endif - ipdstmpl(32)=2 - ipdstmpl(33)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(33)=13 - ipdstmpl(34)=kpds(15)-kpds(14) - ipdstmpl(35)=255 - ipdstmpl(36)=0 - elseif (kpds(16).eq.51) then - ! over time range... - ipdsnum=9 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kprob(1),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=5 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - !ipdstmpl(9)=kpds(15) - ipdstmpl(16)=0 !? - ipdstmpl(17)=kclust(1) !? - ipdstmpl(18)=kprob(2)-1 - if (ipdstmpl(18).eq.0.OR.ipdstmpl(18).eq.2) then - ipdstmpl(19)=3 - ipdstmpl(20)=nint(xprob(1)*1000.0) - else - ipdstmpl(19)=0 - ipdstmpl(20)=0 - endif - if (ipdstmpl(18).eq.1.OR.ipdstmpl(18).eq.2) then - ipdstmpl(21)=3 - ipdstmpl(22)=nint(xprob(2)*1000.0) - else - ipdstmpl(21)=0 - ipdstmpl(22)=0 - endif - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(23)=jdat(1) ! year of end time - ipdstmpl(24)=jdat(2) ! month of end time - ipdstmpl(25)=jdat(3) ! day of end time - ipdstmpl(26)=jdat(5) ! hour of end time - ipdstmpl(27)=jdat(6) ! minute of end time - ipdstmpl(28)=jdat(7) ! second of end time - ipdstmpl(29)=1 - ipdstmpl(30)=0 - ipdstmpl(31)=51 - ipdstmpl(32)=2 - ipdstmpl(33)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(33)=13 - ipdstmpl(34)=kpds(15)-kpds(14) - ipdstmpl(35)=255 - ipdstmpl(36)=0 - else - Print *,' Unrecognized Time Range Ind for Probs = ', & - kpds(16),kens(2) - Print *,'pds2pdtens: Couldn:t construct PDS Template ' - iret=10 - endif - else ! Non-probablility Whole Ens Fcst - if (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then - ! At specific point in time... - ipdsnum=2 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=4 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - !if (kpds(16).eq.10) then - ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) - !else - ipdstmpl(9)=kpds(14) - !endif - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - if (kens(4).eq.1) then - ipdstmpl(16)=0 - elseif (kens(4).eq.2) then - ipdstmpl(16)=1 - elseif (kens(4).eq.11) then - ipdstmpl(16)=2 - elseif (kens(4).eq.12) then - ipdstmpl(16)=3 - endif - ipdstmpl(17)=kclust(1) - elseif (kpds(16).ge.2.AND.kpds(16).le.5) then - ! over time range... - ipdsnum=12 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=4 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - !ipdstmpl(9)=kpds(15) - if (kens(4).eq.1) then - ipdstmpl(16)=0 - elseif (kens(4).eq.2) then - ipdstmpl(16)=1 - elseif (kens(4).eq.11) then - ipdstmpl(16)=2 - elseif (kens(4).eq.12) then - ipdstmpl(16)=3 - endif - ipdstmpl(17)=kclust(1) - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(18)=jdat(1) ! year of end time - ipdstmpl(19)=jdat(2) ! month of end time - ipdstmpl(20)=jdat(3) ! day of end time - ipdstmpl(21)=jdat(5) ! hour of end time - ipdstmpl(22)=jdat(6) ! minute of end time - ipdstmpl(23)=jdat(7) ! second of end time - ipdstmpl(24)=1 - ipdstmpl(25)=0 - if (kpds(16).eq.2) then - ipdstmpl(26)=255 - if (kpds(5).eq.15) ipdstmpl(26)=2 - if (kpds(5).eq.16) ipdstmpl(26)=3 - elseif (kpds(16).eq.3) then - ipdstmpl(26)=0 - elseif (kpds(16).eq.4) then - ipdstmpl(26)=1 - elseif (kpds(16).eq.5) then - ipdstmpl(26)=4 - endif - ipdstmpl(27)=2 - ipdstmpl(28)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(28)=13 - ipdstmpl(29)=kpds(15)-kpds(14) - ipdstmpl(30)=255 - ipdstmpl(31)=0 - elseif (kpds(16).eq.51) then - ! over time range... - ipdsnum=12 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=4 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - !ipdstmpl(9)=kpds(15) - if (kens(4).eq.1) then - ipdstmpl(16)=0 - elseif (kens(4).eq.2) then - ipdstmpl(16)=1 - elseif (kens(4).eq.11) then - ipdstmpl(16)=2 - elseif (kens(4).eq.12) then - ipdstmpl(16)=3 - endif - ipdstmpl(17)=kclust(1) - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(18)=jdat(1) ! year of end time - ipdstmpl(19)=jdat(2) ! month of end time - ipdstmpl(20)=jdat(3) ! day of end time - ipdstmpl(21)=jdat(5) ! hour of end time - ipdstmpl(22)=jdat(6) ! minute of end time - ipdstmpl(23)=jdat(7) ! second of end time - ipdstmpl(24)=1 - ipdstmpl(25)=0 - ipdstmpl(26)=51 - ipdstmpl(27)=2 - ipdstmpl(28)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(28)=13 - ipdstmpl(29)=kpds(15)-kpds(14) - ipdstmpl(30)=255 - ipdstmpl(31)=0 - endif - endif - else - Print *,' Unrecognized Ensemble type = ',kens(2) - Print *,'pds2pdtens: Couldn:t construct PDS Template ' - iret=2 - endif - - return -end subroutine pds2pdtens diff --git a/utils/prlevel.F90 b/utils/prgrib2.F90 similarity index 76% rename from utils/prlevel.F90 rename to utils/prgrib2.F90 index 86e5d4221..d5120aa60 100644 --- a/utils/prlevel.F90 +++ b/utils/prgrib2.F90 @@ -1,6 +1,5 @@ !> @file -!> @brief Print level information to a character array, given the -!> GRIB2 Product Definition Template information. +!> @brief Subroutines for converting GRIB2 info to string output. !> @author Stephen Gilbert @date 2010-09-08 !> Print level information to a character array, given the GRIB2 @@ -280,3 +279,147 @@ subroutine frmt(cval, ival, iscal) return end subroutine frmt + +!> Convert date and time from GRIB2 info to string output. +!> +!> @param[in] ipdtn Product Definition Template Number ([Code Table +!> 4.0] +!> (https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table4-0.shtml)). +!> @param[in] ipdtmpl Array of data values for the Product Definition +!> Template specified by ipdtn. +!> @param[in] listsec1 Contains information read from GRIB +!> Identification Section 1. Must be dimensioned >= 13. +!> @param[out] tabbrev Character array that will get the date and time +!> string. Must be of length 100. +!> +!> @author Stephen Gilbert @date 2010-09-08 +subroutine prvtime(ipdtn, ipdtmpl, listsec1, tabbrev) + implicit none + + integer, intent(in) :: ipdtn + integer, intent(in) :: ipdtmpl(*), listsec1(*) + character(len = 110), intent(out) :: tabbrev + + character(len = 16) :: reftime, endtime + character(len = 12) :: tmpval2 + character(len = 12) :: tmpval + character(len = 10) :: tunit + integer, dimension(200) :: ipos, ipos2 + integer :: is, itemp, itemp2, iunit, iuni2t2, iunit2, iutpos, iutpos2, j + + data ipos /7*0, 16, 23, 17, 19, 18, 32, 31, 27*0, 17, 20, 0, 0, 22, & + 25, 43*0, 23, 109*0/ + + data ipos2 /7*0, 26, 33, 27, 29, 28, 42, 41, 27*0, 22, 30, 0, 0, 32, & + 35, 43*0, 33, 109*0/ + + tabbrev(1:100) = " " + + ! Determine unit of time range. + if ((ipdtn .ge. 0 .and. ipdtn .le. 15) .or. ipdtn .eq. 32 & + .or. ipdtn .eq. 50 .or. ipdtn .eq. 51 & + .or. ipdtn .eq. 91) then + iutpos = 8 + elseif (ipdtn .ge. 40 .and. ipdtn .le. 43) then + iutpos = 9 + elseif (ipdtn .ge. 44 .and. ipdtn .le. 47) then + iutpos = 14 + elseif (ipdtn .eq. 48) then + iutpos = 19 + elseif (ipdtn .eq. 52) then + iutpos = 11 + else + iutpos = 8 + endif + + ! Determine first unit of time range. + selectcase(ipdtmpl(iutpos)) + case (0) + tunit = "minute" + iunit = 1 + case (1) + tunit = "hour" + iunit = 1 + case (2) + tunit = "day" + iunit = 1 + case (3) + tunit = "month" + iunit = 1 + case (4) + tunit = "year" + iunit = 1 + case (10) + tunit = "hour" + iunit = 3 + case (11) + tunit = "hour" + iunit = 6 + case default + tunit = "hour" + iunit = 1 + end select + + ! Determine second unit of time range. + if (ipdtn .eq. 0) then + iunit2 = 1 + iutpos2 = 0 + else + iutpos2 = ipos2(ipdtn) + if (iutpos2 .gt. 0) then + selectcase(ipdtmpl(iutpos2)) + case (0) + iunit2 = 1 + case (1) + iunit2 = 1 + case (2) + iunit2 = 1 + case (3) + iuni2t2 = 1 + case (4) + iunit2 = 1 + case (10) + iunit2 = 3 + case (11) + iunit2 = 6 + case default + iunit2 = 1 + end select + endif + endif + + write(reftime, fmt = '(i4,3i2.2,":",i2.2,":",i2.2)') (listsec1(j), j = 6, 11) + itemp = abs(ipdtmpl(iutpos + 1)) * iunit + write(tmpval, '(I0)') itemp + write(tabbrev, fmt = '("valid at ", i4)') ipdtmpl(iutpos + 1) + + ! Determine Reference Time: Year, Month, Day, Hour, Minute, Second. + if ((ipdtn .ge. 0 .and. ipdtn .le. 7) .or. ipdtn .eq. 15 & + .or. ipdtn .eq. 20 .or. (ipdtn .ge. 30 .and. ipdtn .le. 32) & + .or. ipdtn .eq. 40 .or. ipdtn .eq. 41 .or. ipdtn .eq. 44 & + .or. ipdtn .eq. 45 .or. ipdtn .eq. 48 .or. & + (ipdtn .ge. 50 .and. ipdtn .le. 52)) then ! Point in time + tabbrev = "valid " // trim(tmpval) // " " // trim(tunit) // " after " // reftime + else + is = ipos(ipdtn) ! Continuous time interval + write(endtime, fmt = '(i4,3i2.2,":",i2.2,":",i2.2)') (ipdtmpl(j), j = is, is + 5) + itemp2 = abs(ipdtmpl(iutpos2 + 1)) * iunit2 + itemp2 = itemp + itemp2 + write(tmpval2, '(I0)') itemp2 + if (ipdtn .eq. 8 .and. ipdtmpl(9) .lt. 0) then + tabbrev = "(" // trim(tmpval) // " -" & + // trim(tmpval2) // ") valid " // trim(tmpval) // & + " " // trim(tunit) // " before " & + // reftime // " to " //endtime + elseif ((ipdtn .ge. 8 .and. ipdtn .le. 14) .or. & + (ipdtn .ge. 42 .and. ipdtn .le. 47) .or. & + ipdtn .eq. 91) then ! Continuous time interval + tabbrev = "(" // trim(tmpval) // " -" & + // trim(tmpval2) // " hr) valid " // trim(tmpval) // & + " " // trim(tunit) // " after " & + // reftime // " to " // endtime + endif + endif + + return +end subroutine prvtime \ No newline at end of file diff --git a/utils/prvtime.F90 b/utils/prvtime.F90 deleted file mode 100644 index 93e82e3cd..000000000 --- a/utils/prvtime.F90 +++ /dev/null @@ -1,147 +0,0 @@ -!> @file -!> @brief Convert date and time from GRIB2 info to string output. -!> @author Stephen Gilbert @date 2010-09-08 - -!> Convert date and time from GRIB2 info to string output. -!> -!> @param[in] ipdtn Product Definition Template Number ([Code Table -!> 4.0] -!> (https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table4-0.shtml)). -!> @param[in] ipdtmpl Array of data values for the Product Definition -!> Template specified by ipdtn. -!> @param[in] listsec1 Contains information read from GRIB -!> Identification Section 1. Must be dimensioned >= 13. -!> @param[out] tabbrev Character array that will get the date and time -!> string. Must be of length 100. -!> -!> @author Stephen Gilbert @date 2010-09-08 -subroutine prvtime(ipdtn, ipdtmpl, listsec1, tabbrev) - implicit none - - integer, intent(in) :: ipdtn - integer, intent(in) :: ipdtmpl(*), listsec1(*) - character(len = 110), intent(out) :: tabbrev - - character(len = 16) :: reftime, endtime - character(len = 12) :: tmpval2 - character(len = 12) :: tmpval - character(len = 10) :: tunit - integer, dimension(200) :: ipos, ipos2 - integer :: is, itemp, itemp2, iunit, iuni2t2, iunit2, iutpos, iutpos2, j - - data ipos /7*0, 16, 23, 17, 19, 18, 32, 31, 27*0, 17, 20, 0, 0, 22, & - 25, 43*0, 23, 109*0/ - - data ipos2 /7*0, 26, 33, 27, 29, 28, 42, 41, 27*0, 22, 30, 0, 0, 32, & - 35, 43*0, 33, 109*0/ - - tabbrev(1:100) = " " - - ! Determine unit of time range. - if ((ipdtn .ge. 0 .and. ipdtn .le. 15) .or. ipdtn .eq. 32 & - .or. ipdtn .eq. 50 .or. ipdtn .eq. 51 & - .or. ipdtn .eq. 91) then - iutpos = 8 - elseif (ipdtn .ge. 40 .and. ipdtn .le. 43) then - iutpos = 9 - elseif (ipdtn .ge. 44 .and. ipdtn .le. 47) then - iutpos = 14 - elseif (ipdtn .eq. 48) then - iutpos = 19 - elseif (ipdtn .eq. 52) then - iutpos = 11 - else - iutpos = 8 - endif - - ! Determine first unit of time range. - selectcase(ipdtmpl(iutpos)) - case (0) - tunit = "minute" - iunit = 1 - case (1) - tunit = "hour" - iunit = 1 - case (2) - tunit = "day" - iunit = 1 - case (3) - tunit = "month" - iunit = 1 - case (4) - tunit = "year" - iunit = 1 - case (10) - tunit = "hour" - iunit = 3 - case (11) - tunit = "hour" - iunit = 6 - case default - tunit = "hour" - iunit = 1 - end select - - ! Determine second unit of time range. - if (ipdtn .eq. 0) then - iunit2 = 1 - iutpos2 = 0 - else - iutpos2 = ipos2(ipdtn) - if (iutpos2 .gt. 0) then - selectcase(ipdtmpl(iutpos2)) - case (0) - iunit2 = 1 - case (1) - iunit2 = 1 - case (2) - iunit2 = 1 - case (3) - iuni2t2 = 1 - case (4) - iunit2 = 1 - case (10) - iunit2 = 3 - case (11) - iunit2 = 6 - case default - iunit2 = 1 - end select - endif - endif - - write(reftime, fmt = '(i4,3i2.2,":",i2.2,":",i2.2)') (listsec1(j), j = 6, 11) - itemp = abs(ipdtmpl(iutpos + 1)) * iunit - write(tmpval, '(I0)') itemp - write(tabbrev, fmt = '("valid at ", i4)') ipdtmpl(iutpos + 1) - - ! Determine Reference Time: Year, Month, Day, Hour, Minute, Second. - if ((ipdtn .ge. 0 .and. ipdtn .le. 7) .or. ipdtn .eq. 15 & - .or. ipdtn .eq. 20 .or. (ipdtn .ge. 30 .and. ipdtn .le. 32) & - .or. ipdtn .eq. 40 .or. ipdtn .eq. 41 .or. ipdtn .eq. 44 & - .or. ipdtn .eq. 45 .or. ipdtn .eq. 48 .or. & - (ipdtn .ge. 50 .and. ipdtn .le. 52)) then ! Point in time - tabbrev = "valid " // trim(tmpval) // " " // trim(tunit) // " after " // reftime - else - is = ipos(ipdtn) ! Continuous time interval - write(endtime, fmt = '(i4,3i2.2,":",i2.2,":",i2.2)') (ipdtmpl(j), j = is, is + 5) - itemp2 = abs(ipdtmpl(iutpos2 + 1)) * iunit2 - itemp2 = itemp + itemp2 - write(tmpval2, '(I0)') itemp2 - if (ipdtn .eq. 8 .and. ipdtmpl(9) .lt. 0) then - tabbrev = "(" // trim(tmpval) // " -" & - // trim(tmpval2) // ") valid " // trim(tmpval) // & - " " // trim(tunit) // " before " & - // reftime // " to " //endtime - elseif ((ipdtn .ge. 8 .and. ipdtn .le. 14) .or. & - (ipdtn .ge. 42 .and. ipdtn .le. 47) .or. & - ipdtn .eq. 91) then ! Continuous time interval - tabbrev = "(" // trim(tmpval) // " -" & - // trim(tmpval2) // " hr) valid " // trim(tmpval) // & - " " // trim(tunit) // " after " & - // reftime // " to " // endtime - endif - endif - - return -end subroutine prvtime diff --git a/utils/putgbexn.F90 b/utils/putgbexn.F90 deleted file mode 100644 index fd04cb571..000000000 --- a/utils/putgbexn.F90 +++ /dev/null @@ -1,222 +0,0 @@ -!> @file -!> @brief Pack and write a grib message. -!> @author Mark Iredell @date 94-04-01 - -!> Pack and write a grib message. This subprogram is nearly the inverse -!> of getgbe. -!> -!> @note Subprogram can be called from a multiprocessing environment. -!> Do not engage the same logical unit from more than one processor. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 94-04-01 | Iredell | Initial. -!> 95-10-31 | Iredell | Removed saves and prints -!> 97-02-11 | Y. Zhu | Included probability and cluster arguments -!> 2002-03-18 | Gilbert | Modified from putgbex to account for binary scale factors. -!> -!> @param[in] lugb teger unit of the unblocked grib data file -!> @param[in] kf teger number of data points -!> @param[in] kpds teger (200) pds parameters -!> - 1 id of center -!> - 2 generating process id number -!> - 3 grid definition -!> - 4 gds/bms flag (right adj copy of octet 8) -!> - 5 indicator of parameter -!> - 6 type of level -!> - 7 height/pressure , etc of level -!> - 8 year including (century-1) -!> - 9 month of year -!> - 10 day of month -!> - 11 hour of day -!> - 12 minute of hour -!> - 13 indicator of forecast time unit -!> - 14 time range 1 -!> - 15 time range 2 -!> - 16 time range flag -!> - 17 number included in average -!> - 18 version nr of grib specification -!> - 19 version nr of parameter table -!> - 20 nr missing from average/accumulation -!> - 21 century of reference time of data -!> - 22 units decimal scale factor -!> - 23 subcenter number -!> - 24 pds byte 29, for nmc ensemble products, 128 if forecast field -!> error, 64 if bias corrected fcst field, 32 if smoothed field, -!> warning: can be combination of more than 1. -!> - 25 pds byte 30, not used -!> @param[in] kgds teger (200) gds parameters -!> - 1 data representation type -!> - 19 number of vertical coordinate parameters -!> - 20 octet number of the list of vertical coordinate parameters or -!> octet number of the list of numbers of points in each row or 255 if -!> neither are present. -!> - 21 for grids with pl, number of points in grid -!> - 22 number of words in each row latitude/longitude grids -!> - 2 n(i) nr points on latitude circle -!> - 3 n(j) nr points on longitude meridian -!> - 4 la(1) latitude of origin -!> - 5 lo(1) longitude of origin -!> - 6 resolution flag (right adj copy of octet 17) -!> - 7 la(2) latitude of extreme point -!> - 8 lo(2) longitude of extreme point -!> - 9 di longitudinal direction of increment -!> - 10 dj latitudinal direction increment -!> - 11 scanning mode flag (right adj copy of octet 28) -!> Gaussian grids: -!> - 2 n(i) nr points on latitude circle -!> - 3 n(j) nr points on longitude meridian -!> - 4 la(1) latitude of origin -!> - 5 lo(1) longitude of origin -!> - 6 resolution flag (right adj copy of octet 17) -!> - 7 la(2) latitude of extreme point -!> - 8 lo(2) longitude of extreme point -!> - 9 di longitudinal direction of increment -!> - 10 n - nr of circles pole to equator -!> - 11 scanning mode flag (right adj copy of octet 28) -!> - 12 nv - nr of vert coord parameters -!> - 13 pv - octet nr of list of vert coord parameters or pl - location -!> of the list of numbers of points in each row (if no vert coord -!> parameters are present or 255 if neither are present -!> Polar Stereographic grids: -!> - 2 n(i) nr points along lat circle -!> - 3 n(j) nr points along lon circle -!> - 4 la(1) latitude of origin -!> - 5 lo(1) longitude of origin -!> - 6 resolution flag (right adj copy of octet 17) -!> - 7 lov grid orientation -!> - 8 dx - x direction increment -!> - 9 dy - y direction increment -!> - 10 projection center flag -!> - 11 scanning mode (right adj copy of octet 28) -!> Spherical Harmonic Coefficients: -!> - 2 j pentagonal resolution parameter -!> - 3 k pentagonal resolution parameter -!> - 4 m pentagonal resolution parameter -!> - 5 representation type -!> - 6 coefficient storage mode -!> Mercator grids: -!> - 2 n(i) nr points on latitude circle -!> - 3 n(j) nr points on longitude meridian -!> - 4 la(1) latitude of origin -!> - 5 lo(1) longitude of origin -!> - 6 resolution flag (right adj copy of octet 17) -!> - 7 la(2) latitude of last grid point -!> - 8 lo(2) longitude of last grid point -!> - 9 latit - latitude of projection intersection -!> - 10 reserved -!> - 11 scanning mode flag (right adj copy of octet 28) -!> - 12 longitudinal dir grid length -!> - 13 latitudinal dir grid length -!> Lambert Conformal Grids: -!> - 2 nx nr points along x-axis -!> - 3 ny nr points along y-axis -!> - 4 la1 lat of origin (lower left) -!> - 5 lo1 lon of origin (lower left) -!> - 6 resolution (right adj copy of octet 17) -!> - 7 lov - orientation of grid -!> - 8 dx - x-dir increment -!> - 9 dy - y-dir increment -!> - 10 projection center flag -!> - 11 scanning mode flag (right adj copy of octet 28) -!> - 12 latin 1 - first lat from pole of secant cone inter -!> - 13 latin 2 - second lat from pole of secant cone inter -!> @param[in] kens teger (200) ensemble pds parms -!> - 1 application identifier -!> - 2 ensemble type -!> - 3 ensemble identifier -!> - 4 product identifier -!> - 5 smoothing flag -!> @param[in] kprob teger (2) probability ensemble parms -!> @param[in] xprob al (2) probability ensemble parms -!> @param[in] kclust teger (16) cluster ensemble parms -!> @param[in] kmembr teger (8) cluster ensemble parms -!> @param[in] ibs teger binary scale factor (0 to ignore) -!> @param[in] nbits teger number of bits in which to pack (0 to ignore) -!> @param[in] lb gical*1 (kf) bitmap if present -!> @param[in] f al (kf) data -!> @param[out] iret teger return code -!> - 0 Success -!> - Other W3FI72 GRIB packer return code -!> -!> @author Mark Iredell @date 94-04-01 -SUBROUTINE PUTGBEXN(LUGB,KF,KPDS,KGDS,KENS, & - KPROB,XPROB,KCLUST,KMEMBR,IBS,NBITS,LB,F,IRET) - - INTEGER KPDS(200),KGDS(200),KENS(200) - INTEGER KPROB(2),KCLUST(16),KMEMBR(80) - REAL XPROB(2) - LOGICAL*1 LB(KF) - REAL F(KF) - ! PARAMETER(MAXBIT=16) - PARAMETER(MAXBIT=24) - INTEGER IBM(KF),IPDS(200),IGDS(200),IBDS(200) - CHARACTER PDS(400),GRIB(1000+KF*(MAXBIT+1)/8) - - ! GET W3FI72 PARAMETERS - !print *,'SAGT: start putgbexn' - CALL R63W72(KPDS,KGDS,IPDS,IGDS) - IBDS=0 - - ! COUNT VALID DATA - KBM=KF - IF(IPDS(7).NE.0) THEN - KBM=0 - DO I=1,KF - IF(LB(I)) THEN - IBM(I)=1 - KBM=KBM+1 - ELSE - IBM(I)=0 - ENDIF - ENDDO - IF(KBM.EQ.KF) IPDS(7)=0 - ENDIF - - ! GET NUMBER OF BITS AND ROUND DATA - IF(NBITS.GT.0) THEN - NBIT=NBITS - ELSE - IF(KBM.EQ.0) THEN - DO I=1,KF - F(I)=0. - ENDDO - NBIT=0 - ELSE - !print *,'SAGT:',IPDS(7),IBS,IPDS(25),KF - !print *,'SAGT:',count(ibm.eq.0),count(ibm.eq.1) - CALL SETBIT(IPDS(7),-IBS,IPDS(25),KF,IBM,F,FMIN,FMAX,NBIT) - NBIT=MIN(NBIT,MAXBIT) - ENDIF - ENDIF - - ! CREATE PRODUCT DEFINITION SECTION - CALL W3FI68(IPDS,PDS) - IF(IPDS(24).EQ.2) THEN - ILAST=45 - IF (IPDS(8).EQ.191.OR.IPDS(8).EQ.192) ILAST=55 - IF (KENS(2).EQ.5) ILAST=76 - IF (KENS(2).EQ.5) ILAST=86 - IF (KENS(2).EQ.4) ILAST=86 - CALL PDSENS(KENS,KPROB,XPROB,KCLUST,KMEMBR,ILAST,PDS) - ENDIF - - ! PACK AND WRITE GRIB DATA - igflag=1 - igrid=kpds(3) - if (igrid.ne.255) igflag=0 - !print *,minval(f(1:kf)),maxval(f(1:kf)) - !print *,nbit,kf - !print *,(ipds(j),j=1,28) - !write(6,fmt='(28z2)') (pds(j),j=1,28) - !print *,(kgds(j),j=1,28) - !print *,(igds(j),j=1,28) - icomp=0 - CALL W3FI72(0,F,0,NBIT,1,IPDS,PDS, & - igflag,igrid,IGDS,ICOMP,0,IBM,KF,IBDS, & - KFO,GRIB,LGRIB,IRET) - IF(IRET.EQ.0) CALL WRYTE(LUGB,LGRIB,GRIB) - - RETURN -END SUBROUTINE PUTGBEXN diff --git a/utils/setbit.F90 b/utils/setbit.F90 deleted file mode 100644 index 8a62d63b0..000000000 --- a/utils/setbit.F90 +++ /dev/null @@ -1,69 +0,0 @@ -!> @file -!> Compute bits required to pack a given field. -!> @author Mark Iredell @date 92-10-31 - -!> The number of bits required to pack a given field for particular -!> binary and decimal scalings is computed. The minimum and maximum -!> rounded field values are also returned. GRIB bitmap masking for -!> valid data is optionally used. -!> -!> @param[in] ibm integer bitmap flag (=0 for no bitmap). -!> @param[in] ibs integer binary scaling (e.g. ibs=3 to round field to -!> nearest eighth value). -!> @param[in] ids integer decimal scaling (e.g. ids=3 to round field to -!> nearest milli-value) (note that ids and ibs can both be nonzero, -!> e.g. ids=1 and ibs=1 rounds to the nearest twentieth). -!> @param[in] len integer length of the field and bitmap. -!> @param[in] mg integer (len) bitmap if ibm=1 (0 to skip, 1 to keep). -!> @param[in] g real (len) field. -!> @param[out] gmin real minimum valid rounded field value. -!> @param[out] gmax real maximum valid rounded field value. -!> @param[out] nbit integer number of bits to pack. -!> -!> @author Mark Iredell @date 92-10-31 -SUBROUTINE SETBIT(IBM,IBS,IDS,LEN,MG,G,GMIN,GMAX,NBIT) - - DIMENSION MG(LEN),G(LEN) - - ! ROUND FIELD AND DETERMINE EXTREMES WHERE BITMAP IS ON - S=2.**IBS*10.**IDS - IF(IBM.EQ.0) THEN - GMAX=G(1) - GMIN=G(1) - DO I=2,LEN - GMAX=MAX(GMAX,G(I)) - GMIN=MIN(GMIN,G(I)) - ENDDO - ELSE - I1=1 - DO WHILE(I1.LE.LEN.AND.MG(I1).EQ.0) - I1=I1+1 - ENDDO - IF(I1.LE.LEN) THEN - DO I=1,I1-1 - G(I)=0. - ENDDO - GMAX=G(I1) - GMIN=G(I1) - DO I=I1+1,LEN - IF(MG(I).NE.0) THEN - GMAX=MAX(GMAX,G(I)) - GMIN=MIN(GMIN,G(I)) - ELSE - G(I)=0. - ENDIF - ENDDO - ELSE - DO I=1,LEN - G(I)=0. - ENDDO - GMAX=0. - GMIN=0. - ENDIF - ENDIF - - ! COMPUTE NUMBER OF BITS - NBIT=LOG((GMAX-GMIN)*S+0.9)/LOG(2.)+1. - - RETURN -END SUBROUTINE SETBIT diff --git a/utils/tocgrib.F90 b/utils/tocgrib.F90 index 937f598e2..0f649d7f4 100644 --- a/utils/tocgrib.F90 +++ b/utils/tocgrib.F90 @@ -242,3 +242,96 @@ PROGRAM tocgrib STOP END PROGRAM tocgrib + +!> Generates a TOC Flag Field Separator Block used to separate WMO +!> Bulletins within a transmission file to be ingested in TOC's FTP +!> Input Service, which can be used to disseminate WMO buletins (see +!> http://weather.gov/tg/ftpingest.html). +!> +!> This routine can generate different flag field separator blocks +!> depending on the value of variable iopt. +!> +!> Bulletin "Flag Field Separator" block - OPTION 1 (old) +!> +!> Bytes | Description +!> ------|------------ +!> 1 - 4 | marker string (####) +!> 5 - 7 | block length [018 fixed value] +!> 8 - 13 | total length of bulletin in bytes [octets] (not including the flag field block) +!> 14 - 17 | marker string (####) +!> 18 | line Feed (ASCII "0A") +!> +!> Bulletin "Flag Field Separator" block - OPTION 1a (new) +!> +!> Bytes | Description +!> ------|------------ +!> 1 - 4 | marker string (####) +!> 5 - 7 | block length (nnn) - value always greater than 018 +!> 8 - 18 | total length of bulletin in bytes [octets] (not including the flag field block) +!> 19 - nnn-5 | reserved for future use +!> nnn-4 - nnn-1 | marker string (####) +!> nnn | line Feed (ASCII "0A") +!> +!> Bulletin "Flag Field Separator" block - OPTION 2 (limited) +!> +!> Bytes | Description +!> ------|------------ +!> 1 - 4 | marker string (****) +!> 5 - 14 | total length of bulletin in bytes [octets] (not including the flag field block) +!> 15 - 18 | marker string (****) +!> 19 | line Feed (ASCII "0A") +!> +!> @param[out] csep*(*) Character array containing the flag field separator. +!> @param[in] iopt Flag Field Separator block option: +!> - 1 Separator block for use with alphanumeric bulletins. +!> - if lenin <= 18 and lenbull <= 999999, OPTION 1 block will be generated. +!> - if lenin > 18 or lenbull > 999999, OPTION 1a block will be generated. +!> - 2 Separator block for use with GRIB/BUFR bulletins. +!> @param[in] lenin Desired length of the flag field separator +!> block. ignored, if iopt=2. +!> @param[in] lenbull Integer length of the bulletin (in bytes) that +!> will follow this separator block. +!> @param[out] lenout Integer length of the flag field separator block. +!> +!> @author Gilbert @date 2002-09-16 +subroutine mkfldsep(csep,iopt,lenin,lenbull,lenout) + ! + character*(*),intent(out) :: csep + integer,intent(in) :: iopt,lenin,lenbull + integer,intent(out) :: lenout + ! + character(len=4),parameter :: cstar='****',clb='####' + ! + if (iopt.eq.1) then + if ( lenin .le. 18 .and. lenbull .le. 999999 ) then + ! Create OPTION 1 separator block + csep(1:4)=clb + csep(5:7)='018' + write(csep(8:13),fmt='(I6.6)') lenbull + csep(14:17)=clb + csep(18:18)=char(10) + lenout=18 + else ! Create OPTION 1a separator block + nnn=lenin + if ( nnn.lt.23 ) nnn=23 + csep(1:4)=clb + write(csep(5:7),fmt='(I3.3)') nnn + write(csep(8:18),fmt='(I11.11)') lenbull + csep(19:nnn-5)='0' + csep(nnn-4:nnn-1)=clb + csep(nnn:nnn)=char(10) + lenout=nnn + endif + elseif (iopt.eq.2) then ! Create OPTION 2 separator block + csep(1:4)=cstar + write(csep(5:14),fmt='(I10.10)') lenbull + csep(15:18)=cstar + csep(19:19)=char(10) + lenout=19 + else + print *,"mkfldsep: Option ",iopt," not recognized." + csep(1:lenin)=' ' + endif + ! + return +end subroutine mkfldsep \ No newline at end of file