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