source: XIOS/dev/dev_trunk_omp/src/io/onetcdf4.cpp @ 1646

Last change on this file since 1646 was 1646, checked in by yushan, 5 years ago

branch merged with trunk @1645. arch file (ep&mpi) added for ADA

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