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

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

Use the NetCDF wrapper for inputs for better error checking.

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