2013-03-25 12:04:10 +00:00
|
|
|
/*
|
2019-04-15 13:44:45 +00:00
|
|
|
* Copyright 2005-2019 ECMWF.
|
2013-03-25 12:04:10 +00:00
|
|
|
*
|
|
|
|
* 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 "grib_api_internal.h"
|
2017-11-07 16:42:49 +00:00
|
|
|
#include <float.h>
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2015-02-18 17:42:02 +00:00
|
|
|
#ifdef ECCODES_ON_WINDOWS
|
2015-07-17 12:51:36 +00:00
|
|
|
/* Replace C99/Unix rint() for Windows Visual C++ (only before VC++ 2013 versions) */
|
|
|
|
#if defined _MSC_VER && _MSC_VER < 1800
|
|
|
|
double rint(double x)
|
|
|
|
{
|
|
|
|
char * buf = 0;
|
|
|
|
int decimal=0, sign=0, err = 0;
|
|
|
|
double result = 0;
|
|
|
|
buf = (char*) malloc(_CVTBUFSIZE);
|
|
|
|
err = _fcvt_s(buf, _CVTBUFSIZE, x, 0, &decimal, &sign);
|
|
|
|
Assert(err == 0);
|
|
|
|
result = atof(buf);
|
|
|
|
if(sign == 1) {
|
|
|
|
result = result * -1;
|
|
|
|
}
|
|
|
|
free(buf);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
#endif
|
2013-03-25 14:23:07 +00:00
|
|
|
#endif
|
|
|
|
|
2018-02-05 16:05:31 +00:00
|
|
|
typedef enum {eROUND_ANGLE_UP, eROUND_ANGLE_DOWN} RoundingPolicy;
|
|
|
|
|
2015-12-31 11:51:57 +00:00
|
|
|
static void set_total_length(unsigned char* buffer,long *section_length,long *section_offset,int edition,size_t totalLength)
|
|
|
|
{
|
2013-08-01 15:52:01 +00:00
|
|
|
long off;
|
|
|
|
switch (edition) {
|
|
|
|
case 1:
|
|
|
|
if(totalLength < 0x800000 ) {
|
|
|
|
off=32;
|
|
|
|
grib_encode_unsigned_long(buffer, (unsigned long)totalLength , &off, 24);
|
|
|
|
} else {
|
|
|
|
long s4len,t120;
|
|
|
|
totalLength -= 4;
|
|
|
|
t120 = (totalLength+119)/120;
|
|
|
|
s4len = t120*120 - totalLength;
|
|
|
|
totalLength = 0x800000 | t120;
|
|
|
|
off=32;
|
|
|
|
grib_encode_unsigned_long(buffer, (unsigned long)totalLength , &off, 24);
|
|
|
|
off=section_offset[4]*8;
|
|
|
|
grib_encode_unsigned_long(buffer, (unsigned long)s4len , &off, 24);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
off=64;
|
|
|
|
grib_encode_unsigned_long(buffer, (unsigned long)totalLength , &off, 64);
|
|
|
|
break;
|
|
|
|
}
|
2013-03-25 12:04:10 +00:00
|
|
|
}
|
|
|
|
|
2015-12-31 11:51:57 +00:00
|
|
|
static grib_handle* grib_sections_copy_internal(grib_handle* hfrom,grib_handle* hto,int sections[],int *err)
|
|
|
|
{
|
2013-08-01 15:52:01 +00:00
|
|
|
int i;
|
|
|
|
size_t totalLength=0;
|
|
|
|
unsigned char* buffer;
|
|
|
|
unsigned char *p;
|
|
|
|
long edition=0;
|
|
|
|
long section_length[MAX_NUM_SECTIONS]={0,};
|
|
|
|
long section_offset[MAX_NUM_SECTIONS]={0,};
|
|
|
|
long off=0;
|
|
|
|
grib_handle* h;
|
2018-11-27 21:38:14 +00:00
|
|
|
char section_length_str[64]="section0Length";
|
|
|
|
char section_offset_str[64]="offsetSection0";
|
2013-08-01 15:52:01 +00:00
|
|
|
long length,offset;
|
|
|
|
|
|
|
|
*err=grib_get_long(hfrom,"edition",&edition);
|
|
|
|
if (*err) return NULL;
|
|
|
|
|
|
|
|
for (i=0;i<=hfrom->sections_count;i++) {
|
|
|
|
|
|
|
|
if (sections[i]) {h=hfrom;}
|
|
|
|
else {h=hto;}
|
|
|
|
|
|
|
|
sprintf(section_length_str,"section%dLength",i);
|
|
|
|
if (grib_get_long(h,section_length_str,&length)) continue;
|
|
|
|
section_length[i]=length;
|
|
|
|
|
|
|
|
sprintf(section_offset_str,"offsetSection%d",i);
|
|
|
|
if (grib_get_long(h,section_offset_str,&offset)) continue;
|
|
|
|
section_offset[i]=offset;
|
|
|
|
|
|
|
|
totalLength+=section_length[i];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-10-02 15:50:49 +00:00
|
|
|
buffer=(unsigned char*)grib_context_malloc_clear(hfrom->context,totalLength*sizeof(char));
|
2013-08-01 15:52:01 +00:00
|
|
|
|
|
|
|
p=buffer;
|
|
|
|
off=0;
|
|
|
|
for (i=0;i<=hfrom->sections_count;i++) {
|
2016-04-13 18:32:18 +00:00
|
|
|
grib_handle* hand = NULL;
|
|
|
|
if (sections[i]) hand=hfrom;
|
|
|
|
else hand=hto;
|
|
|
|
p=(unsigned char*)memcpy(p,hand->buffer->data+section_offset[i],section_length[i]);
|
2013-08-01 15:52:01 +00:00
|
|
|
section_offset[i]=off;
|
|
|
|
off+=section_length[i];
|
|
|
|
p+=section_length[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy section 3 present flag*/
|
|
|
|
if (edition==1) {
|
|
|
|
const void* buffer_to=NULL;
|
|
|
|
size_t size_to=0;
|
|
|
|
grib_get_message(hto,&buffer_to,&size_to);
|
|
|
|
memcpy(buffer+15,((unsigned char*)buffer_to)+15,1);
|
|
|
|
}
|
|
|
|
|
|
|
|
set_total_length(buffer,section_length,section_offset,edition,totalLength);
|
|
|
|
|
|
|
|
h=grib_handle_new_from_message(hfrom->context,buffer,totalLength);
|
|
|
|
|
|
|
|
/*to allow free of buffer*/
|
|
|
|
h->buffer->property = GRIB_MY_BUFFER;
|
|
|
|
|
|
|
|
switch (edition) {
|
|
|
|
case 1:
|
|
|
|
if (sections[1] && sections[2]) break;
|
|
|
|
|
|
|
|
if (sections[1]) {
|
|
|
|
long PVPresent;
|
|
|
|
grib_get_long(hfrom,"PVPresent",&PVPresent);
|
|
|
|
if (PVPresent) {
|
|
|
|
double *pv;
|
|
|
|
long numberOfVerticalCoordinateValues;
|
|
|
|
size_t size=0;
|
|
|
|
|
|
|
|
grib_get_long(hfrom,"numberOfVerticalCoordinateValues",&numberOfVerticalCoordinateValues);
|
|
|
|
size=numberOfVerticalCoordinateValues;
|
2014-10-02 15:50:49 +00:00
|
|
|
pv=(double*)grib_context_malloc_clear(hfrom->context,numberOfVerticalCoordinateValues*sizeof(double));
|
2013-08-01 15:52:01 +00:00
|
|
|
grib_get_double_array(hfrom,"pv",pv,&size);
|
|
|
|
grib_set_long(h,"PVPresent",1);
|
|
|
|
grib_set_double_array(h,"pv",pv,size);
|
|
|
|
|
|
|
|
grib_context_free(hfrom->context,pv);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
grib_set_long(h,"PVPresent",0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sections[2]) {
|
|
|
|
long PVPresent;
|
|
|
|
grib_get_long(hto,"PVPresent",&PVPresent);
|
|
|
|
if (PVPresent) {
|
|
|
|
double *pv;
|
|
|
|
long numberOfVerticalCoordinateValues;
|
|
|
|
size_t size=0;
|
|
|
|
|
|
|
|
grib_get_long(hto,"numberOfVerticalCoordinateValues",&numberOfVerticalCoordinateValues);
|
|
|
|
size=numberOfVerticalCoordinateValues;
|
2014-10-02 15:50:49 +00:00
|
|
|
pv=(double*)grib_context_malloc_clear(hto->context,numberOfVerticalCoordinateValues*sizeof(double));
|
2013-08-01 15:52:01 +00:00
|
|
|
grib_get_double_array(hto,"pv",pv,&size);
|
|
|
|
grib_set_long(h,"PVPresent",1);
|
|
|
|
grib_set_double_array(h,"pv",pv,size);
|
|
|
|
|
|
|
|
grib_context_free(hto->context,pv);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
grib_set_long(h,"PVPresent",0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (sections[1]) {
|
|
|
|
long discipline;
|
|
|
|
grib_get_long(hfrom,"discipline",&discipline);
|
|
|
|
grib_set_long(h,"discipline",discipline);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return h;
|
2013-03-25 12:04:10 +00:00
|
|
|
}
|
|
|
|
|
2015-12-31 11:51:57 +00:00
|
|
|
grib_handle* grib_util_sections_copy(grib_handle* hfrom,grib_handle* hto,int what,int *err)
|
|
|
|
{
|
2013-08-01 15:52:01 +00:00
|
|
|
long edition_from=0;
|
|
|
|
long edition_to=0;
|
|
|
|
long localDefinitionNumber=-1;
|
|
|
|
int sections_to_copy[MAX_NUM_SECTIONS]={0,};
|
|
|
|
|
|
|
|
*err=grib_get_long(hfrom,"edition",&edition_from);
|
|
|
|
if (*err) return NULL;
|
|
|
|
*err=grib_get_long(hto,"edition",&edition_to);
|
|
|
|
if (*err) return NULL;
|
|
|
|
|
|
|
|
if (edition_to != 1 && edition_to != 2 ) {
|
|
|
|
*err=GRIB_NOT_IMPLEMENTED;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (edition_from!=edition_to) {
|
|
|
|
*err=GRIB_DIFFERENT_EDITION;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (what & GRIB_SECTION_GRID) {
|
|
|
|
switch (edition_from) {
|
|
|
|
case 1:
|
|
|
|
sections_to_copy[2]=1;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
sections_to_copy[3]=1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (what & GRIB_SECTION_DATA) {
|
|
|
|
switch (edition_from) {
|
|
|
|
case 1:
|
|
|
|
sections_to_copy[3]=1;
|
|
|
|
sections_to_copy[4]=1;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
sections_to_copy[5]=1;
|
|
|
|
sections_to_copy[6]=1;
|
|
|
|
sections_to_copy[7]=1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (what & GRIB_SECTION_LOCAL) {
|
|
|
|
switch (edition_from) {
|
|
|
|
case 1:
|
|
|
|
sections_to_copy[1]=1;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
sections_to_copy[2]=1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (what & GRIB_SECTION_PRODUCT) {
|
|
|
|
switch (edition_from) {
|
|
|
|
case 1:
|
|
|
|
grib_get_long(hfrom,"localDefinitionNumber",&localDefinitionNumber);
|
|
|
|
if (localDefinitionNumber==13) {
|
|
|
|
sections_to_copy[4]=1;
|
|
|
|
}
|
|
|
|
sections_to_copy[1]=1;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
sections_to_copy[1]=1;
|
|
|
|
sections_to_copy[4]=1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (what & GRIB_SECTION_BITMAP) {
|
|
|
|
switch (edition_from) {
|
|
|
|
case 1:
|
|
|
|
sections_to_copy[3]=1;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
sections_to_copy[6]=1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return grib_sections_copy_internal(hfrom,hto,sections_to_copy,err);
|
2013-03-25 12:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static grib_trie* init_list(const char* name);
|
|
|
|
static grib_trie* param_id_list = NULL;
|
|
|
|
static grib_trie* mars_param_list = NULL;
|
|
|
|
/* TODO thread safe */
|
2015-12-31 11:51:57 +00:00
|
|
|
grib_string_list* grib_util_get_param_id(const char* mars_param)
|
|
|
|
{
|
2013-08-01 15:52:01 +00:00
|
|
|
if (!mars_param_list && (mars_param_list=init_list("mars_param.table"))==NULL) return NULL;
|
2014-10-02 15:50:49 +00:00
|
|
|
return (grib_string_list*)grib_trie_get(mars_param_list,mars_param);
|
2013-03-25 12:04:10 +00:00
|
|
|
}
|
|
|
|
|
2015-12-31 11:51:57 +00:00
|
|
|
grib_string_list* grib_util_get_mars_param(const char* param_id)
|
|
|
|
{
|
2013-08-01 15:52:01 +00:00
|
|
|
if (!param_id_list && (param_id_list=init_list("param_id.table"))==NULL) return NULL;
|
2014-10-02 15:50:49 +00:00
|
|
|
return (grib_string_list*)grib_trie_get(param_id_list,param_id);
|
2013-03-25 12:04:10 +00:00
|
|
|
}
|
|
|
|
|
2015-12-31 11:51:57 +00:00
|
|
|
static grib_trie* init_list(const char* name)
|
|
|
|
{
|
2013-08-01 15:52:01 +00:00
|
|
|
char *full_path=0;
|
|
|
|
FILE* fh;
|
2014-03-26 14:30:16 +00:00
|
|
|
char s[101];
|
|
|
|
char param[101];
|
2013-08-01 15:52:01 +00:00
|
|
|
grib_string_list* list=0;
|
|
|
|
grib_string_list* next=0;
|
|
|
|
grib_trie* trie_list;
|
|
|
|
grib_context* c=grib_context_get_default();
|
|
|
|
full_path=grib_context_full_defs_path(c,name);
|
|
|
|
|
2016-06-19 08:22:15 +00:00
|
|
|
fh=codes_fopen(full_path,"r");
|
2013-08-01 15:52:01 +00:00
|
|
|
if (!fh) {
|
|
|
|
grib_context_log(c,GRIB_LOG_PERROR,"unable to read %s",full_path);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-10-02 15:50:49 +00:00
|
|
|
list=(grib_string_list*)grib_context_malloc_clear(c,sizeof(grib_string_list));
|
2013-08-01 15:52:01 +00:00
|
|
|
trie_list=grib_trie_new(c);
|
2014-03-26 14:30:16 +00:00
|
|
|
if (fscanf(fh,"%100s",param)==EOF) {
|
|
|
|
fclose(fh);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
while (fscanf(fh,"%100s",s)!=EOF) {
|
2013-08-01 15:52:01 +00:00
|
|
|
if (!strcmp(s,"|")) {
|
|
|
|
grib_trie_insert(trie_list, param,list);
|
2014-03-26 14:30:16 +00:00
|
|
|
if (fscanf(fh,"%100s",param)==EOF) {
|
|
|
|
fclose(fh);
|
|
|
|
return trie_list;
|
|
|
|
}
|
2013-08-01 15:52:01 +00:00
|
|
|
list=NULL;
|
|
|
|
} else {
|
|
|
|
if (!list) {
|
2014-10-02 15:50:49 +00:00
|
|
|
list=(grib_string_list*)grib_context_malloc_clear(c,sizeof(grib_string_list));
|
2013-08-01 15:52:01 +00:00
|
|
|
list->value=grib_context_strdup(c,s);
|
|
|
|
} else {
|
|
|
|
next=list;
|
|
|
|
while(next->next) next=next->next;
|
2014-10-02 15:50:49 +00:00
|
|
|
next->next=(grib_string_list*)grib_context_malloc_clear(c,sizeof(grib_string_list));
|
2013-08-01 15:52:01 +00:00
|
|
|
next->next->value=grib_context_strdup(c,s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fh);
|
|
|
|
return 0;
|
2013-03-25 12:04:10 +00:00
|
|
|
}
|
|
|
|
|
2017-08-24 13:00:02 +00:00
|
|
|
/* For debugging purposes */
|
2016-09-01 10:21:17 +00:00
|
|
|
static void print_values(grib_context* c, const grib_util_grid_spec2* spec,
|
2017-08-24 13:00:02 +00:00
|
|
|
const double* data_values, const size_t data_values_count, /* the data pay load */
|
2018-07-05 13:15:01 +00:00
|
|
|
const grib_values *keyval_pairs, const size_t count) /* keys and their values */
|
2015-07-27 12:27:03 +00:00
|
|
|
{
|
2017-08-24 13:00:02 +00:00
|
|
|
size_t i=0;
|
|
|
|
int isConstant = 1;
|
2017-11-07 16:42:49 +00:00
|
|
|
double v = 0, minVal=DBL_MAX, maxVal=-DBL_MAX;
|
2019-08-05 10:32:11 +00:00
|
|
|
fprintf(stderr, "ECCODES DEBUG grib_util grib_set_values: setting %lu key/value pairs\n",(unsigned long)count);
|
2013-08-01 15:52:01 +00:00
|
|
|
|
2017-08-24 13:00:02 +00:00
|
|
|
for(i=0; i<count; i++)
|
2013-08-01 15:52:01 +00:00
|
|
|
{
|
2018-07-05 13:15:01 +00:00
|
|
|
switch(keyval_pairs[i].type)
|
2013-08-01 15:52:01 +00:00
|
|
|
{
|
2019-08-05 10:32:11 +00:00
|
|
|
case GRIB_TYPE_LONG: fprintf(stderr, "ECCODES DEBUG grib_util: => %s = %ld;\n"
|
2018-07-05 13:15:01 +00:00
|
|
|
,keyval_pairs[i].name,(long)keyval_pairs[i].long_value); break;
|
2019-08-05 10:32:11 +00:00
|
|
|
case GRIB_TYPE_DOUBLE: fprintf(stderr, "ECCODES DEBUG grib_util: => %s = %.16e;\n"
|
2018-07-05 13:15:01 +00:00
|
|
|
,keyval_pairs[i].name,keyval_pairs[i].double_value); break;
|
2019-08-05 10:32:11 +00:00
|
|
|
case GRIB_TYPE_STRING: fprintf(stderr, "ECCODES DEBUG grib_util: => %s = \"%s\";\n"
|
2018-07-05 13:15:01 +00:00
|
|
|
,keyval_pairs[i].name,keyval_pairs[i].string_value); break;
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-05 10:32:11 +00:00
|
|
|
fprintf(stderr, "ECCODES DEBUG grib_util: data_values_count=%lu;\n", (unsigned long)data_values_count);
|
2017-08-24 13:00:02 +00:00
|
|
|
for (i=0; i<data_values_count; i++) {
|
|
|
|
if (i==0) v = data_values[i];
|
|
|
|
if (data_values[i] != spec->missingValue) {
|
|
|
|
if (v == spec->missingValue) {
|
|
|
|
v = data_values[i];
|
|
|
|
} else if (v != data_values[i]) {
|
|
|
|
isConstant=0;
|
|
|
|
break;
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-11-07 16:42:49 +00:00
|
|
|
|
|
|
|
for (i=0; i<data_values_count; i++) {
|
|
|
|
v = data_values[i];
|
|
|
|
if (v!=spec->missingValue) {
|
|
|
|
if (v < minVal) minVal=v;
|
|
|
|
if (v > maxVal) maxVal=v;
|
|
|
|
}
|
|
|
|
}
|
2019-08-05 10:32:11 +00:00
|
|
|
fprintf(stderr, "ECCODES DEBUG grib_util: data_values are CONSTANT? %d\t(min=%.16e, max=%.16e)\n",
|
2017-11-07 16:42:49 +00:00
|
|
|
isConstant, minVal, maxVal);
|
2019-08-05 10:32:11 +00:00
|
|
|
if (c->gribex_mode_on) fprintf(stderr, "ECCODES DEBUG grib_util: GRIBEX mode is turned on!\n");
|
2017-08-24 13:00:02 +00:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (spec->bitmapPresent) {
|
|
|
|
int missing = 0;
|
|
|
|
size_t j = 0;
|
|
|
|
double min = 1e100;
|
|
|
|
for(j = 0; j < data_values_count ; j++)
|
|
|
|
{
|
|
|
|
double d = data_values[j] - spec->missingValue;
|
|
|
|
if(d < 0) d = -d;
|
|
|
|
if(d < min) {
|
|
|
|
min = d;
|
|
|
|
}
|
|
|
|
if(data_values[j] == spec->missingValue)
|
|
|
|
missing++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2013-03-25 12:04:10 +00:00
|
|
|
}
|
|
|
|
|
2017-11-13 13:26:36 +00:00
|
|
|
/*
|
2015-10-27 16:37:13 +00:00
|
|
|
static int DBL_EQUAL(double d1, double d2, double tolerance)
|
|
|
|
{
|
2015-10-28 17:36:10 +00:00
|
|
|
return fabs(d1-d2) < tolerance;
|
|
|
|
}
|
2017-11-13 13:26:36 +00:00
|
|
|
*/
|
2018-02-05 16:05:31 +00:00
|
|
|
#if 0
|
2015-10-29 13:38:35 +00:00
|
|
|
/* Returns a boolean: 1 if angle can be encoded, 0 otherwise */
|
2015-10-28 17:36:10 +00:00
|
|
|
static int grib1_angle_can_be_encoded(const double angle)
|
|
|
|
{
|
|
|
|
const double angle_milliDegrees = angle * 1000;
|
|
|
|
double rounded = (int)(angle_milliDegrees+0.5)/1000.0;
|
|
|
|
if (angle<0) {
|
|
|
|
rounded = (int)(angle_milliDegrees-0.5)/1000.0;
|
|
|
|
}
|
|
|
|
if (angle == rounded) return 1;
|
|
|
|
return 0; /* sub millidegree. Cannot be encoded in grib1 */
|
|
|
|
}
|
2018-02-05 16:05:31 +00:00
|
|
|
|
|
|
|
/* Returns a boolean: 1 if angle can be encoded, 0 otherwise */
|
|
|
|
static int angle_can_be_encoded(const double angle, const double angular_precision)
|
|
|
|
{
|
|
|
|
const double angle_expanded = angle * angular_precision;
|
|
|
|
Assert(angular_precision>0);
|
2018-02-06 13:39:13 +00:00
|
|
|
double rounded = (long)(angle_expanded+0.5)/angular_precision;
|
2018-02-05 16:05:31 +00:00
|
|
|
if (angle<0) {
|
2018-02-06 13:39:13 +00:00
|
|
|
rounded = (long)(angle_expanded-0.5)/angular_precision;
|
2018-02-05 16:05:31 +00:00
|
|
|
}
|
|
|
|
if (angle == rounded) return 1;
|
|
|
|
/*printf(" ......... angle cannot be encoded: %.10e\n", angle);*/
|
|
|
|
return 0; /* Cannot be encoded */
|
|
|
|
}
|
2018-02-06 17:13:42 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Returns a boolean: 1 if angle can be encoded, 0 otherwise */
|
|
|
|
static int angle_can_be_encoded(grib_handle* h, const double angle)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int retval = 1;
|
|
|
|
grib_handle* h2 = NULL;
|
|
|
|
char sample_name[16] = {0,};
|
2019-01-03 11:48:52 +00:00
|
|
|
long angle_subdivisions = 0; /* e.g. 1e3 for grib1 and 1e6 for grib2 */
|
2018-02-06 17:13:42 +00:00
|
|
|
long edition = 0, coded = 0;
|
|
|
|
double expanded, diff;
|
|
|
|
|
|
|
|
if((ret = grib_get_long(h,"edition",&edition)) != 0) return ret;
|
2019-01-03 11:48:52 +00:00
|
|
|
if((ret = grib_get_long(h, "angleSubdivisions", &angle_subdivisions)) != 0) return ret;
|
|
|
|
Assert(angle_subdivisions > 0);
|
2018-02-06 17:13:42 +00:00
|
|
|
|
|
|
|
sprintf(sample_name, "GRIB%ld", edition);
|
|
|
|
h2 = grib_handle_new_from_samples(0, sample_name);
|
|
|
|
if((ret = grib_set_double(h2, "latitudeOfFirstGridPointInDegrees", angle)) != 0) return ret;
|
|
|
|
if((ret = grib_get_long(h2, "latitudeOfFirstGridPoint", &coded)) != 0) return ret;
|
|
|
|
grib_handle_delete(h2);
|
|
|
|
|
2019-01-03 11:48:52 +00:00
|
|
|
expanded = angle*angle_subdivisions;
|
2018-02-06 17:13:42 +00:00
|
|
|
diff = fabs(expanded - coded);
|
2019-01-03 11:48:52 +00:00
|
|
|
if (diff < 1.0/angle_subdivisions)
|
2018-02-06 17:13:42 +00:00
|
|
|
retval = 1;
|
|
|
|
else
|
|
|
|
retval = 0;
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
2018-02-05 16:05:31 +00:00
|
|
|
|
2018-03-07 19:21:58 +00:00
|
|
|
#ifdef ECCODES_ON_WINDOWS
|
|
|
|
#define round(a) ( (a) >=0 ? ((a)+0.5) : ((a)-0.5) )
|
|
|
|
#endif
|
2019-01-03 11:48:52 +00:00
|
|
|
static double adjust_angle(const double angle, const RoundingPolicy policy, const double angle_subdivisions)
|
2018-02-05 16:05:31 +00:00
|
|
|
{
|
|
|
|
double result = 0;
|
2019-01-03 11:48:52 +00:00
|
|
|
Assert(angle_subdivisions > 0);
|
|
|
|
result = angle * angle_subdivisions;
|
2018-02-05 16:05:31 +00:00
|
|
|
if (policy == eROUND_ANGLE_UP)
|
|
|
|
result = round(result+0.5);
|
|
|
|
else
|
|
|
|
result = round(result-0.5);
|
2019-01-03 11:48:52 +00:00
|
|
|
result = result / angle_subdivisions;
|
2018-02-05 16:05:31 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Search key=value array for:
|
|
|
|
* latitudeOfFirstGridPointInDegrees
|
|
|
|
* longitudeOfFirstGridPointInDegrees
|
|
|
|
* latitudeOfLastGridPointInDegrees
|
|
|
|
* longitudeOfLastGridPointInDegrees
|
2018-02-06 17:13:42 +00:00
|
|
|
* and change their values to expand the bounding box
|
2018-02-05 16:05:31 +00:00
|
|
|
*/
|
|
|
|
static int expand_bounding_box(grib_handle* h, grib_values *values, const size_t count)
|
|
|
|
{
|
|
|
|
int ret = GRIB_SUCCESS;
|
|
|
|
size_t i=0;
|
|
|
|
double new_angle = 0;
|
|
|
|
RoundingPolicy roundingPolicy = eROUND_ANGLE_UP;
|
2019-01-03 11:48:52 +00:00
|
|
|
long angle_subdivisions = 0; /* e.g. 1e3 for grib1 and 1e6 for grib2 */
|
|
|
|
if((ret = grib_get_long(h, "angleSubdivisions", &angle_subdivisions)) != 0)
|
2018-02-05 16:05:31 +00:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
for(i=0; i<count; i++) {
|
|
|
|
int is_angle = 0;
|
|
|
|
if (strcmp(values[i].name, "longitudeOfFirstGridPointInDegrees")==0) {
|
|
|
|
roundingPolicy = eROUND_ANGLE_DOWN;
|
|
|
|
is_angle = 1;
|
|
|
|
}
|
|
|
|
else if (strcmp(values[i].name, "longitudeOfLastGridPointInDegrees")==0) {
|
|
|
|
roundingPolicy = eROUND_ANGLE_UP;
|
|
|
|
is_angle = 1;
|
|
|
|
}
|
|
|
|
else if (strcmp(values[i].name, "latitudeOfFirstGridPointInDegrees")==0) {
|
|
|
|
roundingPolicy = eROUND_ANGLE_UP;
|
|
|
|
is_angle = 1;
|
|
|
|
}
|
|
|
|
else if (strcmp(values[i].name, "latitudeOfLastGridPointInDegrees")==0) {
|
|
|
|
roundingPolicy = eROUND_ANGLE_DOWN;
|
|
|
|
is_angle = 1;
|
|
|
|
}
|
|
|
|
|
2018-02-06 17:13:42 +00:00
|
|
|
if (is_angle && !angle_can_be_encoded(h, values[i].double_value)) {
|
2019-01-03 11:48:52 +00:00
|
|
|
new_angle = adjust_angle(values[i].double_value, roundingPolicy, angle_subdivisions);
|
2018-02-06 18:16:14 +00:00
|
|
|
if (h->context->debug) {
|
2019-08-05 10:32:11 +00:00
|
|
|
fprintf(stderr, "ECCODES DEBUG grib_util EXPAND_BOUNDING_BOX %s: old=%.15e new=%.15e (%s)\n",
|
2018-02-06 18:16:14 +00:00
|
|
|
values[i].name, values[i].double_value, new_angle,
|
|
|
|
(roundingPolicy==eROUND_ANGLE_UP?"Up":"Down"));
|
|
|
|
}
|
2018-02-05 16:05:31 +00:00
|
|
|
values[i].double_value = new_angle;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2015-10-28 17:36:10 +00:00
|
|
|
|
2015-10-29 13:38:35 +00:00
|
|
|
/* Returns a boolean: 1 if angle is too small, 0 otherwise */
|
2017-11-13 13:26:36 +00:00
|
|
|
/*static int angle_too_small(const double angle, const double angular_precision)
|
2015-10-28 17:36:10 +00:00
|
|
|
{
|
|
|
|
const double a = fabs(angle);
|
|
|
|
if (a > 0 && a < angular_precision) return 1;
|
|
|
|
return 0;
|
2015-10-27 16:37:13 +00:00
|
|
|
}
|
|
|
|
|
2015-10-28 18:38:36 +00:00
|
|
|
static double normalise_angle(double angle)
|
|
|
|
{
|
|
|
|
while (angle<0) angle += 360;
|
|
|
|
while (angle>360) angle -= 360;
|
|
|
|
return angle;
|
2018-06-26 13:44:49 +00:00
|
|
|
}
|
2018-06-26 12:40:13 +00:00
|
|
|
static int check_values(const double* data_values, size_t data_values_count)
|
2018-06-22 10:35:16 +00:00
|
|
|
{
|
|
|
|
size_t i = 0;
|
|
|
|
for (i=0; i<data_values_count; i++) {
|
2018-06-22 17:27:35 +00:00
|
|
|
const double val = data_values[i];
|
2018-06-26 12:40:13 +00:00
|
|
|
if ( val >= DBL_MAX ||
|
|
|
|
val <= -DBL_MAX ||
|
|
|
|
isnan(val) )
|
|
|
|
{
|
2018-06-22 12:23:29 +00:00
|
|
|
fprintf(stderr,"GRIB_UTIL_SET_SPEC: Invalid data value: i=%lu, val=%g\n",i, val);
|
2018-06-22 10:35:16 +00:00
|
|
|
return GRIB_ENCODING_ERROR;
|
|
|
|
}
|
|
|
|
}
|
2018-06-26 12:40:13 +00:00
|
|
|
return GRIB_SUCCESS;
|
2017-11-13 13:26:36 +00:00
|
|
|
}*/
|
2015-10-28 18:38:36 +00:00
|
|
|
|
2018-06-26 12:40:13 +00:00
|
|
|
static int check_geometry(grib_handle* handle, const grib_util_grid_spec2* spec,
|
|
|
|
size_t data_values_count, int specified_as_global)
|
|
|
|
{
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if (spec->pl && spec->pl_size != 0 &&
|
2018-06-22 10:35:16 +00:00
|
|
|
(spec->grid_type==GRIB_UTIL_GRID_SPEC_REDUCED_GG || spec->grid_type==GRIB_UTIL_GRID_SPEC_REDUCED_ROTATED_GG))
|
|
|
|
{
|
2018-06-25 11:34:28 +00:00
|
|
|
if (specified_as_global) {
|
2018-06-22 10:35:16 +00:00
|
|
|
char msg[100] = {0,};
|
2018-06-22 12:23:29 +00:00
|
|
|
size_t sum = 0;
|
2018-06-22 10:35:16 +00:00
|
|
|
if (specified_as_global) strcpy(msg, "Specified to be global (in spec)");
|
|
|
|
sum = sum_of_pl_array(spec->pl, spec->pl_size);
|
|
|
|
if (sum != data_values_count) {
|
2018-08-07 14:31:41 +00:00
|
|
|
fprintf(stderr, "GRIB_UTIL_SET_SPEC: Invalid reduced gaussian grid: %s but data_values_count != sum_of_pl_array (%ld!=%ld)\n",
|
|
|
|
msg, (long)data_values_count, (long)sum);
|
2018-06-22 10:35:16 +00:00
|
|
|
return GRIB_WRONG_GRID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2017-11-13 13:26:36 +00:00
|
|
|
#if 0
|
2015-10-27 16:37:13 +00:00
|
|
|
/* Check what is coded in the handle is what is requested by the spec. */
|
|
|
|
/* Return GRIB_SUCCESS if the geometry matches, otherwise the error code */
|
2016-02-08 10:37:21 +00:00
|
|
|
static int check_handle_against_spec(grib_handle* handle, const long edition,
|
|
|
|
const grib_util_grid_spec2* spec, int global_grid)
|
2015-10-27 16:37:13 +00:00
|
|
|
{
|
|
|
|
int err = 0;
|
|
|
|
int check_latitudes = 1;
|
|
|
|
int check_longitudes = 1;
|
2015-10-28 17:36:10 +00:00
|
|
|
double angular_precision = 1.0/1000.0; /* millidegree */
|
|
|
|
double tolerance = angular_precision/2.0; /* half a millidegree */
|
2015-10-27 16:37:13 +00:00
|
|
|
|
2015-10-28 17:36:10 +00:00
|
|
|
if (edition == 2) {
|
|
|
|
angular_precision = 1.0/1000000.0; /* microdegree */
|
|
|
|
tolerance = angular_precision/2.0;
|
|
|
|
}
|
2015-10-27 16:37:13 +00:00
|
|
|
|
2015-10-30 11:28:33 +00:00
|
|
|
if (edition == 2) {
|
|
|
|
return GRIB_SUCCESS; /* For now only do checks on edition 1 */
|
|
|
|
}
|
|
|
|
|
2015-10-29 13:38:35 +00:00
|
|
|
if (spec->grid_type == GRIB_UTIL_GRID_SPEC_POLAR_STEREOGRAPHIC ||
|
|
|
|
spec->grid_type == GRIB_UTIL_GRID_SPEC_SH)
|
|
|
|
{
|
|
|
|
return GRIB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2015-10-28 17:36:10 +00:00
|
|
|
/* Cannot check latitudes of Gaussian grids because are always sub-millidegree */
|
2015-10-27 16:37:13 +00:00
|
|
|
/* and for GRIB1 will differ from the encoded values. We accept this discrepancy! */
|
|
|
|
if (spec->grid_type == GRIB_UTIL_GRID_SPEC_REGULAR_GG ||
|
|
|
|
spec->grid_type == GRIB_UTIL_GRID_SPEC_ROTATED_GG ||
|
|
|
|
spec->grid_type == GRIB_UTIL_GRID_SPEC_REDUCED_GG ||
|
|
|
|
spec->grid_type == GRIB_UTIL_GRID_SPEC_REDUCED_ROTATED_GG)
|
|
|
|
{
|
|
|
|
if (edition == 1) {
|
|
|
|
check_latitudes = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-08 10:37:21 +00:00
|
|
|
/* GRIB-922 */
|
|
|
|
/* Specification was to make the resulting grid global so no point checking for */
|
|
|
|
/* input lat/lon values as they would be reset by setting the "global" key to 1 */
|
|
|
|
if (global_grid)
|
|
|
|
{
|
|
|
|
check_latitudes = check_longitudes = 0;
|
|
|
|
}
|
|
|
|
|
2015-10-27 16:37:13 +00:00
|
|
|
if (check_latitudes) {
|
|
|
|
double lat1, lat2;
|
2015-10-28 18:38:36 +00:00
|
|
|
const double lat1spec = normalise_angle(spec->latitudeOfFirstGridPointInDegrees);
|
|
|
|
const double lat2spec = normalise_angle(spec->latitudeOfLastGridPointInDegrees);
|
2015-10-27 16:37:13 +00:00
|
|
|
if ((err = grib_get_double(handle, "latitudeOfFirstGridPointInDegrees", &lat1))!=0) return err;
|
|
|
|
if ((err = grib_get_double(handle, "latitudeOfLastGridPointInDegrees", &lat2))!=0) return err;
|
2015-10-28 18:38:36 +00:00
|
|
|
lat1 = normalise_angle(lat1);
|
|
|
|
lat2 = normalise_angle(lat2);
|
|
|
|
|
2015-10-28 17:36:10 +00:00
|
|
|
if (angle_too_small(lat1spec, angular_precision)) {
|
2015-12-18 15:59:30 +00:00
|
|
|
fprintf(stderr, "Failed to encode latitude of first grid point %.10e: less than angular precision\n",lat1spec);
|
2015-10-28 17:36:10 +00:00
|
|
|
return GRIB_WRONG_GRID;
|
|
|
|
}
|
|
|
|
if (angle_too_small(lat2spec, angular_precision)) {
|
2015-12-18 15:59:30 +00:00
|
|
|
fprintf(stderr, "Failed to encode latitude of last grid point %.10e: less than angular precision\n", lat2spec);
|
2015-10-28 17:36:10 +00:00
|
|
|
return GRIB_WRONG_GRID;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!DBL_EQUAL(lat1spec, lat1, tolerance)) {
|
2015-12-18 15:59:30 +00:00
|
|
|
fprintf(stderr, "Failed to encode latitude of first grid point: spec=%.10e val=%.10e\n", lat1spec, lat1);
|
2015-10-27 16:37:13 +00:00
|
|
|
return GRIB_WRONG_GRID;
|
|
|
|
}
|
2015-10-28 17:36:10 +00:00
|
|
|
if (!DBL_EQUAL(lat2spec, lat2, tolerance)) {
|
2015-12-18 15:59:30 +00:00
|
|
|
fprintf(stderr, "Failed to encode latitude of last grid point: spec=%.10e val=%.10e\n", lat2spec, lat2);
|
2015-10-27 16:37:13 +00:00
|
|
|
return GRIB_WRONG_GRID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (check_longitudes) {
|
|
|
|
double lon1, lon2;
|
2015-10-28 18:38:36 +00:00
|
|
|
const double lon1spec = normalise_angle(spec->longitudeOfFirstGridPointInDegrees);
|
|
|
|
const double lon2spec = normalise_angle(spec->longitudeOfLastGridPointInDegrees);
|
2015-10-27 16:37:13 +00:00
|
|
|
if ((err = grib_get_double(handle, "longitudeOfFirstGridPointInDegrees", &lon1))!=0) return err;
|
|
|
|
if ((err = grib_get_double(handle, "longitudeOfLastGridPointInDegrees", &lon2))!=0) return err;
|
2015-10-28 18:38:36 +00:00
|
|
|
lon1 = normalise_angle(lon1);
|
|
|
|
lon2 = normalise_angle(lon2);
|
|
|
|
|
2015-10-28 17:36:10 +00:00
|
|
|
if (angle_too_small(lon1spec, angular_precision)) {
|
2015-12-18 15:59:30 +00:00
|
|
|
fprintf(stderr, "Failed to encode longitude of first grid point %.10e: less than angular precision\n", lon1spec);
|
2015-10-28 17:36:10 +00:00
|
|
|
return GRIB_WRONG_GRID;
|
|
|
|
}
|
|
|
|
if (angle_too_small(lon2spec, angular_precision)) {
|
2015-12-18 15:59:30 +00:00
|
|
|
fprintf(stderr, "Failed to encode longitude of last grid point %.10e: less than angular precision\n", lon2spec);
|
2015-10-28 17:36:10 +00:00
|
|
|
return GRIB_WRONG_GRID;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!DBL_EQUAL(lon1spec, lon1, tolerance)) {
|
2015-12-18 15:59:30 +00:00
|
|
|
fprintf(stderr, "Failed to encode longitude of first grid point: spec=%.10e val=%.10e\n", lon1spec, lon1);
|
2015-10-27 16:37:13 +00:00
|
|
|
return GRIB_WRONG_GRID;
|
|
|
|
}
|
2015-10-28 17:36:10 +00:00
|
|
|
if (!DBL_EQUAL(lon2spec, lon2, tolerance)){
|
2015-12-18 15:59:30 +00:00
|
|
|
fprintf(stderr, "Failed to encode longitude of last grid point: spec=%.10e val=%.10e\n", lon2spec, lon2);
|
2015-10-27 16:37:13 +00:00
|
|
|
return GRIB_WRONG_GRID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spec->grid_type == GRIB_UTIL_GRID_SPEC_ROTATED_LL ||
|
|
|
|
spec->grid_type == GRIB_UTIL_GRID_SPEC_ROTATED_GG ||
|
|
|
|
spec->grid_type == GRIB_UTIL_GRID_SPEC_REDUCED_ROTATED_GG)
|
|
|
|
{
|
|
|
|
double latp, lonp;
|
2015-10-28 18:38:36 +00:00
|
|
|
const double latspec = normalise_angle(spec->latitudeOfSouthernPoleInDegrees);
|
|
|
|
const double lonspec = normalise_angle(spec->longitudeOfSouthernPoleInDegrees);
|
2015-10-27 16:37:13 +00:00
|
|
|
if ((err = grib_get_double(handle, "latitudeOfSouthernPoleInDegrees", &latp))!=0) return err;
|
|
|
|
if ((err = grib_get_double(handle, "longitudeOfSouthernPoleInDegrees", &lonp))!=0) return err;
|
2015-10-28 18:38:36 +00:00
|
|
|
latp = normalise_angle(latp);
|
|
|
|
lonp = normalise_angle(lonp);
|
2015-10-27 16:37:13 +00:00
|
|
|
|
2015-10-28 18:38:36 +00:00
|
|
|
if (!DBL_EQUAL(latspec, latp, tolerance)) {
|
2015-12-18 15:59:30 +00:00
|
|
|
fprintf(stderr, "Failed to encode latitude of southern pole: spec=%.10e val=%.10e\n",latspec,latp);
|
2015-10-27 16:37:13 +00:00
|
|
|
return GRIB_WRONG_GRID;
|
|
|
|
}
|
2015-10-28 18:38:36 +00:00
|
|
|
if (!DBL_EQUAL(lonspec, lonp, tolerance)) {
|
2015-12-18 15:59:30 +00:00
|
|
|
fprintf(stderr, "Failed to encode longitude of southern pole: spec=%.10e val=%.10e\n",lonspec,lonp);
|
2015-10-27 16:37:13 +00:00
|
|
|
return GRIB_WRONG_GRID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return GRIB_SUCCESS;
|
|
|
|
}
|
2017-11-13 13:26:36 +00:00
|
|
|
#endif
|
2015-10-27 16:37:13 +00:00
|
|
|
|
2015-12-03 14:35:55 +00:00
|
|
|
static const char* get_grid_type_name(const int spec_grid_type)
|
2015-10-30 11:28:33 +00:00
|
|
|
{
|
|
|
|
if (spec_grid_type == GRIB_UTIL_GRID_SPEC_REGULAR_LL)
|
|
|
|
return "regular_ll";
|
|
|
|
|
|
|
|
if (spec_grid_type == GRIB_UTIL_GRID_SPEC_ROTATED_LL)
|
|
|
|
return "rotated_ll";
|
|
|
|
|
|
|
|
if (spec_grid_type == GRIB_UTIL_GRID_SPEC_REGULAR_GG)
|
|
|
|
return "regular_gg";
|
|
|
|
|
|
|
|
if (spec_grid_type == GRIB_UTIL_GRID_SPEC_ROTATED_GG)
|
|
|
|
return "rotated_gg";
|
|
|
|
|
|
|
|
if (spec_grid_type == GRIB_UTIL_GRID_SPEC_REDUCED_LL)
|
|
|
|
return "reduced_ll";
|
|
|
|
|
|
|
|
if (spec_grid_type == GRIB_UTIL_GRID_SPEC_POLAR_STEREOGRAPHIC)
|
|
|
|
return "polar_stereographic";
|
|
|
|
|
|
|
|
if (spec_grid_type == GRIB_UTIL_GRID_SPEC_REDUCED_GG)
|
|
|
|
return "reduced_gg";
|
|
|
|
|
|
|
|
if (spec_grid_type == GRIB_UTIL_GRID_SPEC_SH)
|
|
|
|
return "sh";
|
|
|
|
|
|
|
|
if (spec_grid_type == GRIB_UTIL_GRID_SPEC_REDUCED_ROTATED_GG)
|
|
|
|
return "reduced_rotated_gg";
|
|
|
|
|
2019-05-31 15:08:48 +00:00
|
|
|
if (spec_grid_type == GRIB_UTIL_GRID_SPEC_LAMBERT_AZIMUTHAL_EQUAL_AREA)
|
|
|
|
return "lambert_azimuthal_equal_area";
|
|
|
|
|
|
|
|
if (spec_grid_type == GRIB_UTIL_GRID_SPEC_LAMBERT_CONFORMAL)
|
|
|
|
return "lambert";
|
|
|
|
|
2015-10-30 11:28:33 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-09-01 10:49:51 +00:00
|
|
|
static int is_constant_field(const double missingValue, const double* data_values, size_t data_values_count)
|
2016-08-31 16:38:31 +00:00
|
|
|
{
|
|
|
|
int ii=0;
|
|
|
|
int constant=1;
|
|
|
|
double value = missingValue;
|
|
|
|
|
|
|
|
for (ii=0;ii<data_values_count;ii++) {
|
|
|
|
if (data_values[ii]!=missingValue) {
|
|
|
|
if (value==missingValue) {
|
|
|
|
value=data_values[ii];
|
|
|
|
} else {
|
|
|
|
if (value!=data_values[ii]) {
|
|
|
|
constant=0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return constant;
|
|
|
|
}
|
|
|
|
|
2014-03-26 14:30:16 +00:00
|
|
|
grib_handle* grib_util_set_spec(grib_handle* h,
|
2013-08-01 15:52:01 +00:00
|
|
|
const grib_util_grid_spec *spec,
|
|
|
|
const grib_util_packing_spec *packing_spec,
|
2014-03-26 14:30:16 +00:00
|
|
|
int flags,
|
|
|
|
const double* data_values,
|
|
|
|
size_t data_values_count,
|
|
|
|
int* err)
|
2013-03-25 12:04:10 +00:00
|
|
|
{
|
2015-10-23 11:55:11 +00:00
|
|
|
/* Create a spec v2 from spec v1 */
|
|
|
|
grib_util_grid_spec2 spec2;
|
|
|
|
Assert(h);
|
|
|
|
|
|
|
|
spec2.grid_type=spec->grid_type;
|
|
|
|
spec2.Ni=spec->Ni;
|
|
|
|
spec2.Nj=spec->Nj;
|
|
|
|
spec2.iDirectionIncrementInDegrees=spec->iDirectionIncrementInDegrees;
|
|
|
|
spec2.jDirectionIncrementInDegrees=spec->jDirectionIncrementInDegrees;
|
|
|
|
spec2.longitudeOfFirstGridPointInDegrees=spec->longitudeOfFirstGridPointInDegrees;
|
|
|
|
spec2.longitudeOfLastGridPointInDegrees=spec->longitudeOfLastGridPointInDegrees;
|
|
|
|
spec2.latitudeOfFirstGridPointInDegrees=spec->latitudeOfFirstGridPointInDegrees;
|
|
|
|
spec2.latitudeOfLastGridPointInDegrees=spec->latitudeOfLastGridPointInDegrees;
|
|
|
|
spec2.uvRelativeToGrid=spec->uvRelativeToGrid;
|
|
|
|
spec2.latitudeOfSouthernPoleInDegrees=spec->latitudeOfSouthernPoleInDegrees;
|
|
|
|
spec2.longitudeOfSouthernPoleInDegrees=spec->longitudeOfSouthernPoleInDegrees;
|
|
|
|
spec2.iScansNegatively=spec->iScansNegatively;
|
|
|
|
spec2.jScansPositively=spec->jScansPositively;
|
|
|
|
spec2.N=spec->N;
|
|
|
|
spec2.bitmapPresent=spec->bitmapPresent;
|
|
|
|
spec2.missingValue=spec->missingValue;
|
|
|
|
spec2.pl=spec->pl;
|
|
|
|
spec2.pl_size=spec->pl_size;
|
|
|
|
spec2.truncation=spec->truncation;
|
|
|
|
spec2.orientationOfTheGridInDegrees=spec->orientationOfTheGridInDegrees;
|
|
|
|
spec2.DyInMetres=spec->DyInMetres;
|
|
|
|
spec2.DxInMetres=spec->DxInMetres;
|
|
|
|
|
|
|
|
/* New data members of spec2 take default values */
|
|
|
|
spec2.angleOfRotationInDegrees = 0;
|
|
|
|
spec2.grid_name= NULL;
|
|
|
|
|
|
|
|
return grib_util_set_spec2(
|
|
|
|
h,
|
|
|
|
&spec2,
|
|
|
|
packing_spec,
|
|
|
|
flags,
|
|
|
|
data_values,
|
|
|
|
data_values_count,
|
|
|
|
err);
|
|
|
|
}
|
|
|
|
|
|
|
|
grib_handle* grib_util_set_spec2(grib_handle* h,
|
|
|
|
const grib_util_grid_spec2 *spec,
|
|
|
|
const grib_util_packing_spec *packing_spec,
|
|
|
|
int flags,
|
|
|
|
const double* data_values,
|
|
|
|
size_t data_values_count,
|
|
|
|
int* err)
|
|
|
|
{
|
2013-03-25 12:04:10 +00:00
|
|
|
|
|
|
|
#define SET_LONG_VALUE(n,v) do { Assert(count<1024); values[count].name = n; values[count].type = GRIB_TYPE_LONG; values[count].long_value = v; count++; } while(0)
|
|
|
|
#define SET_DOUBLE_VALUE(n,v) do { Assert(count<1024); values[count].name = n; values[count].type = GRIB_TYPE_DOUBLE; values[count].double_value = v; count++; } while(0)
|
|
|
|
#define SET_STRING_VALUE(n,v) do { Assert(count<1024); values[count].name = n; values[count].type = GRIB_TYPE_STRING; values[count].string_value = v; count++; } while(0)
|
|
|
|
|
|
|
|
#define COPY_SPEC_LONG(x) do { Assert(count<1024); values[count].name = #x; values[count].type = GRIB_TYPE_LONG; values[count].long_value = spec->x; count++; } while(0)
|
|
|
|
#define COPY_SPEC_DOUBLE(x) do { Assert(count<1024); values[count].name = #x; values[count].type = GRIB_TYPE_DOUBLE; values[count].double_value = spec->x; count++; } while(0)
|
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
grib_values values[1024]={{0,},};
|
|
|
|
size_t count = 0;
|
|
|
|
int i;
|
|
|
|
long editionNumber;
|
|
|
|
grib_handle* outh = NULL;
|
|
|
|
grib_handle* tmp = NULL;
|
|
|
|
const char* grid_type = NULL;
|
|
|
|
char name[1024];
|
|
|
|
char input_grid_type[100];
|
|
|
|
char input_packing_type[100];
|
|
|
|
long input_bits_per_value=0;
|
|
|
|
long input_decimal_scale_factor=0;
|
|
|
|
size_t len=100;
|
|
|
|
size_t input_grid_type_len=100;
|
|
|
|
double laplacianOperator;
|
|
|
|
int packingTypeIsSet=0;
|
|
|
|
int setSecondOrder=0;
|
2016-10-11 15:14:07 +00:00
|
|
|
int setJpegPacking=0;
|
2019-10-01 11:12:18 +00:00
|
|
|
int setCcsdsPacking=0;
|
2019-08-27 14:29:15 +00:00
|
|
|
int convertEditionEarlier=0;/* For cases when we cannot set some keys without converting */
|
2013-08-01 15:52:01 +00:00
|
|
|
size_t slen=17;
|
2015-10-28 17:36:10 +00:00
|
|
|
int grib1_high_resolution_fix = 0; /* boolean: See GRIB-863 */
|
2016-02-08 10:37:21 +00:00
|
|
|
int global_grid = 0; /* boolean */
|
2018-02-05 16:05:31 +00:00
|
|
|
int expandBoundingBox = 0;
|
2013-08-01 15:52:01 +00:00
|
|
|
|
|
|
|
static grib_util_packing_spec default_packing_spec = {0, };
|
2015-09-28 15:54:19 +00:00
|
|
|
Assert(h);
|
2013-08-01 15:52:01 +00:00
|
|
|
|
|
|
|
if(!packing_spec) {
|
|
|
|
packing_spec = &default_packing_spec;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get edition number from input handle */
|
|
|
|
if((*err = grib_get_long(h,"edition",&editionNumber)) != 0)
|
|
|
|
{
|
|
|
|
grib_context* c=grib_context_get_default();
|
|
|
|
if (c->write_on_fail)
|
|
|
|
grib_write_message(h,"error.grib","w");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-09-23 14:10:36 +00:00
|
|
|
if (packing_spec->deleteLocalDefinition) {
|
2017-07-10 13:37:03 +00:00
|
|
|
SET_LONG_VALUE("deleteLocalDefinition",1);
|
2016-09-23 14:10:36 +00:00
|
|
|
}
|
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
len=100;
|
|
|
|
grib_get_string(h,"packingType",input_packing_type,&len);
|
|
|
|
grib_get_long(h,"bitsPerValue",&input_bits_per_value);
|
|
|
|
grib_get_long(h,"decimalScaleFactor",&input_decimal_scale_factor);
|
|
|
|
if (h->context->debug==-1) {
|
2019-08-05 10:32:11 +00:00
|
|
|
fprintf(stderr, "ECCODES DEBUG grib_util: input_packing_type = %s\n",input_packing_type);
|
|
|
|
fprintf(stderr, "ECCODES DEBUG grib_util: input_bits_per_value = %ld\n",input_bits_per_value);
|
|
|
|
fprintf(stderr, "ECCODES DEBUG grib_util: input_decimal_scale_factor = %ld\n",input_decimal_scale_factor);
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
|
|
|
|
2018-06-26 13:44:49 +00:00
|
|
|
/*if ( (*err=check_values(data_values, data_values_count))!=GRIB_SUCCESS ) {
|
2018-06-26 12:40:13 +00:00
|
|
|
fprintf(stderr,"GRIB_UTIL_SET_SPEC: Data values check failed! %s\n", grib_get_error_message(*err));
|
|
|
|
goto cleanup;
|
2018-06-26 13:44:49 +00:00
|
|
|
}*/
|
2018-06-26 12:40:13 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
if (flags & GRIB_UTIL_SET_SPEC_FLAGS_ONLY_PACKING) {
|
|
|
|
if (packing_spec->packing == GRIB_UTIL_PACKING_USE_PROVIDED &&
|
|
|
|
strcmp(input_packing_type,"grid_simple_matrix")) {
|
|
|
|
switch (packing_spec->packing_type) {
|
|
|
|
case GRIB_UTIL_PACKING_TYPE_SPECTRAL_COMPLEX:
|
|
|
|
if (strcmp(input_packing_type,"spectral_complex") && !strcmp(input_packing_type,"spectral_simple"))
|
|
|
|
SET_STRING_VALUE("packingType","spectral_complex");
|
|
|
|
break;
|
|
|
|
case GRIB_UTIL_PACKING_TYPE_SPECTRAL_SIMPLE:
|
|
|
|
if (strcmp(input_packing_type,"spectral_simple") && !strcmp(input_packing_type,"spectral_complex"))
|
|
|
|
SET_STRING_VALUE("packingType","spectral_simple");
|
|
|
|
break;
|
|
|
|
case GRIB_UTIL_PACKING_TYPE_GRID_SIMPLE:
|
|
|
|
if (strcmp(input_packing_type,"grid_simple") && !strcmp(input_packing_type,"grid_complex") )
|
|
|
|
SET_STRING_VALUE("packingType","grid_simple");
|
|
|
|
break;
|
|
|
|
case GRIB_UTIL_PACKING_TYPE_GRID_SIMPLE_MATRIX:
|
|
|
|
SET_STRING_VALUE("packingType","grid_simple_matrix");
|
|
|
|
break;
|
|
|
|
case GRIB_UTIL_PACKING_TYPE_GRID_COMPLEX:
|
|
|
|
if (strcmp(input_packing_type,"grid_complex") && !strcmp(input_packing_type,"grid_simple"))
|
|
|
|
SET_STRING_VALUE("packingType","grid_complex");
|
|
|
|
break;
|
|
|
|
case GRIB_UTIL_PACKING_TYPE_JPEG:
|
|
|
|
if (strcmp(input_packing_type,"grid_jpeg") && !strcmp(input_packing_type,"grid_simple"))
|
|
|
|
SET_STRING_VALUE("packingType","grid_jpeg");
|
|
|
|
break;
|
2019-10-01 11:12:18 +00:00
|
|
|
case GRIB_UTIL_PACKING_TYPE_CCSDS:
|
|
|
|
if (strcmp(input_packing_type,"grid_ccsds") && !strcmp(input_packing_type,"grid_simple"))
|
|
|
|
SET_STRING_VALUE("packingType","grid_ccsds");
|
|
|
|
break;
|
2013-08-01 15:52:01 +00:00
|
|
|
case GRIB_UTIL_PACKING_TYPE_GRID_SECOND_ORDER:
|
|
|
|
/* we delay the set of grid_second_order because we don't want
|
2014-03-26 14:30:16 +00:00
|
|
|
to do it on a field with bitsPerValue=0 */
|
2013-08-01 15:52:01 +00:00
|
|
|
setSecondOrder=1;
|
|
|
|
break;
|
|
|
|
default :
|
2019-09-16 14:15:03 +00:00
|
|
|
fprintf(stderr, "invalid packing_spec->packing_type = %ld\n",(long)packing_spec->packing_type);
|
2018-06-06 11:47:04 +00:00
|
|
|
*err = GRIB_INTERNAL_ERROR;
|
|
|
|
goto cleanup;
|
2014-03-26 14:30:16 +00:00
|
|
|
break;
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
|
|
|
packingTypeIsSet=1;
|
|
|
|
}
|
|
|
|
switch(packing_spec->accuracy) {
|
|
|
|
|
|
|
|
case GRIB_UTIL_ACCURACY_SAME_BITS_PER_VALUES_AS_INPUT:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GRIB_UTIL_ACCURACY_USE_PROVIDED_BITS_PER_VALUES:
|
|
|
|
if (input_bits_per_value!=packing_spec->bitsPerValue)
|
|
|
|
SET_LONG_VALUE("bitsPerValue", packing_spec->bitsPerValue);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GRIB_UTIL_ACCURACY_SAME_DECIMAL_SCALE_FACTOR_AS_INPUT:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GRIB_UTIL_ACCURACY_USE_PROVIDED_DECIMAL_SCALE_FACTOR:
|
|
|
|
if (input_decimal_scale_factor!=packing_spec->decimalScaleFactor)
|
|
|
|
SET_LONG_VALUE("decimalScaleFactor", packing_spec->decimalScaleFactor);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2019-09-16 14:15:03 +00:00
|
|
|
fprintf(stderr, "invalid packing_spec->accuracy = %ld\n",(long)packing_spec->accuracy);
|
2018-06-06 11:47:04 +00:00
|
|
|
*err = GRIB_INTERNAL_ERROR;
|
|
|
|
goto cleanup;
|
2014-03-26 14:30:16 +00:00
|
|
|
break;
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*nothing to be changed*/
|
|
|
|
if (count==0) {
|
|
|
|
*err = -1;
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
2018-04-03 11:35:20 +00:00
|
|
|
if (h->context->debug==-1) {
|
2013-08-01 15:52:01 +00:00
|
|
|
print_values(h->context,spec,data_values,data_values_count,values,count);
|
2018-04-03 11:35:20 +00:00
|
|
|
}
|
2013-08-01 15:52:01 +00:00
|
|
|
|
|
|
|
if((*err = grib_set_values(h,values,count)) != 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr,"GRIB_UTIL_SET_SPEC: Cannot set values %s\n",grib_get_error_message(*err));
|
|
|
|
|
|
|
|
for(i = 0; i < count; i++)
|
|
|
|
if(values[i].error)
|
|
|
|
fprintf(stderr," %s %s\n",values[i].name,grib_get_error_message(values[i].error));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (h->context->debug==-1) {
|
|
|
|
int j=0;
|
2019-08-05 10:32:11 +00:00
|
|
|
fprintf(stderr, "ECCODES DEBUG grib_util: grib_set_double_array\n");
|
|
|
|
for (j=0;j<20;j++) fprintf(stderr, "ECCODES DEBUG grib_util %g\n",data_values[j]);
|
|
|
|
fprintf(stderr, "ECCODES DEBUG grib_util: data_values_count=%d \n",(int)data_values_count);
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if((*err = grib_set_double_array(h,"values",data_values,data_values_count)) != 0)
|
|
|
|
{
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (h->context->debug==-1)
|
2019-08-05 10:32:11 +00:00
|
|
|
fprintf(stderr, "ECCODES DEBUG grib_util: done grib_set_double_array \n");
|
2013-08-01 15:52:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* convert to second_order if not constant field */
|
|
|
|
if (setSecondOrder ) {
|
2016-04-13 18:32:18 +00:00
|
|
|
size_t packTypeLen=17;
|
2016-09-01 10:49:51 +00:00
|
|
|
int constant=0;
|
|
|
|
double missingValue=0;
|
|
|
|
grib_get_double(h,"missingValue",&missingValue);
|
|
|
|
constant=is_constant_field(missingValue, data_values, data_values_count);
|
2016-09-01 10:21:17 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
if (!constant) {
|
|
|
|
if (editionNumber == 1 ) {
|
|
|
|
long numberOfGroups;
|
|
|
|
grib_handle* htmp=grib_handle_clone(h);
|
|
|
|
|
2016-04-13 18:32:18 +00:00
|
|
|
packTypeLen=17;
|
|
|
|
grib_set_string(htmp,"packingType","grid_second_order",&packTypeLen);
|
2013-08-01 15:52:01 +00:00
|
|
|
grib_get_long(htmp,"numberOfGroups",&numberOfGroups);
|
|
|
|
/* GRIBEX is not able to decode overflown numberOfGroups with SPD */
|
|
|
|
if (numberOfGroups>65534 && h->context->no_spd ) {
|
2016-04-13 18:32:18 +00:00
|
|
|
packTypeLen=24;
|
|
|
|
grib_set_string(h,"packingType","grid_second_order_no_SPD",&packTypeLen);
|
2013-08-01 15:52:01 +00:00
|
|
|
grib_handle_delete(htmp);
|
|
|
|
} else {
|
|
|
|
grib_handle_delete(h);
|
|
|
|
h=htmp;
|
|
|
|
}
|
|
|
|
} else {
|
2016-04-13 18:32:18 +00:00
|
|
|
packTypeLen=17;
|
|
|
|
grib_set_string(h,"packingType","grid_second_order",&packTypeLen);
|
2013-08-01 15:52:01 +00:00
|
|
|
grib_set_double_array(h,"values",data_values,data_values_count);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (h->context->gribex_mode_on) {
|
|
|
|
h->context->gribex_mode_on=0;
|
|
|
|
grib_set_double_array(h,"values",data_values,data_values_count);
|
|
|
|
h->context->gribex_mode_on=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
2015-10-30 11:28:33 +00:00
|
|
|
grid_type = get_grid_type_name(spec->grid_type);
|
|
|
|
if (grid_type == NULL) {
|
|
|
|
fprintf(stderr,"GRIB_UTIL_SET_SPEC: Unknown grid type: %d\n", spec->grid_type);
|
2013-08-01 15:52:01 +00:00
|
|
|
*err = GRIB_NOT_IMPLEMENTED;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
SET_STRING_VALUE("gridType", grid_type);
|
|
|
|
|
|
|
|
/* The "pl" is given from the template, but "section_copy" will take care of setting the right headers */
|
|
|
|
|
|
|
|
{
|
|
|
|
switch (spec->grid_type) {
|
2019-06-05 11:02:16 +00:00
|
|
|
case GRIB_UTIL_GRID_SPEC_REDUCED_GG:
|
|
|
|
case GRIB_UTIL_GRID_SPEC_REDUCED_ROTATED_GG:
|
|
|
|
/* Choose a sample with the right Gaussian number and edition */
|
|
|
|
sprintf(name, "%s_pl_%ld_grib%ld", grid_type,spec->N, editionNumber);
|
|
|
|
if (spec->pl && spec->pl_size) {
|
|
|
|
/* GRIB-834: pl is given so can use any of the reduced_gg_pl samples */
|
|
|
|
sprintf(name, "%s_pl_grib%ld", grid_type, editionNumber);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case GRIB_UTIL_GRID_SPEC_LAMBERT_AZIMUTHAL_EQUAL_AREA:
|
2019-08-27 14:29:15 +00:00
|
|
|
if (editionNumber==1) { /* This grid type is not available in edition 1 */
|
|
|
|
if (h->context->debug==-1)
|
2019-08-27 15:05:22 +00:00
|
|
|
fprintf(stderr,"ECCODES DEBUG grib_util: lambert_azimuthal_equal_area specified "
|
|
|
|
"but input is GRIB1. Output must be a higher edition!\n");
|
2019-08-27 14:29:15 +00:00
|
|
|
convertEditionEarlier=1;
|
2019-06-05 11:02:16 +00:00
|
|
|
}
|
|
|
|
sprintf(name, "GRIB%ld", editionNumber);
|
|
|
|
break;
|
|
|
|
case GRIB_UTIL_GRID_SPEC_LAMBERT_CONFORMAL:
|
|
|
|
sprintf(name, "GRIB%ld", editionNumber);
|
|
|
|
break;
|
|
|
|
default :
|
2015-09-23 16:44:27 +00:00
|
|
|
sprintf(name, "%s_pl_grib%ld", grid_type, editionNumber);
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
2015-10-23 11:55:11 +00:00
|
|
|
|
|
|
|
if (spec->pl && spec->grid_name) {
|
|
|
|
/* Cannot have BOTH pl and grid name specified */
|
|
|
|
fprintf(stderr,"GRIB_UTIL_SET_SPEC: Cannot set BOTH pl and grid_name.\n");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (spec->grid_name) {
|
|
|
|
sprintf(name, "%s_grib%ld", spec->grid_name, editionNumber);
|
|
|
|
}
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: recycle tmp handle */
|
|
|
|
tmp = grib_handle_new_from_samples(NULL, name);
|
|
|
|
if(!tmp) {
|
|
|
|
*err = GRIB_INVALID_FILE;
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
/* Set grid */
|
|
|
|
switch(spec->grid_type) {
|
|
|
|
case GRIB_UTIL_GRID_SPEC_REGULAR_LL:
|
|
|
|
case GRIB_UTIL_GRID_SPEC_ROTATED_LL:
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
COPY_SPEC_LONG (bitmapPresent);
|
|
|
|
if (spec->missingValue) COPY_SPEC_DOUBLE(missingValue);
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
SET_LONG_VALUE ("ijDirectionIncrementGiven", 1);
|
2015-10-26 15:48:55 +00:00
|
|
|
if (editionNumber == 1) {
|
|
|
|
/* GRIB-863: GRIB1 cannot represent increments less than a millidegree */
|
2018-02-06 17:13:42 +00:00
|
|
|
if (!angle_can_be_encoded(h, spec->iDirectionIncrementInDegrees) ||
|
|
|
|
!angle_can_be_encoded(h, spec->jDirectionIncrementInDegrees))
|
2015-10-26 15:48:55 +00:00
|
|
|
{
|
2015-10-28 17:36:10 +00:00
|
|
|
grib1_high_resolution_fix = 1;
|
2015-10-26 15:48:55 +00:00
|
|
|
/* Set flag to compute the increments */
|
|
|
|
SET_LONG_VALUE("ijDirectionIncrementGiven", 0);
|
|
|
|
}
|
|
|
|
}
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
/* default iScansNegatively=0 jScansPositively=0 is ok */
|
|
|
|
COPY_SPEC_LONG(iScansNegatively);
|
|
|
|
COPY_SPEC_LONG(jScansPositively);
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
COPY_SPEC_LONG(Ni);
|
|
|
|
COPY_SPEC_LONG(Nj);
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
COPY_SPEC_DOUBLE(iDirectionIncrementInDegrees);
|
|
|
|
COPY_SPEC_DOUBLE(jDirectionIncrementInDegrees);
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
COPY_SPEC_DOUBLE(longitudeOfFirstGridPointInDegrees);
|
|
|
|
COPY_SPEC_DOUBLE(longitudeOfLastGridPointInDegrees);
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
COPY_SPEC_DOUBLE(latitudeOfFirstGridPointInDegrees);
|
|
|
|
COPY_SPEC_DOUBLE(latitudeOfLastGridPointInDegrees);
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
break;
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
case GRIB_UTIL_GRID_SPEC_REGULAR_GG:
|
|
|
|
case GRIB_UTIL_GRID_SPEC_ROTATED_GG:
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
COPY_SPEC_LONG (bitmapPresent);
|
|
|
|
if (spec->missingValue) COPY_SPEC_DOUBLE(missingValue);
|
|
|
|
SET_LONG_VALUE("ijDirectionIncrementGiven", 1);
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
/* TODO: add Assert */
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
COPY_SPEC_LONG(Ni);
|
|
|
|
COPY_SPEC_DOUBLE(iDirectionIncrementInDegrees);
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
COPY_SPEC_LONG(Nj);
|
|
|
|
COPY_SPEC_LONG(N);
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
/* TODO: Compute here ... */
|
|
|
|
COPY_SPEC_DOUBLE(longitudeOfFirstGridPointInDegrees);
|
|
|
|
COPY_SPEC_DOUBLE(longitudeOfLastGridPointInDegrees);
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
COPY_SPEC_DOUBLE(latitudeOfFirstGridPointInDegrees);
|
|
|
|
COPY_SPEC_DOUBLE(latitudeOfLastGridPointInDegrees);
|
|
|
|
break;
|
2013-03-25 12:04:10 +00:00
|
|
|
|
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
case GRIB_UTIL_GRID_SPEC_REDUCED_LL:
|
|
|
|
COPY_SPEC_LONG (bitmapPresent);
|
|
|
|
if (spec->missingValue) COPY_SPEC_DOUBLE(missingValue);
|
|
|
|
SET_LONG_VALUE("ijDirectionIncrementGiven", 0);
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
COPY_SPEC_LONG(Nj);
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
COPY_SPEC_DOUBLE(longitudeOfFirstGridPointInDegrees);
|
|
|
|
COPY_SPEC_DOUBLE(longitudeOfLastGridPointInDegrees);
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
COPY_SPEC_DOUBLE(latitudeOfFirstGridPointInDegrees);
|
|
|
|
COPY_SPEC_DOUBLE(latitudeOfLastGridPointInDegrees);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GRIB_UTIL_GRID_SPEC_POLAR_STEREOGRAPHIC:
|
|
|
|
COPY_SPEC_LONG (bitmapPresent);
|
|
|
|
if (spec->missingValue) COPY_SPEC_DOUBLE(missingValue);
|
|
|
|
|
|
|
|
COPY_SPEC_DOUBLE(longitudeOfFirstGridPointInDegrees);
|
|
|
|
COPY_SPEC_DOUBLE(latitudeOfFirstGridPointInDegrees);
|
|
|
|
COPY_SPEC_LONG(Ni);
|
|
|
|
COPY_SPEC_LONG(Nj);
|
|
|
|
|
|
|
|
/* default iScansNegatively=0 jScansPositively=0 is ok */
|
|
|
|
COPY_SPEC_LONG(iScansNegatively);
|
|
|
|
COPY_SPEC_LONG(jScansPositively);
|
|
|
|
|
|
|
|
COPY_SPEC_DOUBLE(orientationOfTheGridInDegrees);
|
|
|
|
|
|
|
|
COPY_SPEC_LONG(DxInMetres);
|
|
|
|
COPY_SPEC_LONG(DyInMetres);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2019-05-31 15:08:48 +00:00
|
|
|
case GRIB_UTIL_GRID_SPEC_LAMBERT_AZIMUTHAL_EQUAL_AREA:
|
|
|
|
COPY_SPEC_LONG (bitmapPresent);
|
|
|
|
if (spec->missingValue) COPY_SPEC_DOUBLE(missingValue);
|
|
|
|
|
|
|
|
COPY_SPEC_DOUBLE(longitudeOfFirstGridPointInDegrees);
|
|
|
|
COPY_SPEC_DOUBLE(latitudeOfFirstGridPointInDegrees);
|
|
|
|
COPY_SPEC_LONG(Ni); /* same as Nx */
|
|
|
|
COPY_SPEC_LONG(Nj); /* same as Ny */
|
|
|
|
/* TODO
|
|
|
|
* pass in extra keys e.g. Dx, Dy, standardParallel and centralLongitude
|
|
|
|
*/
|
2019-06-03 11:15:23 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
COPY_SPEC_LONG(DxInMetres);
|
|
|
|
COPY_SPEC_LONG(DyInMetres);
|
|
|
|
|
|
|
|
COPY_SPEC_LONG(xDirectionGridLengthInMillimetres);
|
|
|
|
COPY_SPEC_LONG(yDirectionGridLengthInMillimetres);
|
|
|
|
COPY_SPEC_LONG(standardParallelInMicrodegrees);
|
|
|
|
COPY_SPEC_LONG(centralLongitudeInMicrodegrees);
|
|
|
|
*/
|
|
|
|
|
2019-05-31 15:08:48 +00:00
|
|
|
break;
|
|
|
|
case GRIB_UTIL_GRID_SPEC_LAMBERT_CONFORMAL:
|
2019-06-05 11:02:16 +00:00
|
|
|
COPY_SPEC_LONG (bitmapPresent);
|
|
|
|
if (spec->missingValue) COPY_SPEC_DOUBLE(missingValue);
|
|
|
|
COPY_SPEC_DOUBLE(longitudeOfFirstGridPointInDegrees);
|
|
|
|
COPY_SPEC_DOUBLE(latitudeOfFirstGridPointInDegrees);
|
|
|
|
COPY_SPEC_LONG(Ni); /* same as Nx */
|
|
|
|
COPY_SPEC_LONG(Nj); /* same as Ny */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note: DxInMetres and DyInMetres
|
|
|
|
* should be 'double' and not integer. WMO GRIB2 uses millimetres!
|
|
|
|
* TODO:
|
|
|
|
* Add other keys like Latin1, LoV etc
|
|
|
|
|
|
|
|
*err = GRIB_NOT_IMPLEMENTED;
|
|
|
|
goto cleanup;
|
|
|
|
*/
|
2019-05-31 15:08:48 +00:00
|
|
|
break;
|
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
case GRIB_UTIL_GRID_SPEC_REDUCED_GG:
|
2015-06-08 10:16:55 +00:00
|
|
|
case GRIB_UTIL_GRID_SPEC_REDUCED_ROTATED_GG:
|
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
COPY_SPEC_LONG (bitmapPresent);
|
|
|
|
if (spec->missingValue) COPY_SPEC_DOUBLE(missingValue);
|
|
|
|
SET_LONG_VALUE("ijDirectionIncrementGiven", 0);
|
|
|
|
|
|
|
|
COPY_SPEC_LONG(Nj);
|
|
|
|
COPY_SPEC_LONG(N);
|
|
|
|
|
|
|
|
COPY_SPEC_DOUBLE(longitudeOfFirstGridPointInDegrees);
|
|
|
|
COPY_SPEC_DOUBLE(longitudeOfLastGridPointInDegrees);
|
|
|
|
|
|
|
|
COPY_SPEC_DOUBLE(latitudeOfFirstGridPointInDegrees);
|
|
|
|
COPY_SPEC_DOUBLE(latitudeOfLastGridPointInDegrees);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GRIB_UTIL_GRID_SPEC_SH:
|
|
|
|
*err=grib_get_string(h,"gridType",input_grid_type,&input_grid_type_len);
|
|
|
|
|
|
|
|
SET_LONG_VALUE("J", spec->truncation);
|
|
|
|
SET_LONG_VALUE("K", spec->truncation);
|
|
|
|
SET_LONG_VALUE("M", spec->truncation);
|
|
|
|
|
|
|
|
if(packing_spec->packing_type == GRIB_UTIL_PACKING_TYPE_SPECTRAL_COMPLEX)
|
|
|
|
{
|
2019-01-11 10:04:41 +00:00
|
|
|
const long JS = spec->truncation < 20 ? spec->truncation : 20;
|
2013-08-01 15:52:01 +00:00
|
|
|
SET_STRING_VALUE("packingType", "spectral_complex");
|
|
|
|
packingTypeIsSet=1;
|
2019-01-11 02:24:40 +00:00
|
|
|
SET_LONG_VALUE("JS", JS);
|
|
|
|
SET_LONG_VALUE("KS", JS);
|
|
|
|
SET_LONG_VALUE("MS", JS);
|
2013-08-01 15:52:01 +00:00
|
|
|
if (packing_spec->packing == GRIB_UTIL_PACKING_USE_PROVIDED && editionNumber==2 ) {
|
|
|
|
SET_LONG_VALUE("computeLaplacianOperator", 1);
|
|
|
|
} else if ((!(*err) && strcmp(input_grid_type,"sh")) || packing_spec->computeLaplacianOperator ) {
|
|
|
|
SET_LONG_VALUE("computeLaplacianOperator", 1);
|
|
|
|
if (packing_spec->truncateLaplacian)
|
|
|
|
SET_LONG_VALUE("truncateLaplacian",1);
|
|
|
|
} else {
|
|
|
|
SET_LONG_VALUE("computeLaplacianOperator", 0);
|
|
|
|
*err=grib_get_double(h,"laplacianOperator",&laplacianOperator);
|
|
|
|
if (packing_spec->truncateLaplacian) SET_LONG_VALUE("truncateLaplacian",1);
|
|
|
|
SET_DOUBLE_VALUE("laplacianOperator", packing_spec->laplacianOperator);
|
|
|
|
if (laplacianOperator) {
|
|
|
|
SET_DOUBLE_VALUE("laplacianOperator", laplacianOperator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set rotation */
|
|
|
|
switch(spec->grid_type) {
|
|
|
|
case GRIB_UTIL_GRID_SPEC_ROTATED_LL:
|
|
|
|
case GRIB_UTIL_GRID_SPEC_ROTATED_GG:
|
2015-06-08 10:16:55 +00:00
|
|
|
case GRIB_UTIL_GRID_SPEC_REDUCED_ROTATED_GG:
|
2013-08-01 15:52:01 +00:00
|
|
|
COPY_SPEC_LONG(uvRelativeToGrid);
|
|
|
|
COPY_SPEC_DOUBLE(latitudeOfSouthernPoleInDegrees);
|
|
|
|
COPY_SPEC_DOUBLE(longitudeOfSouthernPoleInDegrees);
|
2015-05-07 16:57:58 +00:00
|
|
|
COPY_SPEC_DOUBLE(angleOfRotationInDegrees);
|
2013-08-01 15:52:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* process packing options */
|
|
|
|
if (!packingTypeIsSet &&
|
|
|
|
packing_spec->packing == GRIB_UTIL_PACKING_USE_PROVIDED &&
|
|
|
|
strcmp(input_packing_type,"grid_simple_matrix")) {
|
|
|
|
|
|
|
|
switch (packing_spec->packing_type) {
|
|
|
|
case GRIB_UTIL_PACKING_TYPE_SPECTRAL_COMPLEX:
|
|
|
|
if (strcmp(input_packing_type,"spectral_complex") && !strcmp(input_packing_type,"spectral_simple"))
|
|
|
|
SET_STRING_VALUE("packingType","spectral_complex");
|
|
|
|
break;
|
|
|
|
case GRIB_UTIL_PACKING_TYPE_SPECTRAL_SIMPLE:
|
|
|
|
if (strcmp(input_packing_type,"spectral_simple") && !strcmp(input_packing_type,"spectral_complex"))
|
|
|
|
SET_STRING_VALUE("packingType","spectral_simple");
|
|
|
|
break;
|
|
|
|
case GRIB_UTIL_PACKING_TYPE_GRID_SIMPLE:
|
|
|
|
if (strcmp(input_packing_type,"grid_simple") && !strcmp(input_packing_type,"grid_complex"))
|
|
|
|
SET_STRING_VALUE("packingType","grid_simple");
|
|
|
|
break;
|
|
|
|
case GRIB_UTIL_PACKING_TYPE_GRID_COMPLEX:
|
|
|
|
if (strcmp(input_packing_type,"grid_complex") && !strcmp(input_packing_type,"grid_simple"))
|
|
|
|
SET_STRING_VALUE("packingType","grid_complex");
|
|
|
|
break;
|
|
|
|
case GRIB_UTIL_PACKING_TYPE_JPEG:
|
2016-10-11 15:14:07 +00:00
|
|
|
/* Have to delay JPEG packing:
|
|
|
|
* Reason 1: It is not available in GRIB1 and so we have to wait until we change edition
|
|
|
|
* Reason 2: It has to be done AFTER we set the data values
|
|
|
|
*/
|
2013-08-01 15:52:01 +00:00
|
|
|
if (strcmp(input_packing_type,"grid_jpeg") && !strcmp(input_packing_type,"grid_simple"))
|
2016-10-11 15:14:07 +00:00
|
|
|
setJpegPacking = 1;
|
2013-08-01 15:52:01 +00:00
|
|
|
break;
|
2019-10-01 11:12:18 +00:00
|
|
|
case GRIB_UTIL_PACKING_TYPE_CCSDS:
|
|
|
|
/* Have to delay CCSDS packing:
|
|
|
|
* Reason 1: It is not available in GRIB1 and so we have to wait until we change edition
|
|
|
|
* Reason 2: It has to be done AFTER we set the data values
|
|
|
|
*/
|
|
|
|
if (strcmp(input_packing_type,"grid_ccsds") && !strcmp(input_packing_type,"grid_simple"))
|
|
|
|
setCcsdsPacking = 1;
|
|
|
|
break;
|
2013-08-01 15:52:01 +00:00
|
|
|
case GRIB_UTIL_PACKING_TYPE_GRID_SECOND_ORDER:
|
|
|
|
/* we delay the set of grid_second_order because we don't want
|
2014-03-26 14:30:16 +00:00
|
|
|
to do it on a field with bitsPerValue=0 */
|
2013-08-01 15:52:01 +00:00
|
|
|
setSecondOrder=1;
|
|
|
|
break;
|
|
|
|
default :
|
2019-09-16 14:15:03 +00:00
|
|
|
fprintf(stderr,"invalid packing_spec->packing_type = %ld\n",(long)packing_spec->packing_type);
|
2018-06-06 11:47:04 +00:00
|
|
|
*err = GRIB_INTERNAL_ERROR;
|
|
|
|
goto cleanup;
|
2014-03-26 14:30:16 +00:00
|
|
|
break;
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-20 11:13:43 +00:00
|
|
|
if (strcmp(input_packing_type,"grid_simple_matrix")==0) {
|
2013-08-01 15:52:01 +00:00
|
|
|
long numberOfDirections,numberOfFrequencies;
|
2019-03-20 11:13:43 +00:00
|
|
|
int keep_matrix = h->context->keep_matrix;
|
|
|
|
if (packing_spec->packing_type == GRIB_UTIL_PACKING_TYPE_GRID_SIMPLE) {
|
|
|
|
keep_matrix = 0; /* ECC-911 */
|
|
|
|
}
|
|
|
|
if (keep_matrix) {
|
2014-03-26 14:30:16 +00:00
|
|
|
int ret;
|
2013-08-01 15:52:01 +00:00
|
|
|
SET_STRING_VALUE("packingType","grid_simple_matrix");
|
|
|
|
ret=grib_get_long(h,"numberOfDirections",&numberOfDirections);
|
|
|
|
if (!ret) {
|
|
|
|
ret=grib_get_long(h,"numberOfDirections",&numberOfDirections);
|
|
|
|
SET_LONG_VALUE("NC1",numberOfDirections);
|
|
|
|
ret=grib_get_long(h,"numberOfFrequencies",&numberOfFrequencies);
|
|
|
|
SET_LONG_VALUE("NC2",numberOfFrequencies);
|
|
|
|
SET_LONG_VALUE("physicalFlag1",1);
|
|
|
|
SET_LONG_VALUE("physicalFlag2",2);
|
|
|
|
SET_LONG_VALUE("NR",1);
|
|
|
|
SET_LONG_VALUE("NC",1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
SET_STRING_VALUE("packingType","grid_simple");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(packing_spec->accuracy) {
|
|
|
|
case GRIB_UTIL_ACCURACY_SAME_BITS_PER_VALUES_AS_INPUT:
|
|
|
|
{
|
|
|
|
long bitsPerValue = 0;
|
|
|
|
Assert(grib_get_long(h, "bitsPerValue", &bitsPerValue) == 0);
|
|
|
|
SET_LONG_VALUE("bitsPerValue", bitsPerValue);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GRIB_UTIL_ACCURACY_USE_PROVIDED_BITS_PER_VALUES:
|
|
|
|
SET_LONG_VALUE("bitsPerValue", packing_spec->bitsPerValue);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GRIB_UTIL_ACCURACY_SAME_DECIMAL_SCALE_FACTOR_AS_INPUT:
|
|
|
|
{
|
|
|
|
long decimalScaleFactor = 0;
|
|
|
|
Assert(grib_get_long(h, "decimalScaleFactor", &decimalScaleFactor) == 0);
|
|
|
|
SET_LONG_VALUE("decimalScaleFactor", decimalScaleFactor);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GRIB_UTIL_ACCURACY_USE_PROVIDED_DECIMAL_SCALE_FACTOR:
|
|
|
|
SET_LONG_VALUE("decimalScaleFactor", packing_spec->decimalScaleFactor);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2019-09-16 14:15:03 +00:00
|
|
|
fprintf(stderr, "invalid packing_spec->accuracy = %ld\n",(long)packing_spec->accuracy);
|
2018-06-06 11:47:04 +00:00
|
|
|
*err = GRIB_INTERNAL_ERROR;
|
|
|
|
goto cleanup;
|
2014-03-26 14:30:16 +00:00
|
|
|
break;
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(packing_spec->extra_settings_count) {
|
|
|
|
for(i = 0; i < packing_spec->extra_settings_count; i++) {
|
|
|
|
Assert(count < 1024);
|
2018-02-05 16:05:31 +00:00
|
|
|
if (strcmp(packing_spec->extra_settings[i].name, "expandBoundingBox")==0)
|
|
|
|
{
|
|
|
|
if (packing_spec->extra_settings[i].long_value == 1) {
|
|
|
|
/* ECC-625: Request is for expansion of bounding box (sub-area).
|
|
|
|
* This is also called the "snap-out" policy */
|
|
|
|
expandBoundingBox = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2016-02-08 10:37:21 +00:00
|
|
|
{
|
2018-02-05 16:05:31 +00:00
|
|
|
values[count++] = packing_spec->extra_settings[i];
|
|
|
|
if (strcmp(packing_spec->extra_settings[i].name, "global")==0 &&
|
|
|
|
packing_spec->extra_settings[i].long_value == 1)
|
|
|
|
{
|
|
|
|
/* GRIB-922: Request is for a global grid. Setting this key will
|
|
|
|
* calculate the lat/lon values. So the spec's lat/lon can be ignored */
|
|
|
|
global_grid = 1;
|
|
|
|
}
|
2016-02-08 10:37:21 +00:00
|
|
|
}
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* grib_write_message(h,"input.grib","w"); */
|
|
|
|
/* grib_write_message(tmp,"geo.grib","w"); */
|
2016-02-08 10:37:21 +00:00
|
|
|
/* copy product and local sections from h to tmp handle and store in outh */
|
2013-08-01 15:52:01 +00:00
|
|
|
if((outh = grib_util_sections_copy(h, tmp, GRIB_SECTION_PRODUCT | GRIB_SECTION_LOCAL,err)) == NULL)
|
|
|
|
{
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
grib_handle_delete(tmp);
|
|
|
|
Assert(*err == 0);
|
|
|
|
|
2015-10-23 11:55:11 +00:00
|
|
|
/* Set "pl" array if provided (For reduced Gaussian grids) */
|
|
|
|
/* See GRIB-857 */
|
2015-08-26 09:26:22 +00:00
|
|
|
Assert(spec->pl_size >= 0);
|
|
|
|
if (spec->pl && spec->pl_size == 0) {
|
|
|
|
fprintf(stderr, "pl array not NULL but pl_size == 0!\n");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (spec->pl_size > 0 && spec->pl == NULL) {
|
|
|
|
fprintf(stderr, "pl_size not zero but pl array == NULL!\n");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-09-23 16:44:27 +00:00
|
|
|
if (spec->pl_size!=0 && (spec->grid_type==GRIB_UTIL_GRID_SPEC_REDUCED_GG || spec->grid_type==GRIB_UTIL_GRID_SPEC_REDUCED_ROTATED_GG))
|
|
|
|
{
|
2013-08-01 15:52:01 +00:00
|
|
|
*err=grib_set_long_array(outh,"pl",spec->pl,spec->pl_size);
|
|
|
|
if (*err) {
|
|
|
|
fprintf(stderr,"SET_GRID_DATA_DESCRIPTION: Cannot set pl %s\n",grib_get_error_message(*err));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2018-06-22 10:35:16 +00:00
|
|
|
if (global_grid) {
|
|
|
|
size_t sum = sum_of_pl_array(spec->pl, spec->pl_size);
|
|
|
|
if (data_values_count != sum) {
|
2019-09-16 14:15:03 +00:00
|
|
|
fprintf(stderr, "invalid reduced gaussian grid: specified as global, data_values_count=%ld but sum of pl array=%ld\n",
|
2018-08-07 14:31:41 +00:00
|
|
|
(long)data_values_count, (long)sum);
|
2018-06-22 10:35:16 +00:00
|
|
|
*err = GRIB_WRONG_GRID;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
|
|
|
|
2017-11-13 13:26:36 +00:00
|
|
|
if (h->context->debug==-1) {
|
2019-08-05 10:32:11 +00:00
|
|
|
fprintf(stderr, "ECCODES DEBUG grib_util: global_grid = %d\n", global_grid);
|
|
|
|
fprintf(stderr, "ECCODES DEBUG grib_util: expandBoundingBox = %d\n", expandBoundingBox);
|
2018-02-05 16:05:31 +00:00
|
|
|
print_values(h->context,spec,data_values,data_values_count,values,count);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Apply adjustments to bounding box if needed */
|
|
|
|
if (expandBoundingBox) {
|
|
|
|
if ((*err=expand_bounding_box(outh, values, count)) != 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr,"SET_GRID_DATA_DESCRIPTION: Cannot expand bounding box: %s\n",grib_get_error_message(*err));
|
2018-06-22 12:23:29 +00:00
|
|
|
if (h->context->write_on_fail) grib_write_message(outh,"error.grib","w");
|
2018-02-05 16:05:31 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2017-11-13 13:26:36 +00:00
|
|
|
}
|
2015-10-23 11:55:11 +00:00
|
|
|
|
2019-08-27 14:29:15 +00:00
|
|
|
if (convertEditionEarlier && packing_spec->editionNumber>1) {
|
|
|
|
*err = grib_set_long(outh,"edition", packing_spec->editionNumber);
|
|
|
|
if(*err) {
|
|
|
|
fprintf(stderr,"SET_GRID_DATA_DESCRIPTION: Cannot convert to edition %ld.\n",packing_spec->editionNumber);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-23 11:55:11 +00:00
|
|
|
if((*err = grib_set_values(outh,values,count)) != 0)
|
|
|
|
{
|
2016-08-31 16:38:31 +00:00
|
|
|
fprintf(stderr,"SET_GRID_DATA_DESCRIPTION: Cannot set key values: %s\n",grib_get_error_message(*err));
|
2015-10-23 11:55:11 +00:00
|
|
|
|
|
|
|
for(i = 0; i < count; i++)
|
|
|
|
if(values[i].error)
|
|
|
|
fprintf(stderr," %s %s\n",values[i].name,grib_get_error_message(values[i].error));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2016-09-01 14:03:00 +00:00
|
|
|
if((*err = grib_set_double_array(outh,"values",data_values,data_values_count)) != 0)
|
2013-08-01 15:52:01 +00:00
|
|
|
{
|
2016-09-01 14:03:00 +00:00
|
|
|
FILE* ferror;
|
2017-08-25 16:32:07 +00:00
|
|
|
size_t ii,lcount;
|
2016-09-01 14:03:00 +00:00
|
|
|
grib_context* c=grib_context_get_default();
|
|
|
|
|
|
|
|
ferror=fopen("error.data","w");
|
|
|
|
lcount=0;
|
|
|
|
fprintf(ferror,"# data_values_count=%ld\n",(long)data_values_count);
|
|
|
|
fprintf(ferror,"set values={ ");
|
2017-08-25 16:32:07 +00:00
|
|
|
for (ii=0;ii<data_values_count-1;ii++) {
|
|
|
|
fprintf(ferror,"%g, ",data_values[ii]);
|
2016-09-01 14:03:00 +00:00
|
|
|
if (lcount>10) {fprintf(ferror,"\n");lcount=0;}
|
|
|
|
lcount++;
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
2016-09-01 14:03:00 +00:00
|
|
|
fprintf(ferror,"%g }",data_values[data_values_count-1]);
|
|
|
|
fclose(ferror);
|
|
|
|
if (c->write_on_fail)
|
|
|
|
grib_write_message(outh,"error.grib","w");
|
|
|
|
goto cleanup;
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
2016-09-01 14:03:00 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
/* grib_write_message(outh,"h.grib","w"); */
|
|
|
|
/* if the field is empty GRIBEX is packing as simple*/
|
2016-08-31 16:38:31 +00:00
|
|
|
/* if (!strcmp(input_packing_type,"grid_simple_matrix")) {
|
2013-03-25 12:04:10 +00:00
|
|
|
long numberOfValues;
|
|
|
|
grib_get_long(outh,"numberOfValues",&numberOfValues);
|
|
|
|
if (numberOfValues==0) {
|
|
|
|
slen=11;
|
|
|
|
grib_set_string(outh,"packingType","grid_simple",&slen);
|
|
|
|
}
|
2016-08-31 16:38:31 +00:00
|
|
|
} */
|
2013-08-01 15:52:01 +00:00
|
|
|
|
2015-10-28 17:36:10 +00:00
|
|
|
if (grib1_high_resolution_fix) {
|
2015-10-26 15:48:55 +00:00
|
|
|
/* GRIB-863: must set increments to MISSING */
|
|
|
|
/* increments are not coded in message but computed */
|
|
|
|
if ( (*err = grib_set_missing(outh, "iDirectionIncrement"))!=0 ) {
|
|
|
|
fprintf(stderr,"GRIB_UTIL_SET_SPEC: Cannot set Di to missing: %s\n",grib_get_error_message(*err));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if ( (*err = grib_set_missing(outh, "jDirectionIncrement"))!=0 ){
|
|
|
|
fprintf(stderr,"GRIB_UTIL_SET_SPEC: Cannot set Dj to missing: %s\n",grib_get_error_message(*err));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-28 17:36:10 +00:00
|
|
|
/*grib_dump_content(outh, stdout,"debug", ~0, NULL);*/
|
|
|
|
|
2016-09-01 10:21:17 +00:00
|
|
|
/* convert to second_order if not constant field. (Also see ECC-326) */
|
2013-08-01 15:52:01 +00:00
|
|
|
if (setSecondOrder ) {
|
2016-09-01 10:49:51 +00:00
|
|
|
int constant = 0;
|
|
|
|
double missingValue=0;
|
|
|
|
grib_get_double(outh,"missingValue",&missingValue);
|
|
|
|
constant = is_constant_field(missingValue, data_values, data_values_count);
|
2016-08-31 16:38:31 +00:00
|
|
|
|
2013-08-01 15:52:01 +00:00
|
|
|
if (!constant) {
|
|
|
|
if (editionNumber == 1 ) {
|
2016-03-16 14:11:04 +00:00
|
|
|
long numberOfGroups=0;
|
2013-08-01 15:52:01 +00:00
|
|
|
grib_handle* htmp=grib_handle_clone(outh);
|
|
|
|
|
|
|
|
slen=17;
|
|
|
|
grib_set_string(htmp,"packingType","grid_second_order",&slen);
|
|
|
|
grib_get_long(htmp,"numberOfGroups",&numberOfGroups);
|
|
|
|
/* GRIBEX is not able to decode overflown numberOfGroups with SPD */
|
|
|
|
if (numberOfGroups>65534 && outh->context->no_spd) {
|
|
|
|
slen=24;
|
|
|
|
grib_set_string(outh,"packingType","grid_second_order_no_SPD",&slen);
|
|
|
|
grib_handle_delete(htmp);
|
|
|
|
} else {
|
|
|
|
grib_handle_delete(outh);
|
|
|
|
outh=htmp;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
slen=17;
|
|
|
|
grib_set_string(outh,"packingType","grid_second_order",&slen);
|
2016-08-31 16:38:31 +00:00
|
|
|
*err = grib_set_double_array(outh,"values", data_values, data_values_count);
|
|
|
|
if (*err != GRIB_SUCCESS) {
|
|
|
|
fprintf(stderr,"GRIB_UTIL_SET_SPEC: setting data values failed! %s\n", grib_get_error_message(*err));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (outh->context->gribex_mode_on) {
|
|
|
|
outh->context->gribex_mode_on=0;
|
2016-08-31 16:38:31 +00:00
|
|
|
grib_set_double_array(outh,"values", data_values, data_values_count);
|
2013-08-01 15:52:01 +00:00
|
|
|
outh->context->gribex_mode_on=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-22 15:52:56 +00:00
|
|
|
if (packing_spec->editionNumber && packing_spec->editionNumber!=editionNumber) {
|
2016-09-23 14:10:36 +00:00
|
|
|
*err = grib_set_long(outh,"edition", packing_spec->editionNumber);
|
|
|
|
if (*err != GRIB_SUCCESS) {
|
|
|
|
fprintf(stderr,"GRIB_UTIL_SET_SPEC: Failed to change edition to %ld: %s\n",
|
|
|
|
packing_spec->editionNumber, grib_get_error_message(*err));
|
2018-06-22 12:23:29 +00:00
|
|
|
if (h->context->write_on_fail) grib_write_message(outh,"error.grib","w");
|
2016-09-23 14:10:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2016-10-11 15:14:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (editionNumber > 1 || packing_spec->editionNumber > 1) {
|
2016-10-05 17:32:21 +00:00
|
|
|
/* ECC-353 */
|
2016-10-11 15:14:07 +00:00
|
|
|
/* JPEG packing is not available in GRIB edition 1 and has to be done AFTER we set data values */
|
|
|
|
if (setJpegPacking == 1) {
|
|
|
|
*err = grib_set_string(outh, "packingType", "grid_jpeg", &slen);
|
|
|
|
if (*err != GRIB_SUCCESS) {
|
|
|
|
fprintf(stderr,"GRIB_UTIL_SET_SPEC: Failed to change packingType to JPEG: %s\n",
|
|
|
|
grib_get_error_message(*err));
|
|
|
|
goto cleanup;
|
2016-10-05 17:32:21 +00:00
|
|
|
}
|
|
|
|
}
|
2019-10-01 11:12:18 +00:00
|
|
|
if (setCcsdsPacking == 1) {
|
|
|
|
*err = grib_set_string(outh, "packingType", "grid_ccsds", &slen);
|
|
|
|
if (*err != GRIB_SUCCESS) {
|
|
|
|
fprintf(stderr,"GRIB_UTIL_SET_SPEC: Failed to change packingType to CCSDS: %s\n",
|
|
|
|
grib_get_error_message(*err));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
2016-09-22 15:52:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (packing_spec->deleteLocalDefinition) {
|
|
|
|
grib_set_long(outh,"deleteLocalDefinition", 1);
|
|
|
|
}
|
2013-08-01 15:52:01 +00:00
|
|
|
|
2018-06-18 10:05:57 +00:00
|
|
|
/* ECC-445 */
|
|
|
|
if (expandBoundingBox) {
|
2018-08-03 16:55:53 +00:00
|
|
|
Assert(!global_grid); /* ECC-576: "global" should not be set */
|
2018-06-18 10:05:57 +00:00
|
|
|
}
|
2013-08-01 15:52:01 +00:00
|
|
|
|
2018-06-26 12:40:13 +00:00
|
|
|
if ( (*err = check_geometry(outh, spec, data_values_count, global_grid)) != GRIB_SUCCESS)
|
2018-06-22 10:35:16 +00:00
|
|
|
{
|
2018-06-26 12:40:13 +00:00
|
|
|
fprintf(stderr,"GRIB_UTIL_SET_SPEC: Geometry check failed! %s\n", grib_get_error_message(*err));
|
2018-06-22 12:23:29 +00:00
|
|
|
if (h->context->write_on_fail)
|
2018-06-22 10:35:16 +00:00
|
|
|
grib_write_message(outh,"error.grib","w");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2017-11-06 18:07:01 +00:00
|
|
|
/* Disable check: need to re-examine GRIB-864 */
|
2017-11-13 13:26:36 +00:00
|
|
|
#if 0
|
2016-02-08 10:37:21 +00:00
|
|
|
if ( (*err = check_handle_against_spec(outh, editionNumber, spec, global_grid)) != GRIB_SUCCESS)
|
2015-10-29 13:38:35 +00:00
|
|
|
{
|
2017-11-13 13:26:36 +00:00
|
|
|
|
2015-10-28 17:36:10 +00:00
|
|
|
grib_context* c=grib_context_get_default();
|
2015-10-29 13:38:35 +00:00
|
|
|
fprintf(stderr,"GRIB_UTIL_SET_SPEC: Geometry check failed! %s\n", grib_get_error_message(*err));
|
2015-12-18 15:59:30 +00:00
|
|
|
if (editionNumber == 1) {
|
|
|
|
fprintf(stderr,"Note: in GRIB edition 1 latitude and longitude values cannot be represented with sub-millidegree precision.\n");
|
|
|
|
}
|
2015-10-28 17:36:10 +00:00
|
|
|
if (c->write_on_fail)
|
|
|
|
grib_write_message(outh,"error.grib","w");
|
2015-10-27 16:37:13 +00:00
|
|
|
goto cleanup;
|
2017-11-06 18:07:01 +00:00
|
|
|
}
|
2017-11-13 13:26:36 +00:00
|
|
|
#endif
|
2013-08-01 15:52:01 +00:00
|
|
|
if (h->context->debug==-1)
|
2019-08-05 10:32:11 +00:00
|
|
|
fprintf(stderr, "ECCODES DEBUG: grib_util_set_spec end\n");
|
2013-08-01 15:52:01 +00:00
|
|
|
|
|
|
|
return outh;
|
|
|
|
|
2016-09-01 14:03:00 +00:00
|
|
|
cleanup:
|
2013-08-01 15:52:01 +00:00
|
|
|
if(outh) grib_handle_delete(outh);
|
|
|
|
return NULL;
|
2013-03-25 12:04:10 +00:00
|
|
|
}
|
|
|
|
|
2015-12-31 11:51:57 +00:00
|
|
|
int grib_moments(grib_handle* h,double east,double north,double west,double south,int order,double* moments,long *count)
|
|
|
|
{
|
2013-08-01 15:52:01 +00:00
|
|
|
grib_iterator* iter=NULL;
|
|
|
|
int ret=0,i,j,l;
|
|
|
|
size_t n=0,numberOfPoints=0;
|
|
|
|
double *lat,*lon,*values;
|
|
|
|
double vlat,vlon,val;
|
|
|
|
double dx,dy,ddx,ddy;
|
|
|
|
double mass,centroidX,centroidY;
|
|
|
|
double missingValue;
|
|
|
|
grib_context* c=grib_context_get_default();
|
|
|
|
|
|
|
|
ret=grib_get_size(h,"values",&n);
|
|
|
|
if (ret) return ret;
|
|
|
|
|
2014-10-02 15:50:49 +00:00
|
|
|
lat=(double*)grib_context_malloc_clear(c,sizeof(double)*n);
|
|
|
|
lon=(double*)grib_context_malloc_clear(c,sizeof(double)*n);
|
|
|
|
values=(double*)grib_context_malloc_clear(c,sizeof(double)*n);
|
2013-08-01 15:52:01 +00:00
|
|
|
|
|
|
|
iter=grib_iterator_new(h,0,&ret);
|
|
|
|
numberOfPoints=0;
|
|
|
|
while(grib_iterator_next(iter,&vlat,&vlon,&val)) {
|
|
|
|
if (vlon>=east && vlon<=west && vlat>=south && vlat<=north) {
|
|
|
|
lat[numberOfPoints]=vlat;
|
|
|
|
lon[numberOfPoints]=vlon;
|
|
|
|
values[numberOfPoints]=val;
|
|
|
|
numberOfPoints++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
grib_iterator_delete(iter);
|
|
|
|
|
|
|
|
ret=grib_get_double(h,"missingValue",&missingValue);
|
|
|
|
|
|
|
|
centroidX=0;
|
|
|
|
centroidY=0;
|
|
|
|
mass=0;
|
|
|
|
*count=0;
|
|
|
|
for (i=0;i<numberOfPoints;i++) {
|
|
|
|
if (values[i]!=missingValue) {
|
|
|
|
centroidX+=lon[i]*values[i];
|
|
|
|
centroidY+=lat[i]*values[i];
|
|
|
|
mass+=values[i];
|
|
|
|
(*count)++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
centroidX/=mass;
|
|
|
|
centroidY/=mass;
|
|
|
|
mass/=*count;
|
|
|
|
|
|
|
|
for (j=0;j<order*order;j++) moments[j]=0;
|
|
|
|
|
|
|
|
for (i=0;i<numberOfPoints;i++) {
|
|
|
|
if (values[i]!=missingValue) {
|
|
|
|
dx=(lon[i]-centroidX);
|
|
|
|
dy=(lat[i]-centroidY);
|
|
|
|
ddx=1;
|
|
|
|
for (j=0;j<order;j++) {
|
|
|
|
ddy=1;
|
|
|
|
for (l=0;l<order;l++) {
|
|
|
|
moments[j*order+l]+=ddx*ddy*values[i];
|
|
|
|
ddy*=dy;
|
|
|
|
}
|
|
|
|
ddx*=dx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (j=0;j<order;j++) {
|
|
|
|
for (l=0;l<order;l++) {
|
|
|
|
if (j+l>1) {
|
|
|
|
moments[j*order+l]=pow(fabs(moments[j*order+l]),1.0/(j+l)) / *count ;
|
|
|
|
} else {
|
|
|
|
moments[j*order+l]/=*count ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
grib_context_free(c,lat);
|
|
|
|
grib_context_free(c,lon);
|
|
|
|
grib_context_free(c,values);
|
2018-02-05 16:05:31 +00:00
|
|
|
(void)mass;
|
2013-08-01 15:52:01 +00:00
|
|
|
|
|
|
|
return ret;
|
2013-03-25 12:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Helper function for 'parse_keyval_string' */
|
|
|
|
static void set_value(grib_values* value,char* str,int equal)
|
|
|
|
{
|
2013-08-01 15:52:01 +00:00
|
|
|
char *p=0,*q=0,*s=0;
|
|
|
|
char buf[1000]={0,};
|
|
|
|
grib_context* c=grib_context_get_default();
|
|
|
|
|
|
|
|
value->equal=equal;
|
|
|
|
q=str;
|
|
|
|
|
|
|
|
while (*q != '/' && *q!=0 ) q++;
|
|
|
|
if (*q=='/') {
|
|
|
|
s=grib_context_strdup(c,q+1);
|
2014-10-02 15:50:49 +00:00
|
|
|
value->next=(grib_values*)grib_context_malloc_clear(c,sizeof(grib_values));
|
2013-08-01 15:52:01 +00:00
|
|
|
value->next->type=value->type;
|
|
|
|
value->next->name=grib_context_strdup(c,value->name);
|
|
|
|
set_value(value->next,s,equal);
|
|
|
|
grib_context_free(c,s);
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(buf,str,q-str);
|
|
|
|
|
|
|
|
switch (value->type) {
|
|
|
|
case GRIB_TYPE_DOUBLE:
|
|
|
|
value->double_value = strtod(buf,&p);
|
|
|
|
if(*p != 0) value->has_value=1;
|
|
|
|
else if (!strcmp(str,"missing") ||
|
|
|
|
!strcmp(str,"MISSING") ||
|
|
|
|
!strcmp(str,"Missing") ) {
|
|
|
|
value->type=GRIB_TYPE_MISSING;
|
|
|
|
value->has_value=1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case GRIB_TYPE_LONG:
|
|
|
|
value->long_value = strtol(buf,&p,10);
|
|
|
|
if(*p != 0) value->has_value=1;
|
|
|
|
else if (!strcmp(buf,"missing") ||
|
|
|
|
!strcmp(buf,"MISSING") ||
|
|
|
|
!strcmp(buf,"Missing") ) {
|
|
|
|
value->type=GRIB_TYPE_MISSING;
|
|
|
|
value->has_value=1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case GRIB_TYPE_STRING:
|
|
|
|
if ( !strcmp(buf,"missing") ||
|
|
|
|
!strcmp(buf,"MISSING") ||
|
|
|
|
!strcmp(buf,"Missing") ) {
|
|
|
|
value->type=GRIB_TYPE_MISSING;
|
|
|
|
value->has_value=1;
|
|
|
|
} else {
|
|
|
|
value->string_value = grib_context_strdup(c,buf);
|
|
|
|
value->has_value=1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case GRIB_TYPE_UNDEFINED:
|
|
|
|
value->long_value = strtol(buf,&p,10);
|
|
|
|
if(*p == 0) {
|
|
|
|
value->type = GRIB_TYPE_LONG;
|
|
|
|
value->has_value=1;
|
|
|
|
} else {
|
|
|
|
value->double_value = strtod(buf,&p);
|
|
|
|
if(*p == 0) {
|
|
|
|
value->type = GRIB_TYPE_DOUBLE;
|
|
|
|
value->has_value=1;
|
|
|
|
} else if ( !strcmp(buf,"missing") ||
|
|
|
|
!strcmp(buf,"MISSING") ||
|
|
|
|
!strcmp(buf,"Missing") ) {
|
|
|
|
value->type=GRIB_TYPE_MISSING;
|
|
|
|
value->has_value=1;
|
|
|
|
} else {
|
|
|
|
value->string_value = grib_context_strdup(c,buf);
|
|
|
|
value->type = GRIB_TYPE_STRING;
|
|
|
|
value->has_value=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2013-03-25 12:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
'grib_tool' Optional tool name which is printed on error. Can be NULL
|
|
|
|
'arg' The string to be parsed e.g. key1=value1,key2!=value2 etc
|
|
|
|
'values_required' If true then each key must have a value after it
|
|
|
|
'default_type' The default type e.g. GRIB_TYPE_UNDEFINED or GRIB_TYPE_DOUBLE
|
|
|
|
'values' The array we populate and return
|
|
|
|
'count' The number of elements
|
2013-04-16 16:53:48 +00:00
|
|
|
*/
|
2018-08-07 12:50:41 +00:00
|
|
|
int parse_keyval_string(const char* grib_tool, char* arg, int values_required, int default_type, grib_values values[], int* count)
|
2013-03-25 12:04:10 +00:00
|
|
|
{
|
2013-08-01 15:52:01 +00:00
|
|
|
char* p;
|
|
|
|
int i=0;
|
|
|
|
if (arg == NULL) {
|
|
|
|
*count=0;
|
|
|
|
return GRIB_SUCCESS;
|
|
|
|
}
|
|
|
|
p=strtok(arg,",");
|
|
|
|
while (p != NULL) {
|
|
|
|
values[i].name=(char*)calloc(1,strlen(p)+1);
|
2016-03-16 14:11:04 +00:00
|
|
|
Assert(values[i].name);
|
2013-08-01 15:52:01 +00:00
|
|
|
strcpy((char*)values[i].name,p);
|
|
|
|
p=strtok(NULL,",");
|
|
|
|
i++;
|
|
|
|
if (i > *count) return GRIB_ARRAY_TOO_SMALL;
|
|
|
|
}
|
|
|
|
*count=i;
|
|
|
|
|
|
|
|
for (i=0;i<*count;i++) {
|
|
|
|
int equal=1;
|
|
|
|
char* value=NULL;
|
|
|
|
if (values_required) {
|
|
|
|
/* Can be either k=v or k!=v */
|
|
|
|
p=(char*)values[i].name;
|
|
|
|
while( *p != '=' && *p != '!' && *p != '\0') p++;
|
|
|
|
if (*p == '=') {
|
|
|
|
*p='\0';
|
|
|
|
p++;
|
|
|
|
value=p;
|
|
|
|
equal=1;
|
|
|
|
} else if (*p == '!' && *(++p) == '=' ) {
|
|
|
|
*p='\0';
|
|
|
|
*(p-1)='\0';
|
|
|
|
p++;
|
|
|
|
value=p;
|
|
|
|
equal=0;
|
|
|
|
} else {
|
|
|
|
return GRIB_INVALID_ARGUMENT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p=(char*)values[i].name;
|
|
|
|
while(*p != ':' && *p != '\0') p++;
|
|
|
|
if ( *p == ':' ) {
|
|
|
|
values[i].type = grib_type_to_int(*(p+1));
|
|
|
|
if (*(p+1)=='n') values[i].type = GRIB_NAMESPACE;
|
|
|
|
*p='\0';
|
|
|
|
p++;
|
|
|
|
} else {
|
|
|
|
values[i].type = default_type;
|
|
|
|
}
|
|
|
|
if (values_required) {
|
|
|
|
if (strlen(value)==0) {
|
|
|
|
if (grib_tool)
|
|
|
|
printf("%s error: no value provided for key \"%s\"\n", grib_tool, values[i].name);
|
|
|
|
else
|
|
|
|
printf("Error: no value provided for key \"%s\"\n", values[i].name);
|
2016-06-22 17:41:15 +00:00
|
|
|
return GRIB_INVALID_ARGUMENT;
|
2013-08-01 15:52:01 +00:00
|
|
|
}
|
|
|
|
set_value(&values[i],value,equal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return GRIB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2019-01-04 16:53:35 +00:00
|
|
|
/* Return 1 if the productDefinitionTemplateNumber (GRIB2) is related to EPS */
|
2013-08-01 15:52:01 +00:00
|
|
|
int is_productDefinitionTemplateNumber_EPS(long productDefinitionTemplateNumber)
|
|
|
|
{
|
|
|
|
return (
|
2014-03-26 14:30:16 +00:00
|
|
|
productDefinitionTemplateNumber == 1 || productDefinitionTemplateNumber == 11 ||
|
|
|
|
productDefinitionTemplateNumber ==33 || productDefinitionTemplateNumber == 34 || /*simulated (synthetic) satellite data*/
|
|
|
|
productDefinitionTemplateNumber ==41 || productDefinitionTemplateNumber == 43 || /*atmospheric chemical constituents*/
|
|
|
|
productDefinitionTemplateNumber ==45 || productDefinitionTemplateNumber == 47 /*aerosols*/
|
2013-08-01 15:52:01 +00:00
|
|
|
);
|
2013-03-25 12:04:10 +00:00
|
|
|
}
|
2013-10-25 13:28:32 +00:00
|
|
|
|
2019-01-04 16:53:35 +00:00
|
|
|
/* Return 1 if the productDefinitionTemplateNumber (GRIB2) is related to atmospheric chemical constituents */
|
2013-10-25 13:28:32 +00:00
|
|
|
int is_productDefinitionTemplateNumber_Chemical(long productDefinitionTemplateNumber)
|
|
|
|
{
|
|
|
|
return (
|
2014-03-26 14:30:16 +00:00
|
|
|
productDefinitionTemplateNumber == 40 ||
|
|
|
|
productDefinitionTemplateNumber == 41 ||
|
|
|
|
productDefinitionTemplateNumber == 42 ||
|
|
|
|
productDefinitionTemplateNumber == 43);
|
2013-10-25 13:28:32 +00:00
|
|
|
}
|
|
|
|
|
2019-01-04 16:53:35 +00:00
|
|
|
/* Return 1 if the productDefinitionTemplateNumber (GRIB2) is related to
|
|
|
|
* atmospheric chemical constituents based on a distribution function */
|
2019-01-15 10:52:03 +00:00
|
|
|
int is_productDefinitionTemplateNumber_ChemicalDistFunc(long productDefinitionTemplateNumber)
|
2019-01-04 16:53:35 +00:00
|
|
|
{
|
|
|
|
return (
|
|
|
|
productDefinitionTemplateNumber == 57 ||
|
|
|
|
productDefinitionTemplateNumber == 58 ||
|
|
|
|
productDefinitionTemplateNumber == 67 ||
|
|
|
|
productDefinitionTemplateNumber == 68);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return 1 if the productDefinitionTemplateNumber (GRIB2) is related to aerosols */
|
2013-10-25 13:28:32 +00:00
|
|
|
int is_productDefinitionTemplateNumber_Aerosol(long productDefinitionTemplateNumber)
|
|
|
|
{
|
2019-01-15 10:52:03 +00:00
|
|
|
/* Note: PDT 44 is deprecated. Use 48 instead */
|
2013-10-25 13:28:32 +00:00
|
|
|
return (
|
2019-01-15 10:52:03 +00:00
|
|
|
productDefinitionTemplateNumber == 44 || productDefinitionTemplateNumber == 48 ||
|
2014-03-26 14:30:16 +00:00
|
|
|
productDefinitionTemplateNumber == 45 ||
|
|
|
|
productDefinitionTemplateNumber == 46 ||
|
|
|
|
productDefinitionTemplateNumber == 47);
|
2013-10-25 13:28:32 +00:00
|
|
|
}
|
2014-07-30 16:59:50 +00:00
|
|
|
|
2019-01-15 10:52:03 +00:00
|
|
|
/* Return 1 if the productDefinitionTemplateNumber (GRIB2) is related to
|
|
|
|
* optical properties of aerosol
|
|
|
|
*/
|
|
|
|
int is_productDefinitionTemplateNumber_AerosolOptical(long productDefinitionTemplateNumber)
|
|
|
|
{
|
|
|
|
/* Note: PDT 48 can be used for both plain aerosols as well as optical properties of aerosol.
|
|
|
|
* For the former user must set the optical wavelength range to missing.
|
|
|
|
*/
|
|
|
|
return (
|
|
|
|
productDefinitionTemplateNumber == 48 ||
|
|
|
|
productDefinitionTemplateNumber == 49);
|
|
|
|
}
|
|
|
|
|
2014-07-30 16:59:50 +00:00
|
|
|
int is_index_file(const char* filename)
|
|
|
|
{
|
|
|
|
FILE* fh;
|
|
|
|
char buf[8]={0,};
|
2015-12-03 14:35:55 +00:00
|
|
|
const char* str="GRBIDX";
|
2014-07-30 16:59:50 +00:00
|
|
|
int ret=0;
|
2018-11-27 21:11:24 +00:00
|
|
|
size_t size = 0;
|
2014-07-30 16:59:50 +00:00
|
|
|
|
|
|
|
fh=fopen(filename,"r");
|
|
|
|
if (!fh) return 0;
|
|
|
|
|
2018-11-27 21:11:24 +00:00
|
|
|
size=fread(buf,1,1,fh);
|
2019-01-11 10:04:41 +00:00
|
|
|
if (size != 1) {fclose(fh); return 0;}
|
2018-11-27 21:11:24 +00:00
|
|
|
size=fread(buf,6,1,fh);
|
2019-01-11 10:04:41 +00:00
|
|
|
if (size != 1) {fclose(fh); return 0;}
|
2014-07-30 16:59:50 +00:00
|
|
|
|
|
|
|
ret=!strcmp(buf,str);
|
|
|
|
|
|
|
|
fclose(fh);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2015-07-27 12:27:03 +00:00
|
|
|
|
2015-08-26 09:26:22 +00:00
|
|
|
char get_dir_separator_char(void)
|
2015-07-27 12:27:03 +00:00
|
|
|
{
|
|
|
|
#ifdef ECCODES_ON_WINDOWS
|
|
|
|
# define DIR_SEPARATOR_CHAR '\\'
|
|
|
|
#else
|
|
|
|
# define DIR_SEPARATOR_CHAR '/'
|
|
|
|
#endif
|
|
|
|
return DIR_SEPARATOR_CHAR;
|
|
|
|
}
|
|
|
|
|
2016-01-11 16:36:46 +00:00
|
|
|
char* codes_getenv(const char* name)
|
|
|
|
{
|
|
|
|
/* Look for the new ecCodes environment variable names */
|
|
|
|
/* if not found, then look for old grib_api ones for backward compatibility */
|
2017-07-10 12:50:57 +00:00
|
|
|
char* result = getenv(name);
|
2016-01-11 16:36:46 +00:00
|
|
|
if (result == NULL) {
|
2017-07-10 12:50:57 +00:00
|
|
|
const char* old_name = name;
|
|
|
|
|
|
|
|
/* Test the most commonly used variables first */
|
|
|
|
if (STR_EQ(name, "ECCODES_SAMPLES_PATH")) old_name="GRIB_SAMPLES_PATH";
|
|
|
|
else if (STR_EQ(name, "ECCODES_DEFINITION_PATH")) old_name="GRIB_DEFINITION_PATH";
|
|
|
|
else if (STR_EQ(name, "ECCODES_DEBUG")) old_name="GRIB_API_DEBUG";
|
|
|
|
|
|
|
|
else if (STR_EQ(name, "ECCODES_FAIL_IF_LOG_MESSAGE")) old_name="GRIB_API_FAIL_IF_LOG_MESSAGE";
|
|
|
|
else if (STR_EQ(name, "ECCODES_GRIB_WRITE_ON_FAIL")) old_name="GRIB_API_WRITE_ON_FAIL";
|
|
|
|
else if (STR_EQ(name, "ECCODES_GRIB_LARGE_CONSTANT_FIELDS")) old_name="GRIB_API_LARGE_CONSTANT_FIELDS";
|
|
|
|
else if (STR_EQ(name, "ECCODES_NO_ABORT")) old_name="GRIB_API_NO_ABORT";
|
|
|
|
else if (STR_EQ(name, "ECCODES_GRIBEX_MODE_ON")) old_name="GRIB_GRIBEX_MODE_ON";
|
|
|
|
else if (STR_EQ(name, "ECCODES_GRIB_IEEE_PACKING")) old_name="GRIB_IEEE_PACKING";
|
|
|
|
else if (STR_EQ(name, "ECCODES_IO_BUFFER_SIZE")) old_name="GRIB_API_IO_BUFFER_SIZE";
|
|
|
|
else if (STR_EQ(name, "ECCODES_LOG_STREAM")) old_name="GRIB_API_LOG_STREAM";
|
|
|
|
else if (STR_EQ(name, "ECCODES_GRIB_NO_BIG_GROUP_SPLIT")) old_name="GRIB_API_NO_BIG_GROUP_SPLIT";
|
|
|
|
else if (STR_EQ(name, "ECCODES_GRIB_NO_SPD")) old_name="GRIB_API_NO_SPD";
|
|
|
|
else if (STR_EQ(name, "ECCODES_GRIB_KEEP_MATRIX")) old_name="GRIB_API_KEEP_MATRIX";
|
|
|
|
else if (STR_EQ(name, "_ECCODES_ECMWF_TEST_DEFINITION_PATH")) old_name="_GRIB_API_ECMWF_TEST_DEFINITION_PATH";
|
|
|
|
else if (STR_EQ(name, "_ECCODES_ECMWF_TEST_SAMPLES_PATH")) old_name="_GRIB_API_ECMWF_TEST_SAMPLES_PATH";
|
|
|
|
else if (STR_EQ(name, "ECCODES_GRIB_JPEG")) old_name="GRIB_JPEG";
|
|
|
|
else if (STR_EQ(name, "ECCODES_GRIB_DUMP_JPG_FILE")) old_name="GRIB_DUMP_JPG_FILE";
|
|
|
|
else if (STR_EQ(name, "ECCODES_PRINT_MISSING")) old_name="GRIB_PRINT_MISSING";
|
|
|
|
|
2016-01-11 16:36:46 +00:00
|
|
|
result = getenv(old_name);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2018-06-21 10:33:01 +00:00
|
|
|
|
2018-06-22 10:35:16 +00:00
|
|
|
size_t sum_of_pl_array(const long* pl, size_t plsize)
|
|
|
|
{
|
|
|
|
long i, count=0;
|
|
|
|
for (i=0;i<plsize;i++) {
|
|
|
|
count += pl[i];
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
2019-10-10 17:21:05 +00:00
|
|
|
|
2019-10-11 11:42:33 +00:00
|
|
|
int grib_util_grib_data_quality_check(grib_handle* h, const double min_val, const double max_val)
|
2019-10-10 17:21:05 +00:00
|
|
|
{
|
2019-10-11 11:42:33 +00:00
|
|
|
/* TODO: The limits should depend on the paramId. For now hardcoded */
|
|
|
|
static const double MIN_FIELD_VALUE_ALLOWED = -1e8;
|
|
|
|
static const double MAX_FIELD_VALUE_ALLOWED = +1e8;
|
2019-10-10 17:21:05 +00:00
|
|
|
|
2019-10-11 11:42:33 +00:00
|
|
|
if (min_val < MIN_FIELD_VALUE_ALLOWED || max_val > MAX_FIELD_VALUE_ALLOWED) {
|
|
|
|
long paramId = 0;
|
|
|
|
if (grib_get_long(h, "paramId", ¶mId) == GRIB_SUCCESS) {
|
|
|
|
grib_context_log(h->context, GRIB_LOG_ERROR, "Parameter %ld: min/max (%g, %g) is outside limits (%g, %g)",
|
|
|
|
paramId, min_val, max_val, MIN_FIELD_VALUE_ALLOWED, MAX_FIELD_VALUE_ALLOWED);
|
2019-10-10 17:21:05 +00:00
|
|
|
}
|
|
|
|
return GRIB_OUT_OF_RANGE;
|
|
|
|
}
|
2019-10-11 11:42:33 +00:00
|
|
|
|
2019-10-10 17:21:05 +00:00
|
|
|
return GRIB_SUCCESS;
|
|
|
|
}
|