36#include <libdap/Array.h>
38#include <BESInternalError.h>
39#include <BESSyntaxUserError.h>
42#include "FONcRequestHandler.h"
48#include "FONcAttributes.h"
54#define CLEAR_LOCAL_DATA 1
56vector<FONcDim *> FONcArray::Dimensions;
58const int MAX_CHUNK_SIZE = 1024;
68FONcArray::FONcArray(BaseType *b) :
69 FONcBaseType(), d_a(0), d_array_type(NC_NAT), d_ndims(0), d_actual_ndims(0), d_nelements(1), d4_dim_ids(0),
70 d_dim_ids(0), d_dim_sizes(0), d_dont_use_it(false), d_chunksizes(0),
71 d_grid_maps(0), d4_def_dim(false) {
72 d_a =
dynamic_cast<Array *
>(b);
74 string s =
"File out netcdf, FONcArray was passed a variable that is not a DAP Array";
78 for (
unsigned int i = 0; i < d_a->dimensions(); i++)
79 use_d4_dim_ids.push_back(
false);
82FONcArray::FONcArray(BaseType *b,
const vector<int> &fd4_dim_ids,
const vector<bool> &fuse_d4_dim_ids,
83 const vector<int> &rds_nums) :
84 FONcBaseType(), d_a(0), d_array_type(NC_NAT), d_ndims(0), d_actual_ndims(0), d_nelements(1), d_dim_ids(0),
85 d_dim_sizes(0), d_dont_use_it(false), d_chunksizes(0), d_grid_maps(0) {
86 d_a =
dynamic_cast<Array *
>(b);
88 string s =
"File out netcdf, FONcArray was passed a variable that is not a DAP Array";
92 BESDEBUG(
"fonc",
"FONcArray() - constructor is dap4 " << endl);
93 d4_dim_ids = fd4_dim_ids;
94 use_d4_dim_ids = fuse_d4_dim_ids;
96 d4_rds_nums = rds_nums;
112 vector<FONcDim *>::iterator d = d_dims.begin();
113 while (d != d_dims.end()) {
119 vector<FONcMap *>::iterator i = d_grid_maps.begin();
120 while (i != d_grid_maps.end()) {
141 FONcBaseType::convert(embed, _dap4, is_dap4_group);
145 BESDEBUG(
"fonc",
"FONcArray::convert() - converting array " << _varname << endl);
150 if (d4_dim_ids.size() > 0) {
151 BESDEBUG(
"fonc",
"FONcArray::convert() - d4_dim_ids size is " << d4_dim_ids.size() << endl);
155 d_ndims = d_a->dimensions();
156 d_actual_ndims = d_ndims;
157 if (d_array_type == NC_CHAR) {
166 d_dim_ids.resize(d_ndims);
167 d_dim_sizes.resize(d_ndims);
169 Array::Dim_iter di = d_a->dim_begin();
170 Array::Dim_iter de = d_a->dim_end();
172 for (; di != de; di++) {
173 int size = d_a->dimension_size(di,
true);
174 d_dim_sizes[dimnum] = size;
178 d_chunksizes.push_back(size <= MAX_CHUNK_SIZE ? size : MAX_CHUNK_SIZE);
180 BESDEBUG(
"fonc",
"FONcArray::convert() - dim num: " << dimnum <<
", dim size: " << size <<
", chunk size: "
181 << d_chunksizes[dimnum] << endl);
182 BESDEBUG(
"fonc",
"FONcArray::convert() - dim name: " << d_a->dimension_name(di) << endl);
185 if (
true == d4_def_dim && use_d4_dim_ids[dimnum] ==
true) {
186 d_dim_ids[dimnum] = d4_dim_ids[dimnum];
187 BESDEBUG(
"fonc",
"FONcArray::convert() - has dap4 group" << endl);
194 int ds_num = FONcDim::DimNameNum + 1;
195 while (find(d4_rds_nums.begin(), d4_rds_nums.end(), ds_num) != d4_rds_nums.end()) {
206 FONcDim::DimNameNum = ds_num - 1;
208 FONcDim *use_dim = find_dim(embed, d_a->dimension_name(di), size);
209 d_dims.push_back(use_dim);
216 if (d_array_type == NC_CHAR) {
231 d_a->intern_data(*get_eval(), *get_dds());
234 int array_length = d_a->length();
236 d_str_data.reserve(array_length);
237 d_a->value(d_str_data);
240 size_t max_length = 0;
241 for (
int i = 0; i < array_length; i++) {
242 if (d_str_data[i].length() > max_length) {
243 max_length = d_str_data[i].length();
248 size_t max_length = 0;
249 for (
int i = 0; i < array_length; i++) {
250 if (d_a->get_str()[i].length() > max_length) {
251 max_length = d_a->get_str()[i].length();
256 vector<string> empty_embed;
258 if (is_dap4_group ==
true) {
262 ostringstream dim_suffix_strm;
263 dim_suffix_strm <<
"_len" << FONcDim::DimNameNum + 1;
264 FONcDim::DimNameNum++;
265 lendim_name = _varname + dim_suffix_strm.str();
269 lendim_name = _varname +
"_len";
272 FONcDim *use_dim = find_dim(empty_embed, lendim_name, max_length,
true);
274 if (use_dim->size() <
static_cast<int>(max_length)) {
275 use_dim->update_size(max_length);
278 d_dim_sizes[d_ndims - 1] = use_dim->size();
279 d_dim_ids[d_ndims - 1] = use_dim->dimid();
282 use_d4_dim_ids.push_back(
false);
283 d_dims.push_back(use_dim);
292 d_chunksizes.push_back(max_length <= MAX_CHUNK_SIZE ? max_length : MAX_CHUNK_SIZE);
301 if(is_dap4 ==
false) {
302 if (!
FONcGrid::InGrid && d_actual_ndims == 1 && d_a->name() == d_a->dimension_name(d_a->dim_begin())) {
304 FONcMap *map = FONcGrid::InMaps(d_a);
308 d_grid_maps.push_back(new_map);
312 d_dont_use_it =
true;
317 BESDEBUG(
"fonc",
"FONcArray::convert() - done converting array " << _varname << endl);
334FONcArray::find_dim(vector<string> &embed,
const string &name,
int size,
bool ignore_size) {
338 vector<FONcDim *>::iterator i = FONcArray::Dimensions.begin();
339 vector<FONcDim *>::iterator e = FONcArray::Dimensions.end();
340 for (; i != e && !ret_dim; i++) {
341 if (!((*i)->name().empty()) && ((*i)->name() ==
name)) {
345 else if ((*i)->size() == size) {
349 if (embed.size() > 0) {
351 return find_dim(tmp, ename, size);
353 string err =
"fileout_netcdf: dimension found with the same name, but different size";
360 FONcArray::Dimensions.push_back(ret_dim);
383 BESDEBUG(
"fonc",
"FONcArray::define() - defining array '" << _varname <<
"'" << endl);
385 if (!_defined && !d_dont_use_it) {
387 BESDEBUG(
"fonc",
"FONcArray::define() - defining array ' defined already: " << _varname <<
"'" << endl);
393 if(d4_dim_ids.size() >0) {
394 if(d_array_type == NC_CHAR) {
395 if(d_dims.size() == 1) {
396 FONcDim *fd = *(d_dims.begin());
398 d_dim_ids[d_ndims-1] = fd->dimid();
409 if (
false == d4_def_dim) {
410 vector<FONcDim *>::iterator i = d_dims.begin();
411 vector<FONcDim *>::iterator e = d_dims.end();
413 for (; i != e; i++) {
417 d_dim_ids[dimnum] = fd->dimid();
418 BESDEBUG(
"fonc",
"FONcArray::define() - dim_id: " << fd->dimid() <<
" size:" << fd->size() << endl);
424 for (
unsigned int i = 0; i < use_d4_dim_ids.size(); i++) {
425 if (use_d4_dim_ids[i] ==
false) {
428 d_dim_ids[i] = fd->dimid();
434 int stax = nc_def_var(ncid, _varname.c_str(), d_array_type, d_ndims, &d_dim_ids[0], &_varid);
435 if (stax != NC_NOERR) {
436 string err = (string)
"fileout.netcdf - Failed to define variable " + _varname;
440 stax = nc_def_var_fill(ncid, _varid, NC_NOFILL, NULL );
441 if (stax != NC_NOERR) {
442 string err = (string)
"fileout.netcdf - " +
"Failed to clear fill value for " + _varname;
446 BESDEBUG(
"fonc",
"FONcArray::define() netcdf-4 version is " << _ncVersion << endl);
448 BESDEBUG(
"fonc",
"FONcArray::define() Working netcdf-4 branch " << endl);
449 if (FONcRequestHandler::chunk_size == 0)
451 stax = nc_def_var_chunking(ncid, _varid, NC_CONTIGUOUS, &d_chunksizes[0]);
453 stax = nc_def_var_chunking(ncid, _varid, NC_CHUNKED, &d_chunksizes[0]);
455 if (stax != NC_NOERR) {
456 string err =
"fileout.netcdf - Failed to define chunking for variable " + _varname;
462 if (FONcRequestHandler::use_compression) {
465 int deflate_level = 4;
466 stax = nc_def_var_deflate(ncid, _varid, shuffle, deflate, deflate_level);
468 if (stax != NC_NOERR) {
469 string err = (string)
"fileout.netcdf - Failed to define compression (deflate) level for variable "
478 D4Attributes *d4_attrs = d_a->attributes();
479 updateD4AttrType(d4_attrs, d_array_type);
482 AttrTable &attrs = d_a->get_attr_table();
483 updateAttrType(attrs, d_array_type);
486 BESDEBUG(
"fonc",
"FONcArray::define() - Adding attributes " << endl);
493 BESDEBUG(
"fonc",
"FONcArray::define() - variable " << _varname <<
" is already defined" << endl);
496 BESDEBUG(
"fonc",
"FONcArray::define() - variable " << _varname <<
" is not being used" << endl);
500 BESDEBUG(
"fonc",
"FONcArray::define() - done defining array '" << _varname <<
"'" << endl);
508void FONcArray::write_nc_variable(
int ncid, nc_type var_type) {
512 d_a->intern_data(*get_eval(), *get_dds());
518 stax = nc_put_var_uchar(ncid, _varid,
reinterpret_cast<unsigned char *
>(d_a->get_buf()));
521 stax = nc_put_var_schar(ncid, _varid,
reinterpret_cast<signed char *
>(d_a->get_buf()));
524 stax = nc_put_var_short(ncid, _varid,
reinterpret_cast<short *
>(d_a->get_buf()));
527 stax = nc_put_var_int(ncid, _varid,
reinterpret_cast<int *
>(d_a->get_buf()));
530 stax = nc_put_var_longlong(ncid, _varid,
reinterpret_cast<long long *
>(d_a->get_buf()));
533 stax = nc_put_var_float(ncid, _varid,
reinterpret_cast<float *
>(d_a->get_buf()));
536 stax = nc_put_var_double(ncid, _varid,
reinterpret_cast<double *
>(d_a->get_buf()));
539 stax = nc_put_var_ushort(ncid, _varid,
reinterpret_cast<unsigned short *
>(d_a->get_buf()));
542 stax = nc_put_var_uint(ncid, _varid,
reinterpret_cast<unsigned int *
>(d_a->get_buf()));
545 stax = nc_put_var_ulonglong(ncid, _varid,
reinterpret_cast<unsigned long long *
>(d_a->get_buf()));
549 throw BESInternalError(
"Failed to transform array of unknown type in file out netcdf (1)",
553 if (stax != NC_NOERR) {
554 string err =
"fileout.netcdf - Failed to create array of " + d_a->var()->type_name() +
" for " + _varname;
560 if (!FONcGrid::InMaps(d_a))
561 d_a->clear_local_data();
575 BESDEBUG(
"fonc",
"FONcArray::write() BEGIN var: " << _varname <<
"[" << d_nelements <<
"]" << endl);
576 BESDEBUG(
"fonc",
"FONcArray::write() BEGIN var type: " << d_array_type <<
" " << endl);
579 BESDEBUG(
"fonc",
"FONcTransform::write not using variable " << _varname << endl);
588 if (d_array_type == NC_CHAR) {
593 vector<size_t> var_count(d_ndims);
594 vector<size_t> var_start(d_ndims);
596 for (dim = 0; dim < d_ndims; dim++) {
606 for (
int element = 0; element < d_nelements; element++) {
607 var_count[d_ndims - 1] = d_a->get_str()[element].size() + 1;
608 var_start[d_ndims - 1] = 0;
611 int stax = nc_put_vara_text(ncid, _varid, &var_start[0], &var_count[0], d_a->get_str()[element].c_str());
612 if (stax != NC_NOERR) {
613 string err = (string)
"fileout.netcdf - Failed to create array of strings for " + _varname;
618 if (element + 1 < d_nelements) {
622 var_start[dim] = var_start[dim] + 1;
623 if (var_start[dim] == d_dim_sizes[dim]) {
634 d_a->get_str().clear();
638 else if (isNetCDF4_ENHANCED()) {
639 write_for_nc4_types(ncid);
644 switch (d_array_type) {
648 write_nc_variable(ncid, d_array_type);
656 if (element_type == libdap::dods_byte_c || element_type == libdap::dods_uint8_c) {
660 d_a->intern_data(*get_eval(), *get_dds());
664 vector<short> data(d_nelements);
665 for (
int d_i = 0; d_i < d_nelements; d_i++)
666 data[d_i] = *(
reinterpret_cast<unsigned char *
>(d_a->get_buf()) + d_i);
668 int stax = nc_put_var_short(ncid, _varid, &data[0]);
669 if (stax != NC_NOERR) {
670 string err = (string)
"fileout.netcdf - Failed to create array of shorts for " + _varname;
677 if (!FONcGrid::InMaps(d_a))
678 d_a->clear_local_data();
681 write_nc_variable(ncid, NC_SHORT);
688 if (element_type == libdap::dods_int64_c || element_type == libdap::dods_uint64_c) {
693 if (FONcRequestHandler::classic_model ==
false) {
694 msg =
"You asked for one or more 64-bit integer values returned using a netCDF3 file. "
695 "Try asking for netCDF4 enhanced and/or contact the server administrator.";
698 msg =
"You asked for one or more 64-bit integer values, but either returned using a netCDF3 file or "
699 "from a server that is configured to use the 'classic' netCDF data model with netCDF4. "
700 "Try netCDF4 and/or contact the server administrator.";
705 if (element_type == libdap::dods_uint16_c) {
709 d_a->intern_data(*get_eval(), *get_dds());
711 vector<int> data(d_nelements);
712 for (
int d_i = 0; d_i < d_nelements; d_i++)
713 data[d_i] = *(
reinterpret_cast<unsigned short *
>(d_a->get_buf()) + d_i);
715 int stax = nc_put_var_int(ncid, _varid, &data[0]);
716 if (stax != NC_NOERR) {
717 string err = (string)
"fileout.netcdf - Failed to create array of ints for " + _varname;
721 if (!FONcGrid::InMaps(d_a))
722 d_a->clear_local_data();
725 write_nc_variable(ncid, NC_INT);
730 throw BESInternalError(
"Failed to transform array of unknown type in file out netcdf (2)",
735 BESDEBUG(
"fonc",
"FONcArray::write() END var: " << _varname <<
"[" << d_nelements <<
"]" << endl);
755 strm << BESIndent::LMarg <<
"FONcArray::dump - (" << (
void *)
this <<
")" << endl;
757 strm << BESIndent::LMarg <<
"name = " << _varname << endl;
758 strm << BESIndent::LMarg <<
"ndims = " << d_ndims << endl;
759 strm << BESIndent::LMarg <<
"actual ndims = " << d_actual_ndims << endl;
760 strm << BESIndent::LMarg <<
"nelements = " << d_nelements << endl;
762 strm << BESIndent::LMarg <<
"dimensions:" << endl;
764 vector<FONcDim *>::const_iterator i = d_dims.begin();
765 vector<FONcDim *>::const_iterator e = d_dims.end();
766 for (; i != e; i++) {
769 BESIndent::UnIndent();
772 strm << BESIndent::LMarg <<
"dimensions: none" << endl;
774 BESIndent::UnIndent();
786void FONcArray::write_for_nc4_types(
int ncid) {
795 switch (d_array_type) {
806 write_nc_variable(ncid, d_array_type);
810 string err = (string)
"Failed to transform array of unknown type in file out netcdf";
exception thrown if internal error encountered
virtual void dump(std::ostream &strm) const override
dumps information about this object for debugging purposes
virtual void define(int ncid) override
define the DAP Array in the netcdf file
virtual ~FONcArray() override
Destructor that cleans up the array.
virtual void convert(std::vector< std::string > embed, bool _dap4=false, bool is_dap4_group=false) override
Converts the DAP Array to a FONcArray.
virtual void write(int ncid) override
Write the array out to the netcdf file.
virtual std::string name() override
returns the name of the DAP Array
static void add_original_name(int ncid, int varid, const string &var_name, const string &orig)
Adds an attribute for the variable if the variable name had to be modified in any way.
static void add_variable_attributes(int ncid, int varid, BaseType *b, bool is_netCDF_enhanced, bool is_dap4)
Add the attributes for an OPeNDAP variable to the netcdf file.
A DAP BaseType with file out netcdf information included.
virtual bool isNetCDF4()
Returns true if NetCDF4 features will be required.
A class that represents the dimension of an array.
virtual void define(int ncid)
define the DAP dimension in the netcdf file
static vector< FONcMap * > Maps
global list of maps that could be shared amongst the different grids
static bool InGrid
tells whether we are converting or defining a grid.
A map of a DAP Grid with file out netcdf information included.
static void handle_error(int stax, const string &err, const string &file, int line)
handle any netcdf errors
static nc_type get_nc_type(libdap::BaseType *element, bool isNC4_ENHANCED)
translate the OPeNDAP data type to a netcdf data type
static string gen_name(const vector< string > &embed, const string &name, string &original)
generate a new name for the embedded variable