source: XIOS/dev/branch_openmp/extern/src_netcdf4/nc4var.c @ 1501

Last change on this file since 1501 was 409, checked in by ymipsl, 11 years ago

Add improved nectdf internal library src

YM

  • Property svn:eol-style set to native
File size: 42.1 KB
Line 
1/*
2This file is part of netcdf-4, a netCDF-like interface for HDF5, or a
3HDF5 backend for netCDF, depending on your point of view.
4
5This file handles the nc4 variable functions.
6
7Copyright 2003-2006, University Corporation for Atmospheric
8Research. See COPYRIGHT file for copying and redistribution
9conditions.
10*/
11
12#include <nc4internal.h>
13#include "nc4dispatch.h"
14#include <math.h>
15
16#ifdef USE_PNETCDF
17#include <pnetcdf.h>
18#endif
19
20/* Min and max deflate levels tolerated by HDF5. */
21#define MIN_DEFLATE_LEVEL 0
22#define MAX_DEFLATE_LEVEL 9
23
24/* This is to track opened HDF5 objects to make sure they are
25 * closed. */
26#ifdef EXTRA_TESTS
27extern int num_plists;
28#endif /* EXTRA_TESTS */
29
30/* One meg is the minimum buffer size. */
31#define ONE_MEG 1048576
32
33/* Szip options. */
34#define NC_SZIP_EC_OPTION_MASK 4
35#define NC_SZIP_NN_OPTION_MASK 32
36#define NC_SZIP_MAX_PIXELS_PER_BLOCK 32
37
38int nc4_get_default_fill_value(NC_TYPE_INFO_T *type_info, void *fill_value);
39
40
41/* If the HDF5 dataset for this variable is open, then close it and
42 * reopen it, with the perhaps new settings for chunk caching. */
43int
44nc4_reopen_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
45{
46   hid_t access_pid;
47
48   if (var->hdf_datasetid)
49   {
50      if ((access_pid = H5Pcreate(H5P_DATASET_ACCESS)) < 0)
51         return NC_EHDFERR;
52#ifdef EXTRA_TESTS
53      num_plists++;
54#endif
55      if (H5Pset_chunk_cache(access_pid, var->chunk_cache_nelems, 
56                             var->chunk_cache_size, 
57                             var->chunk_cache_preemption) < 0)
58         return NC_EHDFERR;
59      if (H5Dclose(var->hdf_datasetid) < 0)
60         return NC_EHDFERR;
61      if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpid, var->name, 
62                                         access_pid)) < 0)
63         return NC_EHDFERR;
64      if (H5Pclose(access_pid) < 0)
65         return NC_EHDFERR;
66#ifdef EXTRA_TESTS
67      num_plists--;
68#endif
69
70      if (var->dimscale)
71         var->dim[0]->hdf_dimscaleid = var->hdf_datasetid;
72   }
73   
74   return NC_NOERR;
75}
76
77/* Set chunk cache size for a variable. */
78int
79NC4_set_var_chunk_cache(int ncid, int varid, size_t size, size_t nelems, 
80                        float preemption)
81{
82   NC_FILE_INFO_T *nc;
83   NC_GRP_INFO_T *grp; 
84   NC_HDF5_FILE_INFO_T *h5;
85   NC_VAR_INFO_T *var;
86   int retval;
87
88   /* Check input for validity. */
89   if (preemption < 0 || preemption > 1)
90      return NC_EINVAL;
91
92   /* Find info for this file and group, and set pointer to each. */
93   if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
94      return retval;
95
96   /* An attempt to do any of these things on a netCDF-3 file is
97    * ignored with no error. */
98   if (!h5)
99      return NC_NOERR;
100
101   assert(nc && grp && h5);
102
103   /* Find the var. */
104   for (var = grp->var; var; var = var->next)
105      if (var->varid == varid)
106         break;
107   if (!var)
108      return NC_ENOTVAR;
109
110   /* Set the values. */
111   var->chunk_cache_size = size;
112   var->chunk_cache_nelems = nelems;
113   var->chunk_cache_preemption = preemption;
114
115   if ((retval = nc4_reopen_dataset(grp, var)))
116      return retval;
117
118   return NC_NOERR;
119}
120
121/* Need this version for fortran. Accept negative numbers to leave
122 * settings as they are. */
123int
124nc_set_var_chunk_cache_ints(int ncid, int varid, int size, int nelems, 
125                            int preemption)
126{
127   size_t real_size = H5D_CHUNK_CACHE_NBYTES_DEFAULT;
128   size_t real_nelems = H5D_CHUNK_CACHE_NSLOTS_DEFAULT;
129   float real_preemption = H5D_CHUNK_CACHE_W0_DEFAULT;
130
131   if (size >= 0)
132      real_size = size * MEGABYTE;
133
134   if (nelems >= 0)
135      real_nelems = nelems;
136
137   if (preemption >= 0)
138      real_preemption = preemption / 100.;
139         
140   return nc_set_var_chunk_cache(ncid, varid, real_size, real_nelems, 
141                                 real_preemption);
142}
143
144/* Get chunk cache size for a variable. */
145int
146NC4_get_var_chunk_cache(int ncid, int varid, size_t *sizep, 
147                        size_t *nelemsp, float *preemptionp)
148{
149   NC_FILE_INFO_T *nc;
150   NC_GRP_INFO_T *grp; 
151   NC_HDF5_FILE_INFO_T *h5;
152   NC_VAR_INFO_T *var;
153   int retval;
154
155   /* Find info for this file and group, and set pointer to each. */
156   if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
157      return retval;
158
159   /* Attempting to do any of these things on a netCDF-3 file produces
160    * an error. */
161   if (!h5)
162      return NC_ENOTNC4;
163
164   assert(nc && grp && h5);
165
166   /* Find the var. */
167   for (var = grp->var; var; var = var->next)
168      if (var->varid == varid)
169         break;
170   if (!var)
171      return NC_ENOTVAR;
172
173   /* Give the user what they want. */
174   if (sizep)
175      *sizep = var->chunk_cache_size;
176   if (nelemsp)
177      *nelemsp = var->chunk_cache_nelems;
178   if (preemptionp)
179      *preemptionp = var->chunk_cache_preemption;
180
181   return NC_NOERR;
182}
183
184/* Get chunk cache size for a variable. */
185int
186nc_get_var_chunk_cache_ints(int ncid, int varid, int *sizep, 
187                            int *nelemsp, int *preemptionp)
188{
189   size_t real_size, real_nelems;
190   float real_preemption;
191   int ret;
192
193   if ((ret = nc_get_var_chunk_cache(ncid, varid, &real_size, 
194                                     &real_nelems, &real_preemption)))
195      return ret;
196   
197   if (sizep)
198      *sizep = real_size / MEGABYTE;
199   if (nelemsp)
200      *nelemsp = (int)real_nelems;
201   if(preemptionp)
202      *preemptionp = (int)(real_preemption * 100);
203
204   return NC_NOERR;
205}
206
207/* Check a set of chunksizes to see if they add up to a chunk that is too big. */
208static int
209check_chunksizes(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, const size_t *chunksizes)
210{
211   NC_TYPE_INFO_T *type_info;
212   float total;
213   size_t type_len;
214   int d;
215   int retval;
216   
217   if ((retval = nc4_get_typelen_mem(grp->file->nc4_info, var->xtype, 0, &type_len)))
218      return retval;
219   if ((retval = nc4_find_type(grp->file->nc4_info, var->xtype, &type_info)))
220      return retval;
221   if (type_info && type_info->class == NC_VLEN)
222      total = sizeof(hvl_t);
223   else
224      total = type_len;
225   for (d = 0; d < var->ndims; d++)
226   {
227      if (chunksizes[d] < 1)
228         return NC_EINVAL;
229      total *= chunksizes[d];
230   }
231   
232   if (total > NC_MAX_UINT)
233      return NC_EBADCHUNK;
234
235   return NC_NOERR;
236}
237
238/* Find the default chunk nelems (i.e. length of chunk along each
239 * dimension). */
240static int 
241nc4_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
242{
243   int d;
244   size_t type_size, max_len = 0;
245   float num_values = 1, num_set = 0;
246   int retval;
247#ifdef LOGGING   
248   int max_dim;
249   float total_chunk_size;
250#endif
251
252   if (var->type_info->nc_typeid == NC_STRING)
253      type_size = sizeof(char *);
254   else
255      type_size = var->type_info->size;
256
257   /* Later this will become the total number of bytes in the default
258    * chunk. */
259#ifdef LOGGING   
260   total_chunk_size = type_size;
261#endif
262
263   /* How many values in the variable (or one record, if there are
264    * unlimited dimensions); which is the largest dimension, and how
265    * long is it? */
266   for (d = 0; d < var->ndims; d++)
267   {
268      assert(var->dim[d]);
269      if (var->dim[d]->len) 
270         num_values *= (float)var->dim[d]->len;
271      else
272         num_set++;
273     
274      if (var->dim[d]->len > max_len)
275      {
276         max_len = var->dim[d]->len;
277#ifdef LOGGING
278         max_dim = d;
279#endif
280      }
281      LOG((4, "d = %d max_dim %d max_len %ld num_values %f", d, max_dim, max_len, 
282           num_values));
283   }
284
285   /* If a dim is several orders of magnitude smaller than the max
286    * dimension, set it's chunk size to the full extent of the smaller
287    * dimension. */
288#define NC_DIM_MULTIPLIER 10000
289   for (d = 0; d < var->ndims; d++)
290      if (var->dim[d]->unlimited)
291         var->chunksizes[d] = 1;
292      else if (!var->dim[d]->unlimited && var->dim[d]->len * NC_DIM_MULTIPLIER < max_len)
293      {
294         var->chunksizes[d] = var->dim[d]->len;
295         num_set++; 
296      }
297   
298   /* Pick a chunk length for each dimension, if one has not already
299    * been picked above. */
300   for (d = 0; d < var->ndims; d++)
301      if (!var->chunksizes[d])
302      {
303         size_t suggested_size;
304         suggested_size = (pow((double)DEFAULT_CHUNK_SIZE/(num_values * type_size), 
305                               1/(double)(var->ndims - num_set)) * var->dim[d]->len - .5);
306         if (suggested_size > var->dim[d]->len)
307            suggested_size = var->dim[d]->len;
308         var->chunksizes[d] = suggested_size ? suggested_size : 1;
309         LOG((4, "nc_def_var_nc4: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d "
310              "chunksize %ld", var->name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[d]));
311      }
312
313   /* Find total chunk size. */
314#ifdef LOGGING   
315   for (d = 0; d < var->ndims; d++)
316      total_chunk_size *= var->chunksizes[d];
317   LOG((4, "total_chunk_size %f", total_chunk_size));
318#endif
319   
320   /* But did this add up to a chunk that is too big? */
321   retval = check_chunksizes(grp, var, var->chunksizes);
322   if (retval)
323   {
324      /* Other error? */
325      if (retval != NC_EBADCHUNK)
326         return retval;
327
328      /* Chunk is too big! Reduce each dimension by half and try again. */
329      for ( ; retval == NC_EBADCHUNK; retval = check_chunksizes(grp, var, var->chunksizes))
330         for (d = 0; d < var->ndims; d++)
331            var->chunksizes[d] = var->chunksizes[d]/2 ? var->chunksizes[d]/2 : 1;
332   }
333
334   /* Do we have any big data overhangs? They can be dangerous to
335    * babies, the elderly, or confused campers who have had too much
336    * beer. */
337   for (d = 0; d < var->ndims; d++)
338   {
339       int num_chunks;
340       size_t overhang;
341       assert(var->chunksizes[d] > 0);
342       num_chunks = (var->dim[d]->len + var->chunksizes[d] - 1) / var->chunksizes[d];
343       if(num_chunks > 0) {
344           overhang = (num_chunks * var->chunksizes[d]) - var->dim[d]->len;
345           var->chunksizes[d] -= overhang / num_chunks;
346       }
347   }
348
349   return NC_NOERR;
350}
351
352/* This is called when a new netCDF-4 variable is defined. Break it
353 * down! */
354static int 
355nc_def_var_nc4(int ncid, const char *name, nc_type xtype, 
356               int ndims, const int *dimidsp, int *varidp)
357{
358   NC_GRP_INFO_T *grp;
359   NC_VAR_INFO_T *var;
360   NC_DIM_INFO_T *dim;
361   NC_HDF5_FILE_INFO_T *h5;
362   NC_TYPE_INFO_T *type_info;
363   char norm_name[NC_MAX_NAME + 1];
364   int new_varid = 0;
365   int num_unlim = 0;
366   int d;
367   size_t num_values = 1;
368   int retval;
369
370   /* Find info for this file and group, and set pointer to each. */
371   if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
372      return retval;
373   assert(grp && h5);
374
375   /* If it's not in define mode, strict nc3 files error out,
376    * otherwise switch to define mode. */
377   if (!(h5->flags & NC_INDEF))
378   {
379      if (h5->cmode & NC_CLASSIC_MODEL)
380         return NC_ENOTINDEFINE;
381      if ((retval = NC4_redef(ncid)))
382         return retval;
383   }
384
385   /* Check and normalize the name. */
386   if ((retval = nc4_check_name(name, norm_name)))
387      return retval;
388
389   /* Not a Type is, well, not a type.*/
390   if (xtype == NC_NAT)
391      return NC_EBADTYPE;
392   
393   /* For classic files, only classic types are allowed. */
394   if (h5->cmode & NC_CLASSIC_MODEL && xtype > NC_DOUBLE)
395      return NC_ESTRICTNC3;
396
397   /* If this is a user defined type, find it. */
398   if (xtype > NC_STRING)
399      if (nc4_find_type(grp->file->nc4_info, xtype, &type_info))
400         return NC_EBADTYPE;
401
402   /* cast needed for braindead systems with signed size_t */
403   if((unsigned long) ndims > X_INT_MAX) /* Backward compat */
404      return NC_EINVAL;
405
406   /* Classic model files have a limit on number of vars. */
407   if(h5->cmode & NC_CLASSIC_MODEL && h5->nvars >= NC_MAX_VARS)
408      return NC_EMAXVARS;
409
410   /* Check that this name is not in use as a var, grp, or type. */
411   if ((retval = nc4_check_dup_name(grp, norm_name)))
412      return retval;
413
414   /* If the file is read-only, return an error. */
415   if (h5->no_write)
416     return NC_EPERM;
417
418   /* Get the new varid. */
419   for (var = grp->var; var; var = var->next)
420      new_varid++;
421
422   /* Check all the dimids to make sure they exist. */
423   for (d = 0; d < ndims; d++)
424   {
425      if ((retval = nc4_find_dim(grp, dimidsp[d], &dim, NULL)))
426         return retval;
427      if (dim->unlimited)
428         num_unlim++;
429      else
430         num_values *= dim->len;
431   }
432
433   /* These degrubbing messages sure are handy! */
434   LOG((3, "nc_def_var_nc4: name %s type %d ndims %d", norm_name, xtype, ndims));
435#ifdef LOGGING
436   {
437      int dd;
438      for (dd = 0; dd < ndims; dd++)
439         LOG((4, "dimid[%d] %d", dd, dimidsp[dd]));
440   }
441#endif
442
443   /* Add the var to the end of the list. */
444   if ((retval = nc4_var_list_add(&grp->var, &var)))
445      return retval;
446
447   /* Now fill in the values in the var info structure. */
448   if (!(var->name = malloc((strlen(norm_name) + 1) * sizeof(char))))
449      return NC_ENOMEM;
450   strcpy(var->name, norm_name);
451   var->varid = grp->nvars++;
452   var->xtype = xtype;
453   var->ndims = ndims;
454   var->dirty++;
455   
456   /* If this is a user-defined type, there is a type_info stuct with
457    * all the type information. For atomic types, fake up a type_info
458    * struct. */
459   if (xtype > NC_STRING)
460      var->type_info = type_info;
461   else
462   {
463      if (!(var->type_info = calloc(1, sizeof(NC_TYPE_INFO_T))))
464         return NC_ENOMEM;
465      var->type_info->nc_typeid = xtype;
466      if ((retval = nc4_get_hdf_typeid(h5, var->xtype, &var->type_info->hdf_typeid, 
467                                       var->type_info->endianness)))
468         return retval;
469      if ((var->type_info->native_typeid = H5Tget_native_type(var->type_info->hdf_typeid, 
470                                                              H5T_DIR_DEFAULT)) < 0)
471         return NC_EHDFERR;
472      if ((retval = nc4_get_typelen_mem(h5, var->type_info->nc_typeid, 0, 
473                                        &var->type_info->size)))
474         return retval;
475   }
476   if (!num_unlim)
477      var->contiguous = 1;
478
479   /* Allocate space for dimension information. */
480   if (ndims)
481   {
482      if (!(var->dim = calloc(ndims, sizeof(NC_DIM_INFO_T *))))
483         return NC_ENOMEM;
484      if (!(var->dimids = calloc(ndims, sizeof(int))))
485         return NC_ENOMEM;
486   }
487
488   /* At the same time, check to see if this is a coordinate
489    * variable. If so, it will have the same name as one of its
490    * dimensions. If it is a coordinate var, is it a coordinate var in
491    * the same group as the dim? */
492   for (d = 0; d < ndims; d++)
493   {
494      NC_GRP_INFO_T *dim_grp;
495      if ((retval = nc4_find_dim(grp, dimidsp[d], &dim, &dim_grp)))
496         return retval;
497      if (strcmp(dim->name, norm_name) == 0 && dim_grp == grp && d == 0)
498      {
499         var->dimscale++;
500         dim->coord_var = var;
501         dim->coord_var_in_grp++;
502      }
503      var->dimids[d] = dimidsp[d];
504      var->dim[d] = dim;
505   }
506
507   /* Determine default chunksizes for this variable. (Even for
508    * variables which may be contiguous. */
509   LOG((4, "allocating array of %d size_t to hold chunksizes for var %s",
510        var->ndims, var->name));
511   if (var->ndims)
512      if (!(var->chunksizes = calloc(var->ndims, sizeof(size_t))))
513         return NC_ENOMEM;
514
515   if ((retval = nc4_find_default_chunksizes2(grp, var)))
516      return retval;
517
518   /* Is this a variable with a chunksize greater than the current
519    * cache size? */
520   if ((retval = nc4_adjust_var_cache(grp, var)))
521      return retval;
522
523   /* If the user names this variable the same as a dimension, but
524    * doesn't use that dimension first in its list of dimension ids,
525    * is not a coordinate variable. I need to change its HDF5 name,
526    * because the dimension will cause a HDF5 dataset to be created,
527    * and this var has the same name. */
528   for (dim = grp->dim; dim; dim = dim->next)
529      if (!strcmp(dim->name, norm_name) && 
530          (!var->ndims || dimidsp[0] != dim->dimid))
531      {
532         /* Set a different hdf5 name for this variable to avoid name
533          * clash. */
534         if (strlen(norm_name) + strlen(NON_COORD_PREPEND) > NC_MAX_NAME)
535            return NC_EMAXNAME;
536         if (!(var->hdf5_name = malloc((strlen(NON_COORD_PREPEND) + 
537                                        strlen(norm_name) + 1) * sizeof(char))))
538            return NC_ENOMEM;
539         
540         sprintf(var->hdf5_name, "%s%s", NON_COORD_PREPEND, norm_name);
541      }
542
543   /* If this is a coordinate var, it is marked as a HDF5 dimension
544    * scale. (We found dim above.) Otherwise, allocate space to
545    * remember whether dimension scales have been attached to each
546    * dimension. */
547   if (!var->dimscale && ndims)
548      if (ndims && !(var->dimscale_attached = calloc(ndims, sizeof(int))))
549         return NC_ENOMEM;
550
551   /* Return the varid. */
552   if (varidp)
553      *varidp = var->varid;
554   LOG((4, "new varid %d", var->varid));
555
556   return retval;
557}
558
559/* Create a new variable to hold user data. This is what it's all
560 * about baby! */
561int
562NC4_def_var(int ncid, const char *name, nc_type xtype, int ndims, 
563           const int *dimidsp, int *varidp)
564{
565   NC_FILE_INFO_T *nc;
566
567   LOG((2, "nc_def_var: ncid 0x%x name %s xtype %d ndims %d",
568        ncid, name, xtype, ndims));
569
570   /* If there are dimensions, I need their ids. */
571   if (ndims && !dimidsp)
572      return NC_EINVAL;
573
574   /* Find metadata for this file. */
575   if (!(nc = nc4_find_nc_file(ncid)))
576      return NC_EBADID;
577
578#ifdef USE_PNETCDF
579   /* Take care of files created/opened with parallel-netcdf library. */
580   if (nc->pnetcdf_file)
581   {
582      int ret;
583
584      ret = ncmpi_def_var(nc->int_ncid, name, xtype, ndims, 
585                          dimidsp, varidp);
586      nc->pnetcdf_ndims[*varidp] = ndims;
587      return ret;
588   }
589#endif /* USE_PNETCDF */
590
591   /* Netcdf-3 cases handled by dispatch layer. */
592   assert(nc->nc4_info);
593
594   /* Handle netcdf-4 cases. */
595   return nc_def_var_nc4(ncid, name, xtype, ndims, dimidsp, varidp);
596}
597
598/* Get all the information about a variable. Pass NULL for whatever
599 * you don't care about. This is an internal function, not exposed to
600 * the user. */
601int 
602NC4_inq_var_all(int ncid, int varid, char *name, nc_type *xtypep, 
603               int *ndimsp, int *dimidsp, int *nattsp, 
604               int *shufflep, int *deflatep, int *deflate_levelp,
605               int *fletcher32p, int *contiguousp, size_t *chunksizesp, 
606               int *no_fill, void *fill_valuep, int *endiannessp, 
607               int *options_maskp, int *pixels_per_blockp)
608{
609   NC_FILE_INFO_T *nc;
610   NC_GRP_INFO_T *grp; 
611   NC_HDF5_FILE_INFO_T *h5;
612   NC_VAR_INFO_T *var;
613   NC_ATT_INFO_T *att;
614   int natts=0;
615   size_t type_size;
616   int d;
617   int retval;
618
619   LOG((2, "nc_inq_var_all: ncid 0x%x varid %d", ncid, varid));
620
621   /* Find info for this file and group, and set pointer to each. */
622   if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
623      return retval;
624   assert(nc && grp && h5);
625
626#ifdef USE_PNETCDF
627   /* Take care of files created/opened with parallel-netcdf library. */
628   if (nc->pnetcdf_file)
629      return ncmpi_inq_var(nc->int_ncid, varid, name, xtypep, ndimsp, 
630                           dimidsp, nattsp);
631#endif /* USE_PNETCDF */
632
633   /* Walk through the list of vars, and return the info about the one
634      with a matching varid. If the varid is -1, find the global
635      atts and call it a day. */
636   if (varid == NC_GLOBAL)
637   {
638      if (nattsp)
639      {
640         for (att = grp->att; att; att = att->next)
641            natts++;
642         *nattsp = natts;
643      }
644      return NC_NOERR;
645   }
646
647   /* Find the var. */
648   for (var = grp->var; var; var = var->next)
649      if (var->varid == varid)
650         break;
651   
652   /* Oh no! Maybe we couldn't find it (*sob*)! */
653   if (!var)
654      return NC_ENOTVAR;
655   
656   /* Copy the data to the user's data buffers. */
657   if (name)
658      strcpy(name, var->name);
659   if (xtypep)
660      *xtypep = var->xtype;
661   if (ndimsp)
662      *ndimsp = var->ndims;
663   if (dimidsp)
664      for (d = 0; d < var->ndims; d++)
665         dimidsp[d] = var->dimids[d];
666   if (nattsp)
667   {
668      for (att = var->att; att; att = att->next)
669         natts++;
670      *nattsp = natts;
671   }
672   
673   /* Chunking stuff. */
674   if (!var->contiguous && chunksizesp)
675      for (d = 0; d < var->ndims; d++)
676      {
677         chunksizesp[d] = var->chunksizes[d];
678         LOG((4, "chunksizesp[%d]=%d", d, chunksizesp[d]));
679      }
680
681   if (contiguousp)
682      *contiguousp = var->contiguous ? NC_CONTIGUOUS : NC_CHUNKED;
683
684   /* Filter stuff. */
685   if (deflatep)
686      *deflatep = var->deflate;
687   if (deflate_levelp)
688      *deflate_levelp = var->deflate_level;
689   if (shufflep)
690      *shufflep = var->shuffle;
691   if (fletcher32p)
692      *fletcher32p = var->fletcher32;
693   if (options_maskp)
694      *options_maskp = var->options_mask;
695   if (pixels_per_blockp)
696      *pixels_per_blockp = var->pixels_per_block;
697
698   /* Fill value stuff. */
699   if (no_fill)
700      *no_fill = var->no_fill;
701
702   /* Don't do a thing with fill_valuep if no_fill mode is set for
703    * this var, or if fill_valuep is NULL. */
704   if (!var->no_fill && fill_valuep)
705   {
706      /* Do we have a fill value for this var? */
707      if (var->fill_value)
708      {
709         if ((retval = nc4_get_typelen_mem(grp->file->nc4_info, var->xtype, 0, &type_size)))
710            return retval;
711         memcpy(fill_valuep, var->fill_value, type_size);
712      }
713      else
714      {
715         if ((retval = nc4_get_default_fill_value(var->type_info, fill_valuep)))
716            return retval;
717      }
718   }
719
720   /* Does the user want the endianness of this variable? */
721   if (endiannessp)
722      *endiannessp = var->type_info->endianness;
723
724   return NC_NOERR;
725}
726
727/* This functions sets extra stuff about a netCDF-4 variable which
728   must be set before the enddef but after the def_var. This is an
729   internal function, deliberately hidden from the user so that we can
730   change the prototype of this functions without changing the API. */
731static int
732nc_def_var_extra(int ncid, int varid, int *shuffle, int *deflate, 
733                 int *deflate_level, int *fletcher32, int *contiguous, 
734                 const size_t *chunksizes, int *no_fill, 
735                 const void *fill_value, int *endianness, 
736                 int *options_mask, int *pixels_per_block)
737{
738   NC_FILE_INFO_T *nc;
739   NC_GRP_INFO_T *grp; 
740   NC_HDF5_FILE_INFO_T *h5;
741   NC_VAR_INFO_T *var;
742   NC_DIM_INFO_T *dim;
743   size_t type_size;
744   int d;
745   int retval;
746
747   LOG((2, "nc_def_var_extra: ncid 0x%x varid %d", ncid, varid));
748
749   /* Find info for this file and group, and set pointer to each. */
750   if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
751      return retval;
752
753   /* Attempting to do any of these things on a netCDF-3 file produces
754    * an error. */
755   if (!h5)
756      return NC_ENOTNC4;
757
758   assert(nc && grp && h5);
759
760   /* Find the var. */
761   for (var = grp->var; var; var = var->next)
762      if (var->varid == varid)
763         break;
764   
765   /* Oh no! Maybe we couldn't find it (*sob*)! */
766   if (!var)
767      return NC_ENOTVAR;
768
769   /* Can't turn on contiguous and deflate/fletcher32/szip. */
770   if (contiguous)
771      if ((*contiguous != NC_CHUNKED && deflate) || 
772          (*contiguous != NC_CHUNKED && fletcher32) ||
773          (*contiguous != NC_CHUNKED && options_mask))
774         return NC_EINVAL;
775
776   /* If the HDF5 dataset has already been created, then it is too
777    * late to set all the extra stuff. */
778   if (var->created)
779      return NC_ELATEDEF;
780
781   /* Check compression options. */
782   if ((deflate && options_mask) ||
783       (deflate && !deflate_level) ||
784       (options_mask && !pixels_per_block))
785      return NC_EINVAL;     
786       
787   /* Valid deflate level? */
788   if (deflate && deflate_level)
789   {
790      if (*deflate)
791         if (*deflate_level < MIN_DEFLATE_LEVEL ||
792             *deflate_level > MAX_DEFLATE_LEVEL)
793            return NC_EINVAL;
794      if (var->options_mask)
795            return NC_EINVAL;
796
797      /* For scalars, just ignore attempt to deflate. */
798      if (!var->ndims)
799            return NC_NOERR;
800
801      /* Well, if we couldn't find any errors, I guess we have to take
802       * the users settings. Darn! */
803      var->contiguous = 0;
804      var->deflate = *deflate;
805      if (*deflate)
806         var->deflate_level = *deflate_level;
807      LOG((3, "nc_def_var_extra: *deflate_level %d", *deflate_level));     
808   }
809
810   /* Szip in use? */
811   if (options_mask)
812   {
813#ifndef USE_SZIP
814      return NC_EINVAL;
815#endif
816      if (var->deflate)
817         return NC_EINVAL;
818      if ((*options_mask != NC_SZIP_EC_OPTION_MASK) &&
819          (*options_mask != NC_SZIP_NN_OPTION_MASK))
820         return NC_EINVAL;
821      if ((*pixels_per_block > NC_SZIP_MAX_PIXELS_PER_BLOCK) ||
822          (var->type_info->nc_typeid >= NC_STRING))
823         return NC_EINVAL;
824      var->options_mask = *options_mask;
825      var->pixels_per_block = *pixels_per_block;
826      var->contiguous = 0;
827   }
828
829   /* Shuffle filter? */
830   if (shuffle)
831   {
832      var->shuffle = *shuffle;
833      var->contiguous = 0;
834   }
835
836   /* Fltcher32 checksum error protection? */
837   if (fletcher32)
838   {
839      var->fletcher32 = *fletcher32;
840      var->contiguous = 0;
841   }
842   
843   /* Does the user want a contiguous dataset? Not so fast! Make sure
844    * that there are no unlimited dimensions, and no filters in use
845    * for this data. */
846   if (contiguous && *contiguous)
847   {
848      if (var->deflate || var->fletcher32 || var->shuffle || var->options_mask)
849         return NC_EINVAL;
850     
851      for (d = 0; d < var->ndims; d++)
852      {
853         if ((retval = nc4_find_dim(grp, var->dimids[d], &dim, NULL)))
854            return retval;
855         if (dim->unlimited)
856            return NC_EINVAL;
857      }
858
859      var->contiguous = NC_CONTIGUOUS;
860   }
861
862   /* Chunksizes anyone? */
863   if (contiguous && *contiguous == NC_CHUNKED)
864   {
865      var->contiguous = 0;
866
867      /* If the user provided chunksizes, check that they are not too
868       * big, and that their total size of chunk is less than 4 GB. */
869      if (chunksizes)
870      {
871
872         if ((retval = check_chunksizes(grp, var, chunksizes)))
873            return retval;
874
875         /* Set the chunksizes for this variable. */
876         for (d = 0; d < var->ndims; d++)
877            var->chunksizes[d] = chunksizes[d];
878      }
879   }
880
881   /* Is this a variable with a chunksize greater than the current
882    * cache size? */
883   if (var->contiguous == NC_CHUNKED && (chunksizes || deflate || contiguous))
884   {
885      /* Determine default chunksizes for this variable. */
886      if (!var->chunksizes[0])
887         if ((retval = nc4_find_default_chunksizes2(grp, var)))
888            return retval;
889
890      /* Adjust the cache. */
891      if ((retval = nc4_adjust_var_cache(grp, var)))
892         return retval;
893   }
894
895   /* Are we setting a fill modes? */
896   if (no_fill)
897   {
898      if (*no_fill)
899         var->no_fill = 1;
900      else
901         var->no_fill = 0;
902   }
903
904   /* Are we setting a fill value? */
905   if (fill_value && !var->no_fill)
906   {
907      /* If fill value hasn't been set, allocate space. */
908      if ((retval = nc4_get_typelen_mem(h5, var->xtype, 0, &type_size)))
909         return retval;
910      if (!var->fill_value)
911         if (!(var->fill_value = malloc(type_size)))
912            return NC_ENOMEM;
913
914      /* Copy the fill_value. */
915      LOG((4, "Copying fill value into metadata for variable %s", 
916           var->name));
917      memcpy(var->fill_value, fill_value, type_size);
918
919      /* If there's a _FillValue attribute, delete it. */
920      retval = nc_del_att(ncid, varid, _FillValue);
921      if (retval && retval != NC_ENOTATT)
922         return retval;
923
924      /* Create a _FillValue attribute. */
925      if ((retval = nc_put_att(ncid, varid, _FillValue, var->xtype, 1, fill_value)))
926         return retval;
927   }
928
929   /* Is the user setting the endianness? */
930   if (endianness)
931      var->type_info->endianness = *endianness;
932
933   return NC_NOERR;
934}
935
936/* Set the deflate level for a var, lower is faster, higher is
937 * better. Must be called after nc_def_var and before nc_enddef or any
938 * functions which writes data to the file. */
939int
940NC4_def_var_deflate(int ncid, int varid, int shuffle, int deflate, 
941                   int deflate_level)
942{
943   return nc_def_var_extra(ncid, varid, &shuffle, &deflate, 
944                           &deflate_level, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
945}
946
947/* Set checksum for a var. This must be called after the nc_def_var
948 * but before the nc_enddef. */
949int
950NC4_def_var_fletcher32(int ncid, int varid, int fletcher32)
951{
952   return nc_def_var_extra(ncid, varid, NULL, NULL, NULL, &fletcher32, 
953                           NULL, NULL, NULL, NULL, NULL, NULL, NULL);
954}
955   
956/* Define chunking stuff for a var. This must be done after nc_def_var
957   and before nc_enddef.
958
959   Chunking is required in any dataset with one or more unlimited
960   dimension in HDF5, or any dataset using a filter.
961
962   Where chunksize is a pointer to an array of size ndims, with the
963   chunksize in each dimension.
964*/
965int
966NC4_def_var_chunking(int ncid, int varid, int contiguous, const size_t *chunksizesp)
967{
968   return nc_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL, 
969                           &contiguous, chunksizesp, NULL, NULL, NULL, NULL, NULL);
970}
971
972/* Inquire about chunking stuff for a var. This is a private,
973 * undocumented function, used by the f77 API to avoid size_t
974 * problems. */
975int
976nc_inq_var_chunking_ints(int ncid, int varid, int *contiguousp, int *chunksizesp)
977{
978   NC_FILE_INFO_T *nc;
979   NC_GRP_INFO_T *grp; 
980   NC_HDF5_FILE_INFO_T *h5;
981   NC_VAR_INFO_T *var;
982   size_t *cs = NULL;
983   int i, retval;
984
985   /* Find this ncid's file info. */
986   if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
987      return retval;
988   assert(nc);
989
990   /* Must be netcdf-4. */
991   if (!h5)
992      return NC_ENOTNC4;
993
994   /* Find var cause I need the number of dims. */
995   if ((retval = nc4_find_g_var_nc(nc, ncid, varid, &grp, &var)))
996      return retval;
997   
998   /* Allocate space for the size_t copy of the chunksizes array. */
999   if (var->ndims)
1000      if (!(cs = malloc(var->ndims * sizeof(size_t))))
1001         return NC_ENOMEM;
1002   
1003   retval = NC4_inq_var_all(ncid, varid, NULL, NULL, NULL, NULL, NULL, 
1004                           NULL, NULL, NULL, NULL, contiguousp, cs, NULL,
1005                           NULL, NULL, NULL, NULL);
1006
1007   /* Copy to size_t array. */
1008   if (*contiguousp == NC_CHUNKED)
1009      for (i = 0; i < var->ndims; i++)
1010      {
1011         chunksizesp[i] = cs[i];
1012         if (cs[i] > NC_MAX_INT)
1013            retval = NC_ERANGE;
1014      }
1015
1016   if (var->ndims)
1017      free(cs);
1018   return retval;
1019}
1020
1021/* This function defines the chunking with ints, which works better
1022 * with F77 portability. It is a secret function, which has been
1023 * rendered unmappable, and it is impossible to apparate anywhere in
1024 * this function. */
1025int
1026nc_def_var_chunking_ints(int ncid, int varid, int contiguous, int *chunksizesp)
1027{
1028   NC_FILE_INFO_T *nc;
1029   NC_GRP_INFO_T *grp; 
1030   NC_HDF5_FILE_INFO_T *h5;
1031   NC_VAR_INFO_T *var;
1032   size_t *cs = NULL;
1033   int i, retval;
1034
1035   /* Find this ncid's file info. */
1036   if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
1037      return retval;
1038   assert(nc);
1039
1040   /* Must be netcdf-4. */
1041   if (!h5)
1042      return NC_ENOTNC4;
1043
1044   /* Find var cause I need the number of dims. */
1045   if ((retval = nc4_find_g_var_nc(nc, ncid, varid, &grp, &var)))
1046      return retval;
1047   
1048   /* Allocate space for the size_t copy of the chunksizes array. */
1049   if (var->ndims)
1050      if (!(cs = malloc(var->ndims * sizeof(size_t))))
1051         return NC_ENOMEM;
1052   
1053   /* Copy to size_t array. */
1054   for (i = 0; i < var->ndims; i++)
1055      cs[i] = chunksizesp[i];
1056
1057   retval = nc_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL, 
1058                             &contiguous, cs, NULL, NULL, NULL, NULL, NULL);
1059
1060   if (var->ndims)
1061      free(cs);
1062   return retval;
1063}
1064
1065/* Define fill value behavior for a variable. This must be done after
1066   nc_def_var and before nc_enddef. */
1067int
1068NC4_def_var_fill(int ncid, int varid, int no_fill, const void *fill_value)
1069{
1070   return nc_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL, NULL, 
1071                           NULL, &no_fill, fill_value, NULL, NULL, NULL);
1072}
1073
1074
1075/* Define the endianness of a variable. */
1076int
1077NC4_def_var_endian(int ncid, int varid, int endianness)
1078{
1079   return nc_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL, NULL,
1080                           NULL, NULL, NULL, &endianness, NULL, NULL);
1081}
1082
1083/* Get var id from name. */
1084int
1085NC4_inq_varid(int ncid, const char *name, int *varidp)
1086{
1087   NC_FILE_INFO_T *nc;
1088   NC_GRP_INFO_T *grp; 
1089   NC_HDF5_FILE_INFO_T *h5;
1090   NC_VAR_INFO_T *var;
1091   char norm_name[NC_MAX_NAME + 1];
1092   int retval;
1093   
1094   if (!name)
1095      return NC_EINVAL;
1096   if (!varidp)
1097      return NC_NOERR;
1098
1099   LOG((2, "nc_inq_varid: ncid 0x%x name %s", ncid, name));
1100   
1101   /* Find info for this file and group, and set pointer to each. */
1102   if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
1103      return retval;
1104   
1105   /* Handle netcdf-3. */
1106   assert(h5);
1107   
1108   /* Normalize name. */
1109   if ((retval = nc4_normalize_name(name, norm_name)))
1110      return retval;
1111
1112   /* Find var of this name. */
1113   for (var = grp->var; var; var = var->next)
1114      if (!(strcmp(var->name, norm_name)))
1115      {
1116         *varidp = var->varid;
1117         return NC_NOERR;
1118      }
1119
1120   return NC_ENOTVAR;
1121}
1122
1123/* Rename a var to "bubba," for example.
1124   
1125   According to the netcdf-3.5 docs: If the new name is longer than
1126   the old name, the netCDF dataset must be in define mode.  */
1127int
1128NC4_rename_var(int ncid, int varid, const char *name)
1129{
1130   NC_FILE_INFO_T *nc;
1131   NC_GRP_INFO_T *grp; 
1132   NC_HDF5_FILE_INFO_T *h5;
1133   NC_VAR_INFO_T *var;
1134   int retval = NC_NOERR;
1135
1136   LOG((2, "nc_rename_var: ncid 0x%x varid %d name %s", 
1137        ncid, varid, name));
1138
1139   /* Find info for this file and group, and set pointer to each. */
1140   if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
1141      return retval;
1142   
1143#ifdef USE_PNETCDF
1144   /* Take care of files created/opened with parallel-netcdf library. */
1145   if (nc->pnetcdf_file)
1146      return ncmpi_rename_var(nc->int_ncid, varid, name);
1147#endif /* USE_PNETCDF */
1148
1149   /* Take care of netcdf-3 files. */
1150   assert(h5);
1151
1152   /* Is the new name too long? */
1153   if (strlen(name) > NC_MAX_NAME)
1154      return NC_EMAXNAME;
1155
1156   /* Trying to write to a read-only file? No way, Jose! */
1157   if (h5->no_write)
1158      return NC_EPERM;
1159
1160   /* Check name validity, if strict nc3 rules are in effect for this
1161    * file. */
1162   if ((retval = NC_check_name(name)))
1163      return retval;
1164
1165   /* Is name in use? */
1166   for (var = grp->var; var; var = var->next)
1167      if (!strncmp(var->name, name, NC_MAX_NAME))
1168         return NC_ENAMEINUSE;   
1169
1170   /* Find the var. */
1171   for (var = grp->var; var; var = var->next)
1172      if (var->varid == varid)
1173         break;
1174   if (!var)
1175      return NC_ENOTVAR;
1176
1177   /* If we're not in define mode, new name must be of equal or
1178      less size, if strict nc3 rules are in effect for this . */
1179   if (!(h5->flags & NC_INDEF) && strlen(name) > strlen(var->name) &&
1180       (h5->cmode & NC_CLASSIC_MODEL))
1181      return NC_ENOTINDEFINE;
1182
1183   /* Change the HDF5 file, if this var has already been created
1184      there. */
1185   if (var->created)
1186   {
1187      if (H5Gmove(grp->hdf_grpid, var->name, name) < 0)
1188         BAIL(NC_EHDFERR);
1189   }
1190
1191   /* Now change the name in our metadata. */
1192   free(var->name);
1193   if (!(var->name = malloc((strlen(name) + 1) * sizeof(char))))
1194      return NC_ENOMEM;
1195   strcpy(var->name, name);
1196
1197  exit:
1198   return retval;
1199}
1200
1201
1202int
1203NC4_var_par_access(int ncid, int varid, int par_access) 
1204{
1205#ifndef USE_PARALLEL
1206   return NC_ENOPAR;
1207#else
1208   NC_FILE_INFO_T *nc; 
1209   NC_GRP_INFO_T *grp; 
1210   NC_HDF5_FILE_INFO_T *h5;
1211   NC_VAR_INFO_T *var;
1212   int retval;
1213
1214   LOG((1, "nc_var_par_access: ncid 0x%x varid %d par_access %d", ncid, 
1215        varid, par_access));
1216
1217   if (par_access != NC_INDEPENDENT && par_access != NC_COLLECTIVE)
1218      return NC_EINVAL;
1219   
1220   /* Find info for this file and group, and set pointer to each. */
1221   if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
1222      return retval;
1223
1224#ifdef USE_PNETCDF
1225   /* Handle files opened/created with parallel-netcdf library. */
1226   if (nc->pnetcdf_file)
1227   {
1228      if (par_access == nc->pnetcdf_access_mode)
1229         return NC_NOERR;
1230
1231      nc->pnetcdf_access_mode = par_access;
1232      if (par_access == NC_INDEPENDENT)
1233         return ncmpi_begin_indep_data(nc->int_ncid);
1234      else
1235         return ncmpi_end_indep_data(nc->int_ncid);
1236   }
1237#endif /* USE_PNETCDF */   
1238   
1239   /* This function only for files opened with nc_open_par or nc_create_par. */
1240   if (!h5->parallel)
1241      return NC_ENOPAR;
1242
1243   /* Find the var, and set its preference. */
1244   for (var = grp->var; var; var = var->next)
1245      if (var->varid == varid)
1246         break;
1247   if (!var)
1248      return NC_ENOTVAR;
1249
1250   if (par_access) 
1251      var->parallel_access = NC_COLLECTIVE;
1252   else
1253      var->parallel_access = NC_INDEPENDENT;
1254   return NC_NOERR;
1255#endif /* USE_PARALLEL */
1256}
1257
1258static int
1259nc4_put_vara_tc(int ncid, int varid, nc_type mem_type, int mem_type_is_long, 
1260                const size_t *startp, const size_t *countp, const void *op)
1261{
1262   NC_FILE_INFO_T *nc;
1263
1264   LOG((2, "nc4_put_vara_tc: ncid 0x%x varid %d mem_type %d mem_type_is_long %d", 
1265        ncid, varid, mem_type, mem_type_is_long));
1266
1267   if (!(nc = nc4_find_nc_file(ncid)))
1268      return NC_EBADID;
1269   
1270#ifdef USE_PNETCDF
1271   /* Handle files opened/created with the parallel-netcdf library. */
1272   if (nc->pnetcdf_file)
1273   {
1274      MPI_Offset mpi_start[NC_MAX_DIMS], mpi_count[NC_MAX_DIMS];
1275      int d;
1276
1277      /* No NC_LONGs for parallel-netcdf library! */
1278      if (mem_type_is_long)
1279         return NC_EINVAL;
1280     
1281      /* We must convert the start, count, and stride arrays to
1282       * MPI_Offset type. */
1283      for (d = 0; d < nc->pnetcdf_ndims[varid]; d++)
1284      {
1285         mpi_start[d] = startp[d];
1286         mpi_count[d] = countp[d];
1287      }
1288
1289      if (nc->pnetcdf_access_mode == NC_INDEPENDENT)
1290      {
1291         switch(mem_type)
1292         {
1293            case NC_BYTE:
1294               return ncmpi_put_vara_schar(nc->int_ncid, varid, mpi_start, mpi_count, op);
1295            case NC_UBYTE:
1296               return ncmpi_put_vara_uchar(nc->int_ncid, varid, mpi_start, mpi_count, op);
1297            case NC_CHAR:
1298               return ncmpi_put_vara_text(nc->int_ncid, varid, mpi_start, mpi_count, op);
1299            case NC_SHORT:
1300               return ncmpi_put_vara_short(nc->int_ncid, varid, mpi_start, mpi_count, op);
1301            case NC_INT:
1302               return ncmpi_put_vara_int(nc->int_ncid, varid, mpi_start, mpi_count, op);
1303            case NC_FLOAT:
1304               return ncmpi_put_vara_float(nc->int_ncid, varid, mpi_start, mpi_count, op);
1305            case NC_DOUBLE:
1306               return ncmpi_put_vara_double(nc->int_ncid, varid, mpi_start, mpi_count, op);
1307            case NC_NAT:
1308            default:
1309               return NC_EBADTYPE;
1310         }
1311      } 
1312      else
1313      {
1314         switch(mem_type)
1315         {
1316            case NC_BYTE:
1317               return ncmpi_put_vara_schar_all(nc->int_ncid, varid, mpi_start, mpi_count, op);
1318            case NC_UBYTE:
1319               return ncmpi_put_vara_uchar_all(nc->int_ncid, varid, mpi_start, mpi_count, op);
1320            case NC_CHAR:
1321               return ncmpi_put_vara_text_all(nc->int_ncid, varid, mpi_start, mpi_count, op);
1322            case NC_SHORT:
1323               return ncmpi_put_vara_short_all(nc->int_ncid, varid, mpi_start, mpi_count, op);
1324            case NC_INT:
1325               return ncmpi_put_vara_int_all(nc->int_ncid, varid, mpi_start, mpi_count, op);
1326            case NC_FLOAT:
1327               return ncmpi_put_vara_float_all(nc->int_ncid, varid, mpi_start, mpi_count, op);
1328            case NC_DOUBLE:
1329               return ncmpi_put_vara_double_all(nc->int_ncid, varid, mpi_start, mpi_count, op);
1330            case NC_NAT:
1331            default:
1332               return NC_EBADTYPE;
1333         }
1334      }
1335   }
1336#endif /* USE_PNETCDF */   
1337   
1338   /* NetCDF-3 cases handled by dispatch layer. */
1339   assert(nc->nc4_info);
1340
1341   return nc4_put_vara(nc, ncid, varid, startp, countp, mem_type, 
1342                       mem_type_is_long, (void *)op);
1343}
1344
1345int 
1346nc4_get_hdf4_vara(NC_FILE_INFO_T *nc, int ncid, int varid, const size_t *startp, 
1347                  const size_t *countp, nc_type mem_nc_type, int is_long, void *data)
1348{
1349#ifdef USE_HDF4   
1350   NC_GRP_INFO_T *grp, *g;
1351   NC_HDF5_FILE_INFO_T *h5;
1352   NC_VAR_INFO_T *var;
1353   NC_DIM_INFO_T *dim;
1354   int32 start32[NC_MAX_VAR_DIMS], edge32[NC_MAX_VAR_DIMS];
1355   int retval, d;
1356   
1357   /* Find our metadata for this file, group, and var. */
1358   assert(nc);
1359   if ((retval = nc4_find_g_var_nc(nc, ncid, varid, &grp, &var)))
1360      return retval;
1361   h5 = nc->nc4_info;
1362   assert(grp && h5 && var && var->name);
1363   
1364   for (d = 0; d < var->ndims; d++)
1365   {
1366      start32[d] = startp[d];
1367      edge32[d] = countp[d];
1368   }
1369   
1370   if (SDreaddata(var->sdsid, start32, NULL, edge32, data))
1371      return NC_EHDFERR;
1372
1373#endif /* USE_HDF4 */
1374   return NC_NOERR;
1375}
1376
1377/* Get an array. */
1378static int
1379nc4_get_vara_tc(int ncid, int varid, nc_type mem_type, int mem_type_is_long,
1380                const size_t *startp, const size_t *countp, void *ip)
1381{
1382   NC_FILE_INFO_T *nc;
1383
1384   LOG((2, "nc4_get_vara_tc: ncid 0x%x varid %d mem_type %d mem_type_is_long %d", 
1385        ncid, varid, mem_type, mem_type_is_long));
1386
1387   if (!(nc = nc4_find_nc_file(ncid)))
1388      return NC_EBADID;
1389   
1390#ifdef USE_PNETCDF
1391   /* Handle files opened/created with the parallel-netcdf library. */
1392   if (nc->pnetcdf_file)
1393   {
1394      MPI_Offset mpi_start[NC_MAX_VAR_DIMS], mpi_count[NC_MAX_VAR_DIMS];
1395      int d;
1396
1397      /* No NC_LONGs for parallel-netcdf library! */
1398      if (mem_type_is_long)
1399         return NC_EINVAL;
1400     
1401      /* We must convert the start, count, and stride arrays to
1402       * MPI_Offset type. */
1403      for (d = 0; d < nc->pnetcdf_ndims[varid]; d++)
1404      {
1405         mpi_start[d] = startp[d];
1406         mpi_count[d] = countp[d];
1407      }
1408
1409      if (nc->pnetcdf_access_mode == NC_INDEPENDENT)
1410      {
1411         switch(mem_type)
1412         {
1413            case NC_BYTE:
1414               return ncmpi_get_vara_schar(nc->int_ncid, varid, mpi_start, mpi_count, ip);
1415            case NC_UBYTE:
1416               return ncmpi_get_vara_uchar(nc->int_ncid, varid, mpi_start, mpi_count, ip);
1417            case NC_CHAR:
1418               return ncmpi_get_vara_text(nc->int_ncid, varid, mpi_start, mpi_count, ip);
1419            case NC_SHORT:
1420               return ncmpi_get_vara_short(nc->int_ncid, varid, mpi_start, mpi_count, ip);
1421            case NC_INT:
1422               return ncmpi_get_vara_int(nc->int_ncid, varid, mpi_start, mpi_count, ip);
1423            case NC_FLOAT:
1424               return ncmpi_get_vara_float(nc->int_ncid, varid, mpi_start, mpi_count, ip);
1425            case NC_DOUBLE:
1426               return ncmpi_get_vara_double(nc->int_ncid, varid, mpi_start, mpi_count, ip);
1427            case NC_NAT:
1428            default:
1429               return NC_EBADTYPE;
1430         }
1431      } 
1432      else
1433      {
1434         switch(mem_type)
1435         {
1436            case NC_BYTE:
1437               return ncmpi_get_vara_schar_all(nc->int_ncid, varid, mpi_start, mpi_count, ip);
1438            case NC_UBYTE:
1439               return ncmpi_get_vara_uchar_all(nc->int_ncid, varid, mpi_start, mpi_count, ip);
1440            case NC_CHAR:
1441               return ncmpi_get_vara_text_all(nc->int_ncid, varid, mpi_start, mpi_count, ip);
1442            case NC_SHORT:
1443               return ncmpi_get_vara_short_all(nc->int_ncid, varid, mpi_start, mpi_count, ip);
1444            case NC_INT:
1445               return ncmpi_get_vara_int_all(nc->int_ncid, varid, mpi_start, mpi_count, ip);
1446            case NC_FLOAT:
1447               return ncmpi_get_vara_float_all(nc->int_ncid, varid, mpi_start, mpi_count, ip);
1448            case NC_DOUBLE:
1449               return ncmpi_get_vara_double_all(nc->int_ncid, varid, mpi_start, mpi_count, ip);
1450            case NC_NAT:
1451            default:
1452               return NC_EBADTYPE;
1453         }
1454      }
1455   }
1456#endif /* USE_PNETCDF */   
1457   
1458   /* Handle netCDF-3 cases. */
1459   assert(nc->nc4_info);
1460
1461   /* Handle HDF4 cases. */
1462   if (nc->nc4_info->hdf4)
1463      return nc4_get_hdf4_vara(nc, ncid, varid, startp, countp, mem_type, 
1464                               mem_type_is_long, (void *)ip);
1465   
1466   /* Handle HDF5 cases. */
1467   return nc4_get_vara(nc, ncid, varid, startp, countp, mem_type, 
1468                       mem_type_is_long, (void *)ip);
1469}
1470
1471int
1472NC4_put_vara(int ncid, int varid, const size_t *startp, 
1473            const size_t *countp, const void *op, int memtype)
1474{
1475   return nc4_put_vara_tc(ncid, varid, memtype, 0, startp, countp, op);
1476}
1477
1478
1479/* Read an array of values. */
1480int
1481NC4_get_vara(int ncid, int varid, const size_t *startp, 
1482            const size_t *countp, void *ip, int memtype)
1483{
1484   return nc4_get_vara_tc(ncid, varid, memtype, 0, startp, countp, ip);
1485}
Note: See TracBrowser for help on using the repository browser.