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

Last change on this file since 605 was 605, checked in by rlacroix, 10 years ago

Don't enable NETCDF parallel mode when only one server is used.

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
File size: 19.2 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
15         (const StdString & filename, bool append, bool useClassicFormat, const MPI_Comm* comm, bool multifile)
16            : path()
17            , wmpi(false)
18            , useClassicFormat(useClassicFormat)
19            , recordOffset(0)
20      {
21         this->initialize(filename, append, useClassicFormat, comm,multifile);
22      }
23
24      //---------------------------------------------------------------
25
26
27      CONetCDF4::~CONetCDF4(void)
28      {
29//         CheckError(nc_close(this->ncidp));
30      }
31
32      ///--------------------------------------------------------------
33
34      void CONetCDF4::initialize
35         (const StdString & filename, bool append, bool useClassicFormat, const MPI_Comm* comm, bool multifile)
36      {
37         this->useClassicFormat = useClassicFormat;
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            this->recordOffset = 0;
64         }
65         else
66         {
67            mode |= NC_WRITE;
68            if (wmpi)
69               CNetCdfInterface::openPar(filename, mode, *comm, MPI_INFO_NULL, this->ncidp);
70            else
71               CNetCdfInterface::open(filename, mode, this->ncidp);
72
73            this->appendMode = true;
74            // Find out how many temporal records have been written already to the file we are opening
75            int ncUnlimitedDimId;
76            CNetCdfInterface::inqUnLimDim(this->ncidp, ncUnlimitedDimId);
77            if (ncUnlimitedDimId != -1)
78               CNetCdfInterface::inqDimLen(this->ncidp, ncUnlimitedDimId, this->recordOffset);
79            else
80               this->recordOffset = 0;
81         }
82
83         // If the classic NetCDF format is used, we enable the "no-fill mode" globally.
84         // This is done per variable for the NetCDF4 format.
85         if (useClassicFormat)
86            CNetCdfInterface::setFill(this->ncidp, false);   
87      }
88
89      void CONetCDF4::close()
90      {
91        (CNetCdfInterface::close(this->ncidp));
92      }
93
94      //---------------------------------------------------------------
95
96      void CONetCDF4::definition_start(void)
97      {
98         (CNetCdfInterface::reDef(this->ncidp));
99      }
100
101      //---------------------------------------------------------------
102
103      void CONetCDF4::definition_end(void)
104      {
105         (CNetCdfInterface::endDef(this->ncidp));
106      }
107
108      //---------------------------------------------------------------
109
110// Don't need it anymore?
111//      void CONetCDF4::CheckError(int status)
112//      {
113//         if (status != NC_NOERR)
114//         {
115//            StdString errormsg (nc_strerror(status)); // fuite mémoire ici ?
116//            ERROR("CONetCDF4::CheckError(int status)",
117//                  << "[ status = " << status << " ] " << errormsg);
118//         }
119//      }
120
121      //---------------------------------------------------------------
122
123      int CONetCDF4::getCurrentGroup(void)
124      {
125         return (this->getGroup(this->getCurrentPath()));
126      }
127
128      //---------------------------------------------------------------
129
130      int CONetCDF4::getGroup(const CONetCDF4Path & path)
131      {
132         int retvalue = this->ncidp;
133
134         CONetCDF4Path::const_iterator
135            it  = path.begin(), end = path.end();
136
137         for (;it != end; it++)
138         {
139            const StdString & groupid = *it;
140            (CNetCdfInterface::inqNcId(retvalue, groupid, retvalue));
141         }
142         return (retvalue);
143      }
144
145      //---------------------------------------------------------------
146
147      int CONetCDF4::getVariable(const StdString & varname)
148      {
149         int varid = 0;
150         int grpid = this->getCurrentGroup();
151         (CNetCdfInterface::inqVarId(grpid, varname, varid));
152         return (varid);
153      }
154
155      //---------------------------------------------------------------
156
157      int CONetCDF4::getDimension(const StdString & dimname)
158      {
159         int dimid = 0;
160         int grpid = this->getCurrentGroup();
161         (CNetCdfInterface::inqDimId(grpid, dimname, dimid));
162         return (dimid);
163      }
164
165      //---------------------------------------------------------------
166
167      int CONetCDF4::getUnlimitedDimension(void)
168      {
169         int dimid = 0;
170         int grpid = this->getCurrentGroup();
171         (CNetCdfInterface::inqUnLimDim(grpid, dimid));
172         return (dimid);
173      }
174
175      StdString CONetCDF4::getUnlimitedDimensionName(void)
176      {
177         int grpid = this->getGroup(path);
178         int dimid = this->getUnlimitedDimension();
179
180         if (dimid == -1) return (std::string());
181         StdString dimname;
182         (CNetCdfInterface::inqDimName(grpid, dimid, dimname));
183
184         return (dimname);
185      }
186
187      //---------------------------------------------------------------
188
189      std::vector<StdSize> CONetCDF4::getDimensions(const StdString & varname)
190      {
191         StdSize size = 0;
192         std::vector<StdSize> retvalue;
193         int grpid = this->getCurrentGroup();
194         int varid = this->getVariable(varname);
195         int nbdim = 0, *dimid = NULL;
196
197         (CNetCdfInterface::inqVarNDims(grpid, varid, nbdim));
198         dimid = new int[nbdim]();
199         (CNetCdfInterface::inqVarDimId(grpid, varid, dimid));
200
201         for (int i = 0; i < nbdim; i++)
202         {
203            (CNetCdfInterface::inqDimLen(grpid, dimid[i], size));
204            if (size == NC_UNLIMITED)
205                size = UNLIMITED_DIM;
206            retvalue.push_back(size);
207         }
208         delete [] dimid;
209         return (retvalue);
210      }
211
212      std::vector<std::string> CONetCDF4::getDimensionsIdList (const std::string * _varname)
213      {
214         int nDimNull = 0;
215         int nbdim = 0, *dimid = NULL;
216         int grpid = this->getCurrentGroup();
217         int varid = (_varname != NULL) ? this->getVariable(*_varname) : NC_GLOBAL;
218         std::vector<std::string> retvalue;
219
220         if (_varname != NULL)
221         {
222            (CNetCdfInterface::inqVarNDims(grpid, varid, nbdim));
223            dimid = new int[nbdim]();
224            (CNetCdfInterface::inqVarDimId(grpid, varid, dimid));
225         }
226         else
227         {
228            (CNetCdfInterface::inqDimIds(grpid, nbdim, NULL, 1));
229            dimid = new int[nbdim]();
230            (CNetCdfInterface::inqDimIds(grpid, nDimNull, dimid, 1));
231         }
232
233         for (int i = 0; i < nbdim; i++)
234         {
235            std::string dimname;
236            (CNetCdfInterface::inqDimName(grpid, dimid[i], dimname));
237            retvalue.push_back(dimname);
238         }
239         delete [] dimid;
240
241         return (retvalue);
242      }
243
244
245      //---------------------------------------------------------------
246
247      const CONetCDF4::CONetCDF4Path & CONetCDF4::getCurrentPath(void) const
248      { return (this->path); }
249
250      void CONetCDF4::setCurrentPath(const CONetCDF4Path & path)
251      { this->path = path; }
252
253      //---------------------------------------------------------------
254
255      int CONetCDF4::addGroup(const StdString & name)
256      {
257         int retvalue = 0;
258         int grpid = this->getCurrentGroup();
259         (CNetCdfInterface::defGrp(grpid, name, retvalue));
260         return (retvalue);
261      }
262
263      //---------------------------------------------------------------
264
265      int CONetCDF4::addDimension(const StdString& name, const StdSize size)
266      {
267         int retvalue = 0;
268         int grpid = this->getCurrentGroup();
269         if (size != UNLIMITED_DIM)
270            (CNetCdfInterface::defDim(grpid, name, size, retvalue));
271         else
272            (CNetCdfInterface::defDim(grpid, name, NC_UNLIMITED, retvalue));
273         return (retvalue);
274      }
275
276      //---------------------------------------------------------------
277
278      int CONetCDF4::addVariable(const StdString & name, nc_type type,
279                                  const std::vector<StdString> & dim)
280      {
281         int varid = 0;
282         std::vector<int> dimids;
283         std::vector<StdSize> dimsizes ;
284         StdSize size ;
285         StdSize totalSize ;
286         StdSize maxSize=1024*1024*256 ; // == 2GB/8 if output double
287
288         int grpid = this->getCurrentGroup();
289
290         std::vector<StdString>::const_iterator
291            it  = dim.begin(), end = dim.end();
292
293         for (;it != end; it++)
294         {
295            const StdString & dimid = *it;
296            dimids.push_back(this->getDimension(dimid));
297            (CNetCdfInterface::inqDimLen(grpid, this->getDimension(dimid), size));
298            if (size==NC_UNLIMITED) size=1 ;
299            dimsizes.push_back(size) ;
300         }
301
302         CNetCdfInterface::defVar(grpid, name, type, dimids.size(), &(dimids[0]), varid);
303
304         // The classic NetCDF format does not support chunking nor fill parameters
305         if (!useClassicFormat)
306         {
307            // set chunksize : size of one record
308            // but must not be > 2GB (netcdf or HDF5 problem)
309            totalSize = 1;
310            for (vector<StdSize>::reverse_iterator it = dimsizes.rbegin(); it != dimsizes.rend(); ++it)
311            {
312              totalSize *= *it;
313              if (totalSize >= maxSize) *it = 1;
314            }
315
316            CNetCdfInterface::defVarChunking(grpid, varid, NC_CHUNKED, &dimsizes[0]);
317            CNetCdfInterface::defVarFill(grpid, varid, true, NULL);
318         }
319
320         return (varid);
321      }
322
323      //---------------------------------------------------------------
324
325      template <>
326         void CONetCDF4::addAttribute
327            (const StdString & name, const StdString & value, const StdString * varname )
328      {
329         int grpid = this->getCurrentGroup();
330         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
331         (CNetCdfInterface::putAtt(grpid, varid, name, NC_CHAR, value.size(), value.c_str()));
332         //CheckError(nc_put_att_string(grpid, varid, name.c_str(), 1, &str));
333      }
334
335      //---------------------------------------------------------------
336
337      template <>
338         void CONetCDF4::addAttribute
339            (const StdString & name, const double & value, const StdString * varname )
340      {
341         int grpid = this->getCurrentGroup();
342         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
343         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
344      }
345
346       template <>
347         void CONetCDF4::addAttribute
348            (const StdString & name, const CArray<double,1>& value, const StdString * varname )
349      {
350         int grpid = this->getCurrentGroup();
351         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
352         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
353      }
354      //---------------------------------------------------------------
355
356      template <>
357         void CONetCDF4::addAttribute
358            (const StdString & name, const float & value, const StdString * varname )
359      {
360         int grpid = this->getCurrentGroup();
361         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
362         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
363      }
364
365       template <>
366         void CONetCDF4::addAttribute
367            (const StdString & name, const CArray<float,1>& value, const StdString * varname )
368      {
369         int grpid = this->getCurrentGroup();
370         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
371         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
372      }
373
374      //---------------------------------------------------------------
375
376      template <>
377         void CONetCDF4::addAttribute
378            (const StdString & name, const int & value, const StdString * varname )
379      {
380         int grpid = this->getCurrentGroup();
381         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
382         (CNetCdfInterface::putAttType(grpid, varid, name, 1, &value));
383      }
384
385       template <>
386         void CONetCDF4::addAttribute
387            (const StdString & name, const CArray<int,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      template <>
395         void CONetCDF4::addAttribute
396            (const StdString & name, const short int & 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
405            (const StdString & name, const CArray<short int,1>& value, const StdString * varname )
406      {
407         int grpid = this->getCurrentGroup();
408         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
409         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
410      }
411
412
413
414      template <>
415         void CONetCDF4::addAttribute
416            (const StdString & name, const long int & 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, 1, &value));
421      }
422
423       template <>
424         void CONetCDF4::addAttribute
425            (const StdString & name, const CArray<long int,1>& value, const StdString * varname )
426      {
427         int grpid = this->getCurrentGroup();
428         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
429         (CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst()));
430      }
431
432
433
434                //---------------------------------------------------------------
435
436      void CONetCDF4::getWriteDataInfos(const StdString & name, StdSize record, StdSize & array_size,
437                                        std::vector<StdSize> & sstart,
438                                        std::vector<StdSize> & scount,
439                                        const std::vector<StdSize> * start,
440                                        const std::vector<StdSize> * count)
441      {
442         std::vector<std::size_t> sizes  = this->getDimensions(name);
443         std::vector<std::string> iddims = this->getDimensionsIdList (&name);
444         std::vector<std::size_t>::const_iterator
445            it  = sizes.begin(), end = sizes.end();
446         int i = 0;
447
448         if (iddims.begin()->compare(this->getUnlimitedDimensionName()) == 0)
449         {
450            sstart.push_back(record + recordOffset);
451            scount.push_back(1); 
452            if ((start == NULL) &&
453                (count == NULL)) i++;
454            it++;
455         }
456
457         for (;it != end; it++)
458         { 
459            if ((start != NULL) && (count != NULL))
460            {
461               sstart.push_back((*start)[i]);
462               scount.push_back((*count)[i]);
463               array_size *= (*count)[i];
464               i++;
465            }
466            else
467            {
468               sstart.push_back(0);
469               scount.push_back(sizes[i]);
470               array_size *= sizes[i];
471               i++;
472            }
473         }
474
475      }
476
477
478
479      template <>
480         void CONetCDF4::writeData_(int grpid, int varid,
481                                    const std::vector<StdSize> & sstart,
482                                    const std::vector<StdSize> & scount, const double * data)
483      {
484         (CNetCdfInterface::putVaraType(grpid, varid, &(sstart[0]), &(scount[0]), data));
485//         sync() ;
486      }
487
488      //---------------------------------------------------------------
489
490      template <>
491         void CONetCDF4::writeData_(int grpid, int varid,
492                                    const std::vector<StdSize> & sstart,
493                                    const std::vector<StdSize> & scount, const int * data)
494      {
495          (CNetCdfInterface::putVaraType(grpid, varid, &(sstart[0]), &(scount[0]), data));
496//          sync() ;
497      }
498
499      //---------------------------------------------------------------
500
501      template <>
502         void CONetCDF4::writeData_(int grpid, int varid,
503                                    const std::vector<StdSize> & sstart,
504                                    const std::vector<StdSize> & scount, const float * data)
505      {
506          (CNetCdfInterface::putVaraType(grpid, varid, &(sstart[0]), &(scount[0]), data));
507//          sync() ;
508      }
509
510      //---------------------------------------------------------------
511
512      void CONetCDF4::writeData(const CArray<int, 2>& data, const StdString & name)
513      {
514         int grpid = this->getCurrentGroup();
515         int varid = this->getVariable(name);
516         StdSize array_size = 1;
517         std::vector<StdSize> sstart, scount;
518
519         this->getWriteDataInfos(name, 0, array_size,  sstart, scount, NULL, NULL);
520         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
521      }
522
523      void CONetCDF4::writeTimeAxisData(const CArray<double, 1>& data, const StdString & name,
524                                        bool collective, StdSize record, bool isRoot)
525      {
526         int grpid = this->getCurrentGroup();
527         int varid = this->getVariable(name);
528
529         map<int,size_t>::iterator it=timeAxis.find(varid) ;
530         if (it==timeAxis.end()) timeAxis[varid]=record ;
531         else
532         {
533           if (it->second >= record) return ;
534           else it->second =record ;
535         }
536
537         StdSize array_size = 1;
538         std::vector<StdSize> sstart, scount;
539
540         if (this->wmpi && collective)
541         (CNetCdfInterface::varParAccess(grpid, varid, NC_COLLECTIVE));
542         if (this->wmpi && !collective)
543         (CNetCdfInterface::varParAccess(grpid, varid, NC_INDEPENDENT));
544
545         this->getWriteDataInfos(name, record, array_size,  sstart, scount, NULL, NULL);
546         if (using_netcdf_internal)  if (!isRoot) { sstart[0]=sstart[0]+1 ; scount[0]=0 ;}
547         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
548       }
549
550      //---------------------------------------------------------------
551
552      bool CONetCDF4::varExist(const StdString & varname)
553      {
554         int grpid = this->getCurrentGroup();
555         return (CNetCdfInterface::isVarExisted(grpid, varname));
556      }
557
558      void CONetCDF4::sync(void)
559      {
560         (CNetCdfInterface::sync(this->ncidp)) ;
561      }
562      ///--------------------------------------------------------------
563 } // namespace xios
Note: See TracBrowser for help on using the repository browser.