source: XIOS/branchs/xios-1.0/src/output/onetcdf4.cpp @ 798

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

Append mode

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