source: XIOS/branchs/xios-1.0/src/output/onetcdf4.cpp @ 606

Last change on this file since 606 was 606, checked in by rlacroix, 6 years ago

Support NetCDF4 compression.

Only available for non-parallel output so either if only one server is used or if the multiple file mode is enabled).

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
File size: 18.2 KB
Line 
1#include "onetcdf4.hpp"
2#include "group_template.hpp"
3#include "mpi.hpp"
4#include "netcdf.hpp"
5#include "netCdfInterface.hpp"
6#include "netCdfException.hpp"
7
8namespace xios
9{
10      /// ////////////////////// Définitions ////////////////////// ///
11
12      CONetCDF4::CONetCDF4
13         (const StdString & filename, bool exist, const MPI_Comm * comm, bool multifile)
14            : path()
15            , wmpi(false)
16      {
17         this->initialize(filename, exist, comm,multifile);
18      }
19
20      //---------------------------------------------------------------
21
22
23      CONetCDF4::~CONetCDF4(void)
24      {
25//         CheckError(nc_close(this->ncidp));
26      }
27
28      ///--------------------------------------------------------------
29
30      void CONetCDF4::initialize
31         (const StdString & filename, bool exist, const MPI_Comm * comm, bool multifile)
32      {
33         // Don't use parallel mode if there is only one process
34         if (comm)
35         {
36            int commSize = 0;
37            MPI_Comm_size(*comm, &commSize);
38            if (commSize <= 1)
39               comm = NULL;
40         }
41         wmpi = comm && !multifile;
42
43         if (!exist)
44         {
45            if (wmpi)
46               CNetCdfInterface::createPar(filename, NC_NETCDF4|NC_MPIIO, *comm, MPI_INFO_NULL, this->ncidp);
47            else
48               CNetCdfInterface::create(filename, NC_NETCDF4, this->ncidp);
49         }
50         else
51         {
52            if (wmpi)
53               CNetCdfInterface::openPar(filename, NC_NETCDF4|NC_MPIIO, *comm, MPI_INFO_NULL, this->ncidp);
54            else
55               CNetCdfInterface::open(filename, NC_NETCDF4, this->ncidp);
56         }
57      }
58
59      void CONetCDF4::close()
60      {
61        (CNetCdfInterface::close(this->ncidp));
62      }
63
64      //---------------------------------------------------------------
65
66      void CONetCDF4::definition_start(void)
67      {
68         (CNetCdfInterface::reDef(this->ncidp));
69      }
70
71      //---------------------------------------------------------------
72
73      void CONetCDF4::definition_end(void)
74      {
75         (CNetCdfInterface::endDef(this->ncidp));
76      }
77
78      //---------------------------------------------------------------
79
80// Don't need it anymore?
81//      void CONetCDF4::CheckError(int status)
82//      {
83//         if (status != NC_NOERR)
84//         {
85//            StdString errormsg (nc_strerror(status)); // fuite mémoire ici ?
86//            ERROR("CONetCDF4::CheckError(int status)",
87//                  << "[ status = " << status << " ] " << errormsg);
88//         }
89//      }
90
91      //---------------------------------------------------------------
92
93      int CONetCDF4::getCurrentGroup(void)
94      {
95         return (this->getGroup(this->getCurrentPath()));
96      }
97
98      //---------------------------------------------------------------
99
100      int CONetCDF4::getGroup(const CONetCDF4Path & path)
101      {
102         int retvalue = this->ncidp;
103
104         CONetCDF4Path::const_iterator
105            it  = path.begin(), end = path.end();
106
107         for (;it != end; it++)
108         {
109            const StdString & groupid = *it;
110            (CNetCdfInterface::inqNcId(retvalue, groupid, retvalue));
111         }
112         return (retvalue);
113      }
114
115      //---------------------------------------------------------------
116
117      int CONetCDF4::getVariable(const StdString & varname)
118      {
119         int varid = 0;
120         int grpid = this->getCurrentGroup();
121         (CNetCdfInterface::inqVarId(grpid, varname, varid));
122         return (varid);
123      }
124
125      //---------------------------------------------------------------
126
127      int CONetCDF4::getDimension(const StdString & dimname)
128      {
129         int dimid = 0;
130         int grpid = this->getCurrentGroup();
131         (CNetCdfInterface::inqDimId(grpid, dimname, dimid));
132         return (dimid);
133      }
134
135      //---------------------------------------------------------------
136
137      int CONetCDF4::getUnlimitedDimension(void)
138      {
139         int dimid = 0;
140         int grpid = this->getCurrentGroup();
141         (CNetCdfInterface::inqUnLimDim(grpid, dimid));
142         return (dimid);
143      }
144
145      StdString CONetCDF4::getUnlimitedDimensionName(void)
146      {
147         int grpid = this->getGroup(path);
148         int dimid = this->getUnlimitedDimension();
149
150         if (dimid == -1) return (std::string());
151         StdString dimname;
152         (CNetCdfInterface::inqDimName(grpid, dimid, dimname));
153
154         return (dimname);
155      }
156
157      //---------------------------------------------------------------
158
159      std::vector<StdSize> CONetCDF4::getDimensions(const StdString & varname)
160      {
161         StdSize size = 0;
162         std::vector<StdSize> retvalue;
163         int grpid = this->getCurrentGroup();
164         int varid = this->getVariable(varname);
165         int nbdim = 0, *dimid = NULL;
166
167         (CNetCdfInterface::inqVarNDims(grpid, varid, nbdim));
168         dimid = new int[nbdim]();
169         (CNetCdfInterface::inqVarDimId(grpid, varid, dimid));
170
171         for (int i = 0; i < nbdim; i++)
172         {
173            (CNetCdfInterface::inqDimLen(grpid, dimid[i], size));
174            if (size == NC_UNLIMITED)
175                size = UNLIMITED_DIM;
176            retvalue.push_back(size);
177         }
178         delete [] dimid;
179         return (retvalue);
180      }
181
182      std::vector<std::string> CONetCDF4::getDimensionsIdList (const std::string * _varname)
183      {
184         int nDimNull = 0;
185         int nbdim = 0, *dimid = NULL;
186         int grpid = this->getCurrentGroup();
187         int varid = (_varname != NULL) ? this->getVariable(*_varname) : NC_GLOBAL;
188         std::vector<std::string> retvalue;
189
190         if (_varname != NULL)
191         {
192            (CNetCdfInterface::inqVarNDims(grpid, varid, nbdim));
193            dimid = new int[nbdim]();
194            (CNetCdfInterface::inqVarDimId(grpid, varid, dimid));
195         }
196         else
197         {
198            (CNetCdfInterface::inqDimIds(grpid, nbdim, NULL, 1));
199            dimid = new int[nbdim]();
200            (CNetCdfInterface::inqDimIds(grpid, nDimNull, dimid, 1));
201         }
202
203         for (int i = 0; i < nbdim; i++)
204         {
205            std::string dimname;
206            (CNetCdfInterface::inqDimName(grpid, dimid[i], dimname));
207            retvalue.push_back(dimname);
208         }
209         delete [] dimid;
210
211         return (retvalue);
212      }
213
214
215      //---------------------------------------------------------------
216
217      const CONetCDF4::CONetCDF4Path & CONetCDF4::getCurrentPath(void) const
218      { return (this->path); }
219
220      void CONetCDF4::setCurrentPath(const CONetCDF4Path & path)
221      { this->path = path; }
222
223      //---------------------------------------------------------------
224
225      int CONetCDF4::addGroup(const StdString & name)
226      {
227         int retvalue = 0;
228         int grpid = this->getCurrentGroup();
229         (CNetCdfInterface::defGrp(grpid, name, retvalue));
230         return (retvalue);
231      }
232
233      //---------------------------------------------------------------
234
235      int CONetCDF4::addDimension(const StdString& name, const StdSize size)
236      {
237         int retvalue = 0;
238         int grpid = this->getCurrentGroup();
239         if (size != UNLIMITED_DIM)
240            (CNetCdfInterface::defDim(grpid, name, size, retvalue));
241         else
242            (CNetCdfInterface::defDim(grpid, name, NC_UNLIMITED, retvalue));
243         return (retvalue);
244      }
245
246      //---------------------------------------------------------------
247
248      int CONetCDF4::addVariable(const StdString & name, nc_type type,
249                                  const std::vector<StdString> & dim)
250      {
251         int varid = 0;
252         std::vector<int> dimids;
253         std::vector<StdSize> dimsizes ;
254         StdSize size ;
255         StdSize totalSize ;
256         StdSize maxSize=1024*1024*256 ; // == 2GB/8 if output double
257
258         int grpid = this->getCurrentGroup();
259
260         std::vector<StdString>::const_iterator
261            it  = dim.begin(), end = dim.end();
262
263         for (;it != end; it++)
264         {
265            const StdString & dimid = *it;
266            dimids.push_back(this->getDimension(dimid));
267            (CNetCdfInterface::inqDimLen(grpid, this->getDimension(dimid), size));
268            if (size==NC_UNLIMITED) size=1 ;
269            dimsizes.push_back(size) ;
270         }
271
272         (CNetCdfInterface::defVar(grpid, name, type, dimids.size(), &(dimids[0]), varid));
273
274// set chunksize : size of one record
275// but must not be > 2GB (netcdf or HDF5 problem)
276         totalSize=1 ;
277         for(vector<StdSize>::reverse_iterator it=dimsizes.rbegin(); it!=dimsizes.rend();++it)
278         {
279           totalSize*= *it ;
280           if (totalSize>=maxSize) *it=1 ;
281         }
282
283         (CNetCdfInterface::defVarChunking(grpid, varid, NC_CHUNKED, &(dimsizes[0])));
284         (CNetCdfInterface::defVarFill(grpid, varid, true, NULL));
285         return (varid);
286      }
287
288      //---------------------------------------------------------------
289
290      void CONetCDF4::setCompressionLevel(const StdString& varname, int compressionLevel)
291      {
292         int grpid = this->getCurrentGroup();
293         int varid = this->getVariable(varname);
294         CNetCdfInterface::defVarDeflate(grpid, varid, compressionLevel);
295      }
296
297      //---------------------------------------------------------------
298
299      template <>
300         void CONetCDF4::addAttribute
301            (const StdString & name, const StdString & value, const StdString * varname )
302      {
303         int grpid = this->getCurrentGroup();
304         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
305         (CNetCdfInterface::putAtt(grpid, varid, name, NC_CHAR, value.size(), value.c_str()));
306         //CheckError(nc_put_att_string(grpid, varid, name.c_str(), 1, &str));
307      }
308
309      //---------------------------------------------------------------
310
311      template <>
312         void CONetCDF4::addAttribute
313            (const StdString & name, const double & value, const StdString * varname )
314      {
315         int grpid = this->getCurrentGroup();
316         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
317         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
318      }
319
320       template <>
321         void CONetCDF4::addAttribute
322            (const StdString & name, const CArray<double,1>& value, const StdString * varname )
323      {
324         int grpid = this->getCurrentGroup();
325         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
326         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
327      }
328      //---------------------------------------------------------------
329
330      template <>
331         void CONetCDF4::addAttribute
332            (const StdString & name, const float & value, const StdString * varname )
333      {
334         int grpid = this->getCurrentGroup();
335         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
336         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
337      }
338
339       template <>
340         void CONetCDF4::addAttribute
341            (const StdString & name, const CArray<float,1>& value, const StdString * varname )
342      {
343         int grpid = this->getCurrentGroup();
344         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
345         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
346      }
347
348      //---------------------------------------------------------------
349
350      template <>
351         void CONetCDF4::addAttribute
352            (const StdString & name, const int & value, const StdString * varname )
353      {
354         int grpid = this->getCurrentGroup();
355         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
356         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
357      }
358
359       template <>
360         void CONetCDF4::addAttribute
361            (const StdString & name, const CArray<int,1>& value, const StdString * varname )
362      {
363         int grpid = this->getCurrentGroup();
364         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
365         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
366      }
367
368      template <>
369         void CONetCDF4::addAttribute
370            (const StdString & name, const short int & value, const StdString * varname )
371      {
372         int grpid = this->getCurrentGroup();
373         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
374         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
375      }
376
377       template <>
378         void CONetCDF4::addAttribute
379            (const StdString & name, const CArray<short int,1>& value, const StdString * varname )
380      {
381         int grpid = this->getCurrentGroup();
382         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
383         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
384      }
385
386
387
388      template <>
389         void CONetCDF4::addAttribute
390            (const StdString & name, const long int & value, const StdString * varname )
391      {
392         int grpid = this->getCurrentGroup();
393         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
394         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
395      }
396
397       template <>
398         void CONetCDF4::addAttribute
399            (const StdString & name, const CArray<long int,1>& value, const StdString * varname )
400      {
401         int grpid = this->getCurrentGroup();
402         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
403         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
404      }
405
406
407
408                //---------------------------------------------------------------
409
410      void CONetCDF4::getWriteDataInfos(const StdString & name, StdSize record, StdSize & array_size,
411                                        std::vector<StdSize> & sstart,
412                                        std::vector<StdSize> & scount,
413                                        const std::vector<StdSize> * start,
414                                        const std::vector<StdSize> * count)
415      {
416         std::vector<std::size_t> sizes  = this->getDimensions(name);
417         std::vector<std::string> iddims = this->getDimensionsIdList (&name);
418         std::vector<std::size_t>::const_iterator
419            it  = sizes.begin(), end = sizes.end();
420         int i = 0;
421
422         if (iddims.begin()->compare(this->getUnlimitedDimensionName()) == 0)
423         {
424            sstart.push_back(record);
425            scount.push_back(1);
426            if ((start == NULL) &&
427                (count == NULL)) i++;
428            it++;
429         }
430
431         for (;it != end; it++)
432         {
433            if ((start != NULL) && (count != NULL))
434            {
435               sstart.push_back((*start)[i]);
436               scount.push_back((*count)[i]);
437               array_size *= (*count)[i];
438               i++;
439            }
440            else
441            {
442               sstart.push_back(0);
443               scount.push_back(sizes[i]);
444               array_size *= sizes[i];
445               i++;
446            }
447         }
448
449      }
450
451
452
453      template <>
454         void CONetCDF4::writeData_(int grpid, int varid,
455                                    const std::vector<StdSize> & sstart,
456                                    const std::vector<StdSize> & scount, const double * data)
457      {
458         (CNetCdfInterface::putVaraType(grpid, varid, &(sstart[0]), &(scount[0]), data));
459//         sync() ;
460      }
461
462      //---------------------------------------------------------------
463
464      template <>
465         void CONetCDF4::writeData_(int grpid, int varid,
466                                    const std::vector<StdSize> & sstart,
467                                    const std::vector<StdSize> & scount, const int * data)
468      {
469          (CNetCdfInterface::putVaraType(grpid, varid, &(sstart[0]), &(scount[0]), data));
470//          sync() ;
471      }
472
473      //---------------------------------------------------------------
474
475      template <>
476         void CONetCDF4::writeData_(int grpid, int varid,
477                                    const std::vector<StdSize> & sstart,
478                                    const std::vector<StdSize> & scount, const float * data)
479      {
480          (CNetCdfInterface::putVaraType(grpid, varid, &(sstart[0]), &(scount[0]), data));
481//          sync() ;
482      }
483
484      //---------------------------------------------------------------
485
486      void CONetCDF4::writeData(const CArray<int, 2>& data, const StdString & name)
487      {
488         int grpid = this->getCurrentGroup();
489         int varid = this->getVariable(name);
490         StdSize array_size = 1;
491         std::vector<StdSize> sstart, scount;
492
493         this->getWriteDataInfos(name, 0, array_size,  sstart, scount, NULL, NULL);
494         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
495      }
496
497      void CONetCDF4::writeTimeAxisData(const CArray<double, 1>& data, const StdString & name,
498                                        bool collective, StdSize record, bool isRoot)
499      {
500         int grpid = this->getCurrentGroup();
501         int varid = this->getVariable(name);
502
503         map<int,size_t>::iterator it=timeAxis.find(varid) ;
504         if (it==timeAxis.end()) timeAxis[varid]=record ;
505         else
506         {
507           if (it->second >= record) return ;
508           else it->second =record ;
509         }
510
511         StdSize array_size = 1;
512         std::vector<StdSize> sstart, scount;
513
514         if (this->wmpi && collective)
515         (CNetCdfInterface::varParAccess(grpid, varid, NC_COLLECTIVE));
516         if (this->wmpi && !collective)
517         (CNetCdfInterface::varParAccess(grpid, varid, NC_INDEPENDENT));
518
519         this->getWriteDataInfos(name, record, array_size,  sstart, scount, NULL, NULL);
520         if (using_netcdf_internal)  if (!isRoot) { sstart[0]=sstart[0]+1 ; scount[0]=0 ;}
521         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
522       }
523
524      //---------------------------------------------------------------
525
526      bool CONetCDF4::varExist(const StdString & varname)
527      {
528         int grpid = this->getCurrentGroup();
529         return (CNetCdfInterface::isVarExisted(grpid, varname));
530      }
531
532      void CONetCDF4::sync(void)
533      {
534         (CNetCdfInterface::sync(this->ncidp)) ;
535      }
536      ///--------------------------------------------------------------
537 } // namespace xios
Note: See TracBrowser for help on using the repository browser.