Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: netCDF read/write Driver
4 : * Purpose: GDAL bindings over netCDF library.
5 : * Author: Winor Chen <wchen329 at wisc.edu>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2019, Winor Chen <wchen329 at wisc.edu>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 : #include "netcdfdataset.h"
29 : #include "netcdfvirtual.h"
30 :
31 : // netCDF Virtual
32 : // Provides a layer of "virtual ncID"
33 : // that can be mapped to a real netCDF ID
34 : namespace nccfdriver
35 : {
36 4 : void netCDFVDimension::invalidate()
37 : {
38 4 : this->valid = false;
39 4 : real_dim_name.clear();
40 4 : }
41 :
42 260 : netCDFVVariable::netCDFVVariable(const char *name, nc_type xtype, int ndims,
43 260 : const int *dimidsp)
44 260 : : real_var_name(name), ntype(xtype), ndimc(ndims), dimid(new int[ndims])
45 : {
46 568 : for (int c = 0; c < ndims; c++)
47 : {
48 308 : dimid.get()[c] = dimidsp[c];
49 : }
50 260 : }
51 :
52 21 : void netCDFVVariable::invalidate()
53 : {
54 21 : this->valid = false;
55 21 : real_var_name.clear();
56 21 : attribs.clear();
57 21 : }
58 :
59 168 : int netCDFVID::nc_def_vdim(const char *name, size_t len)
60 : {
61 168 : if (directMode)
62 : {
63 : int ddim;
64 : int err;
65 19 : if ((err = nc_def_dim(ncid, name, len, &ddim)) != NC_NOERR)
66 : {
67 0 : NCDF_ERR(err);
68 : throw SG_Exception_VWrite_Failure("netCDF file",
69 0 : "a dimension definition");
70 : }
71 :
72 19 : return ddim;
73 : }
74 :
75 149 : int dimID = dimTicket;
76 :
77 : // Check if name is already defined
78 149 : if (nameDimTable.count(std::string(name)) > 0)
79 : {
80 0 : throw SG_Exception_DupName(name, "virtual dimension collection");
81 : }
82 :
83 : // Add to lookup tables
84 149 : dimList.push_back(netCDFVDimension(name, len, dimTicket));
85 149 : dimTicket++;
86 149 : nameDimTable.insert(std::pair<std::string, int>(std::string(name), dimID));
87 :
88 : // Return virtual dimID
89 149 : return dimID;
90 : }
91 :
92 362 : int netCDFVID::nc_def_vvar(const char *name, nc_type xtype, int ndims,
93 : const int *dimidsp)
94 : {
95 362 : if (directMode)
96 : {
97 : int dvar;
98 : int err;
99 102 : if ((err = nc_def_var(ncid, name, xtype, ndims, dimidsp, &dvar)) !=
100 : NC_NOERR)
101 : {
102 0 : NCDF_ERR(err);
103 : throw SG_Exception_VWrite_Failure("netCDF file",
104 0 : "a dimension definition");
105 : }
106 :
107 102 : return dvar;
108 : }
109 :
110 260 : int varID = varTicket;
111 :
112 : // Check if name is already defined
113 260 : if (nameVarTable.count(std::string(name)) > 0)
114 : {
115 0 : throw SG_Exception_DupName(name, "virtual variable collection");
116 : }
117 :
118 : // Add to lookup tables
119 260 : varList.push_back(netCDFVVariable(name, xtype, ndims, dimidsp));
120 260 : varTicket++;
121 260 : nameVarTable.insert(std::pair<std::string, int>(std::string(name), varID));
122 :
123 : // Return virtual dimID
124 260 : return varID;
125 : }
126 :
127 4 : void netCDFVID::nc_del_vdim(int dimid)
128 : {
129 : // First remove from name map
130 4 : nameDimTable.erase(this->dimList[dimid].getName());
131 :
132 : // Then clear actual dim
133 4 : this->dimList[dimid].invalidate();
134 4 : }
135 :
136 21 : void netCDFVID::nc_del_vvar(int varid)
137 : {
138 : // First remove from name map
139 21 : nameVarTable.erase(this->varList[varid].getName());
140 :
141 : // Then clear actual variable
142 21 : this->varList[varid].invalidate();
143 21 : }
144 :
145 136 : void netCDFVID::nc_resize_vdim(int dimid, size_t dimlen)
146 : {
147 136 : netCDFVDimension &dim = virtualDIDToDim(dimid);
148 :
149 136 : if (dim.getRealID() == INVALID_DIM_ID)
150 : {
151 136 : dim.setLen(dimlen);
152 : }
153 136 : }
154 :
155 109 : void netCDFVID::nc_set_define_mode()
156 : {
157 109 : nc_redef(ncid);
158 109 : }
159 :
160 109 : void netCDFVID::nc_set_data_mode()
161 : {
162 109 : nc_enddef(ncid);
163 109 : }
164 :
165 109 : void netCDFVID::nc_vmap()
166 : {
167 109 : nc_set_define_mode();
168 :
169 258 : for (size_t itr_d = 0; itr_d < dimList.size(); itr_d++)
170 : {
171 : int realDimID;
172 149 : netCDFVDimension &dim = dimList[itr_d];
173 :
174 149 : if (!dim.isValid())
175 : {
176 4 : continue; // don't do anywork if variable is invalid
177 : }
178 :
179 145 : nc_def_dim(ncid, dim.getName().c_str(), dim.getLen(), &realDimID);
180 145 : dimList[itr_d].setRealID(realDimID);
181 : }
182 :
183 369 : for (size_t itr_v = 0; itr_v < varList.size(); itr_v++)
184 : {
185 : int realVarID;
186 260 : netCDFVVariable &var = varList[itr_v];
187 :
188 260 : if (!var.isValid())
189 : {
190 21 : continue; // don't do any work if variable is invalid
191 : }
192 :
193 : // Convert each virtual dimID to a physical dimID:
194 : std::unique_ptr<int, std::default_delete<int[]>> newdims(
195 478 : new int[var.getDimCount()]);
196 526 : for (int dimct = 0; dimct < var.getDimCount(); dimct++)
197 : {
198 287 : newdims.get()[dimct] =
199 287 : virtualDIDToDim(var.getDimIds()[dimct]).getRealID();
200 : }
201 :
202 239 : nc_def_var(ncid, var.getName().c_str(), var.getType(),
203 239 : var.getDimCount(), newdims.get(), &realVarID);
204 239 : var.setRealID(realVarID);
205 :
206 : // Now write each of its attributes
207 988 : for (size_t attrct = 0; attrct < var.getAttributes().size(); attrct++)
208 : {
209 749 : var.getAttributes()[attrct]->vsync(ncid, realVarID);
210 : }
211 :
212 239 : var.getAttributes().clear();
213 : }
214 :
215 109 : nc_set_data_mode();
216 109 : }
217 :
218 : /* Enquiry Functions
219 : * (For use with enquiry information about virtual entities)
220 : */
221 25098 : netCDFVVariable &netCDFVID::virtualVIDToVar(int virtualID)
222 : {
223 25098 : if (virtualID >= static_cast<int>(varList.size()) || virtualID < 0)
224 : {
225 0 : throw SG_Exception_NVOOB("virtual variable collection");
226 : }
227 :
228 25098 : return varList[virtualID];
229 : }
230 :
231 1307 : netCDFVDimension &netCDFVID::virtualDIDToDim(int virtualID)
232 : {
233 1307 : if (virtualID >= static_cast<int>(dimList.size()) || virtualID < 0)
234 : {
235 0 : throw SG_Exception_NVOOB("virtual dimension collection");
236 : }
237 :
238 1307 : return dimList[virtualID];
239 : }
240 :
241 0 : int netCDFVID::nameToVirtualVID(const std::string &name)
242 : {
243 0 : if (nameVarTable.count(name) < 1)
244 : {
245 0 : throw SG_Exception_BadMapping(name.c_str(), "variable ID lookup");
246 : }
247 :
248 0 : return nameVarTable.at(name);
249 : }
250 :
251 0 : int netCDFVID::nameToVirtualDID(const std::string &name)
252 : {
253 0 : if (nameDimTable.count(name) < 1)
254 : {
255 0 : throw SG_Exception_BadMapping(name.c_str(), "dimension ID lookup");
256 : }
257 0 : return nameDimTable.at(name);
258 : }
259 :
260 : /* Attribute writing
261 : *
262 : */
263 :
264 1679 : void netCDFVID::nc_put_vatt_text(int varid, const char *name, const char *value)
265 : {
266 1679 : if (directMode)
267 : {
268 : int err;
269 981 : if ((err = nc_put_att_text(ncid, varid, name, strlen(value), value)) !=
270 : NC_NOERR)
271 : {
272 0 : NCDF_ERR(err);
273 0 : throw SG_Exception_VWrite_Failure("variable", "text attribute");
274 : }
275 981 : return;
276 : }
277 :
278 698 : nc_put_vatt_generic<netCDFVTextAttribute, char>(varid, name, value);
279 : }
280 :
281 78 : void netCDFVID::nc_put_vatt_int(int varid, const char *name, const int *value)
282 : {
283 78 : if (directMode)
284 : {
285 : int err;
286 27 : if ((err = nc_put_att_int(ncid, varid, name, NC_INT, 1, value)) !=
287 : NC_NOERR)
288 : {
289 0 : NCDF_ERR(err);
290 0 : throw SG_Exception_VWrite_Failure("variable", "int attribute");
291 : }
292 27 : return;
293 : }
294 :
295 51 : nc_put_vatt_generic<netCDFVIntAttribute, int>(varid, name, value);
296 : }
297 :
298 1 : void netCDFVID::nc_put_vatt_double(int varid, const char *name,
299 : const double *value)
300 : {
301 1 : if (directMode)
302 : {
303 : int err;
304 1 : if ((err = nc_put_att_double(ncid, varid, name, NC_DOUBLE, 1, value)) !=
305 : NC_NOERR)
306 : {
307 0 : NCDF_ERR(err);
308 0 : throw SG_Exception_VWrite_Failure("variable", "double attribute");
309 : }
310 1 : return;
311 : }
312 :
313 0 : nc_put_vatt_generic<netCDFVDoubleAttribute, double>(varid, name, value);
314 : }
315 :
316 0 : void netCDFVID::nc_put_vatt_float(int varid, const char *name,
317 : const float *value)
318 : {
319 0 : if (directMode)
320 : {
321 : int err;
322 0 : if ((err = nc_put_att_float(ncid, varid, name, NC_FLOAT, 1, value)) !=
323 : NC_NOERR)
324 : {
325 0 : NCDF_ERR(err);
326 0 : throw SG_Exception_VWrite_Failure("variable", "float attribute");
327 : }
328 0 : return;
329 : }
330 :
331 0 : nc_put_vatt_generic<netCDFVFloatAttribute, float>(varid, name, value);
332 : }
333 :
334 0 : void netCDFVID::nc_put_vatt_byte(int varid, const char *name,
335 : const signed char *value)
336 : {
337 0 : if (directMode)
338 : {
339 : int err;
340 0 : if ((err = nc_put_att_schar(ncid, varid, name, NC_BYTE, 1, value)) !=
341 : NC_NOERR)
342 : {
343 0 : NCDF_ERR(err);
344 0 : throw SG_Exception_VWrite_Failure("variable", "byte attribute");
345 : }
346 0 : return;
347 : }
348 :
349 0 : nc_put_vatt_generic<netCDFVByteAttribute, signed char>(varid, name, value);
350 : }
351 :
352 698 : void netCDFVTextAttribute::vsync(int realncid, int realvarid)
353 : {
354 698 : if (nc_put_att_text(realncid, realvarid, name.c_str(), value.size(),
355 698 : value.c_str()) != NC_NOERR)
356 : {
357 0 : throw SG_Exception_VWrite_Failure("variable", "attribute");
358 : }
359 698 : }
360 :
361 : /* Single Datum Writing
362 : * (mostly just convenience functions)
363 : */
364 0 : void netCDFVID::nc_put_vvar1_text(int varid, const size_t *index,
365 : const char *value)
366 : {
367 0 : int rvarid = !directMode ? virtualVIDToVar(varid).getRealID() : varid;
368 0 : if (rvarid == INVALID_VAR_ID)
369 0 : return; // invalidated variable, don't care condition that Scribe
370 : // relies on
371 :
372 0 : if (nc_put_var1_text(ncid, rvarid, index, value) != NC_NOERR)
373 : {
374 0 : throw SG_Exception_VWrite_Failure("variable", "datum");
375 : }
376 : }
377 :
378 884 : void netCDFVID::nc_put_vvara_text(int varid, const size_t *start,
379 : const size_t *count, const char *value)
380 : {
381 884 : int rvarid = !directMode ? virtualVIDToVar(varid).getRealID() : varid;
382 884 : if (rvarid == INVALID_VAR_ID)
383 0 : return; // invalidated variable, don't care condition that Scribe
384 : // relies on
385 884 : if (nc_put_vara_text(ncid, rvarid, start, count, value) != NC_NOERR)
386 : {
387 0 : throw SG_Exception_VWrite_Failure("variable", "datum");
388 : }
389 : }
390 :
391 14 : void netCDFVID::nc_put_vvar1_string(int varid, const size_t *index,
392 : const char **value)
393 : {
394 14 : int rvarid = !directMode ? virtualVIDToVar(varid).getRealID() : varid;
395 :
396 14 : if (rvarid == INVALID_VAR_ID)
397 0 : return; // invalidated variable
398 :
399 14 : if (nc_put_var1_string(ncid, rvarid, index, value) != NC_NOERR)
400 : {
401 0 : throw SG_Exception_VWrite_Failure("variable", "datum");
402 : }
403 : }
404 :
405 : } // namespace nccfdriver
|