source: XIOS/dev/branch_openmp/src/io/onetcdf4.cpp @ 1356

Last change on this file since 1356 was 1356, checked in by yushan, 6 years ago

unify MPI_Comm type

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