bes Updated for version 3.20.10
NCArray.cc
1
2// -*- mode: c++; c-basic-offset:4 -*-
3
4// This file is part of nc_handler, a data handler for the OPeNDAP data
5// server.
6
7// Copyright (c) 2002,2003 OPeNDAP, Inc.
8// Author: James Gallagher <jgallagher@opendap.org>
9//
10// This is free software; you can redistribute it and/or modify it under the
11// terms of the GNU Lesser General Public License as published by the Free
12// Software Foundation; either version 2.1 of the License, or (at your
13// option) any later version.
14//
15// This software is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18// 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// (c) COPYRIGHT URI/MIT 1994-1999
27// Please read the full copyright statement in the file COPYRIGHT.
28//
29// Authors:
30// reza Reza Nekovei (rnekovei@ieee.org)
31
32// netCDF sub-class implementation for NCByte,...NCGrid.
33// The files are patterned after the subcalssing examples
34// Test<type>.c,h files.
35//
36// ReZa 1/12/95
37
38#include "config_nc.h"
39
40#include <cstring>
41#include <iostream>
42#include <sstream>
43#include <algorithm>
44
45#include <netcdf.h>
46
47// #define DODS_DEBUG 1
48
49#include <libdap/BaseType.h>
50#include <libdap/Error.h>
51#include <libdap/InternalErr.h>
52#include <libdap/util.h>
53#include <libdap/debug.h>
54
55#include <BESDebug.h>
56
57#include "NCRequestHandler.h"
58#include "NCArray.h"
59#include "NCStructure.h"
60// #include "nc_util.h"
61
62#define MODULE "nc"
63#define prolog std::string("NCArray::").append(__func__).append("() - ")
64
65BaseType *
66NCArray::ptr_duplicate()
67{
68 return new NCArray(*this);
69}
70
78NCArray::NCArray(const string &n, const string &d, BaseType *v)
79 : Array(n, d, v)
80{}
81
82NCArray::NCArray(const NCArray &rhs) : Array(rhs)
83{}
84
85NCArray::~NCArray()
86{
87}
88
89NCArray &
90NCArray::operator=(const NCArray &rhs)
91{
92 if (this == &rhs)
93 return *this;
94
95 dynamic_cast<Array &>(*this) = rhs;
96
97 return *this;
98}
99
100
101// Should this be a private method? jhrg 11/3/04
115long
116NCArray::format_constraint(size_t *cor, ptrdiff_t *step, size_t *edg,
117 bool *has_stride)
118{
119 int start, stride, stop;
120 int id = 0;
121 long nels = 1;
122
123 *has_stride = false;
124
125 for (Dim_iter p = dim_begin(); p != dim_end(); ++p) {
126 start = dimension_start(p, true);
127 stride = dimension_stride(p, true);
128 stop = dimension_stop(p, true);
129#if 0
130 // Check for an empty constraint and use the whole dimension if so.
131 if (start + stop + stride == 0) {
132 start = dimension_start(p, false);
133 stride = dimension_stride(p, false);
134 stop = dimension_stop(p, false);
135 }
136#endif
137 cor[id] = start;
138 step[id] = stride;
139 edg[id] = ((stop - start) / stride) + 1; // count of elements
140 nels *= edg[id++]; // total number of values for variable
141
142 if (stride != 1)
143 *has_stride = true;
144 }
145
146 return nels;
147}
148
149void NCArray::do_cardinal_array_read(int ncid, int varid, nc_type datatype,
150 vector<char> &values, bool has_values, int values_offset,
151 int nels, size_t cor[], size_t edg[], ptrdiff_t step[], bool has_stride)
152{
153 size_t size;
154 int errstat;
155#if NETCDF_VERSION >= 4
156 errstat = nc_inq_type(ncid, datatype, 0, &size);
157 if (errstat != NC_NOERR)
158 throw Error(errstat, "Could not get the size for the type.");
159#else
160 size = nctypelen(datatype);
161#endif
162
163 BESDEBUG( MODULE, prolog << "size = " << size << endl);
164 switch (datatype) {
165 case NC_FLOAT:
166 case NC_DOUBLE:
167 case NC_SHORT:
168 case NC_INT:
169#if NETCDF_VERSION >= 4
170 case NC_USHORT:
171 case NC_UINT:
172 case NC_UBYTE:
173#endif
174 {
175 if (!has_values) {
176 values.resize(nels * size);
177 if (has_stride)
178 errstat = nc_get_vars(ncid, varid, cor, edg, step, &values[0]);
179 else
180 errstat = nc_get_vara(ncid, varid, cor, edg, &values[0]);
181 if (errstat != NC_NOERR){
182 ostringstream oss;
183 oss << prolog << "Could not get the value for Array variable '" << name() << "'.";
184 oss << " dimensions: " << dimensions(true);
185 oss << " nc_get_vara() errstat: " << errstat;
186 throw Error(errstat, oss.str());
187 }
188 // Do not set has_values to true here because the 'true' state
189 // indicates that the values for an entire compound have been
190 // read.
191 }
192
193 val2buf(&values[0] + values_offset);
194 set_read_p(true);
195 break;
196 }
197
198 case NC_BYTE:{
199 if (!has_values) {
200 values.resize(nels * size);
201 if (has_stride)
202 errstat = nc_get_vars(ncid, varid, cor, edg, step, &values[0]);
203 else
204 errstat = nc_get_vara(ncid, varid, cor, edg, &values[0]);
205 if (errstat != NC_NOERR)
206 throw Error(errstat, prolog + "Could not get the value for variable '" + name() + string("' (NCArray::do_cardinal_array_read)"));
207 }
208 if (NCRequestHandler::get_promote_byte_to_short()) {
209 // the data set's signed byte data are going to be stored in a short
210 // not an unsigned byte array. But double check that the template
211 // data type is Int16.
212 if (var()->type() != libdap::dods_int16_c) {
213 throw Error(string("NC.PromoteByteToShort is set but the underlying array type is still a Byte: ") + name() + string("."));
214 }
215 // temporary vector for short (int16) data
216 vector<short int> tmp(nels);
217
218 // Pointer into the byte data. These values might be part of a compound and
219 // thus might have been read by a previous call (has_values is true in that
220 // case).
221 char *raw_byte_data = &values[0] + values_offset;
222 for (int i = 0; i < nels; ++i)
223 tmp[i] = *raw_byte_data++;
224 val2buf(&tmp[0]);
225 set_read_p(true);
226 }
227 else {
228 val2buf(&values[0] + values_offset);
229 set_read_p(true);
230 }
231 break;
232 }
233
234 case NC_CHAR: {
235 // Use the dimension info from netcdf since that's the place where
236 // this variable has N-dims. In the DAP representation it's a N-1
237 // dimensional variable.
238 int num_dim; // number of dim. in variable
239 int vdimids[MAX_VAR_DIMS]; // variable dimension ids
240 errstat = nc_inq_var(ncid, varid, (char *)0, (nc_type*)0, &num_dim, vdimids, (int *)0);
241 if (errstat != NC_NOERR)
242 throw Error(errstat, string("Could not read information about the variable `") + name() + string("'."));
243 if (num_dim < 2) // one-dim --> DAP String and we should not be here
244 throw Error(string("A one-dimensional NC_CHAR array should now map to a DAP string: '") + name() + string("'."));
245
246 size_t vdims[MAX_VAR_DIMS]; // variable dimension sizes
247 for (int i = 0; i < num_dim; ++i)
248 if ((errstat = nc_inq_dimlen(ncid, vdimids[i], &vdims[i])) != NC_NOERR)
249 throw Error(errstat, string("Could not read dimension information about the variable `") + name() + string("'."));
250
251 int nth_dim_size = vdims[num_dim - 1];
252 cor[num_dim - 1] = 0;
253 edg[num_dim - 1] = nth_dim_size;
254 if (has_stride)
255 step[num_dim - 1] = 1;
256
257 if (!has_values) {
258 values.resize(nels * nth_dim_size * size);
259 if (has_stride)
260 errstat = nc_get_vars_text(ncid, varid, cor, edg, step, &values[0]);
261 else
262 errstat = nc_get_vara_text(ncid, varid, cor, edg, &values[0]);
263 if (errstat != NC_NOERR)
264 throw Error(errstat, string("Could not read the variable '") + name() + string("'."));
265 }
266
267 // How large is the Nth dimension? Allocate space for the N-1 dims.
268 vector<string> strg(nels);
269 vector<char> buf(nth_dim_size + 1);
270 // put the char values in the string array
271 for (int i = 0; i < nels; i++) {
272 strncpy(&buf[0], &values[0] + values_offset + (i * nth_dim_size), nth_dim_size);
273 buf[nth_dim_size] = '\0';
274 strg[i] = &buf[0];
275 }
276
277 set_read_p(true);
278 val2buf(&strg[0]);
279 break;
280 }
281#if NETCDF_VERSION >= 4
282 case NC_STRING: {
283 if (!has_values) {
284 values.resize(nels * size);
285 if (has_stride)
286 errstat = nc_get_vars_string(ncid, varid, cor, edg, step, (char**)(&values[0] + values_offset));
287 else
288 errstat = nc_get_vara_string(ncid, varid, cor, edg, (char**)(&values[0] + values_offset));
289 if (errstat != NC_NOERR)
290 throw Error(errstat, string("Could not read the variable `") + name() + string("'."));
291 }
292
293 // put the char values in the string array
294 vector < string > strg(nels);
295 for (int i = 0; i < nels; i++) {
296 // values_offset is in bytes; then cast to char** to find the
297 // ith element; then dereference to get the C-style string.
298 strg[i] = *((char**)(&values[0] + values_offset) + i);
299 }
300
301 nc_free_string(nels, (char**)&values[0]);
302 set_read_p(true);
303 val2buf(&strg[0]);
304 break;
305 }
306#endif
307 default:
308 throw InternalErr(__FILE__, __LINE__, string("Unknown data type for the variable '") + name() + string("'."));
309 }
310}
311
312void NCArray::do_array_read(int ncid, int varid, nc_type datatype,
313 vector<char> &values, bool has_values, int values_offset,
314 int nels, size_t cor[], size_t edg[], ptrdiff_t step[], bool has_stride)
315{
316 int errstat;
317
318#if NETCDF_VERSION >= 4
319 if (datatype >= NC_FIRSTUSERTYPEID /*is_user_defined_type(ncid, datatype)*/) {
320 // datatype >= NC_FIRSTUSERTYPEID) {
321 char type_name[NC_MAX_NAME+1];
322 size_t size;
323 nc_type base_type;
324 size_t nfields;
325 int class_type;
326 errstat = nc_inq_user_type(ncid, datatype, type_name, &size, &base_type, &nfields, &class_type);
327 //cerr << "User-defined attribute type size: " << size << ", nfields: " << nfields << endl;
328 if (errstat != NC_NOERR)
329 throw(InternalErr(__FILE__, __LINE__, "Could not get information about a user-defined type (" + long_to_string(errstat) + ")."));
330
331 switch (class_type) {
332 case NC_COMPOUND: {
333 if (!has_values) {
334 values.resize(size * nels);
335 if (has_stride)
336 errstat = nc_get_vars(ncid, varid, cor, edg, step, &values[0]);
337 else
338 errstat = nc_get_vara(ncid, varid, cor, edg, &values[0]);
339 if (errstat != NC_NOERR)
340 throw Error(errstat, string("Could not get the value for variable '") + name() + string("'"));
341 has_values = true;
342 }
343
344 for (int element = 0; element < nels; ++element) {
345 NCStructure *ncs = dynamic_cast<NCStructure*> (var()->ptr_duplicate());
346 for (size_t i = 0; i < nfields; ++i) {
347 char field_name[NC_MAX_NAME+1];
348 nc_type field_typeid;
349 size_t field_offset;
350 // These are unused... should they be used?
351 // int field_ndims;
352 // int field_sizes[MAX_NC_DIMS];
353 nc_inq_compound_field(ncid, datatype, i, field_name, &field_offset, &field_typeid, 0, 0); //&field_ndims, &field_sizes[0]);
354 BaseType *field = ncs->var(field_name);
355 if (field_typeid >= NC_FIRSTUSERTYPEID /*is_user_defined_type(ncid, field_typeid)*/) {
356 // Interior user defined types have names, but not field_names
357 // so use the type name as the field name (matches the
358 // behavior of the ncdds.cc code).
359 nc_inq_compound_name(ncid, field_typeid, field_name);
360 field = ncs->var(field_name);
361 NCStructure &child_ncs = dynamic_cast<NCStructure&> (*field);
362 child_ncs.do_structure_read(ncid, varid, field_typeid,
363 values, has_values, field_offset + values_offset + size * element);
364 }
365 else if (field->is_vector_type()) {
366 // Because the netcdf api reads data 'atomically' from
367 // compounds, this call works for both cardinal and
368 // array variables.
369 NCArray &child_array = dynamic_cast<NCArray&>(*field);
370 child_array.do_array_read(ncid, varid, field_typeid,
371 values, has_values, field_offset + values_offset + size * element,
372 nels, cor, edg, step, has_stride);
373 }
374 else if (field->is_simple_type()) {
375 field->val2buf(&values[0] + (element * size) + field_offset);
376 }
377 else {
378 throw InternalErr(__FILE__, __LINE__, "Expecting a netcdf user defined type or an array or a scalar.");
379 }
380
381 field->set_read_p(true);
382 }
383 ncs->set_read_p(true);
384 set_vec(element, ncs);
385 }
386
387 set_read_p(true);
388 break;
389 }
390
391 case NC_VLEN:
392 if (NCRequestHandler::get_ignore_unknown_types())
393 cerr << "in build_user_defined; found a vlen." << endl;
394 else
395 throw Error("The netCDF handler does not currently support NC_VLEN attributes.");
396 break;
397
398 case NC_OPAQUE: {
399 // Use the dimension info from netcdf since that's the place where
400 // this variable has N-dims. In the DAP representation it's a N-1
401 // dimensional variable.
402 int num_dim; // number of dim. in variable
403 int vdimids[MAX_VAR_DIMS]; // variable dimension ids
404 errstat = nc_inq_var(ncid, varid, (char *)0, (nc_type*)0, &num_dim, vdimids, (int *)0);
405 if (errstat != NC_NOERR)
406 throw Error(errstat, string("Could not read information about the variable `") + name() + string("'."));
407 if (num_dim < 1) // one-dim --> DAP String and we should not be here
408 throw Error(string("A one-dimensional NC_OPAQUE array should now map to a DAP Byte: '") + name() + string("'."));
409
410 size_t vdims[MAX_VAR_DIMS]; // variable dimension sizes
411 for (int i = 0; i < num_dim; ++i)
412 if ((errstat = nc_inq_dimlen(ncid, vdimids[i], &vdims[i])) != NC_NOERR)
413 throw Error(errstat, string("Could not read dimension information about the variable `") + name() + string("'."));
414
415 int nth_dim_size = vdims[num_dim - 1];
416 cor[num_dim - 1] = 0;
417 edg[num_dim - 1] = nth_dim_size;
418 if (has_stride)
419 step[num_dim - 1] = 1;
420
421 if (!has_values) {
422 values.resize(size * nels);
423 if (has_stride)
424 errstat = nc_get_vars(ncid, varid, cor, edg, step, &values[0]);
425 else
426 errstat = nc_get_vara(ncid, varid, cor, edg, &values[0]);
427 if (errstat != NC_NOERR)
428 throw Error(errstat, string("Could not get the value for variable '") + name() + string("' (NC_OPAQUE)"));
429 has_values = true; // This value may never be used. jhrg 1/9/12
430 }
431
432 val2buf(&values[0] + values_offset);
433
434 set_read_p(true);
435 break;
436 }
437
438 case NC_ENUM: {
439 nc_type base_nc_type;
440 errstat = nc_inq_enum(ncid, datatype, 0 /*&name[0]*/, &base_nc_type, 0/*&base_size*/, 0/*&num_members*/);
441 if (errstat != NC_NOERR)
442 throw(InternalErr(__FILE__, __LINE__, "Could not get information about an enum(" + long_to_string(errstat) + ")."));
443
444 do_cardinal_array_read(ncid, varid, base_nc_type,
445 values, has_values, values_offset,
446 nels, cor, edg, step, has_stride);
447
448 set_read_p(true);
449 break;
450 }
451
452 default:
453 throw InternalErr(__FILE__, __LINE__, "Expected one of NC_COMPOUND, NC_VLEN, NC_OPAQUE or NC_ENUM");
454 }
455
456 }
457 else {
458 do_cardinal_array_read(ncid, varid, datatype, values, has_values, values_offset,
459 nels, cor, edg, step, has_stride);
460 }
461#else
462 do_cardinal_array_read(ncid, varid, datatype, values, has_values, values_offset,
463 nels, cor, edg, step, has_stride);
464#endif
465}
466
467bool NCArray::read()
468{
469 if (read_p()) // Nothing to do
470 return true;
471
472 int ncid;
473 int errstat = nc_open(dataset().c_str(), NC_NOWRITE, &ncid); /* netCDF id */
474 if (errstat != NC_NOERR)
475 throw Error(errstat, string("Could not open the dataset's file (") + dataset().c_str() + string(")"));
476
477 int varid; /* variable Id */
478 errstat = nc_inq_varid(ncid, name().c_str(), &varid);
479 if (errstat != NC_NOERR)
480 throw InternalErr(__FILE__, __LINE__, "Could not get variable ID for: " + name() + ". (error: " + long_to_string(errstat) + ").");
481
482 nc_type datatype; // variable data type
483 errstat = nc_inq_vartype(ncid, varid, &datatype);
484 if (errstat != NC_NOERR)
485 throw Error(errstat, string("Could not read information about the variable `") + name() + string("'."));
486
487 size_t cor[MAX_NC_DIMS]; /* corner coordinates */
488 size_t edg[MAX_NC_DIMS]; /* edges of hyper-cube */
489 ptrdiff_t step[MAX_NC_DIMS]; /* stride of hyper-cube */
490 bool has_stride;
491 for(unsigned int i=0; i<MAX_NC_DIMS; i++){
492 cor[i] = edg[i] = step[i] = 0;
493 }
494 long nels = format_constraint(cor, step, edg, &has_stride);
495// ostringstream oss;
496// for(unsigned int i=0; i<MAX_NC_DIMS; i++){
497// oss << cor[i] << ", " << edg[i] << ", " << step[i] << endl;
498// }
499// BESDEBUG( MODULE, prolog << "corners, edges, stride" << endl << oss.str() << endl);
500
501 vector<char> values;
502 do_array_read(ncid, varid, datatype, values, false /*has_values*/, 0 /*values_offset*/,
503 nels, cor, edg, step, has_stride);
504 set_read_p(true);
505
506 if (nc_close(ncid) != NC_NOERR)
507 throw InternalErr(__FILE__, __LINE__, "Could not close the dataset!");
508
509 return true;
510}
NCArray(const string &n, const string &d, BaseType *v)
Definition: NCArray.cc:78