source: XIOS/trunk/src/output/onetcdf4.cpp @ 650

Last change on this file since 650 was 607, checked in by rlacroix, 9 years ago

Improve the error message when compression cannot be used.

  • 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: 20.1 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         if (compressionLevel < 0 || compressionLevel > 9)
327           ERROR("void CONetCDF4::setCompressionLevel(const StdString& varname, int compressionLevel)",
328                 "Invalid compression level for variable \"" << varname << "\", the value should range between 0 and 9.");
329         if (compressionLevel && wmpi)
330           ERROR("void CONetCDF4::setCompressionLevel(const StdString& varname, int compressionLevel)",
331                 "Impossible to use compression for variable \"" << varname << "\" when using parallel mode.");
332
333         int grpid = this->getCurrentGroup();
334         int varid = this->getVariable(varname);
335         CNetCdfInterface::defVarDeflate(grpid, varid, compressionLevel);
336      }
337
338      //---------------------------------------------------------------
339
340      template <>
341         void CONetCDF4::addAttribute
342            (const StdString & name, const StdString & value, const StdString * varname )
343      {
344         int grpid = this->getCurrentGroup();
345         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
346         (CNetCdfInterface::putAtt(grpid, varid, name, NC_CHAR, value.size(), value.c_str()));
347         //CheckError(nc_put_att_string(grpid, varid, name.c_str(), 1, &str));
348      }
349
350      //---------------------------------------------------------------
351
352      template <>
353         void CONetCDF4::addAttribute
354            (const StdString & name, const double & value, const StdString * varname )
355      {
356         int grpid = this->getCurrentGroup();
357         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
358         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
359      }
360
361       template <>
362         void CONetCDF4::addAttribute
363            (const StdString & name, const CArray<double,1>& value, const StdString * varname )
364      {
365         int grpid = this->getCurrentGroup();
366         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
367         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
368      }
369      //---------------------------------------------------------------
370
371      template <>
372         void CONetCDF4::addAttribute
373            (const StdString & name, const float & value, const StdString * varname )
374      {
375         int grpid = this->getCurrentGroup();
376         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
377         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
378      }
379
380       template <>
381         void CONetCDF4::addAttribute
382            (const StdString & name, const CArray<float,1>& value, const StdString * varname )
383      {
384         int grpid = this->getCurrentGroup();
385         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
386         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
387      }
388
389      //---------------------------------------------------------------
390
391      template <>
392         void CONetCDF4::addAttribute
393            (const StdString & name, const int & value, const StdString * varname )
394      {
395         int grpid = this->getCurrentGroup();
396         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
397         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
398      }
399
400       template <>
401         void CONetCDF4::addAttribute
402            (const StdString & name, const CArray<int,1>& value, const StdString * varname )
403      {
404         int grpid = this->getCurrentGroup();
405         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
406         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
407      }
408
409      template <>
410         void CONetCDF4::addAttribute
411            (const StdString & name, const short int & value, const StdString * varname )
412      {
413         int grpid = this->getCurrentGroup();
414         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
415         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
416      }
417
418       template <>
419         void CONetCDF4::addAttribute
420            (const StdString & name, const CArray<short int,1>& value, const StdString * varname )
421      {
422         int grpid = this->getCurrentGroup();
423         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
424         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
425      }
426
427
428
429      template <>
430         void CONetCDF4::addAttribute
431            (const StdString & name, const long int & value, const StdString * varname )
432      {
433         int grpid = this->getCurrentGroup();
434         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
435         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
436      }
437
438       template <>
439         void CONetCDF4::addAttribute
440            (const StdString & name, const CArray<long int,1>& value, const StdString * varname )
441      {
442         int grpid = this->getCurrentGroup();
443         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
444         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
445      }
446
447
448
449                //---------------------------------------------------------------
450
451      void CONetCDF4::getWriteDataInfos(const StdString & name, StdSize record, StdSize & array_size,
452                                        std::vector<StdSize> & sstart,
453                                        std::vector<StdSize> & scount,
454                                        const std::vector<StdSize> * start,
455                                        const std::vector<StdSize> * count)
456      {
457         std::vector<std::size_t> sizes  = this->getDimensions(name);
458         std::vector<std::string> iddims = this->getDimensionsIdList (&name);
459         std::vector<std::size_t>::const_iterator
460            it  = sizes.begin(), end = sizes.end();
461         int i = 0;
462
463         if (iddims.begin()->compare(this->getUnlimitedDimensionName()) == 0)
464         {
465            sstart.push_back(record + recordOffset);
466            scount.push_back(1);
467            if ((start == NULL) &&
468                (count == NULL)) i++;
469            it++;
470         }
471
472         for (;it != end; it++)
473         {
474            if ((start != NULL) && (count != NULL))
475            {
476               sstart.push_back((*start)[i]);
477               scount.push_back((*count)[i]);
478               array_size *= (*count)[i];
479               i++;
480            }
481            else
482            {
483               sstart.push_back(0);
484               scount.push_back(sizes[i]);
485               array_size *= sizes[i];
486               i++;
487            }
488         }
489
490      }
491
492
493
494      template <>
495         void CONetCDF4::writeData_(int grpid, int varid,
496                                    const std::vector<StdSize> & sstart,
497                                    const std::vector<StdSize> & scount, const double * data)
498      {
499         (CNetCdfInterface::putVaraType(grpid, varid, &(sstart[0]), &(scount[0]), data));
500//         sync() ;
501      }
502
503      //---------------------------------------------------------------
504
505      template <>
506         void CONetCDF4::writeData_(int grpid, int varid,
507                                    const std::vector<StdSize> & sstart,
508                                    const std::vector<StdSize> & scount, const int * data)
509      {
510          (CNetCdfInterface::putVaraType(grpid, varid, &(sstart[0]), &(scount[0]), data));
511//          sync() ;
512      }
513
514      //---------------------------------------------------------------
515
516      template <>
517         void CONetCDF4::writeData_(int grpid, int varid,
518                                    const std::vector<StdSize> & sstart,
519                                    const std::vector<StdSize> & scount, const float * data)
520      {
521          (CNetCdfInterface::putVaraType(grpid, varid, &(sstart[0]), &(scount[0]), data));
522//          sync() ;
523      }
524
525      //---------------------------------------------------------------
526
527      void CONetCDF4::writeData(const CArray<int, 2>& data, const StdString & name)
528      {
529         int grpid = this->getCurrentGroup();
530         int varid = this->getVariable(name);
531         StdSize array_size = 1;
532         std::vector<StdSize> sstart, scount;
533
534         this->getWriteDataInfos(name, 0, array_size,  sstart, scount, NULL, NULL);
535         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
536      }
537
538      void CONetCDF4::writeTimeAxisData(const CArray<double, 1>& data, const StdString & name,
539                                        bool collective, StdSize record, bool isRoot)
540      {
541         int grpid = this->getCurrentGroup();
542         int varid = this->getVariable(name);
543
544         map<int,size_t>::iterator it=timeAxis.find(varid) ;
545         if (it==timeAxis.end()) timeAxis[varid]=record ;
546         else
547         {
548           if (it->second >= record) return ;
549           else it->second =record ;
550         }
551
552         StdSize array_size = 1;
553         std::vector<StdSize> sstart, scount;
554
555         if (this->wmpi && collective)
556         (CNetCdfInterface::varParAccess(grpid, varid, NC_COLLECTIVE));
557         if (this->wmpi && !collective)
558         (CNetCdfInterface::varParAccess(grpid, varid, NC_INDEPENDENT));
559
560         this->getWriteDataInfos(name, record, array_size,  sstart, scount, NULL, NULL);
561         if (using_netcdf_internal)  if (!isRoot) { sstart[0]=sstart[0]+1 ; scount[0]=0 ;}
562         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
563       }
564
565      //---------------------------------------------------------------
566
567      bool CONetCDF4::varExist(const StdString & varname)
568      {
569         int grpid = this->getCurrentGroup();
570         return (CNetCdfInterface::isVarExisted(grpid, varname));
571      }
572
573      void CONetCDF4::sync(void)
574      {
575         (CNetCdfInterface::sync(this->ncidp)) ;
576      }
577      ///--------------------------------------------------------------
578 } // namespace xios
Note: See TracBrowser for help on using the repository browser.