53#include <libdap/DDS.h>
54#include <libdap/mime_util.h>
55#include <libdap/util.h>
57#include "NCRequestHandler.h"
71#include "NCStructure.h"
78build_scalar(
const string &varname,
const string &dataset, nc_type datatype)
81#if NETCDF_VERSION >= 4
85 return (
new NCStr(varname, dataset));
88 if (NCRequestHandler::get_promote_byte_to_short()) {
89 return (
new NCInt16(varname, dataset));
92 return (
new NCByte(varname, dataset));
96 return (
new NCInt16(varname, dataset));
99 return (
new NCInt32(varname, dataset));
101#if NETCDF_VERSION >= 4
104 return (
new NCByte(varname, dataset));
107 return (
new NCUInt16(varname, dataset));
110 return (
new NCUInt32(varname, dataset));
113 return (
new NCFloat32(varname, dataset));
116 return (
new NCFloat64(varname, dataset));
118#if NETCDF_VERSION >= 4
121 if (NCRequestHandler::get_ignore_unknown_types())
122 cerr <<
"The netCDF handler does not currently support 64 bit integers.";
124 throw Error(
"The netCDF handler does not currently support 64 bit integers.");
129 throw InternalErr(__FILE__, __LINE__,
"Unknown type (" + long_to_string(datatype) +
") for variable '" + varname +
"'");
138static bool is_user_defined(nc_type type)
140#if NETCDF_VERSION >= 4
141 return type >= NC_FIRSTUSERTYPEID;
154static Grid *build_grid(Array *ar,
int ndims,
const nc_type array_type,
155 const char map_names[MAX_NC_VARS][MAX_NC_NAME],
156 const nc_type map_types[MAX_NC_VARS],
157 const size_t map_sizes[MAX_VAR_DIMS],
162 if (array_type == NC_CHAR)
165 for (
int d = 0; d < ndims; ++d) {
166 ar->append_dim(map_sizes[d], map_names[d]);
168 all_maps->push_back(
string(map_names[d]));
171 const string &filename = ar->dataset();
172 Grid *gr =
new NCGrid(ar->name(), filename);
173 gr->add_var(ar, libdap::array);
176 for (
int d = 0; d < ndims; ++d) {
177 BaseType *local_bt = build_scalar(map_names[d], filename, map_types[d]);
178 NCArray *local_ar =
new NCArray(local_bt->name(), filename, local_bt);
180 local_ar->append_dim(map_sizes[d], map_names[d]);
181 gr->add_var(local_ar, maps);
188#if NETCDF_VERSION >= 4
192static BaseType *build_user_defined(
int ncid,
int varid, nc_type xtype,
const string &dataset,
193 int ndims,
int dim_ids[MAX_VAR_DIMS])
199 int status = nc_inq_user_type(ncid, xtype, 0, &size, &base_type, &nfields, &class_type);
200 if (status != NC_NOERR)
201 throw InternalErr(__FILE__, __LINE__,
"Could not get information about a user-defined type (" + long_to_string(status) +
").");
203 switch (class_type) {
205 char var_name[NC_MAX_NAME+1];
206 nc_inq_varname(ncid, varid, var_name);
210 for (
size_t i = 0; i < nfields; ++i) {
211 char field_name[NC_MAX_NAME+1];
212 nc_type field_typeid;
214 int field_sizes[MAX_NC_DIMS];
215 nc_inq_compound_field(ncid, xtype, i, field_name, 0, &field_typeid, &field_ndims, &field_sizes[0]);
217 if (is_user_defined_type(ncid, field_typeid)) {
220 field = build_user_defined(ncid, varid, field_typeid, dataset, field_ndims, field_sizes);
223 char var_name[NC_MAX_NAME+1];
224 nc_inq_compound_name(ncid, field_typeid, var_name);
225 field->set_name(var_name);
228 field = build_scalar(field_name, dataset, field_typeid);
232 if (field_ndims == 0 || (field_ndims == 1 && field_typeid == NC_CHAR)) {
237 for (
int i = 0; i < field_ndims; ++i) {
238 ar->append_dim(field_sizes[i]);
246 for (
int i = 0; i < ndims; ++i) {
247 char dimname[NC_MAX_NAME+1];
249 int errstat = nc_inq_dim(ncid, dim_ids[i], dimname, &dim_sz);
250 if (errstat != NC_NOERR) {
252 throw InternalErr(__FILE__, __LINE__,
string(
"Failed to read dimension information for the compound variable ") + var_name);
255 ar->append_dim(dim_sz, dimname);
268 if (NCRequestHandler::get_ignore_unknown_types()) {
269 cerr <<
"in build_user_defined; found a vlen." << endl;
273 throw Error(
"The netCDF handler does not yet suppor the NC_VLEN type.");
278 status = nc_inq_varname(ncid, varid, name.data());
279 if (status != NC_NOERR)
280 throw InternalErr(__FILE__, __LINE__,
"Could not get name of an opaque (" + long_to_string(status) +
").");
285 for (
int i = 0; i < ndims; ++i) {
286 char dimname[NC_MAX_NAME+1];
288 int errstat = nc_inq_dim(ncid, dim_ids[i], dimname, &dim_sz);
289 if (errstat != NC_NOERR) {
291 throw InternalErr(__FILE__, __LINE__,
string(
"Failed to read dimension information for the compound variable ") + name.data());
293 opaque->append_dim(dim_sz, dimname);
296 opaque->append_dim(size);
302 nc_type base_nc_type;
304 status = nc_inq_enum(ncid, xtype, 0 , &base_nc_type, &base_size, 0);
305 if (status != NC_NOERR)
306 throw(InternalErr(__FILE__, __LINE__,
"Could not get information about an enum(" + long_to_string(status) +
")."));
310 status = nc_inq_varname(ncid, varid, name.data());
311 if (status != NC_NOERR)
312 throw InternalErr(__FILE__, __LINE__,
"Could not get name of an opaque (" + long_to_string(status) +
").");
315 BaseType *enum_var = build_scalar(name.data(), dataset, base_nc_type);
320 for (
int i = 0; i < ndims; ++i) {
321 char dimname[NC_MAX_NAME + 1];
323 int errstat = nc_inq_dim(ncid, dim_ids[i], dimname, &dim_sz);
324 if (errstat != NC_NOERR) {
326 throw InternalErr(__FILE__, __LINE__,
string(
"Failed to read dimension information for the compound variable ") + name.data());
328 ar->append_dim(dim_sz, dimname);
340 throw InternalErr(__FILE__, __LINE__,
"Expected one of NC_COMPOUND, NC_VLEN, NC_OPAQUE or NC_ENUM");
364static bool find_matching_coordinate_variable(
int ncid,
int var,
365 char dimname[],
size_t dim_sz, nc_type *match_type)
370 int status = nc_inq_dimid(ncid, dimname, &
id);
371 if (status == NC_NOERR) {
374 status = nc_inq_dimlen(ncid,
id, &length);
375 if (status != NC_NOERR) {
376 string msg =
"netcdf 3: could not get size for dimension ";
377 msg += long_to_string(
id);
378 msg +=
" in variable ";
379 msg += string(dimname);
382 if (length == dim_sz) {
387 status = nc_inq_varid(ncid, dimname, &varid);
392 if (var == varid || status != NC_NOERR)
395 status = nc_inq_vartype(ncid, varid, match_type);
396 if (status != NC_NOERR) {
397 string msg =
"netcdf 3: could not get type variable ";
398 msg += string(dimname);
419static bool is_grid(
int ncid,
int var,
int ndims,
const int dim_ids[MAX_VAR_DIMS],
420 size_t map_sizes[MAX_VAR_DIMS],
421 char map_names[MAX_NC_VARS][MAX_NC_NAME],
422 nc_type map_types[MAX_NC_VARS])
425 for (
int d = 0; d < ndims; ++d) {
426 char dimname[MAX_NC_NAME];
429 int errstat = nc_inq_dim(ncid, dim_ids[d], dimname, &dim_sz);
430 if (errstat != NC_NOERR) {
431 string msg =
"netcdf 3: could not get size for dimension ";
432 msg += long_to_string(d);
433 msg +=
" in variable ";
434 msg += long_to_string(var);
439 if (find_matching_coordinate_variable(ncid, var, dimname, dim_sz, &match_type)) {
440 map_types[d] = match_type;
441 map_sizes[d] = dim_sz;
442 strncpy(map_names[d], dimname, MAX_NC_NAME - 1);
443 map_names[d][MAX_NC_NAME - 1] =
'\0';
462static NCArray *build_array(BaseType *bt,
int ncid,
int var,
463 const nc_type array_type,
int ndims,
464 const int dim_ids[MAX_NC_DIMS])
468 if (array_type == NC_CHAR)
471 for (
int d = 0; d < ndims; ++d) {
472 char dimname[MAX_NC_NAME];
474 int errstat = nc_inq_dim(ncid, dim_ids[d], dimname, &dim_sz);
475 if (errstat != NC_NOERR) {
477 throw Error(
"netcdf: could not get size for dimension " + long_to_string(d) +
" in variable " + long_to_string(var));
480 ar->append_dim(dim_sz, dimname);
495static void read_variables(DDS &dds_table,
const string &filename,
int ncid,
int nvars)
513 char name[MAX_NC_NAME];
516 int dim_ids[MAX_VAR_DIMS];
521 for (
int varid = 0; varid < nvars; ++varid) {
522 int errstat = nc_inq_var(ncid, varid, name, &nctype, &ndims, dim_ids, (
int *) 0);
523 if (errstat != NC_NOERR)
524 throw Error(
"netcdf: could not get name or dimension number for variable " + long_to_string(varid));
528 size_t map_sizes[MAX_VAR_DIMS];
529 char map_names[MAX_NC_VARS][MAX_NC_NAME];
530 nc_type map_types[MAX_NC_VARS];
534 if (is_user_defined_type(ncid, nctype)) {
536#if NETCDF_VERSION >= 4
537 BaseType *bt = build_user_defined(ncid, varid, nctype, filename, ndims, dim_ids);
538 dds_table.add_var(bt);
542 else if (ndims == 0 || (ndims == 1 && nctype == NC_CHAR)) {
543 BaseType *bt = build_scalar(name, filename, nctype);
544 dds_table.add_var(bt);
547 else if (is_grid(ncid, varid, ndims, dim_ids, map_sizes, map_names, map_types)) {
548 BaseType *bt = build_scalar(name, filename, nctype);
549 Array *ar =
new NCArray(name, filename, bt);
551 Grid *gr = build_grid(ar, ndims, nctype, map_names, map_types, map_sizes, &all_maps);
553 dds_table.add_var(gr);
557 if (!NCRequestHandler::get_show_shared_dims()) {
558 array_vars.push_back(varid);
560 BaseType *bt = build_scalar(name, filename, nctype);
561 NCArray *ar = build_array(bt, ncid, varid, nctype, ndims, dim_ids);
563 dds_table.add_var(ar);
574 if (!NCRequestHandler::get_show_shared_dims()) {
577 nvars = array_vars.size();
578 for (
int i = 0; i < nvars; ++i) {
579 int var = array_vars.at(i);
581 int errstat = nc_inq_var(ncid, var, name, &nctype, &ndims,
583 if (errstat != NC_NOERR) {
584 string msg =
"netcdf 3: could not get name or dimension number for variable ";
585 msg += long_to_string(var);
591 if (is_dimension(
string(name), all_maps))
594 BaseType *bt = build_scalar(name, filename, nctype);
595 Array *ar = build_array(bt, ncid, var, nctype, ndims, dim_ids);
597 dds_table.add_var(ar);
610void nc_read_dataset_variables(DDS &dds_table,
const string &filename)
616 errstat = nc_open(filename.c_str(), NC_NOWRITE, &ncid);
617 if (errstat != NC_NOERR)
618 throw Error(errstat,
"Could not open " + filename +
".");
621 errstat = nc_inq_nvars(ncid, &nvars);
622 if (errstat != NC_NOERR)
623 throw Error(errstat,
"Could not inquire about netcdf file: " + path_to_filename(filename) +
".");
626 dds_table.set_dataset_name(name_path(filename));
629 read_variables(dds_table, filename, ncid, nvars);
631 if (nc_close(ncid) != NC_NOERR)
632 throw InternalErr(__FILE__, __LINE__,
"ncdds: Could not close the dataset!");