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