From a977fec79cdbf1ff944a8d979d78a1ab7797f686 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 8 Jan 2019 13:41:41 +0000 Subject: [PATCH] Support for legacy GRIB2 encoded with discipline=192 --- src/grib_accessor_class_concept.c | 118 ++++++++++++++++++++++++++---- 1 file changed, 103 insertions(+), 15 deletions(-) diff --git a/src/grib_accessor_class_concept.c b/src/grib_accessor_class_concept.c index 59ded63a9..b6ca30de4 100644 --- a/src/grib_accessor_class_concept.c +++ b/src/grib_accessor_class_concept.c @@ -160,17 +160,10 @@ static void dump(grib_accessor* a, grib_dumper* dumper) static int concept_condition_expression_true(grib_handle* h,grib_concept_condition* c) { long lval; - double dval; long lres=0; - double dres=0.0; - const char *cval; - char buf[80]; - char tmp[80]; - size_t len = sizeof(buf); - size_t size=sizeof(tmp); int ok = 0; int err=0; - int type = grib_expression_native_type(h,c->expression); + const int type = grib_expression_native_type(h,c->expression); switch(type) { @@ -180,17 +173,27 @@ static int concept_condition_expression_true(grib_handle* h,grib_concept_conditi (lval == lres); break; - case GRIB_TYPE_DOUBLE: + case GRIB_TYPE_DOUBLE: { + double dval; + double dres=0.0; grib_expression_evaluate_double(h,c->expression,&dres); ok = (grib_get_double(h,c->name,&dval) == GRIB_SUCCESS) && (dval == dres); break; + } + + case GRIB_TYPE_STRING: { + const char *cval; + char buf[80]; + char tmp[80]; + size_t len = sizeof(buf); + size_t size=sizeof(tmp); - case GRIB_TYPE_STRING: ok = (grib_get_string(h,c->name,buf,&len) == GRIB_SUCCESS) && ((cval = grib_expression_evaluate_string(h,c->expression,tmp,&size,&err)) != NULL) && (err==0) && (grib_inline_strcmp(buf,cval) == 0); break; + } default: /* TODO: */ @@ -425,14 +428,53 @@ static int unpack_double(grib_accessor* a, double* val, size_t *len) return ret; } +static long guess_paramId(grib_handle* h) +{ + int err = 0; + long discipline, category, number; + err=grib_get_long(h,"discipline",&discipline); + if (err || discipline != 192) + return -1; + err=grib_get_long(h,"parameterCategory",&category); + if (err) return -1; + err=grib_get_long(h,"parameterNumber",&number); + if (err) return -1; + + if (category==128) return number; + else return (category * 1000 + number); +} + +/* Return -1 if cannot match */ +static long get_ECMWF_local_paramId(grib_accessor* a, grib_handle* h) +{ + int err = 0; + long edition, centre; + if (h->product_kind != PRODUCT_GRIB) + return -1; + err=grib_get_long(h,"centre",¢re); + if (err) return -1; + err=grib_get_long(h,"edition",&edition); + if (err) return -1; + if (edition==2 && centre==98 && strncmp(a->name,"paramId",7)==0) { + return guess_paramId(h); + } + return -1; +} + static int unpack_long(grib_accessor* a, long* val, size_t *len) { - /* TODO properly calling concept_evaluate_long ! */ const char *p = concept_evaluate(a); if(!p) { + grib_handle* h = grib_handle_of_accessor(a); + long pid = get_ECMWF_local_paramId(a, h); + if (pid != -1) { + *val = pid; + *len = 1; + return GRIB_SUCCESS; + } if (a->creator->defaultkey) - return grib_get_long_internal(grib_handle_of_accessor(a),a->creator->defaultkey,val); + return grib_get_long_internal(h,a->creator->defaultkey,val); return GRIB_NOT_FOUND; } @@ -460,16 +502,62 @@ static void destroy(grib_context* c,grib_accessor* a) */ } +static int is_local_ecmwf_grib2_param_key(grib_accessor* a, long edition, long centre) +{ + if (edition==2 && centre==98) { + if (a->parent->owner && a->parent->owner->name && strcmp(a->parent->owner->name,"parameters")==0) + return 1; + } + return 0; +} + +/* Try to get the name, shortName, units etc for a GRIB2 message with + * local ECMWF coding i.e. discipline=192 etc + */ +static const char* get_ECMWF_local_parameter(grib_accessor* a, grib_handle* h) +{ + int err = 0; + const char* key_name = a->name; /*this is the key whose value we want*/ + long edition, centre; + if (h->product_kind != PRODUCT_GRIB) + return NULL; + err=grib_get_long(h,"centre",¢re); + if (err) return NULL; + err=grib_get_long(h,"edition",&edition); + if (err) return NULL; + if (is_local_ecmwf_grib2_param_key(a,edition,centre)) { + /* Must be one of: 'name', 'shortName', 'units', 'cfName' etc */ + grib_accessor* a2 = NULL; + long pid_guess = guess_paramId(h); + if (pid_guess == -1) return NULL; + + /* Change the paramId so we can get the other string key*/ + err = grib_set_long(h, "paramId", pid_guess); + if (err) return NULL; + /* Get the string value of key. Do not call grib_get_string() to avoid + * dangers of infinite recursion as that calls unpack_string()! + */ + a2 = grib_find_accessor(h, key_name); + if (!a2) return NULL; + return concept_evaluate(a2); + } + return NULL; + +} static int unpack_string (grib_accessor* a, char* val, size_t *len) { size_t slen ; const char *p = concept_evaluate(a); if(!p) { - if (a->creator->defaultkey) - return grib_get_string_internal(grib_handle_of_accessor(a),a->creator->defaultkey,val,len); + grib_handle* h = grib_handle_of_accessor(a); + p = get_ECMWF_local_parameter(a, h); + if (!p) { + if (a->creator->defaultkey) + return grib_get_string_internal(h,a->creator->defaultkey,val,len); - return GRIB_NOT_FOUND; + return GRIB_NOT_FOUND; + } } slen = strlen(p) +1;