Commit cd2c0bac authored by Uwe Schulzweida's avatar Uwe Schulzweida
Browse files

Merged branch Hirlam_extensions.

parent 7ae445c7
...@@ -967,6 +967,9 @@ int gridInqComplexPacking(int gridID); ...@@ -967,6 +967,9 @@ int gridInqComplexPacking(int gridID);
void gridDefUvRelativeToGrid(int gridID, int uvRelativeToGrid); void gridDefUvRelativeToGrid(int gridID, int uvRelativeToGrid);
int gridInqUvRelativeToGrid(int gridID); int gridInqUvRelativeToGrid(int gridID);
void gridDefScanningMode(int gridID, int mode);
int gridInqScanningMode(int gridID);
/* ZAXIS routines */ /* ZAXIS routines */
void zaxisName(int zaxistype, char *zaxisname); void zaxisName(int zaxistype, char *zaxisname);
......
...@@ -152,6 +152,14 @@ typedef struct ...@@ -152,6 +152,14 @@ typedef struct
int ilevel2; int ilevel2;
int ltype; int ltype;
short tsteptype; short tsteptype;
#ifdef HIRLAM_EXTENSIONS
// NOTE: tsteptype MUST be part of attributes used to compare variables!
// Modern NWP models (HARMONIE, HIRLAM) use timeRangeIndicator to specify
// if the field is instantanous or accumulated.
// Both types are typically in the same GRIB-file.
// (181; 105, 0, timeRangeIndicator=0) .. instantanous rain
// (181; 105, 0, timeRangeIndicator=4) .. accumulated rain .. both can be in the same grib file
#endif // HIRLAM_EXTENSIONS
short used; short used;
short varID; short varID;
short levelID; short levelID;
...@@ -303,6 +311,7 @@ typedef enum { ...@@ -303,6 +311,7 @@ typedef enum {
#define CDI_FILETYPE_UNDEF -1 /* Unknown/not yet defined file type */ #define CDI_FILETYPE_UNDEF -1 /* Unknown/not yet defined file type */
extern int cdiDebugExt;
extern int CDI_Debug; /* If set to 1, debuggig (default 0) */ extern int CDI_Debug; /* If set to 1, debuggig (default 0) */
extern int CDI_Recopt; extern int CDI_Recopt;
extern int cdiGribApiDebug; extern int cdiGribApiDebug;
......
...@@ -133,6 +133,71 @@ void grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1) ...@@ -133,6 +133,71 @@ void grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1)
} }
} }
#ifdef HIRLAM_EXTENSIONS
// Even if you are stream-copy records you might need to change a bit of grib-header !
if ( cdiGribDataScanningMode.active )
// allowed modes: <0, 64, 96>; Default is 64
// This will overrule the old scanning mode of the given grid
{
grib_handle *gh = NULL;
gh = grib_handle_new_from_message(NULL, (void *) gribbuffer, recsize);
int scanModeIN = gribapiGetScanningMode(gh);
grib_handle_delete(gh);
if (cdiDebugExt>=20) Message("Change GribDataScanningMode => %d (scanModeIN = %d)", cdiGribDataScanningMode.value, scanModeIN);
if (scanModeIN != cdiGribDataScanningMode.value)
{
int gridID;
int varID, levelID;
int vlistID;
//int zip;
int gridsize, nmiss = 0;
vlistID = streamptr1->vlistID;
varID = streamptr1->tsteps[tsID].records[recID].varID;
levelID = streamptr1->tsteps[tsID].records[recID].levelID;
//gribbuffer = (unsigned char *) streamptr->record->buffer;
// allocate above ..
gridID = vlistInqVarGrid(vlistID, varID);
gridsize = gridInqSize(gridID);
gridsize = vlistGridsizeMax(vlistID);
if ( vlistNumber(vlistID) != CDI_REAL ) gridsize *= 2;
double * data = (double *) malloc(gridsize*sizeof(double));
//int missval = vlistInqVarMissval(vlistID, varID);
//streamptr->numvals += gridsize;
// memtype: MEMTYPE_FLOAT or MEMTYPE_DOUBLE
//int statusDC = grbDecode(filetype, MEMTYPE_DOUBLE, gribbuffer, recsize, data, gridsize, streamptr1->unreduced, &nmiss, missval, vlistID, varID);
//int grbDecode(int filetype, int memtype, void *gribbuffer, int gribsize, void *data, size_t datasize,
// int unreduced, int *nmiss, double missval, int vlistID, int varID);
//streamptr1->tsteps[tsID].records[recID].zip = zip;
//gribapiSetScanningMode(gh, cdoGribDataScanningMode); // T.B.D. this will be done by grbDecode..
//varID = streamptr1->record->varID;
//levelID = streamptr1->record->levelID;
if (cdiDebugExt>=20) Message(" processing varID %d; levelID %d",varID,levelID);
grb_write_var_slice(streamptr2, varID, levelID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
//grb_write_var_slice(streamptr, varID, levelID, memtype, ((double*)data)+levelID*gridsize, nmiss);
//grb_write_var(streamptr2, varID, MEMTYPE_DOUBLE, data, nmiss);
//grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss)
//grb_write_var_slice(streamptr2, varID, levelID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
free(data);
free(gribbuffer);
}
}
#endif // HIRLAM_EXTENSIONS
if ( filetype == CDI_FILETYPE_GRB ) if ( filetype == CDI_FILETYPE_GRB )
{ {
size_t unzipsize; size_t unzipsize;
......
...@@ -382,6 +382,48 @@ int gribapiGetTsteptype(grib_handle *gh) ...@@ -382,6 +382,48 @@ int gribapiGetTsteptype(grib_handle *gh)
// printf("stepType: %s %ld %d\n", stepType, len, tsteptype); // printf("stepType: %s %ld %d\n", stepType, len, tsteptype);
} }
#ifdef HIRLAM_EXTENSIONS
{
// Normaly cdo looks in grib for attribute called "stepType", see above.
// BUT NWP models such as Hirlam and Harmonie 37h1.2, use "timeRangeIndicator" instead!
// Where for example: 0: for instanteneous fields; 4: for accumulated fields
// 0: Forecast product valid at reference time + P1
// 2: Product with a valid time ranging between reference time + P1 and reference time + P2
// 4: Accumulation (reference time + P1 to reference time + P2)
// 5: Difference(reference time + P2 minus reference time + P1) product considered valid at reference time + P2
// More details on WMO standards:
// http://www.wmo.int/pages/prog/www/WDM/Guides/Guide-binary-2.html
//tsteptype = TSTEP_INSTANT; // default value for any case
long timeRangeIND = 0; // typically 0: for instanteneous fields; 4: for accumulated fields
int rc = grib_get_long(gh, "timeRangeIndicator", &timeRangeIND);
if (rc != 0) {
//if ( lprint )
Warning("Could not get 'stepType' either 'timeRangeIndicator'. Using defualt!");
return (tsteptype);
}
extern int cdiGribUseTimeRangeIndicator;
cdiGribUseTimeRangeIndicator = 1;
switch ( timeRangeIND )
{
case 0: tsteptype = TSTEP_INSTANT; break;
case 2: tsteptype = TSTEP_INSTANT2;
strcpy(stepType, "instant2"); // was incorrectly set before into accum
break;
case 4: tsteptype = TSTEP_ACCUM; break;
case 5: tsteptype = TSTEP_DIFF; break;
default:
if ( lprint )
{
if (CDI_Debug)
Warning("timeRangeIND = %d; stepType= %s; tsteptype=%d unsupported timeRangeIND at the moment, set to instant!", timeRangeIND, stepType, tsteptype);
lprint = FALSE;
}
break;
}
if (CDI_Debug)
Warning("timeRangeIND = %d; stepType= %s; tsteptype=%d", timeRangeIND, stepType, tsteptype);
}
#endif // HIRLAM_EXTENSIONS
} }
return tsteptype; return tsteptype;
...@@ -723,6 +765,34 @@ void gribapiGetGrid(grib_handle *gh, grid_t *grid) ...@@ -723,6 +765,34 @@ void gribapiGetGrid(grib_handle *gh, grid_t *grid)
grid->uvRelativeToGrid = (bool)temp; grid->uvRelativeToGrid = (bool)temp;
} }
if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_LONLAT || gridtype == GRID_PROJECTION || gridtype == GRID_LCC )
{
GRIB_CHECK(grib_get_long(gh, "iScansNegatively", &grid->iScansNegatively), 0);
GRIB_CHECK(grib_get_long(gh, "jScansPositively", &grid->jScansPositively), 0);
GRIB_CHECK(grib_get_long(gh, "jPointsAreConsecutive", &grid->jPointsAreConsecutive), 0);
grid->scanningMode = 128*grid->iScansNegatively + 64*grid->jScansPositively + 32*grid->jPointsAreConsecutive;
/* scanningMode = 128 * iScansNegatively + 64 * jScansPositively + 32 * jPointsAreConsecutive;
64 = 128 * 0 + 64 * 1 + 32 * 0
00 = 128 * 0 + 64 * 0 + 32 * 0
96 = 128 * 0 + 64 * 1 + 32 * 1
Default / implicit scanning mode is 64:
i and j scan positively, i points are consecutive (row-major) */
#ifdef HIRLAM_EXTENSIONS
if (cdiDebugExt>=30)
{
// indicatorOfParameter=33,indicatorOfTypeOfLevel=105,level
long paramId, levelTypeId, levelId;
GRIB_CHECK(grib_get_long(gh, "indicatorOfParameter", &paramId), 0);
GRIB_CHECK(grib_get_long(gh, "indicatorOfTypeOfLevel", &levelTypeId), 0);
GRIB_CHECK(grib_get_long(gh, "level", &levelId), 0);
Message("(param,ltype,level) = (%3d,%3d,%4d); Scanning mode = %02d -> bits:(%1d.%1d.%1d)*32; uvRelativeToGrid = %02d",\
(int)paramId, (int)levelTypeId, (int)levelId,
grid->scanningMode,(int)grid->jPointsAreConsecutive,(int)grid->jScansPositively,(int)grid->iScansNegatively,
(int)grid->uvRelativeToGrid);
}
#endif //HIRLAM_EXTENSIONS
}
grid->type = gridtype; grid->type = gridtype;
grid->projtype = projtype; grid->projtype = projtype;
} }
......
...@@ -33,6 +33,11 @@ int gribapiGetParam(grib_handle *gh); ...@@ -33,6 +33,11 @@ int gribapiGetParam(grib_handle *gh);
int gribapiGetGridType(grib_handle *gh); int gribapiGetGridType(grib_handle *gh);
void gribapiGetGrid(grib_handle *gh, grid_t *grid); void gribapiGetGrid(grib_handle *gh, grid_t *grid);
#ifdef HIRLAM_EXTENSIONS
void gribapiSetDataTimeRangeIndicator(grib_handle *gh, int timeRangeIndicator);
void gribapiGetDataTimeRangeIndicator(grib_handle *gh, int *timeRangeIndicator);
#endif // #ifdef HIRLAM_EXTENSIONS
#endif #endif
#endif #endif
......
...@@ -158,6 +158,16 @@ void grid_init(grid_t *gridptr) ...@@ -158,6 +158,16 @@ void grid_init(grid_t *gridptr)
gridptr->atts.nalloc = MAX_ATTRIBUTES; gridptr->atts.nalloc = MAX_ATTRIBUTES;
gridptr->atts.nelems = 0; gridptr->atts.nelems = 0;
gridptr->uvRelativeToGrid = 0; // Some models deliver wind U,V relative to the grid-cell gridptr->uvRelativeToGrid = 0; // Some models deliver wind U,V relative to the grid-cell
gridptr->iScansNegatively = 0;
gridptr->jScansPositively = 1;
gridptr->jPointsAreConsecutive = 0;
gridptr->scanningMode = 128*gridptr->iScansNegatively + 64*gridptr->jScansPositively + 32*gridptr->jPointsAreConsecutive;
/* scanningMode = 128 * iScansNegatively + 64 * jScansPositively + 32 * jPointsAreConsecutive;
64 = 128 * 0 + 64 * 1 + 32 * 0
00 = 128 * 0 + 64 * 0 + 32 * 0
96 = 128 * 0 + 64 * 1 + 32 * 1
Default / implicit scanning mode is 64:
i and j scan positively, i points are consecutive (row-major) */
} }
...@@ -2227,10 +2237,15 @@ bool gridCompare(int gridID, const grid_t *grid, bool coord_compare) ...@@ -2227,10 +2237,15 @@ bool gridCompare(int gridID, const grid_t *grid, bool coord_compare)
} }
} }
if ( (grid->uvRelativeToGrid != gridInqUvRelativeToGrid(gridID)) ) if ( (grid->scanningMode != gridInqScanningMode(gridID)) || (grid->uvRelativeToGrid != gridInqUvRelativeToGrid(gridID)) )
{ {
// often grid definition may differ in UV-relativeToGrid // often grid definition may differ in UV-relativeToGrid
differ = 1; differ = 1;
#ifdef HIRLAM_EXTENSIONS
if ( cdiDebugExt>=200 )
printf("gridCompare(gridID=%d): Differs: grid.scanningMode [%d] != gridInqScanningMode(gridID) [%d] or grid.uvRelativeToGrid [%ld] != gridInqUvRelativeToGrid(gridID) [%d]\n",
gridID, grid->scanningMode, gridInqScanningMode(gridID), grid->uvRelativeToGrid, gridInqUvRelativeToGrid(gridID) );
#endif // HIRLAM_EXTENSIONS
} }
return differ; return differ;
} }
...@@ -2293,6 +2308,7 @@ int gridCompareP(void *gridptr1, void *gridptr2) ...@@ -2293,6 +2308,7 @@ int gridCompareP(void *gridptr1, void *gridptr2)
if ( IS_NOT_EQUAL(g1->lcc.xinc , g2->lcc.xinc) ) return differ; if ( IS_NOT_EQUAL(g1->lcc.xinc , g2->lcc.xinc) ) return differ;
if ( IS_NOT_EQUAL(g1->lcc.yinc , g2->lcc.yinc) ) return differ; if ( IS_NOT_EQUAL(g1->lcc.yinc , g2->lcc.yinc) ) return differ;
if ( IS_NOT_EQUAL(g1->uvRelativeToGrid , g2->uvRelativeToGrid) ) return differ; if ( IS_NOT_EQUAL(g1->uvRelativeToGrid , g2->uvRelativeToGrid) ) return differ;
if ( IS_NOT_EQUAL(g1->scanningMode , g2->scanningMode) ) return differ;
const double *restrict g1_xvals = g1->vtable->inqXValsPtr(g1), const double *restrict g1_xvals = g1->vtable->inqXValsPtr(g1),
*restrict g2_xvals = g2->vtable->inqXValsPtr(g2); *restrict g2_xvals = g2->vtable->inqXValsPtr(g2);
...@@ -2632,6 +2648,10 @@ int gridGenerate(const grid_t *grid) ...@@ -2632,6 +2648,10 @@ int gridGenerate(const grid_t *grid)
gridptr->number = grid->number; gridptr->number = grid->number;
gridptr->position = grid->position; gridptr->position = grid->position;
gridptr->uvRelativeToGrid = grid->uvRelativeToGrid; gridptr->uvRelativeToGrid = grid->uvRelativeToGrid;
gridptr->scanningMode = grid->scanningMode;
gridptr->iScansNegatively = grid->iScansNegatively;
gridptr->jScansPositively = grid->jScansPositively;
gridptr->jPointsAreConsecutive = grid->jPointsAreConsecutive;
memcpy(gridptr->uuid, grid->uuid, CDI_UUID_SIZE); memcpy(gridptr->uuid, grid->uuid, CDI_UUID_SIZE);
if ( gridtype == GRID_UNSTRUCTURED && grid->reference ) if ( gridtype == GRID_UNSTRUCTURED && grid->reference )
gridDefReference(gridID, grid->reference); gridDefReference(gridID, grid->reference);
...@@ -3665,7 +3685,7 @@ void gridDefParamLCC(int gridID, double originLon, double originLat, double lonP ...@@ -3665,7 +3685,7 @@ void gridDefParamLCC(int gridID, double originLon, double originLat, double lonP
@Item yinc Y-direction grid lenght in meter. @Item yinc Y-direction grid lenght in meter.
@Item projflag Projection centre flag. @Item projflag Projection centre flag.
@Item scanflag Scanning mode flag. @Item scanflag Scanning mode flag.
@Description @Description
The function @func{gridInqParamLCC} returns the parameter of a Lambert Conformal Conic grid. The function @func{gridInqParamLCC} returns the parameter of a Lambert Conformal Conic grid.
...@@ -3962,6 +3982,31 @@ int gridInqUvRelativeToGrid(int gridID) ...@@ -3962,6 +3982,31 @@ int gridInqUvRelativeToGrid(int gridID)
} }
void gridDefScanningMode(int gridID, int mode)
{
grid_t *gridptr = grid_to_pointer(gridID);
if ( gridptr->scanningMode != mode )
{
gridMark4Update(gridID);
gridptr->scanningMode = mode;
}
}
int gridInqScanningMode(int gridID)
{
grid_t *gridptr = grid_to_pointer(gridID);
int scanningModeTMP = 128 * gridptr->iScansNegatively + 64 * gridptr->jScansPositively + 32 * gridptr->jPointsAreConsecutive;
if ( scanningModeTMP != gridptr->scanningMode )
Message("WARNING: scanningMode (%d) ! = (%d) 128 * iScansNegatively(%d) + 64 * jScansPositively(%d) + 32 * jPointsAreConsecutive(%d) ",
gridptr->scanningMode, scanningModeTMP, gridptr->iScansNegatively,gridptr->jScansPositively,gridptr->jPointsAreConsecutive );
return gridptr->scanningMode;
}
void cdiGridGetIndexList(unsigned ngrids, int * gridIndexList) void cdiGridGetIndexList(unsigned ngrids, int * gridIndexList)
{ {
reshGetResHListOfType(ngrids, gridIndexList, &gridOps); reshGetResHListOfType(ngrids, gridIndexList, &gridOps);
...@@ -4000,6 +4045,11 @@ enum { ...@@ -4000,6 +4045,11 @@ enum {
GRID_PACK_INT_IDX_MEMBERMASK, GRID_PACK_INT_IDX_MEMBERMASK,
GRID_PACK_INT_IDX_XTSTDNNAME, GRID_PACK_INT_IDX_XTSTDNNAME,
GRID_PACK_INT_IDX_YTSTDNNAME, GRID_PACK_INT_IDX_YTSTDNNAME,
GRID_PACK_INT_IDX_UVRELATIVETOGRID,
GRID_PACK_INT_IDX_ISCANSNEGATIVELY,
GRID_PACK_INT_IDX_JSCANSPOSITIVELY,
GRID_PACK_INT_IDX_JPOINTSARECONSECUTIVE,
GRID_PACK_INT_IDX_SCANNINGMODE,
gridNint gridNint
}; };
...@@ -4213,6 +4263,11 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize, ...@@ -4213,6 +4263,11 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
xystdname_tab[intBuffer[GRID_PACK_INT_IDX_XTSTDNNAME]][0]; xystdname_tab[intBuffer[GRID_PACK_INT_IDX_XTSTDNNAME]][0];
gridP->y.stdname = gridP->y.stdname =
xystdname_tab[intBuffer[GRID_PACK_INT_IDX_YTSTDNNAME]][1]; xystdname_tab[intBuffer[GRID_PACK_INT_IDX_YTSTDNNAME]][1];
gridP->uvRelativeToGrid = intBuffer[GRID_PACK_INT_IDX_UVRELATIVETOGRID];
gridP->iScansNegatively = intBuffer[GRID_PACK_INT_IDX_ISCANSNEGATIVELY];
gridP->jScansPositively = intBuffer[GRID_PACK_INT_IDX_JSCANSPOSITIVELY];
gridP->jPointsAreConsecutive = intBuffer[GRID_PACK_INT_IDX_JPOINTSARECONSECUTIVE];
gridP->scanningMode = intBuffer[GRID_PACK_INT_IDX_SCANNINGMODE];
} }
if (memberMask & gridHasRowLonFlag) if (memberMask & gridHasRowLonFlag)
...@@ -4407,6 +4462,12 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize, ...@@ -4407,6 +4462,12 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
(int)((const char (*)[2][24])gridP->y.stdname (int)((const char (*)[2][24])gridP->y.stdname
- (const char (*)[2][24])xystdname_tab[0][1]); - (const char (*)[2][24])xystdname_tab[0][1]);
intBuffer[GRID_PACK_INT_IDX_UVRELATIVETOGRID] = gridP->uvRelativeToGrid;
intBuffer[GRID_PACK_INT_IDX_ISCANSNEGATIVELY] = gridP->iScansNegatively;
intBuffer[GRID_PACK_INT_IDX_JSCANSPOSITIVELY] = gridP->jScansPositively;
intBuffer[GRID_PACK_INT_IDX_JPOINTSARECONSECUTIVE] = gridP->jPointsAreConsecutive;
intBuffer[GRID_PACK_INT_IDX_SCANNINGMODE] = gridP->scanningMode;
serializePack(intBuffer, gridNint, CDI_DATATYPE_INT, serializePack(intBuffer, gridNint, CDI_DATATYPE_INT,
packBuffer, packBufferSize, packBufferPos, context); packBuffer, packBufferSize, packBufferPos, context);
d = cdiCheckSum(CDI_DATATYPE_INT, gridNint, intBuffer); d = cdiCheckSum(CDI_DATATYPE_INT, gridNint, intBuffer);
......
...@@ -108,12 +108,21 @@ struct grid_t { ...@@ -108,12 +108,21 @@ struct grid_t {
*/ */
bool lcomplex; bool lcomplex;
bool hasdims; bool hasdims;
/* Some models deliver wind U,V relative to the grid-cell */ bool uvRelativeToGrid; /* Some models deliver wind U,V relative to the grid-cell */
bool uvRelativeToGrid;
struct gridaxis_t x; struct gridaxis_t x;
struct gridaxis_t y; struct gridaxis_t y;
const struct gridVirtTable *vtable; const struct gridVirtTable *vtable;
cdi_atts_t atts; cdi_atts_t atts;
long iScansNegatively;
long jScansPositively;
long jPointsAreConsecutive;
int scanningMode;
/* scanningMode = 128 * iScansNegatively + 64 * jScansPositively + 32 * jPointsAreConsecutive;
64 = 128 * 0 + 64 * 1 + 32 * 0
00 = 128 * 0 + 64 * 0 + 32 * 0
96 = 128 * 0 + 64 * 1 + 32 * 1
Default / implicit scanning mode is 64:
i and j scan positively, i points are consecutive (row-major) */
}; };
......
...@@ -10,6 +10,14 @@ ...@@ -10,6 +10,14 @@
#include "file.h" #include "file.h"
#include "cgribex.h" /* gribZip gribGetZip gribGinfo */ #include "cgribex.h" /* gribZip gribGetZip gribGinfo */
int cdiDebugExt = 0; // Debug level for the KNMI extensions
#ifdef HIRLAM_EXTENSIONS
// *** RELATED to GRIB only ***
int cdiGribUseTimeRangeIndicator = 0; // normaly cdo looks in grib for attribute called "stepType"
// but NWP models such as Harmonie 37h1.2, use "timeRangeIndicator"
// where: 0: for instanteneous fields; 4: for accumulated fields
#endif // HIRLAM_EXTENSIONS
// Regarding operation to change parameter identification: // Regarding operation to change parameter identification:
// change if cdiGribChangeParameterID.active // change if cdiGribChangeParameterID.active
...@@ -43,12 +51,12 @@ struct cdiGribScanModeChange cdiGribDataScanningMode; ...@@ -43,12 +51,12 @@ struct cdiGribScanModeChange cdiGribDataScanningMode;
void streamGrbDefDataScanningMode(int scanmode) void streamGrbDefDataScanningMode(int scanmode)
{ {
cdiGribDataScanningMode.active = true; cdiGribDataScanningMode.active = true;
cdiGribDataScanningMode.scanmode = scanmode; cdiGribDataScanningMode.value = scanmode;
} }
int streamGrbInqDataScanningMode(void) int streamGrbInqDataScanningMode(void)
{ {
return cdiGribDataScanningMode.scanmode; return cdiGribDataScanningMode.value;
} }
......
...@@ -38,7 +38,7 @@ struct cdiGribModeChange ...@@ -38,7 +38,7 @@ struct cdiGribModeChange
struct cdiGribScanModeChange struct cdiGribScanModeChange
{ {
int scanmode; int value;
bool active; bool active;
}; };
......
...@@ -36,6 +36,14 @@ typedef struct { ...@@ -36,6 +36,14 @@ typedef struct {
int level2; int level2;
int ltype; int ltype;
int tsteptype; int tsteptype;
#ifdef HIRLAM_EXTENSIONS
// NOTE: tsteptype MUST be part of attributes used to compare variables!
// Modern NWP models (HARMONIE, HIRLAM) use timeRangeIndicator to specify
// if the field is instantanous or accumulated.
// Both types are typically in the same GRIB-file.
// (181; 105, 0, timeRangeIndicator=0) .. instantanous rain
// (181; 105, 0, timeRangeIndicator=4) .. accumulated rain .. both can be in the same grib file
#endif // HIRLAM_EXTENSIONS
char name[32]; char name[32];
var_tile_t tiles; var_tile_t tiles;
...@@ -43,6 +51,9 @@ typedef struct { ...@@ -43,6 +51,9 @@ typedef struct {
} compvar2_t; } compvar2_t;
int scanModeIN; // global variable
static static
int gribapiGetZaxisType(long editionNumber, int grib_ltype) int gribapiGetZaxisType(long editionNumber, int grib_ltype)
{ {
...@@ -1670,6 +1681,8 @@ void gribapiDefStepUnits(int editionNumber, grib_handle *gh, int timeunit, int p ...@@ -1670,6 +1681,8 @@ void gribapiDefStepUnits(int editionNumber, grib_handle *gh, int timeunit, int p
} }
else else
{ {
// NOTE KNMI: HIRLAM model files LAMH_D11 are in grib1 and do NOT have key indicatorOfUnitForTimeRange
// Watch out for compatibility issues.
GRIB_CHECK(my_grib_set_long(gh, "indicatorOfUnitOfTimeRange", unitsOfTime), 0); GRIB_CHECK(my_grib_set_long(gh, "indicatorOfUnitOfTimeRange", unitsOfTime), 0);
} }
} }
...@@ -2558,6 +2571,358 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int zaxisID, int levelI ...@@ -2558,6 +2571,358 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int zaxisID, int levelI
} }
} }
int gribapiGetScanningMode(grib_handle *gh)
{
long iScansNegatively;
long jScansPositively;
long jPointsAreConsecutive;
GRIB_CHECK(grib_get_long(gh, "iScansNegatively", &iScansNegatively), 0);
GRIB_CHECK(grib_get_long(gh, "jScansPositively", &jScansPositively), 0);
GRIB_CHECK(grib_get_long(gh, "jPointsAreConsecutive", &jPointsAreConsecutive), 0);
int scanningMode = 0;
scanningMode = 128*iScansNegatively + 64*jScansPositively + 32*jPointsAreConsecutive;
if (cdiDebugExt>=30)
printf("gribapiGetScanningMode(): Scanning mode = %02d (%1d%1d%1d)*32; \n",\
scanningMode,(int)jPointsAreConsecutive,(int)jScansPositively,(int)iScansNegatively);
return scanningMode;
}
void gribapiSetScanningMode(grib_handle *gh, int scanningMode)
{
long iScansNegatively;
long jScansPositively;
long jPointsAreConsecutive;
// 127: reserved for testing; generated test data will be in 64 scanning mode
//if (scanningMode== 127) scanningMode = 64;
iScansNegatively = (scanningMode & 128)/128;
jScansPositively = (scanningMode & 64)/64;
jPointsAreConsecutive = (scanningMode & 32)/32;
if (cdiDebugExt>=30)
{
long paramId, levelTypeId, levelId, uvRelativeToGrid;
GRIB_CHECK(grib_get_long(gh, "uvRelativeToGrid", &uvRelativeToGrid), 0);
GRIB_CHECK(grib_get_long(gh, "indicatorOfParameter", &paramId), 0);
GRIB_CHECK(grib_get_long(gh, "indicatorOfTypeOfLevel", &levelTypeId), 0);
GRIB_CHECK(grib_get_long(gh, "level", &levelId), 0);
printf("gribapiSetScanningMode(): (param,ltype,level) = (%3d,%3d,%4d); Scanning mode = %02d (%1d%1d%1d)*32; uvRelativeToGrid = %02d\n",\
(int)paramId, (int)levelTypeId, (int)levelId,
scanningMode,(int)jPointsAreConsecutive,(int)jScansPositively,(int)iScansNegatively,
(int)uvRelativeToGrid);
}
GRIB_CHECK(my_grib_set_long(gh, "iScansNegatively", iScansNegatively), 0);
GRIB_CHECK(my_grib_set_long(gh, "jScansPositively", jScansPositively), 0);
GRIB_CHECK(my_grib_set_long(gh, "jPointsAreConsecutive", jPointsAreConsecutive), 0);
}
void gribapiSetUvRelativeToGrid(grib_handle *gh, int mode)
{
long uvRelativeToGridMode = mode;
long uvRelativeToGridModeOld;
GRIB_CHECK(grib_get_long(gh, "uvRelativeToGrid", &uvRelativeToGridModeOld), 0);
if (cdiDebugExt>=30)
printf("gribapiSetUvRelativeToGrid(): uvRelativeToGrid: %02d (old) => %02d (new); \n",(int)uvRelativeToGridModeOld,(int)uvRelativeToGridMode);
GRIB_CHECK(my_grib_set_long(gh, "uvRelativeToGrid", uvRelativeToGridMode), 0);
}
/*
TABLE 8. SCANNING MODE FLAG
(GDS Octe