libdap Updated for version 3.21.1
libdap4 is an implementation of OPeNDAP's DAP protocol.
GridGeoConstraint.cc
Go to the documentation of this file.
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) 2002,2003 OPeNDAP, Inc.
8// Author: James Gallagher <jgallagher@opendap.org>
9//
10// This library is free software; you can redistribute it and/or
11// modify it under the terms of the GNU Lesser General Public
12// License as published by the Free Software Foundation; either
13// version 2.1 of the License, or (at your option) any later version.
14//
15// This library is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18// Lesser General Public License for more details.
19//
20// You should have received a copy of the GNU Lesser General Public
21// License along with this library; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23//
24// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25
26// The Grid Selection Expression Clause class.
27
28#include "config.h"
29
30#include <cmath>
31
32#include <iostream>
33#include <sstream>
34
35// #define DODS_DEBUG
36
37#include <Error.h>
38#include <Float64.h>
39#include <Grid.h>
40#include <InternalErr.h>
41#include <debug.h>
42#include <dods-datatypes.h>
43#include <util.h>
44
45#include "GridGeoConstraint.h"
46
47using namespace std;
48using namespace libdap;
49
50namespace functions {
51
58GridGeoConstraint::GridGeoConstraint(Grid *grid) : GeoConstraint(), d_grid(grid), d_latitude(0), d_longitude(0) {
59 if (d_grid->get_array()->dimensions() < 2 || d_grid->get_array()->dimensions() > 3)
60 throw Error("The geogrid() function works only with Grids of two or three dimensions.");
61
62 // Is this Grid a geo-referenced grid? Throw Error if not.
63 if (!build_lat_lon_maps())
64 throw Error(string("The grid '") + d_grid->name() +
65 "' does not have identifiable latitude/longitude map vectors.");
66
67 if (!lat_lon_dimensions_ok())
68 throw Error("The geogrid() function will only work when the Grid's Longitude and Latitude maps are the "
69 "rightmost dimensions (grid: " +
70 grid->name() + ", 1).");
71}
72
74 : GeoConstraint(), d_grid(grid), d_latitude(0), d_longitude(0) {
75 if (d_grid->get_array()->dimensions() < 2 || d_grid->get_array()->dimensions() > 3)
76 throw Error("The geogrid() function works only with Grids of two or three dimensions.");
77
78 // Is this Grid a geo-referenced grid? Throw Error if not.
79 if (!build_lat_lon_maps(lat, lon))
80 throw Error(string("The grid '") + d_grid->name() + "' does not have valid latitude/longitude map vectors.");
81
82 if (!lat_lon_dimensions_ok())
83 throw Error("The geogrid() function will only work when the Grid's Longitude and Latitude maps are the "
84 "rightmost dimensions (grid: " +
85 grid->name() + ", 2).");
86}
87
103bool GridGeoConstraint::build_lat_lon_maps() {
104 Grid::Map_iter m = d_grid->map_begin();
105
106 // Assume that a Grid is correct and thus has exactly as many maps as its
107 // array part has dimensions. Thus don't bother to test the Grid's array
108 // dimension iterator for '!= dim_end()'.
109 Array::Dim_iter d = d_grid->get_array()->dim_begin();
110
111 // The fields d_latitude and d_longitude may be initialized to null or they
112 // may already contain pointers to the maps to use. In the latter case,
113 // skip the heuristics used in this code. However, given that all this
114 // method does is find the lat/lon maps, if they are given in the ctor,
115 // This method will likely not be called at all.
116 while (m != d_grid->map_end() && (!d_latitude || !d_longitude)) {
117 string units_value = (*m)->get_attr_table().get_attr("units");
118 units_value = remove_quotes(units_value);
119 string map_name = (*m)->name();
120
121 // The 'units' attribute must match exactly; the name only needs to
122 // match a prefix.
123 if (!d_latitude && unit_or_name_match(get_coards_lat_units(), get_lat_names(), units_value, map_name)) {
124
125 // Set both d_latitude (a pointer to the real map vector) and
126 // d_lat, a vector of the values represented as doubles. It's easier
127 // to work with d_lat, but it's d_latitude that needs to be set
128 // when constraining the grid. Also, record the grid variable's
129 // dimension iterator so that it's easier to set the Grid's Array
130 // (which also has to be constrained).
131 d_latitude = dynamic_cast<Array *>(*m);
132 if (!d_latitude)
133 throw InternalErr(__FILE__, __LINE__, "Expected an array.");
134 if (!d_latitude->read_p())
135 d_latitude->read();
136
137 set_lat(extract_double_array(d_latitude)); // throws Error
138 set_lat_length(d_latitude->length());
139
140 set_lat_dim(d);
141 }
142
143 if (!d_longitude // && !units_value.empty()
144 && unit_or_name_match(get_coards_lon_units(), get_lon_names(), units_value, map_name)) {
145
146 d_longitude = dynamic_cast<Array *>(*m);
147 if (!d_longitude)
148 throw InternalErr(__FILE__, __LINE__, "Expected an array.");
149 if (!d_longitude->read_p())
150 d_longitude->read();
151
152 set_lon(extract_double_array(d_longitude));
153 set_lon_length(d_longitude->length());
154
155 set_lon_dim(d);
156
157 if (m + 1 == d_grid->map_end())
159 }
160
161 ++m;
162 ++d;
163 }
164
165 return get_lat() && get_lon();
166}
167
175bool GridGeoConstraint::build_lat_lon_maps(Array *lat, Array *lon) {
176 Grid::Map_iter m = d_grid->map_begin();
177
178 Array::Dim_iter d = d_grid->get_array()->dim_begin();
179
180 while (m != d_grid->map_end() && (!d_latitude || !d_longitude)) {
181 // Look for the Grid map that matches the variable passed as 'lat'
182 if (!d_latitude && *m == lat) {
183
184 d_latitude = lat;
185
186 if (!d_latitude->read_p())
187 d_latitude->read();
188
189 set_lat(extract_double_array(d_latitude)); // throws Error
190 set_lat_length(d_latitude->length());
191
192 set_lat_dim(d);
193 }
194
195 if (!d_longitude && *m == lon) {
196
197 d_longitude = lon;
198
199 if (!d_longitude->read_p())
200 d_longitude->read();
201
202 set_lon(extract_double_array(d_longitude));
203 set_lon_length(d_longitude->length());
204
205 set_lon_dim(d);
206
207 if (m + 1 == d_grid->map_end())
209 }
210
211 ++m;
212 ++d;
213 }
214
215 return get_lat() && get_lon();
216}
217
228bool GridGeoConstraint::lat_lon_dimensions_ok() {
229 // get the last two map iterators
230 Grid::Map_riter rightmost = d_grid->map_rbegin();
231 Grid::Map_riter next_rightmost = rightmost + 1;
232
233 if (*rightmost == d_longitude && *next_rightmost == d_latitude)
235 else if (*rightmost == d_latitude && *next_rightmost == d_longitude)
237 else
238 return false;
239
240 return true;
241}
242
265 if (!is_bounding_box_set())
266 throw InternalErr(
267 "The Latitude and Longitude constraints must be set before calling apply_constraint_to_data().");
268
269 Array::Dim_iter fd = d_latitude->dim_begin();
270
271 if (get_latitude_sense() == inverted) {
272 int tmp = get_latitude_index_top();
275 }
276
277 // It's easy to flip the Latitude values; if the bottom index value
278 // is before/above the top index, return an error explaining that.
280 throw Error("The upper and lower latitude indices appear to be reversed. Please provide the latitude bounding "
281 "box numbers giving the northern-most latitude first.");
282
283 // Constrain the lat vector and lat dim of the array
284 d_latitude->add_constraint(fd, get_latitude_index_top(), 1, get_latitude_index_bottom());
285 d_grid->get_array()->add_constraint(get_lat_dim(), get_latitude_index_top(), 1, get_latitude_index_bottom());
286
287 // Does the longitude constraint cross the edge of the longitude vector?
288 // If so, reorder the grid's data (array), longitude map vector and the
289 // local vector of longitude data used for computation.
292
293 // If the longitude constraint is 'split', join the two parts, reload
294 // the data into the Grid's Array and make sure the Array is marked as
295 // already read. This should be true for the whole Grid, but if some
296 // future modification changes that, the array will be covered here.
297 // Note that the following method only reads the data out and stores
298 // it in this object after joining the two parts. The method
299 // apply_constraint_to_data() transfers the data back from the this
300 // object to the DAP Grid variable.
301 reorder_data_longitude_axis(*d_grid->get_array(), get_lon_dim());
302
303 // Now that the data are all in local storage alter the indices; the
304 // left index has now been moved to 0, and the right index is now
305 // at lon_vector_length-left+right.
308 }
309
310 // If the constraint used the -180/179 (neg_pos) notation, transform
311 // the longitude map so it uses the -180/179 notation. Note that at this
312 // point, d_longitude always uses the pos notation because of the earlier
313 // conditional transformation.
314
315 // Do this _before_ applying the constraint since set_array_using_double()
316 // tests the array length using Vector::length() and that method returns
317 // the length _as constrained_. We want to move all of the longitude
318 // values from d_lon back into the map, not just the number that will be
319 // sent (although an optimization might do this, it's hard to imagine
320 // it would gain much).
323 }
324
325 // Apply constraint; stride is always one and maps only have one dimension
326 fd = d_longitude->dim_begin();
327 d_longitude->add_constraint(fd, get_longitude_index_left(), 1, get_longitude_index_right());
328
329 d_grid->get_array()->add_constraint(get_lon_dim(), get_longitude_index_left(), 1, get_longitude_index_right());
330
331 // Transfer values from the local lat vector to the Grid's
332 // Here test the sense of the latitude vector and invert the vector if the
333 // sense is 'inverted' so that the top is always the northern-most value
334 if (get_latitude_sense() == inverted) {
335 DBG(cerr << "Inverted latitude sense" << endl);
338 // Now read the Array data and flip the latitudes.
341 }
342
345
348
349 // Look for any non-lat/lon maps and make sure they are read correctly
350 Grid::Map_iter i = d_grid->map_begin();
351 Grid::Map_iter end = d_grid->map_end();
352 while (i != end) {
353 if (*i != d_latitude && *i != d_longitude) {
354 if ((*i)->send_p()) {
355 DBG(cerr << "reading grid map: " << (*i)->name() << endl);
356 //(*i)->set_read_p(false);
357 (*i)->read();
358 }
359 }
360 ++i;
361 }
362
363 // ... and then the Grid's array if it has been read.
364 if (get_array_data()) {
365 int size = d_grid->get_array()->val2buf(get_array_data());
366
367 if (size != get_array_data_size())
368 throw InternalErr(__FILE__, __LINE__, "Expected data size not copied to the Grid's buffer.");
369
370 d_grid->set_read_p(true);
371 } else {
372 d_grid->get_array()->read();
373 }
374}
375
376} // namespace functions
set< string > get_coards_lon_units() const
int get_latitude_index_bottom() const
libdap::Array::Dim_iter get_lon_dim() const
libdap::Array::Dim_iter get_lat_dim() const
set< string > get_lat_names() const
virtual void reorder_longitude_map(int longitude_index_left)
virtual void transform_longitude_to_neg_pos_notation()
virtual void reorder_data_longitude_axis(libdap::Array &a, libdap::Array::Dim_iter lon_dim)
void set_lon(double *lon)
void set_lon_dim(libdap::Array::Dim_iter lon)
void set_longitude_rightmost(bool state)
double * get_lat() const
void set_lat(double *lat)
void set_longitude_index_right(int right)
int get_latitude_index_top() const
Notation get_longitude_notation() const
LatitudeSense get_latitude_sense() const
char * get_array_data() const
void set_lat_dim(libdap::Array::Dim_iter lat)
int get_longitude_index_left() const
bool is_bounding_box_set() const
set< string > get_coards_lat_units() const
set< string > get_lon_names() const
void set_latitude_index_top(int top)
virtual void flip_latitude_within_array(libdap::Array &a, int lat_length, int lon_length)
int get_longitude_index_right() const
void set_latitude_index_bottom(int bottom)
double * get_lon() const
virtual void transpose_vector(double *src, const int length)
void set_longitude_index_left(int left)
GridGeoConstraint(libdap::Grid *grid)
Initialize GeoConstraint with a Grid.
A multidimensional array of identical data types.
Definition Array.h:121
std::vector< dimension >::iterator Dim_iter
Definition Array.h:225
Dim_iter dim_begin()
Definition Array.cc:689
virtual bool read()
Read data into a local buffer.
Definition BaseType.cc:775
virtual string name() const
Returns the name of the class instance.
Definition BaseType.cc:296
virtual bool read_p()
Has this variable been read?
Definition BaseType.cc:410
A class for error processing.
Definition Error.h:92
Holds the Grid data type.
Definition Grid.h:121
Map_iter map_begin()
Returns an iterator referencing the first Map vector.
Definition Grid.cc:448
std::vector< BaseType * >::reverse_iterator Map_riter
Definition Grid.h:137
std::vector< BaseType * >::iterator Map_iter
Definition Grid.h:136
Array * get_array()
Returns the Grid Array. This method returns the array using an Array*, so no cast is required.
Definition Grid.cc:445
Map_iter map_end()
Definition Grid.cc:458
A class for software fault reporting.
Definition InternalErr.h:61
int length() const override
Returns the number of elements in the vector. Note that some child classes of Vector use the length o...
Definition Vector.h:210
#define DBG(x)
Definition debug.h:58
bool unit_or_name_match(set< string > units, set< string > names, const string &var_units, const string &var_name)
top level DAP object to house generic methods
Definition AISConnect.cc:30
string remove_quotes(const string &s)
Definition util.cc:562
void set_array_using_double(Array *dest, double *src, int src_len)
Definition util.cc:164
double * extract_double_array(Array *a)
Definition util.cc:257