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

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

Clean Up

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