source: XIOS/dev/branch_yushan_merged/src/io/onetcdf4.cpp @ 1138

Last change on this file since 1138 was 1138, checked in by yushan, 7 years ago

test_remap back to work. No thread for now

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