source: XIOS/trunk/src/output/onetcdf4.cpp @ 537

Last change on this file since 537 was 528, checked in by rlacroix, 10 years ago

Add the ability to append data to existing output file(s).

By default existing file(s) will still be overwritten. Set the new file attribute "append" to true if you wish to append data to existing NetCDF file(s).

Note that the append mode is currently not supported when file splitting is used and that the structure of the output file cannot be changed.

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