source: XIOS/trunk/src/io/onetcdf4.cpp @ 686

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

Use the NetCDF wrapper for inputs for better error checking.

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