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