OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
ArrayJoinExistingAggregation.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 
31 
32 #include "AggregationException.h" // agg_util
33 #include "AggregationUtil.h" // agg_util
34 #include "NCMLDebug.h"
35 #include <sstream>
36 
37 static const string DEBUG_CHANNEL(NCML_MODULE_DBG_CHANNEL_2);
38 static const bool PRINT_CONSTRAINTS = true;
39 
40 namespace agg_util
41 {
42 
44  const libdap::Array& granuleTemplate,
45  const AMDList& memberDatasets,
46  std::auto_ptr<ArrayGetterInterface>& arrayGetter,
47  const Dimension& joinDim
48  )
49  : ArrayAggregationBase(granuleTemplate, memberDatasets, arrayGetter)
50  , _joinDim(joinDim)
51  {
52  BESDEBUG_FUNC(DEBUG_CHANNEL,
53  "Making the aggregated outer dimension be: " +
54  joinDim.toString() + "\n");
55 
56  // We created the array with the given granule prototype, but the resulting
57  // outer dimension size must be calculated according to the
58  // value in the passed in dimension object.
59  libdap::Array::dimension& rOuterDim = *(dim_begin());
60  NCML_ASSERT_MSG(rOuterDim.name == joinDim.name,
61  "The outer dimension name of this is not the expected "
62  "outer dimension name! Broken precondition: This ctor cannot be called "
63  "without this being true!");
64  rOuterDim.size = joinDim.size;
65  // Force it to recompute constraints since we changed size.
66  reset_constraint();
67 
68 
69  ostringstream oss;
71  if (PRINT_CONSTRAINTS)
72  {
73  // constraints as well to ensure reset worked.
75  }
76  BESDEBUG_FUNC(DEBUG_CHANNEL,
77  "Constrained Dims after set are: " +
78  oss.str());
79  }
80 
83  )
85  , _joinDim(rhs._joinDim)
86  {
87  duplicate(rhs);
88  }
89 
90  /* virtual */
92  {
93  cleanup();
94  }
95 
98  {
99  if (this != &rhs)
100  {
101  cleanup();
103  duplicate(rhs);
104  }
105  return *this;
106  }
107 
108  /* virtual */
111  {
112  return new ArrayJoinExistingAggregation(*this);
113  }
114 
116  // Private Impl Below
117 
118  void
119  ArrayJoinExistingAggregation::duplicate(const ArrayJoinExistingAggregation& rhs)
120  {
121  _joinDim = rhs._joinDim;
122  }
123 
124  void
125  ArrayJoinExistingAggregation::cleanup() throw()
126  {
127  }
128 
129  /* virtual */
130  void
132  {
133  // transfer the constraints from this object into the subArray template
134  // skipping our first dim which is the join dim we need to do specially every
135  // granule in the read hook.
137  &(getGranuleTemplateArray()), // into this template
138  *this, // from this
139  true, // skip first dim in the copy since we handle it special
140  true, // also skip it in the toArray for the same reason.
141  true, // print debug
142  DEBUG_CHANNEL); // on this channel
143  }
144 
145  void
147  {
148  // outer one is the first in iteration
149  const Array::dimension& outerDim = *(dim_begin());
150  BESDEBUG("ncml", "Aggregating datasets array with outer dimension constraints: " <<
151  " start=" << outerDim.start <<
152  " stride=" << outerDim.stride <<
153  " stop=" << outerDim.stop << endl);
154 
155  try
156  {
157  // assumes the constraints are already set properly on this
158  reserve_value_capacity();
159 
160  // Start the iteration state for the granule.
161  const AMDList& datasets = getDatasetList(); // the list
162  NCML_ASSERT(!datasets.empty());
163  int currDatasetIndex = 0; // index into datasets
164  const AggMemberDataset* pCurrDataset = (datasets[currDatasetIndex]).get();
165 
166  int outerDimIndexOfCurrDatasetHead = 0;
167  int currDatasetSize = int(pCurrDataset->getCachedDimensionSize(_joinDim.name));
168  bool currDatasetWasRead = false;
169 
170  // where in this output array we are writing next
171  unsigned int nextOutputBufferElementIndex = 0;
172 
173  // Traverse the outer dimension constraints,
174  // Keeping track of which dataset we need to
175  // be inside for the given values of the constraint.
176  for (int outerDimIndex = outerDim.start;
177  outerDimIndex <= outerDim.stop && outerDimIndex < outerDim.size;
178  outerDimIndex += outerDim.stride)
179  {
180  // Figure out where the given outer index maps into in local granule space
181  int localGranuleIndex = outerDimIndex - outerDimIndexOfCurrDatasetHead;
182 
183  // if this is beyond the dataset end, move state to the next dataset
184  // and try again until we're in the proper interval, with proper dataset.
185  while (localGranuleIndex >= currDatasetSize)
186  {
187  localGranuleIndex -= currDatasetSize;
188  outerDimIndexOfCurrDatasetHead += currDatasetSize;
189  ++currDatasetIndex;
190  NCML_ASSERT(currDatasetIndex < int(datasets.size()));
191  pCurrDataset = datasets[currDatasetIndex].get();
192  currDatasetSize = pCurrDataset->getCachedDimensionSize(_joinDim.name);
193  currDatasetWasRead = false;
194 
195  BESDEBUG_FUNC(DEBUG_CHANNEL,
196  "The constraint traversal passed a granule boundary "
197  << "on the outer dimension and is stepping forward into "
198  << "granule index="
199  << currDatasetIndex
200  << endl);
201  }
202 
203  // If we haven't read in this granule yet (we passed a boundary)
204  // then do it now. Map constraints into the local granule space.
205  if (!currDatasetWasRead)
206  {
207  BESDEBUG_FUNC(DEBUG_CHANNEL,
208  " Current granule dataset was traversed but not yet "
209  "read and copied into output. Mapping constraints "
210  "and calling read()..." << endl);
211 
212  // Set up a constraint object for the actual granule read
213  // so that it only loads the data values in which we are
214  // interested.
215  Array& granuleConstraintTemplate = getGranuleTemplateArray();
216 
217  // The inner dim constraints were set up in the containing read() call.
218  // The outer dim was left open for us to fix now...
219  Array::Dim_iter outerDimIt = granuleConstraintTemplate.dim_begin();
220 
221  // modify the outerdim size to match the dataset we need to
222  // load. The inners MUST match so we can let those get
223  //checked later...
224  outerDimIt->size = currDatasetSize;
225  outerDimIt->c_size = currDatasetSize; // this will get recalc below?
226 
227  // find the mapped endpoint
228  // Basically, the fullspace endpoint mapped to local offset,
229  // clamped into the local granule size.
230  int granuleStopIndex =
231  std::min(outerDim.stop - outerDimIndexOfCurrDatasetHead,
232  currDatasetSize-1);
233 
234  // we must clamp the stride to the interval of the
235  // dataset in order to avoid an exception in
236  // add_constraint on stride being larger than dataset.
237  int clampedStride = std::min(outerDim.stride, currDatasetSize);
238  granuleConstraintTemplate.add_constraint(outerDimIt,
239  localGranuleIndex,
240  clampedStride,
241  granuleStopIndex // mapped endpoint clamped within this granule
242  );
243 
244  // Do the constrained read and copy it into this output buffer
246  *this, // into the output buffer of this object
247  nextOutputBufferElementIndex, // into the next open slice
248  getGranuleTemplateArray(), // constraints we just setup
249  name(), // aggvar name
250  const_cast<AggMemberDataset&>(*pCurrDataset), // Dataset who's DDS should be searched
252  DEBUG_CHANNEL
253  );
254 
255  // Jump output buffer index forward by the amount we added.
256  nextOutputBufferElementIndex += getGranuleTemplateArray().length();
257  currDatasetWasRead = true;
258 
259  BESDEBUG_FUNC(DEBUG_CHANNEL,
260  " The granule index "
261  << currDatasetIndex
262  << " was read with constraints and copied into the aggregation output."
263  << endl);
264  } // !currDatasetWasRead
265  } // for loop over outerDim
266  } // try
267 
268  catch (AggregationException& ex)
269  {
270  THROW_NCML_PARSE_ERROR(-1, ex.what());
271  }
272 
273  }
274 
275 } // namespace agg_util
ArrayAggregationBase & operator=(const ArrayAggregationBase &rhs)
Abstract helper superclass for allowing lazy access to the DataDDS for an aggregation.
unsigned int size
Definition: Dimension.h:64
#define BESDEBUG_FUNC(channel, info)
Definition: NCMLDebug.h:58
std::string name
Definition: Dimension.h:61
libdap::Array & getGranuleTemplateArray()
Accessor for subclasses Note this is protected, so not const! Subclasses may mutate the return hence ...
#define NCML_ASSERT(cond)
Definition: NCMLDebug.h:80
virtual void readConstrainedGranuleArraysAndAggregateDataHook()
The meat of the subclass impl of read().
Helper class for temporarily hijacking an existing dhi to load a DDX response for one particular file...
ArrayJoinExistingAggregation & operator=(const ArrayJoinExistingAggregation &rhs)
#define NCML_MODULE_DBG_CHANNEL_2
Definition: NCMLDebug.h:51
#define NCML_ASSERT_MSG(cond, msg)
Definition: NCMLDebug.h:83
ArrayJoinExistingAggregation(const libdap::Array &granuleTemplate, const AMDList &memberDatasets, std::auto_ptr< ArrayGetterInterface > &arrayGetter, const Dimension &joinDim)
Construct a joinNew Array aggregation given the parameters.
virtual unsigned int getCachedDimensionSize(const std::string &dimName) const =0
Get the size of the given dimension named dimName cached within the dataset.
Base class for subclasses of libdap::Array which perform aggregation on a list of AggMemberDatasets w...
#define THROW_NCML_PARSE_ERROR(parseLine, msg)
Definition: NCMLDebug.h:69
std::string toString() const
Dump to string and return (using operator<<)
Definition: Dimension.cc:63
Struct for holding information about a dimension of data, minimally a name and a cardinality (size)...
Definition: Dimension.h:50
virtual void transferOutputConstraintsIntoGranuleTemplateHook()
IMPL of subclass hook for read() to copy granule constraints properly (inner dim ones).
const ArrayGetterInterface & getArrayGetterInterface() const
Accessor for subclasses Note this is protected, so not const! Subclasses may mutate the return hence ...
#define min(a, b)
Definition: os_utils.h:71
static void addDatasetArrayDataToAggregationOutputArray(libdap::Array &oOutputArray, unsigned int atIndex, const libdap::Array &constrainedTemplateArray, const string &varName, AggMemberDataset &dataset, const ArrayGetterInterface &arrayGetter, const string &debugChannel)
Load the given dataset's DataDDS.
std::vector< RCPtr< AggMemberDataset > > AMDList
const AMDList & getDatasetList() const
Get the list of AggMemberDataset's that comprise this aggregation.
static void transferArrayConstraints(libdap::Array *pToArray, const libdap::Array &fromArray, bool skipFirstFromDim, bool skipFirstToDim, bool printDebug=false, const std::string &debugChannel="agg_util")
Copy the constraints from the from Array into the pToArray in Dim_iter order.
static void printDimensions(std::ostream &os, const libdap::Array &fromArray)
Print out the dimensions name and size for the given Array into os.
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
Exception class used by AggregationUtil and other agg_util classes to pass generic exceptions upward ...
virtual ArrayJoinExistingAggregation * ptr_duplicate()
Virtual Constructor: Make a deep copy (clone) of the object and return it.
static void printConstraints(std::ostream &os, const libdap::Array &fromArray)
Stream out the current constraints for all the dimensions in the Array.