/src/netcdf-c/libdispatch/dvar.c
Line | Count | Source |
1 | | /* Copyright 2010-2018 University Corporation for Atmospheric |
2 | | Research/Unidata. See COPYRIGHT file for more info. */ |
3 | | /** |
4 | | * @file |
5 | | * Functions for defining and inquiring about variables. @note The |
6 | | * order of functions in this file affects the doxygen documentation. |
7 | | * |
8 | | * @author Dennis Heimbigner, Edward Hartnett |
9 | | */ |
10 | | |
11 | | #include "config.h" |
12 | | #include "netcdf.h" |
13 | | #include "netcdf_filter.h" |
14 | | #include "ncdispatch.h" |
15 | | #include "nc4internal.h" |
16 | | #include "netcdf_f.h" |
17 | | #include "nc4internal.h" |
18 | | |
19 | | /** |
20 | | @defgroup variables Variables |
21 | | |
22 | | Variables hold multi-dimensional arrays of data. |
23 | | |
24 | | Variables for a netCDF dataset are defined when the dataset is |
25 | | created, while the netCDF dataset is in define mode. Other |
26 | | variables may be added later by reentering define mode. A netCDF |
27 | | variable has a name, a type, and a shape, which are specified when |
28 | | it is defined. A variable may also have values, which are |
29 | | established later in data mode. |
30 | | |
31 | | Ordinarily, the name, type, and shape are fixed when the variable |
32 | | is first defined. The name may be changed, but the type and shape |
33 | | of a variable cannot be changed. However, a variable defined in |
34 | | terms of the unlimited dimension can grow without bound in that |
35 | | dimension. |
36 | | |
37 | | A netCDF variable in an open netCDF dataset is referred to by a |
38 | | small integer called a variable ID. |
39 | | |
40 | | Variable IDs reflect the order in which variables were defined |
41 | | within a netCDF dataset. Variable IDs are 0, 1, 2,..., in the order |
42 | | in which the variables were defined. A function is available for |
43 | | getting the variable ID from the variable name and vice-versa. |
44 | | |
45 | | @ref attributes may be associated with a variable to specify such |
46 | | properties as units. |
47 | | |
48 | | Operations supported on variables are: |
49 | | - Create a variable, given its name, data type, and shape. |
50 | | - Get a variable ID from its name. |
51 | | - Get a variable's name, data type, shape, and number of attributes |
52 | | from its ID. |
53 | | - Put a data value into a variable, given variable ID, indices, and value. |
54 | | - Put an array of values into a variable, given variable ID, corner |
55 | | indices, edge lengths, and a block of values. |
56 | | - Put a subsampled or mapped array-section of values into a variable, |
57 | | given variable ID, corner indices, edge lengths, stride vector, |
58 | | index mapping vector, and a block of values. |
59 | | - Get a data value from a variable, given variable ID and indices. |
60 | | - Get an array of values from a variable, given variable ID, corner |
61 | | indices, and edge lengths. |
62 | | - Get a subsampled or mapped array-section of values from a variable, |
63 | | given variable ID, corner indices, edge lengths, stride vector, and |
64 | | index mapping vector. |
65 | | - Rename a variable. |
66 | | |
67 | | @section language_types Data Types |
68 | | |
69 | | NetCDF supported six atomic data types through version 3.6.0 (char, |
70 | | byte, short, int, float, and double). Starting with version 4.0, many |
71 | | new atomic and user defined data types are supported (unsigned int |
72 | | types, strings, compound types, variable length arrays, enums, |
73 | | opaque). |
74 | | |
75 | | The additional data types are only supported in netCDF-4/HDF5 |
76 | | files. To create netCDF-4/HDF5 files, use the ::NC_NETCDF4 flag in |
77 | | nc_create(). |
78 | | |
79 | | @section classic_types NetCDF-3 Classic and 64-Bit Offset Data Types |
80 | | |
81 | | NetCDF-3 classic and 64-bit offset files support 6 atomic data types, |
82 | | and none of the user defined datatype introduced in NetCDF-4. |
83 | | |
84 | | The following table gives the netCDF-3 external data types and the |
85 | | corresponding type constants for defining variables in the C |
86 | | interface: |
87 | | |
88 | | <table> |
89 | | <tr><td>Type</td><td>C define</td><td>Bits</td></tr> |
90 | | <tr><td>byte</td><td>::NC_BYTE</td><td>8</td></tr> |
91 | | <tr><td>char</td><td>::NC_CHAR</td><td>8</td></tr> |
92 | | <tr><td>short</td><td>::NC_SHORT</td><td>16</td></tr> |
93 | | <tr><td>int</td><td>::NC_INT</td><td>32</td></tr> |
94 | | <tr><td>float</td><td>::NC_FLOAT</td><td>32</td></tr> |
95 | | <tr><td>double</td><td>::NC_DOUBLE</td><td>64</td></tr> |
96 | | </table> |
97 | | |
98 | | The first column gives the netCDF external data type, which is the |
99 | | same as the CDL data type. The next column gives the corresponding C |
100 | | pre-processor macro for use in netCDF functions (the pre-processor |
101 | | macros are defined in the netCDF C header-file netcdf.h). The last |
102 | | column gives the number of bits used in the external representation of |
103 | | values of the corresponding type. |
104 | | |
105 | | @section netcdf_4_atomic NetCDF-4 Atomic Data Types |
106 | | |
107 | | NetCDF-4 files support all of the atomic data types from netCDF-3, |
108 | | plus additional unsigned integer types, 64-bit integer types, and a |
109 | | string type. |
110 | | |
111 | | <table> |
112 | | <tr><td>Type</td><td>C define</td><td>Bits |
113 | | |
114 | | <tr><td>byte</td><td>::NC_BYTE</td><td>8</td></tr> |
115 | | <tr><td>unsigned byte </td><td>::NC_UBYTE^</td><td> 8</td></tr> |
116 | | <tr><td>char </td><td>::NC_CHAR </td><td>8</td></tr> |
117 | | <tr><td>short </td><td>::NC_SHORT </td><td>16</td></tr> |
118 | | <tr><td>unsigned short </td><td>::NC_USHORT^ </td><td>16</td></tr> |
119 | | <tr><td>int </td><td>::NC_INT </td><td>32</td></tr> |
120 | | <tr><td>unsigned int </td><td>::NC_UINT^ </td><td>32</td></tr> |
121 | | <tr><td>unsigned long long </td><td>::NC_UINT64^ </td><td>64</td></tr> |
122 | | <tr><td>long long </td><td>::NC_INT64^ </td><td>64</td></tr> |
123 | | <tr><td>float </td><td>::NC_FLOAT </td><td>32</td></tr> |
124 | | <tr><td>double </td><td>::NC_DOUBLE </td><td>64</td></tr> |
125 | | <tr><td>char ** </td><td>::NC_STRING^ </td><td>string length + 1</td></tr> |
126 | | </table> |
127 | | |
128 | | ^This type was introduced in netCDF-4, and is not supported in netCDF |
129 | | classic or 64-bit offset format files, or in netCDF-4 files if they |
130 | | are created with the ::NC_CLASSIC_MODEL flags. |
131 | | */ |
132 | | |
133 | | /** @{ */ |
134 | | /** |
135 | | @name Defining Variables |
136 | | |
137 | | Use these functions to define variables. |
138 | | */ |
139 | | /*! @{ */ |
140 | | |
141 | | /** |
142 | | Define a new variable. |
143 | | |
144 | | This function adds a new variable to an open netCDF dataset or group. |
145 | | It returns (as an argument) a variable ID, given the netCDF ID, |
146 | | the variable name, the variable type, the number of dimensions, and a |
147 | | list of the dimension IDs. |
148 | | |
149 | | @param ncid NetCDF or group ID, from a previous call to nc_open(), |
150 | | nc_create(), nc_def_grp(), or associated inquiry functions such as |
151 | | nc_inq_ncid(). |
152 | | @param name Variable @ref object_name. |
153 | | @param xtype (Data |
154 | | type)[https://docs.unidata.ucar.edu/nug/current/md_types.html#data_type] |
155 | | of the variable. |
156 | | @param ndims Number of dimensions for the variable. For example, 2 |
157 | | specifies a matrix, 1 specifies a vector, and 0 means the variable is |
158 | | a scalar with no dimensions. Must not be negative or greater than the |
159 | | predefined constant ::NC_MAX_VAR_DIMS. In netCDF-4/HDF5 files, may not |
160 | | exceed the HDF5 maximum number of dimensions (32). |
161 | | @param dimidsp Vector of ndims dimension IDs corresponding to the |
162 | | variable dimensions. For classic model netCDF files, if the ID of the |
163 | | unlimited dimension is included, it must be first. This argument is |
164 | | ignored if ndims is 0. For expanded model netCDF4/HDF5 files, there |
165 | | may be any number of unlimited dimensions, and they may be used in any |
166 | | element of the dimids array. |
167 | | @param varidp Pointer to location for the returned variable ID. |
168 | | |
169 | | @return ::NC_NOERR No error. |
170 | | @return ::NC_EBADID Bad ncid. |
171 | | @return ::NC_ENOTINDEFINE Not in define mode. |
172 | | @return ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 netcdf-4 file. |
173 | | @return ::NC_EMAXVARS NC_MAX_VARS exceeded [Not enforced after 4.5.0] |
174 | | @return ::NC_EBADTYPE Bad type. |
175 | | @return ::NC_EINVAL Invalid input. |
176 | | @return ::NC_ENAMEINUSE Name already in use. |
177 | | @return ::NC_EPERM Attempt to create object in read-only file. |
178 | | |
179 | | @section nc_def_var_example Example |
180 | | |
181 | | Here is an example using nc_def_var to create a variable named rh of |
182 | | type double with three dimensions, time, lat, and lon in a new netCDF |
183 | | dataset named foo.nc: |
184 | | |
185 | | @code |
186 | | #include <netcdf.h> |
187 | | ... |
188 | | int status; |
189 | | int ncid; |
190 | | int lat_dim, lon_dim, time_dim; |
191 | | int rh_id; |
192 | | int rh_dimids[3]; |
193 | | ... |
194 | | status = nc_create("foo.nc", NC_NOCLOBBER, &ncid); |
195 | | if (status != NC_NOERR) handle_error(status); |
196 | | ... |
197 | | |
198 | | status = nc_def_dim(ncid, "lat", 5L, &lat_dim); |
199 | | if (status != NC_NOERR) handle_error(status); |
200 | | status = nc_def_dim(ncid, "lon", 10L, &lon_dim); |
201 | | if (status != NC_NOERR) handle_error(status); |
202 | | status = nc_def_dim(ncid, "time", NC_UNLIMITED, &time_dim); |
203 | | if (status != NC_NOERR) handle_error(status); |
204 | | ... |
205 | | |
206 | | rh_dimids[0] = time_dim; |
207 | | rh_dimids[1] = lat_dim; |
208 | | rh_dimids[2] = lon_dim; |
209 | | status = nc_def_var (ncid, "rh", NC_DOUBLE, 3, rh_dimids, &rh_id); |
210 | | if (status != NC_NOERR) handle_error(status); |
211 | | @endcode |
212 | | |
213 | | @author Glenn Davis, Ed Hartnett, Dennis Heimbigner |
214 | | */ |
215 | | int |
216 | | nc_def_var(int ncid, const char *name, nc_type xtype, |
217 | | int ndims, const int *dimidsp, int *varidp) |
218 | 0 | { |
219 | 0 | NC* ncp; |
220 | 0 | int stat = NC_NOERR; |
221 | |
|
222 | 0 | if ((stat = NC_check_id(ncid, &ncp))) |
223 | 0 | return stat; |
224 | 0 | TRACE(nc_def_var); |
225 | 0 | return ncp->dispatch->def_var(ncid, name, xtype, ndims, |
226 | 0 | dimidsp, varidp); |
227 | 0 | } |
228 | | |
229 | | /** |
230 | | Set the fill value for a variable. |
231 | | |
232 | | @note For netCDF classic, 64-bit offset, and CDF5 formats, it is |
233 | | allowed (but not good practice) to set the fill value after data |
234 | | have been written to the variable. In this case, unless the |
235 | | variable has been completely specified (without gaps in the data), |
236 | | any existing filled values will not be recognized as fill values by |
237 | | applications reading the data. Best practice is to set the fill |
238 | | value after the variable has been defined, but before any data have |
239 | | been written to that variable. In NetCDF-4 files, this is enforced |
240 | | by the HDF5 library. For netCDF-4 files, an error is returned if |
241 | | the user attempts to set the fill value after writing data to the |
242 | | variable. |
243 | | |
244 | | @param ncid NetCDF ID, from a previous call to nc_open() or |
245 | | nc_create(). |
246 | | @param varid Variable ID. |
247 | | @param no_fill Set to ::NC_NOFILL to turn off fill mode for this |
248 | | variable. Set to ::NC_FILL (the default) to turn on fill mode for |
249 | | the variable. |
250 | | @param fill_value the fill value to be used for this variable. Must |
251 | | be the same type as the variable. This must point to enough free |
252 | | memory to hold one element of the data type of the variable. (For |
253 | | example, an ::NC_INT will require 4 bytes for it's fill value, |
254 | | which is also an ::NC_INT.) |
255 | | |
256 | | @return ::NC_NOERR No error. |
257 | | @return ::NC_EBADID Bad ID. |
258 | | @return ::NC_ENOTINDEFINE Not in define mode. This is returned for |
259 | | netCDF classic, 64-bit offset, or 64-bit data files, or for |
260 | | netCDF-4 files, when they were created with ::NC_CLASSIC_MODEL flag by |
261 | | nc_create(). |
262 | | @return ::NC_EPERM Attempt to create object in read-only file. |
263 | | @return ::NC_ELATEDEF (NetCDF-4 only). Returned when user attempts |
264 | | to set fill value after data are written. |
265 | | @return ::NC_EGLOBAL Attempt to set fill value on NC_GLOBAL. |
266 | | |
267 | | Warning: Using a vlen type as the fill value may lead to a memory |
268 | | leak. |
269 | | |
270 | | @section nc_def_var_fill_example Example |
271 | | |
272 | | In this example from libsrc4/tst_vars.c, a variable is defined, and |
273 | | the fill mode turned off. Then nc_inq_fill() is used to check that |
274 | | the setting is correct. Then some data are written to the |
275 | | variable. Since the data that are written do not cover the full |
276 | | extent of the variable, the missing values will just be random. If |
277 | | fill value mode was turned on, the missing values would get the |
278 | | fill value. |
279 | | |
280 | | @code |
281 | | #define DIM7_LEN 2 |
282 | | #define DIM7_NAME "dim_7_from_Indiana" |
283 | | #define VAR7_NAME "var_7_from_Idaho" |
284 | | #define NDIMS 1 |
285 | | int dimids[NDIMS]; |
286 | | size_t index[NDIMS]; |
287 | | int varid; |
288 | | int no_fill; |
289 | | unsigned short ushort_data = 42, ushort_data_in, fill_value_in; |
290 | | |
291 | | if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR; |
292 | | if (nc_def_dim(ncid, DIM7_NAME, DIM7_LEN, &dimids[0])) ERR; |
293 | | if (nc_def_var(ncid, VAR7_NAME, NC_USHORT, NDIMS, dimids, |
294 | | &varid)) ERR; |
295 | | if (nc_def_var_fill(ncid, varid, 1, NULL)) ERR; |
296 | | |
297 | | if (nc_inq_var_fill(ncid, varid, &no_fill, &fill_value_in)) ERR; |
298 | | if (!no_fill) ERR; |
299 | | |
300 | | index[0] = 1; |
301 | | if (nc_put_var1_ushort(ncid, varid, index, &ushort_data)) ERR; |
302 | | |
303 | | index[0] = 0; |
304 | | if (nc_get_var1_ushort(ncid, varid, index, &ushort_data_in)) ERR; |
305 | | |
306 | | if (nc_close(ncid)) ERR; |
307 | | @endcode |
308 | | @author Glenn Davis, Ed Hartnett, Dennis Heimbigner |
309 | | */ |
310 | | int |
311 | | nc_def_var_fill(int ncid, int varid, int no_fill, const void *fill_value) |
312 | 0 | { |
313 | 0 | NC* ncp; |
314 | 0 | int stat = NC_check_id(ncid,&ncp); |
315 | 0 | if(stat != NC_NOERR) return stat; |
316 | | |
317 | | /* Using NC_GLOBAL is illegal, as this API has no provision for |
318 | | * specifying the type of the fillvalue, it must of necessity be |
319 | | * using the type of the variable to interpret the bytes of the |
320 | | * fill_value argument. */ |
321 | 0 | if (varid == NC_GLOBAL) return NC_EGLOBAL; |
322 | | |
323 | 0 | return ncp->dispatch->def_var_fill(ncid,varid,no_fill,fill_value); |
324 | 0 | } |
325 | | |
326 | | /** |
327 | | Set the zlib compression and shuffle settings for a variable in an |
328 | | netCDF/HDF5 file. |
329 | | |
330 | | This function must be called after nc_def_var and before nc_enddef |
331 | | or any functions which writes data to the file. |
332 | | |
333 | | Deflation and shuffle are only available for HDF5 files. Attempting |
334 | | to set them on non-HDF5 files will return ::NC_ENOTNC4. |
335 | | |
336 | | Deflation and shuffle require chunked data. If this function is |
337 | | called on a variable with contiguous data, then the data is changed |
338 | | to chunked data, with default chunksizes. Use nc_def_var_chunking() |
339 | | to tune performance with user-defined chunksizes. |
340 | | |
341 | | If this function is called on a scalar variable, ::NC_EINVAL is |
342 | | returned. Only chunked variables may use filters. |
343 | | |
344 | | Zlib compression cannot be used with szip compression. If this |
345 | | function is called on a variable which already has szip compression |
346 | | turned on, ::NC_EINVAL is returned. |
347 | | |
348 | | @note Parallel I/O reads work with compressed data. Parallel I/O |
349 | | writes work with compressed data in netcdf-c-4.7.4 and later |
350 | | releases, using hdf5-1.10.3 and later releases. Using the zlib, |
351 | | shuffle (or any other) filter requires that collective access be |
352 | | used with the variable. Turning on deflate and/or shuffle for a |
353 | | variable in a file opened for parallel I/O will automatically |
354 | | switch the access for that variable to collective access. |
355 | | |
356 | | @note The HDF5 manual has this to say about shuffle: |
357 | | |
358 | | The shuffle filter de-interlaces a block of data by reordering |
359 | | the bytes. All the bytes from one consistent byte position of |
360 | | each data element are placed together in one block; all bytes |
361 | | from a second consistent byte position of each data element are |
362 | | placed together a second block; etc. For example, given three |
363 | | data elements of a 4-byte datatype stored as 012301230123, |
364 | | shuffling will re-order data as 000111222333. This can be a |
365 | | valuable step in an effective compression algorithm because the |
366 | | bytes in each byte position are often closely related to each |
367 | | other and putting them together can increase the compression |
368 | | ratio. |
369 | | |
370 | | As implied above, the primary value of the shuffle filter lies |
371 | | in its coordinated use with a compression filter; it does not |
372 | | provide data compression when used alone. When the shuffle |
373 | | filter is applied to a dataset immediately prior to the use of a |
374 | | compression filter, the compression ratio achieved is often |
375 | | superior to that achieved by the use of a compression filter |
376 | | without the shuffle filter. |
377 | | |
378 | | @note The shuffle and deflate flags are ambiguous. |
379 | | |
380 | | In most cases, if the shuffle or deflate flag is zero, then it is interpreted |
381 | | to mean that shuffle or deflate should not be set. However, if the variable |
382 | | already has shuffle or deflate turned on, then it is unclear if a flag |
383 | | value of zero means leave the state as it is, or if it means |
384 | | that it should be turned off. Since currently no other filters can be |
385 | | disabled, it is assumed here that a zero value means to leave the |
386 | | state as it is. |
387 | | |
388 | | @param ncid NetCDF or group ID, from a previous call to nc_open(), |
389 | | nc_create(), nc_def_grp(), or associated inquiry functions such as |
390 | | nc_inq_ncid(). |
391 | | @param varid Variable ID |
392 | | @param shuffle True to turn on the shuffle filter. The shuffle |
393 | | filter can assist with the compression of data by changing the byte |
394 | | order in the data stream. It makes no sense to use the shuffle |
395 | | filter without setting a deflate level. |
396 | | @param deflate True to turn on deflation for this variable. |
397 | | @param deflate_level A number between 0 (no compression) and 9 |
398 | | (maximum compression). |
399 | | |
400 | | @return ::NC_NOERR No error. |
401 | | @return ::NC_EBADID Bad ncid. |
402 | | @return ::NC_ENOTVAR Invalid variable ID. |
403 | | @return ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is |
404 | | not netCDF-4/HDF5. |
405 | | @return ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 |
406 | | netcdf-4 file. |
407 | | @return ::NC_ELATEDEF Too late to change settings for this variable. |
408 | | @return ::NC_ENOTINDEFINE Not in define mode. |
409 | | @return ::NC_EPERM File is read only. |
410 | | @return ::NC_ESTRICTNC3 Attempting to create netCDF-4 type var in |
411 | | classic model file |
412 | | @return ::NC_EHDFERR Error returned by HDF5 layer. |
413 | | @return ::NC_EINVAL Invalid input. Deflate can't be set unless |
414 | | variable storage is NC_CHUNK. |
415 | | |
416 | | @section nc_def_var_deflate_example Example |
417 | | |
418 | | Here is an example from /examples/C/simple_xy_nc4_wr.c using |
419 | | nc_def_var_deflate to create a variable and then turn on the shuffle |
420 | | filter and compression. |
421 | | |
422 | | @code |
423 | | #include <netcdf.h> |
424 | | #define NDIMS 2 |
425 | | #define NX 6 |
426 | | #define NY 12 |
427 | | |
428 | | int ncid, x_dimid, y_dimid, varid; |
429 | | int dimids[NDIMS]; |
430 | | int shuffle, deflate, deflate_level; |
431 | | int data_out[NX][NY]; |
432 | | int x, y, retval; |
433 | | |
434 | | shuffle = NC_SHUFFLE; |
435 | | deflate = 1; |
436 | | deflate_level = 1; |
437 | | ... |
438 | | if ((retval = nc_create(FILE_NAME, NC_NETCDF4, &ncid))) |
439 | | ERR(retval); |
440 | | |
441 | | if ((retval = nc_def_dim(ncid, "x", NX, &x_dimid))) |
442 | | ERR(retval); |
443 | | if ((retval = nc_def_dim(ncid, "y", NY, &y_dimid))) |
444 | | ERR(retval); |
445 | | |
446 | | dimids[0] = x_dimid; |
447 | | dimids[1] = y_dimid; |
448 | | |
449 | | if ((retval = nc_def_var(ncid, "data", NC_INT, NDIMS, |
450 | | dimids, &varid))) |
451 | | ERR(retval); |
452 | | |
453 | | ... |
454 | | |
455 | | if ((retval = nc_def_var_deflate(ncid, varid, shuffle, deflate, |
456 | | deflate_level))) |
457 | | ERR(retval); |
458 | | ... |
459 | | @endcode |
460 | | @author Ed Hartnett, Dennis Heimbigner |
461 | | */ |
462 | | int |
463 | | nc_def_var_deflate(int ncid, int varid, int shuffle, int deflate, int deflate_level) |
464 | 0 | { |
465 | 0 | NC* ncp; |
466 | 0 | int stat = NC_check_id(ncid,&ncp); |
467 | 0 | if(stat != NC_NOERR) return stat; |
468 | 0 | return ncp->dispatch->def_var_deflate(ncid,varid,shuffle,deflate,deflate_level); |
469 | 0 | } |
470 | | |
471 | | /** |
472 | | Turn on quantization for a variable. |
473 | | |
474 | | The data are quantized by setting unneeded bits to zeros or ones |
475 | | so that they may compress well. BitGroom sets bits alternately to 1/0, |
476 | | while BitRound and Granular BitRound (GBR) round (more) bits to zeros |
477 | | Quantization is lossy (data are irretrievably altered), and it |
478 | | improves the compression ratio provided by a subsequent lossless |
479 | | compression filter. Quantization alone will not reduce the data size. |
480 | | Lossless compression like zlib must also be used (see nc_def_var_deflate()). |
481 | | |
482 | | Producers of large datasets may find that using quantize with |
483 | | compression will result in significant improvement in the final data |
484 | | size. |
485 | | |
486 | | A notable feature of all the quantization algorithms is data remain |
487 | | in IEEE754 format afterwards. Therefore quantization algorithms do |
488 | | nothing when data are read. |
489 | | |
490 | | Quantization is only available for variables of type NC_FLOAT or |
491 | | NC_DOUBLE. Attempts to set quantization for other variable |
492 | | types return an error (NC_EINVAL). |
493 | | |
494 | | Variables that use quantize will have added an attribute with name |
495 | | NC_QUANTIZE_[ALGORITHM_NAME]_ATT_NAME, which will contain the |
496 | | number of significant digits. Users should not delete or change this |
497 | | attribute. This is the only record that quantize has been applied |
498 | | to the data. |
499 | | |
500 | | Quantization is not applied to values equal to the value of the |
501 | | _FillValue attribute, if any. If the _FillValue attribute is not |
502 | | set, then quantization is not applied to values matching the |
503 | | default fill value. |
504 | | |
505 | | Quantization may be applied to scalar variables. |
506 | | |
507 | | When type conversion takes place during a write, then it occurs |
508 | | before quantization is applied. For example, if nc_put_var_double() |
509 | | is called on a variable of type NC_FLOAT, which has quantize |
510 | | turned on, then the data are first converted from double to float, |
511 | | then quantization is applied to the float values. |
512 | | |
513 | | As with the deflate settings, quantize settings may only be |
514 | | modified before the first call to nc_enddef(). Once nc_enddef() is |
515 | | called for the file, quantize settings for any variable in the file |
516 | | may not be changed. |
517 | | |
518 | | Use of quantization is fully backwards compatible with existing |
519 | | versions and packages that can read compressed netCDF data. A |
520 | | variable which has been quantized is readable to older versions of |
521 | | the netCDF libraries, and to netCDF-Java. |
522 | | |
523 | | For more information about quantization and the BitGroom filter, |
524 | | see @ref quantize. |
525 | | |
526 | | @note Users new to quantization should start with Granular Bit |
527 | | Round, which results in the best compression. The Bit Groom |
528 | | algorithm is not as effective when compressing, but is faster than |
529 | | Granular Bit Round. The Bit Round algorithm accepts a number of |
530 | | bits to maintain, rather than a number of decimal digits, and is |
531 | | provided for users who are already performing some bit-based |
532 | | quantization, and wish to turn this task over to the netCDF |
533 | | library. |
534 | | |
535 | | @param ncid File ID. |
536 | | @param varid Variable ID. ::NC_GLOBAL may not be used. |
537 | | @param quantize_mode Quantization mode. May be ::NC_NOQUANTIZE or |
538 | | ::NC_QUANTIZE_BITGROOM or ::NC_QUANTIZE_GRANULARBR or |
539 | | ::NC_QUANTIZE_BITROUND. |
540 | | @param nsd Number of significant digits (either decimal or binary). |
541 | | May be any integer from 1 to ::NC_QUANTIZE_MAX_FLOAT_NSD (for variables |
542 | | of type ::NC_FLOAT) or ::NC_QUANTIZE_MAX_DOUBLE_NSD (for variables |
543 | | of type ::NC_DOUBLE) for mode ::NC_QUANTIZE_BITGROOM and mode |
544 | | ::NC_QUANTIZE_GRANULARBR. May be any integer from 1 to |
545 | | ::NC_QUANTIZE_MAX_FLOAT_NSB (for variables of type ::NC_FLOAT) or |
546 | | ::NC_QUANTIZE_MAX_DOUBLE_NSB (for variables of type ::NC_DOUBLE) |
547 | | for mode ::NC_QUANTIZE_BITROUND. Ignored if quantize_mode = NC_NOQUANTIZE. |
548 | | |
549 | | @return ::NC_NOERR No error. |
550 | | @return ::NC_EGLOBAL Can't use ::NC_GLOBAL with this function. |
551 | | @return ::NC_EBADID Bad ncid. |
552 | | @return ::NC_ENOTVAR Invalid variable ID. |
553 | | @return ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is |
554 | | not netCDF-4/HDF5. |
555 | | @return ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 |
556 | | netcdf-4 file. |
557 | | @return ::NC_ELATEDEF Too late to change settings for this variable. |
558 | | @return ::NC_EINVAL Invalid input. |
559 | | @since 4.9.0 |
560 | | @author Charlie Zender, Ed Hartnett |
561 | | */ |
562 | | int |
563 | | nc_def_var_quantize(int ncid, int varid, int quantize_mode, int nsd) |
564 | 0 | { |
565 | 0 | NC* ncp; |
566 | 0 | int stat = NC_check_id(ncid,&ncp); |
567 | 0 | if(stat != NC_NOERR) return stat; |
568 | | |
569 | | /* Using NC_GLOBAL is illegal. */ |
570 | 0 | if (varid == NC_GLOBAL) return NC_EGLOBAL; |
571 | 0 | return ncp->dispatch->def_var_quantize(ncid,varid,quantize_mode,nsd); |
572 | 0 | } |
573 | | |
574 | | /** |
575 | | Set checksum for a var. |
576 | | |
577 | | This function must be called after nc_def_var and before nc_enddef |
578 | | or any functions which writes data to the file. |
579 | | |
580 | | Checksums require chunked data. If this function is called on a |
581 | | variable with contiguous data, then the data is changed to chunked |
582 | | data, with default chunksizes. Use nc_def_var_chunking() to tune |
583 | | performance with user-defined chunksizes. |
584 | | |
585 | | @note Parallel I/O reads work with fletcher32 encoded |
586 | | data. Parallel I/O writes work with fletcher32 in netcdf-c-4.7.4 |
587 | | and later releases, using hdf5-1.10.2 and later releases. Using the |
588 | | fletcher32 (or any) filter requires that collective access be used |
589 | | with the variable. Turning on fletcher32 for a variable in a file |
590 | | opened for parallel I/O will automatically switch the access for |
591 | | that variable to collective access. |
592 | | |
593 | | @param ncid NetCDF or group ID, from a previous call to nc_open(), |
594 | | nc_create(), nc_def_grp(), or associated inquiry functions such as |
595 | | nc_inq_ncid(). |
596 | | @param varid Variable ID |
597 | | @param fletcher32 True to turn on Fletcher32 checksums for this |
598 | | variable. |
599 | | |
600 | | @return ::NC_NOERR No error. |
601 | | @return ::NC_EBADID Bad ncid. |
602 | | @return ::NC_ENOTVAR Invalid variable ID. |
603 | | @return ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is |
604 | | not netCDF-4/HDF5. |
605 | | @return ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 |
606 | | netcdf-4 file. |
607 | | @return ::NC_ELATEDEF Too late to change settings for this variable. |
608 | | @return ::NC_EINVAL Invalid input |
609 | | @author Ed Hartnett, Dennis Heimbigner |
610 | | */ |
611 | | int |
612 | | nc_def_var_fletcher32(int ncid, int varid, int fletcher32) |
613 | 0 | { |
614 | 0 | NC* ncp; |
615 | 0 | int stat = NC_check_id(ncid,&ncp); |
616 | 0 | if(stat != NC_NOERR) return stat; |
617 | 0 | return ncp->dispatch->def_var_fletcher32(ncid,varid,fletcher32); |
618 | 0 | } |
619 | | |
620 | | /** |
621 | | Define storage and, if chunked storage is used, chunking parameters |
622 | | for a variable |
623 | | |
624 | | The storage may be set to NC_CONTIGUOUS, NC_COMPACT, or NC_CHUNKED. |
625 | | |
626 | | Contiguous storage means the variable is stored as one block of |
627 | | data in the file. This is the default storage. |
628 | | |
629 | | Compact storage means the variable is stored in the header record |
630 | | of the file. This can have large performance benefits on HPC system |
631 | | running many processors. Compact storage is only available for |
632 | | variables whose data are 64 KB or less. Attempting to turn on |
633 | | compact storage for a variable that is too large will result in the |
634 | | ::NC_EVARSIZE error. |
635 | | |
636 | | Chunked storage means the data are stored as chunks, of |
637 | | user-configurable size. Chunked storage is required for variable |
638 | | with one or more unlimited dimensions, or variable which use |
639 | | compression, or any other filter. |
640 | | |
641 | | The total size of a chunk must be less than 4 GiB. That is, the |
642 | | product of all chunksizes and the size of the data (or the size of |
643 | | nc_vlen_t for VLEN types) must be less than 4 GiB. |
644 | | |
645 | | This function may only be called after the variable is defined, but |
646 | | before nc_enddef is called. Once the chunking parameters are set for a |
647 | | variable, they cannot be changed. |
648 | | |
649 | | @note Scalar variables may have a storage of NC_CONTIGUOUS or |
650 | | NC_COMPACT. Attempts to set chunking on a scalar variable will |
651 | | cause ::NC_EINVAL to be returned. Only non-scalar variables can |
652 | | have chunking. |
653 | | |
654 | | @param ncid NetCDF ID, from a previous call to nc_open() or |
655 | | nc_create(). |
656 | | @param varid Variable ID. |
657 | | @param storage If ::NC_CONTIGUOUS or ::NC_COMPACT, then contiguous |
658 | | or compact storage is used for this variable. Variables with one or |
659 | | more unlimited dimensions cannot use contiguous or compact |
660 | | storage. If contiguous or compact storage is turned on, the |
661 | | chunksizes parameter is ignored. If ::NC_CHUNKED, then chunked |
662 | | storage is used for this variable. Chunk sizes may be specified |
663 | | with the chunksizes parameter or default sizes will be used if that |
664 | | parameter is NULL. |
665 | | @param chunksizesp A pointer to an array list of chunk sizes. The |
666 | | array must have one chunksize for each dimension of the variable. If |
667 | | ::NC_CONTIGUOUS storage is set, then the chunksizes parameter is |
668 | | ignored. Ignored if NULL. |
669 | | |
670 | | @return ::NC_NOERR No error. |
671 | | @return ::NC_EBADID Bad ID. |
672 | | @return ::NC_ENOTNC4 Not a netCDF-4 file. |
673 | | @return ::NC_ELATEDEF This variable has already been the subject of |
674 | | a nc_enddef call. In netCDF-4 files nc_enddef will be called |
675 | | automatically for any data read or write. Once nc_enddef has been |
676 | | called after the nc_def_var call for a variable, it is impossible |
677 | | to set the chunking for that variable. |
678 | | @return ::NC_ENOTINDEFINE Not in define mode. This is returned for |
679 | | netCDF classic or 64-bit offset files, or for netCDF-4 files, when |
680 | | they were created with ::NC_CLASSIC_MODEL flag by nc_create(). |
681 | | @return ::NC_EPERM Attempt to create object in read-only file. |
682 | | @return ::NC_EBADCHUNK Returns if the chunk size specified for a |
683 | | variable is larger than the length of the dimensions associated with |
684 | | variable. |
685 | | @return ::NC_EVARSIZE Compact storage attempted for variable bigger |
686 | | than 64 KB. |
687 | | @return ::NC_EINVAL Attempt to set contiguous or compact storage |
688 | | for var with one or more unlimited dimensions, or chunking for a |
689 | | scalar var. |
690 | | |
691 | | @section nc_def_var_chunking_example Example |
692 | | |
693 | | In this example from libsrc4/tst_vars2.c, chunksizes are set with |
694 | | nc_var_def_chunking, and checked with nc_var_inq_chunking. |
695 | | |
696 | | @code |
697 | | printf("**** testing chunking..."); |
698 | | { |
699 | | #define NDIMS5 1 |
700 | | #define DIM5_NAME "D5" |
701 | | #define VAR_NAME5 "V5" |
702 | | #define DIM5_LEN 1000 |
703 | | |
704 | | int dimids[NDIMS5], dimids_in[NDIMS5]; |
705 | | int varid; |
706 | | int ndims, nvars, natts, unlimdimid; |
707 | | nc_type xtype_in; |
708 | | char name_in[NC_MAX_NAME + 1]; |
709 | | int data[DIM5_LEN], data_in[DIM5_LEN]; |
710 | | size_t chunksize[NDIMS5] = {5}; |
711 | | size_t chunksize_in[NDIMS5]; |
712 | | int storage_in; |
713 | | int i, d; |
714 | | |
715 | | for (i = 0; i < DIM5_LEN; i++) |
716 | | data[i] = i; |
717 | | |
718 | | if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR; |
719 | | if (nc_def_dim(ncid, DIM5_NAME, DIM5_LEN, &dimids[0])) ERR; |
720 | | if (nc_def_var(ncid, VAR_NAME5, NC_INT, NDIMS5, dimids, &varid)) ERR; |
721 | | if (nc_def_var_chunking(ncid, varid, NC_CHUNKED, chunksize)) ERR; |
722 | | if (nc_put_var_int(ncid, varid, data)) ERR; |
723 | | |
724 | | if (nc_inq_var_chunking(ncid, varid, &storage_in, chunksize_in)) ERR; |
725 | | for (d = 0; d < NDIMS5; d++) |
726 | | if (chunksize[d] != chunksize_in[d]) ERR; |
727 | | if (storage_in != NC_CHUNKED) ERR; |
728 | | @endcode |
729 | | @author Ed Hartnett, Dennis Heimbigner |
730 | | */ |
731 | | int |
732 | | nc_def_var_chunking(int ncid, int varid, int storage, const size_t *chunksizesp) |
733 | 0 | { |
734 | 0 | NC* ncp; |
735 | 0 | int stat = NC_check_id(ncid, &ncp); |
736 | 0 | if(stat != NC_NOERR) return stat; |
737 | 0 | return ncp->dispatch->def_var_chunking(ncid, varid, storage, |
738 | 0 | chunksizesp); |
739 | 0 | } |
740 | | |
741 | | /** |
742 | | Define endianness of a variable. |
743 | | |
744 | | With this function the endianness (i.e. order of bytes in integers) can |
745 | | be changed on a per-variable basis. By default, the endianness is the |
746 | | same as the default endianness of the platform. But with |
747 | | nc_def_var_endianness the endianness can be explicitly set for a |
748 | | variable. |
749 | | |
750 | | Warning: this function is only defined if the type of the variable |
751 | | is an atomic integer or float type. |
752 | | |
753 | | This function may only be called after the variable is defined, but |
754 | | before nc_enddef is called. |
755 | | |
756 | | @param ncid NetCDF ID, from a previous call to nc_open() or |
757 | | nc_create(). |
758 | | |
759 | | @param varid Variable ID. |
760 | | |
761 | | @param endian ::NC_ENDIAN_NATIVE to select the native endianness of |
762 | | the platform (the default), ::NC_ENDIAN_LITTLE to use |
763 | | little-endian, ::NC_ENDIAN_BIG to use big-endian. |
764 | | |
765 | | @return ::NC_NOERR No error. |
766 | | @return ::NC_EBADID Bad ID. |
767 | | @return ::NC_ENOTNC4 Not a netCDF-4 file. |
768 | | @return ::NC_ELATEDEF This variable has already been the subject of a |
769 | | nc_enddef call. In netCDF-4 files nc_enddef will be called |
770 | | automatically for any data read or write. Once nc_enddef has been |
771 | | called after the nc_def_var call for a variable, it is impossible to |
772 | | set the chunking for that variable. |
773 | | @return ::NC_ENOTINDEFINE Not in define mode. This is returned for |
774 | | netCDF classic or 64-bit offset files, or for netCDF-4 files, when |
775 | | they were created with ::NC_CLASSIC_MODEL flag by nc_create(). |
776 | | @return ::NC_EPERM Attempt to create object in read-only file. |
777 | | |
778 | | @section nc_def_var_endian_example Example |
779 | | |
780 | | In this example from libsrc4/tst_vars2.c, a variable is created, and |
781 | | the endianness set to ::NC_ENDIAN_BIG. |
782 | | |
783 | | @code |
784 | | #define NDIMS4 1 |
785 | | #define DIM4_NAME "Joe" |
786 | | #define VAR_NAME4 "Ed" |
787 | | #define DIM4_LEN 10 |
788 | | { |
789 | | int dimids[NDIMS4], dimids_in[NDIMS4]; |
790 | | int varid; |
791 | | int ndims, nvars, natts, unlimdimid; |
792 | | nc_type xtype_in; |
793 | | char name_in[NC_MAX_NAME + 1]; |
794 | | int data[DIM4_LEN], data_in[DIM4_LEN]; |
795 | | int endian_in; |
796 | | int i; |
797 | | |
798 | | for (i = 0; i < DIM4_LEN; i++) |
799 | | data[i] = i; |
800 | | |
801 | | if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR; |
802 | | if (nc_def_dim(ncid, DIM4_NAME, DIM4_LEN, &dimids[0])) ERR; |
803 | | if (dimids[0] != 0) ERR; |
804 | | if (nc_def_var(ncid, VAR_NAME4, NC_INT, NDIMS4, dimids, &varid)) ERR; |
805 | | if (nc_def_var_endian(ncid, varid, NC_ENDIAN_BIG)) ERR; |
806 | | @endcode |
807 | | @author Ed Hartnett |
808 | | */ |
809 | | int |
810 | | nc_def_var_endian(int ncid, int varid, int endian) |
811 | 0 | { |
812 | 0 | NC* ncp; |
813 | 0 | int stat = NC_check_id(ncid,&ncp); |
814 | 0 | if(stat != NC_NOERR) return stat; |
815 | 0 | return ncp->dispatch->def_var_endian(ncid,varid,endian); |
816 | 0 | } |
817 | | |
818 | | /** |
819 | | * Set szip compression settings on a variable. Szip is an |
820 | | * implementation of the extended-Rice lossless compression algorithm; |
821 | | * it is reported to provide fast and effective compression. Szip is |
822 | | * only available to netCDF if HDF5 was built with szip support. |
823 | | * |
824 | | * SZIP compression cannot be applied to variables with any |
825 | | * user-defined type. |
826 | | * |
827 | | * If zlib compression has already be turned on for a variable, then |
828 | | * this function will return ::NC_EINVAL. |
829 | | * |
830 | | * To learn the szip settings for a variable, use nc_inq_var_szip(). |
831 | | * |
832 | | * @note The options_mask parameter may be either ::NC_SZIP_EC (entropy |
833 | | * coding) or ::NC_SZIP_NN (nearest neighbor): |
834 | | * * The entropy coding method is best suited for data that has been |
835 | | * processed. The EC method works best for small numbers. |
836 | | * * The nearest neighbor coding method preprocesses the data then the |
837 | | * applies EC method as above. |
838 | | * |
839 | | * For more information about HDF5 and szip, see |
840 | | * https://support.hdfgroup.org/HDF5/doc/RM/RM_H5P.html#Property-SetSzip |
841 | | * and |
842 | | * https://support.hdfgroup.org/doc_resource/SZIP/index.html. |
843 | | * |
844 | | * @param ncid File ID. |
845 | | * @param varid Variable ID. |
846 | | * @param options_mask The options mask. Can be ::NC_SZIP_EC or |
847 | | * ::NC_SZIP_NN. |
848 | | * @param pixels_per_block Pixels per block. Must be even and not |
849 | | * greater than 32, with typical values being 8, 10, 16, or 32. This |
850 | | * parameter affects compression ratio; the more pixel values vary, |
851 | | * the smaller this number should be to achieve better performance. If |
852 | | * pixels_per_block is bigger than the total number of elements in a |
853 | | * dataset chunk, ::NC_EINVAL will be returned. |
854 | | * |
855 | | * @returns ::NC_NOERR No error. |
856 | | * @returns ::NC_EBADID Bad ncid. |
857 | | * @returns ::NC_ENOTVAR Invalid variable ID. |
858 | | * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is |
859 | | * not netCDF-4/HDF5. |
860 | | * @returns ::NC_ELATEDEF Too late to change settings for this variable. |
861 | | * @returns ::NC_ENOTINDEFINE Not in define mode. |
862 | | * @returns ::NC_EINVAL Invalid input, or zlib filter already applied |
863 | | * to this var. |
864 | | * @since 4.0.0 |
865 | | * @author Ed Hartnett |
866 | | */ |
867 | | int |
868 | | nc_def_var_szip(int ncid, int varid, int options_mask, int pixels_per_block) |
869 | 0 | { |
870 | 0 | int ret; |
871 | | |
872 | | /* This will cause H5Pset_szip to be called when the var is |
873 | | * created. */ |
874 | 0 | unsigned int params[2] = {(unsigned int)options_mask, (unsigned int)pixels_per_block}; |
875 | 0 | if ((ret = nc_def_var_filter(ncid, varid, H5Z_FILTER_SZIP, 2, params))) |
876 | 0 | return ret; |
877 | | |
878 | 0 | return NC_NOERR; |
879 | 0 | } |
880 | | |
881 | | /** @} */ |
882 | | |
883 | | /** |
884 | | @name Rename a Variable |
885 | | |
886 | | Rename a variable. |
887 | | */ |
888 | | /** @{ */ |
889 | | |
890 | | /** |
891 | | Rename a variable. |
892 | | |
893 | | This function changes the name of a netCDF variable in an open netCDF |
894 | | file or group. You cannot rename a variable to have the name of any existing |
895 | | variable. |
896 | | |
897 | | For classic format, 64-bit offset format, and netCDF-4/HDF5 with |
898 | | classic mode, if the new name is longer than the old name, the netCDF |
899 | | dataset must be in define mode. |
900 | | |
901 | | For netCDF-4/HDF5 files, renaming the variable changes the order of |
902 | | the variables in the file. The renamed variable becomes the last |
903 | | variable in the file. |
904 | | |
905 | | @param ncid NetCDF or group ID, from a previous call to nc_open(), |
906 | | nc_create(), nc_def_grp(), or associated inquiry functions such as |
907 | | nc_inq_ncid(). |
908 | | |
909 | | @param varid Variable ID |
910 | | |
911 | | @param name New name of the variable. |
912 | | |
913 | | @return ::NC_NOERR No error. |
914 | | @return ::NC_EBADID Bad ncid. |
915 | | @return ::NC_ENOTVAR Invalid variable ID. |
916 | | @return ::NC_EBADNAME Bad name. |
917 | | @return ::NC_EMAXNAME Name is too long. |
918 | | @return ::NC_ENAMEINUSE Name in use. |
919 | | @return ::NC_ENOMEM Out of memory. |
920 | | |
921 | | @section nc_rename_var_example Example |
922 | | |
923 | | Here is an example using nc_rename_var to rename the variable rh to |
924 | | rel_hum in an existing netCDF dataset named foo.nc: |
925 | | |
926 | | @code |
927 | | #include <netcdf.h> |
928 | | ... |
929 | | int status; |
930 | | int ncid; |
931 | | int rh_id; |
932 | | ... |
933 | | status = nc_open("foo.nc", NC_WRITE, &ncid); |
934 | | if (status != NC_NOERR) handle_error(status); |
935 | | ... |
936 | | status = nc_redef(ncid); |
937 | | if (status != NC_NOERR) handle_error(status); |
938 | | status = nc_inq_varid (ncid, "rh", &rh_id); |
939 | | if (status != NC_NOERR) handle_error(status); |
940 | | status = nc_rename_var (ncid, rh_id, "rel_hum"); |
941 | | if (status != NC_NOERR) handle_error(status); |
942 | | status = nc_enddef(ncid); |
943 | | if (status != NC_NOERR) handle_error(status); |
944 | | @endcode |
945 | | @author Glenn Davis, Ed Hartnett, Dennis Heimbigner |
946 | | */ |
947 | | int |
948 | | nc_rename_var(int ncid, int varid, const char *name) |
949 | 0 | { |
950 | 0 | NC* ncp; |
951 | 0 | int stat = NC_check_id(ncid, &ncp); |
952 | 0 | if(stat != NC_NOERR) return stat; |
953 | 0 | TRACE(nc_rename_var); |
954 | 0 | return ncp->dispatch->rename_var(ncid, varid, name); |
955 | 0 | } |
956 | | /** @} */ |
957 | | |
958 | | /** |
959 | | @internal Does a variable have a record dimension? |
960 | | |
961 | | @param ncid File ID. |
962 | | @param varid Variable ID. |
963 | | @param nrecs Pointer that gets number of records. |
964 | | |
965 | | @return 0 if not a record var, 1 if it is. |
966 | | */ |
967 | | int |
968 | | NC_is_recvar(int ncid, int varid, size_t* nrecs) |
969 | 0 | { |
970 | 0 | int status = NC_NOERR; |
971 | 0 | int unlimid; |
972 | 0 | int ndims; |
973 | 0 | int dimset[NC_MAX_VAR_DIMS]; |
974 | |
|
975 | 0 | status = nc_inq_unlimdim(ncid,&unlimid); |
976 | 0 | if(status != NC_NOERR) return 0; /* no unlimited defined */ |
977 | 0 | status = nc_inq_varndims(ncid,varid,&ndims); |
978 | 0 | if(status != NC_NOERR) return 0; /* no unlimited defined */ |
979 | 0 | if(ndims == 0) return 0; /* scalar */ |
980 | 0 | status = nc_inq_vardimid(ncid,varid,dimset); |
981 | 0 | if(status != NC_NOERR) return 0; /* no unlimited defined */ |
982 | 0 | status = nc_inq_dim(ncid,dimset[0],NULL,nrecs); |
983 | 0 | if(status != NC_NOERR) return 0; |
984 | 0 | return (dimset[0] == unlimid ? 1: 0); |
985 | 0 | } |
986 | | |
987 | | /** |
988 | | @internal Get the number of record dimensions for a variable and an |
989 | | array that identifies which of a variable's dimensions are record |
990 | | dimensions. Intended to be used instead of NC_is_recvar(), which |
991 | | doesn't work for netCDF-4 variables which have multiple unlimited |
992 | | dimensions or an unlimited dimension that is not the first of a |
993 | | variable's dimensions. |
994 | | |
995 | | @param ncid File ID. |
996 | | @param varid Variable ID. |
997 | | @param nrecdimsp Pointer that gets number of record dims. |
998 | | @param is_recdim Pointer that gets 1 if there is one or more record |
999 | | dimensions, 0 if not. |
1000 | | |
1001 | | @return 0 if not a record var, 1 if it is. |
1002 | | |
1003 | | Example use: |
1004 | | @code |
1005 | | int nrecdims; |
1006 | | int is_recdim[NC_MAX_VAR_DIMS]; |
1007 | | ... |
1008 | | status = NC_inq_recvar(ncid,varid,&nrecdims,is_recdim); |
1009 | | isrecvar = (nrecdims > 0); |
1010 | | @endcode |
1011 | | */ |
1012 | | int |
1013 | | NC_inq_recvar(int ncid, int varid, int* nrecdimsp, int *is_recdim) |
1014 | 0 | { |
1015 | 0 | int status = NC_NOERR; |
1016 | 0 | int unlimid; |
1017 | 0 | int nvardims; |
1018 | 0 | int dimset[NC_MAX_VAR_DIMS]; |
1019 | 0 | int dim; |
1020 | 0 | int nrecdims = 0; |
1021 | |
|
1022 | 0 | status = nc_inq_varndims(ncid,varid,&nvardims); |
1023 | 0 | if(status != NC_NOERR) return status; |
1024 | 0 | if(nvardims == 0) return NC_NOERR; /* scalars have no dims */ |
1025 | 0 | for(dim = 0; dim < nvardims; dim++) |
1026 | 0 | is_recdim[dim] = 0; |
1027 | 0 | status = nc_inq_unlimdim(ncid, &unlimid); |
1028 | 0 | if(status != NC_NOERR) return status; |
1029 | 0 | if(unlimid == -1) return status; /* no unlimited dims for any variables */ |
1030 | 0 | #ifdef USE_NETCDF4 |
1031 | 0 | { |
1032 | 0 | int nunlimdims; |
1033 | 0 | int *unlimids; |
1034 | 0 | int recdim; |
1035 | 0 | status = nc_inq_unlimdims(ncid, &nunlimdims, NULL); /* for group or file, not variable */ |
1036 | 0 | if(status != NC_NOERR) return status; |
1037 | 0 | if(nunlimdims == 0) return status; |
1038 | | |
1039 | 0 | if (!(unlimids = malloc((size_t)nunlimdims * sizeof(int)))) |
1040 | 0 | return NC_ENOMEM; |
1041 | 0 | status = nc_inq_unlimdims(ncid, &nunlimdims, unlimids); /* for group or file, not variable */ |
1042 | 0 | if(status != NC_NOERR) { |
1043 | 0 | free(unlimids); |
1044 | 0 | return status; |
1045 | 0 | } |
1046 | 0 | status = nc_inq_vardimid(ncid, varid, dimset); |
1047 | 0 | if(status != NC_NOERR) { |
1048 | 0 | free(unlimids); |
1049 | 0 | return status; |
1050 | 0 | } |
1051 | 0 | for (dim = 0; dim < nvardims; dim++) { /* netCDF-4 rec dims need not be first dim for a rec var */ |
1052 | 0 | for(recdim = 0; recdim < nunlimdims; recdim++) { |
1053 | 0 | if(dimset[dim] == unlimids[recdim]) { |
1054 | 0 | is_recdim[dim] = 1; |
1055 | 0 | nrecdims++; |
1056 | 0 | } |
1057 | 0 | } |
1058 | 0 | } |
1059 | 0 | free(unlimids); |
1060 | 0 | } |
1061 | | #else |
1062 | | status = nc_inq_vardimid(ncid, varid, dimset); |
1063 | | if(status != NC_NOERR) return status; |
1064 | | if(dimset[0] == unlimid) { |
1065 | | is_recdim[0] = 1; |
1066 | | nrecdims++; |
1067 | | } |
1068 | | #endif /* USE_NETCDF4 */ |
1069 | 0 | if(nrecdimsp) *nrecdimsp = nrecdims; |
1070 | 0 | return status; |
1071 | 0 | } |
1072 | | |
1073 | | /* Ok to use NC pointers because |
1074 | | all IOSP's will use that structure, |
1075 | | but not ok to use e.g. NC_Var pointers |
1076 | | because they may be different structure |
1077 | | entirely. |
1078 | | */ |
1079 | | |
1080 | | /** |
1081 | | @internal |
1082 | | Find the length of a type. This is how much space is required by |
1083 | | the in memory to hold one element of this type. |
1084 | | |
1085 | | @param type A netCDF atomic type. |
1086 | | |
1087 | | @return Length of the type in bytes, or -1 if type not found. |
1088 | | @author Ed Hartnett |
1089 | | */ |
1090 | | int |
1091 | | nctypelen(nc_type type) |
1092 | 0 | { |
1093 | 0 | switch(type){ |
1094 | 0 | case NC_CHAR : |
1095 | 0 | return ((int)sizeof(char)); |
1096 | 0 | case NC_BYTE : |
1097 | 0 | return ((int)sizeof(signed char)); |
1098 | 0 | case NC_SHORT : |
1099 | 0 | return ((int)sizeof(short)); |
1100 | 0 | case NC_INT : |
1101 | 0 | return ((int)sizeof(int)); |
1102 | 0 | case NC_FLOAT : |
1103 | 0 | return ((int)sizeof(float)); |
1104 | 0 | case NC_DOUBLE : |
1105 | 0 | return ((int)sizeof(double)); |
1106 | | |
1107 | | /* These can occur in netcdf-3 code */ |
1108 | 0 | case NC_UBYTE : |
1109 | 0 | return ((int)sizeof(unsigned char)); |
1110 | 0 | case NC_USHORT : |
1111 | 0 | return ((int)(sizeof(unsigned short))); |
1112 | 0 | case NC_UINT : |
1113 | 0 | return ((int)sizeof(unsigned int)); |
1114 | 0 | case NC_INT64 : |
1115 | 0 | return ((int)sizeof(signed long long)); |
1116 | 0 | case NC_UINT64 : |
1117 | 0 | return ((int)sizeof(unsigned long long)); |
1118 | 0 | #ifdef USE_NETCDF4 |
1119 | 0 | case NC_STRING : |
1120 | 0 | return ((int)sizeof(char*)); |
1121 | 0 | #endif /*USE_NETCDF4*/ |
1122 | | |
1123 | 0 | default: |
1124 | 0 | return -1; |
1125 | 0 | } |
1126 | 0 | } |
1127 | | |
1128 | | /** |
1129 | | @internal |
1130 | | Find the length of a type. Redundant over nctypelen() above. |
1131 | | |
1132 | | @param xtype an nc_type. |
1133 | | |
1134 | | @author Dennis Heimbigner |
1135 | | */ |
1136 | | size_t |
1137 | | NC_atomictypelen(nc_type xtype) |
1138 | 0 | { |
1139 | 0 | size_t sz = 0; |
1140 | 0 | switch(xtype) { |
1141 | 0 | case NC_NAT: sz = 0; break; |
1142 | 0 | case NC_BYTE: sz = sizeof(signed char); break; |
1143 | 0 | case NC_CHAR: sz = sizeof(char); break; |
1144 | 0 | case NC_SHORT: sz = sizeof(short); break; |
1145 | 0 | case NC_INT: sz = sizeof(int); break; |
1146 | 0 | case NC_FLOAT: sz = sizeof(float); break; |
1147 | 0 | case NC_DOUBLE: sz = sizeof(double); break; |
1148 | 0 | case NC_INT64: sz = sizeof(signed long long); break; |
1149 | 0 | case NC_UBYTE: sz = sizeof(unsigned char); break; |
1150 | 0 | case NC_USHORT: sz = sizeof(unsigned short); break; |
1151 | 0 | case NC_UINT: sz = sizeof(unsigned int); break; |
1152 | 0 | case NC_UINT64: sz = sizeof(unsigned long long); break; |
1153 | 0 | #ifdef USE_NETCDF4 |
1154 | 0 | case NC_STRING: sz = sizeof(char*); break; |
1155 | 0 | #endif |
1156 | 0 | default: break; |
1157 | 0 | } |
1158 | 0 | return sz; |
1159 | 0 | } |
1160 | | |
1161 | | /** |
1162 | | @internal |
1163 | | Get the type name. |
1164 | | |
1165 | | @param xtype an nc_type. |
1166 | | |
1167 | | @author Dennis Heimbigner |
1168 | | */ |
1169 | | char * |
1170 | | NC_atomictypename(nc_type xtype) |
1171 | 0 | { |
1172 | 0 | char* nm = NULL; |
1173 | 0 | switch(xtype) { |
1174 | 0 | case NC_NAT: nm = "undefined"; break; |
1175 | 0 | case NC_BYTE: nm = "byte"; break; |
1176 | 0 | case NC_CHAR: nm = "char"; break; |
1177 | 0 | case NC_SHORT: nm = "short"; break; |
1178 | 0 | case NC_INT: nm = "int"; break; |
1179 | 0 | case NC_FLOAT: nm = "float"; break; |
1180 | 0 | case NC_DOUBLE: nm = "double"; break; |
1181 | 0 | case NC_INT64: nm = "int64"; break; |
1182 | 0 | case NC_UBYTE: nm = "ubyte"; break; |
1183 | 0 | case NC_USHORT: nm = "ushort"; break; |
1184 | 0 | case NC_UINT: nm = "uint"; break; |
1185 | 0 | case NC_UINT64: nm = "uint64"; break; |
1186 | 0 | #ifdef USE_NETCDF4 |
1187 | 0 | case NC_STRING: nm = "string"; break; |
1188 | 0 | #endif |
1189 | 0 | default: break; |
1190 | 0 | } |
1191 | 0 | return nm; |
1192 | 0 | } |
1193 | | |
1194 | | /** |
1195 | | @internal |
1196 | | Get the shape of a variable. |
1197 | | |
1198 | | @param ncid NetCDF ID, from a previous call to nc_open() or |
1199 | | nc_create(). |
1200 | | @param varid Variable ID. |
1201 | | @param ndims Number of dimensions for this var. |
1202 | | @param shape Pointer to pre-allocated array that gets the size of |
1203 | | each dimension. |
1204 | | |
1205 | | @return ::NC_NOERR No error. |
1206 | | @return ::NC_EBADID Bad ncid. |
1207 | | @return ::NC_ENOTVAR Bad varid. |
1208 | | |
1209 | | @author Dennis Heimbigner |
1210 | | */ |
1211 | | int |
1212 | | NC_getshape(int ncid, int varid, int ndims, size_t* shape) |
1213 | 0 | { |
1214 | 0 | int dimids[NC_MAX_VAR_DIMS]; |
1215 | 0 | int i; |
1216 | 0 | int status = NC_NOERR; |
1217 | |
|
1218 | 0 | if ((status = nc_inq_vardimid(ncid, varid, dimids))) |
1219 | 0 | return status; |
1220 | 0 | for(i = 0; i < ndims; i++) |
1221 | 0 | if ((status = nc_inq_dimlen(ncid, dimids[i], &shape[i]))) |
1222 | 0 | break; |
1223 | |
|
1224 | 0 | return status; |
1225 | 0 | } |
1226 | | |
1227 | | /** |
1228 | | @internal Check the start, count, and stride parameters for gets |
1229 | | and puts, and handle NULLs. |
1230 | | |
1231 | | @param ncid The file ID. |
1232 | | @param varid The variable ID. |
1233 | | @param start Pointer to start array. If NULL ::NC_EINVALCOORDS will |
1234 | | be returned for non-scalar variable. This array must be same size |
1235 | | as variable's number of dimensions. |
1236 | | @param count Pointer to pointer to count array. If *count is NULL, |
1237 | | an array of the correct size will be allocated, and filled with |
1238 | | counts that represent the full extent of the variable. In this |
1239 | | case, the memory must be freed by the caller. If provided, this |
1240 | | array must be same size as variable's number of dimensions. |
1241 | | @param stride Pointer to pointer to stride array. If NULL, stide is |
1242 | | ignored. If *stride is NULL an array of the correct size will be |
1243 | | allocated, and filled with ones. In this case, the memory must be |
1244 | | freed by the caller. If provided, this |
1245 | | array must be same size as variable's number of dimensions. |
1246 | | |
1247 | | @return ::NC_NOERR No error. |
1248 | | @return ::NC_EBADID Bad ncid. |
1249 | | @return ::NC_ENOTVAR Variable not found. |
1250 | | @return ::NC_ENOMEM Out of memory. |
1251 | | @return ::NC_EINVALCOORDS Missing start array. |
1252 | | @author Ed Hartnett |
1253 | | */ |
1254 | | int |
1255 | | NC_check_nulls(int ncid, int varid, const size_t *start, size_t **count, |
1256 | | ptrdiff_t **stride) |
1257 | 0 | { |
1258 | 0 | int varndims; |
1259 | 0 | int stat; |
1260 | |
|
1261 | 0 | if ((stat = nc_inq_varndims(ncid, varid, &varndims))) |
1262 | 0 | return stat; |
1263 | | |
1264 | | /* For non-scalar vars, start is required. */ |
1265 | 0 | if (!start && varndims) |
1266 | 0 | return NC_EINVALCOORDS; |
1267 | | |
1268 | | /* If count is NULL, assume full extent of var. */ |
1269 | 0 | if (!*count) |
1270 | 0 | { |
1271 | 0 | if (!(*count = malloc((size_t)varndims * sizeof(size_t)))) |
1272 | 0 | return NC_ENOMEM; |
1273 | 0 | if ((stat = NC_getshape(ncid, varid, varndims, *count))) |
1274 | 0 | { |
1275 | 0 | free(*count); |
1276 | 0 | *count = NULL; |
1277 | 0 | return stat; |
1278 | 0 | } |
1279 | 0 | } |
1280 | | |
1281 | | /* If stride is NULL, do nothing, if *stride is NULL use all |
1282 | | * 1s. */ |
1283 | 0 | if (stride && !*stride) |
1284 | 0 | { |
1285 | 0 | int i; |
1286 | |
|
1287 | 0 | if (!(*stride = malloc((size_t)varndims * sizeof(ptrdiff_t)))) |
1288 | 0 | return NC_ENOMEM; |
1289 | 0 | for (i = 0; i < varndims; i++) |
1290 | 0 | (*stride)[i] = 1; |
1291 | 0 | } |
1292 | | |
1293 | 0 | return NC_NOERR; |
1294 | 0 | } |
1295 | | |
1296 | | /** |
1297 | | @name Free String Resources |
1298 | | |
1299 | | Use these functions to free resources associated with ::NC_STRING data. |
1300 | | */ |
1301 | | /*! @{ */ |
1302 | | /** |
1303 | | Free string space allocated by the library. |
1304 | | |
1305 | | When you read an array string typed data the library will allocate the storage |
1306 | | space for the data. The allocated strings must be freed, so pass the |
1307 | | pointer to the array plus a count of the number of elements in the array to this function, |
1308 | | when you're done with the data, and it will free the allocated string memory. |
1309 | | |
1310 | | WARNING: This does not free the top-level array itself, only |
1311 | | the strings to which it points. |
1312 | | |
1313 | | @param len The number of character arrays in the array. |
1314 | | @param data The pointer to the data array. |
1315 | | |
1316 | | @return ::NC_NOERR No error. |
1317 | | @author Ed Hartnett |
1318 | | */ |
1319 | | int |
1320 | | nc_free_string(size_t len, char **data) |
1321 | 0 | { |
1322 | 0 | size_t i; |
1323 | 0 | for (i = 0; i < len; i++) |
1324 | 0 | free(data[i]); |
1325 | 0 | return NC_NOERR; |
1326 | 0 | } |
1327 | | /** @} */ |
1328 | | |
1329 | | /** |
1330 | | @name Variables Chunk Caches |
1331 | | |
1332 | | Use these functions to change the variable chunk cache settings. |
1333 | | */ |
1334 | | /*! @{ */ |
1335 | | /** |
1336 | | Change the cache settings for a chunked variable. This function allows |
1337 | | users to control the amount of memory used in the per-variable chunk |
1338 | | cache at the HDF5 level. Changing the chunk cache only has effect |
1339 | | until the file is closed. Once re-opened, the variable chunk cache |
1340 | | returns to its default value. |
1341 | | |
1342 | | Current cache settings for each var may be obtained with |
1343 | | nc_get_var_chunk_cache(). |
1344 | | |
1345 | | Default values for these settings may be changed for the whole file |
1346 | | with nc_set_chunk_cache(). |
1347 | | |
1348 | | @param ncid NetCDF or group ID, from a previous call to nc_open(), |
1349 | | nc_create(), nc_def_grp(), or associated inquiry functions such as |
1350 | | nc_inq_ncid(). |
1351 | | @param varid Variable ID |
1352 | | @param size The total size of the raw data chunk cache, in bytes. |
1353 | | @param nelems The number of chunk slots in the raw data chunk cache. |
1354 | | @param preemption The preemption, a value between 0 and 1 inclusive |
1355 | | that indicates how much chunks that have been fully read are favored |
1356 | | for preemption. A value of zero means fully read chunks are treated no |
1357 | | differently than other chunks (the preemption is strictly LRU) while a |
1358 | | value of one means fully read chunks are always preempted before other |
1359 | | chunks. |
1360 | | |
1361 | | @return ::NC_NOERR No error. |
1362 | | @return ::NC_EBADID Bad ncid. |
1363 | | @return ::NC_ENOTVAR Invalid variable ID. |
1364 | | @return ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 |
1365 | | netcdf-4 file. |
1366 | | @return ::NC_EINVAL Invalid input |
1367 | | |
1368 | | @section nc_def_var_chunk_cache_example Example |
1369 | | |
1370 | | In this example from nc_test4/tst_coords.c, a variable is defined, and |
1371 | | the chunk cache settings are changed for that variable. |
1372 | | |
1373 | | @code |
1374 | | printf("**** testing setting cache values for coordinate variables..."); |
1375 | | { |
1376 | | #define RANK_1 1 |
1377 | | #define DIM0_NAME "d0" |
1378 | | #define CACHE_SIZE 1000000 |
1379 | | #define CACHE_NELEMS 1009 |
1380 | | #define CACHE_PREEMPTION .90 |
1381 | | |
1382 | | int ncid, dimid, varid; |
1383 | | char name_in[NC_MAX_NAME + 1]; |
1384 | | |
1385 | | if (nc_create(FILE_NAME, NC_CLASSIC_MODEL|NC_NETCDF4, &ncid)) ERR; |
1386 | | if (nc_def_dim(ncid, DIM0_NAME, NC_UNLIMITED, &dimid)) ERR; |
1387 | | if (nc_def_var(ncid, DIM0_NAME, NC_DOUBLE, 1, &dimid, &varid)) ERR; |
1388 | | if (nc_set_var_chunk_cache(ncid, varid, CACHE_SIZE, CACHE_NELEMS, CACHE_PREEMPTION)) ERR; |
1389 | | if (nc_close(ncid)) ERR; |
1390 | | |
1391 | | ... |
1392 | | } |
1393 | | SUMMARIZE_ERR; |
1394 | | @endcode |
1395 | | @author Ed Hartnett |
1396 | | */ |
1397 | | int |
1398 | | nc_set_var_chunk_cache(int ncid, int varid, size_t size, size_t nelems, |
1399 | | float preemption) |
1400 | 0 | { |
1401 | 0 | NC* ncp; |
1402 | 0 | int stat = NC_check_id(ncid, &ncp); |
1403 | 0 | if(stat != NC_NOERR) return stat; |
1404 | 0 | return ncp->dispatch->set_var_chunk_cache(ncid, varid, size, |
1405 | 0 | nelems, preemption); |
1406 | 0 | } |
1407 | | |
1408 | | /** |
1409 | | Get the per-variable chunk cache settings from the HDF5 |
1410 | | layer. These settings may be changed with nc_set_var_chunk_cache(). |
1411 | | |
1412 | | See nc_set_chunk_cache() for a full discussion of these settings. |
1413 | | |
1414 | | @param ncid NetCDF or group ID, from a previous call to nc_open(), |
1415 | | nc_create(), nc_def_grp(), or associated inquiry functions such as |
1416 | | nc_inq_ncid(). |
1417 | | @param varid Variable ID |
1418 | | @param sizep The total size of the raw data chunk cache, in bytes, |
1419 | | will be put here. @ref ignored_if_null. |
1420 | | @param nelemsp The number of chunk slots in the raw data chunk |
1421 | | cache hash table will be put here. @ref ignored_if_null. |
1422 | | @param preemptionp The preemption will be put here. The preemption |
1423 | | value is between 0 and 1 inclusive and indicates how much chunks |
1424 | | that have been fully read are favored for preemption. A value of |
1425 | | zero means fully read chunks are treated no differently than other |
1426 | | chunks (the preemption is strictly LRU) while a value of one means |
1427 | | fully read chunks are always preempted before other chunks. @ref |
1428 | | ignored_if_null. |
1429 | | |
1430 | | @return ::NC_NOERR No error. |
1431 | | @return ::NC_EBADID Bad ncid. |
1432 | | @return ::NC_ENOTVAR Invalid variable ID. |
1433 | | @return ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 |
1434 | | netcdf-4 file. |
1435 | | @return ::NC_EINVAL Invalid input |
1436 | | @author Ed Hartnett |
1437 | | */ |
1438 | | int |
1439 | | nc_get_var_chunk_cache(int ncid, int varid, size_t *sizep, size_t *nelemsp, |
1440 | | float *preemptionp) |
1441 | 0 | { |
1442 | 0 | NC* ncp; |
1443 | 0 | int stat = NC_check_id(ncid, &ncp); |
1444 | 0 | if(stat != NC_NOERR) return stat; |
1445 | 0 | return ncp->dispatch->get_var_chunk_cache(ncid, varid, sizep, |
1446 | 0 | nelemsp, preemptionp); |
1447 | 0 | } |
1448 | | |
1449 | | #ifndef USE_NETCDF4 |
1450 | | /* Make sure the fortran API is defined, even if it only returns errors */ |
1451 | | |
1452 | | int |
1453 | | nc_set_chunk_cache_ints(int size, int nelems, int preemption) |
1454 | | { |
1455 | | return NC_ENOTBUILT; |
1456 | | } |
1457 | | |
1458 | | int |
1459 | | nc_get_chunk_cache_ints(int *sizep, int *nelemsp, int *preemptionp) |
1460 | | { |
1461 | | return NC_ENOTBUILT; |
1462 | | } |
1463 | | |
1464 | | int |
1465 | | nc_set_var_chunk_cache_ints(int ncid, int varid, int size, int nelems, |
1466 | | int preemption) |
1467 | | { |
1468 | | return NC_ENOTBUILT; |
1469 | | } |
1470 | | |
1471 | | int |
1472 | | nc_get_var_chunk_cache_ints(int ncid, int varid, int *sizep, |
1473 | | int *nelemsp, int *preemptionp) |
1474 | | { |
1475 | | return NC_ENOTBUILT; |
1476 | | } |
1477 | | |
1478 | | #endif /*USE_NETCDF4*/ |
1479 | | |
1480 | | /** @} */ |
1481 | | /** @} */ |