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