2013-03-25 12:04:10 +00:00
/*
2020-01-28 14:32:34 +00:00
* ( C ) Copyright 2005 - 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 .
*/
2013-04-03 10:45:13 +00:00
# include "grib_api_internal.h"
2013-03-25 12:04:10 +00:00
# ifdef HAVE_NETCDF
2023-06-23 16:13:23 +00:00
# include <cmath>
2013-03-25 12:04:10 +00:00
# include <stdarg.h>
# include <stdlib.h>
# include <ctype.h>
# include <time.h>
2013-06-13 10:55:09 +00:00
# include <float.h>
2013-03-25 12:04:10 +00:00
# include <netcdf.h>
# include "grib_tools.h"
2019-01-07 16:13:48 +00:00
# include "eccodes_windef.h"
# ifdef ECCODES_ON_WINDOWS
2020-01-22 13:10:59 +00:00
# include <stdint.h>
2019-01-07 16:13:48 +00:00
# endif
2013-03-25 12:04:10 +00:00
2020-07-17 14:37:57 +00:00
const char * tool_description =
2022-01-07 14:28:05 +00:00
" Convert GRIB file(s) to netCDF format. "
2020-01-22 13:10:59 +00:00
" \n \t Note: The GRIB geometry should be a regular lat/lon grid or a regular Gaussian grid "
" \n \t (the key \" typeOfGrid \" should be \" regular_ll \" or \" regular_gg \" ) " ;
2021-02-07 22:06:42 +00:00
const char * tool_name = " grib_to_netcdf " ;
2023-01-04 21:16:24 +00:00
const char * tool_online_doc = " https://confluence.ecmwf.int/display/ECC/grib_to_netcdf " ;
2022-01-07 14:28:05 +00:00
const char * tool_usage = " [options] -o output_file grib_file grib_file ... " ;
2018-08-07 14:16:50 +00:00
static char argvString [ 2048 ] = { 0 , } ;
2013-03-25 12:04:10 +00:00
/*=====================================================================*/
2020-01-22 13:10:59 +00:00
static grib_context * ctx = NULL ;
2016-04-07 13:16:02 +00:00
static double global_missing_value = 9.9692099683868690e+36 ; /* See GRIB-953 */
2013-03-25 12:04:10 +00:00
/*===============================================================================*/
/* request from mars client */
/*===============================================================================*/
2020-01-22 13:10:59 +00:00
# define NUMBER(x) (sizeof(x) / sizeof(x[0]))
2013-03-25 12:04:10 +00:00
typedef int err ;
typedef off_t file_offset ;
static int files = 0 ;
2020-01-22 13:10:59 +00:00
struct value
{
struct value * next ;
2013-07-10 16:58:41 +00:00
char * name ;
2013-03-25 12:04:10 +00:00
} ;
typedef struct value value ;
2020-01-22 13:10:59 +00:00
struct request
{
struct request * next ;
struct parameter * params ;
2013-07-10 16:58:41 +00:00
char * name ;
int order ;
2013-03-25 12:04:10 +00:00
} ;
typedef struct request request ;
/* request part */
/* language part */
2020-01-22 13:10:59 +00:00
struct parameter
{
struct parameter * next ;
struct value * values ;
2013-07-10 16:58:41 +00:00
char * name ;
int count ;
2013-03-25 12:04:10 +00:00
} ;
typedef struct parameter parameter ;
static const char * get_value ( const request * , const char * name , int n ) ;
2023-03-04 12:45:31 +00:00
static bool parsedate ( const char * name , long * julian , long * second , bool * isjul ) ;
2013-03-25 12:04:10 +00:00
2023-03-04 12:45:31 +00:00
static bool eq_string ( const char * l , const char * r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( l & & r )
2013-07-10 16:58:41 +00:00
return strcmp ( l , r ) = = 0 ;
2023-03-04 12:45:31 +00:00
return false ;
2013-03-25 12:04:10 +00:00
}
2023-03-04 12:45:31 +00:00
static bool eq_integer ( const char * l , const char * r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( l & & r )
2013-07-10 16:58:41 +00:00
return atol ( l ) = = atol ( r ) ;
2023-03-04 12:45:31 +00:00
return false ;
2013-03-25 12:04:10 +00:00
}
2023-03-04 12:45:31 +00:00
static bool eq_null ( const char * l , const char * r )
2013-03-25 12:04:10 +00:00
{
2023-03-04 12:45:31 +00:00
return true ;
2013-03-25 12:04:10 +00:00
}
2023-03-04 12:45:31 +00:00
static bool eq_coord ( const char * l , const char * r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( l & & r )
2013-07-10 16:58:41 +00:00
return strcmp ( l , r ) = = 0 ;
2023-03-04 12:45:31 +00:00
return false ;
2013-03-25 12:04:10 +00:00
}
2023-03-04 12:45:31 +00:00
static bool eq_range ( const char * l , const char * r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( l & & r )
2013-07-10 16:58:41 +00:00
return strcmp ( l , r ) = = 0 ;
2023-03-04 12:45:31 +00:00
return false ;
2013-03-25 12:04:10 +00:00
}
2023-03-04 12:45:31 +00:00
static bool eq_date ( const char * l , const char * r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( l & & r )
2013-07-10 16:58:41 +00:00
return strcmp ( l , r ) = = 0 ;
2023-03-04 12:45:31 +00:00
return false ;
2013-03-25 12:04:10 +00:00
}
2023-03-04 12:45:31 +00:00
static bool eq_param ( const char * l , const char * r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( l & & r )
2013-07-10 16:58:41 +00:00
return strcmp ( l , r ) = = 0 ;
2023-03-04 12:45:31 +00:00
return false ;
2013-03-25 12:04:10 +00:00
}
2023-03-04 12:45:31 +00:00
static bool eq_time ( const char * l , const char * r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( l & & r )
2013-07-10 16:58:41 +00:00
return strcmp ( l , r ) = = 0 ;
2023-03-04 12:45:31 +00:00
return false ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static value * new_value ( const char * name )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
value * v = ( value * ) calloc ( sizeof ( value ) , 1 ) ;
2013-07-10 16:58:41 +00:00
Assert ( v ) ;
v - > name = grib_context_strdup ( ctx , name ) ;
return v ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static parameter * find_parameter ( const request * r , const char * parname )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( ! parname )
2013-07-10 16:58:41 +00:00
return 0 ;
2020-01-22 13:10:59 +00:00
if ( r ) {
parameter * p = r - > params ;
while ( p ) {
if ( strcmp ( p - > name , parname ) = = 0 )
2013-07-10 16:58:41 +00:00
return p ;
p = p - > next ;
}
}
return NULL ;
2013-03-25 12:04:10 +00:00
}
2023-01-08 15:23:24 +00:00
static void ecc_reqmerge ( parameter * pa , const parameter * pb , request * a )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
const value * vb = pb - > values ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( strcmp ( pa - > name , pb - > name ) ! = 0 )
2013-07-10 16:58:41 +00:00
return ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
while ( vb ) {
value * va = pa - > values ;
value * last = 0 ;
const char * nb = vb - > name ;
2023-03-04 12:45:31 +00:00
bool add = true ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
while ( va ) {
if ( strcmp ( va - > name , nb ) = = 0 ) {
2023-03-04 12:45:31 +00:00
add = false ;
2013-07-10 16:58:41 +00:00
break ;
}
last = va ;
2020-01-22 13:10:59 +00:00
va = va - > next ;
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
if ( add ) {
2013-07-10 16:58:41 +00:00
value * v = new_value ( nb ) ;
2020-01-22 13:10:59 +00:00
if ( last )
2013-07-10 16:58:41 +00:00
last - > next = v ;
else
pa - > values = v ;
pa - > count = 0 ;
}
vb = vb - > next ;
}
2013-03-25 12:04:10 +00:00
}
/* Fast version if a && b same */
2023-03-04 12:45:31 +00:00
static bool ecc_reqmerge1 ( request * a , const request * b )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
parameter * pa = a - > params ;
const parameter * pb = b - > params ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
while ( pa & & pb ) {
if ( strcmp ( pa - > name , pb - > name ) ! = 0 )
2023-03-04 12:45:31 +00:00
return false ;
2013-03-25 12:04:10 +00:00
2023-01-08 15:23:24 +00:00
ecc_reqmerge ( pa , pb , a ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
pa = pa - > next ;
pb = pb - > next ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return ( pa = = NULL & & pb = = NULL ) ;
2013-03-25 12:04:10 +00:00
}
2013-07-15 13:48:32 +00:00
2020-01-22 13:10:59 +00:00
static void free_one_value ( value * p )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , p - > name ) ;
grib_context_free ( ctx , p ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void free_all_values ( value * p )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
while ( p ) {
value * q = p - > next ;
2013-07-10 16:58:41 +00:00
free_one_value ( p ) ;
p = q ;
}
2013-03-25 12:04:10 +00:00
}
2013-08-16 11:56:13 +00:00
/* Convert the first part of the string 'p' to a number (x) and set n to its length. */
/* Return the rest of the string */
2020-01-22 13:10:59 +00:00
static const char * parse1 ( const char * p , int * x , int * n )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
* x = * n = 0 ;
2020-01-22 13:10:59 +00:00
while ( * p & & isdigit ( * p ) ) {
2013-07-10 16:58:41 +00:00
( * x ) * = 10 ;
( * x ) + = * p - ' 0 ' ;
( * n ) + + ;
p + + ;
}
return p ;
2013-03-25 12:04:10 +00:00
}
2023-03-04 12:45:31 +00:00
static bool is_number ( const char * name )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
const char * p = name ;
2013-07-10 16:58:41 +00:00
int x , n ;
2020-01-22 13:10:59 +00:00
if ( p = = 0 | | * p = = 0 )
2023-03-04 12:45:31 +00:00
return false ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( * p = = ' - ' )
2013-07-10 16:58:41 +00:00
p + + ;
2020-01-22 13:10:59 +00:00
else if ( * p = = ' + ' )
2013-07-10 16:58:41 +00:00
p + + ;
p = parse1 ( p , & x , & n ) ;
2020-01-22 13:10:59 +00:00
if ( n = = 0 & & * p ! = ' . ' )
2023-03-04 12:45:31 +00:00
return false ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( * p = = ' . ' ) {
2013-07-10 16:58:41 +00:00
p + + ;
p = parse1 ( p , & x , & n ) ;
}
2020-01-22 13:10:59 +00:00
if ( * p = = ' e ' | | * p = = ' E ' ) {
2013-07-10 16:58:41 +00:00
p + + ;
2020-01-22 13:10:59 +00:00
if ( * p = = ' - ' )
2013-07-10 16:58:41 +00:00
p + + ;
2020-01-22 13:10:59 +00:00
else if ( * p = = ' + ' )
2013-07-10 16:58:41 +00:00
p + + ;
p = parse1 ( p , & x , & n ) ;
2020-01-22 13:10:59 +00:00
if ( n = = 0 )
2023-03-04 12:45:31 +00:00
return false ;
2013-07-10 16:58:41 +00:00
}
2023-03-04 12:45:31 +00:00
return * p = = 0 ? true : false ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static parameter * new_parameter ( char * name , value * v )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
parameter * p = ( parameter * ) calloc ( sizeof ( parameter ) , 1 ) ;
2013-07-10 16:58:41 +00:00
Assert ( p ) ;
2020-01-22 13:10:59 +00:00
p - > name = grib_context_strdup ( ctx , name ) ;
2013-07-10 16:58:41 +00:00
p - > values = v ;
return p ;
2013-03-25 12:04:10 +00:00
}
2023-03-04 12:45:31 +00:00
static void put_value ( request * r , const char * parname , const char * valname , bool append , bool unique , bool ascending )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
parameter * p ;
value * v ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( ! r )
2013-07-10 16:58:41 +00:00
return ;
2020-01-22 13:10:59 +00:00
if ( ( p = find_parameter ( r , parname ) ) ! = NULL ) {
if ( append ) {
2013-07-10 16:58:41 +00:00
value * a = p - > values , * b = NULL , * c = NULL ;
2020-01-22 13:10:59 +00:00
while ( a ) {
2013-07-10 16:58:41 +00:00
b = a ;
2020-01-22 13:10:59 +00:00
if ( unique ) {
if ( is_number ( a - > name ) & & is_number ( valname ) ) {
if ( atof ( a - > name ) = = atof ( valname ) )
2013-07-10 16:58:41 +00:00
return ;
}
2020-01-22 13:10:59 +00:00
else if ( strcmp ( a - > name , valname ) = = 0 )
2013-07-10 16:58:41 +00:00
return ;
}
2020-01-22 13:10:59 +00:00
if ( ascending ) {
if ( is_number ( a - > name ) ) {
if ( atof ( valname ) < atof ( a - > name ) )
2013-07-10 16:58:41 +00:00
break ;
}
2020-01-22 13:10:59 +00:00
else if ( strcmp ( valname , a - > name ) < 0 )
2013-07-10 16:58:41 +00:00
break ;
}
c = b ;
a = a - > next ;
}
v = new_value ( grib_context_strdup ( ctx , valname ) ) ;
2020-01-22 13:10:59 +00:00
if ( ascending ) {
if ( c ) {
if ( b & & b ! = c )
2013-07-10 16:58:41 +00:00
v - > next = b ;
c - > next = v ;
}
2020-01-22 13:10:59 +00:00
else {
if ( a )
2013-07-10 16:58:41 +00:00
v - > next = a ;
p - > values = v ;
}
}
2020-01-22 13:10:59 +00:00
else {
if ( b )
2013-07-10 16:58:41 +00:00
b - > next = v ;
else
p - > values = v ;
}
/* p->count++; */
p - > count = 0 ;
}
2020-01-22 13:10:59 +00:00
else {
if ( p - > values ) {
2013-07-10 16:58:41 +00:00
free_all_values ( p - > values - > next ) ;
p - > values - > next = NULL ;
/* p->count = 1; */
p - > count = 0 ;
2020-01-22 13:10:59 +00:00
if ( strcmp ( p - > values - > name , valname ) = = 0 )
2013-07-10 16:58:41 +00:00
return ;
2020-01-22 13:10:59 +00:00
else {
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , p - > values - > name ) ;
p - > values - > name = grib_context_strdup ( ctx , valname ) ;
}
}
2020-01-22 13:10:59 +00:00
else {
v = new_value ( grib_context_strdup ( ctx , valname ) ) ;
2013-07-10 16:58:41 +00:00
p - > values = v ;
/* p->count = 1; */
p - > count = 0 ;
}
}
}
2020-01-22 13:10:59 +00:00
else {
parameter * q = NULL ;
parameter * s = r - > params ;
v = new_value ( grib_context_strdup ( ctx , valname ) ) ;
p = new_parameter ( grib_context_strdup ( ctx , parname ) , v ) ;
while ( s ) {
2013-07-10 16:58:41 +00:00
q = s ;
s = s - > next ;
}
2020-01-22 13:10:59 +00:00
if ( q )
2013-07-10 16:58:41 +00:00
q - > next = p ;
else
r - > params = p ;
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void add_value ( request * r , const char * parname , const char * fmt , . . . )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
char buffer [ 1024 ] ;
va_list list ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
va_start ( list , fmt ) ;
2022-11-10 19:18:43 +00:00
vsnprintf ( buffer , sizeof ( buffer ) , fmt , list ) ;
2013-07-10 16:58:41 +00:00
va_end ( list ) ;
2013-03-25 12:04:10 +00:00
2023-03-04 12:45:31 +00:00
put_value ( r , parname , buffer , true , false , false ) ;
2013-03-25 12:04:10 +00:00
}
2023-01-08 15:23:24 +00:00
static void ecc_reqmerge2 ( request * a , const request * b )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
const parameter * pb = b - > params ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
while ( pb ) {
2013-07-10 16:58:41 +00:00
parameter * pa = find_parameter ( a , pb - > name ) ;
2020-01-22 13:10:59 +00:00
if ( pa = = NULL ) {
value * v = pb - > values ;
while ( v ) {
2023-03-04 12:45:31 +00:00
put_value ( a , pb - > name , v - > name , true , true , false ) ;
2013-07-10 16:58:41 +00:00
v = v - > next ;
}
}
2020-01-22 13:10:59 +00:00
else {
2023-01-08 15:23:24 +00:00
ecc_reqmerge ( pa , pb , a ) ;
2013-07-10 16:58:41 +00:00
}
pb = pb - > next ;
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void reqmerge ( request * a , const request * b )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( a & & b ) {
2023-01-08 15:23:24 +00:00
if ( ! ecc_reqmerge1 ( a , b ) )
ecc_reqmerge2 ( a , b ) ;
2013-07-10 16:58:41 +00:00
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void save_name ( FILE * f , const char * name , int n )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
int i = 0 , cnt = 0 ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( name = = NULL )
2013-07-10 16:58:41 +00:00
name = " (null) " ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
cnt = fprintf ( f , " %s " , name ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
for ( i = cnt ; i < n ; i + + )
2013-07-10 16:58:41 +00:00
putc ( ' ' , f ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void save_one_value ( FILE * f , value * r )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
save_name ( f , r - > name , 0 ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void save_all_values ( FILE * f , value * r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
while ( r ) {
2013-07-10 16:58:41 +00:00
save_one_value ( f , r ) ;
2020-01-22 13:10:59 +00:00
if ( r - > next )
2013-07-10 16:58:41 +00:00
putc ( ' / ' , f ) ;
r = r - > next ;
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void save_all_parameters ( FILE * f , parameter * r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
while ( r ) {
if ( r - > values ) {
2013-07-10 16:58:41 +00:00
fprintf ( f , " , \n " ) ;
save_name ( f , r - > name , 10 ) ;
fprintf ( f , " = " ) ;
save_all_values ( f , r - > values ) ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
r = r - > next ;
}
putc ( ' \n ' , f ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void save_one_request ( FILE * f , const request * r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( r ) {
2013-07-10 16:58:41 +00:00
save_name ( f , r - > name , 0 ) ;
save_all_parameters ( f , r - > params ) ;
putc ( ' \n ' , f ) ;
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void save_all_requests ( FILE * f , const request * r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
while ( r ) {
2013-07-10 16:58:41 +00:00
save_one_request ( f , r ) ;
r = r - > next ;
}
2013-03-25 12:04:10 +00:00
}
/* Not used for the moment
static void print_one_request ( const request * r )
{
2013-07-22 13:06:46 +00:00
save_one_request ( stdout , r ) ;
2013-03-25 12:04:10 +00:00
}
2013-07-10 16:58:41 +00:00
*/
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
static void print_all_requests ( const request * r )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
save_all_requests ( stdout , r ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void free_one_parameter ( parameter * p )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , p - > name ) ;
free_all_values ( p - > values ) ;
/*free_all_requests(p->interface);*/
grib_context_free ( ctx , p ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void free_all_parameters ( parameter * p )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
while ( p ) {
parameter * q = p - > next ;
2013-07-10 16:58:41 +00:00
free_one_parameter ( p ) ;
p = q ;
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void free_one_request ( request * r )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , r - > name ) ;
free_all_parameters ( r - > params ) ;
grib_context_free ( ctx , r ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void free_all_requests ( request * p )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
while ( p ) {
request * q = p - > next ;
2013-07-10 16:58:41 +00:00
free_one_request ( p ) ;
p = q ;
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void set_value ( request * r , const char * parname , const char * fmt , . . . )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
char buffer [ 10240 ] ;
va_list list ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
va_start ( list , fmt ) ;
2022-11-10 19:18:43 +00:00
vsnprintf ( buffer , sizeof ( buffer ) , fmt , list ) ;
2013-07-10 16:58:41 +00:00
va_end ( list ) ;
2013-03-25 12:04:10 +00:00
2023-03-04 12:45:31 +00:00
put_value ( r , parname , buffer , false , false , false ) ;
2013-03-25 12:04:10 +00:00
}
2013-07-15 13:48:32 +00:00
2020-01-22 13:10:59 +00:00
static err handle_to_request ( request * r , grib_handle * g )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
grib_keys_iterator * ks ;
2014-02-17 16:14:34 +00:00
char name [ 256 ] ;
char value [ 256 ] ;
2013-07-10 16:58:41 +00:00
size_t len = sizeof ( value ) ;
2020-01-22 13:10:59 +00:00
int e = 0 ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( ! g )
2013-07-10 16:58:41 +00:00
return - 1 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
/* printf("------------\n"); */
ks = grib_keys_iterator_new ( g , GRIB_KEYS_ITERATOR_ALL_KEYS , " mars " ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
while ( grib_keys_iterator_next ( ks ) ) {
2013-07-10 16:58:41 +00:00
strcpy ( name , grib_keys_iterator_get_name ( ks ) ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( ( e = grib_keys_iterator_get_string ( ks , value , & len ) ) ! = GRIB_SUCCESS )
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Cannot get %s as string %d (%s) " , name , e , grib_get_error_message ( e ) ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
set_value ( r , name , " %s " , value ) ;
len = sizeof ( value ) ;
}
2013-03-25 12:04:10 +00:00
2019-02-01 18:12:55 +00:00
strcpy ( name , " stepUnits " ) ;
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_string ( g , name , value , & len ) ) = = GRIB_SUCCESS ) {
2019-02-01 18:12:55 +00:00
set_value ( r , name , " %s " , value ) ;
2020-01-22 13:10:59 +00:00
}
else {
2020-01-20 13:20:02 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Cannot get %s as string (%s) " , name , grib_get_error_message ( e ) ) ;
2019-02-01 18:12:55 +00:00
}
2013-07-10 16:58:41 +00:00
/*
2013-07-22 13:06:46 +00:00
Assert ( grib_get_long ( g , " validityDate " , & l ) = = 0 ) ;
set_value ( r , " validityDate " , " %ld " , l ) ;
2013-03-25 12:04:10 +00:00
2013-07-22 13:06:46 +00:00
Assert ( grib_get_long ( g , " validityTime " , & l ) = = 0 ) ;
set_value ( r , " validityTime " , " %ld " , l ) ;
2013-07-10 16:58:41 +00:00
*/
len = sizeof ( value ) ;
2020-01-22 13:10:59 +00:00
if ( grib_get_string ( g , " cfVarName " , name , & len ) = = 0 ) {
if ( strcmp ( name , " unknown " ) ! = 0 ) {
2013-07-15 13:48:32 +00:00
set_value ( r , " param " , " %s " , name ) ;
}
2020-01-22 13:10:59 +00:00
else {
2013-07-15 13:48:32 +00:00
len = sizeof ( value ) ;
2020-01-22 13:10:59 +00:00
if ( grib_get_string ( g , " shortName " , name , & len ) = = 0 ) {
2013-07-15 13:48:32 +00:00
set_value ( r , " param " , " %s " , name ) ;
}
}
2013-07-10 16:58:41 +00:00
}
len = sizeof ( value ) ;
2020-01-22 13:10:59 +00:00
if ( grib_get_string ( g , " name " , name , & len ) = = 0 ) {
if ( strcmp ( name , " unknown " ) ! = 0 ) {
2013-07-10 16:58:41 +00:00
set_value ( r , " _long_name " , " %s " , name ) ;
}
}
len = sizeof ( value ) ;
2020-01-22 13:10:59 +00:00
if ( grib_get_string ( g , " units " , name , & len ) = = 0 ) {
if ( strcmp ( name , " unknown " ) ! = 0 ) {
2013-07-10 16:58:41 +00:00
set_value ( r , " _units " , " %s " , name ) ;
}
}
len = sizeof ( value ) ;
2020-01-22 13:10:59 +00:00
if ( grib_get_string ( g , " cfName " , name , & len ) = = 0 ) {
if ( strcmp ( name , " unknown " ) ! = 0 ) {
2013-07-10 16:58:41 +00:00
set_value ( r , " _cf_name " , " %s " , name ) ;
}
}
grib_keys_iterator_delete ( ks ) ;
return e ;
2013-03-25 12:04:10 +00:00
}
/*===============================================================================*/
/*===============================================================================*/
2023-03-04 12:45:31 +00:00
typedef bool ( * namecmp ) ( const char * , const char * ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
typedef struct hypercube
{
request * cube ;
request * r ;
request * iterator ;
char * set ;
2013-07-10 16:58:41 +00:00
int count ;
int size ;
int max ;
int * index_cache ;
int index_cache_size ;
2020-01-22 13:10:59 +00:00
namecmp * compare ;
2013-03-25 12:04:10 +00:00
} hypercube ;
2020-01-22 13:10:59 +00:00
typedef struct axis_t
{
const char * name ;
2013-07-10 16:58:41 +00:00
namecmp compare ;
2013-03-25 12:04:10 +00:00
} axis_t ;
/* This should be c++ ... */
2020-01-22 13:10:59 +00:00
typedef enum field_state
{
unknown ,
packed_mem ,
packed_file ,
expand_mem
2013-03-25 12:04:10 +00:00
} field_state ;
2020-01-22 13:10:59 +00:00
typedef struct
{
2013-07-10 16:58:41 +00:00
int refcnt ;
request * r ;
2013-03-25 12:04:10 +00:00
} field_request ;
/* One field .. */
2020-01-22 13:10:59 +00:00
typedef struct field
{
2013-07-10 16:58:41 +00:00
int refcnt ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
field_state shape ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
grib_handle * handle ;
double * values ;
size_t value_count ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
/* if on file */
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
file_offset offset ;
size_t length ;
2020-01-22 13:10:59 +00:00
grib_file * file ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
/* missing fields/values */
2013-03-25 12:04:10 +00:00
2023-03-04 12:45:31 +00:00
/*bool is_missing;*/ /* field is missing */
bool has_bitmap ; /* field has missing values (= bitmap) */
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
field_request * r ;
2013-03-25 12:04:10 +00:00
} field ;
2020-01-22 13:10:59 +00:00
typedef struct fieldset
{
2013-07-10 16:58:41 +00:00
int refcnt ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
/* if fields */
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
int max ;
int count ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
field * * fields ;
2013-03-25 12:04:10 +00:00
} fieldset ;
/*
# define MISSING_VALUE(n) ((n) == missing_value)
# define MISSING_FIELD(f) ((f)->missing)
# define FIELD_HAS_BITMAP(f) ((f)->bitmap)
2013-07-22 13:06:46 +00:00
# define FASTNEW(type) (type*)calloc(sizeof(type),1)
2013-03-25 12:04:10 +00:00
# define grib_context_free(ctx,x) grib_context_free(ctx,x)
*/
2020-01-22 13:10:59 +00:00
static field * get_field ( fieldset * v , int n , field_state shape ) ;
static hypercube * new_hypercube_from_mars_request ( const request * r ) ;
static void release_field ( field * g ) ;
static int count_axis ( const hypercube * h ) ;
static const char * get_axis ( const hypercube * h , int pos ) ;
static const char * get_axis ( const hypercube * h , int pos ) ;
static int cube_order ( const hypercube * h , const request * r ) ;
static void free_hypercube ( hypercube * h ) ;
2023-03-04 12:45:31 +00:00
static int ecc_cube_position ( const hypercube * h , const request * r , bool remove_holes ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
static value * clone_one_value ( const value * p )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
value * q = ( value * ) calloc ( sizeof ( value ) , 1 ) ;
2013-07-10 16:58:41 +00:00
Assert ( q ) ;
q - > next = NULL ;
q - > name = grib_context_strdup ( ctx , p - > name ) ;
return q ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static value * clone_all_values ( const value * p )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( p ) {
value * q = clone_one_value ( p ) ;
q - > next = clone_all_values ( p - > next ) ;
2013-07-10 16:58:41 +00:00
/* q->alias = cone_value(p->alias); */
return q ;
}
return NULL ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static parameter * clone_one_parameter ( const parameter * p )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
parameter * q = ( parameter * ) calloc ( sizeof ( parameter ) , 1 ) ;
2013-07-10 16:58:41 +00:00
Assert ( q ) ;
2020-01-22 13:10:59 +00:00
q - > next = NULL ;
q - > name = grib_context_strdup ( ctx , p - > name ) ;
2013-07-10 16:58:41 +00:00
q - > values = clone_all_values ( p - > values ) ;
return q ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static parameter * clone_all_parameters ( const parameter * p )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( p ) {
parameter * q = clone_one_parameter ( p ) ;
q - > next = clone_all_parameters ( p - > next ) ;
2013-07-10 16:58:41 +00:00
return q ;
}
return NULL ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static request * clone_one_request ( const request * r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( r ) {
request * p = ( request * ) calloc ( sizeof ( request ) , 1 ) ;
2013-07-10 16:58:41 +00:00
Assert ( p ) ;
p - > name = grib_context_strdup ( ctx , r - > name ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
p - > params = clone_all_parameters ( r - > params ) ;
2020-01-22 13:10:59 +00:00
p - > next = NULL ;
2013-07-10 16:58:41 +00:00
return p ;
}
return NULL ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static request * new_request ( const char * name , parameter * p )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
request * r = ( request * ) calloc ( sizeof ( request ) , 1 ) ;
2013-07-10 16:58:41 +00:00
Assert ( r ) ;
2020-01-22 13:10:59 +00:00
r - > name = grib_context_strdup ( ctx , name ) ;
2013-07-10 16:58:41 +00:00
r - > params = p ;
return r ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static request * empty_request ( const char * name )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
return new_request ( name ? name : " " , NULL ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static field_request * new_field_request ( request * r )
2013-03-25 12:04:10 +00:00
{
2014-10-02 16:23:43 +00:00
field_request * g = ( field_request * ) grib_context_malloc_clear ( ctx , sizeof ( field_request ) ) ;
2020-01-22 13:10:59 +00:00
g - > r = clone_one_request ( r ) ;
2013-07-10 16:58:41 +00:00
return g ;
2013-03-25 12:04:10 +00:00
}
static void free_field_request ( field_request * g )
{
2020-01-22 13:10:59 +00:00
if ( ! g )
2013-07-10 16:58:41 +00:00
return ;
g - > refcnt - - ;
2020-01-22 13:10:59 +00:00
if ( g - > refcnt < = 0 ) {
2013-07-10 16:58:41 +00:00
free_all_requests ( g - > r ) ;
grib_context_free ( ctx , g ) ;
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void free_field ( field * g )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( ! g )
2013-07-10 16:58:41 +00:00
return ;
g - > refcnt - - ;
2020-01-22 13:10:59 +00:00
if ( g - > refcnt < = 0 ) {
2013-07-10 16:58:41 +00:00
/*free_gribfile(g->file);*/
free_field_request ( g - > r ) ;
2020-01-22 13:10:59 +00:00
if ( g - > values )
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , g - > values ) ;
grib_handle_delete ( g - > handle ) ;
grib_context_free ( ctx , g ) ;
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void free_fieldset ( fieldset * v )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( ! v )
2013-07-10 16:58:41 +00:00
return ;
v - > refcnt - - ;
2020-01-22 13:10:59 +00:00
if ( v - > refcnt < = 0 ) {
2015-01-07 11:48:17 +00:00
int i ;
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: free_fieldset (%d fields) : " , v - > count ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < v - > count ; i + + )
2013-07-10 16:58:41 +00:00
free_field ( v - > fields [ i ] ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , v - > fields ) ;
grib_context_free ( ctx , v ) ;
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static field * new_field ( )
2013-03-25 12:04:10 +00:00
{
2014-10-02 16:23:43 +00:00
return ( field * ) grib_context_malloc_clear ( ctx , sizeof ( field ) ) ;
2013-03-25 12:04:10 +00:00
}
# define INIT_SIZE 1024
2020-01-22 13:10:59 +00:00
static void grow_fieldset ( fieldset * v , int n )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
int m = v - > count ;
int x = v - > max ;
2020-01-22 13:10:59 +00:00
if ( n < v - > count )
2013-07-10 16:58:41 +00:00
return ;
v - > count = n ;
2020-01-22 13:10:59 +00:00
while ( v - > count > = v - > max )
if ( v - > max < INIT_SIZE )
2013-07-10 16:58:41 +00:00
v - > max = INIT_SIZE ;
else
v - > max + = v - > max / 2 + 1 ;
2020-01-22 13:10:59 +00:00
if ( v - > max ! = x ) {
2015-01-07 11:48:17 +00:00
int i ;
2020-01-22 13:10:59 +00:00
if ( v - > fields = = NULL ) {
v - > fields = ( field * * ) grib_context_malloc ( ctx , sizeof ( field * ) * v - > max ) ;
2013-07-10 16:58:41 +00:00
Assert ( v - > fields ) ;
}
2020-01-22 13:10:59 +00:00
else {
field * * f = ( field * * ) grib_context_malloc ( ctx , sizeof ( field * ) * v - > max ) ;
2013-07-10 16:58:41 +00:00
Assert ( f ) ;
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < m ; i + + )
2013-07-10 16:58:41 +00:00
f [ i ] = v - > fields [ i ] ;
grib_context_free ( ctx , v - > fields ) ;
v - > fields = f ;
}
2020-01-22 13:10:59 +00:00
for ( i = m ; i < v - > max ; i + + )
2013-07-10 16:58:41 +00:00
v - > fields [ i ] = NULL ;
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static fieldset * new_fieldset ( int n )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
fieldset * f = ( fieldset * ) calloc ( sizeof ( fieldset ) , 1 ) ;
2013-07-10 16:58:41 +00:00
Assert ( f ) ;
grow_fieldset ( f , n ) ;
return f ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static field * read_field ( grib_file * file , file_offset pos , long length )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
field * g = new_field ( ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
g - > file = file ;
2013-07-10 16:58:41 +00:00
g - > offset = pos ;
g - > length = length ;
2020-01-22 13:10:59 +00:00
g - > shape = packed_file ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return g ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static err set_field ( fieldset * v , field * g , int pos )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( pos > = 0 ) {
field * h ;
2013-07-10 16:58:41 +00:00
grow_fieldset ( v , pos + 1 ) ;
2020-01-22 13:10:59 +00:00
h = v - > fields [ pos ] ;
2013-07-10 16:58:41 +00:00
v - > fields [ pos ] = g ;
g - > refcnt + + ;
2020-01-22 13:10:59 +00:00
if ( h )
2013-07-10 16:58:41 +00:00
free_field ( h ) ;
}
return 0 ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void count_parval ( parameter * p )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
int n = 0 ;
value * v = p - > values ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
while ( v ) {
2013-07-10 16:58:41 +00:00
n + + ;
v = v - > next ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
p - > count = n ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static int count_values ( const request * r , const char * parname )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
parameter * p = find_parameter ( r , parname ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( p = = NULL )
2013-07-10 16:58:41 +00:00
return 0 ;
2020-01-22 13:10:59 +00:00
if ( p - > count )
2013-07-10 16:58:41 +00:00
return p - > count ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
count_parval ( p ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return p - > count ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static const char * get_value ( const request * r , const char * parname , int nth )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
parameter * p = find_parameter ( r , parname ) ;
value * v ;
2013-07-10 16:58:41 +00:00
int i = 0 ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( p = = NULL )
2013-07-10 16:58:41 +00:00
return NULL ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( ! p - > count )
2013-07-10 16:58:41 +00:00
count_values ( r , parname ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
v = p - > values ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
while ( v ) {
if ( nth = = i + + )
2013-07-10 16:58:41 +00:00
return v - > name ;
v = v - > next ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return NULL ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static err to_packed_mem ( field * g )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( g - > shape = = packed_mem )
2013-07-10 16:58:41 +00:00
return 0 ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( g - > shape = = expand_mem ) {
if ( g - > values )
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , g - > values ) ;
2020-01-22 13:10:59 +00:00
g - > values = NULL ;
2013-07-10 16:58:41 +00:00
g - > value_count = 0 ;
2020-01-22 13:10:59 +00:00
g - > shape = packed_mem ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return 0 ;
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( g - > shape = = packed_file ) {
2013-07-10 16:58:41 +00:00
}
return 0 ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static err to_expand_mem ( field * g )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
err e = 0 ;
2013-03-25 12:04:10 +00:00
2013-08-20 12:38:53 +00:00
Assert ( g ) ;
2020-01-22 13:10:59 +00:00
if ( g - > shape = = expand_mem )
2013-07-10 16:58:41 +00:00
return 0 ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( g - > shape = = packed_file ) {
2013-07-10 16:58:41 +00:00
const void * dummy = NULL ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
grib_file * file = grib_file_open ( g - > file - > name , " r " , & e ) ;
2020-01-22 13:10:59 +00:00
if ( ! file | | ! file - > handle ) {
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR | GRIB_LOG_PERROR , " %s " , g - > file - > name ) ;
return - 1 ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
fseeko ( file - > handle , g - > offset , SEEK_SET ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
g - > handle = grib_handle_new_from_file ( ctx , file - > handle , & e ) ;
Assert ( g - > handle ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( g - > handle )
2013-07-10 16:58:41 +00:00
grib_get_message ( g - > handle , & dummy , & g - > length ) ;
2013-03-25 12:04:10 +00:00
2016-08-19 08:45:51 +00:00
grib_file_close ( file - > name , 0 , & e ) ;
2020-01-22 13:10:59 +00:00
if ( ! g - > handle )
2013-07-10 16:58:41 +00:00
return - 1 ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( g - > values )
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , g - > values ) ;
g - > values = NULL ;
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( g - > values = = NULL ) {
2013-07-10 16:58:41 +00:00
size_t count = 0 ;
2020-01-22 13:10:59 +00:00
long bitmap = 0 ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_size ( g - > handle , " values " , & g - > value_count ) ) ) {
2018-01-30 17:21:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get number of values: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
count = g - > value_count ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( ( e = grib_set_double ( g - > handle , " missingValue " , global_missing_value ) ) ) {
2018-01-30 17:21:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot set missingValue: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
g - > values = ( double * ) grib_context_malloc ( ctx , sizeof ( double ) * g - > value_count ) ;
if ( ( e = grib_get_double_array ( g - > handle , " values " , g - > values , & count ) ) ) {
2018-01-30 17:21:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot decode values: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( count ! = g - > value_count )
2020-10-13 13:05:50 +00:00
grib_context_log ( ctx , GRIB_LOG_FATAL , " ecCodes: value count mismatch %ld %ld " , count , g - > value_count ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_long ( g - > handle , " missingValuesPresent " , & bitmap ) ) ) {
2018-01-30 17:21:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get missingValuesPresent: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
2013-03-25 12:04:10 +00:00
2016-04-07 13:16:02 +00:00
g - > has_bitmap = ( bitmap ! = 0 ) ;
2013-03-25 12:04:10 +00:00
# ifdef COMEBACK
2013-07-10 16:58:41 +00:00
set g - > missing
2013-03-25 12:04:10 +00:00
# endif
2013-07-10 16:58:41 +00:00
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
g - > shape = expand_mem ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return e ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void set_field_state ( field * g , field_state shape )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
switch ( shape ) {
case expand_mem :
to_expand_mem ( g ) ;
break ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
case packed_mem :
to_packed_mem ( g ) ;
break ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
case packed_file :
release_field ( g ) ;
break ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
default :
grib_context_log ( ctx , GRIB_LOG_FATAL , " Internal error %s %d " , __FILE__ , __LINE__ ) ;
break ;
2013-07-10 16:58:41 +00:00
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static field * get_field ( fieldset * v , int n , field_state shape )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
field * g = v - > fields [ n ] ;
2013-07-10 16:58:41 +00:00
set_field_state ( g , shape ) ;
return g ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void release_field ( field * g )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( g - > file ) {
if ( g - > values )
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , g - > values ) ;
g - > values = NULL ;
2020-01-22 13:10:59 +00:00
g - > shape = packed_file ;
2013-07-10 16:58:41 +00:00
grib_handle_delete ( g - > handle ) ;
g - > handle = NULL ;
}
2013-03-25 12:04:10 +00:00
}
static request * field_to_request ( field * f )
{
2020-01-22 13:10:59 +00:00
if ( f - > r = = 0 ) {
2013-07-10 16:58:41 +00:00
field_state state = f - > shape ;
2020-01-22 13:10:59 +00:00
request * r = empty_request (
2013-03-25 12:04:10 +00:00
# ifdef COMEBACK
2020-01-22 13:10:59 +00:00
( ( f - > ksec1 = = NULL ) | | ( f - > ksec1 [ 2 ] ! = mars . computeflg ) ) ? " GRIB " : " COMPUTED " ) ;
2013-03-25 12:04:10 +00:00
# else
2020-01-22 13:10:59 +00:00
" GRIB " ) ;
2013-03-25 12:04:10 +00:00
# endif
2013-07-10 16:58:41 +00:00
set_field_state ( f , packed_mem ) ;
handle_to_request ( r , f - > handle ) ;
set_field_state ( f , state ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
f - > r = new_field_request ( r ) ;
free_all_requests ( r ) ;
}
return f - > r - > r ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static request * fieldset_to_request ( fieldset * fs )
2013-08-19 16:12:09 +00:00
{
int i ;
request * r = empty_request ( " GRIB " ) ;
2020-03-19 16:01:10 +00:00
if ( ! fs ) {
free_one_request ( r ) ;
2013-08-19 16:12:09 +00:00
return 0 ;
2020-03-19 16:01:10 +00:00
}
2013-08-19 16:12:09 +00:00
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < fs - > count ; i + + ) {
request * s = field_to_request ( fs - > fields [ i ] ) ;
reqmerge ( r , s ) ;
2013-08-19 16:12:09 +00:00
}
return r ;
}
2013-03-25 12:04:10 +00:00
/*===============================================================================*/
/* hypercube from mars client */
/*===============================================================================*/
2023-03-04 12:45:31 +00:00
static bool eq_string ( const char * , const char * ) ;
static bool eq_integer ( const char * , const char * ) ;
static bool eq_range ( const char * , const char * ) ;
static bool eq_param ( const char * , const char * ) ;
static bool eq_coord ( const char * , const char * ) ;
static bool eq_date ( const char * , const char * ) ;
static bool eq_time ( const char * , const char * ) ;
static bool eq_null ( const char * , const char * ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
static axis_t global_axis [ ] = {
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
/* From dhsbase.c 'check_grib' */
{
" class " ,
eq_string ,
} ,
{
" type " ,
eq_string ,
} ,
{
" stream " ,
eq_string ,
} ,
{
" levtype " ,
eq_string ,
} ,
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
{
" origin " ,
eq_string ,
} ,
{
" product " ,
eq_string ,
} ,
{
" section " ,
eq_string ,
} ,
{
" method " ,
eq_integer ,
} ,
{
" system " ,
eq_integer ,
} ,
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
/* testing */
/* {"repres", eq_null, }, */
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
/* from field order */
{
" date " ,
eq_date ,
} ,
{
" refdate " ,
eq_date ,
} ,
{
" hdate " ,
eq_date ,
} ,
{
" time " ,
eq_time ,
} ,
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
{
" reference " ,
eq_range ,
} ,
{
" step " ,
eq_range ,
} ,
{
" fcmonth " ,
eq_integer ,
} ,
{
" fcperiod " ,
eq_range ,
} ,
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
{
" leadtime " ,
eq_range ,
} ,
{
" opttime " ,
eq_range ,
} ,
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
{
" expver " ,
eq_string ,
} ,
{
" domain " ,
eq_string ,
} ,
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
{
" diagnostic " ,
eq_integer ,
} ,
{
" iteration " ,
eq_integer ,
} ,
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
{
" quantile " ,
eq_range ,
} ,
{
" number " ,
eq_integer ,
} ,
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
{
" levelist " ,
eq_coord ,
} ,
{
" latitude " ,
eq_coord ,
} ,
{
" longitude " ,
eq_coord ,
} ,
{
" range " ,
eq_range ,
} ,
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
{
" param " ,
eq_param ,
} ,
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
{
" ident " ,
eq_integer ,
} ,
{
" obstype " ,
eq_integer ,
} ,
{
" instrument " ,
eq_integer ,
} ,
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
{
" frequency " ,
eq_integer ,
} ,
{
" direction " ,
eq_integer ,
} ,
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
{
" channel " ,
eq_integer ,
} ,
} ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
static int axisindex ( const char * name )
2013-03-25 12:04:10 +00:00
{
2023-03-04 12:45:31 +00:00
size_t i = 0 ;
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < NUMBER ( global_axis ) ; i + + ) {
2023-10-30 16:35:53 +00:00
if ( STR_EQUAL ( name , global_axis [ i ] . name ) ) {
return ( int ) i ;
}
2013-07-10 16:58:41 +00:00
}
return - 1 ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static namecmp comparator ( const char * name )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
static char * dontcompare = NULL ;
2023-03-04 12:45:31 +00:00
static bool first = 1 ;
2020-01-22 13:10:59 +00:00
int i = 0 ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( first ) {
2013-07-10 16:58:41 +00:00
dontcompare = getenv ( " MARS_DONT_CHECK " ) ;
2023-03-04 12:45:31 +00:00
first = false ;
2013-07-10 16:58:41 +00:00
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( dontcompare ! = NULL ) {
2023-10-30 16:35:53 +00:00
if ( STR_EQUAL ( dontcompare , name ) )
2013-07-10 16:58:41 +00:00
return eq_null ;
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( ( i = axisindex ( name ) ) ! = - 1 )
2013-08-13 10:03:31 +00:00
return global_axis [ i ] . compare ;
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " No comparator for %s " , name ) ;
return eq_string ;
2013-03-25 12:04:10 +00:00
}
/********************/
/* index accessors */
/********************/
2020-01-22 13:10:59 +00:00
static int count_index ( const hypercube * h )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
int i = 0 , n = 0 ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < h - > size ; + + i )
2013-07-10 16:58:41 +00:00
n + = h - > set [ i ] ;
return n ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static int count_holes ( const hypercube * h , int cnt )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
int i = 0 , n = 0 ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < cnt ; + + i )
2013-07-10 16:58:41 +00:00
n + = h - > set [ i ] ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return ( n = = cnt ) ? 0 : ( cnt - n ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void reset_index ( hypercube * h , int v )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
memset ( h - > set , v , h - > size ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void set_index ( hypercube * h , int index , int value )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( index < 0 | | index > = h - > count ) {
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal error, bad hypercube index %d " , index ) ;
exit ( 1 ) ;
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( index > = h - > max ) {
2013-07-10 16:58:41 +00:00
int old = h - > max ;
2020-01-22 13:10:59 +00:00
while ( index > = h - > max )
2013-07-10 16:58:41 +00:00
h - > max + = 4096 ;
2013-03-25 12:04:10 +00:00
2014-10-02 16:23:43 +00:00
h - > set = h - > set ? ( char * ) grib_context_realloc ( ctx , h - > set , h - > max ) : ( char * ) grib_context_malloc ( ctx , h - > max ) ;
2013-07-10 16:58:41 +00:00
Assert ( h - > set ) ;
memset ( h - > set + old , 0 , h - > max - old ) ;
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( index > = h - > size )
2013-07-10 16:58:41 +00:00
h - > size = index + 1 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
h - > set [ index ] = value ;
2013-03-25 12:04:10 +00:00
}
/**************************/
/* End of index accessors */
/**************************/
/*******************/
/* axis accessors */
/*******************/
2020-01-22 13:10:59 +00:00
static int count_axis ( const hypercube * h )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( h & & h - > cube )
2013-07-10 16:58:41 +00:00
return count_values ( h - > cube , " axis " ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return - 1 ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static const char * get_axis ( const hypercube * h , int pos )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
const char * axis = NULL ;
if ( pos < count_axis ( h ) ) {
2013-07-10 16:58:41 +00:00
axis = get_value ( h - > cube , " axis " , pos ) ;
}
return axis ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void add_axis ( hypercube * h , const char * axis )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
add_value ( h - > cube , " axis " , " %s " , axis ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void unset_value ( request * r , const char * parname )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
parameter * p , * q = NULL ;
2020-01-22 13:10:59 +00:00
if ( ! r )
2013-07-10 16:58:41 +00:00
return ;
p = r - > params ;
2020-01-22 13:10:59 +00:00
while ( p ) {
2023-10-30 16:35:53 +00:00
if ( STR_EQUAL ( parname , p - > name ) ) {
2020-01-22 13:10:59 +00:00
if ( q )
2013-07-10 16:58:41 +00:00
q - > next = p - > next ;
else
r - > params = p - > next ;
free_one_parameter ( p ) ;
return ;
}
q = p ;
p = p - > next ;
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void reset_axis ( hypercube * h )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
unset_value ( h - > cube , " axis " ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void valcpy ( request * a , request * b , char * aname , char * bname )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
parameter * p ;
if ( a & & b & & ( p = find_parameter ( b , bname ) ) ) {
2023-03-04 12:45:31 +00:00
bool z = false ;
2020-01-22 13:10:59 +00:00
value * v = p - > values ;
while ( v ) {
2023-03-04 12:45:31 +00:00
put_value ( a , aname , v - > name , z , false , false ) ;
z = true ;
2013-07-10 16:58:41 +00:00
v = v - > next ;
}
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void cube_values ( hypercube * h , const char * p )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
valcpy ( h - > cube , h - > r , ( char * ) p , ( char * ) p ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static int count_dimensions ( const hypercube * , const char * ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
static int set_axis ( hypercube * h )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
int i = 0 ;
2013-07-10 16:58:41 +00:00
int count = ( h & & h - > r ) ? 1 : - 1 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
reset_axis ( h ) ;
2020-01-22 13:10:59 +00:00
for ( i = ( NUMBER ( global_axis ) - 1 ) ; i > = 0 ; - - i ) {
2013-08-13 10:03:31 +00:00
int n = count_dimensions ( h , global_axis [ i ] . name ) ;
2020-01-22 13:10:59 +00:00
if ( n > 1 ) {
2013-08-13 10:03:31 +00:00
add_axis ( h , global_axis [ i ] . name ) ;
cube_values ( h , global_axis [ i ] . name ) ;
2013-07-10 16:58:41 +00:00
count * = n ;
}
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return count ;
2013-03-25 12:04:10 +00:00
}
/*************************/
/* End of axis accessors */
/*************************/
/*******************/
/* Cube dimensions */
/*******************/
2020-01-22 13:10:59 +00:00
static int count_dimensions ( const hypercube * h , const char * axis )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
int dims = - 1 ;
2020-01-22 13:10:59 +00:00
if ( h & & h - > r )
2013-07-10 16:58:41 +00:00
dims = count_values ( h - > r , axis ) ;
return dims ;
2013-03-25 12:04:10 +00:00
}
/**************************/
/* End of cube dimensions */
/**************************/
/**************************/
/* Auxiliary functions */
/**************************/
2020-01-22 13:10:59 +00:00
static int count_hypercube ( const request * r )
2013-03-25 12:04:10 +00:00
{
2023-03-04 12:45:31 +00:00
int count = 1 ;
size_t i = 0 ;
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < NUMBER ( global_axis ) ; + + i ) {
2013-08-13 10:03:31 +00:00
int c = count_values ( r , global_axis [ i ] . name ) ;
2013-07-10 16:58:41 +00:00
count * = c ? c : 1 ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return count ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static int cube_order ( const hypercube * h , const request * r )
2013-03-25 12:04:10 +00:00
{
2023-03-04 12:45:31 +00:00
return ecc_cube_position ( h , r , true ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static int cube_position ( const hypercube * h , const request * r )
2013-03-25 12:04:10 +00:00
{
2023-03-04 12:45:31 +00:00
return ecc_cube_position ( h , r , false ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void reserve_index_cache ( hypercube * h , int size )
2013-03-25 12:04:10 +00:00
{
2023-03-06 20:50:11 +00:00
if ( size < = 0 )
2013-07-10 16:58:41 +00:00
return ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( h - > index_cache ! = 0 )
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , h - > index_cache ) ;
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: Allocating hypercube index_cache: %d entries " , size ) ;
2014-10-02 16:23:43 +00:00
h - > index_cache = ( int * ) calloc ( sizeof ( int ) , size ) ;
2013-07-10 16:58:41 +00:00
Assert ( h - > index_cache ) ;
h - > index_cache_size = size ;
2013-03-25 12:04:10 +00:00
}
2023-03-04 12:45:31 +00:00
static int ecc_cube_position ( const hypercube * h , const request * r , bool remove_holes )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
request * cube = h - > cube ;
int c = count_axis ( h ) ;
int index = 0 ;
int i = 0 ;
int n = 1 ;
int ok = 0 ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( h - > index_cache = = 0 | | h - > index_cache_size ! = c )
reserve_index_cache ( ( hypercube * ) h , c ) ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < c ; + + i ) {
const char * axis = get_axis ( h , i ) ;
const char * v = get_value ( r , axis , 0 ) ;
const char * w = NULL ;
int dims = count_dimensions ( h , axis ) ;
int k = 0 ;
int count = count_values ( cube , axis ) ;
int last = h - > index_cache [ i ] ;
for ( k = 0 ; k < count ; k + + ) {
2013-07-10 16:58:41 +00:00
int j = ( k + last ) % count ;
2020-01-22 13:10:59 +00:00
w = get_value ( cube , axis , j ) ;
if ( h - > compare ? h - > compare [ i ] ( w , v ) : ( strcmp ( w , v ) = = 0 ) ) {
2013-07-10 16:58:41 +00:00
index + = j * n ;
n * = dims ;
ok + + ;
2020-01-22 13:10:59 +00:00
( ( hypercube * ) h ) - > index_cache [ i ] = j ;
2013-07-10 16:58:41 +00:00
break ;
}
else
2023-01-08 15:23:24 +00:00
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: ecc_cube_position, %s, %s != %s [%scompare function available] " , axis , w , v , h - > compare ? " " : " no " ) ;
2013-07-10 16:58:41 +00:00
}
}
2020-01-22 13:10:59 +00:00
if ( remove_holes ) {
2013-07-10 16:58:41 +00:00
int holes = 0 ;
2020-01-22 13:10:59 +00:00
if ( count_index ( h ) ! = h - > size )
2013-07-10 16:58:41 +00:00
holes = count_holes ( h , index ) ;
index - = holes ;
}
return ( ok = = c ) ? index : - 1 ;
2013-03-25 12:04:10 +00:00
}
2015-07-22 16:59:31 +00:00
static void cube_indexes (
2020-01-22 13:10:59 +00:00
const hypercube * h , request * r ,
char * * times_array , size_t times_array_size ,
int * indexes , int size )
{
request * cube = h - > cube ;
int c = count_axis ( h ) ;
int i = 0 ;
int index = 0 ;
int n = 1 ;
if ( size < c ) {
2013-10-01 09:19:35 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal error in cube_indexes. size=%d < axis=%d " , size , c ) ;
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
if ( h - > index_cache = = 0 | | h - > index_cache_size ! = c )
reserve_index_cache ( ( hypercube * ) h , c ) ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < c ; + + i ) {
const char * axis = get_axis ( h , i ) ;
const char * v = get_value ( r , axis , 0 ) ;
const char * w = NULL ;
int dims = count_dimensions ( h , axis ) ;
int j = 0 ;
int k = 0 ;
int count = count_values ( cube , axis ) ;
int last = h - > index_cache [ i ] ;
2023-10-30 16:35:53 +00:00
const bool is_time_axis = ( STR_EQUAL ( axis , " time " ) ) ;
2015-07-22 16:59:31 +00:00
if ( is_time_axis ) {
Assert ( times_array ) ;
Assert ( times_array_size = = count ) ;
}
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
for ( k = 0 ; k < count ; k + + ) {
2013-07-10 16:58:41 +00:00
j = ( k + last ) % count ;
2015-07-22 16:59:31 +00:00
if ( is_time_axis ) {
/* GRIB-792: use fast lookup */
2020-01-22 13:10:59 +00:00
Assert ( j > = 0 & & j < times_array_size ) ;
2015-07-22 16:59:31 +00:00
w = times_array [ j ] ;
/* For testing:
* Assert ( strcmp ( w , get_value ( cube , axis , j ) ) = = 0 ) ;
* */
}
else {
/* slow access method */
w = get_value ( cube , axis , j ) ;
}
2020-01-22 13:10:59 +00:00
if ( h - > compare ? h - > compare [ i ] ( w , v ) : ( w = = v ) ) {
2013-07-10 16:58:41 +00:00
index + = j * n ;
n * = dims ;
2020-01-22 13:10:59 +00:00
( ( hypercube * ) h ) - > index_cache [ i ] = j ;
2013-07-10 16:58:41 +00:00
break ;
}
}
indexes [ i ] = j ;
}
2022-10-28 12:24:17 +00:00
( void ) index ;
2013-03-25 12:04:10 +00:00
}
/*********************************/
/* End of Auxiliary functions */
/*********************************/
2020-01-22 13:10:59 +00:00
static hypercube * new_hypercube ( const request * r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
hypercube * h = ( hypercube * ) calloc ( sizeof ( hypercube ) , 1 ) ;
2013-07-10 16:58:41 +00:00
int total = 0 , count = 0 ;
2023-03-04 12:45:31 +00:00
size_t n = 0 ;
2020-01-22 13:10:59 +00:00
const char * val = 0 ;
2017-02-02 18:29:06 +00:00
Assert ( h ) ;
2020-01-22 13:10:59 +00:00
h - > r = clone_one_request ( r ) ;
2013-07-10 16:58:41 +00:00
h - > cube = empty_request ( " CUBE " ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
h - > count = total = count_hypercube ( r ) ;
2020-01-22 13:10:59 +00:00
count = set_axis ( h ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
h - > compare = 0 ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( ( total ! = count ) | | ( count = = 0 ) ) {
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal error while computing hypercube fields " ) ;
grib_context_log ( ctx , GRIB_LOG_ERROR , " Number of fields in request %d " , total ) ;
grib_context_log ( ctx , GRIB_LOG_ERROR , " Number of fields in hypercube %d " , count ) ;
}
set_index ( h , count - 1 , 1 ) ;
memset ( h - > set , 1 , count ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
/* This is expensive, but makes the iterator with only
2013-07-22 13:06:46 +00:00
those parameters found as axis */
2013-07-10 16:58:41 +00:00
h - > iterator = empty_request ( 0 ) ;
2020-01-22 13:10:59 +00:00
for ( n = 0 ; n < NUMBER ( global_axis ) ; + + n )
if ( ( val = get_value ( h - > r , global_axis [ n ] . name , 0 ) ) ! = NULL )
2013-08-13 10:03:31 +00:00
set_value ( h - > iterator , global_axis [ n ] . name , val ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return h ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void print_hypercube ( const hypercube * h )
2013-03-25 12:04:10 +00:00
{
2020-03-20 12:10:48 +00:00
Assert ( h ) ;
if ( ! h ) return ;
2013-07-10 16:58:41 +00:00
print_all_requests ( h - > r ) ;
print_all_requests ( h - > cube ) ;
grib_context_log ( ctx , GRIB_LOG_INFO , " %d active out of %d fields described \n " , count_index ( h ) , h - > size ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void free_hypercube ( hypercube * h )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
free_all_requests ( h - > r ) ;
free_all_requests ( h - > cube ) ;
free_all_requests ( h - > iterator ) ;
grib_context_free ( ctx , h - > index_cache ) ;
grib_context_free ( ctx , h - > compare ) ;
grib_context_free ( ctx , h - > set ) ;
grib_context_free ( ctx , h ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
struct stuff_1
{
hypercube * c ;
request * r ;
2013-03-25 12:04:10 +00:00
} ;
2020-01-22 13:10:59 +00:00
static void reqcb_1 ( const request * r , int count , axis_t * names , char * vals [ ] , void * data )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
struct stuff_1 * s = ( struct stuff_1 * ) data ;
2013-07-10 16:58:41 +00:00
int i ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < count ; i + + )
if ( vals [ i ] )
2013-07-10 16:58:41 +00:00
set_value ( s - > r , names [ i ] . name , vals [ i ] ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
set_index ( s - > c , cube_position ( s - > c , s - > r ) , 1 ) ;
2013-03-25 12:04:10 +00:00
}
typedef void ( * loopproc ) ( const request * , int , axis_t * , char * * , void * ) ;
2020-01-22 13:10:59 +00:00
static void names_loop ( const request * r , loopproc proc , void * data ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
static hypercube * new_hypercube_from_mars_request ( const request * r )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
int i ;
int n ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
struct stuff_1 s ;
2013-03-25 12:04:10 +00:00
2023-06-25 15:01:22 +00:00
// const request *lang = mars_language_from_request(r);
// int count = 0;
// count = init_axis(lang);
// grib_context_log(ctx,GRIB_LOG_DEBUG,"cube %s",r->kind);
// /* print_all_requests(mars_language_from_request(r)); */
// grib_context_log(ctx,GRIB_LOG_INFO,"NUMBER(axis): %d, number axisnew: %d",NUMBER(axis),count);
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
s . c = new_hypercube ( r ) ;
s . r = clone_one_request ( r ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
reset_index ( s . c , 0 ) ;
names_loop ( r , reqcb_1 , & s ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
free_one_request ( s . r ) ;
2013-03-25 12:04:10 +00:00
2013-08-15 15:08:19 +00:00
/* add single parameters */
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < NUMBER ( global_axis ) ; i + + ) {
2013-08-13 10:03:31 +00:00
int m = count_values ( r , global_axis [ i ] . name ) ;
2020-01-22 13:10:59 +00:00
if ( m = = 1 ) {
2013-08-13 10:03:31 +00:00
add_value ( s . c - > cube , " axis " , global_axis [ i ] . name ) ;
set_value ( s . c - > cube , global_axis [ i ] . name , get_value ( r , global_axis [ i ] . name , 0 ) ) ;
2013-07-10 16:58:41 +00:00
}
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
n = count_values ( s . c - > cube , " axis " ) ;
2020-01-22 13:10:59 +00:00
if ( n ) {
2014-10-02 16:23:43 +00:00
s . c - > compare = ( namecmp * ) calloc ( sizeof ( namecmp ) , n ) ;
2017-02-02 18:29:06 +00:00
Assert ( s . c - > compare ) ;
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < n ; i + + )
2013-07-10 16:58:41 +00:00
s . c - > compare [ i ] = comparator ( get_value ( s . c - > cube , " axis " , i ) ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return s . c ;
2013-03-25 12:04:10 +00:00
}
/* This one doesn't have single parameters in CUBE */
2020-01-22 13:10:59 +00:00
static hypercube * new_simple_hypercube_from_mars_request ( const request * r )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
int i ;
int n ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
struct stuff_1 s ;
s . c = new_hypercube ( r ) ;
s . r = clone_one_request ( r ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
reset_index ( s . c , 0 ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
names_loop ( r , reqcb_1 , & s ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
free_one_request ( s . r ) ;
n = count_values ( s . c - > cube , " axis " ) ;
2020-01-22 13:10:59 +00:00
if ( n ) {
2014-10-02 16:23:43 +00:00
s . c - > compare = ( namecmp * ) calloc ( sizeof ( namecmp ) , n ) ;
2017-02-02 18:29:06 +00:00
Assert ( s . c - > compare ) ;
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < n ; i + + )
2013-07-10 16:58:41 +00:00
s . c - > compare [ i ] = comparator ( get_value ( s . c - > cube , " axis " , i ) ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return s . c ;
2013-03-25 12:04:10 +00:00
}
/*===========================================================================================*/
/*===========================================================================================*/
2019-08-05 10:32:41 +00:00
/* TODO:
2013-03-25 12:04:10 +00:00
- Print usage in log file
2015-04-07 15:52:13 +00:00
- consider FCMONTH and Climatology
2013-03-25 12:04:10 +00:00
- Build logic to create validationtime when only one of DATE or TIME or STEP have multiple values :
for example : date = - 1 , time = 12 , step = 24 / 48
- parametrise the type of data for each axis ( function fill_netcdf_dimensions & define_netcdf_dimensions )
Now , all are INT but TIME could be float
- allow user specified scale_factor
- insert ' user input request '
- ORIGIN
- Monthly means seem not to ignore STEP ( data server , era40 , eg retrieve 39 / 142 )
*/
2020-01-22 13:10:59 +00:00
typedef struct ncatt
{
2013-07-10 16:58:41 +00:00
char name [ 1024 ] ;
2020-01-22 13:10:59 +00:00
char * long_name ;
char * units ;
char * short_name ;
char * standard_name ;
request * metadata ;
2013-07-10 16:58:41 +00:00
nc_type nctype ;
2013-03-25 12:04:10 +00:00
} ncatt_t ;
2023-01-06 19:52:58 +00:00
typedef struct filter_type
2020-01-22 13:10:59 +00:00
{
fieldset * fset ;
hypercube * filter ;
2013-07-10 16:58:41 +00:00
int count ;
double scale_factor ;
double add_offset ;
double missing ;
2023-03-04 12:45:31 +00:00
bool bitmap ;
2013-07-10 16:58:41 +00:00
ncatt_t att ;
2020-01-22 13:10:59 +00:00
request * filter_request ;
2023-03-04 12:45:31 +00:00
bool scale ;
2013-03-25 12:04:10 +00:00
} dataset_t ;
2019-09-05 10:48:44 +00:00
/*
* typedef struct ncfile {
* dataset_t * filters ;
* int ncid ;
* } ncfile_t ;
*/
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
typedef struct ncoptions
{
2023-03-04 12:45:31 +00:00
bool usevalidtime ; /* Whether to use valid TIME only or not */
bool auto_refdate ; /* Automatic Reference Date */
2020-01-22 13:10:59 +00:00
long refdate ; /* Reference date */
const char * version ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
char * title ;
char * history ;
char * unlimited ;
2023-03-04 12:45:31 +00:00
bool checkvalidtime ;
2020-01-22 13:10:59 +00:00
request * mars_description ;
2023-03-04 12:45:31 +00:00
bool mmeans ; /* Whether this dataset is Monthly Means */
bool climatology ; /* Whether this dataset is climatology */
bool shuffle ;
2017-07-16 11:22:52 +00:00
long deflate ;
2013-03-25 12:04:10 +00:00
} ncoptions_t ;
ncoptions_t setup ;
# define NC_TYPES 7
2020-01-22 13:10:59 +00:00
struct nc_types_values
{
2016-04-07 13:16:02 +00:00
double nc_type_max ;
double nc_type_min ;
double nc_type_missing ;
2020-01-22 13:10:59 +00:00
} nc_type_values [ NC_TYPES ] = {
/* In some occasions, SHRT_MIN-2 for the minimum value, makes ncview display
2013-03-25 12:04:10 +00:00
missing values for - 32766 , while NC_FILL_SHORT = - 32767 , and SHRT_MIN = - 32768 */
2020-01-22 13:10:59 +00:00
{ 0 , 0 , 0 } , /* NC_NAT, 'Not A Type' (c.f. NaN) */
{ 0x7f , NC_FILL_BYTE + 1 , NC_FILL_BYTE } , /* NC_BYTE, signed 1 byte integer */
{ 0xff , NC_FILL_CHAR + 1 , NC_FILL_CHAR } , /* NC_CHAR, ISO/ASCII character */
{ 0x7fff , NC_FILL_SHORT + 1 , NC_FILL_SHORT } , /* NC_SHORT, signed 2 byte integer */
{ 0x7ffffff , NC_FILL_INT + 1 , NC_FILL_INT } , /* NC_INT, signed 4 byte integer */
{ FLT_MAX , - FLT_MAX , NC_FILL_FLOAT } , /* NC_FLOAT, single precision floating point number */
{ DBL_MAX , - DBL_MAX , NC_FILL_DOUBLE } , /* NC_DOUBLE, double precision floating point number */
2013-03-25 12:04:10 +00:00
} ;
static long fcmonth2days ( long date , long months )
{
2013-07-10 16:58:41 +00:00
long julianfrom = grib_date_to_julian ( date ) ;
2020-01-22 13:10:59 +00:00
long years = ( long ) ( months / 12 ) ;
long leap = ( long ) ( years / 4 ) - ( long ) ( years / 100 ) ;
long to = years * 365 + ( months % 12 ) * 32 + 1 + leap ; /* FCMONTH can't be > 28 */
long julianto = julianfrom + to ;
long days = 0 ;
long dd = date % 100 ;
long dateto = grib_julian_to_date ( julianto ) ;
2013-07-10 16:58:41 +00:00
long nextdate = ( dateto / 100 ) * 100 + dd ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
julianto = grib_date_to_julian ( nextdate ) ;
2020-01-22 13:10:59 +00:00
days = julianto - julianfrom ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: date: %ld + %ld months = %ld days " , date , months , days ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return days ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static long request_fields ( request * r )
2013-08-19 16:12:09 +00:00
{
2020-01-22 13:10:59 +00:00
long cnt = 1 ;
parameter * p = r - > params ;
while ( p ) {
if ( p - > name [ 0 ] ! = ' _ ' ) {
cnt * = count_values ( r , p - > name ) ;
2013-08-19 16:12:09 +00:00
}
p = p - > next ;
}
return cnt ;
}
2013-03-25 12:04:10 +00:00
/* Transform MARS FCMONTHs into number of months from base date.
For example , FCMONTH = 1 is current month = = 0 */
2020-01-22 13:10:59 +00:00
static void fcmonth2nbmonths ( request * r )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
long n = count_values ( r , " fcmonth " ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( n = = 0 )
2013-07-10 16:58:41 +00:00
return ;
n = atol ( get_value ( r , " fcmonth " , 0 ) ) ;
set_value ( r , " fcmonth " , " %ld " , n - 1 ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static long monthnumber ( const char * m )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
const char * months [ ] = { " JAN " , " FEB " , " MAR " , " APR " , " MAY " , " JUN " , " JUL " , " AUG " , " SEP " , " OCT " , " NOV " , " DEC " } ;
int i = 0 ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
while ( i < 12 )
if ( strcmp ( m , months [ i + + ] ) = = 0 )
2013-07-10 16:58:41 +00:00
return i ;
grib_context_log ( ctx , GRIB_LOG_ERROR , " Error. Translation for MONTH='%s' not found " , m ) ;
return - 1 ;
2013-03-25 12:04:10 +00:00
}
2023-01-08 15:23:24 +00:00
static int check_stepUnits ( const char * step_units_str )
2019-02-01 19:52:30 +00:00
{
/* Only hours, minutes and seconds supported */
2023-10-30 16:35:53 +00:00
if ( STR_EQUAL ( step_units_str , " h " ) | |
STR_EQUAL ( step_units_str , " m " ) | |
STR_EQUAL ( step_units_str , " s " ) ) {
2019-02-01 19:52:30 +00:00
return GRIB_SUCCESS ;
}
return GRIB_WRONG_STEP_UNIT ;
}
2013-03-25 12:04:10 +00:00
/* The argument represents 1 field */
2020-01-22 13:10:59 +00:00
static void validation_time ( request * r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
long date = 0 ;
long time = 0 ;
double step = 0 ;
2013-07-10 16:58:41 +00:00
long fcmonthdays = 0 ;
2020-01-22 13:10:59 +00:00
long fcmonth = 0 ;
2013-07-10 16:58:41 +00:00
double v ;
2020-01-22 13:10:59 +00:00
long julian = 0 ;
2019-02-01 18:12:55 +00:00
const char * step_units = NULL ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
long nstep = count_values ( r , " step " ) ;
long ndate = count_values ( r , " date " ) ;
long ntime = count_values ( r , " time " ) ;
2013-07-10 16:58:41 +00:00
long nfcmonth = count_values ( r , " fcmonth " ) ;
static long julianrefdate = 0 ;
2020-01-22 13:10:59 +00:00
if ( nstep > 1 | | ndate > 1 | | ntime > 1 | | nfcmonth > 1 ) {
if ( nstep > 1 )
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal error. Field has more than 1 STEP " ) ;
2020-01-22 13:10:59 +00:00
if ( ntime > 1 )
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal error. Field has more than 1 TIME " ) ;
2020-01-22 13:10:59 +00:00
if ( ndate > 1 )
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal error. Field has more than 1 DATE " ) ;
2020-01-22 13:10:59 +00:00
if ( nfcmonth > 1 )
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal error. Field has more than 1 FCMONTH " ) ;
print_all_requests ( r ) ;
exit ( 1 ) ;
}
2020-01-22 13:10:59 +00:00
if ( nstep )
2019-02-01 18:12:55 +00:00
step = atof ( get_value ( r , " step " , 0 ) ) ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( ndate ) {
const char * p = get_value ( r , " date " , 0 ) ;
2019-11-26 15:40:58 +00:00
const char * marsClass = get_value ( r , " class " , 0 ) ;
if ( eq_string ( marsClass , " s2 " ) ) {
/* S2S Data. See GRIB-699 and GRIB-762 */
const char * hdate = get_value ( r , " hdate " , 0 ) ;
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: S2S Data " ) ;
if ( hdate ) {
p = hdate ; /* This is a hindcast */
}
2015-04-07 15:52:13 +00:00
}
2020-01-22 13:10:59 +00:00
if ( is_number ( p ) )
2013-07-10 16:58:41 +00:00
date = atol ( p ) ;
2020-01-22 13:10:59 +00:00
else {
2023-01-08 15:23:24 +00:00
long second = 0 ;
2023-03-04 12:45:31 +00:00
bool isjul , date_ok ;
2013-08-16 11:56:13 +00:00
date_ok = parsedate ( p , & julian , & second , & isjul ) ;
2020-01-22 13:10:59 +00:00
if ( ! date_ok )
grib_context_log ( ctx , GRIB_LOG_ERROR , " Failed to parse date: '%s' " , p ) ;
2013-07-10 16:58:41 +00:00
date = grib_julian_to_date ( julian ) ;
}
/* Climatology */
2020-01-22 13:10:59 +00:00
if ( strlen ( p ) = = 3 ) {
if ( setup . usevalidtime )
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Climatology data. Setting usevalidtime=OFF " ) ;
2023-03-04 12:45:31 +00:00
setup . auto_refdate = false ;
setup . usevalidtime = false ;
setup . climatology = true ;
2013-07-10 16:58:41 +00:00
}
}
2020-01-22 13:10:59 +00:00
if ( ntime )
2013-07-10 16:58:41 +00:00
time = atol ( get_value ( r , " time " , 0 ) ) ;
2020-01-22 13:10:59 +00:00
if ( nfcmonth ) {
2013-07-10 16:58:41 +00:00
fcmonth = atol ( get_value ( r , " fcmonth " , 0 ) ) ;
/* FCMONTH needs base DATE */
2020-01-22 13:10:59 +00:00
if ( date = = 0 ) {
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal error: FCMONTH needs DATE " ) ;
exit ( 1 ) ;
}
fcmonthdays = fcmonth2days ( date , fcmonth ) ;
}
2020-01-22 13:10:59 +00:00
julian = grib_date_to_julian ( date ) ;
2019-02-01 18:12:55 +00:00
step_units = get_value ( r , " stepUnits " , 0 ) ;
2020-01-22 13:10:59 +00:00
if ( step_units ) {
if ( check_stepUnits ( step_units ) ! = GRIB_SUCCESS ) {
2019-02-01 19:52:30 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR ,
2020-01-22 13:10:59 +00:00
" Cannot convert stepUnits of '%s'. Only hours, minutes and seconds supported. " , step_units ) ;
2019-02-01 19:52:30 +00:00
}
2023-10-30 16:35:53 +00:00
if ( STR_EQUAL ( " m " , step_units ) ) {
2019-02-01 18:12:55 +00:00
step / = 60 ;
2020-01-22 13:10:59 +00:00
}
2023-10-30 16:35:53 +00:00
else if ( STR_EQUAL ( " s " , step_units ) ) {
2019-02-01 19:52:30 +00:00
step / = 3600 ;
2019-02-01 18:12:55 +00:00
}
}
2013-07-10 16:58:41 +00:00
v = julian * 24.0 + fcmonthdays * 24.0 + time / 100.0 + step * 1.0 ;
2019-08-05 10:32:41 +00:00
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: date=%ld, julian=%ld, fcmonthdays=%ld, time=%ld, step=%g, validation=%.3f " , date , julian , fcmonthdays , time , step , v ) ;
2013-07-10 16:58:41 +00:00
set_value ( r , " _validation " , " %lf " , v ) ;
set_value ( r , " _juliandate " , " %ld " , julian ) ;
2020-01-22 13:10:59 +00:00
if ( ! julianrefdate )
2013-07-10 16:58:41 +00:00
julianrefdate = grib_date_to_julian ( setup . refdate ) ;
set_value ( r , " _validationtime " , " %lf " , v - julianrefdate * 24.0 ) ;
/* Remove minutes from TIME */
2020-01-22 13:10:59 +00:00
if ( ntime )
2013-07-10 16:58:41 +00:00
set_value ( r , " time " , " %.1lf " , time / 100.0 ) ;
2013-03-25 12:04:10 +00:00
}
static void free_nc_options ( )
{
2020-01-22 13:10:59 +00:00
if ( setup . title )
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , setup . title ) ;
2020-01-22 13:10:59 +00:00
if ( setup . history )
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , setup . history ) ;
2020-01-22 13:10:59 +00:00
if ( setup . unlimited )
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , setup . unlimited ) ;
2020-01-22 13:10:59 +00:00
if ( setup . mars_description )
2013-07-10 16:58:41 +00:00
free_all_requests ( setup . mars_description ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void get_nc_options ( const request * user_r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
const char * checkvalidtime_env = NULL ;
const char * validtime = get_value ( user_r , " usevalidtime " , 0 ) ;
const char * refdate = get_value ( user_r , " referencedate " , 0 ) ;
const char * shuffle = get_value ( user_r , " shuffle " , 0 ) ;
const char * deflate = get_value ( user_r , " deflate " , 0 ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
const char * title = get_value ( user_r , " title " , 0 ) ;
const char * history = get_value ( user_r , " history " , 0 ) ;
const char * unlimited = get_value ( user_r , " unlimited " , 0 ) ;
2013-03-25 12:04:10 +00:00
2023-03-04 12:45:31 +00:00
setup . shuffle = shuffle ? ( strcmp ( shuffle , " true " ) = = 0 ) : false ;
2020-01-22 13:10:59 +00:00
setup . deflate = deflate ? ( ( strcmp ( deflate , " none " ) = = 0 ) ? - 1 : atol ( deflate ) ) : - 1 ;
2023-03-04 12:45:31 +00:00
setup . usevalidtime = validtime ? ( strcmp ( validtime , " true " ) = = 0 ) : false ;
2020-01-22 13:10:59 +00:00
setup . refdate = refdate ? atol ( refdate ) : 19000101 ;
2023-03-04 12:45:31 +00:00
setup . auto_refdate = refdate ? ( strcmp ( get_value ( user_r , " referencedate " , 0 ) , " AUTOMATIC " ) = = 0 ) : false ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
setup . title = title ? grib_context_strdup ( ctx , ( title ) ) : NULL ;
setup . history = history ? grib_context_strdup ( ctx , ( history ) ) : NULL ;
2013-07-10 16:58:41 +00:00
setup . unlimited = unlimited ? grib_context_strdup ( ctx , ( ( unlimited ) ) ) : NULL ;
2013-11-29 15:50:22 +00:00
2023-07-27 12:15:48 +00:00
setup . checkvalidtime = true ;
2020-01-22 13:10:59 +00:00
checkvalidtime_env = getenv ( " GRIB_TO_NETCDF_CHECKVALIDTIME " ) ;
2023-07-27 12:15:48 +00:00
if ( checkvalidtime_env ) {
const long v = atol ( checkvalidtime_env ) ;
if ( v = = 0 ) setup . checkvalidtime = false ;
}
2013-07-10 16:58:41 +00:00
setup . mars_description = empty_request ( " MARS " ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static nc_type translate_nctype ( const char * name )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( ! name )
2013-07-10 16:58:41 +00:00
return NC_SHORT ;
2013-03-25 12:04:10 +00:00
2023-10-30 16:35:53 +00:00
if ( STR_EQUAL ( name , " NC_BYTE " ) )
2013-07-10 16:58:41 +00:00
return NC_BYTE ;
2013-03-25 12:04:10 +00:00
2023-10-30 16:35:53 +00:00
if ( STR_EQUAL ( name , " NC_SHORT " ) )
2013-07-10 16:58:41 +00:00
return NC_SHORT ;
2013-03-25 12:04:10 +00:00
2023-10-30 16:35:53 +00:00
if ( STR_EQUAL ( name , " NC_INT " ) )
2013-07-10 16:58:41 +00:00
return NC_INT ;
2013-03-25 12:04:10 +00:00
2023-10-30 16:35:53 +00:00
if ( STR_EQUAL ( name , " NC_FLOAT " ) )
2013-07-10 16:58:41 +00:00
return NC_FLOAT ;
2013-03-25 12:04:10 +00:00
2023-10-30 16:35:53 +00:00
if ( STR_EQUAL ( name , " NC_DOUBLE " ) )
2013-07-10 16:58:41 +00:00
return NC_DOUBLE ;
2013-03-25 12:04:10 +00:00
2022-01-07 14:28:05 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Unknown netCDF type '%s'. Using NC_SHORT " , name ) ;
2013-07-10 16:58:41 +00:00
return NC_SHORT ;
2013-03-25 12:04:10 +00:00
}
2019-11-21 12:00:02 +00:00
static void check_err ( const char * function , const int stat , const int line )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( stat ! = NC_NOERR ) {
2020-07-17 14:37:57 +00:00
/* (void) fprintf(stderr, "line %d of %s: %s\n", line, tool_name, nc_strerror(stat)); */
2019-11-21 12:00:02 +00:00
( void ) fprintf ( stderr , " \n %s ERROR: line %d, %s: %s \n " ,
2020-07-17 14:37:57 +00:00
tool_name , line , function , nc_strerror ( stat ) ) ;
2014-01-29 23:29:17 +00:00
if ( stat = = NC_EVARSIZE ) {
2020-01-22 13:10:59 +00:00
( void ) fprintf ( stderr ,
" \n Cannot create netCDF classic format, dataset is too large! \n "
" Try splitting the input GRIB(s). \n " ) ;
2014-01-29 23:29:17 +00:00
}
2013-07-10 16:58:41 +00:00
exit ( 1 ) ;
}
2013-03-25 12:04:10 +00:00
}
# define DIM_ID 1
2020-01-22 13:10:59 +00:00
static int set_dimension ( int ncid , const char * name , int n , int xtype , const char * units , const char * long_name )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
int var_id = 0 ;
2020-01-22 13:10:59 +00:00
int stat = 0 ;
2013-07-10 16:58:41 +00:00
int dim_id = DIM_ID ;
int dim_vec [ DIM_ID ] ;
2013-03-25 12:04:10 +00:00
2023-10-30 16:35:53 +00:00
if ( setup . unlimited & & ( STR_EQUAL ( name , setup . unlimited ) ) )
2013-07-10 16:58:41 +00:00
n = NC_UNLIMITED ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
stat = nc_def_dim ( ncid , name , n , & dim_id ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_def_dim " , stat , __LINE__ ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
dim_vec [ 0 ] = dim_id ;
2020-01-22 13:10:59 +00:00
stat = nc_def_var ( ncid , name , ( nc_type ) xtype , 1 , dim_vec , & var_id ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_def_var " , stat , __LINE__ ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( units ! = NULL ) {
2013-07-10 16:58:41 +00:00
stat = nc_put_att_text ( ncid , var_id , " units " , strlen ( units ) , units ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_text " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( long_name ! = NULL ) {
2013-07-10 16:58:41 +00:00
stat = nc_put_att_text ( ncid , var_id , " long_name " , strlen ( long_name ) , long_name ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_text " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return var_id ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static int check_grid ( field * f )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
err e = 0 ;
char grid_type [ 80 ] ;
2018-01-30 17:21:48 +00:00
size_t size = sizeof ( grid_type ) ;
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_string ( f - > handle , " typeOfGrid " , grid_type , & size ) ) ! = GRIB_SUCCESS ) {
2016-02-25 10:14:27 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get typeOfGrid %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
2023-10-30 16:35:53 +00:00
if ( ! STR_EQUAL ( grid_type , " regular_ll " ) & & ! STR_EQUAL ( grid_type , " regular_gg " ) ) {
2019-09-05 10:48:44 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Grid type = %s " , grid_type ) ;
grib_context_log ( ctx , GRIB_LOG_ERROR , " First GRIB is not on a regular lat/lon grid or on a regular Gaussian grid. Exiting. \n " ) ;
return GRIB_GEOCALCULUS_PROBLEM ;
2013-07-10 16:58:41 +00:00
}
2018-01-30 17:21:48 +00:00
return e ;
}
2019-02-16 14:56:14 +00:00
static int get_num_latitudes_longitudes ( grib_handle * h , size_t * nlats , size_t * nlons )
{
2020-01-22 13:10:59 +00:00
err e = 0 ;
2019-02-16 14:56:14 +00:00
char grid_type [ 80 ] ;
size_t size = sizeof ( grid_type ) ;
if ( grib_get_string ( h , " typeOfGrid " , grid_type , & size ) = = GRIB_SUCCESS & &
2020-01-22 13:10:59 +00:00
strcmp ( grid_type , " regular_ll " ) = = 0 ) {
2019-09-05 10:48:44 +00:00
/* Special shortcut for regular lat/on grids */
2019-02-16 14:56:14 +00:00
long n ;
2020-01-22 13:10:59 +00:00
Assert ( ! grib_is_missing ( h , " Ni " , & e ) ) ;
2019-02-16 14:56:14 +00:00
if ( ( e = grib_get_long ( h , " Ni " , & n ) ) ! = GRIB_SUCCESS ) {
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get Ni: %s " , grib_get_error_message ( e ) ) ;
return e ;
}
* nlons = n ;
2019-02-16 16:40:31 +00:00
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_long ( h , " Nj " , & n ) ) ! = GRIB_SUCCESS ) {
2019-02-16 14:56:14 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get Nj: %s " , grib_get_error_message ( e ) ) ;
return e ;
}
* nlats = n ;
}
2020-01-22 13:10:59 +00:00
else {
if ( ( e = grib_get_size ( h , " distinctLatitudes " , nlats ) ) ! = GRIB_SUCCESS ) {
2019-02-16 14:56:14 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get distinctLatitudes: %s " , grib_get_error_message ( e ) ) ;
return e ;
}
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_size ( h , " distinctLongitudes " , nlons ) ) ! = GRIB_SUCCESS ) {
2019-02-16 14:56:14 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get distinctLongitudes: %s " , grib_get_error_message ( e ) ) ;
return e ;
}
}
return e ;
}
2020-01-22 13:10:59 +00:00
static int def_latlon ( int ncid , fieldset * fs )
2018-01-30 17:21:48 +00:00
{
2020-01-22 13:10:59 +00:00
int n = 0 ;
size_t nlats = 0 , nlons = 0 ;
2021-02-07 22:06:42 +00:00
err e = 0 ;
2020-01-22 13:10:59 +00:00
field * g = get_field ( fs , 0 , expand_mem ) ;
2018-01-30 17:21:48 +00:00
2023-06-26 20:21:07 +00:00
DEBUG_ASSERT ( check_grid ( g ) = = GRIB_SUCCESS ) ;
2018-01-30 17:21:48 +00:00
2020-01-22 13:10:59 +00:00
if ( ( e = get_num_latitudes_longitudes ( g - > handle , & nlats , & nlons ) ) ! = GRIB_SUCCESS ) {
2019-02-16 14:56:14 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get lat/lon info: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
2019-02-16 14:56:14 +00:00
/* Define longitude */
2021-02-07 22:06:42 +00:00
n = ( int ) nlons ;
2020-02-13 12:38:37 +00:00
set_dimension ( ncid , " longitude " , n , NC_FLOAT , " degrees_east " , " longitude " ) ;
2013-07-10 16:58:41 +00:00
/* Define latitude */
2021-02-07 22:06:42 +00:00
n = nlats ;
2020-02-13 12:38:37 +00:00
set_dimension ( ncid , " latitude " , n , NC_FLOAT , " degrees_north " , " latitude " ) ;
2013-07-10 16:58:41 +00:00
2023-03-04 12:45:31 +00:00
/* g->purge_header = true; */
2013-07-10 16:58:41 +00:00
release_field ( g ) ;
return e ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static int put_latlon ( int ncid , fieldset * fs )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
int var_id = 0 ;
2023-03-04 12:45:31 +00:00
size_t i = 0 ;
2020-01-22 13:10:59 +00:00
size_t n = 0 ;
int stat = 0 ;
err e = 0 ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
field * g = get_field ( fs , 0 , expand_mem ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
double * dvalues = NULL ;
float * fvalues = NULL ;
long nv = 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
size_t ni ;
size_t nj ;
2013-03-25 12:04:10 +00:00
#if 0
2013-07-10 16:58:41 +00:00
/* Get info in degrees */
if ( ( e = grib_get_double ( g - > handle , " iDirectionIncrementInDegrees " , & ew_stride ) ) ! = GRIB_SUCCESS )
{
2018-01-30 17:21:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get iDirectionIncrementInDegrees: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
if ( ( e = grib_get_double ( g - > handle , " jDirectionIncrementInDegrees " , & ns_stride ) ) ! = GRIB_SUCCESS )
{
2016-02-25 10:14:27 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get jDirectionIncrementInDegrees %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
/* Define longitude */
if ( ( e = grib_get_long ( g - > handle , " Ni " , & ni ) ) ! = GRIB_SUCCESS )
{
2016-02-25 10:14:27 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get Ni %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
/* Define latitude */
if ( ( e = grib_get_long ( g - > handle , " Nj " , & nj ) ) ! = GRIB_SUCCESS )
{
2016-02-25 10:14:27 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get Nj %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
2013-03-25 12:04:10 +00:00
# endif
2020-01-22 13:10:59 +00:00
if ( ( e = get_num_latitudes_longitudes ( g - > handle , & nj , & ni ) ) ! = GRIB_SUCCESS ) {
2019-09-05 10:48:44 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: put_latlon: cannot get distinctLatitudes: %s " , grib_get_error_message ( e ) ) ;
return e ;
2013-03-25 12:04:10 +00:00
}
2013-07-10 16:58:41 +00:00
/* Compute max. # values and allocate */
nv = ni ;
2020-01-22 13:10:59 +00:00
if ( nv < nj )
2013-07-10 16:58:41 +00:00
nv = nj ;
2020-01-22 13:10:59 +00:00
fvalues = ( float * ) grib_context_malloc ( ctx , sizeof ( float ) * nv ) ;
dvalues = ( double * ) grib_context_malloc ( ctx , sizeof ( double ) * nv ) ;
2013-07-10 16:58:41 +00:00
/* longitude */
2020-01-22 13:10:59 +00:00
n = ni ;
2013-07-10 16:58:41 +00:00
stat = nc_inq_varid ( ncid , " longitude " , & var_id ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_inq_varid " , stat , __LINE__ ) ;
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_double_array ( g - > handle , " distinctLongitudes " , dvalues , & n ) ) ! = GRIB_SUCCESS ) {
2019-03-26 13:24:40 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: put_latlon: cannot get distinctLongitudes: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
2023-07-19 12:52:03 +00:00
if ( n ! = ni ) {
grib_context_log ( ctx , GRIB_LOG_ERROR , " Number of distinctLongitudes is not the same as Ni (%zu!=%zu) " , n , ni ) ;
return GRIB_GEOCALCULUS_PROBLEM ;
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < n ; i + + ) {
fvalues [ i ] = dvalues [ i ] ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
stat = nc_put_var_float ( ncid , var_id , fvalues ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_var_float " , stat , __LINE__ ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
/* latitude */
2020-01-22 13:10:59 +00:00
n = nj ;
2013-07-10 16:58:41 +00:00
stat = nc_inq_varid ( ncid , " latitude " , & var_id ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_inq_varid " , stat , __LINE__ ) ;
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_double_array ( g - > handle , " distinctLatitudes " , dvalues , & n ) ) ! = GRIB_SUCCESS ) {
2019-03-26 13:24:40 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: put_latlon: cannot get distinctLatitudes: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
2023-07-19 12:52:03 +00:00
if ( n ! = nj ) {
grib_context_log ( ctx , GRIB_LOG_ERROR , " Number of distinctLatitudes is not the same as Nj (%zu!=%zu) " , n , nj ) ;
return GRIB_GEOCALCULUS_PROBLEM ;
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < n ; i + + ) {
fvalues [ i ] = dvalues [ i ] ;
}
2013-07-10 16:58:41 +00:00
stat = nc_put_var_float ( ncid , var_id , fvalues ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_var_float " , stat , __LINE__ ) ;
2013-03-25 12:04:10 +00:00
2023-03-04 12:45:31 +00:00
/* g->purge_header = true; */
2013-07-10 16:58:41 +00:00
release_field ( g ) ;
grib_context_free ( ctx , fvalues ) ;
grib_context_free ( ctx , dvalues ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return e ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static int compute_scale ( dataset_t * subset )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
double max = - DBL_MAX ;
double min = DBL_MAX ;
double median = 0 ;
long i = 0 ;
2023-03-04 12:45:31 +00:00
size_t j = 0 ;
2020-01-22 13:10:59 +00:00
int64_t scaled_max = 0 ;
int64_t scaled_min = 0 ;
2013-07-10 16:58:41 +00:00
int64_t scaled_median = 0 ;
double ao = 0.0 , sf = 0.0 ;
double x ;
2020-01-22 13:10:59 +00:00
char test_scaled_max = 0 ;
char test_scaled_min = 0 ;
2013-07-10 16:58:41 +00:00
char test_scaled_median = 0 ;
err e = 0 ;
2020-01-22 13:10:59 +00:00
fieldset * fs = subset - > fset ;
int idx = subset - > att . nctype ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < fs - > count ; i + + ) {
field * g = get_field ( fs , i , expand_mem ) ;
2013-07-10 16:58:41 +00:00
size_t len ;
2020-01-22 13:10:59 +00:00
static double * vals = NULL ;
2013-07-10 16:58:41 +00:00
static size_t vals_len = 0 ;
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_size ( g - > handle , " values " , & len ) ) ! = GRIB_SUCCESS ) {
2018-01-30 17:21:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get size of values: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
2020-01-22 13:10:59 +00:00
if ( len > vals_len ) {
if ( vals )
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , vals ) ;
2020-01-22 13:10:59 +00:00
vals = ( double * ) grib_context_malloc ( ctx , sizeof ( double ) * len ) ;
2013-07-10 16:58:41 +00:00
vals_len = len ;
}
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_double_array ( g - > handle , " values " , vals , & len ) ) ! = GRIB_SUCCESS ) {
2018-01-30 17:21:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get values: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
2020-01-22 13:10:59 +00:00
if ( g - > has_bitmap ) {
2023-03-04 12:45:31 +00:00
subset - > bitmap = true ;
2020-01-22 13:10:59 +00:00
for ( j = 0 ; j < len ; + + j ) {
2020-03-20 12:10:48 +00:00
if ( vals & & vals [ j ] ! = global_missing_value ) {
if ( vals [ j ] > max ) max = vals [ j ] ;
if ( vals [ j ] < min ) min = vals [ j ] ;
2013-07-10 16:58:41 +00:00
}
}
}
2020-01-22 13:10:59 +00:00
else {
for ( j = 0 ; j < len ; + + j ) {
2020-03-19 16:01:10 +00:00
if ( vals ) {
if ( vals [ j ] > max ) max = vals [ j ] ;
if ( vals [ j ] < min ) min = vals [ j ] ;
}
2013-07-10 16:58:41 +00:00
}
}
2023-03-04 12:45:31 +00:00
/* g->purge_header = true; */
2013-07-10 16:58:41 +00:00
release_field ( g ) ;
}
median = ( max + min ) / 2.0 ;
2016-04-07 13:16:02 +00:00
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: max_int: %lf, min_int: %lf " , nc_type_values [ idx ] . nc_type_max , nc_type_values [ idx ] . nc_type_min ) ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
sf = ( double ) ( ( max - min ) / ( double ) ( nc_type_values [ idx ] . nc_type_max - nc_type_values [ idx ] . nc_type_min ) ) ;
2016-04-07 13:16:02 +00:00
ao = ( ( max + min ) - sf * ( nc_type_values [ idx ] . nc_type_min + nc_type_values [ idx ] . nc_type_max ) ) / 2 ;
2013-07-10 16:58:41 +00:00
if ( min = = max ) {
sf = 1.0 ; /* Prevent divide by zero later. Constant field grib has max == min */
}
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: idx is: %d " , idx ) ;
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: max: %lf, min: %lf, median: %lf, scale factor: %lf, add_offset: %lf " , max , min , median , sf , ao ) ;
x = ( ( median - ao ) ) ;
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: x=%lf " , x ) ;
x / = sf ;
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: x=%lf " , x ) ;
2020-01-22 13:10:59 +00:00
scaled_max = rint ( ( max - ao ) / sf ) ;
scaled_min = rint ( ( min - ao ) / sf ) ;
2013-07-10 16:58:41 +00:00
scaled_median = rint ( ( median - ao ) / sf ) ;
2018-04-30 14:42:52 +00:00
if ( scaled_max > nc_type_values [ idx ] . nc_type_max ) {
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: scaled_max (=%lld) > nc_type_max (=%lf). Set sf to 1.0 " ,
2020-10-13 13:20:36 +00:00
( long long ) scaled_max , nc_type_values [ idx ] . nc_type_max ) ;
2020-01-22 13:10:59 +00:00
sf = 1.0 ; /* ECC-685 */
2018-04-30 14:42:52 +00:00
}
2020-01-22 13:10:59 +00:00
test_scaled_max = ( char ) scaled_max ;
test_scaled_min = ( char ) scaled_min ;
test_scaled_median = ( char ) scaled_median ;
2013-07-10 16:58:41 +00:00
2020-10-13 13:20:36 +00:00
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: scaled_max: %lld, scaled_min: %lld, scaled_median: %lld, x: %lf " ,
( long long ) scaled_max , ( long long ) scaled_min , ( long long ) scaled_median , x ) ;
2013-07-10 16:58:41 +00:00
2020-10-13 13:20:36 +00:00
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: test_scaled_max: %x, test_scaled_min: %x, test_scaled_median: %x " ,
test_scaled_max , test_scaled_min , test_scaled_median ) ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
max = scaled_max * sf + ao ;
min = scaled_min * sf + ao ;
2013-07-10 16:58:41 +00:00
median = scaled_median * sf + ao ;
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: max: %lf, min: %lf, median: %lf " , max , min , median ) ;
subset - > scale_factor = sf ;
2020-01-22 13:10:59 +00:00
subset - > add_offset = ao ;
2013-07-10 16:58:41 +00:00
return 0 ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static int nc_put_att_type ( int ncid , int varid , const char * name , nc_type nctype , int n , double value )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
int r = 0 ;
2020-01-22 13:10:59 +00:00
switch ( nctype ) {
case NC_BYTE : {
unsigned char val_uchar = ( unsigned char ) value ;
r = nc_put_att_uchar ( ncid , varid , name , nctype , n , & val_uchar ) ;
break ;
}
case NC_SHORT : {
short int val_short = ( short int ) value ;
r = nc_put_att_short ( ncid , varid , name , nctype , n , & val_short ) ;
break ;
}
case NC_INT : {
int val_int = ( int ) value ;
r = nc_put_att_int ( ncid , varid , name , nctype , n , & val_int ) ;
break ;
}
case NC_FLOAT : {
float val_flt = ( float ) value ;
r = nc_put_att_float ( ncid , varid , name , nctype , n , & val_flt ) ;
break ;
}
case NC_DOUBLE : {
double val_dbl = ( double ) value ;
r = nc_put_att_double ( ncid , varid , name , nctype , n , & val_dbl ) ;
break ;
}
default :
2022-01-07 14:28:05 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " nc_put_att_type(...): Unknown netCDF type '%d' " , nctype ) ;
2020-01-22 13:10:59 +00:00
break ;
2013-07-10 16:58:41 +00:00
}
return r ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static int nc_put_vara_type ( int ncid , int varid , const size_t start [ ] , const size_t count [ ] , void * valuesp , nc_type nctype )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
int r = 0 ;
2020-01-22 13:10:59 +00:00
switch ( nctype ) {
case NC_BYTE :
r = nc_put_vara_uchar ( ncid , varid , start , count , ( unsigned char * ) valuesp ) ;
break ;
case NC_SHORT :
r = nc_put_vara_short ( ncid , varid , start , count , ( short int * ) valuesp ) ;
break ;
case NC_INT :
r = nc_put_vara_int ( ncid , varid , start , count , ( int * ) valuesp ) ;
break ;
case NC_FLOAT :
r = nc_put_vara_float ( ncid , varid , start , count , ( float * ) valuesp ) ;
break ;
case NC_DOUBLE :
r = nc_put_vara_double ( ncid , varid , start , count , ( double * ) valuesp ) ;
break ;
default :
2022-01-07 14:28:05 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " nc_put_vara_type(...): Unknown netCDF type '%d' " , nctype ) ;
2020-01-22 13:10:59 +00:00
break ;
2013-07-10 16:58:41 +00:00
}
return r ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void scale_bitmap ( double * vals , long n , void * data , dataset_t * subset )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
int i = 0 ;
2013-07-10 16:58:41 +00:00
nc_type nctype = subset - > att . nctype ;
2013-03-25 12:04:10 +00:00
2020-02-26 21:25:12 +00:00
/* if(!subset->bitmap) {
grib_context_log ( ctx , GRIB_LOG_DEBUG , " No scale of bitmap required " ) ;
return ;
} */
if ( n > 0 & & ! vals ) {
Assert ( ! " scale_bitmap: n > 0 but vals == NULL " ) ;
return ;
}
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
switch ( nctype ) {
case NC_BYTE : {
unsigned char * vscaled = ( unsigned char * ) data ;
for ( i = 0 ; i < n ; + + i ) {
if ( vals [ i ] = = global_missing_value ) {
vscaled [ i ] = ( unsigned char ) subset - > missing ;
}
2016-04-07 15:14:41 +00:00
}
2020-01-22 13:10:59 +00:00
break ;
2016-04-07 15:14:41 +00:00
}
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
case NC_SHORT : {
short int * vscaled = ( short int * ) data ;
for ( i = 0 ; i < n ; + + i ) {
if ( vals [ i ] = = global_missing_value ) {
vscaled [ i ] = ( short int ) subset - > missing ;
}
2016-04-07 15:14:41 +00:00
}
2020-01-22 13:10:59 +00:00
break ;
2016-04-07 15:14:41 +00:00
}
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
case NC_INT : {
int * vscaled = ( int * ) data ;
for ( i = 0 ; i < n ; + + i ) {
if ( vals [ i ] = = global_missing_value ) {
vscaled [ i ] = ( int ) subset - > missing ;
}
2016-04-07 15:14:41 +00:00
}
2020-01-22 13:10:59 +00:00
break ;
2016-04-07 15:14:41 +00:00
}
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
case NC_FLOAT : {
float * vscaled = ( float * ) data ;
for ( i = 0 ; i < n ; + + i ) {
if ( vals [ i ] = = global_missing_value ) {
vscaled [ i ] = ( float ) subset - > missing ;
}
2016-04-07 15:14:41 +00:00
}
2020-01-22 13:10:59 +00:00
break ;
2016-04-07 15:14:41 +00:00
}
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
case NC_DOUBLE : {
double * vscaled = ( double * ) data ;
for ( i = 0 ; i < n ; + + i ) {
if ( vals [ i ] = = global_missing_value ) {
vscaled [ i ] = ( double ) subset - > missing ;
}
2016-04-07 15:14:41 +00:00
}
2020-01-22 13:10:59 +00:00
break ;
2016-04-07 15:14:41 +00:00
}
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
default :
2022-01-07 14:28:05 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " scale(...): Unknown netCDF type %d " , nctype ) ;
2020-01-22 13:10:59 +00:00
break ;
2013-07-10 16:58:41 +00:00
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void scale ( double * vals , long n , void * data , dataset_t * g )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
int i = 0 ;
nc_type nctype = g - > att . nctype ;
2013-07-10 16:58:41 +00:00
double scale_factor = g - > scale_factor ;
2020-01-22 13:10:59 +00:00
double add_offset = g - > add_offset ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
/*
2013-07-22 13:06:46 +00:00
if ( ! subset - > scale )
{
grib_context_log ( ctx , GRIB_LOG_DEBUG , " No scale required " ) ;
return ;
}
2020-02-14 12:13:30 +00:00
*/
2023-06-26 20:21:07 +00:00
DEBUG_ASSERT ( vals ) ;
DEBUG_ASSERT ( n > 0 ) ;
2021-02-07 22:06:42 +00:00
if ( ! vals ) return ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
switch ( nctype ) {
case NC_BYTE : {
unsigned char * vscaled = ( unsigned char * ) data ;
for ( i = 0 ; i < n ; + + i ) {
if ( ! g - > bitmap | | ( vals [ i ] ! = global_missing_value ) ) {
double d = rint ( ( vals [ i ] - add_offset ) / scale_factor ) ;
2023-07-18 17:55:31 +00:00
if ( ! ( d > = nc_type_values [ nctype ] . nc_type_min & & d < = nc_type_values [ nctype ] . nc_type_max ) ) {
grib_context_log ( ctx , GRIB_LOG_ERROR , " Scaling for type NC_BYTE failed " ) ;
return ;
}
2020-01-22 13:10:59 +00:00
vscaled [ i ] = d ;
}
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
break ;
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
case NC_SHORT : {
short int * vscaled = ( short int * ) data ;
for ( i = 0 ; i < n ; + + i ) {
if ( ! g - > bitmap | | ( vals [ i ] ! = global_missing_value ) ) {
double d = 0 ;
Assert ( scale_factor > 0 ) ;
d = rint ( ( vals [ i ] - add_offset ) / scale_factor ) ;
2023-07-18 17:55:31 +00:00
if ( ! ( d > = nc_type_values [ nctype ] . nc_type_min & & d < = nc_type_values [ nctype ] . nc_type_max ) ) {
grib_context_log ( ctx , GRIB_LOG_ERROR , " Scaling for type NC_SHORT failed " ) ;
return ;
}
2020-01-22 13:10:59 +00:00
vscaled [ i ] = d ;
}
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
break ;
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
case NC_INT : {
int * vscaled = ( int * ) data ;
for ( i = 0 ; i < n ; + + i ) {
if ( ! g - > bitmap | | ( vals [ i ] ! = global_missing_value ) ) {
double d = rint ( ( vals [ i ] - add_offset ) / scale_factor ) ;
2023-07-18 17:55:31 +00:00
if ( ! ( d > = nc_type_values [ nctype ] . nc_type_min & & d < = nc_type_values [ nctype ] . nc_type_max ) ) {
grib_context_log ( ctx , GRIB_LOG_ERROR , " Scaling for type NC_INT failed " ) ;
return ;
}
2020-01-22 13:10:59 +00:00
vscaled [ i ] = d ;
}
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
break ;
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
case NC_FLOAT : {
float * vscaled = ( float * ) data ;
for ( i = 0 ; i < n ; + + i ) {
if ( ! g - > bitmap | | ( vals [ i ] ! = global_missing_value ) ) {
double d = vals [ i ] ;
2023-07-18 17:55:31 +00:00
if ( ! ( d > = nc_type_values [ nctype ] . nc_type_min & & d < = nc_type_values [ nctype ] . nc_type_max ) ) {
grib_context_log ( ctx , GRIB_LOG_ERROR , " Scaling for type NC_FLOAT failed " ) ;
return ;
}
2020-01-22 13:10:59 +00:00
vscaled [ i ] = d ;
}
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
break ;
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
case NC_DOUBLE : {
double * vscaled = ( double * ) data ;
for ( i = 0 ; i < n ; + + i ) {
if ( ! g - > bitmap | | ( vals [ i ] ! = global_missing_value ) ) {
double d = vals [ i ] ;
2023-07-18 17:55:31 +00:00
if ( ! ( d > = nc_type_values [ nctype ] . nc_type_min & & d < = nc_type_values [ nctype ] . nc_type_max ) ) {
grib_context_log ( ctx , GRIB_LOG_ERROR , " Scaling for type NC_DOUBLE failed " ) ;
return ;
}
2020-01-22 13:10:59 +00:00
vscaled [ i ] = d ;
}
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
break ;
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
default :
2022-01-07 14:28:05 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " scale(...): Unknown netCDF type %d " , nctype ) ;
2020-01-22 13:10:59 +00:00
break ;
2013-07-10 16:58:41 +00:00
}
2013-03-25 12:04:10 +00:00
}
2015-07-22 16:59:31 +00:00
/* Return array of strings which are the "time" values */
static char * * create_times_array ( const request * cube , size_t * size )
{
2020-01-22 13:10:59 +00:00
char * * result = NULL ;
const char * time_axis = " time " ; /* special case */
parameter * the_param = find_parameter ( cube , time_axis ) ;
* size = 0 ;
2015-07-22 16:59:31 +00:00
if ( the_param ) {
2020-01-22 13:10:59 +00:00
size_t i = 0 , num_values = 0 ;
2015-07-22 16:59:31 +00:00
value * va = NULL ;
2020-01-22 13:10:59 +00:00
if ( ! the_param - > count )
2015-07-22 16:59:31 +00:00
count_values ( cube , time_axis ) ;
/* Go thru all values to count how many there are */
va = the_param - > values ;
2020-01-22 13:10:59 +00:00
while ( va ) {
2015-07-22 16:59:31 +00:00
+ + num_values ;
va = va - > next ;
}
/* Create and populate array */
2020-01-22 13:10:59 +00:00
result = ( char * * ) grib_context_malloc ( ctx , sizeof ( char * ) * num_values ) ;
va = the_param - > values ;
while ( va ) {
2015-07-22 16:59:31 +00:00
result [ i + + ] = va - > name ;
2020-01-22 13:10:59 +00:00
va = va - > next ;
2015-07-22 16:59:31 +00:00
}
* size = num_values ;
}
return result ;
}
2020-01-22 13:10:59 +00:00
static int put_data ( hypercube * h , int ncid , const char * name , dataset_t * subset )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
int i = 0 ;
int stat = 0 ;
2013-07-10 16:58:41 +00:00
int dataid = 0 ;
2020-01-22 13:10:59 +00:00
int naxis = count_axis ( h ) ;
2013-07-10 16:58:41 +00:00
size_t start [ NC_MAX_DIMS ] ;
size_t count [ NC_MAX_DIMS ] ;
2020-01-22 13:10:59 +00:00
char * * times_array = NULL ;
2015-07-22 16:59:31 +00:00
size_t times_array_size = 0 ;
2020-01-22 13:10:59 +00:00
fieldset * fs = subset - > fset ;
field * f = get_field ( fs , 0 , expand_mem ) ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
void * vscaled = NULL ;
2023-03-04 12:45:31 +00:00
size_t vscaled_length = 0 ;
2013-07-10 16:58:41 +00:00
long ni ;
long nj ;
err e = 0 ;
/* Define longitude */
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_long ( f - > handle , " Ni " , & ni ) ) ! = GRIB_SUCCESS ) {
2018-01-30 17:21:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get Ni: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
/* Define latitude */
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_long ( f - > handle , " Nj " , & nj ) ) ! = GRIB_SUCCESS ) {
2018-01-30 17:21:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get Nj: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
/* Start filling dimensions at first value */
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < 2 + naxis ; + + i )
2013-07-10 16:58:41 +00:00
start [ i ] = 0 ;
/* Count dimensions per axis */
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < naxis ; + + i )
2013-07-10 16:58:41 +00:00
count [ naxis - i - 1 ] = 1 ;
2020-01-22 13:10:59 +00:00
count [ naxis ] = nj ; /* latitude */
2013-07-10 16:58:41 +00:00
count [ naxis + 1 ] = ni ; /* longitude */
2023-03-04 12:45:31 +00:00
/* f->purge_header = true; */
2013-07-10 16:58:41 +00:00
release_field ( f ) ;
stat = nc_inq_varid ( ncid , name , & dataid ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_inq_varid " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
2015-07-22 16:59:31 +00:00
/* GRIB-792: Build fast array storing values for the "time" axis. */
/* This is for performance reasons */
times_array = create_times_array ( h - > cube , & times_array_size ) ;
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < fs - > count ; i + + ) {
field * g = get_field ( fs , i , expand_mem ) ;
2013-07-10 16:58:41 +00:00
size_t len ;
2020-01-22 13:10:59 +00:00
static double * vals = NULL ;
2013-07-10 16:58:41 +00:00
static size_t vals_len = 0 ;
2023-03-04 12:45:31 +00:00
bool missing = 0 ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
request * r ;
2013-07-10 16:58:41 +00:00
int j = 0 ;
int idx [ 1024 ] ;
int idxsize = 1024 ;
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_size ( g - > handle , " values " , & len ) ) ! = GRIB_SUCCESS ) {
2018-01-30 17:21:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get size of values: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
2020-01-22 13:10:59 +00:00
if ( len > vals_len ) {
if ( vals )
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , vals ) ;
2020-01-22 13:10:59 +00:00
vals = ( double * ) grib_context_malloc ( ctx , sizeof ( double ) * len ) ;
2013-07-10 16:58:41 +00:00
vals_len = len ;
}
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_double_array ( g - > handle , " values " , vals , & len ) ) ! = GRIB_SUCCESS ) {
2018-01-30 17:21:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get values: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
2013-03-25 12:04:10 +00:00
2023-06-25 15:01:22 +00:00
// bool missing = (g->ksec4[0] < 0); /* If negative number of values, field is missing */
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
r = field_to_request ( g ) ;
2020-01-22 13:10:59 +00:00
if ( ! missing ) {
2013-07-10 16:58:41 +00:00
/* Reserved the maximum memory needed */
/* This should only be done once, as all fields have the same geometry */
2020-01-22 13:10:59 +00:00
if ( ( vscaled_length = = 0 ) | | ( vscaled_length < sizeof ( double ) * len ) ) {
if ( vscaled )
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , vscaled ) ;
2020-01-22 13:10:59 +00:00
vscaled = ( void * ) grib_context_malloc ( ctx , sizeof ( double ) * len ) ;
2013-07-10 16:58:41 +00:00
vscaled_length = sizeof ( double ) * len ;
}
scale ( vals , len , vscaled , subset ) ;
2020-01-22 13:10:59 +00:00
if ( subset - > bitmap )
2013-07-10 16:58:41 +00:00
scale_bitmap ( vals , len , vscaled , subset ) ;
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_long ( g - > handle , " Ni " , & ni ) ) ! = GRIB_SUCCESS ) {
2018-01-30 17:21:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get Ni: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
/* Define latitude */
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_long ( g - > handle , " Nj " , & nj ) ) ! = GRIB_SUCCESS ) {
2018-01-30 17:21:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get Nj: %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
2020-01-22 13:10:59 +00:00
if ( nj ! = count [ naxis ] | | ni ! = count [ naxis + 1 ] ) {
2021-01-05 16:39:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " GRIB message %d has different resolution \n " , i + 1 ) ;
2020-10-13 13:05:50 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " lat=%ld, long=%ld instead of lat=%ld, long=%ld \n " , nj , ni , count [ naxis ] , count [ naxis + 1 ] ) ;
2013-07-10 16:58:41 +00:00
exit ( 1 ) ;
}
2015-07-22 16:59:31 +00:00
cube_indexes ( h , r , times_array , times_array_size , idx , idxsize ) ;
2020-01-22 13:10:59 +00:00
for ( j = 0 ; j < naxis ; + + j )
2013-07-10 16:58:41 +00:00
start [ naxis - j - 1 ] = idx [ j ] ;
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: Put data from field %d " , i ) ;
stat = nc_put_vara_type ( ncid , dataid , start , count , vscaled , subset - > att . nctype ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_vara_type " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
}
2023-03-04 12:45:31 +00:00
/* g->purge_header = true; */
2013-07-10 16:58:41 +00:00
release_field ( g ) ;
}
2015-07-22 16:59:31 +00:00
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , vscaled ) ;
2015-07-22 16:59:31 +00:00
grib_context_free ( ctx , times_array ) ;
2013-07-10 16:58:41 +00:00
return 0 ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void set_always_a_time ( hypercube * h , request * data_r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( setup . usevalidtime & & count_values ( data_r , " time " ) = = 1 ) {
2013-07-10 16:58:41 +00:00
set_value ( h - > cube , " time " , " %.2lf " , atof ( get_value ( data_r , " _validationtime " , 0 ) ) ) ;
add_value ( h - > cube , " axis " , " time " ) ;
{
int i = 0 ;
int n = count_values ( h - > cube , " axis " ) ;
2020-01-22 13:10:59 +00:00
if ( n ) {
2014-10-02 16:23:43 +00:00
h - > compare = ( namecmp * ) calloc ( sizeof ( namecmp ) , n ) ;
2013-07-10 16:58:41 +00:00
Assert ( h - > compare ) ;
}
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < n ; i + + )
2013-07-10 16:58:41 +00:00
h - > compare [ i ] = comparator ( get_value ( h - > cube , " axis " , i ) ) ;
}
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static int define_netcdf_dimensions ( hypercube * h , fieldset * fs , int ncid , dataset_t * subsets , int subsetcnt , const request * data_r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
const request * cube = h - > cube ;
int naxis = count_axis ( h ) ;
int i = 0 ;
int stat = 0 ;
int n = 0 ;
int var_id = 0 ; /* Variable ID */
2013-07-10 16:58:41 +00:00
int dims [ 1024 ] ;
2017-08-08 13:52:47 +00:00
size_t chunks [ NC_MAX_DIMS ] = { 0 , } ; /* For chunking */
2017-07-16 11:22:52 +00:00
err e = 0 ;
2020-01-22 13:10:59 +00:00
2017-07-16 11:22:52 +00:00
long ni ;
long nj ;
2018-01-30 17:21:48 +00:00
2020-01-22 13:10:59 +00:00
field * f = get_field ( fs , 0 , expand_mem ) ;
if ( ( e = check_grid ( f ) ) ! = GRIB_SUCCESS ) {
2018-01-30 17:21:48 +00:00
release_field ( f ) ;
return e ;
}
2020-01-22 13:10:59 +00:00
if ( ( e = grib_get_long ( f - > handle , " Ni " , & ni ) ) ! = GRIB_SUCCESS ) {
2018-01-30 17:21:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get Ni: %s " , grib_get_error_message ( e ) ) ;
2017-07-16 11:22:52 +00:00
return e ;
}
2017-08-08 13:52:47 +00:00
if ( ( e = grib_get_long ( f - > handle , " Nj " , & nj ) ) ! = GRIB_SUCCESS ) {
2018-01-30 17:21:48 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " ecCodes: cannot get Nj: %s " , grib_get_error_message ( e ) ) ;
2017-07-16 11:22:52 +00:00
return e ;
}
release_field ( f ) ;
/* Count dimensions per axis */
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < naxis ; + + i )
2017-08-08 13:52:47 +00:00
chunks [ naxis - i - 1 ] = 1 ;
2017-07-16 11:22:52 +00:00
2020-01-22 13:10:59 +00:00
chunks [ naxis ] = nj ; /* latitude */
2017-08-08 13:52:47 +00:00
chunks [ naxis + 1 ] = ni ; /* longitude */
2017-07-16 11:22:52 +00:00
2013-07-10 16:58:41 +00:00
/* START DEFINITIONS */
/* Define latitude/longitude dimensions */
2017-07-16 11:22:52 +00:00
e = def_latlon ( ncid , fs ) ;
2013-07-10 16:58:41 +00:00
if ( e ! = GRIB_SUCCESS )
return e ;
2022-01-07 14:28:05 +00:00
/* Define netCDF dimensions */
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < naxis ; + + i ) {
int nctype = NC_INT ;
const char * axis = get_axis ( h , i ) ;
2023-01-06 19:14:02 +00:00
const char * units = NULL ;
2013-07-10 16:58:41 +00:00
char u [ 10240 ] ;
2020-01-22 13:10:59 +00:00
const char * lowaxis = ( axis ) ;
2023-01-06 19:14:02 +00:00
const char * longname = ( char * ) lowaxis ;
2020-01-22 13:10:59 +00:00
n = count_values ( cube , axis ) ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( count_values ( data_r , " levtype " ) > 1 ) {
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Cannot handle fields for different levtypes. \n " ) ;
grib_context_log ( ctx , GRIB_LOG_ERROR , " Please split input data into different files. Exiting! \n " ) ;
exit ( 1 ) ;
}
2020-01-22 13:10:59 +00:00
if ( count_values ( data_r , " stepUnits " ) > 1 ) {
2019-02-01 18:12:55 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Cannot handle fields for different stepUnits. \n " ) ;
grib_context_log ( ctx , GRIB_LOG_ERROR , " Please split input data into different files. Exiting! \n " ) ;
exit ( 1 ) ;
}
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( strcmp ( axis , " levelist " ) = = 0 ) {
const char * levtype = get_value ( data_r , " levtype " , 0 ) ;
if ( levtype ) {
if ( strcmp ( " pl " , levtype ) = = 0 ) {
units = " millibars " ;
2013-07-10 16:58:41 +00:00
longname = " pressure_level " ;
}
2020-01-22 13:10:59 +00:00
if ( strcmp ( " ml " , levtype ) = = 0 ) {
2013-07-10 16:58:41 +00:00
longname = " model_level_number " ;
}
}
lowaxis = " level " ;
}
2020-01-22 13:10:59 +00:00
if ( strcmp ( axis , " number " ) = = 0 ) {
2013-07-10 16:58:41 +00:00
longname = " ensemble_member " ;
}
2020-01-22 13:10:59 +00:00
if ( strcmp ( axis , " date " ) = = 0 ) {
2022-11-10 19:18:43 +00:00
snprintf ( u , sizeof ( u ) , " days since %ld-%02ld-%02ld 00:00:0.0 " , setup . refdate / 10000 , ( setup . refdate % 10000 ) / 100 , ( setup . refdate % 100 ) ) ;
2020-01-22 13:10:59 +00:00
units = u ;
2013-07-10 16:58:41 +00:00
longname = " Base_date " ;
2020-01-22 13:10:59 +00:00
if ( setup . climatology ) {
2022-11-10 19:18:43 +00:00
snprintf ( u , sizeof ( u ) , " months " ) ;
2013-07-10 16:58:41 +00:00
units = u ;
}
}
2020-01-22 13:10:59 +00:00
if ( strcmp ( axis , " time " ) = = 0 ) {
2023-03-04 12:45:31 +00:00
bool onedtime = ( count_values ( cube , " date " ) = = 0 & & count_values ( cube , " step " ) = = 0 ) ;
2022-11-10 19:18:43 +00:00
snprintf ( u , sizeof ( u ) , " hours since 0000-00-00 00:00:00.0 " ) ;
2013-07-10 16:58:41 +00:00
longname = " reference_time " ;
2020-01-22 13:10:59 +00:00
if ( setup . usevalidtime | | onedtime ) {
2022-11-10 19:18:43 +00:00
snprintf ( u , sizeof ( u ) , " hours since %ld-%02ld-%02ld 00:00:00.0 " , setup . refdate / 10000 , ( setup . refdate % 10000 ) / 100 , ( setup . refdate % 100 ) ) ;
2013-07-10 16:58:41 +00:00
longname = " time " ;
}
2020-01-22 13:10:59 +00:00
if ( setup . climatology ) {
2022-11-10 19:18:43 +00:00
snprintf ( u , sizeof ( u ) , " hours " ) ;
2013-07-10 16:58:41 +00:00
}
units = u ;
/* nctype = NC_FLOAT; */
}
2020-01-22 13:10:59 +00:00
if ( strcmp ( axis , " step " ) = = 0 ) {
units = " hours " ;
2013-07-10 16:58:41 +00:00
longname = " time_step " ;
2020-01-22 13:10:59 +00:00
if ( count_values ( cube , " date " ) = = 0 & & count_values ( cube , " time " ) = = 0 ) {
const char * d = get_value ( data_r , " date " , 0 ) ;
const char * t = get_value ( data_r , " time " , 0 ) ;
long date = d ? atol ( d ) : 0 ;
long hour = t ? atol ( t ) : 0 ;
long min = t ? 60 * ( atof ( t ) - hour ) : 0 ;
2022-11-10 19:18:43 +00:00
snprintf ( u , sizeof ( u ) , " hours since %ld-%02ld-%02ld %02ld:%02ld:00.0 " , date / 10000 , ( date % 10000 ) / 100 , ( date % 100 ) , hour , min ) ;
2013-07-10 16:58:41 +00:00
units = u ;
}
}
2020-01-22 13:10:59 +00:00
if ( ( strcmp ( axis , " fcmonth " ) = = 0 ) ) {
const char * date = get_value ( data_r , " date " , 0 ) ;
char ymd [ 32 ] = " " ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( date ) {
2013-07-10 16:58:41 +00:00
strncat ( ymd , date , 4 ) ;
strcat ( ymd , " - " ) ;
strncat ( ymd , date + 4 , 2 ) ;
strcat ( ymd , " - " ) ;
/* udunits is a bit tricky with month being 30.4 days */
/* ncview doesn't display properly */
strcat ( ymd , " 01 " ) ;
}
2020-01-22 13:10:59 +00:00
else {
2022-11-10 19:18:43 +00:00
snprintf ( ymd , sizeof ( ymd ) , " 00-00-00 " ) ;
2013-07-10 16:58:41 +00:00
}
2022-11-10 19:18:43 +00:00
snprintf ( u , sizeof ( u ) , " months since %s 00:00:00.0 " , ymd ) ;
2020-01-22 13:10:59 +00:00
units = u ;
2013-07-10 16:58:41 +00:00
longname = " time " ;
}
var_id = set_dimension ( ncid , lowaxis , n , nctype , units , longname ) ;
2020-01-22 13:10:59 +00:00
if ( strcmp ( axis , " time " ) = = 0 ) {
if ( setup . usevalidtime ) {
const char * cal = " gregorian " ;
if ( setup . mmeans ) {
2023-01-06 19:14:02 +00:00
const char * period = " 0000-01-00 00:00:00 " ;
2020-01-22 13:10:59 +00:00
stat = nc_put_att_text ( ncid , var_id , " avg_period " , strlen ( period ) , period ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_text " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
}
2014-11-03 18:36:17 +00:00
stat = nc_put_att_text ( ncid , var_id , " calendar " , strlen ( cal ) , cal ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_text " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
}
}
}
/* Define data dimension */
n = 1 + 1 + naxis ; /* longitude + latitude + # axis */
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < n ; + + i )
2013-07-10 16:58:41 +00:00
dims [ i ] = n - i - 1 ;
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < subsetcnt ; + + i ) {
2020-07-17 14:37:57 +00:00
printf ( " %s: Defining variable '%s'. \n " , tool_name , subsets [ i ] . att . name ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
stat = nc_def_var ( ncid , subsets [ i ] . att . name , subsets [ i ] . att . nctype , n , dims , & var_id ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_def_var " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( setup . deflate > - 1 ) {
2018-05-29 12:52:44 +00:00
# ifdef NC_NETCDF4
2017-08-08 13:52:47 +00:00
stat = nc_def_var_chunking ( ncid , var_id , NC_CHUNKED , chunks ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_def_var_chunking " , stat , __LINE__ ) ;
2017-07-16 11:22:52 +00:00
2017-08-08 13:52:47 +00:00
/* Set compression settings for a variable */
2017-07-16 11:22:52 +00:00
stat = nc_def_var_deflate ( ncid , var_id , setup . shuffle , 1 , setup . deflate ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_def_var_deflate " , stat , __LINE__ ) ;
2018-05-29 12:52:44 +00:00
# else
2020-08-29 11:45:41 +00:00
( void ) chunks ;
2022-01-07 14:28:05 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Deflate option only supported in netCDF4 " ) ;
2018-05-29 12:52:44 +00:00
# endif
2017-07-16 11:22:52 +00:00
}
2020-01-22 13:10:59 +00:00
if ( subsets [ i ] . scale ) {
2013-07-10 16:58:41 +00:00
compute_scale ( & subsets [ i ] ) ;
stat = nc_put_att_double ( ncid , var_id , " scale_factor " , NC_DOUBLE , 1 , & subsets [ i ] . scale_factor ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_double " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
stat = nc_put_att_double ( ncid , var_id , " add_offset " , NC_DOUBLE , 1 , & subsets [ i ] . add_offset ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_double " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
}
2016-04-07 13:16:02 +00:00
stat = nc_put_att_type ( ncid , var_id , " _FillValue " , subsets [ i ] . att . nctype , 1 , nc_type_values [ subsets [ i ] . att . nctype ] . nc_type_missing ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_type " , stat , __LINE__ ) ;
2016-04-07 13:16:02 +00:00
stat = nc_put_att_type ( ncid , var_id , " missing_value " , subsets [ i ] . att . nctype , 1 , nc_type_values [ subsets [ i ] . att . nctype ] . nc_type_missing ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_type " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( subsets [ i ] . att . units ) {
const char * txt = subsets [ i ] . att . units ;
stat = nc_put_att_text ( ncid , var_id , " units " , strlen ( txt ) , txt ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_text " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
if ( subsets [ i ] . att . long_name ) {
const char * txt = subsets [ i ] . att . long_name ;
stat = nc_put_att_text ( ncid , var_id , " long_name " , strlen ( txt ) , txt ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_text " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
if ( subsets [ i ] . att . short_name ) {
const char * txt = subsets [ i ] . att . short_name ;
stat = nc_put_att_text ( ncid , var_id , " short_name " , strlen ( txt ) , txt ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_text " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
if ( subsets [ i ] . att . standard_name ) {
const char * txt = subsets [ i ] . att . standard_name ;
stat = nc_put_att_text ( ncid , var_id , " standard_name " , strlen ( txt ) , txt ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_text " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
}
2013-03-25 12:04:10 +00:00
2023-06-25 15:01:22 +00:00
// if(subsets[i].att.other)
// {
// const char *txt = subsets[i].att.long_name;
// stat = nc_put_att_text(ncid, var_id, "other",strlen(txt),txt);
// check_err("nc_put_att_text", stat,__LINE__,__FILE__);
// }
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( subsets [ i ] . att . metadata ) {
parameter * p = subsets [ i ] . att . metadata - > params ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
while ( p ) {
const char * txt = p - > values - > name ;
stat = nc_put_att_text ( ncid , var_id , p - > name , strlen ( txt ) , txt ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_text " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
p = p - > next ;
}
}
}
/* Dimension-less variable for MARS request */
2023-01-08 15:23:24 +00:00
if ( ( 0 ) ) /* reset when we have proper & fast mars_description */
2013-07-10 16:58:41 +00:00
{
/* parameter *p = data_r->params; */
2020-01-22 13:10:59 +00:00
parameter * p = setup . mars_description - > params ;
stat = nc_def_var ( ncid , " MARS " , NC_CHAR , 0 , 0 , & var_id ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_def_var " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
/* Store request for those parameters with single value */
2020-01-22 13:10:59 +00:00
while ( p ) {
2013-07-10 16:58:41 +00:00
/* if((p->name[0] != '_') && (p->count == 1)) */
2020-01-22 13:10:59 +00:00
if ( p - > name [ 0 ] ! = ' _ ' ) {
2013-07-10 16:58:41 +00:00
char par [ 1024 ] ;
char val [ 1024000 ] = " " ;
2022-11-10 19:18:43 +00:00
snprintf ( par , sizeof ( par ) , " %s " , ( p - > name ) ) ;
2013-03-25 12:04:10 +00:00
#if 0
2013-07-10 16:58:41 +00:00
value2string ( p - > values , val ) ;
2013-03-25 12:04:10 +00:00
# else
2022-11-10 19:18:43 +00:00
snprintf ( val , sizeof ( val ) , " %s " , ( p - > values - > name ) ) ;
2013-03-25 12:04:10 +00:00
# endif
2013-07-10 16:58:41 +00:00
stat = nc_put_att_text ( ncid , var_id , par , strlen ( val ) , ( val ) ) ;
2020-01-22 13:10:59 +00:00
if ( stat ! = NC_NOERR ) {
2013-07-10 16:58:41 +00:00
printf ( " Error setting request for %s = %s \n " , par , val ) ;
}
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_text " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
}
p = p - > next ;
}
}
/* Global attributes */
{
char timestamp [ 80 ] ;
time_t now ;
/* char *convention = "MARS;CF"; */
2023-01-06 19:14:02 +00:00
const char * convention = " CF-1.6 " ;
2013-07-10 16:58:41 +00:00
char history [ 10240 ] ;
/* char *institution = "ECMWF Meteorological Archival and Retrieval System"; */
/* Convention */
stat = nc_put_att_text ( ncid , NC_GLOBAL , " Conventions " , strlen ( convention ) , convention ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_text " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
/* Use history provided or Timestamp */
2020-01-22 13:10:59 +00:00
if ( setup . history ) {
2022-11-10 19:18:43 +00:00
snprintf ( history , sizeof ( history ) , " %s " , setup . history ) ;
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
else {
int major = ECCODES_MAJOR_VERSION ;
int minor = ECCODES_MINOR_VERSION ;
2015-02-25 17:42:04 +00:00
int revision = ECCODES_REVISION_VERSION ;
2013-07-10 16:58:41 +00:00
time ( & now ) ;
strftime ( timestamp , sizeof ( timestamp ) , " %Y-%m-%d %H:%M:%S GMT " , gmtime ( & now ) ) ;
2022-11-10 19:18:43 +00:00
snprintf ( history , sizeof ( history ) , " %s by grib_to_netcdf-%d.%d.%d: %s " , timestamp , major , minor , revision , argvString ) ;
2013-07-10 16:58:41 +00:00
}
stat = nc_put_att_text ( ncid , NC_GLOBAL , " history " , strlen ( history ) , history ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_text " , stat , __LINE__ ) ;
2013-03-25 12:04:10 +00:00
2023-06-25 15:01:22 +00:00
//stat = nc_put_att_text(ncid, NC_GLOBAL, "source",strlen(setup.source),setup.source);
//check_err(stat,__LINE__,__FILE__);
//stat = nc_put_att_text(ncid, NC_GLOBAL, "institution",strlen(institution),institution);
//check_err(stat,__LINE__,__FILE__);
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( setup . title ) {
2013-07-10 16:58:41 +00:00
stat = nc_put_att_text ( ncid , NC_GLOBAL , " title " , strlen ( setup . title ) , setup . title ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_att_text " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
}
}
return e ;
2013-03-25 12:04:10 +00:00
}
2018-07-25 12:25:13 +00:00
static size_t string_to_unique_number ( const char * axis , const char * str )
{
size_t result = 0 ;
2020-01-22 13:10:59 +00:00
if ( strcmp ( axis , " type " ) = = 0 ) {
2018-07-25 12:25:13 +00:00
/* TODO: not ideal but capture the most common MARS types */
2020-01-22 13:10:59 +00:00
if ( strcmp ( str , " an " ) = = 0 )
return 2 ;
else if ( strcmp ( str , " fc " ) = = 0 )
return 9 ;
else if ( strcmp ( str , " cf " ) = = 0 )
return 10 ;
else if ( strcmp ( str , " pf " ) = = 0 )
return 11 ;
else if ( strcmp ( str , " em " ) = = 0 )
return 17 ;
else if ( strcmp ( str , " es " ) = = 0 )
return 18 ;
else if ( strcmp ( str , " ep " ) = = 0 )
return 30 ;
else if ( strcmp ( str , " 4i " ) = = 0 )
return 33 ;
else if ( strcmp ( str , " 4g " ) = = 0 )
return 8 ;
else if ( strcmp ( str , " ia " ) = = 0 )
return 3 ;
else if ( strcmp ( str , " efi " ) = = 0 )
return 27 ;
2018-07-25 12:25:13 +00:00
}
/* Fallback general case: Use hashing */
result = 5381 ;
while ( * str ) {
2020-01-22 13:10:59 +00:00
result = 33 * result ^ ( unsigned char ) * str + + ;
2018-07-25 12:25:13 +00:00
}
return result ;
}
2023-07-19 12:52:03 +00:00
2020-01-22 13:10:59 +00:00
static int fill_netcdf_dimensions ( hypercube * h , fieldset * fs , int ncid )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
const request * cube = h - > cube ;
int naxis = count_axis ( h ) ;
int i = 0 ;
int var_id = 0 ;
int stat = 0 ;
2013-07-10 16:58:41 +00:00
/* Put latitude/longitude values */
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: Put latitude/longitude values " ) ;
put_latlon ( ncid , fs ) ;
2022-01-07 14:28:05 +00:00
/* Put netCDF axis values */
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: Put netcdf axis values " ) ;
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < naxis ; + + i ) {
int j = 0 ;
const char * axis = get_axis ( h , i ) ;
int n = count_values ( cube , axis ) ;
int * values = ( int * ) grib_context_malloc ( ctx , sizeof ( int ) * n ) ;
const char * lowaxis = ( axis ) ;
2020-03-19 16:01:10 +00:00
if ( ! values ) {
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " fill_netcdf_dimensions: cannot allocate %ld bytes " , sizeof ( int ) * n ) ;
2020-03-19 16:01:10 +00:00
exit ( 1 ) ;
}
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( strcmp ( " levelist " , axis ) = = 0 )
2013-07-10 16:58:41 +00:00
lowaxis = " level " ;
2020-01-22 13:10:59 +00:00
if ( strcmp ( " date " , axis ) = = 0 ) {
if ( setup . climatology )
for ( j = 0 ; j < n ; + + j )
2013-07-10 16:58:41 +00:00
values [ j ] = monthnumber ( get_value ( cube , axis , j ) ) ;
else
2020-01-22 13:10:59 +00:00
for ( j = 0 ; j < n ; + + j )
2013-07-10 16:58:41 +00:00
values [ j ] = grib_date_to_julian ( atol ( get_value ( cube , axis , j ) ) ) - grib_date_to_julian ( setup . refdate ) ;
}
2020-01-22 13:10:59 +00:00
else {
for ( j = 0 ; j < n ; + + j ) {
long lv = 0 ;
2018-07-25 12:25:13 +00:00
const char * sv = get_value ( cube , axis , j ) ;
if ( is_number ( sv ) ) {
lv = atol ( sv ) ; /* Detect error? */
2020-01-22 13:10:59 +00:00
}
else {
2018-07-25 12:25:13 +00:00
/* ECC-725: Convert string-valued dimension to integer
* e . g . mars type or stream */
lv = string_to_unique_number ( axis , sv ) ;
}
values [ j ] = lv ;
}
2013-07-10 16:58:41 +00:00
}
stat = nc_inq_varid ( ncid , ( lowaxis ) , & var_id ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_inq_varid " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
2014-10-31 15:36:37 +00:00
/* if ( strcmp("time", axis) == 0 && setup.unlimited != NULL && strcmp(setup.unlimited, "time") == 0 && setup.usevalidtime) */
/* GRIB-437, GRIB-625 Special treatment of RECORD (unlimited) dimension */
/* See "The NetCDF C Interface Guide" Section 6.23 */
2020-01-22 13:10:59 +00:00
if ( setup . unlimited ! = NULL & & strcmp ( setup . unlimited , axis ) = = 0 ) {
2014-10-31 15:36:37 +00:00
/* This is tricky. I'm not sure it works when this dimension is not outer dimension */
2013-07-10 16:58:41 +00:00
size_t start [ NC_MAX_DIMS ] ;
size_t count [ NC_MAX_DIMS ] ;
2014-10-31 15:36:37 +00:00
nc_type dim_type = 0 ;
2013-07-10 16:58:41 +00:00
start [ 0 ] = 0 ;
count [ 0 ] = n ;
2014-10-31 15:36:37 +00:00
stat = nc_inq_vartype ( ncid , var_id , & dim_type ) ; /* get the type of this dimension */
2019-11-21 12:00:02 +00:00
check_err ( " nc_inq_vartype " , stat , __LINE__ ) ;
2014-10-31 15:36:37 +00:00
stat = nc_put_vara_type ( ncid , var_id , start , count , values , dim_type ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_vara_type " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
else {
2013-07-10 16:58:41 +00:00
stat = nc_put_var_int ( ncid , var_id , values ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_put_var_int " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
}
grib_context_free ( ctx , values ) ;
}
return 0 ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void remove_param ( request * r , void * data , const char * p )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
request * config = ( request * ) data ;
const char * ignore ;
2013-07-10 16:58:41 +00:00
int i = 0 ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
while ( ( ignore = get_value ( config , p , i + + ) ) ! = NULL ) {
2013-07-10 16:58:41 +00:00
unset_value ( r , ignore ) ;
2014-11-13 14:16:43 +00:00
}
}
static void print_ignored_keys ( FILE * f , request * data )
{
2020-01-22 13:10:59 +00:00
const char * ignore = NULL ;
int i = 0 ;
2014-11-13 14:16:43 +00:00
while ( ( ignore = get_value ( data , " ignore " , i ) ) ! = NULL ) {
2020-01-22 13:10:59 +00:00
if ( i = = 0 ) {
2020-07-17 14:37:57 +00:00
fprintf ( f , " %s: Ignoring key(s): %s " , tool_name , ignore ) ;
2020-01-22 13:10:59 +00:00
}
else {
2014-11-13 14:16:43 +00:00
fprintf ( f , " , %s " , ignore ) ;
}
+ + i ;
}
2020-01-22 13:10:59 +00:00
if ( i > 0 )
fprintf ( f , " \n " ) ;
2013-03-25 12:04:10 +00:00
}
# define NO_TABLE -1
2020-01-22 13:10:59 +00:00
# define NO_PARAM 0
2013-03-25 12:04:10 +00:00
2023-03-04 12:45:31 +00:00
static void paramtable ( const char * p , long * param , long * table , bool paramIdMode )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
const char * q = p ;
int len = strlen ( p ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
* param = atol ( p ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
while ( p & & ( * p ! = ' . ' ) & & ( ( p - q ) < len ) )
2013-07-10 16:58:41 +00:00
+ + p ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( ( * p = = ' . ' ) )
2013-07-10 16:58:41 +00:00
* table = atol ( + + p ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
/* This version is grib_api... It should rely on what grib_api returns,
2013-07-22 13:06:46 +00:00
either param . table or paramId
2013-07-10 16:58:41 +00:00
*/
2020-01-22 13:10:59 +00:00
if ( paramIdMode ) {
2013-07-10 16:58:41 +00:00
/* Special case for param=228015 => 15.228 */
2020-01-22 13:10:59 +00:00
if ( ( * param ! = NO_PARAM ) & & ( * table = = NO_TABLE ) & & ( len = = 6 ) ) {
2013-07-10 16:58:41 +00:00
char tbl [ 4 ] ;
char par [ 4 ] ;
p = q ;
strncpy ( tbl , p , 3 ) ;
tbl [ 3 ] = ' \0 ' ;
strncpy ( par , p + 3 , 3 ) ;
par [ 3 ] = ' \0 ' ;
* param = atol ( par ) ;
* table = atol ( tbl ) ;
}
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void find_nc_attributes ( const request * subset_r , const request * user_r , ncatt_t * att , const request * config_r , const request * data_r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
const char * split = NULL ;
int j = 0 ;
2023-03-04 12:45:31 +00:00
bool set_param_as_name = true ;
2020-01-22 13:10:59 +00:00
long datatable = 0 ; /* = atol(get_value(data_r,"_CODETABLE2",0)); */
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( count_values ( user_r , " split " ) = = 0 )
2013-07-10 16:58:41 +00:00
strcat ( att - > name , " data " ) ;
2020-01-22 13:10:59 +00:00
while ( ( split = get_value ( user_r , " split " , j + + ) ) ! = NULL ) {
if ( strcmp ( split , " param " ) ! = 0 ) {
if ( count_values ( data_r , split ) > 1 )
2023-03-04 12:45:31 +00:00
set_param_as_name = false ;
2013-07-10 16:58:41 +00:00
}
}
j = 0 ;
2020-01-22 13:10:59 +00:00
while ( ( split = get_value ( user_r , " split " , j + + ) ) ! = NULL ) {
2023-03-04 12:45:31 +00:00
bool found = false ;
2020-01-22 13:10:59 +00:00
request * cfg = ( request * ) config_r ;
2023-03-04 12:45:31 +00:00
bool is_param = strcmp ( split , " param " ) = = 0 ;
2013-07-10 16:58:41 +00:00
/* Only use this parameter in the name if there is more
2013-07-22 13:06:46 +00:00
than one value in the original request or if param */
2023-03-04 12:45:31 +00:00
bool setname = ( ( count_values ( data_r , split ) > 1 ) | | ( is_param & & set_param_as_name ) ) ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
while ( cfg ) {
const char * cfgname = get_value ( cfg , " NAME " , 0 ) ;
const char * cfgval = get_value ( cfg , " VALUE " , 0 ) ;
const char * dataval = NULL ;
int i = 0 ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( strcmp ( split , cfgname ) = = 0 ) {
while ( ( dataval = get_value ( subset_r , cfgname , i + + ) ) ! = NULL ) {
const char * tablestr = get_value ( cfg , " TABLE2 " , 0 ) ;
long cfgtable = ( is_param & & tablestr ! = NULL ) ? atol ( get_value ( cfg , " TABLE2 " , 0 ) ) : - 1 ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
long cfgparam = atol ( cfgval ) ;
2013-07-10 16:58:41 +00:00
long dataparam = atol ( dataval ) ;
2023-03-04 12:45:31 +00:00
paramtable ( dataval , & dataparam , & datatable , false ) ;
2013-07-10 16:58:41 +00:00
/* If it is not param and they're EXACTLY equal or
2013-07-22 13:06:46 +00:00
being param , they ' re the same parameter and table */
2020-01-22 13:10:59 +00:00
if ( ( ! is_param & & ( strcmp ( dataval , cfgval ) = = 0 ) ) | | ( is_param & & ( dataparam = = cfgparam ) & & ( datatable = = cfgtable | | ( datatable = = 0 & & ( cfgtable = = 128 ) ) ) ) ) {
const char * val = NULL ;
const char * metafile = NULL ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( ( val = get_value ( cfg , " accuracy " , 0 ) ) ! = NULL )
2013-07-10 16:58:41 +00:00
att - > nctype = translate_nctype ( val ) ;
2020-01-22 13:10:59 +00:00
att - > long_name = grib_context_strdup ( ctx , ( get_value ( cfg , " LONG_NAME " , 0 ) ) ) ;
2013-07-10 16:58:41 +00:00
att - > short_name = grib_context_strdup ( ctx , ( get_value ( cfg , " SHORT_NAME " , 0 ) ) ) ;
2020-01-22 13:10:59 +00:00
att - > units = grib_context_strdup ( ctx , ( get_value ( cfg , " UNITS " , 0 ) ) ) ;
2013-07-10 16:58:41 +00:00
/* Check if there is more metadata for this variable */
2020-01-22 13:10:59 +00:00
if ( ( metafile = get_value ( cfg , " METADATA " , 0 ) ) ! = NULL ) {
static const char * metadata_dir = NULL ;
2013-07-10 16:58:41 +00:00
char metapath [ 1024 ] ;
2020-01-22 13:10:59 +00:00
if ( ! metadata_dir )
2013-07-10 16:58:41 +00:00
metadata_dir = getenv ( " METADATA_DIR " ) ;
2022-11-10 19:18:43 +00:00
snprintf ( metapath , sizeof ( metapath ) , " %s/%s " , metadata_dir ? metadata_dir : " . " , metafile ) ;
2020-01-22 13:10:59 +00:00
att - > metadata = 0 ; /* read_request_file(metapath); */
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
if ( setname ) {
const char * pname = get_value ( cfg , " DATA " , 0 ) ;
if ( strlen ( att - > name ) )
2013-07-10 16:58:41 +00:00
strcat ( att - > name , " _ " ) ;
strcat ( att - > name , pname ) ;
}
2023-03-04 12:45:31 +00:00
found = true ;
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: Var. name found: '%s' " , att - > name ) ;
}
}
}
cfg = cfg - > next ;
}
/* We have not found configuration for this attribute */
2020-01-22 13:10:59 +00:00
if ( ! found ) {
const char * val = get_value ( subset_r , split , 0 ) ;
if ( val & & ( setname ) ) {
if ( strlen ( att - > name ) )
2013-07-10 16:58:41 +00:00
strcat ( att - > name , " _ " ) ;
strcat ( att - > name , val ) ;
}
}
}
2013-07-22 13:06:46 +00:00
/* NetCDF does not allow variable names to start with a digit */
2020-01-22 13:10:59 +00:00
if ( ! isalpha ( att - > name [ 0 ] ) ) {
2018-02-02 09:54:40 +00:00
char buf [ 1048 ] ;
2020-01-22 13:10:59 +00:00
const char * val = get_value ( subset_r , " param " , 0 ) ;
2022-11-10 19:18:43 +00:00
snprintf ( buf , sizeof ( buf ) , " %s_%s " , ( val ? val : " p " ) , att - > name ) ;
2020-01-22 13:10:59 +00:00
strcpy ( att - > name , buf ) ;
2013-07-10 16:58:41 +00:00
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static request * first ;
static request * last ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
static void reqcb ( const request * r , int count , axis_t * names , char * vals [ ] , void * data )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
request * w = clone_one_request ( r ) ;
2013-07-10 16:58:41 +00:00
int i ;
/*request **d = (request**)data;*/
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
int * n = ( int * ) data ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
w - > order = ( * n ) + + ;
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < count ; i + + ) {
if ( vals [ i ] )
2023-03-04 12:45:31 +00:00
put_value ( w , names [ i ] . name , vals [ i ] , false , false , false ) ;
2013-07-10 16:58:41 +00:00
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( first = = NULL )
2013-07-10 16:58:41 +00:00
first = w ;
else
last - > next = w ;
last = w ;
2013-03-25 12:04:10 +00:00
}
2023-03-04 12:45:31 +00:00
static bool chk_152 ( int count , axis_t * names , char * vals [ ] )
2013-03-25 12:04:10 +00:00
{
2023-03-04 12:45:31 +00:00
return true ;
2013-03-25 12:04:10 +00:00
}
2023-03-04 12:45:31 +00:00
static void loop ( const request * r , bool ml , int index , int count , axis_t * strings , char * values [ ] , loopproc callback , void * data )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
if ( index < count ) {
parameter * p = find_parameter ( r , strings [ index ] . name ) ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
( void ) count_values ( r , strings [ index ] . name ) ; /* force list expansion */
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( p ) {
value * v = p - > values ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
while ( v ) {
2013-07-10 16:58:41 +00:00
values [ index ] = v - > name ;
loop ( r , ml , index + 1 , count , strings , values , callback , data ) ;
v = v - > next ;
}
}
2020-01-22 13:10:59 +00:00
else {
2013-07-10 16:58:41 +00:00
values [ index ] = NULL ;
loop ( r , ml , index + 1 , count , strings , values , callback , data ) ;
}
}
2020-01-22 13:10:59 +00:00
else if ( ! ml | | chk_152 ( count , strings , values ) )
2013-07-10 16:58:41 +00:00
callback ( r , count , strings , values , data ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void values_loop ( const request * r , int count , axis_t * parnames , loopproc callback , void * data )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
char * * values = ( char * * ) grib_context_malloc ( ctx , sizeof ( char * ) * count ) ;
const char * p = get_value ( r , " levtype " , 0 ) ;
2023-03-04 12:45:31 +00:00
bool ml = ( bool ) ( p & & ( strcmp ( p , " ml " ) = = 0 ) ) ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( ml ) {
2013-07-10 16:58:41 +00:00
p = get_value ( r , " expect " , 0 ) ;
2020-01-22 13:10:59 +00:00
if ( p & & atol ( p ) ! = 0 ) {
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " EXPECT provided, special treatment of LNSP " ) ;
grib_context_log ( ctx , GRIB_LOG_ERROR , " and other single level parameters disabled " ) ;
2023-03-04 12:45:31 +00:00
ml = false ;
2013-07-10 16:58:41 +00:00
}
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
loop ( r , ml , 0 , count , parnames , values , callback , data ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , values ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void names_loop ( const request * r , loopproc proc , void * data )
2013-03-25 12:04:10 +00:00
{
2013-08-13 10:03:31 +00:00
values_loop ( r , NUMBER ( global_axis ) , global_axis , proc , data ) ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static request * unwind_one_request ( const request * r )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
int n = 0 ;
first = last = NULL ;
names_loop ( r , reqcb , & n ) ;
return first ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static int split_fieldset ( fieldset * fs , request * data_r , dataset_t * * subsets , const request * user_r , const request * config_r )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
const char * split = NULL ;
int count = 1 ;
int i = 0 ;
request * s = NULL ;
request * u = NULL ;
dataset_t * filters = NULL ;
nc_type nctype = translate_nctype ( get_value ( user_r , " accuracy " , 0 ) ) ;
2013-07-10 16:58:41 +00:00
s = empty_request ( " filter " ) ;
2020-01-22 13:10:59 +00:00
while ( ( split = get_value ( user_r , " split " , i + + ) ) ! = NULL ) {
2013-07-10 16:58:41 +00:00
int cnt = count_values ( data_r , split ) ;
2020-01-22 13:10:59 +00:00
if ( cnt ) {
2013-07-10 16:58:41 +00:00
count * = count_values ( data_r , split ) ;
2020-01-22 13:10:59 +00:00
valcpy ( s , data_r , ( char * ) split , ( char * ) split ) ;
2013-07-10 16:58:41 +00:00
}
}
u = unwind_one_request ( s ) ;
free_all_requests ( s ) ;
2014-10-02 16:23:43 +00:00
filters = ( dataset_t * ) calloc ( sizeof ( dataset_t ) , count ) ;
2013-07-10 16:58:41 +00:00
Assert ( filters ) ;
s = u ;
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < count ; + + i ) {
2013-07-10 16:58:41 +00:00
Assert ( s ) ;
2020-01-22 13:10:59 +00:00
filters [ i ] . filter = new_hypercube_from_mars_request ( s ) ;
filters [ i ] . fset = new_fieldset ( 1 ) ;
filters [ i ] . count = 0 ;
2014-10-02 16:23:43 +00:00
filters [ i ] . filter_request = clone_one_request ( s ) ;
2023-03-04 12:45:31 +00:00
filters [ i ] . bitmap = false ;
/* filters[i].mmeans = false; */
2013-07-10 16:58:41 +00:00
s = s - > next ;
}
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < fs - > count ; + + i ) {
2023-03-04 12:45:31 +00:00
bool ok = false ;
2020-01-22 13:10:59 +00:00
field * f = get_field ( fs , i , packed_mem ) ;
request * g = field_to_request ( f ) ;
int j = 0 ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
while ( ! ok & & ( j < count ) ) {
2013-07-10 16:58:41 +00:00
ok = ( cube_order ( filters [ j ] . filter , g ) ! = - 1 ) ;
2020-01-22 13:10:59 +00:00
if ( ok ) {
const char * p ;
2013-07-10 16:58:41 +00:00
set_field ( filters [ j ] . fset , f , filters [ j ] . count + + ) ;
2016-04-07 13:16:02 +00:00
filters [ j ] . bitmap | = f - > has_bitmap ;
2020-01-22 13:10:59 +00:00
if ( ( p = get_value ( f - > r - > r , " _units " , 0 ) ) ! = NULL ) {
2013-07-10 16:58:41 +00:00
filters [ j ] . att . units = grib_context_strdup ( ctx , p ) ;
}
2020-01-22 13:10:59 +00:00
if ( ( p = get_value ( f - > r - > r , " _long_name " , 0 ) ) ! = NULL ) {
2013-07-10 16:58:41 +00:00
filters [ j ] . att . long_name = grib_context_strdup ( ctx , p ) ;
}
2020-01-22 13:10:59 +00:00
if ( ( p = get_value ( f - > r - > r , " _cf_name " , 0 ) ) ! = NULL ) {
2013-07-10 16:58:41 +00:00
filters [ j ] . att . standard_name = grib_context_strdup ( ctx , p ) ;
}
}
j + + ;
}
2020-01-22 13:10:59 +00:00
if ( ! ok ) {
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal error. Lost field %d while splitting fieldset " , i ) ;
print_all_requests ( g ) ;
grib_context_log ( ctx , GRIB_LOG_ERROR , " count is %d " , count ) ;
grib_context_log ( ctx , GRIB_LOG_ERROR , " First cube is: " ) ;
print_hypercube ( filters [ 0 ] . filter ) ;
exit ( 1 ) ;
}
2023-03-04 12:45:31 +00:00
/* f->purge_header = true; */
2013-07-10 16:58:41 +00:00
release_field ( f ) ;
}
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < count ; + + i ) {
2013-07-10 16:58:41 +00:00
filters [ i ] . att . nctype = nctype ;
2023-03-04 12:45:31 +00:00
filters [ i ] . scale = true ;
2020-01-22 13:10:59 +00:00
filters [ i ] . missing = nc_type_values [ nctype ] . nc_type_missing ;
2014-10-02 16:23:43 +00:00
find_nc_attributes ( filters [ i ] . filter_request , user_r , & ( filters [ i ] . att ) , config_r , data_r ) ;
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: filter[%d] found.- Var. name '%s', nctype: %d, found nctype: %d " , i , filters [ i ] . att . name , nctype , filters [ i ] . att . nctype ) ;
2020-01-22 13:10:59 +00:00
if ( strlen ( filters [ i ] . att . name ) = = 0 ) {
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Variable name not found " ) ;
exit ( 1 ) ;
}
/* Check if we need scaling */
2020-01-22 13:10:59 +00:00
switch ( filters [ i ] . att . nctype ) {
case NC_FLOAT :
case NC_DOUBLE :
2023-03-04 12:45:31 +00:00
filters [ i ] . scale = false ;
2020-01-22 13:10:59 +00:00
break ;
default :
2023-03-04 12:45:31 +00:00
filters [ i ] . scale = true ;
2020-01-22 13:10:59 +00:00
break ;
2013-07-10 16:58:41 +00:00
}
}
free_all_requests ( u ) ;
* subsets = filters ;
return count ;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void free_subsets ( dataset_t * subsets , int count )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
int i = 0 ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < count ; + + i ) {
2013-07-10 16:58:41 +00:00
grib_context_free ( ctx , subsets [ i ] . att . units ) ;
grib_context_free ( ctx , subsets [ i ] . att . long_name ) ;
grib_context_free ( ctx , subsets [ i ] . att . short_name ) ;
grib_context_free ( ctx , subsets [ i ] . att . standard_name ) ;
free_all_requests ( subsets [ i ] . att . metadata ) ;
free_hypercube ( subsets [ i ] . filter ) ;
free_fieldset ( subsets [ i ] . fset ) ;
2014-10-02 16:23:43 +00:00
free_all_requests ( subsets [ i ] . filter_request ) ;
2013-07-10 16:58:41 +00:00
}
grib_context_free ( ctx , subsets ) ;
2013-08-16 11:56:13 +00:00
}
2013-03-25 12:04:10 +00:00
2013-08-16 11:56:13 +00:00
/* Return the number of the given month or -1 if it fails to match */
static int convert_month ( const char * pMonthString )
{
2020-01-22 13:10:59 +00:00
if ( strcmp ( pMonthString , " jan " ) = = 0 )
return 1 ;
if ( strcmp ( pMonthString , " feb " ) = = 0 )
return 2 ;
if ( strcmp ( pMonthString , " mar " ) = = 0 )
return 3 ;
if ( strcmp ( pMonthString , " apr " ) = = 0 )
return 4 ;
if ( strcmp ( pMonthString , " may " ) = = 0 )
return 5 ;
if ( strcmp ( pMonthString , " jun " ) = = 0 )
return 6 ;
if ( strcmp ( pMonthString , " jul " ) = = 0 )
return 7 ;
if ( strcmp ( pMonthString , " aug " ) = = 0 )
return 8 ;
if ( strcmp ( pMonthString , " sep " ) = = 0 )
return 9 ;
if ( strcmp ( pMonthString , " oct " ) = = 0 )
return 10 ;
if ( strcmp ( pMonthString , " nov " ) = = 0 )
return 11 ;
if ( strcmp ( pMonthString , " dec " ) = = 0 )
return 12 ;
2013-08-16 11:56:13 +00:00
return - 1 ; /*Failed*/
2013-03-25 12:04:10 +00:00
}
2023-03-04 12:45:31 +00:00
static bool parsedate ( const char * name , long * julian , long * second , bool * isjul )
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
const char * p = name ;
2013-07-10 16:58:41 +00:00
int n ;
int y = 0 , m = 0 , d = 0 , H = 0 , M = 0 , S = 0 ;
* julian = * second = 0 ;
2023-03-04 12:45:31 +00:00
* isjul = false ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( p = = 0 | | * p = = 0 )
2023-03-04 12:45:31 +00:00
return false ;
2013-07-10 16:58:41 +00:00
2013-08-16 11:56:13 +00:00
/* Special ERA Interim grib1 date format: jul-21, sep-02 etc
* See GRIB - 416
*/
2020-01-22 13:10:59 +00:00
if ( isalpha ( * p ) ) {
2013-08-16 11:56:13 +00:00
char month [ 32 ] ;
int day = 0 ;
2023-01-08 15:23:24 +00:00
n = sscanf ( p , " %[^-]-%d " , month , & day ) ;
2013-08-16 11:56:13 +00:00
/* Matched two items (month and day) and month is 3 letters */
if ( n = = 2 & & strlen ( month ) = = 3 ) {
y = 1900 ; /* no year specified */
m = convert_month ( month ) ;
2020-01-22 13:10:59 +00:00
if ( m = = - 1 )
2023-03-04 12:45:31 +00:00
return false ;
2013-08-16 11:56:13 +00:00
* julian = grib_date_to_julian ( y * 10000 + m * 100 + day ) ;
* second = 0 ;
2023-03-04 12:45:31 +00:00
return true ;
2013-08-16 11:56:13 +00:00
}
}
2013-07-10 16:58:41 +00:00
/* year */
p = parse1 ( p , & y , & n ) ;
2020-01-22 13:10:59 +00:00
if ( n ! = 2 & & n ! = 4 ) /* year string must be 2 or 4 characters long: 93 or 1993 */
2023-03-04 12:45:31 +00:00
return false ;
2020-01-22 13:10:59 +00:00
if ( * p + + ! = ' - ' )
2023-03-04 12:45:31 +00:00
return false ;
2013-07-10 16:58:41 +00:00
/* month */
p = parse1 ( p , & m , & n ) ;
2020-01-22 13:10:59 +00:00
if ( n = = 2 ) {
2013-07-10 16:58:41 +00:00
/* day */
2020-01-22 13:10:59 +00:00
if ( * p + + ! = ' - ' )
2023-03-04 12:45:31 +00:00
return false ;
2013-07-10 16:58:41 +00:00
p = parse1 ( p , & d , & n ) ;
2020-01-22 13:10:59 +00:00
if ( n ! = 2 )
2023-03-04 12:45:31 +00:00
return false ;
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
else if ( n = = 3 ) {
2013-07-10 16:58:41 +00:00
long j = grib_date_to_julian ( y * 10000 + 101 ) + m - 1 ;
2020-01-22 13:10:59 +00:00
j = grib_julian_to_date ( j ) ;
2013-07-10 16:58:41 +00:00
/* julian day */ ;
2020-01-22 13:10:59 +00:00
d = j % 100 ;
m = ( j % 10000 ) / 100 ;
2023-03-04 12:45:31 +00:00
* isjul = true ;
2013-07-10 16:58:41 +00:00
}
else
2023-03-04 12:45:31 +00:00
return false ;
2013-07-10 16:58:41 +00:00
2013-08-16 11:56:13 +00:00
if ( m = = 0 | | m > 12 ) {
2023-03-04 12:45:31 +00:00
return false ; /* month out of range */
2013-08-16 11:56:13 +00:00
}
2020-01-22 13:10:59 +00:00
while ( * p & & isspace ( * p ) )
2013-07-10 16:58:41 +00:00
p + + ;
/* hour */
p = parse1 ( p , & H , & n ) ;
2020-01-22 13:10:59 +00:00
if ( n ! = 0 ) {
if ( n ! = 2 )
2023-03-04 12:45:31 +00:00
return false ;
2013-07-10 16:58:41 +00:00
/* minute */
2020-01-22 13:10:59 +00:00
if ( * p + + ! = ' : ' )
2023-03-04 12:45:31 +00:00
return false ;
2013-07-10 16:58:41 +00:00
p = parse1 ( p , & M , & n ) ;
2020-01-22 13:10:59 +00:00
if ( n ! = 2 )
2023-03-04 12:45:31 +00:00
return false ;
2013-07-10 16:58:41 +00:00
2020-01-22 13:10:59 +00:00
if ( * p ! = 0 ) {
2013-07-10 16:58:41 +00:00
/* second */
2020-01-22 13:10:59 +00:00
if ( * p + + ! = ' : ' )
2023-03-04 12:45:31 +00:00
return false ;
2013-07-10 16:58:41 +00:00
p = parse1 ( p , & S , & n ) ;
2020-01-22 13:10:59 +00:00
if ( n ! = 2 )
2023-03-04 12:45:31 +00:00
return false ;
2013-07-10 16:58:41 +00:00
}
}
* julian = grib_date_to_julian ( y * 10000 + m * 100 + d ) ;
* second = H * 3600 + M * 60 + S ;
2023-03-04 12:45:31 +00:00
return * p = = 0 ? true : false ;
2013-03-25 12:04:10 +00:00
}
2023-03-04 12:45:31 +00:00
static bool check_dimension_name ( const char * dim )
2014-10-29 13:03:04 +00:00
{
/* Dimension name must begin with an alphabetic character, followed by zero
* or more alphanumeric characters including the underscore */
int i = 0 , len = 0 ;
2020-01-22 13:10:59 +00:00
if ( ! dim )
2023-03-04 12:45:31 +00:00
return false ;
2014-10-29 13:03:04 +00:00
len = strlen ( dim ) ;
2020-01-22 13:10:59 +00:00
if ( len = = 0 )
2023-03-04 12:45:31 +00:00
return false ;
2020-01-22 13:10:59 +00:00
if ( ! isalpha ( dim [ 0 ] ) )
2023-03-04 12:45:31 +00:00
return false ;
2014-10-29 13:03:04 +00:00
2020-01-22 13:10:59 +00:00
for ( i = 1 ; i < len ; + + i ) {
2014-10-29 13:03:04 +00:00
const char c = dim [ i ] ;
const int ok = isalnum ( c ) | | c = = ' _ ' ;
2020-01-22 13:10:59 +00:00
if ( ! ok )
2023-03-04 12:45:31 +00:00
return false ;
2014-10-29 13:03:04 +00:00
}
2023-03-04 12:45:31 +00:00
return true ;
2014-10-29 13:03:04 +00:00
}
2015-01-07 11:48:17 +00:00
static int get_creation_mode ( int option_kind )
{
/* Return the mode flag for nc_create based */
2022-01-07 14:28:05 +00:00
/* on the kind of netCDF user wants to create */
2015-01-07 11:48:17 +00:00
int creation_mode = NC_CLOBBER ;
2020-01-22 13:10:59 +00:00
switch ( option_kind ) {
case NC_FORMAT_CLASSIC :
2020-07-17 14:37:57 +00:00
printf ( " %s: Creating classic file format. \n " , tool_name ) ;
2020-01-22 13:10:59 +00:00
break ;
case NC_FORMAT_64BIT :
creation_mode | = NC_64BIT_OFFSET ;
2020-07-17 14:37:57 +00:00
printf ( " %s: Creating large (64 bit) file format. \n " , tool_name ) ;
2020-01-22 13:10:59 +00:00
break ;
2015-01-07 11:48:17 +00:00
# ifdef NC_NETCDF4
2020-01-22 13:10:59 +00:00
case NC_FORMAT_NETCDF4 :
creation_mode | = NC_NETCDF4 ;
2020-07-17 14:37:57 +00:00
printf ( " %s: Creating netCDF-4/HDF5 format. \n " , tool_name ) ;
2020-01-22 13:10:59 +00:00
break ;
case NC_FORMAT_NETCDF4_CLASSIC :
creation_mode | = NC_NETCDF4 | NC_CLASSIC_MODEL ;
2020-07-17 14:37:57 +00:00
printf ( " %s: Creating netCDF-4 classic model file format. \n " , tool_name ) ;
2020-01-22 13:10:59 +00:00
break ;
2015-01-07 11:48:17 +00:00
# else
2020-01-22 13:10:59 +00:00
case NC_FORMAT_NETCDF4 :
case NC_FORMAT_NETCDF4_CLASSIC :
2022-01-07 14:28:05 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " %s not built with netCDF4, cannot create netCDF-4 files. " , tool_name ) ;
2020-01-22 13:10:59 +00:00
exit ( 1 ) ;
break ;
2015-01-07 11:48:17 +00:00
# endif
2020-01-22 13:10:59 +00:00
default :
fprintf ( stderr , " Bad value (%d) for -k option \n " , option_kind ) ;
exit ( 1 ) ;
break ;
2015-01-07 11:48:17 +00:00
}
return creation_mode ;
}
2013-03-25 12:04:10 +00:00
/*=====================================================================*/
2013-06-07 10:27:06 +00:00
grib_option grib_options [ ] = {
2020-01-22 13:10:59 +00:00
{ " I: " , " key1,key2,... " , " \n \t \t Ignore keys. Default method,type,stream,refdate,hdate \n " , 0 , 1 , " method,type,stream,refdate,hdate " } ,
{ " S: " , " key1,key2,... " , " \n \t \t Split according to keys. Default param,expver \n " , 0 , 1 , " param,expver " } ,
{ " R: " , " date " , " \n \t \t Reference date in the format YYYYMMDD. Default value 19000101. \n " , 0 , 1 , " 19000101 " } ,
{ " D: " , " NC_DATATYPE " ,
" \n \t \t Type of data. Possible values NC_BYTE, NC_SHORT, NC_INT, NC_FLOAT, NC_DOUBLE. "
" \n \t \t Default NC_SHORT \n " ,
0 , 1 , " NC_SHORT " } ,
{ " T " , 0 , " Don't use time of validity. \n " , 0 , 1 , 0 } ,
{ " f " , 0 , 0 , 0 , 1 , 0 } ,
2022-01-07 14:28:05 +00:00
{ " o: " , " output_file " , " \n \t \t The name of the netCDF output file. \n " , 1 , 1 , 0 } ,
2020-01-22 13:10:59 +00:00
{ " V " , 0 , 0 , 0 , 1 , 0 } ,
{ " M " , 0 , 0 , 0 , 1 , 0 } ,
{ " k: " , " kind " ,
" \n \t \t Specifies the kind of file to be created. Possible values are: "
" \n \t \t 1 -> netCDF classic file format "
" \n \t \t 2 -> netCDF 64 bit classic file format (Default) "
" \n \t \t 3 -> netCDF-4 file format "
" \n \t \t 4 -> netCDF-4 classic model file format \n " ,
0 , 1 , " 2 " } ,
{ " d: " , " level " ,
" \n \t \t Deflate data (compression level). Only for netCDF-4 output format. "
" \n \t \t Possible values [0,9]. Default None. "
" \n \t \t Chunking strategy based on GRIB message. \n " ,
0 , 1 , " 6 " } ,
{ " s " , 0 , " Shuffle data before deflation compression. \n " , 0 , 1 , 0 } ,
2023-11-02 19:52:42 +00:00
{ " u: " , " dimension " , " \n \t \t Set dimension to be an unlimited dimension. \n " , 0 , 1 , " time " } ,
{ " h " , 0 , 0 , 0 , 1 , 0 } ,
2013-06-07 10:27:06 +00:00
} ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
int grib_options_count = sizeof ( grib_options ) / sizeof ( grib_option ) ;
static fieldset * fs = NULL ;
static request * data_r = NULL ;
request * user_r = NULL ;
static int option_kind = 2 ; /* By default NetCDF3, 64-bit offset */
2017-07-16 11:22:52 +00:00
static int deflate_option = 0 ;
2015-01-07 11:48:17 +00:00
/* Table of formats for legal -k values. Inspired by nccopy */
2020-01-22 13:10:59 +00:00
struct KindValue
{
2023-01-06 19:14:02 +00:00
const char * name ;
2015-01-07 11:48:17 +00:00
int kind ;
} legalkinds [ ] = {
2020-01-22 13:10:59 +00:00
{ " 1 " , NC_FORMAT_CLASSIC } ,
{ " classic " , NC_FORMAT_CLASSIC } ,
/* The 64-bit offset kind */
{ " 2 " , NC_FORMAT_64BIT } ,
{ " 64-bit-offset " , NC_FORMAT_64BIT } ,
{ " 64-bit offset " , NC_FORMAT_64BIT } ,
/* NetCDF-4 HDF5 format */
{ " 3 " , NC_FORMAT_NETCDF4 } ,
{ " hdf5 " , NC_FORMAT_NETCDF4 } ,
{ " netCDF-4 " , NC_FORMAT_NETCDF4 } ,
{ " netCDF4 " , NC_FORMAT_NETCDF4 } ,
{ " enhanced " , NC_FORMAT_NETCDF4 } ,
/* NetCDF-4 HDF5 format, but using only nc3 data model */
{ " 4 " , NC_FORMAT_NETCDF4_CLASSIC } ,
{ " hdf5-nc3 " , NC_FORMAT_NETCDF4_CLASSIC } ,
{ " netCDF-4 classic model " , NC_FORMAT_NETCDF4_CLASSIC } ,
{ " netCDF4_classic " , NC_FORMAT_NETCDF4_CLASSIC } ,
{ " enhanced-nc3 " , NC_FORMAT_NETCDF4_CLASSIC } ,
/* null terminate*/
{ NULL , 0 }
2015-01-07 11:48:17 +00:00
} ;
2013-08-13 10:03:31 +00:00
2020-01-22 13:10:59 +00:00
int main ( int argc , char * argv [ ] )
2013-03-25 12:04:10 +00:00
{
2020-01-23 12:24:46 +00:00
int i = 0 ;
2015-07-22 16:59:31 +00:00
2013-08-13 15:47:23 +00:00
/* GRIB-413: Collect all program arguments into a string */
2018-08-07 14:16:50 +00:00
const size_t maxLen = sizeof ( argvString ) ;
2020-01-22 13:10:59 +00:00
size_t currLen = 0 ;
for ( i = 0 ; i < argc ; + + i ) {
2018-08-07 14:16:50 +00:00
currLen + = strlen ( argv [ i ] ) ;
2020-01-22 13:10:59 +00:00
if ( currLen > = maxLen - 1 )
break ;
2013-08-13 10:03:31 +00:00
strcat ( argvString , argv [ i ] ) ;
2020-01-22 13:10:59 +00:00
if ( i ! = argc - 1 )
strcat ( argvString , " " ) ;
2013-08-13 10:03:31 +00:00
}
2020-01-23 12:24:46 +00:00
return grib_tool ( argc , argv ) ;
2013-03-25 12:04:10 +00:00
}
int grib_tool_before_getopt ( grib_runtime_options * options )
{
2013-07-10 16:58:41 +00:00
return 0 ;
2013-03-25 12:04:10 +00:00
}
int grib_tool_init ( grib_runtime_options * options )
{
2020-01-22 13:10:59 +00:00
char * p = NULL ;
char * list = NULL ;
ctx = grib_context_get_default ( ) ;
2013-07-10 16:58:41 +00:00
options - > onlyfiles = 1 ;
2020-01-22 13:10:59 +00:00
fs = new_fieldset ( 0 ) ;
data_r = empty_request ( 0 ) ;
user_r = empty_request ( 0 ) ;
2013-07-10 16:58:41 +00:00
2020-07-17 14:37:57 +00:00
printf ( " %s: Version " , tool_name ) ;
2013-08-20 16:38:25 +00:00
grib_print_api_version ( stdout ) ;
printf ( " \n " ) ;
2020-01-22 13:10:59 +00:00
if ( grib_options_on ( " D: " ) ) {
2013-07-10 16:58:41 +00:00
set_value ( user_r , " accuracy " , grib_options_get_option ( " D: " ) ) ;
}
2020-01-22 13:10:59 +00:00
else {
2013-07-10 16:58:41 +00:00
set_value ( user_r , " accuracy " , " NC_SHORT " ) ;
2013-08-15 15:08:19 +00:00
}
2013-07-10 16:58:41 +00:00
2013-08-15 15:08:19 +00:00
/* Option -S: Split according to keys */
2020-01-22 13:10:59 +00:00
if ( grib_options_on ( " S: " ) ) {
2023-02-11 15:02:55 +00:00
char * lasts = NULL ;
2013-07-10 16:58:41 +00:00
list = grib_options_get_option ( " S: " ) ;
2023-02-11 15:02:55 +00:00
p = strtok_r ( list , " , " , & lasts ) ;
2013-07-10 16:58:41 +00:00
set_value ( user_r , " split " , p ) ;
2023-02-11 15:02:55 +00:00
p = strtok_r ( NULL , " , " , & lasts ) ;
2020-01-22 13:10:59 +00:00
while ( p ! = NULL ) {
2013-07-10 16:58:41 +00:00
add_value ( user_r , " split " , p ) ;
2023-02-11 15:02:55 +00:00
p = strtok_r ( NULL , " , " , & lasts ) ;
2013-07-10 16:58:41 +00:00
}
}
2020-01-22 13:10:59 +00:00
else {
2013-07-10 16:58:41 +00:00
set_value ( user_r , " split " , " param " ) ;
add_value ( user_r , " split " , " expver " ) ;
}
2013-08-15 15:08:19 +00:00
/* Option -I: Ignore keys */
2020-01-22 13:10:59 +00:00
if ( grib_options_on ( " I: " ) ) {
2023-02-11 15:02:55 +00:00
char * lasts = NULL ;
2013-08-15 15:08:19 +00:00
list = grib_options_get_option ( " I: " ) ;
2023-02-11 15:02:55 +00:00
p = strtok_r ( list , " , " , & lasts ) ;
2013-08-15 15:08:19 +00:00
set_value ( user_r , " ignore " , p ) ;
2023-02-11 15:02:55 +00:00
p = strtok_r ( NULL , " , " , & lasts ) ;
2020-01-22 13:10:59 +00:00
while ( p ! = NULL ) {
2013-08-15 15:08:19 +00:00
add_value ( user_r , " ignore " , p ) ;
2023-02-11 15:02:55 +00:00
p = strtok_r ( NULL , " , " , & lasts ) ;
2013-08-15 15:08:19 +00:00
}
}
else {
set_value ( user_r , " ignore " , " method " ) ;
add_value ( user_r , " ignore " , " type " ) ;
add_value ( user_r , " ignore " , " stream " ) ;
add_value ( user_r , " ignore " , " refdate " ) ;
add_value ( user_r , " ignore " , " hdate " ) ;
}
2020-01-22 13:10:59 +00:00
if ( grib_options_on ( " T " ) )
2013-07-10 16:58:41 +00:00
set_value ( user_r , " usevalidtime " , " false " ) ;
else
set_value ( user_r , " usevalidtime " , " true " ) ;
2020-01-22 13:10:59 +00:00
if ( grib_options_on ( " k: " ) ) {
2015-01-07 11:48:17 +00:00
struct KindValue * kvalue = NULL ;
2020-01-22 13:10:59 +00:00
char * kind_name = grib_options_get_option ( " k: " ) ;
for ( kvalue = legalkinds ; kvalue - > name ; kvalue + + ) {
2015-01-07 11:48:17 +00:00
if ( strcmp ( kind_name , kvalue - > name ) = = 0 ) {
2020-01-22 13:10:59 +00:00
option_kind = kvalue - > kind ; /* Found the right kind */
2015-01-07 11:48:17 +00:00
break ;
}
}
if ( kvalue - > name = = NULL ) {
fprintf ( stderr , " Invalid format: %s " , kind_name ) ;
usage ( ) ;
exit ( 1 ) ;
}
}
2014-01-29 23:29:17 +00:00
2020-01-22 13:10:59 +00:00
if ( grib_options_on ( " d: " ) ) {
2017-08-08 10:46:35 +00:00
if ( option_kind = = 3 | | option_kind = = 4 ) { /* netCDF-4 */
2017-07-16 11:22:52 +00:00
char * theArg = grib_options_get_option ( " d: " ) ;
2020-01-22 13:10:59 +00:00
if ( ! is_number ( theArg ) | | atol ( theArg ) < 0 | | atol ( theArg ) > 9 ) {
2017-08-08 10:46:35 +00:00
fprintf ( stderr , " Invalid deflate option: %s (must be 0 to 9) \n " , theArg ) ;
2017-07-16 11:22:52 +00:00
usage ( ) ;
exit ( 1 ) ;
}
set_value ( user_r , " deflate " , theArg ) ;
2020-01-22 13:10:59 +00:00
deflate_option = 1 ;
}
else {
2017-08-08 10:46:35 +00:00
fprintf ( stderr , " Invalid deflate option for non netCDF-4 output formats \n " ) ;
2017-07-16 11:22:52 +00:00
usage ( ) ;
exit ( 1 ) ;
}
}
2020-01-22 13:10:59 +00:00
else {
2017-07-16 11:22:52 +00:00
set_value ( user_r , " deflate " , " none " ) ;
}
2020-01-22 13:10:59 +00:00
if ( grib_options_on ( " s " ) ) {
if ( deflate_option )
2017-07-16 11:22:52 +00:00
set_value ( user_r , " shuffle " , " true " ) ;
2020-01-22 13:10:59 +00:00
else {
2017-07-16 11:22:52 +00:00
fprintf ( stderr , " Invalid shuffle option. Deflate option needed. \n " ) ;
usage ( ) ;
exit ( 1 ) ;
}
}
else
set_value ( user_r , " shuffle " , " false " ) ;
2020-01-22 13:10:59 +00:00
if ( grib_options_on ( " R: " ) ) {
2013-07-17 10:11:59 +00:00
char * theArg = grib_options_get_option ( " R: " ) ;
if ( ! is_number ( theArg ) ) {
fprintf ( stderr , " Invalid reference date: %s \n " , theArg ) ;
usage ( ) ;
exit ( 1 ) ;
}
set_value ( user_r , " referencedate " , theArg ) ;
2013-07-10 16:58:41 +00:00
}
2020-01-22 13:10:59 +00:00
else {
2013-07-10 16:58:41 +00:00
set_value ( user_r , " referencedate " , " 19000101 " ) ;
}
2014-10-29 13:03:04 +00:00
if ( grib_options_on ( " u: " ) ) {
char * theDimension = grib_options_get_option ( " u: " ) ;
2020-01-22 13:10:59 +00:00
if ( ! check_dimension_name ( theDimension ) ) {
2014-10-29 13:03:04 +00:00
fprintf ( stderr , " Invalid dimension: \" %s \" \n " , theDimension ) ;
exit ( 1 ) ;
}
set_value ( user_r , " unlimited " , theDimension ) ;
}
2013-07-10 16:58:41 +00:00
get_nc_options ( user_r ) ;
return 0 ;
2013-03-25 12:04:10 +00:00
}
int grib_tool_new_filename_action ( grib_runtime_options * options , const char * filename )
{
2020-01-22 13:10:59 +00:00
char buf [ 1024 ] = { 0 , } ;
int e = 0 ;
int i = 0 ;
grib_handle * h = NULL ;
2013-07-10 16:58:41 +00:00
grib_file * file = NULL ;
2013-03-25 12:04:10 +00:00
2020-07-17 14:37:57 +00:00
printf ( " %s: Processing input file '%s'. \n " , tool_name , filename ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
file = grib_file_open ( filename , " r " , & e ) ;
2020-01-22 13:10:59 +00:00
if ( ! file | | ! file - > handle )
2013-07-10 16:58:41 +00:00
return e ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
fseeko ( file - > handle , 0 , SEEK_SET ) ;
2013-03-25 12:04:10 +00:00
files + + ;
2020-01-22 13:10:59 +00:00
while ( ( h = grib_handle_new_from_file ( ctx , file - > handle , & e ) ) ! = NULL ) {
2013-07-10 16:58:41 +00:00
long length ;
field * g ;
2020-01-22 13:10:59 +00:00
request * r ;
2013-07-10 16:58:41 +00:00
/* process only GRIB for the moment*/
size_t size = sizeof ( buf ) ;
Assert ( grib_get_string ( h , " identifier " , buf , & size ) = = 0 ) ;
2020-01-22 13:10:59 +00:00
if ( strcmp ( buf , " GRIB " ) ) {
2013-07-10 16:58:41 +00:00
grib_handle_delete ( h ) ;
continue ;
}
2020-01-22 13:10:59 +00:00
Assert ( grib_get_long ( h , " totalLength " , & length ) = = 0 ) ;
2013-07-10 16:58:41 +00:00
g = read_field ( file , h - > offset , length ) ;
r = empty_request ( " " ) ;
2020-01-22 13:10:59 +00:00
if ( handle_to_request ( r , h ) ! = GRIB_SUCCESS ) {
2020-01-20 13:20:02 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Failed to convert GRIB handle to a request " ) ;
}
2013-07-10 16:58:41 +00:00
/* Keep full MARS description */
/* copy = clone_one_request(r); */
/* reqmerge(setup.mars_description,copy); */
/* reqmerge(setup.mars_description,r); */
2020-01-22 13:10:59 +00:00
if ( i = = 1 ) {
const char * mmeans = get_value ( r , " _MONTHLY_MEANS " , 0 ) ;
2023-03-04 12:45:31 +00:00
setup . mmeans = mmeans ? ( atol ( mmeans ) = = 1 ) : false ;
2013-07-10 16:58:41 +00:00
}
fcmonth2nbmonths ( r ) ;
2020-01-22 13:10:59 +00:00
if ( ! setup . refdate ) {
if ( setup . auto_refdate )
2013-07-10 16:58:41 +00:00
setup . refdate = atol ( get_value ( r , " date " , 0 ) ) ;
2020-01-22 13:10:59 +00:00
else {
const char * p = get_value ( user_r , " referencedate " , 0 ) ;
if ( is_number ( p ) )
2013-07-10 16:58:41 +00:00
setup . refdate = atol ( p ) ;
2020-01-22 13:10:59 +00:00
else {
2013-07-10 16:58:41 +00:00
long julian = 0 , second = 0 ;
2023-03-04 12:45:31 +00:00
bool isjul ;
2013-07-10 16:58:41 +00:00
parsedate ( p , & julian , & second , & isjul ) ;
setup . refdate = grib_julian_to_date ( julian ) ;
}
}
}
validation_time ( r ) ;
2020-01-22 13:10:59 +00:00
if ( setup . usevalidtime ) {
2013-07-10 16:58:41 +00:00
unset_value ( r , " date " ) ;
unset_value ( r , " time " ) ;
unset_value ( r , " step " ) ;
unset_value ( r , " fcmonth " ) ;
set_value ( r , " time " , " %.2lf " , atof ( get_value ( r , " _validationtime " , 0 ) ) ) ;
}
g - > r = new_field_request ( r ) ;
set_field ( fs , g , i + + ) ;
reqmerge ( data_r , r ) ;
free_all_requests ( r ) ;
grib_handle_delete ( h ) ;
}
2024-03-08 12:07:15 +00:00
if ( e ! = GRIB_SUCCESS ) {
grib_context_log ( ctx , GRIB_LOG_ERROR , " %s (message %d) " , grib_get_error_message ( e ) , i ) ;
}
int e2 = 0 ;
grib_file_close ( file - > name , 0 , & e2 ) ;
if ( e2 ! = GRIB_SUCCESS ) {
grib_context_log ( ctx , GRIB_LOG_ERROR , " Failed to close file %s (%s) " , file - > name , grib_get_error_message ( e2 ) ) ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
{
2013-08-20 12:38:53 +00:00
/* Now do some checks */
request * temp_data_r = fieldset_to_request ( fs ) ;
2020-01-22 13:10:59 +00:00
if ( setup . checkvalidtime ) {
2013-08-20 12:38:53 +00:00
int cnt = request_fields ( temp_data_r ) ;
2020-01-22 13:10:59 +00:00
if ( fs - > count ! = i | | ( cnt < i ) ) {
2013-08-20 12:38:53 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Wrong number of fields " ) ;
grib_context_log ( ctx , GRIB_LOG_ERROR , " File contains %d GRIBs, %d left in internal description, %d in request " , i , fs - > count , cnt ) ;
2016-07-27 09:43:10 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " The fields are not considered distinct! \n " ) ;
2013-08-20 12:38:53 +00:00
/*grib_context_log(ctx, GRIB_LOG_ERROR, "MARS description");*/
/*print_all_requests(setup.mars_description);*/
2016-07-27 09:43:10 +00:00
if ( ctx - > debug ) {
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal description " ) ;
print_all_requests ( temp_data_r ) ;
}
2018-03-06 13:23:57 +00:00
if ( grib_options_on ( " T " ) ) {
grib_context_log ( ctx , GRIB_LOG_ERROR , " Hint: This may be due to several fields having the same date, time and step. " ) ;
2020-01-22 13:10:59 +00:00
}
else {
2018-03-06 13:23:57 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Hint: This may be due to several fields having the same validity time. " ) ;
grib_context_log ( ctx , GRIB_LOG_ERROR , " Try using the -T option (Do not use time of validity) " ) ;
}
2013-08-20 12:38:53 +00:00
exit ( 1 ) ;
}
2013-07-10 16:58:41 +00:00
}
2013-08-20 12:38:53 +00:00
free_all_requests ( temp_data_r ) ;
2013-07-10 16:58:41 +00:00
}
2013-08-19 16:12:09 +00:00
2013-07-10 16:58:41 +00:00
return e ;
2013-03-25 12:04:10 +00:00
}
int grib_tool_new_file_action ( grib_runtime_options * options , grib_tools_file * file )
{
2013-07-10 16:58:41 +00:00
return 0 ;
2013-03-25 12:04:10 +00:00
}
int grib_tool_new_handle_action ( grib_runtime_options * options , grib_handle * h )
{
2013-07-10 16:58:41 +00:00
return 0 ;
2013-03-25 12:04:10 +00:00
}
int grib_tool_skip_handle ( grib_runtime_options * options , grib_handle * h )
{
2013-07-10 16:58:41 +00:00
return 0 ;
2013-03-25 12:04:10 +00:00
}
int grib_tool_finalise_action ( grib_runtime_options * options )
{
2020-01-22 13:10:59 +00:00
request * config_r = NULL ;
hypercube * dims = NULL ;
dataset_t * subsets = NULL ;
2013-07-10 16:58:41 +00:00
int count ;
int i ;
int ncid ;
int stat ;
2020-01-22 13:10:59 +00:00
int err = 0 ;
2014-01-29 23:29:17 +00:00
int creation_mode = NC_CLOBBER ;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( options - > outfile = = NULL | | options - > outfile - > name = = NULL ) {
2013-07-10 16:58:41 +00:00
usage ( ) ;
exit ( 1 ) ;
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if ( fs - > count = = 0 ) {
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Input does not contain any field. Exiting! " ) ;
return - 1 ;
}
2013-03-25 12:04:10 +00:00
2020-07-17 14:37:57 +00:00
printf ( " %s: Found %d GRIB field%s in %d file%s. \n " , tool_name , fs - > count , fs - > count > 1 ? " s " : " " , files , files > 1 ? " s " : " " ) ;
2013-03-25 12:04:10 +00:00
2018-05-18 12:58:37 +00:00
if ( ctx - > debug ) {
grib_context_log ( ctx , GRIB_LOG_INFO , " Request representing %d fields " , fs - > count ) ;
print_all_requests ( data_r ) ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
/* Split the SOURCE from request into as many datasets as specified */
count = split_fieldset ( fs , data_r , & subsets , user_r , config_r ) ;
2020-01-22 13:10:59 +00:00
remove_param ( data_r , ( void * ) user_r , " ignore " ) ;
remove_param ( data_r , ( void * ) user_r , " split " ) ;
2014-11-13 14:16:43 +00:00
print_ignored_keys ( stdout , user_r ) ;
2015-07-22 16:59:31 +00:00
2013-07-10 16:58:41 +00:00
dims = new_simple_hypercube_from_mars_request ( data_r ) ;
2018-05-18 12:58:37 +00:00
if ( ctx - > debug ) {
grib_context_log ( ctx , GRIB_LOG_INFO , " Hypercube " ) ;
print_hypercube ( dims ) ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
/* In case there is only 1 DATE+TIME+STEP, set at least 1 time as axis */
set_always_a_time ( dims , data_r ) ;
2013-03-25 12:04:10 +00:00
2022-01-07 14:28:05 +00:00
/* Create netCDF file */
2013-03-25 12:04:10 +00:00
2020-07-17 14:37:57 +00:00
printf ( " %s: Creating netCDF file '%s' \n " , tool_name , options - > outfile - > name ) ;
printf ( " %s: NetCDF library version: %s \n " , tool_name , nc_inq_libvers ( ) ) ;
2014-01-29 23:29:17 +00:00
2015-01-07 11:48:17 +00:00
creation_mode = get_creation_mode ( option_kind ) ;
2020-01-22 13:10:59 +00:00
stat = nc_create ( options - > outfile - > name , creation_mode , & ncid ) ;
2019-11-21 12:00:02 +00:00
if ( stat ! = NC_NOERR ) {
char msg [ 1024 ] ;
2022-11-10 21:51:06 +00:00
snprintf ( msg , sizeof ( msg ) , " nc_create: '%s' " , options - > outfile - > name ) ;
2019-11-21 12:00:02 +00:00
check_err ( msg , stat , __LINE__ ) ;
}
2013-07-10 16:58:41 +00:00
2022-01-07 14:28:05 +00:00
/* Define netCDF dataset */
2013-07-10 16:58:41 +00:00
err = define_netcdf_dimensions ( dims , fs , ncid , subsets , count , data_r ) ;
if ( err ! = GRIB_SUCCESS ) {
stat = nc_close ( ncid ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_close " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
stat = nc_delete ( options - > outfile - > name ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_delete " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
exit ( 1 ) ;
}
/* End definitions */
stat = nc_enddef ( ncid ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_enddef " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
/* Fill dimensions */
fill_netcdf_dimensions ( dims , fs , ncid ) ;
/* Put data values */
2020-01-22 13:10:59 +00:00
for ( i = 0 ; i < count ; + + i ) {
if ( subsets [ i ] . fset ) {
2013-07-10 16:58:41 +00:00
char dataset [ 100 ] ;
2022-11-10 21:51:06 +00:00
snprintf ( dataset , sizeof ( dataset ) , subsets [ i ] . att . name , i + 1 ) ;
2013-07-10 16:58:41 +00:00
put_data ( dims , ncid , dataset , & subsets [ i ] ) ;
}
2020-01-22 13:10:59 +00:00
else {
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Fieldset %d is empty!! " , i + 1 ) ;
}
}
stat = nc_close ( ncid ) ;
2019-11-21 12:00:02 +00:00
check_err ( " nc_close " , stat , __LINE__ ) ;
2013-07-10 16:58:41 +00:00
free_all_requests ( data_r ) ;
free_hypercube ( dims ) ;
free_fieldset ( fs ) ;
free_subsets ( subsets , count ) ;
free_nc_options ( ) ;
2020-07-17 14:37:57 +00:00
printf ( " %s: Done. \n " , tool_name ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
return 0 ;
2013-03-25 12:04:10 +00:00
}
2016-08-30 12:45:02 +00:00
int grib_no_handle_action ( grib_runtime_options * options , int err )
2015-05-05 09:33:13 +00:00
{
2020-01-22 13:10:59 +00:00
fprintf ( dump_file , " \t \t \" ERROR: unreadable message \" \n " ) ;
2016-04-07 13:16:02 +00:00
return 0 ;
2015-05-05 09:33:13 +00:00
}
2013-03-25 12:04:10 +00:00
# else
# include <stdio.h>
int main ( int argc , char * * argv )
{
printf ( " \n " ) ;
2019-09-11 14:37:16 +00:00
printf ( " grib_to_netcdf: \n " ) ;
2013-03-25 12:04:10 +00:00
printf ( " \n " ) ;
2015-07-31 14:44:36 +00:00
printf ( " ecCodes was not compiled with NETCDF enabled \n " ) ;
2013-03-25 12:04:10 +00:00
printf ( " \n " ) ;
exit ( 1 ) ;
}
# endif