source: XIOS/trunk/src/io/onetcdf4.cpp @ 774

Last change on this file since 774 was 707, checked in by rlacroix, 9 years ago

Append mode: Detect the correct restart point and erase some records if need be.

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