Merge branch 'develop' into feature/ECC-1403-Nearest-Part2

This commit is contained in:
Shahram Najm 2022-06-17 10:36:44 +01:00
commit 866593c4bb
14 changed files with 211 additions and 49 deletions

View File

@ -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");

View File

@ -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,

View File

@ -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 */

View File

@ -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;

View File

@ -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"

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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 <assert.h>
#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; i<NUMBER(samples); ++i) {
const char* name = samples[i].sample_name;
char identifier[254] = {0,};
size_t len = 254;
printf("Testing codes_handle_new_from_samples on %s\n", name);
h = codes_handle_new_from_samples(0, name);
assert(h);
assert(samples[i].expected_kind == h->product_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;
}

13
tests/codes_new_from_samples.sh Executable file
View File

@ -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

49
tests/grib_ecc-1406.sh Executable file
View File

@ -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 <<EOF
set numberOfDataPoints = 5016591;
set numberOfValues = 5016591;
set Ni = 2801;
set Nj = 1791;
set latitudeOfFirstGridPoint = 55400000;
set longitudeOfFirstGridPoint = 348000000;
set latitudeOfLastGridPoint = 37500000;
set longitudeOfLastGridPoint = 16000000;
set iDirectionIncrement = 10000;
set jDirectionIncrement = 10000;
meta lastVal element(values, numberOfValues - 1);
set lastVal = 42;
write;
EOF
${tools_dir}/grib_filter -o $tempGrib $tempFilt $sample2
${tools_dir}/grib_ls -l 37.5,16.0,1 $tempGrib > $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

View File

@ -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);
}