43 #include "config_nc.h"
61 #include "NCRequestHandler.h"
64 #define ATTR_STRING_QUOTE_FIX
66 #define NETCDF_VERSION 4
68 #if NETCDF_VERSION >= 4
69 #define READ_ATTRIBUTES_MACRO read_attributes_netcdf4
71 #define READ_ATTRIBUTES_MACRO read_attributes_netcdf3
75 #define prolog std::string("ncdas::").append(__func__).append("() - ")
89 static string print_attr(nc_type type,
int loc,
void *vals)
104 #if NETCDF_VERSION >= 4
107 gp.cp = (
char *) vals;
115 if (NCRequestHandler::get_promote_byte_to_short()) {
117 gp.cp = (
char *) vals;
125 gp.cp = (
char *) vals;
133 #ifndef ATTR_STRING_QUOTE_FIX
134 rep <<
"\"" << escattr(
static_cast<const char*
>(vals)) <<
"\"";
137 return escattr(
static_cast<const char*
>(vals));
140 #if NETCDF_VERSION >= 4
142 gp.stringp = (
char **) vals;
143 rep << *(gp.stringp + loc);
148 gp.sp = (
short *) vals;
149 rep << *(gp.sp + loc);
152 #if NETCDF_VERSION >= 4
154 gp.usp = (uint16_t *) vals;
155 rep << *(gp.usp + loc);
160 gp.i = (int32_t *) vals;
161 rep << *(gp.i + loc);
164 #if NETCDF_VERSION >= 4
166 gp.ui = (uint32_t *) vals;
167 rep << *(gp.ui + loc);
172 gp.fp = (
float *) vals;
173 float valAtLoc = *(gp.fp + loc);
175 rep << std::showpoint;
176 rep << std::setprecision(9);
178 if (isnan(valAtLoc)) {
189 string tmp_value = rep.str();
190 if (tmp_value.find(
'.') == string::npos && tmp_value.find(
'e') == string::npos && tmp_value.find(
'E') == string::npos
191 && tmp_value.find(
"nan") == string::npos && tmp_value.find(
"NaN") == string::npos && tmp_value.find(
"NAN") == string::npos) rep <<
".";
196 gp.dp = (
double *) vals;
197 double valAtLoc = *(gp.dp + loc);
199 rep << std::showpoint;
200 rep << std::setprecision(16);
202 if (std::isnan(valAtLoc)) {
208 string tmp_value = rep.str();
209 if (tmp_value.find(
'.') == string::npos && tmp_value.find(
'e') == string::npos && tmp_value.find(
'E') == string::npos
210 && tmp_value.find(
"nan") == string::npos && tmp_value.find(
"NaN") == string::npos && tmp_value.find(
"NAN") == string::npos) rep <<
".";
215 if (NCRequestHandler::get_ignore_unknown_types())
216 cerr <<
"The netcdf handler tried to print an attribute that has an unrecognized type. (1)" << endl;
218 throw InternalErr(__FILE__, __LINE__,
"The netcdf handler tried to print an attribute that has an unrecognized type. (1)");
231 static string print_type(nc_type datatype)
234 #if NETCDF_VERSION >= 4
240 #if NETCDF_VERSION >= 4
245 if (NCRequestHandler::get_promote_byte_to_short()) {
258 #if NETCDF_VERSION >= 4
272 #if NETCDF_VERSION >= 4
274 return "NC_COMPOUND";
277 #if NETCDF_VERSION >= 4
296 if (NCRequestHandler::get_ignore_unknown_types())
297 cerr <<
"The netcdf handler tried to print an attribute that has an unrecognized type. (2)" << endl;
299 throw InternalErr(__FILE__, __LINE__,
"The netcdf handler tried to print an attribute that has an unrecognized type. (2)");
310 static void append_values(
int ncid,
int v,
int len, nc_type datatype,
char *attrname, AttrTable *at)
314 #if NETCDF_VERSION >= 4
315 errstat = nc_inq_type(ncid, datatype, 0, &size);
316 if (errstat != NC_NOERR)
throw Error(errstat,
"Could not get the size for the type.");
318 size = nctypelen(datatype);
321 vector<char> value((len + 1) * size);
322 errstat = nc_get_att(ncid, v, attrname, &value[0]);
323 if (errstat != NC_NOERR) {
324 throw Error(errstat,
string(
"Could not get the value for attribute '") + attrname +
string(
"'"));
330 if (datatype == NC_CHAR) {
336 for (
int loc = 0; loc < len; loc++) {
337 string print_rep =
print_attr(datatype, loc, &value[0]);
338 at->append_attr(attrname, print_type(datatype), print_rep);
353 static void read_attributes_netcdf3(
int ncid,
int v,
int natts, AttrTable *at)
355 char attrname[MAX_NC_NAME];
358 int errstat = NC_NOERR;
360 for (
int a = 0; a < natts; ++a) {
361 errstat = nc_inq_attname(ncid, v, a, attrname);
362 if (errstat != NC_NOERR) {
363 string msg =
"Could not get the name for attribute ";
364 msg += long_to_string(a);
365 throw Error(errstat, msg);
370 errstat = nc_inq_att(ncid, v, attrname, &datatype, &len);
371 if (errstat != NC_NOERR) {
372 string msg =
"Could not get the name for attribute '";
373 msg += attrname + string(
"'");
374 throw Error(errstat, msg);
384 append_values(ncid, v, len, datatype, attrname, at);
388 if (NCRequestHandler::get_ignore_unknown_types())
389 cerr <<
"Unrecognized attribute type." << endl;
391 throw InternalErr(__FILE__, __LINE__,
"Unrecognized attribute type.");
397 #if NETCDF_VERSION >= 4
410 static void read_attributes_netcdf4(
int ncid,
int varid,
int natts, AttrTable *at)
412 BESDEBUG(MODULE, prolog <<
"In read_attributes_netcdf4" << endl);
414 for (
int attr_num = 0; attr_num < natts; ++attr_num) {
415 int errstat = NC_NOERR;
417 char attrname[MAX_NC_NAME];
418 errstat = nc_inq_attname(ncid, varid, attr_num, attrname);
419 if (errstat != NC_NOERR)
throw Error(errstat,
"Could not get the name for attribute " + long_to_string(attr_num));
424 errstat = nc_inq_att(ncid, varid, attrname, &datatype, &len);
425 if (errstat != NC_NOERR)
throw Error(errstat,
"Could not get the name for attribute '" +
string(attrname) +
"'");
427 BESDEBUG(MODULE, prolog <<
"nc_inq_att returned datatype = " << datatype <<
" for '" << attrname <<
"'" << endl);
430 if (datatype >= NC_FIRSTUSERTYPEID) {
431 char type_name[NC_MAX_NAME + 1];
436 errstat = nc_inq_user_type(ncid, datatype, type_name, &size, &base_type, &nfields, &class_type);
437 if (errstat != NC_NOERR)
438 throw(InternalErr(__FILE__, __LINE__,
"Could not get information about a user-defined type (" + long_to_string(errstat) +
")."));
440 BESDEBUG(MODULE, prolog <<
"Before switch(class_type)" << endl);
441 switch (class_type) {
444 vector<unsigned char> values((len + 1) * size);
446 int errstat = nc_get_att(ncid, varid, attrname, &values[0]);
447 if (errstat != NC_NOERR)
throw Error(errstat,
string(
"Could not get the value for attribute '") + attrname +
string(
"'"));
449 for (
size_t i = 0; i < nfields; ++i) {
450 char field_name[NC_MAX_NAME + 1];
451 nc_type field_typeid;
453 nc_inq_compound_field(ncid, datatype, i, field_name, &field_offset, &field_typeid, 0, 0);
455 at->append_attr(field_name, print_type(field_typeid),
print_attr(field_typeid, 0, &values[0] + field_offset));
461 if (NCRequestHandler::get_ignore_unknown_types())
462 cerr <<
"in build_user_defined; found a vlen." << endl;
464 throw Error(
"The netCDF handler does not yet support the NC_VLEN type.");
468 vector<unsigned char> values((len + 1) * size);
470 int errstat = nc_get_att(ncid, varid, attrname, &values[0]);
471 if (errstat != NC_NOERR)
throw Error(errstat,
string(
"Could not get the value for attribute '") + attrname +
string(
"'"));
473 for (
size_t i = 0; i < size; ++i)
474 at->append_attr(attrname, print_type(NC_BYTE),
print_attr(NC_BYTE, i, &values[0]));
482 size_t base_size, num_members;
483 errstat = nc_inq_enum(ncid, datatype, 0, &basetype, &base_size, &num_members);
484 if (errstat != NC_NOERR)
throw Error(errstat,
string(
"Could not get the size of the enum base type for '") + attrname +
string(
"'"));
486 vector<unsigned char> values((len + 1) * size);
488 int errstat = nc_get_att(ncid, varid, attrname, &values[0]);
489 if (errstat != NC_NOERR)
throw Error(errstat,
string(
"Could not get the value for attribute '") + attrname +
string(
"'"));
491 for (
size_t i = 0; i < len; ++i)
492 at->append_attr(attrname, print_type(base_type),
print_attr(base_type, i, &values[0]));
498 throw InternalErr(__FILE__, __LINE__,
"Expected one of NC_COMPOUND, NC_VLEN, NC_OPAQUE or NC_ENUM");
501 BESDEBUG(MODULE, prolog <<
"After switch(class-type)" << endl);
515 BESDEBUG(MODULE, prolog <<
"Before append_values ..." << endl);
516 append_values(ncid, varid, len, datatype, attrname, at);
517 BESDEBUG(MODULE, prolog <<
"After append_values ..." << endl);
522 string note =
"Attribute edlided: Unsupported attribute type ";
523 note +=
"(" + print_type(datatype) +
")";
524 at->append_attr(attrname,
"String", note);
532 throw InternalErr(__FILE__, __LINE__,
"user-defined attribute type not recognized as such!");
535 throw InternalErr(__FILE__, __LINE__,
"Unrecognized attribute type.");
539 BESDEBUG(MODULE, prolog <<
"Exiting read_attributes_netcdf4" << endl);
552 void nc_read_dataset_attributes(DAS &das,
const string &filename)
554 BESDEBUG(MODULE, prolog <<
"In nc_read_dataset_attributes" << endl);
557 errstat = nc_open(filename.c_str(), NC_NOWRITE, &ncid);
558 if (errstat != NC_NOERR)
throw Error(errstat,
"NetCDF handler: Could not open " + filename +
".");
562 errstat = nc_inq(ncid, (
int *) 0, &nvars, &ngatts, (
int *) 0);
563 if (errstat != NC_NOERR)
throw Error(errstat,
"NetCDF handler: Could not inquire about netcdf file: " + path_to_filename(filename) +
".");
566 char varname[MAX_NC_NAME];
569 for (
int varid = 0; varid < nvars; ++varid) {
570 BESDEBUG(MODULE, prolog <<
"Top of for loop; for each var..." << endl);
572 errstat = nc_inq_var(ncid, varid, varname, &var_type, (
int*) 0, (
int*) 0, &natts);
573 if (errstat != NC_NOERR)
throw Error(errstat,
"Could not get information for variable: " + long_to_string(varid));
575 AttrTable *attr_table_ptr = das.get_table(varname);
576 if (!attr_table_ptr) attr_table_ptr = das.add_table(varname,
new AttrTable);
578 READ_ATTRIBUTES_MACRO(ncid, varid, natts, attr_table_ptr);
581 if (var_type == NC_CHAR) {
584 int vdimids[MAX_VAR_DIMS];
585 errstat = nc_inq_var(ncid, varid, (
char *) 0, (nc_type *) 0, &num_dim, vdimids, (
int *) 0);
586 if (errstat != NC_NOERR)
587 throw Error(errstat,
string(
"NetCDF handler: Could not read information about a NC_CHAR variable while building the DAS."));
592 string print_rep =
print_attr(NC_INT, 0, (
void *) &size);
593 attr_table_ptr->append_attr(
"string_length", print_type(NC_INT), print_rep);
597 vector<size_t> dim_sizes(num_dim);
598 for (
int i = 0; i < num_dim; ++i) {
599 if ((errstat = nc_inq_dimlen(ncid, vdimids[i], &dim_sizes[i])) != NC_NOERR) {
601 string(
"NetCDF handler: Could not read dimension information about the variable `") + varname +
string(
"'."));
606 string print_rep =
print_attr(NC_INT, 0, (
void *) (&dim_sizes[num_dim - 1]));
607 attr_table_ptr->append_attr(
"string_length", print_type(NC_INT), print_rep);
611 #if NETCDF_VERSION >= 4
612 else if (is_user_defined_type(ncid, var_type)) {
614 vector<char> name(MAX_NC_NAME + 1);
616 errstat = nc_inq_user_type(ncid, var_type, &name[0], 0, 0, 0, &class_type);
617 if (errstat != NC_NOERR)
618 throw(InternalErr(__FILE__, __LINE__,
"Could not get information about a user-defined type (" + long_to_string(errstat) +
")."));
620 switch (class_type) {
622 attr_table_ptr->append_attr(
"DAP2_OriginalNetCDFBaseType", print_type(NC_STRING),
"NC_OPAQUE");
623 attr_table_ptr->append_attr(
"DAP2_OriginalNetCDFTypeName", print_type(NC_STRING), &name[0]);
629 nc_type base_nc_type;
630 size_t base_size, num_members;
631 errstat = nc_inq_enum(ncid, var_type, 0, &base_nc_type, &base_size, &num_members);
632 if (errstat != NC_NOERR)
633 throw(InternalErr(__FILE__, __LINE__,
"Could not get information about an enum(" + long_to_string(errstat) +
")."));
637 if (base_nc_type == NC_INT64 || base_nc_type == NC_UINT64) {
638 if (NCRequestHandler::get_ignore_unknown_types())
639 cerr <<
"An Enum uses 64-bit integers, but this handler does not support that type." << endl;
641 throw Error(
"An Enum uses 64-bit integers, but this handler does not support that type.");
645 for (
size_t i = 0; i < num_members; ++i) {
646 vector<char> member_name(MAX_NC_NAME + 1);
647 vector<char> member_value(base_size);
648 errstat = nc_inq_enum_member(ncid, var_type, i, &member_name[0], &member_value[0]);
649 if (errstat != NC_NOERR)
650 throw(InternalErr(__FILE__, __LINE__,
"Could not get information about an enum value (" + long_to_string(errstat) +
")."));
651 attr_table_ptr->append_attr(
"DAP2_EnumValues", print_type(base_nc_type),
print_attr(base_nc_type, 0, &member_value[0]));
652 attr_table_ptr->append_attr(
"DAP2_EnumNames", print_type(NC_STRING), &member_name[0]);
655 attr_table_ptr->append_attr(
"DAP2_OriginalNetCDFBaseType", print_type(NC_STRING),
"NC_ENUM");
656 attr_table_ptr->append_attr(
"DAP2_OriginalNetCDFTypeName", print_type(NC_STRING), &name[0]);
668 BESDEBUG(MODULE, prolog <<
"Starting global attributes" << endl);
672 AttrTable *attr_table_ptr = das.add_table(
"NC_GLOBAL",
new AttrTable);
673 READ_ATTRIBUTES_MACRO(ncid, NC_GLOBAL, ngatts, attr_table_ptr);
678 char dimname[MAX_NC_NAME];
679 nc_type datatype = NC_CHAR;
680 if ((errstat = nc_inq(ncid, (
int *) 0, (
int *) 0, (
int *) 0, &xdimid)) != NC_NOERR)
681 throw InternalErr(__FILE__, __LINE__,
string(
"NetCDF handler: Could not access variable information: ") + nc_strerror(errstat));
683 if ((errstat = nc_inq_dim(ncid, xdimid, dimname, (
size_t *) 0)) != NC_NOERR)
684 throw InternalErr(__FILE__, __LINE__,
string(
"NetCDF handler: Could not access dimension information: ") + nc_strerror(errstat));
685 string print_rep =
print_attr(datatype, 0, dimname);
686 AttrTable *attr_table_ptr = das.add_table(
"DODS_EXTRA",
new AttrTable);
687 attr_table_ptr->append_attr(
"Unlimited_Dimension", print_type(datatype), print_rep);
690 if (nc_close(ncid) != NC_NOERR)
throw InternalErr(__FILE__, __LINE__,
"NetCDF handler: Could not close the dataset!");
692 BESDEBUG(MODULE, prolog <<
"Exiting nc_read_dataset_attributes" << endl);
string print_attr(hid_t type, int loc, void *sm_buf)