bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
HDFGrid.cc
1// This file is part of the hdf4 data handler for the OPeNDAP data server.
2
3// Copyright (c) 2005 OPeNDAP, Inc.
4// Author: James Gallagher <jgallagher@opendap.org>
5//
6// This is free software; you can redistribute it and/or modify it under the
7// terms of the GNU Lesser General Public License as published by the Free
8// Software Foundation; either version 2.1 of the License, or (at your
9// option) any later version.
10//
11// This software is distributed in the hope that it will be useful, but
12// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14// License for more details.
15//
16// You should have received a copy of the GNU Lesser General Public License
17// along with this software; if not, write to the Free Software Foundation,
18// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19//
20// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
21
23// Copyright 1996, by the California Institute of Technology.
24// ALL RIGHTS RESERVED. United States Government Sponsorship
25// acknowledged. Any commercial use must be negotiated with the
26// Office of Technology Transfer at the California Institute of
27// Technology. This software may be subject to U.S. export control
28// laws and regulations. By accepting this software, the user
29// agrees to comply with all applicable U.S. export laws and
30// regulations. User has the responsibility to obtain export
31// licenses, or other export authority as may be required before
32// exporting such information to foreign countries or providing
33// access to foreign persons.
34
35// Author: Todd Karakashian, NASA/Jet Propulsion Laboratory
36// Todd.K.Karakashian@jpl.nasa.gov
37//
39
40#include "config_hdf.h"
41
42#include <vector>
43// Include this on linux to suppres an annoying warning about multiple
44// definitions of MIN and MAX.
45#ifdef HAVE_SYS_PARAM_H
46#include <sys/param.h>
47#endif
48#include <mfhdf.h>
49#include <hdfclass.h>
50#include <hcstream.h>
51
52#include <libdap/Error.h>
53#include <libdap/InternalErr.h>
54#include <libdap/debug.h>
55#include <libdap/escaping.h>
56
57#include <BESDebug.h>
58
59#include "HDFGrid.h"
60#include "HDFArray.h"
61#include "hdfutil.h"
62
63using namespace libdap;
64using namespace std;
65
66HDFGrid::HDFGrid(const string &n, const string &d) :
67 Grid(n, d) {
68}
69
70HDFGrid::~HDFGrid() = default;
71
72BaseType *HDFGrid::ptr_duplicate() {
73 return new HDFGrid(*this);
74}
75
76void LoadGridFromSDS(HDFGrid * gr, const hdf_sds & sds);
77
78// Build a vector of array_ce structs. This holds the constraint
79// information *for each map* of the Grid.
80vector<array_ce> HDFGrid::get_map_constraints() {
81 vector<array_ce> a_ce_vec;
82
83 // Load the array_ce vector with info about each map vector.
84 for (Grid::Map_iter p = map_begin(); p != map_end(); ++p) {
85 Array & a = static_cast<Array &> (**p);
86 Array::Dim_iter q = a.dim_begin(); // maps have only one dimension.
87 int start = a.dimension_start(q, true);
88 int stop = a.dimension_stop(q, true);
89 int stride = a.dimension_stride(q, true);
90 int edge = (int) ((stop - start) / stride) + 1;
91 array_ce a_ce(a.name(), start, edge, stride);
92 a_ce_vec.push_back(a_ce);
93 }
94
95 return a_ce_vec;
96}
97
98// Read in a Grid from an SDS in an HDF file.
99bool HDFGrid::read() {
100 int err = 0;
101 int status = read_tagref(-1, -1, err);
102 if (err)
103 throw Error(unknown_error, "Could not read from dataset.");
104 return status;
105}
106
107bool HDFGrid::read_tagref(int32, int32 ref, int &err) {
108 if (read_p())
109 return true;
110
111 err = 0; // OK initially
112
113 string hdf_file = dataset();
114 string hdf_name = this->name();
115
116 hdf_sds sds;
117
118 // read in SDS
119 hdfistream_sds sdsin(hdf_file.c_str());
120 try {
121 vector<int> start;
122 vector<int> edge;
123 vector<int> stride;
124 auto primary_array = static_cast<HDFArray *> (array_var());
125 if (!primary_array)
126 throw InternalErr(__FILE__, __LINE__, "Expected an HDFArray.");
127
128 bool isslab = primary_array->GetSlabConstraint(start, edge, stride);
129
130 // get slab constraint from primary array
131 if (isslab)
132 sdsin.setslab(start, edge, stride, false);
133
134 // get the constraints on each map
135 sdsin.set_map_ce(get_map_constraints());
136
137 if (ref != -1)
138 sdsin.seek_ref(ref);
139 else
140 sdsin.seek(hdf_name.c_str());
141
142 // If we read the array, we also read the maps. 2/3/2002 jhrg
143 if (array_var()->send_p() || array_var()->is_in_selection()) {
144 sdsin >> sds;
145 if (!sds) {
146 throw Error(
147 string("Could not read ") + array_var()->name()
148 + string(" from dataset ") + dataset()
149 + string("."));
150 }
151
152 LoadGridFromSDS(this, sds); // load data into primary array
153 }
154 // load map data. There's little point in checking if the maps really
155 // need to be read. If the array was read, chances are good and the
156 // map vectors are much smaller. If the array was not read, then some
157 // map must be marked to be sent or we wouldn't be here. So just load
158 // the maps...
159
160 // Read only if not above. sdsin >> hdf_sds also reads the maps so we
161 // should read here only if we didn't read above.
162 if (!(array_var()->send_p() || array_var()->is_in_selection())) {
163 // This initialization is done by hdfistream_sds op>>(hdf_sds&)
164 // but not hdfistream_sds op>>(hdf_dim&).
165 sds.dims = vector<hdf_dim> ();
166 sds.data = hdf_genvec(); // needed?
167 sdsin >> sds.dims;
168 }
169
170 for (Grid::Map_iter p = map_begin(); p != map_end(); ++p) {
171 if ((*p)->send_p() || (*p)->is_in_selection()) {
172 for (unsigned int i = 0; i < sds.dims.size(); i++) {
173 if ((*p)->name() == sds.dims[i].name) {
174 // Read the data from the sds dimension.
175 char *data = static_cast<char *> (ExportDataForDODS(
176 sds.dims[i].scale));
177 (*p)->val2buf(data);
178 delete[] data;
179 (*p)->set_read_p(true);
180 }
181 }
182 }
183 }
184
185 sdsin.close();
186 } catch (...) {
187 sdsin.close();
188 err = 1;
189 return false;
190 }
191
192 return true;
193}
194
195void HDFGrid::transfer_attributes(AttrTable *at) {
196 if (at) {
197 array_var()->transfer_attributes(at);
198
199 Map_iter map = map_begin();
200 while (map != map_end()) {
201 (*map)->transfer_attributes(at);
202 map++;
203 }
204
205 AttrTable *mine = at->get_attr_table(name());
206
207 if (mine) {
208 mine->set_is_global_attribute(false);
209 AttrTable::Attr_iter at_p = mine->attr_begin();
210 while (at_p != mine->attr_end()) {
211 if (mine->get_attr_type(at_p) == Attr_container)
212 get_attr_table().append_container(
213 new AttrTable(*mine->get_attr_table(at_p)),
214 mine->get_name(at_p));
215 else
216 get_attr_table().append_attr(mine->get_name(at_p),
217 mine->get_type(at_p), mine->get_attr_vector(at_p));
218 at_p++;
219 }
220 }
221
222 // Now look for those pesky <var>_dim_<digit> attributes
223
224 string dim_name_base = name() + "_dim_";
225
226 AttrTable::Attr_iter a_p = at->attr_begin();
227 while (a_p != at->attr_end()) {
228 string::size_type i = at->get_name(a_p).find(dim_name_base);
229 // Found a matching container?
230 // See comment in HDFArray::transfer_attributes regarding 'i == 0'
231 // jhrg 8/17/11
232 if (i == 0 && at->get_attr_type(a_p) == Attr_container) {
233 AttrTable *dim = at->get_attr_table(a_p);
234 // Get the integer from the end of the name and use that as the
235 // index to find the matching Map variable.
236 BESDEBUG("h4", "dim->name(): " << dim->get_name() << endl);
237 BESDEBUG("h4", "dim->get_name().substr(i + dim_name_base.size()): "
238 << dim->get_name().substr(i + dim_name_base.size()) << endl);
239 int n = atoi(dim->get_name().substr(i + dim_name_base.size()).c_str());
240 // Note that the maps are HDFArray instances, so we use that
241 // for the actual copy operation.
242 BESDEBUG("h4", "Inside HDFGrid::transfer_attreibutes: n = " << n << endl);
243 static_cast<HDFArray&> (*(*(map_begin() + n))).transfer_dimension_attribute(dim);
244 }
245
246 a_p++;
247 }
248 }
249}
250