NetCDF  4.3.2
 All Data Structures Files Functions Variables Typedefs Macros Modules Pages
nccopy.c
1 /*********************************************************************
2  * Copyright 2010, University Corporation for Atmospheric Research
3  * See netcdf/README file for copying and redistribution conditions.
4  * Thanks to Philippe Poilbarbe and Antonio S. CofiƱo for
5  * compression additions.
6  * $Id: nccopy.c 400 2010-08-27 21:02:52Z russ $
7  *********************************************************************/
8 
9 #include "config.h" /* for USE_NETCDF4 macro */
10 #include <stdlib.h>
11 #ifdef HAVE_GETOPT_H
12 #include <getopt.h>
13 #endif
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17 #include <string.h>
18 #include <netcdf.h>
19 #include "nciter.h"
20 #include "utils.h"
21 #include "chunkspec.h"
22 #include "dimmap.h"
23 #include "nccomps.h"
24 
25 #ifdef _MSC_VER
26 #include "XGetopt.h"
27 #define snprintf _snprintf
28 int opterr;
29 int optind;
30 #endif
31 
32 /* default bytes of memory we are willing to allocate for variable
33  * values during copy */
34 #define COPY_BUFFER_SIZE (5000000)
35 #define COPY_CHUNKCACHE_PREEMPTION (1.0f) /* for copying, can eject fully read chunks */
36 #define SAME_AS_INPUT (-1) /* default, if kind not specified */
37 #define CHUNK_THRESHOLD (8192) /* non-record variables with fewer bytes don't get chunked */
38 
39 #ifndef USE_NETCDF4
40 #define NC_CLASSIC_MODEL 0x0100 /* Enforce classic model if netCDF-4 not available. */
41 #endif
42 
43 /* Global variables for command-line requests */
44 char *progname; /* for error messages */
45 static int option_kind = SAME_AS_INPUT;
46 static int option_deflate_level = -1; /* default, compress output only if input compressed */
47 static int option_shuffle_vars = NC_NOSHUFFLE; /* default, no shuffling on compression */
48 static int option_fix_unlimdims = 0; /* default, preserve unlimited dimensions */
49 static char* option_chunkspec = 0; /* default, no chunk specification */
50 static size_t option_copy_buffer_size = COPY_BUFFER_SIZE;
51 static size_t option_chunk_cache_size = CHUNK_CACHE_SIZE; /* default from config.h */
52 static size_t option_chunk_cache_nelems = CHUNK_CACHE_NELEMS; /* default from config.h */
53 static int option_read_diskless = 0; /* default, don't read input into memory on open */
54 static int option_write_diskless = 0; /* default, don't write output to diskless file */
55 static int option_min_chunk_bytes = CHUNK_THRESHOLD; /* default, don't chunk variable if prod of
56  * chunksizes of its dimensions is smaller
57  * than this */
58 static int option_nlgrps = 0; /* Number of groups specified with -g
59  * option on command line */
60 static char** option_lgrps = 0; /* list of group names specified with -g
61  * option on command line */
62 static idnode_t* option_grpids = 0; /* list of grpids matching list specified with -g option */
63 static bool_t option_grpstruct = false; /* if -g set, copy structure for non-selected groups */
64 static int option_nlvars = 0; /* Number of variables specified with -v * option on command line */
65 static char** option_lvars = 0; /* list of variable names specified with -v
66  * option on command line */
67 static bool_t option_varstruct = false; /* if -v set, copy structure for non-selected vars */
68 static int option_compute_chunkcaches = 0; /* default, don't try still flaky estimate of
69  * chunk cache for each variable */
70 
71 /* get group id in output corresponding to group igrp in input,
72  * given parent group id (or root group id) parid in output. */
73 static int
74 get_grpid(int igrp, int parid, int *ogrpp) {
75  int stat = NC_NOERR;
76  int ogid = parid; /* like igrp but in output file */
77 #ifdef USE_NETCDF4
78  int inparid;
79 
80  /* if not root group, get corresponding output groupid from group name */
81  stat = nc_inq_grp_parent(igrp, &inparid);
82  if(stat == NC_NOERR) { /* not root group */
83  char grpname[NC_MAX_NAME + 1];
84  NC_CHECK(nc_inq_grpname(igrp, grpname));
85  NC_CHECK(nc_inq_grp_ncid(parid, grpname, &ogid));
86  } else if(stat == NC_ENOGRP) { /* root group */
87  stat = NC_NOERR;
88  } else {
89  NC_CHECK(stat);
90  }
91 #endif /* USE_NETCDF4 */
92  *ogrpp = ogid;
93  return stat;
94 }
95 
96 /* Return size in bytes of a variable value */
97 static size_t
98 val_size(int grpid, int varid) {
99  nc_type vartype;
100  size_t value_size;
101  NC_CHECK(nc_inq_vartype(grpid, varid, &vartype));
102  NC_CHECK(nc_inq_type(grpid, vartype, NULL, &value_size));
103  return value_size;
104 }
105 
106 #ifdef USE_NETCDF4
107 /* Get parent id needed to define a new group from its full name in an
108  * open file identified by ncid. Assumes all intermediate groups are
109  * already defined. */
110 static int
111 nc_inq_parid(int ncid, const char *fullname, int *locidp) {
112  char *parent = strdup(fullname);
113  char *slash = "/"; /* groupname separator */
114  char *last_slash;
115  if(parent == NULL) {
116  return NC_ENOMEM; /* exits */
117  }
118  last_slash = strrchr(parent, '/');
119  if(last_slash == parent || last_slash == NULL) { /* parent is root */
120  free(parent);
121  parent = strdup(slash);
122  } else {
123  *last_slash = '\0'; /* truncate to get parent name */
124  }
125  NC_CHECK(nc_inq_grp_full_ncid(ncid, parent, locidp));
126  free(parent);
127  return NC_NOERR;
128 }
129 
130 /* Return size of chunk in bytes for a variable varid in a group igrp, or 0 if
131  * layout is contiguous */
132 static int
133 inq_var_chunksize(int igrp, int varid, size_t* chunksizep) {
134  int stat = NC_NOERR;
135  int ndims;
136  size_t *chunksizes;
137  int dim;
138  int contig = 1;
139  nc_type vartype;
140  size_t value_size;
141  size_t prod;
142 
143  NC_CHECK(nc_inq_vartype(igrp, varid, &vartype));
144  /* from type, get size in memory needed for each value */
145  NC_CHECK(nc_inq_type(igrp, vartype, NULL, &value_size));
146  prod = value_size;
147  NC_CHECK(nc_inq_varndims(igrp, varid, &ndims));
148  chunksizes = (size_t *) emalloc((ndims + 1) * sizeof(size_t));
149  if(ndims > 0) {
150  NC_CHECK(nc_inq_var_chunking(igrp, varid, &contig, NULL));
151  }
152  if(contig == 1) {
153  *chunksizep = 0;
154  } else {
155  NC_CHECK(nc_inq_var_chunking(igrp, varid, &contig, chunksizes));
156  for(dim = 0; dim < ndims; dim++) {
157  prod *= chunksizes[dim];
158  }
159  *chunksizep = prod;
160  }
161  free(chunksizes);
162  return stat;
163 }
164 
165 /* Return estimated number of elems required in chunk cache and
166  * estimated size of chunk cache adequate to efficiently copy input
167  * variable ivarid to output variable ovarid, which may have different
168  * chunk size and shape */
169 static int
170 inq_var_chunking_params(int igrp, int ivarid, int ogrp, int ovarid,
171  size_t* chunkcache_sizep,
172  size_t *chunkcache_nelemsp,
173  float * chunkcache_preemptionp)
174 {
175  int stat = NC_NOERR;
176  int ndims;
177  size_t *ichunksizes, *ochunksizes;
178  int dim;
179  int icontig = 1, ocontig = 1;
180  nc_type vartype;
181  size_t value_size;
182  size_t prod, iprod, oprod;
183  size_t nelems;
184  *chunkcache_nelemsp = CHUNK_CACHE_NELEMS;
185  *chunkcache_sizep = CHUNK_CACHE_SIZE;
186  *chunkcache_preemptionp = COPY_CHUNKCACHE_PREEMPTION;
187 
188  NC_CHECK(nc_inq_varndims(igrp, ivarid, &ndims));
189  if(ndims > 0) {
190  NC_CHECK(nc_inq_var_chunking(igrp, ivarid, &icontig, NULL));
191  NC_CHECK(nc_inq_var_chunking(ogrp, ovarid, &ocontig, NULL));
192  }
193  if(icontig == 1 && ocontig == 1) { /* no chunking in input or output */
194  *chunkcache_nelemsp = 0;
195  *chunkcache_sizep = 0;
196  *chunkcache_preemptionp = 0;
197  return stat;
198  }
199 
200  NC_CHECK(nc_inq_vartype(igrp, ivarid, &vartype));
201  NC_CHECK(nc_inq_type(igrp, vartype, NULL, &value_size));
202  iprod = value_size;
203 
204  if(icontig == 0 && ocontig == 1) { /* chunking only in input */
205  *chunkcache_nelemsp = 1; /* read one input chunk at a time */
206  *chunkcache_sizep = iprod;
207  *chunkcache_preemptionp = 1.0f;
208  return stat;
209  }
210 
211  ichunksizes = (size_t *) emalloc((ndims + 1) * sizeof(size_t));
212  if(icontig == 1) { /* if input contiguous, treat as if chunked on
213  * first dimension */
214  ichunksizes[0] = 1;
215  for(dim = 1; dim < ndims; dim++) {
216  ichunksizes[dim] = dim;
217  }
218  } else {
219  NC_CHECK(nc_inq_var_chunking(igrp, ivarid, &icontig, ichunksizes));
220  }
221 
222  /* now can assume chunking in both input and output */
223  ochunksizes = (size_t *) emalloc((ndims + 1) * sizeof(size_t));
224  NC_CHECK(nc_inq_var_chunking(ogrp, ovarid, &ocontig, ochunksizes));
225 
226  nelems = 1;
227  oprod = value_size;
228  for(dim = 0; dim < ndims; dim++) {
229  nelems += 1 + (ichunksizes[dim] - 1) / ochunksizes[dim];
230  iprod *= ichunksizes[dim];
231  oprod *= ochunksizes[dim];
232  }
233  prod = iprod + oprod * (nelems - 1);
234  *chunkcache_nelemsp = nelems;
235  *chunkcache_sizep = prod;
236  free(ichunksizes);
237  free(ochunksizes);
238  return stat;
239 }
240 
241 /* Forward declaration, because copy_type, copy_vlen_type call each other */
242 static int copy_type(int igrp, nc_type typeid, int ogrp);
243 
244 /*
245  * copy a user-defined variable length type in the group igrp to the
246  * group ogrp
247  */
248 static int
249 copy_vlen_type(int igrp, nc_type itype, int ogrp)
250 {
251  int stat = NC_NOERR;
252  nc_type ibasetype;
253  nc_type obasetype; /* base type in target group */
254  char name[NC_MAX_NAME];
255  size_t size;
256  char basename[NC_MAX_NAME];
257  size_t basesize;
258  nc_type vlen_type;
259 
260  NC_CHECK(nc_inq_vlen(igrp, itype, name, &size, &ibasetype));
261  /* to get base type id in target group, use name of base type in
262  * source group */
263  NC_CHECK(nc_inq_type(igrp, ibasetype, basename, &basesize));
264  stat = nc_inq_typeid(ogrp, basename, &obasetype);
265  /* if no such type, create it now */
266  if(stat == NC_EBADTYPE) {
267  NC_CHECK(copy_type(igrp, ibasetype, ogrp));
268  stat = nc_inq_typeid(ogrp, basename, &obasetype);
269  }
270  NC_CHECK(stat);
271 
272  /* Now we know base type exists in output and we know its type id */
273  NC_CHECK(nc_def_vlen(ogrp, name, obasetype, &vlen_type));
274 
275  return stat;
276 }
277 
278 /*
279  * copy a user-defined opaque type in the group igrp to the group ogrp
280  */
281 static int
282 copy_opaque_type(int igrp, nc_type itype, int ogrp)
283 {
284  int stat = NC_NOERR;
285  nc_type otype;
286  char name[NC_MAX_NAME];
287  size_t size;
288 
289  NC_CHECK(nc_inq_opaque(igrp, itype, name, &size));
290  NC_CHECK(nc_def_opaque(ogrp, size, name, &otype));
291 
292  return stat;
293 }
294 
295 /*
296  * copy a user-defined enum type in the group igrp to the group ogrp
297  */
298 static int
299 copy_enum_type(int igrp, nc_type itype, int ogrp)
300 {
301  int stat = NC_NOERR;
302  nc_type otype;
303  nc_type basetype;
304  size_t basesize;
305  size_t nmembers;
306  char name[NC_MAX_NAME];
307  int i;
308 
309  NC_CHECK(nc_inq_enum(igrp, itype, name, &basetype, &basesize, &nmembers));
310  NC_CHECK(nc_def_enum(ogrp, basetype, name, &otype));
311  for(i = 0; i < nmembers; i++) { /* insert enum members */
312  char ename[NC_MAX_NAME];
313  long long val; /* large enough to hold any integer type */
314  NC_CHECK(nc_inq_enum_member(igrp, itype, i, ename, &val));
315  NC_CHECK(nc_insert_enum(ogrp, otype, ename, &val));
316  }
317  return stat;
318 }
319 
320 /*
321  * copy a user-defined compound type in the group igrp to the group ogrp
322  */
323 static int
324 copy_compound_type(int igrp, nc_type itype, int ogrp)
325 {
326  int stat = NC_NOERR;
327  char name[NC_MAX_NAME];
328  size_t size;
329  size_t nfields;
330  nc_type otype;
331  int fid;
332 
333  NC_CHECK(nc_inq_compound(igrp, itype, name, &size, &nfields));
334  NC_CHECK(nc_def_compound(ogrp, size, name, &otype));
335 
336  for (fid = 0; fid < nfields; fid++) {
337  char fname[NC_MAX_NAME];
338  char ftypename[NC_MAX_NAME];
339  size_t foff;
340  nc_type iftype, oftype;
341  int fndims;
342 
343  NC_CHECK(nc_inq_compound_field(igrp, itype, fid, fname, &foff, &iftype, &fndims, NULL));
344  /* type ids in source don't necessarily correspond to same
345  * typeids in destination, so look up destination typeid by using
346  * field type name */
347  NC_CHECK(nc_inq_type(igrp, iftype, ftypename, NULL));
348  NC_CHECK(nc_inq_typeid(ogrp, ftypename, &oftype));
349  if(fndims == 0) {
350  NC_CHECK(nc_insert_compound(ogrp, otype, fname, foff, oftype));
351  } else { /* field is array type */
352  int *fdimsizes;
353  fdimsizes = (int *) emalloc((fndims + 1) * sizeof(int));
354  stat = nc_inq_compound_field(igrp, itype, fid, NULL, NULL, NULL,
355  NULL, fdimsizes);
356  NC_CHECK(nc_insert_array_compound(ogrp, otype, fname, foff, oftype, fndims, fdimsizes));
357  free(fdimsizes);
358  }
359  }
360  return stat;
361 }
362 
363 
364 /*
365  * copy a user-defined type in the group igrp to the group ogrp
366  */
367 static int
368 copy_type(int igrp, nc_type typeid, int ogrp)
369 {
370  int stat = NC_NOERR;
371  nc_type type_class;
372 
373  NC_CHECK(nc_inq_user_type(igrp, typeid, NULL, NULL, NULL, NULL, &type_class));
374 
375  switch(type_class) {
376  case NC_VLEN:
377  NC_CHECK(copy_vlen_type(igrp, typeid, ogrp));
378  break;
379  case NC_OPAQUE:
380  NC_CHECK(copy_opaque_type(igrp, typeid, ogrp));
381  break;
382  case NC_ENUM:
383  NC_CHECK(copy_enum_type(igrp, typeid, ogrp));
384  break;
385  case NC_COMPOUND:
386  NC_CHECK(copy_compound_type(igrp, typeid, ogrp));
387  break;
388  default:
389  NC_CHECK(NC_EBADTYPE);
390  }
391  return stat;
392 }
393 
394 /* Copy a group and all its subgroups, recursively, from iroot to
395  * oroot, the ncids of input file and output file. This just creates
396  * all the groups in the destination, but doesn't copy anything that's
397  * in the groups yet. */
398 static int
399 copy_groups(int iroot, int oroot)
400 {
401  int stat = NC_NOERR;
402  int numgrps;
403  int *grpids;
404  int i;
405 
406  /* get total number of groups and their ids, including all descendants */
407  NC_CHECK(nc_inq_grps_full(iroot, &numgrps, NULL));
408  if(numgrps > 1) { /* there's always 1 root group */
409  grpids = emalloc(numgrps * sizeof(int));
410  NC_CHECK(nc_inq_grps_full(iroot, NULL, grpids));
411  /* create corresponding new groups in ogrp, except for root group */
412  for(i = 1; i < numgrps; i++) {
413  char *grpname_full;
414  char grpname[NC_MAX_NAME];
415  size_t len_name;
416  int ogid = 0, oparid = 0, iparid = 0;
417  /* get full group name of input group */
418  NC_CHECK(nc_inq_grpname(grpids[i], grpname));
419  if (option_grpstruct || group_wanted(grpids[i], option_nlgrps, option_grpids)) {
420  NC_CHECK(nc_inq_grpname_full(grpids[i], &len_name, NULL));
421  grpname_full = emalloc(len_name + 1);
422  NC_CHECK(nc_inq_grpname_full(grpids[i], &len_name, grpname_full));
423  /* Make sure, the parent group is also wanted (root group is always wanted) */
424  NC_CHECK(nc_inq_parid(iroot, grpname_full, &iparid));
425  if (!option_grpstruct && !group_wanted(iparid, option_nlgrps, option_grpids)
426  && iparid != iroot) {
427  error("ERROR: trying to copy a group but not the parent: %s", grpname_full);
428  }
429  /* get id of parent group of corresponding group in output.
430  * Note that this exists, because nc_inq_groups returned
431  * grpids in preorder, so parents are always copied before
432  * their subgroups */
433  NC_CHECK(nc_inq_parid(oroot, grpname_full, &oparid));
434  NC_CHECK(nc_inq_grpname(grpids[i], grpname));
435  /* define corresponding group in output */
436  NC_CHECK(nc_def_grp(oparid, grpname, &ogid));
437  free(grpname_full);
438  }
439  }
440  free(grpids);
441  }
442  return stat;
443 }
444 
445 /*
446  * Copy the user-defined types in this group (igrp) and all its
447  * subgroups, recursively, to corresponding group in output (ogrp)
448  */
449 static int
450 copy_types(int igrp, int ogrp)
451 {
452  int stat = NC_NOERR;
453  int ntypes;
454  nc_type *types = NULL;
455  int numgrps;
456  int *grpids = NULL;
457  int i;
458 
459  NC_CHECK(nc_inq_typeids(igrp, &ntypes, NULL));
460 
461  if(ntypes > 0) {
462  types = (nc_type *) emalloc(ntypes * sizeof(nc_type));
463  NC_CHECK(nc_inq_typeids(igrp, &ntypes, types));
464  for (i = 0; i < ntypes; i++) {
465  NC_CHECK(copy_type(igrp, types[i], ogrp));
466  }
467  free(types);
468  }
469 
470  /* Copy types from subgroups */
471  NC_CHECK(nc_inq_grps(igrp, &numgrps, NULL));
472  if(numgrps > 0) {
473  grpids = (int *)emalloc(sizeof(int) * numgrps);
474  NC_CHECK(nc_inq_grps(igrp, &numgrps, grpids));
475  for(i = 0; i < numgrps; i++) {
476  if (option_grpstruct || group_wanted(grpids[i], option_nlgrps, option_grpids)) {
477  int ogid;
478  /* get groupid in output corresponding to grpids[i] in
479  * input, given parent group (or root group) ogrp in
480  * output */
481  NC_CHECK(get_grpid(grpids[i], ogrp, &ogid));
482  NC_CHECK(copy_types(grpids[i], ogid));
483  }
484  }
485  free(grpids);
486  }
487  return stat;
488 }
489 
490 /* Copy all netCDF-4 specific variable properties such as chunking,
491  * endianness, deflation, checksumming, fill, etc. */
492 static int
493 copy_var_specials(int igrp, int varid, int ogrp, int o_varid)
494 {
495  int stat = NC_NOERR;
496  { /* handle chunking parameters */
497  int ndims;
498  NC_CHECK(nc_inq_varndims(igrp, varid, &ndims));
499  if (ndims > 0) { /* no chunking for scalar variables */
500  int contig = 0;
501  size_t *chunkp = (size_t *) emalloc(ndims * sizeof(size_t));
502  int *dimids = (int *) emalloc(ndims * sizeof(int));
503  int idim;
504  /* size of a chunk: product of dimension chunksizes and size of value */
505  size_t csprod = val_size(ogrp, o_varid);
506  int is_unlimited = 0;
507  NC_CHECK(nc_inq_var_chunking(igrp, varid, &contig, chunkp));
508  NC_CHECK(nc_inq_vardimid(igrp, varid, dimids));
509 
510  for(idim = 0; idim < ndims; idim++) {
511  int idimid = dimids[idim];
512  int odimid = dimmap_odimid(idimid);
513  size_t chunksize = chunkspec_size(idimid);
514  if(chunksize > 0) { /* found in chunkspec */
515  chunkp[idim] = chunksize;
516  }
517  csprod *= chunkp[idim];
518  if(dimmap_ounlim(odimid))
519  is_unlimited = 1;
520  }
521  /* Explicitly set chunking, even if default */
522  /* If product of chunksizes is too small and no unlimited
523  * dimensions used, don't chunk. Also if chunking
524  * explicitly turned off with chunk spec, don't chunk. */
525  if ((csprod < option_min_chunk_bytes && !is_unlimited) || contig == 1
526  || chunkspec_omit() == true) {
527  NC_CHECK(nc_def_var_chunking(ogrp, o_varid, NC_CONTIGUOUS, NULL));
528  } else {
529  NC_CHECK(nc_def_var_chunking(ogrp, o_varid, NC_CHUNKED, chunkp));
530  }
531  free(dimids);
532  free(chunkp);
533  }
534  }
535  { /* handle compression parameters, copying from input, overriding
536  * with command-line options */
537  int shuffle_in=0, deflate_in=0, deflate_level_in=0;
538  int shuffle_out=0, deflate_out=0, deflate_level_out=0;
539  if(option_deflate_level != 0) {
540  NC_CHECK(nc_inq_var_deflate(igrp, varid, &shuffle_in, &deflate_in, &deflate_level_in));
541  if(option_deflate_level == -1) { /* not specified, copy input compression and shuffling */
542  shuffle_out = shuffle_in;
543  deflate_out = deflate_in;
544  deflate_level_out = deflate_level_in;
545  } else if(option_deflate_level > 0) { /* change to specified compression, shuffling */
546  shuffle_out = option_shuffle_vars;
547  deflate_out=1;
548  deflate_level_out = option_deflate_level;
549  }
550  NC_CHECK(nc_def_var_deflate(ogrp, o_varid, shuffle_out, deflate_out, deflate_level_out));
551  }
552  }
553  { /* handle checksum parameters */
554  int fletcher32 = 0;
555  NC_CHECK(nc_inq_var_fletcher32(igrp, varid, &fletcher32));
556  if(fletcher32 != 0) {
557  NC_CHECK(nc_def_var_fletcher32(ogrp, o_varid, fletcher32));
558  }
559  }
560  { /* handle endianness */
561  int endianness = 0;
562  NC_CHECK(nc_inq_var_endian(igrp, varid, &endianness));
563  if(endianness != NC_ENDIAN_NATIVE) { /* native is the default */
564  NC_CHECK(nc_def_var_endian(ogrp, o_varid, endianness));
565  }
566  }
567  return stat;
568 }
569 
570 /* Set output variable o_varid (in group ogrp) to use chunking
571  * specified on command line, only called for classic format input and
572  * netCDF-4 format output, so no existing chunk lengths to override. */
573 static int
574 set_var_chunked(int ogrp, int o_varid)
575 {
576  int stat = NC_NOERR;
577  int ndims;
578  int odim;
579  size_t chunk_threshold = CHUNK_THRESHOLD;
580 
581  if(chunkspec_ndims() == 0) /* no chunking specified on command line */
582  return stat;
583  NC_CHECK(nc_inq_varndims(ogrp, o_varid, &ndims));
584 
585  if (ndims > 0) { /* no chunking for scalar variables */
586  int chunked = 0;
587  int *dimids = (int *) emalloc(ndims * sizeof(int));
588  size_t varsize;
589  nc_type vartype;
590  size_t value_size;
591  int is_unlimited = 0;
592 
593  NC_CHECK(nc_inq_vardimid (ogrp, o_varid, dimids));
594  NC_CHECK(nc_inq_vartype(ogrp, o_varid, &vartype));
595  /* from type, get size in memory needed for each value */
596  NC_CHECK(nc_inq_type(ogrp, vartype, NULL, &value_size));
597  varsize = value_size;
598 
599  /* Determine if this variable should be chunked. A variable
600  * should be chunked if any of its dims are in command-line
601  * chunk spec. It will also be chunked if any of its
602  * dims are unlimited. */
603  for(odim = 0; odim < ndims; odim++) {
604  int odimid = dimids[odim];
605  int idimid = dimmap_idimid(odimid); /* corresponding dimid in input file */
606  if(dimmap_ounlim(odimid))
607  is_unlimited = 1;
608  if(idimid != -1) {
609  size_t chunksize = chunkspec_size(idimid); /* from chunkspec */
610  size_t dimlen;
611  NC_CHECK(nc_inq_dimlen(ogrp, odimid, &dimlen));
612  if( (chunksize > 0) || dimmap_ounlim(odimid)) {
613  chunked = 1;
614  }
615  varsize *= dimlen;
616  }
617  }
618  /* Don't chunk small variables that don't use an unlimited
619  * dimension. */
620  if(varsize < chunk_threshold && !is_unlimited)
621  chunked = 0;
622 
623  if(chunked) {
624  /* Allocate chunksizes and set defaults to dimsize for any
625  * dimensions not mentioned in chunkspec. */
626  size_t *chunkp = (size_t *) emalloc(ndims * sizeof(size_t));
627  for(odim = 0; odim < ndims; odim++) {
628  int odimid = dimids[odim];
629  int idimid = dimmap_idimid(odimid);
630  size_t chunksize = chunkspec_size(idimid);
631  if(chunksize > 0) {
632  chunkp[odim] = chunksize;
633  } else {
634  NC_CHECK(nc_inq_dimlen(ogrp, odimid, &chunkp[odim]));
635  }
636  }
637  NC_CHECK(nc_def_var_chunking(ogrp, o_varid, NC_CHUNKED, chunkp));
638  free(chunkp);
639  }
640  free(dimids);
641  }
642  return stat;
643 }
644 
645 /* Set variable to compression specified on command line */
646 static int
647 set_var_compressed(int ogrp, int o_varid)
648 {
649  int stat = NC_NOERR;
650  if (option_deflate_level > 0) {
651  int deflate = 1;
652  NC_CHECK(nc_def_var_deflate(ogrp, o_varid, option_shuffle_vars, deflate, option_deflate_level));
653  }
654  return stat;
655 }
656 
657 /* Release the variable chunk cache allocated for variable varid in
658  * group grp. This is not necessary, but will save some memory when
659  * processing one variable at a time. */
660 #ifdef UNUSED
661 static int
662 free_var_chunk_cache(int grp, int varid)
663 {
664  int stat = NC_NOERR;
665  size_t chunk_cache_size = 1;
666  size_t cache_nelems = 1;
667  float cache_preemp = 0;
668  int kind;
669  NC_CHECK(nc_inq_format(grp, &kind));
670  if(kind == NC_FORMAT_NETCDF4 || kind == NC_FORMAT_NETCDF4_CLASSIC) {
671  int contig = 1;
672  NC_CHECK(nc_inq_var_chunking(grp, varid, &contig, NULL));
673  if(contig == 0) { /* chunked */
674  NC_CHECK(nc_set_var_chunk_cache(grp, varid, chunk_cache_size, cache_nelems, cache_preemp));
675  }
676  }
677  return stat;
678 }
679 #endif
680 
681 #endif /* USE_NETCDF4 */
682 
683 /* Copy dimensions from group igrp to group ogrp, also associate input
684  * dimids with output dimids (they need not match, because the input
685  * dimensions may have been defined in a different order than we define
686  * the output dimensions here. */
687 static int
688 copy_dims(int igrp, int ogrp)
689 {
690  int stat = NC_NOERR;
691  int ndims;
692  int dgrp;
693 #ifdef USE_NETCDF4
694  int nunlims;
695  int *dimids;
696  int *unlimids;
697 #else
698  int unlimid;
699 #endif /* USE_NETCDF4 */
700 
701  NC_CHECK(nc_inq_ndims(igrp, &ndims));
702 
703 #ifdef USE_NETCDF4
704  /* In netCDF-4 files, dimids may not be sequential because they
705  * may be defined in various groups, and we are only looking at one
706  * group at a time. */
707  /* Find the dimension ids in this group, don't include parents. */
708  dimids = (int *) emalloc((ndims + 1) * sizeof(int));
709  NC_CHECK(nc_inq_dimids(igrp, NULL, dimids, 0));
710  /* Find the number of unlimited dimensions and get their IDs */
711  NC_CHECK(nc_inq_unlimdims(igrp, &nunlims, NULL));
712  unlimids = (int *) emalloc((nunlims + 1) * sizeof(int));
713  NC_CHECK(nc_inq_unlimdims(igrp, NULL, unlimids));
714 #else
715  NC_CHECK(nc_inq_unlimdim(igrp, &unlimid));
716 #endif /* USE_NETCDF4 */
717 
718  /* Copy each dimension to output, including unlimited dimension(s) */
719  for (dgrp = 0; dgrp < ndims; dgrp++) {
720  char name[NC_MAX_NAME];
721  size_t length;
722  int i_is_unlim;
723  int o_is_unlim;
724  int idimid, odimid;
725 #ifdef USE_NETCDF4
726  int uld;
727 #endif
728 
729  i_is_unlim = 0;
730 #ifdef USE_NETCDF4
731  idimid = dimids[dgrp];
732  for (uld = 0; uld < nunlims; uld++) {
733  if(idimid == unlimids[uld]) {
734  i_is_unlim = 1;
735  break;
736  }
737  }
738 #else
739  idimid = dgrp;
740  if(unlimid != -1 && (idimid == unlimid)) {
741  i_is_unlim = 1;
742  }
743 #endif /* USE_NETCDF4 */
744 
745  stat = nc_inq_dim(igrp, idimid, name, &length);
746  if (stat == NC_EDIMSIZE && sizeof(size_t) < 8) {
747  error("dimension \"%s\" requires 64-bit platform", name);
748  }
749  NC_CHECK(stat);
750  o_is_unlim = i_is_unlim;
751  if(i_is_unlim && !option_fix_unlimdims) {
752  NC_CHECK(nc_def_dim(ogrp, name, NC_UNLIMITED, &odimid));
753  } else {
754  NC_CHECK(nc_def_dim(ogrp, name, length, &odimid));
755  o_is_unlim = 0;
756  }
757  /* Store (idimid, odimid) mapping for later use, also whether unlimited */
758  dimmap_store(idimid, odimid, i_is_unlim, o_is_unlim);
759  }
760 #ifdef USE_NETCDF4
761  free(dimids);
762  free(unlimids);
763 #endif /* USE_NETCDF4 */
764  return stat;
765 }
766 
767 /* Copy the attributes for variable ivar in group igrp to variable
768  * ovar in group ogrp. Global (group) attributes are specified by
769  * using the varid NC_GLOBAL */
770 static int
771 copy_atts(int igrp, int ivar, int ogrp, int ovar)
772 {
773  int natts;
774  int iatt;
775  int stat = NC_NOERR;
776 
777  NC_CHECK(nc_inq_varnatts(igrp, ivar, &natts));
778 
779  for(iatt = 0; iatt < natts; iatt++) {
780  char name[NC_MAX_NAME];
781  NC_CHECK(nc_inq_attname(igrp, ivar, iatt, name));
782  NC_CHECK(nc_copy_att(igrp, ivar, name, ogrp, ovar));
783  }
784  return stat;
785 }
786 
787 /* copy the schema for a single variable in group igrp to group ogrp */
788 static int
789 copy_var(int igrp, int varid, int ogrp)
790 {
791  int stat = NC_NOERR;
792  int ndims;
793  int *idimids; /* ids of dims for input variable */
794  int *odimids; /* ids of dims for output variable */
795  char name[NC_MAX_NAME];
796  nc_type typeid, o_typeid;
797  int natts;
798  int i;
799  int o_varid;
800 
801  NC_CHECK(nc_inq_varndims(igrp, varid, &ndims));
802  idimids = (int *) emalloc((ndims + 1) * sizeof(int));
803  NC_CHECK(nc_inq_var(igrp, varid, name, &typeid, NULL, idimids, &natts));
804  o_typeid = typeid;
805 #ifdef USE_NETCDF4
806  if (typeid > NC_STRING) { /* user-defined type */
807  /* type ids in source don't necessarily correspond to same
808  * typeids in destination, so look up destination typeid by
809  * using type name */
810  char type_name[NC_MAX_NAME];
811  NC_CHECK(nc_inq_type(igrp, typeid, type_name, NULL));
812  NC_CHECK(nc_inq_typeid(ogrp, type_name, &o_typeid));
813  }
814 #endif /* USE_NETCDF4 */
815 
816  /* get the corresponding dimids in the output file */
817  odimids = (int *) emalloc((ndims + 1) * sizeof(int));
818  for(i = 0; i < ndims; i++) {
819  odimids[i] = dimmap_odimid(idimids[i]);
820  if(odimids[i] == -1) {
821  error("Oops, no dimension in output associated with input dimid %d", idimids[i]);
822  }
823  }
824 
825  /* define the output variable */
826  NC_CHECK(nc_def_var(ogrp, name, o_typeid, ndims, odimids, &o_varid));
827  /* attach the variable attributes to the output variable */
828  NC_CHECK(copy_atts(igrp, varid, ogrp, o_varid));
829 #ifdef USE_NETCDF4
830  {
831  int inkind;
832  int outkind;
833  NC_CHECK(nc_inq_format(igrp, &inkind));
834  NC_CHECK(nc_inq_format(ogrp, &outkind));
835  if(outkind == NC_FORMAT_NETCDF4 || outkind == NC_FORMAT_NETCDF4_CLASSIC) {
836  if((inkind == NC_FORMAT_NETCDF4 || inkind == NC_FORMAT_NETCDF4_CLASSIC)) {
837  /* Copy all netCDF-4 specific variable properties such as
838  * chunking, endianness, deflation, checksumming, fill, etc. */
839  NC_CHECK(copy_var_specials(igrp, varid, ogrp, o_varid));
840  } else {
841  /* Set chunking if specified in command line option */
842  NC_CHECK(set_var_chunked(ogrp, o_varid));
843  /* Set compression if specified in command line option */
844  NC_CHECK(set_var_compressed(ogrp, o_varid));
845  }
846  }
847  }
848 #endif /* USE_NETCDF4 */
849  free(idimids);
850  free(odimids);
851  return stat;
852 }
853 
854 /* copy the schema for all the variables in group igrp to group ogrp */
855 static int
856 copy_vars(int igrp, int ogrp)
857 {
858  int stat = NC_NOERR;
859  int nvars;
860  int varid;
861 
862  int iv; /* variable number */
863  idnode_t* vlist = 0; /* list for vars specified with -v option */
864 
865  /*
866  * If any vars were specified with -v option, get list of
867  * associated variable ids relative to this group. Assume vars
868  * specified with syntax like "grp1/grp2/varname" or
869  * "/grp1/grp2/varname" if they are in groups.
870  */
871  vlist = newidlist(); /* list for vars specified with -v option */
872  for (iv=0; iv < option_nlvars; iv++) {
873  if(nc_inq_gvarid(igrp, option_lvars[iv], &varid) == NC_NOERR)
874  idadd(vlist, varid);
875  }
876 
877  NC_CHECK(nc_inq_nvars(igrp, &nvars));
878  for (varid = 0; varid < nvars; varid++) {
879  if (!option_varstruct && option_nlvars > 0 && ! idmember(vlist, varid))
880  continue;
881  NC_CHECK(copy_var(igrp, varid, ogrp));
882  }
883  freeidlist(vlist);
884  return stat;
885 }
886 
887 /* Copy the schema in a group and all its subgroups, recursively, from
888  * group igrp in input to parent group ogrp in destination. Use
889  * dimmap array to map input dimids to output dimids. */
890 static int
891 copy_schema(int igrp, int ogrp)
892 {
893  int stat = NC_NOERR;
894  int ogid; /* like igrp but in output file */
895 
896  /* get groupid in output corresponding to group igrp in input,
897  * given parent group (or root group) ogrp in output */
898  NC_CHECK(get_grpid(igrp, ogrp, &ogid));
899 
900  NC_CHECK(copy_dims(igrp, ogid));
901  NC_CHECK(copy_atts(igrp, NC_GLOBAL, ogid, NC_GLOBAL));
902  NC_CHECK(copy_vars(igrp, ogid));
903 #ifdef USE_NETCDF4
904  {
905  int numgrps;
906  int *grpids;
907  int i;
908  /* Copy schema from subgroups */
909  stat = nc_inq_grps(igrp, &numgrps, NULL);
910  grpids = (int *)emalloc((numgrps + 1) * sizeof(int));
911  NC_CHECK(nc_inq_grps(igrp, &numgrps, grpids));
912 
913  for(i = 0; i < numgrps; i++) {
914  if (option_grpstruct || group_wanted(grpids[i], option_nlgrps, option_grpids)) {
915  NC_CHECK(copy_schema(grpids[i], ogid));
916  }
917  }
918  free(grpids);
919  }
920 #endif /* USE_NETCDF4 */
921  return stat;
922 }
923 
924 /* Return number of values for a variable varid in a group igrp */
925 static int
926 inq_nvals(int igrp, int varid, long long *nvalsp) {
927  int stat = NC_NOERR;
928  int ndims;
929  int *dimids;
930  int dim;
931  long long nvals = 1;
932 
933  NC_CHECK(nc_inq_varndims(igrp, varid, &ndims));
934  dimids = (int *) emalloc((ndims + 1) * sizeof(int));
935  NC_CHECK(nc_inq_vardimid (igrp, varid, dimids));
936  for(dim = 0; dim < ndims; dim++) {
937  size_t len;
938  NC_CHECK(nc_inq_dimlen(igrp, dimids[dim], &len));
939  nvals *= len;
940  }
941  if(nvalsp)
942  *nvalsp = nvals;
943  free(dimids);
944  return stat;
945 }
946 
947 /* Copy data from variable varid in group igrp to corresponding group
948  * ogrp. */
949 static int
950 copy_var_data(int igrp, int varid, int ogrp) {
951  int stat = NC_NOERR;
952  nc_type vartype;
953  long long nvalues; /* number of values for this variable */
954  size_t ntoget; /* number of values to access this iteration */
955  size_t value_size; /* size of a single value of this variable */
956  static void *buf = 0; /* buffer for the variable values */
957  char varname[NC_MAX_NAME];
958  int ovarid;
959  size_t *start;
960  size_t *count;
961  nciter_t *iterp; /* opaque structure for iteration status */
962  int do_realloc = 0;
963 #ifdef USE_NETCDF4
964  int okind;
965  size_t chunksize;
966 #endif
967 
968  NC_CHECK(inq_nvals(igrp, varid, &nvalues));
969  if(nvalues == 0)
970  return stat;
971  /* get corresponding output variable */
972  NC_CHECK(nc_inq_varname(igrp, varid, varname));
973  NC_CHECK(nc_inq_varid(ogrp, varname, &ovarid));
974  NC_CHECK(nc_inq_vartype(igrp, varid, &vartype));
975  value_size = val_size(igrp, varid);
976  if(value_size > option_copy_buffer_size) {
977  option_copy_buffer_size = value_size;
978  do_realloc = 1;
979  }
980 #ifdef USE_NETCDF4
981  NC_CHECK(nc_inq_format(ogrp, &okind));
982  if(okind == NC_FORMAT_NETCDF4 || okind == NC_FORMAT_NETCDF4_CLASSIC) {
983  /* if this variable chunked, set variable chunk cache size */
984  int contig = 1;
985  NC_CHECK(nc_inq_var_chunking(ogrp, ovarid, &contig, NULL));
986  if(contig == 0) { /* chunked */
987  if(option_compute_chunkcaches) {
988  /* Try to estimate variable-specific chunk cache,
989  * depending on specific size and shape of this
990  * variable's chunks. This doesn't work yet. */
991  size_t chunkcache_size, chunkcache_nelems;
992  float chunkcache_preemption;
993  NC_CHECK(inq_var_chunking_params(igrp, varid, ogrp, ovarid,
994  &chunkcache_size,
995  &chunkcache_nelems,
996  &chunkcache_preemption));
997  NC_CHECK(nc_set_var_chunk_cache(ogrp, ovarid,
998  chunkcache_size,
999  chunkcache_nelems,
1000  chunkcache_preemption));
1001  } else {
1002  /* by default, use same chunk cache for all chunked variables */
1003  NC_CHECK(nc_set_var_chunk_cache(ogrp, ovarid,
1004  option_chunk_cache_size,
1005  option_chunk_cache_nelems,
1006  COPY_CHUNKCACHE_PREEMPTION));
1007  }
1008  }
1009  }
1010  /* For chunked variables, option_copy_buffer_size must also be at least as large as
1011  * size of a chunk in input, otherwise resize it. */
1012  {
1013  NC_CHECK(inq_var_chunksize(igrp, varid, &chunksize));
1014  if(chunksize > option_copy_buffer_size) {
1015  option_copy_buffer_size = chunksize;
1016  do_realloc = 1;
1017  }
1018  }
1019 #endif /* USE_NETCDF4 */
1020  if(buf && do_realloc) {
1021  free(buf);
1022  buf = 0;
1023  }
1024  if(buf == 0) { /* first time or needs to grow */
1025  buf = emalloc(option_copy_buffer_size);
1026  memset((void*)buf,0,option_copy_buffer_size);
1027  }
1028 
1029  /* initialize variable iteration */
1030  NC_CHECK(nc_get_iter(igrp, varid, option_copy_buffer_size, &iterp));
1031 
1032  start = (size_t *) emalloc((iterp->rank + 1) * sizeof(size_t));
1033  count = (size_t *) emalloc((iterp->rank + 1) * sizeof(size_t));
1034  /* nc_next_iter() initializes start and count on first call,
1035  * changes start and count to iterate through whole variable on
1036  * subsequent calls. */
1037  while((ntoget = nc_next_iter(iterp, start, count)) > 0) {
1038  NC_CHECK(nc_get_vara(igrp, varid, start, count, buf));
1039  NC_CHECK(nc_put_vara(ogrp, ovarid, start, count, buf));
1040 #ifdef USE_NETCDF4
1041  /* we have to explicitly free values for strings and vlens */
1042  if(vartype == NC_STRING) {
1043  NC_CHECK(nc_free_string(ntoget, (char **)buf));
1044  } else if(vartype > NC_STRING) { /* user-defined type */
1045  nc_type vclass;
1046  NC_CHECK(nc_inq_user_type(igrp, vartype, NULL, NULL, NULL, NULL, &vclass));
1047  if(vclass == NC_VLEN) {
1048  NC_CHECK(nc_free_vlens(ntoget, (nc_vlen_t *)buf));
1049  }
1050  }
1051 #endif /* USE_NETCDF4 */
1052  } /* end main iteration loop */
1053 #ifdef USE_NETCDF4
1054  /* We're all done with this input and output variable, so if
1055  * either variable is chunked, free up its variable chunk cache */
1056  /* NC_CHECK(free_var_chunk_cache(igrp, varid)); */
1057  /* NC_CHECK(free_var_chunk_cache(ogrp, ovarid)); */
1058 #endif /* USE_NETCDF4 */
1059  free(start);
1060  free(count);
1061  NC_CHECK(nc_free_iter(iterp));
1062  return stat;
1063 }
1064 
1065 /* Copy data from variables in group igrp to variables in
1066  * corresponding group with parent ogrp, and all subgroups
1067  * recursively */
1068 static int
1069 copy_data(int igrp, int ogrp)
1070 {
1071  int stat = NC_NOERR;
1072  int ogid;
1073  int nvars;
1074  int varid;
1075 #ifdef USE_NETCDF4
1076  int numgrps;
1077  int *grpids;
1078  int i;
1079 #endif
1080 
1081  int iv; /* variable number */
1082  idnode_t* vlist = NULL; /* list for vars specified with -v option */
1083 
1084  /*
1085  * If any vars were specified with -v option, get list of
1086  * associated variable ids relative to this group. Assume vars
1087  * specified with syntax like "grp1/grp2/varname" or
1088  * "/grp1/grp2/varname" if they are in groups.
1089  */
1090  vlist = newidlist(); /* list for vars specified with -v option */
1091  for (iv=0; iv < option_nlvars; iv++) {
1092  if(nc_inq_gvarid(igrp, option_lvars[iv], &varid) == NC_NOERR)
1093  idadd(vlist, varid);
1094  }
1095 
1096  /* get groupid in output corresponding to group igrp in input,
1097  * given parent group (or root group) ogrp in output */
1098  NC_CHECK(get_grpid(igrp, ogrp, &ogid));
1099 
1100  /* Copy data from this group */
1101  NC_CHECK(nc_inq_nvars(igrp, &nvars));
1102 
1103  for (varid = 0; varid < nvars; varid++) {
1104  if (option_nlvars > 0 && ! idmember(vlist, varid))
1105  continue;
1106  if (!group_wanted(igrp, option_nlgrps, option_grpids))
1107  continue;
1108  NC_CHECK(copy_var_data(igrp, varid, ogid));
1109  }
1110 #ifdef USE_NETCDF4
1111  /* Copy data from subgroups */
1112  stat = nc_inq_grps(igrp, &numgrps, NULL);
1113  grpids = (int *)emalloc((numgrps + 1) * sizeof(int));
1114  NC_CHECK(nc_inq_grps(igrp, &numgrps, grpids));
1115 
1116  for(i = 0; i < numgrps; i++) {
1117  if (!option_grpstruct && !group_wanted(grpids[i], option_nlgrps, option_grpids))
1118  continue;
1119  NC_CHECK(copy_data(grpids[i], ogid));
1120  }
1121  free(grpids);
1122 #endif /* USE_NETCDF4 */
1123  freeidlist(vlist);
1124  return stat;
1125 }
1126 
1127 /* Count total number of dimensions in ncid and all its descendant subgroups */
1128 int
1129 count_dims(ncid) {
1130  int numgrps;
1131  int ndims;
1132  NC_CHECK(nc_inq_ndims(ncid, &ndims));
1133 #ifdef USE_NETCDF4
1134  NC_CHECK(nc_inq_grps(ncid, &numgrps, NULL));
1135  if(numgrps > 0) {
1136  int igrp;
1137  int *grpids = emalloc(numgrps * sizeof(int));
1138  NC_CHECK(nc_inq_grps(ncid, &numgrps, grpids));
1139  for(igrp = 0; igrp < numgrps; igrp++) {
1140  ndims += count_dims(grpids[igrp]);
1141  }
1142  free(grpids);
1143  }
1144 #endif /* USE_NETCDF4 */
1145  return ndims;
1146 }
1147 
1148 /* Test if special case: netCDF-3 file with more than one record
1149  * variable. Performance can be very slow for this case when the disk
1150  * block size is large, there are many record variables, and a
1151  * record's worth of data for some variables is smaller than the disk
1152  * block size. In this case, copying the record variables a variable
1153  * at a time causes much rereading of record data, so instead we want
1154  * to copy data a record at a time. */
1155 static int
1156 nc3_special_case(int ncid, int kind) {
1157  if (kind == NC_FORMAT_CLASSIC || kind == NC_FORMAT_64BIT) {
1158  int recdimid = 0;
1159  NC_CHECK(nc_inq_unlimdim(ncid, &recdimid));
1160  if (recdimid != -1) { /* we have a record dimension */
1161  int nvars;
1162  int varid;
1163  NC_CHECK(nc_inq_nvars(ncid, &nvars));
1164  for (varid = 0; varid < nvars; varid++) {
1165  int *dimids = 0;
1166  int ndims;
1167  NC_CHECK( nc_inq_varndims(ncid, varid, &ndims) );
1168  if (ndims > 0) {
1169  int dimids0;
1170  dimids = (int *) emalloc((ndims + 1) * sizeof(int));
1171  NC_CHECK( nc_inq_vardimid(ncid, varid, dimids) );
1172  dimids0 = dimids[0];
1173  free(dimids);
1174  if(dimids0 == recdimid) {
1175  return 1; /* found a record variable */
1176  }
1177  }
1178  }
1179  }
1180  }
1181  return 0;
1182 }
1183 
1184 /* Classify variables in ncid as either fixed-size variables (with no
1185  * unlimited dimension) or as record variables (with an unlimited
1186  * dimension) */
1187 static int
1188 classify_vars(
1189  int ncid, /* netCDF ID */
1190  size_t *nf, /* for returning number of fixed-size variables */
1191  int **fvars, /* the array of fixed_size variable IDS, caller should free */
1192  size_t *nr, /* for returning number of record variables */
1193  int **rvars) /* the array of record variable IDs, caller should free */
1194 {
1195  int varid;
1196  int nvars;
1197  NC_CHECK(nc_inq_nvars(ncid, &nvars));
1198  *nf = 0;
1199  *fvars = (int *) emalloc(nvars * sizeof(int));
1200  *nr = 0;
1201  *rvars = (int *) emalloc(nvars * sizeof(int));
1202  for (varid = 0; varid < nvars; varid++) {
1203  if (isrecvar(ncid, varid)) {
1204  (*rvars)[*nr] = varid;
1205  (*nr)++;
1206  } else {
1207  (*fvars)[*nf] = varid;
1208  (*nf)++;
1209  }
1210  }
1211  return NC_NOERR;
1212 }
1213 
1214 /* Only called for classic format or 64-bit offset format files, to speed up special case */
1215 static int
1216 copy_fixed_size_data(int igrp, int ogrp, size_t nfixed_vars, int *fixed_varids) {
1217  size_t ivar;
1218  /* for each fixed-size variable, copy data */
1219  for (ivar = 0; ivar < nfixed_vars; ivar++) {
1220  int varid = fixed_varids[ivar];
1221  NC_CHECK(copy_var_data(igrp, varid, ogrp));
1222  }
1223  if (fixed_varids)
1224  free(fixed_varids);
1225  return NC_NOERR;
1226 }
1227 
1228 /* copy a record's worth of data for a variable from input to output */
1229 static int
1230 copy_rec_var_data(int ncid, /* input */
1231  int ogrp, /* output */
1232  int irec, /* record number */
1233  int varid, /* input variable id */
1234  int ovarid, /* output variable id */
1235  size_t *start, /* start indices for record data */
1236  size_t *count, /* edge lengths for record data */
1237  void *buf /* buffer large enough to hold data */
1238  )
1239 {
1240  NC_CHECK(nc_get_vara(ncid, varid, start, count, buf));
1241  NC_CHECK(nc_put_vara(ogrp, ovarid, start, count, buf));
1242  return NC_NOERR;
1243 }
1244 
1245 /* Only called for classic format or 64-bit offset format files, to speed up special case */
1246 static int
1247 copy_record_data(int ncid, int ogrp, size_t nrec_vars, int *rec_varids) {
1248  int unlimid;
1249  size_t nrecs = 0; /* how many records? */
1250  size_t irec;
1251  size_t ivar;
1252  void **buf; /* space for reading in data for each variable */
1253  int *rec_ovarids; /* corresponding varids in output */
1254  size_t **start;
1255  size_t **count;
1256  NC_CHECK(nc_inq_unlimdim(ncid, &unlimid));
1257  NC_CHECK(nc_inq_dimlen(ncid, unlimid, &nrecs));
1258  buf = (void **) emalloc(nrec_vars * sizeof(void *));
1259  rec_ovarids = (int *) emalloc(nrec_vars * sizeof(int));
1260  start = (size_t **) emalloc(nrec_vars * sizeof(size_t*));
1261  count = (size_t **) emalloc(nrec_vars * sizeof(size_t*));
1262  /* get space to hold one record's worth of data for each record variable */
1263  for (ivar = 0; ivar < nrec_vars; ivar++) {
1264  int varid;
1265  int ndims;
1266  int *dimids;
1267  size_t value_size;
1268  int dimid;
1269  int ii;
1270  size_t nvals;
1271  char varname[NC_MAX_NAME];
1272  varid = rec_varids[ivar];
1273  NC_CHECK(nc_inq_varndims(ncid, varid, &ndims));
1274  dimids = (int *) emalloc((1 + ndims) * sizeof(int));
1275  start[ivar] = (size_t *) emalloc(ndims * sizeof(size_t));
1276  count[ivar] = (size_t *) emalloc(ndims * sizeof(size_t));
1277  NC_CHECK(nc_inq_vardimid (ncid, varid, dimids));
1278  value_size = val_size(ncid, varid);
1279  nvals = 1;
1280  for(ii = 1; ii < ndims; ii++) { /* for rec size, don't include first record dimension */
1281  size_t dimlen;
1282  dimid = dimids[ii];
1283  NC_CHECK(nc_inq_dimlen(ncid, dimid, &dimlen));
1284  nvals *= dimlen;
1285  start[ivar][ii] = 0;
1286  count[ivar][ii] = dimlen;
1287  }
1288  start[ivar][0] = 0;
1289  count[ivar][0] = 1; /* 1 record */
1290  buf[ivar] = (void *) emalloc(nvals * value_size);
1291  NC_CHECK(nc_inq_varname(ncid, varid, varname));
1292  NC_CHECK(nc_inq_varid(ogrp, varname, &rec_ovarids[ivar]));
1293  if(dimids)
1294  free(dimids);
1295  }
1296 
1297  /* for each record, copy all variable data */
1298  for(irec = 0; irec < nrecs; irec++) {
1299  for (ivar = 0; ivar < nrec_vars; ivar++) {
1300  int varid, ovarid;
1301  varid = rec_varids[ivar];
1302  ovarid = rec_ovarids[ivar];
1303  start[ivar][0] = irec;
1304  NC_CHECK(copy_rec_var_data(ncid, ogrp, irec, varid, ovarid,
1305  start[ivar], count[ivar], buf[ivar]));
1306  }
1307  }
1308  for (ivar = 0; ivar < nrec_vars; ivar++) {
1309  if(start[ivar])
1310  free(start[ivar]);
1311  if(count[ivar])
1312  free(count[ivar]);
1313  }
1314  if(start)
1315  free(start);
1316  if(count)
1317  free(count);
1318  for (ivar = 0; ivar < nrec_vars; ivar++) {
1319  if(buf[ivar]) {
1320  free(buf[ivar]);
1321  }
1322  }
1323  if (rec_varids)
1324  free(rec_varids);
1325  if(buf)
1326  free(buf);
1327  if(rec_ovarids)
1328  free(rec_ovarids);
1329  return NC_NOERR;
1330 }
1331 
1332 /* copy infile to outfile using netCDF API
1333  */
1334 static int
1335 copy(char* infile, char* outfile)
1336 {
1337  int stat = NC_NOERR;
1338  int igrp, ogrp;
1339  int inkind, outkind;
1340  int open_mode = NC_NOWRITE;
1341  int create_mode = NC_CLOBBER;
1342  size_t ndims;
1343 
1344  if(option_read_diskless) {
1345  open_mode |= NC_DISKLESS;
1346  }
1347 
1348  NC_CHECK(nc_open(infile, open_mode, &igrp));
1349 
1350  NC_CHECK(nc_inq_format(igrp, &inkind));
1351 
1352 /* option_kind specifies which netCDF format for output:
1353  * -1 -> same as input,
1354  * 1 -> classic
1355  * 2 -> 64-bit offset
1356  * 3 -> netCDF-4,
1357  * 4 -> netCDF-4 classic model
1358  *
1359  * However, if compression or shuffling was specified and kind was -1,
1360  * kind is changed to format 4 that supports compression for input of
1361  * type 1 or 2.
1362  */
1363  outkind = option_kind;
1364  if (option_kind == SAME_AS_INPUT) { /* default, kind not specified */
1365  outkind = inkind;
1366  /* Deduce output kind if netCDF-4 features requested */
1367  if (inkind == NC_FORMAT_CLASSIC || inkind == NC_FORMAT_64BIT) {
1368  if (option_deflate_level > 0 ||
1369  option_shuffle_vars == NC_SHUFFLE ||
1370  option_chunkspec)
1371  {
1372  outkind = NC_FORMAT_NETCDF4_CLASSIC;
1373  }
1374  }
1375  }
1376 
1377 #ifdef USE_NETCDF4
1378  if(option_chunkspec) {
1379  /* Now that input is open, can parse option_chunkspec into binary
1380  * structure. */
1381  NC_CHECK(chunkspec_parse(igrp, option_chunkspec));
1382  }
1383 #endif /* USE_NETCDF4 */
1384 
1385  /* Check if any vars in -v don't exist */
1386  if(missing_vars(igrp, option_nlvars, option_lvars))
1387  exit(EXIT_FAILURE);
1388 
1389  if(option_nlgrps > 0) {
1390  if(inkind != NC_FORMAT_NETCDF4) {
1391  error("Group list (-g ...) only permitted for netCDF-4 file");
1392  exit(EXIT_FAILURE);
1393  }
1394  /* Check if any grps in -g don't exist */
1395  if(grp_matches(igrp, option_nlgrps, option_lgrps, option_grpids) == 0)
1396  exit(EXIT_FAILURE);
1397  }
1398 
1399  if(option_write_diskless)
1400  create_mode |= NC_WRITE | NC_DISKLESS; /* NC_WRITE persists diskless file on close */
1401  switch(outkind) {
1402  case NC_FORMAT_CLASSIC:
1403  /* nothing to do */
1404  break;
1405  case NC_FORMAT_64BIT:
1406  create_mode |= NC_64BIT_OFFSET;
1407  break;
1408 #ifdef USE_NETCDF4
1409  case NC_FORMAT_NETCDF4:
1410  create_mode |= NC_NETCDF4;
1411  break;
1413  create_mode |= NC_NETCDF4 | NC_CLASSIC_MODEL;
1414  break;
1415 #else
1416  case NC_FORMAT_NETCDF4:
1418  error("nccopy built with --disable-netcdf4, can't create netCDF-4 files");
1419  break;
1420 #endif /* USE_NETCDF4 */
1421  default:
1422  error("bad value (%d) for -k option\n", option_kind);
1423  break;
1424  }
1425  NC_CHECK(nc_create(outfile, create_mode, &ogrp));
1426  NC_CHECK(nc_set_fill(ogrp, NC_NOFILL, NULL));
1427 
1428 #ifdef USE_NETCDF4
1429  /* Because types in one group may depend on types in a different
1430  * group, need to create all groups before defining types */
1431  if(inkind == NC_FORMAT_NETCDF4) {
1432  NC_CHECK(copy_groups(igrp, ogrp));
1433  NC_CHECK(copy_types(igrp, ogrp));
1434  }
1435 #endif /* USE_NETCDF4 */
1436 
1437  ndims = count_dims(igrp);
1438  NC_CHECK(dimmap_init(ndims));
1439  NC_CHECK(copy_schema(igrp, ogrp));
1440  NC_CHECK(nc_enddef(ogrp));
1441 
1442  /* For performance, special case netCDF-3 input or output file with record
1443  * variables, to copy a record-at-a-time instead of a
1444  * variable-at-a-time. */
1445  /* TODO: check that these special cases work with -v option */
1446  if(nc3_special_case(igrp, inkind)) {
1447  size_t nfixed_vars, nrec_vars;
1448  int *fixed_varids;
1449  int *rec_varids;
1450  NC_CHECK(classify_vars(igrp, &nfixed_vars, &fixed_varids, &nrec_vars, &rec_varids));
1451  NC_CHECK(copy_fixed_size_data(igrp, ogrp, nfixed_vars, fixed_varids));
1452  NC_CHECK(copy_record_data(igrp, ogrp, nrec_vars, rec_varids));
1453  } else if (nc3_special_case(ogrp, outkind)) {
1454  size_t nfixed_vars, nrec_vars;
1455  int *fixed_varids;
1456  int *rec_varids;
1457  /* classifies output vars, but returns input varids */
1458  NC_CHECK(classify_vars(ogrp, &nfixed_vars, &fixed_varids, &nrec_vars, &rec_varids));
1459  NC_CHECK(copy_fixed_size_data(igrp, ogrp, nfixed_vars, fixed_varids));
1460  NC_CHECK(copy_record_data(igrp, ogrp, nrec_vars, rec_varids));
1461  } else {
1462  NC_CHECK(copy_data(igrp, ogrp)); /* recursive, to handle nested groups */
1463  }
1464 
1465  NC_CHECK(nc_close(igrp));
1466  NC_CHECK(nc_close(ogrp));
1467  return stat;
1468 }
1469 
1470 /*
1471  * For non-negative numeric string with multiplier suffix K, M, G, T,
1472  * or P (or lower-case equivalent), return corresponding value
1473  * incorporating multiplier 1000, 1000000, 1.0d9, ... 1.0d15, or -1.0
1474  * for error.
1475  */
1476 static double
1477 double_with_suffix(char *str) {
1478  double dval;
1479  char *suffix = 0;
1480  errno = 0;
1481  dval = strtod(str, &suffix);
1482  if(dval < 0 || errno != 0)
1483  return -1.0;
1484  if(*suffix) {
1485  switch (*suffix) {
1486  case 'k': case 'K':
1487  dval *= 1000;
1488  break;
1489  case 'm': case 'M':
1490  dval *= 1000000;
1491  break;
1492  case 'g': case 'G':
1493  dval *= 1000000000;
1494  break;
1495  case 't': case 'T':
1496  dval *= 1.0e12;
1497  break;
1498  case 'p': case 'P':
1499  dval *= 1.0e15;
1500  break;
1501  default:
1502  dval = -1.0; /* error, suffix multiplier must be K, M, G, or T */
1503  }
1504  }
1505  return dval;
1506 }
1507 
1508 static void
1509 usage(void)
1510 {
1511 #define USAGE "\
1512  [-k n] specify kind of netCDF format for output file, default same as input\n\
1513  1 classic, 2 64-bit offset, 3 netCDF-4, 4 netCDF-4 classic model\n\
1514  [-d n] set deflation compression level, default same as input (0=none 9=max)\n\
1515  [-s] add shuffle option to deflation compression\n\
1516  [-c chunkspec] specify chunking for dimensions, e.g. \"dim1/N1,dim2/N2,...\"\n\
1517  [-u] convert unlimited dimensions to fixed-size dimensions in output copy\n\
1518  [-w] write whole output file from diskless netCDF on close\n\
1519  [-v var1,...] include data for only listed variables, but definitions for all variables\n\
1520  [-V var1,...] include definitions and data for only listed variables\n\
1521  [-g grp1,...] include data for only variables in listed groups, but all definitions\n\
1522  [-G grp1,...] include definitions and data only for variables in listed groups\n\
1523  [-m n] set size in bytes of copy buffer, default is 5000000 bytes\n\
1524  [-h n] set size in bytes of chunk_cache for chunked variables\n\
1525  [-e n] set number of elements that chunk_cache can hold\n\
1526  [-r] read whole input file into diskless file on open (classic or 64-bit offset format only)\n\
1527  infile name of netCDF input file\n\
1528  outfile name for netCDF output file\n"
1529 
1530  /* Don't document this flaky option until it works better */
1531  /* [-x] use experimental computed estimates for variable-specific chunk caches\n\ */
1532 
1533  error("%s [-k n] [-d n] [-s] [-c chunkspec] [-u] [-w] [-[v|V] varlist] [-[g|G] grplist] [-m n] [-h n] [-e n] [-r] infile outfile\n%s",
1534  progname, USAGE);
1535 }
1536 
1537 int
1538 main(int argc, char**argv)
1539 {
1540  char* inputfile = NULL;
1541  char* outputfile = NULL;
1542  int c;
1543 
1544 /* table of formats for legal -k values */
1545  struct Kvalues {
1546  char* name;
1547  int kind;
1548  } legalkinds[] = {
1549  {"1", NC_FORMAT_CLASSIC},
1550  {"classic", NC_FORMAT_CLASSIC},
1551 
1552  /* The 64-bit offset kind (2) */
1553  {"2", NC_FORMAT_64BIT},
1554  {"64-bit-offset", NC_FORMAT_64BIT},
1555  {"64-bit offset", NC_FORMAT_64BIT},
1556 
1557  /* NetCDF-4 HDF5 format */
1558  {"3", NC_FORMAT_NETCDF4},
1559  {"hdf5", NC_FORMAT_NETCDF4},
1560  {"netCDF-4", NC_FORMAT_NETCDF4},
1561  {"netCDF4", NC_FORMAT_NETCDF4},
1562  {"enhanced", NC_FORMAT_NETCDF4},
1563 
1564  /* NetCDF-4 HDF5 format, but using only nc3 data model */
1566  {"hdf5-nc3", NC_FORMAT_NETCDF4_CLASSIC},
1567  {"netCDF-4 classic model", NC_FORMAT_NETCDF4_CLASSIC},
1568  {"netCDF4_classic", NC_FORMAT_NETCDF4_CLASSIC},
1569  {"enhanced-nc3", NC_FORMAT_NETCDF4_CLASSIC},
1570 
1571  /* null terminate*/
1572  {NULL,0}
1573  };
1574 
1575  opterr = 1;
1576  progname = argv[0];
1577 
1578  if (argc <= 1)
1579  {
1580  usage();
1581  }
1582 
1583  while ((c = getopt(argc, argv, "k:d:sum:c:h:e:rwxg:G:v:V:")) != -1) {
1584  switch(c) {
1585  case 'k': /* for specifying variant of netCDF format to be generated
1586  Possible values are:
1587  1 (=> classic 32 bit)
1588  2 (=> classic 64 bit offsets)
1589  3 (=> netCDF-4/HDF5)
1590  4 (=> classic, but stored in netCDF-4/HDF5 format)
1591  Also allow string versions of above
1592  "classic"
1593  "64-bit-offset"
1594  "64-bit offset"
1595  "enhanced" | "hdf5" | "netCDF-4"
1596  "enhanced-nc3" | "hdf5-nc3" | "netCDF-4 classic model"
1597  */
1598  {
1599  struct Kvalues* kvalue;
1600  char *kind_name = (char *) emalloc(strlen(optarg)+1);
1601  (void)strcpy(kind_name, optarg);
1602  for(kvalue=legalkinds;kvalue->name;kvalue++) {
1603  if(strcmp(kind_name,kvalue->name) == 0) {
1604  option_kind = kvalue->kind;
1605  break;
1606  }
1607  }
1608  if(kvalue->name == NULL) {
1609  error("invalid format: %s", kind_name);
1610  }
1611  }
1612  break;
1613  case 'd': /* non-default compression level specified */
1614  option_deflate_level = strtol(optarg, NULL, 10);
1615  if(option_deflate_level < 0 || option_deflate_level > 9) {
1616  error("invalid deflation level: %d", option_deflate_level);
1617  }
1618  break;
1619  case 's': /* shuffling, may improve compression */
1620  option_shuffle_vars = NC_SHUFFLE;
1621  break;
1622  case 'u': /* convert unlimited dimensions to fixed size */
1623  option_fix_unlimdims = 1;
1624  break;
1625  case 'm': /* non-default size of data copy buffer */
1626  {
1627  double dval = double_with_suffix(optarg); /* "K" for kilobytes. "M" for megabytes, ... */
1628  if(dval < 0)
1629  error("Suffix used for '-m' option value must be K, M, G, T, or P");
1630  option_copy_buffer_size = dval;
1631  break;
1632  }
1633  case 'h': /* non-default size of chunk cache */
1634  {
1635  double dval = double_with_suffix(optarg); /* "K" for kilobytes. "M" for megabytes, ... */
1636  if(dval < 0)
1637  error("Suffix used for '-h' option value must be K, M, G, T, or P");
1638  option_chunk_cache_size = dval;
1639  break;
1640  }
1641  case 'e': /* number of elements chunk cache can hold */
1642  {
1643  double dval = double_with_suffix(optarg); /* "K" for kilobytes. "M" for megabytes, ... */
1644  if(dval < 0 )
1645  error("Suffix used for '-e' option value must be K, M, G, T, or P");
1646  option_chunk_cache_nelems = (long)dval;
1647  break;
1648  }
1649  case 'r':
1650  option_read_diskless = 1; /* read into memory on open */
1651  break;
1652  case 'w':
1653  option_write_diskless = 1; /* write to memory, persist on close */
1654  break;
1655  case 'x': /* use experimental variable-specific chunk caches */
1656  option_compute_chunkcaches = 1;
1657  break;
1658  case 'c': /* optional chunking spec for each dimension in list */
1659  /* save chunkspec string for parsing later, once we know input ncid */
1660  option_chunkspec = strdup(optarg);
1661  break;
1662  case 'g': /* group names */
1663  /* make list of names of groups specified */
1664  make_lgrps (optarg, &option_nlgrps, &option_lgrps, &option_grpids);
1665  option_grpstruct = true;
1666  break;
1667  case 'G': /* group names */
1668  /* make list of names of groups specified */
1669  make_lgrps (optarg, &option_nlgrps, &option_lgrps, &option_grpids);
1670  option_grpstruct = false;
1671  break;
1672  case 'v': /* variable names */
1673  /* make list of names of variables specified */
1674  make_lvars (optarg, &option_nlvars, &option_lvars);
1675  option_varstruct = true;
1676  break;
1677  case 'V': /* variable names */
1678  /* make list of names of variables specified */
1679  make_lvars (optarg, &option_nlvars, &option_lvars);
1680  option_varstruct = false;
1681  break;
1682  default:
1683  usage();
1684  }
1685  }
1686  argc -= optind;
1687  argv += optind;
1688 
1689  if (argc != 2) {
1690  error("one input file and one output file required");
1691  }
1692  inputfile = argv[0];
1693  outputfile = argv[1];
1694 
1695  if(strcmp(inputfile, outputfile) == 0) {
1696  error("output would overwrite input");
1697  }
1698 
1699  if(copy(inputfile, outputfile) != NC_NOERR)
1700  exit(EXIT_FAILURE);
1701  exit(EXIT_SUCCESS);
1702 }
1703 END_OF_MAIN();
EXTERNL int nc_def_enum(int ncid, nc_type base_typeid, const char *name, nc_type *typeidp)
Create an enum type.
Definition: denum.c:43
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:353
EXTERNL int nc_inq_var_endian(int ncid, int varid, int *endianp)
Find the endianness of a variable.
Definition: dvarinq.c:506
#define NC_CHUNKED
In HDF5 files you can set storage for each variable to be either contiguous or chunked, with nc_def_var_chunking().
Definition: netcdf.h:250
EXTERNL int nc_inq_unlimdim(int ncid, int *unlimdimidp)
Find the ID of the unlimited dimension.
Definition: ddim.c:280
EXTERNL int nc_inq_opaque(int ncid, nc_type xtype, char *name, size_t *sizep)
Learn about an opaque type.
Definition: dopaque.c:61
EXTERNL int nc_inq_vardimid(int ncid, int varid, int *dimidsp)
Learn the dimension IDs associated with a variable.
Definition: dvarinq.c:213
#define NC_CONTIGUOUS
In HDF5 files you can set storage for each variable to be either contiguous or chunked, with nc_def_var_chunking().
Definition: netcdf.h:251
EXTERNL int nc_def_var(int ncid, const char *name, nc_type xtype, int ndims, const int *dimidsp, int *varidp)
Define a new variable.
Definition: dvar.c:207
#define NC_CLASSIC_MODEL
Enforce classic model.
Definition: netcdf.h:135
#define NC_OPAQUE
opaque types
Definition: netcdf.h:56
Main header file for the C API.
EXTERNL int nc_free_vlens(size_t len, nc_vlen_t vlens[])
Free an array of vlens given the number of elements and an array.
Definition: dvlen.c:52
EXTERNL int nc_inq_var_chunking(int ncid, int varid, int *storagep, size_t *chunksizesp)
This is a wrapper for nc_inq_var_all().
Definition: dvarinq.c:424
#define NC_STRING
string
Definition: netcdf.h:49
EXTERNL int nc_put_vara(int ncid, int varid, const size_t *startp, const size_t *countp, const void *op)
Write an array of values to a variable.
Definition: dvarput.c:575
EXTERNL int nc_insert_array_compound(int ncid, nc_type xtype, const char *name, size_t offset, nc_type field_typeid, int ndims, const int *dim_sizes)
Insert a named array field into a compound type.
Definition: dcompound.c:141
EXTERNL int nc_inq_varndims(int ncid, int varid, int *ndimsp)
Learn how many dimensions are associated with a variable.
Definition: dvarinq.c:191
EXTERNL int nc_inq_format(int ncid, int *formatp)
Inquire about the binary format of a netCDF file as presented by the API.
Definition: dfile.c:1278
EXTERNL int nc_inq_enum(int ncid, nc_type xtype, char *name, nc_type *base_nc_typep, size_t *base_sizep, size_t *num_membersp)
Learn about a user-define enumeration type.
Definition: denum.c:107
EXTERNL int nc_def_opaque(int ncid, size_t size, const char *name, nc_type *xtypep)
Create an opaque type.
Definition: dopaque.c:33
int nc_type
The nc_type type is just an int.
Definition: netcdf.h:27
#define NC_64BIT_OFFSET
Use large (64-bit) file offsets.
Definition: netcdf.h:136
#define NC_NOWRITE
Set read-only access for nc_open().
Definition: netcdf.h:126
EXTERNL int nc_def_dim(int ncid, const char *name, size_t len, int *idp)
Define a new dimension.
Definition: ddim.c:67
#define NC_EDIMSIZE
Invalid dimension size.
Definition: netcdf.h:355
EXTERNL int nc_set_var_chunk_cache(int ncid, int varid, size_t size, size_t nelems, float preemption)
Definition: dvar.c:468
#define NC_ENOGRP
No group found.
Definition: netcdf.h:410
EXTERNL int nc_inq_vlen(int ncid, nc_type xtype, char *name, size_t *datum_sizep, nc_type *base_nc_typep)
Learn about a VLEN type.
Definition: dvlen.c:118
EXTERNL int nc_close(int ncid)
Close an open netCDF dataset.
Definition: dfile.c:1093
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:55
#define NC_NOSHUFFLE
Control the HDF5 shuffle filter.
Definition: netcdf.h:268
EXTERNL int nc_inq_compound_field(int ncid, nc_type xtype, int fieldid, char *name, size_t *offsetp, nc_type *field_typeidp, int *ndimsp, int *dim_sizesp)
Get information about one of the fields of a compound type.
Definition: dcompound.c:287
EXTERNL int nc_def_compound(int ncid, size_t size, const char *name, nc_type *typeidp)
Create a compound type.
Definition: dcompound.c:63
#define NC_FORMAT_64BIT
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:166
This is the type of arrays of vlens.
Definition: netcdf.h:624
#define NC_EBADTYPE
Not a netcdf data type.
Definition: netcdf.h:315
EXTERNL int nc_inq_compound(int ncid, nc_type xtype, char *name, size_t *sizep, size_t *nfieldsp)
Learn about a compound type.
Definition: dcompound.c:175
EXTERNL int nc_inq_var_fletcher32(int ncid, int varid, int *fletcher32p)
Learn the checksum settings for a variable.
Definition: dvarinq.c:375
#define NC_NOFILL
Argument to nc_set_fill() to turn off filling of data.
Definition: netcdf.h:119
EXTERNL int nc_set_fill(int ncid, int fillmode, int *old_modep)
Change the fill-value mode to improve write performance.
Definition: dfile.c:1211
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:231
EXTERNL int nc_inq_vartype(int ncid, int varid, nc_type *xtypep)
Learn the type of a variable.
Definition: dvarinq.c:168
EXTERNL int nc_inq_type(int ncid, nc_type xtype, char *name, size_t *size)
Inquire about a type.
Definition: dfile.c:1448
EXTERNL int nc_free_string(size_t len, char **data)
Free string space allocated by the library.
Definition: dvar.c:530
EXTERNL int nc_inq_varname(int ncid, int varid, char *name)
Learn the name of a variable.
Definition: dvarinq.c:146
#define NC_NETCDF4
Use netCDF-4/HDF5 format.
Definition: netcdf.h:148
#define NC_FORMAT_NETCDF4_CLASSIC
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:168
#define NC_FORMAT_NETCDF4
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:167
#define NC_UNLIMITED
Size argument to nc_def_dim() for an unlimited dimension.
Definition: netcdf.h:204
EXTERNL int nc_insert_enum(int ncid, nc_type xtype, const char *name, const void *value)
Insert a named member into a enum type.
Definition: denum.c:71
EXTERNL int nc_inq_varid(int ncid, const char *name, int *varidp)
Find the ID of a variable, from the name.
Definition: dvarinq.c:52
EXTERNL int nc_insert_compound(int ncid, nc_type xtype, const char *name, size_t offset, nc_type field_typeid)
Insert a named field into a compound type.
Definition: dcompound.c:99
EXTERNL int nc_inq_enum_member(int ncid, nc_type xtype, int idx, char *name, void *value)
Learn about a about a member of an enum type.
Definition: denum.c:140
#define NC_CLOBBER
Destroy existing file.
Definition: netcdf.h:129
#define NC_WRITE
Set read-write access for nc_open().
Definition: netcdf.h:127
#define NC_ENDIAN_NATIVE
In HDF5 files you can set the endianness of variables with nc_def_var_endian().
Definition: netcdf.h:241
EXTERNL int nc_inq_var_deflate(int ncid, int varid, int *shufflep, int *deflatep, int *deflate_levelp)
Learn the storage and deflate settings for a variable.
Definition: dvarinq.c:273
EXTERNL int nc_inq_unlimdims(int ncid, int *nunlimdimsp, int *unlimdimidsp)
Return number and list of unlimited dimensions.
Definition: dvarinq.c:563
EXTERNL int nc_inq_var(int ncid, int varid, char *name, nc_type *xtypep, int *ndimsp, int *dimidsp, int *nattsp)
Learn about a variable.
Definition: dvarinq.c:116
#define NC_NOERR
No Error.
Definition: netcdf.h:278
#define NC_ENUM
enum types
Definition: netcdf.h:57
#define NC_DISKLESS
Use diskless file.
Definition: netcdf.h:132
EXTERNL int nc_def_vlen(int ncid, const char *name, nc_type base_typeid, nc_type *xtypep)
Use this function to define a variable length array type.
Definition: dvlen.c:90
EXTERNL int nc_open(const char *path, int mode, int *ncidp)
Open an existing netCDF file.
Definition: dfile.c:588
EXTERNL int nc_inq_ndims(int ncid, int *ndimsp)
Find the number of dimensions.
Definition: ddim.c:250
EXTERNL int nc_inq_varnatts(int ncid, int varid, int *nattsp)
Learn how many attributes are associated with a variable.
Definition: dvarinq.c:236
EXTERNL int nc_enddef(int ncid)
Leave define mode.
Definition: dfile.c:815
#define NC_COMPOUND
compound types
Definition: netcdf.h:58
EXTERNL int nc_inq_dimlen(int ncid, int dimid, size_t *lenp)
Find the length of a dimension.
Definition: ddim.c:394
EXTERNL int nc_inq_user_type(int ncid, nc_type xtype, char *name, size_t *size, nc_type *base_nc_typep, size_t *nfieldsp, int *classp)
Learn about a user defined type.
Definition: dtype.c:102
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition: netcdf.h:207
#define NC_SHUFFLE
Control the HDF5 shuffle filter.
Definition: netcdf.h:269
#define NC_FORMAT_CLASSIC
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:165
#define END_OF_MAIN()
NO_NETCDF_2.
Definition: netcdf.h:1918
EXTERNL int nc_get_vara(int ncid, int varid, const size_t *startp, const size_t *countp, void *ip)
Read an array of values from a variable.
Definition: dvarget.c:627
EXTERNL int nc_create(const char *path, int cmode, int *ncidp)
Create a new netCDF file.
Definition: dfile.c:383
EXTERNL int nc_inq_dim(int ncid, int dimid, char *name, size_t *lenp)
Find the name and length of a dimension.
Definition: ddim.c:159
EXTERNL int nc_inq_attname(int ncid, int varid, int attnum, char *name)
Find the name of an attribute.
Definition: dattinq.c:129
EXTERNL int nc_inq_typeid(int ncid, const char *name, nc_type *typeidp)
Find a type by name.
Definition: dtype.c:59

Return to the Main Unidata NetCDF page.
Generated on Sun Nov 23 2014 16:20:09 for NetCDF. NetCDF is a Unidata library.