bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
NCStructure.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
27// (c) COPYRIGHT URI/MIT 1994-1996
28// Please read the full copyright statement in the file COPYRIGHT.
29//
30// Authors:
31// reza Reza Nekovei (reza@intcomm.net)
32
33// netCDF sub-class implementation for NCByte,...NCGrid.
34// The files are patterned after the subcalssing examples
35// Test<type>.c,h files.
36//
37// ReZa 1/12/95
38
39#include "config_nc.h"
40
41static char rcsid[] not_used ={"$Id$"};
42
43#include <vector>
44#include <algorithm>
45
46#include <netcdf.h>
47
48#include <libdap/D4Attributes.h>
49#include <libdap/util.h>
50#include <libdap/InternalErr.h>
51
52#include "nc_util.h"
53#include "NCStructure.h"
54#include "NCArray.h"
55
56BaseType *
57NCStructure::ptr_duplicate()
58{
59 return new NCStructure(*this);
60}
61
62NCStructure::NCStructure(const string &n, const string &d) : Structure(n, d)
63{
64}
65
66NCStructure::NCStructure(const NCStructure &rhs) : Structure(rhs)
67{
68}
69
70NCStructure::~NCStructure()
71{
72}
73
75NCStructure::operator=(const NCStructure &rhs)
76{
77 if (this == &rhs)
78 return *this;
79
80 dynamic_cast<Structure&>(*this) = rhs; // run Structure assignment
81
82 return *this;
83}
84
87
88class AddAttribute: public unary_function<BaseType *, void> {
89
90public:
91 AddAttribute() {}
92
93 void operator()(BaseType *a) {
94 AttrTable *at;
95 AttrTable::Attr_iter aiter;
96 a->get_attr_table().find("translation", &at, &aiter);
97 if (a->get_attr_table().attr_end() == aiter) {
98 a->get_attr_table().append_attr("translation", "String",
99 "\"flatten\"");
100 }
101 }
102};
103
125{
126 if (at) {
127 Vars_iter var = var_begin();
128 while (var != var_end()) {
129 (*var)->transfer_attributes(at);
130 var++;
131 }
132 }
133}
134
147void
148NCStructure::transform_to_dap4(D4Group *root, Constructor *container)
149{
150 Structure *dest = new NCStructure(name(), dataset());
151 Constructor::transform_to_dap4(root, dest);
152 container->add_var_nocopy(dest);
153}
154
155void NCStructure::do_structure_read(int ncid, int varid, nc_type datatype,
156 vector<char> &values, bool has_values, int values_offset)
157{
158#if NETCDF_VERSION >= 4
159 if (is_user_defined_type(ncid, datatype)) {
160 char type_name[NC_MAX_NAME+1];
161 size_t size;
162 nc_type base_type;
163 size_t nfields;
164 int class_type;
165 int errstat = nc_inq_user_type(ncid, datatype, type_name, &size, &base_type, &nfields, &class_type);
166 if (errstat != NC_NOERR)
167 throw InternalErr(__FILE__, __LINE__, "Could not get information about a user-defined type (" + long_to_string(errstat) + ").");
168
169 switch (class_type) {
170 case NC_COMPOUND: {
171 if (!has_values) {
172 values.resize(size);
173 int errstat = nc_get_var(ncid, varid, values.data() /*values.data()*/);
174 if (errstat != NC_NOERR)
175 throw Error(errstat, string("Could not get the value for variable '") + name() + string("'"));
176 has_values = true;
177 }
178
179 for (size_t i = 0; i < nfields; ++i) {
180 char field_name[NC_MAX_NAME+1];
181 nc_type field_typeid;
182 size_t field_offset;
183 int field_ndims;
184 nc_inq_compound_field(ncid, datatype, i, field_name, &field_offset, &field_typeid, &field_ndims, 0);
185 if (is_user_defined_type(ncid, field_typeid)) {
186 // Interior user defined types have names, but not field_names
187 // so use the type name as the field name (matches the
188 // behavior of the ncdds.cc code).
189 nc_inq_compound_name(ncid, field_typeid, field_name);
190 NCStructure &ncs = dynamic_cast<NCStructure&>(*var(field_name));
191 ncs.do_structure_read(ncid, varid, field_typeid, values, has_values, field_offset + values_offset);
192 }
193 else if (var(field_name)->is_vector_type()) {
194 // Because the netcdf api reads data 'atomically' from
195 // compounds, this call works for both cardinal and
196 // array variables.
197 NCArray &child_array = dynamic_cast<NCArray&>(*var(field_name));
198 vector<size_t> cor(field_ndims);
199 vector<size_t> edg(field_ndims);
200 vector<ptrdiff_t> step(field_ndims);
201 bool has_stride;
202 long nels = child_array.format_constraint(cor.data(), step.data(), edg.data(), &has_stride);
203 child_array.do_array_read(ncid, varid, field_typeid,
204 values, has_values, field_offset + values_offset,
205 nels, cor.data(), edg.data(), step.data(), has_stride);
206 }
207 else if (var(field_name)->is_simple_type()) {
208 var(field_name)->val2buf(values.data() + field_offset + values_offset);
209 }
210 else {
211 throw InternalErr(__FILE__, __LINE__, "Expecting a netcdf user defined type or an array or a scalar.");
212 }
213
214 var(field_name)->set_read_p(true);
215 }
216 break;
217 }
218
219 case NC_VLEN:
220 cerr << "in build_user_defined; found a vlen." << endl;
221 break;
222 case NC_OPAQUE:
223 cerr << "in build_user_defined; found a opaque." << endl;
224 break;
225 case NC_ENUM:
226 cerr << "in build_user_defined; found a enum." << endl;
227 break;
228 default:
229 throw InternalErr(__FILE__, __LINE__, "Expected one of NC_COMPOUND, NC_VLEN, NC_OPAQUE or NC_ENUM");
230 }
231 }
232 else
233 throw InternalErr(__FILE__, __LINE__, "Found a DAP Structure bound to a non-user-defined type in the netcdf file " + dataset());
234#else
235 throw InternalErr(__FILE__, __LINE__, "Found a DAP Structure bound to a non-user-defined type in the netcdf file " + dataset());
236#endif
237}
238
239bool NCStructure::read()
240{
241 if (read_p()) // nothing to do
242 return true;
243
244 int ncid;
245 int errstat = nc_open(dataset().c_str(), NC_NOWRITE, &ncid); /* netCDF id */
246 if (errstat != NC_NOERR)
247 throw Error(errstat, "Could not open the dataset's file (" + dataset() + ")");
248
249 int varid; /* variable Id */
250 errstat = nc_inq_varid(ncid, name().c_str(), &varid);
251 if (errstat != NC_NOERR)
252 throw InternalErr(__FILE__, __LINE__, "Could not get variable ID for: " + name() + ". (error: " + long_to_string(errstat) + ").");
253
254 nc_type datatype; /* variable data type */
255 errstat = nc_inq_vartype(ncid, varid, &datatype);
256 if (errstat != NC_NOERR)
257 throw Error(errstat, "Could not read data type information about : " + name() + ". (error: " + long_to_string(errstat) + ").");
258
259 // For Compound types, netcdf's nc_get_var() reads all of the structure's
260 // values in one shot, including values for nested structures. Pass the
261 // (reference to the) space for these in at the start of what may be a
262 // series of recursive calls.
263 vector<char> values;
264 do_structure_read(ncid, varid, datatype, values, false /*has_values*/, 0 /*values_offset*/);
265
266 set_read_p(true);
267
268 if (nc_close(ncid) != NC_NOERR)
269 throw InternalErr(__FILE__, __LINE__, "Could not close the dataset!");
270
271 return true;
272}
273
274
virtual void transfer_attributes(AttrTable *at)
virtual void transform_to_dap4(D4Group *root, Constructor *container)
STL class.