bes  Updated for version 3.20.6
MakeMaskFunction.cc
1 // -*- mode: c++; c-basic-offset:4 -*-
2 
3 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
4 // Access Protocol.
5 
6 // Copyright (c) 2015 OPeNDAP, Inc.
7 // Authors: Dan Holloway <dholloway@opendap.org>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //
23 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24 
25 #include "config.h"
26 
27 //#define DODS_DEBUG 1
28 
29 #include <cassert>
30 
31 #include <sstream>
32 #include <vector>
33 #include <algorithm>
34 
35 #include <Type.h>
36 #include <BaseType.h>
37 #include <Byte.h>
38 #include <Str.h>
39 
40 #include <Array.h>
41 #include <Error.h>
42 #include <DDS.h>
43 
44 #if 0
45 // No DAP4 support yet...
46 #include <DMR.h>
47 #include <D4Group.h>
48 #include <D4RValue.h>
49 #endif
50 
51 #include <debug.h>
52 #include <util.h>
53 
54 #include <BESDebug.h>
55 
56 #include "MakeMaskFunction.h"
57 #include "Odometer.h"
58 #include "functions_util.h"
59 
60 using namespace libdap;
61 using namespace std;
62 
63 namespace functions {
64 
65 vector<int> parse_dims(const string &shape); // defined in MakeArrayFunction.cc
66 
67 string make_mask_info =
68  string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
69  + "<function name=\"make_array\" version=\"1.0\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#make_mask\">\n"
70  + "</function>";
71 
79 int
80 find_value_index(double value, const vector<double> &map)
81 {
82  // If C++ hadn't borked passing functions to stl algorithms, we could use...
83  //vector<double>::iterator loc = find_if(map.begin(), map.end(), bind2nd(ptr_fun(double_eq), value));
84 
85  for (vector<double>::const_iterator i = map.begin(), e = map.end(); i != e; ++i) {
86  if (double_eq(*i, value, 0.1)) { // FIXME Hack: 0.1 epsilon is a hack. jhrg 5/25/15
87  return i - map.begin(); // there's an official iterator diff function somewhere...
88  }
89  }
90 
91  return -1;
92 }
93 
105 vector<int>
106 find_value_indices(const vector<double> &values, const vector< vector<double> > &maps)
107 {
108  assert(values.size() == maps.size());
109 
110  vector<int> indices;
111  vector <vector<double> >::const_iterator m = maps.begin();
112  for (vector<double>::const_iterator d = values.begin(), e = values.end(); d != e; ++d) {
113  indices.push_back(find_value_index(*d, *m++));
114  }
115 
116  return indices;
117 }
118 
124 bool all_indices_valid(vector<int> indices)
125 {
126  return find(indices.begin(), indices.end(), -1) == indices.end();
127 }
128 
142 template<typename T>
143 void make_mask_helper(const vector<Array*> dims, Array *tuples, vector<dods_byte> &mask)
144 {
145  vector< vector<double> > dim_value_vecs(dims.size());
146  int i = 0; // index the dim_value_vecs vector of vectors;
147  for (vector<Array*>::const_iterator d = dims.begin(), e = dims.end(); d != e; ++d) {
148  // This version of extract...() takes the vector<double> by reference:
149  // In util.cc/h: void extract_double_array(Array *a, vector<double> &dest)
150  extract_double_array(*d, dim_value_vecs.at(i++));
151  }
152 
153  // Construct and Odometer used to calculate offsets
154  Odometer::shape shape(dims.size());
155 
156  int j = 0; // index the shape vector for an Odometer;
157  for (vector<Array*>::const_iterator d = dims.begin(), e = dims.end(); d != e; ++d) {
158  shape[j++] = (*d)->length();
159  }
160 
161  Odometer odometer(shape);
162 
163  // Copy the 'tuple' data to a simple vector<T>
164  vector<T> data(tuples->length());
165  tuples->value(&data[0]);
166 
167  // Iterate over the tuples, searching the dimensions for their values
168  int nDims = dims.size();
169  int nTuples = data.size() / nDims;
170 
171  // NB: 'data' holds the tuple values
172 
173  // unsigned int tuple_offset = 0; // an optimization...
174  for (int n = 0; n < nTuples; ++n) {
175  vector<double> tuple(nDims);
176  // Build the next tuple
177  for (int dim = 0; dim < nDims; ++dim) {
178  // could replace 'tuple * nDims' with 'tuple_offset'
179  tuple[dim] = data[n * nDims + dim];
180  }
181 
182  DBG(cerr << "tuple: ");
183  DBGN(copy(tuple.begin(), tuple.end(), ostream_iterator<int>(std::cerr, " ")));
184  DBGN(cerr << endl);
185 
186  // find indices for tuple-values in the specified
187  // target-grid dimensions
188  vector<int> indices = find_value_indices(tuple, dim_value_vecs);
189  DBG(cerr << "indices: ");
190  DBGN(copy(indices.begin(), indices.end(), ostream_iterator<int>(std::cerr, " ")));
191  DBGN(cerr << endl);
192 
193  // if all of the indices are >= 0, then add this point to the mask
194  if (all_indices_valid(indices)) {
195 
196  // Pass identified indices to Odometer, it will automatically
197  // calculate offset within defined 'shape' using those index values.
198  // Result of set_indices() will update d_offset value, accessible
199  // using the Odometer::offset() accessor.
200  odometer.set_indices(indices);
201  DBG(cerr << "odometer.offset(): " << odometer.offset() << endl);
202  mask[odometer.offset()] = 1;
203  }
204  }
205 }
206 
216 void function_dap2_make_mask(int argc, BaseType * argv[], DDS &, BaseType **btpp)
217 {
218  if (argc == 0) {
219  Str *response = new Str("info");
220  response->set_value(make_mask_info);
221  *btpp = response;
222  return;
223  }
224 
225  // Check for three args or more. The first two must be strings.
226  DBG(cerr << "argc = " << argc << endl);
227  if (argc < 3)
228  throw Error(malformed_expr,
229  "make_mask(shape_string,[dim1,...],$TYPE(dim1_value0,dim2_value0,...)) requires at least four arguments.");
230 
231  if (argv[0]->type() != dods_str_c)
232  throw Error(malformed_expr, "make_mask(): first argument must point to a string variable.");
233 
234  string shape_str = extract_string_argument(argv[0]);
235  vector<int> shape = parse_dims(shape_str);
236 
237  // Create the 'mask' array using the shape of the target grid variable's array.
238  int length = 1;
239  for (vector<int>::iterator i = shape.begin(), e = shape.end(); i != e; ++i)
240  length *= *i;
241  vector<dods_byte> mask(length, 0); // Create 'mask', initialized with zero's
242  unsigned int nDims = shape.size();
243 
244  // read argv[1] -> argv[1+numberOfDims]; the grid dimensions where we will find the values
245  // of the mask tuples. Also note that the number of dims (shape.size() above) should be the
246  // same as argc-2.
247  assert(nDims == (unsigned int)argc-2);
248 
249  vector<Array*> dims;
250  for (unsigned int i = 0; i < nDims; i++) {
251 
252  BaseType *btp = argv[1 + i];
253  if (btp->type() != dods_array_c) {
254  throw Error(malformed_expr,
255  "make_mask(): dimension-name arguments must point to Grid variable dimensions.");
256  }
257 
258  Array *a = static_cast<Array*>(btp);
259 
260  // Check that each map size matches the 'shape' info passed in the first arg.
261  // This might not be the case for DAP4 (or if we change this to support level
262  // 2 swath data).
263  assert(a->dimension_size(a->dim_begin()) == shape.at(i));
264 
265  a->read();
266  a->set_read_p(true);
267  dims.push_back(a);
268  }
269 
270  BaseType *btp = argv[argc - 1];
271  if (btp->type() != dods_array_c) {
272  throw Error(malformed_expr, "make_mask(): last argument must be an array.");
273  }
274 
275  check_number_type_array(btp); // Throws an exception if not a numeric type.
276 
277  Array *tuples = static_cast<Array*>(btp);
278 
279  switch (tuples->var()->type()) {
280  // All mask values are stored in Byte DAP variables by the stock argument parser
281  // except values too large; those are stored in a UInt32
282  case dods_byte_c:
283  make_mask_helper<dods_byte>(dims, tuples, mask);
284  break;
285 
286  case dods_int16_c:
287  make_mask_helper<dods_int16>(dims, tuples, mask);
288  break;
289 
290  case dods_uint16_c:
291  make_mask_helper<dods_uint16>(dims, tuples, mask);
292  break;
293 
294  case dods_int32_c:
295  make_mask_helper<dods_int32>(dims, tuples, mask);
296  break;
297 
298  case dods_uint32_c:
299  make_mask_helper<dods_uint32>(dims, tuples, mask);
300  break;
301 
302  case dods_float32_c:
303  make_mask_helper<dods_float32>(dims, tuples, mask);
304  break;
305 
306  case dods_float64_c:
307  make_mask_helper<dods_float64>(dims, tuples, mask);
308  break;
309 
310  case dods_str_c:
311  case dods_url_c:
312  default:
313  throw InternalErr(__FILE__, __LINE__,
314  "make_mask(): Expect an array of mask points (numbers) but found something else instead.");
315  }
316 
317  Array *dest = new Array("mask", 0); // The ctor for Array copies the prototype pointer...
318  BaseTypeFactory btf;
319  dest->add_var_nocopy(new Byte("mask")); // ... so use add_var_nocopy() to add it instead
320 
321  for (vector<int>::iterator i = shape.begin(), e = shape.end(); i != e; ++i)
322  dest->append_dim(*i);
323 
324  dest->set_value(mask, length);
325 
326  dest->set_read_p(true);
327 
328  *btpp = dest;
329 }
330 
331 } // namespace functions
libdap
Definition: BESDapFunctionResponseCache.h:35
Error