bes  Updated for version 3.20.8
FONcArray.cc
1 // FONcArray.cc
2 
3 // This file is part of BES Netcdf File Out Module
4 
5 // Copyright (c) 2004,2005 University Corporation for Atmospheric Research
6 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 //
22 // You can contact University Corporation for Atmospheric Research at
23 // 3080 Center Green Drive, Boulder, CO 80301
24 
25 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
26 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
27 //
28 // Authors:
29 // pwest Patrick West <pwest@ucar.edu>
30 // jgarcia Jose Garcia <jgarcia@ucar.edu>
31 // Kent Yang <myang6@hdfgroup.org> (for DAP4/netCDF-4 enhancement)
32 
33 #include <sstream>
34 #include <BESInternalError.h>
35 #include <BESDebug.h>
36 
37 #include "FONcRequestHandler.h" // For access to the handler's keys
38 #include "FONcArray.h"
39 #include "FONcDim.h"
40 #include "FONcGrid.h"
41 #include "FONcMap.h"
42 #include "FONcUtils.h"
43 #include "FONcAttributes.h"
44 #include <algorithm>
45 
46 vector<FONcDim *> FONcArray::Dimensions;
47 
48 const int MAX_CHUNK_SIZE = 1024;
49 
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)
61 {
62  d_a = dynamic_cast<Array *>(b);
63  if (!d_a) {
64  string s = "File out netcdf, FONcArray was passed a variable that is not a DAP Array";
65  throw BESInternalError(s, __FILE__, __LINE__);
66  }
67 
68  for(unsigned int i = 0; i<d_a->dimensions();i++)
69  use_d4_dim_ids.push_back(false);
70 
71 
72 }
73 
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)
77 {
78  d_a = dynamic_cast<Array *>(b);
79  if (!d_a) {
80  string s = "File out netcdf, FONcArray was passed a variable that is not a DAP Array";
81  throw BESInternalError(s, __FILE__, __LINE__);
82  }
83  if(d_a ->is_dap4()) {
84  BESDEBUG("fonc", "FONcArray() - constructor is dap4 "<< endl);
85  d4_dim_ids = fd4_dim_ids;
86  use_d4_dim_ids = fuse_d4_dim_ids;
87  d4_def_dim = true;
88  d4_rbs_nums = rbs_nums;
89  }
90 }
102 {
103  // Added jhrg 8/28/13
104  vector<FONcDim*>::iterator d = d_dims.begin();
105  while (d != d_dims.end()) {
106  (*d)->decref();
107  ++d;
108  }
109 
110  // Added jhrg 8/28/13
111  vector<FONcMap*>::iterator i = d_grid_maps.begin();
112  while (i != d_grid_maps.end()) {
113  (*i)->decref();
114  ++i;
115  }
116 }
117 
132 void FONcArray::convert(vector<string> embed,bool is_dap4_group)
133 {
134  FONcBaseType::convert(embed,is_dap4_group);
135 
136  //TOODOO: don't use _d_dim_ids when has_dap4_group.
137  _varname = FONcUtils::gen_name(embed, _varname, _orig_varname);
138 
139  BESDEBUG("fonc", "FONcArray::convert() - converting array " << _varname << endl);
140 
141  d_array_type = FONcUtils::get_nc_type(d_a->var(),isNetCDF4_ENHANCED());
142 
143 #if 0
144  if(d4_dim_ids.size() >0) {
145  BESDEBUG("fonc", "FONcArray::convert() - d4_dim_ids size is " << d4_dim_ids.size() << endl);
146 
147  }
148 #endif
149 
150  d_ndims = d_a->dimensions();
151  d_actual_ndims = d_ndims; //replace this with _a->dimensions(); below TODO
152  if (d_array_type == NC_CHAR) {
153  // if we have array of strings then we need to add the string length
154  // dimension, so add one more to ndims
155  d_ndims++;
156  }
157 
158  // See HYRAX-805. When assigning values using [], set the size using resize
159  // not reserve. THe reserve method works to optimize push_back(), but apparently
160  // does not work with []. jhrg 8/3/18
161  d_dim_ids.resize(d_ndims);
162  d_dim_sizes.resize(d_ndims);
163 
164  Array::Dim_iter di = d_a->dim_begin();
165  Array::Dim_iter de = d_a->dim_end();
166  int dimnum = 0;
167  for (; di != de; di++) {
168  int size = d_a->dimension_size(di, true);
169  d_dim_sizes[dimnum] = size;
170  d_nelements *= size;
171 
172  // Set COMPRESSION CHUNK SIZE for each dimension.
173  d_chunksizes.push_back(size <= MAX_CHUNK_SIZE ? size: MAX_CHUNK_SIZE);
174 
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);
177 
178  // If this dimension is a D4 dimension defined in its group, just obtain the dimension ID.
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);
182 
183  }
184  else {
185  // See if this dimension has already been defined. If it has the
186  // same name and same size as another dimension, then it is a
187  // shared dimension. Create it only once and share the FONcDim
188  int ds_num = FONcDim::DimNameNum+1;
189  while(find(d4_rbs_nums.begin(),d4_rbs_nums.end(),ds_num) != d4_rbs_nums.end()) {
190  // This may be an optimization for rare cases. May do this when performance issue hurts
191  //d4_rbs_nums_visited.push_back(ds_num);
192  ds_num++;
193  }
194  FONcDim::DimNameNum = ds_num-1;
195 
196  FONcDim *use_dim = find_dim(embed, d_a->dimension_name(di), size);
197  d_dims.push_back(use_dim);
198  }
199 
200  dimnum++;
201  }
202 
203  // if this array is a string array, then add the length dimension
204  if (d_array_type == NC_CHAR) {
205 
206  // get the data from the dap array
207  int array_length = d_a->length();
208 
209  d_str_data.reserve(array_length);
210  d_a->value(d_str_data);
211 
212  // determine the max length of the strings
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();
217  }
218  }
219  max_length++;
220  vector<string> empty_embed;
221  string lendim_name;
222  if(is_dap4_group == true) {
223  // Here is a quick implementation.
224  // We just append the DimNameNum(globally defined)
225  // and then increase the number by 1.
226  ostringstream dim_suffix_strm;
227  dim_suffix_strm <<"_len"<<FONcDim::DimNameNum +1;
228  FONcDim::DimNameNum++;
229  lendim_name = _varname+dim_suffix_strm.str();
230 
231  }
232  else
233  lendim_name = _varname + "_len";
234 
235 
236  FONcDim *use_dim = find_dim(empty_embed, lendim_name, max_length, true);
237  // Added static_cast to suppress warning. 12.27.2011 jhrg
238  if (use_dim->size() < static_cast<int>(max_length)) {
239  use_dim->update_size(max_length);
240  }
241 
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);
246 
247  // Adding this fixes the bug reported by GSFC where arrays of strings
248  // caused the handler to throw an error stating that 'Bad chunk sizes'
249  // were used. When the dimension of the string array was extended (because
250  // strings become char arrays in netcdf3/4), the numbers of dimensions
251  // in 'chunksizes' was not bumped up. The code below in convert() that
252  // set the chunk sizes then tried to access data that had never been set.
253  // jhrg 11/25/15
254  d_chunksizes.push_back(max_length <= MAX_CHUNK_SIZE ? max_length: MAX_CHUNK_SIZE);
255  }
256 
257  // If this array has a single dimension, and the name of the array
258  // and the name of that dimension are the same, then this array
259  // might be used as a map for a grid defined elsewhere.
260  //if(is_dap4_group ==false) {
261  if (!FONcGrid::InGrid && d_actual_ndims == 1 && d_a->name() == d_a->dimension_name(d_a->dim_begin())) {
262  // is it already in there?
263  FONcMap *map = FONcGrid::InMaps(d_a);
264  if (!map) {
265  // This memory is/was leaked. jhrg 8/28/13
266  FONcMap *new_map = new FONcMap(this);
267  d_grid_maps.push_back(new_map); // save it here so we can free it later. jhrg 8/28/13
268  FONcGrid::Maps.push_back(new_map);
269  }
270  else {
271  d_dont_use_it = true;
272  }
273  }
274  //}
275 
276  BESDEBUG("fonc", "FONcArray::convert() - done converting array " << _varname << endl);
277 }
278 
292 FONcDim *
293 FONcArray::find_dim(vector<string> &embed, const string &name, int size, bool ignore_size)
294 {
295  string oname;
296  string ename = FONcUtils::gen_name(embed, name, oname);
297  FONcDim *ret_dim = 0;
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)) {
302  if (ignore_size) {
303  ret_dim = (*i);
304  }
305  else if ((*i)->size() == size) {
306  ret_dim = (*i);
307  }
308  else {
309  if (embed.size() > 0) {
310  vector<string> tmp;
311  return find_dim(tmp, ename, size);
312  }
313  string err = "fileout_netcdf: dimension found with the same name, but different size";
314  throw BESInternalError(err, __FILE__, __LINE__);
315  }
316  }
317  }
318  if (!ret_dim) {
319  ret_dim = new FONcDim(name, size);
320  FONcArray::Dimensions.push_back(ret_dim);
321  }
322  else {
323  ret_dim->incref();
324  }
325  return ret_dim;
326 }
327 
342 void FONcArray::define(int ncid)
343 {
344  BESDEBUG("fonc", "FONcArray::define() - defining array '" << _varname << "'" << endl);
345 
346  if (!_defined && !d_dont_use_it) {
347 
348  BESDEBUG("fonc", "FONcArray::define() - defining array ' defined already" << _varname << "'" << endl);
349 #if 0
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());
354  fd->define(ncid);
355  d_dim_ids[d_ndims-1] = fd->dimid();
356 
357  }
358  else {
359 
360  }
361  }
362  }
363  else {
364 #endif
365  // If not defined DAP4 dimensions(mostly DAP2 or DAP4 no groups)
366  if(false == d4_def_dim) {
367  vector<FONcDim *>::iterator i = d_dims.begin();
368  vector<FONcDim *>::iterator e = d_dims.end();
369  int dimnum = 0;
370  for (; i != e; i++) {
371  FONcDim *fd = *i;
372  fd->define(ncid);
373  //d_dim_ids.at(dimnum) = fd->dimid();
374  d_dim_ids[dimnum] = fd->dimid();
375  BESDEBUG("fonc", "FONcArray::define() - dim_id: " << fd->dimid() << " size:" << fd->size() << endl);
376  dimnum++;
377  }
378  }
379  else {// Maybe some dimensions are not DAP4 dimensions, will still generate those dimensions.
380  int j = 0;
381  for(unsigned int i = 0; i< use_d4_dim_ids.size();i++) {
382  if(use_d4_dim_ids[i] == false) {
383  FONcDim *fd = d_dims[j];
384  fd->define(ncid);
385  d_dim_ids[i] = fd->dimid();
386  j++;
387  }
388  }
389  }
390 
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;
394  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
395  }
396 
397  if (isNetCDF4()) {
398  BESDEBUG("fonc", "FONcArray::define() Working netcdf-4 branch " << endl);
399  if (FONcRequestHandler::chunk_size == 0)
400  // I have no idea if chunksizes is needed in this case.
401  stax = nc_def_var_chunking(ncid, _varid, NC_CONTIGUOUS, &d_chunksizes[0]);
402  else
403  stax = nc_def_var_chunking(ncid, _varid, NC_CHUNKED, &d_chunksizes[0]);
404 
405  if (stax != NC_NOERR) {
406  string err = "fileout.netcdf - Failed to define chunking for variable " + _varname;
407  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
408  }
409 
410  // TODO Make this more adaptable to the Array's data type. Find out when it's
411  // best to use shuffle, et c. jhrg 7/22/18
412  if (FONcRequestHandler::use_compression) {
413  int shuffle = 0;
414  int deflate = 1;
415  int deflate_level = 4;
416  stax = nc_def_var_deflate(ncid, _varid, shuffle, deflate, deflate_level);
417 
418  if (stax != NC_NOERR) {
419  string err = (string) "fileout.netcdf - Failed to define compression (deflate) level for variable "
420  + _varname;
421  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
422  }
423  }
424  }
425 
426  // If the array type is NC_SHORT it may have been an unsigned byte type before,
427  // so make sure the _FillValue is also 16 bits (SMAP NetCDF-3 reformatting issue
428  // for landcover_class).
429  //
430  // Contributed by abdul.g.khan@nasa.gov
431  //
432  // Question: Are there other cases where an unsigned type is 'promoted' and thus
433  // the type of the fill value attribute should be too? jhrg 10/12/15
434  // TODO: The following code is a hack. We may need to review all cases and re-implement it. KY 12/4/2020
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);
441  }
442  break;
443  }
444  }
445  }
446 
447  BESDEBUG("fonc", "FONcArray::define() - Adding attributes " << endl);
448  FONcAttributes::add_variable_attributes(ncid, _varid, d_a,isNetCDF4_ENHANCED(),is_dap4);
449  FONcAttributes::add_original_name(ncid, _varid, _varname, _orig_varname);
450  _defined = true;
451  }
452  else {
453  if (_defined) {
454  BESDEBUG("fonc", "FONcArray::define() - variable " << _varname << " is already defined" << endl);
455  }
456  if (d_dont_use_it) {
457  BESDEBUG("fonc", "FONcArray::define() - variable " << _varname << " is not being used" << endl);
458  }
459  }
460 
461  BESDEBUG("fonc", "FONcArray::define() - done defining array '" << _varname << "'" << endl);
462 }
463 
473 void FONcArray::write(int ncid)
474 {
475  BESDEBUG("fonc", "FONcArray::write() BEGIN var: " << _varname << "[" << d_nelements << "]" << endl);
476 
477  if (d_dont_use_it) {
478  BESDEBUG("fonc", "FONcTransform::write not using variable " << _varname << endl);
479  return;
480  }
481 
482  ncopts = NC_VERBOSE;
483  int stax = NC_NOERR;
484 
485  if (d_array_type != NC_CHAR) {
486 
487  // If we support the netCDF-4 enhanced model, the unsigned integer
488  // can be directly mapped to the netcdf-4 unsigned integer.
489  if(isNetCDF4_ENHANCED())
490  write_for_nc4_types(ncid);
491  else {
492  string var_type = d_a->var()->type_name();
493 
494  // create array to hold data hyperslab
495  switch (d_array_type) {
496  case NC_BYTE: {
497  unsigned char *data = new unsigned char[d_nelements];
498  d_a->buf2val((void**) &data);
499  stax = nc_put_var_uchar(ncid, _varid, data);
500  delete[] data;
501 
502  if (stax != NC_NOERR) {
503  string err = "fileout.netcdf - Failed to create array of bytes for " + _varname;
504  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
505  }
506  break;
507  }
508 
509  case NC_SHORT: {
510  short *data = new short[d_nelements];
511 
512  // Given Byte/UInt8 will always be unsigned they must map
513  // to a NetCDF type that will support unsigned bytes. This
514  // detects the original variable was of type Byte and typecasts
515  // each data value to a short.
516  if (var_type == "Byte") {
517 
518  unsigned char *orig_data = new unsigned char[d_nelements];
519  d_a->buf2val((void**) &orig_data);
520 
521  for (int d_i = 0; d_i < d_nelements; d_i++)
522  data[d_i] = orig_data[d_i];
523 
524  delete[] orig_data;
525  }
526  else {
527  d_a->buf2val((void**) &data);
528  }
529  int stax = nc_put_var_short(ncid, _varid, data);
530  delete[] data;
531 
532  if (stax != NC_NOERR) {
533  string err = (string) "fileout.netcdf - Failed to create array of shorts for " + _varname;
534  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
535  }
536  break;
537  }
538 
539  case NC_INT: {
540  // Added as a stop-gap measure to alert SAs and inform users of a misconfigured server.
541  // jhrg 6/15/20
542  if (var_type == "Int64" || var_type == "UInt64" ) {
543  // We should not be here. The server configuration is wrong since the netcdf classic
544  // model is being used (either a netCDf3 response is requested OR a netCDF4 with the
545  // classic model. Tell the user and the SA.
546  string msg;
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.";
550  }
551  else {
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.";
555  }
556  throw BESInternalError(msg, __FILE__, __LINE__);
557  }
558 
559  int *data = new int[d_nelements];
560  // Since UInt16 also maps to NC_INT, we need to obtain the data correctly
561  // KY 2012-10-25
562  if (var_type == "UInt16") {
563  unsigned short *orig_data = new unsigned short[d_nelements];
564  d_a->buf2val((void**) &orig_data);
565 
566  for (int d_i = 0; d_i < d_nelements; d_i++)
567  data[d_i] = orig_data[d_i];
568 
569  delete[] orig_data;
570  }
571  else {
572  d_a->buf2val((void**) &data);
573  }
574 
575  int stax = nc_put_var_int(ncid, _varid, data);
576  delete[] data;
577 
578  if (stax != NC_NOERR) {
579  string err = (string) "fileout.netcdf - Failed to create array of ints for " + _varname;
580  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
581  }
582  break;
583  }
584 
585  case NC_FLOAT: {
586  float *data = new float[d_nelements];
587  d_a->buf2val((void**) &data);
588  int stax = nc_put_var_float(ncid, _varid, data);
589  delete[] data;
590 
591  if (stax != NC_NOERR) {
592  string err = (string) "fileout.netcdf - Failed to create array of floats for " + _varname;
593  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
594  }
595  break;
596  }
597 
598  case NC_DOUBLE: {
599  double *data = new double[d_nelements];
600  d_a->buf2val((void**) &data);
601  int stax = nc_put_var_double(ncid, _varid, data);
602  delete[] data;
603 
604  if (stax != NC_NOERR) {
605  string err = (string) "fileout.netcdf - Failed to create array of doubles for " + _varname;
606  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
607  }
608  break;
609  }
610  // TODO: should add other DAP4 types: NC_UINT...
611  }
612  }
613  }
614  else {
615  // special case for string data. Could have put this in the
616  // switch, but it's pretty big
617  size_t var_count[d_ndims];
618  size_t var_start[d_ndims];
619  int dim = 0;
620  for (dim = 0; dim < d_ndims; dim++) {
621  // the count for each of the dimensions will always be 1 except
622  // for the string length dimension
623  var_count[dim] = 1;
624 
625  // the start for each of the dimensions will start at 0. We will
626  // bump this up in the while loop below
627  var_start[dim] = 0;
628  }
629 
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;
633 
634  // write out the string
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;
638  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
639  }
640 
641  // bump up the start.
642  if (element + 1 < d_nelements) {
643  bool done = false;
644  dim = d_ndims - 2;
645  while (!done) {
646  var_start[dim] = var_start[dim] + 1;
647  if (var_start[dim] == d_dim_sizes[dim]) {
648  var_start[dim] = 0;
649  dim--;
650  }
651  else {
652  done = true;
653  }
654  }
655  }
656  }
657  }
658 
659  BESDEBUG("fonc", "FONcArray::write() END var: " << _varname << "[" << d_nelements << "]" << endl);
660 }
661 
667 {
668  return d_a->name();
669 }
670 
679 void FONcArray::dump(ostream &strm) const
680 {
681  strm << BESIndent::LMarg << "FONcArray::dump - (" << (void *) this << ")" << endl;
682  BESIndent::Indent();
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;
687  if (d_dims.size()) {
688  strm << BESIndent::LMarg << "dimensions:" << endl;
689  BESIndent::Indent();
690  vector<FONcDim *>::const_iterator i = d_dims.begin();
691  vector<FONcDim *>::const_iterator e = d_dims.end();
692  for (; i != e; i++) {
693  (*i)->dump(strm);
694  }
695  BESIndent::UnIndent();
696  }
697  else {
698  strm << BESIndent::LMarg << "dimensions: none" << endl;
699  }
700  BESIndent::UnIndent();
701 }
702 
713 void FONcArray::write_for_nc4_types(int ncid) {
714 
715  int stax = NC_NOERR;
716 
717  // create array to hold data hyperslab
718  // DAP2 only supports unsigned BYTE. So here
719  // we don't inlcude NC_BYTE (the signed BYTE, the same
720  // as 64-bit integer). KY 2020-03-20
721  // Actually 64-bit integer is supported.
722  switch (d_array_type) {
723  case NC_BYTE: {
724  signed char *data = new signed char[d_nelements];
725  d_a->buf2val((void**) &data);
726  stax = nc_put_var_schar(ncid, _varid, data);
727  delete[] data;
728 
729  if (stax != NC_NOERR) {
730  string err = "fileout.netcdf - Failed to create array of bytes for " + _varname;
731  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
732  }
733  break;
734  }
735 
736  case NC_UBYTE: {
737  unsigned char *data = new unsigned char[d_nelements];
738  d_a->buf2val((void**) &data);
739  stax = nc_put_var_uchar(ncid, _varid, data);
740  delete[] data;
741 
742  if (stax != NC_NOERR) {
743  string err = "fileout.netcdf - Failed to create array of bytes for " + _varname;
744  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
745  }
746  break;
747  }
748 
749  case NC_SHORT: {
750 
751  short *data = new short[d_nelements];
752  d_a->buf2val((void**) &data);
753  int stax = nc_put_var_short(ncid, _varid, data);
754  delete[] data;
755 
756  if (stax != NC_NOERR) {
757  string err = (string) "fileout.netcdf - Failed to create array of shorts for " + _varname;
758  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
759  }
760  break;
761  }
762 
763  case NC_INT: {
764 
765  int *data = new int[d_nelements];
766  d_a->buf2val((void**) &data);
767 
768  int stax = nc_put_var_int(ncid, _varid, data);
769  delete[] data;
770 
771  if (stax != NC_NOERR) {
772  string err = (string) "fileout.netcdf - Failed to create array of ints for " + _varname;
773  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
774  }
775  break;
776  }
777 
778  case NC_INT64: {
779 
780  int64_t *data = new int64_t[d_nelements];
781  d_a->buf2val((void**) &data);
782 
783  int stax = nc_put_var_longlong(ncid, _varid, (const long long*)data);
784  delete[] data;
785 
786  if (stax != NC_NOERR) {
787  string err = (string) "fileout.netcdf - Failed to create array of ints for " + _varname;
788  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
789  }
790  break;
791  }
792 
793  case NC_FLOAT: {
794  float *data = new float[d_nelements];
795  d_a->buf2val((void**) &data);
796  int stax = nc_put_var_float(ncid, _varid, data);
797  delete[] data;
798 
799  if (stax != NC_NOERR) {
800  string err = (string) "fileout.netcdf - Failed to create array of floats for " + _varname;
801  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
802  }
803  break;
804  }
805 
806  case NC_DOUBLE: {
807  double *data = new double[d_nelements];
808  d_a->buf2val((void**) &data);
809  int stax = nc_put_var_double(ncid, _varid, data);
810  delete[] data;
811 
812  if (stax != NC_NOERR) {
813  string err = (string) "fileout.netcdf - Failed to create array of doubles for " + _varname;
814  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
815  }
816  break;
817  }
818 
819  case NC_USHORT: {
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);
823  delete[] data;
824 
825  if (stax != NC_NOERR) {
826  string err = (string) "fileout.netcdf - Failed to create array of unsigned short for " + _varname;
827  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
828  }
829  break;
830  }
831 
832  case NC_UINT: {
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);
836  delete[] data;
837 
838  if (stax != NC_NOERR) {
839  string err = (string) "fileout.netcdf - Failed to create array of unsigned int for " + _varname;
840  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
841  }
842  break;
843  }
844 
845  case NC_UINT64: {
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);
849  delete[] data;
850 
851  if (stax != NC_NOERR) {
852  string err = (string) "fileout.netcdf - Failed to create array of unsigned int for " + _varname;
853  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
854  }
855  break;
856  }
857 
858  default:
859  string err = (string) "Failed to transform array of unknown type in file out netcdf";
860  throw BESInternalError(err, __FILE__, __LINE__);
861  }
862 
863 }
864 
865 // This function is only used for handling _FillValue. TODO: review all cases and generalize it.
866 libdap::AttrType FONcArray::getAttrType(nc_type nct) {
867  switch (nct)
868  {
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;
874  case NC_CHAR:
875  case NC_STRING: return Attr_string;
876  default: return Attr_unknown;
877  }
878 }
exception thrown if internal error encountered
virtual void define(int ncid)
define the DAP Array in the netcdf file
Definition: FONcArray.cc:342
virtual void convert(std::vector< std::string > embed, bool is_dap4_group=false)
Converts the DAP Array to a FONcArray.
Definition: FONcArray.cc:132
virtual std::string name()
returns the name of the DAP Array
Definition: FONcArray.cc:666
virtual void dump(std::ostream &strm) const
dumps information about this object for debugging purposes
Definition: FONcArray.cc:679
virtual ~FONcArray()
Destructor that cleans up the array.
Definition: FONcArray.cc:101
virtual void write(int ncid)
Write the array out to the netcdf file.
Definition: FONcArray.cc:473
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.
Definition: FONcBaseType.h:61
virtual bool isNetCDF4()
Returns true if NetCDF4 features will be required.
A class that represents the dimension of an array.
Definition: FONcDim.h:45
virtual void define(int ncid)
define the DAP dimension in the netcdf file
Definition: FONcDim.cc:79
static vector< FONcMap * > Maps
global list of maps that could be shared amongst the different grids
Definition: FONcGrid.h:74
static bool InGrid
tells whether we are converting or defining a grid.
Definition: FONcGrid.h:76
A map of a DAP Grid with file out netcdf information included.
Definition: FONcMap.h:52
static void handle_error(int stax, const string &err, const string &file, int line)
handle any netcdf errors
Definition: FONcUtils.cc:399
static nc_type get_nc_type(BaseType *element, bool isNC4_ENHANCED)
translate the OPeNDAP data type to a netcdf data type
Definition: FONcUtils.cc:112
static string gen_name(const vector< string > &embed, const string &name, string &original)
generate a new name for the embedded variable
Definition: FONcUtils.cc:189