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