source: XIOS/dev/branch_yushan/src/io/onetcdf4.cpp @ 1070

Last change on this file since 1070 was 1070, checked in by yushan, 7 years ago

Preperation for merge from trunk

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