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

Last change on this file since 537 was 528, checked in by rlacroix, 10 years ago

Add the ability to append data to existing output file(s).

By default existing file(s) will still be overwritten. Set the new file attribute "append" to true if you wish to append data to existing NetCDF file(s).

Note that the append mode is currently not supported when file splitting is used and that the structure of the output file cannot be changed.

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