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 : #ifndef __NETCDFVIRTUAL_H__
29 : #define __NETCDFVIRTUAL_H__
30 : #include <map>
31 : #include <memory>
32 : #include <string>
33 : #include <vector>
34 : #include "netcdfsg.h"
35 : #include "netcdf.h"
36 :
37 : // netCDF Virtual
38 : // Provides a layer of "virtual ncID"
39 : // that can be mapped to a real netCDF ID
40 : namespace nccfdriver
41 : {
42 : // Exceptions
43 : class SG_Exception_NVOOB : public SG_Exception
44 : {
45 : std::string err_msg;
46 :
47 : public:
48 0 : explicit SG_Exception_NVOOB(const char *dsname)
49 0 : : err_msg(std::string("An attempt to read an undefined ID from ") +
50 0 : std::string(dsname) + std::string(" was made"))
51 : {
52 0 : }
53 :
54 0 : const char *get_err_msg() override
55 : {
56 0 : return this->err_msg.c_str();
57 : }
58 : };
59 :
60 : class SG_Exception_DupName : public SG_Exception
61 : {
62 : std::string err_msg;
63 :
64 : public:
65 0 : SG_Exception_DupName(const char *keyn, const char *dsname)
66 0 : : err_msg(std::string("The key ") + std::string(keyn) +
67 0 : std::string(" already exists in") + std::string(dsname))
68 : {
69 0 : }
70 :
71 0 : const char *get_err_msg() override
72 : {
73 0 : return this->err_msg.c_str();
74 : }
75 : };
76 :
77 : class SG_Exception_BadMapping : public SG_Exception
78 : {
79 : std::string err_msg;
80 :
81 : public:
82 0 : SG_Exception_BadMapping(const char *key, const char *where)
83 0 : : err_msg(std::string(key) + std::string(" not found in ") +
84 0 : std::string(where))
85 : {
86 0 : }
87 :
88 0 : const char *get_err_msg() override
89 : {
90 0 : return this->err_msg.c_str();
91 : }
92 : };
93 :
94 : class SG_Exception_VWrite_Failure : public SG_Exception
95 : {
96 : std::string err_msg;
97 :
98 : public:
99 0 : SG_Exception_VWrite_Failure(const char *where, const char *type)
100 0 : : err_msg(std::string("Failed to write ") + std::string(type) +
101 0 : std::string(" to ") + std::string(where))
102 : {
103 0 : }
104 :
105 0 : const char *get_err_msg() override
106 : {
107 0 : return this->err_msg.c_str();
108 : }
109 : };
110 :
111 : /* netCDFVAttribute
112 : * -
113 : * Contains attribute name and data.
114 : * Central to derived types are reimplementations of vsync
115 : */
116 : class netCDFVAttribute
117 : {
118 : public:
119 : /* vsync(...)
120 : * Implementation: Given the REAL ncID and REAL variable ID
121 : * Write the attribute to the variable
122 : */
123 : virtual void vsync(int realncid, int realvarid) = 0;
124 :
125 : /* ~netCDFVAttribute()
126 : * Virtual destructor
127 : */
128 749 : virtual ~netCDFVAttribute()
129 749 : {
130 749 : }
131 : };
132 :
133 : template <class VClass, nc_type ntype>
134 : class netCDFVGeneralAttribute : public netCDFVAttribute
135 : {
136 : std::string name;
137 : VClass value;
138 :
139 : public:
140 51 : netCDFVGeneralAttribute<VClass, ntype>(const char *a_name,
141 : const VClass *a_value)
142 51 : : name(a_name), value(*a_value)
143 : {
144 51 : }
145 :
146 51 : void vsync(int realncid, int realvarid) override
147 : {
148 51 : if (nc_put_att(realncid, realvarid, name.c_str(), ntype, 1, &value) !=
149 : NC_NOERR)
150 : {
151 0 : throw SG_Exception_VWrite_Failure("variable", "attribute");
152 : }
153 51 : }
154 : };
155 :
156 : /* netCDFVTextAttribute
157 : * -
158 : * Attribute that has a text string value
159 : */
160 : class netCDFVTextAttribute : public netCDFVAttribute
161 : {
162 : std::string name;
163 : std::string value;
164 :
165 : public:
166 698 : netCDFVTextAttribute(const char *a_name, const char *a_value)
167 698 : : name(a_name), value(a_value)
168 : {
169 698 : }
170 :
171 : void vsync(int realncid, int realvarid) override;
172 : };
173 :
174 : typedef netCDFVGeneralAttribute<signed char, NC_BYTE> netCDFVByteAttribute;
175 : typedef netCDFVGeneralAttribute<int, NC_INT> netCDFVIntAttribute;
176 : typedef netCDFVGeneralAttribute<double, NC_DOUBLE> netCDFVDoubleAttribute;
177 : typedef netCDFVGeneralAttribute<float, NC_FLOAT> netCDFVFloatAttribute;
178 :
179 : /* netCDFVDimension
180 : * -
181 : * Contains the real dim id, real dimension name, and dimension length
182 : */
183 : class netCDFVDimension
184 : {
185 : friend class netCDFVID;
186 :
187 : std::string real_dim_name;
188 : int r_did = INVALID_DIM_ID;
189 : int v_did;
190 : size_t dim_len;
191 : bool valid = true;
192 :
193 : protected:
194 145 : void setRealID(int realID)
195 : {
196 145 : this->r_did = realID;
197 145 : }
198 :
199 : void invalidate();
200 :
201 136 : void setLen(size_t len)
202 : {
203 136 : this->dim_len = len;
204 136 : }
205 :
206 : public:
207 149 : netCDFVDimension(const char *name, size_t len, int dimid)
208 149 : : real_dim_name(name), v_did(dimid), dim_len(len)
209 : {
210 149 : }
211 :
212 149 : std::string &getName()
213 : {
214 149 : return this->real_dim_name;
215 : }
216 :
217 1029 : size_t getLen()
218 : {
219 1029 : return this->dim_len;
220 : }
221 :
222 423 : int getRealID()
223 : {
224 423 : return this->r_did;
225 : }
226 :
227 : int getVirtualID()
228 : {
229 : return this->v_did;
230 : }
231 :
232 149 : bool isValid()
233 : {
234 149 : return this->valid;
235 : }
236 : };
237 :
238 : /* netCDFVVariable
239 : * -
240 : * Contains the variable name, variable type, etc.
241 : */
242 : class netCDFVVariable
243 : {
244 : friend class netCDFVID;
245 :
246 : std::string real_var_name;
247 : nc_type ntype;
248 : int r_vid = INVALID_VAR_ID;
249 : int ndimc;
250 : std::unique_ptr<int, std::default_delete<int[]>> dimid;
251 : std::vector<std::shared_ptr<netCDFVAttribute>> attribs;
252 : bool valid = true;
253 :
254 : protected:
255 2725 : std::vector<std::shared_ptr<netCDFVAttribute>> &getAttributes()
256 : {
257 2725 : return attribs;
258 : }
259 :
260 : void invalidate();
261 :
262 239 : void setRealID(int realID)
263 : {
264 239 : this->r_vid = realID;
265 239 : }
266 :
267 : public:
268 : netCDFVVariable(const char *name, nc_type xtype, int ndims,
269 : const int *dimidsp);
270 :
271 260 : std::string &getName()
272 : {
273 260 : return real_var_name;
274 : }
275 :
276 24349 : int getRealID()
277 : {
278 24349 : return r_vid;
279 : }
280 :
281 239 : nc_type getType()
282 : {
283 239 : return ntype;
284 : }
285 :
286 1004 : int getDimCount()
287 : {
288 1004 : return this->ndimc;
289 : }
290 :
291 287 : const int *getDimIds()
292 : {
293 287 : return this->dimid.get();
294 : }
295 :
296 260 : bool isValid()
297 : {
298 260 : return this->valid;
299 : }
300 : };
301 :
302 : /* netCDFVID
303 : * -
304 : * A netCDF ID that sits on top of an actual netCDF ID
305 : * And manages actual interaction with the real netCDF file
306 : *
307 : * A bit difference is that netCDFVID
308 : * doesn't have fixed dim sizes, until defines are committed
309 : *
310 : * Also, virtual attributes only exist until the variable is committed. Use
311 : * "real" attributes and "real" IDs for a variable after its been committed.
312 : *
313 : * ** Do not mix netCDF virtual dim and variable IDs with regular netCDF dim
314 : * (a.k.a. "real") ids and variable ids. They are NOT necessarily compatible,
315 : * and must be translated first, to be used in this manner **
316 : *
317 : * The netCDFVID can also be used in what is called "direct mode" and the
318 : * netCDFVID will just act as a wrapper to the netCDF Library. In such a case
319 : * netCDFVID should take real IDs, not real ones. However, the big advantages of
320 : * using netCDFVID (such as quick dim resizing) are no longer are available.
321 : */
322 : class netCDFVID
323 : {
324 : int &ncid; // ncid REF. which tracks ncID changes that may be made upstream
325 : int dimTicket = 0;
326 : int varTicket = 0;
327 : bool directMode = true;
328 :
329 : std::vector<netCDFVVariable> varList;
330 : std::vector<netCDFVDimension> dimList;
331 :
332 : std::map<std::string, int> nameDimTable;
333 : std::map<std::string, int> nameVarTable;
334 :
335 : public:
336 : // Each of these returns an ID, NOT an error code
337 :
338 : /* nc_def_vdim(...)
339 : * Defines a virtual dim given the parameters NAME and LENGTH.
340 : * Returns: virtual dimID
341 : */
342 : int nc_def_vdim(
343 : const char *name,
344 : size_t dimlen); // for dims that don't already exist in netCDF file
345 :
346 : /* nc_def_vvar(...)
347 : * Defines a virtual var given the parameters NAME, NC TYPE, NUMBER OF DIMS,
348 : * and DIM IDS The dim IDs in dimidsp given are to be virtual dim IDs, using
349 : * real dim IDs is undefined
350 : */
351 : int nc_def_vvar(const char *name, nc_type xtype, int ndims,
352 : const int *dimidsp);
353 :
354 : /* nc_del_vdim(...)
355 : * Delete a virtual dimension
356 : * NOTES:
357 : * This doesn't work on committed IDs.
358 : * Also the dimension (for now) will be only invalidated, doesn't
359 : * completely *delete* it in memory.
360 : */
361 : void nc_del_vdim(int dimid);
362 :
363 : /* nc_del_vvar(...)
364 : * Delete a virtual variable
365 : * NOTES:
366 : * This doesn't work on committed IDs.
367 : * Also the variable (for now) will be only invalidated, doesn't
368 : * completely *delete* it in memory.
369 : */
370 : void nc_del_vvar(int varid);
371 :
372 : /* nc_resize_vdim(...)
373 : * Change the size of a virtual dim to the given size.
374 : * NOTE: if the dim has committed using nc_vmap then this has no effect.
375 : */
376 : void nc_resize_vdim(
377 : int dimid,
378 : size_t dimlen); // for dims that haven't been mapped to physical yet
379 :
380 : /* nc_set_define_mode()
381 : * Convenience function for setting the ncid to define mode
382 : */
383 : void nc_set_define_mode();
384 :
385 : /* nc_set_data_mode()
386 : * Convenience function for setting the ncid to data mode
387 : */
388 : void nc_set_data_mode();
389 :
390 : /* nc_vmap()
391 : * Maps virtual IDs to real physical ID if that mapping doesn't already
392 : * exist This is required before writing data to virtual IDs that do not
393 : * exist yet in the netCDF file
394 : */
395 : void nc_vmap();
396 :
397 : /* void enableFullVirtualMode
398 : * Enables full virtual mode (i.e. allows netCDFVID to use its full
399 : * capabilities).
400 : */
401 109 : void enableFullVirtualMode()
402 : {
403 109 : this->directMode = false;
404 109 : }
405 :
406 : // Attribute function(s)
407 : template <class attrC, class attrT>
408 749 : void nc_put_vatt_generic(int varid, const char *name, const attrT *value)
409 : {
410 :
411 749 : if (varid >= static_cast<int>(varList.size()) || varid < 0)
412 : {
413 0 : throw SG_Exception_NVOOB("virtual variable collection");
414 : }
415 :
416 749 : netCDFVVariable &v = virtualVIDToVar(varid);
417 1498 : v.getAttributes().push_back(
418 749 : std::shared_ptr<netCDFVAttribute>(new attrC(name, value)));
419 749 : }
420 :
421 : void nc_put_vatt_text(int varid, const char *name, const char *value);
422 : void nc_put_vatt_int(int varid, const char *name, const int *value);
423 : void nc_put_vatt_double(int varid, const char *name, const double *value);
424 : void nc_put_vatt_float(int varid, const char *name, const float *value);
425 : void nc_put_vatt_byte(int varid, const char *name,
426 : const signed char *value);
427 :
428 : // Writing Functions
429 : template <class out_T>
430 23250 : void nc_put_vvar_generic(int varid, const size_t *index, const out_T *value)
431 : {
432 23250 : int rvarid = !directMode ? virtualVIDToVar(varid).getRealID() : varid;
433 :
434 23250 : if (rvarid == INVALID_VAR_ID)
435 95 : return; // invalidated variable, specific condition that Scribe
436 : // relies on
437 :
438 23155 : if (nc_put_var1(ncid, rvarid, index, value) != NC_NOERR)
439 : {
440 0 : throw SG_Exception_VWrite_Failure("variable", "datum");
441 : }
442 : }
443 :
444 : template <class outArr_T>
445 201 : void nc_put_vvara_generic(int varid, const size_t *index,
446 : const size_t *count, const outArr_T *value)
447 : {
448 201 : int rvarid = !directMode ? virtualVIDToVar(varid).getRealID() : varid;
449 :
450 201 : if (rvarid == INVALID_VAR_ID)
451 20 : return; // invalidated variable, specific condition that Scribe
452 : // relies on
453 :
454 181 : if (nc_put_vara(ncid, rvarid, index, count, value) != NC_NOERR)
455 : {
456 0 : throw SG_Exception_VWrite_Failure("variable", "data array");
457 : }
458 : }
459 :
460 : void nc_put_vvar1_text(int varid, const size_t *index, const char *value);
461 : void nc_put_vvara_text(int varid, const size_t *start, const size_t *index,
462 : const char *value);
463 : void nc_put_vvar1_string(int varid, const size_t *index,
464 : const char **value);
465 :
466 : // Equivalent "enquiry" functions
467 : netCDFVVariable &
468 : virtualVIDToVar(int virtualID); // converts a virtual var ID to a real ID
469 : netCDFVDimension &
470 : virtualDIDToDim(int virtualID); // converts a virtual dim ID to a real ID
471 : int nameToVirtualVID(const std::string &name);
472 : int nameToVirtualDID(const std::string &name);
473 :
474 77 : bool virtualVarNameDefined(const std::string &nm)
475 : {
476 77 : return nameVarTable.count(nm) > 0;
477 : }
478 :
479 : // Constructor
480 1036 : explicit netCDFVID(int &ncid_in) : ncid(ncid_in)
481 : {
482 1036 : }
483 : };
484 :
485 : } // namespace nccfdriver
486 : #endif
|