mirror of https://github.com/ecmwf/eccodes.git
ECC-1733: GRIB2: codes_set_missing doesn't work for timeIncrement and indicatorOfUnitOfTimeIncrement keys
This commit is contained in:
parent
1183031e71
commit
591f335cdb
|
@ -196,6 +196,7 @@ int main(int argc, char** argv)
|
|||
|
||||
/* 255 = Missing (grib2/tables/4/4.5.table) */
|
||||
CODES_CHECK(codes_set_long(h, "typeOfSecondFixedSurface", 255), 0);
|
||||
CODES_CHECK(codes_set_missing(h, "typeOfSecondFixedSurface"), 0);
|
||||
|
||||
CODES_CHECK(codes_set_missing(h, "scaleFactorOfSecondFixedSurface"), 0);
|
||||
CODES_CHECK(codes_set_missing(h, "scaledValueOfSecondFixedSurface"), 0);
|
||||
|
|
|
@ -340,6 +340,9 @@ void grib_smart_table_delete(grib_context* c);
|
|||
|
||||
/* grib_accessor_class_codetable.cc*/
|
||||
void grib_codetable_delete(grib_context* c);
|
||||
int codes_codetable_get_contents_malloc(const grib_handle* h, const char* key, code_table_entry** entries, size_t* num_entries);
|
||||
int codes_codetable_check_code_figure(const grib_handle* h, const char* key, long code_figure);
|
||||
int codes_codetable_check_abbreviation(const grib_handle* h, const char* key, const char* abbreviation);
|
||||
|
||||
/* grib_accessor_class_codetable_units.cc*/
|
||||
|
||||
|
@ -1144,6 +1147,7 @@ int grib_set_missing(grib_handle* h, const char* name);
|
|||
int grib_is_missing_long(grib_accessor* a, long x);
|
||||
int grib_is_missing_double(grib_accessor* a, double x);
|
||||
int grib_is_missing_string(grib_accessor* a, const unsigned char* x, size_t len);
|
||||
int grib_accessor_can_be_missing(grib_accessor* a, int* err);
|
||||
int grib_accessor_is_missing(grib_accessor* a, int* err);
|
||||
int grib_is_missing(const grib_handle* h, const char* name, int* err);
|
||||
int grib_is_defined(const grib_handle* h, const char* name);
|
||||
|
|
|
@ -50,7 +50,7 @@ static void thread_init()
|
|||
CLASS = accessor
|
||||
SUPER = grib_accessor_class_unsigned
|
||||
IMPLEMENTS = init;dump;unpack_string;pack_expression;unpack_long
|
||||
IMPLEMENTS = value_count;pack_string; destroy; get_native_type;
|
||||
IMPLEMENTS = value_count;pack_string; destroy; get_native_type;pack_missing
|
||||
MEMBERS = const char* tablename
|
||||
MEMBERS = const char* masterDir
|
||||
MEMBERS = const char* localDir
|
||||
|
@ -71,6 +71,7 @@ or edit "accessor.class" and rerun ./make_class.pl
|
|||
*/
|
||||
|
||||
static int get_native_type(grib_accessor*);
|
||||
static int pack_missing(grib_accessor*);
|
||||
static int pack_string(grib_accessor*, const char*, size_t* len);
|
||||
static int pack_expression(grib_accessor*, grib_expression*);
|
||||
static int unpack_long(grib_accessor*, long* val, size_t* len);
|
||||
|
@ -115,7 +116,7 @@ static grib_accessor_class _grib_accessor_class_codetable = {
|
|||
0, /* get offset to bytes */
|
||||
&get_native_type, /* get native type */
|
||||
0, /* get sub_section */
|
||||
0, /* pack_missing */
|
||||
&pack_missing, /* pack_missing */
|
||||
0, /* is_missing */
|
||||
0, /* pack_long */
|
||||
&unpack_long, /* unpack_long */
|
||||
|
@ -523,6 +524,94 @@ void grib_codetable_delete(grib_context* c)
|
|||
}
|
||||
}
|
||||
|
||||
int codes_codetable_get_contents_malloc(const grib_handle* h, const char* key, code_table_entry** entries, size_t* num_entries)
|
||||
{
|
||||
long lvalue = 0;
|
||||
size_t size = 1;
|
||||
int err = 0;
|
||||
grib_context* c = h->context;
|
||||
|
||||
grib_accessor* aa = grib_find_accessor(h, key);
|
||||
if (!aa) return GRIB_NOT_FOUND;
|
||||
|
||||
if (!STR_EQUAL(aa->cclass->name, "codetable")) {
|
||||
return GRIB_INVALID_ARGUMENT; // key is not a codetable
|
||||
}
|
||||
|
||||
const grib_accessor_codetable* ca = (const grib_accessor_codetable*)aa; // could be dynamic_cast
|
||||
|
||||
// Decode the key itself. This will either fetch it from the cache or place it there
|
||||
if ((err = grib_unpack_long(aa, &lvalue, &size)) != GRIB_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const grib_codetable* table = ca->table;
|
||||
if (!table) return GRIB_INTERNAL_ERROR;
|
||||
|
||||
grib_codetable* cached_table = c->codetable; // Access the codetable cache
|
||||
while (cached_table) {
|
||||
if (STR_EQUAL(table->recomposed_name[0], cached_table->recomposed_name[0])) {
|
||||
// Found a cache entry that matches the recomposed name of ours
|
||||
*num_entries = cached_table->size;
|
||||
*entries = (code_table_entry*)calloc(cached_table->size, sizeof(code_table_entry));
|
||||
if (!*entries) {
|
||||
return GRIB_OUT_OF_MEMORY;
|
||||
}
|
||||
for (size_t i = 0; i < cached_table->size; i++) {
|
||||
(*entries)[i] = cached_table->entries[i];
|
||||
}
|
||||
return GRIB_SUCCESS;
|
||||
}
|
||||
cached_table = cached_table->next;
|
||||
}
|
||||
|
||||
return GRIB_CODE_NOT_FOUND_IN_TABLE;
|
||||
}
|
||||
|
||||
int codes_codetable_check_code_figure(const grib_handle* h, const char* key, long code_figure)
|
||||
{
|
||||
code_table_entry* entries = NULL;
|
||||
size_t num_entries = 0;
|
||||
int err = 0;
|
||||
err = codes_codetable_get_contents_malloc(h, key, &entries, &num_entries);
|
||||
if (err) return err;
|
||||
|
||||
if (code_figure < 0 || (size_t)code_figure >= num_entries) {
|
||||
err = GRIB_OUT_OF_RANGE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (entries[code_figure].abbreviation == NULL) {
|
||||
err = GRIB_INVALID_KEY_VALUE;
|
||||
goto cleanup;
|
||||
}
|
||||
cleanup:
|
||||
free(entries);
|
||||
return err;
|
||||
}
|
||||
|
||||
int codes_codetable_check_abbreviation(const grib_handle* h, const char* key, const char* abbreviation)
|
||||
{
|
||||
code_table_entry* entries = NULL;
|
||||
size_t num_entries = 0;
|
||||
int err = 0;
|
||||
err = codes_codetable_get_contents_malloc(h, key, &entries, &num_entries);
|
||||
if (err) return err;
|
||||
|
||||
bool found = false;
|
||||
for (size_t i=0; i<num_entries; ++i) {
|
||||
const char* abbrev = entries[i].abbreviation;
|
||||
if (abbrev && STR_EQUAL(abbrev, abbreviation)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) err = GRIB_INVALID_KEY_VALUE;
|
||||
|
||||
free(entries);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void dump(grib_accessor* a, grib_dumper* dumper)
|
||||
{
|
||||
grib_accessor_codetable* self = (grib_accessor_codetable*)a;
|
||||
|
@ -824,3 +913,27 @@ static int unpack_long(grib_accessor* a, long* val, size_t* len)
|
|||
*len = rlen;
|
||||
return GRIB_SUCCESS;
|
||||
}
|
||||
|
||||
static int pack_missing(grib_accessor* a)
|
||||
{
|
||||
// Many of the code tables do have a 'Missing' entry (all bits = 1)
|
||||
// So it is more user-friendly to allow setting codetable keys to
|
||||
// missing. For tables that do not have such an entry, an error is issued
|
||||
grib_accessor_codetable* self = (grib_accessor_codetable*)a;
|
||||
grib_handle* h = grib_handle_of_accessor(a);
|
||||
|
||||
const long nbytes = a->length;
|
||||
const long nbits = nbytes*8;
|
||||
const long maxVal = (1<<nbits) - 1;
|
||||
|
||||
int err = codes_codetable_check_code_figure(h, a->name, maxVal);
|
||||
if (!err) {
|
||||
size_t l = 1;
|
||||
return grib_pack_long(a, &maxVal, &l);
|
||||
}
|
||||
|
||||
grib_context_log(a->context, GRIB_LOG_ERROR, "There is no 'missing' entry in Code Table %s (%s)",
|
||||
self->tablename, grib_get_error_message(err));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -113,8 +113,6 @@ static void default_long_value(grib_dumper* d, grib_accessor* a, long actualValu
|
|||
return;
|
||||
|
||||
const int type = grib_expression_native_type(h, expression);
|
||||
DEBUG_ASSERT(type == GRIB_TYPE_LONG);
|
||||
|
||||
if (type == GRIB_TYPE_LONG) {
|
||||
long defaultValue = 0;
|
||||
if (grib_expression_evaluate_long(h, expression, &defaultValue) == GRIB_SUCCESS && defaultValue != actualValue) {
|
||||
|
|
|
@ -571,7 +571,7 @@ int grib_set_missing(grib_handle* h, const char* name)
|
|||
if (a->flags & GRIB_ACCESSOR_FLAG_READ_ONLY)
|
||||
return GRIB_READ_ONLY;
|
||||
|
||||
if (a->flags & GRIB_ACCESSOR_FLAG_CAN_BE_MISSING) {
|
||||
if (grib_accessor_can_be_missing(a, &ret)) {
|
||||
if (h->context->debug)
|
||||
fprintf(stderr, "ECCODES DEBUG grib_set_missing %s\n", name);
|
||||
|
||||
|
@ -641,6 +641,19 @@ int grib_accessor_is_missing(grib_accessor* a, int* err)
|
|||
}
|
||||
}
|
||||
|
||||
int grib_accessor_can_be_missing(grib_accessor* a, int* err)
|
||||
{
|
||||
if (a->flags & GRIB_ACCESSOR_FLAG_CAN_BE_MISSING) {
|
||||
return 1;
|
||||
}
|
||||
if (STR_EQUAL(a->cclass->name, "codetable")) {
|
||||
// Special case of Code Table keys
|
||||
// The vast majority have a 'Missing' entry
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int grib_is_missing(const grib_handle* h, const char* name, int* err)
|
||||
{
|
||||
grib_accessor* a = grib_find_accessor(h, name);
|
||||
|
|
|
@ -50,6 +50,7 @@ list(APPEND test_c_bins
|
|||
codes_set_samples_path
|
||||
codes_compare_keys
|
||||
codes_dump_content
|
||||
codes_codetable
|
||||
grib_sh_ieee64
|
||||
grib_ieee
|
||||
grib_set_bytes
|
||||
|
@ -243,6 +244,7 @@ if( HAVE_BUILD_TOOLS )
|
|||
grib_set_force
|
||||
bufr_ecc-556
|
||||
codes_ecc-1698
|
||||
codes_codetable
|
||||
gts_get
|
||||
gts_ls
|
||||
gts_count
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* (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.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "grib_api_internal.h"
|
||||
|
||||
#undef NDEBUG
|
||||
#include <assert.h>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
Assert(argc == 1);
|
||||
grib_handle* h = grib_handle_new_from_samples(0, "GRIB2");
|
||||
|
||||
code_table_entry* entries = NULL;
|
||||
size_t num_entries = 0;
|
||||
int err = codes_codetable_get_contents_malloc(h, "indicatorOfUnitOfTimeRange", &entries, &num_entries);
|
||||
Assert(!err);
|
||||
Assert(entries != NULL);
|
||||
Assert(num_entries == 256);
|
||||
|
||||
for (size_t i=0; i<num_entries;++i) {
|
||||
const char* abbrev = entries[i].abbreviation;
|
||||
const char* title = entries[i].title;
|
||||
if (abbrev) {
|
||||
Assert(title != NULL);
|
||||
printf(" i=%zu |%s| |%s|\n", i, abbrev, title);
|
||||
} else {
|
||||
Assert(title == NULL);
|
||||
}
|
||||
}
|
||||
Assert( STR_EQUAL(entries[13].abbreviation, "s") );
|
||||
Assert( STR_EQUAL(entries[13].title, "Second") );
|
||||
free(entries);
|
||||
entries = NULL;
|
||||
|
||||
// Check a given code is in the table
|
||||
err = codes_codetable_check_code_figure(h, "indicatorOfUnitOfTimeRange", 7); //century
|
||||
Assert(err == GRIB_SUCCESS);
|
||||
err = codes_codetable_check_code_figure(h, "indicatorOfUnitOfTimeRange", 255); //missing
|
||||
Assert(err == GRIB_SUCCESS);
|
||||
err = codes_codetable_check_code_figure(h, "indicatorOfUnitOfTimeRange", -1); //-ve code
|
||||
Assert(err == GRIB_OUT_OF_RANGE);
|
||||
err = codes_codetable_check_code_figure(h, "indicatorOfUnitOfTimeRange", 666); //out of bounds
|
||||
Assert(err == GRIB_OUT_OF_RANGE);
|
||||
err = codes_codetable_check_code_figure(h, "indicatorOfUnitOfTimeRange", 200); // entry not present
|
||||
Assert(err == GRIB_INVALID_KEY_VALUE);
|
||||
err = codes_codetable_check_code_figure(h, "American Pie", 0); // non-existent key
|
||||
Assert(err == GRIB_NOT_FOUND);
|
||||
err = codes_codetable_check_code_figure(h, "year", 0); // not a codetable key
|
||||
Assert(err == GRIB_INVALID_ARGUMENT);
|
||||
|
||||
// Check a given abbreviation is in the table
|
||||
err = codes_codetable_check_abbreviation(h, "indicatorOfUnitOfTimeRange", "15m"); // entry not present
|
||||
Assert(err == GRIB_INVALID_KEY_VALUE);
|
||||
err = codes_codetable_check_abbreviation(h, "indicatorOfUnitOfTimeRange", "D"); // Day
|
||||
Assert(err == GRIB_SUCCESS);
|
||||
err = codes_codetable_check_abbreviation(h, "centre", "ecmf");
|
||||
Assert(err == GRIB_SUCCESS);
|
||||
err = codes_codetable_check_abbreviation(h, "centre", "Smoke On The Water"); // non-existent key
|
||||
Assert(err == GRIB_INVALID_KEY_VALUE);
|
||||
|
||||
// Now try a codetable key with 2 octets
|
||||
err = codes_codetable_get_contents_malloc(h, "gridDefinitionTemplateNumber", &entries, &num_entries);
|
||||
Assert(!err);
|
||||
Assert(entries != NULL);
|
||||
Assert(num_entries == 65536);
|
||||
Assert( STR_EQUAL(entries[40].title, "Gaussian latitude/longitude") );
|
||||
free(entries);
|
||||
|
||||
grib_handle_delete(h);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/sh
|
||||
# (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.
|
||||
#
|
||||
|
||||
. ./include.ctest.sh
|
||||
|
||||
REDIRECT=/dev/null
|
||||
|
||||
label="codes_codetable_test"
|
||||
tempGrib=temp.$label.grib
|
||||
tempLog=temp.$label.log
|
||||
|
||||
$EXEC ${test_dir}/codes_codetable
|
||||
|
||||
# Clean up
|
||||
rm -f $tempGrib $tempLog
|
|
@ -29,10 +29,26 @@ scaleFactorOfSecondFixedSurface=`${tools_dir}/grib_get -w count=1 -p scaleFactor
|
|||
scaledValueOfSecondFixedSurface=`${tools_dir}/grib_get -w count=1 -p scaledValueOfSecondFixedSurface $outfile`
|
||||
[ "$scaledValueOfSecondFixedSurface" = "MISSING" ]
|
||||
|
||||
set +e
|
||||
# Codetable keys being set to 'missing'
|
||||
# -----------------------------------------
|
||||
sample1=$ECCODES_SAMPLES_PATH/GRIB1.tmpl
|
||||
sample2=$ECCODES_SAMPLES_PATH/GRIB2.tmpl
|
||||
temp=temp.grib_missing.grib
|
||||
|
||||
${tools_dir}/grib_set -s centre=missing $infile $outfile 2> $REDIRECT > $REDIRECT
|
||||
# Make sure it works with the default sample
|
||||
${tools_dir}/grib_set -s typeOfFirstFixedSurface=missing $sample2 $outfile
|
||||
grib_check_key_equals $outfile 'typeOfFirstFixedSurface:i' '255'
|
||||
|
||||
[ $? -ne 0 ]
|
||||
# Make sure it works with the latest GRIB2 version code table 4.5
|
||||
latest=`${tools_dir}/grib_get -p tablesVersionLatest $sample2`
|
||||
${tools_dir}/grib_set -s tablesVersion=$latest $sample2 $temp
|
||||
${tools_dir}/grib_set -s typeOfFirstFixedSurface=missing $temp $outfile
|
||||
grib_check_key_equals $outfile 'typeOfFirstFixedSurface:i' '255'
|
||||
rm -f $temp
|
||||
|
||||
${tools_dir}/grib_set -s centre=missing $sample1 $outfile
|
||||
grib_check_key_equals $outfile 'centre' 'consensus'
|
||||
|
||||
|
||||
# Clean up
|
||||
rm -f $outfile
|
||||
|
|
Loading…
Reference in New Issue