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

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

Add a new attribute to the file definition so that the output format can be controlled.

Currently the supported formats are "netcdf4" and "netcdf4_classic". The "format" attribute is optional. The "netcdf4" format will be used when no format is explicitly defined. Since "netcdf4" is the format which was previously used by XIOS, existing configuration files will not be affected by this change.

If "netcdf4_classic" is used, the output file(s) will be created using the classic NetCDF format. This format can be used with the attribute "type" set to "one_file" if the NetCDF4 library was compiled with Parallel NetCDF support (--enable-pnetcdf).

  • 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: 18.5 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 exist, bool useClassicFormat, const MPI_Comm * comm, bool multifile)
14            : path()
15            , useClassicFormat(useClassicFormat)
16      {
17         this->wmpi = (comm != NULL) && !multifile;
18         this->initialize(filename, exist, useClassicFormat, comm,multifile);
19      }
20
21      //---------------------------------------------------------------
22
23
24      CONetCDF4::~CONetCDF4(void)
25      {
26//         CheckError(nc_close(this->ncidp));
27      }
28
29      ///--------------------------------------------------------------
30
31      void CONetCDF4::initialize
32         (const StdString & filename, bool exist, bool useClassicFormat, const MPI_Comm * comm, bool multifile)
33      {
34         this->useClassicFormat = useClassicFormat;
35
36         int mode = useClassicFormat ? 0 : NC_NETCDF4;
37         if (!multifile)
38            mode |= useClassicFormat ? NC_PNETCDF : NC_MPIIO;
39
40         if (!exist)
41         {
42            if (comm != NULL)
43            {
44               if (!multifile) CNetCdfInterface::createPar(filename, mode, *comm, MPI_INFO_NULL, this->ncidp);
45               else CNetCdfInterface::create(filename, mode, this->ncidp);
46            }
47            else CNetCdfInterface::create(filename, mode, this->ncidp);
48         }
49         else
50         {
51            if (comm != NULL)
52            {
53               if (!multifile) CNetCdfInterface::openPar(filename, mode, *comm, MPI_INFO_NULL, this->ncidp);
54               else CNetCdfInterface::open(filename, mode, this->ncidp);
55            }
56            else CNetCdfInterface::open(filename, mode, this->ncidp);
57         }
58
59         // If the classic NetCDF format is used, we enable the "no-fill mode" globally.
60         // This is done per variable for the NetCDF4 format.
61         if (useClassicFormat)
62            CNetCdfInterface::setFill(this->ncidp, false);   
63      }
64
65      void CONetCDF4::close()
66      {
67        (CNetCdfInterface::close(this->ncidp));
68      }
69
70      //---------------------------------------------------------------
71
72      void CONetCDF4::definition_start(void)
73      {
74         (CNetCdfInterface::reDef(this->ncidp));
75      }
76
77      //---------------------------------------------------------------
78
79      void CONetCDF4::definition_end(void)
80      {
81         (CNetCdfInterface::endDef(this->ncidp));
82      }
83
84      //---------------------------------------------------------------
85
86// Don't need it anymore?
87//      void CONetCDF4::CheckError(int status)
88//      {
89//         if (status != NC_NOERR)
90//         {
91//            StdString errormsg (nc_strerror(status)); // fuite mémoire ici ?
92//            ERROR("CONetCDF4::CheckError(int status)",
93//                  << "[ status = " << status << " ] " << errormsg);
94//         }
95//      }
96
97      //---------------------------------------------------------------
98
99      int CONetCDF4::getCurrentGroup(void)
100      {
101         return (this->getGroup(this->getCurrentPath()));
102      }
103
104      //---------------------------------------------------------------
105
106      int CONetCDF4::getGroup(const CONetCDF4Path & path)
107      {
108         int retvalue = this->ncidp;
109
110         CONetCDF4Path::const_iterator
111            it  = path.begin(), end = path.end();
112
113         for (;it != end; it++)
114         {
115            const StdString & groupid = *it;
116            (CNetCdfInterface::inqNcId(retvalue, groupid, retvalue));
117         }
118         return (retvalue);
119      }
120
121      //---------------------------------------------------------------
122
123      int CONetCDF4::getVariable(const StdString & varname)
124      {
125         int varid = 0;
126         int grpid = this->getCurrentGroup();
127         (CNetCdfInterface::inqVarId(grpid, varname, varid));
128         return (varid);
129      }
130
131      //---------------------------------------------------------------
132
133      int CONetCDF4::getDimension(const StdString & dimname)
134      {
135         int dimid = 0;
136         int grpid = this->getCurrentGroup();
137         (CNetCdfInterface::inqDimId(grpid, dimname, dimid));
138         return (dimid);
139      }
140
141      //---------------------------------------------------------------
142
143      int CONetCDF4::getUnlimitedDimension(void)
144      {
145         int dimid = 0;
146         int grpid = this->getCurrentGroup();
147         (CNetCdfInterface::inqUnLimDim(grpid, dimid));
148         return (dimid);
149      }
150
151      StdString CONetCDF4::getUnlimitedDimensionName(void)
152      {
153         int grpid = this->getGroup(path);
154         int dimid = this->getUnlimitedDimension();
155
156         if (dimid == -1) return (std::string());
157         StdString dimname;
158         (CNetCdfInterface::inqDimName(grpid, dimid, dimname));
159
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
223      const CONetCDF4::CONetCDF4Path & CONetCDF4::getCurrentPath(void) const
224      { return (this->path); }
225
226      void CONetCDF4::setCurrentPath(const CONetCDF4Path & path)
227      { this->path = path; }
228
229      //---------------------------------------------------------------
230
231      int CONetCDF4::addGroup(const StdString & name)
232      {
233         int retvalue = 0;
234         int grpid = this->getCurrentGroup();
235         (CNetCdfInterface::defGrp(grpid, name, retvalue));
236         return (retvalue);
237      }
238
239      //---------------------------------------------------------------
240
241      int CONetCDF4::addDimension(const StdString& name, const StdSize size)
242      {
243         int retvalue = 0;
244         int grpid = this->getCurrentGroup();
245         if (size != UNLIMITED_DIM)
246            (CNetCdfInterface::defDim(grpid, name, size, retvalue));
247         else
248            (CNetCdfInterface::defDim(grpid, name, NC_UNLIMITED, retvalue));
249         return (retvalue);
250      }
251
252      //---------------------------------------------------------------
253
254      int CONetCDF4::addVariable(const StdString & name, nc_type type,
255                                  const std::vector<StdString> & dim)
256      {
257         int varid = 0;
258         std::vector<int> dimids;
259         std::vector<StdSize> dimsizes ;
260         StdSize size ;
261         StdSize totalSize ;
262         StdSize maxSize=1024*1024*256 ; // == 2GB/8 if output double
263
264         int grpid = this->getCurrentGroup();
265
266         std::vector<StdString>::const_iterator
267            it  = dim.begin(), end = dim.end();
268
269         for (;it != end; it++)
270         {
271            const StdString & dimid = *it;
272            dimids.push_back(this->getDimension(dimid));
273            (CNetCdfInterface::inqDimLen(grpid, this->getDimension(dimid), size));
274            if (size==NC_UNLIMITED) size=1 ;
275            dimsizes.push_back(size) ;
276         }
277
278         CNetCdfInterface::defVar(grpid, name, type, dimids.size(), &(dimids[0]), varid);
279
280         // The classic NetCDF format does not support chunking nor fill parameters
281         if (!useClassicFormat)
282         {
283            // set chunksize : size of one record
284            // but must not be > 2GB (netcdf or HDF5 problem)
285            totalSize = 1;
286            for (vector<StdSize>::reverse_iterator it = dimsizes.rbegin(); it != dimsizes.rend(); ++it)
287            {
288              totalSize *= *it;
289              if (totalSize >= maxSize) *it = 1;
290            }
291
292            CNetCdfInterface::defVarChunking(grpid, varid, NC_CHUNKED, &dimsizes[0]);
293            CNetCdfInterface::defVarFill(grpid, varid, true, NULL);
294         }
295
296         return (varid);
297      }
298
299      //---------------------------------------------------------------
300
301      template <>
302         void CONetCDF4::addAttribute
303            (const StdString & name, const StdString & value, const StdString * varname )
304      {
305         int grpid = this->getCurrentGroup();
306         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
307         (CNetCdfInterface::putAtt(grpid, varid, name, NC_CHAR, value.size(), value.c_str()));
308         //CheckError(nc_put_att_string(grpid, varid, name.c_str(), 1, &str));
309      }
310
311      //---------------------------------------------------------------
312
313      template <>
314         void CONetCDF4::addAttribute
315            (const StdString & name, const double & value, const StdString * varname )
316      {
317         int grpid = this->getCurrentGroup();
318         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
319         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
320      }
321
322       template <>
323         void CONetCDF4::addAttribute
324            (const StdString & name, const CArray<double,1>& 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.numElements(), value.dataFirst()));
329      }
330      //---------------------------------------------------------------
331
332      template <>
333         void CONetCDF4::addAttribute
334            (const StdString & name, const float & 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
343            (const StdString & name, const CArray<float,1>& value, const StdString * varname )
344      {
345         int grpid = this->getCurrentGroup();
346         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
347         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
348      }
349
350      //---------------------------------------------------------------
351
352      template <>
353         void CONetCDF4::addAttribute
354            (const StdString & name, const int & 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
363            (const StdString & name, const CArray<int,1>& value, const StdString * varname )
364      {
365         int grpid = this->getCurrentGroup();
366         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
367         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
368      }
369
370      template <>
371         void CONetCDF4::addAttribute
372            (const StdString & name, const short 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<short 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
389
390      template <>
391         void CONetCDF4::addAttribute
392            (const StdString & name, const long int & value, const StdString * varname )
393      {
394         int grpid = this->getCurrentGroup();
395         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
396         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
397      }
398
399       template <>
400         void CONetCDF4::addAttribute
401            (const StdString & name, const CArray<long int,1>& 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, value.numElements(), value.dataFirst()));
406      }
407
408
409
410                //---------------------------------------------------------------
411
412      void CONetCDF4::getWriteDataInfos(const StdString & name, StdSize record, StdSize & array_size,
413                                        std::vector<StdSize> & sstart,
414                                        std::vector<StdSize> & scount,
415                                        const std::vector<StdSize> * start,
416                                        const std::vector<StdSize> * count)
417      {
418         std::vector<std::size_t> sizes  = this->getDimensions(name);
419         std::vector<std::string> iddims = this->getDimensionsIdList (&name);
420         std::vector<std::size_t>::const_iterator
421            it  = sizes.begin(), end = sizes.end();
422         int i = 0;
423
424         if (iddims.begin()->compare(this->getUnlimitedDimensionName()) == 0)
425         {
426            sstart.push_back(record);
427            scount.push_back(1); 
428            if ((start == NULL) &&
429                (count == NULL)) i++;
430            it++;
431         }
432
433         for (;it != end; it++)
434         { 
435            if ((start != NULL) && (count != NULL))
436            {
437               sstart.push_back((*start)[i]);
438               scount.push_back((*count)[i]);
439               array_size *= (*count)[i];
440               i++;
441            }
442            else
443            {
444               sstart.push_back(0);
445               scount.push_back(sizes[i]);
446               array_size *= sizes[i];
447               i++;
448            }
449         }
450
451      }
452
453
454
455      template <>
456         void CONetCDF4::writeData_(int grpid, int varid,
457                                    const std::vector<StdSize> & sstart,
458                                    const std::vector<StdSize> & scount, const double * data)
459      {
460         (CNetCdfInterface::putVaraType(grpid, varid, &(sstart[0]), &(scount[0]), data));
461//         sync() ;
462      }
463
464      //---------------------------------------------------------------
465
466      template <>
467         void CONetCDF4::writeData_(int grpid, int varid,
468                                    const std::vector<StdSize> & sstart,
469                                    const std::vector<StdSize> & scount, const int * data)
470      {
471          (CNetCdfInterface::putVaraType(grpid, varid, &(sstart[0]), &(scount[0]), data));
472//          sync() ;
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 float * data)
481      {
482          (CNetCdfInterface::putVaraType(grpid, varid, &(sstart[0]), &(scount[0]), data));
483//          sync() ;
484      }
485
486      //---------------------------------------------------------------
487
488      void CONetCDF4::writeData(const CArray<int, 2>& data, const StdString & name)
489      {
490         int grpid = this->getCurrentGroup();
491         int varid = this->getVariable(name);
492         StdSize array_size = 1;
493         std::vector<StdSize> sstart, scount;
494
495         this->getWriteDataInfos(name, 0, array_size,  sstart, scount, NULL, NULL);
496         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
497      }
498
499      void CONetCDF4::writeTimeAxisData(const CArray<double, 1>& data, const StdString & name,
500                                        bool collective, StdSize record, bool isRoot)
501      {
502         int grpid = this->getCurrentGroup();
503         int varid = this->getVariable(name);
504
505         map<int,size_t>::iterator it=timeAxis.find(varid) ;
506         if (it==timeAxis.end()) timeAxis[varid]=record ;
507         else
508         {
509           if (it->second >= record) return ;
510           else it->second =record ;
511         }
512
513         StdSize array_size = 1;
514         std::vector<StdSize> sstart, scount;
515
516         if (this->wmpi && collective)
517         (CNetCdfInterface::varParAccess(grpid, varid, NC_COLLECTIVE));
518         if (this->wmpi && !collective)
519         (CNetCdfInterface::varParAccess(grpid, varid, NC_INDEPENDENT));
520
521         this->getWriteDataInfos(name, record, array_size,  sstart, scount, NULL, NULL);
522         if (using_netcdf_internal)  if (!isRoot) { sstart[0]=sstart[0]+1 ; scount[0]=0 ;}
523         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
524       }
525
526      //---------------------------------------------------------------
527
528      bool CONetCDF4::varExist(const StdString & varname)
529      {
530         int grpid = this->getCurrentGroup();
531         return (CNetCdfInterface::isVarExisted(grpid, varname));
532      }
533
534      void CONetCDF4::sync(void)
535      {
536         (CNetCdfInterface::sync(this->ncidp)) ;
537      }
538      ///--------------------------------------------------------------
539 } // namespace xios
Note: See TracBrowser for help on using the repository browser.