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

Last change on this file since 813 was 802, checked in by rlacroix, 8 years ago

Add a new file attribute time_counter_name.

Users can now modify the name of the time counter dimension and axis name.

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