source: XIOS/dev/branch_yushan_merged/src/io/onetcdf4.cpp @ 1156

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

branch merged with trunk @1155

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