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

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

Preperation for merge from trunk

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