27#include <BESInternalError.h>
29#include <libdap/Array.h>
30#include <libdap/Structure.h>
31#include <libdap/Byte.h>
32#include <libdap/Int8.h>
33#include <libdap/Int16.h>
34#include <libdap/Int32.h>
35#include <libdap/Int64.h>
36#include <libdap/UInt16.h>
37#include <libdap/UInt32.h>
38#include <libdap/UInt64.h>
39#include <libdap/Float32.h>
40#include <libdap/Float64.h>
41#include <libdap/Str.h>
42#include <libdap/util.h>
46#include "FONcArrayStructureField.h"
49#include "FONcAttributes.h"
67 Type b_data_type = b->type();
68 Type supported_atomic_data_type = b_data_type;
69 if(b_data_type == libdap::dods_array_c)
70 supported_atomic_data_type = b->var()->type();
72 if (!is_simple_type(supported_atomic_data_type)
73 || supported_atomic_data_type == dods_url_c
74 || supported_atomic_data_type == dods_enum_c || supported_atomic_data_type ==dods_opaque_c) {
75 string s =
"File out netcdf, only support one-layer of simple int/float fields inside an array of structure.";
80 if (supported_atomic_data_type == dods_str_c)
81 handle_structure_string_field(b);
83 d_varname = b->name();
84 if (b_data_type == libdap::dods_array_c) {
86 auto t_b =
dynamic_cast<Array *
>(b);
87 d_array_type_size = (t_b->width_ll()) / (t_b->length_ll());
90 d_array_type_size = (b->width_ll()) / (b->length_ll());
94 Array::Dim_iter di = d_a->dim_begin();
95 Array::Dim_iter de = d_a->dim_end();
96 for (; di != de; di++) {
97 int64_t size = d_a->dimension_size_ll(di,
true);
98 struct_dim_sizes.push_back(size);
99 total_nelements *= size;
100 FONcDim *use_dim = find_sdim(d_a->dimension_name(di), size);
101 struct_dims.push_back(use_dim);
103 if (b_data_type == libdap::dods_array_c) {
104 auto db_a =
dynamic_cast<Array *
>(b);
106 string s =
"File out netcdf, FONcArrayStructField was passed a variable that is not a DAP Array";
109 Array::Dim_iter b_di = db_a->dim_begin();
110 Array::Dim_iter b_de = db_a->dim_end();
111 for (; b_di != b_de; b_di++) {
112 int64_t size = d_a->dimension_size_ll(b_di,
true);
113 struct_dim_sizes.push_back(size);
114 total_nelements *= size;
115 field_nelements *= size;
116 FONcDim *use_dim = find_sdim(db_a->dimension_name(b_di), size);
117 struct_dims.push_back(use_dim);
125FONcArrayStructureField::obtain_maximum_string_length( ){
127 size_t asf_max_str_len = 0;
131 for (
unsigned i= 0; i<d_a->length_ll();i++) {
132 BaseType *cb = compound_buf[i];
133 if (cb->type()!=libdap::dods_structure_c){
134 throw BESInternalError(
"Fileout netcdf: This is not array of structure", __FILE__, __LINE__);
136 auto structure_elem =
dynamic_cast<Structure *
>(cb);
138 throw BESInternalError(
"Fileout netcdf: This is not array of structure", __FILE__, __LINE__);
140 for (
auto &bt:structure_elem->variables()) {
144 if (bt->name() == d_varname) {
145 if (bt->type() == libdap::dods_array_c) {
146 auto memb_array =
dynamic_cast<Array *
>(bt);
148 throw BESInternalError(
"Fileout netcdf: This structure member is not an array", __FILE__, __LINE__);
149 for (int64_t ma_i = 0; ma_i < memb_array->length_ll(); ma_i++) {
150 if (memb_array->get_str()[ma_i].size() > asf_max_str_len) {
151 asf_max_str_len = memb_array->get_str()[ma_i].size();
156 auto memb_str =
dynamic_cast<Str *
>(bt);
157 if ((
size_t)(memb_str->length_ll())>asf_max_str_len)
158 asf_max_str_len = memb_str->length_ll();
166 return asf_max_str_len;
170FONcArrayStructureField::handle_structure_string_field(BaseType *b){
172 d_varname = b->name();
173 d_array_type = NC_CHAR;
175 BESDEBUG(
"fonc",
"d_varname is: "<<d_varname <<endl);
178 Array::Dim_iter di = d_a->dim_begin();
179 Array::Dim_iter de = d_a->dim_end();
180 for (; di != de; di++) {
181 int64_t size = d_a->dimension_size_ll(di,
true);
182 struct_dim_sizes.push_back(size);
183 total_nelements *= size;
184 FONcDim *use_dim = find_sdim(d_a->dimension_name(di), size);
185 struct_dims.push_back(use_dim);
189 if (b->type() == libdap::dods_array_c) {
190 auto db_a =
dynamic_cast<Array *
>(b);
192 string s =
"File out netcdf, FONcArrayStructField was passed a variable that is not a DAP Array";
193 throw BESInternalError(s, __FILE__, __LINE__);
195 Array::Dim_iter b_di = db_a->dim_begin();
196 Array::Dim_iter b_de = db_a->dim_end();
197 for (; b_di != b_de; b_di++) {
198 int64_t size = d_a->dimension_size_ll(b_di,
true);
199 struct_dim_sizes.push_back(size);
200 total_nelements *= size;
201 field_nelements *= size;
202 FONcDim *use_dim = find_sdim(db_a->dimension_name(b_di), size);
203 struct_dims.push_back(use_dim);
206 size_t max_length = obtain_maximum_string_length();
207 struct_dim_sizes.push_back(max_length);
208 string last_dim_name = d_a->name()+
"_"+b->name() +
"_len";
209 FONcDim *use_dim = find_sdim(last_dim_name,max_length);
210 struct_dims.push_back(use_dim);
214FONcArrayStructureField::~FONcArrayStructureField() {
216 for (
auto &dim: struct_dims) {
217 dim->struct_decref();
222void FONcArrayStructureField::convert(
vector<string> embed,
bool _dap4,
bool is_dap4_group){
235 BESDEBUG(
"fonc",
"FONcArray::define() - defining array '" << d_varname <<
"'" << endl);
239 BESDEBUG(
"fonc",
"FONcArray::define() - defining array of structure field: " << d_varname <<
"'" << endl);
240 auto i = struct_dims.begin();
241 auto e = struct_dims.end();
242 for (; i != e; i++) {
244 fd->define_struct(ncid);
245 d_dim_ids.push_back(fd->dimid());
246 BESDEBUG(
"fonc",
"FONcArray::define() - dim_id: " << fd->dimid() <<
" size:" << fd->size() << endl);
249 int stax = nc_def_var(ncid, var_name.c_str(), d_array_type, (
int)(struct_dims.size()), d_dim_ids.data(), &d_varid);
250 if (stax != NC_NOERR) {
251 string err = (
string)
"fileout.netcdf - Failed to define variable " + d_varname;
255 stax = nc_def_var_fill(ncid, d_varid, NC_NOFILL,
nullptr );
256 if (stax != NC_NOERR) {
257 string err = (
string)
"fileout.netcdf - " +
"Failed to clear fill value for " + d_varname;
273 BESDEBUG(
"fonc",
"FONcArrayStructureField::write for var " << d_varname << endl ) ;
275 if (d_array_type == NC_CHAR) {
283 data_buf.resize(total_nelements*d_array_type_size);
284 char* data_buf_ptr = data_buf.data();
288 for (
unsigned i= 0; i<d_a->length_ll();i++) {
289 BaseType *cb = compound_buf[i];
290 if (cb->type()!=libdap::dods_structure_c){
291 throw BESInternalError(
"Fileout netcdf: This is not array of structure", __FILE__, __LINE__);
293 auto structure_elem =
dynamic_cast<Structure *
>(cb);
295 throw BESInternalError(
"Fileout netcdf: This is not array of structure", __FILE__, __LINE__);
297 for (
auto &bt:structure_elem->variables()) {
301 if (bt->name() == d_varname) {
302 if (bt->type() == libdap::dods_array_c) {
303 auto memb_array =
dynamic_cast<Array *
>(bt);
305 throw BESInternalError(
"Fileout netcdf: This structure member is not an array", __FILE__, __LINE__);
306 const char *buf = memb_array->get_buf();
307 size_t memb_array_size = memb_array->width_ll();
310 memcpy(data_buf_ptr, buf, memb_array_size);
311 BESDEBUG(
"fonc",
"memb_array_length is "<<memb_array->length_ll()<<endl);
312 BESDEBUG(
"fonc",
"memb_array_type is "<<memb_array->width_ll()<<endl);
313 BESDEBUG(
"fonc",
"memb_array_size is "<<memb_array_size<<endl);
314 data_buf_ptr +=memb_array_size;
317 obtain_scalar_data(data_buf_ptr,bt);
318 data_buf_ptr += d_array_type_size;
324 int stax = nc_put_var(ncid, d_varid, (
void*)data_buf.data());
325 if (stax != NC_NOERR) {
326 string err =
"fileout.netcdf - cannot write the array of structure members " + d_varname;
331void FONcArrayStructureField::obtain_scalar_data(
char *data_buf_ptr, BaseType *b)
const{
337 auto byte_var =
dynamic_cast<Byte *
>(b);
338 uint8_t byte_value = byte_var->value();
339 memcpy(data_buf_ptr,(
void*)&byte_value,d_array_type_size);
343 auto int8_var =
dynamic_cast<Int8 *
>(b);
344 int8_t int8_value = int8_var->value();
345 memcpy(data_buf_ptr,(
void*)&int8_value,d_array_type_size);
349 case dods_uint16_c: {
350 auto uint16_var =
dynamic_cast<UInt16 *
>(b);
351 uint16_t uint16_value = uint16_var->value();
352 memcpy(data_buf_ptr,(
void*)&uint16_value,d_array_type_size);
356 auto int16_var =
dynamic_cast<Int16 *
>(b);
357 int16_t int16_value = int16_var->value();
358 memcpy(data_buf_ptr, (
void *) &int16_value, d_array_type_size);
361 case dods_uint32_c: {
362 auto uint32_var =
dynamic_cast<UInt32 *
>(b);
363 uint32_t uint32_value = uint32_var->value();
364 memcpy(data_buf_ptr,(
void*)&uint32_value,d_array_type_size);
368 auto int32_var =
dynamic_cast<Int32 *
>(b);
369 int32_t int32_value = int32_var->value();
370 memcpy(data_buf_ptr, (
void *) &int32_value, d_array_type_size);
373 case dods_uint64_c: {
374 auto uint64_var =
dynamic_cast<UInt64 *
>(b);
375 uint64_t uint64_value = uint64_var->value();
376 memcpy(data_buf_ptr,(
void*)&uint64_value,d_array_type_size);
380 auto int64_var =
dynamic_cast<Int64 *
>(b);
381 int64_t int64_value = int64_var->value();
382 memcpy(data_buf_ptr,(
void*)&int64_value,d_array_type_size);
385 case dods_float32_c: {
386 auto float32_var =
dynamic_cast<Float32 *
>(b);
387 float float32_value = float32_var->value();
388 memcpy(data_buf_ptr,(
void*)&float32_value,d_array_type_size);
391 case dods_float64_c: {
392 auto float64_var =
dynamic_cast<Float64 *
>(b);
393 double float64_value = float64_var->value();
394 memcpy(data_buf_ptr,(
void*)&float64_value,d_array_type_size);
398 string err =
"file out netcdf structure array: Only support int/float types";
399 throw BESInternalError(err, __FILE__, __LINE__);
406void FONcArrayStructureField::write_str(
int ncid){
408 size_t d_ndims = struct_dims.size();
409 vector<size_t> var_count(d_ndims);
410 vector<size_t> var_start(d_ndims);
413 for (dim = 0; dim < d_ndims; dim++) {
426 vector<BaseType*> compound_buf = d_a->get_compound_buf();
428 for (
unsigned i= 0; i<d_a->length_ll();i++) {
429 BaseType *cb = compound_buf[i];
430 if (cb->type()!=libdap::dods_structure_c){
431 throw BESInternalError(
"Fileout netcdf: This is not array of structure", __FILE__, __LINE__);
433 auto structure_elem =
dynamic_cast<Structure *
>(cb);
435 throw BESInternalError(
"Fileout netcdf: Dynamic cast failed. This is not array of structure", __FILE__, __LINE__);
437 for (
auto &bt:structure_elem->variables()) {
440 if (bt->name() == d_varname) {
441 if (bt->type() == libdap::dods_array_c) {
442 auto memb_array =
dynamic_cast<Array *
>(bt);
444 throw BESInternalError(
"Fileout netcdf: This structure member is not an array", __FILE__, __LINE__);
445 auto const &m_a_str = memb_array->get_str();
447 for (int64_t element = 0; element < field_nelements; element++) {
448 var_count[d_ndims -1] = m_a_str[element].size() +1;
449 var_start[d_ndims - 1] = 0;
452 int stax = nc_put_vara_text(ncid, d_varid, var_start.data(), var_count.data(),
453 m_a_str[element].c_str());
455 if (stax != NC_NOERR) {
456 string err = (string)
"fileout.netcdf - Failed to create array of strings in a DAP4 structure for " + d_varname ;
465 var_start[dim] = var_start[dim] + 1;
466 if (var_start[dim] == struct_dim_sizes[dim]) {
478 auto memb_type=
dynamic_cast<Str *
>(bt);
480 throw BESInternalError(
"Fileout netcdf: This structure member is not a string", __FILE__, __LINE__);
481 auto const & str_value = memb_type->value();
482 var_count[d_ndims -1] = str_value.size() +1;
483 var_start[d_ndims - 1] = 0;
486 int stax = nc_put_vara_text(ncid, d_varid, var_start.data(), var_count.data(),
489 if (stax != NC_NOERR) {
490 string err = (string)
"fileout.netcdf - Failed to create array of strings for " + d_varname;
495 if (i + 1 < d_a->length_ll()) {
499 var_start[dim] = var_start[dim] + 1;
500 if (var_start[dim] == struct_dim_sizes[dim]) {
540FONcArrayStructureField::find_sdim(
const string &name, int64_t size) {
545 for (; i != e && !ret_dim; i++) {
546 if (!((*i)->name().empty()) && ((*i)->name() ==
name)) {
547 if ((*i)->size() == size) {
551 string err =
"fileout_netcdf: dimension found with the same name, but different size";
552 throw BESInternalError(err, __FILE__, __LINE__);
558 ret_dim =
new FONcDim(
name, size);
559 FONcArrayStructureField::SDimensions.push_back(ret_dim);
562 ret_dim->struct_incref();
577 strm << BESIndent::LMarg <<
"FONcArrayStructureField::dump - ("
578 << (
void *)
this <<
")" << endl ;
579 BESIndent::Indent() ;
580 strm << BESIndent::LMarg <<
"memb name = " << var_name << endl ;
581 for (
const auto& sdim:struct_dims)
583 BESIndent::UnIndent() ;
exception thrown if internal error encountered
FONcArrayStructureField(libdap::BaseType *b, libdap::Array *a, bool is_netCDF4_enhanced)
Constructor for FONcArrayStructureField.
void dump(std::ostream &strm) const override
dumps information about this object for debugging purposes
std::string name() override
returns the name of the array structure field
nc_type type() override
returns the netcdf type of the DAP object
void write(int ncid) override
Write the netcdf variable data out to the netcdf file.
void define(int ncid) override
define the DAP array of structure field in the netcdf file
A class that represents the dimension of an array.
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