Coverage Report

Created: 2023-05-28 06:42

/src/netcdf-c/libdispatch/ddim.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright 2018 University Corporation for Atmospheric
2
   Research/Unidata. See COPYRIGHT file for more info. */
3
/**
4
   @file
5
6
   The functions in this file define, inquire about, and rename
7
   dimensions.
8
*/
9
10
#include "ncdispatch.h"
11
12
/**
13
   @defgroup dimensions Dimensions
14
15
   Dimensions are used to define the shape of data in netCDF.
16
17
   Dimensions for a netCDF dataset are defined when it is created,
18
   while the netCDF dataset is in define mode. Additional dimensions
19
   may be added later by reentering define mode. A netCDF dimension
20
   has a name and a length. In a netCDF classic or 64-bit offset file,
21
   at most one dimension can have the unlimited length, which means
22
   variables using this dimension can grow along this dimension. In a
23
   netCDF-4 file multiple unlimited dimensions are supported.
24
25
   There is a suggested limit (1024) to the number of dimensions that
26
   can be defined in a single netCDF dataset. The limit is the value
27
   of the predefined macro ::NC_MAX_DIMS. The purpose of the limit is
28
   to make writing generic applications simpler. They need only
29
   provide an array of ::NC_MAX_DIMS dimensions to handle any netCDF
30
   dataset. The implementation of the netCDF library does not enforce
31
   this advisory maximum, so it is possible to use more dimensions, if
32
   necessary, but netCDF utilities that assume the advisory maximums
33
   may not be able to handle the resulting netCDF datasets.
34
35
   ::NC_MAX_VAR_DIMS, which must not exceed ::NC_MAX_DIMS, is the
36
   maximum number of dimensions that can be used to specify the shape
37
   of a single variable. It is also intended to simplify writing
38
   generic applications.
39
40
   Ordinarily, the name and length of a dimension are fixed when the
41
   dimension is first defined. The name may be changed later, but the
42
   length of a dimension (other than the unlimited dimension) cannot
43
   be changed without copying all the data to a new netCDF dataset
44
   with a redefined dimension length.
45
46
   Dimension lengths in the C interface are type size_t rather than
47
   type int to make it possible to access all the data in a netCDF
48
   dataset on a platform that only supports a 16-bit int data type,
49
   for example MSDOS. If dimension lengths were type int instead, it
50
   would not be possible to access data from variables with a
51
   dimension length greater than a 16-bit int can accommodate.
52
53
   A netCDF dimension in an open netCDF dataset is referred to by a
54
   small integer called a dimension ID. In the C interface, dimension
55
   IDs are 0, 1, 2, ..., in the order in which the dimensions were
56
   defined.
57
58
   Operations supported on dimensions are:
59
   - Create a dimension, given its name and length.
60
   - Get a dimension ID from its name.
61
   - Get a dimension's name and length from its ID.
62
   - Rename a dimension.
63
*/
64
65
/** @{ */
66
67
/**
68
   Define a new dimension. The function nc_def_dim() adds a new
69
   dimension to an open netCDF dataset in define mode. It returns (as an
70
   argument) a dimension ID, given the netCDF ID, the dimension name, and
71
   the dimension length. At most one unlimited length dimension, called
72
   the record dimension, may be defined for each classic or 64-bit offset
73
   netCDF dataset. NetCDF-4 datasets may have multiple unlimited
74
   dimensions.
75
76
   @param ncid NetCDF or group ID, from a previous call to nc_open(),
77
   nc_create(), nc_def_grp(), or associated inquiry functions such as
78
   nc_inq_ncid().
79
   @param name Name of the dimension to be created.
80
   @param len Length of the dimension to be created. Use NC_UNLIMITED for
81
   unlimited dimensions.
82
   @param idp Pointer where dimension ID will be stored.
83
84
   @return ::NC_NOERR No error.
85
   @return ::NC_EBADID Not a valid ID.
86
   @return ::NC_EMAXNAME Name is too long.
87
   @return ::NC_EBADNAME Name breaks netCDF name rules.
88
   @return ::NC_EINVAL Invalid input.
89
   @return ::NC_ENOTINDEFINE Not in define mode.
90
   @return ::NC_EDIMSIZE Invalid dimension size.
91
   @return ::NC_EUNLIMIT NC_UNLIMITED size already in use
92
   @return ::NC_EMAXDIMS NC_MAX_DIMS exceeded [not enforced after 4.5.0]
93
   @return ::NC_ENAMEINUSE String match to name in use
94
   @return ::NC_ENOMEM Memory allocation (malloc) failure
95
   @return ::NC_EPERM Write to read only
96
97
   @section nc_def_dim_example Example
98
99
   Here is an example using nc_def_dim() to create a dimension named lat of
100
   length 18 and a unlimited dimension named rec in a new netCDF dataset
101
   named foo.nc:
102
103
   @code
104
   #include <netcdf.h>
105
   ...
106
   int status, ncid, latid, recid;
107
   ...
108
   status = nc_create("foo.nc", NC_NOCLOBBER, &ncid);
109
   if (status != NC_NOERR) handle_error(status);
110
   ...
111
   status = nc_def_dim(ncid, "lat", 18L, &latid);
112
   if (status != NC_NOERR) handle_error(status);
113
   status = nc_def_dim(ncid, "rec", NC_UNLIMITED, &recid);
114
   if (status != NC_NOERR) handle_error(status);
115
   @endcode
116
117
   @author Glenn Davis, Russ Rew, Ed Hartnett, Dennis Heimbigner, Ward
118
   Fisher
119
*/
120
int
121
nc_def_dim(int ncid, const char *name, size_t len, int *idp)
122
0
{
123
0
    NC* ncp;
124
0
    int stat = NC_check_id(ncid, &ncp);
125
0
    if(stat != NC_NOERR) return stat;
126
0
    TRACE(nc_def_dim);
127
0
    return ncp->dispatch->def_dim(ncid, name, len, idp);
128
0
}
129
130
/**
131
   Find the ID of a dimension from the name.
132
133
   The function nc_inq_dimid returns (as an argument) the ID of a
134
   netCDF dimension, given the name of the dimension. If ndims is the
135
   number of dimensions defined for a netCDF dataset, each dimension
136
   has an ID between 0 and ndims-1.
137
138
   @param ncid NetCDF or group ID, from a previous call to nc_open(),
139
   nc_create(), nc_def_grp(), or associated inquiry functions such as
140
   nc_inq_ncid().
141
   @param name Name of the dimension.
142
   @param idp Pointer where dimension ID will be stored.
143
144
   @return ::NC_NOERR No error.
145
   @return ::NC_EBADID Not a valid ID.
146
   @return ::NC_EBADDIM Invalid dimension ID.
147
148
   @author Glenn Davis, Russ Rew, Ed Hartnett, Dennis Heimbigner, Ward
149
   Fisher
150
*/
151
int
152
nc_inq_dimid(int ncid, const char *name, int *idp)
153
0
{
154
0
    NC* ncp;
155
0
    int stat = NC_check_id(ncid, &ncp);
156
0
    if(stat != NC_NOERR) return stat;
157
0
    TRACE(nc_inq_dimid);
158
0
    return ncp->dispatch->inq_dimid(ncid,name,idp);
159
0
}
160
161
/**
162
   Find the name and length of a dimension.
163
164
   The length for the unlimited dimension, if any, is the number of
165
   records written so far.
166
167
   @param ncid NetCDF or group ID, from a previous call to nc_open(),
168
   nc_create(), nc_def_grp(), or associated inquiry functions such as
169
   nc_inq_ncid().
170
   @param dimid Dimension ID, from a previous call to nc_inq_dimid() or
171
   nc_def_dim().
172
   @param name Returned dimension name. The caller must allocate space
173
   for the returned name. The maximum possible length, in characters, of
174
   a dimension name is given by the predefined constant
175
   ::NC_MAX_NAME. (This doesn't include the null terminator, so declare
176
   your array to be size NC_MAX_NAME+1). The returned character array
177
   will be null-terminated.
178
   @param lenp Pointer to location for returned length of dimension. For
179
   the unlimited dimension, this is the number of records written so far.
180
181
   @return ::NC_NOERR No error.
182
   @return ::NC_EBADID Not a valid ID.
183
   @return ::NC_EBADDIM Invalid dimension ID or name.
184
185
   @section nc_inq_dim_example Example
186
187
   Here is an example using nc_inq_dim() to determine the length of a
188
   dimension named lat, and the name and current maximum length of the
189
   unlimited dimension for an existing netCDF dataset named foo.nc:
190
191
   @code
192
   #include <netcdf.h>
193
   ...
194
   int status, ncid, latid, recid;
195
   size_t latlength, recs;
196
   char recname[NC_MAX_NAME+1];
197
   ...
198
   status = nc_open("foo.nc", NC_NOWRITE, &ncid);
199
   if (status != NC_NOERR) handle_error(status);
200
   status = nc_inq_unlimdim(ncid, &recid);
201
   if (status != NC_NOERR) handle_error(status);
202
   ...
203
   status = nc_inq_dimid(ncid, "lat", &latid);
204
   if (status != NC_NOERR) handle_error(status);
205
   status = nc_inq_dimlen(ncid, latid, &latlength);
206
   if (status != NC_NOERR) handle_error(status);
207
208
   status = nc_inq_dim(ncid, recid, recname, &recs);
209
   if (status != NC_NOERR) handle_error(status);
210
   @endcode
211
212
   @author Glenn Davis, Russ Rew, Ed Hartnett, Dennis Heimbigner, Ward
213
   Fisher
214
*/
215
int
216
nc_inq_dim(int ncid, int dimid, char *name, size_t *lenp)
217
0
{
218
0
    NC* ncp;
219
0
    int stat = NC_check_id(ncid, &ncp);
220
0
    if(stat != NC_NOERR) return stat;
221
0
    TRACE(nc_inq_dim);
222
0
    return ncp->dispatch->inq_dim(ncid,dimid,name,lenp);
223
0
}
224
225
/**
226
   Rename a dimension.
227
228
   This function renames an existing dimension in a netCDF dataset
229
   open for writing. You cannot rename a dimension to have the same
230
   name as another dimension.
231
232
   For netCDF classic and 64-bit offset files, if the new name is
233
   longer than the old name, which has been flushed to disk, the
234
   netCDF dataset must be in define mode.
235
236
   For netCDF-4 files the length of the name is not checked against
237
   the length of the old name, even for classic model files. This is
238
   due to the difficulty of exactly reproducing classic library
239
   behavior in this case.
240
241
   @param ncid NetCDF or group ID, from a previous call to nc_open(),
242
   nc_create(), nc_def_grp(), or associated inquiry functions such as
243
   nc_inq_ncid().
244
   @param dimid Dimension ID, from a previous call to nc_inq_dimid()
245
   or nc_def_dim().
246
   @param name New name for dimension. Must be a null-terminated
247
   string with length less than ::NC_MAX_NAME.
248
249
   @return ::NC_NOERR No error.
250
   @return ::NC_EBADID Not a valid ID.
251
   @return ::NC_EBADDIM Invalid dimension ID or name.
252
   @return ::NC_ENAMEINUSE String match to name in use
253
   @return ::NC_ENOMEM Memory allocation (malloc) failure
254
   @return ::NC_EPERM Write to read only
255
   @return ::NC_ENOTINDEFINE Not in define mode and new name is longer
256
   than old.
257
258
   @section nc_rename_dim_example Example
259
260
   Here is an example using nc_rename_dim to rename the dimension lat
261
   to latitude in an existing netCDF dataset named foo.nc:
262
263
   @code
264
   #include <netcdf.h>
265
   ...
266
   int status, ncid, latid;
267
   ...
268
   status = nc_open("foo.nc", NC_WRITE, &ncid);
269
   if (status != NC_NOERR) handle_error(status);
270
   ...
271
   status = nc_redef(ncid);
272
   if (status != NC_NOERR) handle_error(status);
273
   status = nc_inq_dimid(ncid, "lat", &latid);
274
   if (status != NC_NOERR) handle_error(status);
275
   status = nc_rename_dim(ncid, latid, "latitude");
276
   if (status != NC_NOERR) handle_error(status);
277
   status = nc_enddef(ncid);
278
   if (status != NC_NOERR) handle_error(status);
279
   @endcode
280
281
   @author Glenn Davis, Russ Rew, Ed Hartnett, Dennis Heimbigner, Ward
282
   Fisher
283
*/
284
int
285
nc_rename_dim(int ncid, int dimid, const char *name)
286
0
{
287
0
    NC* ncp;
288
0
    int stat = NC_check_id(ncid, &ncp);
289
0
    if(stat != NC_NOERR) return stat;
290
0
    TRACE(nc_rename_dim);
291
0
    return ncp->dispatch->rename_dim(ncid,dimid,name);
292
0
}
293
294
/**
295
   Find the number of dimensions.
296
297
   In a classic model netCDF file, this function returns the number of
298
   defined dimensions. In a netCDF-4/HDF5 file, this function returns
299
   the number of dimensions available in the group specified by ncid,
300
   which may be less than the total number of dimensions in a file. In
301
   a netCDF-4/HDF5 file, dimensions are in all sub-groups,
302
   sub-sub-groups, etc.
303
304
   @param ncid NetCDF or group ID, from a previous call to nc_open(),
305
   nc_create(), nc_def_grp(), or associated inquiry functions such as
306
   nc_inq_ncid().
307
   @param ndimsp Pointer where number of dimensions will be
308
   written. Ignored if NULL.
309
310
   @return ::NC_NOERR  No error.
311
   @return ::NC_EBADID Not a valid ID.
312
313
   @author Glenn Davis, Russ Rew, Ed Hartnett, Dennis Heimbigner, Ward
314
   Fisher
315
*/
316
int
317
nc_inq_ndims(int ncid, int *ndimsp)
318
0
{
319
0
    NC* ncp;
320
0
    int stat = NC_check_id(ncid, &ncp);
321
0
    if(stat != NC_NOERR) return stat;
322
0
    if(ndimsp == NULL) return NC_NOERR;
323
0
    TRACE(nc_inq_ndims);
324
0
    return ncp->dispatch->inq(ncid,ndimsp,NULL,NULL,NULL);
325
0
}
326
327
/**
328
   Find the ID of the unlimited dimension.
329
330
   This function finds the ID of the unlimited dimension. For
331
   netCDF-4/HDF5 files (which may have more than one unlimited
332
   dimension), the ID of the first unlimited dimesnion is
333
   returned. For these files, nc_inq_unlimdims() will return all the
334
   unlimited dimension IDs.
335
336
   @param ncid NetCDF or group ID, from a previous call to nc_open(),
337
   nc_create(), nc_def_grp(), or associated inquiry functions such as
338
   nc_inq_ncid().
339
   @param unlimdimidp Pointer where unlimited dimension ID will be
340
   stored. If there is no unlimited dimension, -1 will be stored
341
   here. Ignored if NULL.
342
343
   @return ::NC_NOERR  No error.
344
   @return ::NC_EBADID Not a valid ID.
345
346
   @author Glenn Davis, Russ Rew, Ed Hartnett, Dennis Heimbigner, Ward
347
   Fisher
348
*/
349
int
350
nc_inq_unlimdim(int ncid, int *unlimdimidp)
351
0
{
352
0
    NC* ncp;
353
0
    int stat = NC_check_id(ncid, &ncp);
354
0
    if(stat != NC_NOERR) return stat;
355
0
    TRACE(nc_inq_unlimdim);
356
0
    return ncp->dispatch->inq_unlimdim(ncid,unlimdimidp);
357
0
}
358
359
/**
360
   Find out the name of a dimension.
361
362
   @param ncid NetCDF or group ID, from a previous call to nc_open(),
363
   nc_create(), nc_def_grp(), or associated inquiry functions such as
364
   nc_inq_ncid().
365
   @param dimid Dimension ID, from a previous call to nc_inq_dimid()
366
   or nc_def_dim().
367
   @param name Returned dimension name. The caller must allocate space
368
   for the returned name. The maximum possible length, in characters,
369
   of a dimension name is given by the predefined constant
370
   ::NC_MAX_NAME. (This doesn't include the null terminator, so
371
   declare your array to be size NC_MAX_NAME+1). The returned
372
   character array will be null-terminated. Ignored if NULL.
373
374
   @return ::NC_NOERR   No error.
375
   @return ::NC_EBADID  Not a valid ID.
376
   @return ::NC_EBADDIM Invalid dimension ID or name.
377
378
   @section nc_inq_dim_example2 Example
379
380
   Here is an example using nc_inq_dim() to determine the length of a
381
   dimension named lat, and the name and current maximum length of the
382
   unlimited dimension for an existing netCDF dataset named foo.nc:
383
384
   @code
385
   #include <netcdf.h>
386
   ...
387
   int status, ncid, latid, recid;
388
   size_t latlength, recs;
389
   char recname[NC_MAX_NAME+1];
390
   ...
391
   status = nc_open("foo.nc", NC_NOWRITE, &ncid);
392
   if (status != NC_NOERR) handle_error(status);
393
   status = nc_inq_unlimdim(ncid, &recid);
394
   if (status != NC_NOERR) handle_error(status);
395
   ...
396
   status = nc_inq_dimid(ncid, "lat", &latid);
397
   if (status != NC_NOERR) handle_error(status);
398
   status = nc_inq_dimlen(ncid, latid, &latlength);
399
   if (status != NC_NOERR) handle_error(status);
400
401
   status = nc_inq_dim(ncid, recid, recname, &recs);
402
   if (status != NC_NOERR) handle_error(status);
403
   @endcode
404
405
   @author Glenn Davis, Russ Rew, Ed Hartnett, Dennis Heimbigner, Ward
406
   Fisher
407
*/
408
int
409
nc_inq_dimname(int ncid, int dimid, char *name)
410
0
{
411
0
    NC* ncp;
412
0
    int stat = NC_check_id(ncid, &ncp);
413
0
    if(stat != NC_NOERR) return stat;
414
0
    if(name == NULL) return NC_NOERR;
415
0
    TRACE(nc_inq_dimname);
416
0
    return ncp->dispatch->inq_dim(ncid,dimid,name,NULL);
417
0
}
418
419
/**
420
   Find the length of a dimension.
421
422
   The length for the unlimited dimension, if any, is the number of
423
   records written so far.
424
425
   @param ncid NetCDF or group ID, from a previous call to nc_open(),
426
   nc_create(), nc_def_grp(), or associated inquiry functions such as
427
   nc_inq_ncid().
428
   @param dimid Dimension ID, from a previous call to nc_inq_dimid()
429
   or nc_def_dim().
430
   @param lenp Pointer where the length will be stored.
431
432
   @return ::NC_NOERR   No error.
433
   @return ::NC_EBADID  Not a valid ID.
434
   @return ::NC_EBADDIM Invalid dimension ID or name.
435
436
   @section nc_inq_dim_example3 Example
437
438
   Here is an example using nc_inq_dim() to determine the length of a
439
   dimension named lat, and the name and current maximum length of the
440
   unlimited dimension for an existing netCDF dataset named foo.nc:
441
442
   @code
443
   #include <netcdf.h>
444
   ...
445
   int status, ncid, latid, recid;
446
   size_t latlength, recs;
447
   char recname[NC_MAX_NAME+1];
448
   ...
449
   status = nc_open("foo.nc", NC_NOWRITE, &ncid);
450
   if (status != NC_NOERR) handle_error(status);
451
   status = nc_inq_unlimdim(ncid, &recid);
452
   if (status != NC_NOERR) handle_error(status);
453
   ...
454
   status = nc_inq_dimid(ncid, "lat", &latid);
455
   if (status != NC_NOERR) handle_error(status);
456
   status = nc_inq_dimlen(ncid, latid, &latlength);
457
   if (status != NC_NOERR) handle_error(status);
458
459
   status = nc_inq_dim(ncid, recid, recname, &recs);
460
   if (status != NC_NOERR) handle_error(status);
461
   @endcode
462
463
   @author Glenn Davis, Russ Rew, Ed Hartnett, Dennis Heimbigner, Ward
464
   Fisher
465
*/
466
int
467
nc_inq_dimlen(int ncid, int dimid, size_t *lenp)
468
0
{
469
0
    NC* ncp;
470
0
    int stat = NC_check_id(ncid, &ncp);
471
0
    if(stat != NC_NOERR) return stat;
472
0
    if(lenp == NULL) return NC_NOERR;
473
0
    TRACE(nc_inq_dimlen);
474
0
    return ncp->dispatch->inq_dim(ncid,dimid,NULL,lenp);
475
0
}
476
477
/** @} */