Skip to content

Commit 36ecd3b

Browse files
authored
Merge pull request #2584 from srherbener/feature/ncdump-dtime-vlen-units
Allow ncdump -t to handle variable length string attributes
2 parents 17c7314 + 94cad50 commit 36ecd3b

8 files changed

Lines changed: 364 additions & 10 deletions

File tree

ncdump/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ endif()
263263
add_sh_test(ncdump tst_ncgen4)
264264
add_sh_test(ncdump tst_netcdf4_4)
265265
add_sh_test(ncdump tst_nccopy4)
266+
add_sh_test(ncdump tst_calendars_nc4)
266267

267268
SET_TESTS_PROPERTIES(ncdump_tst_nccopy4 PROPERTIES DEPENDS "ncdump_run_ncgen_tests;ncdump_tst_output;ncdump_tst_ncgen4;ncdump_sh_tst_fillbug;ncdump_tst_netcdf4_4;ncdump_tst_h_scalar;tst_comp;tst_comp2;tst_nans;tst_opaque_data;tst_create_files;tst_special_atts")
268269
SET_TESTS_PROPERTIES(ncdump_tst_nccopy5 PROPERTIES DEPENDS "ncdump_tst_nccopy4")

ncdump/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ TESTS += tst_output.sh
151151
TESTS += tst_nccopy3.sh
152152
if USE_HDF5
153153
TESTS += run_back_comp_tests.sh tst_netcdf4_4.sh
154-
TESTS += tst_nccopy4.sh tst_nccopy5.sh
154+
TESTS += tst_nccopy4.sh tst_nccopy5.sh tst_calendars_nc4.sh
155155
endif
156156
endif
157157
endif

ncdump/nctime0.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,18 @@ calendar_type(int ncid, int varid) {
7979
int ncals = (sizeof calmap)/(sizeof calmap[0]);
8080
ctype = cdMixed; /* default mixed Gregorian/Julian ala udunits */
8181
stat = nc_inq_att(ncid, varid, CF_CAL_ATT_NAME, &catt.type, &catt.len);
82-
if(stat == NC_NOERR && catt.type == NC_CHAR && catt.len > 0) {
83-
char *calstr = (char *)emalloc(catt.len + 1);
82+
if(stat == NC_NOERR && (catt.type == NC_CHAR || catt.type == NC_STRING) && catt.len > 0) {
83+
char *calstr;
84+
size_t cf_cal_att_name_len = strlen(CF_CAL_ATT_NAME);
85+
strncpy(catt.name, CF_CAL_ATT_NAME, cf_cal_att_name_len);
86+
catt.name[cf_cal_att_name_len] = '\0';
87+
catt.tinfo = get_typeinfo(catt.type);
88+
nc_get_att_single_string(ncid, varid, &catt, &calstr);
89+
8490
int itype;
85-
NC_CHECK(nc_get_att(ncid, varid, CF_CAL_ATT_NAME, calstr));
86-
calstr[catt.len] = '\0';
91+
int calstr_len = strlen(calstr);
8792
for(itype = 0; itype < ncals; itype++) {
88-
if(strncasecmp(calstr, calmap[itype].attname, catt.len) == 0) {
93+
if(strncasecmp(calstr, calmap[itype].attname, calstr_len) == 0) {
8994
ctype = calmap[itype].type;
9095
break;
9196
}
@@ -204,10 +209,11 @@ get_timeinfo(int ncid1, int varid1, ncvar_t *vp) {
204209

205210
/* time variables must have appropriate units attribute or be a bounds variable */
206211
nc_status = nc_inq_att(ncid, varid, "units", &uatt.type, &uatt.len);
207-
if(nc_status == NC_NOERR && uatt.type == NC_CHAR) { /* TODO: NC_STRING? */
208-
units = emalloc(uatt.len + 1);
209-
NC_CHECK(nc_get_att(ncid, varid, "units", units));
210-
units[uatt.len] = '\0';
212+
if(nc_status == NC_NOERR && (uatt.type == NC_CHAR || uatt.type == NC_STRING)) {
213+
strncpy(uatt.name, "units", 5);
214+
uatt.name[5] = '\0';
215+
uatt.tinfo = get_typeinfo(uatt.type);
216+
nc_get_att_single_string(ncid, varid, &uatt, &units);
211217
if(!is_valid_time_unit(units)) {
212218
free(units);
213219
return;

ncdump/ref_times_nc4.cdl

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
netcdf tst_times_nc4 {
2+
dimensions:
3+
time = 1 ;
4+
bnds = 2 ;
5+
t3 = UNLIMITED ; // (3 currently)
6+
variables:
7+
double t1_days(time) ;
8+
t1_days:units = "days since 1500-1-1" ;
9+
double t1_days_case(time) ;
10+
t1_days_case:units = "DaYs since 1500-1-1" ;
11+
double t1_st_days(time) ;
12+
t1_st_days:calendar = "standard" ;
13+
t1_st_days:units = "days since 1500-01-01 00:00:00" ;
14+
double t1_gr_days(time) ;
15+
t1_gr_days:calendar = "gregorian" ;
16+
t1_gr_days:units = "days since 1500-01-01 00:00:00" ;
17+
double t1_pg_days(time) ;
18+
t1_pg_days:calendar = "proleptic_gregorian" ;
19+
t1_pg_days:units = "days since 1500-01-01 00:00:00" ;
20+
double t1_nl_days(time) ;
21+
t1_nl_days:calendar = "noleap" ;
22+
t1_nl_days:units = "days since 1500-01-01 00:00:00" ;
23+
double t1_365_days(time) ;
24+
t1_365_days:calendar = "365_day" ;
25+
t1_365_days:units = "days since 1500-01-01 00:00:00" ;
26+
double t1_al_days(time) ;
27+
t1_al_days:calendar = "all_leap" ;
28+
t1_al_days:units = "days since 1500-01-01 00:00:00" ;
29+
double t1_366_days(time) ;
30+
t1_366_days:calendar = "366_day" ;
31+
t1_366_days:units = "days since 1500-01-01 00:00:00" ;
32+
double t1_360_days(time) ;
33+
t1_360_days:calendar = "360_day" ;
34+
t1_360_days:units = "days since 1500-01-01 00:00:00" ;
35+
double t1_jl_days(time) ;
36+
t1_jl_days:calendar = "julian" ;
37+
t1_jl_days:units = "days since 1500-01-01 00:00:00" ;
38+
double t2_days(time) ;
39+
string t2_days:units = "days since 2000-6-15 12:00" ;
40+
double t2_st_days(time) ;
41+
string t2_st_days:calendar = "standard" ;
42+
string t2_st_days:units = "days since 2000-06-15 12:00:00" ;
43+
double t2_gr_days(time) ;
44+
string t2_gr_days:calendar = "gregorian" ;
45+
string t2_gr_days:units = "days since 2000-06-15 12:00:00" ;
46+
double t2_pg_days(time) ;
47+
string t2_pg_days:calendar = "proleptic_gregorian" ;
48+
string t2_pg_days:units = "days since 2000-06-15 12:00:00" ;
49+
double t2_pgt_days(time) ;
50+
string t2_pgt_days:calendar = "proleptic_gregorian" ;
51+
string t2_pgt_days:units = "days since 2000-06-15T12:00:00" ;
52+
double t2_nl_days(time) ;
53+
string t2_nl_days:calendar = "noleap" ;
54+
string t2_nl_days:units = "days since 2000-06-15 12:00:00" ;
55+
double t2_365_days(time) ;
56+
string t2_365_days:calendar = "365_day" ;
57+
string t2_365_days:units = "days since 2000-06-15 12:00:00" ;
58+
double t2_al_days(time) ;
59+
string t2_al_days:calendar = "all_leap" ;
60+
string t2_al_days:units = "days since 2000-06-15 12:00:00" ;
61+
double t2_366_days(time) ;
62+
string t2_366_days:calendar = "366_day" ;
63+
string t2_366_days:units = "days since 2000-06-15 12:00:00" ;
64+
double t2_360_days(time) ;
65+
string t2_360_days:calendar = "360_day" ;
66+
string t2_360_days:units = "days since 2000-06-15 12:00:00" ;
67+
double t2_jl_days(time) ;
68+
string t2_jl_days:calendar = "julian" ;
69+
string t2_jl_days:units = "days since 2000-06-15 12:00:00" ;
70+
int t3(t3) ;
71+
t3:units = "days since 1804-1-1" ;
72+
t3:calendar = "gregorian" ;
73+
t3:bounds = "t3_bnds" ;
74+
t3:time1 = 1 ; // "1804-01-02"
75+
t3:time2 = 5, 6 ; // "1804-01-06", "1804-01-07"
76+
t3:time3 = 7.125f, 8.75f ; // "1804-01-08 03", "1804-01-09 18"
77+
t3:time4 = 58.5, 59.5, 60.5 ;
78+
// "1804-02-28 12", "1804-02-29 12", "1804-03-01 12"
79+
t3:time5 = 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120 ;
80+
// "1804-04-10", "1804-04-11", "1804-04-12", "1804-04-13",
81+
// "1804-04-14", "1804-04-15", "1804-04-16", "1804-04-17",
82+
// "1804-04-18", "1804-04-19", "1804-04-20", "1804-04-21",
83+
// "1804-04-22", "1804-04-23", "1804-04-24", "1804-04-25",
84+
// "1804-04-26", "1804-04-27", "1804-04-28", "1804-04-29",
85+
// "1804-04-30"
86+
double t3_bnds(t3, bnds) ;
87+
int t4 ;
88+
t4:units = "days" ;
89+
t4:att1 = 1 ;
90+
t4:att2 = 5, 6 ;
91+
t4:att3 = 7.125f, 8.75f ;
92+
data:
93+
94+
t1_days = "2009-01-01" ;
95+
96+
t1_days_case = "2009-01-01" ;
97+
98+
t1_st_days = "2009-01-01" ;
99+
100+
t1_gr_days = "2009-01-01" ;
101+
102+
t1_pg_days = "2009-01-01" ;
103+
104+
t1_nl_days = "2009-01-01" ;
105+
106+
t1_365_days = "2009-01-01" ;
107+
108+
t1_al_days = "2009-01-01" ;
109+
110+
t1_366_days = "2009-01-01" ;
111+
112+
t1_360_days = "2009-01-01" ;
113+
114+
t1_jl_days = "2009-01-01" ;
115+
116+
t2_days = "2009-01-01" ;
117+
118+
t2_st_days = "2009-01-01" ;
119+
120+
t2_gr_days = "2009-01-01" ;
121+
122+
t2_pg_days = "2009-01-01" ;
123+
124+
t2_pgt_days = "2009-01-01" ;
125+
126+
t2_nl_days = "2009-01-01" ;
127+
128+
t2_365_days = "2009-01-01" ;
129+
130+
t2_al_days = "2009-01-01" ;
131+
132+
t2_366_days = "2009-01-01" ;
133+
134+
t2_360_days = "2009-01-01" ;
135+
136+
t2_jl_days = "2009-01-01" ;
137+
138+
t3 = "1804-01-11", "1804-01-12", "1804-01-13" ;
139+
140+
t3_bnds =
141+
"1804-01-10 12", "1804-01-11 12",
142+
"1804-01-11 12", "1804-01-12 12",
143+
"1804-01-12 12", "1804-01-13 12" ;
144+
145+
t4 = _ ;
146+
}

ncdump/tst_calendars_nc4.cdl

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
netcdf tst_calendars_nc4 { // test climate calendars and CDL time with -t option
2+
dimensions:
3+
time = 1;
4+
bnds = 2 ; // for cell bounds on t3 time coordinate variable
5+
t3 = unlimited ;
6+
variables:
7+
// Use fixed length string attributes for the t1 set of variables
8+
double t1_days(time);
9+
t1_days:units = "days since 1500-1-1";
10+
double t1_days_case(time);
11+
t1_days_case:units = "DaYs since 1500-1-1";
12+
double t1_st_days(time);
13+
t1_st_days:calendar = "standard" ; // mixed julian-gregorian
14+
t1_st_days:units = "days since 1500-01-01 00:00:00";
15+
double t1_gr_days(time);
16+
t1_gr_days:calendar = "gregorian" ; // same as "standard"
17+
t1_gr_days:units = "days since 1500-01-01 00:00:00";
18+
double t1_pg_days(time);
19+
t1_pg_days:calendar = "proleptic_gregorian" ;
20+
t1_pg_days:units = "days since 1500-01-01 00:00:00";
21+
double t1_nl_days(time);
22+
t1_nl_days:calendar = "noleap" ;
23+
t1_nl_days:units = "days since 1500-01-01 00:00:00";
24+
double t1_365_days(time);
25+
t1_365_days:calendar = "365_day" ; // same as "noleap"
26+
t1_365_days:units = "days since 1500-01-01 00:00:00";
27+
double t1_al_days(time);
28+
t1_al_days:calendar = "all_leap" ;
29+
t1_al_days:units = "days since 1500-01-01 00:00:00";
30+
double t1_366_days(time);
31+
t1_366_days:calendar = "366_day" ; // same as "all_leap"
32+
t1_366_days:units = "days since 1500-01-01 00:00:00";
33+
double t1_360_days(time);
34+
t1_360_days:calendar = "360_day" ;
35+
t1_360_days:units = "days since 1500-01-01 00:00:00";
36+
double t1_jl_days(time);
37+
t1_jl_days:calendar = "julian" ;
38+
t1_jl_days:units = "days since 1500-01-01 00:00:00";
39+
40+
// Use variable length string attributes for the t2 set of variables
41+
double t2_days(time);
42+
string t2_days:units = "days since 2000-6-15 12:00";
43+
double t2_st_days(time);
44+
string t2_st_days:calendar = "standard" ; // mixed julian-gregorian
45+
string t2_st_days:units = "days since 2000-06-15 12:00:00";
46+
double t2_gr_days(time);
47+
string t2_gr_days:calendar = "gregorian" ; // same as "standard"
48+
string t2_gr_days:units = "days since 2000-06-15 12:00:00";
49+
double t2_pg_days(time);
50+
string t2_pg_days:calendar = "proleptic_gregorian" ;
51+
string t2_pg_days:units = "days since 2000-06-15 12:00:00";
52+
double t2_pgt_days(time);
53+
string t2_pgt_days:calendar = "proleptic_gregorian" ;
54+
string t2_pgt_days:units = "days since 2000-06-15T12:00:00";
55+
double t2_nl_days(time);
56+
string t2_nl_days:calendar = "noleap" ;
57+
string t2_nl_days:units = "days since 2000-06-15 12:00:00";
58+
double t2_365_days(time);
59+
string t2_365_days:calendar = "365_day" ; // same as "noleap"
60+
string t2_365_days:units = "days since 2000-06-15 12:00:00";
61+
double t2_al_days(time); // *** no year, 07-29 12:00
62+
string t2_al_days:calendar = "all_leap" ; // seems wrong, same as gregorian
63+
string t2_al_days:units = "days since 2000-06-15 12:00:00";
64+
double t2_366_days(time); // *** no year, 07-29 12:00
65+
string t2_366_days:calendar = "366_day" ; // omits years, same as "clim"??
66+
string t2_366_days:units = "days since 2000-06-15 12:00:00";
67+
double t2_360_days(time);
68+
string t2_360_days:calendar = "360_day" ; // omits years, same as "clim"??
69+
string t2_360_days:units = "days since 2000-06-15 12:00:00";
70+
double t2_jl_days(time);
71+
string t2_jl_days:calendar = "julian" ;
72+
string t2_jl_days:units = "days since 2000-06-15 12:00:00";
73+
74+
// double t1_none_days(time);
75+
// t1_none_days:calendar = "none" ;
76+
// t1_none_days:units = "days since 1500-01-01 00:00:00";
77+
// double t2_none_days(time);
78+
// t2_none_days:calendar = "none" ;
79+
// t2_none_days:units = "days since 2000-06-15 12:00:00";
80+
81+
// test -t option on numeric attributes of a time-valued variable
82+
int t3(t3) ;
83+
t3:units = "days since 1804-1-1" ;
84+
t3:calendar = "gregorian" ;
85+
t3:bounds = "t3_bnds" ;
86+
t3:time1 = 1 ;
87+
t3:time2 = 5, 6 ;
88+
t3:time3 = 7.125f, 8.75f ;
89+
t3:time4 = 58.5, 59.5, 60.5 ;
90+
t3:time5 = 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120 ;
91+
double t3_bnds(t3, bnds) ; // no attributes, since a cell bounds variable
92+
93+
// test -t bug fix, time unit without base time should not interpret numeric atts as times
94+
int t4 ;
95+
t4:units = "days" ;
96+
t4:att1 = 1 ;
97+
t4:att2 = 5, 6 ;
98+
t4:att3 = 7.125f, 8.75f ;
99+
100+
data:
101+
// Should all represent 2009-01-01 00:00:00
102+
t1_days = 185900;
103+
t1_days_case = 185900;
104+
t1_st_days = 185900;
105+
t1_gr_days = 185900;
106+
t1_pg_days = 185909;
107+
t1_nl_days = 185785;
108+
t1_365_days = 185785;
109+
t1_366_days = 186294;
110+
t1_al_days = 186294;
111+
t1_360_days = 183240;
112+
t1_jl_days = 185913;
113+
114+
t2_days = 3121.5;
115+
t2_st_days = 3121.5;
116+
t2_gr_days = 3121.5;
117+
t2_pg_days = 3121.5;
118+
t2_pgt_days = 3121.5;
119+
t2_nl_days = 3119.5;
120+
t2_365_days = 3119.5;
121+
t2_366_days = 3127.5;
122+
t2_al_days = 3127.5;
123+
t2_360_days = 3075.5;
124+
t2_jl_days = 3121.5;
125+
126+
// Not sure what these should represent yet ...
127+
// t1_none_days = 185900;
128+
// t2_none_days = 3121.5;
129+
130+
t3 = 10, 11, 12;
131+
t3_bnds = 9.5, 10.5, 10.5, 11.5, 11.5, 12.5 ;
132+
}
133+

ncdump/tst_calendars_nc4.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/sh
2+
3+
if test "x$srcdir" = x ; then srcdir=`pwd`; fi
4+
. ../test_common.sh
5+
6+
# This shell script tests ncdump -t option for CF calendar attributes using netcdf4 format
7+
8+
set -e
9+
echo ""
10+
echo "*** Testing ncdump -t output for times with CF calendar attribute, netcdf4 format"
11+
echo "*** creating netcdf4 file tst_calendars.nc from tst_calendars.cdl..."
12+
${NCGEN} -b -k nc4 -o tst_calendars_nc4.nc $srcdir/tst_calendars_nc4.cdl
13+
echo "*** creating tst_times_nc4.cdl from tst_calendars.nc with ncdump -t ..."
14+
${NCDUMP} -n tst_times_nc4 -t tst_calendars_nc4.nc > tst_times_nc4.cdl
15+
echo "*** comparing tst_times_nc4.cdl with ref_times_nc4.cdl..."
16+
diff -b tst_times_nc4.cdl $srcdir/ref_times_nc4.cdl
17+
echo ""
18+
echo "*** All ncdump test output (netcdf4 format) for -t option with CF calendar atts passed!"
19+
20+
exit 0

0 commit comments

Comments
 (0)