diff --git a/docs/Doxyfile.qmake b/docs/Doxyfile.qmake index 4f2af8f6b..f2fed4d01 100644 --- a/docs/Doxyfile.qmake +++ b/docs/Doxyfile.qmake @@ -804,7 +804,8 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = $(DOXY_SRC_ROOT)/xbus/libxplanemp +EXCLUDE = $(DOXY_SRC_ROOT)/xbus/libxplanemp \ + $(DOXY_SRC_ROOT)/plugins/weatherdata/gfs/g2clib # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded diff --git a/src/blackmisc/weather/registermetadataweather.cpp b/src/blackmisc/weather/registermetadataweather.cpp index 323c8f655..a24a3d2bc 100644 --- a/src/blackmisc/weather/registermetadataweather.cpp +++ b/src/blackmisc/weather/registermetadataweather.cpp @@ -25,6 +25,8 @@ namespace BlackMisc CPresentWeatherList::registerMetadata(); CTemperatureLayer::registerMetadata(); CTemperatureLayerList::registerMetadata(); + CWeatherDataPluginInfo::registerMetadata(); + CWeatherDataPluginInfoList::registerMetadata(); CWeatherGrid::registerMetadata(); CWindLayer::registerMetadata(); CWindLayerList::registerMetadata(); diff --git a/src/blackmisc/weather/weather.h b/src/blackmisc/weather/weather.h index 04bc896c8..f6c0c2e83 100644 --- a/src/blackmisc/weather/weather.h +++ b/src/blackmisc/weather/weather.h @@ -26,6 +26,8 @@ #include "blackmisc/weather/presentweatherlist.h" #include "blackmisc/weather/temperaturelayer.h" #include "blackmisc/weather/temperaturelayerlist.h" +#include "blackmisc/weather/weatherdataplugininfo.h" +#include "blackmisc/weather/weatherdataplugininfolist.h" #include "blackmisc/weather/weathergrid.h" #include "blackmisc/weather/windlayer.h" #include "blackmisc/weather/windlayerlist.h" diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 9b364e973..8ecff72dc 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -4,5 +4,6 @@ TEMPLATE = subdirs CONFIG += ordered SUBDIRS += simulator +SUBDIRS += weatherdata load(common_post) diff --git a/src/plugins/weatherdata/gfs/g2clib/CHANGES b/src/plugins/weatherdata/gfs/g2clib/CHANGES new file mode 100644 index 000000000..e6beba874 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/CHANGES @@ -0,0 +1,68 @@ +glib-1.0 - August 2003 - Original version + +g2libc-1.0.1 - May 2004 - Changed the library name from "libg2c.a" to + "libgrib2c.a" to avoid conflict with the g77 libg2c + library. + - Added support for Grid Definition Template 3.31, + Albers Equal Area. + - Changed most PDT templates in module pdstemplates to + allow negative surface values. + - Many minor changes to help get clean compiles. + +g2libc-1.0.2 - December 2004 - WMO approved the JPEG2000 and PNG Data + Representation Templates ( 5.40000 and 5.40010, + respectively ) for operational use. The templates + were assigned WMO values of 5.40 and 5.41, + respectively. Changes were made to the source to + recognize either template number. + - Fixed bug encountered when packing a near constant + field with DRT 5.40 or 5.40000 (JPEG2000). + - Added consistency check, provided by + Arthur Taylor/MDL, used when unpacking Data + Templates 7.2 and 7.3. + - Added functionality to support encoding of + "Missing" data values within the data field when + using Data Representation Templates 5.2 + (complex packing) and 5.3 (complex packing and + spatial differencing). See octets 23 - 31 in DRTs + 5.2 and 5.3 for more info on missing value + management. + - Increased the packing efficiency of Data + Representation Templates 5.2 and 5.3 by adding + MDL/Glahn algorithm for determining effective + groupings. + +g2libc-1.0.3 - December 2005 - Two bug fixes: 1) Error encoding constant + data field. 2) Error encoding grid with + large bitmap using DRT 5.40 - JPEG2000. + +g2libc-1.0.5 - August 2007 - Added GDT 3.204 Curvilinear Orthogonal Grid + +g2libc-1.1.7 - August 2008 - Added GDT 3.32768 Rot Lat/Lon E-grid (Arakawa) + +g2libc-1.1.8 - January 2009 - Initialize variable lencsec2 in routine g2_unpack2.c + variable ndpts in routine g2_unpack7.c + - Changed the structure name template to gtemplate to avoid + of reserved word in C++ + - Change routine seekgb.c to use 4 bytes instead of sizeof(g2int) + +g2libc-1.1.9 - June 2009 - Updated version jasper-1.900.1, libpng-1.2.35 and zlib-1.2.3 + - Fixed bug causing seg fault when using PNG 1.2.35 + +g2libc-1.2.0 - March 2010 - Added PDT 4.31 Satellite Product + - Added PDT 4.15 WAFS Product + +g2libc-1.2.1 - August 2010 - Added PDT 4.40,4.41,4.42,4.43 for Atmospheric Chemical Constituents + - Added GDT 3.32769 Rot Lat/Lon None E-grid (Arakawa) + - If section 2 has zero length, return IERR=0 + +g2libc-1.2.2 - March 2011 - Corrected PDT 4.42,4.43 for Atmospheric Chemical Constituents + +g2libc-1.2.3 - November 2011 - Fixed bugs in routines dec_png.c and enc_png.c + +g2libc-1.4.0 - May 2012 - Added PDT 4.44,4.45,4.46,4.47,4.48 for Aerosol products + - PDT 4.50,4.51,4.52 iand 4.91 for Categorical forecast at a horizonal + +g2libc-1.5.0 - Sept. 2013 - Added PDT 4.33,4.34,4.53,4.54,4.50 + - Added GDT 3.4,3.5,3.12,3.101,3.140 + - Free up memory igds diff --git a/src/plugins/weatherdata/gfs/g2clib/README b/src/plugins/weatherdata/gfs/g2clib/README new file mode 100644 index 000000000..ed6428190 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/README @@ -0,0 +1,68 @@ + August 06, 2013 + W/SIB:VUONG + + +g2clib Library. + +This library contains "C" decoder/encoder +routines for GRIB edition 2. The user API for the GRIB2 routines +is described in file "grib2c.doc". + +This "C" source code conatins many uses of the C++ +comment style "//". Please make sure you include the +appropriate compiler option in the CFLAGS variable in the +makefile to allow the use of "//" comment indicators. + + +We have added support for PNG and JPEG2000 image compression +algorithms within the GRIB2 standard. If you would like +to compile this library to utilize these GRIB2 Templates, +make sure that -DUSE_PNG and -DUSE_JPEG2000 are specified +in the DEFS variable in the makefile. You will also need +to download and install the external libraries listed below, +if they are not already installed on your system. + +If you do not wish to bother with the external libs and +don't need PNG and JPEG2000 support, you can remove the +-DUSE_PNG and -DUSE_JPEG2000 flags from the DEFS variable +in the makefile. + + +------------------------------------------------------------------------------- + + External Libraries: + +libjasper.a - This library is a C implementation of the JPEG-2000 Part-1 + standard (i.e., ISO/IEC 15444-1). This library is required + if JPEG2000 support in GRIB2 is desired. If not, remove + the -DUSE_JPEG2000 option from the DEFS variable + in the makefile. + + Download version jasper-1.900.1 from the JasPer Project's + home page, http://www.ece.uvic.ca/~mdadams/jasper/. + + More information about JPEG2000 can be found at + http://www.jpeg.org/JPEG2000.html. + +libpng.a This library is a C implementation of the Portable Network + Graphics PNG image compression format. This library is required + if PNG support in GRIB2 is desired. If not, remove + the -DUSE_PNG option from the DEFS variable + in the makefile. + + If not already installed on your system, download version + libpng-1.2.44 from http://www.libpng.org/pub/png/libpng.html. + + More information about PNG can be found at + http://www.libpng.org/pub/png/. + +libz.a This library contains compression/decompression routines + used by libpng.a for PNG image compression support. + This library is required if PNG support in GRIB2 is desired. + If not, remove the -DUSE_PNG option from the DEFS variable + in g2lib/makefile. + + If not already installed on your system, download version + zlib-1.2.6 from http://www.gzip.org/zlib/. + + diff --git a/src/plugins/weatherdata/gfs/g2clib/cmplxpack.c b/src/plugins/weatherdata/gfs/g2clib/cmplxpack.c new file mode 100644 index 000000000..4d9908cc0 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/cmplxpack.c @@ -0,0 +1,75 @@ +#include "grib2.h" + +void cmplxpack(g2float *fld,g2int ndpts, g2int idrsnum,g2int *idrstmpl, + unsigned char *cpack, g2int *lcpack) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: cmplxpack +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2004-08-27 +// +// ABSTRACT: This subroutine packs up a data field using a complex +// packing algorithm as defined in the GRIB2 documention. It +// supports GRIB2 complex packing templates with or without +// spatial differences (i.e. DRTs 5.2 and 5.3). +// It also fills in GRIB2 Data Representation Template 5.2 or 5.3 +// with the appropriate values. +// +// PROGRAM HISTORY LOG: +// 2004-08-27 Gilbert +// +// USAGE: cmplxpack(g2float *fld,g2int ndpts, g2int idrsnum,g2int *idrstmpl, +// unsigned char *cpack, g2int *lcpack) +// INPUT ARGUMENT LIST: +// fld[] - Contains the data values to pack +// ndpts - The number of data values in array fld[] +// idrsnum - Data Representation Template number 5.N +// Must equal 2 or 3. +// idrstmpl - Contains the array of values for Data Representation +// Template 5.2 or 5.3 +// [0] = Reference value - ignored on input +// [1] = Binary Scale Factor +// [2] = Decimal Scale Factor +// . +// . +// [6] = Missing value management +// [7] = Primary missing value +// [8] = Secondary missing value +// . +// . +// [16] = Order of Spatial Differencing ( 1 or 2 ) +// . +// . +// +// OUTPUT ARGUMENT LIST: +// idrstmpl - Contains the array of values for Data Representation +// Template 5.3 +// [0] = Reference value - set by compack routine. +// [1] = Binary Scale Factor - unchanged from input +// [2] = Decimal Scale Factor - unchanged from input +// . +// . +// cpack - The packed data field (character*1 array) +// lcpack - length of packed field cpack[]. +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: IBM SP +// +//$$$ +{ + + + if ( idrstmpl[6] == 0 ) { // No internal missing values + compack(fld,ndpts,idrsnum,idrstmpl,cpack,lcpack); + } + else if ( idrstmpl[6] == 1 || idrstmpl[6] == 2) { + misspack(fld,ndpts,idrsnum,idrstmpl,cpack,lcpack); + } + else { + printf("cmplxpack: Don:t recognize Missing value option."); + *lcpack=-1; + } + +} diff --git a/src/plugins/weatherdata/gfs/g2clib/compack.c b/src/plugins/weatherdata/gfs/g2clib/compack.c new file mode 100644 index 000000000..50fb01f64 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/compack.c @@ -0,0 +1,416 @@ +#include +#include +#include "grib2.h" + + +void compack(g2float *fld,g2int ndpts,g2int idrsnum,g2int *idrstmpl, + unsigned char *cpack,g2int *lcpack) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: compack +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-11-07 +// +// ABSTRACT: This subroutine packs up a data field using a complex +// packing algorithm as defined in the GRIB2 documention. It +// supports GRIB2 complex packing templates with or without +// spatial differences (i.e. DRTs 5.2 and 5.3). +// It also fills in GRIB2 Data Representation Template 5.2 or 5.3 +// with the appropriate values. +// +// PROGRAM HISTORY LOG: +// 2002-11-07 Gilbert +// +// USAGE: void compack(g2float *fld,g2int ndpts,g2int idrsnum, +// g2int *idrstmpl,unsigned char *cpack,g2int *lcpack) +// +// INPUT ARGUMENTS: +// fld[] - Contains the data values to pack +// ndpts - The number of data values in array fld[] +// idrsnum - Data Representation Template number 5.N +// Must equal 2 or 3. +// idrstmpl - Contains the array of values for Data Representation +// Template 5.2 or 5.3 +// [0] = Reference value - ignored on input +// [1] = Binary Scale Factor +// [2] = Decimal Scale Factor +// . +// . +// [6] = Missing value management +// [7] = Primary missing value +// [8] = Secondary missing value +// . +// . +// [16] = Order of Spatial Differencing ( 1 or 2 ) +// . +// . +// +// OUTPUT ARGUMENTS: +// idrstmpl - Contains the array of values for Data Representation +// Template 5.3 +// [0] = Reference value - set by compack routine. +// [1] = Binary Scale Factor - unchanged from input +// [2] = Decimal Scale Factor - unchanged from input +// . +// . +// cpack - The packed data field +// lcpack - length of packed field cpack. +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ +{ + + static g2int zero=0; + g2int *ifld,*gref,*glen,*gwidth; + g2int *jmin, *jmax, *lbit; + g2int i,j,n,nbits,imin,imax,left; + g2int isd,itemp,ilmax,ngwidthref=0,nbitsgwidth=0; + g2int nglenref=0,nglenlast=0,iofst,ival1,ival2; + g2int minsd,nbitsd=0,maxorig,nbitorig,ngroups; + g2int lg,ng,igmax,iwmax,nbitsgref; + g2int glength,grpwidth,nbitsglen=0; + g2int kfildo, minpk, inc, maxgrps, ibit, jbit, kbit, novref, lbitref; + g2int missopt, miss1, miss2, ier; + g2float bscale,dscale,rmax,rmin,temp; + static g2int simple_alg = 0; + static g2float alog2=0.69314718; // ln(2.0) + static g2int one=1; + + bscale=int_power(2.0,-idrstmpl[1]); + dscale=int_power(10.0,idrstmpl[2]); +// +// Find max and min values in the data +// + rmax=fld[0]; + rmin=fld[0]; + for (j=1;j rmax) rmax=fld[j]; + if (fld[j] < rmin) rmin=fld[j]; + } + +// +// If max and min values are not equal, pack up field. +// If they are equal, we have a constant field, and the reference +// value (rmin) is the value for each point in the field and +// set nbits to 0. +// + if (rmin != rmax) { + iofst=0; + ifld=calloc(ndpts,sizeof(g2int)); + gref=calloc(ndpts,sizeof(g2int)); + gwidth=calloc(ndpts,sizeof(g2int)); + glen=calloc(ndpts,sizeof(g2int)); + // + // Scale original data + // + if (idrstmpl[1] == 0) { // No binary scaling + imin=(g2int)rint(rmin*dscale); + //imax=(g2int)rint(rmax*dscale); + rmin=(g2float)imin; + for (j=0;j0;j--) + ifld[j]=ifld[j]-ifld[j-1]; + ifld[0]=0; + } + else if (idrstmpl[16] == 2) { // second order + ival1=ifld[0]; + ival2=ifld[1]; + for (j=ndpts-1;j>1;j--) + ifld[j]=ifld[j]-(2*ifld[j-1])+ifld[j-2]; + ifld[0]=0; + ifld[1]=0; + } + // + // subtract min value from spatial diff field + // + isd=idrstmpl[16]; + minsd=ifld[isd]; + for (j=isd;jival1) maxorig=ival2; + temp=log((double)(maxorig+1))/alog2; + nbitorig=(g2int)ceil(temp)+1; + if (nbitorig > nbitsd) nbitsd=nbitorig; + // increase number of bits to even multiple of 8 ( octet ) + if ( (nbitsd%8) != 0) nbitsd=nbitsd+(8-(nbitsd%8)); + // + // Store extra spatial differencing info into the packed + // data section. + // + if (nbitsd != 0) { + // pack first original value + if (ival1 >= 0) { + sbit(cpack,&ival1,iofst,nbitsd); + iofst=iofst+nbitsd; + } + else { + sbit(cpack,&one,iofst,1); + iofst=iofst+1; + itemp=abs(ival1); + sbit(cpack,&itemp,iofst,nbitsd-1); + iofst=iofst+nbitsd-1; + } + if (idrstmpl[16] == 2) { + // pack second original value + if (ival2 >= 0) { + sbit(cpack,&ival2,iofst,nbitsd); + iofst=iofst+nbitsd; + } + else { + sbit(cpack,&one,iofst,1); + iofst=iofst+1; + itemp=abs(ival2); + sbit(cpack,&itemp,iofst,nbitsd-1); + iofst=iofst+nbitsd-1; + } + } + // pack overall min of spatial differences + if (minsd >= 0) { + sbit(cpack,&minsd,iofst,nbitsd); + iofst=iofst+nbitsd; + } + else { + sbit(cpack,&one,iofst,1); + iofst=iofst+1; + itemp=abs(minsd); + sbit(cpack,&itemp,iofst,nbitsd-1); + iofst=iofst+nbitsd-1; + } + } + //printf("SDp %ld %ld %ld %ld\n",ival1,ival2,minsd,nbitsd); + } // end of spatial diff section + // + // Determine Groups to be used. + // + if ( simple_alg == 1 ) { + // set group length to 10; calculate number of groups + // and length of last group + ngroups=ndpts/10; + for (j=0;j imax) imax=ifld[j]; + j++; + } + // calc num of bits needed to hold data + if ( gref[ng] != imax ) { + temp=log((double)(imax-gref[ng]+1))/alog2; + gwidth[ng]=(g2int)ceil(temp); + } + else + gwidth[ng]=0; + // Subtract min from data + j=n; + for (lg=0;lg igmax) igmax=gref[j]; + if (igmax != 0) { + temp=log((double)(igmax+1))/alog2; + nbitsgref=(g2int)ceil(temp); + sbits(cpack,gref,iofst,nbitsgref,0,ngroups); + itemp=nbitsgref*ngroups; + iofst=iofst+itemp; + // Pad last octet with Zeros, if necessary, + if ( (itemp%8) != 0) { + left=8-(itemp%8); + sbit(cpack,&zero,iofst,left); + iofst=iofst+left; + } + } + else + nbitsgref=0; + // + // Find max/min of the group widths and calc num of bits needed + // to pack each groups width value, then + // pack up group width values + // + iwmax=gwidth[0]; + ngwidthref=gwidth[0]; + for (j=1;j iwmax) iwmax=gwidth[j]; + if (gwidth[j] < ngwidthref) ngwidthref=gwidth[j]; + } + if (iwmax != ngwidthref) { + temp=log((double)(iwmax-ngwidthref+1))/alog2; + nbitsgwidth=(g2int)ceil(temp); + for (i=0;i ilmax) ilmax=glen[j]; + if (glen[j] < nglenref) nglenref=glen[j]; + } + nglenlast=glen[ngroups-1]; + if (ilmax != nglenref) { + temp=log((double)(ilmax-nglenref+1))/alog2; + nbitsglen=(g2int)ceil(temp); + for (i=0;i +#include +#include "grib2.h" + + +int comunpack(unsigned char *cpack,g2int lensec,g2int idrsnum,g2int *idrstmpl,g2int ndpts,g2float *fld) +////$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: comunpack +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-29 +// +// ABSTRACT: This subroutine unpacks a data field that was packed using a +// complex packing algorithm as defined in the GRIB2 documention, +// using info from the GRIB2 Data Representation Template 5.2 or 5.3. +// Supports GRIB2 complex packing templates with or without +// spatial differences (i.e. DRTs 5.2 and 5.3). +// +// PROGRAM HISTORY LOG: +// 2002-10-29 Gilbert +// 2004-12-16 Gilbert - Added test ( provided by Arthur Taylor/MDL ) +// to verify that group widths and lengths are +// consistent with section length. +// +// USAGE: int comunpack(unsigned char *cpack,g2int lensec,g2int idrsnum, +// g2int *idrstmpl, g2int ndpts,g2float *fld) +// INPUT ARGUMENT LIST: +// cpack - pointer to the packed data field. +// lensec - length of section 7 (used for error checking). +// idrsnum - Data Representation Template number 5.N +// Must equal 2 or 3. +// idrstmpl - pointer to the array of values for Data Representation +// Template 5.2 or 5.3 +// ndpts - The number of data values to unpack +// +// OUTPUT ARGUMENT LIST: +// fld - Contains the unpacked data values. fld must be allocated +// with at least ndpts*sizeof(g2float) bytes before +// calling this routine. +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$// +{ + + g2int nbitsd=0,isign; + g2int j,iofst,ival1,ival2,minsd,itemp,l,k,n,non=0; + g2int *ifld,*ifldmiss=0; + g2int *gref,*gwidth,*glen; + g2int itype,ngroups,nbitsgref,nbitsgwidth,nbitsglen; + g2int msng1,msng2; + g2float ref,bscale,dscale,rmiss1,rmiss2; + g2int totBit, totLen; + + //printf('IDRSTMPL: ',(idrstmpl(j),j=1,16) + rdieee(idrstmpl+0,&ref,1); +// printf("SAGTref: %f\n",ref); + bscale = (g2float)int_power(2.0,idrstmpl[1]); + dscale = (g2float)int_power(10.0,-idrstmpl[2]); + nbitsgref = idrstmpl[3]; + itype = idrstmpl[4]; + ngroups = idrstmpl[9]; + nbitsgwidth = idrstmpl[11]; + nbitsglen = idrstmpl[15]; + if (idrsnum == 3) + nbitsd=idrstmpl[17]*8; + + // Constant field + + if (ngroups == 0) { + for (j=0;j lensec) { + return 1; + } +// +// For each group, unpack data values +// + if ( idrstmpl[6] == 0 ) { // no missing values + n=0; + for (j=0;j +#include +#include +#include "grib2.h" +#include "jasper/jasper.h" +#define JAS_1_700_2 + + + int dec_jpeg2000(char *injpc,g2int bufsize,g2int *outfld) +/*$$$ SUBPROGRAM DOCUMENTATION BLOCK +* . . . . +* SUBPROGRAM: dec_jpeg2000 Decodes JPEG2000 code stream +* PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-12-02 +* +* ABSTRACT: This Function decodes a JPEG2000 code stream specified in the +* JPEG2000 Part-1 standard (i.e., ISO/IEC 15444-1) using JasPer +* Software version 1.500.4 (or 1.700.2) written by the University of British +* Columbia and Image Power Inc, and others. +* JasPer is available at http://www.ece.uvic.ca/~mdadams/jasper/. +* +* PROGRAM HISTORY LOG: +* 2002-12-02 Gilbert +* +* USAGE: int dec_jpeg2000(char *injpc,g2int bufsize,g2int *outfld) +* +* INPUT ARGUMENTS: +* injpc - Input JPEG2000 code stream. +* bufsize - Length (in bytes) of the input JPEG2000 code stream. +* +* OUTPUT ARGUMENTS: +* outfld - Output matrix of grayscale image values. +* +* RETURN VALUES : +* 0 = Successful decode +* -3 = Error decode jpeg2000 code stream. +* -5 = decoded image had multiple color components. +* Only grayscale is expected. +* +* REMARKS: +* +* Requires JasPer Software version 1.500.4 or 1.700.2 +* +* ATTRIBUTES: +* LANGUAGE: C +* MACHINE: IBM SP +* +*$$$*/ + +{ + int ier; + g2int i,j,k; + jas_image_t *image=0; + jas_stream_t *jpcstream; + jas_image_cmpt_t *pcmpt; + char *opts=0; + jas_matrix_t *data; + +// jas_init(); + + ier=0; +// +// Create jas_stream_t containing input JPEG200 codestream in memory. +// + + jpcstream=jas_stream_memopen(injpc,bufsize); + +// +// Decode JPEG200 codestream into jas_image_t structure. +// + image=jpc_decode(jpcstream,opts); + if ( image == 0 ) { + printf(" jpc_decode return\n"); + return -3; + } + + pcmpt=image->cmpts_[0]; +/* + printf(" SAGOUT DECODE:\n"); + printf(" tlx %d \n",image->tlx_); + printf(" tly %d \n",image->tly_); + printf(" brx %d \n",image->brx_); + printf(" bry %d \n",image->bry_); + printf(" numcmpts %d \n",image->numcmpts_); + printf(" maxcmpts %d \n",image->maxcmpts_); +#ifdef JAS_1_500_4 + printf(" colormodel %d \n",image->colormodel_); +#endif +#ifdef JAS_1_700_2 + printf(" colorspace %d \n",image->clrspc_); +#endif + printf(" inmem %d \n",image->inmem_); + printf(" COMPONENT:\n"); + printf(" tlx %d \n",pcmpt->tlx_); + printf(" tly %d \n",pcmpt->tly_); + printf(" hstep %d \n",pcmpt->hstep_); + printf(" vstep %d \n",pcmpt->vstep_); + printf(" width %d \n",pcmpt->width_); + printf(" height %d \n",pcmpt->height_); + printf(" prec %d \n",pcmpt->prec_); + printf(" sgnd %d \n",pcmpt->sgnd_); + printf(" cps %d \n",pcmpt->cps_); +#ifdef JAS_1_700_2 + printf(" type %d \n",pcmpt->type_); +#endif +*/ + +// Expecting jpeg2000 image to be grayscale only. +// No color components. +// + if (image->numcmpts_ != 1 ) { + printf("dec_jpeg2000: Found color image. Grayscale expected.\n"); + return (-5); + } + +// +// Create a data matrix of grayscale image values decoded from +// the jpeg2000 codestream. +// + data=jas_matrix_create(jas_image_height(image), jas_image_width(image)); + jas_image_readcmpt(image,0,0,0,jas_image_width(image), + jas_image_height(image),data); +// +// Copy data matrix to output integer array. +// + k=0; + for (i=0;iheight_;i++) + for (j=0;jwidth_;j++) + outfld[k++]=data->rows_[i][j]; +// +// Clean up JasPer work structures. +// + jas_matrix_destroy(data); + ier=jas_stream_close(jpcstream); + jas_image_destroy(image); + + return 0; + +} +#endif /* USE_JPEG2000 */ diff --git a/src/plugins/weatherdata/gfs/g2clib/dec_png.c b/src/plugins/weatherdata/gfs/g2clib/dec_png.c new file mode 100644 index 000000000..f7f958e12 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/dec_png.c @@ -0,0 +1,144 @@ +#ifndef USE_PNG + void dummy(void) {} +#else /* USE_PNG */ + +#include +#include +#include +#include +#include "grib2.h" + + +struct png_stream { + unsigned char *stream_ptr; /* location to write PNG stream */ + g2int stream_len; /* number of bytes written */ +}; +typedef struct png_stream png_stream; + +void user_read_data(png_structp , png_bytep , png_uint_32 ); + +void user_read_data(png_structp png_ptr,png_bytep data, png_uint_32 length) +/* + Custom read function used so that libpng will read a PNG stream + from memory instead of a file on disk. +*/ +{ + char *ptr; + g2int offset; + png_stream *mem; + + mem=(png_stream *)png_get_io_ptr(png_ptr); + ptr=(void *)mem->stream_ptr; + offset=mem->stream_len; +/* printf("SAGrd %ld %ld %x\n",offset,length,ptr); */ + memcpy(data,ptr+offset,length); + mem->stream_len += length; +} + + + +int dec_png(unsigned char *pngbuf,g2int *width,g2int *height,char *cout) +{ + int interlace,color,compres,filter,bit_depth; + g2int j,k,n,bytes,clen; + png_structp png_ptr; + png_infop info_ptr,end_info; + png_bytepp row_pointers; + png_stream read_io_ptr; + png_uint_32 h32, w32; + +/* check if stream is a valid PNG format */ + + if ( png_sig_cmp(pngbuf,0,8) != 0) + return (-3); + +/* create and initialize png_structs */ + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, + NULL, NULL); + if (!png_ptr) + return (-1); + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr,(png_infopp)NULL,(png_infopp)NULL); + return (-2); + } + + end_info = png_create_info_struct(png_ptr); + if (!end_info) + { + png_destroy_read_struct(&png_ptr,(png_infopp)info_ptr,(png_infopp)NULL); + return (-2); + } + +/* Set Error callback */ + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr,&end_info); + return (-3); + } + +/* Initialize info for reading PNG stream from memory */ + + read_io_ptr.stream_ptr=(png_voidp)pngbuf; + read_io_ptr.stream_len=0; + +/* Set new custom read function */ + + png_set_read_fn(png_ptr,(png_voidp)&read_io_ptr,(png_rw_ptr)user_read_data); +/* png_init_io(png_ptr, fptr); */ + +/* Read and decode PNG stream */ + + png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + +/* Get pointer to each row of image data */ + + row_pointers = png_get_rows(png_ptr, info_ptr); + +/* Get image info, such as size, depth, colortype, etc... */ + + /*printf("SAGT:png %d %d %d\n",info_ptr->width,info_ptr->height,info_ptr->bit_depth);*/ + // (void)png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *)width, (png_uint_32 *)height, + (void)png_get_IHDR(png_ptr, info_ptr, &w32, &h32, + &bit_depth, &color, &interlace, &compres, &filter); + + *height = h32; + *width = w32; + +/* Check if image was grayscale */ + +/* + if (color != PNG_COLOR_TYPE_GRAY ) { + fprintf(stderr,"dec_png: Grayscale image was expected. \n"); + } +*/ + if ( color == PNG_COLOR_TYPE_RGB ) { + bit_depth=24; + } + else if ( color == PNG_COLOR_TYPE_RGB_ALPHA ) { + bit_depth=32; + } +/* Copy image data to output string */ + + n=0; + bytes=bit_depth/8; + clen=(*width)*bytes; + for (j=0;j<*height;j++) { + for (k=0;k +#include "grib2.h" +#include "drstemplates.h" + +g2int getdrsindex(g2int number) +/*!$$$ SUBPROGRAM DOCUMENTATION BLOCK +! . . . . +! SUBPROGRAM: getdrsindex +! PRGMMR: Gilbert ORG: W/NP11 DATE: 2001-06-28 +! +! ABSTRACT: This function returns the index of specified Data +! Representation Template 5.NN (NN=number) in array templates. +! +! PROGRAM HISTORY LOG: +! 2001-06-28 Gilbert +! 2009-01-14 Vuong Changed structure name template to gtemplate +! +! USAGE: index=getdrsindex(number) +! INPUT ARGUMENT LIST: +! number - NN, indicating the number of the Data Representation +! Template 5.NN that is being requested. +! +! RETURNS: Index of DRT 5.NN in array gtemplates, if gtemplate exists. +! = -1, otherwise. +! +! REMARKS: None +! +! ATTRIBUTES: +! LANGUAGE: C +! MACHINE: IBM SP +! +!$$$*/ +{ + g2int j,getdrsindex=-1; + + for (j=0;jtype=5; + new->num=templatesdrs[index].template_num; + new->maplen=templatesdrs[index].mapdrslen; + new->needext=templatesdrs[index].needext; + new->map=(g2int *)templatesdrs[index].mapdrs; + new->extlen=0; + new->ext=0; //NULL + return(new); + } + else { + printf("getdrstemplate: DRS Template 5.%d not defined.\n",(int)number); + return(0); //NULL + } + + return(0); //NULL +} + +gtemplate *extdrstemplate(g2int number,g2int *list) +/*!$$$ SUBPROGRAM DOCUMENTATION BLOCK +! . . . . +! SUBPROGRAM: extdrstemplate +! PRGMMR: Gilbert ORG: W/NP11 DATE: 2000-05-11 +! +! ABSTRACT: This subroutine generates the remaining octet map for a +! given Data Representation Template, if required. Some Templates can +! vary depending on data values given in an earlier part of the +! Template, and it is necessary to know some of the earlier entry +! values to generate the full octet map of the Template. +! +! PROGRAM HISTORY LOG: +! 2000-05-11 Gilbert +! 2009-01-14 Vuong Changed structure name template to gtemplate +! +! USAGE: new=extdrstemplate(number,list); +! INPUT ARGUMENT LIST: +! number - NN, indicating the number of the Data Representation +! Template 5.NN that is being requested. +! list() - The list of values for each entry in the +! the Data Representation Template 5.NN. +! +! RETURN VALUE: +! - Pointer to the returned template struct. +! Returns NULL pointer, if template not found. +! +! ATTRIBUTES: +! LANGUAGE: C +! MACHINE: IBM SP +! +!$$$*/ +{ + gtemplate *new; + g2int index,i; + + index=getdrsindex(number); + if (index == -1) return(0); + + new=getdrstemplate(number); + + if ( ! new->needext ) return(new); + + if ( number == 1 ) { + new->extlen=list[10]+list[12]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iextlen;i++) { + new->ext[i]=4; + } + } + return(new); + +} + diff --git a/src/plugins/weatherdata/gfs/g2clib/drstemplates.h b/src/plugins/weatherdata/gfs/g2clib/drstemplates.h new file mode 100644 index 000000000..5e4c7331a --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/drstemplates.h @@ -0,0 +1,69 @@ +#ifndef _drstemplates_H +#define _drstemplates_H +#include "grib2.h" + +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-26 +// +// ABSTRACT: This Fortran Module contains info on all the available +// GRIB2 Data Representation Templates used in Section 5 (DRS). +// The information decribing each template is stored in the +// drstemplate structure defined below. +// +// Each Template has three parts: The number of entries in the template +// (mapdrslen); A map of the template (mapdrs), which contains the +// number of octets in which to pack each of the template values; and +// a logical value (needext) that indicates whether the Template needs +// to be extended. In some cases the number of entries in a template +// can vary depending upon values specified in the "static" part of +// the template. ( See Template 5.1 as an example ) +// +// NOTE: Array mapdrs contains the number of octets in which the +// corresponding template values will be stored. A negative value in +// mapdrs is used to indicate that the corresponding template entry can +// contain negative values. This information is used later when packing +// (or unpacking) the template data values. Negative data values in GRIB +// are stored with the left most bit set to one, and a negative number +// of octets value in mapdrs[] indicates that this possibility should +// be considered. The number of octets used to store the data value +// in this case would be the absolute value of the negative value in +// mapdrs[]. +// +// +/////////////////////////////////////////////////////////////////////// + + #define MAXDRSTEMP 9 // maximum number of templates + #define MAXDRSMAPLEN 200 // maximum template map length + + struct drstemplate + { + g2int template_num; + g2int mapdrslen; + g2int needext; + g2int mapdrs[MAXDRSMAPLEN]; + }; + + const struct drstemplate templatesdrs[MAXDRSTEMP] = { + // 5.0: Grid point data - Simple Packing + { 0, 5, 0, {4,-2,-2,1,1} }, + // 5.2: Grid point data - Complex Packing + { 2, 16, 0, {4,-2,-2,1,1,1,1,4,4,4,1,1,4,1,4,1} }, + // 5.3: Grid point data - Complex Packing and spatial differencing + { 3, 18, 0, {4,-2,-2,1,1,1,1,4,4,4,1,1,4,1,4,1,1,1} }, + // 5.50: Spectral Data - Simple Packing + { 50, 5, 0, {4,-2,-2,1,4} }, + // 5.51: Spherical Harmonics data - Complex packing + { 51, 10, 0, {4,-2,-2,1,-4,2,2,2,4,1} }, +// // 5.1: Matrix values at gridpoint - Simple packing +// { 1, 15, 1, {4,-2,-2,1,1,1,4,2,2,1,1,1,1,1,1} }, + // 5.40: Grid point data - JPEG2000 encoding + { 40, 7, 0, {4,-2,-2,1,1,1,1} }, + // 5.41: Grid point data - PNG encoding + { 41, 5, 0, {4,-2,-2,1,1} }, + // 5.40000: Grid point data - JPEG2000 encoding + { 40000, 7, 0, {4,-2,-2,1,1,1,1} }, + // 5.40010: Grid point data - PNG encoding + { 40010, 5, 0, {4,-2,-2,1,1} } + } ; + + +#endif /* _drstemplates_H */ diff --git a/src/plugins/weatherdata/gfs/g2clib/enc_jpeg2000.c b/src/plugins/weatherdata/gfs/g2clib/enc_jpeg2000.c new file mode 100644 index 000000000..8d0359a33 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/enc_jpeg2000.c @@ -0,0 +1,179 @@ +#ifndef USE_JPEG2000 + void dummy(void) {} +#else /* USE_JPEG2000 */ + +#include +#include +#include "grib2.h" +#include "jasper/jasper.h" +#define JAS_1_700_2 + + +int enc_jpeg2000(unsigned char *cin,g2int width,g2int height,g2int nbits, + g2int ltype, g2int ratio, g2int retry, char *outjpc, + g2int jpclen) +/*$$$ SUBPROGRAM DOCUMENTATION BLOCK +* . . . . +* SUBPROGRAM: enc_jpeg2000 Encodes JPEG2000 code stream +* PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-12-02 +* +* ABSTRACT: This Function encodes a grayscale image into a JPEG2000 code stream +* specified in the JPEG2000 Part-1 standard (i.e., ISO/IEC 15444-1) +* using JasPer Software version 1.500.4 (or 1.700.2 ) written by the +* University of British Columbia, Image Power Inc, and others. +* JasPer is available at http://www.ece.uvic.ca/~mdadams/jasper/. +* +* PROGRAM HISTORY LOG: +* 2002-12-02 Gilbert +* 2004-12-16 Gilbert - Added retry argument/option to allow option of +* increasing the maximum number of guard bits to the +* JPEG2000 algorithm. +* +* USAGE: int enc_jpeg2000(unsigned char *cin,g2int width,g2int height, +* g2int nbits, g2int ltype, g2int ratio, +* g2int retry, char *outjpc, g2int jpclen) +* +* INPUT ARGUMENTS: +* cin - Packed matrix of Grayscale image values to encode. +* width - width of image +* height - height of image +* nbits - depth (in bits) of image. i.e number of bits +* used to hold each data value +* ltype - indicator of lossless or lossy compression +* = 1, for lossy compression +* != 1, for lossless compression +* ratio - target compression ratio. (ratio:1) +* Used only when ltype == 1. +* retry - Pointer to option type. +* 1 = try increasing number of guard bits +* otherwise, no additional options +* jpclen - Number of bytes allocated for new JPEG2000 code stream in +* outjpc. +* +* INPUT ARGUMENTS: +* outjpc - Output encoded JPEG2000 code stream +* +* RETURN VALUES : +* > 0 = Length in bytes of encoded JPEG2000 code stream +* -3 = Error decode jpeg2000 code stream. +* -5 = decoded image had multiple color components. +* Only grayscale is expected. +* +* REMARKS: +* +* Requires JasPer Software version 1.500.4 or 1.700.2 +* +* ATTRIBUTES: +* LANGUAGE: C +* MACHINE: IBM SP +* +*$$$*/ +{ + int ier,rwcnt; + jas_image_t image; + jas_stream_t *jpcstream,*istream; + jas_image_cmpt_t cmpt,*pcmpt; +#define MAXOPTSSIZE 1024 + char opts[MAXOPTSSIZE]; + +/* + printf(" enc_jpeg2000:width %ld\n",width); + printf(" enc_jpeg2000:height %ld\n",height); + printf(" enc_jpeg2000:nbits %ld\n",nbits); + printf(" enc_jpeg2000:jpclen %ld\n",jpclen); +*/ +// jas_init(); + +// +// Set lossy compression options, if requested. +// + if ( ltype != 1 ) { + opts[0]=(char)0; + } + else { + snprintf(opts,MAXOPTSSIZE,"mode=real\nrate=%f",1.0/(float)ratio); + } + if ( retry == 1 ) { // option to increase number of guard bits + strcat(opts,"\nnumgbits=4"); + } + //printf("SAGopts: %s\n",opts); + +// +// Initialize the JasPer image structure describing the grayscale +// image to encode into the JPEG2000 code stream. +// + image.tlx_=0; + image.tly_=0; +#ifdef JAS_1_500_4 + image.brx_=(uint_fast32_t)width; + image.bry_=(uint_fast32_t)height; +#endif +#ifdef JAS_1_700_2 + image.brx_=(jas_image_coord_t)width; + image.bry_=(jas_image_coord_t)height; +#endif + image.numcmpts_=1; + image.maxcmpts_=1; +#ifdef JAS_1_500_4 + image.colormodel_=JAS_IMAGE_CM_GRAY; /* grayscale Image */ +#endif +#ifdef JAS_1_700_2 + image.clrspc_=JAS_CLRSPC_SGRAY; /* grayscale Image */ + image.cmprof_=0; +#endif + image.inmem_=1; + + cmpt.tlx_=0; + cmpt.tly_=0; + cmpt.hstep_=1; + cmpt.vstep_=1; +#ifdef JAS_1_500_4 + cmpt.width_=(uint_fast32_t)width; + cmpt.height_=(uint_fast32_t)height; +#endif +#ifdef JAS_1_700_2 + cmpt.width_=(jas_image_coord_t)width; + cmpt.height_=(jas_image_coord_t)height; + cmpt.type_=JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y); +#endif + cmpt.prec_=nbits; + cmpt.sgnd_=0; + cmpt.cps_=(nbits+7)/8; + + pcmpt=&cmpt; + image.cmpts_=&pcmpt; + +// +// Open a JasPer stream containing the input grayscale values +// + istream=jas_stream_memopen((char *)cin,height*width*cmpt.cps_); + cmpt.stream_=istream; + +// +// Open an output stream that will contain the encoded jpeg2000 +// code stream. +// + jpcstream=jas_stream_memopen(outjpc,(int)jpclen); + +// +// Encode image. +// + ier=jpc_encode(&image,jpcstream,opts); + if ( ier != 0 ) { + printf(" jpc_encode return = %d \n",ier); + return -3; + } +// +// Clean up JasPer work structures. +// + rwcnt=jpcstream->rwcnt_; + ier=jas_stream_close(istream); + ier=jas_stream_close(jpcstream); +// +// Return size of jpeg2000 code stream +// + return (rwcnt); + +} + +#endif /* USE_JPEG2000 */ diff --git a/src/plugins/weatherdata/gfs/g2clib/enc_png.c b/src/plugins/weatherdata/gfs/g2clib/enc_png.c new file mode 100644 index 000000000..c3f75bd4c --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/enc_png.c @@ -0,0 +1,134 @@ +#ifndef USE_PNG + void dummy(void) {} +#else /* USE_PNG */ + +#include +#include +#include +#include +#include "grib2.h" + + +struct png_stream { + unsigned char *stream_ptr; /* location to write PNG stream */ + g2int stream_len; /* number of bytes written */ +}; +typedef struct png_stream png_stream; + +void user_write_data(png_structp ,png_bytep , png_uint_32 ); +void user_flush_data(png_structp ); + +void user_write_data(png_structp png_ptr,png_bytep data, png_uint_32 length) +/* + Custom write function used to that libpng will write + to memory location instead of a file on disk +*/ +{ + unsigned char *ptr; + g2int offset; + png_stream *mem; + + mem=(png_stream *)png_get_io_ptr(png_ptr); + ptr=mem->stream_ptr; + offset=mem->stream_len; +/* printf("SAGwr %ld %ld %x\n",offset,length,ptr); */ + /*for (j=offset,k=0;kstream_len += length; +} + + +void user_flush_data(png_structp png_ptr) +/* + Dummy Custom flush function +*/ +{ + int *do_nothing; + do_nothing=NULL; +} + + +int enc_png(char *data,g2int width,g2int height,g2int nbits,char *pngbuf) +{ + + int color_type; + g2int j,bytes,pnglen,bit_depth; + png_structp png_ptr; + png_infop info_ptr; +// png_bytep *row_pointers[height]; + png_bytep **row_pointers; + png_stream write_io_ptr; + +/* create and initialize png_structs */ + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, + NULL, NULL); + if (!png_ptr) + return (-1); + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_write_struct(&png_ptr,(png_infopp)NULL); + return (-2); + } + +/* Set Error callback */ + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_write_struct(&png_ptr, &info_ptr); + return (-3); + } + +/* Initialize info for writing PNG stream to memory */ + + write_io_ptr.stream_ptr=(png_voidp)pngbuf; + write_io_ptr.stream_len=0; + +/* Set new custom write functions */ + + png_set_write_fn(png_ptr,(png_voidp)&write_io_ptr,(png_rw_ptr)user_write_data, + (png_flush_ptr)user_flush_data); +/* png_init_io(png_ptr, fptr); */ +/* png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); */ + +/* Set the image size, colortype, filter type, etc... */ + +/* printf("SAGTsettingIHDR %d %d %d\n",width,height,bit_depth); */ + bit_depth=nbits; + color_type=PNG_COLOR_TYPE_GRAY; + if (nbits == 24 ) { + bit_depth=8; + color_type=PNG_COLOR_TYPE_RGB; + } + else if (nbits == 32 ) { + bit_depth=8; + color_type=PNG_COLOR_TYPE_RGB_ALPHA; + } + png_set_IHDR(png_ptr, info_ptr, width, height, + bit_depth, color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + +/* Put image data into the PNG info structure */ + + /*bytes=bit_depth/8;*/ + bytes=nbits/8; + row_pointers=malloc(height*sizeof(png_bytep)); + for (j=0;j +#include +#include "grib2.h" + +g2int getdim(unsigned char *,g2int *,g2int *,g2int *); +g2int getpoly(unsigned char *,g2int *,g2int *,g2int *); +void simpack(g2float *, g2int, g2int *, unsigned char *, g2int *); +void cmplxpack(g2float *, g2int, g2int, g2int *, unsigned char *, g2int *); +void specpack(g2float *,g2int,g2int,g2int,g2int,g2int *,unsigned char *, + g2int *); +#ifdef USE_PNG + void pngpack(g2float *,g2int,g2int,g2int *,unsigned char *,g2int *); +#endif /* USE_PNG */ +#ifdef USE_JPEG2000 + void jpcpack(g2float *,g2int,g2int,g2int *,unsigned char *,g2int *); +#endif /* USE_JPEG2000 */ + + +g2int g2_addfield(unsigned char *cgrib,g2int ipdsnum,g2int *ipdstmpl, + g2float *coordlist,g2int numcoord,g2int idrsnum,g2int *idrstmpl, + g2float *fld,g2int ngrdpts,g2int ibmap,g2int *bmap) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_addfield +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-11-05 +// +// ABSTRACT: This routine packs up Sections 4 through 7 for a given field +// and adds them to a GRIB2 message. They are Product Definition Section, +// Data Representation Section, Bit-Map Section and Data Section, +// respectively. +// This routine is used with routines "g2_create", "g2_addlocal", +// "g2_addgrid", and "g2_gribend" to create a complete GRIB2 message. +// g2_create must be called first to initialize a new GRIB2 message. +// Also, routine g2_addgrid must be called after g2_create and +// before this routine to add the appropriate grid description to +// the GRIB2 message. Also, a call to g2_gribend is required to complete +// GRIB2 message after all fields have been added. +// +// PROGRAM HISTORY LOG: +// 2002-11-05 Gilbert +// 2002-12-23 Gilbert - Added complex spherical harmonic packing +// 2003-08-27 Gilbert - Added support for new templates using +// PNG and JPEG2000 algorithms/templates. +// 2004-11-29 Gilbert - JPEG2000 now allowed to use WMO Template no. 5.40 +// PNG now allowed to use WMO Template no. 5.41 +// - Added check to determine if packing algorithm failed. +// 2005-05-10 Gilbert - Imposed minimum size on cpack, used to hold encoded +// bit string. +// 2009-01-14 Vuong Changed structure name template to gtemplate +// +// USAGE: int g2_addfield(unsigned char *cgrib,g2int ipdsnum,g2int *ipdstmpl, +// g2float *coordlist,g2int numcoord,g2int idrsnum,g2int *idrstmpl, +// g2float *fld,g2int ngrdpts,g2int ibmap,g2int *bmap) +// INPUT ARGUMENT LIST: +// cgrib - Char array that contains the GRIB2 message to which sections +// 4 through 7 should be added. +// ipdsnum - Product Definition Template Number ( see Code Table 4.0) +// ipdstmpl - Contains the data values for the specified Product Definition +// Template ( N=ipdsnum ). Each element of this integer +// array contains an entry (in the order specified) of Product +// Defintion Template 4.N +// coordlist- Array containg floating point values intended to document +// the vertical discretisation associated to model data +// on hybrid coordinate vertical levels. +// numcoord - number of values in array coordlist. +// idrsnum - Data Representation Template Number ( see Code Table 5.0 ) +// idrstmpl - Contains the data values for the specified Data Representation +// Template ( N=idrsnum ). Each element of this integer +// array contains an entry (in the order specified) of Data +// Representation Template 5.N +// Note that some values in this template (eg. reference +// values, number of bits, etc...) may be changed by the +// data packing algorithms. +// Use this to specify scaling factors and order of +// spatial differencing, if desired. +// fld[] - Array of data points to pack. +// ngrdpts - Number of data points in grid. +// i.e. size of fld and bmap. +// ibmap - Bitmap indicator ( see Code Table 6.0 ) +// 0 = bitmap applies and is included in Section 6. +// 1-253 = Predefined bitmap applies +// 254 = Previously defined bitmap applies to this field +// 255 = Bit map does not apply to this product. +// bmap[] - Integer array containing bitmap to be added. ( if ibmap=0 ) +// +// OUTPUT ARGUMENT LIST: +// cgrib - Character array to contain the updated GRIB2 message. +// Must be allocated large enough to store the entire +// GRIB2 message. +// +// RETURN VALUES: +// ierr - Return code. +// > 0 = Current size of updated GRIB2 message +// -1 = GRIB message was not initialized. Need to call +// routine g2_create first. +// -2 = GRIB message already complete. Cannot add new section. +// -3 = Sum of Section byte counts doesn't add to total byte count +// -4 = Previous Section was not 3 or 7. +// -5 = Could not find requested Product Definition Template. +// -6 = Section 3 (GDS) not previously defined in message +// -7 = Tried to use unsupported Data Representationi Template +// -8 = Specified use of a previously defined bitmap, but one +// does not exist in the GRIB message. +// -9 = GDT of one of 5.50 through 5.53 required to pack field +// using DRT 5.51. +// -10 = Error packing data field. +// +// REMARKS: Note that the Sections 4 through 7 can only follow +// Section 3 or Section 7 in a GRIB2 message. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ +{ + g2int ierr; + static unsigned char G=0x47; // 'G' + static unsigned char R=0x52; // 'R' + static unsigned char I=0x49; // 'I' + static unsigned char B=0x42; // 'B' + static unsigned char s7=0x37; // '7' + + unsigned char *cpack; + static g2int zero=0,one=1,four=4,five=5,six=6,seven=7; + const g2int minsize=50000; + g2int iofst,ibeg,lencurr,len,nsize; + g2int ilen,isecnum,i,nbits,temp,left; + g2int ibmprev,j,lcpack,ioctet,newlen,ndpts; + g2int lensec4,lensec5,lensec6,lensec7; + g2int issec3,isprevbmap,lpos3=0,JJ,KK,MM; + g2int *coordieee; + g2int width,height,iscan,itemp; + g2float *pfld; + gtemplate *mappds,*mapdrs; + unsigned int allones=4294967295u; + + ierr=0; +// +// Check to see if beginning of GRIB message exists +// + if ( cgrib[0]!=G || cgrib[1]!=R || cgrib[2]!=I || cgrib[3]!=B ) { + printf("g2_addfield: GRIB not found in given message.\n"); + printf("g2_addfield: Call to routine g2_create required to initialize GRIB messge.\n"); + ierr=-1; + return(ierr); + } +// +// Get current length of GRIB message +// + gbit(cgrib,&lencurr,96,32); +// +// Check to see if GRIB message is already complete +// + if ( cgrib[lencurr-4]==s7 && cgrib[lencurr-3]==s7 && + cgrib[lencurr-2]==s7 && cgrib[lencurr-1]==s7 ) { + printf("g2_addfield: GRIB message already complete. Cannot add new section.\n"); + ierr=-2; + return(ierr); + } +// +// Loop through all current sections of the GRIB message to +// find the last section number. +// + issec3=0; + isprevbmap=0; + len=16; // length of Section 0 + for (;;) { + // Get number and length of next section + iofst=len*8; + gbit(cgrib,&ilen,iofst,32); + iofst=iofst+32; + gbit(cgrib,&isecnum,iofst,8); + iofst=iofst+8; + // Check if previous Section 3 exists + if (isecnum == 3) { + issec3=1; + lpos3=len; + } + // Check if a previous defined bitmap exists + if (isecnum == 6) { + gbit(cgrib,&ibmprev,iofst,8); + iofst=iofst+8; + if ((ibmprev >= 0) && (ibmprev <= 253)) isprevbmap=1; + } + len=len+ilen; + // Exit loop if last section reached + if ( len == lencurr ) break; + // If byte count for each section doesn't match current + // total length, then there is a problem. + if ( len > lencurr ) { + printf("g2_addfield: Section byte counts don''t add to total.\n"); + printf("g2_addfield: Sum of section byte counts = %ld\n",len); + printf("g2_addfield: Total byte count in Section 0 = %ld\n",lencurr); + ierr=-3; + return(ierr); + } + } +// +// Sections 4 through 7 can only be added after section 3 or 7. +// + if ( (isecnum != 3) && (isecnum != 7) ) { + printf("g2_addfield: Sections 4-7 can only be added after Section 3 or 7.\n"); + printf("g2_addfield: Section ',isecnum,' was the last found in given GRIB message.\n"); + ierr=-4; + return(ierr); +// +// Sections 4 through 7 can only be added if section 3 was previously defined. +// + } + else if ( ! issec3) { + printf("g2_addfield: Sections 4-7 can only be added if Section 3 was previously included.\n"); + printf("g2_addfield: Section 3 was not found in given GRIB message.\n"); + printf("g2_addfield: Call to routine addgrid required to specify Grid definition.\n"); + ierr=-6; + return(ierr); + } +// +// Add Section 4 - Product Definition Section +// + ibeg=lencurr*8; // Calculate offset for beginning of section 4 + iofst=ibeg+32; // leave space for length of section + sbit(cgrib,&four,iofst,8); // Store section number ( 4 ) + iofst=iofst+8; + sbit(cgrib,&numcoord,iofst,16); // Store num of coordinate values + iofst=iofst+16; + sbit(cgrib,&ipdsnum,iofst,16); // Store Prod Def Template num. + iofst=iofst+16; + // + // Get Product Definition Template + // + mappds=getpdstemplate(ipdsnum); + if (mappds == 0) { // undefined template + ierr=-5; + return(ierr); + } + // + // Extend the Product Definition Template, if necessary. + // The number of values in a specific template may vary + // depending on data specified in the "static" part of the + // template. + // + if ( mappds->needext ) { + free(mappds); + mappds=extpdstemplate(ipdsnum,ipdstmpl); + } + // + // Pack up each input value in array ipdstmpl into the + // the appropriate number of octets, which are specified in + // corresponding entries in array mappds. + // + for (i=0;imaplen;i++) { + nbits=abs(mappds->map[i])*8; + if ( (mappds->map[i] >= 0) || (ipdstmpl[i] >= 0) ) + sbit(cgrib,ipdstmpl+i,iofst,nbits); + else { + sbit(cgrib,&one,iofst,1); + temp=abs(ipdstmpl[i]); + sbit(cgrib,&temp,iofst+1,nbits-1); + } + iofst=iofst+nbits; + } + // Pack template extension, if appropriate + j=mappds->maplen; + if ( mappds->needext && (mappds->extlen > 0) ) { + for (i=0;iextlen;i++) { + nbits=abs(mappds->ext[i])*8; + if ( (mappds->ext[i] >= 0) || (ipdstmpl[j] >= 0) ) + sbit(cgrib,ipdstmpl+j,iofst,nbits); + else { + sbit(cgrib,&one,iofst,1); + temp=abs(ipdstmpl[j]); + sbit(cgrib,&temp,iofst+1,nbits-1); + } + iofst=iofst+nbits; + j++; + } + } + free(mappds); + // + // Add Optional list of vertical coordinate values + // after the Product Definition Template, if necessary. + // + if ( numcoord != 0 ) { + coordieee=(g2int *)calloc(numcoord,sizeof(g2int)); + mkieee(coordlist,coordieee,numcoord); + sbits(cgrib,coordieee,iofst,32,0,numcoord); + iofst=iofst+(32*numcoord); + free(coordieee); + } + // + // Calculate length of section 4 and store it in octets + // 1-4 of section 4. + // + lensec4=(iofst-ibeg)/8; + sbit(cgrib,&lensec4,ibeg,32); +// +// Pack Data using appropriate algorithm +// + // + // Get Data Representation Template + // + mapdrs=getdrstemplate(idrsnum); + if (mapdrs == 0) { + ierr=-5; + return(ierr); + } + // + // contract data field, removing data at invalid grid points, + // if bit-map is provided with field. + // + if ( ibmap == 0 || ibmap==254 ) { + pfld=(g2float *)malloc(ngrdpts*sizeof(g2float)); + ndpts=0; + for (j=0;jmaplen;i++) { + nbits=abs(mapdrs->map[i])*8; + if ( (mapdrs->map[i] >= 0) || (idrstmpl[i] >= 0) ) + sbit(cgrib,idrstmpl+i,iofst,nbits); + else { + sbit(cgrib,&one,iofst,1); + temp=abs(idrstmpl[i]); + sbit(cgrib,&temp,iofst+1,nbits-1); + } + iofst=iofst+nbits; + } + free(mapdrs); + // + // Calculate length of section 5 and store it in octets + // 1-4 of section 5. + // + lensec5=(iofst-ibeg)/8; + sbit(cgrib,&lensec5,ibeg,32); + +// +// Add Section 6 - Bit-Map Section +// + ibeg=iofst; // Calculate offset for beginning of section 6 + iofst=ibeg+32; // leave space for length of section + sbit(cgrib,&six,iofst,8); // Store section number ( 6 ) + iofst=iofst+8; + sbit(cgrib,&ibmap,iofst,8); // Store Bit Map indicator + iofst=iofst+8; + // + // Store bitmap, if supplied + // + if (ibmap == 0) { + sbits(cgrib,bmap,iofst,1,0,ngrdpts); // Store BitMap + iofst=iofst+ngrdpts; + } + // + // If specifying a previously defined bit-map, make sure + // one already exists in the current GRIB message. + // + if ((ibmap==254) && ( ! isprevbmap)) { + printf("g2_addfield: Requested previously defined bitmap,"); + printf(" but one does not exist in the current GRIB message.\n"); + ierr=-8; + return(ierr); + } + // + // Calculate length of section 6 and store it in octets + // 1-4 of section 6. Pad to end of octect, if necessary. + // + left=8-(iofst%8); + if (left != 8) { + sbit(cgrib,&zero,iofst,left); // Pad with zeros to fill Octet + iofst=iofst+left; + } + lensec6=(iofst-ibeg)/8; + sbit(cgrib,&lensec6,ibeg,32); + +// +// Add Section 7 - Data Section +// + ibeg=iofst; // Calculate offset for beginning of section 7 + iofst=ibeg+32; // leave space for length of section + sbit(cgrib,&seven,iofst,8); // Store section number ( 7 ) + iofst=iofst+8; + // Store Packed Binary Data values, if non-constant field + if (lcpack != 0) { + ioctet=iofst/8; + //cgrib(ioctet+1:ioctet+lcpack)=cpack(1:lcpack) + for (j=0;j +#include +#include "grib2.h" + + +g2int g2_addgrid(unsigned char *cgrib,g2int *igds,g2int *igdstmpl,g2int *ideflist,g2int idefnum) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_addgrid +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-11-01 +// +// ABSTRACT: This routine packs up a Grid Definition Section (Section 3) +// and adds it to a GRIB2 message. It is used with routines "g2_create", +// "g2_addlocal", "g2_addfield", +// and "g2_gribend" to create a complete GRIB2 message. +// g2_create must be called first to initialize a new GRIB2 message. +// +// PROGRAM HISTORY LOG: +// 2002-11-01 Gilbert +// 2009-01-14 Vuong Changed structure name template to gtemplate +// +// USAGE: int g2_addgrid(unsigned char *cgrib,g2int *igds,g2int *igdstmpl, +// g2int *ideflist,g2int idefnum) +// INPUT ARGUMENTS: +// cgrib - Char array that contains the GRIB2 message to which +// section should be added. +// igds - Contains information needed for GRIB Grid Definition Section 3 +// Must be dimensioned >= 5. +// igds[0]=Source of grid definition (see Code Table 3.0) +// igds[1]=Number of grid points in the defined grid. +// igds[2]=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[3]=Interpretation of list for optional points +// definition. (Code Table 3.11) +// igds[4]=Grid Definition Template Number (Code Table 3.1) +// igdstmpl - Contains the data values for the specified Grid Definition +// Template ( NN=igds[4] ). Each element of this integer +// array contains an entry (in the order specified) of Grid +// Defintion Template 3.NN +// ideflist - (Used if igds[2] != 0) This array contains the +// number of grid points contained in each row ( or column ) +// idefnum - (Used if igds[2] != 0) The number of entries +// in array ideflist. i.e. number of rows ( or columns ) +// for which optional grid points are defined. +// +// OUTPUT ARGUMENTS: +// cgrib - Char array to contain the updated GRIB2 message. +// Must be allocated large enough to store the entire +// GRIB2 message. +// +// RETURN VALUES: +// ierr - Return code. +// > 0 = Current size of updated GRIB2 message +// -1 = GRIB message was not initialized. Need to call +// routine gribcreate first. +// -2 = GRIB message already complete. Cannot add new section. +// -3 = Sum of Section byte counts doesn't add to total byte count +// -4 = Previous Section was not 1, 2 or 7. +// -5 = Could not find requested Grid Definition Template. +// +// REMARKS: Note that the Grid Def Section ( Section 3 ) can only follow +// Section 1, 2 or Section 7 in a GRIB2 message. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ +{ + + g2int ierr; + static unsigned char G=0x47; // 'G' + static unsigned char R=0x52; // 'R' + static unsigned char I=0x49; // 'I' + static unsigned char B=0x42; // 'B' + static unsigned char seven=0x37; // '7' + + static g2int one=1,three=3,miss=65535; + g2int lensec3,iofst,ibeg,lencurr,len; + g2int i,j,temp,ilen,isecnum,nbits; + gtemplate *mapgrid=0; + + ierr=0; +// +// Check to see if beginning of GRIB message exists +// + if ( cgrib[0]!=G || cgrib[1]!=R || cgrib[2]!=I || cgrib[3]!=B ) { + printf("g2_addgrid: GRIB not found in given message.\n"); + printf("g2_addgrid: Call to routine gribcreate required to initialize GRIB messge.\n"); + ierr=-1; + return(ierr); + } +// +// Get current length of GRIB message +// + gbit(cgrib,&lencurr,96,32); +// +// Check to see if GRIB message is already complete +// + if ( cgrib[lencurr-4]==seven && cgrib[lencurr-3]==seven && + cgrib[lencurr-2]==seven && cgrib[lencurr-1]==seven ) { + printf("g2_addgrid: GRIB message already complete. Cannot add new section.\n"); + ierr=-2; + return(ierr); + } +// +// Loop through all current sections of the GRIB message to +// find the last section number. +// + len=16; // length of Section 0 + for (;;) { + // Get section number and length of next section + iofst=len*8; + gbit(cgrib,&ilen,iofst,32); + iofst=iofst+32; + gbit(cgrib,&isecnum,iofst,8); + len=len+ilen; + // Exit loop if last section reached + if ( len == lencurr ) break; + // If byte count for each section doesn't match current + // total length, then there is a problem. + if ( len > lencurr ) { + printf("g2_addgrid: Section byte counts don''t add to total.\n"); + printf("g2_addgrid: Sum of section byte counts = %ld\n",len); + printf("g2_addgrid: Total byte count in Section 0 = %ld\n",lencurr); + ierr=-3; + return(ierr); + } + } +// +// Section 3 can only be added after sections 1, 2 and 7. +// + if ( (isecnum!=1) && (isecnum!=2) && (isecnum!=7) ) { + printf("g2_addgrid: Section 3 can only be added after Section 1, 2 or 7.\n"); + printf("g2_addgrid: Section ',isecnum,' was the last found in given GRIB message.\n"); + ierr=-4; + return(ierr); + } +// +// Add Section 3 - Grid Definition Section +// + ibeg=lencurr*8; // Calculate offset for beginning of section 3 + iofst=ibeg+32; // leave space for length of section + sbit(cgrib,&three,iofst,8); // Store section number ( 3 ) + iofst=iofst+8; + sbit(cgrib,igds+0,iofst,8); // Store source of Grid def. + iofst=iofst+8; + sbit(cgrib,igds+1,iofst,32); // Store number of data pts. + iofst=iofst+32; + sbit(cgrib,igds+2,iofst,8); // Store number of extra octets. + iofst=iofst+8; + sbit(cgrib,igds+3,iofst,8); // Store interp. of extra octets. + iofst=iofst+8; + // if Octet 6 is not equal to zero, Grid Definition Template may + // not be supplied. + if ( igds[0] == 0 ) + sbit(cgrib,igds+4,iofst,16); // Store Grid Def Template num. + else + sbit(cgrib,&miss,iofst,16); // Store missing value as Grid Def Template num. + iofst=iofst+16; + // + // Get Grid Definition Template + // + if (igds[0] == 0) { + mapgrid=getgridtemplate(igds[4]); + if (mapgrid == 0) { // undefined template + ierr=-5; + return(ierr); + } + // + // Extend the Grid Definition Template, if necessary. + // The number of values in a specific template may vary + // depending on data specified in the "static" part of the + // template. + // + if ( mapgrid->needext ) { + free(mapgrid); + mapgrid=extgridtemplate(igds[4],igdstmpl); + } + } + // + // Pack up each input value in array igdstmpl into the + // the appropriate number of octets, which are specified in + // corresponding entries in array mapgrid. + // + for (i=0;imaplen;i++) { + nbits=abs(mapgrid->map[i])*8; + if ( (mapgrid->map[i] >= 0) || (igdstmpl[i] >= 0) ) + sbit(cgrib,igdstmpl+i,iofst,nbits); + else { + sbit(cgrib,&one,iofst,1); + temp=abs(igdstmpl[i]); + sbit(cgrib,&temp,iofst+1,nbits-1); + } + iofst=iofst+nbits; + } + // Pack template extension, if appropriate + j=mapgrid->maplen; + if ( mapgrid->needext && (mapgrid->extlen > 0) ) { + for (i=0;iextlen;i++) { + nbits=abs(mapgrid->ext[i])*8; + if ( (mapgrid->ext[i] >= 0) || (igdstmpl[j] >= 0) ) + sbit(cgrib,igdstmpl+j,iofst,nbits); + else { + sbit(cgrib,&one,iofst,1); + temp=abs(igdstmpl[j]); + sbit(cgrib,&temp,iofst+1,nbits-1); + } + iofst=iofst+nbits; + j++; + } + } + free(mapgrid); + // + // If requested, + // Insert optional list of numbers defining number of points + // in each row or column. This is used for non regular + // grids. + // + if ( igds[2] != 0 ) { + nbits=igds[2]*8; + sbits(cgrib,ideflist,iofst,nbits,0,idefnum); + iofst=iofst+(nbits*idefnum); + } + // + // Calculate length of section 3 and store it in octets + // 1-4 of section 3. + // + lensec3=(iofst-ibeg)/8; + sbit(cgrib,&lensec3,ibeg,32); + +// +// Update current byte total of message in Section 0 +// + lencurr+=lensec3; + sbit(cgrib,&lencurr,96,32); + + return(lencurr); + +} diff --git a/src/plugins/weatherdata/gfs/g2clib/g2_addlocal.c b/src/plugins/weatherdata/gfs/g2clib/g2_addlocal.c new file mode 100644 index 000000000..c291367b2 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/g2_addlocal.c @@ -0,0 +1,147 @@ +#include +#include "grib2.h" + +g2int g2_addlocal(unsigned char *cgrib,unsigned char *csec2,g2int lcsec2) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_addlocal +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-11-01 +// +// ABSTRACT: This routine adds a Local Use Section (Section 2) to +// a GRIB2 message. It is used with routines "g2_create", +// "g2_addgrid", "g2_addfield", +// and "g2_gribend" to create a complete GRIB2 message. +// g2_create must be called first to initialize a new GRIB2 message. +// +// PROGRAM HISTORY LOG: +// 2002-11-01 Gilbert +// +// USAGE: int g2_addlocal(unsigned char *cgrib,unsigned char *csec2, +// g2int lcsec2) +// INPUT ARGUMENTS: +// cgrib - Char array that contains the GRIB2 message to which section +// 2 should be added. +// csec2 - Character array containing information to be added in +// Section 2. +// lcsec2 - Number of bytes of character array csec2 to be added to +// Section 2. +// +// OUTPUT ARGUMENT: +// cgrib - Char array to contain the updated GRIB2 message. +// Must be allocated large enough to store the entire +// GRIB2 message. +// +// RETURN VALUES: +// ierr - Return code. +// > 0 = Current size of updated GRIB2 message +// -1 = GRIB message was not initialized. Need to call +// routine gribcreate first. +// -2 = GRIB message already complete. Cannot add new section. +// -3 = Sum of Section byte counts doesn't add to total byte count +// -4 = Previous Section was not 1 or 7. +// +// REMARKS: Note that the Local Use Section ( Section 2 ) can only follow +// Section 1 or Section 7 in a GRIB2 message. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ +{ + + g2int ierr; + static unsigned char G=0x47; // 'G' + static unsigned char R=0x52; // 'R' + static unsigned char I=0x49; // 'I' + static unsigned char B=0x42; // 'B' + static unsigned char seven=0x37; // '7' + + static g2int two=2; + g2int j,k,lensec2,iofst,ibeg,lencurr,ilen,len,istart; + g2int isecnum; + + ierr=0; +// +// Check to see if beginning of GRIB message exists +// + if ( cgrib[0]!=G || cgrib[1]!=R || cgrib[2]!=I || cgrib[3]!=B ) { + printf("g2_addlocal: GRIB not found in given message.\n"); + printf("g2_addlocal: Call to routine g2_create required to initialize GRIB messge.\n"); + ierr=-1; + return(ierr); + } +// +// Get current length of GRIB message +// + gbit(cgrib,&lencurr,96,32); +// +// Check to see if GRIB message is already complete +// + if ( cgrib[lencurr-4]==seven && cgrib[lencurr-3]==seven && + cgrib[lencurr-2]==seven && cgrib[lencurr-1]==seven ) { + printf("g2_addlocal: GRIB message already complete. Cannot add new section.\n"); + ierr=-2; + return(ierr); + } +// +// Loop through all current sections of the GRIB message to +// find the last section number. +// + len=16; // length of Section 0 + for (;;) { + // Get section number and length of next section + iofst=len*8; + gbit(cgrib,&ilen,iofst,32); + iofst=iofst+32; + gbit(cgrib,&isecnum,iofst,8); + len=len+ilen; + // Exit loop if last section reached + if ( len == lencurr ) break; + // If byte count for each section doesn't match current + // total length, then there is a problem. + if ( len > lencurr ) { + printf("g2_addlocal: Section byte counts don't add to total.\n"); + printf("g2_addlocal: Sum of section byte counts = %ld\n",len); + printf("g2_addlocal: Total byte count in Section 0 = %ld\n",lencurr); + ierr=-3; + return(ierr); + } + } +// +// Section 2 can only be added after sections 1 and 7. +// + if ( (isecnum!=1) && (isecnum!=7) ) { + printf("g2_addlocal: Section 2 can only be added after Section 1 or Section 7.\n"); + printf("g2_addlocal: Section %ld was the last found in given GRIB message.\n",isecnum); + ierr=-4; + return(ierr); + } +// +// Add Section 2 - Local Use Section +// + ibeg=lencurr*8; // Calculate offset for beginning of section 2 + iofst=ibeg+32; // leave space for length of section + sbit(cgrib,&two,iofst,8); // Store section number ( 2 ) + istart=lencurr+5; + //cgrib(istart+1:istart+lcsec2)=csec2(1:lcsec2) + k=0; + for (j=istart;j +#include "grib2.h" + +#define MAPSEC1LEN 13 + +g2int g2_create(unsigned char *cgrib,g2int *listsec0,g2int *listsec1) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_create +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 +// +// ABSTRACT: This routine initializes a new GRIB2 message and packs +// GRIB2 sections 0 (Indicator Section) and 1 (Identification Section). +// This routine is used with routines "g2_addlocal", "g2_addgrid", +// "g2_addfield", and "g2_gribend" to create a complete GRIB2 message. +// g2_create must be called first to initialize a new GRIB2 message. +// Also, a call to g2_gribend is required to complete GRIB2 message +// after all fields have been added. +// +// PROGRAM HISTORY LOG: +// 2002-10-31 Gilbert +// +// USAGE: int g2_create(unsigned char *cgrib,g2int *listsec0,g2int *listsec1) +// INPUT ARGUMENTS: +// cgrib - Character array to contain the GRIB2 message +// listsec0 - Contains information needed for GRIB Indicator Section 0. +// Must be dimensioned >= 2. +// listsec0[0]=Discipline-GRIB Master Table Number +// (see Code Table 0.0) +// listsec0[1]=GRIB Edition Number (currently 2) +// listsec1 - Contains information needed for GRIB Identification Section 1. +// Must be dimensioned >= 13. +// listsec1[0]=Id of orginating centre (Common Code Table C-1) +// listsec1[1]=Id of orginating sub-centre (local table) +// listsec1[2]=GRIB Master Tables Version Number (Code Table 1.0) +// listsec1[3]=GRIB Local Tables Version Number (Code Table 1.1) +// listsec1[4]=Significance of Reference Time (Code Table 1.2) +// listsec1[5]=Reference Time - Year (4 digits) +// listsec1[6]=Reference Time - Month +// listsec1[7]=Reference Time - Day +// listsec1[8]=Reference Time - Hour +// listsec1[9]=Reference Time - Minute +// listsec1[10]=Reference Time - Second +// listsec1[11]=Production status of data (Code Table 1.3) +// listsec1[12]=Type of processed data (Code Table 1.4) +// +// OUTPUT ARGUMENTS: +// cgrib - Char array to contain the new GRIB2 message. +// Must be allocated large enough to store the entire +// GRIB2 message. +// +// RETURN VALUES: +// ierr - return code. +// > 0 = Current size of new GRIB2 message +// -1 = Tried to use for version other than GRIB Edition 2 +// +// REMARKS: This routine is intended for use with routines "g2_addlocal", +// "g2_addgrid", "g2_addfield", and "g2_gribend" to create a complete +// GRIB2 message. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ +{ + + g2int ierr; + g2int zero=0,one=1; + g2int mapsec1len=MAPSEC1LEN; + g2int mapsec1[MAPSEC1LEN]={ 2,2,1,1,1,2,1,1,1,1,1,1,1 }; + g2int i,lensec0,lensec1,iofst,ibeg,nbits,len; + + ierr=0; +// +// Currently handles only GRIB Edition 2. +// + if (listsec0[1] != 2) { + printf("g2_create: can only code GRIB edition 2."); + ierr=-1; + return (ierr); + } +// +// Pack Section 0 - Indicator Section +// ( except for total length of GRIB message ) +// + cgrib[0]=0x47; // 'G' // Beginning of GRIB message + cgrib[1]=0x52; // 'R' + cgrib[2]=0x49; // 'I' + cgrib[3]=0x42; // 'B' + sbit(cgrib,&zero,32,16); // reserved for future use + sbit(cgrib,listsec0+0,48,8); // Discipline + sbit(cgrib,listsec0+1,56,8); // GRIB edition number + lensec0=16; // bytes (octets) +// +// Pack Section 1 - Identification Section +// + ibeg=lensec0*8; // Calculate offset for beginning of section 1 + iofst=ibeg+32; // leave space for length of section + sbit(cgrib,&one,iofst,8); // Store section number ( 1 ) + iofst=iofst+8; + // + // Pack up each input value in array listsec1 into the + // the appropriate number of octets, which are specified in + // corresponding entries in array mapsec1. + // + for (i=0;i +#include "grib2.h" + +void g2_free(gribfield *gfld) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_free +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-28 +// +// ABSTRACT: This routine frees up memory that was allocated for +// struct gribfield. +// +// PROGRAM HISTORY LOG: +// 2002-10-28 Gilbert +// +// USAGE: g2_free(gribfield *gfld) +// ARGUMENT: +// gfld - pointer to gribfield structure (defined in include file grib2.h) +// returned from routine g2_getfld. +// +// REMARKS: This routine must be called to free up memory used by +// the decode routine, g2_getfld, when user no longer needs to +// reference this data. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ +{ + + if (gfld->idsect != 0 ) free(gfld->idsect); + if (gfld->local != 0 ) free(gfld->local); + if (gfld->list_opt != 0 ) free(gfld->list_opt); + if (gfld->igdtmpl != 0 ) free(gfld->igdtmpl); + if (gfld->ipdtmpl != 0 ) free(gfld->ipdtmpl); + if (gfld->coord_list != 0 ) free(gfld->coord_list); + if (gfld->idrtmpl != 0 ) free(gfld->idrtmpl); + if (gfld->bmap != 0 ) free(gfld->bmap); + if (gfld->fld != 0 ) free(gfld->fld); + free(gfld); + + return; +} diff --git a/src/plugins/weatherdata/gfs/g2clib/g2_getfld.c b/src/plugins/weatherdata/gfs/g2clib/g2_getfld.c new file mode 100644 index 000000000..239c2f768 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/g2_getfld.c @@ -0,0 +1,552 @@ +#include +#include +#include "grib2.h" + +g2int g2_unpack1(unsigned char *,g2int *,g2int **,g2int *); +g2int g2_unpack2(unsigned char *,g2int *,g2int *,unsigned char **); +g2int g2_unpack3(unsigned char *,g2int *,g2int **,g2int **, + g2int *,g2int **,g2int *); +g2int g2_unpack4(unsigned char *,g2int *,g2int *,g2int **, + g2int *,g2float **,g2int *); +g2int g2_unpack5(unsigned char *,g2int *,g2int *,g2int *, g2int **,g2int *); +g2int g2_unpack6(unsigned char *,g2int *,g2int ,g2int *, g2int **); +g2int g2_unpack7(unsigned char *,g2int *,g2int ,g2int *, + g2int ,g2int *,g2int ,g2float **); + +g2int g2_getfld(unsigned char *cgrib,g2int ifldnum,g2int unpack,g2int expand, + gribfield **gfld) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_getfld +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-28 +// +// ABSTRACT: This subroutine returns all the metadata, template values, +// Bit-map ( if applicable ), and the unpacked data for a given data +// field. All of the information returned is stored in a gribfield +// structure, which is defined in file grib2.h. +// Users of this routine will need to include "grib2.h" in their source +// code that calls this routine. Each component of the gribfield +// struct is also described in the OUTPUT ARGUMENTS section below. +// +// Since there can be multiple data fields packed into a GRIB2 +// message, the calling routine indicates which field is being requested +// with the ifldnum argument. +// +// PROGRAM HISTORY LOG: +// 2002-10-28 Gilbert +// 2013-08-08 Vuong Free up memory in array igds - free(igds) +// +// USAGE: #include "grib2.h" +// int g2_getfld(unsigned char *cgrib,g2int ifldnum,g2int unpack, +// g2int expand,gribfield **gfld) +// INPUT ARGUMENTS: +// cgrib - Character pointer to the GRIB2 message +// ifldnum - Specifies which field in the GRIB2 message to return. +// unpack - Boolean value indicating whether to unpack bitmap/data field +// 1 = unpack bitmap (if present) and data values +// 0 = do not unpack bitmap and data values +// expand - Boolean value indicating whether the data points should be +// expanded to the correspond grid, if a bit-map is present. +// 1 = if possible, expand data field to grid, inserting zero +// values at gridpoints that are bitmapped out. +// (SEE REMARKS2) +// 0 = do not expand data field, leaving it an array of +// consecutive data points for each "1" in the bitmap. +// This argument is ignored if unpack == 0 OR if the +// returned field does not contain a bit-map. +// +// OUTPUT ARGUMENT: +// gribfield gfld; - pointer to structure gribfield containing +// all decoded data for the data field. +// +// gfld->version = GRIB edition number ( currently 2 ) +// gfld->discipline = Message Discipline ( see Code Table 0.0 ) +// gfld->idsect = Contains the entries in the Identification +// Section ( Section 1 ) +// This element is a pointer to an array +// that holds the data. +// gfld->idsect[0] = Identification of originating Centre +// ( see Common Code Table C-1 ) +// 7 - US National Weather Service +// gfld->idsect[1] = Identification of originating Sub-centre +// gfld->idsect[2] = GRIB Master Tables Version Number +// ( see Code Table 1.0 ) +// 0 - Experimental +// 1 - Initial operational version number +// gfld->idsect[3] = GRIB Local Tables Version Number +// ( see Code Table 1.1 ) +// 0 - Local tables not used +// 1-254 - Number of local tables version used +// gfld->idsect[4] = Significance of Reference Time (Code Table 1.2) +// 0 - Analysis +// 1 - Start of forecast +// 2 - Verifying time of forecast +// 3 - Observation time +// gfld->idsect[5] = Year ( 4 digits ) +// gfld->idsect[6] = Month +// gfld->idsect[7) = Day +// gfld->idsect[8] = Hour +// gfld->idsect[9] = Minute +// gfld->idsect[10] = Second +// gfld->idsect[11] = Production status of processed data +// ( see Code Table 1.3 ) +// 0 - Operational products +// 1 - Operational test products +// 2 - Research products +// 3 - Re-analysis products +// gfld->idsect[12] = Type of processed data ( see Code Table 1.4 ) +// 0 - Analysis products +// 1 - Forecast products +// 2 - Analysis and forecast products +// 3 - Control forecast products +// 4 - Perturbed forecast products +// 5 - Control and perturbed forecast products +// 6 - Processed satellite observations +// 7 - Processed radar observations +// gfld->idsectlen = Number of elements in gfld->idsect[]. +// gfld->local = Pointer to character array containing contents +// of Local Section 2, if included +// gfld->locallen = length of array gfld->local[] +// gfld->ifldnum = field number within GRIB message +// gfld->griddef = Source of grid definition (see Code Table 3.0) +// 0 - Specified in Code table 3.1 +// 1 - Predetermined grid Defined by originating centre +// gfld->ngrdpts = Number of grid points in the defined grid. +// gfld->numoct_opt = 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. +// gfld->interp_opt = Interpretation of list for optional points +// definition. (Code Table 3.11) +// gfld->igdtnum = Grid Definition Template Number (Code Table 3.1) +// gfld->igdtmpl = Contains the data values for the specified Grid +// Definition Template ( NN=gfld->igdtnum ). Each +// element of this integer array contains an entry (in +// the order specified) of Grid Defintion Template 3.NN +// This element is a pointer to an array +// that holds the data. +// gfld->igdtlen = Number of elements in gfld->igdtmpl[]. i.e. number of +// entries in Grid Defintion Template 3.NN +// ( NN=gfld->igdtnum ). +// gfld->list_opt = (Used if gfld->numoct_opt .ne. 0) This array +// contains the number of grid points contained in +// each row ( or column ). (part of Section 3) +// This element is a pointer to an array +// that holds the data. This pointer is nullified +// if gfld->numoct_opt=0. +// gfld->num_opt = (Used if gfld->numoct_opt .ne. 0) +// The number of entries +// in array ideflist. i.e. number of rows ( or columns ) +// for which optional grid points are defined. This value +// is set to zero, if gfld->numoct_opt=0. +// gfdl->ipdtnum = Product Definition Template Number(see Code Table 4.0) +// gfld->ipdtmpl = Contains the data values for the specified Product +// Definition Template ( N=gfdl->ipdtnum ). Each element +// of this integer array contains an entry (in the +// order specified) of Product Defintion Template 4.N. +// This element is a pointer to an array +// that holds the data. +// gfld->ipdtlen = Number of elements in gfld->ipdtmpl[]. i.e. number of +// entries in Product Defintion Template 4.N +// ( N=gfdl->ipdtnum ). +// gfld->coord_list = Real array containing floating point values +// intended to document the vertical discretisation +// associated to model data on hybrid coordinate +// vertical levels. (part of Section 4) +// This element is a pointer to an array +// that holds the data. +// gfld->num_coord = number of values in array gfld->coord_list[]. +// gfld->ndpts = Number of data points unpacked and returned. +// gfld->idrtnum = Data Representation Template Number +// ( see Code Table 5.0) +// gfld->idrtmpl = Contains the data values for the specified Data +// Representation Template ( N=gfld->idrtnum ). Each +// element of this integer array contains an entry +// (in the order specified) of Product Defintion +// Template 5.N. +// This element is a pointer to an array +// that holds the data. +// gfld->idrtlen = Number of elements in gfld->idrtmpl[]. i.e. number +// of entries in Data Representation Template 5.N +// ( N=gfld->idrtnum ). +// gfld->unpacked = logical value indicating whether the bitmap and +// data values were unpacked. If false, +// gfld->bmap and gfld->fld pointers are nullified. +// gfld->expanded = Logical value indicating whether the data field +// was expanded to the grid in the case where a +// bit-map is present. If true, the data points in +// gfld->fld match the grid points and zeros were +// inserted at grid points where data was bit-mapped +// out. If false, the data values in gfld->fld were +// not expanded to the grid and are just a consecutive +// array of data points corresponding to each value of +// "1" in gfld->bmap. +// gfld->ibmap = Bitmap indicator ( see Code Table 6.0 ) +// 0 = bitmap applies and is included in Section 6. +// 1-253 = Predefined bitmap applies +// 254 = Previously defined bitmap applies to this field +// 255 = Bit map does not apply to this product. +// gfld->bmap = integer array containing decoded bitmap, +// if gfld->ibmap=0 or gfld->ibap=254. Otherwise nullified +// This element is a pointer to an array +// that holds the data. +// gfld->fld = Array of gfld->ndpts unpacked data points. +// This element is a pointer to an array +// that holds the data. +// +// +// RETURN VALUES: +// ierr - Error return code. +// 0 = no error +// 1 = Beginning characters "GRIB" not found. +// 2 = GRIB message is not Edition 2. +// 3 = The data field request number was not positive. +// 4 = End string "7777" found, but not where expected. +// 6 = GRIB message did not contain the requested number of +// data fields. +// 7 = End string "7777" not found at end of message. +// 8 = Unrecognized Section encountered. +// 9 = Data Representation Template 5.NN not yet implemented. +// 15 = Error unpacking Section 1. +// 16 = Error unpacking Section 2. +// 10 = Error unpacking Section 3. +// 11 = Error unpacking Section 4. +// 12 = Error unpacking Section 5. +// 13 = Error unpacking Section 6. +// 14 = Error unpacking Section 7. +// 17 = Previous bitmap specified, yet none exists. +// +// REMARKS: Note that struct gribfield is allocated by this routine and it +// also contains pointers to many arrays of data that were allocated +// during decoding. Users are encouraged to free up this memory, +// when it is no longer needed, by an explicit call to routine g2_free. +// EXAMPLE: +// #include "grib2.h" +// gribfield *gfld; +// ret=g2_getfld(cgrib,1,1,1,&gfld); +// ... +// g2_free(gfld); +// +// Routine g2_info can be used to first determine +// how many data fields exist in a given GRIB message. +// +// REMARKS2: It may not always be possible to expand a bit-mapped data field. +// If a pre-defined bit-map is used and not included in the GRIB2 +// message itself, this routine would not have the necessary +// information to expand the data. In this case, gfld->expanded would +// would be set to 0 (false), regardless of the value of input +// argument expand. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ +{ + + g2int have3,have4,have5,have6,have7,ierr,jerr; + g2int numfld,j,n,istart,iofst,ipos; + g2int disc,ver,lensec0,lengrib,lensec,isecnum; + g2int *igds; + g2int *bmpsave; + g2float *newfld; + gribfield *lgfld; + + have3=0; + have4=0; + have5=0; + have6=0; + have7=0; + ierr=0; + numfld=0; + + lgfld=(gribfield *)malloc(sizeof(gribfield)); + *gfld=lgfld; + + lgfld->locallen=0; + lgfld->idsect=0; + lgfld->local=0; + lgfld->list_opt=0; + lgfld->igdtmpl=0; + lgfld->ipdtmpl=0; + lgfld->idrtmpl=0; + lgfld->coord_list=0; + lgfld->bmap=0; + lgfld->fld=0; +// +// Check for valid request number +// + if (ifldnum <= 0) { + printf("g2_getfld: Request for field number must be positive.\n"); + ierr=3; + return(ierr); + } +// +// Check for beginning of GRIB message in the first 100 bytes +// + istart=-1; + for (j=0;j<100;j++) { + if (cgrib[j]=='G' && cgrib[j+1]=='R' &&cgrib[j+2]=='I' && + cgrib[j+3]=='B') { + istart=j; + break; + } + } + if (istart == -1) { + printf("g2_getfld: Beginning characters GRIB not found.\n"); + ierr=1; + return(ierr); + } +// +// Unpack Section 0 - Indicator Section +// + iofst=8*(istart+6); + gbit(cgrib,&disc,iofst,8); // Discipline + iofst=iofst+8; + gbit(cgrib,&ver,iofst,8); // GRIB edition number + iofst=iofst+8; + iofst=iofst+32; + gbit(cgrib,&lengrib,iofst,32); // Length of GRIB message + iofst=iofst+32; + lensec0=16; + ipos=istart+lensec0; +// +// Currently handles only GRIB Edition 2. +// + if (ver != 2) { + printf("g2_getfld: can only decode GRIB edition 2.\n"); + ierr=2; + return(ierr); + } +// +// Loop through the remaining sections keeping track of the +// length of each. Also keep the latest Grid Definition Section info. +// Unpack the requested field number. +// + for (;;) { + // Check to see if we are at end of GRIB message + if (cgrib[ipos]=='7' && cgrib[ipos+1]=='7' && cgrib[ipos+2]=='7' && + cgrib[ipos+3]=='7') { + ipos=ipos+4; + // If end of GRIB message not where expected, issue error + if (ipos != (istart+lengrib)) { + printf("g2_getfld: '7777' found, but not where expected.\n"); + ierr=4; + return(ierr); + } + break; + } + // Get length of Section and Section number + iofst=(ipos-1)*8; + iofst=ipos*8; + gbit(cgrib,&lensec,iofst,32); // Get Length of Section + iofst=iofst+32; + gbit(cgrib,&isecnum,iofst,8); // Get Section number + iofst=iofst+8; + //printf(" lensec= %ld secnum= %ld \n",lensec,isecnum); + // + // Check to see if section number is valid + // + if ( isecnum<1 || isecnum>7 ) { + printf("g2_getfld: Unrecognized Section Encountered=%ld\n",isecnum); + ierr=8; + return(ierr); + } + // + // If found Section 1, decode elements in Identification Section + // + if (isecnum == 1) { + iofst=iofst-40; // reset offset to beginning of section + jerr=g2_unpack1(cgrib,&iofst,&lgfld->idsect,&lgfld->idsectlen); + if (jerr !=0 ) { + ierr=15; + return(ierr); + } + } + // + // If found Section 2, Grab local section + // Save in case this is the latest one before the requested field. + // + if (isecnum == 2) { + iofst=iofst-40; // reset offset to beginning of section + if (lgfld->local!=0) free(lgfld->local); + jerr=g2_unpack2(cgrib,&iofst,&lgfld->locallen,&lgfld->local); + if (jerr != 0) { + ierr=16; + return(ierr); + } + } + // + // If found Section 3, unpack the GDS info using the + // appropriate template. Save in case this is the latest + // grid before the requested field. + // + if (isecnum == 3) { + iofst=iofst-40; // reset offset to beginning of section + if (lgfld->igdtmpl!=0) free(lgfld->igdtmpl); + if (lgfld->list_opt!=0) free(lgfld->list_opt); + jerr=g2_unpack3(cgrib,&iofst,&igds,&lgfld->igdtmpl, + &lgfld->igdtlen,&lgfld->list_opt,&lgfld->num_opt); + if (jerr == 0) { + have3=1; + lgfld->griddef=igds[0]; + lgfld->ngrdpts=igds[1]; + lgfld->numoct_opt=igds[2]; + lgfld->interp_opt=igds[3]; + lgfld->igdtnum=igds[4]; + free(igds); + } + else { + ierr=10; + return(ierr); + } + } + // + // If found Section 4, check to see if this field is the + // one requested. + // + if (isecnum == 4) { + numfld=numfld+1; + if (numfld == ifldnum) { + lgfld->discipline=disc; + lgfld->version=ver; + lgfld->ifldnum=ifldnum; + lgfld->unpacked=unpack; + lgfld->expanded=0; + iofst=iofst-40; // reset offset to beginning of section + jerr=g2_unpack4(cgrib,&iofst,&lgfld->ipdtnum, + &lgfld->ipdtmpl,&lgfld->ipdtlen,&lgfld->coord_list, + &lgfld->num_coord); + if (jerr == 0) + have4=1; + else { + ierr=11; + return(ierr); + } + } + } + // + // If found Section 5, check to see if this field is the + // one requested. + // + if (isecnum == 5 && numfld == ifldnum) { + iofst=iofst-40; // reset offset to beginning of section + jerr=g2_unpack5(cgrib,&iofst,&lgfld->ndpts,&lgfld->idrtnum, + &lgfld->idrtmpl,&lgfld->idrtlen); + if (jerr == 0) + have5=1; + else { + ierr=12; + return(ierr); + } + } + // + // If found Section 6, Unpack bitmap. + // Save in case this is the latest + // bitmap before the requested field. + // + if (isecnum == 6) { + if (unpack) { // unpack bitmap + iofst=iofst-40; // reset offset to beginning of section + bmpsave=lgfld->bmap; // save pointer to previous bitmap + jerr=g2_unpack6(cgrib,&iofst,lgfld->ngrdpts,&lgfld->ibmap, + &lgfld->bmap); + if (jerr == 0) { + have6=1; + if (lgfld->ibmap == 254) // use previously specified bitmap + if( bmpsave!=0 ) + lgfld->bmap=bmpsave; + else { + printf("g2_getfld: Prev bit-map specified, but none exist.\n"); + ierr=17; + return(ierr); + } + else // get rid of it + if( bmpsave!=0 ) free(bmpsave); + } + else { + ierr=13; + return(ierr); + } + } + else { // do not unpack bitmap + gbit(cgrib,&lgfld->ibmap,iofst,8); // Get BitMap Indicator + have6=1; + } + } + // + // If found Section 7, check to see if this field is the + // one requested. + // + if (isecnum==7 && numfld==ifldnum && unpack) { + iofst=iofst-40; // reset offset to beginning of section + jerr=g2_unpack7(cgrib,&iofst,lgfld->igdtnum,lgfld->igdtmpl, + lgfld->idrtnum,lgfld->idrtmpl,lgfld->ndpts, + &lgfld->fld); + if (jerr == 0) { + have7=1; + // If bitmap is used with this field, expand data field + // to grid, if possible. + if ( lgfld->ibmap != 255 && lgfld->bmap != 0 ) { + if ( expand == 1 ) { + n=0; + newfld=(g2float *)calloc(lgfld->ngrdpts,sizeof(g2float)); + for (j=0;jngrdpts;j++) { + if (lgfld->bmap[j]==1) newfld[j]=lgfld->fld[n++]; + } + free(lgfld->fld); + lgfld->fld=newfld; + lgfld->expanded=1; + } + else { + lgfld->expanded=0; + } + } + else { + lgfld->expanded=1; + } + } + else { + printf("g2_getfld: return from g2_unpack7 = %d \n",(int)jerr); + ierr=14; + return(ierr); + } + } + // + // Check to see if we read pass the end of the GRIB + // message and missed the terminator string '7777'. + // + ipos=ipos+lensec; // Update beginning of section pointer + if (ipos > (istart+lengrib)) { + printf("g2_getfld: '7777' not found at end of GRIB message.\n"); + ierr=7; + return(ierr); + } + // + // If unpacking requested, return when all sections have been + // processed + // + if (unpack && have3 && have4 && have5 && have6 && have7) + return(ierr); + // + // If unpacking is not requested, return when sections + // 3 through 6 have been processed + // + if ((! unpack) && have3 && have4 && have5 && have6) + return(ierr); + + } + +// +// If exited from above loop, the end of the GRIB message was reached +// before the requested field was found. +// + printf("g2_getfld: GRIB message contained %ld different fields.\n",numfld); + printf("g2_getfld: The request was for field %ld.\n",ifldnum); + ierr=6; + + return(ierr); + +} diff --git a/src/plugins/weatherdata/gfs/g2clib/g2_gribend.c b/src/plugins/weatherdata/gfs/g2clib/g2_gribend.c new file mode 100644 index 000000000..5373aaada --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/g2_gribend.c @@ -0,0 +1,122 @@ +#include +#include "grib2.h" + +g2int g2_gribend(unsigned char *cgrib) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_gribend +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 +// +// ABSTRACT: This routine finalizes a GRIB2 message after all grids +// and fields have been added. It adds the End Section ( "7777" ) +// to the end of the GRIB message and calculates the length and stores +// it in the appropriate place in Section 0. +// This routine is used with routines "g2_create", "g2_addlocal", +// "g2_addgrid", and "g2_addfield" to create a complete GRIB2 message. +// g2_create must be called first to initialize a new GRIB2 message. +// +// PROGRAM HISTORY LOG: +// 2002-10-31 Gilbert +// +// USAGE: int g2_gribend(unsigned char *cgrib) +// INPUT ARGUMENT: +// cgrib - Char array containing all the data sections added +// be previous calls to g2_create, g2_addlocal, g2_addgrid, +// and g2_addfield. +// +// OUTPUT ARGUMENTS: +// cgrib - Char array containing the finalized GRIB2 message +// +// RETURN VALUES: +// ierr - Return code. +// > 0 = Length of the final GRIB2 message in bytes. +// -1 = GRIB message was not initialized. Need to call +// routine g2_create first. +// -2 = GRIB message already complete. +// -3 = Sum of Section byte counts doesn't add to total byte count +// -4 = Previous Section was not 7. +// +// REMARKS: This routine is intended for use with routines "g2_create", +// "g2_addlocal", "g2_addgrid", and "g2_addfield" to create a complete +// GRIB2 message. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ +{ + + g2int iofst,lencurr,len,ilen,isecnum; + g2int ierr,lengrib; + static unsigned char G=0x47; // 'G' + static unsigned char R=0x52; // 'R' + static unsigned char I=0x49; // 'I' + static unsigned char B=0x42; // 'B' + static unsigned char seven=0x37; // '7' + + ierr=0; +// +// Check to see if beginning of GRIB message exists +// + if ( cgrib[0]!=G || cgrib[1]!=R || cgrib[2]!=I || cgrib[3]!=B ) { + printf("g2_gribend: GRIB not found in given message.\n"); + ierr=-1; + return (ierr); + } +// +// Get current length of GRIB message +// + gbit(cgrib,&lencurr,96,32); +// +// Loop through all current sections of the GRIB message to +// find the last section number. +// + len=16; // Length of Section 0 + for (;;) { + // Get number and length of next section + iofst=len*8; + gbit(cgrib,&ilen,iofst,32); + iofst=iofst+32; + gbit(cgrib,&isecnum,iofst,8); + len=len+ilen; + // Exit loop if last section reached + if ( len == lencurr ) break; + // If byte count for each section doesn't match current + // total length, then there is a problem. + if ( len > lencurr ) { + printf("g2_gribend: Section byte counts don''t add to total.\n"); + printf("g2_gribend: Sum of section byte counts = %d\n",(int)len); + printf("g2_gribend: Total byte count in Section 0 = %d\n",(int)lencurr); + ierr=-3; + return (ierr); + } + } +// +// Can only add End Section (Section 8) after Section 7. +// + if ( isecnum != 7 ) { + printf("g2_gribend: Section 8 can only be added after Section 7.\n"); + printf("g2_gribend: Section %ld was the last found in given GRIB message.\n",isecnum); + ierr=-4; + return (ierr); + } +// +// Add Section 8 - End Section +// + //cgrib(lencurr+1:lencurr+4)=c7777 + cgrib[lencurr]=seven; + cgrib[lencurr+1]=seven; + cgrib[lencurr+2]=seven; + cgrib[lencurr+3]=seven; + +// +// Update current byte total of message in Section 0 +// + lengrib=lencurr+4; + sbit(cgrib,&lengrib,96,32); + + return (lengrib); + +} + diff --git a/src/plugins/weatherdata/gfs/g2clib/g2_info.c b/src/plugins/weatherdata/gfs/g2clib/g2_info.c new file mode 100644 index 000000000..443a5b868 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/g2_info.c @@ -0,0 +1,190 @@ +#include +#include +#include "grib2.h" + +g2int g2_info(unsigned char *cgrib,g2int *listsec0,g2int *listsec1, + g2int *numfields,g2int *numlocal) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_info +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-28 +// +// ABSTRACT: This subroutine searches through a GRIB2 message and +// returns the number of gridded fields found in the message and +// the number (and maximum size) of Local Use Sections. +// Also various checks are performed +// to see if the message is a valid GRIB2 message. +// +// PROGRAM HISTORY LOG: +// 2002-10-28 Gilbert +// +// USAGE: int g2_info(unsigned char *cgrib,g2int *listsec0,g2int *listsec1, +// g2int *numfields,g2int *numlocal) +// INPUT ARGUMENT: +// cgrib - Character pointer to the GRIB2 message +// +// OUTPUT ARGUMENTS: +// listsec0 - pointer to an array containing information decoded from +// GRIB Indicator Section 0. +// Must be allocated with >= 3 elements. +// listsec0[0]=Discipline-GRIB Master Table Number +// (see Code Table 0.0) +// listsec0[1]=GRIB Edition Number (currently 2) +// listsec0[2]=Length of GRIB message +// listsec1 - pointer to an array containing information read from GRIB +// Identification Section 1. +// Must be allocated with >= 13 elements. +// listsec1[0]=Id of orginating centre (Common Code Table C-1) +// listsec1[1]=Id of orginating sub-centre (local table) +// listsec1[2]=GRIB Master Tables Version Number (Code Table 1.0) +// listsec1[3]=GRIB Local Tables Version Number +// listsec1[4]=Significance of Reference Time (Code Table 1.1) +// listsec1[5]=Reference Time - Year (4 digits) +// listsec1[6]=Reference Time - Month +// listsec1[7]=Reference Time - Day +// listsec1[8]=Reference Time - Hour +// listsec1[9]=Reference Time - Minute +// listsec1[10]=Reference Time - Second +// listsec1[11]=Production status of data (Code Table 1.2) +// listsec1[12]=Type of processed data (Code Table 1.3) +// numfields- The number of gridded fields found in the GRIB message. +// That is, the number of occurences of Sections 4 - 7. +// numlocal - The number of Local Use Sections ( Section 2 ) found in +// the GRIB message. +// +// RETURN VALUES: +// ierr - Error return code. +// 0 = no error +// 1 = Beginning characters "GRIB" not found. +// 2 = GRIB message is not Edition 2. +// 3 = Could not find Section 1, where expected. +// 4 = End string "7777" found, but not where expected. +// 5 = End string "7777" not found at end of message. +// 6 = Invalid section number found. +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ +{ + + g2int ierr,mapsec1len=13; + g2int mapsec1[13]={2,2,1,1,1,2,1,1,1,1,1,1,1}; + g2int i,j,istart,iofst,lengrib,lensec0,lensec1; + g2int ipos,isecnum,nbits,lensec; + + ierr=0; + *numlocal=0; + *numfields=0; +// +// Check for beginning of GRIB message in the first 100 bytes +// + istart=-1; + for (j=0;j<100;j++) { + if (cgrib[j]=='G' && cgrib[j+1]=='R' &&cgrib[j+2]=='I' && + cgrib[j+3]=='B') { + istart=j; + break; + } + } + if (istart == -1) { + printf("g2_info: Beginning characters GRIB not found."); + ierr=1; + return(ierr); + } +// +// Unpack Section 0 - Indicator Section +// + iofst=8*(istart+6); + gbit(cgrib,listsec0+0,iofst,8); // Discipline + iofst=iofst+8; + gbit(cgrib,listsec0+1,iofst,8); // GRIB edition number + iofst=iofst+8; + iofst=iofst+32; + gbit(cgrib,&lengrib,iofst,32); // Length of GRIB message + iofst=iofst+32; + listsec0[2]=lengrib; + lensec0=16; + ipos=istart+lensec0; +// +// Currently handles only GRIB Edition 2. +// + if (listsec0[1] != 2) { + printf("g2_info: can only decode GRIB edition 2."); + ierr=2; + return(ierr); + } +// +// Unpack Section 1 - Identification Section +// + gbit(cgrib,&lensec1,iofst,32); // Length of Section 1 + iofst=iofst+32; + gbit(cgrib,&isecnum,iofst,8); // Section number ( 1 ) + iofst=iofst+8; + if (isecnum != 1) { + printf("g2_info: Could not find section 1."); + ierr=3; + return(ierr); + } + // + // Unpack each input value in array listsec1 into the + // the appropriate number of octets, which are specified in + // corresponding entries in array mapsec1. + // + for (i=0;i (istart+lengrib)) { + printf("g2_info: '7777' not found at end of GRIB message.\n"); + ierr=5; + return(ierr); + } + if ( isecnum>=2 && isecnum<=7 ) { + if (isecnum == 2) // Local Section 2 + // increment counter for total number of local sections found + (*numlocal)++; + + else if (isecnum == 4) + // increment counter for total number of fields found + (*numfields)++; + } + else { + printf("g2_info: Invalid section number found in GRIB message: %ld\n" ,isecnum); + ierr=6; + return(ierr); + } + + } + + return(0); + +} diff --git a/src/plugins/weatherdata/gfs/g2clib/g2_miss.c b/src/plugins/weatherdata/gfs/g2clib/g2_miss.c new file mode 100644 index 000000000..3dab744b0 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/g2_miss.c @@ -0,0 +1,69 @@ +#include "grib2.h" + +void g2_miss( gribfield *gfld, float *rmiss, int *nmiss ) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_miss +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2004-12-16 +// +// ABSTRACT: This routine checks the Data Representation Template to see if +// missing value management is used, and returns the missing value(s) +// in the data field. +// +// PROGRAM HISTORY LOG: +// 2004-12-16 Gilbert +// +// USAGE: g2_miss( gribfield *gfld, float *rmiss, int *nmiss ) +// +// INPUT ARGUMENT LIST: +// *gfld - pointer to gribfield structure (defined in include file +// grib2.h) +// +// OUTPUT ARGUMENT LIST: +// rmiss - List of the missing values used +// nmiss - NUmber of the missing values included in the field +// +// REMARKS: rmiss must be allocated in the calling program with enough space +// hold all the missing values. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: IBM SP +// +//$$$ +{ + g2int itype; + + /* + * Missing value management currnetly only used in + * DRT's 5.2 and 5.3. + */ + if ( gfld->idrtnum != 2 && gfld->idrtnum != 3 ) { + *nmiss=0; + return; + } + + itype = gfld->idrtmpl[4]; + if ( gfld->idrtmpl[6] == 1 ) { + *nmiss=1; + if (itype == 0) + rdieee(gfld->idrtmpl+7,rmiss+0,1); + else + rmiss[0]=(float)gfld->idrtmpl[7]; + } + else if ( gfld->idrtmpl[6] == 2 ) { + *nmiss=2; + if (itype == 0) { + rdieee(gfld->idrtmpl+7,rmiss+0,1); + rdieee(gfld->idrtmpl+8,rmiss+1,1); + } + else { + rmiss[0]=(float)gfld->idrtmpl[7]; + rmiss[1]=(float)gfld->idrtmpl[8]; + } + } + else { + *nmiss=0; + } + +} diff --git a/src/plugins/weatherdata/gfs/g2clib/g2_unpack1.c b/src/plugins/weatherdata/gfs/g2clib/g2_unpack1.c new file mode 100644 index 000000000..02114e909 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/g2_unpack1.c @@ -0,0 +1,99 @@ +#include +#include +#include "grib2.h" + +g2int g2_unpack1(unsigned char *cgrib,g2int *iofst,g2int **ids,g2int *idslen) +/*//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_unpack1 +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-29 +// +// ABSTRACT: This subroutine unpacks Section 1 (Identification Section) +// as defined in GRIB Edition 2. +// +// PROGRAM HISTORY LOG: +// 2002-10-29 Gilbert +// +// USAGE: int g2_unpack1(unsigned char *cgrib,g2int *iofst,g2int **ids, +// g2int *idslen) +// INPUT ARGUMENTS: +// cgrib - char array containing Section 1 of the GRIB2 message +// iofst - Bit offset for the beginning of Section 1 in cgrib. +// +// OUTPUT ARGUMENTS: +// iofst - Bit offset at the end of Section 1, returned. +// ids - address of pointer to integer array containing information +// read from Section 1, the Identification section. +// ids[0] = Identification of originating Centre +// ( see Common Code Table C-1 ) +// ids[1] = Identification of originating Sub-centre +// ids[2] = GRIB Master Tables Version Number +// ( see Code Table 1.0 ) +// ids[3] = GRIB Local Tables Version Number +// ( see Code Table 1.1 ) +// ids[4] = Significance of Reference Time (Code Table 1.2) +// ids[5] = Year ( 4 digits ) +// ids[6] = Month +// ids[7] = Day +// ids[8] = Hour +// ids[9] = Minute +// ids[10] = Second +// ids[11] = Production status of processed data +// ( see Code Table 1.3 ) +// ids[12] = Type of processed data ( see Code Table 1.4 ) +// idslen - Number of elements in ids[]. +// +// RETURN VALUES: +// ierr - Error return code. +// 0 = no error +// 2 = Array passed is not section 1 +// 6 = memory allocation error +// +// REMARKS: +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ +*/ +{ + + g2int i,lensec,nbits,ierr,isecnum; + g2int mapid[13]={2,2,1,1,1,2,1,1,1,1,1,1,1}; + + ierr=0; + *idslen=13; + *ids=0; + + gbit(cgrib,&lensec,*iofst,32); // Get Length of Section + *iofst=*iofst+32; + gbit(cgrib,&isecnum,*iofst,8); // Get Section Number + *iofst=*iofst+8; + + if ( isecnum != 1 ) { + ierr=2; + *idslen=13; + fprintf(stderr,"g2_unpack1: Not Section 1 data.\n"); + return(ierr); + } + + // + // Unpack each value into array ids from the + // the appropriate number of octets, which are specified in + // corresponding entries in array mapid. + // + *ids=(g2int *)calloc(*idslen,sizeof(g2int)); + if (*ids == 0) { + ierr=6; + return(ierr); + } + + for (i=0;i<*idslen;i++) { + nbits=mapid[i]*8; + gbit(cgrib,*ids+i,*iofst,nbits); + *iofst=*iofst+nbits; + } + + return(ierr); // End of Section 1 processing +} diff --git a/src/plugins/weatherdata/gfs/g2clib/g2_unpack2.c b/src/plugins/weatherdata/gfs/g2clib/g2_unpack2.c new file mode 100644 index 000000000..08d9ef592 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/g2_unpack2.c @@ -0,0 +1,86 @@ +#include +#include +#include "grib2.h" + +g2int g2_unpack2(unsigned char *cgrib,g2int *iofst,g2int *lencsec2,unsigned char **csec2) +////$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_unpack2 +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 +// +// ABSTRACT: This subroutine unpacks Section 2 (Local Use Section) +// as defined in GRIB Edition 2. +// +// PROGRAM HISTORY LOG: +// 2002-10-31 Gilbert +// 2008-12-23 Wesley - Initialize lencsec2 Length of Local Use data +// 2010-08-05 Vuong - If section 2 has zero length, ierr=0 +// +// USAGE: int g2_unpack2(unsigned char *cgrib,g2int *iofst,g2int *lencsec2, +// unsigned char **csec2) +// INPUT ARGUMENT LIST: +// cgrib - char array containing Section 2 of the GRIB2 message +// iofst - Bit offset for the beginning of Section 2 in cgrib. +// +// OUTPUT ARGUMENT LIST: +// iofst - Bit offset at the end of Section 2, returned. +// lencsec2 - Length (in octets) of Local Use data +// csec2 - Pointer to a char array containing local use data +// +// RETURN VALUES: +// ierr - Error return code. +// 0 = no error +// 2 = Array passed is not section 2 +// 6 = memory allocation error +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$// +{ + + g2int ierr,isecnum; + g2int lensec,ipos,j; + + ierr=0; + *lencsec2=0; + *csec2=0; // NULL + + gbit(cgrib,&lensec,*iofst,32); // Get Length of Section + *iofst=*iofst+32; + *lencsec2=lensec-5; + gbit(cgrib,&isecnum,*iofst,8); // Get Section Number + *iofst=*iofst+8; + ipos=(*iofst/8); + + if ( isecnum != 2 ) { + ierr=2; + *lencsec2=0; + fprintf(stderr,"g2_unpack2: Not Section 2 data.\n"); + return(ierr); + } + + if (*lencsec2 == 0) { + ierr = 0; + return(ierr); + } + + *csec2=(unsigned char *)malloc(*lencsec2+1); + if (*csec2 == 0) { + ierr=6; + *lencsec2=0; + return(ierr); + } + + //printf(" SAGIPO %d \n",(int)ipos); + for (j=0;j<*lencsec2;j++) { + *(*csec2+j)=cgrib[ipos+j]; + } + *iofst=*iofst+(*lencsec2*8); + + return(ierr); // End of Section 2 processing + +} diff --git a/src/plugins/weatherdata/gfs/g2clib/g2_unpack3.c b/src/plugins/weatherdata/gfs/g2clib/g2_unpack3.c new file mode 100644 index 000000000..0b691127f --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/g2_unpack3.c @@ -0,0 +1,214 @@ +#include +#include +#include "grib2.h" + + +g2int g2_unpack3(unsigned char *cgrib,g2int *iofst,g2int **igds,g2int **igdstmpl, + g2int *mapgridlen,g2int **ideflist,g2int *idefnum) +////$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_unpack3 +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 +// +// ABSTRACT: This routine unpacks Section 3 (Grid Definition Section) +// as defined in GRIB Edition 2. +// +// PROGRAM HISTORY LOG: +// 2002-10-31 Gilbert +// 2009-01-14 Vuong Changed structure name template to gtemplate +// +// USAGE: int g2_unpack3(unsigned char *cgrib,g2int *iofst,g2int **igds, +// g2int **igdstmpl,g2int *mapgridlen, +// g2int **ideflist,g2int *idefnum) +// INPUT ARGUMENTS: +// cgrib - Char array ontaining Section 3 of the GRIB2 message +// iofst - Bit offset for the beginning of Section 3 in cgrib. +// +// OUTPUT ARGUMENTS: +// iofst - Bit offset at the end of Section 3, returned. +// igds - Contains information read from the appropriate GRIB Grid +// Definition Section 3 for the field being returned. +// igds[0]=Source of grid definition (see Code Table 3.0) +// igds[1]=Number of grid points in the defined grid. +// igds[2]=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[3]=Interpretation of list for optional points +// definition. (Code Table 3.11) +// igds[4]=Grid Definition Template Number (Code Table 3.1) +// igdstmpl - Pointer to integer array containing the data values for +// the specified Grid Definition +// Template ( NN=igds[4] ). Each element of this integer +// array contains an entry (in the order specified) of Grid +// Defintion Template 3.NN +// mapgridlen- Number of elements in igdstmpl[]. i.e. number of entries +// in Grid Defintion Template 3.NN ( NN=igds[4] ). +// ideflist - (Used if igds[2] .ne. 0) Pointer to integer array containing +// the number of grid points contained in each row ( or column ). +// (part of Section 3) +// idefnum - (Used if igds[2] .ne. 0) The number of entries +// in array ideflist. i.e. number of rows ( or columns ) +// for which optional grid points are defined. +// ierr - Error return code. +// 0 = no error +// 2 = Not Section 3 +// 5 = "GRIB" message contains an undefined Grid Definition +// Template. +// 6 = memory allocation error +// +// REMARKS: +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ + +{ + g2int ierr,i,j,nbits,isecnum; + g2int lensec,ibyttem=0,isign,newlen; + g2int *ligds,*ligdstmpl=0,*lideflist=0; + gtemplate *mapgrid; + + ierr=0; + *igds=0; // NULL + *igdstmpl=0; // NULL + *ideflist=0; // NULL + + gbit(cgrib,&lensec,*iofst,32); // Get Length of Section + *iofst=*iofst+32; + gbit(cgrib,&isecnum,*iofst,8); // Get Section Number + *iofst=*iofst+8; + + if ( isecnum != 3 ) { + ierr=2; + *idefnum=0; + *mapgridlen=0; + // fprintf(stderr,"g2_unpack3: Not Section 3 data.\n"); + return(ierr); + } + + ligds=(g2int *)calloc(5,sizeof(g2int)); + *igds=ligds; + + gbit(cgrib,ligds+0,*iofst,8); // Get source of Grid def. + *iofst=*iofst+8; + gbit(cgrib,ligds+1,*iofst,32); // Get number of grid pts. + *iofst=*iofst+32; + gbit(cgrib,ligds+2,*iofst,8); // Get num octets for opt. list + *iofst=*iofst+8; + gbit(cgrib,ligds+3,*iofst,8); // Get interpret. for opt. list + *iofst=*iofst+8; + gbit(cgrib,ligds+4,*iofst,16); // Get Grid Def Template num. + *iofst=*iofst+16; + + if (ligds[4] != 65535) { + // Get Grid Definition Template + mapgrid=getgridtemplate(ligds[4]); + if (mapgrid == 0) { // undefined template + ierr=5; + return(ierr); + } + *mapgridlen=mapgrid->maplen; + // + // Unpack each value into array igdstmpl from the + // the appropriate number of octets, which are specified in + // corresponding entries in array mapgrid. + // + if (*mapgridlen > 0) { + ligdstmpl=0; + ligdstmpl=(g2int *)calloc(*mapgridlen,sizeof(g2int)); + if (ligdstmpl == 0) { + ierr=6; + *mapgridlen=0; + *igdstmpl=0; //NULL + if( mapgrid != 0 ) free(mapgrid); + return(ierr); + } + else { + *igdstmpl=ligdstmpl; + } + } + ibyttem=0; + for (i=0;i<*mapgridlen;i++) { + nbits=abs(mapgrid->map[i])*8; + if ( mapgrid->map[i] >= 0 ) { + gbit(cgrib,ligdstmpl+i,*iofst,nbits); + } + else { + gbit(cgrib,&isign,*iofst,1); + gbit(cgrib,ligdstmpl+i,*iofst+1,nbits-1); + if (isign == 1) ligdstmpl[i]=-1*ligdstmpl[i]; + } + *iofst=*iofst+nbits; + ibyttem=ibyttem+abs(mapgrid->map[i]); + } + // + // Check to see if the Grid Definition Template needs to be + // extended. + // The number of values in a specific template may vary + // depending on data specified in the "static" part of the + // gtemplate. + // + if ( mapgrid->needext == 1 ) { + free(mapgrid); + mapgrid=extgridtemplate(ligds[4],ligdstmpl); + // Unpack the rest of the Grid Definition Template + newlen=mapgrid->maplen+mapgrid->extlen; + ligdstmpl=(g2int *)realloc(ligdstmpl,newlen*sizeof(g2int)); + *igdstmpl=ligdstmpl; + j=0; + for (i=*mapgridlen;iext[j])*8; + if ( mapgrid->ext[j] >= 0 ) { + gbit(cgrib,ligdstmpl+i,*iofst,nbits); + } + else { + gbit(cgrib,&isign,*iofst,1); + gbit(cgrib,ligdstmpl+i,*iofst+1,nbits-1); + if (isign == 1) ligdstmpl[i]=-1*ligdstmpl[i]; + } + *iofst=*iofst+nbits; + ibyttem=ibyttem+abs(mapgrid->ext[j]); + j++; + } + *mapgridlen=newlen; + } + if( mapgrid->ext != 0 ) free(mapgrid->ext); + if( mapgrid != 0 ) free(mapgrid); + } + else { // No Grid Definition Template + *mapgridlen=0; + *igdstmpl=0; + } + // + // Unpack optional list of numbers defining number of points + // in each row or column, if included. This is used for non regular + // grids. + // + if ( ligds[2] != 0 ) { + nbits=ligds[2]*8; + *idefnum=(lensec-14-ibyttem)/ligds[2]; + if (*idefnum > 0) lideflist=(g2int *)calloc(*idefnum,sizeof(g2int)); + if (lideflist == 0) { + ierr=6; + *idefnum=0; + *ideflist=0; //NULL + return(ierr); + } + else { + *ideflist=lideflist; + } + gbits(cgrib,lideflist,*iofst,nbits,0,*idefnum); + *iofst=*iofst+(nbits*(*idefnum)); + } + else { + *idefnum=0; + *ideflist=0; // NULL + } + + return(ierr); // End of Section 3 processing +} diff --git a/src/plugins/weatherdata/gfs/g2clib/g2_unpack4.c b/src/plugins/weatherdata/gfs/g2clib/g2_unpack4.c new file mode 100644 index 000000000..524549d0b --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/g2_unpack4.c @@ -0,0 +1,185 @@ +#include +#include +#include "grib2.h" + + +g2int g2_unpack4(unsigned char *cgrib,g2int *iofst,g2int *ipdsnum,g2int **ipdstmpl, + g2int *mappdslen,g2float **coordlist,g2int *numcoord) +////$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_unpack4 +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 +// +// ABSTRACT: This subroutine unpacks Section 4 (Product Definition Section) +// as defined in GRIB Edition 2. +// +// PROGRAM HISTORY LOG: +// 2002-10-31 Gilbert +// 2009-01-14 Vuong Changed structure name template to gtemplate +// +// USAGE: int g2_unpack4(unsigned char *cgrib,g2int *iofst,g2int *ipdsnum, +// g2int **ipdstmpl,g2int *mappdslen, +// g2float **coordlist,g2int *numcoord) +// INPUT ARGUMENTS: +// cgrib - Char array containing Section 4 of the GRIB2 message +// iofst - Bit offset of the beginning of Section 4 in cgrib. +// +// OUTPUT ARGUMENTS: +// iofst - Bit offset of the end of Section 4, returned. +// ipdsnum - Product Definition Template Number ( see Code Table 4.0) +// ipdstmpl - Pointer to integer array containing the data values for +// the specified Product Definition +// Template ( N=ipdsnum ). Each element of this integer +// array contains an entry (in the order specified) of Product +// Defintion Template 4.N +// mappdslen- Number of elements in ipdstmpl[]. i.e. number of entries +// in Product Defintion Template 4.N ( N=ipdsnum ). +// coordlist- Pointer to real array containing floating point values +// intended to document +// the vertical discretisation associated to model data +// on hybrid coordinate vertical levels. (part of Section 4) +// numcoord - number of values in array coordlist. +// +// RETURN VALUES: +// ierr - Error return code. +// 0 = no error +// 2 = Not section 4 +// 5 = "GRIB" message contains an undefined Product Definition +// Template. +// 6 = memory allocation error +// +// REMARKS: +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$// +{ + + g2int ierr,needext,i,j,nbits,isecnum; + g2int lensec,isign,newlen; + g2int *coordieee; + g2int *lipdstmpl=0; + g2float *lcoordlist; + gtemplate *mappds; + + ierr=0; + *ipdstmpl=0; // NULL + *coordlist=0; // NULL + + gbit(cgrib,&lensec,*iofst,32); // Get Length of Section + *iofst=*iofst+32; + gbit(cgrib,&isecnum,*iofst,8); // Get Section Number + *iofst=*iofst+8; + + if ( isecnum != 4 ) { + ierr=2; + *numcoord=0; + *mappdslen=0; + // fprintf(stderr,"g2_unpack4: Not Section 4 data.\n"); + return(ierr); + } + + gbit(cgrib,numcoord,*iofst,16); // Get num of coordinate values + *iofst=*iofst+16; + gbit(cgrib,ipdsnum,*iofst,16); // Get Prod. Def Template num. + *iofst=*iofst+16; + + // Get Product Definition Template + mappds=getpdstemplate(*ipdsnum); + if (mappds == 0) { // undefine template + ierr=5; + *mappdslen=0; + return(ierr); + } + *mappdslen=mappds->maplen; + needext=mappds->needext; + // + // Unpack each value into array ipdstmpl from the + // the appropriate number of octets, which are specified in + // corresponding entries in array mappds. + // + if (*mappdslen > 0) lipdstmpl=(g2int *)calloc(*mappdslen,sizeof(g2int)); + if (lipdstmpl == 0) { + ierr=6; + *mappdslen=0; + *ipdstmpl=0; //NULL + if ( mappds != 0 ) free(mappds); + return(ierr); + } + else { + *ipdstmpl=lipdstmpl; + } + for (i=0;imaplen;i++) { + nbits=abs(mappds->map[i])*8; + if ( mappds->map[i] >= 0 ) { + gbit(cgrib,lipdstmpl+i,*iofst,nbits); + } + else { + gbit(cgrib,&isign,*iofst,1); + gbit(cgrib,lipdstmpl+i,*iofst+1,nbits-1); + if (isign == 1) lipdstmpl[i]=-1*lipdstmpl[i]; + } + *iofst=*iofst+nbits; + } + // + // Check to see if the Product Definition Template needs to be + // extended. + // The number of values in a specific template may vary + // depending on data specified in the "static" part of the + // gtemplate. + // + if ( needext ==1 ) { + free(mappds); + mappds=extpdstemplate(*ipdsnum,lipdstmpl); + newlen=mappds->maplen+mappds->extlen; + lipdstmpl=(g2int *)realloc(lipdstmpl,newlen*sizeof(g2int)); + *ipdstmpl=lipdstmpl; + // Unpack the rest of the Product Definition Template + j=0; + for (i=*mappdslen;iext[j])*8; + if ( mappds->ext[j] >= 0 ) { + gbit(cgrib,lipdstmpl+i,*iofst,nbits); + } + else { + gbit(cgrib,&isign,*iofst,1); + gbit(cgrib,lipdstmpl+i,*iofst+1,nbits-1); + if (isign == 1) lipdstmpl[i]=-1*lipdstmpl[i]; + } + *iofst=*iofst+nbits; + j++; + } + *mappdslen=newlen; + } + if( mappds->ext != 0 ) free(mappds->ext); + if( mappds != 0 ) free(mappds); + // + // Get Optional list of vertical coordinate values + // after the Product Definition Template, if necessary. + // + *coordlist=0; // NULL + if ( *numcoord != 0 ) { + coordieee=(g2int *)calloc(*numcoord,sizeof(g2int)); + lcoordlist=(g2float *)calloc(*numcoord,sizeof(g2float)); + if (coordieee == 0 || lcoordlist == 0) { + ierr=6; + *numcoord=0; + *coordlist=0; // NULL + if( coordieee != 0 ) free(coordieee); + if( lcoordlist != 0 ) free(lcoordlist); + return(ierr); + } + else { + *coordlist=lcoordlist; + } + gbits(cgrib,coordieee,*iofst,32,0,*numcoord); + rdieee(coordieee,*coordlist,*numcoord); + free(coordieee); + *iofst=*iofst+(32*(*numcoord)); + } + + return(ierr); // End of Section 4 processing + +} diff --git a/src/plugins/weatherdata/gfs/g2clib/g2_unpack5.c b/src/plugins/weatherdata/gfs/g2clib/g2_unpack5.c new file mode 100644 index 000000000..978c12829 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/g2_unpack5.c @@ -0,0 +1,152 @@ +#include +#include +#include "grib2.h" + + +g2int g2_unpack5(unsigned char *cgrib,g2int *iofst,g2int *ndpts,g2int *idrsnum, + g2int **idrstmpl,g2int *mapdrslen) +////$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_unpack5 +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 +// +// ABSTRACT: This subroutine unpacks Section 5 (Data Representation Section) +// as defined in GRIB Edition 2. +// +// PROGRAM HISTORY LOG: +// 2002-10-31 Gilbert +// 2009-01-14 Vuong Changed structure name template to gtemplate +// +// USAGE: int g2_unpack5(unsigned char *cgrib,g2int *iofst,g2int *ndpts, +// g2int *idrsnum,g2int **idrstmpl,g2int *mapdrslen) +// INPUT ARGUMENTS: +// cgrib - char array containing Section 5 of the GRIB2 message +// iofst - Bit offset for the beginning of Section 5 in cgrib. +// +// OUTPUT ARGUMENTS: +// iofst - Bit offset at the end of Section 5, returned. +// ndpts - Number of data points unpacked and returned. +// idrsnum - Data Representation Template Number ( see Code Table 5.0) +// idrstmpl - Pointer to an integer array containing the data values for +// the specified Data Representation +// Template ( N=idrsnum ). Each element of this integer +// array contains an entry (in the order specified) of Data +// Representation Template 5.N +// mapdrslen- Number of elements in idrstmpl[]. i.e. number of entries +// in Data Representation Template 5.N ( N=idrsnum ). +// +// RETURN VALUES: +// ierr - Error return code. +// 0 = no error +// 2 = Not Section 5 +// 6 = memory allocation error +// 7 = "GRIB" message contains an undefined Data +// Representation Template. +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$// +{ + g2int ierr,needext,i,j,nbits,isecnum; + g2int lensec,isign,newlen; + g2int *lidrstmpl=0; + gtemplate *mapdrs; + + ierr=0; + *idrstmpl=0; //NULL + + gbit(cgrib,&lensec,*iofst,32); // Get Length of Section + *iofst=*iofst+32; + gbit(cgrib,&isecnum,*iofst,8); // Get Section Number + *iofst=*iofst+8; + + if ( isecnum != 5 ) { + ierr=2; + *ndpts=0; + *mapdrslen=0; + // fprintf(stderr,"g2_unpack5: Not Section 5 data.\n"); + return(ierr); + } + + gbit(cgrib,ndpts,*iofst,32); // Get num of data points + *iofst=*iofst+32; + gbit(cgrib,idrsnum,*iofst,16); // Get Data Rep Template Num. + *iofst=*iofst+16; + + // Gen Data Representation Template + mapdrs=getdrstemplate(*idrsnum); + if (mapdrs == 0) { + ierr=7; + *mapdrslen=0; + return(ierr); + } + *mapdrslen=mapdrs->maplen; + needext=mapdrs->needext; + // + // Unpack each value into array ipdstmpl from the + // the appropriate number of octets, which are specified in + // corresponding entries in array mapdrs. + // + if (*mapdrslen > 0) lidrstmpl=(g2int *)calloc(*mapdrslen,sizeof(g2int)); + if (lidrstmpl == 0) { + ierr=6; + *mapdrslen=0; + *idrstmpl=0; //NULL + if ( mapdrs != 0 ) free(mapdrs); + return(ierr); + } + else { + *idrstmpl=lidrstmpl; + } + for (i=0;imaplen;i++) { + nbits=abs(mapdrs->map[i])*8; + if ( mapdrs->map[i] >= 0 ) { + gbit(cgrib,lidrstmpl+i,*iofst,nbits); + } + else { + gbit(cgrib,&isign,*iofst,1); + gbit(cgrib,lidrstmpl+i,*iofst+1,nbits-1); + if (isign == 1) lidrstmpl[i]=-1*lidrstmpl[i]; + } + *iofst=*iofst+nbits; + } + // + // Check to see if the Data Representation Template needs to be + // extended. + // The number of values in a specific gtemplate may vary + // depending on data specified in the "static" part of the + // gtemplate. + // + if ( needext == 1 ) { + free(mapdrs); + mapdrs=extdrstemplate(*idrsnum,lidrstmpl); + newlen=mapdrs->maplen+mapdrs->extlen; + lidrstmpl=(g2int *)realloc(lidrstmpl,newlen*sizeof(g2int)); + *idrstmpl=lidrstmpl; + // Unpack the rest of the Data Representation Template + j=0; + for (i=*mapdrslen;iext[j])*8; + if ( mapdrs->ext[j] >= 0 ) { + gbit(cgrib,lidrstmpl+i,*iofst,nbits); + } + else { + gbit(cgrib,&isign,*iofst,1); + gbit(cgrib,lidrstmpl+i,*iofst+1,nbits-1); + if (isign == 1) lidrstmpl[i]=-1*lidrstmpl[i]; + } + *iofst=*iofst+nbits; + j++; + } + *mapdrslen=newlen; + } + if( mapdrs->ext != 0 ) free(mapdrs->ext); + if( mapdrs != 0 ) free(mapdrs); + + return(ierr); // End of Section 5 processing + +} diff --git a/src/plugins/weatherdata/gfs/g2clib/g2_unpack6.c b/src/plugins/weatherdata/gfs/g2clib/g2_unpack6.c new file mode 100644 index 000000000..9f6da7ee5 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/g2_unpack6.c @@ -0,0 +1,97 @@ +#include +#include +#include "grib2.h" + +g2int g2_unpack6(unsigned char *cgrib,g2int *iofst,g2int ngpts,g2int *ibmap, + g2int **bmap) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_unpack6 +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 +// +// ABSTRACT: This subroutine unpacks Section 6 (Bit-Map Section) +// as defined in GRIB Edition 2. +// +// PROGRAM HISTORY LOG: +// 2002-10-31 Gilbert +// +// USAGE: int g2_unpack6(unsigned char *cgrib,g2int *iofst,g2int ngpts, +// g2int *ibmap,g2int **bmap) +// INPUT ARGUMENTS: +// cgrib - char array containing Section 6 of the GRIB2 message +// iofst - Bit offset of the beginning of Section 6 in cgrib. +// ngpts - Number of grid points specified in the bit-map +// +// OUTPUT ARGUMENTS: +// iofst - Bit offset at the end of Section 6, returned. +// ibmap - Bitmap indicator ( see Code Table 6.0 ) +// 0 = bitmap applies and is included in Section 6. +// 1-253 = Predefined bitmap applies +// 254 = Previously defined bitmap applies to this field +// 255 = Bit map does not apply to this product. +// bmap - Pointer to an integer array containing decoded bitmap. +// ( if ibmap=0 ) +// +// RETURN VALUES: +// ierr - Error return code. +// 0 = no error +// 2 = Not Section 6 +// 4 = Unrecognized pre-defined bit-map. +// 6 = memory allocation error +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$// +{ + g2int j,ierr,isecnum; + g2int *lbmap=0; + g2int *intbmap; + + ierr=0; + *bmap=0; //NULL + + *iofst=*iofst+32; // skip Length of Section + gbit(cgrib,&isecnum,*iofst,8); // Get Section Number + *iofst=*iofst+8; + + if ( isecnum != 6 ) { + ierr=2; + fprintf(stderr,"g2_unpack6: Not Section 6 data.\n"); + return(ierr); + } + + gbit(cgrib,ibmap,*iofst,8); // Get bit-map indicator + *iofst=*iofst+8; + + if (*ibmap == 0) { // Unpack bitmap + if (ngpts > 0) lbmap=(g2int *)calloc(ngpts,sizeof(g2int)); + if (lbmap == 0) { + ierr=6; + return(ierr); + } + else { + *bmap=lbmap; + } + intbmap=(g2int *)calloc(ngpts,sizeof(g2int)); + gbits(cgrib,intbmap,*iofst,1,0,ngpts); + *iofst=*iofst+ngpts; + for (j=0;j +#include +#include +#include +#include "grib2.h" + +g2int simunpack(unsigned char *,g2int *, g2int,g2float *); +int comunpack(unsigned char *,g2int,g2int,g2int *,g2int,g2float *); +g2int specunpack(unsigned char *,g2int *,g2int,g2int,g2int, g2int, g2float *); +#ifdef USE_PNG + g2int pngunpack(unsigned char *,g2int,g2int *,g2int, g2float *); +#endif /* USE_PNG */ +#ifdef USE_JPEG2000 + g2int jpcunpack(unsigned char *,g2int,g2int *,g2int, g2float *); +#endif /* USE_JPEG2000 */ + +g2int g2_unpack7(unsigned char *cgrib,g2int *iofst,g2int igdsnum,g2int *igdstmpl, + g2int idrsnum,g2int *idrstmpl,g2int ndpts,g2float **fld) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_unpack7 +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 +// +// ABSTRACT: This subroutine unpacks Section 7 (Data Section) +// as defined in GRIB Edition 2. +// +// PROGRAM HISTORY LOG: +// 2002-10-31 Gilbert +// 2002-12-20 Gilbert - Added GDT info to arguments +// and added 5.51 processing. +// 2003-08-29 Gilbert - Added support for new templates using +// PNG and JPEG2000 algorithms/templates. +// 2004-11-29 Gilbert - JPEG2000 now allowed to use WMO Template no. 5.40 +// PNG now allowed to use WMO Template no. 5.41 +// 2004-12-16 Taylor - Added check on comunpack return code. +// 2008-12-23 Wesley - Initialize Number of data points unpacked +// +// USAGE: int g2_unpack7(unsigned char *cgrib,g2int *iofst,g2int igdsnum, +// g2int *igdstmpl, g2int idrsnum, +// g2int *idrstmpl, g2int ndpts,g2float **fld) +// INPUT ARGUMENTS: +// cgrib - char array containing Section 7 of the GRIB2 message +// iofst - Bit offset of the beginning of Section 7 in cgrib. +// igdsnum - Grid Definition Template Number ( see Code Table 3.0) +// ( Only used for DRS Template 5.51 ) +// igdstmpl - Pointer to an integer array containing the data values for +// the specified Grid Definition +// Template ( N=igdsnum ). Each element of this integer +// array contains an entry (in the order specified) of Grid +// Definition Template 3.N +// ( Only used for DRS Template 5.51 ) +// idrsnum - Data Representation Template Number ( see Code Table 5.0) +// idrstmpl - Pointer to an integer array containing the data values for +// the specified Data Representation +// Template ( N=idrsnum ). Each element of this integer +// array contains an entry (in the order specified) of Data +// Representation Template 5.N +// ndpts - Number of data points unpacked and returned. +// +// OUTPUT ARGUMENTS: +// iofst - Bit offset at the end of Section 7, returned. +// fld - Pointer to a float array containing the unpacked data field. +// +// RETURN VALUES: +// ierr - Error return code. +// 0 = no error +// 2 = Not section 7 +// 4 = Unrecognized Data Representation Template +// 5 = need one of GDT 3.50 through 3.53 to decode DRT 5.51 +// 6 = memory allocation error +// 7 = corrupt section 7. +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$// +{ + g2int ierr,isecnum; + g2int ipos,lensec; + g2float *lfld; + + ierr=0; + *fld=0; //NULL + + gbit(cgrib,&lensec,*iofst,32); // Get Length of Section + *iofst=*iofst+32; + gbit(cgrib,&isecnum,*iofst,8); // Get Section Number + *iofst=*iofst+8; + + if ( isecnum != 7 ) { + ierr=2; + //fprintf(stderr,"g2_unpack7: Not Section 7 data.\n"); + return(ierr); + } + + ipos=(*iofst/8); + lfld=(g2float *)calloc(ndpts ? ndpts : 1,sizeof(g2float)); + if (lfld == 0) { + ierr=6; + return(ierr); + } + else { + *fld=lfld; + } + + if (idrsnum == 0) + simunpack(cgrib+ipos,idrstmpl,ndpts,lfld); + else if (idrsnum == 2 || idrsnum == 3) { + if (comunpack(cgrib+ipos,lensec,idrsnum,idrstmpl,ndpts,lfld) != 0) { + return 7; + } + } + else if (idrsnum == 50) { // Spectral Simple + simunpack(cgrib+ipos,idrstmpl,ndpts-1,lfld+1); + rdieee(idrstmpl+4,lfld+0,1); + } + else if (idrsnum == 51) // Spectral complex + if ( igdsnum>=50 && igdsnum <=53 ) + specunpack(cgrib+ipos,idrstmpl,ndpts,igdstmpl[0],igdstmpl[2],igdstmpl[2],lfld); + else { + fprintf(stderr,"g2_unpack7: Cannot use GDT 3.%d to unpack Data Section 5.51.\n",(int)igdsnum); + ierr=5; + if ( lfld != 0 ) free(lfld); + *fld=0; //NULL + return(ierr); + } +#ifdef USE_JPEG2000 + else if (idrsnum == 40 || idrsnum == 40000) { + jpcunpack(cgrib+ipos,lensec-5,idrstmpl,ndpts,lfld); + } +#endif /* USE_JPEG2000 */ +#ifdef USE_PNG + else if (idrsnum == 41 || idrsnum == 40010) { + pngunpack(cgrib+ipos,lensec-5,idrstmpl,ndpts,lfld); + } +#endif /* USE_PNG */ + else { + fprintf(stderr,"g2_unpack7: Data Representation Template 5.%d not yet implemented.\n",(int)idrsnum); + ierr=4; + if ( lfld != 0 ) free(lfld); + *fld=0; //NULL + return(ierr); + } + + *iofst=*iofst+(8*lensec); + + return(ierr); // End of Section 7 processing + +} diff --git a/src/plugins/weatherdata/gfs/g2clib/g2clib.pri b/src/plugins/weatherdata/gfs/g2clib/g2clib.pri new file mode 100644 index 000000000..e9f6e69a9 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/g2clib.pri @@ -0,0 +1,46 @@ +# g2clib module + +HEADERS += \ + g2clib/drstemplates.h \ + g2clib/grib2.h \ + g2clib/gridtemplates.h \ + g2clib/pdstemplates.h \ + + +SOURCES += \ + g2clib/cmplxpack.c \ + g2clib/compack.c \ + g2clib/comunpack.c \ + g2clib/drstemplates.c \ + g2clib/g2_addfield.c \ + g2clib/g2_addgrid.c \ + g2clib/g2_addlocal.c \ + g2clib/g2_create.c \ + g2clib/g2_free.c \ + g2clib/g2_getfld.c \ + g2clib/g2_gribend.c \ + g2clib/g2_info.c \ + g2clib/g2_miss.c \ + g2clib/g2_unpack1.c \ + g2clib/g2_unpack2.c \ + g2clib/g2_unpack3.c \ + g2clib/g2_unpack4.c \ + g2clib/g2_unpack5.c \ + g2clib/g2_unpack6.c \ + g2clib/g2_unpack7.c \ + g2clib/gbits.c \ + g2clib/getdim.c \ + g2clib/getpoly.c \ + g2clib/gridtemplates.c \ + g2clib/int_power.c \ + g2clib/misspack.c \ + g2clib/mkieee.c \ + g2clib/pack_gp.c \ + g2clib/pdstemplates.c \ + g2clib/rdieee.c \ + g2clib/reduce.c \ + g2clib/seekgb.c \ + g2clib/simpack.c \ + g2clib/simunpack.c \ + g2clib/specpack.c \ + g2clib/specunpack.c \ diff --git a/src/plugins/weatherdata/gfs/g2clib/gbits.c b/src/plugins/weatherdata/gfs/g2clib/gbits.c new file mode 100644 index 000000000..34709dab3 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/gbits.c @@ -0,0 +1,124 @@ +#include "grib2.h" + +void gbit(unsigned char *in,g2int *iout,g2int iskip,g2int nbyte) +{ + gbits(in,iout,iskip,nbyte,(g2int)0,(g2int)1); +} + +void sbit(unsigned char *out,g2int *in,g2int iskip,g2int nbyte) +{ + sbits(out,in,iskip,nbyte,(g2int)0,(g2int)1); +} + + +void gbits(unsigned char *in,g2int *iout,g2int iskip,g2int nbyte,g2int nskip, + g2int n) +/* Get bits - unpack bits: Extract arbitrary size values from a +/ packed bit string, right justifying each value in the unpacked +/ iout array. +/ *in = pointer to character array input +/ *iout = pointer to unpacked array output +/ iskip = initial number of bits to skip +/ nbyte = number of bits to take +/ nskip = additional number of bits to skip on each iteration +/ n = number of iterations +/ v1.1 +*/ +{ + g2int i,tbit,bitcnt,ibit,itmp; + g2int nbit,index; + static g2int ones[]={1,3,7,15,31,63,127,255}; + +// nbit is the start position of the field in bits + nbit = iskip; + for (i=0;i>= (8-ibit-tbit); + index++; + bitcnt = bitcnt - tbit; + +// now transfer whole bytes + while (bitcnt >= 8) { + itmp = itmp<<8 | (int)*(in+index); + bitcnt = bitcnt - 8; + index++; + } + +// get data from last byte + if (bitcnt > 0) { + itmp = ( itmp << bitcnt ) | ( ((int)*(in+index) >> (8-bitcnt)) & ones[bitcnt-1] ); + } + + *(iout+i) = itmp; + } +} + + +void sbits(unsigned char *out,g2int *in,g2int iskip,g2int nbyte,g2int nskip, + g2int n) +/*C Store bits - pack bits: Put arbitrary size values into a +/ packed bit string, taking the low order bits from each value +/ in the unpacked array. +/ *iout = pointer to packed array output +/ *in = pointer to unpacked array input +/ iskip = initial number of bits to skip +/ nbyte = number of bits to pack +/ nskip = additional number of bits to skip on each iteration +/ n = number of iterations +/ v1.1 +*/ +{ + g2int i,bitcnt,tbit,ibit,itmp,imask,itmp2,itmp3; + g2int nbit,index; + static g2int ones[]={1,3,7,15,31,63,127,255}; + +// number bits from zero to ... +// nbit is the last bit of the field to be filled + + nbit = iskip + nbyte - 1; + for (i=0;i> tbit; + index--; + } + +// now byte aligned + +// do by bytes + while (bitcnt >= 8) { + out[index] = (unsigned char)(itmp & 255); + itmp = itmp >> 8; + bitcnt = bitcnt - 8; + index--; + } + +// do last byte + + if (bitcnt > 0) { + itmp2 = itmp & ones[bitcnt-1]; + itmp3 = (int)*(out+index) & (255-ones[bitcnt-1]); + out[index] = (unsigned char)(itmp2 | itmp3); + } + } + +} diff --git a/src/plugins/weatherdata/gfs/g2clib/getdim.c b/src/plugins/weatherdata/gfs/g2clib/getdim.c new file mode 100644 index 000000000..c86228fc9 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/getdim.c @@ -0,0 +1,127 @@ +#include +#include +#include "grib2.h" + +g2int g2_unpack3(unsigned char *,g2int *,g2int **,g2int **, + g2int *,g2int **,g2int *); + +g2int getdim(unsigned char *csec3,g2int *width,g2int *height,g2int *iscan) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: getdim +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-12-11 +// +// ABSTRACT: This subroutine returns the dimensions and scanning mode of +// a grid definition packed in GRIB2 Grid Definition Section 3 format. +// +// PROGRAM HISTORY LOG: +// 2002-12-11 Gilbert +// +// USAGE: int getdim(unsigned char *csec3,g2int *width, +// g2int *height, g2int *iscan) +// INPUT ARGUMENT LIST: +// csec3 - Character array that contains the packed GRIB2 GDS +// +// OUTPUT ARGUMENT LIST: +// width - x (or i) dimension of the grid. +// height - y (or j) dimension of the grid. +// iscan - Scanning mode ( see Code Table 3.4 ) +// +// REMARKS: Returns width and height set to zero, if grid template +// not recognized. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: IBM SP +// +//$$$ +{ + + g2int *igdstmpl,*list_opt; + g2int *igds; + g2int iofst,igdtlen,num_opt,jerr; + + igdstmpl=0; + list_opt=0; + igds=0; + iofst=0; // set offset to beginning of section + jerr= g2_unpack3(csec3,&iofst,&igds,&igdstmpl, + &igdtlen,&list_opt,&num_opt); + if (jerr == 0) { + switch ( igds[4] ) // Template number + { + case 0: // Lat/Lon + case 1: + case 2: + case 3: + { + *width=igdstmpl[7]; + *height=igdstmpl[8]; + *iscan=igdstmpl[18]; + break; + } + case 10: // Mercator + { + *width=igdstmpl[7]; + *height=igdstmpl[8]; + *iscan=igdstmpl[15]; + break; + } + case 20: // Polar Stereographic + { + *width=igdstmpl[7]; + *height=igdstmpl[8]; + *iscan=igdstmpl[17]; + break; + } + case 30: // Lambert Conformal + { + *width=igdstmpl[7]; + *height=igdstmpl[8]; + *iscan=igdstmpl[17]; + break; + } + case 40: // Gaussian + case 41: + case 42: + case 43: + { + *width=igdstmpl[7]; + *height=igdstmpl[8]; + *iscan=igdstmpl[18]; + break; + } + case 90: // Space View/Orthographic + { + *width=igdstmpl[7]; + *height=igdstmpl[8]; + *iscan=igdstmpl[16]; + break; + } + case 110: // Equatorial Azimuthal + { + *width=igdstmpl[7]; + *height=igdstmpl[8]; + *iscan=igdstmpl[15]; + break; + } + default: + { + *width=0; + *height=0; + *iscan=0; + break; + } + } // end switch + } + else { + *width=0; + *height=0; + } + + if (igds != 0) free(igds); + if (igdstmpl != 0) free(igdstmpl); + if (list_opt != 0) free(list_opt); + + return 0; +} diff --git a/src/plugins/weatherdata/gfs/g2clib/getpoly.c b/src/plugins/weatherdata/gfs/g2clib/getpoly.c new file mode 100644 index 000000000..9e2a5a69b --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/getpoly.c @@ -0,0 +1,80 @@ +#include +#include +#include "grib2.h" + +g2int g2_unpack3(unsigned char *,g2int *,g2int **,g2int **, + g2int *,g2int **,g2int *); + +g2int getpoly(unsigned char *csec3,g2int *jj,g2int *kk,g2int *mm) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: getpoly +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-12-11 +// +// ABSTRACT: This subroutine returns the J, K, and M pentagonal resolution +// parameters specified in a GRIB Grid Definition Section used +// spherical harmonic coefficients using GDT 5.50 through 5.53 +// +// PROGRAM HISTORY LOG: +// 2002-12-11 Gilbert +// +// USAGE: int getpoly(unsigned char *csec3,g2int *jj,g2int *kk,g2int *mm) +// INPUT ARGUMENTS: +// csec3 - Character array that contains the packed GRIB2 GDS +// +// OUTPUT ARGUMENTS: +// JJ = J - pentagonal resolution parameter +// KK = K - pentagonal resolution parameter +// MM = M - pentagonal resolution parameter +// +// REMARKS: Returns JJ, KK, and MM set to zero, if grid template +// not recognized. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: IBM SP +// +//$$$ +{ + + g2int *igdstmpl,*list_opt; + g2int *igds; + g2int iofst,igdtlen,num_opt,jerr; + + iofst=0; // set offset to beginning of section + jerr=g2_unpack3(csec3,&iofst,&igds,&igdstmpl, + &igdtlen,&list_opt,&num_opt); + if (jerr == 0) { + switch ( igds[4] ) // Template number + { + case 50: // Spherical harmonic coefficients + case 51: + case 52: + case 53: + { + *jj=igdstmpl[0]; + *kk=igdstmpl[1]; + *mm=igdstmpl[2]; + break; + } + default: + { + *jj=0; + *kk=0; + *mm=0; + break; + } + } // end switch + } + else { + *jj=0; + *kk=0; + *mm=0; + } + + if (igds != 0) free(igds); + if (igdstmpl != 0) free(igdstmpl); + if (list_opt != 0) free(list_opt); + + return 0; +} diff --git a/src/plugins/weatherdata/gfs/g2clib/grib2.h b/src/plugins/weatherdata/gfs/g2clib/grib2.h new file mode 100755 index 000000000..432a11f78 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/grib2.h @@ -0,0 +1,249 @@ +#ifndef _grib2_H +#define _grib2_H +#include + +#define G2_VERSION "g2clib-1.5.0" +/* . . . . +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-25 +// +// PROGRAM HISTORY LOG: +// 2002-10-25 Gilbert +// 2009-01-14 Vuong Changed struct template to gtemplate +// +// Each element of structure gribfield is defined as: +// +// gribfield gfld; +// +// gfld->version = GRIB edition number ( currently 2 ) +// gfld->discipline = Message Discipline ( see Code Table 0.0 ) +// gfld->idsect = Contains the entries in the Identification +// Section ( Section 1 ) +// This element is a pointer to an array +// that holds the data. +// gfld->idsect[0] = Identification of originating Centre +// ( see Common Code Table C-1 ) +// 7 - US National Weather Service +// gfld->idsect[1] = Identification of originating Sub-centre +// gfld->idsect[2] = GRIB Master Tables Version Number +// ( see Code Table 1.0 ) +// 0 - Experimental +// 1 - Initial operational version number +// gfld->idsect[3] = GRIB Local Tables Version Number +// ( see Code Table 1.1 ) +// 0 - Local tables not used +// 1-254 - Number of local tables version used +// gfld->idsect[4] = Significance of Reference Time (Code Table 1.2) +// 0 - Analysis +// 1 - Start of forecast +// 2 - Verifying time of forecast +// 3 - Observation time +// gfld->idsect[5] = Year ( 4 digits ) +// gfld->idsect[6] = Month +// gfld->idsect[7) = Day +// gfld->idsect[8] = Hour +// gfld->idsect[9] = Minute +// gfld->idsect[10] = Second +// gfld->idsect[11] = Production status of processed data +// ( see Code Table 1.3 ) +// 0 - Operational products +// 1 - Operational test products +// 2 - Research products +// 3 - Re-analysis products +// gfld->idsect[12] = Type of processed data ( see Code Table 1.4 ) +// 0 - Analysis products +// 1 - Forecast products +// 2 - Analysis and forecast products +// 3 - Control forecast products +// 4 - Perturbed forecast products +// 5 - Control and perturbed forecast products +// 6 - Processed satellite observations +// 7 - Processed radar observations +// gfld->idsectlen = Number of elements in gfld->idsect[]. +// gfld->local = Pointer to character array containing contents +// of Local Section 2, if included +// gfld->locallen = length of array gfld->local[] +// gfld->ifldnum = field number within GRIB message +// gfld->griddef = Source of grid definition (see Code Table 3.0) +// 0 - Specified in Code table 3.1 +// 1 - Predetermined grid Defined by originating centre +// gfld->ngrdpts = Number of grid points in the defined grid. +// gfld->numoct_opt = 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. +// gfld->interp_opt = Interpretation of list for optional points +// definition. (Code Table 3.11) +// gfld->igdtnum = Grid Definition Template Number (Code Table 3.1) +// gfld->igdtmpl = Contains the data values for the specified Grid +// Definition Template ( NN=gfld->igdtnum ). Each +// element of this integer array contains an entry (in +// the order specified) of Grid Defintion Template 3.NN +// This element is a pointer to an array +// that holds the data. +// gfld->igdtlen = Number of elements in gfld->igdtmpl[]. i.e. number of +// entries in Grid Defintion Template 3.NN +// ( NN=gfld->igdtnum ). +// gfld->list_opt = (Used if gfld->numoct_opt .ne. 0) This array +// contains the number of grid points contained in +// each row ( or column ). (part of Section 3) +// This element is a pointer to an array +// that holds the data. This pointer is nullified +// if gfld->numoct_opt=0. +// gfld->num_opt = (Used if gfld->numoct_opt .ne. 0) The number of entries +// in array ideflist. i.e. number of rows ( or columns ) +// for which optional grid points are defined. This value +// is set to zero, if gfld->numoct_opt=0. +// gfdl->ipdtnum = Product Definition Template Number (see Code Table 4.0) +// gfld->ipdtmpl = Contains the data values for the specified Product +// Definition Template ( N=gfdl->ipdtnum ). Each element +// of this integer array contains an entry (in the +// order specified) of Product Defintion Template 4.N. +// This element is a pointer to an array +// that holds the data. +// gfld->ipdtlen = Number of elements in gfld->ipdtmpl[]. i.e. number of +// entries in Product Defintion Template 4.N +// ( N=gfdl->ipdtnum ). +// gfld->coord_list = Real array containing floating point values +// intended to document the vertical discretisation +// associated to model data on hybrid coordinate +// vertical levels. (part of Section 4) +// This element is a pointer to an array +// that holds the data. +// gfld->num_coord = number of values in array gfld->coord_list[]. +// gfld->ndpts = Number of data points unpacked and returned. +// gfld->idrtnum = Data Representation Template Number +// ( see Code Table 5.0) +// gfld->idrtmpl = Contains the data values for the specified Data +// Representation Template ( N=gfld->idrtnum ). Each +// element of this integer array contains an entry +// (in the order specified) of Product Defintion +// Template 5.N. +// This element is a pointer to an array +// that holds the data. +// gfld->idrtlen = Number of elements in gfld->idrtmpl[]. i.e. number +// of entries in Data Representation Template 5.N +// ( N=gfld->idrtnum ). +// gfld->unpacked = logical value indicating whether the bitmap and +// data values were unpacked. If false, +// gfld->bmap and gfld->fld pointers are nullified. +// gfld->expanded = Logical value indicating whether the data field +// was expanded to the grid in the case where a +// bit-map is present. If true, the data points in +// gfld->fld match the grid points and zeros were +// inserted at grid points where data was bit-mapped +// out. If false, the data values in gfld->fld were +// not expanded to the grid and are just a consecutive +// array of data points corresponding to each value of +// "1" in gfld->bmap. +// gfld->ibmap = Bitmap indicator ( see Code Table 6.0 ) +// 0 = bitmap applies and is included in Section 6. +// 1-253 = Predefined bitmap applies +// 254 = Previously defined bitmap applies to this field +// 255 = Bit map does not apply to this product. +// gfld->bmap = integer array containing decoded bitmap, +// if gfld->ibmap=0 or gfld->ibap=254. Otherwise nullified. +// This element is a pointer to an array +// that holds the data. +// gfld->fld = Array of gfld->ndpts unpacked data points. +// This element is a pointer to an array +// that holds the data. +*/ + +#ifdef __64BIT__ +typedef int g2int; +typedef unsigned int g2intu; +#else +typedef long g2int; +typedef unsigned long g2intu; +#endif +typedef float g2float; + +struct gtemplate { + g2int type; /* 3=Grid Defintion Template. */ + /* 4=Product Defintion Template. */ + /* 5=Data Representation Template. */ + g2int num; /* template number. */ + g2int maplen; /* number of entries in the static part */ + /* of the template. */ + g2int *map; /* num of octets of each entry in the */ + /* static part of the template. */ + g2int needext; /* indicates whether or not the template needs */ + /* to be extended. */ + g2int extlen; /* number of entries in the template extension. */ + g2int *ext; /* num of octets of each entry in the extension */ + /* part of the template. */ +}; + +typedef struct gtemplate gtemplate; + +struct gribfield { + g2int version,discipline; + g2int *idsect; + g2int idsectlen; + unsigned char *local; + g2int locallen; + g2int ifldnum; + g2int griddef,ngrdpts; + g2int numoct_opt,interp_opt,num_opt; + g2int *list_opt; + g2int igdtnum,igdtlen; + g2int *igdtmpl; + g2int ipdtnum,ipdtlen; + g2int *ipdtmpl; + g2int num_coord; + g2float *coord_list; + g2int ndpts,idrtnum,idrtlen; + g2int *idrtmpl; + g2int unpacked; + g2int expanded; + g2int ibmap; + g2int *bmap; + g2float *fld; +}; + +typedef struct gribfield gribfield; + + +/* Prototypes for unpacking API */ +void seekgb(FILE *,g2int ,g2int ,g2int *,g2int *); +g2int g2_info(unsigned char *,g2int *,g2int *,g2int *,g2int *); +g2int g2_getfld(unsigned char *,g2int ,g2int ,g2int ,gribfield **); +void g2_free(gribfield *); + +/* Prototypes for packing API */ +g2int g2_create(unsigned char *,g2int *,g2int *); +g2int g2_addlocal(unsigned char *,unsigned char *,g2int ); +g2int g2_addgrid(unsigned char *,g2int *,g2int *,g2int *,g2int ); +g2int g2_addfield(unsigned char *,g2int ,g2int *, + g2float *,g2int ,g2int ,g2int *, + g2float *,g2int ,g2int ,g2int *); +g2int g2_gribend(unsigned char *); + +/* Prototypes for supporting routines */ +extern double int_power(double, g2int ); +extern void mkieee(g2float *,g2int *,g2int); +void rdieee(g2int *,g2float *,g2int ); +extern gtemplate *getpdstemplate(g2int); +extern gtemplate *extpdstemplate(g2int,g2int *); +extern gtemplate *getdrstemplate(g2int); +extern gtemplate *extdrstemplate(g2int,g2int *); +extern gtemplate *getgridtemplate(g2int); +extern gtemplate *extgridtemplate(g2int,g2int *); +extern void simpack(g2float *,g2int,g2int *,unsigned char *,g2int *); +extern void compack(g2float *,g2int,g2int,g2int *,unsigned char *,g2int *); +void misspack(g2float *,g2int ,g2int ,g2int *, unsigned char *, g2int *); +void gbit(unsigned char *,g2int *,g2int ,g2int ); +void sbit(unsigned char *,g2int *,g2int ,g2int ); +void gbits(unsigned char *,g2int *,g2int ,g2int ,g2int ,g2int ); +void sbits(unsigned char *,g2int *,g2int ,g2int ,g2int ,g2int ); + +int pack_gp(g2int *, g2int *, g2int *, + g2int *, g2int *, g2int *, g2int *, g2int *, + g2int *, g2int *, g2int *, g2int *, + g2int *, g2int *, g2int *, g2int *, g2int *, + g2int *, g2int *, g2int *); + +#endif /* _grib2_H */ + diff --git a/src/plugins/weatherdata/gfs/g2clib/grib2c.doc b/src/plugins/weatherdata/gfs/g2clib/grib2c.doc new file mode 100644 index 000000000..4ad7c3411 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/grib2c.doc @@ -0,0 +1,946 @@ + GRIB2 USERS GUIDE (C) + +Contents: + +- Introduction +- GRIB2 Tables/Templates +- GRIB2 Encoding Routines +- GRIB2 Decoding Routines +- Decoding all GRIB2 Fields in a File +- Extracting Selected GRIB2 Fields from a GRIB2 file +- GRIB2 Routine Documentation + +=============================================================================== + + Introduction + +This document briefly describes the routines available for encoding/decoding +GRIB Edition 2 (GRIB2) messages. A basic familiarity with GRIB is assumed. + +A GRIB Edition 2 message is a machine independent format for storing +one or more gridded data fields. Each GRIB2 message consists of the +following sections: + +SECTION 0 - Indicator Section +SECTION 1 - Identification Section +SECTION 2 - (Local Use Section) - optional } +SECTION 3 - Grid Definition Section } } +SECTION 4 - Product Definition Section } } }(repeated) +SECTION 5 - Data Representation Section } }(repeated) } +SECTION 6 - Bit-map Section }(repeated) } } +SECTION 7 - Data Section } } } +SECTION 8 - End Section } } } + +Sequences of GRIB sections 2 to 7, 3 to 7, or sections 4 to 7 may be repeated +within a single GRIB message. All sections within such repeated sequences +must be present and shall appear in the numerical order noted above. +Unrepeated sections remain in effect until redefined. + +The above overview was taken from WMO's FM 92-XII GRIB description +of the GRIB Edition 2 form. + +=============================================================================== + + GRIB2 Tables/Templates + +WMO's GRIB2 specification "FM 92-XII GRIB - General Regularly-distributed +Information in Binary Form" contains descriptions of each template +and code table information. This document can be found at +http://www.wmo.ch/web/www/WMOCodes.html +(PDF and MSWord formats are available) + +=============================================================================== + + GRIB2 Encoding Routines + +Since a GRIB2 message can contain gridded fields for many parameters on +a number of different grids, several routines are used to encode a message. +This should give users more flexibility in how to organize data +within one or more GRIB2 messages. + +To start a new GRIB2 message, call function g2_create. G2_create +encodes Sections 0 and 1 at the beginning of the message. This routine +must be used to create each message. + +Routine g2_addlocal can be used to add a Local Use Section ( Section 2 ). +Note that this section is optional and need not appear in a GRIB2 message. + +Function g2_addgrid is used to encode a grid definition into Section 3. +This grid definition defines the geometry of the the data values in the +fields that follow it. g2_addgrid can be called again to change the grid +definition describing subsequent data fields. + +Each data field is added to the GRIB2 message using routine g2_addfield, +which adds Sections 4, 5, 6, and 7 to the message. + +After all desired data fields have been added to the GRIB2 message, a +call to function g2_gribend is needed to add the final section 8 to the +message and to update the length of the message. A call to g2_gribend +is required for each GRIB2 message. + +Please see the "GRIB2 Routine Documentation" section below for subroutine +argument usage for the routines mentioned above. + +=============================================================================== + + GRIB2 Decoding Routines + +Routine g2_info can be used to find out how many Local Use sections +and data fields are contained in a given GRIB2 message. This routine also +returns all the information stored in Sections 0 and 1 of the GRIB2 +message. + +g2_getfld can be used to get all information pertaining to the nth +data field in the message. The subroutine returns all the unpacked metadata +for each Section and Template in a gribfield structure, +which is defined in include file grib2.h. An option exists that lets the +user decide if the decoder should unpack the Bit-map ( if applicable ) +and the data values or just return the field description information. + +Note that a struct gribfield is allocated by g2_getfld, and it also +contains pointers to many arrays of data that are alloated during decoding. +Because of this, users are encouraged to free up this memory, when it is +no longer needed, by an explicit call to routine g2_free. + +Please see the "GRIB2 Routine Documentation" section below for subroutine +argument usage for the routines mentioned above. + +=============================================================================== + Decoding all GRIB2 Fields in a File + +Routines seekgb, g2_info and g2_getfld can be used to sequentially decode +all the GRIB2 fields in a file. This is illustrated by the following example: + + #include + #include + #include "grib2.h" + + unsigned char *cgrib; + g2int listsec0[3],listsec1[13],numlocal,numfields; + long lskip,n,lgrib,iseek; + int unpack,ret,ierr; + gribfield *gfld; + FILE *fptr; + size_t lengrib; + + iseek=0; + unpack=1; + expand=1; + fptr=fopen("inputgribfile","r"); + for (;;) { + seekgb(fptr,iseek,32000,&lskip,&lgrib); + if (lgrib == 0) break; // end loop at EOF or problem + cgrib=(unsigned char *)malloc(lgrib); + ret=fseek(fptr,lskip,SEEK_SET); + lengrib=fread(cgrib,sizeof(unsigned char),lgrib,fptr); + iseek=lskip+lgrib; + ierr=g2_info(cgrib,listsec0,listsec1,&numfields,&numlocal); + for (n=0;nversion = GRIB edition number ( currently 2 ) +// gfld->discipline = Message Discipline ( see Code Table 0.0 ) +// gfld->idsect = Contains the entries in the Identification +// Section ( Section 1 ) +// This element is a pointer to an array +// that holds the data. +// gfld->idsect[0] = Identification of originating Centre +// ( see Common Code Table C-1 ) +// 7 - US National Weather Service +// gfld->idsect[1] = Identification of originating Sub-centre +// gfld->idsect[2] = GRIB Master Tables Version Number +// ( see Code Table 1.0 ) +// 0 - Experimental +// 1 - Initial operational version number +// gfld->idsect[3] = GRIB Local Tables Version Number +// ( see Code Table 1.1 ) +// 0 - Local tables not used +// 1-254 - Number of local tables version used +// gfld->idsect[4] = Significance of Reference Time (Code Table 1.2) +// 0 - Analysis +// 1 - Start of forecast +// 2 - Verifying time of forecast +// 3 - Observation time +// gfld->idsect[5] = Year ( 4 digits ) +// gfld->idsect[6] = Month +// gfld->idsect[7) = Day +// gfld->idsect[8] = Hour +// gfld->idsect[9] = Minute +// gfld->idsect[10] = Second +// gfld->idsect[11] = Production status of processed data +// ( see Code Table 1.3 ) +// 0 - Operational products +// 1 - Operational test products +// 2 - Research products +// 3 - Re-analysis products +// gfld->idsect[12] = Type of processed data ( see Code Table 1.4 ) +// 0 - Analysis products +// 1 - Forecast products +// 2 - Analysis and forecast products +// 3 - Control forecast products +// 4 - Perturbed forecast products +// 5 - Control and perturbed forecast products +// 6 - Processed satellite observations +// 7 - Processed radar observations +// gfld->idsectlen = Number of elements in gfld->idsect[]. +// gfld->local = Pointer to character array containing contents +// of Local Section 2, if included +// gfld->locallen = length of array gfld->local[] +// gfld->ifldnum = field number within GRIB message +// gfld->griddef = Source of grid definition (see Code Table 3.0) +// 0 - Specified in Code table 3.1 +// 1 - Predetermined grid Defined by originating centre +// gfld->ngrdpts = Number of grid points in the defined grid. +// gfld->numoct_opt = 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. +// gfld->interp_opt = Interpretation of list for optional points +// definition. (Code Table 3.11) +// gfld->igdtnum = Grid Definition Template Number (Code Table 3.1) +// gfld->igdtmpl = Contains the data values for the specified Grid +// Definition Template ( NN=gfld->igdtnum ). Each +// element of this integer array contains an entry (in +// the order specified) of Grid Defintion Template 3.NN +// This element is a pointer to an array +// that holds the data. +// gfld->igdtlen = Number of elements in gfld->igdtmpl[]. i.e. number of +// entries in Grid Defintion Template 3.NN +// ( NN=gfld->igdtnum ). +// gfld->list_opt = (Used if gfld->numoct_opt .ne. 0) This array +// contains the number of grid points contained in +// each row ( or column ). (part of Section 3) +// This element is a pointer to an array +// that holds the data. This pointer is nullified +// if gfld->numoct_opt=0. +// gfld->num_opt = (Used if gfld->numoct_opt .ne. 0) +// The number of entries +// in array ideflist. i.e. number of rows ( or columns ) +// for which optional grid points are defined. This value +// is set to zero, if gfld->numoct_opt=0. +// gfdl->ipdtnum = Product Definition Template Number(see Code Table 4.0) +// gfld->ipdtmpl = Contains the data values for the specified Product +// Definition Template ( N=gfdl->ipdtnum ). Each element +// of this integer array contains an entry (in the +// order specified) of Product Defintion Template 4.N. +// This element is a pointer to an array +// that holds the data. +// gfld->ipdtlen = Number of elements in gfld->ipdtmpl[]. i.e. number of +// entries in Product Defintion Template 4.N +// ( N=gfdl->ipdtnum ). +// gfld->coord_list = Real array containing floating point values +// intended to document the vertical discretisation +// associated to model data on hybrid coordinate +// vertical levels. (part of Section 4) +// This element is a pointer to an array +// that holds the data. +// gfld->num_coord = number of values in array gfld->coord_list[]. +// gfld->ndpts = Number of data points unpacked and returned. +// gfld->idrtnum = Data Representation Template Number +// ( see Code Table 5.0) +// gfld->idrtmpl = Contains the data values for the specified Data +// Representation Template ( N=gfld->idrtnum ). Each +// element of this integer array contains an entry +// (in the order specified) of Product Defintion +// Template 5.N. +// This element is a pointer to an array +// that holds the data. +// gfld->idrtlen = Number of elements in gfld->idrtmpl[]. i.e. number +// of entries in Data Representation Template 5.N +// ( N=gfld->idrtnum ). +// gfld->unpacked = logical value indicating whether the bitmap and +// data values were unpacked. If false, +// gfld->bmap and gfld->fld pointers are nullified. +// gfld->expanded = Logical value indicating whether the data field +// was expanded to the grid in the case where a +// bit-map is present. If true, the data points in +// gfld->fld match the grid points and zeros were +// inserted at grid points where data was bit-mapped +// out. If false, the data values in gfld->fld were +// not expanded to the grid and are just a consecutive +// array of data points corresponding to each value of +// "1" in gfld->bmap. +// gfld->ibmap = Bitmap indicator ( see Code Table 6.0 ) +// 0 = bitmap applies and is included in Section 6. +// 1-253 = Predefined bitmap applies +// 254 = Previously defined bitmap applies to this field +// 255 = Bit map does not apply to this product. +// gfld->bmap = integer array containing decoded bitmap, +// if gfld->ibmap=0 or gfld->ibap=254. +// Otherwise nullified. +// This element is a pointer to an array +// that holds the data. +// gfld->fld = Array of gfld->ndpts unpacked data points. +// This element is a pointer to an array +// that holds the data. +/////////////////////////////////////////////////////////////////////////// + + + +//$$$ SUBPROGRAM DOCUMENTATION BLOCK //////////////////////////////////// +// +// SUBPROGRAM: seekgb Searches a file for the next GRIB message. +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-28 +// +// ABSTRACT: This subprogram searches a file for the next GRIB Message. +// The search is done starting at byte offset iseek of the file referenced +// by lugb for mseek bytes at a time. +// If found, the starting position and length of the message are returned +// in lskip and lgrib, respectively. +// The search is terminated when an EOF or I/O error is encountered. +// +// PROGRAM HISTORY LOG: +// 2002-10-28 GILBERT Modified from Iredell's skgb subroutine +// +// USAGE: seekgb(FILE *lugb,long iseek,long mseek,int *lskip,int *lgrib) +// INPUT ARGUMENTS: +// lugb - FILE pointer for the file to search. File must be +// opened before this routine is called. +// iseek - number of bytes in the file to skip before search +// mseek - number of bytes to search at a time +// OUTPUT ARGUMENTS: +// lskip - number of bytes to skip from the beggining of the file +// to where the GRIB message starts +// lgrib - number of bytes in message (set to 0, if no message found) +// +// ATTRIBUTES: +// LANGUAGE: C +// +////////////////////////////////////////////////////////////////////////// + + + +//$$$ SUBPROGRAM DOCUMENTATION BLOCK /////////////////////////////////// +// . . . . +// SUBPROGRAM: g2_info +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-28 +// +// ABSTRACT: This subroutine searches through a GRIB2 message and +// returns the number of gridded fields found in the message and +// the number (and maximum size) of Local Use Sections. +// Also various checks are performed +// to see if the message is a valid GRIB2 message. +// +// PROGRAM HISTORY LOG: +// 2002-10-28 Gilbert +// +// USAGE: int g2_info(unsigned char *cgrib,g2int *listsec0,g2int *listsec1, +// g2int *numfields,g2int *numlocal) +// INPUT ARGUMENT: +// cgrib - Character pointer to the GRIB2 message +// +// OUTPUT ARGUMENTS: +// listsec0 - pointer to an array containing information decoded from +// GRIB Indicator Section 0. +// Must be allocated with >= 3 elements. +// listsec0[0]=Discipline-GRIB Master Table Number +// (see Code Table 0.0) +// listsec0[1]=GRIB Edition Number (currently 2) +// listsec0[2]=Length of GRIB message +// listsec1 - pointer to an array containing information read from GRIB +// Identification Section 1. +// Must be allocated with >= 13 elements. +// listsec1[0]=Id of orginating centre (Common Code Table C-1) +// listsec1[1]=Id of orginating sub-centre (local table) +// listsec1[2]=GRIB Master Tables Version Number (Code Table 1.0) +// listsec1[3]=GRIB Local Tables Version Number +// listsec1[4]=Significance of Reference Time (Code Table 1.1) +// listsec1[5]=Reference Time - Year (4 digits) +// listsec1[6]=Reference Time - Month +// listsec1[7]=Reference Time - Day +// listsec1[8]=Reference Time - Hour +// listsec1[9]=Reference Time - Minute +// listsec1[10]=Reference Time - Second +// listsec1[11]=Production status of data (Code Table 1.2) +// listsec1[12]=Type of processed data (Code Table 1.3) +// numfields- The number of gridded fields found in the GRIB message. +// That is, the number of occurences of Sections 4 - 7. +// numlocal - The number of Local Use Sections ( Section 2 ) found in +// the GRIB message. +// +// RETURN VALUES: +// ierr - Error return code. +// 0 = no error +// 1 = Beginning characters "GRIB" not found. +// 2 = GRIB message is not Edition 2. +// 3 = Could not find Section 1, where expected. +// 4 = End string "7777" found, but not where expected. +// 5 = End string "7777" not found at end of message. +// 6 = Invalid section number found. +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +////////////////////////////////////////////////////////////////////////// + + + +//$$$ SUBPROGRAM DOCUMENTATION BLOCK /////////////////////////////////// +// . . . . +// SUBPROGRAM: g2_getfld +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-28 +// +// ABSTRACT: This subroutine returns all the metadata, template values, +// Bit-map ( if applicable ), and the unpacked data for a given data +// field. All of the information returned is stored in a gribfield +// structure, which is defined in file grib2.h. +// Users of this routine will need to include "grib2.h" in their source +// code that calls this routine. Each component of the gribfield +// struct is also described in the OUTPUT ARGUMENTS section below. +// +// Since there can be multiple data fields packed into a GRIB2 +// message, the calling routine indicates which field is being requested +// with the ifldnum argument. +// +// PROGRAM HISTORY LOG: +// 2002-10-28 Gilbert +// +// USAGE: #include "grib2.h" +// int g2_getfld(unsigned char *cgrib,g2int ifldnum,g2int unpack, +// g2int expand,gribfield **gfld) +// INPUT ARGUMENTS: +// cgrib - Character pointer to the GRIB2 message +// ifldnum - Specifies which field in the GRIB2 message to return. +// unpack - Boolean value indicating whether to unpack bitmap/data +// 1 = unpack bitmap and data values +// 0 = do not unpack bitmap and data values +// expand - Boolean value indicating whether the data points should be +// expanded to the correspond grid, if a bit-map is present. +// 1 = if possible, expand data field to grid, inserting zero +// values at gridpoints that are bitmapped out. +// (SEE REMARKS2) +// 0 = do not expand data field, leaving it an array of +// consecutive data points for each "1" in the bitmap. +// This argument is ignored if unpack == 0 OR if the +// returned field does not contain a bit-map. +// +// OUTPUT ARGUMENT: +// gribfield gfld; - pointer to structure gribfield containing +// all decoded data for the data field. +// +// gfld->version = GRIB edition number ( currently 2 ) +// gfld->discipline = Message Discipline ( see Code Table 0.0 ) +// gfld->idsect = Contains the entries in the Identification +// Section ( Section 1 ) +// This element is a pointer to an array +// that holds the data. +// gfld->idsect[0] = Identification of originating Centre +// ( see Common Code Table C-1 ) +// 7 - US National Weather Service +// gfld->idsect[1] = Identification of originating Sub-centre +// gfld->idsect[2] = GRIB Master Tables Version Number +// ( see Code Table 1.0 ) +// 0 - Experimental +// 1 - Initial operational version number +// gfld->idsect[3] = GRIB Local Tables Version Number +// ( see Code Table 1.1 ) +// 0 - Local tables not used +// 1-254 - Number of local tables version used +// gfld->idsect[4] = Significance of Reference Time (Code Table 1.2) +// 0 - Analysis +// 1 - Start of forecast +// 2 - Verifying time of forecast +// 3 - Observation time +// gfld->idsect[5] = Year ( 4 digits ) +// gfld->idsect[6] = Month +// gfld->idsect[7) = Day +// gfld->idsect[8] = Hour +// gfld->idsect[9] = Minute +// gfld->idsect[10] = Second +// gfld->idsect[11] = Production status of processed data +// ( see Code Table 1.3 ) +// 0 - Operational products +// 1 - Operational test products +// 2 - Research products +// 3 - Re-analysis products +// gfld->idsect[12] = Type of processed data ( see Code Table 1.4 ) +// 0 - Analysis products +// 1 - Forecast products +// 2 - Analysis and forecast products +// 3 - Control forecast products +// 4 - Perturbed forecast products +// 5 - Control and perturbed forecast products +// 6 - Processed satellite observations +// 7 - Processed radar observations +// gfld->idsectlen = Number of elements in gfld->idsect[]. +// gfld->local = Pointer to character array containing contents +// of Local Section 2, if included +// gfld->locallen = length of array gfld->local[] +// gfld->ifldnum = field number within GRIB message +// gfld->griddef = Source of grid definition (see Code Table 3.0) +// 0 - Specified in Code table 3.1 +// 1 - Predetermined grid Defined by originating centre +// gfld->ngrdpts = Number of grid points in the defined grid. +// gfld->numoct_opt = 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. +// gfld->interp_opt = Interpretation of list for optional points +// definition. (Code Table 3.11) +// gfld->igdtnum = Grid Definition Template Number (Code Table 3.1) +// gfld->igdtmpl = Contains the data values for the specified Grid +// Definition Template ( NN=gfld->igdtnum ). Each +// element of this integer array contains an entry (in +// the order specified) of Grid Defintion Template 3.NN +// This element is a pointer to an array +// that holds the data. +// gfld->igdtlen = Number of elements in gfld->igdtmpl[]. i.e. number of +// entries in Grid Defintion Template 3.NN +// ( NN=gfld->igdtnum ). +// gfld->list_opt = (Used if gfld->numoct_opt .ne. 0) This array +// contains the number of grid points contained in +// each row ( or column ). (part of Section 3) +// This element is a pointer to an array +// that holds the data. This pointer is nullified +// if gfld->numoct_opt=0. +// gfld->num_opt = (Used if gfld->numoct_opt .ne. 0) +// The number of entries +// in array ideflist. i.e. number of rows ( or columns ) +// for which optional grid points are defined. This value +// is set to zero, if gfld->numoct_opt=0. +// gfdl->ipdtnum = Product Definition Template Number(see Code Table 4.0) +// gfld->ipdtmpl = Contains the data values for the specified Product +// Definition Template ( N=gfdl->ipdtnum ). Each element +// of this integer array contains an entry (in the +// order specified) of Product Defintion Template 4.N. +// This element is a pointer to an array +// that holds the data. +// gfld->ipdtlen = Number of elements in gfld->ipdtmpl[]. i.e. number of +// entries in Product Defintion Template 4.N +// ( N=gfdl->ipdtnum ). +// gfld->coord_list = Real array containing floating point values +// intended to document the vertical discretisation +// associated to model data on hybrid coordinate +// vertical levels. (part of Section 4) +// This element is a pointer to an array +// that holds the data. +// gfld->num_coord = number of values in array gfld->coord_list[]. +// gfld->ndpts = Number of data points unpacked and returned. +// gfld->idrtnum = Data Representation Template Number +// ( see Code Table 5.0) +// gfld->idrtmpl = Contains the data values for the specified Data +// Representation Template ( N=gfld->idrtnum ). Each +// element of this integer array contains an entry +// (in the order specified) of Product Defintion +// Template 5.N. +// This element is a pointer to an array +// that holds the data. +// gfld->idrtlen = Number of elements in gfld->idrtmpl[]. i.e. number +// of entries in Data Representation Template 5.N +// ( N=gfld->idrtnum ). +// gfld->unpacked = logical value indicating whether the bitmap and +// data values were unpacked. If false, +// gfld->bmap and gfld->fld pointers are nullified. +// gfld->expanded = Logical value indicating whether the data field +// was expanded to the grid in the case where a +// bit-map is present. If true, the data points in +// gfld->fld match the grid points and zeros were +// inserted at grid points where data was bit-mapped +// out. If false, the data values in gfld->fld were +// not expanded to the grid and are just a consecutive +// array of data points corresponding to each value of +// "1" in gfld->bmap. +// gfld->ibmap = Bitmap indicator ( see Code Table 6.0 ) +// 0 = bitmap applies and is included in Section 6. +// 1-253 = Predefined bitmap applies +// 254 = Previously defined bitmap applies to this field +// 255 = Bit map does not apply to this product. +// gfld->bmap = integer array containing decoded bitmap, +// if gfld->ibmap=0 or gfld->ibap=254. Otherwise nullified +// This element is a pointer to an array +// that holds the data. +// gfld->fld = Array of gfld->ndpts unpacked data points. +// This element is a pointer to an array +// that holds the data. +// +// +// RETURN VALUES: +// ierr - Error return code. +// 0 = no error +// 1 = Beginning characters "GRIB" not found. +// 2 = GRIB message is not Edition 2. +// 3 = The data field request number was not positive. +// 4 = End string "7777" found, but not where expected. +// 6 = GRIB message did not contain the requested number of +// data fields. +// 7 = End string "7777" not found at end of message. +// 8 = Unrecognized Section encountered. +// 9 = Data Representation Template 5.NN not yet implemented. +// 15 = Error unpacking Section 1. +// 16 = Error unpacking Section 2. +// 10 = Error unpacking Section 3. +// 11 = Error unpacking Section 4. +// 12 = Error unpacking Section 5. +// 13 = Error unpacking Section 6. +// 14 = Error unpacking Section 7. +// +// REMARKS: Note that struct gribfield is allocated by this routine and it +// also contains pointers to many arrays of data that were allocated +// during decoding. Users are encouraged to free up this memory, +// when it is no longer needed, by an explicit call to routine g2_free. +// EXAMPLE: +// #include "grib2.h" +// gribfield *gfld; +// ret=g2_getfld(cgrib,1,1,1,&gfld); +// ... +// g2_free(gfld); +// +// Routine g2_info can be used to first determine +// how many data fields exist in a given GRIB message. +// +// REMARKS2: It may not always be possible to expand a bit-mapped data field. +// If a pre-defined bit-map is used and not included in the GRIB2 +// message itself, this routine would not have the necessary +// information to expand the data. In this case, gfld->expanded would +// would be set to 0 (false), regardless of the value of input +// argument expand. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +/////////////////////////////////////////////////////////////////////////// + + + +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_create +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 +// +// ABSTRACT: This routine initializes a new GRIB2 message and packs +// GRIB2 sections 0 (Indicator Section) and 1 (Identification Section). +// This routine is used with routines "g2_addlocal", "g2_addgrid", +// "g2_addfield", and "g2_gribend" to create a complete GRIB2 message. +// g2_create must be called first to initialize a new GRIB2 message. +// Also, a call to g2_gribend is required to complete GRIB2 message +// after all fields have been added. +// +// PROGRAM HISTORY LOG: +// 2002-10-31 Gilbert +// +// USAGE: int g2_create(unsigned char *cgrib,long *listsec0,long *listsec1) +// INPUT ARGUMENTS: +// cgrib - Character array to contain the GRIB2 message +// listsec0 - Contains information needed for GRIB Indicator Section 0. +// Must be dimensioned >= 2. +// listsec0[0]=Discipline-GRIB Master Table Number +// (see Code Table 0.0) +// listsec0[1]=GRIB Edition Number (currently 2) +// listsec1 - Contains information needed for GRIB Identification Section 1. +// Must be dimensioned >= 13. +// listsec1[0]=Id of orginating centre (Common Code Table C-1) +// listsec1[1]=Id of orginating sub-centre (local table) +// listsec1[2]=GRIB Master Tables Version Number (Code Table 1.0) +// listsec1[3]=GRIB Local Tables Version Number (Code Table 1.1) +// listsec1[4]=Significance of Reference Time (Code Table 1.2) +// listsec1[5]=Reference Time - Year (4 digits) +// listsec1[6]=Reference Time - Month +// listsec1[7]=Reference Time - Day +// listsec1[8]=Reference Time - Hour +// listsec1[9]=Reference Time - Minute +// listsec1[10]=Reference Time - Second +// listsec1[11]=Production status of data (Code Table 1.3) +// listsec1[12]=Type of processed data (Code Table 1.4) +// +// OUTPUT ARGUMENTS: +// cgrib - Char array to contain the new GRIB2 message. +// Must be allocated large enough to store the entire +// GRIB2 message. +// +// RETURN VALUES: +// ierr - return code. +// > 0 = Current size of new GRIB2 message +// -1 = Tried to use for version other than GRIB Edition 2 +// +// REMARKS: This routine is intended for use with routines "g2_addlocal", +// "g2_addgrid", "g2_addfield", and "g2_gribend" to create a complete +// GRIB2 message. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ + + + +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_addlocal +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-11-01 +// +// ABSTRACT: This routine adds a Local Use Section (Section 2) to +// a GRIB2 message. It is used with routines "g2_create", +// "g2_addgrid", "g2_addfield", +// and "g2_gribend" to create a complete GRIB2 message. +// g2_create must be called first to initialize a new GRIB2 message. +// +// PROGRAM HISTORY LOG: +// 2002-11-01 Gilbert +// +// USAGE: int g2_addlocal(unsigned char *cgrib,unsigned char *csec2, +// long lcsec2) +// INPUT ARGUMENTS: +// cgrib - Char array that contains the GRIB2 message to which section +// 2 should be added. +// csec2 - Character array containing information to be added in +// Section 2. +// lcsec2 - Number of bytes of character array csec2 to be added to +// Section 2. +// +// OUTPUT ARGUMENT: +// cgrib - Char array to contain the updated GRIB2 message. +// Must be allocated large enough to store the entire +// GRIB2 message. +// +// RETURN VALUES: +// ierr - Return code. +// > 0 = Current size of updated GRIB2 message +// -1 = GRIB message was not initialized. Need to call +// routine gribcreate first. +// -2 = GRIB message already complete. Cannot add new section. +// -3 = Sum of Section byte counts doesn't add to total byte count +// -4 = Previous Section was not 1 or 7. +// +// REMARKS: Note that the Local Use Section ( Section 2 ) can only follow +// Section 1 or Section 7 in a GRIB2 message. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ + + + +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_addgrid +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-11-01 +// +// ABSTRACT: This routine packs up a Grid Definition Section (Section 3) +// and adds it to a GRIB2 message. It is used with routines "g2_create", +// "g2_addlocal", "g2_addfield", +// and "g2_gribend" to create a complete GRIB2 message. +// g2_create must be called first to initialize a new GRIB2 message. +// +// PROGRAM HISTORY LOG: +// 2002-11-01 Gilbert +// +// USAGE: int g2_addgrid(unsigned char *cgrib,long *igds,g2int *igdstmpl, +// long *ideflist,long idefnum) +// INPUT ARGUMENTS: +// cgrib - Char array that contains the GRIB2 message to which +// section should be added. +// igds - Contains information needed for GRIB Grid Definition Section 3 +// Must be dimensioned >= 5. +// igds[0]=Source of grid definition (see Code Table 3.0) +// igds[1]=Number of grid points in the defined grid. +// igds[2]=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[3]=Interpretation of list for optional points +// definition. (Code Table 3.11) +// igds[4]=Grid Definition Template Number (Code Table 3.1) +// igdstmpl - Contains the data values for the specified Grid Definition +// Template ( NN=igds[4] ). Each element of this integer +// array contains an entry (in the order specified) of Grid +// Defintion Template 3.NN +// ideflist - (Used if igds[2] != 0) This array contains the +// number of grid points contained in each row ( or column ) +// idefnum - (Used if igds[2] != 0) The number of entries +// in array ideflist. i.e. number of rows ( or columns ) +// for which optional grid points are defined. +// +// OUTPUT ARGUMENTS: +// cgrib - Char array to contain the updated GRIB2 message. +// Must be allocated large enough to store the entire +// GRIB2 message. +// +// RETURN VALUES: +// ierr - Return code. +// > 0 = Current size of updated GRIB2 message +// -1 = GRIB message was not initialized. Need to call +// routine gribcreate first. +// -2 = GRIB message already complete. Cannot add new section. +// -3 = Sum of Section byte counts doesn't add to total byte count +// -4 = Previous Section was not 1, 2 or 7. +// -5 = Could not find requested Grid Definition Template. +// +// REMARKS: Note that the Grid Def Section ( Section 3 ) can only follow +// Section 1, 2 or Section 7 in a GRIB2 message. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ + + + +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_addfield +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-11-05 +// +// ABSTRACT: This routine packs up Sections 4 through 7 for a given field +// and adds them to a GRIB2 message. They are Product Definition Section, +// Data Representation Section, Bit-Map Section and Data Section, +// respectively. +// This routine is used with routines "g2_create", "g2_addlocal", +// "g2_addgrid", and "g2_gribend" to create a complete GRIB2 message. +// g2_create must be called first to initialize a new GRIB2 message. +// Also, routine g2_addgrid must be called after g2_create and +// before this routine to add the appropriate grid description to +// the GRIB2 message. Also, a call to g2_gribend is required to complete +// GRIB2 message after all fields have been added. +// +// PROGRAM HISTORY LOG: +// 2002-11-05 Gilbert +// +// USAGE: int g2_addfield(unsigned char *cgrib,g2int ipdsnum,g2int *ipdstmpl, +// g2float *coordlist,g2int numcoord,g2int idrsnum,g2int *idrstmpl, +// g2float *fld,g2int ngrdpts,g2int ibmap,g2int *bmap) +// INPUT ARGUMENT LIST: +// cgrib - Char array that contains the GRIB2 message to which sections +// 4 through 7 should be added. +// ipdsnum - Product Definition Template Number ( see Code Table 4.0) +// ipdstmpl - Contains the data values for the specified Product Definition +// Template ( N=ipdsnum ). Each element of this integer +// array contains an entry (in the order specified) of Product +// Defintion Template 4.N +// coordlist- Array containg floating point values intended to document +// the vertical discretisation associated to model data +// on hybrid coordinate vertical levels. +// numcoord - number of values in array coordlist. +// idrsnum - Data Representation Template Number ( see Code Table 5.0 ) +// idrstmpl - Contains the data values for the specified Data Representation +// Template ( N=idrsnum ). Each element of this integer +// array contains an entry (in the order specified) of Data +// Representation Template 5.N +// Note that some values in this template (eg. reference +// values, number of bits, etc...) may be changed by the +// data packing algorithms. +// Use this to specify scaling factors and order of +// spatial differencing, if desired. +// fld[] - Array of data points to pack. +// ngrdpts - Number of data points in grid. +// i.e. size of fld and bmap. +// ibmap - Bitmap indicator ( see Code Table 6.0 ) +// 0 = bitmap applies and is included in Section 6. +// 1-253 = Predefined bitmap applies +// 254 = Previously defined bitmap applies to this field +// 255 = Bit map does not apply to this product. +// bmap[] - Integer array containing bitmap to be added. ( if ibmap=0 ) +// +// OUTPUT ARGUMENT LIST: +// cgrib - Character array to contain the updated GRIB2 message. +// Must be allocated large enough to store the entire +// GRIB2 message. +// +// RETURN VALUES: +// ierr - Return code. +// > 0 = Current size of updated GRIB2 message +// -1 = GRIB message was not initialized. Need to call +// routine gribcreate first. +// -2 = GRIB message already complete. Cannot add new section. +// -3 = Sum of Section byte counts doesn't add to total byte count +// -4 = Previous Section was not 3 or 7. +// -5 = Could not find requested Product Definition Template. +// -6 = Section 3 (GDS) not previously defined in message +// -7 = Tried to use unsupported Data Representationi Template +// -8 = Specified use of a previously defined bitmap, but one +// does not exist in the GRIB message. +// +// REMARKS: Note that the Sections 4 through 7 can only follow +// Section 3 or Section 7 in a GRIB2 message. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ + + + +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: g2_gribend +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 +// +// ABSTRACT: This routine finalizes a GRIB2 message after all grids +// and fields have been added. It adds the End Section ( "7777" ) +// to the end of the GRIB message and calculates the length and stores +// it in the appropriate place in Section 0. +// This routine is used with routines "g2_create", "g2_addlocal", +// "g2_addgrid", and "g2_addfield" to create a complete GRIB2 message. +// g2_create must be called first to initialize a new GRIB2 message. +// +// PROGRAM HISTORY LOG: +// 2002-10-31 Gilbert +// +// USAGE: int g2_gribend(unsigned char *cgrib) +// INPUT ARGUMENT: +// cgrib - Char array containing all the data sections added +// be previous calls to g2_create, g2_addlocal, g2_addgrid, +// and g2_addfield. +// +// OUTPUT ARGUMENTS: +// cgrib - Char array containing the finalized GRIB2 message +// +// RETURN VALUES: +// ierr - Return code. +// > 0 = Length of the final GRIB2 message in bytes. +// -1 = GRIB message was not initialized. Need to call +// routine g2_create first. +// -2 = GRIB message already complete. +// -3 = Sum of Section byte counts doesn't add to total byte count +// -4 = Previous Section was not 7. +// +// REMARKS: This routine is intended for use with routines "g2_create", +// "g2_addlocal", "g2_addgrid", and "g2_addfield" to create a complete +// GRIB2 message. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ diff --git a/src/plugins/weatherdata/gfs/g2clib/gridtemplates.c b/src/plugins/weatherdata/gfs/g2clib/gridtemplates.c new file mode 100644 index 000000000..255622796 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/gridtemplates.c @@ -0,0 +1,210 @@ +#include +#include "grib2.h" +#include "gridtemplates.h" + +g2int getgridindex(g2int number) +/*!$$$ SUBPROGRAM DOCUMENTATION BLOCK +! . . . . +! SUBPROGRAM: getgridindex +! PRGMMR: Gilbert ORG: W/NP11 DATE: 2001-06-28 +! +! ABSTRACT: This function returns the index of specified Grid +! Definition Template 3.NN (NN=number) in array templates. +! +! PROGRAM HISTORY LOG: +! 2001-06-28 Gilbert +! 2007-08-16 Vuong - Added GDT 3.204 Curvilinear Orthogonal Grid +! 2008-07-08 Vuong - Added GDT 3.32768 Rotate Lat/Lon E-grid (Arakawa) +! 2009-01-14 Vuong - Changed structure name template to gtemplate +! 2010-05-11 Vuong - Added GDT 3.32769 Rotate Lat/Lon Non-E Staggered grid (Arakawa) +! 2013-08-06 Vuong - Added GDT 3.4,3.5,3.12,3.101,3.140 +! +! USAGE: index=getgridindex(number) +! INPUT ARGUMENT LIST: +! number - NN, indicating the number of the Grid Definition +! Template 3.NN that is being requested. +! +! RETURNS: Index of GDT 3.NN in array templates, if template exists. +! = -1, otherwise. +! +! REMARKS: None +! +! ATTRIBUTES: +! LANGUAGE: C +! MACHINE: IBM SP +! +!$$$*/ +{ + g2int j,getgridindex=-1; + + for (j=0;jtype=3; + new->num=templatesgrid[index].template_num; + new->maplen=templatesgrid[index].mapgridlen; + new->needext=templatesgrid[index].needext; + new->map=(g2int *)templatesgrid[index].mapgrid; + new->extlen=0; + new->ext=0; //NULL + return(new); + } + else { + printf("getgridtemplate: GDT Template 3.%d not defined.\n",(int)number); + return(0); //NULL + } + + return(0); //NULL +} + + +gtemplate *extgridtemplate(g2int number,g2int *list) +/*!$$$ SUBPROGRAM DOCUMENTATION BLOCK +! . . . . +! SUBPROGRAM: extgridtemplate +! PRGMMR: Gilbert ORG: W/NP11 DATE: 2000-05-09 +! +! ABSTRACT: This subroutine generates the remaining octet map for a +! given Grid Definition Template, if required. Some Templates can +! vary depending on data values given in an earlier part of the +! Template, and it is necessary to know some of the earlier entry +! values to generate the full octet map of the Template. +! +! PROGRAM HISTORY LOG: +! 2000-05-09 Gilbert +! 2008-07-08 Vuong - Added GDT 3.32768 Rotate Lat/Lon E-grid (Arakawa) +! 2009-01-14 Vuong - Changed structure name template to gtemplate +! 2010-05-11 Vuong - Added GDT 3.32769 Rotate Lat/Lon Non-E Staggered grid (Arakawa) +! 2013-08-06 Vuong - Added GDT 3.4,3.5,3.12,3.101,3.140 +! +! USAGE: CALL extgridtemplate(number,list) +! INPUT ARGUMENT LIST: +! number - NN, indicating the number of the Grid Definition +! Template 3.NN that is being requested. +! list() - The list of values for each entry in +! the Grid Definition Template. +! +! RETURN VALUE: +! - Pointer to the returned template struct. +! Returns NULL pointer, if template not found. +! +! ATTRIBUTES: +! LANGUAGE: C +! MACHINE: IBM SP +! +!$$$*/ +{ + gtemplate *new; + g2int index,i; + + index=getgridindex(number); + if (index == -1) return(0); + + new=getgridtemplate(number); + + if ( ! new->needext ) return(new); + + if ( number == 120 ) { + new->extlen=list[1]*2; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iextlen;i++) { + if ( i%2 == 0 ) { + new->ext[i]=2; + } + else { + new->ext[i]=-2; + } + } + } + else if ( number == 4 ) { + new->extlen=list[7]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iextlen;i++) { + new->ext[i]=4; + } + new->extlen=list[8]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iextlen;i++) { + new->ext[i]=-4; + } + } + else if ( number == 5 ) { + new->extlen=list[7]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iextlen;i++) { + new->ext[i]=4; + } + new->extlen=list[8]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iextlen;i++) { + new->ext[i]=-4; + } + } + else if ( number == 1000 ) { + new->extlen=list[19]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iextlen;i++) { + new->ext[i]=4; + } + } + else if ( number == 1200 ) { + new->extlen=list[15]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iextlen;i++) { + new->ext[i]=4; + } + } + + return(new); + +} diff --git a/src/plugins/weatherdata/gfs/g2clib/gridtemplates.h b/src/plugins/weatherdata/gfs/g2clib/gridtemplates.h new file mode 100644 index 000000000..f45a88fd8 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/gridtemplates.h @@ -0,0 +1,121 @@ +#ifndef _gridtemplates_H +#define _gridtemplates_H +#include "grib2.h" + +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2001-10-26 +// +// ABSTRACT: This Fortran Module contains info on all the available +// GRIB2 Grid Definition Templates used in Section 3 (GDS). +// The information decribing each template is stored in the +// gridtemplate structure defined below. +// +// Each Template has three parts: The number of entries in the template +// (mapgridlen); A map of the template (mapgrid), which contains the +// number of octets in which to pack each of the template values; and +// a logical value (needext) that indicates whether the Template needs +// to be extended. In some cases the number of entries in a template +// can vary depending upon values specified in the "static" part of +// the template. ( See Template 3.120 as an example ) +// +// NOTE: Array mapgrid contains the number of octets in which the +// corresponding template values will be stored. A negative value in +// mapgrid is used to indicate that the corresponding template entry can +// contain negative values. This information is used later when packing +// (or unpacking) the template data values. Negative data values in GRIB +// are stored with the left most bit set to one, and a negative number +// of octets value in mapgrid[] indicates that this possibility should +// be considered. The number of octets used to store the data value +// in this case would be the absolute value of the negative value in +// mapgrid[]. +// +// PROGRAM HISTORY LOG: +// +// 2001-10-26 Gilbert +// 2007-08-16 Vuong - Added GDT 3.204 Curvilinear Orthogonal Grid +// 2008-07-08 Vuong - Added GDT 3.32768 Rot Lat/Lon E-grid (Arakawa) +// 2010-05-11 Vuong - Added GDT 3.32769 Rotate Lat/Lon Non-E Staggered grid (Arakawa) +// 2013-08-06 Vuong - Added GDT 3.4,3.5,3.12,3.101,3.140 +// +//////////////////////////////////////////////////////////////////// + + #define MAXGRIDTEMP 31 // maximum number of templates + #define MAXGRIDMAPLEN 200 // maximum template map length + + struct gridtemplate + { + g2int template_num; + g2int mapgridlen; + g2int needext; + g2int mapgrid[MAXGRIDMAPLEN]; + }; + + const struct gridtemplate templatesgrid[MAXGRIDTEMP] = { + // 3.0: Lat/Lon grid + { 0, 19, 0, {1,1,4,1,4,1,4,4,4,4,4,-4,4,1,-4,4,4,4,1} }, + // 3.1: Rotated Lat/Lon grid + { 1, 22, 0, {1,1,4,1,4,1,4,4,4,4,4,-4,4,1,-4,4,4,4,1,-4,4,4} }, + // 3.2: Stretched Lat/Lon grid + { 2, 22, 0, {1,1,4,1,4,1,4,4,4,4,4,-4,4,1,-4,4,4,4,1,-4,4,-4} }, + // 3.3: Stretched & Rotated Lat/Lon grid + { 3, 25, 0, {1,1,4,1,4,1,4,4,4,4,4,-4,4,1,-4,4,4,4,1,-4,4,4,-4,4,-4} }, +// Added GDT 3.4,3.5 (08/05/2013) + // 3.4: Variable resolution Latitude/Longitude + { 4, 13, 1, {1,1,4,1,4,1,4,4,4,4,4,1,1} }, + // 3.5: Variable resolution rotate Latitude/Longitude + { 5, 16, 1, {1,1,4,1,4,1,4,4,4,4,4,1,1,-4,4,4} }, + // 3.12: Transverse Mercator + {12, 22, 0, {1,1,4,1,4,1,4,4,4,-4,4,1,-4,4,4,1,4,4,-4,-4,-4,-4} }, + // 3.101: General unstructured grid + {101, 4, 0, {1,4,1,-4} }, + // 3.140: Lambert Azimuthal Equal Area Projection + {140, 17, 0, {1,1,4,1,4,1,4,4,4,-4,4,4,4,1,4,4,1} }, +// + // 3.10: Mercator + {10, 19, 0, {1,1,4,1,4,1,4,4,4,-4,4,1,-4,-4,4,1,4,4,4} }, + // 3.20: Polar Stereographic Projection + {20, 18, 0, {1,1,4,1,4,1,4,4,4,-4,4,1,-4,4,4,4,1,1} }, + // 3.30: Lambert Conformal + {30, 22, 0, {1,1,4,1,4,1,4,4,4,-4,4,1,-4,4,4,4,1,1,-4,-4,-4,4} }, + // 3.31: Albers equal area + {31, 22, 0, {1,1,4,1,4,1,4,4,4,-4,4,1,-4,4,4,4,1,1,-4,-4,-4,4} }, + // 3.40: Guassian Lat/Lon + {40, 19, 0, {1,1,4,1,4,1,4,4,4,4,4,-4,4,1,-4,4,4,4,1} }, + // 3.41: Rotated Gaussian Lat/Lon + {41, 22, 0, {1,1,4,1,4,1,4,4,4,4,4,-4,4,1,-4,4,4,4,1,-4,4,4} }, + // 3.42: Stretched Gaussian Lat/Lon + {42, 22, 0, {1,1,4,1,4,1,4,4,4,4,4,-4,4,1,-4,4,4,4,1,-4,4,-4} }, + // 3.43: Stretched and Rotated Gaussian Lat/Lon + {43, 25, 0, {1,1,4,1,4,1,4,4,4,4,4,-4,4,1,-4,4,4,4,1,-4,4,4,-4,4,-4} }, + // 3.50: Spherical Harmonic Coefficients + {50, 5, 0, {4,4,4,1,1} }, + // 3.51: Rotated Spherical Harmonic Coefficients + {51, 8, 0, {4,4,4,1,1,-4,4,4} }, + // 3.52: Stretched Spherical Harmonic Coefficients + {52, 8, 0, {4,4,4,1,1,-4,4,-4} }, + // 3.53: Stretched and Rotated Spherical Harmonic Coefficients + {53, 11, 0, {4,4,4,1,1,-4,4,4,-4,4,-4} }, + // 3.90: Space View Perspective or orthographic + {90, 21, 0, {1,1,4,1,4,1,4,4,4,-4,4,1,4,4,4,4,1,4,4,4,4} }, + // 3.100: Triangular grid based on an icosahedron + {100, 11, 0, {1,1,2,1,-4,4,4,1,1,1,4} }, + // 3.110: Equatorial Azimuthal equidistant + {110, 16, 0, {1,1,4,1,4,1,4,4,4,-4,4,1,4,4,1,1} }, + // 3.120: Azimuth-range projection + {120, 7, 1, {4,4,-4,4,4,4,1} }, + // 3.204: Curvilinear Orthogonal Grid + {204, 19, 0, {1,1,4,1,4,1,4,4,4,4,4,-4,4,1,-4,4,4,4,1} }, + // 3.32768: Rot Lat/Lon E-grid (Arakawa) + {32768, 19, 0, {1,1,4,1,4,1,4,4,4,4,4,-4,4,1,-4,4,4,4,1} }, + // 3.32769: Rot Lat/Lon Non-E Staggered grid (Arakawa) + {32769, 21, 0, {1,1,4,1,4,1,4,4,4,4,4,-4,4,1,-4,4,4,4,1,4,4} }, + // 3.1000: Cross Section Grid + {1000, 20, 1, {1,1,4,1,4,1,4,4,4,4,-4,4,1,4,4,1,2,1,1,2} }, + // 3.1100: Hovmoller Diagram Grid + {1100, 28, 0, {1,1,4,1,4,1,4,4,4,4,-4,4,1,-4,4,1,4,1,-4,1,1,-4,2,1,1,1,1,1} }, + // 3.1200: Time Section Grid + {1200, 16, 1, {4,1,-4,1,1,-4,2,1,1,1,1,1,2,1,1,2} } + + } ; + + +#endif /* _gridtemplates_H */ diff --git a/src/plugins/weatherdata/gfs/g2clib/int_power.c b/src/plugins/weatherdata/gfs/g2clib/int_power.c new file mode 100644 index 000000000..76f645abd --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/int_power.c @@ -0,0 +1,30 @@ +#include "grib2.h" +/* + * w. ebisuzaki + * + * return x**y + * + * + * input: double x + * int y + */ +double int_power(double x, g2int y) { + + double value; + + if (y < 0) { + y = -y; + x = 1.0 / x; + } + value = 1.0; + + while (y) { + if (y & 1) { + value *= x; + } + x = x * x; + y >>= 1; + } + return value; +} + diff --git a/src/plugins/weatherdata/gfs/g2clib/jpcpack.c b/src/plugins/weatherdata/gfs/g2clib/jpcpack.c new file mode 100644 index 000000000..266666868 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/jpcpack.c @@ -0,0 +1,175 @@ +#include +#include +#include "grib2.h" + +int enc_jpeg2000(unsigned char *,g2int ,g2int ,g2int , + g2int , g2int, g2int , char *, g2int ); + +void jpcpack(g2float *fld,g2int width,g2int height,g2int *idrstmpl, + unsigned char *cpack,g2int *lcpack) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: jpcpack +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2003-08-17 +// +// ABSTRACT: This subroutine packs up a data field into a JPEG2000 code stream. +// After the data field is scaled, and the reference value is subtracted out, +// it is treated as a grayscale image and passed to a JPEG2000 encoder. +// It also fills in GRIB2 Data Representation Template 5.40 or 5.40000 with +// the appropriate values. +// +// PROGRAM HISTORY LOG: +// 2003-08-17 Gilbert +// 2004-11-92 Gilbert - Fixed bug encountered when packing a near constant +// field. +// 2004-07-19 Gilbert - Added check on whether the jpeg2000 encoding was +// successful. If not, try again with different encoder +// options. +// 2005-05-10 Gilbert - Imposed minimum size on cpack, used to hold encoded +// bit string. +// +// USAGE: jpcpack(g2float *fld,g2int width,g2int height,g2int *idrstmpl, +// unsigned char *cpack,g2int *lcpack); +// INPUT ARGUMENT LIST: +// fld[] - Contains the data values to pack +// width - number of points in the x direction +// height - number of points in the y direction +// idrstmpl - Contains the array of values for Data Representation +// Template 5.40 or 5.40000 +// [0] = Reference value - ignored on input +// [1] = Binary Scale Factor +// [2] = Decimal Scale Factor +// [3] = number of bits for each data value - ignored on input +// [4] = Original field type - currently ignored on input +// Data values assumed to be reals. +// [5] = 0 - use lossless compression +// = 1 - use lossy compression +// [6] = Desired compression ratio, if idrstmpl[5]=1. +// Set to 255, if idrstmpl[5]=0. +// lcpack - size of array cpack[] +// +// OUTPUT ARGUMENT LIST: +// idrstmpl - Contains the array of values for Data Representation +// Template 5.0 +// [0] = Reference value - set by jpcpack routine. +// [1] = Binary Scale Factor - unchanged from input +// [2] = Decimal Scale Factor - unchanged from input +// [3] = Number of bits containing each grayscale pixel value +// [4] = Original field type - currently set = 0 on output. +// Data values assumed to be reals. +// [5] = 0 - use lossless compression +// = 1 - use lossy compression +// [6] = Desired compression ratio, if idrstmpl[5]=1 +// cpack - The packed data field +// lcpack - length of packed field in cpack. +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: IBM SP +// +//$$$ +{ + g2int *ifld; + static g2float alog2=0.69314718; // ln(2.0) + g2int j,nbits,imin,imax,maxdif; + g2int ndpts,nbytes,nsize,retry; + g2float bscale,dscale,rmax,rmin,temp; + unsigned char *ctemp; + + ifld=0; + ndpts=width*height; + bscale=int_power(2.0,-idrstmpl[1]); + dscale=int_power(10.0,idrstmpl[2]); +// +// Find max and min values in the data +// + rmax=fld[0]; + rmin=fld[0]; + for (j=1;j rmax) rmax=fld[j]; + if (fld[j] < rmin) rmin=fld[j]; + } + if (idrstmpl[1] == 0) + maxdif = (g2int) (rint(rmax*dscale) - rint(rmin*dscale)); + else + maxdif = (g2int)rint( (rmax-rmin)*dscale*bscale ); +// +// If max and min values are not equal, pack up field. +// If they are equal, we have a constant field, and the reference +// value (rmin) is the value for each point in the field and +// set nbits to 0. +// + if ( rmin != rmax && maxdif != 0 ) { + ifld=(g2int *)malloc(ndpts*sizeof(g2int)); + // + // Determine which algorithm to use based on user-supplied + // binary scale factor and number of bits. + // + if (idrstmpl[1] == 0) { + // + // No binary scaling and calculate minumum number of + // bits in which the data will fit. + // + imin=(g2int)rint(rmin*dscale); + imax=(g2int)rint(rmax*dscale); + maxdif=imax-imin; + temp=log((double)(maxdif+1))/alog2; + nbits=(g2int)ceil(temp); + rmin=(g2float)imin; + // scale data + for(j=0;j +#include +#include "grib2.h" + + int dec_jpeg2000(char *,g2int ,g2int *); + +g2int jpcunpack(unsigned char *cpack,g2int len,g2int *idrstmpl,g2int ndpts, + g2float *fld) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: jpcunpack +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2003-08-27 +// +// ABSTRACT: This subroutine unpacks a data field that was packed into a +// JPEG2000 code stream +// using info from the GRIB2 Data Representation Template 5.40 or 5.40000. +// +// PROGRAM HISTORY LOG: +// 2003-08-27 Gilbert +// +// USAGE: jpcunpack(unsigned char *cpack,g2int len,g2int *idrstmpl,g2int ndpts, +// g2float *fld) +// INPUT ARGUMENT LIST: +// cpack - The packed data field (character*1 array) +// len - length of packed field cpack(). +// idrstmpl - Pointer to array of values for Data Representation +// Template 5.40 or 5.40000 +// ndpts - The number of data values to unpack +// +// OUTPUT ARGUMENT LIST: +// fld[] - Contains the unpacked data values +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: IBM SP +// +//$$$ +{ + + g2int *ifld; + g2int j,nbits,iret; + g2float ref,bscale,dscale; + + rdieee(idrstmpl+0,&ref,1); + bscale = int_power(2.0,idrstmpl[1]); + dscale = int_power(10.0,-idrstmpl[2]); + nbits = idrstmpl[3]; +// +// if nbits equals 0, we have a constant field where the reference value +// is the data value at each gridpoint +// + if (nbits != 0) { + + ifld=(g2int *)calloc(ndpts,sizeof(g2int)); + if ( ifld == 0 ) { + fprintf(stderr,"Could not allocate space in jpcunpack.\n Data field NOT upacked.\n"); + return(1); + } + iret=(g2int)dec_jpeg2000(cpack,len,ifld); + for (j=0;j +#include +#include "grib2.h" + +void misspack(g2float *fld,g2int ndpts,g2int idrsnum,g2int *idrstmpl, + unsigned char *cpack, g2int *lcpack) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: misspack +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2000-06-21 +// +// ABSTRACT: This subroutine packs up a data field using a complex +// packing algorithm as defined in the GRIB2 documention. It +// supports GRIB2 complex packing templates with or without +// spatial differences (i.e. DRTs 5.2 and 5.3). +// It also fills in GRIB2 Data Representation Template 5.2 or 5.3 +// with the appropriate values. +// This version assumes that Missing Value Management is being used and that +// 1 or 2 missing values appear in the data. +// +// PROGRAM HISTORY LOG: +// 2000-06-21 Gilbert +// +// USAGE: misspack(g2float *fld,g2int ndpts,g2int idrsnum,g2int *idrstmpl, +// unsigned char *cpack, g2int *lcpack) +// INPUT ARGUMENT LIST: +// fld[] - Contains the data values to pack +// ndpts - The number of data values in array fld[] +// idrsnum - Data Representation Template number 5.N +// Must equal 2 or 3. +// idrstmpl - Contains the array of values for Data Representation +// Template 5.2 or 5.3 +// [0] = Reference value - ignored on input +// [1] = Binary Scale Factor +// [2] = Decimal Scale Factor +// . +// . +// [6] = Missing value management +// [7] = Primary missing value +// [8] = Secondary missing value +// . +// . +// [16] = Order of Spatial Differencing ( 1 or 2 ) +// . +// . +// +// OUTPUT ARGUMENT LIST: +// idrstmpl - Contains the array of values for Data Representation +// Template 5.3 +// [0] = Reference value - set by misspack routine. +// [1] = Binary Scale Factor - unchanged from input +// [2] = Decimal Scale Factor - unchanged from input +// . +// . +// cpack - The packed data field (character*1 array) +// *lcpack - length of packed field cpack(). +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ +{ + + g2int *ifld, *ifldmiss, *jfld; + g2int *jmin, *jmax, *lbit; + static g2int zero=0; + g2int *gref, *gwidth, *glen; + g2int glength, grpwidth; + g2int i, n, iofst, imin, ival1, ival2, isd, minsd, nbitsd; + g2int nbitsgref, left, iwmax, ngwidthref, nbitsgwidth, ilmax; + g2int nglenref, nglenlast, nbitsglen, ij; + g2int j, missopt, nonmiss, itemp, maxorig, nbitorig, miss1, miss2; + g2int ngroups, ng, num0, num1, num2; + g2int imax, lg, mtemp, ier, igmax; + g2int kfildo, minpk, inc, maxgrps, ibit, jbit, kbit, novref, lbitref; + g2float rmissp, rmisss, bscale, dscale, rmin, temp; + static g2int simple_alg = 0; + static g2float alog2=0.69314718; // ln(2.0) + static g2int one=1; + + bscale=int_power(2.0,-idrstmpl[1]); + dscale=int_power(10.0,idrstmpl[2]); + missopt=idrstmpl[6]; + if ( missopt != 1 && missopt != 2 ) { + printf("misspack: Unrecognized option.\n"); + *lcpack=-1; + return; + } + else { // Get missing values + rdieee(idrstmpl+7,&rmissp,1); + if (missopt == 2) rdieee(idrstmpl+8,&rmisss,1); + } +// +// Find min value of non-missing values in the data, +// AND set up missing value mapping of the field. +// + ifldmiss = calloc(ndpts,sizeof(g2int)); + rmin=1E+37; + if ( missopt == 1 ) { // Primary missing value only + for ( j=0; j0; j--) + jfld[j]=jfld[j]-jfld[j-1]; + jfld[0]=0; + } + else if (idrstmpl[16] == 2) { // second order + ival1=jfld[0]; + ival2=jfld[1]; + for ( j=nonmiss-1; j>1; j--) + jfld[j]=jfld[j]-(2*jfld[j-1])+jfld[j-2]; + jfld[0]=0; + jfld[1]=0; + } + // + // subtract min value from spatial diff field + // + isd=idrstmpl[16]; + minsd=jfld[isd]; + for ( j=isd; jival1) maxorig=ival2; + temp=log((double)(maxorig+1))/alog2; + nbitorig=(g2int)ceil(temp)+1; + if (nbitorig > nbitsd) nbitsd=nbitorig; + // increase number of bits to even multiple of 8 ( octet ) + if ( (nbitsd%8) != 0) nbitsd=nbitsd+(8-(nbitsd%8)); + // + // Store extra spatial differencing info into the packed + // data section. + // + if (nbitsd != 0) { + // pack first original value + if (ival1 >= 0) { + sbit(cpack,&ival1,iofst,nbitsd); + iofst=iofst+nbitsd; + } + else { + sbit(cpack,&one,iofst,1); + iofst=iofst+1; + itemp=abs(ival1); + sbit(cpack,&itemp,iofst,nbitsd-1); + iofst=iofst+nbitsd-1; + } + if (idrstmpl[16] == 2) { + // pack second original value + if (ival2 >= 0) { + sbit(cpack,&ival2,iofst,nbitsd); + iofst=iofst+nbitsd; + } + else { + sbit(cpack,&one,iofst,1); + iofst=iofst+1; + itemp=abs(ival2); + sbit(cpack,&itemp,iofst,nbitsd-1); + iofst=iofst+nbitsd-1; + } + } + // pack overall min of spatial differences + if (minsd >= 0) { + sbit(cpack,&minsd,iofst,nbitsd); + iofst=iofst+nbitsd; + } + else { + sbit(cpack,&one,iofst,1); + iofst=iofst+1; + itemp=abs(minsd); + sbit(cpack,&itemp,iofst,nbitsd-1); + iofst=iofst+nbitsd-1; + } + } + //print *,'SDp ',ival1,ival2,minsd,nbitsd + } // end of spatial diff section + // + // Expand non-missing data values to original grid. + // + miss1=jfld[0]; + for ( j=0; j imax) imax=ifld[j]; + } + j++; + } + if (missopt == 1) imax=imax+1; + if (missopt == 2) imax=imax+2; + // calc num of bits needed to hold data + if ( gref[ng] != imax ) { + temp=log((double)(imax-gref[ng]+1))/alog2; + gwidth[ng]=(g2int)ceil(temp); + } + else { + gwidth[ng]=0; + } + } + // Subtract min from data + j=n; + mtemp=(g2int)int_power(2.,gwidth[ng]); + for ( lg=0; lg igmax) igmax=gref[j]; + if (missopt == 1) igmax=igmax+1; + if (missopt == 2) igmax=igmax+2; + if (igmax != 0) { + temp=log((double)(igmax+1))/alog2; + nbitsgref=(g2int)ceil(temp); + // reset the ref values of any "missing only" groups. + mtemp=(g2int)int_power(2.,nbitsgref); + for ( j=0; j iwmax) iwmax=gwidth[j]; + if (gwidth[j] < ngwidthref) ngwidthref=gwidth[j]; + } + if (iwmax != ngwidthref) { + temp=log((double)(iwmax-ngwidthref+1))/alog2; + nbitsgwidth=(g2int)ceil(temp); + for ( i=0; i ilmax) ilmax=glen[j]; + if (glen[j] < nglenref) nglenref=glen[j]; + } + nglenlast=glen[ngroups-1]; + if (ilmax != nglenref) { + temp=log((double)(ilmax-nglenref+1))/alog2; + nbitsglen=(g2int)ceil(temp); + for ( i=0; i +#include +#include "grib2.h" + + +void mkieee(g2float *a,g2int *rieee,g2int num) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: mkieee +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-29 +// +// ABSTRACT: This subroutine stores a list of real values in +// 32-bit IEEE floating point format. +// +// PROGRAM HISTORY LOG: +// 2002-10-29 Gilbert +// +// USAGE: mkieee(g2float *a,g2int *rieee,g2int num); +// INPUT ARGUMENT LIST: +// a - Input array of floating point values. +// num - Number of floating point values to convert. +// +// OUTPUT ARGUMENT LIST: +// rieee - Output array of data values in 32-bit IEEE format +// stored in g2int integer array. rieee must be allocated +// with at least 4*num bytes of memory before calling this +// function. +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ +{ + + g2int j,n,ieee,iexp,imant; + double alog2,atemp; + + static double two23,two126; + static g2int test=0; + //g2intu msk1=0x80000000; // 10000000000000000000000000000000 binary + //g2int msk2=0x7F800000; // 01111111100000000000000000000000 binary + //g2int msk3=0x007FFFFF; // 00000000011111111111111111111111 binary + + if ( test == 0 ) { + two23=(double)int_power(2.0,23); + two126=(double)int_power(2.0,126); + test=1; + } + + alog2=0.69314718; // ln(2.0) + + for (j=0;j= 1.0 ) { + n = 0; + while ( int_power(2.0,n+1) <= atemp ) { + n++; + } + } + else { + n = -1; + while ( int_power(2.0,n) > atemp ) { + n--; + } + } + //n=(g2int)floor(log(atemp)/alog2); + iexp=n+127; + if (n > 127) iexp=255; // overflow + if (n < -127) iexp=0; + //printf("exp %ld %ld \n",iexp,n); + // set exponent bits ( bits 30-23 ) + ieee = ieee | ( iexp << 23 ); +// +// Determine Mantissa +// + if (iexp != 255) { + if (iexp != 0) + atemp=(atemp/int_power(2.0,n))-1.0; + else + atemp=atemp*two126; + imant=(g2int)rint(atemp*two23); + } + else { + imant=0; + } + //printf("mant %ld %x \n",imant,imant); + // set mantissa bits ( bits 22-0 ) + ieee = ieee | imant; +// +// Transfer IEEE bit string to rieee array +// + rieee[j]=ieee; + + } + + return; + +} diff --git a/src/plugins/weatherdata/gfs/g2clib/pack_gp.c b/src/plugins/weatherdata/gfs/g2clib/pack_gp.c new file mode 100644 index 000000000..2eaa00ee5 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/pack_gp.c @@ -0,0 +1,1447 @@ +/* pack_gp.f -- translated by f2c (version 20031025). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +/*#include "f2c.h"*/ +#include +#include "grib2.h" +typedef g2int integer; +typedef g2int logical; +#define TRUE_ (1) +#define FALSE_ (0) + +/* Subroutine */ int pack_gp(integer *kfildo, integer *ic, integer *nxy, + integer *is523, integer *minpk, integer *inc, integer *missp, integer + *misss, integer *jmin, integer *jmax, integer *lbit, integer *nov, + integer *ndg, integer *lx, integer *ibit, integer *jbit, integer * + kbit, integer *novref, integer *lbitref, integer *ier) +{ + /* Initialized data */ + + const integer mallow = 1073741825; /* MALLOW=2**30+1 */ + static integer ifeed = 12; + static integer ifirst = 0; + + /* System generated locals */ + integer i__1, i__2, i__3; + + /* Local variables */ + static integer j, k, l; + static logical adda; + static integer ired, kinc, mina, maxa, minb, maxb, minc, maxc, ibxx2[31]; + static char cfeed[1]; + static integer nenda, nendb, ibita, ibitb, minak, minbk, maxak, maxbk, + minck, maxck, nouta, lmiss, itest, nount; + extern /* Subroutine */ int reduce(integer *, integer *, integer *, + integer *, integer *, integer *, integer *, integer *, integer *, + integer *, integer *, integer *, integer *); + static integer ibitbs, mislla, misllb, misllc, iersav, lminpk, ktotal, + kounta, kountb, kstart, mstart, mintst, maxtst, + kounts, mintstk, maxtstk; + integer *misslx; + + +/* FEBRUARY 1994 GLAHN TDL MOS-2000 */ +/* JUNE 1995 GLAHN MODIFIED FOR LMISS ERROR. */ +/* JULY 1996 GLAHN ADDED MISSS */ +/* FEBRUARY 1997 GLAHN REMOVED 4 REDUNDANT TESTS FOR */ +/* MISSP.EQ.0; INSERTED A TEST TO BETTER */ +/* HANDLE A STRING OF 9999'S */ +/* FEBRUARY 1997 GLAHN ADDED LOOPS TO ELIMINATE TEST FOR */ +/* MISSS WHEN MISSS = 0 */ +/* MARCH 1997 GLAHN CORRECTED FOR SECONDARY MISSING VALUE */ +/* MARCH 1997 GLAHN CORRECTED FOR USE OF LOCAL VALUE */ +/* OF MINPK */ +/* MARCH 1997 GLAHN CORRECTED FOR SECONDARY MISSING VALUE */ +/* MARCH 1997 GLAHN CHANGED CALCULATING NUMBER OF BITS */ +/* THROUGH EXPONENTS TO AN ARRAY (IMPROVED */ +/* OVERALL PACKING PERFORMANCE BY ABOUT */ +/* 35 PERCENT!). ALLOWED 0 BITS FOR */ +/* PACKING JMIN( ), LBIT( ), AND NOV( ). */ +/* MAY 1997 GLAHN A NUMBER OF CHANGES FOR EFFICIENCY. */ +/* MOD FUNCTIONS ELIMINATED AND ONE */ +/* IFTHEN ADDED. JOUNT REMOVED. */ +/* RECOMPUTATION OF BITS NOT MADE UNLESS */ +/* NECESSARY AFTER MOVING POINTS FROM */ +/* ONE GROUP TO ANOTHER. NENDB ADJUSTED */ +/* TO ELIMINATE POSSIBILITY OF VERY */ +/* SMALL GROUP AT THE END. */ +/* ABOUT 8 PERCENT IMPROVEMENT IN */ +/* OVERALL PACKING. ISKIPA REMOVED; */ +/* THERE IS ALWAYS A GROUP B THAT CAN */ +/* BECOME GROUP A. CONTROL ON SIZE */ +/* OF GROUP B (STATEMENT BELOW 150) */ +/* ADDED. ADDED ADDA, AND USE */ +/* OF GE AND LE INSTEAD OF GT AND LT */ +/* IN LOOPS BETWEEN 150 AND 160. */ +/* IBITBS ADDED TO SHORTEN TRIPS */ +/* THROUGH LOOP. */ +/* MARCH 2000 GLAHN MODIFIED FOR GRIB2; CHANGED NAME FROM */ +/* PACKGP */ +/* JANUARY 2001 GLAHN COMMENTS; IER = 706 SUBSTITUTED FOR */ +/* STOPS; ADDED RETURN1; REMOVED STATEMENT */ +/* NUMBER 110; ADDED IER AND * RETURN */ +/* NOVEMBER 2001 GLAHN CHANGED SOME DIAGNOSTIC FORMATS TO */ +/* ALLOW PRINTING LARGER NUMBERS */ +/* NOVEMBER 2001 GLAHN ADDED MISSLX( ) TO PUT MAXIMUM VALUE */ +/* INTO JMIN( ) WHEN ALL VALUES MISSING */ +/* TO AGREE WITH GRIB STANDARD. */ +/* NOVEMBER 2001 GLAHN CHANGED TWO TESTS ON MISSP AND MISSS */ +/* EQ 0 TO TESTS ON IS523. HOWEVER, */ +/* MISSP AND MISSS CANNOT IN GENERAL BE */ +/* = 0. */ +/* NOVEMBER 2001 GLAHN ADDED CALL TO REDUCE; DEFINED ITEST */ +/* BEFORE LOOPS TO REDUCE COMPUTATION; */ +/* STARTED LARGE GROUP WHEN ALL SAME */ +/* VALUE */ +/* DECEMBER 2001 GLAHN MODIFIED AND ADDED A FEW COMMENTS */ +/* JANUARY 2002 GLAHN REMOVED LOOP BEFORE 150 TO DETERMINE */ +/* A GROUP OF ALL SAME VALUE */ +/* JANUARY 2002 GLAHN CHANGED MALLOW FROM 9999999 TO 2**30+1, */ +/* AND MADE IT A PARAMETER */ +/* MARCH 2002 GLAHN ADDED NON FATAL IER = 716, 717; */ +/* REMOVED NENDB=NXY ABOVE 150; */ +/* ADDED IERSAV=0; COMMENTS */ + +/* PURPOSE */ +/* DETERMINES GROUPS OF VARIABLE SIZE, BUT AT LEAST OF */ +/* SIZE MINPK, THE ASSOCIATED MAX (JMAX( )) AND MIN (JMIN( )), */ +/* THE NUMBER OF BITS NECESSARY TO HOLD THE VALUES IN EACH */ +/* GROUP (LBIT( )), THE NUMBER OF VALUES IN EACH GROUP */ +/* (NOV( )), THE NUMBER OF BITS NECESSARY TO PACK THE JMIN( ) */ +/* VALUES (IBIT), THE NUMBER OF BITS NECESSARY TO PACK THE */ +/* LBIT( ) VALUES (JBIT), AND THE NUMBER OF BITS NECESSARY */ +/* TO PACK THE NOV( ) VALUES (KBIT). THE ROUTINE IS DESIGNED */ +/* TO DETERMINE THE GROUPS SUCH THAT A SMALL NUMBER OF BITS */ +/* IS NECESSARY TO PACK THE DATA WITHOUT EXCESSIVE */ +/* COMPUTATIONS. IF ALL VALUES IN THE GROUP ARE ZERO, THE */ +/* NUMBER OF BITS TO USE IN PACKING IS DEFINED AS ZERO WHEN */ +/* THERE CAN BE NO MISSING VALUES; WHEN THERE CAN BE MISSING */ +/* VALUES, THE NUMBER OF BITS MUST BE AT LEAST 1 TO HAVE */ +/* THE CAPABILITY TO RECOGNIZE THE MISSING VALUE. HOWEVER, */ +/* IF ALL VALUES IN A GROUP ARE MISSING, THE NUMBER OF BITS */ +/* NEEDED IS 0, AND THE UNPACKER RECOGNIZES THIS. */ +/* ALL VARIABLES ARE INTEGER. EVEN THOUGH THE GROUPS ARE */ +/* INITIALLY OF SIZE MINPK OR LARGER, AN ADJUSTMENT BETWEEN */ +/* TWO GROUPS (THE LOOKBACK PROCEDURE) MAY MAKE A GROUP */ +/* SMALLER THAN MINPK. THE CONTROL ON GROUP SIZE IS THAT */ +/* THE SUM OF THE SIZES OF THE TWO CONSECUTIVE GROUPS, EACH OF */ +/* SIZE MINPK OR LARGER, IS NOT DECREASED. WHEN DETERMINING */ +/* THE NUMBER OF BITS NECESSARY FOR PACKING, THE LARGEST */ +/* VALUE THAT CAN BE ACCOMMODATED IN, SAY, MBITS, IS */ +/* 2**MBITS-1; THIS LARGEST VALUE (AND THE NEXT SMALLEST */ +/* VALUE) IS RESERVED FOR THE MISSING VALUE INDICATOR (ONLY) */ +/* WHEN IS523 NE 0. IF THE DIMENSION NDG */ +/* IS NOT LARGE ENOUGH TO HOLD ALL THE GROUPS, THE LOCAL VALUE */ +/* OF MINPK IS INCREASED BY 50 PERCENT. THIS IS REPEATED */ +/* UNTIL NDG WILL SUFFICE. A DIAGNOSTIC IS PRINTED WHENEVER */ +/* THIS HAPPENS, WHICH SHOULD BE VERY RARELY. IF IT HAPPENS */ +/* OFTEN, NDG IN SUBROUTINE PACK SHOULD BE INCREASED AND */ +/* A CORRESPONDING INCREASE IN SUBROUTINE UNPACK MADE. */ +/* CONSIDERABLE CODE IS PROVIDED SO THAT NO MORE CHECKING */ +/* FOR MISSING VALUES WITHIN LOOPS IS DONE THAN NECESSARY; */ +/* THE ADDED EFFICIENCY OF THIS IS RELATIVELY MINOR, */ +/* BUT DOES NO HARM. FOR GRIB2, THE REFERENCE VALUE FOR */ +/* THE LENGTH OF GROUPS IN NOV( ) AND FOR THE NUMBER OF */ +/* BITS NECESSARY TO PACK GROUP VALUES ARE DETERMINED, */ +/* AND SUBTRACTED BEFORE JBIT AND KBIT ARE DETERMINED. */ + +/* WHEN 1 OR MORE GROUPS ARE LARGE COMPARED TO THE OTHERS, */ +/* THE WIDTH OF ALL GROUPS MUST BE AS LARGE AS THE LARGEST. */ +/* A SUBROUTINE REDUCE BREAKS UP LARGE GROUPS INTO 2 OR */ +/* MORE TO REDUCE TOTAL BITS REQUIRED. IF REDUCE SHOULD */ +/* ABORT, PACK_GP WILL BE EXECUTED AGAIN WITHOUT THE CALL */ +/* TO REDUCE. */ + +/* DATA SET USE */ +/* KFILDO - UNIT NUMBER FOR OUTPUT (PRINT) FILE. (OUTPUT) */ + +/* VARIABLES IN CALL SEQUENCE */ +/* KFILDO = UNIT NUMBER FOR OUTPUT (PRINT) FILE. (INPUT) */ +/* IC( ) = ARRAY TO HOLD DATA FOR PACKING. THE VALUES */ +/* DO NOT HAVE TO BE POSITIVE AT THIS POINT, BUT */ +/* MUST BE IN THE RANGE -2**30 TO +2**30 (THE */ +/* THE VALUE OF MALLOW). THESE INTEGER VALUES */ +/* WILL BE RETAINED EXACTLY THROUGH PACKING AND */ +/* UNPACKING. (INPUT) */ +/* NXY = NUMBER OF VALUES IN IC( ). ALSO TREATED */ +/* AS ITS DIMENSION. (INPUT) */ +/* IS523 = missing value management */ +/* 0=data contains no missing values */ +/* 1=data contains Primary missing values */ +/* 2=data contains Primary and secondary missing values */ +/* (INPUT) */ +/* MINPK = THE MINIMUM SIZE OF EACH GROUP, EXCEPT POSSIBLY */ +/* THE LAST ONE. (INPUT) */ +/* INC = THE NUMBER OF VALUES TO ADD TO AN ALREADY */ +/* EXISTING GROUP IN DETERMINING WHETHER OR NOT */ +/* TO START A NEW GROUP. IDEALLY, THIS WOULD BE */ +/* 1, BUT EACH TIME INC VALUES ARE ATTEMPTED, THE */ +/* MAX AND MIN OF THE NEXT MINPK VALUES MUST BE */ +/* FOUND. THIS IS "A LOOP WITHIN A LOOP," AND */ +/* A SLIGHTLY LARGER VALUE MAY GIVE ABOUT AS GOOD */ +/* RESULTS WITH SLIGHTLY LESS COMPUTATIONAL TIME. */ +/* IF INC IS LE 0, 1 IS USED, AND A DIAGNOSTIC IS */ +/* OUTPUT. NOTE: IT IS EXPECTED THAT INC WILL */ +/* EQUAL 1. THE CODE USES INC PRIMARILY IN THE */ +/* LOOPS STARTING AT STATEMENT 180. IF INC */ +/* WERE 1, THERE WOULD NOT NEED TO BE LOOPS */ +/* AS SUCH. HOWEVER, KINC (THE LOCAL VALUE OF */ +/* INC) IS SET GE 1 WHEN NEAR THE END OF THE DATA */ +/* TO FORESTALL A VERY SMALL GROUP AT THE END. */ +/* (INPUT) */ +/* MISSP = WHEN MISSING POINTS CAN BE PRESENT IN THE DATA, */ +/* THEY WILL HAVE THE VALUE MISSP OR MISSS. */ +/* MISSP IS THE PRIMARY MISSING VALUE AND MISSS */ +/* IS THE SECONDARY MISSING VALUE . THESE MUST */ +/* NOT BE VALUES THAT WOULD OCCUR WITH SUBTRACTING */ +/* THE MINIMUM (REFERENCE) VALUE OR SCALING. */ +/* FOR EXAMPLE, MISSP = 0 WOULD NOT BE ADVISABLE. */ +/* (INPUT) */ +/* MISSS = SECONDARY MISSING VALUE INDICATOR (SEE MISSP). */ +/* (INPUT) */ +/* JMIN(J) = THE MINIMUM OF EACH GROUP (J=1,LX). (OUTPUT) */ +/* JMAX(J) = THE MAXIMUM OF EACH GROUP (J=1,LX). THIS IS */ +/* NOT REALLY NEEDED, BUT SINCE THE MAX OF EACH */ +/* GROUP MUST BE FOUND, SAVING IT HERE IS CHEAP */ +/* IN CASE THE USER WANTS IT. (OUTPUT) */ +/* LBIT(J) = THE NUMBER OF BITS NECESSARY TO PACK EACH GROUP */ +/* (J=1,LX). IT IS ASSUMED THE MINIMUM OF EACH */ +/* GROUP WILL BE REMOVED BEFORE PACKING, AND THE */ +/* VALUES TO PACK WILL, THEREFORE, ALL BE POSITIVE. */ +/* HOWEVER, IC( ) DOES NOT NECESSARILY CONTAIN */ +/* ALL POSITIVE VALUES. IF THE OVERALL MINIMUM */ +/* HAS BEEN REMOVED (THE USUAL CASE), THEN IC( ) */ +/* WILL CONTAIN ONLY POSITIVE VALUES. (OUTPUT) */ +/* NOV(J) = THE NUMBER OF VALUES IN EACH GROUP (J=1,LX). */ +/* (OUTPUT) */ +/* NDG = THE DIMENSION OF JMIN( ), JMAX( ), LBIT( ), AND */ +/* NOV( ). (INPUT) */ +/* LX = THE NUMBER OF GROUPS DETERMINED. (OUTPUT) */ +/* IBIT = THE NUMBER OF BITS NECESSARY TO PACK THE JMIN(J) */ +/* VALUES, J=1,LX. (OUTPUT) */ +/* JBIT = THE NUMBER OF BITS NECESSARY TO PACK THE LBIT(J) */ +/* VALUES, J=1,LX. (OUTPUT) */ +/* KBIT = THE NUMBER OF BITS NECESSARY TO PACK THE NOV(J) */ +/* VALUES, J=1,LX. (OUTPUT) */ +/* NOVREF = REFERENCE VALUE FOR NOV( ). (OUTPUT) */ +/* LBITREF = REFERENCE VALUE FOR LBIT( ). (OUTPUT) */ +/* IER = ERROR RETURN. */ +/* 706 = VALUE WILL NOT PACK IN 30 BITS--FATAL */ +/* 714 = ERROR IN REDUCE--NON-FATAL */ +/* 715 = NGP NOT LARGE ENOUGH IN REDUCE--NON-FATAL */ +/* 716 = MINPK INCEASED--NON-FATAL */ +/* 717 = INC SET = 1--NON-FATAL */ +/* (OUTPUT) */ +/* * = ALTERNATE RETURN WHEN IER NE 0 AND FATAL ERROR. */ + +/* INTERNAL VARIABLES */ +/* CFEED = CONTAINS THE CHARACTER REPRESENTATION */ +/* OF A PRINTER FORM FEED. */ +/* IFEED = CONTAINS THE INTEGER VALUE OF A PRINTER */ +/* FORM FEED. */ +/* KINC = WORKING COPY OF INC. MAY BE MODIFIED. */ +/* MINA = MINIMUM VALUE IN GROUP A. */ +/* MAXA = MAXIMUM VALUE IN GROUP A. */ +/* NENDA = THE PLACE IN IC( ) WHERE GROUP A ENDS. */ +/* KSTART = THE PLACE IN IC( ) WHERE GROUP A STARTS. */ +/* IBITA = NUMBER OF BITS NEEDED TO HOLD VALUES IN GROUP A. */ +/* MINB = MINIMUM VALUE IN GROUP B. */ +/* MAXB = MAXIMUM VALUE IN GROUP B. */ +/* NENDB = THE PLACE IN IC( ) WHERE GROUP B ENDS. */ +/* IBITB = NUMBER OF BITS NEEDED TO HOLD VALUES IN GROUP B. */ +/* MINC = MINIMUM VALUE IN GROUP C. */ +/* MAXC = MAXIMUM VALUE IN GROUP C. */ +/* KTOTAL = COUNT OF NUMBER OF VALUES IN IC( ) PROCESSED. */ +/* NOUNT = NUMBER OF VALUES ADDED TO GROUP A. */ +/* LMISS = 0 WHEN IS523 = 0. WHEN PACKING INTO A */ +/* SPECIFIC NUMBER OF BITS, SAY MBITS, */ +/* THE MAXIMUM VALUE THAT CAN BE HANDLED IS */ +/* 2**MBITS-1. WHEN IS523 = 1, INDICATING */ +/* PRIMARY MISSING VALUES, THIS MAXIMUM VALUE */ +/* IS RESERVED TO HOLD THE PRIMARY MISSING VALUE */ +/* INDICATOR AND LMISS = 1. WHEN IS523 = 2, */ +/* THE VALUE JUST BELOW THE MAXIMUM (I.E., */ +/* 2**MBITS-2) IS RESERVED TO HOLD THE SECONDARY */ +/* MISSING VALUE INDICATOR AND LMISS = 2. */ +/* LMINPK = LOCAL VALUE OF MINPK. THIS WILL BE ADJUSTED */ +/* UPWARD WHENEVER NDG IS NOT LARGE ENOUGH TO HOLD */ +/* ALL THE GROUPS. */ +/* MALLOW = THE LARGEST ALLOWABLE VALUE FOR PACKING. */ +/* MISLLA = SET TO 1 WHEN ALL VALUES IN GROUP A ARE MISSING. */ +/* THIS IS USED TO DISTINGUISH BETWEEN A REAL */ +/* MINIMUM WHEN ALL VALUES ARE NOT MISSING */ +/* AND A MINIMUM THAT HAS BEEN SET TO ZERO WHEN */ +/* ALL VALUES ARE MISSING. 0 OTHERWISE. */ +/* NOTE THAT THIS DOES NOT DISTINGUISH BETWEEN */ +/* PRIMARY AND SECONDARY MISSINGS WHEN SECONDARY */ +/* MISSINGS ARE PRESENT. THIS MEANS THAT */ +/* LBIT( ) WILL NOT BE ZERO WITH THE RESULTING */ +/* COMPRESSION EFFICIENCY WHEN SECONDARY MISSINGS */ +/* ARE PRESENT. ALSO NOTE THAT A CHECK HAS BEEN */ +/* MADE EARLIER TO DETERMINE THAT SECONDARY */ +/* MISSINGS ARE REALLY THERE. */ +/* MISLLB = SET TO 1 WHEN ALL VALUES IN GROUP B ARE MISSING. */ +/* THIS IS USED TO DISTINGUISH BETWEEN A REAL */ +/* MINIMUM WHEN ALL VALUES ARE NOT MISSING */ +/* AND A MINIMUM THAT HAS BEEN SET TO ZERO WHEN */ +/* ALL VALUES ARE MISSING. 0 OTHERWISE. */ +/* MISLLC = PERFORMS THE SAME FUNCTION FOR GROUP C THAT */ +/* MISLLA AND MISLLB DO FOR GROUPS B AND C, */ +/* RESPECTIVELY. */ +/* IBXX2(J) = AN ARRAY THAT WHEN THIS ROUTINE IS FIRST ENTERED */ +/* IS SET TO 2**J, J=0,30. IBXX2(30) = 2**30, WHICH */ +/* IS THE LARGEST VALUE PACKABLE, BECAUSE 2**31 */ +/* IS LARGER THAN THE INTEGER WORD SIZE. */ +/* IFIRST = SET BY DATA STATEMENT TO 0. CHANGED TO 1 ON */ +/* FIRST */ +/* ENTRY WHEN IBXX2( ) IS FILLED. */ +/* MINAK = KEEPS TRACK OF THE LOCATION IN IC( ) WHERE THE */ +/* MINIMUM VALUE IN GROUP A IS LOCATED. */ +/* MAXAK = DOES THE SAME AS MINAK, EXCEPT FOR THE MAXIMUM. */ +/* MINBK = THE SAME AS MINAK FOR GROUP B. */ +/* MAXBK = THE SAME AS MAXAK FOR GROUP B. */ +/* MINCK = THE SAME AS MINAK FOR GROUP C. */ +/* MAXCK = THE SAME AS MAXAK FOR GROUP C. */ +/* ADDA = KEEPS TRACK WHETHER OR NOT AN ATTEMPT TO ADD */ +/* POINTS TO GROUP A WAS MADE. IF SO, THEN ADDA */ +/* KEEPS FROM TRYING TO PUT ONE BACK INTO B. */ +/* (LOGICAL) */ +/* IBITBS = KEEPS CURRENT VALUE IF IBITB SO THAT LOOP */ +/* ENDING AT 166 DOESN'T HAVE TO START AT */ +/* IBITB = 0 EVERY TIME. */ +/* MISSLX(J) = MALLOW EXCEPT WHEN A GROUP IS ALL ONE VALUE (AND */ +/* LBIT(J) = 0) AND THAT VALUE IS MISSING. IN */ +/* THAT CASE, MISSLX(J) IS MISSP OR MISSS. THIS */ +/* GETS INSERTED INTO JMIN(J) LATER AS THE */ +/* MISSING INDICATOR; IT CAN'T BE PUT IN UNTIL */ +/* THE END, BECAUSE JMIN( ) IS USED TO CALCULATE */ +/* THE MAXIMUM NUMBER OF BITS (IBITS) NEEDED TO */ +/* PACK JMIN( ). */ +/* 1 2 3 4 5 6 7 X */ + +/* NON SYSTEM SUBROUTINES CALLED */ +/* NONE */ + + + +/* MISSLX( ) was AN AUTOMATIC ARRAY. */ + misslx = (integer *)calloc(*ndg,sizeof(integer)); + + + /* Parameter adjustments */ + --ic; + --nov; + --lbit; + --jmax; + --jmin; + + /* Function Body */ + + *ier = 0; + iersav = 0; +/* CALL TIMPR(KFILDO,KFILDO,'START PACK_GP ') */ + *(unsigned char *)cfeed = (char) ifeed; + + ired = 0; +/* IRED IS A FLAG. WHEN ZERO, REDUCE WILL BE CALLED. */ +/* IF REDUCE ABORTS, IRED = 1 AND IS NOT CALLED. IN */ +/* THIS CASE PACK_GP EXECUTES AGAIN EXCEPT FOR REDUCE. */ + + if (*inc <= 0) { + iersav = 717; +/* WRITE(KFILDO,101)INC */ +/* 101 FORMAT(/' ****INC ='I8,' NOT CORRECT IN PACK_GP. 1 IS USED.') */ + } + +/* THERE WILL BE A RESTART OF PACK_GP IF SUBROUTINE REDUCE */ +/* ABORTS. THIS SHOULD NOT HAPPEN, BUT IF IT DOES, PACK_GP */ +/* WILL COMPLETE WITHOUT SUBROUTINE REDUCE. A NON FATAL */ +/* DIAGNOSTIC RETURN IS PROVIDED. */ + +L102: + /*kinc = max(*inc,1);*/ + kinc = (*inc > 1) ? *inc : 1; + lminpk = *minpk; + +/* CALCULATE THE POWERS OF 2 THE FIRST TIME ENTERED. */ + + if (ifirst == 0) { + ifirst = 1; + ibxx2[0] = 1; + + for (j = 1; j <= 30; ++j) { + ibxx2[j] = ibxx2[j - 1] << 1; +/* L104: */ + } + + } + +/* THERE WILL BE A RESTART AT 105 IS NDG IS NOT LARGE ENOUGH. */ +/* A NON FATAL DIAGNOSTIC RETURN IS PROVIDED. */ + +L105: + kstart = 1; + ktotal = 0; + *lx = 0; + adda = FALSE_; + lmiss = 0; + if (*is523 == 1) { + lmiss = 1; + } + if (*is523 == 2) { + lmiss = 2; + } + +/* ************************************* */ + +/* THIS SECTION COMPUTES STATISTICS FOR GROUP A. GROUP A IS */ +/* A GROUP OF SIZE LMINPK. */ + +/* ************************************* */ + + ibita = 0; + mina = mallow; + maxa = -mallow; + minak = mallow; + maxak = -mallow; + +/* FIND THE MIN AND MAX OF GROUP A. THIS WILL INITIALLY BE OF */ +/* SIZE LMINPK (IF THERE ARE STILL LMINPK VALUES IN IC( )), BUT */ +/* WILL INCREASE IN SIZE IN INCREMENTS OF INC UNTIL A NEW */ +/* GROUP IS STARTED. THE DEFINITION OF GROUP A IS DONE HERE */ +/* ONLY ONCE (UPON INITIAL ENTRY), BECAUSE A GROUP B CAN ALWAYS */ +/* BECOME A NEW GROUP A AFTER A IS PACKED, EXCEPT IF LMINPK */ +/* HAS TO BE INCREASED BECAUSE NDG IS TOO SMALL. THEREFORE, */ +/* THE SEPARATE LOOPS FOR MISSING AND NON-MISSING HERE BUYS */ +/* ALMOST NOTHING. */ + +/* Computing MIN */ + i__1 = kstart + lminpk - 1; + /*nenda = min(i__1,*nxy);*/ + nenda = (i__1 < *nxy) ? i__1 : *nxy; + if (*nxy - nenda <= lminpk / 2) { + nenda = *nxy; + } +/* ABOVE STATEMENT GUARANTEES THE LAST GROUP IS GT LMINPK/2 BY */ +/* MAKING THE ACTUAL GROUP LARGER. IF A PROVISION LIKE THIS IS */ +/* NOT INCLUDED, THERE WILL MANY TIMES BE A VERY SMALL GROUP */ +/* AT THE END. USE SEPARATE LOOPS FOR MISSING AND NO MISSING */ +/* VALUES FOR EFFICIENCY. */ + +/* DETERMINE WHETHER THERE IS A LONG STRING OF THE SAME VALUE */ +/* UNLESS NENDA = NXY. THIS MAY ALLOW A LARGE GROUP A TO */ +/* START WITH, AS WITH MISSING VALUES. SEPARATE LOOPS FOR */ +/* MISSING OPTIONS. THIS SECTION IS ONLY EXECUTED ONCE, */ +/* IN DETERMINING THE FIRST GROUP. IT HELPS FOR AN ARRAY */ +/* OF MOSTLY MISSING VALUES OR OF ONE VALUE, SUCH AS */ +/* RADAR OR PRECIP DATA. */ + + if (nenda != *nxy && ic[kstart] == ic[kstart + 1]) { +/* NO NEED TO EXECUTE IF FIRST TWO VALUES ARE NOT EQUAL. */ + + if (*is523 == 0) { +/* THIS LOOP IS FOR NO MISSING VALUES. */ + + i__1 = *nxy; + for (k = kstart + 1; k <= i__1; ++k) { + + if (ic[k] != ic[kstart]) { +/* Computing MAX */ + i__2 = nenda, i__3 = k - 1; + /*nenda = max(i__2,i__3);*/ + nenda = (i__2 > i__3) ? i__2 : i__3; + goto L114; + } + +/* L111: */ + } + + nenda = *nxy; +/* FALL THROUGH THE LOOP MEANS ALL VALUES ARE THE SAME. */ + + } else if (*is523 == 1) { +/* THIS LOOP IS FOR PRIMARY MISSING VALUES ONLY. */ + + i__1 = *nxy; + for (k = kstart + 1; k <= i__1; ++k) { + + if (ic[k] != *missp) { + + if (ic[k] != ic[kstart]) { +/* Computing MAX */ + i__2 = nenda, i__3 = k - 1; + /*nenda = max(i__2,i__3);*/ + nenda = (i__2 > i__3) ? i__2 : i__3; + goto L114; + } + + } + +/* L112: */ + } + + nenda = *nxy; +/* FALL THROUGH THE LOOP MEANS ALL VALUES ARE THE SAME. */ + + } else { +/* THIS LOOP IS FOR PRIMARY AND SECONDARY MISSING VALUES. */ + + i__1 = *nxy; + for (k = kstart + 1; k <= i__1; ++k) { + + if (ic[k] != *missp && ic[k] != *misss) { + + if (ic[k] != ic[kstart]) { +/* Computing MAX */ + i__2 = nenda, i__3 = k - 1; + /*nenda = max(i__2,i__3);*/ + nenda = (i__2 > i__3) ? i__2 : i__3; + goto L114; + } + + } + +/* L113: */ + } + + nenda = *nxy; +/* FALL THROUGH THE LOOP MEANS ALL VALUES ARE THE SAME. */ + } + + } + +L114: + if (*is523 == 0) { + + i__1 = nenda; + for (k = kstart; k <= i__1; ++k) { + if (ic[k] < mina) { + mina = ic[k]; + minak = k; + } + if (ic[k] > maxa) { + maxa = ic[k]; + maxak = k; + } +/* L115: */ + } + + } else if (*is523 == 1) { + + i__1 = nenda; + for (k = kstart; k <= i__1; ++k) { + if (ic[k] == *missp) { + goto L117; + } + if (ic[k] < mina) { + mina = ic[k]; + minak = k; + } + if (ic[k] > maxa) { + maxa = ic[k]; + maxak = k; + } +L117: + ; + } + + } else { + + i__1 = nenda; + for (k = kstart; k <= i__1; ++k) { + if (ic[k] == *missp || ic[k] == *misss) { + goto L120; + } + if (ic[k] < mina) { + mina = ic[k]; + minak = k; + } + if (ic[k] > maxa) { + maxa = ic[k]; + maxak = k; + } +L120: + ; + } + + } + + kounta = nenda - kstart + 1; + +/* INCREMENT KTOTAL AND FIND THE BITS NEEDED TO PACK THE A GROUP. */ + + ktotal += kounta; + mislla = 0; + if (mina != mallow) { + goto L125; + } +/* ALL MISSING VALUES MUST BE ACCOMMODATED. */ + mina = 0; + maxa = 0; + mislla = 1; + ibitb = 0; + if (*is523 != 2) { + goto L130; + } +/* WHEN ALL VALUES ARE MISSING AND THERE ARE NO */ +/* SECONDARY MISSING VALUES, IBITA = 0. */ +/* OTHERWISE, IBITA MUST BE CALCULATED. */ + +L125: + itest = maxa - mina + lmiss; + + for (ibita = 0; ibita <= 30; ++ibita) { + if (itest < ibxx2[ibita]) { + goto L130; + } +/* *** THIS TEST IS THE SAME AS: */ +/* *** IF(MAXA-MINA.LT.IBXX2(IBITA)-LMISS)GO TO 130 */ +/* L126: */ + } + +/* WRITE(KFILDO,127)MAXA,MINA */ +/* 127 FORMAT(' ****ERROR IN PACK_GP. VALUE WILL NOT PACK IN 30 BITS.', */ +/* 1 ' MAXA ='I13,' MINA ='I13,'. ERROR AT 127.') */ + *ier = 706; + goto L900; + +L130: + +/* ***D WRITE(KFILDO,131)KOUNTA,KTOTAL,MINA,MAXA,IBITA,MISLLA */ +/* ***D131 FORMAT(' AT 130, KOUNTA ='I8,' KTOTAL ='I8,' MINA ='I8, */ +/* ***D 1 ' MAXA ='I8,' IBITA ='I3,' MISLLA ='I3) */ + +L133: + if (ktotal >= *nxy) { + goto L200; + } + +/* ************************************* */ + +/* THIS SECTION COMPUTES STATISTICS FOR GROUP B. GROUP B IS A */ +/* GROUP OF SIZE LMINPK IMMEDIATELY FOLLOWING GROUP A. */ + +/* ************************************* */ + +L140: + minb = mallow; + maxb = -mallow; + minbk = mallow; + maxbk = -mallow; + ibitbs = 0; + mstart = ktotal + 1; + +/* DETERMINE WHETHER THERE IS A LONG STRING OF THE SAME VALUE. */ +/* THIS WORKS WHEN THERE ARE NO MISSING VALUES. */ + + nendb = 1; + + if (mstart < *nxy) { + + if (*is523 == 0) { +/* THIS LOOP IS FOR NO MISSING VALUES. */ + + i__1 = *nxy; + for (k = mstart + 1; k <= i__1; ++k) { + + if (ic[k] != ic[mstart]) { + nendb = k - 1; + goto L150; + } + +/* L145: */ + } + + nendb = *nxy; +/* FALL THROUGH THE LOOP MEANS ALL REMAINING VALUES */ +/* ARE THE SAME. */ + } + + } + +L150: +/* Computing MAX */ +/* Computing MIN */ + i__3 = ktotal + lminpk; + /*i__1 = nendb, i__2 = min(i__3,*nxy);*/ + i__1 = nendb, i__2 = (i__3 < *nxy) ? i__3 : *nxy; + /*nendb = max(i__1,i__2);*/ + nendb = (i__1 > i__2) ? i__1 : i__2; +/* **** 150 NENDB=MIN(KTOTAL+LMINPK,NXY) */ + + if (*nxy - nendb <= lminpk / 2) { + nendb = *nxy; + } +/* ABOVE STATEMENT GUARANTEES THE LAST GROUP IS GT LMINPK/2 BY */ +/* MAKING THE ACTUAL GROUP LARGER. IF A PROVISION LIKE THIS IS */ +/* NOT INCLUDED, THERE WILL MANY TIMES BE A VERY SMALL GROUP */ +/* AT THE END. USE SEPARATE LOOPS FOR MISSING AND NO MISSING */ + +/* USE SEPARATE LOOPS FOR MISSING AND NO MISSING VALUES */ +/* FOR EFFICIENCY. */ + + if (*is523 == 0) { + + i__1 = nendb; + for (k = mstart; k <= i__1; ++k) { + if (ic[k] <= minb) { + minb = ic[k]; +/* NOTE LE, NOT LT. LT COULD BE USED BUT THEN A */ +/* RECOMPUTE OVER THE WHOLE GROUP WOULD BE NEEDED */ +/* MORE OFTEN. SAME REASONING FOR GE AND OTHER */ +/* LOOPS BELOW. */ + minbk = k; + } + if (ic[k] >= maxb) { + maxb = ic[k]; + maxbk = k; + } +/* L155: */ + } + + } else if (*is523 == 1) { + + i__1 = nendb; + for (k = mstart; k <= i__1; ++k) { + if (ic[k] == *missp) { + goto L157; + } + if (ic[k] <= minb) { + minb = ic[k]; + minbk = k; + } + if (ic[k] >= maxb) { + maxb = ic[k]; + maxbk = k; + } +L157: + ; + } + + } else { + + i__1 = nendb; + for (k = mstart; k <= i__1; ++k) { + if (ic[k] == *missp || ic[k] == *misss) { + goto L160; + } + if (ic[k] <= minb) { + minb = ic[k]; + minbk = k; + } + if (ic[k] >= maxb) { + maxb = ic[k]; + maxbk = k; + } +L160: + ; + } + + } + + kountb = nendb - ktotal; + misllb = 0; + if (minb != mallow) { + goto L165; + } +/* ALL MISSING VALUES MUST BE ACCOMMODATED. */ + minb = 0; + maxb = 0; + misllb = 1; + ibitb = 0; + + if (*is523 != 2) { + goto L170; + } +/* WHEN ALL VALUES ARE MISSING AND THERE ARE NO SECONDARY */ +/* MISSING VALUES, IBITB = 0. OTHERWISE, IBITB MUST BE */ +/* CALCULATED. */ + +L165: + for (ibitb = ibitbs; ibitb <= 30; ++ibitb) { + if (maxb - minb < ibxx2[ibitb] - lmiss) { + goto L170; + } +/* L166: */ + } + +/* WRITE(KFILDO,167)MAXB,MINB */ +/* 167 FORMAT(' ****ERROR IN PACK_GP. VALUE WILL NOT PACK IN 30 BITS.', */ +/* 1 ' MAXB ='I13,' MINB ='I13,'. ERROR AT 167.') */ + *ier = 706; + goto L900; + +/* COMPARE THE BITS NEEDED TO PACK GROUP B WITH THOSE NEEDED */ +/* TO PACK GROUP A. IF IBITB GE IBITA, TRY TO ADD TO GROUP A. */ +/* IF NOT, TRY TO ADD A'S POINTS TO B, UNLESS ADDITION TO A */ +/* HAS BEEN DONE. THIS LATTER IS CONTROLLED WITH ADDA. */ + +L170: + +/* ***D WRITE(KFILDO,171)KOUNTA,KTOTAL,MINA,MAXA,IBITA,MISLLA, */ +/* ***D 1 MINB,MAXB,IBITB,MISLLB */ +/* ***D171 FORMAT(' AT 171, KOUNTA ='I8,' KTOTAL ='I8,' MINA ='I8, */ +/* ***D 1 ' MAXA ='I8,' IBITA ='I3,' MISLLA ='I3, */ +/* ***D 2 ' MINB ='I8,' MAXB ='I8,' IBITB ='I3,' MISLLB ='I3) */ + + if (ibitb >= ibita) { + goto L180; + } + if (adda) { + goto L200; + } + +/* ************************************* */ + +/* GROUP B REQUIRES LESS BITS THAN GROUP A. PUT AS MANY OF A'S */ +/* POINTS INTO B AS POSSIBLE WITHOUT EXCEEDING THE NUMBER OF */ +/* BITS NECESSARY TO PACK GROUP B. */ + +/* ************************************* */ + + kounts = kounta; +/* KOUNTA REFERS TO THE PRESENT GROUP A. */ + mintst = minb; + maxtst = maxb; + mintstk = minbk; + maxtstk = maxbk; + +/* USE SEPARATE LOOPS FOR MISSING AND NO MISSING VALUES */ +/* FOR EFFICIENCY. */ + + if (*is523 == 0) { + + i__1 = kstart; + for (k = ktotal; k >= i__1; --k) { +/* START WITH THE END OF THE GROUP AND WORK BACKWARDS. */ + if (ic[k] < minb) { + mintst = ic[k]; + mintstk = k; + } else if (ic[k] > maxb) { + maxtst = ic[k]; + maxtstk = k; + } + if (maxtst - mintst >= ibxx2[ibitb]) { + goto L174; + } +/* NOTE THAT FOR THIS LOOP, LMISS = 0. */ + minb = mintst; + maxb = maxtst; + minbk = mintstk; + maxbk = maxtstk; + --kounta; +/* THERE IS ONE LESS POINT NOW IN A. */ +/* L1715: */ + } + + } else if (*is523 == 1) { + + i__1 = kstart; + for (k = ktotal; k >= i__1; --k) { +/* START WITH THE END OF THE GROUP AND WORK BACKWARDS. */ + if (ic[k] == *missp) { + goto L1718; + } + if (ic[k] < minb) { + mintst = ic[k]; + mintstk = k; + } else if (ic[k] > maxb) { + maxtst = ic[k]; + maxtstk = k; + } + if (maxtst - mintst >= ibxx2[ibitb] - lmiss) { + goto L174; + } +/* FOR THIS LOOP, LMISS = 1. */ + minb = mintst; + maxb = maxtst; + minbk = mintstk; + maxbk = maxtstk; + misllb = 0; +/* WHEN THE POINT IS NON MISSING, MISLLB SET = 0. */ +L1718: + --kounta; +/* THERE IS ONE LESS POINT NOW IN A. */ +/* L1719: */ + } + + } else { + + i__1 = kstart; + for (k = ktotal; k >= i__1; --k) { +/* START WITH THE END OF THE GROUP AND WORK BACKWARDS. */ + if (ic[k] == *missp || ic[k] == *misss) { + goto L1729; + } + if (ic[k] < minb) { + mintst = ic[k]; + mintstk = k; + } else if (ic[k] > maxb) { + maxtst = ic[k]; + maxtstk = k; + } + if (maxtst - mintst >= ibxx2[ibitb] - lmiss) { + goto L174; + } +/* FOR THIS LOOP, LMISS = 2. */ + minb = mintst; + maxb = maxtst; + minbk = mintstk; + maxbk = maxtstk; + misllb = 0; +/* WHEN THE POINT IS NON MISSING, MISLLB SET = 0. */ +L1729: + --kounta; +/* THERE IS ONE LESS POINT NOW IN A. */ +/* L173: */ + } + + } + +/* AT THIS POINT, KOUNTA CONTAINS THE NUMBER OF POINTS TO CLOSE */ +/* OUT GROUP A WITH. GROUP B NOW STARTS WITH KSTART+KOUNTA AND */ +/* ENDS WITH NENDB. MINB AND MAXB HAVE BEEN ADJUSTED AS */ +/* NECESSARY TO REFLECT GROUP B (EVEN THOUGH THE NUMBER OF BITS */ +/* NEEDED TO PACK GROUP B HAVE NOT INCREASED, THE END POINTS */ +/* OF THE RANGE MAY HAVE). */ + +L174: + if (kounta == kounts) { + goto L200; + } +/* ON TRANSFER, GROUP A WAS NOT CHANGED. CLOSE IT OUT. */ + +/* ONE OR MORE POINTS WERE TAKEN OUT OF A. RANGE AND IBITA */ +/* MAY HAVE TO BE RECOMPUTED; IBITA COULD BE LESS THAN */ +/* ORIGINALLY COMPUTED. IN FACT, GROUP A CAN NOW CONTAIN */ +/* ONLY ONE POINT AND BE PACKED WITH ZERO BITS */ +/* (UNLESS MISSS NE 0). */ + + nouta = kounts - kounta; + ktotal -= nouta; + kountb += nouta; + if (nenda - nouta > minak && nenda - nouta > maxak) { + goto L200; + } +/* WHEN THE ABOVE TEST IS MET, THE MIN AND MAX OF THE */ +/* CURRENT GROUP A WERE WITHIN THE OLD GROUP A, SO THE */ +/* RANGE AND IBITA DO NOT NEED TO BE RECOMPUTED. */ +/* NOTE THAT MINAK AND MAXAK ARE NO LONGER NEEDED. */ + ibita = 0; + mina = mallow; + maxa = -mallow; + +/* USE SEPARATE LOOPS FOR MISSING AND NO MISSING VALUES */ +/* FOR EFFICIENCY. */ + + if (*is523 == 0) { + + i__1 = nenda - nouta; + for (k = kstart; k <= i__1; ++k) { + if (ic[k] < mina) { + mina = ic[k]; + } + if (ic[k] > maxa) { + maxa = ic[k]; + } +/* L1742: */ + } + + } else if (*is523 == 1) { + + i__1 = nenda - nouta; + for (k = kstart; k <= i__1; ++k) { + if (ic[k] == *missp) { + goto L1744; + } + if (ic[k] < mina) { + mina = ic[k]; + } + if (ic[k] > maxa) { + maxa = ic[k]; + } +L1744: + ; + } + + } else { + + i__1 = nenda - nouta; + for (k = kstart; k <= i__1; ++k) { + if (ic[k] == *missp || ic[k] == *misss) { + goto L175; + } + if (ic[k] < mina) { + mina = ic[k]; + } + if (ic[k] > maxa) { + maxa = ic[k]; + } +L175: + ; + } + + } + + mislla = 0; + if (mina != mallow) { + goto L1750; + } +/* ALL MISSING VALUES MUST BE ACCOMMODATED. */ + mina = 0; + maxa = 0; + mislla = 1; + if (*is523 != 2) { + goto L177; + } +/* WHEN ALL VALUES ARE MISSING AND THERE ARE NO SECONDARY */ +/* MISSING VALUES IBITA = 0 AS ORIGINALLY SET. OTHERWISE, */ +/* IBITA MUST BE CALCULATED. */ + +L1750: + itest = maxa - mina + lmiss; + + for (ibita = 0; ibita <= 30; ++ibita) { + if (itest < ibxx2[ibita]) { + goto L177; + } +/* *** THIS TEST IS THE SAME AS: */ +/* *** IF(MAXA-MINA.LT.IBXX2(IBITA)-LMISS)GO TO 177 */ +/* L176: */ + } + +/* WRITE(KFILDO,1760)MAXA,MINA */ +/* 1760 FORMAT(' ****ERROR IN PACK_GP. VALUE WILL NOT PACK IN 30 BITS.', */ +/* 1 ' MAXA ='I13,' MINA ='I13,'. ERROR AT 1760.') */ + *ier = 706; + goto L900; + +L177: + goto L200; + +/* ************************************* */ + +/* AT THIS POINT, GROUP B REQUIRES AS MANY BITS TO PACK AS GROUPA. */ +/* THEREFORE, TRY TO ADD INC POINTS TO GROUP A WITHOUT INCREASING */ +/* IBITA. THIS AUGMENTED GROUP IS CALLED GROUP C. */ + +/* ************************************* */ + +L180: + if (mislla == 1) { + minc = mallow; + minck = mallow; + maxc = -mallow; + maxck = -mallow; + } else { + minc = mina; + maxc = maxa; + minck = minak; + maxck = minak; + } + + nount = 0; + if (*nxy - (ktotal + kinc) <= lminpk / 2) { + kinc = *nxy - ktotal; + } +/* ABOVE STATEMENT CONSTRAINS THE LAST GROUP TO BE NOT LESS THAN */ +/* LMINPK/2 IN SIZE. IF A PROVISION LIKE THIS IS NOT INCLUDED, */ +/* THERE WILL MANY TIMES BE A VERY SMALL GROUP AT THE END. */ + +/* USE SEPARATE LOOPS FOR MISSING AND NO MISSING VALUES */ +/* FOR EFFICIENCY. SINCE KINC IS USUALLY 1, USING SEPARATE */ +/* LOOPS HERE DOESN'T BUY MUCH. A MISSING VALUE WILL ALWAYS */ +/* TRANSFER BACK TO GROUP A. */ + + if (*is523 == 0) { + +/* Computing MIN */ + i__2 = ktotal + kinc; + /*i__1 = min(i__2,*nxy);*/ + i__1 = (i__2 < *nxy) ? i__2 : *nxy; + for (k = ktotal + 1; k <= i__1; ++k) { + if (ic[k] < minc) { + minc = ic[k]; + minck = k; + } + if (ic[k] > maxc) { + maxc = ic[k]; + maxck = k; + } + ++nount; +/* L185: */ + } + + } else if (*is523 == 1) { + +/* Computing MIN */ + i__2 = ktotal + kinc; + /*i__1 = min(i__2,*nxy);*/ + i__1 = (i__2 < *nxy) ? i__2 : *nxy; + for (k = ktotal + 1; k <= i__1; ++k) { + if (ic[k] == *missp) { + goto L186; + } + if (ic[k] < minc) { + minc = ic[k]; + minck = k; + } + if (ic[k] > maxc) { + maxc = ic[k]; + maxck = k; + } +L186: + ++nount; +/* L187: */ + } + + } else { + +/* Computing MIN */ + i__2 = ktotal + kinc; + /*i__1 = min(i__2,*nxy);*/ + i__1 = (i__2 < *nxy) ? i__2 : *nxy; + for (k = ktotal + 1; k <= i__1; ++k) { + if (ic[k] == *missp || ic[k] == *misss) { + goto L189; + } + if (ic[k] < minc) { + minc = ic[k]; + minck = k; + } + if (ic[k] > maxc) { + maxc = ic[k]; + maxck = k; + } +L189: + ++nount; +/* L190: */ + } + + } + +/* ***D WRITE(KFILDO,191)KOUNTA,KTOTAL,MINA,MAXA,IBITA,MISLLA, */ +/* ***D 1 MINC,MAXC,NOUNT,IC(KTOTAL),IC(KTOTAL+1) */ +/* ***D191 FORMAT(' AT 191, KOUNTA ='I8,' KTOTAL ='I8,' MINA ='I8, */ +/* ***D 1 ' MAXA ='I8,' IBITA ='I3,' MISLLA ='I3, */ +/* ***D 2 ' MINC ='I8,' MAXC ='I8, */ +/* ***D 3 ' NOUNT ='I5,' IC(KTOTAL) ='I9,' IC(KTOTAL+1) =',I9) */ + +/* IF THE NUMBER OF BITS NEEDED FOR GROUP C IS GT IBITA, */ +/* THEN THIS GROUP A IS A GROUP TO PACK. */ + + if (minc == mallow) { + minc = mina; + maxc = maxa; + minck = minak; + maxck = maxak; + misllc = 1; + goto L195; +/* WHEN THE NEW VALUE(S) ARE MISSING, THEY CAN ALWAYS */ +/* BE ADDED. */ + + } else { + misllc = 0; + } + + if (maxc - minc >= ibxx2[ibita] - lmiss) { + goto L200; + } + +/* THE BITS NECESSARY FOR GROUP C HAS NOT INCREASED FROM THE */ +/* BITS NECESSARY FOR GROUP A. ADD THIS POINT(S) TO GROUP A. */ +/* COMPUTE THE NEXT GROUP B, ETC., UNLESS ALL POINTS HAVE BEEN */ +/* USED. */ + +L195: + ktotal += nount; + kounta += nount; + mina = minc; + maxa = maxc; + minak = minck; + maxak = maxck; + mislla = misllc; + adda = TRUE_; + if (ktotal >= *nxy) { + goto L200; + } + + if (minbk > ktotal && maxbk > ktotal) { + mstart = nendb + 1; +/* THE MAX AND MIN OF GROUP B WERE NOT FROM THE POINTS */ +/* REMOVED, SO THE WHOLE GROUP DOES NOT HAVE TO BE LOOKED */ +/* AT TO DETERMINE THE NEW MAX AND MIN. RATHER START */ +/* JUST BEYOND THE OLD NENDB. */ + ibitbs = ibitb; + nendb = 1; + goto L150; + } else { + goto L140; + } + +/* ************************************* */ + +/* GROUP A IS TO BE PACKED. STORE VALUES IN JMIN( ), JMAX( ), */ +/* LBIT( ), AND NOV( ). */ + +/* ************************************* */ + +L200: + ++(*lx); + if (*lx <= *ndg) { + goto L205; + } + lminpk += lminpk / 2; +/* WRITE(KFILDO,201)NDG,LMINPK,LX */ +/* 201 FORMAT(' ****NDG ='I5,' NOT LARGE ENOUGH.', */ +/* 1 ' LMINPK IS INCREASED TO 'I3,' FOR THIS FIELD.'/ */ +/* 2 ' LX = 'I10) */ + iersav = 716; + goto L105; + +L205: + jmin[*lx] = mina; + jmax[*lx] = maxa; + lbit[*lx] = ibita; + nov[*lx] = kounta; + kstart = ktotal + 1; + + if (mislla == 0) { + misslx[*lx - 1] = mallow; + } else { + misslx[*lx - 1] = ic[ktotal]; +/* IC(KTOTAL) WAS THE LAST VALUE PROCESSED. IF MISLLA NE 0, */ +/* THIS MUST BE THE MISSING VALUE FOR THIS GROUP. */ + } + +/* ***D WRITE(KFILDO,206)MISLLA,IC(KTOTAL),KTOTAL,LX,JMIN(LX),JMAX(LX), */ +/* ***D 1 LBIT(LX),NOV(LX),MISSLX(LX) */ +/* ***D206 FORMAT(' AT 206, MISLLA ='I2,' IC(KTOTAL) ='I5,' KTOTAL ='I8, */ +/* ***D 1 ' LX ='I6,' JMIN(LX) ='I8,' JMAX(LX) ='I8, */ +/* ***D 2 ' LBIT(LX) ='I5,' NOV(LX) ='I8,' MISSLX(LX) =',I7) */ + + if (ktotal >= *nxy) { + goto L209; + } + +/* THE NEW GROUP A WILL BE THE PREVIOUS GROUP B. SET LIMITS, ETC. */ + + ibita = ibitb; + mina = minb; + maxa = maxb; + minak = minbk; + maxak = maxbk; + mislla = misllb; + nenda = nendb; + kounta = kountb; + ktotal += kounta; + adda = FALSE_; + goto L133; + +/* ************************************* */ + +/* CALCULATE IBIT, THE NUMBER OF BITS NEEDED TO HOLD THE GROUP */ +/* MINIMUM VALUES. */ + +/* ************************************* */ + +L209: + *ibit = 0; + + i__1 = *lx; + for (l = 1; l <= i__1; ++l) { +L210: + if (jmin[l] < ibxx2[*ibit]) { + goto L220; + } + ++(*ibit); + goto L210; +L220: + ; + } + +/* INSERT THE VALUE IN JMIN( ) TO BE USED FOR ALL MISSING */ +/* VALUES WHEN LBIT( ) = 0. WHEN SECONDARY MISSING */ +/* VALUES CAN BE PRESENT, LBIT(L) WILL NOT = 0. */ + + if (*is523 == 1) { + + i__1 = *lx; + for (l = 1; l <= i__1; ++l) { + + if (lbit[l] == 0) { + + if (misslx[l - 1] == *missp) { + jmin[l] = ibxx2[*ibit] - 1; + } + + } + +/* L226: */ + } + + } + +/* ************************************* */ + +/* CALCULATE JBIT, THE NUMBER OF BITS NEEDED TO HOLD THE BITS */ +/* NEEDED TO PACK THE VALUES IN THE GROUPS. BUT FIND AND */ +/* REMOVE THE REFERENCE VALUE FIRST. */ + +/* ************************************* */ + +/* WRITE(KFILDO,228)CFEED,LX */ +/* 228 FORMAT(A1,/' *****************************************' */ +/* 1 /' THE GROUP WIDTHS LBIT( ) FOR ',I8,' GROUPS' */ +/* 2 /' *****************************************') */ +/* WRITE(KFILDO,229) (LBIT(J),J=1,MIN(LX,100)) */ +/* 229 FORMAT(/' '20I6) */ + + *lbitref = lbit[1]; + + i__1 = *lx; + for (k = 1; k <= i__1; ++k) { + if (lbit[k] < *lbitref) { + *lbitref = lbit[k]; + } +/* L230: */ + } + + if (*lbitref != 0) { + + i__1 = *lx; + for (k = 1; k <= i__1; ++k) { + lbit[k] -= *lbitref; +/* L240: */ + } + + } + +/* WRITE(KFILDO,241)CFEED,LBITREF */ +/* 241 FORMAT(A1,/' *****************************************' */ +/* 1 /' THE GROUP WIDTHS LBIT( ) AFTER REMOVING REFERENCE ', */ +/* 2 I8, */ +/* 3 /' *****************************************') */ +/* WRITE(KFILDO,242) (LBIT(J),J=1,MIN(LX,100)) */ +/* 242 FORMAT(/' '20I6) */ + + *jbit = 0; + + i__1 = *lx; + for (k = 1; k <= i__1; ++k) { +L310: + if (lbit[k] < ibxx2[*jbit]) { + goto L320; + } + ++(*jbit); + goto L310; +L320: + ; + } + +/* ************************************* */ + +/* CALCULATE KBIT, THE NUMBER OF BITS NEEDED TO HOLD THE NUMBER */ +/* OF VALUES IN THE GROUPS. BUT FIND AND REMOVE THE */ +/* REFERENCE FIRST. */ + +/* ************************************* */ + +/* WRITE(KFILDO,321)CFEED,LX */ +/* 321 FORMAT(A1,/' *****************************************' */ +/* 1 /' THE GROUP SIZES NOV( ) FOR ',I8,' GROUPS' */ +/* 2 /' *****************************************') */ +/* WRITE(KFILDO,322) (NOV(J),J=1,MIN(LX,100)) */ +/* 322 FORMAT(/' '20I6) */ + + *novref = nov[1]; + + i__1 = *lx; + for (k = 1; k <= i__1; ++k) { + if (nov[k] < *novref) { + *novref = nov[k]; + } +/* L400: */ + } + + if (*novref > 0) { + + i__1 = *lx; + for (k = 1; k <= i__1; ++k) { + nov[k] -= *novref; +/* L405: */ + } + + } + +/* WRITE(KFILDO,406)CFEED,NOVREF */ +/* 406 FORMAT(A1,/' *****************************************' */ +/* 1 /' THE GROUP SIZES NOV( ) AFTER REMOVING REFERENCE ',I8, */ +/* 2 /' *****************************************') */ +/* WRITE(KFILDO,407) (NOV(J),J=1,MIN(LX,100)) */ +/* 407 FORMAT(/' '20I6) */ +/* WRITE(KFILDO,408)CFEED */ +/* 408 FORMAT(A1,/' *****************************************' */ +/* 1 /' THE GROUP REFERENCES JMIN( )' */ +/* 2 /' *****************************************') */ +/* WRITE(KFILDO,409) (JMIN(J),J=1,MIN(LX,100)) */ +/* 409 FORMAT(/' '20I6) */ + + *kbit = 0; + + i__1 = *lx; + for (k = 1; k <= i__1; ++k) { +L410: + if (nov[k] < ibxx2[*kbit]) { + goto L420; + } + ++(*kbit); + goto L410; +L420: + ; + } + +/* DETERMINE WHETHER THE GROUP SIZES SHOULD BE REDUCED */ +/* FOR SPACE EFFICIENCY. */ + + if (ired == 0) { + reduce(kfildo, &jmin[1], &jmax[1], &lbit[1], &nov[1], lx, ndg, ibit, + jbit, kbit, novref, ibxx2, ier); + + if (*ier == 714 || *ier == 715) { +/* REDUCE HAS ABORTED. REEXECUTE PACK_GP WITHOUT REDUCE. */ +/* PROVIDE FOR A NON FATAL RETURN FROM REDUCE. */ + iersav = *ier; + ired = 1; + *ier = 0; + goto L102; + } + + } + + if ( misslx != 0 ) { + free(misslx); + misslx=0; + } +/* CALL TIMPR(KFILDO,KFILDO,'END PACK_GP ') */ + if (iersav != 0) { + *ier = iersav; + return 0; + } + +/* 900 IF(IER.NE.0)RETURN1 */ + +L900: + if ( misslx != 0 ) free(misslx); + return 0; +} /* pack_gp__ */ + diff --git a/src/plugins/weatherdata/gfs/g2clib/pdstemplates.c b/src/plugins/weatherdata/gfs/g2clib/pdstemplates.c new file mode 100644 index 000000000..02a952510 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/pdstemplates.c @@ -0,0 +1,430 @@ +#include +#include "grib2.h" +#include "pdstemplates.h" + +g2int getpdsindex(g2int number) +///$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: getpdsindex +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2001-06-28 +// +// ABSTRACT: This function returns the index of specified Product +// Definition Template 4.NN (NN=number) in array templates. +// +// PROGRAM HISTORY LOG: +// 2001-06-28 Gilbert +// 2009-01-14 Vuong Changed structure name template to gtemplate +// 2009-12-15 Vuong Added Product Definition Template 4.31 +// Added Product Definition Template 4.15 +// 2010-08-03 Vuong Added Product Definition Template 4.42 and 4.43 +// 2010-12-08 Vuong Corrected Product Definition Template 4.42 and 4.43 +// 2012-03-29 Vuong Added Templates 4.44,4.45,4.46,4.47,4.48,4.50, +// 4.51,4.91,4.32 and 4.52 +// 2013-08-05 Vuong Corrected 4.91 and added Templates 4.33,4.34,4.53,4.54 +// +// USAGE: index=getpdsindex(number) +// INPUT ARGUMENT LIST: +// number - NN, indicating the number of the Product Definition +// Template 4.NN that is being requested. +// +// RETURNS: Index of PDT 4.NN in array templates, if template exists. +// = -1, otherwise. +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: IBM SP +// +//$$$/ +{ + g2int j,getpdsindex=-1; + + for (j=0;jtype=4; + new->num=templatespds[index].template_num; + new->maplen=templatespds[index].mappdslen; + new->needext=templatespds[index].needext; + new->map=(g2int *)templatespds[index].mappds; + new->extlen=0; + new->ext=0; //NULL + return(new); + } + else { + printf("getpdstemplate: PDS Template 4.%d not defined.\n",(int)number); + return(0); //NULL + } + + return(0); //NULL +} + + +gtemplate *extpdstemplate(g2int number,g2int *list) +///$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: extpdstemplate +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2000-05-11 +// +// ABSTRACT: This subroutine generates the remaining octet map for a +// given Product Definition Template, if required. Some Templates can +// vary depending on data values given in an earlier part of the +// Template, and it is necessary to know some of the earlier entry +// values to generate the full octet map of the Template. +// +// PROGRAM HISTORY LOG: +// 2000-05-11 Gilbert +// 2009-01-14 Vuong Changed structure name template to gtemplate +// 2009-08-05 Vuong Added Product Definition Template 4.31 +// 2010-08-03 Vuong Added Product Definition Template 4.42 and 4.43 +// 2010-12-08 Vuong Corrected Product Definition Template 4.42 and 4.43 +// 2012-02-15 Vuong Added Templates 4.44,4.45,4.46,4.47,4.48,4.50, +// 4.51,4.91,4.32 and 4.52 +// 2013-08-05 Vuong Corrected 4.91 and added Templates 4.33,4.34,4.53,4.54 +// +// USAGE: CALL extpdstemplate(number,list) +// INPUT ARGUMENT LIST: +// number - NN, indicating the number of the Product Definition +// Template 4.NN that is being requested. +// list() - The list of values for each entry in the +// the Product Definition Template 4.NN. +// +// RETURN VALUE: +// - Pointer to the returned template struct. +// Returns NULL pointer, if template not found. +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: IBM SP +// +//$$$ +{ + gtemplate *new; + g2int index,i,j,k,l; + + index=getpdsindex(number); + if (index == -1) return(0); + + new=getpdstemplate(number); + + if ( ! new->needext ) return(new); + + if ( number == 3 ) { + new->extlen=list[26]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iextlen;i++) { + new->ext[i]=1; + } + } + else if ( number == 4 ) { + new->extlen=list[25]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iextlen;i++) { + new->ext[i]=1; + } + } + else if ( number == 8 ) { + if ( list[21] > 1 ) { + new->extlen=(list[21]-1)*6; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (j=2;j<=list[21];j++) { + l=(j-2)*6; + for (k=0;k<6;k++) { + new->ext[l+k]=new->map[23+k]; + } + } + } + } + else if ( number == 9 ) { + if ( list[28] > 1 ) { + new->extlen=(list[28]-1)*6; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (j=2;j<=list[28];j++) { + l=(j-2)*6; + for (k=0;k<6;k++) { + new->ext[l+k]=new->map[30+k]; + } + } + } + } + else if ( number == 10 ) { + if ( list[22] > 1 ) { + new->extlen=(list[22]-1)*6; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (j=2;j<=list[22];j++) { + l=(j-2)*6; + for (k=0;k<6;k++) { + new->ext[l+k]=new->map[24+k]; + } + } + } + } + else if ( number == 11 ) { + if ( list[24] > 1 ) { + new->extlen=(list[24]-1)*6; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (j=2;j<=list[24];j++) { + l=(j-2)*6; + for (k=0;k<6;k++) { + new->ext[l+k]=new->map[26+k]; + } + } + } + } + else if ( number == 12 ) { + if ( list[23] > 1 ) { + new->extlen=(list[23]-1)*6; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (j=2;j<=list[23];j++) { + l=(j-2)*6; + for (k=0;k<6;k++) { + new->ext[l+k]=new->map[25+k]; + } + } + } + } + else if ( number == 13 ) { + new->extlen=((list[37]-1)*6)+list[26]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + if ( list[37] > 1 ) { + for (j=2;j<=list[37];j++) { + l=(j-2)*6; + for (k=0;k<6;k++) { + new->ext[l+k]=new->map[39+k]; + } + } + } + l=(list[37]-1)*6; + if ( l<0 ) l=0; + for (i=0;iext[l+i]=1; + } + } + else if ( number == 14 ) { + new->extlen=((list[36]-1)*6)+list[25]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + if ( list[36] > 1 ) { + for (j=2;j<=list[36];j++) { + l=(j-2)*6; + for (k=0;k<6;k++) { + new->ext[l+k]=new->map[38+k]; + } + } + } + l=(list[36]-1)*6; + if ( l<0 ) l=0; + for (i=0;iext[l+i]=1; + } + } + else if ( number == 30 ) { + new->extlen=list[4]*5; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iext[l]=2; + new->ext[l+1]=2; + new->ext[l+2]=1; + new->ext[l+3]=1; + new->ext[l+4]=4; + } + } + else if ( number == 31 ) { + new->extlen=list[4]*5; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iext[l]=2; + new->ext[l+1]=2; + new->ext[l+2]=2; + new->ext[l+3]=1; + new->ext[l+4]=4; + } + } + else if ( number == 42 ) { + if ( list[22] > 1 ) { + new->extlen=(list[22]-1)*6; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (j=2;j<=list[22];j++) { + l=(j-2)*6; + for (k=0;k<6;k++) { + new->ext[l+k]=new->map[24+k]; + } + } + } + } + else if ( number == 43 ) { + if ( list[25] > 1 ) { + new->extlen=(list[25]-1)*6; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (j=2;j<=list[25];j++) { + l=(j-2)*6; + for (k=0;k<6;k++) { + new->ext[l+k]=new->map[27+k]; + } + } + } + } + else if ( number == 32 ) { + new->extlen=list[9]*10; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iext[l]=2; + new->ext[l+1]=2; + new->ext[l+2]=2; + new->ext[l+3]=-1; + new->ext[l+4]=-4; + } + } + else if ( number == 46 ) { + if ( list[27] > 1 ) { + new->extlen=(list[27]-1)*6; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (j=2;j<=list[27];j++) { + l=(j-2)*6; + for (k=0;k<6;k++) { + new->ext[l+k]=new->map[29+k]; + } + } + } + } + else if ( number == 47 ) { + if ( list[30] > 1 ) { + new->extlen=(list[30]-1)*6; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (j=2;j<=list[30];j++) { + l=(j-2)*6; + for (k=0;k<6;k++) { + new->ext[l+k]=new->map[32+k]; + } + } + } + else if ( number == 51 ) { + new->extlen=list[15]*11; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iext[l]=1; + new->ext[l+1]=1; + new->ext[l+2]=-1; + new->ext[l+3]=-4; + new->ext[l+4]=-1; + new->ext[l+5]=-4; + } + } + else if ( number == 33 ) { + new->extlen=list[9]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iextlen;i++) { + new->ext[i]=1; + } + } + else if ( number == 34 ) { + new->extlen=((list[24]-1)*6)+list[9]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + if ( list[24] > 1 ) { + for (j=2;j<=list[24];j++) { + l=(j-2)*6; + for (k=0;k<6;k++) { + new->ext[l+k]=new->map[26+k]; + } + } + } + l=(list[24]-1)*6; + if ( l<0 ) l=0; + for (i=0;iext[l+i]=1; + } + } + else if ( number == 53 ) { + new->extlen=list[3]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iextlen;i++) { + new->ext[i]=1; + } + } + else if ( number == 54 ) { + new->extlen=list[3]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + for (i=0;iextlen;i++) { + new->ext[i]=1; + } + } + else if ( number == 91 ) { + new->extlen=((list[28]-1)*6)+list[15]; + new->ext=(g2int *)malloc(sizeof(g2int)*new->extlen); + if ( list[28] > 1 ) { + for (j=2;j<=list[28];j++) { + l=(j-2)*6; + for (k=0;k<6;k++) { + new->ext[l+k]=new->map[30+k]; + } + } + } + l=(list[29]-1)*6; + if ( l<0 ) l=0; + for (i=0;iext[l+i]=1; + } + } + } + + return(new); + +} diff --git a/src/plugins/weatherdata/gfs/g2clib/pdstemplates.h b/src/plugins/weatherdata/gfs/g2clib/pdstemplates.h new file mode 100644 index 000000000..fa0350aec --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/pdstemplates.h @@ -0,0 +1,206 @@ +#ifndef _pdstemplates_H +#define _pdstemplates_H +#include "grib2.h" + +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-26 +// +// ABSTRACT: This inculde file contains info on all the available +// GRIB2 Product Definition Templates used in Section 4 (PDS). +// The information decribing each template is stored in the +// pdstemplate structure defined below. +// +// Each Template has three parts: The number of entries in the template +// (mappdslen); A map of the template (mappds), which contains the +// number of octets in which to pack each of the template values; and +// a logical value (needext) that indicates whether the Template needs +// to be extended. In some cases the number of entries in a template +// can vary depending upon values specified in the "static" part of +// the template. ( See Template 4.3 as an example ) +// +// NOTE: Array mappds contains the number of octets in which the +// corresponding template values will be stored. A negative value in +// mappds is used to indicate that the corresponding template entry can +// contain negative values. This information is used later when packing +// (or unpacking) the template data values. Negative data values in GRIB +// are stored with the left most bit set to one, and a negative number +// of octets value in mappds[] indicates that this possibility should +// be considered. The number of octets used to store the data value +// in this case would be the absolute value of the negative value in +// mappds[]. +// +// 2005-12-08 Gilbert Allow negative scale factors and limits for +// Templates 4.5 and 4.9 +// 2009-12-15 Vuong Added Product Definition Template 4.31 +// Added Product Definition Template 4.15 +// 2010-08-03 Vuong Added Product Definition Template 4.40,4.41,4.42,4.43 +// 2010-12-08 Vuong Corrected Definition Template 4.42,4.43 +// 2010-12-08 Vuong Corrected Definition Template 4.42,4.43 +// 2012-03-29 Vuong Added Templates 4.44,4.45,4.46,4.47,4.48,4.50, +// 4.51,4.91,4.32 and 4.52 +// 2013-08-05 Vuong Corrected 4.91 and added Templates 4.33,4.34,4.53,4.54 +// +//$$$ + + #define MAXPDSTEMP 43 // maximum number of templates + #define MAXPDSMAPLEN 200 // maximum template map length + + struct pdstemplate + { + g2int template_num; + g2int mappdslen; + g2int needext; + g2int mappds[MAXPDSMAPLEN]; + }; + + const struct pdstemplate templatespds[MAXPDSTEMP] = { + // 4.0: Analysis or Forecast at Horizontal Level/Layer + // at a point in time + {0,15,0, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4} }, + // 4.1: Individual Ensemble Forecast at Horizontal Level/Layer + // at a point in time + {1,18,0, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,1} }, + // 4.2: Derived Fcst based on whole Ensemble at Horiz Level/Layer + // at a point in time + {2,17,0, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1} }, + // 4.3: Derived Fcst based on Ensemble cluster over rectangular + // area at Horiz Level/Layer at a point in time + {3,31,1, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,1,1,1,1,1,-4,-4,4,4,1,-1,4,-1,4} }, + // 4.4: Derived Fcst based on Ensemble cluster over circular + // area at Horiz Level/Layer at a point in time + {4,30,1, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,1,1,1,1,1,-4,4,4,1,-1,4,-1,4} }, + // 4.5: Probablility Forecast at Horiz Level/Layer + // at a point in time + {5,22,0, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,1,-1,-4,-1,-4} }, + // 4.6: Percentile Forecast at Horiz Level/Layer + // at a point in time + {6,16,0, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1} }, + // 4.7: Analysis or Forecast Error at Horizontal Level/Layer + // at a point in time + {7,15,0, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4} }, + // 4.8: Ave/Accum/etc... at Horiz Level/Layer + // in a time interval + {8,29,1, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,2,1,1,1,1,1,1,4,1,1,1,4,1,4} }, + // 4.9: Probablility Forecast at Horiz Level/Layer + // in a time interval + {9,36,1, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,1,-1,-4,-1,-4,2,1,1,1,1,1,1,4,1,1,1,4,1,4} }, + // 4.10: Percentile Forecast at Horiz Level/Layer + // in a time interval + {10,30,1, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,2,1,1,1,1,1,1,4,1,1,1,4,1,4} }, + // 4.11: Individual Ensemble Forecast at Horizontal Level/Layer + // in a time interval + {11,32,1, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,1,2,1,1,1,1,1,1,4,1,1,1,4,1,4} }, + // 4.12: Derived Fcst based on whole Ensemble at Horiz Level/Layer + // in a time interval + {12,31,1, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,2,1,1,1,1,1,1,4,1,1,1,4,1,4} }, + // 4.13: Derived Fcst based on Ensemble cluster over rectangular + // area at Horiz Level/Layer in a time interval + {13,45,1, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,1,1,1,1,1,-4,-4,4,4,1,-1,4,-1,4,2,1,1,1,1,1,1,4,1,1,1,4,1,4} }, + // 4.14: Derived Fcst based on Ensemble cluster over circular + // area at Horiz Level/Layer in a time interval + {14,44,1, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,1,1,1,1,1,-4,4,4,1,-1,4,-1,4,2,1,1,1,1,1,1,4,1,1,1,4,1,4} }, + // 4.15: Average, accumulation, extreme values or other statistically-processed values over a + // spatial area at a horizontal level or in a horizontal layer at a point in time + {15,18,0, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,1} }, + // 4.20: Radar Product + {20,19,0, {1,1,1,1,1,-4,4,2,4,2,1,1,1,1,1,2,1,3,2} }, + // 4.30: Satellite Product + {30,5,1, {1,1,1,1,1} }, + // 4.31: Satellite Product + {31,5,1, {1,1,1,1,1} }, + // 4.40: Analysis or forecast at a horizontal level or in a horizontal layer + // at a point in time for atmospheric chemical constituents + {40,16,0, {1,1,2,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4} }, + // 4.41: Individual ensemble forecast, control and perturbed, at a horizontal level or + // in a horizontal layer at a point in time for atmospheric chemical constituents + {41,19,0, {1,1,2,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,1} }, + // 4.42: Average, accumulation, and/or extreme values or other statistically-processed values + // at a horizontal level or in a horizontal layer in a continuous or non-continuous + // time interval for atmospheric chemical constituents + {42,30,1, {1,1,2,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,2,1,1,1,1,1,1,4,1,1,1,4,1,4} }, + // 4.43: Individual ensemble forecast, control and perturbed, at a horizontal level + // or in a horizontal layer in a continuous or non-continuous + // time interval for atmospheric chemical constituents + {43,33,1, {1,1,2,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,1,2,1,1,1,1,1,1,4,1,1,1,4,1,4} }, + // 4.254: CCITT IA5 Character String + {254,3,0, {1,1,4} }, + // 4.1000: Cross section of analysis or forecast + // at a point in time + {1000,9,0, {1,1,1,1,1,2,1,1,4} }, + // 4.1001: Cross section of Ave/Accum/etc... analysis or forecast + // in a time interval + {1001,16,0, {1,1,1,1,1,2,1,1,4,4,1,1,1,4,1,4} }, + // 4.1001: Cross section of Ave/Accum/etc... analysis or forecast + // over latitude or longitude + {1002,15,0, {1,1,1,1,1,2,1,1,4,1,1,1,4,4,2} }, + // 4.1100: Hovmoller-type grid w/ no averaging or other + // statistical processing + {1100,15,0, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4} }, + // 4.1100: Hovmoller-type grid with averaging or other + // statistical processing + {1101,22,0, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,4,1,1,1,4,1,4} }, + // 4.32:Simulate (synthetic) Satellite Product + {32,10,1, {1,1,1,1,1,2,1,1,2,1} }, + // 4.44: Analysis or forecast at a horizontal level or in a horizontal layer + // at a point in time for Aerosol + {44,21,0, {1,1,2,1,-1,-4,-1,-4,1,1,1,2,1,1,2,1,-1,-4,1,-1,-4} }, + // 4.45: Individual ensemble forecast, control and + // perturbed, at a horizontal level or in a horizontal layer + // at a point in time for Aerosol + {45,24,0, {1,1,2,1,-1,-4,-1,-4,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,1} }, + // 4.46: Ave or Accum or Extreme value at level/layer + // at horizontal level or in a horizontal in a continuous or + // non-continuous time interval for Aerosol + {46,35,1, {1,1,2,1,-1,-4,-1,-4,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,2,1,1,1,1,1,1,4,1,1,1,4,1,4} }, + // 4.47: Individual ensemble forecast, control and + // perturbed, at horizontal level or in a horizontal + // in a continuous or non-continuous time interval for Aerosol + {47,38,1, {1,1,1,2,1,-1,-4,-1,-4,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,1,2,1,1,1,1,1,1,4,1,1,1,4,1,4} }, + + // PDT 4.48 + // 4.48: Analysis or forecast at a horizontal level or in a horizontal layer + // at a point in time for Optical Properties of Aerosol + {48,26,0, {1,1,2,1,-1,-4,-1,-4,1,-1,-4,-1,-4,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4} }, + + // VALIDATION --- PDT 4.50 + // 4.50: Analysis or forecast of multi component parameter or + // matrix element at a point in time + {50,21,0, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,4,4,4,4} }, + + // VALIDATION --- PDT 4.52 + // 4.52: Analysis or forecast of Wave parameters + // at the Sea surface at a point in time + {52,15,0, {1,1,1,1,1,1,1,1,2,1,1,4,1,-1,-4} }, + + // 4.51: Categorical forecasts at a horizontal level or + // in a horizontal layer at a point in time + {51,16,1, {1,1,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1} }, + + // 4.91: Categorical forecasts at a horizontal level or + // in a horizontal layer at a point in time + // in a continuous or non-continuous time interval + {91,36,1, {1,1,2,1,-1,-4,-1,-4,1,-1,-4,-1,-4,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4} }, +// PDT 4.33 (07/29/2013) + // 4.33: Individual ensemble forecast, control, perturbed, + // at a horizontal level or in a horizontal layer + // at a point in time for simulated (synthetic) Satellite data + {33,18,1, {1,1,1,1,1,2,1,1,4,1,2,2,2,-1,-4,1,1,1} }, +// PDT 4.34 (07/29/2013) + // 4.34: Individual ensemble forecast, control, perturbed, + // at a horizontal level or in a horizontal layer,in a continuous or + // non-continuous interval for simulated (synthetic) Satellite data + {34,32,1, {1,1,1,1,1,2,1,1,4,1,2,2,2,-1,-4,1,1,1,2,1,1,1,1,1,1,4,1,1,1,4,1,4} }, +// PDT 4.53 (07/29/2013) + // 4.53: Partitioned parameters at + // horizontal level or horizontal layer + // at a point in time + {53,19,1, {1,1,1,1,4,2,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4} }, +// PDT 4.54 (07/29/2013) + // 4.54: Individual ensemble forecast, control, perturbed, + // at a horizontal level or in a horizontal layer + // at a point in time for partitioned parameters + {54,22,1, {1,1,1,1,4,2,1,1,1,2,1,1,4,1,-1,-4,1,-1,-4,1,1,1} } + + } ; + + +#endif /* _pdstemplates_H */ diff --git a/src/plugins/weatherdata/gfs/g2clib/pngpack.c b/src/plugins/weatherdata/gfs/g2clib/pngpack.c new file mode 100644 index 000000000..f81ee4165 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/pngpack.c @@ -0,0 +1,162 @@ +#include +#include +#include "grib2.h" + +int enc_png(char *,g2int ,g2int ,g2int ,char *); + +void pngpack(g2float *fld,g2int width,g2int height,g2int *idrstmpl, + unsigned char *cpack,g2int *lcpack) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: pngpack +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2003-08-27 +// +// ABSTRACT: This subroutine packs up a data field into PNG image format. +// After the data field is scaled, and the reference value is subtracted out, +// it is treated as a grayscale image and passed to a PNG encoder. +// It also fills in GRIB2 Data Representation Template 5.41 or 5.40010 with +// the appropriate values. +// +// PROGRAM HISTORY LOG: +// 2003-08-27 Gilbert +// +// USAGE: pngpack(g2float *fld,g2int width,g2int height,g2int *idrstmpl, +// unsigned char *cpack,g2int *lcpack); +// INPUT ARGUMENT LIST: +// fld[] - Contains the data values to pack +// width - number of points in the x direction +// height - number of points in the y direction +// idrstmpl - Contains the array of values for Data Representation +// Template 5.41 or 5.40010 +// [0] = Reference value - ignored on input +// [1] = Binary Scale Factor +// [2] = Decimal Scale Factor +// [3] = number of bits for each data value - ignored on input +// [4] = Original field type - currently ignored on input +// Data values assumed to be reals. +// +// OUTPUT ARGUMENT LIST: +// idrstmpl - Contains the array of values for Data Representation +// Template 5.41 or 5.40010 +// [0] = Reference value - set by pngpack routine. +// [1] = Binary Scale Factor - unchanged from input +// [2] = Decimal Scale Factor - unchanged from input +// [3] = Number of bits containing each grayscale pixel value +// [4] = Original field type - currently set = 0 on output. +// Data values assumed to be reals. +// cpack - The packed data field +// lcpack - length of packed field cpack. +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: IBM SP +// +//$$$ +{ + g2int *ifld; + static g2float alog2=0.69314718; // ln(2.0) + g2int j,nbits,imin,imax,maxdif; + g2int ndpts,nbytes; + g2float bscale,dscale,rmax,rmin,temp; + unsigned char *ctemp; + + ifld=0; + ndpts=width*height; + bscale=int_power(2.0,-idrstmpl[1]); + dscale=int_power(10.0,idrstmpl[2]); +// +// Find max and min values in the data +// + rmax=fld[0]; + rmin=fld[0]; + for (j=1;j rmax) rmax=fld[j]; + if (fld[j] < rmin) rmin=fld[j]; + } + maxdif = (g2int)rint( (rmax-rmin)*dscale*bscale ); +// +// If max and min values are not equal, pack up field. +// If they are equal, we have a constant field, and the reference +// value (rmin) is the value for each point in the field and +// set nbits to 0. +// + if (rmin != rmax && maxdif != 0 ) { + ifld=(g2int *)malloc(ndpts*sizeof(g2int)); + // + // Determine which algorithm to use based on user-supplied + // binary scale factor and number of bits. + // + if (idrstmpl[1] == 0) { + // + // No binary scaling and calculate minumum number of + // bits in which the data will fit. + // + imin=(g2int)rint(rmin*dscale); + imax=(g2int)rint(rmax*dscale); + maxdif=imax-imin; + temp=log((double)(maxdif+1))/alog2; + nbits=(g2int)ceil(temp); + rmin=(g2float)imin; + // scale data + for(j=0;j +#include +#include "grib2.h" + +int dec_png(unsigned char *,g2int *,g2int *,char *); + +g2int pngunpack(unsigned char *cpack,g2int len,g2int *idrstmpl,g2int ndpts, + g2float *fld) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: pngunpack +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2003-08-27 +// +// ABSTRACT: This subroutine unpacks a data field that was packed into a +// PNG image format +// using info from the GRIB2 Data Representation Template 5.41 or 5.40010. +// +// PROGRAM HISTORY LOG: +// 2003-08-27 Gilbert +// +// USAGE: pngunpack(unsigned char *cpack,g2int len,g2int *idrstmpl,g2int ndpts, +// g2float *fld) +// INPUT ARGUMENT LIST: +// cpack - The packed data field (character*1 array) +// len - length of packed field cpack(). +// idrstmpl - Pointer to array of values for Data Representation +// Template 5.41 or 5.40010 +// ndpts - The number of data values to unpack +// +// OUTPUT ARGUMENT LIST: +// fld[] - Contains the unpacked data values +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: IBM SP +// +//$$$ +{ + + g2int *ifld; + g2int j,nbits,iret,width,height; + g2float ref,bscale,dscale; + unsigned char *ctemp; + + rdieee(idrstmpl+0,&ref,1); + bscale = int_power(2.0,idrstmpl[1]); + dscale = int_power(10.0,-idrstmpl[2]); + nbits = idrstmpl[3]; +// +// if nbits equals 0, we have a constant field where the reference value +// is the data value at each gridpoint +// + if (nbits != 0) { + + ifld=(g2int *)calloc(ndpts,sizeof(g2int)); + ctemp=(unsigned char *)calloc(ndpts*4,1); + if ( ifld == 0 || ctemp == 0) { + fprintf(stderr,"Could not allocate space in jpcunpack.\n Data field NOT upacked.\n"); + return(1); + } + iret=(g2int)dec_png(cpack,&width,&height,ctemp); + gbits(ctemp,ifld,0,nbits,0,ndpts); + for (j=0;j>31; + iexp=(rieee[j]&msk2)>>23; + imant=(rieee[j]&msk3); + //printf("SAGieee= %ld %ld %ld\n",isign,iexp,imant); + + sign=1.0; + if (isign == 1) sign=-1.0; + + if ( (iexp > 0) && (iexp < 255) ) { + temp=(g2float)int_power(2.0,(iexp-127)); + a[j]=sign*temp*(1.0+(two23*(g2float)imant)); + } + else if ( iexp == 0 ) { + if ( imant != 0 ) + a[j]=sign*two126*two23*(g2float)imant; + else + a[j]=sign*0.0; + + } + else if ( iexp == 255 ) + a[j]=sign*(1E+37); + + + } + +} diff --git a/src/plugins/weatherdata/gfs/g2clib/reduce.c b/src/plugins/weatherdata/gfs/g2clib/reduce.c new file mode 100644 index 000000000..b1c3502c5 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/reduce.c @@ -0,0 +1,410 @@ +/* reduce.f -- translated by f2c (version 20031025). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +/*#include "f2c.h"*/ +#include +#include "grib2.h" +typedef g2int integer; +typedef g2float real; + +/* Subroutine */ int reduce(integer *kfildo, integer *jmin, integer *jmax, + integer *lbit, integer *nov, integer *lx, integer *ndg, integer *ibit, + integer *jbit, integer *kbit, integer *novref, integer *ibxx2, + integer *ier) +{ + /* Initialized data */ + + static integer ifeed = 12; + + /* System generated locals */ + integer i__1, i__2; + + /* Local variables */ + static integer newboxtp, j, l, m, jj, lxn, left; + static real pimp; + static integer move, novl; + static char cfeed[1]; + static integer nboxj[31], lxnkp, iorigb, ibxx2m1, movmin, + ntotbt[31], ntotpr, newboxt; + integer *newbox, *newboxp; + + +/* NOVEMBER 2001 GLAHN TDL GRIB2 */ +/* MARCH 2002 GLAHN COMMENT IER = 715 */ +/* MARCH 2002 GLAHN MODIFIED TO ACCOMMODATE LX=1 ON ENTRY */ + +/* PURPOSE */ +/* DETERMINES WHETHER THE NUMBER OF GROUPS SHOULD BE */ +/* INCREASED IN ORDER TO REDUCE THE SIZE OF THE LARGE */ +/* GROUPS, AND TO MAKE THAT ADJUSTMENT. BY REDUCING THE */ +/* SIZE OF THE LARGE GROUPS, LESS BITS MAY BE NECESSARY */ +/* FOR PACKING THE GROUP SIZES AND ALL THE INFORMATION */ +/* ABOUT THE GROUPS. */ + +/* THE REFERENCE FOR NOV( ) WAS REMOVED IN THE CALLING */ +/* ROUTINE SO THAT KBIT COULD BE DETERMINED. THIS */ +/* FURNISHES A STARTING POINT FOR THE ITERATIONS IN REDUCE. */ +/* HOWEVER, THE REFERENCE MUST BE CONSIDERED. */ + +/* DATA SET USE */ +/* KFILDO - UNIT NUMBER FOR OUTPUT (PRINT) FILE. (OUTPUT) */ + +/* VARIABLES IN CALL SEQUENCE */ +/* KFILDO = UNIT NUMBER FOR OUTPUT (PRINT) FILE. (INPUT) */ +/* JMIN(J) = THE MINIMUM OF EACH GROUP (J=1,LX). IT IS */ +/* POSSIBLE AFTER SPLITTING THE GROUPS, JMIN( ) */ +/* WILL NOT BE THE MINIMUM OF THE NEW GROUP. */ +/* THIS DOESN'T MATTER; JMIN( ) IS REALLY THE */ +/* GROUP REFERENCE AND DOESN'T HAVE TO BE THE */ +/* SMALLEST VALUE. (INPUT/OUTPUT) */ +/* JMAX(J) = THE MAXIMUM OF EACH GROUP (J=1,LX). */ +/* (INPUT/OUTPUT) */ +/* LBIT(J) = THE NUMBER OF BITS NECESSARY TO PACK EACH GROUP */ +/* (J=1,LX). (INPUT/OUTPUT) */ +/* NOV(J) = THE NUMBER OF VALUES IN EACH GROUP (J=1,LX). */ +/* (INPUT/OUTPUT) */ +/* LX = THE NUMBER OF GROUPS. THIS WILL BE INCREASED */ +/* IF GROUPS ARE SPLIT. (INPUT/OUTPUT) */ +/* NDG = THE DIMENSION OF JMIN( ), JMAX( ), LBIT( ), AND */ +/* NOV( ). (INPUT) */ +/* IBIT = THE NUMBER OF BITS NECESSARY TO PACK THE JMIN(J) */ +/* VALUES, J=1,LX. (INPUT) */ +/* JBIT = THE NUMBER OF BITS NECESSARY TO PACK THE LBIT(J) */ +/* VALUES, J=1,LX. (INPUT) */ +/* KBIT = THE NUMBER OF BITS NECESSARY TO PACK THE NOV(J) */ +/* VALUES, J=1,LX. IF THE GROUPS ARE SPLIT, KBIT */ +/* IS REDUCED. (INPUT/OUTPUT) */ +/* NOVREF = REFERENCE VALUE FOR NOV( ). (INPUT) */ +/* IBXX2(J) = 2**J (J=0,30). (INPUT) */ +/* IER = ERROR RETURN. (OUTPUT) */ +/* 0 = GOOD RETURN. */ +/* 714 = PROBLEM IN ALGORITHM. REDUCE ABORTED. */ +/* 715 = NGP NOT LARGE ENOUGH. REDUCE ABORTED. */ +/* NTOTBT(J) = THE TOTAL BITS USED FOR THE PACKING BITS J */ +/* (J=1,30). (INTERNAL) */ +/* NBOXJ(J) = NEW BOXES NEEDED FOR THE PACKING BITS J */ +/* (J=1,30). (INTERNAL) */ +/* NEWBOX(L) = NUMBER OF NEW BOXES (GROUPS) FOR EACH ORIGINAL */ +/* GROUP (L=1,LX) FOR THE CURRENT J. (AUTOMATIC) */ +/* (INTERNAL) */ +/* NEWBOXP(L) = SAME AS NEWBOX( ) BUT FOR THE PREVIOUS J. */ +/* THIS ELIMINATES RECOMPUTATION. (AUTOMATIC) */ +/* (INTERNAL) */ +/* CFEED = CONTAINS THE CHARACTER REPRESENTATION */ +/* OF A PRINTER FORM FEED. (CHARACTER) (INTERNAL) */ +/* IFEED = CONTAINS THE INTEGER VALUE OF A PRINTER */ +/* FORM FEED. (INTERNAL) */ +/* IORIGB = THE ORIGINAL NUMBER OF BITS NECESSARY */ +/* FOR THE GROUP VALUES. (INTERNAL) */ +/* 1 2 3 4 5 6 7 X */ + +/* NON SYSTEM SUBROUTINES CALLED */ +/* NONE */ + + +/* NEWBOX( ) AND NEWBOXP( ) were AUTOMATIC ARRAYS. */ + newbox = (integer *)calloc(*ndg,sizeof(integer)); + newboxp = (integer *)calloc(*ndg,sizeof(integer)); + + /* Parameter adjustments */ + --nov; + --lbit; + --jmax; + --jmin; + + /* Function Body */ + + *ier = 0; + if (*lx == 1) { + goto L410; + } +/* IF THERE IS ONLY ONE GROUP, RETURN. */ + + *(unsigned char *)cfeed = (char) ifeed; + +/* INITIALIZE NUMBER OF NEW BOXES PER GROUP TO ZERO. */ + + i__1 = *lx; + for (l = 1; l <= i__1; ++l) { + newbox[l - 1] = 0; +/* L110: */ + } + +/* INITIALIZE NUMBER OF TOTAL NEW BOXES PER J TO ZERO. */ + + for (j = 1; j <= 31; ++j) { + ntotbt[j - 1] = 999999999; + nboxj[j - 1] = 0; +/* L112: */ + } + + iorigb = (*ibit + *jbit + *kbit) * *lx; +/* IBIT = BITS TO PACK THE JMIN( ). */ +/* JBIT = BITS TO PACK THE LBIT( ). */ +/* KBIT = BITS TO PACK THE NOV( ). */ +/* LX = NUMBER OF GROUPS. */ + ntotbt[*kbit - 1] = iorigb; +/* THIS IS THE VALUE OF TOTAL BITS FOR THE ORIGINAL LX */ +/* GROUPS, WHICH REQUIRES KBITS TO PACK THE GROUP */ +/* LENGHTS. SETTING THIS HERE MAKES ONE LESS LOOPS */ +/* NECESSARY BELOW. */ + +/* COMPUTE BITS NOW USED FOR THE PARAMETERS DEFINED. */ + +/* DETERMINE OTHER POSSIBILITES BY INCREASING LX AND DECREASING */ +/* NOV( ) WITH VALUES GREATER THAN THRESHOLDS. ASSUME A GROUP IS */ +/* SPLIT INTO 2 OR MORE GROUPS SO THAT KBIT IS REDUCED WITHOUT */ +/* CHANGING IBIT OR JBIT. */ + + jj = 0; + +/* Computing MIN */ + i__1 = 30, i__2 = *kbit - 1; + /*for (j = min(i__1,i__2); j >= 2; --j) {*/ + for (j = (i__1 < i__2) ? i__1 : i__2; j >= 2; --j) { +/* VALUES GE KBIT WILL NOT REQUIRE SPLITS. ONCE THE TOTAL */ +/* BITS START INCREASING WITH DECREASING J, STOP. ALSO, THE */ +/* NUMBER OF BITS REQUIRED IS KNOWN FOR KBITS = NTOTBT(KBIT). */ + + newboxt = 0; + + i__1 = *lx; + for (l = 1; l <= i__1; ++l) { + + if (nov[l] < ibxx2[j]) { + newbox[l - 1] = 0; +/* NO SPLITS OR NEW BOXES. */ + goto L190; + } else { + novl = nov[l]; + + m = (nov[l] - 1) / (ibxx2[j] - 1) + 1; +/* M IS FOUND BY SOLVING THE EQUATION BELOW FOR M: */ +/* (NOV(L)+M-1)/M LT IBXX2(J) */ +/* M GT (NOV(L)-1)/(IBXX2(J)-1) */ +/* SET M = (NOV(L)-1)/(IBXX2(J)-1)+1 */ +L130: + novl = (nov[l] + m - 1) / m; +/* THE +M-1 IS NECESSARY. FOR INSTANCE, 15 WILL FIT */ +/* INTO A BOX 4 BITS WIDE, BUT WON'T DIVIDE INTO */ +/* TWO BOXES 3 BITS WIDE EACH. */ + + if (novl < ibxx2[j]) { + goto L185; + } else { + ++m; +/* *** WRITE(KFILDO,135)L,NOV(L),NOVL,M,J,IBXX2(J) */ +/* *** 135 FORMAT(/' AT 135--L,NOV(L),NOVL,M,J,IBXX2(J)',6I10) */ + goto L130; + } + +/* THE ABOVE DO LOOP WILL NEVER COMPLETE. */ + } + +L185: + newbox[l - 1] = m - 1; + newboxt = newboxt + m - 1; +L190: + ; + } + + nboxj[j - 1] = newboxt; + ntotpr = ntotbt[j]; + ntotbt[j - 1] = (*ibit + *jbit) * (*lx + newboxt) + j * (*lx + + newboxt); + + if (ntotbt[j - 1] >= ntotpr) { + jj = j + 1; +/* THE PLUS IS USED BECAUSE J DECREASES PER ITERATION. */ + goto L250; + } else { + +/* SAVE THE TOTAL NEW BOXES AND NEWBOX( ) IN CASE THIS */ +/* IS THE J TO USE. */ + + newboxtp = newboxt; + + i__1 = *lx; + for (l = 1; l <= i__1; ++l) { + newboxp[l - 1] = newbox[l - 1]; +/* L195: */ + } + +/* WRITE(KFILDO,197)NEWBOXT,IBXX2(J) */ +/* 197 FORMAT(/' *****************************************' */ +/* 1 /' THE NUMBER OF NEWBOXES PER GROUP OF THE TOTAL', */ +/* 2 I10,' FOR GROUP MAXSIZE PLUS 1 ='I10 */ +/* 3 /' *****************************************') */ +/* WRITE(KFILDO,198) (NEWBOX(L),L=1,LX) */ +/* 198 FORMAT(/' '20I6/(' '20I6)) */ + } + +/* 205 WRITE(KFILDO,209)KBIT,IORIGB */ +/* 209 FORMAT(/' ORIGINAL BITS WITH KBIT OF',I5,' =',I10) */ +/* WRITE(KFILDO,210)(N,N=2,10),(IBXX2(N),N=2,10), */ +/* 1 (NTOTBT(N),N=2,10),(NBOXJ(N),N=2,10), */ +/* 2 (N,N=11,20),(IBXX2(N),N=11,20), */ +/* 3 (NTOTBT(N),N=11,20),(NBOXJ(N),N=11,20), */ +/* 4 (N,N=21,30),(IBXX2(N),N=11,20), */ +/* 5 (NTOTBT(N),N=21,30),(NBOXJ(N),N=21,30) */ +/* 210 FORMAT(/' THE TOTAL BYTES FOR MAXIMUM GROUP LENGTHS BY ROW'// */ +/* 1 ' J = THE NUMBER OF BITS PER GROUP LENGTH'/ */ +/* 2 ' IBXX2(J) = THE MAXIMUM GROUP LENGTH PLUS 1 FOR THIS J'/ */ +/* 3 ' NTOTBT(J) = THE TOTAL BITS FOR THIS J'/ */ +/* 4 ' NBOXJ(J) = THE NEW GROUPS FOR THIS J'/ */ +/* 5 4(/10X,9I10)/4(/10I10)/4(/10I10)) */ + +/* L200: */ + } + +L250: + pimp = (iorigb - ntotbt[jj - 1]) / (real) iorigb * 100.f; +/* WRITE(KFILDO,252)PIMP,KBIT,JJ */ +/* 252 FORMAT(/' PERCENT IMPROVEMENT =',F6.1, */ +/* 1 ' BY DECREASING GROUP LENGTHS FROM',I4,' TO',I4,' BITS') */ + if (pimp >= 2.f) { + +/* WRITE(KFILDO,255)CFEED,NEWBOXTP,IBXX2(JJ) */ +/* 255 FORMAT(A1,/' *****************************************' */ +/* 1 /' THE NUMBER OF NEWBOXES PER GROUP OF THE TOTAL', */ +/* 2 I10,' FOR GROUP MAXSIZE PLUS 1 ='I10 */ +/* 2 /' *****************************************') */ +/* WRITE(KFILDO,256) (NEWBOXP(L),L=1,LX) */ +/* 256 FORMAT(/' '20I6) */ + +/* ADJUST GROUP LENGTHS FOR MAXIMUM LENGTH OF JJ BITS. */ +/* THE MIN PER GROUP AND THE NUMBER OF BITS REQUIRED */ +/* PER GROUP ARE NOT CHANGED. THIS MAY MEAN THAT A */ +/* GROUP HAS A MIN (OR REFERENCE) THAT IS NOT ZERO. */ +/* THIS SHOULD NOT MATTER TO THE UNPACKER. */ + + lxnkp = *lx + newboxtp; +/* LXNKP = THE NEW NUMBER OF BOXES */ + + if (lxnkp > *ndg) { +/* DIMENSIONS NOT LARGE ENOUGH. PROBABLY AN ERROR */ +/* OF SOME SORT. ABORT. */ +/* WRITE(KFILDO,257)NDG,LXNPK */ +/* 1 2 3 4 5 6 7 X */ +/* 257 FORMAT(/' DIMENSIONS OF JMIN, ETC. IN REDUCE =',I8, */ +/* 1 ' NOT LARGE ENOUGH FOR THE EXPANDED NUMBER OF', */ +/* 2 ' GROUPS =',I8,'. ABORT REDUCE.') */ + *ier = 715; + goto L410; +/* AN ABORT CAUSES THE CALLING PROGRAM TO REEXECUTE */ +/* WITHOUT CALLING REDUCE. */ + } + + lxn = lxnkp; +/* LXN IS THE NUMBER OF THE BOX IN THE NEW SERIES BEING */ +/* FILLED. IT DECREASES PER ITERATION. */ + ibxx2m1 = ibxx2[jj] - 1; +/* IBXX2M1 IS THE MAXIMUM NUMBER OF VALUES PER GROUP. */ + + for (l = *lx; l >= 1; --l) { + +/* THE VALUES IS NOV( ) REPRESENT THOSE VALUES + NOVREF. */ +/* WHEN VALUES ARE MOVED TO ANOTHER BOX, EACH VALUE */ +/* MOVED TO A NEW BOX REPRESENTS THAT VALUE + NOVREF. */ +/* THIS HAS TO BE CONSIDERED IN MOVING VALUES. */ + + if (newboxp[l - 1] * (ibxx2m1 + *novref) + *novref > nov[l] + * + novref) { +/* IF THE ABOVE TEST IS MET, THEN MOVING IBXX2M1 VALUES */ +/* FOR ALL NEW BOXES WILL LEAVE A NEGATIVE NUMBER FOR */ +/* THE LAST BOX. NOT A TOLERABLE SITUATION. */ + movmin = (nov[l] - newboxp[l - 1] * *novref) / newboxp[l - 1]; + left = nov[l]; +/* LEFT = THE NUMBER OF VALUES TO MOVE FROM THE ORIGINAL */ +/* BOX TO EACH NEW BOX EXCEPT THE LAST. LEFT IS THE */ +/* NUMBER LEFT TO MOVE. */ + } else { + movmin = ibxx2m1; +/* MOVMIN VALUES CAN BE MOVED FOR EACH NEW BOX. */ + left = nov[l]; +/* LEFT IS THE NUMBER OF VALUES LEFT TO MOVE. */ + } + + if (newboxp[l - 1] > 0) { + if ((movmin + *novref) * newboxp[l - 1] + *novref <= nov[l] + + *novref && (movmin + *novref) * (newboxp[l - 1] + 1) + >= nov[l] + *novref) { + goto L288; + } else { +/* ***D WRITE(KFILDO,287)L,MOVMIN,NOVREF,NEWBOXP(L),NOV(L) */ +/* ***D287 FORMAT(/' AT 287 IN REDUCE--L,MOVMIN,NOVREF,', */ +/* ***D 1 'NEWBOXP(L),NOV(L)',5I12 */ +/* ***D 2 ' REDUCE ABORTED.') */ +/* WRITE(KFILDO,2870) */ +/* 2870 FORMAT(/' AN ERROR IN REDUCE ALGORITHM. ABORT REDUCE.') */ + *ier = 714; + goto L410; +/* AN ABORT CAUSES THE CALLING PROGRAM TO REEXECUTE */ +/* WITHOUT CALLING REDUCE. */ + } + + } + +L288: + i__1 = newboxp[l - 1] + 1; + for (j = 1; j <= i__1; ++j) { + /*move = min(movmin,left);*/ + move = (movmin < left) ? movmin : left; + jmin[lxn] = jmin[l]; + jmax[lxn] = jmax[l]; + lbit[lxn] = lbit[l]; + nov[lxn] = move; + --lxn; + left -= move + *novref; +/* THE MOVE OF MOVE VALUES REALLY REPRESENTS A MOVE OF */ +/* MOVE + NOVREF VALUES. */ +/* L290: */ + } + + if (left != -(*novref)) { +/* *** WRITE(KFILDO,292)L,LXN,MOVE,LXNKP,IBXX2(JJ),LEFT,NOV(L), */ +/* *** 1 MOVMIN */ +/* *** 292 FORMAT(' AT 292 IN REDUCE--L,LXN,MOVE,LXNKP,', */ +/* *** 1 'IBXX2(JJ),LEFT,NOV(L),MOVMIN'/8I12) */ + } + +/* L300: */ + } + + *lx = lxnkp; +/* LX IS NOW THE NEW NUMBER OF GROUPS. */ + *kbit = jj; +/* KBIT IS NOW THE NEW NUMBER OF BITS REQUIRED FOR PACKING */ +/* GROUP LENGHTS. */ + } + +/* WRITE(KFILDO,406)CFEED,LX */ +/* 406 FORMAT(A1,/' *****************************************' */ +/* 1 /' THE GROUP SIZES NOV( ) AFTER REDUCTION IN SIZE', */ +/* 2 ' FOR'I10,' GROUPS', */ +/* 3 /' *****************************************') */ +/* WRITE(KFILDO,407) (NOV(J),J=1,LX) */ +/* 407 FORMAT(/' '20I6) */ +/* WRITE(KFILDO,408)CFEED,LX */ +/* 408 FORMAT(A1,/' *****************************************' */ +/* 1 /' THE GROUP MINIMA JMIN( ) AFTER REDUCTION IN SIZE', */ +/* 2 ' FOR'I10,' GROUPS', */ +/* 3 /' *****************************************') */ +/* WRITE(KFILDO,409) (JMIN(J),J=1,LX) */ +/* 409 FORMAT(/' '20I6) */ + +L410: + if ( newbox != 0 ) free(newbox); + if ( newboxp != 0 ) free(newboxp); + return 0; +} /* reduce_ */ + diff --git a/src/plugins/weatherdata/gfs/g2clib/seekgb.c b/src/plugins/weatherdata/gfs/g2clib/seekgb.c new file mode 100644 index 000000000..69cf66cc9 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/seekgb.c @@ -0,0 +1,83 @@ +#include +#include +#include "grib2.h" + +void seekgb(FILE *lugb,g2int iseek,g2int mseek,g2int *lskip,g2int *lgrib) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// +// SUBPROGRAM: seekgb Searches a file for the next GRIB message. +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-28 +// +// ABSTRACT: This subprogram searches a file for the next GRIB Message. +// The search is done starting at byte offset iseek of the file referenced +// by lugb for mseek bytes at a time. +// If found, the starting position and length of the message are returned +// in lskip and lgrib, respectively. +// The search is terminated when an EOF or I/O error is encountered. +// +// PROGRAM HISTORY LOG: +// 2002-10-28 GILBERT Modified from Iredell's skgb subroutine +// 2009-01-16 VUONG Changed lskip to 4 instead of sizof(g2int) +// +// USAGE: seekgb(FILE *lugb,g2int iseek,g2int mseek,int *lskip,int *lgrib) +// INPUT ARGUMENTS: +// lugb - FILE pointer for the file to search. File must be +// opened before this routine is called. +// iseek - number of bytes in the file to skip before search +// mseek - number of bytes to search at a time +// OUTPUT ARGUMENTS: +// lskip - number of bytes to skip from the beggining of the file +// to where the GRIB message starts +// lgrib - number of bytes in message (set to 0, if no message found) +// +// ATTRIBUTES: +// LANGUAGE: C +// +//$$$ +{ + g2int ret; + g2int k,k4,ipos,nread,lim,start,vers,lengrib; + int end; + unsigned char *cbuf; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + *lgrib=0; + cbuf=(unsigned char *)malloc(mseek); + nread=mseek; + ipos=iseek; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// LOOP UNTIL GRIB MESSAGE IS FOUND + + while (*lgrib==0 && nread==mseek) { + +// READ PARTIAL SECTION + + ret=fseek(lugb,ipos,SEEK_SET); + nread=fread(cbuf,sizeof(unsigned char),mseek,lugb); + lim=nread-8; + +// LOOK FOR 'GRIB...' IN PARTIAL SECTION + + for (k=0;k +#include +#include "grib2.h" + + +void simpack(g2float *fld,g2int ndpts,g2int *idrstmpl,unsigned char *cpack,g2int *lcpack) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: simpack +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-11-06 +// +// ABSTRACT: This subroutine packs up a data field using the simple +// packing algorithm as defined in the GRIB2 documention. It +// also fills in GRIB2 Data Representation Template 5.0 with the +// appropriate values. +// +// PROGRAM HISTORY LOG: +// 2002-11-06 Gilbert +// +// USAGE: CALL simpack(fld,ndpts,idrstmpl,cpack,lcpack) +// INPUT ARGUMENT LIST: +// fld[] - Contains the data values to pack +// ndpts - The number of data values in array fld[] +// idrstmpl - Contains the array of values for Data Representation +// Template 5.0 +// [0] = Reference value - ignored on input +// [1] = Binary Scale Factor +// [2] = Decimal Scale Factor +// [3] = Number of bits used to pack data, if value is +// > 0 and <= 31. +// If this input value is 0 or outside above range +// then the num of bits is calculated based on given +// data and scale factors. +// [4] = Original field type - currently ignored on input +// Data values assumed to be reals. +// +// OUTPUT ARGUMENT LIST: +// idrstmpl - Contains the array of values for Data Representation +// Template 5.0 +// [0] = Reference value - set by simpack routine. +// [1] = Binary Scale Factor - unchanged from input +// [2] = Decimal Scale Factor - unchanged from input +// [3] = Number of bits used to pack data, unchanged from +// input if value is between 0 and 31. +// If this input value is 0 or outside above range +// then the num of bits is calculated based on given +// data and scale factors. +// [4] = Original field type - currently set = 0 on output. +// Data values assumed to be reals. +// cpack - The packed data field +// lcpack - length of packed field starting at cpack. +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ +{ + + static g2int zero=0; + g2int *ifld; + g2int j,nbits,imin,imax,maxdif,nbittot,left; + g2float bscale,dscale,rmax,rmin,temp; + double maxnum; + static g2float alog2=0.69314718; // ln(2.0) + + bscale=int_power(2.0,-idrstmpl[1]); + dscale=int_power(10.0,idrstmpl[2]); + if (idrstmpl[3] <= 0 || idrstmpl[3] > 31) + nbits=0; + else + nbits=idrstmpl[3]; +// +// Find max and min values in the data +// + rmax=fld[0]; + rmin=fld[0]; + for (j=1;j rmax) rmax=fld[j]; + if (fld[j] < rmin) rmin=fld[j]; + } + + ifld=calloc(ndpts,sizeof(g2int)); +// +// If max and min values are not equal, pack up field. +// If they are equal, we have a constant field, and the reference +// value (rmin) is the value for each point in the field and +// set nbits to 0. +// + if (rmin != rmax) { + // + // Determine which algorithm to use based on user-supplied + // binary scale factor and number of bits. + // + if (nbits==0 && idrstmpl[1]==0) { + // + // No binary scaling and calculate minumum number of + // bits in which the data will fit. + // + imin=(g2int)rint(rmin*dscale); + imax=(g2int)rint(rmax*dscale); + maxdif=imax-imin; + temp=log((double)(maxdif+1))/alog2; + nbits=(g2int)ceil(temp); + rmin=(g2float)imin; + // scale data + for(j=0;j +#include +#include "grib2.h" + + +g2int simunpack(unsigned char *cpack,g2int *idrstmpl,g2int ndpts,g2float *fld) +////$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: simunpack +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-29 +// +// ABSTRACT: This subroutine unpacks a data field that was packed using a +// simple packing algorithm as defined in the GRIB2 documention, +// using info from the GRIB2 Data Representation Template 5.0. +// +// PROGRAM HISTORY LOG: +// 2002-10-29 Gilbert +// +// USAGE: int simunpack(unsigned char *cpack,g2int *idrstmpl,g2int ndpts, +// g2float *fld) +// INPUT ARGUMENT LIST: +// cpack - pointer to the packed data field. +// idrstmpl - pointer to the array of values for Data Representation +// Template 5.0 +// ndpts - The number of data values to unpack +// +// OUTPUT ARGUMENT LIST: +// fld - Contains the unpacked data values. fld must be allocated +// with at least ndpts*sizeof(g2float) bytes before +// calling this routine. +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$// +{ + + g2int *ifld; + g2int j,nbits,itype; + g2float ref,bscale,dscale; + + + rdieee(idrstmpl+0,&ref,1); + bscale = int_power(2.0,idrstmpl[1]); + dscale = int_power(10.0,-idrstmpl[2]); + nbits = idrstmpl[3]; + itype = idrstmpl[4]; + + ifld=(g2int *)calloc(ndpts,sizeof(g2int)); + if ( ifld == 0 ) { + fprintf(stderr,"Could not allocate space in simunpack.\n Data field NOT upacked.\n"); + return(1); + } + +// +// if nbits equals 0, we have a constant field where the reference value +// is the data value at each gridpoint +// + if (nbits != 0) { + gbits(cpack,ifld,0,nbits,0,ndpts); + for (j=0;j +#include +#include +#include "grib2.h" + + +void specpack(g2float *fld,g2int ndpts,g2int JJ,g2int KK,g2int MM, + g2int *idrstmpl,unsigned char *cpack,g2int *lcpack) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: specpack +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-12-19 +// +// ABSTRACT: This subroutine packs a spectral data field using the complex +// packing algorithm for spherical harmonic data as +// defined in the GRIB2 Data Representation Template 5.51. +// +// PROGRAM HISTORY LOG: +// 2002-12-19 Gilbert +// +// USAGE: void specpack(g2float *fld,g2int ndpts,g2int JJ,g2int KK,g2int MM, +// g2int *idrstmpl,insigned char *cpack,g2int *lcpack) +// INPUT ARGUMENT LIST: +// fld[] - Contains the packed data values +// ndpts - The number of data values to pack +// JJ - J - pentagonal resolution parameter +// KK - K - pentagonal resolution parameter +// MM - M - pentagonal resolution parameter +// idrstmpl - Contains the array of values for Data Representation +// Template 5.51 +// +// OUTPUT ARGUMENT LIST: +// cpack - The packed data field (character*1 array) +// lcpack - length of packed field cpack(). +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: IBM SP +// +//$$$ +{ + + g2int *ifld,tmplsim[5]; + g2float bscale,dscale,*unpk,*tfld; + g2float *pscale,tscale; + g2int Js,Ks,Ms,Ts,Ns,inc,incu,incp,n,Nm,m,ipos; + + bscale = int_power(2.0,-idrstmpl[1]); + dscale = int_power(10.0,idrstmpl[2]); + Js=idrstmpl[5]; + Ks=idrstmpl[6]; + Ms=idrstmpl[7]; + Ts=idrstmpl[8]; + +// +// Calculate Laplacian scaling factors for each possible wave number. +// + pscale=(g2float *)malloc((JJ+MM)*sizeof(g2float)); + tscale=(g2float)idrstmpl[4]*1E-6; + for (n=Js;n<=JJ+MM;n++) + pscale[n]=pow((g2float)(n*(n+1)),tscale); +// +// Separate spectral coeffs into two lists; one to contain unpacked +// values within the sub-spectrum Js, Ks, Ms, and the other with values +// outside of the sub-spectrum to be packed. +// + tfld=(g2float *)malloc(ndpts*sizeof(g2float)); + unpk=(g2float *)malloc(ndpts*sizeof(g2float)); + ifld=(g2int *)malloc(ndpts*sizeof(g2int)); + inc=0; + incu=0; + incp=0; + for (m=0;m<=MM;m++) { + Nm=JJ; // triangular or trapezoidal + if ( KK == JJ+MM ) Nm=JJ+m; // rhombodial + Ns=Js; // triangular or trapezoidal + if ( Ks == Js+Ms ) Ns=Js+m; // rhombodial + for (n=m;n<=Nm;n++) { + if (n<=Ns && m<=Ms) { // save unpacked value + unpk[incu++]=fld[inc++]; // real part + unpk[incu++]=fld[inc++]; // imaginary part + } + else { // Save value to be packed and scale + // Laplacian scale factor + tfld[incp++]=fld[inc++]*pscale[n]; // real part + tfld[incp++]=fld[inc++]*pscale[n]; // imaginary part + } + } + } + + free(pscale); + + if (incu != Ts) { + printf("specpack: Incorrect number of unpacked values %d given:\n",(int)Ts); + printf("specpack: Resetting idrstmpl[8] to %d\n",(int)incu); + Ts=incu; + } +// +// Add unpacked values to the packed data array in 32-bit IEEE format +// + mkieee(unpk,(g2int *)cpack,Ts); + ipos=4*Ts; +// +// Scale and pack the rest of the coefficients +// + tmplsim[1]=idrstmpl[1]; + tmplsim[2]=idrstmpl[2]; + tmplsim[3]=idrstmpl[3]; + simpack(tfld,ndpts-Ts,tmplsim,cpack+ipos,lcpack); + *lcpack=(*lcpack)+ipos; +// +// Fill in Template 5.51 +// + idrstmpl[0]=tmplsim[0]; + idrstmpl[1]=tmplsim[1]; + idrstmpl[2]=tmplsim[2]; + idrstmpl[3]=tmplsim[3]; + idrstmpl[8]=Ts; + idrstmpl[9]=1; // Unpacked spectral data is 32-bit IEEE + + free(tfld); + free(unpk); + free(ifld); + + return; +} diff --git a/src/plugins/weatherdata/gfs/g2clib/specunpack.c b/src/plugins/weatherdata/gfs/g2clib/specunpack.c new file mode 100644 index 000000000..5b35459a3 --- /dev/null +++ b/src/plugins/weatherdata/gfs/g2clib/specunpack.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include "grib2.h" + + +g2int specunpack(unsigned char *cpack,g2int *idrstmpl,g2int ndpts,g2int JJ, + g2int KK, g2int MM, g2float *fld) +//$$$ SUBPROGRAM DOCUMENTATION BLOCK +// . . . . +// SUBPROGRAM: specunpack +// PRGMMR: Gilbert ORG: W/NP11 DATE: 2000-06-21 +// +// ABSTRACT: This subroutine unpacks a spectral data field that was packed +// using the complex packing algorithm for spherical harmonic data as +// defined in the GRIB2 documention, +// using info from the GRIB2 Data Representation Template 5.51. +// +// PROGRAM HISTORY LOG: +// 2000-06-21 Gilbert +// +// USAGE: int specunpack(unsigned char *cpack,g2int *idrstmpl, +// g2int ndpts,g2int JJ,g2int KK,g2int MM,g2float *fld) +// INPUT ARGUMENT LIST: +// cpack - pointer to the packed data field. +// idrstmpl - pointer to the array of values for Data Representation +// Template 5.51 +// ndpts - The number of data values to unpack (real and imaginary parts) +// JJ - J - pentagonal resolution parameter +// KK - K - pentagonal resolution parameter +// MM - M - pentagonal resolution parameter +// +// OUTPUT ARGUMENT LIST: +// fld() - Contains the unpacked data values. fld must be allocated +// with at least ndpts*sizeof(g2float) bytes before +// calling this routine. +// +// REMARKS: None +// +// ATTRIBUTES: +// LANGUAGE: C +// MACHINE: +// +//$$$ +{ + + g2int *ifld,j,iofst,nbits; + g2float ref,bscale,dscale,*unpk; + g2float *pscale,tscale; + g2int Js,Ks,Ms,Ts,Ns,Nm,n,m; + g2int inc,incu,incp; + + rdieee(idrstmpl+0,&ref,1); + bscale = int_power(2.0,idrstmpl[1]); + dscale = int_power(10.0,-idrstmpl[2]); + nbits = idrstmpl[3]; + Js=idrstmpl[5]; + Ks=idrstmpl[6]; + Ms=idrstmpl[7]; + Ts=idrstmpl[8]; + + if (idrstmpl[9] == 1) { // unpacked floats are 32-bit IEEE + + unpk=(g2float *)malloc(ndpts*sizeof(g2float)); + ifld=(g2int *)malloc(ndpts*sizeof(g2int)); + + gbits(cpack,ifld,0,32,0,Ts); + iofst=32*Ts; + rdieee(ifld,unpk,Ts); // read IEEE unpacked floats + gbits(cpack,ifld,iofst,nbits,0,ndpts-Ts); // unpack scaled data +// +// Calculate Laplacian scaling factors for each possible wave number. +// + pscale=(g2float *)malloc((JJ+MM+1)*sizeof(g2float)); + tscale=(g2float)idrstmpl[4]*1E-6; + for (n=Js;n<=JJ+MM;n++) + pscale[n]=pow((g2float)(n*(n+1)),-tscale); +// +// Assemble spectral coeffs back to original order. +// + inc=0; + incu=0; + incp=0; + for (m=0;m<=MM;m++) { + Nm=JJ; // triangular or trapezoidal + if ( KK == JJ+MM ) Nm=JJ+m; // rhombodial + Ns=Js; // triangular or trapezoidal + if ( Ks == Js+Ms ) Ns=Js+m; // rhombodial + for (n=m;n<=Nm;n++) { + if (n<=Ns && m<=Ms) { // grab unpacked value + fld[inc++]=unpk[incu++]; // real part + fld[inc++]=unpk[incu++]; // imaginary part + } + else { // Calc coeff from packed value + fld[inc++]=(((g2float)ifld[incp++]*bscale)+ref)* + dscale*pscale[n]; // real part + fld[inc++]=(((g2float)ifld[incp++]*bscale)+ref)* + dscale*pscale[n]; // imaginary part + } + } + } + + free(pscale); + free(unpk); + free(ifld); + + } + else { + printf("specunpack: Cannot handle 64 or 128-bit floats.\n"); + for (j=0;j +#include +#include + +using namespace BlackMisc; +using namespace BlackMisc::Aviation; +using namespace BlackMisc::Geo; +using namespace BlackMisc::PhysicalQuantities; +using namespace BlackMisc::Weather; +using namespace BlackMisc::Math; + +namespace BlackWxPlugin +{ + namespace Gfs + { + const CWeatherDataGfs::Grib2ParameterTable CWeatherDataGfs::m_grib2ParameterTable + { + { {0, 0}, { TMP, "Temperature", "K" } }, + { {1, 1}, { RH, "Relative Humidity", "%" } }, + { {2, 2}, { UGRD, "U-Component of Wind", "m s-1" } }, + { {2, 3}, { VGRD, "V-Component of Wind", "m s-1" } }, + { {3, 0}, { PRES, "Pressure", "Pa" } }, + { {3, 1}, { PRMSL, "Pressure Reduced to MSL", "Pa" } }, + { {6, 1}, { TCDC, "Total Cloud Cover", "%" } }, + }; + + double millibarToLevel(double millibar) + { + millibar /= 100; + double level = (1 - std::pow(millibar / 1013.25, 0.190284)) * 145366.45; + return level; + } + + CWeatherDataGfs::CWeatherDataGfs(QObject *parent) : + IWeatherData(parent), + m_networkAccessManager(this) + { + connect(&m_networkAccessManager, &QNetworkAccessManager::finished, this, &CWeatherDataGfs::ps_parseGfsFile); + } + + void CWeatherDataGfs::fetchWeatherData(const CLatitude &latitude, const CLongitude &longitude, double maxDistance) + { + m_latitude = latitude; + m_longitude = longitude; + m_maxDistance = maxDistance; + if (m_gribData.isEmpty()) + { + CLogMessage(this).debug() << "Started to download GFS data..."; + QUrl url = getDownloadUrl(); + CLogMessage(this).debug() << "Download url:" << url.toString(); + QNetworkRequest request(url); + m_networkAccessManager.get(request); + } + else + { + CLogMessage(this).debug() << "Using cached data"; + CWorker *worker = BlackMisc::CWorker::fromTask(this, "parseGribFile", [this]() + { + parseGfsFileImpl(m_gribData); + }); + worker->then(this, &CWeatherDataGfs::ps_fetchingWeatherDataFinished); + } + } + + CWeatherGrid CWeatherDataGfs::getWeatherData() const + { + QReadLocker l(&m_lockData); + return m_weatherGrid; + } + + void CWeatherDataGfs::ps_fetchingWeatherDataFinished() + { + emit fetchingFinished(); + } + + void CWeatherDataGfs::ps_parseGfsFile(QNetworkReply *reply) + { + CLogMessage(this).debug() << "finished"; + m_gribData = reply->readAll(); + CWorker *worker = BlackMisc::CWorker::fromTask(this, "parseGribFile", [this]() + { + parseGfsFileImpl(m_gribData); + }); + worker->then(this, &CWeatherDataGfs::ps_fetchingWeatherDataFinished); + reply->deleteLater(); + } + + QUrl CWeatherDataGfs::getDownloadUrl() const + { + QString baseurl = "http://nomads.ncep.noaa.gov/cgi-bin/filter_gfs_0p50.pl?"; + + static const QStringList grib2Levels = + { + "100_mb", + "150_mb", + "200_mb", + "300_mb", + "400_mb", + "500_mb", + "600_mb", + "700_mb", + "800_mb", + "900_mb", + "high_cloud_bottom_level", + "high_cloud_layer", + "high_cloud_top_level", + "low_cloud_bottom_level", + "low_cloud_layer", + "low_cloud_top_level", + "middle_cloud_bottom_level", + "middle_cloud_layer", + "middle_cloud_top_level", + }; + + static const QStringList grib2Variables = + { + "PRES", + "PRMSL", + "RH", + "TCDC", + "TMP", + "UGRD", + "VGRD", + }; + + static const std::array cycles = { 0, 6, 12, 18 }; + const QDateTime now = QDateTime::currentDateTimeUtc(); + + // GFS data is published after 4 yours. + const QDateTime cnow = now.addSecs( -5 * 60 * 60); + + int hourLastPublishedCycle = 0; + for (const auto &cycle : cycles) + { + if (cnow.time().hour() > cycle) { hourLastPublishedCycle = cycle; } + } + + // Forecast is published in 3 hours steps. + // Round down to a multiple of 3 + int forecast = now.time().hour() - hourLastPublishedCycle; + if (forecast < 0) { forecast += 24; } + forecast = CMathUtils::roundToMultipleOf(forecast, 3); + + QString filename("gfs.t%1z.pgrb2full.0p50.f%2"); + filename = filename.arg(hourLastPublishedCycle, 2, 10, QLatin1Char('0')); + filename = filename.arg(forecast, 3, 10, QLatin1Char('0')); + + QString directory("gfs.%1%2"); + directory = directory.arg(cnow.toString("yyyyMMdd")); + directory = directory.arg(hourLastPublishedCycle, 2, 10, QLatin1Char('0')); + + QStringList params; + params.append("file=" + filename); + for (const auto &level : grib2Levels) + { + params.append("lev_" + level + "=on"); + } + for (const auto &variable : grib2Variables) + { + params.append("var_" + variable + "=on"); + } + params.append("leftlon=0"); + params.append("rightlon=360"); + params.append("toplat=90"); + params.append("bottomlat=-90"); + params.append("dir=%2F" + directory); + + return QUrl(baseurl + params.join('&')); + } + + void CWeatherDataGfs::parseGfsFileImpl(const QByteArray &gribData) + { + QWriteLocker lock(&m_lockData); + + m_gfsWeatherGrid.clear(); + m_weatherGrid.clear(); + + int messageNo = 0; + g2int iseek = 0; + for(;;) + { + // Search next grib field + g2int lskip = 0; + g2int lgrib = 0; + findNextGribMessage((unsigned char*)gribData.data(), gribData.size(), iseek, &lskip, &lgrib); + if (lgrib == 0) { break; } + + unsigned char *readPtr = (unsigned char*)gribData.data() + lskip; + iseek=lskip + lgrib; + + g2int sec0[3]; + g2int sec1[13]; + g2int numlocal = 0; + g2int numfields = 0; + g2_info(readPtr, sec0, sec1, &numfields, &numlocal); + + CLogMessage(this).debug() << "Parsing grib message no:" << messageNo; + for (int n = 0; n < numfields; n++) + { + g2int unpack = 1; + g2int expand = 1; + gribfield *gfld = nullptr; + g2_getfld(readPtr, n + 1, unpack, expand, &gfld); + if (gfld->idsectlen < 12) { CLogMessage(this).warning("Identification section: wrong length!"); continue; } + + if (gfld->igdtnum != 0) { CLogMessage(this).warning("Can handle only grid definition template number = 0"); } + + int nscan = gfld->igdtmpl[18]; + int npnts = gfld->ngrdpts; + int nx = gfld->igdtmpl[7]; + int ny = gfld->igdtmpl[8]; + if (nscan != 0) { CLogMessage(this).error("Can only handle scanning mode NS:WE."); } + if (npnts != nx * ny) { CLogMessage(this).error("Cannot handle non-regular grid."); } + + if (m_gfsWeatherGrid.empty()) { createWeatherGrid(gfld); } + + if (gfld->ipdtnum == 0) { handleProductDefinitionTemplate40(gfld); } + else if (gfld->ipdtnum == 8) { handleProductDefinitionTemplate48(gfld); } + else { CLogMessage(this).warning("Cannot handle product definition template %1") << gfld->ipdtnum; continue; } + + g2_free(gfld); + } + messageNo++; + } + + for (const GfsGridPoint &gfsGridPoint : m_gfsWeatherGrid) + { + CTemperatureLayerList temperatureLayers; + CWindLayerList windLayers; + for (auto isobaricLayerIt = gfsGridPoint.isobaricLayers.begin(); isobaricLayerIt != gfsGridPoint.isobaricLayers.end(); ++isobaricLayerIt) + { + GfsIsobaricLayer isobaricLayer = isobaricLayerIt.value(); + CAltitude level(isobaricLayerIt.key(), CAltitude::MeanSeaLevel, CLengthUnit::ft()); + + CTemperatureLayer temperature(level, CTemperature(isobaricLayer.temperature, CTemperatureUnit::K()), isobaricLayer.relativeHumidity); + temperatureLayers.insert(temperature); + + double windDirection = -1 * CMathUtils::rad2deg(std::atan2(-isobaricLayer.windU, isobaricLayer.windV)); + windDirection += 180.0; + if (windDirection < 0.0) { windDirection += 360.0; } + if (windDirection >= 360.0) { windDirection -= 360.0; } + double windSpeed = std::hypot(isobaricLayer.windU, isobaricLayer.windV); + CWindLayer windLayer(level, CAngle(windDirection, CAngleUnit::deg()), CSpeed(windSpeed, CSpeedUnit::m_s()), {}); + windLayers.insert(windLayer); + } + + CCloudLayerList cloudLayers; + for(auto cloudLayerIt = gfsGridPoint.cloudLayers.begin(); cloudLayerIt != gfsGridPoint.cloudLayers.end(); ++cloudLayerIt) + { + CCloudLayer cloudLayer; + cloudLayer.setBase(CAltitude(cloudLayerIt.value().bottomLevel, CAltitude::MeanSeaLevel, CLengthUnit::ft())); + cloudLayer.setCeiling(CAltitude(cloudLayerIt.value().topLevel, CAltitude::MeanSeaLevel, CLengthUnit::ft())); + cloudLayer.setCoveragePercent(cloudLayerIt.value().totalCoverage); + cloudLayers.insert(cloudLayer); + } + + CLatitude latitude(gfsGridPoint.latitude, CAngleUnit::deg()); + CLongitude longitude(gfsGridPoint.longitude, CAngleUnit::deg()); + BlackMisc::Weather::CGridPoint gridPoint(latitude, longitude, cloudLayers, temperatureLayers, windLayers); + m_weatherGrid.insert(gridPoint); + } + } + + void CWeatherDataGfs::findNextGribMessage(unsigned char *buffer, g2int size, g2int iseek, g2int *lskip, g2int *lgrib) + { + *lgrib = 0; + + if (iseek >= size) return; + g2int ipos = iseek; + unsigned char *bufferStart = buffer + iseek; + + // READ PARTIAL SECTION + g2int lim = size - 8; + + for (g2int k = 0; k < lim; k++) + { + g2int start; + g2int vers; + // Look for "GRIB" at the beginning + gbit(bufferStart,&start,(k+0)*8,4*8); + gbit(bufferStart,&vers,(k+7)*8,1*8); + if (start == 1196575042 && (vers == 1 || vers == 2)) + { + g2int lengrib; + // Look for '7777' at end of GRIB message + if (vers == 1) gbit(bufferStart,&lengrib,(k+4)*8,3*8); + if (vers == 2) gbit(bufferStart,&lengrib,(k+12)*8,4*8); + + // Check the limits + g2int endPos = ipos + k + lengrib; + if (endPos > size) return; + unsigned char *bufferEnd = buffer + endPos - 4; + // Hard code to 4 instead of sizeof(g2int) + g2int end; + gbit(bufferEnd,&end, 0, 4*8); + if (end == 926365495) + { + // GRIB message found + *lskip=ipos+k; + *lgrib=lengrib; + return; + } + } + } + } + + void CWeatherDataGfs::createWeatherGrid(const gribfield *gfld) + { + int npnts = gfld->ngrdpts; + int nx = gfld->igdtmpl[7]; + int ny = gfld->igdtmpl[8]; + double units = 0.000001; + double latitude1 = gfld->igdtmpl[11] * units; + double longitude1 = gfld->igdtmpl[12] * units; + int nres = gfld->igdtmpl[13]; + double latitude2 = gfld->igdtmpl[14] * units; + double longitude2 = gfld->igdtmpl[15] * units; + double dlatitude = gfld->igdtmpl[16] * units; + double dlongitude = gfld->igdtmpl[17] * units; + + if (latitude1 < -90.0 || latitude2 < -90.0 || latitude1 > 90.0 || latitude2 > 90.0) + { + CLogMessage(this).warning("Invalid grid definition: lat1 = %1 - lat2 = %2") << latitude1 << latitude2; + return; + } + if (longitude1 < 0.0 || longitude2 < 0.0 || longitude1 > 360.0 || longitude2 > 360.0) + { + CLogMessage(this).warning("Invalid grid definition: lon1 = %1 - lon2 = %2") << longitude1 << longitude2; + return; + } + if (npnts != nx * ny) + { + CLogMessage(this).warning("Invalid grid definition: npnts != nx * ny!"); + return; + } + + // Scan direction is North -> South + double north = latitude1; + double south = latitude2; + + if (south > north) + { + CLogMessage(this).warning("Invalid grid definition: South = %1 - North = %2") << south << north; + return; + } + + double dy = 0; + if (ny != 1) + { + dy = (north - south) / (ny - 1.0); + if (nres & 16) + { + if (fabs(dy - dlatitude) > 0.001) + { + CLogMessage(this).warning("Invalid grid definition: delta latitude is inconsistent"); + return; + } + } + } + else + { + dy = 0.0; + } + + // Scan direction is West -> East + double west = longitude1; + double east = longitude2; + if (east <= west) { east += 360.0; } + if (east - west > 360.0) { east -= 360.0; } + if (west < 0) + { + west += 360.0; + east += 360.0; + } + + double dx = 0; + if (nx != 1) + { + dx = (east - west) / (nx - 1); + dx = fabs(dx); + if (nres & 32) + { + if (fabs(dx - fabs(dlongitude)) > 0.001) + { + CLogMessage(this).warning("Invalid grid definition: delta longitude is inconsistent"); + return; + } + } + } + else + { + dx = 0.0; + } + dy = fabs(dy); + + if (nx > 0 && ny > 0) + { + for (int iy = 0; iy < ny; iy++) + { + int i = nx * iy; + for (int ix = 0; ix < nx; ix++) + { + GfsGridPoint gridPoint; + gridPoint.latitude = latitude1 - iy * dy; + gridPoint.longitude = longitude1 + ix * dx; + if(gridPoint.longitude >= 360.0) { gridPoint.longitude -= 360.0; } + if(gridPoint.longitude < 0.0) { gridPoint.longitude += 360.0; } + gridPoint.fieldPosition = ix + i; + CCoordinateGeodetic gridPointPosition(gridPoint.latitude, gridPoint.longitude, 0); + CCoordinateGeodetic centralPosition(m_latitude, m_longitude, {0}); + if ((m_maxDistance == -1) || calculateEuclideanDistance(gridPointPosition, centralPosition) < m_maxDistance ) + { + m_gfsWeatherGrid.append(gridPoint); + } + } + } + } + } + + void CWeatherDataGfs::handleProductDefinitionTemplate40(const gribfield *gfld) + { + if (gfld->ipdtlen != 15) + { + CLogMessage(this).warning("Template 4.0 has wrong length"); + return; + } + + g2int parameterCategory = gfld->ipdtmpl[0]; + g2int parameterNumber = gfld->ipdtmpl[1]; + g2int valueFirstFixedSurface = gfld->ipdtmpl[11]; + + std::array key { parameterCategory, parameterNumber }; + // Make sure the key exists + if (!m_grib2ParameterTable.contains(key)) + { + CLogMessage(this).warning("Unknown GRIB2 parameter: %1 - %2") << parameterCategory << parameterNumber; + return; + } + + double level = std::round(millibarToLevel(valueFirstFixedSurface)); + auto parameterValue = m_grib2ParameterTable[key]; + + switch (parameterValue.code) + { + case TMP: + setTemperature(gfld->fld, level); + break; + case RH: + setHumidity(gfld->fld, level); + break; + case UGRD: + setWindU(gfld->fld, level); + break; + case VGRD: + setWindV(gfld->fld, level); + break; + case PRMSL: + break; + default: + Q_ASSERT(false); + break; + } + } + + void CWeatherDataGfs::handleProductDefinitionTemplate48(const gribfield *gfld) + { + if (gfld->ipdtlen != 29) + { + CLogMessage(this).warning("Template 4.8 has wrong length."); + return; + } + + g2int parameterCategory = gfld->ipdtmpl[0]; + g2int parameterNumber = gfld->ipdtmpl[1]; + g2int typeFirstFixedSurface = gfld->ipdtmpl[9]; + + std::array key { parameterCategory, parameterNumber }; + // Make sure the key exists + if (!m_grib2ParameterTable.contains(key)) + { + CLogMessage(this).warning("Unknown GRIB2 parameter: %1 - %2") << parameterCategory << parameterNumber; + return; + } + + static const QHash grib2CloudLevelHash = + { + { LowCloudBottomLevel, LowCloud }, + { LowCloudTopLevel, LowCloud }, + { LowCloudLayer, LowCloud }, + { MiddleCloudBottomLevel, MiddleCloud }, + { MiddleCloudTopLevel, MiddleCloud }, + { MiddleCloudLayer, MiddleCloud }, + { HighCloudBottomLevel, HighCloud }, + { HighCloudTopLevel, HighCloud }, + { HighCloudLayer, HighCloud }, + }; + + auto parameterValue = m_grib2ParameterTable[key]; + switch (parameterValue.code) + { + case TCDC: + setCloudCoverage(gfld->fld, grib2CloudLevelHash.value(typeFirstFixedSurface)); + break; + case PRES: + setCloudLevel(gfld->fld, typeFirstFixedSurface, grib2CloudLevelHash.value(typeFirstFixedSurface)); + break; + default: + break; + } + } + + void CWeatherDataGfs::setTemperature(const g2float *fld, double level) + { + for (auto gridPointIt = m_gfsWeatherGrid.begin(); gridPointIt < m_gfsWeatherGrid.end(); ++gridPointIt) + { + gridPointIt->isobaricLayers[level].temperature = fld[gridPointIt->fieldPosition]; + } + } + + void CWeatherDataGfs::setHumidity(const g2float *fld, double level) + { + for (auto gridPointIt = m_gfsWeatherGrid.begin(); gridPointIt < m_gfsWeatherGrid.end(); ++gridPointIt) + { + gridPointIt->isobaricLayers[level].relativeHumidity = fld[gridPointIt->fieldPosition]; + } + } + + void CWeatherDataGfs::setWindV(const g2float *fld, double level) + { + for (auto gridPointIt = m_gfsWeatherGrid.begin(); gridPointIt < m_gfsWeatherGrid.end(); ++gridPointIt) + { + gridPointIt->isobaricLayers[level].windV = fld[gridPointIt->fieldPosition]; + } + } + + void CWeatherDataGfs::setWindU(const g2float *fld, double level) + { + for (auto gridPointIt = m_gfsWeatherGrid.begin(); gridPointIt < m_gfsWeatherGrid.end(); ++gridPointIt) + { + gridPointIt->isobaricLayers[level].windU = fld[gridPointIt->fieldPosition]; + } + } + + void CWeatherDataGfs::setCloudCoverage(const g2float *fld, int level) + { + for (auto gridPointIt = m_gfsWeatherGrid.begin(); gridPointIt < m_gfsWeatherGrid.end(); ++gridPointIt) + { + if(fld[gridPointIt->fieldPosition] > 0.0) { gridPointIt->cloudLayers[level].totalCoverage = fld[gridPointIt->fieldPosition]; } + } + } + + void CWeatherDataGfs::setCloudLevel(const g2float *fld, int surfaceType, int level) + { + for (auto gridPointIt = m_gfsWeatherGrid.begin(); gridPointIt < m_gfsWeatherGrid.end(); ++gridPointIt) + { + static const g2float minimumLayer = 0.0; + switch(surfaceType) + { + case LowCloudBottomLevel: + case MiddleCloudBottomLevel: + case HighCloudBottomLevel: + if (fld[gridPointIt->fieldPosition] > minimumLayer) { gridPointIt->cloudLayers[level].bottomLevel = millibarToLevel(fld[gridPointIt->fieldPosition]); } + break; + case LowCloudTopLevel: + case MiddleCloudTopLevel: + case HighCloudTopLevel: + if (fld[gridPointIt->fieldPosition] > minimumLayer) { gridPointIt->cloudLayers[level].topLevel = millibarToLevel(fld[gridPointIt->fieldPosition]); } + break; + default: + Q_ASSERT(false); + break; + } + } + } + + BlackCore::IWeatherData *CWeatherDataGfsFactory::create(QObject *parent) + { + return new CWeatherDataGfs(parent); + } + + } // namespace +} // namespace diff --git a/src/plugins/weatherdata/gfs/weatherdatagfs.h b/src/plugins/weatherdata/gfs/weatherdatagfs.h new file mode 100644 index 000000000..ebe1618e5 --- /dev/null +++ b/src/plugins/weatherdata/gfs/weatherdatagfs.h @@ -0,0 +1,169 @@ +/* Copyright (C) 2016 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKWXPLUGIN_GFS_H +#define BLACKWXPLUGIN_GFS_H + +#include "g2clib/grib2.h" +#include "blackmisc/weather/gridpoint.h" +#include "blackcore/weatherdata.h" +#include +#include +#include +#include +#include +#include +#include + +class QNetworkAccessManager; + +namespace BlackWxPlugin +{ + namespace Gfs + { + /*! + * GFS implemenation + */ + class CWeatherDataGfs : public BlackCore::IWeatherData + { + Q_OBJECT + + public: + //! Constructor + CWeatherDataGfs(QObject *parent = nullptr); + + //! \copydoc BlackCore::IWeatherData::fetchWeatherData() + virtual void fetchWeatherData(const BlackMisc::Geo::CLatitude &latitude, const BlackMisc::Geo::CLongitude &longitude, double maxDistance = -1) override; + + //! \copydoc BlackCore::IWeatherData::getWeatherData() + virtual BlackMisc::Weather::CWeatherGrid getWeatherData() const override; + + private slots: + //! Asyncronous fetching finished + //! \threadsafe + void ps_fetchingWeatherDataFinished(); + + void ps_parseGfsFile(QNetworkReply *reply); + + private: + enum Grib2CloudLevel + { + LowCloud, + MiddleCloud, + HighCloud + }; + + enum Grib2ParameterCode + { + UNKNOWN, + TMP, + RH, + UGRD, + VGRD, + PRES, + PRMSL, + TCDC + }; + + enum Grib2FixedSurfaceTypes + { + IsobaricSurface = 100, + LowCloudBottomLevel = 212, + LowCloudTopLevel = 213, + LowCloudLayer = 214, + MiddleCloudBottomLevel = 222, + MiddleCloudTopLevel = 223, + MiddleCloudLayer = 224, + HighCloudBottomLevel = 232, + HighCloudTopLevel = 233, + HighCloudLayer = 234 + }; + + struct Grib2ParameterValue + { + Grib2ParameterValue() = default; + Grib2ParameterValue(Grib2ParameterCode code_, const QString &name_, const QString &unit_) : code(code_), name(name_), unit(unit_) {} + Grib2ParameterCode code = UNKNOWN; + QString name; + QString unit; + }; + + struct GfsIsobaricLayer + { + double temperature = 0.0; + double relativeHumidity = 0.0; + double windU = 0.0; + double windV = 0.0; + }; + + struct GfsCloudLayer + { + double bottomLevel = 0.0; + double topLevel = 0.0; + double totalCoverage = 0.0; + }; + + struct GfsGridPoint + { + double latitude = 0.0; + double longitude = 0.0; + int fieldPosition = 0; + QHash cloudLayers; + QHash isobaricLayers; + }; + + QUrl getDownloadUrl() const; + + void parseGfsFileImpl(const QByteArray &gribData); + void findNextGribMessage(unsigned char *buffer, g2int size, g2int iseek, g2int *lskip, g2int *lgrib); + void createWeatherGrid(const gribfield *gfld); + void handleProductDefinitionTemplate40(const gribfield *gfld); + void handleProductDefinitionTemplate48(const gribfield *gfld); + void setTemperature(const g2float *fld, double level); + void setHumidity(const g2float *fld, double level); + void setWindV(const g2float *fld, double level); + void setWindU(const g2float *fld, double level); + void setCloudCoverage(const g2float *fld, int level); + void setCloudLevel(const g2float *fld, int surfaceType, int level); + + BlackMisc::Geo::CLatitude m_latitude; + BlackMisc::Geo::CLongitude m_longitude; + double m_maxDistance = -1; + + mutable QReadWriteLock m_lockData; + QByteArray m_gribData; + QNetworkAccessManager m_networkAccessManager; + + QVector m_gfsWeatherGrid; + BlackMisc::Weather::CWeatherGrid m_weatherGrid; + + using Grib2ParameterKey = std::array; + using Grib2ParameterTable = QMap; + static const Grib2ParameterTable m_grib2ParameterTable; + }; + + //! Factory for creating CWeatherDataGfs instance + class CWeatherDataGfsFactory : public QObject, public BlackCore::IWeatherDataFactory + { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.swift-project.blackcore.weatherdata" FILE "weatherdatagfs.json") + Q_INTERFACES(BlackCore::IWeatherDataFactory) + + public: + //! \copydoc BlackCore::IWeatherDataFactory::create() + virtual BlackCore::IWeatherData *create(QObject *parent = nullptr) override; + + }; + + } // ns +} // ns + +#endif // guard diff --git a/src/plugins/weatherdata/gfs/weatherdatagfs.json b/src/plugins/weatherdata/gfs/weatherdatagfs.json new file mode 100644 index 000000000..4fd1633a4 --- /dev/null +++ b/src/plugins/weatherdata/gfs/weatherdatagfs.json @@ -0,0 +1,5 @@ +{ + "identifier" : "org.swift-project.plugins.weatherdata.gfs", + "name" : "gfs", + "description" : "Global forecast from National Centers for Environmental Prediction." +} diff --git a/src/plugins/weatherdata/weatherdata.pro b/src/plugins/weatherdata/weatherdata.pro new file mode 100644 index 000000000..165a3907c --- /dev/null +++ b/src/plugins/weatherdata/weatherdata.pro @@ -0,0 +1,8 @@ +load(common_pre) + +TEMPLATE = subdirs +CONFIG += ordered + +SUBDIRS += gfs + +load(common_post)