Coverage Report

Created: 2025-06-09 07:42

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