2021-02-10 16:03:11 +00:00
|
|
|
/*
|
|
|
|
* (C) Copyright 2005- ECMWF.
|
|
|
|
*
|
|
|
|
* This software is licensed under the terms of the Apache Licence Version 2.0
|
|
|
|
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
|
|
|
|
*
|
|
|
|
* In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
|
|
|
|
* virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
|
|
|
|
*/
|
|
|
|
|
2021-02-11 15:02:11 +00:00
|
|
|
/*
|
|
|
|
* Check GRIB2 parameter concept file e.g. shortName.def, paramId.def
|
|
|
|
*/
|
|
|
|
|
2024-12-07 19:17:55 +00:00
|
|
|
#include "expression/grib_expression_class_long.h"
|
|
|
|
#include "expression/grib_expression_class_functor.h"
|
|
|
|
#include "expression/grib_expression_class_string.h"
|
2021-02-10 16:03:11 +00:00
|
|
|
#include "grib_api_internal.h"
|
|
|
|
|
2021-04-05 19:20:01 +00:00
|
|
|
static int type_of_surface_missing(const char* name, const char* value)
|
2021-02-11 15:02:11 +00:00
|
|
|
{
|
|
|
|
/* Surface Type is Code Table 4.5 in which 255 is the same as missing */
|
2021-04-05 19:20:01 +00:00
|
|
|
if (strcmp(value, "255") == 0) {
|
2021-02-11 15:02:11 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2021-04-05 19:20:01 +00:00
|
|
|
/* Beware of problems where we put 'missing()' for a code table key! */
|
|
|
|
if (strncmp(value, "missing", 7) == 0) {
|
|
|
|
fprintf(stderr, "Invalid value for %s Code Table entry: '%s'\n", name, value);
|
2024-12-20 12:58:07 +00:00
|
|
|
ECCODES_ASSERT(0);
|
2021-04-05 19:20:01 +00:00
|
|
|
}
|
2021-02-11 15:02:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int scale_factor_missing(const char* value)
|
|
|
|
{
|
|
|
|
/* Scale factor is one octet so 255 is the same as missing */
|
|
|
|
if (strcmp(value, "missing") == 0 || strcmp(value, "255") == 0) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-04-24 17:17:20 +00:00
|
|
|
#define STAT_PROC_MAX_VAL 103 // increase this with new Code Table 4.10 entries
|
|
|
|
|
2021-11-13 17:39:54 +00:00
|
|
|
/*
|
|
|
|
* key = paramId or shortName
|
|
|
|
* filename = paramId.def or shortName.def
|
|
|
|
*/
|
2021-02-10 16:03:11 +00:00
|
|
|
static int grib_check_param_concepts(const char* key, const char* filename)
|
|
|
|
{
|
2022-02-16 11:49:40 +00:00
|
|
|
int isLocal = 0;
|
2024-04-22 12:35:25 +00:00
|
|
|
int count = 0;
|
2021-02-10 16:03:11 +00:00
|
|
|
grib_concept_value* concept_value = grib_parse_concept_file(NULL, filename);
|
2021-02-11 15:02:11 +00:00
|
|
|
if (!concept_value)
|
|
|
|
return GRIB_IO_PROBLEM;
|
|
|
|
|
2022-02-16 11:49:40 +00:00
|
|
|
if (strstr(filename, "/localConcepts/")) {
|
|
|
|
isLocal = 1;
|
|
|
|
}
|
2021-02-10 16:03:11 +00:00
|
|
|
while (concept_value) {
|
2024-04-22 12:35:25 +00:00
|
|
|
count++;
|
|
|
|
if (strlen(concept_value->name) == 0) {
|
|
|
|
fprintf(stderr, "%s %s: Empty concept value (count=%d)\n", key, concept_value->name, count);
|
2024-12-20 12:58:07 +00:00
|
|
|
ECCODES_ASSERT(0);
|
2024-04-22 12:35:25 +00:00
|
|
|
}
|
2021-02-10 16:03:11 +00:00
|
|
|
grib_concept_condition* concept_condition = concept_value->conditions;
|
2021-02-11 15:02:11 +00:00
|
|
|
/* Convention:
|
2021-11-13 17:39:54 +00:00
|
|
|
* -1 key not present
|
|
|
|
* 0 key present and not missing
|
|
|
|
* 1 key present and missing
|
2021-02-11 15:02:11 +00:00
|
|
|
*/
|
|
|
|
int scaleFactor1Missing = -1, scaleFactor2Missing = -1;
|
|
|
|
int scaledValue1Missing = -1, scaledValue2Missing = -1;
|
|
|
|
int type1Missing = -1, type2Missing = -1;
|
2021-02-10 16:03:11 +00:00
|
|
|
int err = 0;
|
2021-11-13 17:39:54 +00:00
|
|
|
/* concept_value->name is the value of the key (e.g. 151163 or sst) */
|
2024-08-02 11:37:53 +00:00
|
|
|
if (strcmp(key, "cfVarName")==0) {
|
2024-12-20 12:58:07 +00:00
|
|
|
ECCODES_ASSERT( strlen(concept_value->name) > 0 );
|
2024-08-02 11:37:53 +00:00
|
|
|
if ( isdigit(concept_value->name[0]) || strcmp(concept_value->name, "~")==0 ) {
|
|
|
|
fprintf(stderr, "%s %s: Invalid cfVarName in file %s\n",
|
|
|
|
key, concept_value->name, filename);
|
|
|
|
return GRIB_INVALID_KEY_VALUE;
|
|
|
|
}
|
|
|
|
}
|
2021-02-10 16:03:11 +00:00
|
|
|
while (concept_condition) {
|
2024-12-07 19:17:55 +00:00
|
|
|
char condition_value[512] = {0, };
|
|
|
|
eccodes::Expression* expression = concept_condition->expression;
|
2021-02-10 16:03:11 +00:00
|
|
|
const char* condition_name = concept_condition->name;
|
2021-04-05 19:20:01 +00:00
|
|
|
/* printf("%s\n", concept_value->name); */
|
2021-02-10 18:03:20 +00:00
|
|
|
/* condition_name is discipline, parameterCategory etc. */
|
2024-12-07 19:17:55 +00:00
|
|
|
if (strcmp(expression->class_name(), "long") == 0) {
|
|
|
|
eccodes::expression::Long* el = dynamic_cast<eccodes::expression::Long*>(expression);
|
|
|
|
long value;
|
|
|
|
el->evaluate_long(NULL, &value);
|
|
|
|
snprintf(condition_value, sizeof(condition_value), "%ld", value);
|
2021-02-11 15:02:11 +00:00
|
|
|
}
|
2024-12-07 19:17:55 +00:00
|
|
|
else if (strcmp(expression->class_name(), "functor") == 0) {
|
|
|
|
eccodes::expression::Functor* ef = dynamic_cast<eccodes::expression::Functor*>(expression);
|
|
|
|
snprintf(condition_value, sizeof(condition_value), "%s", ef->name());
|
2021-02-11 15:02:11 +00:00
|
|
|
}
|
2024-12-07 19:17:55 +00:00
|
|
|
else if (strcmp(expression->class_name(), "string") == 0) {
|
|
|
|
eccodes::expression::String* es = dynamic_cast<eccodes::expression::String*>(expression);
|
|
|
|
int error;
|
|
|
|
const char* value = es->evaluate_string(NULL, NULL, NULL, &error);
|
|
|
|
snprintf(condition_value, sizeof(condition_value), "%s", value);
|
2021-02-11 15:02:11 +00:00
|
|
|
}
|
|
|
|
else {
|
2021-04-05 19:20:01 +00:00
|
|
|
fprintf(stderr, "%s %s: Unknown class name: '%s'\n",
|
2024-12-07 19:17:55 +00:00
|
|
|
key, concept_value->name, expression->class_name());
|
2024-12-20 12:58:07 +00:00
|
|
|
ECCODES_ASSERT(0);
|
2021-02-10 16:03:11 +00:00
|
|
|
}
|
2022-02-16 11:49:40 +00:00
|
|
|
if (!isLocal && strcmp(condition_name, "localTablesVersion") == 0) {
|
|
|
|
fprintf(stderr, "%s %s: Cannot have localTablesVersion key in WMO file %s!\n",
|
|
|
|
key, concept_value->name, filename);
|
|
|
|
return GRIB_INVALID_KEY_VALUE;
|
|
|
|
}
|
2024-04-24 17:17:20 +00:00
|
|
|
if (strcmp(condition_name, "typeOfStatisticalProcessing") == 0) {
|
|
|
|
long lValue = atol(condition_value);
|
|
|
|
if (lValue > STAT_PROC_MAX_VAL || lValue < 0) {
|
|
|
|
fprintf(stderr, "Bad value for %s in %s=%s in file %s\n",
|
|
|
|
condition_name, key, concept_value->name, filename);
|
|
|
|
return GRIB_INVALID_KEY_VALUE;
|
|
|
|
}
|
|
|
|
}
|
2021-02-11 15:02:11 +00:00
|
|
|
if (strcmp(condition_name, "typeOfFirstFixedSurface") == 0) {
|
2021-04-05 19:20:01 +00:00
|
|
|
type1Missing = type_of_surface_missing(condition_name, condition_value);
|
2021-02-11 15:02:11 +00:00
|
|
|
}
|
|
|
|
if (strcmp(condition_name, "typeOfSecondFixedSurface") == 0) {
|
2021-04-05 19:20:01 +00:00
|
|
|
type2Missing = type_of_surface_missing(condition_name, condition_value);
|
2021-02-11 15:02:11 +00:00
|
|
|
}
|
|
|
|
if (strcmp(condition_name, "scaleFactorOfFirstFixedSurface") == 0) {
|
|
|
|
scaleFactor1Missing = scale_factor_missing(condition_value);
|
2021-02-10 18:03:20 +00:00
|
|
|
}
|
2021-02-11 15:02:11 +00:00
|
|
|
if (strcmp(condition_name, "scaleFactorOfSecondFixedSurface") == 0) {
|
|
|
|
scaleFactor2Missing = scale_factor_missing(condition_value);
|
|
|
|
}
|
|
|
|
if (strcmp(condition_name, "scaledValueOfFirstFixedSurface") == 0) {
|
2021-04-05 19:20:01 +00:00
|
|
|
scaledValue1Missing = (strncmp(condition_value, "missing", 7) == 0);
|
2021-02-11 15:02:11 +00:00
|
|
|
}
|
|
|
|
if (strcmp(condition_name, "scaledValueOfSecondFixedSurface") == 0) {
|
2021-04-05 19:20:01 +00:00
|
|
|
scaledValue2Missing = (strncmp(condition_value, "missing", 7) == 0);
|
2021-02-10 18:03:20 +00:00
|
|
|
}
|
2021-02-10 16:03:11 +00:00
|
|
|
|
|
|
|
concept_condition = concept_condition->next;
|
|
|
|
}
|
|
|
|
/* Now check the scale factor/value pairs */
|
2021-02-11 15:02:11 +00:00
|
|
|
if (type1Missing == 1 && scaleFactor1Missing == 0 && scaledValue1Missing == 0) err = 1;
|
|
|
|
if (type2Missing == 1 && scaleFactor2Missing == 0 && scaledValue2Missing == 0) err = 1;
|
|
|
|
if (scaleFactor1Missing == 1 && scaledValue1Missing == 0) err = 1;
|
|
|
|
if (scaleFactor1Missing == 0 && scaledValue1Missing == 1) err = 1;
|
|
|
|
if (scaleFactor2Missing == 1 && scaledValue2Missing == 0) err = 1;
|
|
|
|
if (scaleFactor2Missing == 0 && scaledValue2Missing == 1) err = 1;
|
2021-02-10 16:03:11 +00:00
|
|
|
if (err) {
|
2021-02-11 15:02:11 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"Error: Mismatched type of surface, scale factor, scaled value keys for %s='%s'.\n"
|
|
|
|
" If the type of surface is missing so should its scaled keys\n"
|
|
|
|
" If the scale factor is missing so should the scaled value and vice versa\n",
|
2021-02-10 18:03:20 +00:00
|
|
|
key, concept_value->name);
|
|
|
|
return GRIB_INVALID_KEY_VALUE;
|
2021-02-10 16:03:11 +00:00
|
|
|
}
|
|
|
|
concept_value = concept_value->next;
|
|
|
|
}
|
2021-02-10 18:03:20 +00:00
|
|
|
return GRIB_SUCCESS;
|
2021-02-10 16:03:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char** argv)
|
|
|
|
{
|
2021-02-11 15:02:11 +00:00
|
|
|
int err = 0;
|
|
|
|
const char* concepts_key = argv[1];
|
2021-02-10 16:03:11 +00:00
|
|
|
const char* concepts_filename = argv[2];
|
2021-02-11 15:02:11 +00:00
|
|
|
|
2024-12-20 12:58:07 +00:00
|
|
|
ECCODES_ASSERT(argc == 3);
|
2021-02-10 16:03:11 +00:00
|
|
|
err = grib_check_param_concepts(concepts_key, concepts_filename);
|
|
|
|
if (err) return err;
|
|
|
|
|
|
|
|
printf("ALL OK\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|