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

Last change on this file since 878 was 878, checked in by oabramkina, 5 years ago

Sequential version for UGRID norms. File attribute "convention" has been added with two possible values "CF" and "UGRID". The default value is "CF".

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