bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
GeoGridFunction.cc
1
2// -*- mode: c++; c-basic-offset:4 -*-
3
4// This file is part of libdap, A C++ implementation of the OPeNDAP Data
5// Access Protocol.
6
7// Copyright (c) 2003,2013 OPeNDAP, Inc.
8// Authors: Nathan Potter <npotter@opendap.org>
9// James Gallagher <jgallagher@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// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
26
27#include "config.h"
28
29#include <libdap/BaseType.h>
30#include <libdap/Str.h>
31#include <libdap/Array.h>
32#include <libdap/Grid.h>
33#include <libdap/Structure.h>
34#include <libdap/D4RValue.h>
35#include <libdap/D4Maps.h>
36#include <libdap/Error.h>
37#include <libdap/DDS.h>
38#include <libdap/DMR.h>
39#include <libdap/D4Group.h>
40#include <libdap/debug.h>
41#include <libdap/util.h>
42
43#include <BESDebug.h>
44
45#include "GeoGridFunction.h"
46#include "GridGeoConstraint.h"
47#include "gse_parser.h"
48#include "grid_utils.h"
49
50using namespace libdap;
51
52namespace functions {
53
54 string geogrid_info =
55 string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") +
56 "<function name=\"geogrid\" version=\"1.2\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#geogrid\">\n"+
57 "</function>";
58
93void
94function_dap2_geogrid(int argc, BaseType *argv[], DDS &, BaseType **btpp)
95{
96 if (argc == 0) {
97 Str *response = new Str("version");
98 response->set_value(geogrid_info);
99 *btpp = response;
100 return ;
101 }
102
103 // There are two main forms of this function, one that takes a Grid and one
104 // that takes a Grid and two Arrays. The latter provides a way to explicitly
105 // tell the function which maps contain lat and lon data. The remaining
106 // arguments are the same for both versions, although that includes a
107 // varying argument list.
108
109 // Look at the types of the first three arguments to determine which of the
110 // two forms were used to call this function.
111 Grid *l_grid = 0;
112 if (argc < 1 || !(l_grid = dynamic_cast < Grid * >(argv[0]->ptr_duplicate())))
113 throw Error(malformed_expr,"The first argument to geogrid() must be a Grid variable!");
114
115 // Both forms require at least this many args
116 if (argc < 5)
117 throw Error(malformed_expr,"Wrong number of arguments to geogrid() (expected at least 5 args). See geogrid() for more information.");
118
119 bool grid_lat_lon_form;
120 Array *l_lat = 0;
121 Array *l_lon = 0;
122 if (!(l_lat = dynamic_cast < Array * >(argv[1]))) //->ptr_duplicate())))
123 grid_lat_lon_form = false;
124 else if (!(l_lon = dynamic_cast < Array * >(argv[2]))) //->ptr_duplicate())))
125 throw Error(malformed_expr,"When using the Grid, Lat, Lon form of geogrid() both the lat and lon maps must be given (lon map missing)!");
126 else
127 grid_lat_lon_form = true;
128
129 if (grid_lat_lon_form && argc < 7)
130 throw Error(malformed_expr,"Wrong number of arguments to geogrid() (expected at least 7 args). See geogrid() for more information.");
131
132#if 0
133 Grid *l_grid = dynamic_cast < Grid * >(argv[0]->ptr_duplicate());
134 if (!l_grid)
135 throw Error(malformed_expr,"The first argument to geogrid() must be a Grid variable!");
136#endif
137 // Read the maps. Do this before calling parse_gse_expression(). Avoid
138 // reading the array until the constraints have been applied because it
139 // might be really large.
140 //
141 // Trick: Some handlers build Grids from a combination of Array
142 // variables and attributes. Those handlers (e.g., hdf4) use the send_p
143 // property to determine which parts of the Grid to read *but they can
144 // only read the maps from within Grid::read(), not the map's read()*.
145 // Since the Grid's array does not have send_p set, it will not be read
146 // by the call below to Grid::read().
147 Grid::Map_iter i = l_grid->map_begin();
148 while (i != l_grid->map_end())
149 (*i++)->set_send_p(true);
150
151 l_grid->read();
152 // Calling read() above sets the read_p flag for the entire grid; clear it
153 // for the grid's array so that later on the code will be sure to read it
154 // under all circumstances.
155 l_grid->get_array()->set_read_p(false);
156
157 // Look for Grid Selection Expressions tacked onto the end of the BB
158 // specification. If there are any, evaluate them before evaluating the BB.
159 int min_arg_count = (grid_lat_lon_form) ? 7 : 5;
160 if (argc > min_arg_count) {
161 // argv[5..n] holds strings; each are little Grid Selection Expressions
162 // to be parsed and evaluated.
163 vector < GSEClause * > clauses;
164 gse_arg *arg = new gse_arg(l_grid);
165 for (int i = min_arg_count; i < argc; ++i) {
166 parse_gse_expression(arg, argv[i]);
167 clauses.push_back(arg->get_gsec());
168 }
169 delete arg;
170 arg = 0;
171
172 apply_grid_selection_expressions(l_grid, clauses);
173 }
174
175 try {
176 // Build a GeoConstraint object. If there are no longitude/latitude
177 // maps then this constructor throws Error.
178 GridGeoConstraint gc(l_grid);
179
180 // This sets the bounding box and modifies the maps to match the
181 // notation of the box (0/359 or -180/179)
182 int box_index_offset = (grid_lat_lon_form) ? 3 : 1;
183 double top = extract_double_value(argv[box_index_offset]);
184 double left = extract_double_value(argv[box_index_offset + 1]);
185 double bottom = extract_double_value(argv[box_index_offset + 2]);
186 double right = extract_double_value(argv[box_index_offset + 3]);
187 gc.set_bounding_box(top, left, bottom, right);
188 DBG(cerr << "geogrid: past bounding box set" << endl);
189
190 // This also reads all of the data into the grid variable
191 gc.apply_constraint_to_data();
192 DBG(cerr << "geogrid: past apply constraint" << endl);
193
194 // In this function the l_grid pointer is the same as the pointer returned
195 // by this call. The caller of the function must free the pointer.
196 *btpp = gc.get_constrained_grid();
197 return;
198 }
199 catch (Error &e) {
200 throw e;
201 }
202 catch (exception & e) {
203 throw
204 InternalErr(string
205 ("A C++ exception was thrown from inside geogrid(): ")
206 + e.what());
207 }
208}
209
217{
218 bool usable = false;
219
220 // Go find all the Grid variables.
221 //vector<Grid *> *grids = new vector<Grid *>();
222 vector<Grid*> grids;
223 get_grids(dds, &grids);
224
225 // Were there any?
226 if(!grids.empty()){
227 // Apparently so...
228
229 // See if any one of them looks like suitable GeoGrid
231 for(git=grids.begin(); !usable && git!=grids.end() ; git++){
232 Grid *grid = *git;
233 usable = is_geo_grid(grid);
234 }
235 }
236 //delete grids;
237
238 return usable;
239}
240
241BaseType *function_dap4_geogrid(D4RValueList *args, DMR &dmr)
242{
243 BESDEBUG("function", "function_dap4_geogrid() BEGIN " << endl);
244
245 // There are two main forms of this function, one that takes a Grid and one
246 // that takes a Grid and two Arrays. The latter provides a way to explicitly
247 // tell the function which maps contain lat and lon data. The remaining
248 // arguments are the same for both versions, although that includes a
249 // varying argument list.
250
251 // Look at the types of the first three arguments to determine which of the
252 // two forms were used to call this function.
253 // Both forms require at least this many (5) args
254
255 // DAP4 function porting information: in place of 'argc' use 'args.size()'
256 if (args == 0 || args->size() < 5) {
257 Str *response = new Str("info");
258 response->set_value(geogrid_info);
259 // DAP4 function porting: return a BaseType* instead of using the value-result parameter
260 return response;
261 }
262
263 BaseType *a_btp = args->get_rvalue(0)->value(dmr);
264 Array *original_array = dynamic_cast < Array * >(a_btp);
265 if (!original_array) {
266 delete a_btp;
267 throw Error(malformed_expr,"The first argument to geogrid() must be a Dap4 array variable!");
268 //throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
269 }
270
271 // Duplicate the array; ResponseBuilder::send_data() will delete the variable
272 // after serializing it.
273 BaseType *btp = original_array->ptr_duplicate();
274 Array *l_array = dynamic_cast < Array * >(btp);
275 if (!l_array) {
276 delete btp;
277 throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
278 }
279
280 DBG(cerr << "array: past initialization code" << endl);
281
282 bool grid_lat_lon_form = false;
283
284 BaseType *lat_btp = args->get_rvalue(1)->value(dmr);
285 Array *l_lat = dynamic_cast < Array * >(lat_btp);
286 BaseType *lon_btp = args->get_rvalue(2)->value(dmr);
287 Array *l_lon = dynamic_cast < Array * >(lon_btp);
288
289 if (!l_lat) { // If first argument is an array then second must be an array as well.
290 grid_lat_lon_form = false;
291 }
292 else if (!l_lon) {
293 throw Error(malformed_expr,
294 "When using the Grid, Lat, Lon form of geogrid() both the lat and lon maps must be given (lon map missing)!");
295 }
296 else {
297 grid_lat_lon_form = true;
298 }
299
300 if (grid_lat_lon_form && args->size() < 7) {
301 throw Error(malformed_expr,
302 "Wrong number of arguments to geogrid() (expected at least 7 args). See geogrid() for more information.");
303 }
304
305 // Read the maps. Do this before calling parse_gse_expression(). Avoid
306 // reading the array until the constraints have been applied because it
307 // might be really large.
308 //
309
310 BESDEBUG("functions", "original_array: read_p: " << original_array->read_p() << endl);
311 BESDEBUG("functions", "l_array: read_p: " << l_array->read_p() << endl);
312
313 // Basic plan: For each map, set the send_p flag and read the map
314 D4Maps *d4_maps = l_array->maps();
315 D4Maps::D4MapsIter miter = d4_maps->map_begin();
316 while (miter != d4_maps->map_end()) {
317 D4Map *d4_map = (*miter);
318 Array *map = const_cast<Array *>(d4_map->array());
319 map->set_send_p(true);
320 map->read();
321 ++miter;
322 }
323
324 DBG(cerr << "array: past map read" << endl);
325
326 // Look for Grid Selection Expressions tacked onto the end of the BB
327 // specification. If there are any, evaluate them before evaluating the BB.
328 unsigned int min_arg_count = (grid_lat_lon_form) ? 7 : 5;
329
330 if (args->size() > min_arg_count) {
331 // argv[5..n] holds strings; each are little Grid Selection Expressions
332 // to be parsed and evaluated.
333 vector < GSEClause * > clauses;
334 gse_arg *arg = new gse_arg(l_array); // unique_ptr here
335 for (unsigned int i = min_arg_count; i < args->size(); ++i) {
336 parse_gse_expression(arg, args->get_rvalue(i)->value(dmr));
337 clauses.push_back(arg->get_gsec());
338 }
339 delete arg;
340 arg = 0;
341
342 apply_grid_selection_expressions(l_array, clauses);
343 }
344 DBG(cerr << "array: past gse application" << endl);
345
346 try {
347 // Build a GeoConstraint object. If there are no longitude/latitude
348 // maps then this constructor throws Error.
349 GridGeoConstraint gc(l_array);
350
351 // This sets the bounding box and modifies the maps to match the
352 // notation of the box (0/359 or -180/179)
353 int box_index_offset = (grid_lat_lon_form) ? 3 : 1;
354 double top = extract_double_value(args->get_rvalue(box_index_offset)->value(dmr));
355 double left = extract_double_value(args->get_rvalue(box_index_offset + 1)->value(dmr));
356 double bottom = extract_double_value(args->get_rvalue(box_index_offset + 2)->value(dmr));
357 double right = extract_double_value(args->get_rvalue(box_index_offset + 3)->value(dmr));
358 gc.set_bounding_box(top, left, bottom, right);
359 DBG(cerr << "geogrid: past bounding box set" << endl);
360
361 // This also reads all of the data into the grid variable
362 gc.apply_constraint_to_data();
363 DBG(cerr << "geogrid: past apply constraint" << endl);
364
365 // Build the return value(s) - this means make copies of the Map arrays
366 D4Group *dapResult = new D4Group("geogrid_result");
367
368 // Set this container's parent ot the root D4Group
369 dapResult->set_parent(dmr.root());
370
371 // Basic plan: Add the new array to the destination D4Group, and clear read_p flag.
372 l_array->set_read_p(false);
373 dapResult->add_var_nocopy(l_array);
374
375 // Basic plan: Add D4Dimensions to the destination D4Group; copy all dims to the parent group.
376 D4Dimensions *grp_d4_dims = dapResult->dims();
377
378 Array *g_array = dynamic_cast<Array *>(dapResult->find_var(l_array->name()));
379 // Basic plan: For each D4Dimension in the array, add it to the destination D4Group
380 Array::Dim_iter dim_i = g_array->dim_begin();
381 while (dim_i != g_array->dim_end()) {
382 D4Dimension *d4_dim = g_array->dimension_D4dim(dim_i);
383 grp_d4_dims->add_dim_nocopy(d4_dim);
384 ++dim_i;
385 }
386
387 // Basic plan: For each map in the array, add it to the destination structure and clear the read_p flag
388 d4_maps = l_array->maps();
389 miter = d4_maps->map_begin();
390 while (miter != d4_maps->map_end()) {
391 D4Map *d4_map = (*miter);
392 Array *map = const_cast<Array *>(d4_map->array());
393 map->set_read_p(false);
394 dapResult->add_var_nocopy(map);
395 ++miter;
396 }
397 // Basic plan: Mark the Group for sending and read the data.
398 dapResult->set_send_p(true);
399 dapResult->read();
400
401 return dapResult;
402 }
403 catch (Error &e) {
404 throw e;
405 }
406 catch (exception & e) {
407 throw
408 InternalErr(string
409 ("A C++ exception was thrown from inside geogrid(): ")
410 + e.what());
411 }
412}
413
414
421{
422 vector<Array *> coverages;
423 get_coverages(dmr, &coverages);
424
425 return !coverages.empty();
426}
427
428} // namesspace libdap
bool canOperateOn(libdap::DDS &dds)
STL iterator class.
STL class.