/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 | | /** @} */ |