bes  Updated for version 3.20.6
MaskArrayFunction.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: James Gallagher <jgallagher@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 #include <cassert>
28 
29 #include <sstream>
30 #include <vector>
31 #include <algorithm>
32 
33 #include <Type.h>
34 #include <BaseType.h>
35 #include <Str.h>
36 #include <Array.h>
37 #include <Structure.h>
38 #include <Error.h>
39 #include <DDS.h>
40 
41 #include <DMR.h>
42 #include <D4Group.h>
43 #include <D4RValue.h>
44 
45 #include <debug.h>
46 #include <util.h>
47 
48 #include <BaseTypeFactory.h>
49 
50 #include <BESDebug.h>
51 
52 #include "MakeArrayFunction.h"
53 #include "functions_util.h"
54 
55 using namespace libdap;
56 
57 namespace functions {
58 
59 string mask_array_info =
60  string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
61  + "<function name=\"mask_array\" version=\"1.0\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#mask_array\">\n"
62  + "</function>";
63 
76 template <typename T>
77 void mask_array_helper(Array *array, double no_data_value, const vector<dods_byte> &mask)
78 {
79  // Read the data array's data
80  array->read();
81  array->set_read_p(true);
82  vector<T> data(array->length());
83  array->value(&data[0]);
84 
85  assert(data.size() == mask.size());
86 
87  // mask the data array
88  vector<dods_byte>::const_iterator mi = mask.begin();
89  for (typename vector<T>::iterator i = data.begin(), e = data.end(); i != e; ++i) {
90  if (!*mi++) *i = no_data_value;
91  }
92 
93  // reset the values
94  array->set_value(data, data.size());
95 }
96 
111 void function_mask_dap2_array(int argc, BaseType * argv[], DDS &, BaseType **btpp)
112 {
113  // Called with no args? Return usage information.
114  if (argc == 0) {
115  Str *response = new Str("info");
116  response->set_value(mask_array_info);
117  *btpp = response;
118  return;
119  }
120 
121  BESDEBUG("functions", "function_mask_dap2_array() - argc: " << argc << endl);
122 
123  // QC args: must have a mask, ND value and 1+ array.
124  if (argc < 3) throw Error(malformed_expr, "In mask_array(Array1, ..., ArrayN, NoData, Mask) requires at least three arguments.");
125 
126  // Get the NoData value; it must be a number
127  double no_data_value = extract_double_value(argv[argc-2]);
128 
129  // Get the mask, which must be a DAP Byte array
130  check_number_type_array(argv[argc-1]); // Throws Error if not a numeric array
131  Array *mask_var = static_cast<Array*>(argv[argc-1]);
132  if (mask_var->var()->type() != dods_byte_c)
133  throw Error(malformed_expr, "In mask_array(): Expected the last argument (the mask) to be a byte array.");
134 
135  mask_var->read();
136  mask_var->set_read_p(true);
137  vector<dods_byte> mask(mask_var->length());
138  mask_var->value(&mask[0]); // get the value
139 
140  // Now mask the arrays
141  for (int i = 0; i < argc-2; ++i) {
142  check_number_type_array (argv[i]);
143  Array *array = static_cast<Array*>(argv[i]);
144  // The Mask and Array(s) should match in shape, but to simplify use, we test
145  // only that they have the same number of elements.
146  if ((vector<dods_byte>::size_type)array->length() != mask.size())
147  throw Error(malformed_expr, "In make_array(): The array '" + array->name() + "' and the mask do not match in size.");
148 
149  switch (array->var()->type()) {
150  case dods_byte_c:
151  mask_array_helper<dods_byte>(array, no_data_value, mask);
152  break;
153  case dods_int16_c:
154  mask_array_helper<dods_int16>(array, no_data_value, mask);
155  break;
156  case dods_uint16_c:
157  mask_array_helper<dods_uint16>(array, no_data_value, mask);
158  break;
159  case dods_int32_c:
160  mask_array_helper<dods_int32>(array, no_data_value, mask);
161  break;
162  case dods_uint32_c:
163  mask_array_helper<dods_uint32>(array, no_data_value, mask);
164  break;
165  case dods_float32_c:
166  mask_array_helper<dods_float32>(array, no_data_value, mask);
167  break;
168  case dods_float64_c:
169  mask_array_helper<dods_float64>(array, no_data_value, mask);
170  break;
171  default:
172  throw InternalErr(__FILE__, __LINE__, "In mask_array(): Type " + array->type_name() + " not handled.");
173  }
174  }
175 
176  // Build the return value(s) - this means make copies of the masked arrays
177  BaseType *dest = 0; // null_ptr
178  if (argc == 3)
179  dest = argv[0]->ptr_duplicate();
180  else {
181  dest = new Structure("masked_arays");
182  for (int i = 0; i < argc-2; ++i) {
183  dest->add_var(argv[i]); //add_var() copies its arg
184  }
185  }
186 
187  dest->set_send_p(true);
188  dest->set_read_p(true);
189 
190  // Return the array or structure containing the arrays
191  *btpp = dest;
192 
193  return;
194 }
195 
208 BaseType *function_mask_dap4_array(D4RValueList *args, DMR &dmr)
209 {
210  // DAP4 function porting information: in place of 'argc' use 'args.size()'
211  if (args == 0 || args->size() == 0) {
212  Str *response = new Str("info");
213  response->set_value(mask_array_info);
214  // DAP4 function porting: return a BaseType* instead of using the value-result parameter
215  return response;
216  }
217 
218  // Check for 3+ arguments
219  if (args->size() < 3) throw Error(malformed_expr, "In mask_array(Array1, ..., ArrayN, NoData, Mask) requires at least three arguments.");
220 
221  // Get the NoData value (second to last last); it must be a number
222  double no_data_value = extract_double_value(args->get_rvalue(args->size()-2)->value(dmr));
223 
224  // Get the mask (last arg), which must be a DAP Byte array
225  BaseType *mask_btp = args->get_rvalue(args->size()-1)->value(dmr);
226  check_number_type_array (mask_btp); // Throws Error if not a numeric array
227  Array *mask_var = static_cast<Array*>(mask_btp);
228  if (mask_var->var()->type() != dods_byte_c)
229  throw Error(malformed_expr, "In mask_array(): Expected the last argument (the mask) to be a byte array.");
230 
231  mask_var->read();
232  mask_var->set_read_p(true);
233  vector<dods_byte> mask(mask_var->length());
234  mask_var->value(&mask[0]); // get the value
235 
236  // Now mask the arrays
237  for (unsigned int i = 0; i < args->size() - 2; ++i) {
238  BaseType *array_btp = args->get_rvalue(i)->value(dmr);
239  check_number_type_array (array_btp);
240  Array *array = static_cast<Array*>(array_btp);
241  // The Mask and Array(s) should match in shape, but to simplify use, we test
242  // only that they have the same number of elements.
243  if ((vector<dods_byte>::size_type) array->length() != mask.size())
244  throw Error(malformed_expr,
245  "In make_array(): The array '" + array->name() + "' and the mask do not match in size.");
246 
247  switch (array->var()->type()) {
248  case dods_byte_c:
249  mask_array_helper<dods_byte>(array, no_data_value, mask);
250  break;
251  case dods_int16_c:
252  mask_array_helper<dods_int16>(array, no_data_value, mask);
253  break;
254  case dods_uint16_c:
255  mask_array_helper<dods_uint16>(array, no_data_value, mask);
256  break;
257  case dods_int32_c:
258  mask_array_helper<dods_int32>(array, no_data_value, mask);
259  break;
260  case dods_uint32_c:
261  mask_array_helper<dods_uint32>(array, no_data_value, mask);
262  break;
263  case dods_float32_c:
264  mask_array_helper<dods_float32>(array, no_data_value, mask);
265  break;
266  case dods_float64_c:
267  mask_array_helper<dods_float64>(array, no_data_value, mask);
268  break;
269  default:
270  throw InternalErr(__FILE__, __LINE__, "In mask_array(): Type " + array->type_name() + " not handled.");
271  }
272  }
273 
274  // Build the return value(s) - this means make copies of the masked arrays
275  BaseType *dest = 0; // null_ptr
276  if (args->size() == 3)
277  dest = args->get_rvalue(0)->value(dmr)->ptr_duplicate();
278  else {
279  dest = new Structure("masked_arays");
280  for (unsigned int i = 0; i < args->size() - 2; ++i) {
281  dest->add_var(args->get_rvalue(i)->value(dmr)); //add_var() copies its arg
282  }
283  }
284 
285  dest->set_send_p(true);
286  dest->set_read_p(true);
287 
288  return dest;
289 }
290 
291 } // namesspace functions
libdap
Definition: BESDapFunctionResponseCache.h:35
Error