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 @ref data_type of the variable.
152    @param ndims Number of dimensions for the variable. For example, 2
153    specifies a matrix, 1 specifies a vector, and 0 means the variable is
154    a scalar with no dimensions. Must not be negative or greater than the
155    predefined constant ::NC_MAX_VAR_DIMS. In netCDF-4/HDF5 files, may not
156    exceed the HDF5 maximum number of dimensions (32).
157    @param dimidsp Vector of ndims dimension IDs corresponding to the
158    variable dimensions. For classic model netCDF files, if the ID of the
159    unlimited dimension is included, it must be first. This argument is
160    ignored if ndims is 0. For expanded model netCDF4/HDF5 files, there
161    may be any number of unlimited dimensions, and they may be used in any
162    element of the dimids array.
163    @param varidp Pointer to location for the returned variable ID.
164 
165    @return ::NC_NOERR No error.
166    @return ::NC_EBADID Bad ncid.
167    @return ::NC_ENOTINDEFINE Not in define mode.
168    @return ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 netcdf-4 file.
169    @return ::NC_EMAXVARS NC_MAX_VARS exceeded [Not enforced after 4.5.0]
170    @return ::NC_EBADTYPE Bad type.
171    @return ::NC_EINVAL Invalid input.
172    @return ::NC_ENAMEINUSE Name already in use.
173    @return ::NC_EPERM Attempt to create object in read-only file.
174 
175    @section nc_def_var_example Example
176 
177    Here is an example using nc_def_var to create a variable named rh of
178    type double with three dimensions, time, lat, and lon in a new netCDF
179    dataset named foo.nc:
180 
181    @code
182    #include <netcdf.h>
183    ...
184    int  status;
185    int  ncid;
186    int  lat_dim, lon_dim, time_dim;
187    int  rh_id;
188    int  rh_dimids[3];
189    ...
190    status = nc_create("foo.nc", NC_NOCLOBBER, &ncid);
191    if (status != NC_NOERR) handle_error(status);
192    ...
193 
194    status = nc_def_dim(ncid, "lat", 5L, &lat_dim);
195    if (status != NC_NOERR) handle_error(status);
196    status = nc_def_dim(ncid, "lon", 10L, &lon_dim);
197    if (status != NC_NOERR) handle_error(status);
198    status = nc_def_dim(ncid, "time", NC_UNLIMITED, &time_dim);
199    if (status != NC_NOERR) handle_error(status);
200    ...
201 
202    rh_dimids[0] = time_dim;
203    rh_dimids[1] = lat_dim;
204    rh_dimids[2] = lon_dim;
205    status = nc_def_var (ncid, "rh", NC_DOUBLE, 3, rh_dimids, &rh_id);
206    if (status != NC_NOERR) handle_error(status);
207    @endcode
208 
209    @author Glenn Davis, Ed Hartnett, Dennis Heimbigner
210 */
211 int
nc_def_var(int ncid,const char * name,nc_type xtype,int ndims,const int * dimidsp,int * varidp)212 nc_def_var(int ncid, const char *name, nc_type xtype,
213            int ndims,  const int *dimidsp, int *varidp)
214 {
215     NC* ncp;
216     int stat = NC_NOERR;
217 
218     if ((stat = NC_check_id(ncid, &ncp)))
219         return stat;
220     TRACE(nc_def_var);
221     return ncp->dispatch->def_var(ncid, name, xtype, ndims,
222                                   dimidsp, varidp);
223 }
224 
225 /**
226    Set the fill value for a variable.
227 
228    @note For netCDF classic, 64-bit offset, and CDF5 formats, it is
229    allowed (but not good practice) to set the fill value after data
230    have been written to the variable. In this case, unless the
231    variable has been completely specified (without gaps in the data),
232    any existing filled values will not be recognized as fill values by
233    applications reading the data. Best practice is to set the fill
234    value after the variable has been defined, but before any data have
235    been written to that variable. In NetCDF-4 files, this is enforced
236    by the HDF5 library. For netCDF-4 files, an error is returned if
237    the user attempts to set the fill value after writing data to the
238    variable.
239 
240    @param ncid NetCDF ID, from a previous call to nc_open() or
241    nc_create().
242    @param varid Variable ID.
243    @param no_fill Set to ::NC_NOFILL to turn off fill mode for this
244    variable. Set to ::NC_FILL (the default) to turn on fill mode for
245    the variable.
246    @param fill_value the fill value to be used for this variable. Must
247    be the same type as the variable. This must point to enough free
248    memory to hold one element of the data type of the variable. (For
249    example, an ::NC_INT will require 4 bytes for it's fill value,
250    which is also an ::NC_INT.)
251 
252    @return ::NC_NOERR No error.
253    @return ::NC_EBADID Bad ID.
254    @return ::NC_ENOTINDEFINE Not in define mode.  This is returned for
255    netCDF classic, 64-bit offset, or 64-bit data files, or for
256    netCDF-4 files, when they were created with ::NC_CLASSIC_MODEL flag by
257    nc_creae().
258    @return ::NC_EPERM Attempt to create object in read-only file.
259    @return ::NC_ELATEDEF (NetCDF-4 only). Returned when user attempts
260    to set fill value after data are written.
261    @return ::NC_EGLOBAL Attempt to set fill value on NC_GLOBAL.
262 
263    @section nc_def_var_fill_example Example
264 
265    In this example from libsrc4/tst_vars.c, a variable is defined, and
266    the fill mode turned off. Then nc_inq_fill() is used to check that
267    the setting is correct. Then some data are written to the
268    variable. Since the data that are written do not cover the full
269    extent of the variable, the missing values will just be random. If
270    fill value mode was turned on, the missing values would get the
271    fill value.
272 
273    @code
274    #define DIM7_LEN 2
275    #define DIM7_NAME "dim_7_from_Indiana"
276    #define VAR7_NAME "var_7_from_Idaho"
277    #define NDIMS 1
278    int dimids[NDIMS];
279    size_t index[NDIMS];
280    int varid;
281    int no_fill;
282    unsigned short ushort_data = 42, ushort_data_in, fill_value_in;
283 
284    if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
285    if (nc_def_dim(ncid, DIM7_NAME, DIM7_LEN, &dimids[0])) ERR;
286    if (nc_def_var(ncid, VAR7_NAME, NC_USHORT, NDIMS, dimids,
287    &varid)) ERR;
288    if (nc_def_var_fill(ncid, varid, 1, NULL)) ERR;
289 
290    if (nc_inq_var_fill(ncid, varid, &no_fill, &fill_value_in)) ERR;
291    if (!no_fill) ERR;
292 
293    index[0] = 1;
294    if (nc_put_var1_ushort(ncid, varid, index, &ushort_data)) ERR;
295 
296    index[0] = 0;
297    if (nc_get_var1_ushort(ncid, varid, index, &ushort_data_in)) ERR;
298 
299    if (nc_close(ncid)) ERR;
300    @endcode
301    @author Glenn Davis, Ed Hartnett, Dennis Heimbigner
302 */
303 int
nc_def_var_fill(int ncid,int varid,int no_fill,const void * fill_value)304 nc_def_var_fill(int ncid, int varid, int no_fill, const void *fill_value)
305 {
306     NC* ncp;
307     int stat = NC_check_id(ncid,&ncp);
308     if(stat != NC_NOERR) return stat;
309 
310     /* Using NC_GLOBAL is illegal, as this API has no provision for
311      * specifying the type of the fillvalue, it must of necessity be
312      * using the type of the variable to interpret the bytes of the
313      * fill_value argument. */
314     if (varid == NC_GLOBAL) return NC_EGLOBAL;
315 
316     return ncp->dispatch->def_var_fill(ncid,varid,no_fill,fill_value);
317 }
318 
319 /**
320    Set the zlib compression settings for a netCDF-4/HDF5 variable.
321 
322    This function must be called after nc_def_var and before nc_enddef
323    or any functions which writes data to the file.
324 
325    Deflation and shuffline require chunked data. If this function is
326    called on a variable with contiguous data, then the data is changed
327    to chunked data, with default chunksizes. Use nc_def_var_chunking()
328    to tune performance with user-defined chunksizes.
329 
330    If this function is called on a scalar variable, ::NC_EINVAL is
331    returned. Only chunked variables may use filters.
332 
333    If this function is called on a variable which already has szip
334    compression turned on, ::NC_EINVAL is returned.
335 
336    @note Parallel I/O reads work with compressed data. Parallel I/O
337    writes work with compressed data in netcdf-c-4.7.4 and later
338    releases, using hdf5-1.10.3 and later releases. Using the zlib,
339    shuffle (or any other) filter requires that collective access be
340    used with the variable. Turning on deflate and/or shuffle for a
341    variable in a file opened for parallel I/O will automatically
342    switch the access for that variable to collective access.
343 
344    @param ncid NetCDF or group ID, from a previous call to nc_open(),
345    nc_create(), nc_def_grp(), or associated inquiry functions such as
346    nc_inq_ncid().
347    @param varid Variable ID
348    @param shuffle True to turn on the shuffle filter. The shuffle
349    filter can assist with the compression of data by changing the byte
350    order in the data stream. It makes no sense to use the shuffle
351    filter without setting a deflate level.
352    @param deflate True to turn on deflation for this variable.
353    @param deflate_level A number between 0 (no compression) and 9
354    (maximum compression).
355 
356    @return ::NC_NOERR No error.
357    @return ::NC_EBADID Bad ncid.
358    @return ::NC_ENOTVAR Invalid variable ID.
359    @return ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is
360    not netCDF-4/HDF5.
361    @return ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3
362    netcdf-4 file.
363    @return ::NC_ELATEDEF Too late to change settings for this variable.
364    @return ::NC_ENOTINDEFINE Not in define mode.
365    @return ::NC_EPERM File is read only.
366    @return ::NC_ESTRICTNC3 Attempting to create netCDF-4 type var in
367    classic model file
368    @return ::NC_EHDFERR Error returned by HDF5 layer.
369    @return ::NC_EINVAL Invalid input. Deflate can't be set unless
370    variable storage is NC_CHUNK.
371 
372    @section nc_def_var_deflate_example Example
373 
374    Here is an example from /examples/C/simple_xy_nc4_wr.c using
375    nc_def_var_deflate to create a variable and then turn on the shuffle
376    filter and compression.
377 
378    @code
379    #include <netcdf.h>
380    #define NDIMS 2
381    #define NX 6
382    #define NY 12
383 
384    int ncid, x_dimid, y_dimid, varid;
385    int dimids[NDIMS];
386    int shuffle, deflate, deflate_level;
387    int data_out[NX][NY];
388    int x, y, retval;
389 
390    shuffle = NC_SHUFFLE;
391    deflate = 1;
392    deflate_level = 1;
393    ...
394    if ((retval = nc_create(FILE_NAME, NC_NETCDF4, &ncid)))
395    ERR(retval);
396 
397    if ((retval = nc_def_dim(ncid, "x", NX, &x_dimid)))
398    ERR(retval);
399    if ((retval = nc_def_dim(ncid, "y", NY, &y_dimid)))
400    ERR(retval);
401 
402    dimids[0] = x_dimid;
403    dimids[1] = y_dimid;
404 
405    if ((retval = nc_def_var(ncid, "data", NC_INT, NDIMS,
406    dimids, &varid)))
407    ERR(retval);
408 
409    ...
410 
411    if ((retval = nc_def_var_deflate(ncid, varid, shuffle, deflate,
412    deflate_level)))
413    ERR(retval);
414    ...
415    @endcode
416    @author Ed Hartnett, Dennis Heimbigner
417 */
418 int
nc_def_var_deflate(int ncid,int varid,int shuffle,int deflate,int deflate_level)419 nc_def_var_deflate(int ncid, int varid, int shuffle, int deflate, int deflate_level)
420 {
421     NC* ncp;
422     int stat = NC_check_id(ncid,&ncp);
423     if(stat != NC_NOERR) return stat;
424     return ncp->dispatch->def_var_deflate(ncid,varid,shuffle,deflate,deflate_level);
425 }
426 
427 /**
428    Set checksum for a var.
429 
430    This function must be called after nc_def_var and before nc_enddef
431    or any functions which writes data to the file.
432 
433    Checksums require chunked data. If this function is called on a
434    variable with contiguous data, then the data is changed to chunked
435    data, with default chunksizes. Use nc_def_var_chunking() to tune
436    performance with user-defined chunksizes.
437 
438    @note Parallel I/O reads work with fletcher32 encoded
439    data. Parallel I/O writes work with fletcher32 in netcdf-c-4.7.4
440    and later releases, using hdf5-1.10.2 and later releases. Using the
441    fletcher32 (or any) filter requires that collective access be used
442    with the variable. Turning on fletcher32 for a variable in a file
443    opened for parallel I/O will automatically switch the access for
444    that variable to collective access.
445 
446    @param ncid NetCDF or group ID, from a previous call to nc_open(),
447    nc_create(), nc_def_grp(), or associated inquiry functions such as
448    nc_inq_ncid().
449    @param varid Variable ID
450    @param fletcher32 True to turn on Fletcher32 checksums for this
451    variable.
452 
453    @return ::NC_NOERR No error.
454    @return ::NC_EBADID Bad ncid.
455    @return ::NC_ENOTVAR Invalid variable ID.
456    @return ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is
457    not netCDF-4/HDF5.
458    @return ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3
459    netcdf-4 file.
460    @return ::NC_ELATEDEF Too late to change settings for this variable.
461    @return ::NC_EINVAL Invalid input
462    @author Ed Hartnett, Dennis Heimbigner
463 */
464 int
nc_def_var_fletcher32(int ncid,int varid,int fletcher32)465 nc_def_var_fletcher32(int ncid, int varid, int fletcher32)
466 {
467     NC* ncp;
468     int stat = NC_check_id(ncid,&ncp);
469     if(stat != NC_NOERR) return stat;
470     return ncp->dispatch->def_var_fletcher32(ncid,varid,fletcher32);
471 }
472 
473 /**
474    Define storage and, if chunked storage is used, chunking parameters
475    for a variable
476 
477    The storage may be set to NC_CONTIGUOUS, NC_COMPACT, or NC_CHUNKED.
478 
479    Contiguous storage means the variable is stored as one block of
480    data in the file. This is the default storage.
481 
482    Compact storage means the variable is stored in the header record
483    of the file. This can have large performance benefits on HPC system
484    running many processors. Compact storage is only available for
485    variables whose data are 64 KB or less. Attempting to turn on
486    compact storage for a variable that is too large will result in the
487    ::NC_EVARSIZE error.
488 
489    Chunked storage means the data are stored as chunks, of
490    user-configurable size. Chunked storage is required for variable
491    with one or more unlimted dimensions, or variable which use
492    compression, or any other filter.
493 
494    The total size of a chunk must be less than 4 GiB. That is, the
495    product of all chunksizes and the size of the data (or the size of
496    nc_vlen_t for VLEN types) must be less than 4 GiB.
497 
498    This function may only be called after the variable is defined, but
499    before nc_enddef is called. Once the chunking parameters are set for a
500    variable, they cannot be changed.
501 
502    @note Scalar variables may have a storage of NC_CONTIGUOUS or
503    NC_COMPACT. Attempts to set chunking on a scalare variable will
504    cause ::NC_EINVEL to be returned. Only non-scalar variables can
505    have chunking.
506 
507    @param ncid NetCDF ID, from a previous call to nc_open() or
508    nc_create().
509    @param varid Variable ID.
510    @param storage If ::NC_CONTIGUOUS or ::NC_COMPACT, then contiguous
511    or compact storage is used for this variable. Variables with one or
512    more unlimited dimensions cannot use contiguous or compact
513    storage. If contiguous or compact storage is turned on, the
514    chunksizes parameter is ignored. If ::NC_CHUNKED, then chunked
515    storage is used for this variable. Chunk sizes may be specified
516    with the chunksizes parameter or default sizes will be used if that
517    parameter is NULL.
518    @param chunksizesp A pointer to an array list of chunk sizes. The
519    array must have one chunksize for each dimension of the variable. If
520    ::NC_CONTIGUOUS storage is set, then the chunksizes parameter is
521    ignored. Ignored if NULL.
522 
523    @return ::NC_NOERR No error.
524    @return ::NC_EBADID Bad ID.
525    @return ::NC_ENOTNC4 Not a netCDF-4 file.
526    @return ::NC_ELATEDEF This variable has already been the subject of
527    a nc_enddef call.  In netCDF-4 files nc_enddef will be called
528    automatically for any data read or write. Once nc_enddef has been
529    called after the nc_def_var call for a variable, it is impossible
530    to set the chunking for that variable.
531    @return ::NC_ENOTINDEFINE Not in define mode.  This is returned for
532    netCDF classic or 64-bit offset files, or for netCDF-4 files, when
533    they wwere created with ::NC_CLASSIC_MODEL flag by nc_create().
534    @return ::NC_EPERM Attempt to create object in read-only file.
535    @return ::NC_EBADCHUNK Returns if the chunk size specified for a
536    variable is larger than the length of the dimensions associated with
537    variable.
538    @return ::NC_EVARSIZE Compact storage attempted for variable bigger
539    than 64 KB.
540    @return ::NC_EINVAL Attempt to set contiguous or compact storage
541    for var with one or more unlimited dimensions, or chunking for a
542    scalar var.
543 
544    @section nc_def_var_chunking_example Example
545 
546    In this example from libsrc4/tst_vars2.c, chunksizes are set with
547    nc_var_def_chunking, and checked with nc_var_inq_chunking.
548 
549    @code
550    printf("**** testing chunking...");
551    {
552    #define NDIMS5 1
553    #define DIM5_NAME "D5"
554    #define VAR_NAME5 "V5"
555    #define DIM5_LEN 1000
556 
557    int dimids[NDIMS5], dimids_in[NDIMS5];
558    int varid;
559    int ndims, nvars, natts, unlimdimid;
560    nc_type xtype_in;
561    char name_in[NC_MAX_NAME + 1];
562    int data[DIM5_LEN], data_in[DIM5_LEN];
563    size_t chunksize[NDIMS5] = {5};
564    size_t chunksize_in[NDIMS5];
565    int storage_in;
566    int i, d;
567 
568    for (i = 0; i < DIM5_LEN; i++)
569    data[i] = i;
570 
571    if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
572    if (nc_def_dim(ncid, DIM5_NAME, DIM5_LEN, &dimids[0])) ERR;
573    if (nc_def_var(ncid, VAR_NAME5, NC_INT, NDIMS5, dimids, &varid)) ERR;
574    if (nc_def_var_chunking(ncid, varid, NC_CHUNKED, chunksize)) ERR;
575    if (nc_put_var_int(ncid, varid, data)) ERR;
576 
577    if (nc_inq_var_chunking(ncid, varid, &storage_in, chunksize_in)) ERR;
578    for (d = 0; d < NDIMS5; d++)
579    if (chunksize[d] != chunksize_in[d]) ERR;
580    if (storage_in != NC_CHUNKED) ERR;
581    @endcode
582    @author Ed Hartnett, Dennis Heimbigner
583 */
584 int
nc_def_var_chunking(int ncid,int varid,int storage,const size_t * chunksizesp)585 nc_def_var_chunking(int ncid, int varid, int storage, const size_t *chunksizesp)
586 {
587     NC* ncp;
588     int stat = NC_check_id(ncid, &ncp);
589     if(stat != NC_NOERR) return stat;
590     return ncp->dispatch->def_var_chunking(ncid, varid, storage,
591                                            chunksizesp);
592 }
593 
594 /**
595    Define endianness of a variable.
596 
597    With this function the endianness (i.e. order of bits in integers) can
598    be changed on a per-variable basis. By default, the endianness is the
599    same as the default endianness of the platform. But with
600    nc_def_var_endianness the endianness can be explicitly set for a
601    variable.
602 
603    Warning: this function is only defined if the type of the variable
604    is an atomic integer or float type.
605 
606    This function may only be called after the variable is defined, but
607    before nc_enddef is called.
608 
609    @param ncid NetCDF ID, from a previous call to nc_open() or
610    nc_create().
611 
612    @param varid Variable ID.
613 
614    @param endian ::NC_ENDIAN_NATIVE to select the native endianness of
615    the platform (the default), ::NC_ENDIAN_LITTLE to use
616    little-endian, ::NC_ENDIAN_BIG to use big-endian.
617 
618    @return ::NC_NOERR No error.
619    @return ::NC_EBADID Bad ID.
620    @return ::NC_ENOTNC4 Not a netCDF-4 file.
621    @return ::NC_ELATEDEF This variable has already been the subject of a
622    nc_enddef call. In netCDF-4 files nc_enddef will be called
623    automatically for any data read or write. Once nc_enddef has been
624    called after the nc_def_var call for a variable, it is impossible to
625    set the chunking for that variable.
626    @return ::NC_ENOTINDEFINE Not in define mode. This is returned for
627    netCDF classic or 64-bit offset files, or for netCDF-4 files, when
628    they wwere created with ::NC_CLASSIC_MODEL flag by nc_create().
629    @return ::NC_EPERM Attempt to create object in read-only file.
630 
631    @section nc_def_var_endian_example Example
632 
633    In this example from libsrc4/tst_vars2.c, a variable is created, and
634    the endianness set to ::NC_ENDIAN_BIG.
635 
636    @code
637    #define NDIMS4 1
638    #define DIM4_NAME "Joe"
639    #define VAR_NAME4 "Ed"
640    #define DIM4_LEN 10
641    {
642    int dimids[NDIMS4], dimids_in[NDIMS4];
643    int varid;
644    int ndims, nvars, natts, unlimdimid;
645    nc_type xtype_in;
646    char name_in[NC_MAX_NAME + 1];
647    int data[DIM4_LEN], data_in[DIM4_LEN];
648    int endian_in;
649    int i;
650 
651    for (i = 0; i < DIM4_LEN; i++)
652    data[i] = i;
653 
654    if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
655    if (nc_def_dim(ncid, DIM4_NAME, DIM4_LEN, &dimids[0])) ERR;
656    if (dimids[0] != 0) ERR;
657    if (nc_def_var(ncid, VAR_NAME4, NC_INT, NDIMS4, dimids, &varid)) ERR;
658    if (nc_def_var_endian(ncid, varid, NC_ENDIAN_BIG)) ERR;
659    @endcode
660    @author Ed Hartnett
661 */
662 int
nc_def_var_endian(int ncid,int varid,int endian)663 nc_def_var_endian(int ncid, int varid, int endian)
664 {
665     NC* ncp;
666     int stat = NC_check_id(ncid,&ncp);
667     if(stat != NC_NOERR) return stat;
668     return ncp->dispatch->def_var_endian(ncid,varid,endian);
669 }
670 
671 /**
672  * Set szip compression settings on a variable. Szip is an
673  * implementation of the extended-Rice lossless compression algorithm;
674  * it is reported to provide fast and effective compression. Szip is
675  * only available to netCDF if HDF5 was built with szip support.
676  *
677  * SZIP compression cannot be applied to variables with any
678  * user-defined type.
679  *
680  * If zlib compression has already be turned on for a variable, then
681  * this function will return ::NC_EINVAL.
682  *
683  * To learn the szip settings for a variable, use nc_inq_var_szip().
684  *
685  * @note The options_mask parameter may be either NC_SZIP_EC (entropy
686  * coding) or NC_SZIP_NN (nearest neighbor):
687  * * The entropy coding method is best suited for data that has been
688  * processed. The EC method works best for small numbers.
689  * * The nearest neighbor coding method preprocesses the data then the
690  * applies EC method as above.
691  *
692  * For more information about HDF5 and szip, see
693  * https://support.hdfgroup.org/HDF5/doc/RM/RM_H5P.html#Property-SetSzip
694  * and
695  * https://support.hdfgroup.org/doc_resource/SZIP/index.html.
696  *
697  * @param ncid File ID.
698  * @param varid Variable ID.
699  * @param options_mask The options mask. Can be NC_SZIP_EC or
700  * NC_SZIP_NN.
701  * @param pixels_per_block Pixels per block. Must be even and not
702  * greater than 32, with typical values being 8, 10, 16, or 32. This
703  * parameter affects compression ratio; the more pixel values vary,
704  * the smaller this number should be to achieve better performance. If
705  * pixels_per_block is bigger than the total number of elements in a
706  * dataset chunk, ::NC_EINVAL will be returned.
707  *
708  * @returns ::NC_NOERR No error.
709  * @returns ::NC_EBADID Bad ncid.
710  * @returns ::NC_ENOTVAR Invalid variable ID.
711  * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is
712  * not netCDF-4/HDF5.
713  * @returns ::NC_ELATEDEF Too late to change settings for this variable.
714  * @returns ::NC_ENOTINDEFINE Not in define mode.
715  * @returns ::NC_EINVAL Invalid input, or zlib filter already applied
716  * to this var.
717  * @author Ed Hartnett
718  */
719 int
nc_def_var_szip(int ncid,int varid,int options_mask,int pixels_per_block)720 nc_def_var_szip(int ncid, int varid, int options_mask, int pixels_per_block)
721 {
722     int ret;
723 
724     /* This will cause H5Pset_szip to be called when the var is
725      * created. */
726     unsigned int params[2];
727     params[0] = options_mask;
728     params[1] = pixels_per_block;
729     if ((ret = nc_def_var_filter(ncid, varid, HDF5_FILTER_SZIP, 2, params)))
730         return ret;
731 
732     return NC_NOERR;
733 }
734 
735 /** @} */
736 
737 /**
738    @name Rename a Variable
739 
740    Rename a variable.
741 */
742 /** @{ */
743 
744 /**
745    Rename a variable.
746 
747    This function changes the name of a netCDF variable in an open netCDF
748    file or group. You cannot rename a variable to have the name of any existing
749    variable.
750 
751    For classic format, 64-bit offset format, and netCDF-4/HDF5 with
752    classic mode, if the new name is longer than the old name, the netCDF
753    dataset must be in define mode.
754 
755    For netCDF-4/HDF5 files, renaming the variable changes the order of
756    the variables in the file. The renamed variable becomes the last
757    variable in the file.
758 
759    @param ncid NetCDF or group ID, from a previous call to nc_open(),
760    nc_create(), nc_def_grp(), or associated inquiry functions such as
761    nc_inq_ncid().
762 
763    @param varid Variable ID
764 
765    @param name New name of the variable.
766 
767    @return ::NC_NOERR No error.
768    @return ::NC_EBADID Bad ncid.
769    @return ::NC_ENOTVAR Invalid variable ID.
770    @return ::NC_EBADNAME Bad name.
771    @return ::NC_EMAXNAME Name is too long.
772    @return ::NC_ENAMEINUSE Name in use.
773    @return ::NC_ENOMEM Out of memory.
774 
775    @section nc_rename_var_example Example
776 
777    Here is an example using nc_rename_var to rename the variable rh to
778    rel_hum in an existing netCDF dataset named foo.nc:
779 
780    @code
781    #include <netcdf.h>
782    ...
783    int  status;
784    int  ncid;
785    int  rh_id;
786    ...
787    status = nc_open("foo.nc", NC_WRITE, &ncid);
788    if (status != NC_NOERR) handle_error(status);
789    ...
790    status = nc_redef(ncid);
791    if (status != NC_NOERR) handle_error(status);
792    status = nc_inq_varid (ncid, "rh", &rh_id);
793    if (status != NC_NOERR) handle_error(status);
794    status = nc_rename_var (ncid, rh_id, "rel_hum");
795    if (status != NC_NOERR) handle_error(status);
796    status = nc_enddef(ncid);
797    if (status != NC_NOERR) handle_error(status);
798    @endcode
799    @author Glenn Davis, Ed Hartnett, Dennis Heimbigner
800 */
801 int
nc_rename_var(int ncid,int varid,const char * name)802 nc_rename_var(int ncid, int varid, const char *name)
803 {
804     NC* ncp;
805     int stat = NC_check_id(ncid, &ncp);
806     if(stat != NC_NOERR) return stat;
807     TRACE(nc_rename_var);
808     return ncp->dispatch->rename_var(ncid, varid, name);
809 }
810 /** @} */
811 
812 /**
813    @internal Does a variable have a record dimension?
814 
815    @param ncid File ID.
816    @param varid Variable ID.
817    @param nrecs Pointer that gets number of records.
818 
819    @return 0 if not a record var, 1 if it is.
820 */
821 int
NC_is_recvar(int ncid,int varid,size_t * nrecs)822 NC_is_recvar(int ncid, int varid, size_t* nrecs)
823 {
824     int status = NC_NOERR;
825     int unlimid;
826     int ndims;
827     int dimset[NC_MAX_VAR_DIMS];
828 
829     status = nc_inq_unlimdim(ncid,&unlimid);
830     if(status != NC_NOERR) return 0; /* no unlimited defined */
831     status = nc_inq_varndims(ncid,varid,&ndims);
832     if(status != NC_NOERR) return 0; /* no unlimited defined */
833     if(ndims == 0) return 0; /* scalar */
834     status = nc_inq_vardimid(ncid,varid,dimset);
835     if(status != NC_NOERR) return 0; /* no unlimited defined */
836     status = nc_inq_dim(ncid,dimset[0],NULL,nrecs);
837     if(status != NC_NOERR) return 0;
838     return (dimset[0] == unlimid ? 1: 0);
839 }
840 
841 /**
842    @internal Get the number of record dimensions for a variable and an
843    array that identifies which of a variable's dimensions are record
844    dimensions. Intended to be used instead of NC_is_recvar(), which
845    doesn't work for netCDF-4 variables which have multiple unlimited
846    dimensions or an unlimited dimension that is not the first of a
847    variable's dimensions.
848 
849    @param ncid File ID.
850    @param varid Variable ID.
851    @param nrecdimsp Pointer that gets number of record dims.
852    @param is_recdim Pointer that gets 1 if there is one or more record
853    dimensions, 0 if not.
854 
855    @return 0 if not a record var, 1 if it is.
856 
857    Example use:
858    @code
859    int nrecdims;
860    int is_recdim[NC_MAX_VAR_DIMS];
861    ...
862    status = NC_inq_recvar(ncid,varid,&nrecdims,is_recdim);
863    isrecvar = (nrecdims > 0);
864    @endcode
865 */
866 int
NC_inq_recvar(int ncid,int varid,int * nrecdimsp,int * is_recdim)867 NC_inq_recvar(int ncid, int varid, int* nrecdimsp, int *is_recdim)
868 {
869     int status = NC_NOERR;
870     int unlimid;
871     int nvardims;
872     int dimset[NC_MAX_VAR_DIMS];
873     int dim;
874     int nrecdims = 0;
875 
876     status = nc_inq_varndims(ncid,varid,&nvardims);
877     if(status != NC_NOERR) return status;
878     if(nvardims == 0) return NC_NOERR; /* scalars have no dims */
879     for(dim = 0; dim < nvardims; dim++)
880         is_recdim[dim] = 0;
881     status = nc_inq_unlimdim(ncid, &unlimid);
882     if(status != NC_NOERR) return status;
883     if(unlimid == -1) return status; /* no unlimited dims for any variables */
884 #ifdef USE_NETCDF4
885     {
886         int nunlimdims;
887         int *unlimids;
888         int recdim;
889         status = nc_inq_unlimdims(ncid, &nunlimdims, NULL); /* for group or file, not variable */
890         if(status != NC_NOERR) return status;
891         if(nunlimdims == 0) return status;
892 
893         if (!(unlimids = malloc(nunlimdims * sizeof(int))))
894             return NC_ENOMEM;
895         status = nc_inq_unlimdims(ncid, &nunlimdims, unlimids); /* for group or file, not variable */
896         if(status != NC_NOERR) {
897             free(unlimids);
898             return status;
899         }
900         status = nc_inq_vardimid(ncid, varid, dimset);
901         if(status != NC_NOERR) {
902             free(unlimids);
903             return status;
904         }
905         for (dim = 0; dim < nvardims; dim++) { /* netCDF-4 rec dims need not be first dim for a rec var */
906             for(recdim = 0; recdim < nunlimdims; recdim++) {
907                 if(dimset[dim] == unlimids[recdim]) {
908                     is_recdim[dim] = 1;
909                     nrecdims++;
910                 }
911             }
912         }
913         free(unlimids);
914     }
915 #else
916     status = nc_inq_vardimid(ncid, varid, dimset);
917     if(status != NC_NOERR) return status;
918     if(dimset[0] == unlimid) {
919         is_recdim[0] = 1;
920         nrecdims++;
921     }
922 #endif /* USE_NETCDF4 */
923     if(nrecdimsp) *nrecdimsp = nrecdims;
924     return status;
925 }
926 
927 /* Ok to use NC pointers because
928    all IOSP's will use that structure,
929    but not ok to use e.g. NC_Var pointers
930    because they may be different structure
931    entirely.
932 */
933 
934 /**
935    @internal
936    Find the length of a type. This is how much space is required by
937    the in memory to hold one element of this type.
938 
939    @param type A netCDF atomic type.
940 
941    @return Length of the type in bytes, or -1 if type not found.
942    @author Ed Hartnett
943 */
944 int
nctypelen(nc_type type)945 nctypelen(nc_type type)
946 {
947     switch(type){
948     case NC_CHAR :
949         return ((int)sizeof(char));
950     case NC_BYTE :
951         return ((int)sizeof(signed char));
952     case NC_SHORT :
953         return ((int)sizeof(short));
954     case NC_INT :
955         return ((int)sizeof(int));
956     case NC_FLOAT :
957         return ((int)sizeof(float));
958     case NC_DOUBLE :
959         return ((int)sizeof(double));
960 
961         /* These can occur in netcdf-3 code */
962     case NC_UBYTE :
963         return ((int)sizeof(unsigned char));
964     case NC_USHORT :
965         return ((int)(sizeof(unsigned short)));
966     case NC_UINT :
967         return ((int)sizeof(unsigned int));
968     case NC_INT64 :
969         return ((int)sizeof(signed long long));
970     case NC_UINT64 :
971         return ((int)sizeof(unsigned long long));
972 #ifdef USE_NETCDF4
973     case NC_STRING :
974         return ((int)sizeof(char*));
975 #endif /*USE_NETCDF4*/
976 
977     default:
978         return -1;
979     }
980 }
981 
982 /**
983     @internal
984     Find the length of a type. Redundant over nctypelen() above.
985 
986     @param xtype an nc_type.
987 
988     @author Dennis Heimbigner
989 */
990 size_t
NC_atomictypelen(nc_type xtype)991 NC_atomictypelen(nc_type xtype)
992 {
993     size_t sz = 0;
994     switch(xtype) {
995     case NC_NAT: sz = 0; break;
996     case NC_BYTE: sz = sizeof(signed char); break;
997     case NC_CHAR: sz = sizeof(char); break;
998     case NC_SHORT: sz = sizeof(short); break;
999     case NC_INT: sz = sizeof(int); break;
1000     case NC_FLOAT: sz = sizeof(float); break;
1001     case NC_DOUBLE: sz = sizeof(double); break;
1002     case NC_INT64: sz = sizeof(signed long long); break;
1003     case NC_UBYTE: sz = sizeof(unsigned char); break;
1004     case NC_USHORT: sz = sizeof(unsigned short); break;
1005     case NC_UINT: sz = sizeof(unsigned int); break;
1006     case NC_UINT64: sz = sizeof(unsigned long long); break;
1007 #ifdef USE_NETCDF4
1008     case NC_STRING: sz = sizeof(char*); break;
1009 #endif
1010     default: break;
1011     }
1012     return sz;
1013 }
1014 
1015 /**
1016     @internal
1017     Get the type name.
1018 
1019     @param xtype an nc_type.
1020 
1021     @author Dennis Heimbigner
1022 */
1023 char *
NC_atomictypename(nc_type xtype)1024 NC_atomictypename(nc_type xtype)
1025 {
1026     char* nm = NULL;
1027     switch(xtype) {
1028     case NC_NAT: nm = "undefined"; break;
1029     case NC_BYTE: nm = "byte"; break;
1030     case NC_CHAR: nm = "char"; break;
1031     case NC_SHORT: nm = "short"; break;
1032     case NC_INT: nm = "int"; break;
1033     case NC_FLOAT: nm = "float"; break;
1034     case NC_DOUBLE: nm = "double"; break;
1035     case NC_INT64: nm = "int64"; break;
1036     case NC_UBYTE: nm = "ubyte"; break;
1037     case NC_USHORT: nm = "ushort"; break;
1038     case NC_UINT: nm = "uint"; break;
1039     case NC_UINT64: nm = "uint64"; break;
1040 #ifdef USE_NETCDF4
1041     case NC_STRING: nm = "string"; break;
1042 #endif
1043     default: break;
1044     }
1045     return nm;
1046 }
1047 
1048 /**
1049    @internal
1050    Get the shape of a variable.
1051 
1052    @param ncid NetCDF ID, from a previous call to nc_open() or
1053    nc_create().
1054    @param varid Variable ID.
1055    @param ndims Number of dimensions for this var.
1056    @param shape Pointer to pre-allocated array that gets the size of
1057    each dimension.
1058 
1059    @return ::NC_NOERR No error.
1060    @return ::NC_EBADID Bad ncid.
1061    @return ::NC_ENOTVAR Bad varid.
1062 
1063    @author Dennis Heimbigner
1064 */
1065 int
NC_getshape(int ncid,int varid,int ndims,size_t * shape)1066 NC_getshape(int ncid, int varid, int ndims, size_t* shape)
1067 {
1068     int dimids[NC_MAX_VAR_DIMS];
1069     int i;
1070     int status = NC_NOERR;
1071 
1072     if ((status = nc_inq_vardimid(ncid, varid, dimids)))
1073         return status;
1074     for(i = 0; i < ndims; i++)
1075         if ((status = nc_inq_dimlen(ncid, dimids[i], &shape[i])))
1076             break;
1077 
1078     return status;
1079 }
1080 
1081 /**
1082    @internal Check the start, count, and stride parameters for gets
1083    and puts, and handle NULLs.
1084 
1085    @param ncid The file ID.
1086    @param varid The variable ID.
1087    @param start Pointer to start array. If NULL ::NC_EINVALCOORDS will
1088    be returned for non-scalar variable.
1089    @param count Pointer to pointer to count array. If *count is NULL,
1090    an array of the correct size will be allocated, and filled with
1091    counts that represent the full extent of the variable. In this
1092    case, the memory must be freed by the caller.
1093    @param stride Pointer to pointer to stride array. If NULL, stide is
1094    ignored. If *stride is NULL an array of the correct size will be
1095    allocated, and filled with ones. In this case, the memory must be
1096    freed by the caller.
1097 
1098    @return ::NC_NOERR No error.
1099    @return ::NC_EBADID Bad ncid.
1100    @return ::NC_ENOTVAR Variable not found.
1101    @return ::NC_ENOMEM Out of memory.
1102    @return ::NC_EINVALCOORDS Missing start array.
1103    @author Ed Hartnett
1104 */
1105 int
NC_check_nulls(int ncid,int varid,const size_t * start,size_t ** count,ptrdiff_t ** stride)1106 NC_check_nulls(int ncid, int varid, const size_t *start, size_t **count,
1107                ptrdiff_t **stride)
1108 {
1109     int varndims;
1110     int stat;
1111 
1112     if ((stat = nc_inq_varndims(ncid, varid, &varndims)))
1113         return stat;
1114 
1115     /* For non-scalar vars, start is required. */
1116     if (!start && varndims)
1117         return NC_EINVALCOORDS;
1118 
1119     /* If count is NULL, assume full extent of var. */
1120     if (!*count)
1121     {
1122         if (!(*count = malloc(varndims * sizeof(size_t))))
1123             return NC_ENOMEM;
1124         if ((stat = NC_getshape(ncid, varid, varndims, *count)))
1125         {
1126             free(*count);
1127             *count = NULL;
1128             return stat;
1129         }
1130     }
1131 
1132     /* If stride is NULL, do nothing, if *stride is NULL use all
1133      * 1s. */
1134     if (stride && !*stride)
1135     {
1136         int i;
1137 
1138         if (!(*stride = malloc(varndims * sizeof(ptrdiff_t))))
1139             return NC_ENOMEM;
1140         for (i = 0; i < varndims; i++)
1141             (*stride)[i] = 1;
1142     }
1143 
1144     return NC_NOERR;
1145 }
1146 
1147 /**
1148    @name Free String Resources
1149 
1150    Use this functions to free resources associated with ::NC_STRING
1151    data.
1152 */
1153 /*! @{ */
1154 /**
1155    Free string space allocated by the library.
1156 
1157    When you read string type the library will allocate the storage
1158    space for the data. This storage space must be freed, so pass the
1159    pointer back to this function, when you're done with the data, and
1160    it will free the string memory.
1161 
1162    @param len The number of character arrays in the array.
1163    @param data The pointer to the data array.
1164 
1165    @return ::NC_NOERR No error.
1166    @author Ed Hartnett
1167 */
1168 int
nc_free_string(size_t len,char ** data)1169 nc_free_string(size_t len, char **data)
1170 {
1171     int i;
1172     for (i = 0; i < len; i++)
1173         free(data[i]);
1174     return NC_NOERR;
1175 }
1176 /** @} */
1177 
1178 /**
1179    @name Variables Chunk Caches
1180 
1181    Use these functions to change the variable chunk cache settings.
1182 */
1183 /*! @{ */
1184 /**
1185    Change the cache settings for a chunked variable. This function allows
1186    users to control the amount of memory used in the per-variable chunk
1187    cache at the HDF5 level. Changing the chunk cache only has effect
1188    until the file is closed. Once re-opened, the variable chunk cache
1189    returns to its default value.
1190 
1191    Current cache settings for each var may be obtained with
1192    nc_get_var_chunk_cache().
1193 
1194    Default values for these settings may be changed for the whole file
1195    with nc_set_chunk_cache().
1196 
1197    @param ncid NetCDF or group ID, from a previous call to nc_open(),
1198    nc_create(), nc_def_grp(), or associated inquiry functions such as
1199    nc_inq_ncid().
1200    @param varid Variable ID
1201    @param size The total size of the raw data chunk cache, in bytes.
1202    @param nelems The number of chunk slots in the raw data chunk cache.
1203    @param preemption The preemption, a value between 0 and 1 inclusive
1204    that indicates how much chunks that have been fully read are favored
1205    for preemption. A value of zero means fully read chunks are treated no
1206    differently than other chunks (the preemption is strictly LRU) while a
1207    value of one means fully read chunks are always preempted before other
1208    chunks.
1209 
1210    @return ::NC_NOERR No error.
1211    @return ::NC_EBADID Bad ncid.
1212    @return ::NC_ENOTVAR Invalid variable ID.
1213    @return ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3
1214    netcdf-4 file.
1215    @return ::NC_EINVAL Invalid input
1216 
1217    @section nc_def_var_chunk_cache_example Example
1218 
1219    In this example from nc_test4/tst_coords.c, a variable is defined, and
1220    the chunk cache settings are changed for that variable.
1221 
1222    @code
1223    printf("**** testing setting cache values for coordinate variables...");
1224    {
1225    #define RANK_1 1
1226    #define DIM0_NAME "d0"
1227    #define CACHE_SIZE 1000000
1228    #define CACHE_NELEMS 1009
1229    #define CACHE_PREEMPTION .90
1230 
1231    int ncid, dimid, varid;
1232    char name_in[NC_MAX_NAME + 1];
1233 
1234    if (nc_create(FILE_NAME, NC_CLASSIC_MODEL|NC_NETCDF4, &ncid)) ERR;
1235    if (nc_def_dim(ncid, DIM0_NAME, NC_UNLIMITED, &dimid)) ERR;
1236    if (nc_def_var(ncid, DIM0_NAME, NC_DOUBLE, 1, &dimid, &varid)) ERR;
1237    if (nc_set_var_chunk_cache(ncid, varid, CACHE_SIZE, CACHE_NELEMS, CACHE_PREEMPTION)) ERR;
1238    if (nc_close(ncid)) ERR;
1239 
1240    ...
1241    }
1242    SUMMARIZE_ERR;
1243    @endcode
1244    @author Ed Hartnett
1245 */
1246 int
nc_set_var_chunk_cache(int ncid,int varid,size_t size,size_t nelems,float preemption)1247 nc_set_var_chunk_cache(int ncid, int varid, size_t size, size_t nelems,
1248                        float preemption)
1249 {
1250     NC* ncp;
1251     int stat = NC_check_id(ncid, &ncp);
1252     if(stat != NC_NOERR) return stat;
1253     return ncp->dispatch->set_var_chunk_cache(ncid, varid, size,
1254                                               nelems, preemption);
1255 }
1256 
1257 /**
1258    Get the per-variable chunk cache settings from the HDF5
1259    layer. These settings may be changed with nc_set_var_chunk_cache().
1260 
1261    See nc_set_chunk_cache() for a full discussion of these settings.
1262 
1263    @param ncid NetCDF or group ID, from a previous call to nc_open(),
1264    nc_create(), nc_def_grp(), or associated inquiry functions such as
1265    nc_inq_ncid().
1266    @param varid Variable ID
1267    @param sizep The total size of the raw data chunk cache, in bytes,
1268    will be put here. @ref ignored_if_null.
1269    @param nelemsp The number of chunk slots in the raw data chunk
1270    cache hash table will be put here. @ref ignored_if_null.
1271    @param preemptionp The preemption will be put here. The preemtion
1272    value is between 0 and 1 inclusive and indicates how much chunks
1273    that have been fully read are favored for preemption. A value of
1274    zero means fully read chunks are treated no differently than other
1275    chunks (the preemption is strictly LRU) while a value of one means
1276    fully read chunks are always preempted before other chunks. @ref
1277    ignored_if_null.
1278 
1279    @return ::NC_NOERR No error.
1280    @return ::NC_EBADID Bad ncid.
1281    @return ::NC_ENOTVAR Invalid variable ID.
1282    @return ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3
1283    netcdf-4 file.
1284    @return ::NC_EINVAL Invalid input
1285    @author Ed Hartnett
1286 */
1287 int
nc_get_var_chunk_cache(int ncid,int varid,size_t * sizep,size_t * nelemsp,float * preemptionp)1288 nc_get_var_chunk_cache(int ncid, int varid, size_t *sizep, size_t *nelemsp,
1289                        float *preemptionp)
1290 {
1291     NC* ncp;
1292     int stat = NC_check_id(ncid, &ncp);
1293     if(stat != NC_NOERR) return stat;
1294     return ncp->dispatch->get_var_chunk_cache(ncid, varid, sizep,
1295                                               nelemsp, preemptionp);
1296 }
1297 /** @} */
1298 /** @} */
1299