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

Last change on this file since 1097 was 1097, checked in by ymipsl, 7 years ago

Expected performance enhancement when using append mode.
Instead to read the whole time axis, only the last record is read first, and eventually continue until to reach the record corresponding to the current timestep.
(currently untested)

YM

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