diff --git a/examples/C/new_sample.c b/examples/C/new_sample.c index 50fabf02f..0e483c472 100644 --- a/examples/C/new_sample.c +++ b/examples/C/new_sample.c @@ -25,7 +25,8 @@ int main(int argc, char** argv) exit(1); } - h = codes_grib_handle_new_from_samples(NULL, "GRIB2"); + /* h = codes_grib_handle_new_from_samples(NULL, "GRIB2"); */ + h = codes_handle_new_from_samples(NULL, "GRIB2"); if (!h) { fprintf(stderr, "Cannot create grib handle\n"); return 1; @@ -363,10 +364,7 @@ int main(int argc, char** argv) CODES_CHECK(codes_set_double_array(h, "values", vdouble, size), 0); free(vdouble); - CODES_CHECK(codes_set_long(h, "dirty_statistics", 1), 0); - CODES_CHECK(codes_set_long(h, "changeDecimalPrecision", 0), 0); - CODES_CHECK(codes_set_long(h, "decimalPrecision", 0), 0); - CODES_CHECK(codes_set_long(h, "setBitsPerValue", 0), 0); + /* Save the message */ f = fopen(argv[1], "wb"); diff --git a/src/eccodes.h b/src/eccodes.h index 76127cd06..08cf54587 100644 --- a/src/eccodes.h +++ b/src/eccodes.h @@ -477,6 +477,17 @@ codes_handle* codes_grib_handle_new_from_samples(codes_context* c, const char* s */ codes_handle* codes_bufr_handle_new_from_samples(codes_context* c, const char* sample_name); +/** + * Create a handle from a file contained in a samples directory. + * The samples file can be GRIB, BUFR etc. Its type will be determined at runtime. + * The message is copied at the creation of the handle + * + * @param c : the context from which the handle will be created (NULL for default context) + * @param sample_name : the name of the sample file + * @return the new handle, NULL if the resource is invalid or a problem is encountered + */ +codes_handle* codes_handle_new_from_samples(codes_context* c, const char* sample_name); + /** * Clone an existing handle using the context of the original handle, diff --git a/src/eccodes_prototypes.h b/src/eccodes_prototypes.h index 0881fcea9..7adaacf9a 100644 --- a/src/eccodes_prototypes.h +++ b/src/eccodes_prototypes.h @@ -1026,6 +1026,7 @@ void grib_empty_section(grib_context* c, grib_section* b); void grib_section_delete(grib_context* c, grib_section* b); int grib_handle_delete(grib_handle* h); grib_handle* grib_new_handle(grib_context* c); +grib_handle* codes_handle_new_from_samples(grib_context* c, const char* name); grib_handle* grib_handle_new_from_samples(grib_context* c, const char* name); grib_handle* codes_bufr_handle_new_from_samples(grib_context* c, const char* name); int grib_write_message(const grib_handle* h, const char* file, const char* mode); @@ -1187,9 +1188,7 @@ long grib_get_bits_per_value(double max, double min, long binary_scale_factor); long grib_get_decimal_scale_fact(double max, double min, long bpval, long binary_scale); /* grib_templates.c */ -/*grib_handle *grib_internal_sample(grib_context *c, const char *name);*/ -grib_handle* grib_external_template(grib_context* c, const char* name); -grib_handle* bufr_external_template(grib_context* c, const char* name); +grib_handle* codes_external_template(grib_context* c, ProductKind product_kind, const char* name); char* get_external_template_path(grib_context* c, const char* name); /* grib_dependency.c */ diff --git a/src/grib_geography.c b/src/grib_geography.c index cab00429a..4d76b0b72 100644 --- a/src/grib_geography.c +++ b/src/grib_geography.c @@ -3951,7 +3951,8 @@ static int get_precomputed_latitudes_N640(double* lats) } /* 'trunc' is the Gaussian number (or order) */ -/* i.e. Number of parallels between a pole and the equator */ +/* i.e. Number of parallels between a pole and the equator. */ +/* The provided 'lats' array should have allocated 2*trunc elements */ static int _grib_get_gaussian_latitudes(long trunc, double* lats) { long jlat, iter, legi; @@ -3959,7 +3960,7 @@ static int _grib_get_gaussian_latitudes(long trunc, double* lats) double mem1, mem2, conv; double denom = 0.0; double precision = 1.0E-14; - long nlat = trunc * 2; + const long nlat = trunc * 2; rad2deg = 180.0 / M_PI; diff --git a/src/grib_handle.c b/src/grib_handle.c index 6ed1a683a..84c152cc5 100644 --- a/src/grib_handle.c +++ b/src/grib_handle.c @@ -248,6 +248,29 @@ static grib_handle* grib_handle_create(grib_handle* gl, grib_context* c, const v return gl; } +grib_handle* codes_handle_new_from_samples(grib_context* c, const char* name) +{ + grib_handle* g = 0; + if (c == NULL) + c = grib_context_get_default(); + grib_context_set_handle_file_count(c, 0); + grib_context_set_handle_total_count(c, 0); + + if (c->debug) { + fprintf(stderr, "ECCODES DEBUG codes_handle_new_from_samples '%s'\n", name); + } + + g = codes_external_template(c, PRODUCT_ANY, name); + if (!g) + grib_context_log(c, GRIB_LOG_ERROR, + "Unable to load sample file '%s.tmpl'\n" + " from %s\n" + " (ecCodes Version=%s)", + name, c->grib_samples_path, ECCODES_VERSION_STR); + + return g; +} + grib_handle* grib_handle_new_from_samples(grib_context* c, const char* name) { grib_handle* g = 0; @@ -264,7 +287,7 @@ grib_handle* grib_handle_new_from_samples(grib_context* c, const char* name) fprintf(stderr, "ECCODES DEBUG grib_handle_new_from_samples '%s'\n", name); } - g = grib_external_template(c, name); + g = codes_external_template(c, PRODUCT_GRIB, name); if (!g) grib_context_log(c, GRIB_LOG_ERROR, "Unable to load GRIB sample file '%s.tmpl'\n" @@ -283,15 +306,11 @@ grib_handle* codes_bufr_handle_new_from_samples(grib_context* c, const char* nam grib_context_set_handle_file_count(c, 0); grib_context_set_handle_total_count(c, 0); - /* - * g = grib_internal_sample(c,name); - * if(g) return g; - */ if (c->debug) { fprintf(stderr, "ECCODES DEBUG bufr_handle_new_from_samples '%s'\n", name); } - g = bufr_external_template(c, name); + g = codes_external_template(c, PRODUCT_BUFR, name); if (!g) grib_context_log(c, GRIB_LOG_ERROR, "Unable to load BUFR sample file '%s.tmpl'\n" diff --git a/src/grib_iterator_class_latlon.c b/src/grib_iterator_class_latlon.c index 2826a3036..9da3631a3 100644 --- a/src/grib_iterator_class_latlon.c +++ b/src/grib_iterator_class_latlon.c @@ -210,6 +210,10 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) self->las[lai] = lat1; lat1 -= jdir; } + /* ECC-1406: Due to rounding, errors can accumulate. + * So we ensure the last latitude is latitudeOfLastGridPointInDegrees + */ + self->las[self->Nj-1] = lat2; iter->e = -1; return err; diff --git a/src/grib_iterator_class_regular.c b/src/grib_iterator_class_regular.c index b46064920..499d16767 100644 --- a/src/grib_iterator_class_regular.c +++ b/src/grib_iterator_class_regular.c @@ -219,6 +219,10 @@ static int init(grib_iterator* i, grib_handle* h, grib_arguments* args) self->los[loi] = lon1; lon1 += idir; } + /* ECC-1406: Due to rounding, errors can accumulate. + * So we ensure the last longitude is longitudeOfLastGridPointInDegrees + */ + self->los[Ni-1] = lon2; return ret; } diff --git a/src/grib_nearest_class_regular.c b/src/grib_nearest_class_regular.c index 4dfeece03..85835958a 100644 --- a/src/grib_nearest_class_regular.c +++ b/src/grib_nearest_class_regular.c @@ -322,8 +322,8 @@ static int find(grib_nearest* nearest, grib_handle* h, return ret; } while (grib_iterator_next(iter, &lat, &lon, &dummy)) { - if (olat != lat) { - Assert(ilat < self->lats_count); + if (ilat < self->lats_count && olat != lat) { + /* Assert(ilat < self->lats_count); */ self->lats[ilat++] = lat; olat = lat; } diff --git a/src/grib_templates.c b/src/grib_templates.c index 5ff8e859f..b179dd987 100644 --- a/src/grib_templates.c +++ b/src/grib_templates.c @@ -49,6 +49,7 @@ grib_handle* grib_internal_sample(grib_context* c,const char* name) #define ECC_PATH_DELIMITER_CHAR ':' #endif +/* if product_kind is PRODUCT_ANY, the type of sample file is determined at runtime */ static grib_handle* try_product_template(grib_context* c, ProductKind product_kind, const char* dir, const char* name) { char path[1024]; @@ -70,14 +71,37 @@ static grib_handle* try_product_template(grib_context* c, ProductKind product_ki grib_context_log(c, GRIB_LOG_PERROR, "cannot open %s", path); return NULL; } + if (product_kind == PRODUCT_ANY) + { + /* Determine the product kind from sample file */ + char* mesg = NULL; + size_t size = 0; + off_t offset = 0; + mesg = (char*)wmo_read_any_from_file_malloc(f, 0, &size, &offset, &err); + if (mesg && !err) { + Assert(size > 4); + if (strncmp(mesg, "GRIB", 4) == 0 || strncmp(mesg, "DIAG", 4) == 0 || strncmp(mesg, "BUDG", 4) == 0) { + product_kind = PRODUCT_GRIB; + } else if (strncmp(mesg, "BUFR", 4) == 0) { + product_kind = PRODUCT_BUFR; + } else { + grib_context_log(c, GRIB_LOG_ERROR, "Could not determine product kind"); + } + grib_context_free(c, mesg); + rewind(f); + } else { + grib_context_log(c, GRIB_LOG_ERROR, "Could not determine product kind"); + } + } if (product_kind == PRODUCT_BUFR) { g = codes_bufr_handle_new_from_file(c, f, &err); } else { /* Note: Pseudo GRIBs like DIAG and BUDG also come here */ + DebugAssert(product_kind == PRODUCT_GRIB); g = grib_handle_new_from_file(c, f, &err); } if (!g) { - grib_context_log(c, GRIB_LOG_ERROR, "cannot create handle from %s", path); + grib_context_log(c, GRIB_LOG_ERROR, "Cannot create handle from %s", path); } fclose(f); } @@ -100,7 +124,7 @@ static char* try_template_path(grib_context* c, const char* dir, const char* nam return NULL; } -grib_handle* grib_external_template(grib_context* c, const char* name) +grib_handle* codes_external_template(grib_context* c, ProductKind product_kind, const char* name) { const char* base = c->grib_samples_path; char buffer[1024]; @@ -113,7 +137,7 @@ grib_handle* grib_external_template(grib_context* c, const char* name) while (*base) { if (*base == ECC_PATH_DELIMITER_CHAR) { *p = 0; - g = try_product_template(c, PRODUCT_GRIB, buffer, name); + g = try_product_template(c, product_kind, buffer, name); if (g) return g; p = buffer; @@ -123,33 +147,7 @@ grib_handle* grib_external_template(grib_context* c, const char* name) } *p = 0; - return g = try_product_template(c, PRODUCT_GRIB, buffer, name); -} - -grib_handle* bufr_external_template(grib_context* c, const char* name) -{ - const char* base = c->grib_samples_path; - char buffer[1024]; - char* p = buffer; - grib_handle* g = NULL; - - if (!base) - return NULL; - - while (*base) { - if (*base == ECC_PATH_DELIMITER_CHAR) { - *p = 0; - g = try_product_template(c, PRODUCT_BUFR, buffer, name); - if (g) - return g; - p = buffer; - base++; /*advance past delimiter*/ - } - *p++ = *base++; - } - - *p = 0; - g = try_product_template(c, PRODUCT_BUFR, buffer, name); + g = try_product_template(c, product_kind, buffer, name); return g; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index bbaa944af..5f915d6e5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -36,6 +36,7 @@ list(APPEND test_bins bufr_extract_headers extract_offsets bufr_check_descriptors + codes_new_from_samples grib_sh_ieee64 grib_ieee grib_set_bytes @@ -95,6 +96,7 @@ if( HAVE_BUILD_TOOLS ) grib_ecc-1315 grib_ecc-1322 grib_ecc-1319 + grib_ecc-1406 bufr_ecc-1028 bufr_ecc-1195 bufr_ecc-1259 @@ -245,6 +247,7 @@ if( HAVE_BUILD_TOOLS ) grib_statistics grib_tigge_check read_any + codes_new_from_samples grib_dump grib_dump_debug grib_dump_json diff --git a/tests/codes_new_from_samples.c b/tests/codes_new_from_samples.c new file mode 100644 index 000000000..642e90f8d --- /dev/null +++ b/tests/codes_new_from_samples.c @@ -0,0 +1,61 @@ +/* + * (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 +#include "grib_api_internal.h" + +typedef struct sample_t { + const char* sample_name; + const char* expected_ID; + ProductKind expected_kind; +} sample_t; + +static sample_t samples[] = { + {"GRIB1", "GRIB", PRODUCT_GRIB}, + {"GRIB2", "GRIB", PRODUCT_GRIB}, + {"reduced_gg_pl_256_grib1", "GRIB", PRODUCT_GRIB}, + {"reduced_gg_pl_256_grib2", "GRIB", PRODUCT_GRIB}, + {"sh_ml_grib1.tmpl", "GRIB", PRODUCT_GRIB}, + {"sh_ml_grib2.tmpl", "GRIB", PRODUCT_GRIB}, + + {"diag", "DIAG", PRODUCT_GRIB}, /* pseudo GRIBs */ + {"budg", "BUDG", PRODUCT_GRIB}, + + {"BUFR4_local_satellite", "BUFR", PRODUCT_BUFR}, + {"BUFR4_local", "BUFR", PRODUCT_BUFR}, + {"BUFR4", "BUFR", PRODUCT_BUFR}, + {"BUFR3", "BUFR", PRODUCT_BUFR} +}; + +#define NUMBER(a) sizeof(a)/sizeof(a[0]) + +int main(int argc, char** argv) +{ + grib_handle* h = NULL; + size_t i = 0; + + for (i=0; iproduct_kind); + + GRIB_CHECK(grib_get_string(h, "identifier", identifier, &len), 0); + assert( strcmp(samples[i].expected_ID, identifier) == 0 ); + grib_handle_delete(h); + } + + fprintf(stderr,"All done\n"); + return 0; +} diff --git a/tests/codes_new_from_samples.sh b/tests/codes_new_from_samples.sh new file mode 100755 index 000000000..a9b0a3acf --- /dev/null +++ b/tests/codes_new_from_samples.sh @@ -0,0 +1,13 @@ +#!/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 + +$EXEC ${test_dir}/codes_new_from_samples diff --git a/tests/grib_ecc-1406.sh b/tests/grib_ecc-1406.sh new file mode 100755 index 000000000..ace8e0031 --- /dev/null +++ b/tests/grib_ecc-1406.sh @@ -0,0 +1,49 @@ +#!/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 +set -u +REDIRECT=/dev/null +label="grib_ecc-1406_test" + +tempGrib=temp.$label.grib +tempFilt=temp.${label}.filt +tempOut=temp.${label}.txt + +sample2="$samp_dir/GRIB2.tmpl" + +cat > $tempFilt < $tempOut + +grep -q "Grid Point chosen #1 index=5016590" $tempOut +grep -q "grid_simple 42" $tempOut + +${tools_dir}/grib_ls -j -l 37.5,16.0,1 $tempGrib > $tempOut +grep -q 'latitude" : 37.5, "longitude" : 16, "distance" : 0,.*"value" : 42 ,' $tempOut + +rm -f $tempGrib $tempFilt $tempOut diff --git a/tools/grib_get_data.c b/tools/grib_get_data.c index b5aadd581..682d7764b 100644 --- a/tools/grib_get_data.c +++ b/tools/grib_get_data.c @@ -136,7 +136,9 @@ int grib_tool_new_handle_action(grib_runtime_options* options, grib_handle* h) /* Do a very basic sanity check */ const char* str = grib_options_get_option("L:"); if (string_count_char(str, '%') != 2) { - fprintf(stderr, "ERROR: Invalid lats/lons format option \"%s\".\nThe default is: \"%s\"\n", + fprintf(stderr, "ERROR: Invalid lats/lons format option \"%s\".\n" + " The default is: \"%s\"." + " For higher precision, try: \"%%12.6f%%12.6f\"\n", str, default_format_latlons); exit(1); }