34 #include <BESInternalError.h>
37 #include "FONcRequestHandler.h"
38 #include "FONcArray.h"
42 #include "FONcUtils.h"
43 #include "FONcAttributes.h"
46 vector<FONcDim *> FONcArray::Dimensions;
48 const int MAX_CHUNK_SIZE = 1024;
58 FONcArray::FONcArray(BaseType *b) :
59 FONcBaseType(), d_a(0), d_array_type(NC_NAT), d_ndims(0), d_actual_ndims(0), d_nelements(1), d4_dim_ids(0),d_dim_ids(0),
60 d_dim_sizes(0), d_str_data(0), d_dont_use_it(false), d_chunksizes(0), d_grid_maps(0),d4_def_dim(false)
62 d_a =
dynamic_cast<Array *
>(b);
64 string s =
"File out netcdf, FONcArray was passed a variable that is not a DAP Array";
68 for(
unsigned int i = 0; i<d_a->dimensions();i++)
69 use_d4_dim_ids.push_back(
false);
74 FONcArray::FONcArray(BaseType *b,
const vector<int> &fd4_dim_ids,
const vector<bool> &fuse_d4_dim_ids,
const vector<int> &rbs_nums):
75 FONcBaseType(), d_a(0), d_array_type(NC_NAT), d_ndims(0),d_actual_ndims(0), d_nelements(1),d_dim_ids(0),
76 d_dim_sizes(0), d_str_data(0), d_dont_use_it(false), d_chunksizes(0), d_grid_maps(0)
78 d_a =
dynamic_cast<Array *
>(b);
80 string s =
"File out netcdf, FONcArray was passed a variable that is not a DAP Array";
84 BESDEBUG(
"fonc",
"FONcArray() - constructor is dap4 "<< endl);
85 d4_dim_ids = fd4_dim_ids;
86 use_d4_dim_ids = fuse_d4_dim_ids;
88 d4_rbs_nums = rbs_nums;
104 vector<FONcDim*>::iterator d = d_dims.begin();
105 while (d != d_dims.end()) {
111 vector<FONcMap*>::iterator i = d_grid_maps.begin();
112 while (i != d_grid_maps.end()) {
134 FONcBaseType::convert(embed,is_dap4_group);
139 BESDEBUG(
"fonc",
"FONcArray::convert() - converting array " << _varname << endl);
144 if(d4_dim_ids.size() >0) {
145 BESDEBUG(
"fonc",
"FONcArray::convert() - d4_dim_ids size is " << d4_dim_ids.size() << endl);
150 d_ndims = d_a->dimensions();
151 d_actual_ndims = d_ndims;
152 if (d_array_type == NC_CHAR) {
161 d_dim_ids.resize(d_ndims);
162 d_dim_sizes.resize(d_ndims);
164 Array::Dim_iter di = d_a->dim_begin();
165 Array::Dim_iter de = d_a->dim_end();
167 for (; di != de; di++) {
168 int size = d_a->dimension_size(di,
true);
169 d_dim_sizes[dimnum] = size;
173 d_chunksizes.push_back(size <= MAX_CHUNK_SIZE ? size: MAX_CHUNK_SIZE);
175 BESDEBUG(
"fonc",
"FONcArray::convert() - dim num: " << dimnum <<
", dim size: " << size <<
", chunk size: " << d_chunksizes[dimnum] << endl);
176 BESDEBUG(
"fonc",
"FONcArray::convert() - dim name: " << d_a->dimension_name(di) << endl);
179 if(
true == d4_def_dim && use_d4_dim_ids[dimnum]==
true) {
180 d_dim_ids[dimnum] = d4_dim_ids[dimnum];
181 BESDEBUG(
"fonc",
"FONcArray::convert() - has dap4 group" << endl);
188 int ds_num = FONcDim::DimNameNum+1;
189 while(find(d4_rbs_nums.begin(),d4_rbs_nums.end(),ds_num) != d4_rbs_nums.end()) {
194 FONcDim::DimNameNum = ds_num-1;
196 FONcDim *use_dim = find_dim(embed, d_a->dimension_name(di), size);
197 d_dims.push_back(use_dim);
204 if (d_array_type == NC_CHAR) {
207 int array_length = d_a->length();
209 d_str_data.reserve(array_length);
210 d_a->value(d_str_data);
213 size_t max_length = 0;
214 for (
int i = 0; i < array_length; i++) {
215 if (d_str_data[i].length() > max_length) {
216 max_length = d_str_data[i].length();
220 vector<string> empty_embed;
222 if(is_dap4_group ==
true) {
226 ostringstream dim_suffix_strm;
227 dim_suffix_strm <<
"_len"<<FONcDim::DimNameNum +1;
228 FONcDim::DimNameNum++;
229 lendim_name = _varname+dim_suffix_strm.str();
233 lendim_name = _varname +
"_len";
236 FONcDim *use_dim = find_dim(empty_embed, lendim_name, max_length,
true);
238 if (use_dim->size() <
static_cast<int>(max_length)) {
239 use_dim->update_size(max_length);
242 d_dim_sizes[d_ndims - 1] = use_dim->size();
243 d_dim_ids[d_ndims - 1] = use_dim->dimid();
244 use_d4_dim_ids.push_back(
false);
245 d_dims.push_back(use_dim);
254 d_chunksizes.push_back(max_length <= MAX_CHUNK_SIZE ? max_length: MAX_CHUNK_SIZE);
261 if (!
FONcGrid::InGrid && d_actual_ndims == 1 && d_a->name() == d_a->dimension_name(d_a->dim_begin())) {
263 FONcMap *map = FONcGrid::InMaps(d_a);
267 d_grid_maps.push_back(new_map);
271 d_dont_use_it =
true;
276 BESDEBUG(
"fonc",
"FONcArray::convert() - done converting array " << _varname << endl);
293 FONcArray::find_dim(vector<string> &embed,
const string &name,
int size,
bool ignore_size)
298 vector<FONcDim *>::iterator i = FONcArray::Dimensions.begin();
299 vector<FONcDim *>::iterator e = FONcArray::Dimensions.end();
300 for (; i != e && !ret_dim; i++) {
301 if (!((*i)->name().empty()) && ((*i)->name() ==
name)) {
305 else if ((*i)->size() == size) {
309 if (embed.size() > 0) {
311 return find_dim(tmp, ename, size);
313 string err =
"fileout_netcdf: dimension found with the same name, but different size";
320 FONcArray::Dimensions.push_back(ret_dim);
344 BESDEBUG(
"fonc",
"FONcArray::define() - defining array '" << _varname <<
"'" << endl);
346 if (!_defined && !d_dont_use_it) {
348 BESDEBUG(
"fonc",
"FONcArray::define() - defining array ' defined already" << _varname <<
"'" << endl);
350 if(d4_dim_ids.size() >0) {
351 if(d_array_type == NC_CHAR) {
352 if(d_dims.size() == 1) {
353 FONcDim *fd = *(d_dims.begin());
355 d_dim_ids[d_ndims-1] = fd->dimid();
366 if(
false == d4_def_dim) {
367 vector<FONcDim *>::iterator i = d_dims.begin();
368 vector<FONcDim *>::iterator e = d_dims.end();
370 for (; i != e; i++) {
374 d_dim_ids[dimnum] = fd->dimid();
375 BESDEBUG(
"fonc",
"FONcArray::define() - dim_id: " << fd->dimid() <<
" size:" << fd->size() << endl);
381 for(
unsigned int i = 0; i< use_d4_dim_ids.size();i++) {
382 if(use_d4_dim_ids[i] ==
false) {
385 d_dim_ids[i] = fd->dimid();
391 int stax = nc_def_var(ncid, _varname.c_str(), d_array_type, d_ndims, &d_dim_ids[0], &_varid);
392 if (stax != NC_NOERR) {
393 string err = (string)
"fileout.netcdf - Failed to define variable " + _varname;
398 BESDEBUG(
"fonc",
"FONcArray::define() Working netcdf-4 branch " << endl);
399 if (FONcRequestHandler::chunk_size == 0)
401 stax = nc_def_var_chunking(ncid, _varid, NC_CONTIGUOUS, &d_chunksizes[0]);
403 stax = nc_def_var_chunking(ncid, _varid, NC_CHUNKED, &d_chunksizes[0]);
405 if (stax != NC_NOERR) {
406 string err =
"fileout.netcdf - Failed to define chunking for variable " + _varname;
412 if (FONcRequestHandler::use_compression) {
415 int deflate_level = 4;
416 stax = nc_def_var_deflate(ncid, _varid, shuffle, deflate, deflate_level);
418 if (stax != NC_NOERR) {
419 string err = (string)
"fileout.netcdf - Failed to define compression (deflate) level for variable "
435 AttrTable &attrs = d_a->get_attr_table();
436 if (attrs.get_size()) {
437 for (AttrTable::Attr_iter iter = attrs.attr_begin(); iter != attrs.attr_end(); iter++) {
438 if (attrs.get_name(iter) == _FillValue || attrs.get_name(iter) ==
"FillValue"){
439 if(FONcArray::getAttrType(d_array_type) != attrs.get_attr_type(iter)) {
440 (*iter)->type = FONcArray::getAttrType(d_array_type);
447 BESDEBUG(
"fonc",
"FONcArray::define() - Adding attributes " << endl);
454 BESDEBUG(
"fonc",
"FONcArray::define() - variable " << _varname <<
" is already defined" << endl);
457 BESDEBUG(
"fonc",
"FONcArray::define() - variable " << _varname <<
" is not being used" << endl);
461 BESDEBUG(
"fonc",
"FONcArray::define() - done defining array '" << _varname <<
"'" << endl);
475 BESDEBUG(
"fonc",
"FONcArray::write() BEGIN var: " << _varname <<
"[" << d_nelements <<
"]" << endl);
478 BESDEBUG(
"fonc",
"FONcTransform::write not using variable " << _varname << endl);
485 if (d_array_type != NC_CHAR) {
489 if(isNetCDF4_ENHANCED())
490 write_for_nc4_types(ncid);
492 string var_type = d_a->var()->type_name();
495 switch (d_array_type) {
497 unsigned char *data =
new unsigned char[d_nelements];
498 d_a->buf2val((
void**) &data);
499 stax = nc_put_var_uchar(ncid, _varid, data);
502 if (stax != NC_NOERR) {
503 string err =
"fileout.netcdf - Failed to create array of bytes for " + _varname;
510 short *data =
new short[d_nelements];
516 if (var_type ==
"Byte") {
518 unsigned char *orig_data =
new unsigned char[d_nelements];
519 d_a->buf2val((
void**) &orig_data);
521 for (
int d_i = 0; d_i < d_nelements; d_i++)
522 data[d_i] = orig_data[d_i];
527 d_a->buf2val((
void**) &data);
529 int stax = nc_put_var_short(ncid, _varid, data);
532 if (stax != NC_NOERR) {
533 string err = (string)
"fileout.netcdf - Failed to create array of shorts for " + _varname;
542 if (var_type ==
"Int64" || var_type ==
"UInt64" ) {
547 if (FONcRequestHandler::classic_model ==
false) {
548 msg =
"You asked for one or more 64-bit integer values returned using a netCDF3 file. "
549 "Try asking for netCDF4 and/or contact the server administrator.";
552 msg =
"You asked for one or more 64-bit integer values, but either returned using a netCDF3 file or "
553 "from a server that is configured to use the 'classic' netCDF data model with netCDF4. "
554 "Try netCDF4 and/or contact the server administrator.";
559 int *data =
new int[d_nelements];
562 if (var_type ==
"UInt16") {
563 unsigned short *orig_data =
new unsigned short[d_nelements];
564 d_a->buf2val((
void**) &orig_data);
566 for (
int d_i = 0; d_i < d_nelements; d_i++)
567 data[d_i] = orig_data[d_i];
572 d_a->buf2val((
void**) &data);
575 int stax = nc_put_var_int(ncid, _varid, data);
578 if (stax != NC_NOERR) {
579 string err = (string)
"fileout.netcdf - Failed to create array of ints for " + _varname;
586 float *data =
new float[d_nelements];
587 d_a->buf2val((
void**) &data);
588 int stax = nc_put_var_float(ncid, _varid, data);
591 if (stax != NC_NOERR) {
592 string err = (string)
"fileout.netcdf - Failed to create array of floats for " + _varname;
599 double *data =
new double[d_nelements];
600 d_a->buf2val((
void**) &data);
601 int stax = nc_put_var_double(ncid, _varid, data);
604 if (stax != NC_NOERR) {
605 string err = (string)
"fileout.netcdf - Failed to create array of doubles for " + _varname;
617 size_t var_count[d_ndims];
618 size_t var_start[d_ndims];
620 for (dim = 0; dim < d_ndims; dim++) {
630 for (
int element = 0; element < d_nelements; element++) {
631 var_count[d_ndims - 1] = d_str_data[element].size() + 1;
632 var_start[d_ndims - 1] = 0;
635 int stax = nc_put_vara_text(ncid, _varid, var_start, var_count, d_str_data[element].c_str());
636 if (stax != NC_NOERR) {
637 string err = (string)
"fileout.netcdf - Failed to create array of strings for " + _varname;
642 if (element + 1 < d_nelements) {
646 var_start[dim] = var_start[dim] + 1;
647 if (var_start[dim] == d_dim_sizes[dim]) {
659 BESDEBUG(
"fonc",
"FONcArray::write() END var: " << _varname <<
"[" << d_nelements <<
"]" << endl);
681 strm << BESIndent::LMarg <<
"FONcArray::dump - (" << (
void *)
this <<
")" << endl;
683 strm << BESIndent::LMarg <<
"name = " << _varname << endl;
684 strm << BESIndent::LMarg <<
"ndims = " << d_ndims << endl;
685 strm << BESIndent::LMarg <<
"actual ndims = " << d_actual_ndims << endl;
686 strm << BESIndent::LMarg <<
"nelements = " << d_nelements << endl;
688 strm << BESIndent::LMarg <<
"dimensions:" << endl;
690 vector<FONcDim *>::const_iterator i = d_dims.begin();
691 vector<FONcDim *>::const_iterator e = d_dims.end();
692 for (; i != e; i++) {
695 BESIndent::UnIndent();
698 strm << BESIndent::LMarg <<
"dimensions: none" << endl;
700 BESIndent::UnIndent();
713 void FONcArray::write_for_nc4_types(
int ncid) {
722 switch (d_array_type) {
724 signed char *data =
new signed char[d_nelements];
725 d_a->buf2val((
void**) &data);
726 stax = nc_put_var_schar(ncid, _varid, data);
729 if (stax != NC_NOERR) {
730 string err =
"fileout.netcdf - Failed to create array of bytes for " + _varname;
737 unsigned char *data =
new unsigned char[d_nelements];
738 d_a->buf2val((
void**) &data);
739 stax = nc_put_var_uchar(ncid, _varid, data);
742 if (stax != NC_NOERR) {
743 string err =
"fileout.netcdf - Failed to create array of bytes for " + _varname;
751 short *data =
new short[d_nelements];
752 d_a->buf2val((
void**) &data);
753 int stax = nc_put_var_short(ncid, _varid, data);
756 if (stax != NC_NOERR) {
757 string err = (string)
"fileout.netcdf - Failed to create array of shorts for " + _varname;
765 int *data =
new int[d_nelements];
766 d_a->buf2val((
void**) &data);
768 int stax = nc_put_var_int(ncid, _varid, data);
771 if (stax != NC_NOERR) {
772 string err = (string)
"fileout.netcdf - Failed to create array of ints for " + _varname;
780 int64_t *data =
new int64_t[d_nelements];
781 d_a->buf2val((
void**) &data);
783 int stax = nc_put_var_longlong(ncid, _varid, (
const long long*)data);
786 if (stax != NC_NOERR) {
787 string err = (string)
"fileout.netcdf - Failed to create array of ints for " + _varname;
794 float *data =
new float[d_nelements];
795 d_a->buf2val((
void**) &data);
796 int stax = nc_put_var_float(ncid, _varid, data);
799 if (stax != NC_NOERR) {
800 string err = (string)
"fileout.netcdf - Failed to create array of floats for " + _varname;
807 double *data =
new double[d_nelements];
808 d_a->buf2val((
void**) &data);
809 int stax = nc_put_var_double(ncid, _varid, data);
812 if (stax != NC_NOERR) {
813 string err = (string)
"fileout.netcdf - Failed to create array of doubles for " + _varname;
820 unsigned short *data =
new unsigned short[d_nelements];
821 d_a->buf2val((
void**) &data);
822 int stax = nc_put_var_ushort(ncid, _varid, data);
825 if (stax != NC_NOERR) {
826 string err = (string)
"fileout.netcdf - Failed to create array of unsigned short for " + _varname;
833 unsigned int *data =
new unsigned int[d_nelements];
834 d_a->buf2val((
void**) &data);
835 int stax = nc_put_var_uint(ncid, _varid, data);
838 if (stax != NC_NOERR) {
839 string err = (string)
"fileout.netcdf - Failed to create array of unsigned int for " + _varname;
846 uint64_t *data =
new uint64_t[d_nelements];
847 d_a->buf2val((
void**) &data);
848 int stax = nc_put_var_ulonglong(ncid, _varid, (
const unsigned long long*)data);
851 if (stax != NC_NOERR) {
852 string err = (string)
"fileout.netcdf - Failed to create array of unsigned int for " + _varname;
859 string err = (string)
"Failed to transform array of unknown type in file out netcdf";
866 libdap::AttrType FONcArray::getAttrType(nc_type nct) {
869 case NC_BYTE:
return Attr_byte;
870 case NC_SHORT:
return Attr_int16;
871 case NC_LONG:
return Attr_int32;
872 case NC_FLOAT:
return Attr_float32;
873 case NC_DOUBLE:
return Attr_float64;
875 case NC_STRING:
return Attr_string;
876 default:
return Attr_unknown;
exception thrown if internal error encountered
virtual void define(int ncid)
define the DAP Array in the netcdf file
virtual void convert(std::vector< std::string > embed, bool is_dap4_group=false)
Converts the DAP Array to a FONcArray.
virtual std::string name()
returns the name of the DAP Array
virtual void dump(std::ostream &strm) const
dumps information about this object for debugging purposes
virtual ~FONcArray()
Destructor that cleans up the array.
virtual void write(int ncid)
Write the array out to the netcdf file.
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(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