bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
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 <libdap/Type.h>
34#include <libdap/BaseType.h>
35#include <libdap/Str.h>
36#include <libdap/Array.h>
37#include <libdap/Structure.h>
38#include <libdap/Error.h>
39#include <libdap/DDS.h>
40
41#include <libdap/DMR.h>
42#include <libdap/D4Group.h>
43#include <libdap/D4RValue.h>
44
45#include <libdap/debug.h>
46#include <libdap/util.h>
47
48#include <libdap/BaseTypeFactory.h>
49
50#include <BESDebug.h>
51
52#include "MakeArrayFunction.h"
53#include "functions_util.h"
54
55using namespace libdap;
56
57namespace functions {
58
59string 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
76template <typename T>
77void 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.data());
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
111void 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.data()); // 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
208BaseType *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.data()); // 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