40#include <libdap/DDS.h>
41#include <libdap/DMR.h>
42#include <libdap/D4Group.h>
43#include <libdap/D4Attributes.h>
44#include <libdap/Structure.h>
45#include <libdap/Array.h>
46#include <libdap/Grid.h>
47#include <libdap/Sequence.h>
49#include <BESResponseObject.h>
50#include <BESDapResponseBuilder.h>
51#include <BESDataHandlerInterface.h>
54#include <BESDapNames.h>
55#include <BESDataNames.h>
56#include <BESDataDDSResponse.h>
57#include <BESDMRResponse.h>
58#include <BESRequestHandlerList.h>
59#include <BESDapFunctionResponseCache.h>
61#include <BESInternalError.h>
62#include <BESInternalFatalError.h>
63#include "BESSyntaxUserError.h"
64#include "RequestServiceTimer.h"
66#include "DapFunctionUtils.h"
69#include "FONcRequestHandler.h"
71#include "FONcTransform.h"
73#include "FONcBaseType.h"
74#include "FONcAttributes.h"
75#include "FONcTransmitter.h"
76#include "history_utils.h"
83#define prolog std::string("FONcTransform::").append(__func__).append("() - ")
85#define FOUR_GB_IN_KB (4294967296/1024)
86#define TWO_GB_IN_KB (2147483648/1024)
87#define MSG_LABEL_CLASSIC_MODEL " (classic model)"
88#define MSG_LABEL_SIXTYFOUR_BIT_MODEL " (64-bit offset model)"
101 const string &ncVersion)
102 : d_obj(obj), d_dhi(dhi), _localfile(localfile), _returnAs(ncVersion) {
104 throw BESInternalError(
"File out netcdf, null BESResponseObject passed to constructor", __FILE__, __LINE__);
106 if (_localfile.empty()) {
107 throw BESInternalError(
"File out netcdf, empty local file name passed to constructor", __FILE__, __LINE__);
118 FONcUtils::name_prefix = dhi->container->get_container_type() +
"_";
121 FONcUtils::name_prefix =
"nc_";
130 for (
auto &b: _fonc_vars) {
133 for (
auto &b: _total_fonc_vars_in_grp) {
150string FONcTransform::too_big_error_msg(
151 const unsigned dap_version,
152 const string &return_encoding,
153 const unsigned long long dap2_response_size_kb,
154 const unsigned long long contextual_max_response_size_kb,
160 msg <<
"Your request was for a (DAP"<< dap_version <<
" data model response) to be encoded as ";
161 msg << return_encoding <<
". ";
162 msg <<
"The response to your specific request will produce a " << dap2_response_size_kb;
163 msg <<
" kilobyte response. On this server the response size for your request is limited to ";
164 msg << contextual_max_response_size_kb <<
" kilobytes. ";
166 msg <<
"The server is configured to allow ";
167 auto conf_max_request_size_kb =FONcRequestHandler::get_request_max_size_kb();
168 if(conf_max_request_size_kb==0){
169 msg <<
" responses of unlimited size. ";
172 msg <<
"responses as large as: " << conf_max_request_size_kb <<
" kilobytes. ";
175 if (FONcTransform::_returnAs == FONC_RETURN_AS_NETCDF3) {
176 msg <<
"Additionally, the requested response encoding " << return_encoding <<
" is structurally limited to ";
177 if (FONcRequestHandler::nc3_classic_format) {
178 msg << TWO_GB_IN_KB <<
" kilobytes" << MSG_LABEL_CLASSIC_MODEL <<
".";
181 msg << FOUR_GB_IN_KB <<
" kilobytes" << MSG_LABEL_SIXTYFOUR_BIT_MODEL <<
".";
183 msg <<
"One thing to try would be to reissue the the request, but change the requested response encoding ";
184 msg <<
"to NetCDF-4. This can be accomplished with the buttons in the Data Request Form, or by modifying ";
185 msg <<
"the request URL by changing the terminal path suffix from \".nc\" to \".nc4\". ";
189 msg <<
"I've noticed that no constraint expression accompanied your request. ";
191 msg <<
"Your request employed the constraint expression: \"" << ce <<
"\" ";
193 msg <<
"You may also reduce the size of the request by choosing just the variable(s) you need and/or by ";
194 msg <<
"using the DAP index based array sub-setting syntax to additionally limit the amount of data requested.";
208void FONcTransform::set_max_size_and_encoding(
unsigned long long &max_request_size_kb,
string &return_encoding){
210 return_encoding.clear();
218 if (FONcTransform::_returnAs == FONC_RETURN_AS_NETCDF3) {
219 return_encoding = string(FONC_RETURN_AS_NETCDF3).append(
"-3 ");
220 if (FONcRequestHandler::nc3_classic_format) {
221 return_encoding += MSG_LABEL_CLASSIC_MODEL;
222 if (max_request_size_kb == 0 || max_request_size_kb >= TWO_GB_IN_KB) {
223 max_request_size_kb = TWO_GB_IN_KB - 1 ;
224 BESDEBUG(MODULE, prolog <<
"Configured max request size was incompatible with NetCDF-3 classic format. " <<
225 "Reset to: " << max_request_size_kb << endl);
229 return_encoding += MSG_LABEL_SIXTYFOUR_BIT_MODEL;
230 if (max_request_size_kb == 0 || max_request_size_kb >= FOUR_GB_IN_KB) {
231 max_request_size_kb = FOUR_GB_IN_KB - 1 ;
232 BESDEBUG(MODULE, prolog <<
"Configured max request size was incompatible with NetCDF-3 w/64-bit offset format. " <<
233 "Reset to: " << max_request_size_kb << endl);
238 return_encoding = FONC_RETURN_AS_NETCDF4;
239 if (FONcRequestHandler::nc3_classic_format) {
240 return_encoding += MSG_LABEL_CLASSIC_MODEL;
243 BESDEBUG(MODULE, prolog <<
"return_encoding: " << return_encoding << endl);
244 BESDEBUG(MODULE, prolog <<
"max_request_size_kb: " << max_request_size_kb << endl);
254void FONcTransform::throw_if_dap2_response_too_big(DDS *dds,
const string &dap2_ce)
256 string return_encoding;
258 unsigned long long max_response_size_kb = FONcRequestHandler::get_request_max_size_kb();
259 BESDEBUG(MODULE, prolog <<
"Configured max_request_size_kb: " << max_response_size_kb << endl);
261 unsigned long long dap2_response_size_kb = dds->get_request_size_kb(
true);
262 BESDEBUG(MODULE, prolog <<
"dds->get_request_size_kb(): " << dap2_response_size_kb << endl);
264 set_max_size_and_encoding(max_response_size_kb, return_encoding);
267 dds->set_response_limit_kb(max_response_size_kb);
269 if (dds->too_big()) {
270 string err_msg = too_big_error_msg(2,return_encoding,dap2_response_size_kb, max_response_size_kb, dap2_ce);
271 throw BESSyntaxUserError(err_msg,__FILE__,__LINE__);
285 BESDEBUG(MODULE, prolog <<
"BEGIN" << endl);
286 BESDEBUG(MODULE, prolog <<
"Reading data into DataDDS" << endl);
290 d_dhi->first_container();
293 if (!bdds)
throw BESInternalFatalError(
"Expected a BESDataDDSResponse instance", __FILE__, __LINE__);
295 _dds = bdds->get_dds();
300 besDRB.
set_ce(d_dhi->data[POST_CONSTRAINT]);
301 besDRB.set_async_accepted(d_dhi->data[ASYNC]);
302 besDRB.set_store_result(d_dhi->data[STORE_RESULT]);
307 if (bdds->get_ia_flag() ==
false) {
309 d_dhi->container->get_container_type());
310 besRH->add_attributes(*d_dhi);
313 ConstraintEvaluator &eval = bdds->get_ce();
320 if (!besDRB.get_btp_func_ce().empty()) {
321 BESDEBUG(MODULE, prolog <<
"Found function(s) in CE: " << besDRB.get_btp_func_ce() << endl);
325 ConstraintEvaluator func_eval;
327 if (responseCache && responseCache->can_be_cached(_dds, besDRB.get_btp_func_ce())) {
331 func_eval.parse_constraint(besDRB.get_btp_func_ce(), *_dds);
332 fdds = func_eval.eval_function_clauses(*_dds);
344 _dds->mark_all(
false);
355 promote_function_output_structures(_dds);
360 eval.parse_constraint(besDRB.
get_ce(), *_dds);
362 _dds->tag_nested_sequences();
365 vector<BaseType *> projected_dap4_variable_inventory;
366 bool d4_true = d4_tools::is_dap4_projected(_dds, projected_dap4_variable_inventory);
377 "request cannot be fulfilled because the response contains types that are not compatible with the requested encoding",
383 throw_if_dap2_response_too_big(_dds, besDRB.
get_ce());
384 dap_utils::throw_for_dap4_typed_vars_or_attrs(_dds,__FILE__,__LINE__);
390 for (
auto vi = _dds->var_begin(), ve = _dds->var_end(); vi != ve; vi++) {
391 if ((*vi)->send_p()) {
392 BESDEBUG(MODULE, prolog <<
"Converting variable '" << (*vi)->name() <<
"'" << endl);
395 FONcBaseType *fb = FONcUtils::convert((*vi), FONcTransform::_returnAs, FONcRequestHandler::classic_model);
397 _fonc_vars.push_back(fb);
398 vector <string> embed;
403 fonc_history_util::updateHistoryAttributes(_dds, d_dhi->data[POST_CONSTRAINT]);
407 if (FONcTransform::_returnAs == FONC_RETURN_AS_NETCDF4) {
408 if (FONcRequestHandler::classic_model) {
409 BESDEBUG(MODULE, prolog <<
"Opening NetCDF-4 cache file in classic mode. fileName: "
410 << _localfile << endl);
411 stax = nc_create(_localfile.c_str(), NC_CLOBBER | NC_NETCDF4 | NC_CLASSIC_MODEL, &_ncid);
414 BESDEBUG(MODULE, prolog <<
"Opening NetCDF-4 cache file. fileName: " << _localfile << endl);
415 stax = nc_create(_localfile.c_str(), NC_CLOBBER | NC_NETCDF4, &_ncid);
419 BESDEBUG(MODULE, prolog <<
"Opening NetCDF-3 cache file. fileName: " << _localfile << endl);
420 if (FONcRequestHandler::nc3_classic_format)
421 stax = nc_create(_localfile.c_str(), NC_CLOBBER, &_ncid);
423 stax = nc_create(_localfile.c_str(), NC_CLOBBER | NC_64BIT_OFFSET, &_ncid);
426 if (stax != NC_NOERR) {
427 FONcUtils::handle_error(stax, prolog +
"Call to nc_create() failed for file: " + _localfile, __FILE__, __LINE__);
430 int current_fill_prop_vaule;
432 stax = nc_set_fill(_ncid, NC_NOFILL, ¤t_fill_prop_vaule);
433 if (stax != NC_NOERR) {
447 BESDEBUG(MODULE, prolog <<
"Defining variable: " << fbt->name() << endl);
451 if (FONcRequestHandler::no_global_attrs ==
false) {
453 AttrTable &globals = _dds->get_attr_table();
454 BESDEBUG(MODULE, prolog <<
"Adding Global Attributes" << endl << globals << endl);
455 bool is_netCDF_enhanced =
false;
456 if (FONcTransform::_returnAs == FONC_RETURN_AS_NETCDF4 && FONcRequestHandler::classic_model ==
false)
457 is_netCDF_enhanced =
true;
467 int stax = nc_enddef(_ncid);
471 if (stax != NC_NOERR) {
476 BESDEBUG(MODULE, prolog <<
"Writing data for variable: " << fbt->name() << endl);
479 fbt->set_eval(&eval);
485 stax = nc_close(_ncid);
486 if (stax != NC_NOERR)
491 (void) nc_close(_ncid);
503void FONcTransform::throw_if_dap4_response_too_big(DMR *dmr,
const string &dap4_ce)
505 unsigned long long max_response_size_kb = FONcRequestHandler::get_request_max_size_kb();
506 BESDEBUG(MODULE, prolog <<
"Configured max_request_size_kb: " << max_response_size_kb << endl);
508 unsigned long long req_size_kb = dmr->request_size_kb(
true);
509 BESDEBUG(MODULE, prolog <<
"dmr->get_request_size_kb(): " << req_size_kb << endl);
511 string return_encoding;
512 set_max_size_and_encoding(max_response_size_kb, return_encoding);
515 dmr->set_response_limit_kb(max_response_size_kb);
517 if (dmr->too_big()) {
518 string err_msg = too_big_error_msg(4,return_encoding,req_size_kb, max_response_size_kb, dap4_ce);
532 BESDEBUG(MODULE, prolog <<
"BEGIN" << endl);
536 d_dhi->first_container();
539 _dmr = responseBuilder.setup_dap4_intern_data(d_obj, *d_dhi).release();
541 _dmr->set_response_limit_kb(FONcRequestHandler::get_request_max_size_kb());
543 vector<string> inventory;
544 bool d4_true = _dmr->is_dap4_projected(inventory);
546 if (d4_true && _returnAs ==
"netcdf"){
548 msg <<
"This dataset contains variables and/or attributes whose data types are not compatible with the " << endl;
549 msg <<
"NetCDF-3 data model. If your request includes any of variables represented by one of these " << endl;
550 msg <<
"incompatible variables and/or attributes and you choose the “NetCDF-3” download encoding, " << endl;
551 msg <<
"your request will FAIL. " << endl;
553 msg <<
"You may also try constraining your request to omit the problematic data type(s), " << endl;
554 msg <<
"or ask for a different encoding such as DAP4 binary or NetCDF-4." << endl;
555 msg <<
"There are" << inventory.size() <<
" incompatible variables referenced in your request." << endl;
556 msg <<
"Incompatible variables: " << endl;
558 for(
const auto &entry: inventory){
559 msg <<
" " << entry << endl;
567 throw_if_dap4_response_too_big(_dmr,responseBuilder.
get_dap4ce() );
574 besDRB.
set_dap4ce(d_dhi->data[DAP4_CONSTRAINT]);
577 besDRB.set_async_accepted(d_dhi->data[ASYNC]);
578 besDRB.set_store_result(d_dhi->data[STORE_RESULT]);
581 if (FONcRequestHandler::reduce_dim ==
true) {
582 do_reduce_dim = check_reduce_dim();
587 BESDEBUG(MODULE, prolog <<
"reduced dimensions" << endl);
589 BESDEBUG(MODULE, prolog <<
"Not reduced dimensions" << endl);
592 D4Group *root_grp_debug = _dmr->root();
593 for (
auto &var:root_grp_debug->variables()) {
595 if (var->type() == dods_array_c) {
596 auto t_a =
dynamic_cast<Array *
>(var);
597 Array::Dim_iter dim_i = t_a->dim_begin();
598 Array::Dim_iter dim_e = t_a->dim_end();
599 for (; dim_i != dim_e; dim_i++) {
600 BESDEBUG(MODULE, prolog <<
"CHANGED dim name: " << dim_i->name<<endl);
605 D4Dimensions *root_dims = root_grp_debug->dims();
606 for (D4Dimensions::D4DimensionsIter di = root_dims->dim_begin(), de = root_dims->dim_end(); di != de; ++di) {
607 BESDEBUG(MODULE, prolog <<
"transform_dap4() - check dimensions" << endl);
608 BESDEBUG(MODULE, prolog <<
"transform_dap4() - dim name is: " << (*di)->name() << endl);
609 BESDEBUG(MODULE, prolog <<
"transform_dap4() - dim size is: " << (*di)->size() << endl);
610 BESDEBUG(MODULE, prolog <<
"transform_dap4() - fully_qualfied_dim name is: " << (*di)->fully_qualified_name() << endl);
618 if (FONC_RETURN_AS_NETCDF4 == FONcTransform::_returnAs &&
false == FONcRequestHandler::classic_model) {
619 global_dio_flag = _dmr->get_global_dio_flag();
622 if(global_dio_flag) {
623 BESDEBUG(MODULE, prolog <<
"global_dio_flag is true" << endl);
626 BESDEBUG(MODULE, prolog <<
"global_dio_flag is false" << endl);
638 bool support_group = check_group_support();
640 if (
true == support_group) {
643 BESDEBUG(MODULE, prolog <<
"Opening NetCDF-4 cache file. fileName: " << _localfile << endl);
644 stax = nc_create(_localfile.c_str(), NC_CLOBBER | NC_NETCDF4, &_ncid);
645 if (stax != NC_NOERR)
646 FONcUtils::handle_error(stax, prolog +
"Call to nc_create() failed for file: " + _localfile, __FILE__, __LINE__);
648 D4Group *root_grp = _dmr->root();
651 map<string, int> fdimname_to_id;
655 gen_included_grp_list(root_grp);
658 for (std::set<string>::iterator it = _included_grp_names.begin(); it != _included_grp_names.end(); ++it)
659 BESDEBUG(MODULE, prolog <<
"Included group list name is: " << *it << endl);
663 check_and_obtain_dimensions(root_grp,
true);
669 for (it = GFQN_dimname_to_dimsize.begin(); it != GFQN_dimname_to_dimsize.end(); ++it) {
670 BESDEBUG(MODULE, prolog <<
"Final GFQN dim name is: " << it->first << endl);
671 BESDEBUG(MODULE, prolog <<
"Final GFQN dim size is: " << it->second << endl);
674 for (it = VFQN_dimname_to_dimsize.begin(); it != VFQN_dimname_to_dimsize.end(); ++it) {
675 BESDEBUG(MODULE, prolog <<
"Final VFQN dim name is: " << it->first << endl);
676 BESDEBUG(MODULE, prolog <<
"Final VFQN dim size is: " << it->second << endl);
685 for (git = GFQN_dimname_to_dimsize.begin(); git != GFQN_dimname_to_dimsize.end(); ++git) {
686 for (vit = VFQN_dimname_to_dimsize.begin(); vit != VFQN_dimname_to_dimsize.end(); ++vit) {
687 if (git->first == vit->first) {
688 if (git->second != vit->second)
689 git->second = vit->second;
705 vector <string> root_d4_dimname_list;
706 for (git = GFQN_dimname_to_dimsize.begin(); git != GFQN_dimname_to_dimsize.end(); ++git) {
707 string d4_temp_dimname = git->first.substr(1);
709 if (d4_temp_dimname.find(
'/') == string::npos)
710 root_d4_dimname_list.push_back(d4_temp_dimname);
714 for (
unsigned int i = 0; i < root_d4_dimname_list.size(); i++)
715 BESDEBUG(MODULE, prolog <<
"root_d4 dim name is: " << root_d4_dimname_list[i] << endl);
719 vector<int> root_dim_suffix_nums;
720 for (
unsigned int i = 0; i < root_d4_dimname_list.size(); i++) {
721 if (root_d4_dimname_list[i].size() < 4)
723 else if (root_d4_dimname_list[i].substr(0, 3) !=
"dim")
726 string temp_suffix = root_d4_dimname_list[i].substr(3);
728 bool ignored_suffix =
false;
729 for (
unsigned int j = 0; j < temp_suffix.size(); j++) {
730 if (!isdigit(temp_suffix[j])) {
731 ignored_suffix =
true;
735 if (ignored_suffix ==
true)
738 root_dim_suffix_nums.push_back(atoi(temp_suffix.c_str()));
743 for (
unsigned int i = 0; i < root_dim_suffix_nums.size(); i++)
744 BESDEBUG(MODULE, prolog <<
"root_dim_suffix_nums: " << root_dim_suffix_nums[i] << endl);
747 for (it = GFQN_dimname_to_dimsize.begin(); it != GFQN_dimname_to_dimsize.end(); ++it) {
748 BESDEBUG(MODULE, prolog <<
"RFinal GFQN dim name is: " << it->first << endl);
749 BESDEBUG(MODULE, prolog <<
"RFinal GFQN dim size is: " << it->second << endl);
752 for (it = VFQN_dimname_to_dimsize.begin(); it != VFQN_dimname_to_dimsize.end(); ++it) {
753 BESDEBUG(MODULE, prolog <<
"RFinal VFQN dim name is: " << it->first << endl);
754 BESDEBUG(MODULE, prolog <<
"RFinal VFQN dim size is: " << it->second << endl);
759 transform_dap4_group(root_grp,
true, _ncid, fdimname_to_id, root_dim_suffix_nums);
760 stax = nc_close(_ncid);
761 if (stax != NC_NOERR)
766 transform_dap4_no_group();
768 BESDEBUG(MODULE, prolog <<
"END" << endl);
778void FONcTransform::transform_dap4_no_group() {
780 D4Group *root_grp = _dmr->root();
782 D4Dimensions *root_dims = root_grp->dims();
783 for (D4Dimensions::D4DimensionsIter di = root_dims->dim_begin(), de = root_dims->dim_end(); di != de; ++di) {
784 BESDEBUG(MODULE, prolog <<
"transform_dap4() - check dimensions" << endl);
785 BESDEBUG(MODULE, prolog <<
"transform_dap4() - dim name is: " << (*di)->name() << endl);
786 BESDEBUG(MODULE, prolog <<
"transform_dap4() - dim size is: " << (*di)->size() << endl);
787 BESDEBUG(MODULE, prolog <<
"transform_dap4() - fully_qualfied_dim name is: " << (*di)->fully_qualified_name() << endl);
790 Constructor::Vars_iter vi = root_grp->var_begin();
791 Constructor::Vars_iter ve = root_grp->var_end();
795 if (global_dio_flag ==
false) {
796 for (; vi != ve; vi++) {
797 if ((*vi)->send_p()) {
800 BESDEBUG(MODULE, prolog <<
"Converting variable '" << v->name() <<
"'" << endl);
803 FONcBaseType *fb = FONcUtils::convert(v, FONcTransform::_returnAs, FONcRequestHandler::classic_model);
805 _fonc_vars.push_back(fb);
807 vector <string> embed;
809 fb->convert(embed,
true,
false);
814 for (; vi != ve; vi++) {
815 if ((*vi)->send_p()) {
818 BESDEBUG(MODULE, prolog <<
"Direct IO is off, Converting variable '" << v->name() <<
"'" << endl);
820 if (v->type() == dods_array_c) {
821 auto t_a =
dynamic_cast<Array *
>(v);
822 if (t_a->get_dio_flag())
823 set_constraint_var_dio_flag(t_a);
827 FONcBaseType *fb = FONcUtils::convert(v, FONcTransform::_returnAs, FONcRequestHandler::classic_model);
830 _fonc_vars.push_back(fb);
832 vector <string> embed;
834 fb->convert(embed,
true,
false);
840 if (root_grp->grp_begin() == root_grp->grp_end())
841 BESDEBUG(MODULE, prolog <<
"No group " << endl);
843 BESDEBUG(MODULE, prolog <<
"Has group " << endl);
844 for (D4Group::groupsIter gi = root_grp->grp_begin(), ge = root_grp->grp_end(); gi != ge; ++gi)
845 BESDEBUG(MODULE, prolog <<
"Group name: " << (*gi)->name() << endl);
848 fonc_history_util::updateHistoryAttributes(_dmr, d_dhi->data[POST_CONSTRAINT]);
852 if (FONcTransform::_returnAs == FONC_RETURN_AS_NETCDF4) {
853 if (FONcRequestHandler::classic_model) {
854 BESDEBUG(MODULE, prolog <<
"Opening NetCDF-4 cache file in classic mode. fileName: "
855 << _localfile << endl);
856 stax = nc_create(_localfile.c_str(), NC_CLOBBER | NC_NETCDF4 | NC_CLASSIC_MODEL, &_ncid);
859 BESDEBUG(MODULE, prolog <<
"Opening NetCDF-4 cache file. fileName: " << _localfile
861 stax = nc_create(_localfile.c_str(), NC_CLOBBER | NC_NETCDF4, &_ncid);
865 BESDEBUG(MODULE, prolog <<
"Opening NetCDF-3 cache file. fileName: " << _localfile
867 if (FONcRequestHandler::nc3_classic_format)
868 stax = nc_create(_localfile.c_str(), NC_CLOBBER, &_ncid);
870 stax = nc_create(_localfile.c_str(), NC_CLOBBER | NC_64BIT_OFFSET, &_ncid);
873 if (stax != NC_NOERR) {
874 FONcUtils::handle_error(stax, prolog +
"Call to nc_create() failed for file: " + _localfile, __FILE__, __LINE__);
885 vector<FONcBaseType *>::iterator i = _fonc_vars.begin();
886 vector<FONcBaseType *>::iterator e = _fonc_vars.end();
887 for (; i != e; i++) {
888 FONcBaseType *fbt = *i;
889 BESDEBUG(MODULE, prolog <<
"Defining variable: " << fbt->name() << endl);
894 if (FONcRequestHandler::no_global_attrs ==
false) {
897 D4Group *root_grp = _dmr->root();
898 D4Attributes *d4_attrs = root_grp->attributes();
900 BESDEBUG(MODULE, prolog <<
"Handle GLOBAL DAP4 attributes " << d4_attrs << endl);
902 for (D4Attributes::D4AttributesIter ii = d4_attrs->attribute_begin(), ee = d4_attrs->attribute_end();
904 string name = (*ii)->name();
905 BESDEBUG(MODULE, prolog <<
"GLOBAL attribute name is " << name << endl);
908 bool is_netCDF_enhanced =
false;
909 if (FONcTransform::_returnAs == FONC_RETURN_AS_NETCDF4 && FONcRequestHandler::classic_model ==
false)
910 is_netCDF_enhanced =
true;
917 int stax = nc_enddef(_ncid);
921 if (stax != NC_NOERR) {
927 i = _fonc_vars.begin();
928 e = _fonc_vars.end();
929 for (; i != e; i++) {
930 FONcBaseType *fbt = *i;
932 BESDEBUG(MODULE, prolog <<
"Writing data for variable: " << fbt->name() << endl);
936 stax = nc_close(_ncid);
937 if (stax != NC_NOERR)
940 catch (BESError &e) {
941 (void) nc_close(_ncid);
948void FONcTransform::transform_dap4_group(D4Group *grp,
950 int par_grp_id, map<string, int> &fdimname_to_id,
951 vector<int> &root_dim_suffix_nums) {
953 bool included_grp =
false;
955 if (_dmr->get_ce_empty()) {
956 BESDEBUG(MODULE, prolog <<
"In group - group name: " << grp->FQN() << endl);
960 else if (is_root_grp ==
true)
964 set<string>::iterator iset;
965 if (_included_grp_names.find(grp->FQN()) != _included_grp_names.end())
971 if (included_grp ==
true)
972 transform_dap4_group_internal(grp, is_root_grp, par_grp_id, fdimname_to_id, root_dim_suffix_nums);
984void FONcTransform::transform_dap4_group_internal(D4Group *grp,
986 int par_grp_id, map<string, int> &fdimname_to_id,
987 vector<int> &rds_nums) {
989 BESDEBUG(MODULE, prolog <<
"BEGIN" << endl);
993 fonc_history_util::updateHistoryAttributes(_dmr, d_dhi->data[POST_CONSTRAINT]);
995 if (is_root_grp ==
true)
1001 string grp_name = (*grp).name();
1003 stax = nc_def_grp(par_grp_id, new_grp_name.c_str(), &grp_id);
1004 BESDEBUG(MODULE, prolog <<
"Group name is " << (*grp).name() << endl);
1005 if (stax != NC_NOERR)
1010 D4Dimensions *grp_dims = grp->dims();
1011 for (D4Dimensions::D4DimensionsIter di = grp_dims->dim_begin(), de = grp_dims->dim_end(); di != de; ++di) {
1014 BESDEBUG(MODULE, prolog <<
"Check dimensions" << endl);
1015 BESDEBUG(MODULE, prolog <<
"Dim name is: " << (*di)->name() << endl);
1016 BESDEBUG(MODULE, prolog <<
"Dim size is: " << (*di)->size() << endl);
1017 BESDEBUG(MODULE, prolog <<
"Fully_qualfied_dim name is: " << (*di)->fully_qualified_name() << endl);
1020 int64_t dimsize = (*di)->size();
1023 map<string, int64_t>::iterator it;
1024 for (it = GFQN_dimname_to_dimsize.begin(); it != GFQN_dimname_to_dimsize.end(); ++it) {
1025 if (it->first == (*di)->fully_qualified_name())
1026 dimsize = it->second;
1031 stax = nc_def_dim(grp_id, (*di)->name().c_str(), dimsize, &g_dimid);
1032 if (stax != NC_NOERR)
1036 fdimname_to_id[(*di)->fully_qualified_name()] = g_dimid;
1039 Constructor::Vars_iter vi = grp->var_begin();
1040 Constructor::Vars_iter ve = grp->var_end();
1042 vector < FONcBaseType * > fonc_vars_in_grp;
1046 if (global_dio_flag ==
false) {
1047 for (; vi != ve; vi++) {
1048 if ((*vi)->send_p()) {
1051 BESDEBUG(MODULE, prolog <<
"Converting variable '" << v->name() <<
"'" << endl);
1055 FONcBaseType *fb = FONcUtils::convert(v, FONC_RETURN_AS_NETCDF4,
false, fdimname_to_id, rds_nums);
1057 fonc_vars_in_grp.push_back(fb);
1060 _total_fonc_vars_in_grp.push_back(fb);
1062 vector <string> embed;
1064 fb->convert(embed,
true,
true);
1069 for (; vi != ve; vi++) {
1070 if ((*vi)->send_p()) {
1073 BESDEBUG(MODULE, prolog <<
"Converting variable '" << v->name() <<
"'" << endl);
1075 if (v->type() == dods_array_c) {
1076 auto t_a =
dynamic_cast<Array *
>(v);
1077 if (t_a->get_dio_flag())
1078 set_constraint_var_dio_flag(t_a);
1084 FONcBaseType *fb = FONcUtils::convert(v, FONC_RETURN_AS_NETCDF4,
false, fdimname_to_id, rds_nums);
1086 fonc_vars_in_grp.push_back(fb);
1089 _total_fonc_vars_in_grp.push_back(fb);
1091 vector <string> embed;
1093 fb->convert(embed,
true,
true);
1099 if (grp->grp_begin() == grp->grp_end())
1100 BESDEBUG(MODULE, prolog <<
"No group" << endl);
1102 BESDEBUG(MODULE, prolog <<
"Has group" << endl);
1111 vector<FONcBaseType *>::iterator i = fonc_vars_in_grp.begin();
1112 vector<FONcBaseType *>::iterator e = fonc_vars_in_grp.end();
1113 for (; i != e; i++) {
1114 FONcBaseType *fbt = *i;
1115 BESDEBUG(MODULE, prolog <<
"Defining variable: " << fbt->name() << endl);
1120 bool is_netCDF_enhanced =
false;
1121 if (FONcTransform::_returnAs == FONC_RETURN_AS_NETCDF4 && FONcRequestHandler::classic_model ==
false)
1122 is_netCDF_enhanced =
true;
1125 bool add_attr =
true;
1128 if (FONcRequestHandler::no_global_attrs ==
true && is_root_grp ==
true)
1131 if (
true == add_attr) {
1132 D4Attributes *d4_attrs = grp->attributes();
1133 BESDEBUG(MODULE, prolog <<
"Adding Group Attributes" << endl);
1140 i = fonc_vars_in_grp.begin();
1141 e = fonc_vars_in_grp.end();
1142 for (; i != e; i++) {
1143 FONcBaseType *fbt = *i;
1145 BESDEBUG(MODULE, prolog <<
"Writing data for variable: " << fbt->name() << endl);
1151 for (D4Group::groupsIter gi = grp->grp_begin(), ge = grp->grp_end(); gi != ge; ++gi) {
1152 BESDEBUG(MODULE, prolog <<
"In group: " << (*gi)->name() << endl);
1153 transform_dap4_group(*gi,
false, grp_id, fdimname_to_id, rds_nums);
1157 catch (BESError &e) {
1158 (void) nc_close(_ncid);
1161 BESDEBUG(MODULE, prolog <<
"END" << endl);
1166bool FONcTransform::check_group_support() {
1167 if (FONC_RETURN_AS_NETCDF4 == FONcTransform::_returnAs &&
false == FONcRequestHandler::classic_model &&
1168 (_dmr->root()->grp_begin() != _dmr->root()->grp_end()))
1175void FONcTransform::gen_included_grp_list(D4Group *grp) {
1176 bool grp_has_var =
false;
1178 BESDEBUG(MODULE, prolog <<
"Processing D4 Group: " << grp->name() <<
" fullpath: " << grp->FQN() << endl);
1180 if (grp->var_begin() != grp->var_end()) {
1182 BESDEBUG(MODULE, prolog <<
"Has child variables" << endl);
1183 Constructor::Vars_iter vi = grp->var_begin();
1184 Constructor::Vars_iter ve = grp->var_end();
1186 for (; vi != ve; vi++) {
1189 if ((*vi)->send_p()) {
1194 if (grp->FQN() !=
"/")
1195 _included_grp_names.insert(grp->FQN());
1201 for (D4Group::groupsIter gi = grp->grp_begin(), ge = grp->grp_end(); gi != ge; ++gi) {
1202 BESDEBUG(MODULE, prolog <<
"Obtain included groups - group name: " << (*gi)->name() << endl);
1203 gen_included_grp_list(*gi);
1208 if (grp_has_var ==
true) {
1209 D4Group *temp_grp = grp;
1211 if (temp_grp->get_parent()) {
1212 temp_grp =
static_cast<D4Group *
>(temp_grp->get_parent());
1213 if (temp_grp->FQN() !=
"/")
1214 _included_grp_names.insert(temp_grp->FQN());
1223void FONcTransform::check_and_obtain_dimensions(D4Group *grp,
bool is_root_grp) {
1226 bool included_grp =
false;
1228 if (_dmr->get_ce_empty())
1229 included_grp =
true;
1231 else if (is_root_grp ==
true)
1232 included_grp =
true;
1235 set<string>::iterator iset;
1236 if (_included_grp_names.find(grp->FQN()) != _included_grp_names.end())
1237 included_grp =
true;
1240 if (included_grp ==
true)
1241 check_and_obtain_dimensions_internal(grp);
1244void FONcTransform::check_and_obtain_dimensions_internal(D4Group *grp) {
1247 D4Dimensions *grp_dims = grp->dims();
1249 for (D4Dimensions::D4DimensionsIter di = grp_dims->dim_begin(), de = grp_dims->dim_end(); di != de; ++di) {
1252 BESDEBUG(MODULE, prolog <<
"Check dimensions" << endl);
1253 BESDEBUG(MODULE, prolog <<
"Dim name is: " << (*di)->name() << endl);
1254 BESDEBUG(MODULE, prolog <<
"Dim size is: " << (*di)->size() << endl);
1255 BESDEBUG(MODULE, prolog <<
"Fully qualfied dim name: " << (*di)->fully_qualified_name() << endl);
1257 int64_t dimsize = (*di)->size();
1258 if ((*di)->constrained()) {
1259 dimsize = ((*di)->c_stop() - (*di)->c_start()) / (*di)->c_stride() + 1;
1262 GFQN_dimname_to_dimsize[(*di)->fully_qualified_name()] = dimsize;
1269 Constructor::Vars_iter vi = grp->var_begin();
1270 Constructor::Vars_iter ve = grp->var_end();
1271 for (; vi != ve; vi++) {
1272 if ((*vi)->send_p()) {
1273 if ((*vi)->is_vector_type()) {
1274 Array *t_a =
dynamic_cast<Array *
>(*vi);
1275 Array::Dim_iter dim_i = t_a->dim_begin();
1276 Array::Dim_iter dim_e = t_a->dim_end();
1277 for (; dim_i != dim_e; dim_i++) {
1278 if ((*dim_i).name !=
"") {
1279 D4Dimension *d4dim = t_a->dimension_D4dim(dim_i);
1281 BESDEBUG(MODULE, prolog <<
"Check dim- dim name is: " << d4dim->name() << endl);
1282 BESDEBUG(MODULE, prolog <<
"Check dim- dim size is: " << d4dim->size() << endl);
1283 BESDEBUG(MODULE, prolog <<
"Check dim- fully_qualfied_dim name is: "
1284 << d4dim->fully_qualified_name() << endl);
1286 int64_t dimsize = t_a->dimension_size_ll(dim_i,
true);
1288 BESDEBUG(MODULE, prolog <<
"Check dim- final dim size is: " << dimsize << endl);
1290 pair<map<string, int64_t>::iterator,
bool> ret_it;
1291 ret_it = VFQN_dimname_to_dimsize.insert(
1292 pair<string, int64_t>(d4dim->fully_qualified_name(), dimsize));
1293 if (ret_it.second ==
false && ret_it.first->second != dimsize) {
1294 string err =
"fileout_netcdf-4: dimension found with the same name, but different size";
1295 throw BESInternalError(err, __FILE__, __LINE__);
1300 throw BESInternalError(
"Has dimension name but D4 dimension is NULL", __FILE__, __LINE__);
1310 map<string, int64_t>::iterator it;
1311 for (it = GFQN_dimname_to_dimsize.begin(); it != GFQN_dimname_to_dimsize.end(); ++it) {
1312 BESDEBUG(MODULE, prolog <<
"GFQN dim name is: " << it->first << endl);
1313 BESDEBUG(MODULE, prolog <<
"GFQN dim size is: " << it->second << endl);
1316 for (it = VFQN_dimname_to_dimsize.begin(); it != VFQN_dimname_to_dimsize.end(); ++it) {
1317 BESDEBUG(MODULE, prolog <<
"VFQN dim name is: " << it->first << endl);
1318 BESDEBUG(MODULE, prolog <<
"VFQN dim size is: " << it->second << endl);
1324 for (D4Group::groupsIter gi = grp->grp_begin(), ge = grp->grp_end(); gi != ge; ++gi) {
1325 BESDEBUG(MODULE,prolog <<
"In group: " << (*gi)->name() << endl);
1326 check_and_obtain_dimensions(*gi,
false);
1330void FONcTransform::set_constraint_var_dio_flag(libdap::Array* t_a)
const {
1336 bool partial_subset_array =
false;
1337 Array::Dim_iter di = t_a->dim_begin();
1338 Array::Dim_iter de = t_a->dim_end();
1339 for (; di != de; di++) {
1340 if (t_a->dimension_size_ll(di,
true) != t_a->dimension_size_ll(di,
false)) {
1341 partial_subset_array =
true;
1345 if (partial_subset_array)
1346 t_a->set_dio_flag(
false);
1351void FONcTransform::set_constraint_var_dio_flag(libdap::BaseType* bt)
const{
1353 if (bt->type() == dods_array_c) {
1355 auto t_a=
dynamic_cast<Array *
>(bt);
1359 if (t_a->get_dio_flag()) {
1361 bool partial_subset_array =
false;
1362 Array::Dim_iter di = t_a->dim_begin();
1363 Array::Dim_iter de = t_a->dim_end();
1365 for (; di != de; di++) {
1366 if (t_a->dimension_size_ll(di,
true) != t_a->dimension_size_ll(di,
false)) {
1367 partial_subset_array =
true;
1371 if (partial_subset_array)
1372 t_a->set_dio_flag(
false);
1377bool FONcTransform::check_reduce_dim() {
1379 bool ret_value =
true;
1380 D4Group *root_grp = _dmr->root();
1381 ret_value = check_reduce_dim_internal(root_grp);
1385bool FONcTransform::check_reduce_dim_internal(D4Group*grp) {
1387 bool ret_value =
true;
1388 D4Dimensions *grp_dims = grp->dims();
1391 for (D4Dimensions::D4DimensionsIter di = grp_dims->dim_begin(), de = grp_dims->dim_end(); di != de; ++di) {
1392 if((*di)->name().empty() ==
false) {
1400 for (
const auto &var:grp->variables()) {
1401 if (var->send_p()) {
1402 ret_value = check_var_dim(var);
1403 if (ret_value ==
false)
1410 for (D4Group::groupsIter gi = grp->grp_begin(), ge = grp->grp_end(); gi != ge; ++gi) {
1411 ret_value = check_reduce_dim_internal(*gi);
1412 if (ret_value ==
false)
1420bool FONcTransform::check_var_dim(BaseType *var) {
1422 bool ret_value =
true;
1424 if (var->type() == dods_array_c) {
1426 auto t_a =
dynamic_cast<Array *
>(var);
1427 Array::Dim_iter dim_i = t_a->dim_begin();
1428 Array::Dim_iter dim_e = t_a->dim_end();
1429 for (; dim_i != dim_e; dim_i++) {
1430 if ((*dim_i).name !=
"") {
1439void FONcTransform::build_reduce_dim() {
1441 D4Group *root_grp = _dmr->root();
1442 build_reduce_dim_internal(root_grp, root_grp);
1445void FONcTransform::build_reduce_dim_internal(D4Group *grp, D4Group *root_grp) {
1447 for (
auto &var:grp->variables()) {
1449 if (var->type() == dods_array_c && var->send_p()) {
1450 auto t_a =
dynamic_cast<Array *
>(var);
1452 unordered_map<int64_t,int> local_dsize_count;
1454 Array::Dim_iter dim_i = t_a->dim_begin();
1455 Array::Dim_iter dim_e = t_a->dim_end();
1456 for (; dim_i != dim_e; dim_i++) {
1458 if ((*dim_i).name ==
"") {
1460 int64_t dimsize = t_a->dimension_size_ll(dim_i,
true);
1463 bool local_dsize_found =
false;
1464 if(local_dsize_count.find(dimsize)!=local_dsize_count.end()) {
1465 int prev_count = local_dsize_count[dimsize];
1466 local_dsize_count[dimsize] = prev_count +1;
1467 local_dsize_found =
true;
1470 local_dsize_count[dimsize] = 1;
1472 bool dim_name_exist =
false;
1473 auto it_sn=dimsize_to_dup_dimnames.find(dimsize);
1474 if (it_sn !=dimsize_to_dup_dimnames.end()) {
1475 vector<string>temp_dimnames = dimsize_to_dup_dimnames[dimsize];
1476 if (local_dsize_found) {
1478 int temp_local_dsize_count = local_dsize_count[dimsize];
1482 if (temp_local_dsize_count > temp_dimnames.size()) {
1483 string dim_name_suffix= to_string(reduced_dim_num);
1484 (*dim_i).name =
"dim" + dim_name_suffix;
1487 temp_dimnames.push_back((*dim_i).name);
1488 dimsize_to_dup_dimnames[dimsize]=temp_dimnames;
1491 (*dim_i).name = temp_dimnames[temp_local_dsize_count-1];
1492 dim_name_exist =
true;
1497 (*dim_i).name = temp_dimnames[0];
1498 dim_name_exist =
true;
1502 string dim_name_suffix= to_string(reduced_dim_num);
1503 (*dim_i).name =
"dim" + dim_name_suffix;
1505 vector<string>temp_dimnames;
1506 temp_dimnames.push_back((*dim_i).name);
1507 dimsize_to_dup_dimnames[dimsize] = temp_dimnames;
1510 if (dim_name_exist) {
1512 D4Dimensions *dims = root_grp->dims();
1513 D4Dimension *d4_dim = dims->find_dim((*dim_i).name);
1514 if(d4_dim ==
nullptr)
1515 throw BESInternalError(
"D4 dimension cannot be found", __FILE__, __LINE__);
1517 (*dim_i).dim= d4_dim;
1521 auto d4_dim0_unique = make_unique<D4Dimension>((*dim_i).name, dimsize);
1522 (*dim_i).dim=d4_dim0_unique.get();
1525 D4Dimensions *dims = root_grp->dims();
1526 dims->add_dim_nocopy(d4_dim0_unique.release());
1533 for (D4Group::groupsIter gi = grp->grp_begin(), ge = grp->grp_end(); gi != ge; ++gi)
1534 build_reduce_dim_internal(*gi,root_grp);
1549 strm << BESIndent::LMarg <<
"FONcTransform::dump - (" << (
void *)
this <<
")" << endl;
1550 BESIndent::Indent();
1551 strm << BESIndent::LMarg <<
"ncid = " << _ncid << endl;
1552 strm << BESIndent::LMarg <<
"temporary file = " << _localfile << endl;
1553 BESIndent::Indent();
1556 for (; i != e; i++) {
1560 BESIndent::UnIndent();
1561 BESIndent::UnIndent();
Cache the results from server functions.
virtual libdap::DDS * get_or_cache_dataset(libdap::DDS *dds, const std::string &constraint)
Return a DDS loaded with data that can be serialized back to a client.
virtual void set_dataset_name(const std::string &_dataset)
Set the dataset pathname.
virtual void split_ce(libdap::ConstraintEvaluator &eval, const std::string &expr="")
virtual std::string get_ce() const
Get the constraint expression.
virtual void set_dap4function(const std::string &_func)
virtual std::string get_dap4ce() const
Get the DAP4 constraint expression.
virtual void set_dap4ce(const std::string &_ce)
virtual void set_ce(std::string _ce)
Represents an OPeNDAP DataDDS DAP2 data object within the BES.
Structure storing information used by the BES to handle the request.
void first_container()
set the container pointer to the first container in the containers list
BESContainer * container
pointer to current container in this interface
Base exception class for the BES with basic string message.
exception thrown if internal error encountered
exception thrown if an internal error is found and is fatal to the BES
Represents a specific data type request handler.
Abstract base class representing a specific set of information in response to a request to the BES.
error thrown if there is a user syntax error in the request or any other user error
static void add_dap4_attributes(int ncid, int varid, D4Attributes *d4_attrs, const string &var_name, const string &prepend_attr, bool is_netCDF_enhanced)
add_dap4_attributes
static void add_attributes(int ncid, int varid, AttrTable &attrs, const string &var_name, const string &prepend_attr, bool is_netCDF_enhanced)
helper function for add_attributes
A DAP BaseType with file out netcdf information included.
virtual void define(int ncid)
Define the variable in the netcdf file.
void dump(std::ostream &strm) const override=0
dump the contents of this object to the specified ostream
static void handle_error(int stax, const string &err, const string &file, int line)
handle any netcdf errors
static void reset()
Resets the FONc transformation for a new input and out file.
static string id2netcdf(string in)
convert the provided string to a netcdf allowed identifier.
static RequestServiceTimer * TheTimer()
Return a pointer to a singleton timer instance. If an instance does not exist it will create and init...
void throw_if_timeout_expired(const std::string &message, const std::string &file, const int line)
Checks the RequestServiceTimer to determine if the time spent servicing the request at this point has...