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

Last change on this file since 680 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
RevLine 
[528]1#include <fstream>
2
[219]3#include "onetcdf4.hpp"
[352]4#include "group_template.hpp"
[382]5#include "mpi.hpp"
[379]6#include "netcdf.hpp"
[498]7#include "netCdfInterface.hpp"
8#include "netCdfException.hpp"
[219]9
[335]10namespace xios
[219]11{
12      /// ////////////////////// Définitions ////////////////////// ///
13
14      CONetCDF4::CONetCDF4
[605]15         (const StdString & filename, bool append, bool useClassicFormat, const MPI_Comm* comm, bool multifile)
[219]16            : path()
[605]17            , wmpi(false)
[517]18            , useClassicFormat(useClassicFormat)
[528]19            , recordOffset(0)
[219]20      {
[528]21         this->initialize(filename, append, useClassicFormat, comm,multifile);
[219]22      }
[498]23
[219]24      //---------------------------------------------------------------
[286]25
[498]26
[219]27      CONetCDF4::~CONetCDF4(void)
28      {
[286]29//         CheckError(nc_close(this->ncidp));
[219]30      }
31
32      ///--------------------------------------------------------------
33
34      void CONetCDF4::initialize
[605]35         (const StdString & filename, bool append, bool useClassicFormat, const MPI_Comm* comm, bool multifile)
[219]36      {
[517]37         this->useClassicFormat = useClassicFormat;
38
39         int mode = useClassicFormat ? 0 : NC_NETCDF4;
[605]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)
[517]52            mode |= useClassicFormat ? NC_PNETCDF : NC_MPIIO;
53
[528]54         // If the file does not exist, we always create it
55         if (!append || !std::ifstream(filename.c_str()))
[219]56         {
[605]57            if (wmpi)
58               CNetCdfInterface::createPar(filename, mode, *comm, MPI_INFO_NULL, this->ncidp);
59            else
60               CNetCdfInterface::create(filename, mode, this->ncidp);
[528]61
62            this->appendMode = false;
63            this->recordOffset = 0;
[219]64         }
65         else
66         {
[528]67            mode |= NC_WRITE;
[605]68            if (wmpi)
69               CNetCdfInterface::openPar(filename, mode, *comm, MPI_INFO_NULL, this->ncidp);
70            else
71               CNetCdfInterface::open(filename, mode, this->ncidp);
[528]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;
[219]81         }
[517]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)
[606]86            CNetCdfInterface::setFill(this->ncidp, false);
[219]87      }
[498]88
[286]89      void CONetCDF4::close()
90      {
[498]91        (CNetCdfInterface::close(this->ncidp));
[286]92      }
[498]93
[219]94      //---------------------------------------------------------------
[498]95
[219]96      void CONetCDF4::definition_start(void)
[498]97      {
98         (CNetCdfInterface::reDef(this->ncidp));
[219]99      }
[498]100
[219]101      //---------------------------------------------------------------
[498]102
[219]103      void CONetCDF4::definition_end(void)
104      {
[498]105         (CNetCdfInterface::endDef(this->ncidp));
[219]106      }
107
108      //---------------------------------------------------------------
[498]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
[219]123      int CONetCDF4::getCurrentGroup(void)
124      {
125         return (this->getGroup(this->getCurrentPath()));
126      }
[498]127
[219]128      //---------------------------------------------------------------
[498]129
[219]130      int CONetCDF4::getGroup(const CONetCDF4Path & path)
131      {
132         int retvalue = this->ncidp;
[498]133
[219]134         CONetCDF4Path::const_iterator
135            it  = path.begin(), end = path.end();
136
137         for (;it != end; it++)
138         {
139            const StdString & groupid = *it;
[498]140            (CNetCdfInterface::inqNcId(retvalue, groupid, retvalue));
[219]141         }
142         return (retvalue);
143      }
[498]144
[219]145      //---------------------------------------------------------------
[498]146
[219]147      int CONetCDF4::getVariable(const StdString & varname)
148      {
149         int varid = 0;
150         int grpid = this->getCurrentGroup();
[498]151         (CNetCdfInterface::inqVarId(grpid, varname, varid));
[219]152         return (varid);
153      }
[498]154
[219]155      //---------------------------------------------------------------
[498]156
[219]157      int CONetCDF4::getDimension(const StdString & dimname)
158      {
159         int dimid = 0;
160         int grpid = this->getCurrentGroup();
[498]161         (CNetCdfInterface::inqDimId(grpid, dimname, dimid));
[219]162         return (dimid);
163      }
[498]164
[219]165      //---------------------------------------------------------------
[498]166
[219]167      int CONetCDF4::getUnlimitedDimension(void)
168      {
169         int dimid = 0;
170         int grpid = this->getCurrentGroup();
[498]171         (CNetCdfInterface::inqUnLimDim(grpid, dimid));
[219]172         return (dimid);
173      }
[498]174
[266]175      StdString CONetCDF4::getUnlimitedDimensionName(void)
176      {
177         int grpid = this->getGroup(path);
178         int dimid = this->getUnlimitedDimension();
[498]179
[266]180         if (dimid == -1) return (std::string());
[498]181         StdString dimname;
182         (CNetCdfInterface::inqDimName(grpid, dimid, dimname));
183
[266]184         return (dimname);
185      }
[498]186
[219]187      //---------------------------------------------------------------
[498]188
[219]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
[498]197         (CNetCdfInterface::inqVarNDims(grpid, varid, nbdim));
[219]198         dimid = new int[nbdim]();
[498]199         (CNetCdfInterface::inqVarDimId(grpid, varid, dimid));
[219]200
201         for (int i = 0; i < nbdim; i++)
202         {
[498]203            (CNetCdfInterface::inqDimLen(grpid, dimid[i], size));
[219]204            if (size == NC_UNLIMITED)
205                size = UNLIMITED_DIM;
206            retvalue.push_back(size);
207         }
[401]208         delete [] dimid;
[219]209         return (retvalue);
210      }
211
[266]212      std::vector<std::string> CONetCDF4::getDimensionsIdList (const std::string * _varname)
213      {
[498]214         int nDimNull = 0;
[266]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;
[498]219
[266]220         if (_varname != NULL)
221         {
[498]222            (CNetCdfInterface::inqVarNDims(grpid, varid, nbdim));
[266]223            dimid = new int[nbdim]();
[498]224            (CNetCdfInterface::inqVarDimId(grpid, varid, dimid));
[266]225         }
226         else
227         {
[498]228            (CNetCdfInterface::inqDimIds(grpid, nbdim, NULL, 1));
[266]229            dimid = new int[nbdim]();
[498]230            (CNetCdfInterface::inqDimIds(grpid, nDimNull, dimid, 1));
[266]231         }
[498]232
[266]233         for (int i = 0; i < nbdim; i++)
234         {
[498]235            std::string dimname;
236            (CNetCdfInterface::inqDimName(grpid, dimid[i], dimname));
[266]237            retvalue.push_back(dimname);
238         }
239         delete [] dimid;
[498]240
[266]241         return (retvalue);
242      }
243
244
[219]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();
[498]259         (CNetCdfInterface::defGrp(grpid, name, retvalue));
[219]260         return (retvalue);
261      }
[498]262
[219]263      //---------------------------------------------------------------
[498]264
[219]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)
[498]270            (CNetCdfInterface::defDim(grpid, name, size, retvalue));
[219]271         else
[498]272            (CNetCdfInterface::defDim(grpid, name, NC_UNLIMITED, retvalue));
[219]273         return (retvalue);
274      }
[498]275
[219]276      //---------------------------------------------------------------
[498]277
[219]278      int CONetCDF4::addVariable(const StdString & name, nc_type type,
[606]279                                 const std::vector<StdString> & dim)
[219]280      {
[350]281         int varid = 0;
[219]282         std::vector<int> dimids;
[606]283         std::vector<StdSize> dimsizes;
284         StdSize size;
285         StdSize totalSize;
286         StdSize maxSize = 1024 * 1024 * 256; // == 2GB/8 if output double
[498]287
[219]288         int grpid = this->getCurrentGroup();
[498]289
[606]290         std::vector<StdString>::const_iterator it = dim.begin(), end = dim.end();
[219]291
[606]292         for (; it != end; it++)
[219]293         {
294            const StdString & dimid = *it;
295            dimids.push_back(this->getDimension(dimid));
[606]296            CNetCdfInterface::inqDimLen(grpid, this->getDimension(dimid), size);
297            if (size == NC_UNLIMITED) size = 1;
298            dimsizes.push_back(size);
[219]299         }
[453]300
[606]301         CNetCdfInterface::defVar(grpid, name, type, dimids.size(), &dimids[0], varid);
[498]302
[517]303         // The classic NetCDF format does not support chunking nor fill parameters
304         if (!useClassicFormat)
[453]305         {
[517]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);
[453]317         }
318
[606]319         return varid;
[219]320      }
321
322      //---------------------------------------------------------------
323
[606]324      void CONetCDF4::setCompressionLevel(const StdString& varname, int compressionLevel)
325      {
[607]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
[606]333         int grpid = this->getCurrentGroup();
334         int varid = this->getVariable(varname);
335         CNetCdfInterface::defVarDeflate(grpid, varid, compressionLevel);
336      }
337
338      //---------------------------------------------------------------
339
[219]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);
[498]346         (CNetCdfInterface::putAtt(grpid, varid, name, NC_CHAR, value.size(), value.c_str()));
[219]347         //CheckError(nc_put_att_string(grpid, varid, name.c_str(), 1, &str));
348      }
[498]349
[219]350      //---------------------------------------------------------------
[498]351
[219]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);
[498]358         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
[219]359      }
[391]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);
[498]367         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
368      }
[219]369      //---------------------------------------------------------------
[498]370
[219]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);
[498]377         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
[219]378      }
[391]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);
[498]386         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
387      }
388
[219]389      //---------------------------------------------------------------
[498]390
[219]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);
[498]397         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
[219]398      }
399
[391]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);
[498]406         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
407      }
408
[472]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);
[498]415         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
[472]416      }
[219]417
[472]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);
[498]424         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
425      }
426
427
428
[472]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);
[498]435         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
[472]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);
[498]444         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
445      }
446
447
448
[472]449                //---------------------------------------------------------------
450
[219]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)
[498]456      {
[266]457         std::vector<std::size_t> sizes  = this->getDimensions(name);
[498]458         std::vector<std::string> iddims = this->getDimensionsIdList (&name);
[266]459         std::vector<std::size_t>::const_iterator
[219]460            it  = sizes.begin(), end = sizes.end();
461         int i = 0;
[438]462
[266]463         if (iddims.begin()->compare(this->getUnlimitedDimensionName()) == 0)
464         {
[528]465            sstart.push_back(record + recordOffset);
[606]466            scount.push_back(1);
[266]467            if ((start == NULL) &&
468                (count == NULL)) i++;
469            it++;
470         }
[219]471
472         for (;it != end; it++)
[606]473         {
[219]474            if ((start != NULL) && (count != NULL))
475            {
[266]476               sstart.push_back((*start)[i]);
477               scount.push_back((*count)[i]);
478               array_size *= (*count)[i];
479               i++;
[219]480            }
481            else
482            {
[266]483               sstart.push_back(0);
484               scount.push_back(sizes[i]);
485               array_size *= sizes[i];
[219]486               i++;
487            }
488         }
[498]489
[219]490      }
[498]491
492
493
[219]494      template <>
495         void CONetCDF4::writeData_(int grpid, int varid,
496                                    const std::vector<StdSize> & sstart,
[369]497                                    const std::vector<StdSize> & scount, const double * data)
[219]498      {
[498]499         (CNetCdfInterface::putVaraType(grpid, varid, &(sstart[0]), &(scount[0]), data));
[286]500//         sync() ;
[219]501      }
[498]502
[219]503      //---------------------------------------------------------------
[498]504
[219]505      template <>
506         void CONetCDF4::writeData_(int grpid, int varid,
507                                    const std::vector<StdSize> & sstart,
[369]508                                    const std::vector<StdSize> & scount, const int * data)
[219]509      {
[498]510          (CNetCdfInterface::putVaraType(grpid, varid, &(sstart[0]), &(scount[0]), data));
[286]511//          sync() ;
[219]512      }
[498]513
[219]514      //---------------------------------------------------------------
[498]515
[219]516      template <>
517         void CONetCDF4::writeData_(int grpid, int varid,
518                                    const std::vector<StdSize> & sstart,
[369]519                                    const std::vector<StdSize> & scount, const float * data)
[219]520      {
[498]521          (CNetCdfInterface::putVaraType(grpid, varid, &(sstart[0]), &(scount[0]), data));
[286]522//          sync() ;
[219]523      }
524
525      //---------------------------------------------------------------
526
[369]527      void CONetCDF4::writeData(const CArray<int, 2>& data, const StdString & name)
[219]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);
[369]535         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
[219]536      }
537
[413]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);
[498]543
[413]544         map<int,size_t>::iterator it=timeAxis.find(varid) ;
545         if (it==timeAxis.end()) timeAxis[varid]=record ;
[498]546         else
[413]547         {
548           if (it->second >= record) return ;
549           else it->second =record ;
550         }
[498]551
[413]552         StdSize array_size = 1;
553         std::vector<StdSize> sstart, scount;
[498]554
[413]555         if (this->wmpi && collective)
[498]556         (CNetCdfInterface::varParAccess(grpid, varid, NC_COLLECTIVE));
[413]557         if (this->wmpi && !collective)
[498]558         (CNetCdfInterface::varParAccess(grpid, varid, NC_INDEPENDENT));
559
[413]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
[219]565      //---------------------------------------------------------------
[498]566
[219]567      bool CONetCDF4::varExist(const StdString & varname)
568      {
569         int grpid = this->getCurrentGroup();
[498]570         return (CNetCdfInterface::isVarExisted(grpid, varname));
[219]571      }
572
[286]573      void CONetCDF4::sync(void)
574      {
[498]575         (CNetCdfInterface::sync(this->ncidp)) ;
576      }
[219]577      ///--------------------------------------------------------------
[337]578 } // namespace xios
Note: See TracBrowser for help on using the repository browser.