OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
GridAggregationBase.cc
Go to the documentation of this file.
1 // 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 #include "AggregationUtil.h" // agg_util
31 #include <Array.h> // libdap
32 #include <D4Group.h>
33 #include <Constructor.h>
34 #include <D4Maps.h>
35 #include <InternalErr.h>
36 
37 #include "GridAggregationBase.h" // agg_util
38 #include "NCMLDebug.h"
39 
40 using libdap::Array;
41 using libdap::BaseType;
42 using libdap::Grid;
43 #if 1
44 using libdap::D4Group;
45 using libdap::Constructor;
46 using libdap::InternalErr;
47 using libdap::D4Maps;
48 using libdap::D4Map;
49 #endif
50 
51 // Local debug flags
52 static const string DEBUG_CHANNEL("agg_util");
53 static const bool PRINT_CONSTRAINTS(true);
54 
55 namespace agg_util
56 {
58  const libdap::Grid& proto,
59  const AMDList& memberDatasets,
60  const DDSLoader& loaderProto)
61  : Grid(proto)
62  , _loader(loaderProto.getDHI())
63  , _pSubGridProto(cloneSubGridProto(proto))
64  , _memberDatasets(memberDatasets)
65  {
66  }
67 
69  const string& name,
70  const AMDList& memberDatasets,
71  const DDSLoader& loaderProto)
72  : Grid(name)
73  , _loader(loaderProto.getDHI())
74  , _pSubGridProto(0)
75  , _memberDatasets(memberDatasets)
76  {
77  }
78 
80  : Grid(proto)
81  , _loader(proto._loader.getDHI())
82  , _pSubGridProto(0) // init below
83  , _memberDatasets()
84  {
85  duplicate(proto);
86  }
87 
88  /* virtual */
90  {
91  cleanup();
92  }
93 
96  {
97  if (this != &rhs)
98  {
99  cleanup();
100  Grid::operator=(rhs);
101  duplicate(rhs);
102  }
103  return *this;
104  }
105 
106 #if 1
107 BaseType *
108 GridAggregationBase::transform_to_dap4(D4Group *root, Constructor *container)
109 {
110  BaseType *btp = array_var()->transform_to_dap4(root, container);
111  Array *coverage = static_cast<Array*>(btp);
112  if (!coverage) throw InternalErr(__FILE__, __LINE__, "Expected an Array while transforming a Grid (coverage)");
113 
114  coverage->set_parent(container);
115 
116  // Next find the maps; add them to the coverage and to the container,
117  // the latter only on the condition that they are not already there.
118 
119  for (Map_iter i = map_begin(), e = map_end(); i != e; ++i) {
120  btp = (*i)->transform_to_dap4(root, container);
121  Array *map = static_cast<Array*>(btp);
122  if (!map) throw InternalErr(__FILE__, __LINE__, "Expected an Array while transforming a Grid (map)");
123 
124  // map must be non-null (Grids cannot contain Grids in DAP2)
125  if (map) {
126  // Only add the map/array if it not already present; given the scoping rules
127  // for DAP2 and the assumption the DDS is valid, testing for the same name
128  // is good enough.
129  if (!root->var(map->name())) {
130  map->set_parent(container);
131  container->add_var_nocopy(map); // this adds the array to the container
132  }
133  D4Map *dap4_map = new D4Map(map->name(), map, coverage); // bind the 'map' to the coverage
134  coverage->maps()->add_map(dap4_map); // bind the coverage to the map
135  }
136  else {
137  throw InternalErr(__FILE__, __LINE__,
138  "transform_to_dap4() returned a null value where there can be no Grid.");
139  }
140  }
141 
142  container->add_var_nocopy(coverage);
143 
144  // Since a Grid (DAP2) to a Coverage (DAP4) removes a lexical scope
145  // in favor of a set of relations, Grid::transform_to_dap4() does not
146  // return a BaseType*. Callers should assume it has correctly added
147  // stuff to the container and group.
148  return 0;
149 }
150 #endif
151 
152 void
153  GridAggregationBase::setShapeFrom(const libdap::Grid& constProtoSubGrid, bool addMaps)
154  {
155  // calls used are semantically const, but not syntactically.
156  Grid& protoSubGrid = const_cast<Grid&>(constProtoSubGrid);
157 
158  // Save a clone of the template for read() to use.
159  // We always use these maps...
160  _pSubGridProto = auto_ptr<Grid>(cloneSubGridProto(protoSubGrid));
161 
162  // Pass in the data array and maps from the proto by hand.
163  Array* pDataArrayTemplate = protoSubGrid.get_array();
164  VALID_PTR(pDataArrayTemplate);
165  set_array( static_cast<Array*>(pDataArrayTemplate->ptr_duplicate()) );
166 
167  // Now the maps in order if asked
168  if (addMaps)
169  {
170  Grid::Map_iter endIt = protoSubGrid.map_end();
171  for (Grid::Map_iter it = protoSubGrid.map_begin();
172  it != endIt;
173  ++it)
174  {
175  // have to case, the iter is for some reason BaseType*
176  Array* pMap = dynamic_cast<Array*>(*it);
177  VALID_PTR(pMap);
178  add_map(pMap, true); // add as a copy
179  }
180  }
181  }
182 
183  /* virtual */
184  const AMDList&
186  {
187  return _memberDatasets;
188  }
189 
190  /* virtual */
191  bool
193  {
194  BESDEBUG_FUNC(DEBUG_CHANNEL, "Function entered..." << endl);
195 
196  if (read_p())
197  {
198  BESDEBUG_FUNC(DEBUG_CHANNEL, "read_p() set, early exit!");
199  return true;
200  }
201 
202  if (PRINT_CONSTRAINTS)
203  {
204  printConstraints(*(get_array()));
205  }
206 
207  // Call the subclass hook methods to do this work properly
209 
210  // Now make the read call on the data array.
211  // The aggregation subclass will do the right thing.
212  Array* pAggArray = get_array();
213  VALID_PTR(pAggArray);
214 
215  // Only do this portion if the array part is supposed to serialize!
216  if (pAggArray->send_p() || pAggArray->is_in_selection())
217  {
218  pAggArray->read();
219  }
220 
221  // Set the cache bit.
222  set_read_p(true);
223  return true;
224  }
225 
228 
229  Grid*
231  {
232  return _pSubGridProto.get();
233  }
234 
235  void
236  GridAggregationBase::duplicate(const GridAggregationBase& rhs)
237  {
238  _loader = DDSLoader(rhs._loader.getDHI());
239 
240  std::auto_ptr<Grid> pGridTemplateClone(( (rhs._pSubGridProto.get()) ?
241  (static_cast<Grid*>(rhs._pSubGridProto->ptr_duplicate())) :
242  (0) ));
243  _pSubGridProto = pGridTemplateClone;
244 
245  _memberDatasets = rhs._memberDatasets;
246  }
247 
248  void
249  GridAggregationBase::cleanup() throw()
250  {
251  _loader.cleanup();
252 
253  _memberDatasets.clear();
254  _memberDatasets.resize(0);
255  }
256 
257  /* virtual */
258  void
260  {
261  // Transfers constraints to the proto grid and reads it
263 
264  // Copy the read-in, constrained maps from the proto grid
265  // into our output maps.
267  }
268 
269  /* static */
270  libdap::Grid*
271  GridAggregationBase::cloneSubGridProto(const libdap::Grid& proto)
272  {
273  return static_cast<Grid*>( const_cast<Grid&>(proto).ptr_duplicate() );
274  }
275 
276  void
278  {
279  ostringstream oss;
280  AggregationUtil::printConstraints(oss, fromArray);
281  BESDEBUG("ncml:2", "Constraints for Grid: " << name() << ": " << oss.str() << endl);
282  }
283 
284  void
286  {
287  Grid* pSubGridTemplate = getSubGridTemplate();
288  VALID_PTR(pSubGridTemplate);
289 
290  // Call the specialized subclass constraint transfer method
291  transferConstraintsToSubGridHook(pSubGridTemplate);
292 
293  // Pass it the values for the aggregated grid...
294  pSubGridTemplate->set_send_p(send_p());
295  pSubGridTemplate->set_in_selection(is_in_selection());
296 
297  // Those settings will be used by read.
298  pSubGridTemplate->read();
299 
300  // For some reason, some handlers only set read_p for the parts, not the whole!!
301  pSubGridTemplate->set_read_p(true);
302  }
303 
304  void
306  {
307  Grid* pSubGridTemplate = getSubGridTemplate();
308  VALID_PTR(pSubGridTemplate);
309 
310  Map_iter mapIt;
311  Map_iter mapEndIt = map_end();
312  for (mapIt = map_begin();
313  mapIt != mapEndIt;
314  ++mapIt)
315  {
316  Array* pOutMap = static_cast<Array*>(*mapIt);
317  VALID_PTR(pOutMap);
318 
319  // If it isn't getting dumped, then don't bother with it
320  if (! (pOutMap->send_p() || pOutMap->is_in_selection()) )
321  {
322  continue;
323  }
324 
325  // We don't want to touch the aggregation dimension since it's
326  // handled specially.
327  if (pOutMap->name() == aggDim.name)
328  {
329  if (PRINT_CONSTRAINTS)
330  {
331  BESDEBUG_FUNC(DEBUG_CHANNEL,
332  "About to call read() on the map for the new outer dimension name=" <<
333  aggDim.name <<
334  " It's constraints are:" << endl);
335  printConstraints(*pOutMap);
336  }
337 
338  // Make sure it's read with these constraints.
339  pOutMap->read();
340  continue;
341  }
342 
343  // Otherwise, find the map in the protogrid and copy it's data into this.
344  Array* pProtoGridMap = const_cast<Array*>(AggregationUtil::findMapByName(*pSubGridTemplate, pOutMap->name()));
345  NCML_ASSERT_MSG(pProtoGridMap,
346  "Couldn't find map in prototype grid for map name=" + pOutMap->name() );
347  BESDEBUG_FUNC(DEBUG_CHANNEL,
348  "About to call read() on prototype map vector name="
349  << pOutMap->name() << " and calling transfer constraints..." << endl);
350 
351  // Make sure the protogrid maps were properly read
352  NCML_ASSERT_MSG(pProtoGridMap->read_p(),
353  "Expected the prototype map to have been read but it wasn't.");
354 
355  // Make sure the lengths match to be sure we're not gonna blow memory up
356  NCML_ASSERT_MSG(pOutMap->length() == pProtoGridMap->length(),
357  "Expected the prototype and output maps to have same length() "
358  "after transfer of constraints, but they were not so we can't "
359  "copy the data!");
360 
361  // The dimensions will have been set up correctly now so length() is correct...
362  // We assume the pProtoGridMap matches at this point as well.
363  // So we can use this call to copy from one vector to the other
364  // so we don't use temp storage in between
365  pOutMap->reserve_value_capacity(); // reserves mem for length
366  pOutMap->set_value_slice_from_row_major_vector(*pProtoGridMap, 0);
367  pOutMap->set_read_p(true);
368  }
369  }
370 
371  /* virtual */
372  void
374  {
375  THROW_NCML_INTERNAL_ERROR("Impl me!");
376  }
377 
378 }
virtual const AMDList & getDatasetList() const
Accessor for the dataset description list that describes this aggregation.
#define BESDEBUG_FUNC(channel, info)
Definition: NCMLDebug.h:58
std::string name
Definition: Dimension.h:61
void copyProtoMapsIntoThisGrid(const Dimension &aggDim)
Copy the template's read in subgrid maps into this.
void setShapeFrom(const libdap::Grid &protoSubGrid, bool addMaps)
Use the data array and maps from protoSubGrid as the initial point for the shape of the Grid...
static const libdap::Array * findMapByName(const libdap::Grid &inGrid, const std::string &findName)
Find the given map name in the given Grid and return it if found, else NULL.
Helper class for temporarily hijacking an existing dhi to load a DDX response for one particular file...
#define NCML_ASSERT_MSG(cond, msg)
Definition: NCMLDebug.h:83
GridAggregationBase(const libdap::Grid &proto, const AMDList &memberDatasets, const DDSLoader &loaderProto)
BESDataHandlerInterface & getDHI() const
Return a reference to the dhi we are using.
Definition: DDSLoader.h:121
virtual bool read()
Read in only those datasets that are in the constrained output making sure to apply the internal dime...
void readProtoSubGrid()
Transfer constraints properly from this object's maps and read in the proto subgrid entirely (respect...
void printConstraints(const libdap::Array &fromArray)
Struct for holding information about a dimension of data, minimally a name and a cardinality (size)...
Definition: Dimension.h:50
virtual const Dimension & getAggregationDimension() const =0
Get the contained aggregation dimension info.
#define THROW_NCML_INTERNAL_ERROR(msg)
Definition: NCMLDebug.h:61
virtual void readAndAggregateConstrainedMapsHook()
Called from read()! Invokes the user hooks eventually.
std::vector< RCPtr< AggMemberDataset > > AMDList
virtual void transferConstraintsToSubGridHook(Grid *pSubGrid)
To be specialized in subclass to copy constraints on this object properly into the given pSubGrid map...
Grid * getSubGridTemplate()
Reveals the raw ptr, but only to subclasses.
#define VALID_PTR(ptr)
Definition: NCMLDebug.h:88
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
GridAggregationBase & operator=(const GridAggregationBase &rhs)
BaseType * transform_to_dap4(libdap::D4Group *root, libdap::Constructor *container)
static void printConstraints(std::ostream &os, const libdap::Array &fromArray)
Stream out the current constraints for all the dimensions in the Array.
void cleanup()
restore dhi to clean state
Definition: DDSLoader.cc:209