Finish handling bounds variables with ncdump -t (NCF-70). Fix bug with permitted dimension sizes in netCDF classic files (NCF-117).

This commit is contained in:
Russ Rew 2011-09-05 16:09:17 +00:00
parent 616aadc321
commit b658836a6e
6 changed files with 129 additions and 9 deletions

View File

@ -120,11 +120,10 @@ NC4_def_dim(int ncid, const char *name, size_t len, int *idp)
if ((retval = nc4_check_name(name, norm_name)))
return retval;
/* For classic model, stick with the classic format restriction:
* dim length has to fit in a 32-bit signed int. For 64-bit offset,
* it has to fit in a 32-bit unsigned int. */
/* For classic model: dim length has to fit in a 32-bit unsigned
* int, as permitted for 64-bit offset format. */
if (h5->cmode & NC_CLASSIC_MODEL)
if((unsigned long) len > X_INT_MAX) /* Backward compat */
if(len > X_UINT_MAX) /* Backward compat */
return NC_EDIMSIZE;
/* Make sure the name is not already in use. */

View File

@ -630,16 +630,90 @@ calendar_type(int ncid, int varid) {
return ctype;
}
/* Return true only if this is a "bounds" attribute */
static boolean
is_bounds_att(ncatt_t *attp) {
if(attp->type == NC_CHAR && attp->valgp && STREQ((char *)attp->name, "bounds")) {
return true;
}
#ifdef USE_NETCDF4
if(attp->type == NC_STRING && attp->valgp && STREQ((char *)attp->name, "bounds")) {
return true;
}
#endif /* USE_NETCDF4 */
return false;
}
struct bounds_node{
int ncid; /* group (or file) in which variable with associated
* bounds variable resides */
int varid; /* has "bounds" attribute naming its bounds variable */
char *bounds_name; /* the named variable, which stores bounds for varid */
struct bounds_node *next; /* next node on list or NULL ifn last list node */
};
typedef struct bounds_node bounds_node_t;
static struct {
size_t nbnds; /* number of bounds variables */
bounds_node_t *first;
} bounds_list;
void
bounds_add(char *bounds_name, int ncid, int varid) {
bounds_node_t *bnode = emalloc(sizeof(bounds_node_t) + 1);
bounds_list.nbnds++;
bnode->ncid = ncid;
bnode->varid = varid;
bnode->bounds_name = strdup(bounds_name);
bnode->next = bounds_list.first;
bounds_list.first = bnode;
}
/* Insert info about a bounds attribute into bounds list, so we can
* later determine which variables are bounds variables for which
* other variables. att must be a variable "bounds" attribute. */
void
insert_bounds_info(int ncid, int varid, ncatt_t att) {
static boolean uninitialized = true;
if(uninitialized) {
bounds_list.nbnds = 0;
bounds_list.first = NULL;
}
assert(is_bounds_att(&att));
bounds_add(att.valgp, ncid, varid);
}
static boolean
is_bounds_var(char *varname, int *pargrpidp, int *parvaridp) {
bounds_node_t *bp = bounds_list.first;
for(; bp; bp = bp->next) {
if(STREQ(bp->bounds_name, varname)) {
*pargrpidp = bp->ncid;
*parvaridp = bp->varid;
return true;
}
}
return false;
}
static void
get_timeinfo(int ncid, int varid, ncvar_t *vp) {
get_timeinfo(int ncid1, int varid1, ncvar_t *vp) {
ncatt_t uatt; /* units attribute */
int nc_status; /* return from netcdf calls */
char *units;
int ncid = ncid1;
int varid = varid1;
vp->has_timeval = false; /* by default, turn on if criteria met */
vp->timeinfo = 0;
/* time variables must have appropriate units attribute */
vp->is_bounds_var = false;
/* for timeinfo, treat a bounds variable like its "parent" time variable */
if(is_bounds_var(vp->name, &ncid, &varid)) {
vp->is_bounds_var = true;
}
/* time variables must have appropriate units attribute or be a bounds variable */
nc_status = nc_inq_att(ncid, varid, "units", &uatt.type, &uatt.len);
if(nc_status == NC_NOERR && uatt.type == NC_CHAR) { /* TODO: NC_STRING? */
units = emalloc(uatt.len + 1);
@ -838,6 +912,9 @@ pr_att(
* Prints nothing if not qualified for time interpretation.
* Will include line breaks for longer lists. */
print_att_times(ncid, varid, att);
if(is_bounds_att(&att)) {
insert_bounds_info(ncid, varid, att);
}
}
#ifdef USE_NETCDF4
/* If NC_STRING, need to free all the strings also */

View File

@ -80,6 +80,7 @@ typedef struct ncvar_t { /* variable */
void* fillvalp; /* pointer to the fill value, if any */
boolean has_timeval; /* has date-time values, for -t output option */
struct timeinfo_t *timeinfo; /* if time values, units, calendar, and origin */
boolean is_bounds_var; /* cell bounds variable, inherits timeinfo */
const char *fmt; /* overriding variable-specific format for
printing values or base values, if any */
int locid; /* group id */

View File

@ -1,6 +1,8 @@
netcdf tst_times {
dimensions:
time = 1 ;
bnds = 2 ;
t3 = UNLIMITED ; // (3 currently)
variables:
double t1_days(time) ;
t1_days:units = "days since 1500-1-1" ;
@ -63,6 +65,23 @@ variables:
double t2_jl_days(time) ;
t2_jl_days:calendar = "julian" ;
t2_jl_days:units = "days since 2000-06-15 12:00:00" ;
int t3(t3) ;
t3:units = "days since 1804-1-1" ;
t3:calendar = "gregorian" ;
t3:bounds = "t3_bnds" ;
t3:time1 = 1 ; // "1804-01-02"
t3:time2 = 5, 6 ; // "1804-01-06", "1804-01-07"
t3:time3 = 7.125f, 8.75f ; // "1804-01-08 03", "1804-01-09 18"
t3:time4 = 58.5, 59.5, 60.5 ;
// "1804-02-28 12", "1804-02-29 12", "1804-03-01 12"
t3:time5 = 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120 ;
// "1804-04-10", "1804-04-11", "1804-04-12", "1804-04-13",
// "1804-04-14", "1804-04-15", "1804-04-16", "1804-04-17",
// "1804-04-18", "1804-04-19", "1804-04-20", "1804-04-21",
// "1804-04-22", "1804-04-23", "1804-04-24", "1804-04-25",
// "1804-04-26", "1804-04-27", "1804-04-28", "1804-04-29",
// "1804-04-30"
double t3_bnds(t3, bnds) ;
data:
t1_days = "2009-01-01" ;
@ -106,4 +125,11 @@ data:
t2_360_days = "2009-01-01" ;
t2_jl_days = "2009-01-01" ;
t3 = "1804-01-11", "1804-01-12", "1804-01-13" ;
t3_bnds =
"1804-01-10 12", "1804-01-11 12",
"1804-01-11 12", "1804-01-12 12",
"1804-01-12 12", "1804-01-13 12" ;
}

View File

@ -1,6 +1,8 @@
netcdf tst_calendars { // test climate calendars and CDL time with -t option
dimensions:
time = 1;
bnds = 2 ; // for cell bounds on t3 time coordinate variable
t3 = unlimited ;
variables:
double t1_days(time);
t1_days:units = "days since 1500-1-1";
@ -72,6 +74,18 @@ variables:
// t2_none_days:calendar = "none" ;
// t2_none_days:units = "days since 2000-06-15 12:00:00";
// test -t option on numeric attributes of a time-valued variable
int t3(t3) ;
t3:units = "days since 1804-1-1" ;
t3:calendar = "gregorian" ;
t3:bounds = "t3_bnds" ;
t3:time1 = 1 ;
t3:time2 = 5, 6 ;
t3:time3 = 7.125f, 8.75f ;
t3:time4 = 58.5, 59.5, 60.5 ;
t3:time5 = 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120 ;
double t3_bnds(t3, bnds) ; // no attributes, since a cell bounds variable
data:
// Should all represent 2009-01-01 00:00:00
t1_days = 185900;
@ -100,5 +114,8 @@ data:
// Not sure what these should represent yet ...
// t1_none_days = 185900;
// t2_none_days = 3121.5;
t3 = 10, 11, 12;
t3_bnds = 9.5, 10.5, 10.5, 11.5, 11.5, 12.5 ;
}

View File

@ -7,7 +7,7 @@ echo ""
echo "*** Testing ncdump -t output for times with CF calendar attribute"
echo "*** creating netcdf file tst_calendars.nc from tst_calendars.cdl..."
../ncgen/ncgen -b -o tst_calendars.nc $srcdir/tst_calendars.cdl
echo "*** creating tst_isotimes.cdl from tst_calendars.nc..."
echo "*** creating tst_times.cdl from tst_calendars.nc with ncdump -t ..."
./ncdump -n tst_times -t tst_calendars.nc > tst_times.cdl
echo "*** comparing tst_times.cdl with ref_times.cdl..."
diff tst_times.cdl $srcdir/ref_times.cdl