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

Last change on this file since 863 was 857, checked in by ymipsl, 8 years ago

Bug fix four output scalir variable without time records.

YM+MHN

  • 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.2 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         int dimSize = dim.size();
286         StdSize size;
287         StdSize totalSize;
288         StdSize maxSize = 1024 * 1024 * 256; // == 2GB/8 if output double
289
290         int grpid = this->getCurrentGroup();
291
292         std::vector<StdString>::const_iterator it = dim.begin(), end = dim.end();
293
294         for (; it != end; it++)
295         {
296            const StdString& dimid = *it;
297            dimids.push_back(this->getDimension(dimid));
298            CNetCdfInterface::inqDimLen(grpid, this->getDimension(dimid), size);
299            if (size == NC_UNLIMITED) size = 1;
300            dimsizes.push_back(size);
301         }
302
303         CNetCdfInterface::defVar(grpid, name, type, dimids.size(), &dimids[0], varid);
304
305         // The classic NetCDF format does not support chunking nor fill parameters
306         if (!useClassicFormat)
307         {
308            // set chunksize : size of one record
309            // but must not be > 2GB (netcdf or HDF5 problem)
310            totalSize = 1;
311            for (vector<StdSize>::reverse_iterator it = dimsizes.rbegin(); it != dimsizes.rend(); ++it)
312            {
313              totalSize *= *it;
314              if (totalSize >= maxSize) *it = 1;
315            }
316
317            int storageType = (0 == dimSize) ? NC_CONTIGUOUS : NC_CHUNKED;
318            CNetCdfInterface::defVarChunking(grpid, varid, storageType, &dimsizes[0]);
319            CNetCdfInterface::defVarFill(grpid, varid, true, NULL);
320         }
321
322         return varid;
323      }
324
325      //---------------------------------------------------------------
326
327      void CONetCDF4::setCompressionLevel(const StdString& varname, int compressionLevel)
328      {
329         if (compressionLevel < 0 || compressionLevel > 9)
330           ERROR("void CONetCDF4::setCompressionLevel(const StdString& varname, int compressionLevel)",
331                 "Invalid compression level for variable \"" << varname << "\", the value should range between 0 and 9.");
332         if (compressionLevel && wmpi)
333           ERROR("void CONetCDF4::setCompressionLevel(const StdString& varname, int compressionLevel)",
334                 "Impossible to use compression for variable \"" << varname << "\" when using parallel mode.");
335
336         int grpid = this->getCurrentGroup();
337         int varid = this->getVariable(varname);
338         CNetCdfInterface::defVarDeflate(grpid, varid, compressionLevel);
339      }
340
341      //---------------------------------------------------------------
342
343      template <>
344      void CONetCDF4::addAttribute(const StdString& name, const StdString& value, const StdString* varname)
345      {
346         int grpid = this->getCurrentGroup();
347         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
348         CNetCdfInterface::putAttType(grpid, varid, name, value.size(), value.c_str());
349      }
350
351      //---------------------------------------------------------------
352
353      template <>
354      void CONetCDF4::addAttribute(const StdString& name, const double& value, const StdString* varname)
355      {
356         int grpid = this->getCurrentGroup();
357         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
358         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
359      }
360
361      template <>
362      void CONetCDF4::addAttribute(const StdString& name, const CArray<double,1>& value, const StdString* varname)
363      {
364         int grpid = this->getCurrentGroup();
365         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
366         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
367      }
368      //---------------------------------------------------------------
369
370      template <>
371      void CONetCDF4::addAttribute(const StdString& name, const float& value, const StdString* varname)
372      {
373         int grpid = this->getCurrentGroup();
374         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
375         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
376      }
377
378      template <>
379      void CONetCDF4::addAttribute(const StdString& name, const CArray<float,1>& value, const StdString* varname)
380      {
381         int grpid = this->getCurrentGroup();
382         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
383         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
384      }
385
386      //---------------------------------------------------------------
387
388      template <>
389      void CONetCDF4::addAttribute(const StdString& name, const int& value, const StdString* varname)
390      {
391         int grpid = this->getCurrentGroup();
392         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
393         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
394      }
395
396      template <>
397      void CONetCDF4::addAttribute(const StdString& name, const CArray<int,1>& value, const StdString* varname)
398      {
399         int grpid = this->getCurrentGroup();
400         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
401         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
402      }
403
404      template <>
405      void CONetCDF4::addAttribute(const StdString& name, const short int& value, const StdString* varname)
406      {
407         int grpid = this->getCurrentGroup();
408         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
409         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
410      }
411
412      template <>
413      void CONetCDF4::addAttribute(const StdString& name, const CArray<short int,1>& value, const StdString* varname)
414      {
415         int grpid = this->getCurrentGroup();
416         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
417         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
418      }
419
420      template <>
421      void CONetCDF4::addAttribute(const StdString& name, const long int& value, const StdString* varname)
422      {
423         int grpid = this->getCurrentGroup();
424         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
425         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
426      }
427
428      template <>
429      void CONetCDF4::addAttribute(const StdString& name, const CArray<long int,1>& value, const StdString* varname)
430      {
431         int grpid = this->getCurrentGroup();
432         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
433         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
434      }
435
436      //---------------------------------------------------------------
437
438      void CONetCDF4::getWriteDataInfos(const StdString& name, StdSize record, StdSize& array_size,
439                                        std::vector<StdSize>& sstart,
440                                        std::vector<StdSize>& scount,
441                                        const std::vector<StdSize>* start,
442                                        const std::vector<StdSize>* count)
443      {
444         std::vector<std::size_t> sizes  = this->getDimensions(name);
445         if (sizes.size()==0) 
446         {
447            array_size=1 ;
448            sstart.push_back(0);
449            scount.push_back(1);
450         }
451         else
452         {
453           std::vector<std::string> iddims = this->getDimensionsIdList (&name);
454           std::vector<std::size_t>::const_iterator
455           it  = sizes.begin(), end = sizes.end();
456           int i = 0;
457
458           if (iddims.begin()->compare(timeCounterName) == 0)
459           {
460             sstart.push_back(record);
461             scount.push_back(1);
462              if ((start == NULL) &&
463                  (count == NULL)) i++;
464              it++;
465           }
466
467           for (;it != end; it++)
468           {
469              if ((start != NULL) && (count != NULL))
470              {
471                 sstart.push_back((*start)[i]);
472                 scount.push_back((*count)[i]);
473                 array_size *= (*count)[i];
474                 i++;
475              }
476              else
477              {
478                 sstart.push_back(0);
479                 scount.push_back(sizes[i]);
480                 array_size *= sizes[i];
481                 i++;
482              }
483           }
484
485         }
486      }
487
488
489      template <>
490      void CONetCDF4::writeData_(int grpid, int varid,
491                                 const std::vector<StdSize>& sstart,
492                                 const std::vector<StdSize>& scount, const double* data)
493      {
494         CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
495      }
496
497      //---------------------------------------------------------------
498
499      template <>
500      void CONetCDF4::writeData_(int grpid, int varid,
501                                 const std::vector<StdSize>& sstart,
502                                 const std::vector<StdSize>& scount, const int* data)
503      {
504          CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
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 float* data)
513      {
514          CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
515      }
516
517      //---------------------------------------------------------------
518
519      void CONetCDF4::writeData(const CArray<int, 2>& data, const StdString& name)
520      {
521         int grpid = this->getCurrentGroup();
522         int varid = this->getVariable(name);
523         StdSize array_size = 1;
524         std::vector<StdSize> sstart, scount;
525
526         this->getWriteDataInfos(name, 0, array_size,  sstart, scount, NULL, NULL);
527         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
528      }
529
530      void CONetCDF4::writeTimeAxisData(const CArray<double, 1>& data, const StdString& name,
531                                        bool collective, StdSize record, bool isRoot)
532      {
533         int grpid = this->getCurrentGroup();
534         int varid = this->getVariable(name);
535
536         map<int,size_t>::iterator it=timeAxis.find(varid);
537         if (it == timeAxis.end()) timeAxis[varid] = record;
538         else
539         {
540           if (it->second >= record) return;
541           else it->second =record;
542         }
543
544         StdSize array_size = 1;
545         std::vector<StdSize> sstart, scount;
546
547         if (this->wmpi && collective)
548            CNetCdfInterface::varParAccess(grpid, varid, NC_COLLECTIVE);
549         if (this->wmpi && !collective)
550            CNetCdfInterface::varParAccess(grpid, varid, NC_INDEPENDENT);
551
552         this->getWriteDataInfos(name, record, array_size,  sstart, scount, NULL, NULL);
553         if (using_netcdf_internal)
554         {
555           if (!isRoot)
556           {
557             sstart[0] = sstart[0] + 1;
558             scount[0] = 0;
559           }
560         }
561         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
562       }
563
564      //---------------------------------------------------------------
565
566      bool CONetCDF4::varExist(const StdString& varname)
567      {
568         int grpid = this->getCurrentGroup();
569         return CNetCdfInterface::isVarExisted(grpid, varname);
570      }
571
572      void CONetCDF4::sync(void)
573      {
574         CNetCdfInterface::sync(this->ncidp);
575      }
576      ///--------------------------------------------------------------
577 } // namespace xios
Note: See TracBrowser for help on using the repository browser.