bes Updated for version 3.20.13
GridAggregationBase.cc
1
2// This file is part of the "NcML Module" project, a BES module designed
3// to allow NcML files to be used to be used as a wrapper to add
4// AIS to existing datasets of any format.
5//
6// Copyright (c) 2010 OPeNDAP, Inc.
7// Author: Michael Johnson <m.johnson@opendap.org>
8//
9// For more information, please also see the main website: http://opendap.org/
10//
11// This library is free software; you can redistribute it and/or
12// modify it under the terms of the GNU Lesser General Public
13// License as published by the Free Software Foundation; either
14// version 2.1 of the License, or (at your option) any later version.
15//
16// This library is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19// Lesser General Public License for more details.
20//
21// You should have received a copy of the GNU Lesser General Public
22// License along with this library; if not, write to the Free Software
23// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24//
25// Please see the files COPYING and COPYRIGHT for more information on the GLPL.
26//
27// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
29
30
31#include <libdap/Array.h> // libdap
32#include <libdap/D4Group.h>
33#include <libdap/Constructor.h>
34#include <libdap/D4Maps.h>
35#include <libdap/InternalErr.h>
36
37#include "BESStopWatch.h"
38
39#include "AggregationUtil.h" // agg_util
40#include "GridAggregationBase.h" // agg_util
41
42#include "NCMLDebug.h"
43
44using libdap::Array;
45using libdap::BaseType;
46using libdap::Grid;
47
48using libdap::D4Group;
49using libdap::Constructor;
50using libdap::InternalErr;
51using libdap::D4Maps;
52using libdap::D4Map;
53
54// Local debug flags
55#define DEBUG_CHANNEL "agg_util"
56
57namespace agg_util {
58GridAggregationBase::GridAggregationBase(const libdap::Grid& proto, const AMDList& memberDatasets, const DDSLoader& loaderProto) :
59 Grid(proto), _loader(loaderProto.getDHI()), _pSubGridProto(cloneSubGridProto(proto)), _memberDatasets(memberDatasets)
60{
61}
62
63GridAggregationBase::GridAggregationBase(const string& name, const AMDList& memberDatasets, const DDSLoader& loaderProto) :
64 Grid(name), _loader(loaderProto.getDHI()), _memberDatasets(memberDatasets)
65{
66}
67
68GridAggregationBase::GridAggregationBase(const GridAggregationBase& proto) :
69 Grid(proto), _loader(proto._loader.getDHI())
70{
71 duplicate(proto);
72}
73
74/* virtual */
75GridAggregationBase::~GridAggregationBase()
76{
77 cleanup();
78}
79
80GridAggregationBase&
81GridAggregationBase::operator=(const GridAggregationBase& rhs)
82{
83 if (this != &rhs) {
84 cleanup();
85 Grid::operator=(rhs);
86 duplicate(rhs);
87 }
88 return *this;
89}
90
91
92void
93GridAggregationBase::transform_to_dap4(D4Group *root, Constructor *container)
94{
95 Grid::transform_to_dap4(root,container);
96
97#if 0 // I removed this method because I think the parent class implementation should work correctly.
98 BaseType *btp = array_var()->transform_to_dap4(root, container);
99 Array *coverage = static_cast<Array*>(btp);
100 if (!coverage) throw InternalErr(__FILE__, __LINE__, "Expected an Array while transforming a Grid (coverage)");
101
102 coverage->set_parent(container);
103
104 // Next find the maps; add them to the coverage and to the container,
105 // the latter only on the condition that they are not already there.
106
107 for (Map_iter i = map_begin(), e = map_end(); i != e; ++i) {
108 btp = (*i)->transform_to_dap4(root, container);
109 Array *map = static_cast<Array*>(btp);
110 if (!map) throw InternalErr(__FILE__, __LINE__, "Expected an Array while transforming a Grid (map)");
111
112 // map must be non-null (Grids cannot contain Grids in DAP2)
113 if (map) {
114 // Only add the map/array if it not already present; given the scoping rules
115 // for DAP2 and the assumption the DDS is valid, testing for the same name
116 // is good enough.
117 if (!root->var(map->name())) {
118 map->set_parent(container);
119 container->add_var_nocopy(map); // this adds the array to the container
120 }
121 D4Map *dap4_map = new D4Map(map->name(), map, coverage); // bind the 'map' to the coverage
122 coverage->maps()->add_map(dap4_map); // bind the coverage to the map
123 }
124 else {
125 throw InternalErr(__FILE__, __LINE__,
126 "transform_to_dap4() returned a null value where there can be no Grid.");
127 }
128 }
129
130 container->add_var_nocopy(coverage);
131#endif
132}
133
134void GridAggregationBase::setShapeFrom(const libdap::Grid& constProtoSubGrid, bool addMaps)
135{
136 // calls used are semantically const, but not syntactically.
137 Grid& protoSubGrid = const_cast<Grid&>(constProtoSubGrid);
138
139 // Save a clone of the template for read() to use.
140 // We always use these maps...
141 _pSubGridProto = unique_ptr<Grid>(cloneSubGridProto(protoSubGrid));
142
143 // Pass in the data array and maps from the proto by hand.
144 Array* pDataArrayTemplate = protoSubGrid.get_array();
145 VALID_PTR(pDataArrayTemplate);
146 set_array(static_cast<Array*>(pDataArrayTemplate->ptr_duplicate()));
147
148 // Now the maps in order if asked
149 if (addMaps) {
150 Grid::Map_iter endIt = protoSubGrid.map_end();
151 for (Grid::Map_iter it = protoSubGrid.map_begin(); it != endIt; ++it) {
152 // have to case, the iter is for some reason BaseType*
153 Array* pMap = dynamic_cast<Array*>(*it);
154 VALID_PTR(pMap);
155 add_map(pMap, true); // add as a copy
156 }
157 }
158}
159
160/* virtual */
161const AMDList&
163{
164 return _memberDatasets;
165}
166
167/* virtual */
169{
170 BESDEBUG_FUNC(DEBUG_CHANNEL, "Function entered..." << endl);
171
172 if (read_p()) {
173 BESDEBUG_FUNC(DEBUG_CHANNEL, "read_p() set, early exit!");
174 return true;
175 }
176
177 // Call the subclass hook methods to do this work properly
179
180 // Now make the read call on the data array.
181 // The aggregation subclass will do the right thing.
182 Array* pAggArray = get_array();
183 VALID_PTR(pAggArray);
184
185 // Only do this portion if the array part is supposed to serialize!
186 if (pAggArray->send_p() || pAggArray->is_in_selection()) {
187 pAggArray->read();
188 }
189
190 // Set the cache bit.
191 set_read_p(true);
192 return true;
193}
194
195#define PIPELINING 1
196
217bool
218GridAggregationBase::serialize(libdap::ConstraintEvaluator &eval, libdap::DDS &dds, libdap::Marshaller &m,
219 bool ce_eval)
220{
221 BESStopWatch sw;
222 if (BESDebug::IsSet(TIMING_LOG_KEY)) sw.start("GridAggregationBase::serialize", "");
223
224 bool status = false;
225
226 if (!read_p()) {
227 // Call the subclass hook methods to do this work properly
228 // *** Replace Map code readAndAggregateConstrainedMapsHook();
229
230 // Transfers constraints to the proto grid and reads it
232
233 // Make the call to serialize the data array.
234 // The aggregation subclass will do the right thing.
235 Array* pAggArray = get_array();
236 VALID_PTR(pAggArray);
237
238 // Only do this portion if the array part is supposed to serialize!
239 if (pAggArray->send_p() || pAggArray->is_in_selection()) {
240#if PIPELINING
241 pAggArray->serialize(eval, dds, m, ce_eval);
242#else
243 pAggArray->read();
244#endif
245 }
246
247 // Get the read-in, constrained maps from the proto grid and serialize them.
248 // *** Replace copyProtoMapsIntoThisGrid(getAggregationDimension());
249
250 Grid* pSubGridTemplate = getSubGridTemplate();
251 VALID_PTR(pSubGridTemplate);
252
253 Map_iter mapIt;
254 Map_iter mapEndIt = map_end();
255 for (mapIt = map_begin(); mapIt != mapEndIt; ++mapIt) {
256 Array* pOutMap = static_cast<Array*>(*mapIt);
257 VALID_PTR(pOutMap);
258
259 // If it isn't getting dumped, then don't bother with it
260 if (!(pOutMap->send_p() || pOutMap->is_in_selection())) {
261 continue;
262 }
263
264 // We don't want to touch the aggregation dimension since it's
265 // handled specially.
266 if (pOutMap->name() == getAggregationDimension().name) {
267 // Make sure it's read with these constraints.
268#if PIPELINING
269 pOutMap->serialize(eval, dds, m, ce_eval);
270#else
271 pOutMap->read();
272#endif
273 continue;
274 }
275
276 // Otherwise, find the map in the protogrid and copy it's data into this.
277 Array* pProtoGridMap = const_cast<Array*>(AggregationUtil::findMapByName(*pSubGridTemplate, pOutMap->name()));
278 NCML_ASSERT_MSG(pProtoGridMap, "Couldn't find map in prototype grid for map name=" + pOutMap->name());
279 BESDEBUG_FUNC(DEBUG_CHANNEL,
280 "About to call read() on prototype map vector name=" << pOutMap->name() << " and calling transfer constraints..." << endl);
281
282 // Make sure the protogrid maps were properly read
283 NCML_ASSERT_MSG(pProtoGridMap->read_p(), "Expected the prototype map to have been read but it wasn't.");
284
285 // Make sure the lengths match to be sure we're not gonna blow memory up
286 NCML_ASSERT_MSG(pOutMap->length() == pProtoGridMap->length(),
287 "Expected the prototype and output maps to have same length() after transfer of constraints, but they were not so we can't copy the data!");
288
289 // The dimensions will have been set up correctly now so length() is correct...
290 // We assume the pProtoGridMap matches at this point as well.
291 // So we can use this call to copy from one vector to the other
292 // so we don't use temp storage in between
293#if PIPELINING
294 pProtoGridMap->serialize(eval, dds, m, ce_eval);
295#else
296 pOutMap->reserve_value_capacity(); // reserves mem for length
297 pOutMap->set_value_slice_from_row_major_vector(*pProtoGridMap, 0);
298#endif
299 pOutMap->set_read_p(true);
300 }
301
302 // Set the cache bit.
303 set_read_p(true);
304
305#if PIPELINING
306 status = true;
307#else
308 status = libdap::Grid::serialize(eval, dds, m, ce_eval);
309#endif
310 }
311 else {
312 status = libdap::Grid::serialize(eval, dds, m, ce_eval);
313 }
314
315 return status;
316}
317
320
321Grid*
323{
324 return _pSubGridProto.get();
325}
326
327void GridAggregationBase::duplicate(const GridAggregationBase& rhs)
328{
329 _loader = DDSLoader(rhs._loader.getDHI());
330
331 _pSubGridProto.reset((rhs._pSubGridProto.get()) ? (static_cast<Grid*>(rhs._pSubGridProto->ptr_duplicate())) : nullptr);
332
333 _memberDatasets = rhs._memberDatasets;
334}
335
336void GridAggregationBase::cleanup()
337{
338 _loader.cleanup();
339
340 _memberDatasets.clear();
341 _memberDatasets.resize(0);
342}
343
344/* virtual */
346{
347 // Transfers constraints to the proto grid and reads it
349
350 // Copy the read-in, constrained maps from the proto grid
351 // into our output maps.
353}
354
355/* static */
356libdap::Grid*
357GridAggregationBase::cloneSubGridProto(const libdap::Grid& proto)
358{
359 return static_cast<Grid*>(const_cast<Grid&>(proto).ptr_duplicate());
360}
361
362void GridAggregationBase::printConstraints(const Array& fromArray)
363{
364 ostringstream oss;
365 AggregationUtil::printConstraints(oss, fromArray);
366 BESDEBUG("ncml:2", "Constraints for Grid: " << name() << ": " << oss.str() << endl);
367}
368
370{
371 Grid* pSubGridTemplate = getSubGridTemplate();
372 VALID_PTR(pSubGridTemplate);
373
374 // Call the specialized subclass constraint transfer method
375 transferConstraintsToSubGridHook(pSubGridTemplate);
376
377 // Pass it the values for the aggregated grid...
378 pSubGridTemplate->set_send_p(send_p());
379 pSubGridTemplate->set_in_selection(is_in_selection());
380
381 // Those settings will be used by read.
382 pSubGridTemplate->read();
383
384 // For some reason, some handlers only set read_p for the parts, not the whole!!
385 pSubGridTemplate->set_read_p(true);
386}
387
389{
390 Grid* pSubGridTemplate = getSubGridTemplate();
391 VALID_PTR(pSubGridTemplate);
392
393 Map_iter mapIt;
394 Map_iter mapEndIt = map_end();
395 for (mapIt = map_begin(); mapIt != mapEndIt; ++mapIt) {
396 Array* pOutMap = static_cast<Array*>(*mapIt);
397 VALID_PTR(pOutMap);
398
399 // If it isn't getting dumped, then don't bother with it
400 if (!(pOutMap->send_p() || pOutMap->is_in_selection())) {
401 continue;
402 }
403
404 // We don't want to touch the aggregation dimension since it's
405 // handled specially.
406 if (pOutMap->name() == aggDim.name) {
407 // Make sure it's read with these constraints.
408 pOutMap->read();
409 continue;
410 }
411
412 // Otherwise, find the map in the protogrid and copy it's data into this.
413 Array* pProtoGridMap = const_cast<Array*>(AggregationUtil::findMapByName(*pSubGridTemplate, pOutMap->name()));
414 NCML_ASSERT_MSG(pProtoGridMap, "Couldn't find map in prototype grid for map name=" + pOutMap->name());
415 BESDEBUG_FUNC(DEBUG_CHANNEL,
416 "About to call read() on prototype map vector name=" << pOutMap->name() << " and calling transfer constraints..." << endl);
417
418 // Make sure the protogrid maps were properly read
419 NCML_ASSERT_MSG(pProtoGridMap->read_p(), "Expected the prototype map to have been read but it wasn't.");
420
421 // Make sure the lengths match to be sure we're not gonna blow memory up
422 NCML_ASSERT_MSG(pOutMap->length() == pProtoGridMap->length(),
423 "Expected the prototype and output maps to have same length() "
424 "after transfer of constraints, but they were not so we can't "
425 "copy the data!");
426
427 // The dimensions will have been set up correctly now so length() is correct...
428 // We assume the pProtoGridMap matches at this point as well.
429 // So we can use this call to copy from one vector to the other
430 // so we don't use temp storage in between
431 pOutMap->reserve_value_capacity(); // reserves mem for length
432 pOutMap->set_value_slice_from_row_major_vector(*pProtoGridMap, 0);
433 pOutMap->set_read_p(true);
434 }
435}
436
437/* virtual */
439{
440 THROW_NCML_INTERNAL_ERROR("Impl me!");
441}
442
443}
static bool IsSet(const std::string &flagName)
see if the debug context flagName is set to true
Definition: BESDebug.h:168
virtual bool start(std::string name)
Definition: BESStopWatch.cc:67
static const libdap::Array * findMapByName(const libdap::Grid &inGrid, const std::string &findName)
static void printConstraints(std::ostream &os, const libdap::Array &fromArray)
void cleanup()
restore dhi to clean state
Definition: DDSLoader.cc:256
BESDataHandlerInterface & getDHI() const
Definition: DDSLoader.h:119
virtual const Dimension & getAggregationDimension() const =0
bool serialize(libdap::ConstraintEvaluator &eval, libdap::DDS &dds, libdap::Marshaller &m, bool ce_eval) override
virtual void readAndAggregateConstrainedMapsHook()
void copyProtoMapsIntoThisGrid(const Dimension &aggDim)
void setShapeFrom(const libdap::Grid &protoSubGrid, bool addMaps)
virtual const AMDList & getDatasetList() const
virtual void transferConstraintsToSubGridHook(Grid *pSubGrid)
Helper class for temporarily hijacking an existing dhi to load a DDX response for one particular file...