398 lines
20 KiB
C
398 lines
20 KiB
C
/*****************************************************************************
|
|
* meta.h
|
|
*
|
|
* DESCRIPTION
|
|
* This file contains the code necessary to handle the meta data that
|
|
* comes out of the GRIB2 decoder. This includes parsing the integer arrays
|
|
* to create a meta structure, and providing routines to write the meta
|
|
* structure to disk.
|
|
*
|
|
* HISTORY
|
|
* 9/2002 Arthur Taylor (MDL / RSIS): Created.
|
|
*
|
|
* NOTES
|
|
*****************************************************************************
|
|
*/
|
|
#ifndef META_H
|
|
#define META_H
|
|
|
|
#include <time.h>
|
|
/* Include type.h for uChar and sChar */
|
|
#include "type.h"
|
|
#ifdef MEMWATCH
|
|
#include "memwatch.h"
|
|
#endif
|
|
|
|
#ifndef GRIB2BIT_ENUM
|
|
#define GRIB2BIT_ENUM
|
|
/* See rule (8) bit 1 is most significant, bit 8 least significant. */
|
|
enum {GRIB2BIT_1=128, GRIB2BIT_2=64, GRIB2BIT_3=32, GRIB2BIT_4=16,
|
|
GRIB2BIT_5=8, GRIB2BIT_6=4, GRIB2BIT_7=2, GRIB2BIT_8=1};
|
|
#endif
|
|
|
|
#ifndef UNITCONVERT_ENUM
|
|
#define UNITCONVERT_ENUM
|
|
typedef enum { UC_NONE, UC_K2F, UC_InchWater, UC_M2Feet, UC_M2Inch,
|
|
UC_MS2Knots
|
|
} unit_convert;
|
|
#endif
|
|
|
|
/* For GRIB1 GDS Types. */
|
|
enum { GB1S2_LATLON = 0, GB1S2_MERCATOR = 1, GB1S2_LAMBERT = 3,
|
|
GB1S2_POLAR = 5
|
|
};
|
|
|
|
#define GRIB2MISSING_1 (int) (0xff)
|
|
#define GRIB2MISSING_2 (int) (0xffff)
|
|
#define GRIB2MISSING_4 (long int) (0xffffffff)
|
|
|
|
#define NUM_UGLY_WORD 5
|
|
#define NUM_UGLY_ATTRIB 5
|
|
|
|
typedef struct {
|
|
uChar numValid; /* (0..5) How many valid "types" */
|
|
uChar wx[NUM_UGLY_WORD]; /* (see WxCode) */
|
|
uChar cover[NUM_UGLY_WORD]; /* (see WxCover) */
|
|
uChar intens[NUM_UGLY_WORD]; /* (see WxIntens) */
|
|
uChar vis[NUM_UGLY_WORD]; /* 255 no vis, otherwise in units of 1/32 SM
|
|
* so 6SM -> 192. P6SM -> 224 */
|
|
uChar f_or[NUM_UGLY_WORD]; /* true if OR, or MX was a hazzard. */
|
|
uChar attrib[NUM_UGLY_WORD][NUM_UGLY_ATTRIB]; /* (see WxAttrib) */
|
|
uChar minVis; /* vis[] should be constant, but just in case
|
|
* we use the minimum value. */
|
|
uChar f_valid; /* 1 valid may be not-used, 2 valid and used,
|
|
* 0 invalid may be not-used,
|
|
* temporarily 3 (invalid and used). */
|
|
long int validIndex; /* Which index this is, counting only used
|
|
* valid indexes. If it is not used it is -1 */
|
|
char *english[NUM_UGLY_WORD]; /* The english translation of ugly string. */
|
|
uChar wx_inten[NUM_UGLY_WORD]; /* A code to represent the wx and
|
|
intensity for an "ugly word". */
|
|
long int HazCode[NUM_UGLY_WORD]; /* A code to represent all the attributes. */
|
|
int SimpleCode; /* Simple weather code for this ugly string. */
|
|
char *errors; /* if STORE_ERRORS, then it contains any error
|
|
* messages found while parsing this string. */
|
|
} UglyStringType;
|
|
|
|
typedef struct {
|
|
char **data; /* Array of text strings (aka "ugly strings) */
|
|
long int dataLen; /* number of text strings in data. */
|
|
int maxLen; /* Max Length of all of the "ugly strings"
|
|
* It includes 1 for the \0 character. */
|
|
UglyStringType *ugly; /* The parsed Ugly string. */
|
|
int maxEng[NUM_UGLY_WORD]; /* Max length of english phrases for all ugly
|
|
* word number X. */
|
|
} sect2_WxType;
|
|
|
|
typedef struct {
|
|
double *data; /* Array of actual values (cast from int or
|
|
float to double). */
|
|
long int dataLen; /* Number of elements in data. */
|
|
} sect2_UnknownType;
|
|
|
|
enum { GS2_NONE, GS2_WXTYPE, GS2_UNKNOWN };
|
|
|
|
typedef struct {
|
|
/* void *ptr; */ /* Pointer to section 2 data. */
|
|
sect2_WxType wx; /* wx data. */
|
|
sect2_UnknownType unknown; /* unknown type of section 2 data. */
|
|
uChar ptrType; /* Which structure is valid.
|
|
GS2_WXTYPE => wx
|
|
GS2_UNKNOWN => unknown */
|
|
} sect2_type;
|
|
|
|
enum { CAT_TEMP, CAT_MOIST, CAT_MOMENT, CAT_MASS, CAT_SW_RAD,
|
|
CAT_LW_RAD, CAT_CLOUD, CAT_THERMO_INDEX, CAT_KINEMATIC_INDEX,
|
|
CAT_TEMP_PROB, CAT_MOISTURE_PROB, CAT_MOMENT_PROB, CAT_MASS_PROB,
|
|
CAT_AEROSOL, CAT_TRACE, CAT_RADAR, CAT_RADAR_IMAGERY, CAT_ELECTRO,
|
|
CAT_NUCLEAR, CAT_PHYS_ATMOS };
|
|
enum { TEMP_TEMP, TEMP_VIRT, TEMP_POTENTIAL, TEMP_PSEUDO_POTENTIAL,
|
|
TEMP_MAXT, TEMP_MINT, TEMP_DEW_TEMP, TEMP_DEW_DEPRESS,
|
|
TEMP_LAPSE, TEMP_ANOMALY, TEMP_LATENT_FLUX, TEMP_SENSIBLE_FLUX,
|
|
TEMP_HEAT, TEMP_WINDCHILL, TEMP_MIN_DEW_DEPRESS, TEMP_VIRT_POTENTIAL };
|
|
enum { CLOUD_ICE, CLOUD_COVER, CLOUD_CONVECT_COVER, CLOUD_LOW,
|
|
CLOUD_MEDIUM, CLOUD_HIGH, CLOUD_WATER, CLOUD_AMNT, CLOUD_TYPE,
|
|
CLOUD_THUDER_MAX, CLOUD_THUNDER_COVER, CLOUD_BASE, CLOUD_TOP,
|
|
CLOUD_CEIL };
|
|
enum { MOMENT_WINDDIR, MOMENT_WINDSPD, MOMENT_U_WIND, MOMENT_V_WIND,
|
|
MOMENT_STREAM, MOMENT_VEL_POTENT, MOMENT_MONT_STREAM,
|
|
MOMENT_SIGMA_VERTVEL, MOMENT_VERTVEL_PRESS, MOMENT_VERTVEL_GEOMETRIC,
|
|
MOMENT_ABS_VORT, MOMENT_ABS_DIV, MOMENT_REL_VORT, MOMENT_REL_DIV,
|
|
MOMENT_POT_VORT, MOMENT_VERT_U_SHEAR, MOMENT_VERT_V_SHEAR,
|
|
MOMENT_U_FLUX, MOMENT_V_FLUX, MOMENT_MIX_ENERGY,
|
|
MOMENT_BOUNDARY_DISSPATE, MOMENT_MAX_WINDSPD, MOMENT_GUSTSPD,
|
|
MOMENT_U_GUSTSPD, MOMENT_V_GUSTSPD };
|
|
enum { MOIST_SPEC_HUMID, MOIST_REL_HUMID, MOIST_HUMID_MIX, MOIST_PRECIP_WATER,
|
|
MOIST_VAPOR_PRESS, MOIST_SAT_DEFICIT, MOIST_EVAP, MOIST_PRECIP_RATE,
|
|
MOIST_PRECIP_TOT, MOIST_LARGE_SCALE, MOIST_CONVECT_PRECIP,
|
|
MOIST_SNOWAMT, MOIST_SNOWRATE_WATER, MOIST_SNOWAMT_WATER,
|
|
MOIST_CONVECT_SNOW, MOIST_LARGE_SCALE_SNOW, MOIST_SNOWMELT,
|
|
MOIST_SNOWAGE, MOIST_ABS_HUMID, MOIST_PRECIP_TYPE,
|
|
MOIST_INTEGRATE_WATER, MOIST_CONDENSATE, MOIST_CLOUDMIX_RATIO,
|
|
MOIST_ICEMIX_RATIO, MOIST_RAINMIX_RATIO, MOIST_SNOWMIX_RATIO,
|
|
MOIST_HORIZ_CONVERGE, MOIST_MAXREL_HUMID, MOIST_MAXABS_HUMID,
|
|
MOIST_TOT_SNOW, MOIST_PRECIP_WATER_CAT, MOIST_HAIL, MOIST_GRAUPEL };
|
|
enum { OCEAN_CAT_WAVES, OCEAN_CAT_CURRENT, OCEAN_CAT_ICE,
|
|
OCEAN_CAT_SURF, OCEAN_CAT_SUBSURF };
|
|
enum { OCEAN_WAVE_SPECTRA1, OCEAN_WAVE_SPECTRA2, OCEAN_WAVE_SPECTRA3,
|
|
OCEAN_WAVE_SIG_HT_WV_SWELL, OCEAN_WAVE_DIR_WV,
|
|
OCEAN_WAVE_SIG_HT_WV, OCEAN_WAVE_PD_WV, OCEAN_WAVE_DIR_SWELL,
|
|
OCEAN_WAVE_SIG_HT_SWELL, OCEAN_WAVE_PD_SWELL, OCEAN_WAVE_PRIM_DIR,
|
|
OCEAN_WAVE_PRIM_PD, OCEAN_WAVE_SEC_DIR, OCEAN_WAVE_SEC_PD };
|
|
|
|
typedef struct {
|
|
uChar processID; /* Statistical process method used. */
|
|
uChar incrType; /* Type of time increment between intervals */
|
|
uChar timeRangeUnit; /* Time range unit. */
|
|
long int lenTime; /* Range or length of time interval. */
|
|
uChar incrUnit; /* Unit of time increment. */
|
|
long int timeIncr; /* Time increment between intervals. */
|
|
} sect4_IntervalType;
|
|
|
|
typedef struct { /* Used to store data where unpacked value =
|
|
value / 10**factor */
|
|
long int value; /* scale value in equation */
|
|
sChar factor; /* scale factor in equation. */
|
|
} ScaleType;
|
|
|
|
typedef struct { /* See Template 4.30. */
|
|
unsigned short int series; /* Satellite series of band. */
|
|
unsigned short int numbers; /* Satellite numbers of band. */
|
|
uChar instType; /* Instrument type of band */
|
|
ScaleType centWaveNum; /* scaled value for central wave number of
|
|
band. */
|
|
} sect4_BandType;
|
|
|
|
enum { GS4_ANALYSIS, GS4_ENSEMBLE, GS4_DERIVED, GS4_STATISTIC = 8,
|
|
GS4_PROBABILITY = 9, GS4_RADAR = 20, GS4_SATELLITE = 30
|
|
};
|
|
|
|
typedef struct {
|
|
unsigned short int templat; /* The section 4 template number. */
|
|
uChar cat; /* General category of Meteo Product. */
|
|
uChar subcat; /* Specific subcategory of Meteo Product. */
|
|
uChar genProcess; /* What type of generate process (Analysis,
|
|
Forecast, Probability Forecast, etc). */
|
|
uChar bgGenID; /* Background generating process id. */
|
|
uChar genID; /* Analysis/Forecast generating process id. */
|
|
uChar f_validCutOff; /* 1 if cutOff is valid, 0 if cutoff missing. */
|
|
long int cutOff; /* Data Cutoff in seconds after reference time
|
|
(see sect 1 for reference time). */
|
|
double foreSec; /* forecast "projection time" in seconds. */
|
|
uChar fstSurfType; /* Type of the first fixed surface. */
|
|
double fstSurfValue; /* Value of first fixed surface. */
|
|
uChar fstSurfScale; /* Scale factor used when storing value. */
|
|
uChar sndSurfType; /* Type of the second fixed surface. */
|
|
double sndSurfValue; /* Value of second fixed surface. */
|
|
uChar sndSurfScale; /* Scale factor used when storing value. */
|
|
time_t validTime; /* The ending time, or valid time, in seconds
|
|
UTC. This is specified in template 4.8, 4.9,
|
|
for the others it is refTime + foreSec. */
|
|
/* The following are somewhat template specific. */
|
|
uChar typeEnsemble; /* The type of Ensemble forecast
|
|
Template 4.1, (Code Table 4.5) */
|
|
uChar perturbNum; /* Perturbation number, Template 4.1 */
|
|
uChar numberFcsts; /* Number of forecasts in Ensemble.
|
|
Template, 4.1, 4.2 */
|
|
uChar derivedFcst; /* Derived Forecast (from Ensemble).
|
|
Template 4.2 */
|
|
uChar numInterval; /* Number of time intervals. Template 4.8,4.9 */
|
|
long int numMissing; /* Number of missing values. Template 4.8,4.9 */
|
|
sect4_IntervalType *Interval; /* Stores the array of time intervals.
|
|
Template 4.8,4.9 */
|
|
uChar numBands; /* Number of Spectral Bands. Template 4.30 */
|
|
sect4_BandType *bands; /* Holds info about each Band Template 4.30 */
|
|
uChar foreProbNum; /* Forecast Probability number (Template 4.9) */
|
|
uChar numForeProbs; /* Total # of forecast probabilities (4.9) */
|
|
uChar probType; /* Type of probability range. (Template 4.9)
|
|
0 below lower limit. 1 above upper limit.
|
|
2 between lower (inclusive) and
|
|
upper limit (exclusive)
|
|
3 above lower limit. 4 below upper limit. */
|
|
ScaleType lowerLimit; /* Lower Limit probability field. Template 4.9*/
|
|
ScaleType upperLimit; /* Upper Limit probability field. Template 4.9*/
|
|
} sect4_type;
|
|
|
|
/* This is the structure needed for the PDS (Product Definition Section)
|
|
* for GRIB2. I hope to combine stuff, but there is a lot more to GRIB2
|
|
* than GRIB1
|
|
*/
|
|
typedef struct {
|
|
/* Section 0 Data */
|
|
uChar prodType; /* 0 is meteo product, 1 is hydro, 2 is land
|
|
3 is space, 10 is oceanographic. */
|
|
/* Section 1 Data */
|
|
unsigned short int center, subcenter; /* Who produced it. */
|
|
uChar mstrVersion; /* Master table version. */
|
|
uChar lclVersion; /* Local table version. */
|
|
uChar sigTime; /* Significance of reference time */
|
|
time_t refTime; /* Reference time in seconds UTC */
|
|
uChar operStatus; /* What is operational status of data. */
|
|
uChar dataType; /* What type of data. (analysis, forecast,
|
|
analysis & forecast, ...) */
|
|
|
|
/* Rest of PDS. */
|
|
uChar f_sect2; /* 1 if sect2 exists, 0 otherwise. */
|
|
long int sect2NumGroups; /* total number of groups in section 2 data. */
|
|
sect2_type sect2; /* sect 2 info */
|
|
sect4_type sect4; /* sect 4 info */
|
|
} pdsG2Type;
|
|
|
|
/* This is the structure needed for the PDS (Product Definition Section)
|
|
* for GRIB1
|
|
*/
|
|
typedef struct {
|
|
uChar mstrVersion; /* Parameter Table Version #. */
|
|
uChar center, subcenter; /* Who produced it. */
|
|
uChar genProcess; /* Generating Process ID. ?Sect 4? */
|
|
uChar cat; /* General category of Meteo Product. */
|
|
uChar gridID; /* The Grid Defin ID number (GRIB1 specific) */
|
|
uChar levelType; /* Type of level. ?sect 4 fstSurf? */
|
|
int levelVal; /* Value of level. */
|
|
time_t refTime; /* Reference time in seconds UTC */
|
|
time_t P1; /* Period of time1 ?sect 4 valid time? */
|
|
time_t P2; /* Period of time2 */
|
|
time_t validTime; /* Valid time in seconds UTC */
|
|
uChar timeRange; /* Time Range Indicator. */
|
|
/* Specific for averages or accumulations. (determined by timeRange) */
|
|
int Average; /* number included in average. */
|
|
uChar numberMissing; /* number missing from averages. */
|
|
} pdsG1Type;
|
|
|
|
/* This is the structure and enumerated types needed for the GDS (Grid
|
|
* Definition Section. In GRIB2 the GDS was in section 3, in GRIB1 it was in
|
|
* section 2.
|
|
*/
|
|
enum { GS3_LATLON = 0, GS3_MERCATOR = 10, GS3_POLAR = 20,
|
|
GS3_LAMBERT = 30, GS3_ORTHOGRAPHIC = 90,
|
|
GS3_EQUATOR_EQUIDIST = 110, GS3_AZIMUTH_RANGE = 120};
|
|
|
|
/* Note: It appears that compilers break up a struct based on the largest
|
|
element type. In this case a double. So to avoid wasted memory, we need
|
|
things to stop at 8 byte borders. long int, double, long int is larger than
|
|
long int, long int, double. */
|
|
typedef struct {
|
|
sInt4 numPts; /* Number of data points. Typically Nx * Ny, but
|
|
for some exotic grids they don't have Nx,Ny */
|
|
uChar projType; /* Projection type / template type. Valid choices
|
|
0(lat/lon), 10(mercator), 20(Polar Stereo),
|
|
30(Lambert Conformal),
|
|
in future maybe 90, 110, 120. */
|
|
/* Shape of Earth */
|
|
uChar f_sphere; /* 1 is a sphere, => majEarth == minEarth */
|
|
double majEarth, minEarth; /* semi major and minor axis of earth in km. */
|
|
/* Projection info. */
|
|
sInt4 Nx, Ny; /* Dimensions of grid. */
|
|
double lat1, lon1; /* lat,lon position of first grid point. */
|
|
/* resFlag: moved to save memory. */
|
|
double orientLon; /* Where up is North. (0 for lat/lon grids) */
|
|
double Dx, Dy; /* Mesh delta x,y in degrees or meters. */
|
|
double meshLat; /* Where the mesh size is defined
|
|
(0 for lat/lon grids.) */
|
|
uChar resFlag; /* Table 7 GRIB1 : Section 2 */
|
|
uChar center; /* For lambert and polar stereographic, answers:
|
|
(south/north?) and (bi-polar?) */
|
|
uChar scan; /* describes how the grid was traversed when it
|
|
was stored. (ie top/down left/right etc.)
|
|
Internally we use 0100. (start lower left) */
|
|
double lat2, lon2; /* lat,lon position of last grid point.
|
|
(0 if unused) */
|
|
/* Specific to Lambert Conformal grids. */
|
|
double scaleLat1, scaleLat2; /* The tangent latitude. If different:
|
|
then the latitude where the scale should be
|
|
equal, which allows one to compute the correct
|
|
tangent latitude. (0 for lat/lon and mercator,
|
|
90 for north polar stereographic). */
|
|
double southLat, southLon; /* Not needed. 0 except lambert.
|
|
(and rotated lat/lon) */
|
|
/* Following is for stretched Lat/Lon grids. */
|
|
double poleLat, poleLon; /* Pole of stretching. */
|
|
double stretchFactor; /* Factor of stretching. */
|
|
int f_typeLatLon; /* 0 regular, 1 stretch, 2 stretch / rotate. */
|
|
double angleRotate; /* Rotation angle. */
|
|
} gdsType;
|
|
|
|
typedef struct {
|
|
uChar projType; /* Projection type / template type. Valid choices
|
|
0(lat/lon), 10(mercator), 20(Polar Stereo),
|
|
30(Lambert Conformal),
|
|
in future maybe 90, 110, 120. */
|
|
double majEarth, minEarth; /* semi major and minor axis of earth in km. */
|
|
} gdsType2;
|
|
|
|
enum { GS5_SIMPLE = 0, GS5_CMPLX = 2, GS5_CMPLXSEC = 3, GS5_SPECTRAL = 50,
|
|
GS5_HARMONIC = 41, GS5_JPEG2000 = 40000, GS5_PNG = 40010
|
|
};
|
|
typedef struct {
|
|
sInt4 packType; /* What kind of packing was used. */
|
|
float refVal; /* The refrence value for the grid, also the
|
|
* minimum value? */
|
|
short int ESF; /* Power of 2 scaling factor. */
|
|
short int DSF; /* Decimal Scale Factor */
|
|
uChar fieldType; /* 0 data was float, 1 if int. */
|
|
uChar f_maxmin; /* boolean, if min/max are valid*/
|
|
double min, max; /* Min / Max values in data. */
|
|
uChar missManage; /* Missing value management
|
|
0 none, 1 primary, 2 primary & secondary. */
|
|
double missPrim, missSec; /* primary and secondary missing values. */
|
|
long int numMissing; /* Number of missing values detected,
|
|
both primary and secondary. */
|
|
} gridAttribType;
|
|
|
|
typedef struct {
|
|
uChar GribVersion; /* 1 if GRIB1, 2 if GRIB2 */
|
|
char wfo[5]; /* Name of wfo that generated the data. */
|
|
pdsG1Type pds1; /* Product Definition section for GRIB1. */
|
|
pdsG2Type pds2; /* Product Definition section for GRIB2. */
|
|
gdsType gds; /* Grid Definition section (sect3 for GRIB2) */
|
|
gridAttribType gridAttrib; /* Attributes of the Grid (min/max values etc) */
|
|
char *element; /* A short char look up of variable type. */
|
|
char *comment; /* A more descriptive look up of variable type. */
|
|
char *unitName; /* Unit if not the one specified in the GRIB2
|
|
* document, otherwise NULL. */
|
|
int convert; /* Enum type of unit conversions (meta.h),
|
|
Conversion method for this variable's unit. */
|
|
char *shortFstLevel; /* Short description of the level of this data
|
|
(above ground) (500 mb), etc */
|
|
char *longFstLevel; /* Long description of the level of this data
|
|
(above ground) (500 mb), etc */
|
|
char refTime[20]; /* When forecast was issued. */
|
|
char validTime[20]; /* When forecast is valid. */
|
|
long int deltTime; /* validTime - refTime in seconds. */
|
|
|
|
/* int *size_wx; */ /* (idat[0] + 2) * sizeof (int) */
|
|
/* char **release_datetime; *//* pds2.refTime + pds2.cutOffHour */
|
|
} grib_MetaData;
|
|
|
|
void MetaInit (grib_MetaData *meta);
|
|
|
|
void MetaSect2Free (grib_MetaData * meta);
|
|
|
|
void MetaFree (grib_MetaData *meta);
|
|
|
|
int ParseTime (time_t * AnsTime, int year, uChar mon, uChar day, uChar hour,
|
|
uChar min, uChar sec);
|
|
|
|
int ParseSect4Time2sec (long int time, int unit, double *ans);
|
|
|
|
/* Possible error messages left in errSprintf() */
|
|
int MetaParse (grib_MetaData * meta, long int *is0, long int ns0,
|
|
long int *is1, long int ns1, long int *is2, long int ns2,
|
|
float *rdat, long int nrdat, long int *idat, long int nidat,
|
|
long int *is3, long int ns3, long int *is4, long int ns4,
|
|
long int *is5, long int ns5, long int grib_len,
|
|
float xmissp, float xmisss, int simpVer);
|
|
|
|
void ParseGrid (gridAttribType * attrib, double **Grib_Data,
|
|
long int *grib_DataLen, long int Nx, long int Ny, int scan,
|
|
long int *iain, long int ibitmap, long int *ib, double unitM,
|
|
double unitB, uChar f_wxType, sect2_WxType * WxType,
|
|
uChar f_subGrid, int startX, int startY, int stopX, int stopY);
|
|
|
|
/* Possible error messages left in errSprintf() */
|
|
/* int MetaPrintGDS (gdsType * gds, char **ans); */
|
|
|
|
/* Possible error messages left in errSprintf() */
|
|
int MetaPrint (grib_MetaData *meta, char **ans, sChar decimal, sChar f_unit);
|
|
|
|
#endif
|