2013-03-25 12:04:10 +00:00
/*
2013-04-18 09:23:23 +00:00
* Copyright 2005 - 2013 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
# include <math.h>
# include <stdarg.h>
# include <stdlib.h>
# include <ctype.h>
# include <time.h>
# include <limits.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"
char * grib_tool_description = " Convert a GRIB file to netCDF format. " ;
char * grib_tool_name = " grib_to_netcdf " ;
char * grib_tool_usage = " [options] grib_file grib_file ... " ;
2013-08-13 10:03:31 +00:00
static char argvString [ 2048 ] ;
2013-03-25 12:04:10 +00:00
/*=====================================================================*/
static grib_context * ctx = NULL ;
static double missing_value = 9999 ; /* TODO: Get from GRIBs */
/*===============================================================================*/
/* request from mars client */
/*===============================================================================*/
# define NUMBER(x) (sizeof(x) / sizeof(x[0]))
typedef int boolean ;
typedef int err ;
typedef off_t file_offset ;
static int false = 0 ;
static int true = 1 ;
static int files = 0 ;
struct value {
2013-07-10 16:58:41 +00:00
struct value * next ;
char * name ;
2013-03-25 12:04:10 +00:00
} ;
typedef struct value value ;
struct request {
2013-07-10 16:58:41 +00:00
struct request * next ;
struct parameter * params ;
char * name ;
int order ;
2013-03-25 12:04:10 +00:00
} ;
typedef struct request request ;
/* request part */
/* language part */
struct parameter {
2013-07-10 16:58:41 +00:00
struct parameter * next ;
struct value * values ;
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 ) ;
static boolean parsedate ( const char * name , long * julian , long * second , boolean * isjul ) ;
static boolean eq_string ( const char * l , const char * r )
{
2013-07-10 16:58:41 +00:00
if ( l & & r )
return strcmp ( l , r ) = = 0 ;
return false ;
2013-03-25 12:04:10 +00:00
}
static boolean eq_integer ( const char * l , const char * r )
{
2013-07-10 16:58:41 +00:00
if ( l & & r )
return atol ( l ) = = atol ( r ) ;
return false ;
2013-03-25 12:04:10 +00:00
}
static boolean eq_null ( const char * l , const char * r )
{
2013-07-10 16:58:41 +00:00
return true ;
2013-03-25 12:04:10 +00:00
}
static boolean eq_coord ( const char * l , const char * r )
{
2013-07-10 16:58:41 +00:00
if ( l & & r )
return strcmp ( l , r ) = = 0 ;
return false ;
2013-03-25 12:04:10 +00:00
}
static boolean eq_range ( const char * l , const char * r )
{
2013-07-10 16:58:41 +00:00
if ( l & & r )
return strcmp ( l , r ) = = 0 ;
return false ;
2013-03-25 12:04:10 +00:00
}
static boolean eq_date ( const char * l , const char * r )
{
2013-07-10 16:58:41 +00:00
if ( l & & r )
return strcmp ( l , r ) = = 0 ;
return false ;
2013-03-25 12:04:10 +00:00
}
static boolean eq_param ( const char * l , const char * r )
{
2013-07-10 16:58:41 +00:00
if ( l & & r )
return strcmp ( l , r ) = = 0 ;
return false ;
2013-03-25 12:04:10 +00:00
}
static boolean eq_time ( const char * l , const char * r )
{
2013-07-10 16:58:41 +00:00
if ( l & & r )
return strcmp ( l , r ) = = 0 ;
return false ;
2013-03-25 12:04:10 +00:00
}
static value * new_value ( const char * name )
{
2013-07-10 16:58:41 +00:00
value * v = calloc ( sizeof ( value ) , 1 ) ;
Assert ( v ) ;
v - > name = grib_context_strdup ( ctx , name ) ;
return v ;
2013-03-25 12:04:10 +00:00
}
static parameter * find_parameter ( const request * r , const char * parname )
{
2013-07-10 16:58:41 +00:00
if ( ! parname )
return 0 ;
if ( r )
{
parameter * p = r - > params ;
while ( p )
{
if ( strcmp ( p - > name , parname ) = = 0 )
return p ;
p = p - > next ;
}
}
return NULL ;
2013-03-25 12:04:10 +00:00
}
static void _reqmerge ( parameter * pa , const parameter * pb , request * a )
{
2013-07-10 16:58:41 +00:00
const value * vb = pb - > values ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( strcmp ( pa - > name , pb - > name ) ! = 0 )
return ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
while ( vb )
{
value * va = pa - > values ;
value * last = 0 ;
const char * nb = vb - > name ;
boolean add = true ;
while ( va )
{
if ( strcmp ( va - > name , nb ) = = 0 )
{
add = false ;
break ;
}
last = va ;
va = va - > next ;
}
if ( add )
{
value * v = new_value ( nb ) ;
if ( last )
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 */
static boolean _reqmerge1 ( request * a , const request * b )
{
2013-07-10 16:58:41 +00:00
parameter * pa = a - > params ;
const parameter * pb = b - > params ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
while ( pa & & pb )
{
if ( strcmp ( pa - > name , pb - > name ) ! = 0 )
return false ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
_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
2013-03-25 12:04:10 +00:00
static void free_one_value ( value * p )
{
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
}
static void free_all_values ( value * p )
{
2013-07-10 16:58:41 +00:00
while ( p )
{
value * q = p - > next ;
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 */
2013-03-25 12:04:10 +00:00
static const char * parse1 ( const char * p , int * x , int * n )
{
2013-07-10 16:58:41 +00:00
* x = * n = 0 ;
while ( * p & & isdigit ( * p ) )
{
( * x ) * = 10 ;
( * x ) + = * p - ' 0 ' ;
( * n ) + + ;
p + + ;
}
return p ;
2013-03-25 12:04:10 +00:00
}
static boolean is_number ( const char * name )
{
2013-07-10 16:58:41 +00:00
const char * p = name ;
int x , n ;
if ( p = = 0 | | * p = = 0 )
return false ;
if ( * p = = ' - ' )
p + + ;
else if ( * p = = ' + ' )
p + + ;
p = parse1 ( p , & x , & n ) ;
if ( n = = 0 & & * p ! = ' . ' )
return false ;
if ( * p = = ' . ' )
{
p + + ;
p = parse1 ( p , & x , & n ) ;
}
if ( * p = = ' e ' | | * p = = ' E ' )
{
p + + ;
if ( * p = = ' - ' )
p + + ;
else if ( * p = = ' + ' )
p + + ;
p = parse1 ( p , & x , & n ) ;
if ( n = = 0 )
return false ;
}
return * p = = 0 ? true : false ;
2013-03-25 12:04:10 +00:00
}
static parameter * new_parameter ( char * name , value * v )
{
2013-07-10 16:58:41 +00:00
parameter * p = calloc ( sizeof ( parameter ) , 1 ) ;
Assert ( p ) ;
p - > name = grib_context_strdup ( ctx , name ) ;
p - > values = v ;
return p ;
2013-03-25 12:04:10 +00:00
}
static void put_value ( request * r , const char * parname , const char * valname , boolean append , boolean unique , boolean ascending )
{
2013-07-10 16:58:41 +00:00
parameter * p ;
value * v ;
if ( ! r )
return ;
if ( ( p = find_parameter ( r , parname ) ) ! = NULL )
{
if ( append )
{
value * a = p - > values , * b = NULL , * c = NULL ;
while ( a )
{
b = a ;
if ( unique )
{
if ( is_number ( a - > name ) & & is_number ( valname ) )
{
if ( atof ( a - > name ) = = atof ( valname ) )
return ;
}
else if ( strcmp ( a - > name , valname ) = = 0 )
return ;
}
if ( ascending )
{
if ( is_number ( a - > name ) )
{
if ( atof ( valname ) < atof ( a - > name ) )
break ;
}
else if ( strcmp ( valname , a - > name ) < 0 )
break ;
}
c = b ;
a = a - > next ;
}
v = new_value ( grib_context_strdup ( ctx , valname ) ) ;
if ( ascending )
{
if ( c )
{
if ( b & & b ! = c )
v - > next = b ;
c - > next = v ;
}
else
{
if ( a )
v - > next = a ;
p - > values = v ;
}
}
else
{
if ( b )
b - > next = v ;
else
p - > values = v ;
}
/* p->count++; */
p - > count = 0 ;
}
else
{
if ( p - > values )
{
free_all_values ( p - > values - > next ) ;
p - > values - > next = NULL ;
/* p->count = 1; */
p - > count = 0 ;
if ( strcmp ( p - > values - > name , valname ) = = 0 )
return ;
else
{
grib_context_free ( ctx , p - > values - > name ) ;
p - > values - > name = grib_context_strdup ( ctx , valname ) ;
}
}
else
{
v = new_value ( grib_context_strdup ( ctx , valname ) ) ;
p - > values = v ;
/* p->count = 1; */
p - > count = 0 ;
}
}
}
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 )
{
q = s ;
s = s - > next ;
}
if ( q )
q - > next = p ;
else
r - > params = p ;
}
2013-03-25 12:04:10 +00:00
}
static void add_value ( request * r , const char * parname , const char * fmt , . . . )
{
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 ) ;
vsprintf ( buffer , fmt , list ) ;
va_end ( list ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
put_value ( r , parname , buffer , true , false , false ) ;
va_end ( list ) ;
2013-03-25 12:04:10 +00:00
}
static void _reqmerge2 ( request * a , const request * b )
{
2013-07-10 16:58:41 +00:00
const parameter * pb = b - > params ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
while ( pb )
{
parameter * pa = find_parameter ( a , pb - > name ) ;
if ( pa = = NULL )
{
value * v = pb - > values ;
while ( v )
{
put_value ( a , pb - > name , v - > name , true , true , false ) ;
v = v - > next ;
}
}
else
{
_reqmerge ( pa , pb , a ) ;
}
pb = pb - > next ;
}
2013-03-25 12:04:10 +00:00
}
static void reqmerge ( request * a , const request * b )
{
2013-07-10 16:58:41 +00:00
if ( a & & b )
{
if ( ! _reqmerge1 ( a , b ) )
_reqmerge2 ( a , b ) ;
}
2013-03-25 12:04:10 +00:00
}
static void save_name ( FILE * f , const char * name , int n )
{
2013-07-10 16:58:41 +00:00
int i = 0 , cnt = 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( name = = NULL )
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
2013-07-10 16:58:41 +00:00
for ( i = cnt ; i < n ; i + + )
putc ( ' ' , f ) ;
2013-03-25 12:04:10 +00:00
}
static void save_one_value ( FILE * f , value * r )
{
2013-07-10 16:58:41 +00:00
save_name ( f , r - > name , 0 ) ;
2013-03-25 12:04:10 +00:00
}
static void save_all_values ( FILE * f , value * r )
{
2013-07-10 16:58:41 +00:00
while ( r )
{
save_one_value ( f , r ) ;
if ( r - > next )
putc ( ' / ' , f ) ;
r = r - > next ;
}
2013-03-25 12:04:10 +00:00
}
static void save_all_parameters ( FILE * f , parameter * r )
{
2013-07-10 16:58:41 +00:00
while ( r )
{
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( r - > values )
{
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
}
static void save_one_request ( FILE * f , const request * r )
{
2013-07-10 16:58:41 +00:00
if ( r )
{
save_name ( f , r - > name , 0 ) ;
save_all_parameters ( f , r - > params ) ;
putc ( ' \n ' , f ) ;
}
2013-03-25 12:04:10 +00:00
}
static void save_all_requests ( FILE * f , const request * r )
{
2013-07-10 16:58:41 +00:00
while ( r )
{
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
static void print_all_requests ( const request * r )
{
2013-07-10 16:58:41 +00:00
save_all_requests ( stdout , r ) ;
2013-03-25 12:04:10 +00:00
}
static void free_one_parameter ( parameter * p )
{
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
}
static void free_all_parameters ( parameter * p )
{
2013-07-10 16:58:41 +00:00
while ( p )
{
parameter * q = p - > next ;
free_one_parameter ( p ) ;
p = q ;
}
2013-03-25 12:04:10 +00:00
}
static void free_one_request ( request * r )
{
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
}
static void free_all_requests ( request * p )
{
2013-07-10 16:58:41 +00:00
while ( p )
{
request * q = p - > next ;
free_one_request ( p ) ;
p = q ;
}
2013-03-25 12:04:10 +00:00
}
static void set_value ( request * r , const char * parname , const char * fmt , . . . )
{
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 ) ;
vsprintf ( buffer , fmt , list ) ;
va_end ( list ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +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
2013-03-25 12:04:10 +00:00
static err handle_to_request ( request * r , grib_handle * g )
{
2013-07-10 16:58:41 +00:00
grib_keys_iterator * ks ;
char name [ 80 ] ;
char value [ 80 ] ;
size_t len = sizeof ( value ) ;
int e = 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( ! g )
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
2013-07-10 16:58:41 +00:00
while ( grib_keys_iterator_next ( ks ) )
{
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
strcpy ( name , grib_keys_iterator_get_name ( ks ) ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( ( e = grib_keys_iterator_get_string ( ks , value , & len ) ) ! = GRIB_SUCCESS )
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
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 ) ;
2013-07-15 13:48:32 +00:00
if ( grib_get_string ( g , " cfVarName " , name , & len ) = = 0 )
2013-07-10 16:58:41 +00:00
{
2013-07-15 13:48:32 +00:00
if ( strcmp ( name , " unknown " ) ! = 0 )
{
set_value ( r , " param " , " %s " , name ) ;
}
else
{
len = sizeof ( value ) ;
if ( grib_get_string ( g , " shortName " , name , & len ) = = 0 )
{
set_value ( r , " param " , " %s " , name ) ;
}
}
2013-07-10 16:58:41 +00:00
}
len = sizeof ( value ) ;
if ( grib_get_string ( g , " name " , name , & len ) = = 0 )
{
if ( strcmp ( name , " unknown " ) ! = 0 )
{
set_value ( r , " _long_name " , " %s " , name ) ;
}
}
len = sizeof ( value ) ;
if ( grib_get_string ( g , " units " , name , & len ) = = 0 )
{
if ( strcmp ( name , " unknown " ) ! = 0 )
{
set_value ( r , " _units " , " %s " , name ) ;
}
}
len = sizeof ( value ) ;
if ( grib_get_string ( g , " cfName " , name , & len ) = = 0 )
{
if ( strcmp ( name , " unknown " ) ! = 0 )
{
set_value ( r , " _cf_name " , " %s " , name ) ;
}
}
grib_keys_iterator_delete ( ks ) ;
return e ;
2013-03-25 12:04:10 +00:00
}
/*===============================================================================*/
/*===============================================================================*/
typedef boolean ( * namecmp ) ( const char * , const char * ) ;
typedef struct hypercube {
2013-07-10 16:58:41 +00:00
request * cube ;
request * r ;
request * iterator ;
char * set ;
int count ;
int size ;
int max ;
int * index_cache ;
int index_cache_size ;
namecmp * compare ;
2013-03-25 12:04:10 +00:00
} hypercube ;
typedef struct axis_t {
2013-07-10 16:58:41 +00:00
const char * name ;
namecmp compare ;
2013-03-25 12:04:10 +00:00
} axis_t ;
/* This should be c++ ... */
typedef enum field_state {
2013-07-10 16:58:41 +00:00
unknown , packed_mem , packed_file , expand_mem
2013-03-25 12:04:10 +00:00
} field_state ;
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 .. */
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 ;
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
2013-07-10 16:58:41 +00:00
boolean missing ; /* field is missing */
boolean bitmap ; /* field has missing values (= bitmap) */
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
field_request * r ;
2013-03-25 12:04:10 +00:00
} field ;
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
2013-07-10 16:58:41 +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)
*/
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 ) ;
static int _cube_position ( const hypercube * h , const request * r , boolean remove_holes ) ;
static value * clone_one_value ( const value * p )
{
2013-07-10 16:58:41 +00:00
value * q = calloc ( sizeof ( value ) , 1 ) ;
Assert ( q ) ;
q - > next = NULL ;
q - > name = grib_context_strdup ( ctx , p - > name ) ;
return q ;
2013-03-25 12:04:10 +00:00
}
static value * clone_all_values ( const value * p )
{
2013-07-10 16:58:41 +00:00
if ( p )
{
value * q = clone_one_value ( p ) ;
q - > next = clone_all_values ( p - > next ) ;
/* q->alias = cone_value(p->alias); */
return q ;
}
return NULL ;
2013-03-25 12:04:10 +00:00
}
static parameter * clone_one_parameter ( const parameter * p )
{
2013-07-10 16:58:41 +00:00
parameter * q = calloc ( sizeof ( parameter ) , 1 ) ;
Assert ( q ) ;
q - > next = NULL ;
q - > name = grib_context_strdup ( ctx , p - > name ) ;
q - > values = clone_all_values ( p - > values ) ;
return q ;
2013-03-25 12:04:10 +00:00
}
static parameter * clone_all_parameters ( const parameter * p )
{
2013-07-10 16:58:41 +00:00
if ( p )
{
parameter * q = clone_one_parameter ( p ) ;
q - > next = clone_all_parameters ( p - > next ) ;
return q ;
}
return NULL ;
2013-03-25 12:04:10 +00:00
}
static request * clone_one_request ( const request * r )
{
2013-07-10 16:58:41 +00:00
if ( r )
{
request * p = calloc ( sizeof ( request ) , 1 ) ;
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 ) ;
p - > next = NULL ;
return p ;
}
return NULL ;
2013-03-25 12:04:10 +00:00
}
static request * new_request ( const char * name , parameter * p )
{
2013-07-10 16:58:41 +00:00
request * r = calloc ( sizeof ( request ) , 1 ) ;
Assert ( r ) ;
r - > name = grib_context_strdup ( ctx , name ) ;
r - > params = p ;
return r ;
2013-03-25 12:04:10 +00:00
}
static request * empty_request ( const char * name )
{
2013-07-10 16:58:41 +00:00
return new_request ( name ? name : " " , NULL ) ;
2013-03-25 12:04:10 +00:00
}
static field_request * new_field_request ( request * r )
{
2013-07-10 16:58:41 +00:00
field_request * g = grib_context_malloc_clear ( ctx , sizeof ( field_request ) ) ;
g - > r = clone_one_request ( r ) ;
return g ;
2013-03-25 12:04:10 +00:00
}
static void free_field_request ( field_request * g )
{
2013-07-10 16:58:41 +00:00
if ( ! g )
return ;
g - > refcnt - - ;
if ( g - > refcnt < = 0 )
{
free_all_requests ( g - > r ) ;
grib_context_free ( ctx , g ) ;
}
2013-03-25 12:04:10 +00:00
}
static void free_field ( field * g )
{
2013-07-10 16:58:41 +00:00
if ( ! g )
return ;
g - > refcnt - - ;
if ( g - > refcnt < = 0 )
{
/*free_gribfile(g->file);*/
free_field_request ( g - > r ) ;
if ( g - > values )
grib_context_free ( ctx , g - > values ) ;
grib_handle_delete ( g - > handle ) ;
grib_context_free ( ctx , g ) ;
}
2013-03-25 12:04:10 +00:00
}
static void free_fieldset ( fieldset * v )
{
2013-07-10 16:58:41 +00:00
int i ;
if ( ! v )
return ;
v - > refcnt - - ;
if ( v - > refcnt < = 0 )
{
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: free_fieldset (%d fields) : " , v - > count ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
for ( i = 0 ; i < v - > count ; i + + )
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
}
static field * new_field ( )
{
2013-07-10 16:58:41 +00:00
return grib_context_malloc_clear ( ctx , sizeof ( field ) ) ;
2013-03-25 12:04:10 +00:00
}
# define INIT_SIZE 1024
static void grow_fieldset ( fieldset * v , int n )
{
2013-07-10 16:58:41 +00:00
int i ;
int m = v - > count ;
int x = v - > max ;
if ( n < v - > count )
return ;
v - > count = n ;
while ( v - > count > = v - > max )
if ( v - > max < INIT_SIZE )
v - > max = INIT_SIZE ;
else
v - > max + = v - > max / 2 + 1 ;
if ( v - > max ! = x )
{
if ( v - > fields = = NULL )
{
v - > fields = ( field * * ) grib_context_malloc ( ctx , sizeof ( field * ) * v - > max ) ;
Assert ( v - > fields ) ;
}
else
{
field * * f = ( field * * ) grib_context_malloc ( ctx , sizeof ( field * ) * v - > max ) ;
Assert ( f ) ;
for ( i = 0 ; i < m ; i + + )
f [ i ] = v - > fields [ i ] ;
grib_context_free ( ctx , v - > fields ) ;
v - > fields = f ;
}
for ( i = m ; i < v - > max ; i + + )
v - > fields [ i ] = NULL ;
}
2013-03-25 12:04:10 +00:00
}
static fieldset * new_fieldset ( int n )
{
2013-07-10 16:58:41 +00:00
fieldset * f = calloc ( sizeof ( fieldset ) , 1 ) ;
Assert ( f ) ;
grow_fieldset ( f , n ) ;
return f ;
2013-03-25 12:04:10 +00:00
}
static field * read_field ( grib_file * file , file_offset pos , long length )
{
2013-07-10 16:58:41 +00:00
field * g = new_field ( ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
g - > file = file ;
g - > offset = pos ;
g - > length = length ;
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
}
static err set_field ( fieldset * v , field * g , int pos )
{
2013-07-10 16:58:41 +00:00
field * h ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( pos > = 0 )
{
grow_fieldset ( v , pos + 1 ) ;
h = v - > fields [ pos ] ;
v - > fields [ pos ] = g ;
g - > refcnt + + ;
if ( h )
free_field ( h ) ;
}
return 0 ;
2013-03-25 12:04:10 +00:00
}
static void count_parval ( parameter * p )
{
2013-07-10 16:58:41 +00:00
int n = 0 ;
value * v = p - > values ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
while ( v )
{
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
}
static int count_values ( const request * r , const char * parname )
{
2013-07-10 16:58:41 +00:00
parameter * p = find_parameter ( r , parname ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( p = = NULL )
return 0 ;
if ( p - > count )
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
}
static const char * get_value ( const request * r , const char * parname , int nth )
{
2013-07-10 16:58:41 +00:00
parameter * p = find_parameter ( r , parname ) ;
value * v ;
int i = 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( p = = NULL )
return NULL ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( ! p - > count )
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
2013-07-10 16:58:41 +00:00
while ( v )
{
if ( nth = = i + + )
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
}
static err to_packed_mem ( field * g )
{
2013-07-10 16:58:41 +00:00
if ( g - > shape = = packed_mem )
return 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( g - > shape = = expand_mem )
{
if ( g - > values )
grib_context_free ( ctx , g - > values ) ;
g - > values = NULL ;
g - > value_count = 0 ;
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
2013-07-10 16:58:41 +00:00
if ( g - > shape = = packed_file )
{
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
}
static err to_expand_mem ( field * g )
{
2013-07-10 16:58:41 +00:00
err e = 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( g - > shape = = expand_mem )
return 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( g - > shape = = packed_file )
{
2013-03-25 12:04:10 +00:00
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 ) ;
if ( ! file | | ! file - > handle )
{
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
2013-07-10 16:58:41 +00:00
if ( g - > handle )
grib_get_message ( g - > handle , & dummy , & g - > length ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
grib_file_close ( file - > name , & e ) ;
if ( ! g - > handle )
return - 1 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( g - > values )
grib_context_free ( ctx , g - > values ) ;
g - > values = NULL ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( g - > values = = NULL )
{
size_t count = 0 ;
long bitmap = 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( ( e = grib_get_size ( g - > handle , " values " , & g - > value_count ) ) )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get number of values %s " , grib_get_error_message ( e ) ) ;
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
2013-07-10 16:58:41 +00:00
if ( ( e = grib_set_double ( g - > handle , " missingValue " , missing_value ) ) )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot set missingValue %s " , grib_get_error_message ( e ) ) ;
return e ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +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 ) ) )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get decode values %s " , grib_get_error_message ( e ) ) ;
return e ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( count ! = g - > value_count )
grib_context_log ( ctx , GRIB_LOG_FATAL , " grib_api: value count mismatch %d %d " , count , g - > value_count ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( ( e = grib_get_long ( g - > handle , " bitmapPresent " , & bitmap ) ) )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get bitmapPresent %s " , grib_get_error_message ( e ) ) ;
return e ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
g - > 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
}
static void set_field_state ( field * g , field_state shape )
{
2013-07-10 16:58:41 +00:00
switch ( shape )
{
case expand_mem :
to_expand_mem ( g ) ;
break ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
case packed_mem :
to_packed_mem ( g ) ;
break ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
case packed_file :
release_field ( g ) ;
break ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
default :
grib_context_log ( ctx , GRIB_LOG_FATAL , " Internal error %s %d " , __FILE__ , __LINE__ ) ;
break ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
}
2013-03-25 12:04:10 +00:00
}
static field * get_field ( fieldset * v , int n , field_state shape )
{
2013-07-10 16:58:41 +00:00
field * g = v - > fields [ n ] ;
set_field_state ( g , shape ) ;
return g ;
2013-03-25 12:04:10 +00:00
}
static void release_field ( field * g )
{
2013-07-10 16:58:41 +00:00
if ( g - > file )
{
if ( g - > values )
grib_context_free ( ctx , g - > values ) ;
g - > values = NULL ;
g - > shape = packed_file ;
grib_handle_delete ( g - > handle ) ;
g - > handle = NULL ;
}
2013-03-25 12:04:10 +00:00
}
static request * field_to_request ( field * f )
{
2013-07-10 16:58:41 +00:00
if ( f - > r = = 0 )
{
field_state state = f - > shape ;
request * r = empty_request (
2013-03-25 12:04:10 +00:00
# ifdef COMEBACK
2013-07-10 16:58:41 +00:00
( ( f - > ksec1 = = NULL ) | | ( f - > ksec1 [ 2 ] ! = mars . computeflg ) ) ? " GRIB " : " COMPUTED " ) ;
2013-03-25 12:04:10 +00:00
# else
2013-07-10 16:58:41 +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
}
/*===============================================================================*/
/* hypercube from mars client */
/*===============================================================================*/
static boolean eq_string ( const char * , const char * ) ;
static boolean eq_integer ( const char * , const char * ) ;
static boolean eq_range ( const char * , const char * ) ;
static boolean eq_param ( const char * , const char * ) ;
static boolean eq_coord ( const char * , const char * ) ;
static boolean eq_date ( const char * , const char * ) ;
static boolean eq_time ( const char * , const char * ) ;
static boolean eq_null ( const char * , const char * ) ;
2013-08-13 10:03:31 +00:00
static axis_t global_axis [ ] =
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +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
2013-07-10 16:58:41 +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
2013-07-10 16:58:41 +00:00
/* testing */
/* {"repres", eq_null, }, */
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +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
2013-07-10 16:58:41 +00:00
{ " reference " , eq_range , } ,
{ " step " , eq_range , } ,
{ " fcmonth " , eq_integer , } ,
{ " fcperiod " , eq_range , } ,
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
{ " leadtime " , eq_range , } ,
{ " opttime " , eq_range , } ,
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
{ " expver " , eq_string , } ,
{ " domain " , eq_string , } ,
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
{ " diagnostic " , eq_integer , } ,
{ " iteration " , eq_integer , } ,
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
{ " quantile " , eq_range , } ,
{ " number " , eq_integer , } ,
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
{ " levelist " , eq_coord , } ,
{ " latitude " , eq_coord , } ,
{ " longitude " , eq_coord , } ,
{ " range " , eq_range , } ,
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
{ " param " , eq_param , } ,
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
{ " ident " , eq_integer , } ,
{ " obstype " , eq_integer , } ,
{ " instrument " , eq_integer , } ,
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
{ " frequency " , eq_integer , } ,
{ " direction " , eq_integer , } ,
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
{ " channel " , eq_integer , } , } ;
2013-03-25 12:04:10 +00:00
static int axisindex ( const char * name )
{
2013-07-10 16:58:41 +00:00
int i = 0 ;
2013-08-13 10:03:31 +00:00
for ( i = 0 ; i < NUMBER ( global_axis ) ; i + + )
2013-07-10 16:58:41 +00:00
{
2013-08-13 10:03:31 +00:00
if ( strcmp ( name , global_axis [ i ] . name ) = = 0 )
2013-07-10 16:58:41 +00:00
return i ;
}
return - 1 ;
2013-03-25 12:04:10 +00:00
}
static namecmp comparator ( const char * name )
{
2013-07-10 16:58:41 +00:00
static char * dontcompare = NULL ;
static boolean first = 1 ;
int i = 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( first )
{
dontcompare = getenv ( " MARS_DONT_CHECK " ) ;
first = false ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( dontcompare ! = NULL )
{
if ( strcmp ( dontcompare , name ) = = 0 )
return eq_null ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +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 */
/********************/
static int count_index ( const hypercube * h )
{
2013-07-10 16:58:41 +00:00
int i = 0 , n = 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
for ( i = 0 ; i < h - > size ; + + i )
n + = h - > set [ i ] ;
return n ;
2013-03-25 12:04:10 +00:00
}
static int count_holes ( const hypercube * h , int cnt )
{
2013-07-10 16:58:41 +00:00
int i = 0 , n = 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
for ( i = 0 ; i < cnt ; + + i )
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
}
static void reset_index ( hypercube * h , int v )
{
2013-07-10 16:58:41 +00:00
memset ( h - > set , v , h - > size ) ;
2013-03-25 12:04:10 +00:00
}
static void set_index ( hypercube * h , int index , int value )
{
2013-07-10 16:58:41 +00:00
if ( index < 0 | | index > = h - > count )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal error, bad hypercube index %d " , index ) ;
exit ( 1 ) ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( index > = h - > max )
{
int old = h - > max ;
while ( index > = h - > max )
h - > max + = 4096 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
h - > set = h - > set ? grib_context_realloc ( ctx , h - > set , h - > max ) : grib_context_malloc ( ctx , h - > max ) ;
Assert ( h - > set ) ;
memset ( h - > set + old , 0 , h - > max - old ) ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( index > = h - > size )
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 */
/*******************/
static int count_axis ( const hypercube * h )
{
2013-07-10 16:58:41 +00:00
if ( h & & h - > cube )
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
}
static const char * get_axis ( const hypercube * h , int pos )
{
2013-07-10 16:58:41 +00:00
const char * axis = NULL ;
if ( pos < count_axis ( h ) )
{
axis = get_value ( h - > cube , " axis " , pos ) ;
}
return axis ;
2013-03-25 12:04:10 +00:00
}
static void add_axis ( hypercube * h , const char * axis )
{
2013-07-10 16:58:41 +00:00
add_value ( h - > cube , " axis " , " %s " , axis ) ;
2013-03-25 12:04:10 +00:00
}
static void unset_value ( request * r , const char * parname )
{
2013-07-10 16:58:41 +00:00
parameter * p , * q = NULL ;
if ( ! r )
return ;
p = r - > params ;
while ( p )
{
if ( strcmp ( parname , p - > name ) = = 0 )
{
if ( q )
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
}
static void reset_axis ( hypercube * h )
{
2013-07-10 16:58:41 +00:00
unset_value ( h - > cube , " axis " ) ;
2013-03-25 12:04:10 +00:00
}
static void valcpy ( request * a , request * b , char * aname , char * bname )
{
2013-07-10 16:58:41 +00:00
parameter * p ;
if ( a & & b & & ( p = find_parameter ( b , bname ) ) )
{
boolean z = false ;
value * v = p - > values ;
while ( v )
{
put_value ( a , aname , v - > name , z , false , false ) ;
z = true ;
v = v - > next ;
}
}
2013-03-25 12:04:10 +00:00
}
static void cube_values ( hypercube * h , const char * p )
{
2013-07-10 16:58:41 +00:00
valcpy ( h - > cube , h - > r , ( char * ) p , ( char * ) p ) ;
2013-03-25 12:04:10 +00:00
}
static int count_dimensions ( const hypercube * , const char * ) ;
static int set_axis ( hypercube * h )
{
2013-07-10 16:58:41 +00:00
int i = 0 ;
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 ) ;
2013-08-13 10:03:31 +00:00
for ( i = ( NUMBER ( global_axis ) - 1 ) ; i > = 0 ; - - i )
2013-07-10 16:58:41 +00:00
{
2013-08-13 10:03:31 +00:00
int n = count_dimensions ( h , global_axis [ i ] . name ) ;
2013-07-10 16:58:41 +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 */
/*******************/
static int count_dimensions ( const hypercube * h , const char * axis )
{
2013-07-10 16:58:41 +00:00
int dims = - 1 ;
if ( h & & h - > r )
dims = count_values ( h - > r , axis ) ;
return dims ;
2013-03-25 12:04:10 +00:00
}
/**************************/
/* End of cube dimensions */
/**************************/
/**************************/
/* Auxiliary functions */
/**************************/
static int count_hypercube ( const request * r )
{
2013-07-10 16:58:41 +00:00
int i = 0 , count = 1 ;
2013-08-13 10:03:31 +00:00
for ( i = 0 ; i < NUMBER ( global_axis ) ; + + i )
2013-07-10 16:58:41 +00:00
{
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
}
static int cube_order ( const hypercube * h , const request * r )
{
2013-07-10 16:58:41 +00:00
return _cube_position ( h , r , true ) ;
2013-03-25 12:04:10 +00:00
}
static int cube_position ( const hypercube * h , const request * r )
{
2013-07-10 16:58:41 +00:00
return _cube_position ( h , r , false ) ;
2013-03-25 12:04:10 +00:00
}
static void reserve_index_cache ( hypercube * h , int size )
{
2013-07-10 16:58:41 +00:00
if ( size = = 0 )
return ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( h - > index_cache ! = 0 )
grib_context_free ( ctx , h - > index_cache ) ;
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: Allocating hypercube index_cache: %d entries " , size ) ;
h - > index_cache = calloc ( sizeof ( int ) , size ) ;
Assert ( h - > index_cache ) ;
h - > index_cache_size = size ;
2013-03-25 12:04:10 +00:00
}
static int _cube_position ( const hypercube * h , const request * r , boolean remove_holes )
{
2013-07-10 16:58:41 +00:00
request * cube = h - > cube ;
int c = count_axis ( h ) ;
int index = 0 ;
int i = 0 ;
int n = 1 ;
int ok = 0 ;
if ( h - > index_cache = = 0 | | h - > index_cache_size ! = c )
reserve_index_cache ( ( hypercube * ) h , c ) ;
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 + + )
{
int j = ( k + last ) % count ;
w = get_value ( cube , axis , j ) ;
if ( h - > compare ? h - > compare [ i ] ( w , v ) : ( strcmp ( w , v ) = = 0 ) )
{
index + = j * n ;
n * = dims ;
ok + + ;
( ( hypercube * ) h ) - > index_cache [ i ] = j ;
break ;
}
else
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: _cube_position, %s, %s != %s [%scompare function available] " , axis , w , v , h - > compare ? " " : " no " ) ;
}
}
if ( remove_holes )
{
int holes = 0 ;
if ( count_index ( h ) ! = h - > size )
holes = count_holes ( h , index ) ;
index - = holes ;
}
return ( ok = = c ) ? index : - 1 ;
2013-03-25 12:04:10 +00:00
}
static void cube_indexes ( const hypercube * h , request * r , int * indexes , int size )
{
2013-07-10 16:58:41 +00:00
request * cube = h - > cube ;
int c = count_axis ( h ) ;
int i = 0 ;
int index = 0 ;
int n = 1 ;
int ok = 0 ;
if ( size < c )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " MARS internal error in cube_indexes. size=%d < axis=%d " , size , c ) ;
}
if ( h - > index_cache = = 0 | | h - > index_cache_size ! = c )
reserve_index_cache ( ( hypercube * ) h , c ) ;
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 ] ;
for ( k = 0 ; k < count ; k + + )
{
j = ( k + last ) % count ;
w = get_value ( cube , axis , j ) ;
if ( h - > compare ? h - > compare [ i ] ( w , v ) : ( w = = v ) )
{
index + = j * n ;
n * = dims ;
ok + + ;
( ( hypercube * ) h ) - > index_cache [ i ] = j ;
break ;
}
}
indexes [ i ] = j ;
}
2013-03-25 12:04:10 +00:00
}
/*********************************/
/* End of Auxiliary functions */
/*********************************/
static hypercube * new_hypercube ( const request * r )
{
2013-07-10 16:58:41 +00:00
hypercube * h = ( hypercube * ) calloc ( sizeof ( hypercube ) , 1 ) ;
int total = 0 , count = 0 ;
int n = 0 ;
const char * val = 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
h - > r = clone_one_request ( r ) ;
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 ) ;
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
2013-07-10 16:58:41 +00:00
if ( ( total ! = count ) | | ( count = = 0 ) )
{
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 ) ;
2013-08-13 10:03:31 +00:00
for ( n = 0 ; n < NUMBER ( global_axis ) ; + + n )
if ( ( val = get_value ( h - > r , global_axis [ n ] . name , 0 ) ) ! = NULL )
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
}
static void print_hypercube ( const hypercube * h )
{
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
}
static void free_hypercube ( hypercube * h )
{
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
}
struct stuff_1 {
2013-07-10 16:58:41 +00:00
hypercube * c ;
request * r ;
2013-03-25 12:04:10 +00:00
} ;
static void reqcb_1 ( const request * r , int count , axis_t * names , char * vals [ ] , void * data )
{
2013-07-10 16:58:41 +00:00
struct stuff_1 * s = ( struct stuff_1 * ) data ;
int i ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
for ( i = 0 ; i < count ; i + + )
if ( vals [ i ] )
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 * ) ;
static void names_loop ( const request * r , loopproc proc , void * data ) ;
static hypercube * new_hypercube_from_mars_request ( const request * r )
{
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
#if 0
2013-07-10 16:58:41 +00:00
const request * lang = mars_language_from_request ( r ) ;
int count = 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
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
# endif
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
2013-08-13 10:03:31 +00:00
for ( i = 0 ; i < NUMBER ( global_axis ) ; i + + )
2013-07-10 16:58:41 +00:00
{
2013-08-13 10:03:31 +00:00
int m = count_values ( r , global_axis [ i ] . name ) ;
2013-07-10 16:58:41 +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 " ) ;
if ( n )
s . c - > compare = calloc ( sizeof ( namecmp ) , n ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
for ( i = 0 ; i < n ; i + + )
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 */
static hypercube * new_simple_hypercube_from_mars_request ( const request * r )
{
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 " ) ;
if ( n )
s . c - > compare = calloc ( sizeof ( namecmp ) , n ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
for ( i = 0 ; i < n ; i + + )
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
}
/*===========================================================================================*/
/*===========================================================================================*/
/* Todo:
- BUILD A TEST SUITE ! !
- Print usage in log file
- consider FCMONTH and CLimatolofy
- 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 )
*/
typedef struct ncatt {
2013-07-10 16:58:41 +00:00
char name [ 1024 ] ;
char * long_name ;
char * units ;
char * short_name ;
char * standard_name ;
request * metadata ;
nc_type nctype ;
2013-03-25 12:04:10 +00:00
} ncatt_t ;
typedef struct filter {
2013-07-10 16:58:41 +00:00
fieldset * fset ;
hypercube * filter ;
int count ;
double scale_factor ;
double add_offset ;
double missing ;
boolean bitmap ;
ncatt_t att ;
request * request ;
boolean scale ;
2013-03-25 12:04:10 +00:00
} dataset_t ;
typedef struct ncfile {
2013-07-10 16:58:41 +00:00
dataset_t * filters ;
int ncid ;
2013-03-25 12:04:10 +00:00
} ncfile_t ;
typedef struct ncoptions {
2013-07-10 16:58:41 +00:00
boolean usevalidtime ; /* Whether to use valid TIME only or not */
boolean auto_refdate ; /* Automatic Reference Date */
long refdate ; /* Reference date */
const char * version ;
char * title ;
char * history ;
char * unlimited ;
boolean checkvalidtime ;
request * mars_description ;
boolean mmeans ; /* Whether this dataset is Monthly Means */
boolean climatology ; /* Whether this dataset is climatology */
2013-03-25 12:04:10 +00:00
} ncoptions_t ;
ncoptions_t setup ;
# define NC_TYPES 7
struct nc_types_values {
2013-07-10 16:58:41 +00:00
double max ;
double min ;
double missing ;
2013-03-25 12:04:10 +00:00
} nc_type_values [ NC_TYPES ] =
{
2013-07-10 16:58:41 +00:00
/* 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 */
2013-07-10 16:58:41 +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 ) ;
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 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
long dd = date % 100 ;
long dateto = grib_julian_to_date ( julianto ) ;
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 ) ;
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
}
/* Transform MARS FCMONTHs into number of months from base date.
For example , FCMONTH = 1 is current month = = 0 */
static void fcmonth2nbmonths ( request * r )
{
2013-07-10 16:58:41 +00:00
long n = count_values ( r , " fcmonth " ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( n = = 0 )
return ;
n = atol ( get_value ( r , " fcmonth " , 0 ) ) ;
set_value ( r , " fcmonth " , " %ld " , n - 1 ) ;
2013-03-25 12:04:10 +00:00
}
static long monthnumber ( const char * m )
{
2013-07-10 16:58:41 +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
2013-07-10 16:58:41 +00:00
while ( i < 12 )
if ( strcmp ( m , months [ i + + ] ) = = 0 )
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
}
/* The argument represents 1 field */
static void validation_time ( request * r )
{
2013-07-10 16:58:41 +00:00
long date = 0 ;
long time = 0 ;
long step = 0 ;
long fcmonthdays = 0 ;
long fcmonth = 0 ;
double v ;
long julian = 0 ;
long nstep = count_values ( r , " step " ) ;
long ndate = count_values ( r , " date " ) ;
long ntime = count_values ( r , " time " ) ;
long nfcmonth = count_values ( r , " fcmonth " ) ;
static long julianrefdate = 0 ;
if ( nstep > 1 | | ndate > 1 | | ntime > 1 | | nfcmonth > 1 )
{
if ( nstep > 1 )
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal error. Field has more than 1 STEP " ) ;
if ( ntime > 1 )
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal error. Field has more than 1 TIME " ) ;
if ( ndate > 1 )
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal error. Field has more than 1 DATE " ) ;
if ( nfcmonth > 1 )
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal error. Field has more than 1 FCMONTH " ) ;
print_all_requests ( r ) ;
exit ( 1 ) ;
}
if ( nstep )
step = atol ( get_value ( r , " step " , 0 ) ) ;
if ( ndate )
{
const char * p = get_value ( r , " date " , 0 ) ;
if ( is_number ( p ) )
date = atol ( p ) ;
else
{
long julian = 0 , second = 0 ;
2013-08-16 11:56:13 +00:00
boolean isjul , date_ok ;
date_ok = parsedate ( p , & julian , & second , & isjul ) ;
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 */
if ( strlen ( p ) = = 3 )
{
if ( setup . usevalidtime )
grib_context_log ( ctx , GRIB_LOG_ERROR , " Climatology data. Setting usevalidtime=OFF " ) ;
setup . auto_refdate = false ;
setup . usevalidtime = false ;
setup . climatology = true ;
}
}
if ( ntime )
time = atol ( get_value ( r , " time " , 0 ) ) ;
if ( nfcmonth )
{
fcmonth = atol ( get_value ( r , " fcmonth " , 0 ) ) ;
/* FCMONTH needs base DATE */
if ( date = = 0 )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal error: FCMONTH needs DATE " ) ;
exit ( 1 ) ;
}
fcmonthdays = fcmonth2days ( date , fcmonth ) ;
}
julian = grib_date_to_julian ( date ) ;
v = julian * 24.0 + fcmonthdays * 24.0 + time / 100.0 + step * 1.0 ;
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: date=%ld, julian=%ld, fcmonthdays=%ld, time=%ld, step=%ld, validation=%ld " , date , julian , fcmonthdays , time , step , v ) ;
set_value ( r , " _validation " , " %lf " , v ) ;
set_value ( r , " _juliandate " , " %ld " , julian ) ;
if ( ! julianrefdate )
julianrefdate = grib_date_to_julian ( setup . refdate ) ;
set_value ( r , " _validationtime " , " %lf " , v - julianrefdate * 24.0 ) ;
/* Remove minutes from TIME */
if ( ntime )
set_value ( r , " time " , " %.1lf " , time / 100.0 ) ;
2013-03-25 12:04:10 +00:00
}
static void free_nc_options ( )
{
2013-07-10 16:58:41 +00:00
if ( setup . title )
grib_context_free ( ctx , setup . title ) ;
if ( setup . history )
grib_context_free ( ctx , setup . history ) ;
if ( setup . unlimited )
grib_context_free ( ctx , setup . unlimited ) ;
if ( setup . mars_description )
free_all_requests ( setup . mars_description ) ;
2013-03-25 12:04:10 +00:00
}
static void get_nc_options ( const request * user_r )
{
2013-07-10 16:58:41 +00:00
const char * validtime = get_value ( user_r , " usevalidtime " , 0 ) ;
const char * refdate = get_value ( user_r , " referencedate " , 0 ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +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
2013-07-10 16:58:41 +00:00
setup . usevalidtime = validtime ? ( strcmp ( validtime , " true " ) = = 0 ) : false ;
setup . refdate = refdate ? atol ( refdate ) : 19000101 ;
setup . auto_refdate = refdate ? ( strcmp ( get_value ( user_r , " referencedate " , 0 ) , " AUTOMATIC " ) = = 0 ) : false ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
setup . title = title ? grib_context_strdup ( ctx , ( title ) ) : NULL ;
setup . history = history ? grib_context_strdup ( ctx , ( history ) ) : NULL ;
setup . unlimited = unlimited ? grib_context_strdup ( ctx , ( ( unlimited ) ) ) : NULL ;
setup . checkvalidtime = getenv ( " checkvalidtime " ) ? atol ( getenv ( " checkvalidtime " ) ) : 1 ;
setup . mars_description = empty_request ( " MARS " ) ;
2013-03-25 12:04:10 +00:00
}
static nc_type translate_nctype ( const char * name )
{
2013-07-10 16:58:41 +00:00
if ( ! name )
return NC_SHORT ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( strcmp ( name , " NC_BYTE " ) = = 0 )
return NC_BYTE ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( strcmp ( name , " NC_SHORT " ) = = 0 )
return NC_SHORT ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( strcmp ( name , " NC_INT " ) = = 0 )
return NC_INT ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( strcmp ( name , " NC_FLOAT " ) = = 0 )
return NC_FLOAT ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( strcmp ( name , " NC_DOUBLE " ) = = 0 )
return NC_DOUBLE ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
grib_context_log ( ctx , GRIB_LOG_ERROR , " Unknown Netcdf type '%s'. Using NC_SHORT " ) ;
return NC_SHORT ;
2013-03-25 12:04:10 +00:00
}
static void check_err ( const int stat , const int line , const char * file )
{
2013-07-10 16:58:41 +00:00
if ( stat ! = NC_NOERR )
{
( void ) fprintf ( stderr , " line %d of %s: %s \n " , line , file , nc_strerror ( stat ) ) ;
exit ( 1 ) ;
}
2013-03-25 12:04:10 +00:00
}
# define DIM_ID 1
static int set_dimension ( int ncid , const char * name , int n , int xtype , const char * units , const char * long_name )
{
2013-07-10 16:58:41 +00:00
int var_id = 0 ;
int stat = 0 ;
int dim_id = DIM_ID ;
int dim_vec [ DIM_ID ] ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( setup . unlimited & & ( strcmp ( name , setup . unlimited ) = = 0 ) )
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 ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
dim_vec [ 0 ] = dim_id ;
stat = nc_def_var ( ncid , name , ( nc_type ) xtype , 1 , dim_vec , & var_id ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( units ! = NULL )
{
stat = nc_put_att_text ( ncid , var_id , " units " , strlen ( units ) , units ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( long_name ! = NULL )
{
stat = nc_put_att_text ( ncid , var_id , " long_name " , strlen ( long_name ) , long_name ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
}
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
}
static int def_latlon ( int ncid , fieldset * fs )
{
2013-07-10 16:58:41 +00:00
int n = 0 ;
size_t l = 0 ;
int var_id = 0 ;
err e = 0 ;
field * g = get_field ( fs , 0 , expand_mem ) ;
char grid_type [ 80 ] ;
size_t size ;
size = sizeof ( grid_type ) ;
if ( ( e = grib_get_string ( g - > handle , " typeOfGrid " , grid_type , & size ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get typeOfGrid %s " , grib_get_error_message ( e ) ) ;
return e ;
}
if ( strcmp ( grid_type , " regular_ll " ) ! = 0 & & ( strcmp ( grid_type , " regular_gg " ) ! = 0 ) )
{
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 ;
}
/* Define longitude */
if ( ( e = grib_get_size ( g - > handle , " distinctLongitudes " , & l ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get distinctLongitudes %s " , grib_get_error_message ( e ) ) ;
return e ;
}
n = l ;
var_id = set_dimension ( ncid , " longitude " , n , NC_FLOAT , " degrees_east " , " longitude " ) ;
/* Define latitude */
if ( ( e = grib_get_size ( g - > handle , " distinctLatitudes " , & l ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get distinctLatitudes %s " , grib_get_error_message ( e ) ) ;
return e ;
}
n = l ;
var_id = set_dimension ( ncid , " latitude " , n , NC_FLOAT , " degrees_north " , " latitude " ) ;
/* g->purge_header = true; */
release_field ( g ) ;
return e ;
2013-03-25 12:04:10 +00:00
}
static int put_latlon ( int ncid , fieldset * fs )
{
2013-07-10 16:58:41 +00:00
int var_id = 0 ;
int i = 0 ;
size_t n = 0 ;
int stat = 0 ;
err e = 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
field * g = get_field ( fs , 0 , expand_mem ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +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 )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get iDirectionIncrementInDegrees %s " , grib_get_error_message ( e ) ) ;
return e ;
}
if ( ( e = grib_get_double ( g - > handle , " jDirectionIncrementInDegrees " , & ns_stride ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get jDirectionIncrementInDegrees %s " , grib_get_error_message ( e ) ) ;
return e ;
}
/* Define longitude */
if ( ( e = grib_get_long ( g - > handle , " Ni " , & ni ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get Ni %s " , grib_get_error_message ( e ) ) ;
return e ;
}
/* Define latitude */
if ( ( e = grib_get_long ( g - > handle , " Nj " , & nj ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get Nj %s " , grib_get_error_message ( e ) ) ;
return e ;
}
2013-03-25 12:04:10 +00:00
# endif
if ( ( e = grib_get_size ( g - > handle , " distinctLatitudes " , & nj ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get distinctLatitudes %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
2013-03-25 12:04:10 +00:00
}
if ( ( e = grib_get_size ( g - > handle , " distinctLongitudes " , & ni ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get distinctLongitudes %s " , grib_get_error_message ( e ) ) ;
2013-07-10 16:58:41 +00:00
return e ;
}
/* Compute max. # values and allocate */
nv = ni ;
if ( nv < nj )
nv = nj ;
fvalues = ( float * ) grib_context_malloc ( ctx , sizeof ( float ) * nv ) ;
dvalues = ( double * ) grib_context_malloc ( ctx , sizeof ( double ) * nv ) ;
/* longitude */
n = ni ;
stat = nc_inq_varid ( ncid , " longitude " , & var_id ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
if ( ( e = grib_get_double_array ( g - > handle , " distinctLongitudes " , dvalues , & n ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get distinctLongitudes %s " , grib_get_error_message ( e ) ) ;
return e ;
}
2013-03-25 12:04:10 +00:00
Assert ( n = = ni ) ;
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 ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
/* latitude */
n = nj ;
stat = nc_inq_varid ( ncid , " latitude " , & var_id ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
if ( ( e = grib_get_double_array ( g - > handle , " distinctLatitudes " , dvalues , & n ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get distinctLatitudes %s " , grib_get_error_message ( e ) ) ;
return e ;
}
2013-03-25 12:04:10 +00:00
Assert ( n = = nj ) ;
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 ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
/* g->purge_header = true; */
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
}
static int compute_scale ( dataset_t * subset )
{
2013-07-10 16:58:41 +00:00
double max = - DBL_MAX ;
double min = DBL_MAX ;
double median = 0 ;
long i = 0 ;
long j = 0 ;
int64_t scaled_max = 0 ;
int64_t scaled_min = 0 ;
int64_t scaled_median = 0 ;
double ao = 0.0 , sf = 0.0 ;
double x ;
char test_scaled_max = 0 ;
char test_scaled_min = 0 ;
char test_scaled_median = 0 ;
err e = 0 ;
fieldset * fs = subset - > fset ;
int idx = subset - > att . nctype ;
for ( i = 0 ; i < fs - > count ; i + + )
{
field * g = get_field ( fs , i , expand_mem ) ;
size_t len ;
static double * vals = NULL ;
static size_t vals_len = 0 ;
if ( ( e = grib_get_size ( g - > handle , " values " , & len ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get size of values %s " , grib_get_error_message ( e ) ) ;
return e ;
}
if ( len > vals_len )
{
if ( vals )
grib_context_free ( ctx , vals ) ;
vals = ( double * ) grib_context_malloc ( ctx , sizeof ( double ) * len ) ;
vals_len = len ;
}
if ( ( e = grib_get_double_array ( g - > handle , " values " , vals , & len ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get values %s " , grib_get_error_message ( e ) ) ;
return e ;
}
if ( g - > bitmap )
{
subset - > bitmap = true ;
for ( j = 0 ; j < len ; + + j )
{
if ( vals [ j ] ! = ( double ) missing_value )
{
if ( vals [ j ] > max )
max = vals [ j ] ;
if ( vals [ j ] < min )
min = vals [ j ] ;
}
}
}
else
{
for ( j = 0 ; j < len ; + + j )
{
if ( vals [ j ] > max )
max = vals [ j ] ;
if ( vals [ j ] < min )
min = vals [ j ] ;
}
}
/* g->purge_header = true; */
release_field ( g ) ;
}
median = ( max + min ) / 2.0 ;
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: max_int: %lf, min_int: %lf " , nc_type_values [ idx ] . max , nc_type_values [ idx ] . min ) ;
sf = ( double ) ( ( max - min ) / ( double ) ( nc_type_values [ idx ] . max - nc_type_values [ idx ] . min ) ) ;
ao = ( ( max + min ) - sf * ( nc_type_values [ idx ] . min + nc_type_values [ idx ] . max ) ) / 2 ;
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 ) ;
scaled_max = rint ( ( max - ao ) / sf ) ;
scaled_min = rint ( ( min - ao ) / sf ) ;
scaled_median = rint ( ( median - ao ) / sf ) ;
test_scaled_max = ( char ) scaled_max ;
test_scaled_min = ( char ) scaled_min ;
test_scaled_median = ( char ) scaled_median ;
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: scaled_max: %lld, scaled_min: %lld, scaled_median: %lld, x: %lf " , scaled_max , scaled_min , scaled_median , x ) ;
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 , x ) ;
max = scaled_max * sf + ao ;
min = scaled_min * sf + ao ;
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 ;
subset - > add_offset = ao ;
return 0 ;
2013-03-25 12:04:10 +00:00
}
static int nc_put_att_type ( int ncid , int varid , const char * name , nc_type nctype , int n , double value )
{
2013-07-10 16:58:41 +00:00
int r = 0 ;
unsigned char val_uchar = ( unsigned char ) value ;
short int val_short = ( short int ) value ;
int val_int = ( int ) value ;
float val_flt = ( float ) value ;
double val_dbl = ( double ) value ;
switch ( nctype )
{
case NC_BYTE :
r = nc_put_att_uchar ( ncid , varid , name , nctype , n , & val_uchar ) ;
break ;
case NC_SHORT :
r = nc_put_att_short ( ncid , varid , name , nctype , n , & val_short ) ;
break ;
case NC_INT :
r = nc_put_att_int ( ncid , varid , name , nctype , n , & val_int ) ;
break ;
case NC_FLOAT :
r = nc_put_att_float ( ncid , varid , name , nctype , n , & val_flt ) ;
break ;
case NC_DOUBLE :
r = nc_put_att_double ( ncid , varid , name , nctype , n , & val_dbl ) ;
break ;
default :
grib_context_log ( ctx , GRIB_LOG_ERROR , " nc_put_att_type(...): Unknown netcdf type '%d' " , nctype ) ;
break ;
}
return r ;
2013-03-25 12:04:10 +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-07-10 16:58:41 +00:00
int r = 0 ;
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 :
grib_context_log ( ctx , GRIB_LOG_ERROR , " nc_put_vara_type(...): Unknown netcdf type '%d' " , nctype ) ;
break ;
}
return r ;
2013-03-25 12:04:10 +00:00
}
static void scale_bitmap ( double * vals , long n , void * data , dataset_t * subset )
{
2013-07-10 16:58:41 +00:00
int i = 0 ;
nc_type nctype = subset - > att . nctype ;
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 - > bitmap )
{
grib_context_log ( ctx , GRIB_LOG_DEBUG , " No scale of bitmap required " ) ;
return ;
}
2013-07-10 16:58:41 +00:00
*/
switch ( nctype )
{
case NC_BYTE :
{
unsigned char * vscaled = ( unsigned char * ) data ;
for ( i = 0 ; i < n ; + + i )
if ( vals [ i ] = = missing_value )
vscaled [ i ] = ( unsigned char ) subset - > missing ;
break ;
}
case NC_SHORT :
{
short int * vscaled = ( short int * ) data ;
for ( i = 0 ; i < n ; + + i )
if ( vals [ i ] = = missing_value )
vscaled [ i ] = ( short int ) subset - > missing ;
break ;
}
case NC_INT :
{
int * vscaled = ( int * ) data ;
for ( i = 0 ; i < n ; + + i )
if ( vals [ i ] = = missing_value )
vscaled [ i ] = ( int ) subset - > missing ;
break ;
}
case NC_FLOAT :
{
float * vscaled = ( float * ) data ;
for ( i = 0 ; i < n ; + + i )
if ( vals [ i ] = = missing_value )
vscaled [ i ] = ( float ) subset - > missing ;
break ;
}
case NC_DOUBLE :
{
double * vscaled = ( double * ) data ;
for ( i = 0 ; i < n ; + + i )
if ( vals [ i ] = = missing_value )
vscaled [ i ] = ( double ) subset - > missing ;
break ;
}
default :
grib_context_log ( ctx , GRIB_LOG_ERROR , " scale(...): Unknown netcdf type %d " , nctype ) ;
break ;
}
2013-03-25 12:04:10 +00:00
}
static void scale ( double * vals , long n , void * data , dataset_t * g )
{
2013-07-10 16:58:41 +00:00
int i = 0 ;
nc_type nctype = g - > att . nctype ;
double scale_factor = g - > scale_factor ;
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 ;
}
2013-07-10 16:58:41 +00:00
*/
switch ( nctype )
{
case NC_BYTE :
{
unsigned char * vscaled = ( unsigned char * ) data ;
for ( i = 0 ; i < n ; + + i )
{
if ( ! g - > bitmap | | ( vals [ i ] ! = missing_value ) )
{
double d = rint ( ( vals [ i ] - add_offset ) / scale_factor ) ;
Assert ( d > = nc_type_values [ nctype ] . min & & d < = nc_type_values [ nctype ] . max ) ;
vscaled [ i ] = d ;
}
}
break ;
}
case NC_SHORT :
{
short int * vscaled = ( short int * ) data ;
for ( i = 0 ; i < n ; + + i )
{
if ( ! g - > bitmap | | ( vals [ i ] ! = missing_value ) )
{
double d = 0 ;
Assert ( scale_factor > 0 ) ;
d = rint ( ( vals [ i ] - add_offset ) / scale_factor ) ;
Assert ( d > = nc_type_values [ nctype ] . min & & d < = nc_type_values [ nctype ] . max ) ;
vscaled [ i ] = d ;
}
}
break ;
}
case NC_INT :
{
int * vscaled = ( int * ) data ;
for ( i = 0 ; i < n ; + + i )
{
if ( ! g - > bitmap | | ( vals [ i ] ! = missing_value ) )
{
double d = rint ( ( vals [ i ] - add_offset ) / scale_factor ) ;
Assert ( d > = nc_type_values [ nctype ] . min & & d < = nc_type_values [ nctype ] . max ) ;
vscaled [ i ] = d ;
}
}
break ;
}
case NC_FLOAT :
{
float * vscaled = ( float * ) data ;
for ( i = 0 ; i < n ; + + i )
{
if ( ! g - > bitmap | | ( vals [ i ] ! = missing_value ) )
{
double d = vals [ i ] ;
Assert ( d > = nc_type_values [ nctype ] . min & & d < = nc_type_values [ nctype ] . max ) ;
vscaled [ i ] = d ;
}
}
break ;
}
case NC_DOUBLE :
{
double * vscaled = ( double * ) data ;
for ( i = 0 ; i < n ; + + i )
{
if ( ! g - > bitmap | | ( vals [ i ] ! = missing_value ) )
{
double d = vals [ i ] ;
Assert ( d > = nc_type_values [ nctype ] . min & & d < = nc_type_values [ nctype ] . max ) ;
vscaled [ i ] = d ;
}
}
break ;
}
default :
grib_context_log ( ctx , GRIB_LOG_ERROR , " scale(...): Unknown netcdf type %d " , nctype ) ;
break ;
}
2013-03-25 12:04:10 +00:00
}
static int put_data ( hypercube * h , int ncid , const char * name , dataset_t * subset )
{
2013-07-10 16:58:41 +00:00
int i = 0 ;
int stat = 0 ;
int dataid = 0 ;
int naxis = count_axis ( h ) ;
size_t start [ NC_MAX_DIMS ] ;
size_t count [ NC_MAX_DIMS ] ;
fieldset * fs = subset - > fset ;
field * f = get_field ( fs , 0 , expand_mem ) ;
void * vscaled = NULL ;
long vscaled_length = 0 ;
long ni ;
long nj ;
err e = 0 ;
/* Define longitude */
if ( ( e = grib_get_long ( f - > handle , " Ni " , & ni ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get Ni %s " , grib_get_error_message ( e ) ) ;
return e ;
}
/* Define latitude */
if ( ( e = grib_get_long ( f - > handle , " Nj " , & nj ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get Nj %s " , grib_get_error_message ( e ) ) ;
return e ;
}
/* Start filling dimensions at first value */
for ( i = 0 ; i < 2 + naxis ; + + i )
start [ i ] = 0 ;
/* Count dimensions per axis */
for ( i = 0 ; i < naxis ; + + i )
count [ naxis - i - 1 ] = 1 ;
count [ naxis ] = nj ; /* latitude */
count [ naxis + 1 ] = ni ; /* longitude */
/* f->purge_header = true; */
release_field ( f ) ;
stat = nc_inq_varid ( ncid , name , & dataid ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
for ( i = 0 ; i < fs - > count ; i + + )
{
field * g = get_field ( fs , i , expand_mem ) ;
size_t len ;
static double * vals = NULL ;
static size_t vals_len = 0 ;
boolean missing = 0 ;
request * r ;
int j = 0 ;
int idx [ 1024 ] ;
int idxsize = 1024 ;
if ( ( e = grib_get_size ( g - > handle , " values " , & len ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get size of values %s " , grib_get_error_message ( e ) ) ;
return e ;
}
if ( len > vals_len )
{
if ( vals )
grib_context_free ( ctx , vals ) ;
vals = ( double * ) grib_context_malloc ( ctx , sizeof ( double ) * len ) ;
vals_len = len ;
}
if ( ( e = grib_get_double_array ( g - > handle , " values " , vals , & len ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get values %s " , grib_get_error_message ( e ) ) ;
return e ;
}
2013-03-25 12:04:10 +00:00
#if 0
2013-07-10 16:58:41 +00:00
boolean missing = ( g - > ksec4 [ 0 ] < 0 ) ; /* If negative number of values, field is missing */
2013-03-25 12:04:10 +00:00
# endif
2013-07-10 16:58:41 +00:00
r = field_to_request ( g ) ;
if ( ! missing )
{
/* Reserved the maximum memory needed */
/* This should only be done once, as all fields have the same geometry */
if ( ( vscaled_length = = 0 ) | | ( vscaled_length < sizeof ( double ) * len ) )
{
if ( vscaled )
grib_context_free ( ctx , vscaled ) ;
vscaled = ( void * ) grib_context_malloc ( ctx , sizeof ( double ) * len ) ;
vscaled_length = sizeof ( double ) * len ;
}
scale ( vals , len , vscaled , subset ) ;
if ( subset - > bitmap )
scale_bitmap ( vals , len , vscaled , subset ) ;
if ( ( e = grib_get_long ( g - > handle , " Ni " , & ni ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get Ni %s " , grib_get_error_message ( e ) ) ;
return e ;
}
/* Define latitude */
if ( ( e = grib_get_long ( g - > handle , " Nj " , & nj ) ) ! = GRIB_SUCCESS )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " grib_api: cannot get Nj %s " , grib_get_error_message ( e ) ) ;
return e ;
}
if ( nj ! = count [ naxis ] | | ni ! = count [ naxis + 1 ] )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " Grib %d has different resolution \n " , i + 1 ) ;
grib_context_log ( ctx , GRIB_LOG_ERROR , " lat=%d, long=%d instead of lat=%d, long=%d \n " , nj , ni , count [ naxis ] , count [ naxis + 1 ] ) ;
exit ( 1 ) ;
}
cube_indexes ( h , r , idx , idxsize ) ;
for ( j = 0 ; j < naxis ; + + j )
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 ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
}
/* g->purge_header = true; */
release_field ( g ) ;
}
grib_context_free ( ctx , vscaled ) ;
return 0 ;
2013-03-25 12:04:10 +00:00
}
static void set_always_a_time ( hypercube * h , request * data_r )
{
2013-08-19 15:44:32 +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 " ) ;
if ( n )
{
h - > compare = calloc ( sizeof ( namecmp ) , n ) ;
Assert ( h - > compare ) ;
}
for ( i = 0 ; i < n ; i + + )
h - > compare [ i ] = comparator ( get_value ( h - > cube , " axis " , i ) ) ;
}
}
2013-03-25 12:04:10 +00:00
}
static int define_netcdf_dimensions ( hypercube * h , fieldset * fs , int ncid , dataset_t * subsets , int subsetcnt , const request * data_r )
{
2013-07-10 16:58:41 +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 */
int dims [ 1024 ] ;
err e = GRIB_SUCCESS ;
/* START DEFINITIONS */
/* Define latitude/longitude dimensions */
e = def_latlon ( ncid , fs ) ;
if ( e ! = GRIB_SUCCESS )
return e ;
/* Define netcdf dimensions */
for ( i = 0 ; i < naxis ; + + i )
{
int nctype = NC_INT ;
const char * axis = get_axis ( h , i ) ;
char * units = NULL ;
char u [ 10240 ] ;
const char * lowaxis = ( axis ) ;
char * longname = ( char * ) lowaxis ;
n = count_values ( cube , axis ) ;
if ( count_values ( data_r , " LEVTYPE " ) > 1 )
{
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 ) ;
}
if ( strcmp ( axis , " levelist " ) = = 0 )
{
const char * levtype = get_value ( data_r , " levtype " , 0 ) ;
if ( levtype )
{
if ( strcmp ( " pl " , levtype ) = = 0 )
{
units = " millibars " ;
longname = " pressure_level " ;
}
if ( strcmp ( " ml " , levtype ) = = 0 )
{
longname = " model_level_number " ;
}
}
lowaxis = " level " ;
}
if ( strcmp ( axis , " number " ) = = 0 )
{
longname = " ensemble_member " ;
}
if ( strcmp ( axis , " date " ) = = 0 )
{
sprintf ( u , " days since %ld-%02ld-%02ld 00:00:0.0 " , setup . refdate / 10000 , ( setup . refdate % 10000 ) / 100 , ( setup . refdate % 100 ) ) ;
units = u ;
longname = " Base_date " ;
if ( setup . climatology )
{
sprintf ( u , " months " ) ;
units = u ;
}
}
if ( strcmp ( axis , " time " ) = = 0 )
{
boolean onedtime = ( count_values ( cube , " date " ) = = 0 & & count_values ( cube , " step " ) = = 0 ) ;
sprintf ( u , " hours since 0000-00-00 00:00:0.0 " ) ;
longname = " reference_time " ;
if ( setup . usevalidtime | | onedtime )
{
sprintf ( u , " hours since %ld-%02ld-%02ld 00:00:0.0 " , setup . refdate / 10000 , ( setup . refdate % 10000 ) / 100 , ( setup . refdate % 100 ) ) ;
longname = " time " ;
}
if ( setup . climatology )
{
sprintf ( u , " hours " ) ;
}
units = u ;
/* nctype = NC_FLOAT; */
}
if ( strcmp ( axis , " step " ) = = 0 )
{
units = " hours " ;
longname = " time_step " ;
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 ;
sprintf ( u , " hours since %ld-%02ld-%02ld %02ld:%02ld:0.0 " , date / 10000 , ( date % 10000 ) / 100 , ( date % 100 ) , hour , min ) ;
units = u ;
}
}
if ( ( strcmp ( axis , " fcmonth " ) = = 0 ) )
{
const char * date = get_value ( data_r , " date " , 0 ) ;
char ymd [ 32 ] = " " ;
if ( date )
{
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 " ) ;
}
else
{
sprintf ( ymd , " 00-00-00 " ) ;
}
sprintf ( u , " months since %s 00:00:00.0 " , ymd ) ;
units = u ;
longname = " time " ;
}
var_id = set_dimension ( ncid , lowaxis , n , nctype , units , longname ) ;
if ( strcmp ( axis , " time " ) = = 0 )
{
if ( setup . usevalidtime )
{
if ( setup . mmeans )
{
char * period = " 0000-01-00 00:00:00 " ;
stat = nc_put_att_text ( ncid , var_id , " avg_period " , strlen ( period ) , period ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
}
}
}
}
/* Define data dimension */
n = 1 + 1 + naxis ; /* longitude + latitude + # axis */
for ( i = 0 ; i < n ; + + i )
dims [ i ] = n - i - 1 ;
for ( i = 0 ; i < subsetcnt ; + + i )
{
2013-03-25 12:04:10 +00:00
printf ( " %s: Defining variable '%s'. \n " , grib_tool_name , subsets [ i ] . att . name ) ;
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 ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
if ( subsets [ i ] . scale )
{
compute_scale ( & subsets [ i ] ) ;
stat = nc_put_att_double ( ncid , var_id , " scale_factor " , NC_DOUBLE , 1 , & subsets [ i ] . scale_factor ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
stat = nc_put_att_double ( ncid , var_id , " add_offset " , NC_DOUBLE , 1 , & subsets [ i ] . add_offset ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
}
stat = nc_put_att_type ( ncid , var_id , " _FillValue " , subsets [ i ] . att . nctype , 1 , nc_type_values [ subsets [ i ] . att . nctype ] . missing ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
stat = nc_put_att_type ( ncid , var_id , " missing_value " , subsets [ i ] . att . nctype , 1 , nc_type_values [ subsets [ i ] . att . nctype ] . missing ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
if ( subsets [ i ] . att . units )
{
const char * txt = subsets [ i ] . att . units ;
stat = nc_put_att_text ( ncid , var_id , " units " , strlen ( txt ) , txt ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
}
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 ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
}
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 ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
}
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 ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
}
2013-03-25 12:04:10 +00:00
#if 0
2013-07-10 16:58:41 +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 ( stat , __LINE__ , __FILE__ ) ;
}
2013-03-25 12:04:10 +00:00
# endif
2013-07-10 16:58:41 +00:00
if ( subsets [ i ] . att . metadata )
{
parameter * p = subsets [ i ] . att . metadata - > params ;
while ( p )
{
const char * txt = p - > values - > name ;
stat = nc_put_att_text ( ncid , var_id , p - > name , strlen ( txt ) , txt ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
p = p - > next ;
}
}
}
/* Dimension-less variable for MARS request */
if ( 0 ) /* reset when we have proper & fast mars_description */
{
/* parameter *p = data_r->params; */
parameter * p = setup . mars_description - > params ;
stat = nc_def_var ( ncid , " MARS " , NC_CHAR , 0 , 0 , & var_id ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
/* Store request for those parameters with single value */
while ( p )
{
/* if((p->name[0] != '_') && (p->count == 1)) */
if ( p - > name [ 0 ] ! = ' _ ' )
{
char par [ 1024 ] ;
char val [ 1024000 ] = " " ;
sprintf ( 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
2013-07-10 16:58:41 +00:00
sprintf ( 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 ) ) ;
if ( stat ! = NC_NOERR )
{
printf ( " Error setting request for %s = %s \n " , par , val ) ;
}
check_err ( stat , __LINE__ , __FILE__ ) ;
}
p = p - > next ;
}
}
/* Global attributes */
{
char timestamp [ 80 ] ;
time_t now ;
/* char *convention = "MARS;CF"; */
char * convention = " CF-1.0 " ;
char history [ 10240 ] ;
/* char *institution = "ECMWF Meteorological Archival and Retrieval System"; */
/* Convention */
stat = nc_put_att_text ( ncid , NC_GLOBAL , " Conventions " , strlen ( convention ) , convention ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
/* Use history provided or Timestamp */
if ( setup . history )
{
sprintf ( history , " %s " , setup . history ) ;
}
else
{
int major = GRIB_API_MAJOR_VERSION ;
int minor = GRIB_API_MINOR_VERSION ;
int revision = GRIB_API_REVISION_VERSION ;
time ( & now ) ;
strftime ( timestamp , sizeof ( timestamp ) , " %Y-%m-%d %H:%M:%S GMT " , gmtime ( & now ) ) ;
2013-08-13 15:47:23 +00:00
sprintf ( 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 ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
2013-03-25 12:04:10 +00:00
#if 0
2013-07-10 16:58:41 +00:00
stat = nc_put_att_text ( ncid , NC_GLOBAL , " source " , strlen ( setup . source ) , setup . source ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
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
# endif
2013-07-10 16:58:41 +00:00
if ( setup . title )
{
stat = nc_put_att_text ( ncid , NC_GLOBAL , " title " , strlen ( setup . title ) , setup . title ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
}
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
}
static int fill_netcdf_dimensions ( hypercube * h , fieldset * fs , int ncid )
{
2013-07-10 16:58:41 +00:00
const request * cube = h - > cube ;
int naxis = count_axis ( h ) ;
int i = 0 ;
int var_id = 0 ;
int stat = 0 ;
/* Put latitude/longitude values */
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: Put latitude/longitude values " ) ;
put_latlon ( ncid , fs ) ;
/* Put netcdf axis values */
grib_context_log ( ctx , GRIB_LOG_DEBUG , " grib_to_netcdf: Put netcdf axis values " ) ;
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 ) ;
if ( ! values )
grib_context_log ( ctx , GRIB_LOG_ERROR , " fill_netcdf_dimensions: cannot allocate %ld bytes " , sizeof ( int ) * n ) ;
if ( strcmp ( " levelist " , axis ) = = 0 )
lowaxis = " level " ;
if ( strcmp ( " date " , axis ) = = 0 )
{
if ( setup . climatology )
for ( j = 0 ; j < n ; + + j )
values [ j ] = monthnumber ( get_value ( cube , axis , j ) ) ;
else
for ( j = 0 ; j < n ; + + j )
values [ j ] = grib_date_to_julian ( atol ( get_value ( cube , axis , j ) ) ) - grib_date_to_julian ( setup . refdate ) ;
}
else
{
for ( j = 0 ; j < n ; + + j )
values [ j ] = atol ( get_value ( cube , axis , j ) ) ;
}
stat = nc_inq_varid ( ncid , ( lowaxis ) , & var_id ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
if ( strcmp ( " time " , axis ) = = 0 & & setup . unlimited ! = NULL & & strcmp ( setup . unlimited , " time " ) = = 0 & & setup . usevalidtime )
{
/* This is tricky. I'm not sure it works when time is not outer dimension */
size_t start [ NC_MAX_DIMS ] ;
size_t count [ NC_MAX_DIMS ] ;
start [ 0 ] = 0 ;
count [ 0 ] = n ;
stat = nc_put_vara_type ( ncid , var_id , start , count , values , NC_INT ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
}
else
{
stat = nc_put_var_int ( ncid , var_id , values ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
}
grib_context_free ( ctx , values ) ;
}
return 0 ;
2013-03-25 12:04:10 +00:00
}
static void remove_param ( request * r , void * data , const char * p )
{
2013-07-10 16:58:41 +00:00
request * config = ( request * ) data ;
const char * ignore ;
int i = 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
while ( ( ignore = get_value ( config , p , i + + ) ) ! = NULL )
unset_value ( r , ignore ) ;
2013-03-25 12:04:10 +00:00
}
# define NO_TABLE -1
# define NO_PARAM 0
static void paramtable ( const char * p , long * param , long * table , boolean paramIdMode )
{
2013-07-10 16:58:41 +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
2013-07-10 16:58:41 +00:00
while ( p & & ( * p ! = ' . ' ) & & ( ( p - q ) < len ) )
+ + p ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( ( * p = = ' . ' ) )
* 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
*/
if ( paramIdMode )
{
/* Special case for param=228015 => 15.228 */
if ( ( * param ! = NO_PARAM ) & & ( * table = = NO_TABLE ) & & ( len = = 6 ) )
{
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
}
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-07-10 16:58:41 +00:00
const char * split = NULL ;
int j = 0 ;
boolean set_param_as_name = true ;
long datatable = 0 ; /* = atol(get_value(data_r,"_CODETABLE2",0)); */
if ( count_values ( user_r , " split " ) = = 0 )
strcat ( att - > name , " data " ) ;
while ( ( split = get_value ( user_r , " split " , j + + ) ) ! = NULL )
{
if ( strcmp ( split , " param " ) ! = 0 )
{
if ( count_values ( data_r , split ) > 1 )
set_param_as_name = false ;
}
}
j = 0 ;
while ( ( split = get_value ( user_r , " split " , j + + ) ) ! = NULL )
{
boolean found = false ;
request * cfg = ( request * ) config_r ;
boolean is_param = strcmp ( split , " param " ) = = 0 ;
/* 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 */
2013-07-10 16:58:41 +00:00
boolean setname = ( ( count_values ( data_r , split ) > 1 ) | | ( is_param & & set_param_as_name ) ) ;
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 ;
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 ;
long cfgparam = atol ( cfgval ) ;
long dataparam = atol ( dataval ) ;
paramtable ( dataval , & dataparam , & datatable , false ) ;
/* 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 */
2013-07-10 16:58:41 +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 ;
if ( ( val = get_value ( cfg , " accuracy " , 0 ) ) ! = NULL )
att - > nctype = translate_nctype ( val ) ;
att - > long_name = grib_context_strdup ( ctx , ( get_value ( cfg , " LONG_NAME " , 0 ) ) ) ;
att - > short_name = grib_context_strdup ( ctx , ( get_value ( cfg , " SHORT_NAME " , 0 ) ) ) ;
att - > units = grib_context_strdup ( ctx , ( get_value ( cfg , " UNITS " , 0 ) ) ) ;
/* Check if there is more metadata for this variable */
if ( ( metafile = get_value ( cfg , " METADATA " , 0 ) ) ! = NULL )
{
static const char * metadata_dir = NULL ;
char metapath [ 1024 ] ;
if ( ! metadata_dir )
metadata_dir = getenv ( " METADATA_DIR " ) ;
sprintf ( metapath , " %s/%s " , metadata_dir ? metadata_dir : " . " , metafile ) ;
att - > metadata = 0 ; /* read_request_file(metapath); */
}
if ( setname )
{
const char * pname = get_value ( cfg , " DATA " , 0 ) ;
if ( strlen ( att - > name ) )
strcat ( att - > name , " _ " ) ;
strcat ( att - > name , pname ) ;
}
found = true ;
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 */
if ( ! found )
{
const char * val = get_value ( subset_r , split , 0 ) ;
if ( val & & ( setname ) )
{
if ( strlen ( att - > name ) )
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 */
2013-07-10 16:58:41 +00:00
if ( ! isalpha ( att - > name [ 0 ] ) )
{
char buf [ 1024 ] ;
2013-07-22 13:06:46 +00:00
sprintf ( buf , " p%s " , att - > name ) ;
2013-07-10 16:58:41 +00:00
strcpy ( att - > name , buf ) ;
}
2013-03-25 12:04:10 +00:00
}
static request * first ;
static request * last ;
static void reqcb ( const request * r , int count , axis_t * names , char * vals [ ] , void * data )
{
2013-07-10 16:58:41 +00:00
request * w = clone_one_request ( r ) ;
int i ;
/*request **d = (request**)data;*/
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +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 ) + + ;
for ( i = 0 ; i < count ; i + + )
{
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( vals [ i ] )
put_value ( w , names [ i ] . name , vals [ i ] , false , false , false ) ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( first = = NULL )
first = w ;
else
last - > next = w ;
last = w ;
2013-03-25 12:04:10 +00:00
}
static boolean chk_152 ( int count , axis_t * names , char * vals [ ] )
{
2013-07-10 16:58:41 +00:00
return true ;
2013-03-25 12:04:10 +00:00
}
static void loop ( const request * r , boolean ml , int index , int count , axis_t * strings , char * values [ ] , loopproc callback , void * data )
{
2013-07-10 16:58:41 +00:00
if ( index < count )
{
parameter * p = find_parameter ( r , strings [ index ] . name ) ;
2013-08-15 15:08:19 +00:00
( void ) count_values ( r , strings [ index ] . name ) ; /* force list expansion */
2013-07-10 16:58:41 +00:00
if ( p )
{
value * v = p - > values ;
while ( v )
{
values [ index ] = v - > name ;
loop ( r , ml , index + 1 , count , strings , values , callback , data ) ;
v = v - > next ;
}
}
else
{
values [ index ] = NULL ;
loop ( r , ml , index + 1 , count , strings , values , callback , data ) ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
}
else if ( ! ml | | chk_152 ( count , strings , values ) )
callback ( r , count , strings , values , data ) ;
2013-03-25 12:04:10 +00:00
}
static void values_loop ( const request * r , int count , axis_t * parnames , loopproc callback , void * data )
{
2013-07-10 16:58:41 +00:00
char * * values = ( char * * ) grib_context_malloc ( ctx , sizeof ( char * ) * count ) ;
const char * p = get_value ( r , " levtype " , 0 ) ;
boolean ml = ( boolean ) ( p & & ( strcmp ( p , " ml " ) = = 0 ) ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( ml )
{
p = get_value ( r , " expect " , 0 ) ;
if ( p & & atol ( p ) ! = 0 )
{
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 " ) ;
ml = false ;
}
}
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
}
static void names_loop ( const request * r , loopproc proc , void * data )
{
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
}
static request * unwind_one_request ( const request * r )
{
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
}
static int split_fieldset ( fieldset * fs , request * data_r , dataset_t * * subsets , const request * user_r , const request * config_r )
{
2013-07-10 16:58:41 +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 ) ) ;
s = empty_request ( " filter " ) ;
while ( ( split = get_value ( user_r , " split " , i + + ) ) ! = NULL )
{
int cnt = count_values ( data_r , split ) ;
if ( cnt )
{
count * = count_values ( data_r , split ) ;
valcpy ( s , data_r , ( char * ) split , ( char * ) split ) ;
}
}
u = unwind_one_request ( s ) ;
free_all_requests ( s ) ;
filters = calloc ( sizeof ( dataset_t ) , count ) ;
Assert ( filters ) ;
s = u ;
for ( i = 0 ; i < count ; + + i )
{
Assert ( s ) ;
filters [ i ] . filter = new_hypercube_from_mars_request ( s ) ;
filters [ i ] . fset = new_fieldset ( 1 ) ;
filters [ i ] . count = 0 ;
filters [ i ] . request = clone_one_request ( s ) ;
filters [ i ] . bitmap = false ;
/* filters[i].mmeans = false; */
s = s - > next ;
}
for ( i = 0 ; i < fs - > count ; + + i )
{
boolean ok = false ;
field * f = get_field ( fs , i , packed_mem ) ;
request * g = field_to_request ( f ) ;
int j = 0 ;
while ( ! ok & & ( j < count ) )
{
ok = ( cube_order ( filters [ j ] . filter , g ) ! = - 1 ) ;
if ( ok )
{
const char * p ;
set_field ( filters [ j ] . fset , f , filters [ j ] . count + + ) ;
filters [ j ] . bitmap | = f - > bitmap ;
if ( ( p = get_value ( f - > r - > r , " _units " , 0 ) ) ! = NULL )
{
filters [ j ] . att . units = grib_context_strdup ( ctx , p ) ;
}
if ( ( p = get_value ( f - > r - > r , " _long_name " , 0 ) ) ! = NULL )
{
filters [ j ] . att . long_name = grib_context_strdup ( ctx , p ) ;
}
if ( ( p = get_value ( f - > r - > r , " _cf_name " , 0 ) ) ! = NULL )
{
filters [ j ] . att . standard_name = grib_context_strdup ( ctx , p ) ;
}
}
j + + ;
}
if ( ! ok )
{
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 ) ;
}
/* f->purge_header = true; */
release_field ( f ) ;
}
for ( i = 0 ; i < count ; + + i )
{
filters [ i ] . att . nctype = nctype ;
filters [ i ] . scale = true ;
filters [ i ] . missing = nc_type_values [ nctype ] . missing ;
find_nc_attributes ( filters [ i ] . request , user_r , & ( filters [ i ] . att ) , config_r , data_r ) ;
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 ) ;
if ( strlen ( filters [ i ] . att . name ) = = 0 )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " Variable name not found " ) ;
exit ( 1 ) ;
}
/* Check if we need scaling */
switch ( filters [ i ] . att . nctype )
{
case NC_FLOAT :
case NC_DOUBLE :
filters [ i ] . scale = false ;
break ;
default :
filters [ i ] . scale = true ;
break ;
}
}
free_all_requests ( u ) ;
* subsets = filters ;
return count ;
2013-03-25 12:04:10 +00:00
}
static void free_subsets ( dataset_t * subsets , int count )
{
2013-07-10 16:58:41 +00:00
int i = 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
for ( i = 0 ; i < count ; + + i )
{
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 ) ;
free_all_requests ( subsets [ i ] . request ) ;
}
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 )
{
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 ;
return - 1 ; /*Failed*/
2013-03-25 12:04:10 +00:00
}
static boolean parsedate ( const char * name , long * julian , long * second , boolean * isjul )
{
2013-07-10 16:58:41 +00:00
const char * p = name ;
int n ;
int y = 0 , m = 0 , d = 0 , H = 0 , M = 0 , S = 0 ;
* julian = * second = 0 ;
* isjul = false ;
if ( p = = 0 | | * p = = 0 )
return false ;
2013-08-16 11:56:13 +00:00
/* Special ERA Interim grib1 date format: jul-21, sep-02 etc
* See GRIB - 416
*/
if ( isalpha ( * p ) )
{
char month [ 32 ] ;
int day = 0 ;
int n = sscanf ( p , " %[^-]-%d " , month , & day ) ;
/* 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 ) ;
if ( m = = - 1 ) return false ;
* julian = grib_date_to_julian ( y * 10000 + m * 100 + day ) ;
* second = 0 ;
return true ;
}
}
2013-07-10 16:58:41 +00:00
/* year */
p = parse1 ( p , & y , & n ) ;
2013-08-16 11:56:13 +00:00
if ( n ! = 2 & & n ! = 4 ) /* year string must be 2 or 4 characters long: 93 or 1993 */
2013-07-10 16:58:41 +00:00
return false ;
if ( * p + + ! = ' - ' )
return false ;
/* month */
p = parse1 ( p , & m , & n ) ;
if ( n = = 2 )
{
/* day */
if ( * p + + ! = ' - ' )
return false ;
p = parse1 ( p , & d , & n ) ;
if ( n ! = 2 )
return false ;
}
else if ( n = = 3 )
{
long j = grib_date_to_julian ( y * 10000 + 101 ) + m - 1 ;
j = grib_julian_to_date ( j ) ;
/* julian day */ ;
d = j % 100 ;
m = ( j % 10000 ) / 100 ;
* isjul = true ;
}
else
return false ;
2013-08-16 11:56:13 +00:00
if ( m = = 0 | | m > 12 ) {
return false ; /* month out of range */
}
2013-07-10 16:58:41 +00:00
while ( * p & & isspace ( * p ) )
p + + ;
/* hour */
p = parse1 ( p , & H , & n ) ;
if ( n ! = 0 )
{
if ( n ! = 2 )
return false ;
/* minute */
if ( * p + + ! = ' : ' )
return false ;
p = parse1 ( p , & M , & n ) ;
if ( n ! = 2 )
return false ;
if ( * p ! = 0 )
{
/* second */
if ( * p + + ! = ' : ' )
return false ;
p = parse1 ( p , & S , & n ) ;
if ( n ! = 2 )
return false ;
}
}
* julian = grib_date_to_julian ( y * 10000 + m * 100 + d ) ;
* second = H * 3600 + M * 60 + S ;
return * p = = 0 ? true : false ;
2013-03-25 12:04:10 +00:00
}
/*=====================================================================*/
2013-06-07 10:27:06 +00:00
grib_option grib_options [ ] = {
2013-07-10 16:58:41 +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 } ,
{ " o: " , " output file " , " \n \t \t The name of the netcdf file. \n " , 1 , 1 , 0 } ,
{ " k: " , 0 , 0 , 0 , 1 , 0 } ,
{ " V " , 0 , 0 , 0 , 1 , 0 } ,
{ " M " , 0 , 0 , 0 , 1 , 0 }
2013-06-07 10:27:06 +00:00
} ;
2013-03-25 12:04:10 +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 ;
2013-08-13 10:03:31 +00:00
2013-03-25 12:04:10 +00:00
int main ( int argc , char * argv [ ] )
{
2013-08-13 10:03:31 +00:00
int i , ret = 0 ;
2013-08-13 15:47:23 +00:00
/* GRIB-413: Collect all program arguments into a string */
for ( i = 0 ; i < argc ; + + i ) {
2013-08-13 10:03:31 +00:00
strcat ( argvString , argv [ i ] ) ;
if ( i ! = argc - 1 ) strcat ( argvString , " " ) ;
}
ret = grib_tool ( argc , argv ) ;
2013-07-10 16:58:41 +00:00
return ret ;
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 )
{
2013-07-10 16:58:41 +00:00
char * p = NULL ;
char * list = NULL ;
ctx = grib_context_get_default ( ) ;
options - > onlyfiles = 1 ;
fs = new_fieldset ( 0 ) ;
data_r = empty_request ( 0 ) ;
user_r = empty_request ( 0 ) ;
if ( grib_options_on ( " D: " ) )
{
set_value ( user_r , " accuracy " , grib_options_get_option ( " D: " ) ) ;
}
else
2013-08-15 15:08:19 +00:00
{
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 */
2013-07-10 16:58:41 +00:00
if ( grib_options_on ( " S: " ) )
{
list = grib_options_get_option ( " S: " ) ;
p = strtok ( list , " , " ) ;
set_value ( user_r , " split " , p ) ;
p = strtok ( NULL , " , " ) ;
while ( p ! = NULL )
{
add_value ( user_r , " split " , p ) ;
p = strtok ( NULL , " , " ) ;
}
}
else
{
set_value ( user_r , " split " , " param " ) ;
add_value ( user_r , " split " , " expver " ) ;
}
2013-08-15 15:08:19 +00:00
/* Option -I: Ignore keys */
if ( grib_options_on ( " I: " ) )
{
list = grib_options_get_option ( " I: " ) ;
p = strtok ( list , " , " ) ;
set_value ( user_r , " ignore " , p ) ;
p = strtok ( NULL , " , " ) ;
while ( p ! = NULL ) {
add_value ( user_r , " ignore " , p ) ;
p = strtok ( NULL , " , " ) ;
}
}
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 " ) ;
}
2013-07-10 16:58:41 +00:00
if ( grib_options_on ( " T " ) )
set_value ( user_r , " usevalidtime " , " false " ) ;
else
set_value ( user_r , " usevalidtime " , " true " ) ;
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
}
else
{
set_value ( user_r , " referencedate " , " 19000101 " ) ;
}
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 )
{
2013-08-19 15:44:32 +00:00
char buf [ 1024 ] = { 0 , } ;
2013-07-10 16:58:41 +00:00
int e = 0 ;
int i = 0 ;
grib_handle * h = NULL ;
grib_file * file = NULL ;
2013-03-25 12:04:10 +00:00
printf ( " %s: Processing input file '%s'. \n " , grib_tool_name , filename ) ;
2013-07-10 16:58:41 +00:00
file = grib_file_open ( filename , " r " , & e ) ;
if ( ! file | | ! file - > handle )
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 + + ;
2013-07-10 16:58:41 +00:00
while ( ( h = grib_handle_new_from_file ( ctx , file - > handle , & e ) ) ! = NULL )
{
long length ;
field * g ;
request * r ;
/* process only GRIB for the moment*/
size_t size = sizeof ( buf ) ;
Assert ( grib_get_string ( h , " identifier " , buf , & size ) = = 0 ) ;
if ( strcmp ( buf , " GRIB " ) )
{
grib_handle_delete ( h ) ;
continue ;
}
Assert ( grib_get_long ( h , " totalLength " , & length ) = = 0 ) ;
g = read_field ( file , h - > offset , length ) ;
r = empty_request ( " " ) ;
Assert ( handle_to_request ( r , h ) = = 0 ) ;
/* Keep full MARS description */
/* copy = clone_one_request(r); */
/* reqmerge(setup.mars_description,copy); */
/* reqmerge(setup.mars_description,r); */
if ( i = = 1 )
{
const char * mmeans = get_value ( r , " _MONTHLY_MEANS " , 0 ) ;
setup . mmeans = mmeans ? ( atol ( mmeans ) = = 1 ) : false ;
}
fcmonth2nbmonths ( r ) ;
if ( ! setup . refdate )
{
if ( setup . auto_refdate )
setup . refdate = atol ( get_value ( r , " date " , 0 ) ) ;
else
{
const char * p = get_value ( user_r , " referencedate " , 0 ) ;
if ( is_number ( p ) )
setup . refdate = atol ( p ) ;
else
{
long julian = 0 , second = 0 ;
boolean isjul ;
parsedate ( p , & julian , & second , & isjul ) ;
setup . refdate = grib_julian_to_date ( julian ) ;
}
}
}
validation_time ( r ) ;
if ( setup . usevalidtime )
{
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 ) ;
}
grib_file_close ( file - > name , & e ) ;
2013-03-25 12:04:10 +00:00
#if 0
2013-07-10 16:58:41 +00:00
* data_r = fieldset_to_mars_request ( v ) ;
if ( setup . checkvalidtime )
{
int cnt = request_fields ( * data_r ) ;
if ( v - > count ! = i | | ( cnt < i ) )
{
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 , v - > count , cnt ) ;
grib_context_log ( ctx , GRIB_LOG_ERROR , " MARS description " ) ;
print_all_requests ( setup . mars_description ) ;
grib_context_log ( ctx , GRIB_LOG_ERROR , " Internal description " ) ;
print_all_requests ( * data_r ) ;
return - 1 ;
}
}
* fs = v ;
2013-03-25 12:04:10 +00:00
# endif
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
}
void grib_tool_print_key_values ( grib_runtime_options * options , grib_handle * h )
{
}
int grib_tool_finalise_action ( grib_runtime_options * options )
{
2013-07-10 16:58:41 +00:00
request * config_r = NULL ;
hypercube * dims = NULL ;
dataset_t * subsets = NULL ;
int count ;
int i ;
int ncid ;
int stat ;
int err = 0 ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( options - > outfile = = NULL | | options - > outfile - > name = = NULL )
2013-03-25 12:04:10 +00:00
{
2013-07-10 16:58:41 +00:00
usage ( ) ;
exit ( 1 ) ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
if ( fs - > count = = 0 )
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " Input does not contain any field. Exiting! " ) ;
return - 1 ;
}
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
printf ( " %s: Found %d GRIB field%s in %d file%s. \n " , grib_tool_name , fs - > count , fs - > count > 1 ? " s " : " " , files , files > 1 ? " s " : " " ) ;
2013-03-25 12:04:10 +00:00
2013-07-10 16:58:41 +00:00
/*
2013-07-22 13:06:46 +00:00
grib_context_log ( ctx , GRIB_LOG_INFO , " Request representing %d fields " , fs - > count ) ;
print_all_requests ( data_r ) ;
2013-07-10 16:58:41 +00:00
*/
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 ) ;
remove_param ( data_r , ( void * ) user_r , " ignore " ) ;
remove_param ( data_r , ( void * ) user_r , " split " ) ;
dims = new_simple_hypercube_from_mars_request ( data_r ) ;
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
2013-07-10 16:58:41 +00:00
/* Create netcdf file */
2013-03-25 12:04:10 +00:00
printf ( " %s: Creating netcdf file '%s' \n " , grib_tool_name , options - > outfile - > name ) ;
printf ( " %s: NetCDF library version: %s \n " , grib_tool_name , nc_inq_libvers ( ) ) ;
2013-07-10 16:58:41 +00:00
stat = nc_create ( options - > outfile - > name , NC_CLOBBER , & ncid ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
/* Define netcdf dataset */
err = define_netcdf_dimensions ( dims , fs , ncid , subsets , count , data_r ) ;
if ( err ! = GRIB_SUCCESS ) {
stat = nc_close ( ncid ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
stat = nc_delete ( options - > outfile - > name ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
exit ( 1 ) ;
}
/* End definitions */
stat = nc_enddef ( ncid ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
/* Fill dimensions */
fill_netcdf_dimensions ( dims , fs , ncid ) ;
/* Put data values */
for ( i = 0 ; i < count ; + + i )
{
if ( subsets [ i ] . fset )
{
char dataset [ 100 ] ;
sprintf ( dataset , subsets [ i ] . att . name , i + 1 ) ;
put_data ( dims , ncid , dataset , & subsets [ i ] ) ;
}
else
{
grib_context_log ( ctx , GRIB_LOG_ERROR , " Fieldset %d is empty!! " , i + 1 ) ;
}
}
stat = nc_close ( ncid ) ;
check_err ( stat , __LINE__ , __FILE__ ) ;
free_all_requests ( data_r ) ;
free_hypercube ( dims ) ;
free_fieldset ( fs ) ;
free_subsets ( subsets , count ) ;
free_nc_options ( ) ;
2013-03-25 12:04:10 +00:00
printf ( " %s: Done. \n " , grib_tool_name ) ;
2013-07-10 16:58:41 +00:00
return 0 ;
2013-03-25 12:04:10 +00:00
}
# else
# include <stdio.h>
# include <stdlib.h>
int main ( int argc , char * * argv )
{
printf ( " \n " ) ;
printf ( " grib_to_netcdf: \n " ) ;
printf ( " \n " ) ;
printf ( " GRIB API was not compiled with NETCDF enabled \n " ) ;
printf ( " Please rerun configure with --with-netcdf=PATH_TO_NETCDF_INSTALLATION \n " ) ;
printf ( " and re-install the software. \n " ) ;
printf ( " \n " ) ;
exit ( 1 ) ;
}
# endif