source: XIOS/dev/branch_yushan/src/io/onetcdf4.cpp @ 1053

Last change on this file since 1053 was 1053, checked in by yushan, 6 years ago

ep_lib namespace specified when netcdf involved

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