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

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

branch merged with trunk r1130

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