source: XIOS3/trunk/src/io/onetcdf4.cpp

Last change on this file was 2628, checked in by jderouillat, 3 months ago

New timers integration/reporting

  • 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: 32.9 KB
Line 
1#include <fstream>
2
3#include "onetcdf4.hpp"
4#include "onetcdf4_plugin.hpp"
5#include "group_template.hpp"
6#include "mpi.hpp"
7#include "netcdf.hpp"
8#include "netCdfInterface.hpp"
9#include "netCdfException.hpp"
10#include "timer.hpp"
11#include "file.hpp"
12
13namespace xios
14{
15      extern CLogType logProfile ;
16      /// ////////////////////// Définitions ////////////////////// ///
17
18      CONetCDF4::CONetCDF4(const StdString& filename, bool append, bool useClassicFormat,
19                                                        bool useCFConvention,
20                           const MPI_Comm* comm, bool multifile, const StdString& timeCounterName)
21        : path()
22        , wmpi(false)
23        , useClassicFormat(useClassicFormat)
24        , useCFConvention(useCFConvention)
25      {
26         this->initialize(filename, append, useClassicFormat, useCFConvention, comm, multifile, timeCounterName);
27      }
28
29      //---------------------------------------------------------------
30
31      CONetCDF4::~CONetCDF4(void)
32      {
33      }
34
35      ///--------------------------------------------------------------
36
37      void CONetCDF4::initialize(const StdString& filename, bool append, bool useClassicFormat, bool useCFConvention, 
38                                 const MPI_Comm* comm, bool multifile, const StdString& timeCounterName)
39      {
40         this->useClassicFormat = useClassicFormat;
41         this->useCFConvention = useCFConvention;
42
43         int mode = useClassicFormat ? 0 : NC_NETCDF4;
44
45         // Don't use parallel mode if there is only one process
46         if (comm)
47         {
48            int commSize = 0;
49            MPI_Comm_size(*comm, &commSize);
50            if (commSize <= 1)
51               comm = NULL;
52         }
53         wmpi = comm && !multifile;
54
55         if (wmpi)
56            mode |= useClassicFormat ? NC_PNETCDF : NC_MPIIO;
57
58         // If the file does not exist, we always create it
59         if (!append || !std::ifstream(filename.c_str()))
60         {
61            if (info.isActive(logProfile)) CTimer::get("Files : create").resume();
62            if (wmpi)
63               CNetCdfInterface::createPar(filename, mode, *comm, MPI_INFO_NULL, this->ncidp);
64            else
65               CNetCdfInterface::create(filename, mode, this->ncidp);
66            if (info.isActive(logProfile)) CTimer::get("Files : create").suspend();
67 
68            this->appendMode = false;
69         }
70         else
71         {
72            mode |= NC_WRITE;
73            if (info.isActive(logProfile)) CTimer::get("Files : open").resume();
74            if (wmpi)
75               CNetCdfInterface::openPar(filename, mode, *comm, MPI_INFO_NULL, this->ncidp);
76            else
77               CNetCdfInterface::open(filename, mode, this->ncidp);
78            if (info.isActive(logProfile)) CTimer::get("Files : open").suspend();
79            this->appendMode = true;
80         }
81
82         // If the classic NetCDF format is used, we enable the "no-fill mode" globally.
83         // This is done per variable for the NetCDF4 format.
84         if (useClassicFormat)
85            CNetCdfInterface::setFill(this->ncidp, false);
86
87         this->timeCounterName = timeCounterName;
88      }
89
90      void CONetCDF4::close()
91      {
92        if (info.isActive(logProfile)) CTimer::get("Files : close").resume();
93        CNetCdfInterface::close(this->ncidp);
94        if (info.isActive(logProfile)) CTimer::get("Files : close").suspend();
95      }
96
97      //---------------------------------------------------------------
98
99      void CONetCDF4::definition_start(void)
100      {
101         CNetCdfInterface::reDef(this->ncidp);
102      }
103
104      //---------------------------------------------------------------
105
106      void CONetCDF4::definition_end(void)
107      {
108         CNetCdfInterface::endDef(this->ncidp);
109      }
110
111      //---------------------------------------------------------------
112
113      int CONetCDF4::getCurrentGroup(void)
114      {
115         return this->getGroup(this->getCurrentPath());
116      }
117
118      //---------------------------------------------------------------
119
120      int CONetCDF4::getGroup(const CONetCDF4Path& path)
121      {
122         int retvalue = this->ncidp;
123
124         CONetCDF4Path::const_iterator it = path.begin(), end = path.end();
125
126         for (; it != end; it++)
127         {
128            const StdString& groupid = *it;
129            CNetCdfInterface::inqNcId(retvalue, groupid, retvalue);
130         }
131         return retvalue;
132      }
133
134      //---------------------------------------------------------------
135
136      int CONetCDF4::getVariable(const StdString& varname)
137      {
138         int varid = 0;
139         int grpid = this->getCurrentGroup();
140         CNetCdfInterface::inqVarId(grpid, varname, varid);
141         return varid;
142      }
143
144      //---------------------------------------------------------------
145
146      int CONetCDF4::getDimension(const StdString& dimname)
147      {
148         int dimid = 0;
149         int grpid = this->getCurrentGroup();
150         CNetCdfInterface::inqDimId(grpid, dimname, dimid);
151         return dimid;
152      }
153
154      //---------------------------------------------------------------
155
156      int CONetCDF4::getUnlimitedDimension(void)
157      {
158         int dimid = 0;
159         int grpid = this->getCurrentGroup();
160         CNetCdfInterface::inqUnLimDim(grpid, dimid);
161         return dimid;
162      }
163
164      StdString CONetCDF4::getUnlimitedDimensionName(void)
165      {
166         int grpid = this->getGroup(path);
167         int dimid = this->getUnlimitedDimension();
168
169         StdString dimname;
170         if (dimid != -1)
171           CNetCdfInterface::inqDimName(grpid, dimid, dimname);
172         return dimname;
173      }
174
175      //---------------------------------------------------------------
176
177      std::vector<StdSize> CONetCDF4::getDimensions(const StdString& varname)
178      {
179         StdSize size = 0;
180         std::vector<StdSize> retvalue;
181         int grpid = this->getCurrentGroup();
182         int varid = this->getVariable(varname);
183         int nbdim = 0, *dimid = NULL;
184
185         CNetCdfInterface::inqVarNDims(grpid, varid, nbdim);
186         dimid = new int[nbdim]();
187         CNetCdfInterface::inqVarDimId(grpid, varid, dimid);
188
189         for (int i = 0; i < nbdim; i++)
190         {
191            CNetCdfInterface::inqDimLen(grpid, dimid[i], size);
192            if (size == NC_UNLIMITED)
193                size = UNLIMITED_DIM;
194            retvalue.push_back(size);
195         }
196         delete [] dimid;
197         return retvalue;
198      }
199
200      std::vector<std::string> CONetCDF4::getDimensionsIdList(const std::string* _varname)
201      {
202         int nDimNull = 0;
203         int nbdim = 0, *dimid = NULL;
204         int grpid = this->getCurrentGroup();
205         int varid = (_varname != NULL) ? this->getVariable(*_varname) : NC_GLOBAL;
206         std::vector<std::string> retvalue;
207
208         if (_varname != NULL)
209         {
210            CNetCdfInterface::inqVarNDims(grpid, varid, nbdim);
211            dimid = new int[nbdim]();
212            CNetCdfInterface::inqVarDimId(grpid, varid, dimid);
213         }
214         else
215         {
216            CNetCdfInterface::inqDimIds(grpid, nbdim, NULL, 1);
217            dimid = new int[nbdim]();
218            CNetCdfInterface::inqDimIds(grpid, nDimNull, dimid, 1);
219         }
220
221         for (int i = 0; i < nbdim; i++)
222         {
223            std::string dimname;
224            CNetCdfInterface::inqDimName(grpid, dimid[i], dimname);
225            retvalue.push_back(dimname);
226         }
227         delete [] dimid;
228
229         return retvalue;
230      }
231
232      //---------------------------------------------------------------
233
234      void CONetCDF4::getTimeAxisBounds(CArray<double,2>& timeAxisBounds, const StdString& name, bool collective)
235      {
236        int grpid = this->getCurrentGroup();
237        int varid = this->getVariable(name);
238
239        std::vector<StdSize> start(2), count(2);
240        start[0] = 0;
241        // Find out how many temporal records have been written already to the file we are opening
242        int ncUnlimitedDimId;
243        CNetCdfInterface::inqUnLimDim(this->ncidp, ncUnlimitedDimId);
244        CNetCdfInterface::inqDimLen(this->ncidp, ncUnlimitedDimId, count[0]);
245        start[1] = 0;
246        count[1] = 2;
247
248        timeAxisBounds.resize(count[1], count[0]);
249
250        if (this->wmpi && collective)
251          CNetCdfInterface::varParAccess(grpid, varid, NC_COLLECTIVE);
252        if (this->wmpi && !collective)
253          CNetCdfInterface::varParAccess(grpid, varid, NC_INDEPENDENT);
254
255        CNetCdfInterface::getVaraType(grpid, varid, &start[0], &count[0], timeAxisBounds.dataFirst());
256      }
257
258      void CONetCDF4::getTimeAxisBounds(CArray<double,2>& timeAxisBounds, const StdString& name, bool collective, size_t record)
259      {
260        int grpid = this->getCurrentGroup();
261        int varid = this->getVariable(name);
262
263        std::vector<StdSize> start(2), count(2);
264        start[0] = record;
265        count[0] = 1 ;
266        start[1] = 0;
267        count[1] = 2;
268
269        timeAxisBounds.resize(2, 1);
270
271        if (this->wmpi && collective)
272          CNetCdfInterface::varParAccess(grpid, varid, NC_COLLECTIVE);
273        if (this->wmpi && !collective)
274          CNetCdfInterface::varParAccess(grpid, varid, NC_INDEPENDENT);
275
276        CNetCdfInterface::getVaraType(grpid, varid, &start[0], &count[0], timeAxisBounds.dataFirst());
277      }
278
279
280
281      const CONetCDF4::CONetCDF4Path& CONetCDF4::getCurrentPath(void) const
282      { return this->path; }
283
284      void CONetCDF4::setCurrentPath(const CONetCDF4Path& path)
285      { this->path = path; }
286
287      //---------------------------------------------------------------
288
289      int CONetCDF4::addGroup(const StdString& name)
290      {
291         int retvalue = 0;
292         int grpid = this->getCurrentGroup();
293         CNetCdfInterface::defGrp(grpid, name, retvalue);
294         return retvalue;
295      }
296
297      //---------------------------------------------------------------
298
299      int CONetCDF4::addDimension(const StdString& name, const StdSize size)
300      {
301         int retvalue = 0;
302         int grpid = this->getCurrentGroup();
303         if (size != UNLIMITED_DIM)
304            CNetCdfInterface::defDim(grpid, name, size, retvalue);
305         else
306            CNetCdfInterface::defDim(grpid, name, NC_UNLIMITED, retvalue);
307         return retvalue;
308      }
309
310      //---------------------------------------------------------------
311
312      int CONetCDF4::addVariable(const StdString& name, nc_type type,
313                                 const std::vector<StdString>& dim, bool defineChunking)
314      {
315         int varid = 0;
316         std::vector<int> dimids;
317         std::vector<StdSize> dimsizes;
318         int dimSize = dim.size();
319
320         StdSize size;
321
322         int grpid = this->getCurrentGroup();
323
324         std::vector<StdString>::const_iterator it = dim.begin(), end = dim.end();
325
326         for (int idx = 0; it != end; it++, ++idx)
327         {
328            const StdString& dimid = *it;
329            dimids.push_back(this->getDimension(dimid));
330            CNetCdfInterface::inqDimLen(grpid, this->getDimension(dimid), size);
331            if (size == NC_UNLIMITED) size = 1;
332            dimsizes.push_back(size);
333         }
334
335         CNetCdfInterface::defVar(grpid, name, type, dimids.size(), &dimids[0], varid);
336
337         if (defineChunking) {
338           int storageType = (0 == dimSize) ? NC_CONTIGUOUS : NC_CHUNKED;
339           CNetCdfInterface::defVarChunking(grpid, varid, storageType, &dimsizes[0]);
340           CNetCdfInterface::defVarFill(grpid, varid, true, NULL);
341         }
342
343         
344         return varid;
345      }
346
347      //---------------------------------------------------------------
348
349      int CONetCDF4::addChunk(CField* field, nc_type type,
350                              const std::vector<StdString>& dim, int compressionLevel)
351      {
352         const StdString& name = field->getFieldOutputName();
353         int varid = 0;
354         std::vector<StdSize> dimsizes;
355         int dimSize = dim.size();
356         
357         StdSize size;
358         StdSize totalSize;
359
360         // default chunk size         
361         StdSize maxSize = 1024 * 1024 * 20; // = 20 Mo (exp using large NEMO like grids)
362         StdSize targetSize = maxSize;
363         if (!field->chunking_blocksize_target.isEmpty())
364         {
365           targetSize = field->chunking_blocksize_target.getValue()*1024*1024;
366         }
367         StdSize recordSize = 1; //sizeof(type);
368         if (field->prec.isEmpty()) recordSize *= 4;
369         else recordSize *= field->prec;
370
371         int grpid = this->getCurrentGroup();
372
373         std::vector<StdString>::const_iterator it = dim.begin(), end = dim.end();
374
375         for (int idx = 0; it != end; it++, ++idx)
376         {
377            const StdString& dimid = *it;
378            CNetCdfInterface::inqDimLen(grpid, this->getDimension(dimid), size);
379            if (size == NC_UNLIMITED) size = 1;
380            recordSize *= size;
381            dimsizes.push_back(size);
382         }
383         double chunkingRatio = (double)recordSize / (double)targetSize;
384
385         varid = this->getVariable(name);
386
387         // The classic NetCDF format does not support chunking nor fill parameters
388         if (!useClassicFormat)
389         {
390            // Browse field's elements (domain, axis) and NetCDF meta-data to retrieve corresponding chunking coefficients
391            //   in the file order !
392            CGrid* grid = field->getGrid();
393            std::vector<CDomain*> domains = grid->getDomains();
394            std::vector<CAxis*> axis = grid->getAxis();
395            bool singleDomain = (field->getRelFile()->nbDomains == 1);
396
397            std::vector<double> userChunkingWeights; // store chunking coefficients defined by users
398            std::vector<StdString>::const_reverse_iterator itId = dim.rbegin(); // NetCDF is fed using dim, see this::addVariable()
399            int elementIdx(0);
400            int outerAxis(-1), outerDomJ(-1), outerDomI(-1);
401            for (vector<StdSize>::reverse_iterator itDim = dimsizes.rbegin(); itDim != dimsizes.rend(); ++itDim, ++itId, ++elementIdx)
402            {
403              bool isAxis(false);
404              for ( auto ax : axis )
405              {
406                StdString axisDim;
407                // Rebuild axis name from axis before comparing
408                if (ax->dim_name.isEmpty()) axisDim = ax->getAxisOutputName();
409                else axisDim=ax->dim_name.getValue();
410                if (axisDim == *itId)
411                {
412                  if (!ax->chunking_weight.isEmpty()) userChunkingWeights.push_back( ax->chunking_weight.getValue() );
413                  else userChunkingWeights.push_back( 0. );
414                  isAxis = true;
415                  outerAxis = elementIdx; // Going backward in dimsizes, overwriting will keep outer
416                  break;
417                }
418              } // end scanning axis
419              bool isDomain(false);
420              for ( auto dom : domains )
421              {
422                StdString axisDim;
423                // Rebuild axis I name from domain before comparing
424                if (!dom->dim_i_name.isEmpty()) axisDim = dom->dim_i_name.getValue();
425                else
426                {
427                  if (dom->type==CDomain::type_attr::curvilinear)  axisDim="x";
428                  if (dom->type==CDomain::type_attr::unstructured) axisDim="cell";
429                  if (dom->type==CDomain::type_attr::rectilinear)  axisDim="lon";
430                }
431                if (!singleDomain) axisDim+="_"+dom->getDomainOutputName();
432                if (axisDim == *itId)
433                {
434                  if (!dom->chunking_weight_i.isEmpty()) userChunkingWeights.push_back( dom->chunking_weight_i.getValue() );
435                  else userChunkingWeights.push_back( 0. );
436                  isDomain = true;
437                  outerDomI = elementIdx; // Going backward in dimsizes, overwriting will keep outer
438                  break;
439                }
440                // Rebuild axis J name from domain before comparing
441                if (!dom->dim_j_name.isEmpty()) axisDim = dom->dim_j_name.getValue();
442                else {
443                  if (dom->type==CDomain::type_attr::curvilinear)  axisDim="y";
444                  if (dom->type==CDomain::type_attr::rectilinear)  axisDim="lat";
445                }
446                if (!singleDomain) axisDim+="_"+dom->getDomainOutputName();
447                if (axisDim == *itId)
448                {
449                  if (!dom->chunking_weight_j.isEmpty()) userChunkingWeights.push_back( dom->chunking_weight_j.getValue() );
450                  else userChunkingWeights.push_back( 0. );
451                  outerDomJ = elementIdx; // Going backward in dimsizes, overwriting will keep outer
452                  isDomain = true;
453                  break;
454                }
455              } // end scanning domain
456              // No chunking applied on scalars or time
457              if ((!isAxis)&&(!isDomain))
458              {
459                userChunkingWeights.push_back( 0. );
460              }
461            }
462
463            double sumChunkingWeights(0);
464            for (int i=0;i<userChunkingWeights.size();i++) sumChunkingWeights += userChunkingWeights[i];
465            if ( (!sumChunkingWeights) && (chunkingRatio > 1) )
466            {
467              if (outerAxis!=-1) userChunkingWeights[outerAxis] = 1;      // chunk along outer axis
468              else if (outerDomJ!=-1) userChunkingWeights[outerDomJ] = 1; // if no axis ? -> along j
469              else if (outerDomI!=-1) userChunkingWeights[outerDomI] = 1; // if no j      -> along i
470              else {;}
471            }
472
473            int countChunkingDims(0); // number of dimensions on which chunking is operated : algo uses pow(value, 1/countChunkingDims)
474            double normalizingWeight(0); // use to relativize chunking coefficients for all dimensions
475            for (int i=0;i<userChunkingWeights.size();i++)
476              if (userChunkingWeights[i]>0.)
477              {
478                countChunkingDims++;
479                normalizingWeight = userChunkingWeights[i];
480              }
481            if (normalizingWeight!=0) // no chunk for scalar
482            {
483              std::vector<double> chunkingRatioPerDims; // will store coefficients used to compute chunk size
484              double productRatios = 1; // last_coeff = pow( shrink_ratio / (product of all ratios), 1/countChunkingDims )
485              for (int i=0;i<userChunkingWeights.size();i++)
486              {
487                chunkingRatioPerDims.push_back( userChunkingWeights[i] / normalizingWeight );
488                if (chunkingRatioPerDims[i]) productRatios *= chunkingRatioPerDims[i];
489              }
490              for (int i=0;i<userChunkingWeights.size();i++)
491              {
492                chunkingRatioPerDims[i] *= pow( chunkingRatio / productRatios, 1./countChunkingDims );
493              }
494             
495              std::vector<double>::iterator itChunkingRatios = chunkingRatioPerDims.begin();
496              //itId = dim.rbegin();
497              double correctionFromPreviousDim = 1.;
498              for (vector<StdSize>::reverse_iterator itDim = dimsizes.rbegin(); itDim != dimsizes.rend(); ++itDim, ++itChunkingRatios, ++itId)
499              {
500                *itChunkingRatios *= correctionFromPreviousDim;
501                correctionFromPreviousDim = 1;
502                if (*itChunkingRatios > 1) // else target larger than size !
503                {
504                  StdSize dimensionSize = *itDim;
505                  //info(0) << *itId << " " << *itDim << " " << *itChunkingRatios << " " << (*itDim)/(*itChunkingRatios) << endl;
506                  *itDim = ceil( *itDim / ceil(*itChunkingRatios) );
507                  correctionFromPreviousDim = *itChunkingRatios/ ((double)dimensionSize/(*itDim));
508                }
509              }
510            }
511            int storageType = (0 == dimSize) ? NC_CONTIGUOUS : NC_CHUNKED;
512            CNetCdfInterface::defVarChunking(grpid, varid, storageType, &dimsizes[0]);
513            CNetCdfInterface::defVarFill(grpid, varid, true, NULL);
514         }
515         
516         return varid;
517      }
518
519      //---------------------------------------------------------------
520
521      void CONetCDF4::setCompressionLevel(const StdString& varname, const StdString& compressionType, int compressionLevel, const CArray<double,1>& compressionParams)
522      {
523         if (compressionLevel < 0 || compressionLevel > 9)
524           ERROR("void CONetCDF4::setCompressionLevel(const StdString& varname, int compressionLevel)",
525                 "Invalid compression level for variable \"" << varname << "\", the value should range between 0 and 9.");
526#ifndef PARALLEL_COMPRESSION
527         if ( ((compressionLevel)||(compressionParams.numElements())) && wmpi)
528           ERROR("void CONetCDF4::setCompressionLevel(const StdString& varname, int compressionLevel)",
529                 "Impossible to use compression for variable \"" << varname << "\" when using parallel mode.");
530#endif
531         int grpid = this->getCurrentGroup();
532         int varid = this->getVariable(varname);
533         if (compressionType=="None")
534         {
535         }
536         else if (compressionType=="gzip")
537         {
538           CNetCdfInterface::defVarDeflate(grpid, varid, compressionLevel);
539         }
540         else
541         {
542           size_t cd_nelmts;
543           unsigned int* cd_values = NULL;
544           if (compressionType=="SZ")
545           {
546             CONetCDF4Plugin::interpretParametersSZ(compressionParams, &cd_nelmts, &cd_values);
547             CNetCdfInterface::defVarFilter(grpid, varid, 32017, cd_nelmts, cd_values);
548           }
549           else if (compressionType=="ZFP")
550           {
551             CONetCDF4Plugin::interpretParametersZFP(compressionParams, &cd_nelmts, &cd_values);
552             CNetCdfInterface::defVarFilter(grpid, varid, 32013, cd_nelmts, cd_values);
553           }
554           else
555           {
556               ERROR("void CONetCDF4::setCompressionLevel(...)", "compression_type = " << compressionType << " is not managed");
557           }
558           if (cd_values!=NULL) delete [] cd_values;
559         }
560                     
561      }
562
563      //---------------------------------------------------------------
564
565      template <>
566      void CONetCDF4::addAttribute(const StdString& name, const StdString& value, const StdString* varname)
567      {
568         int grpid = this->getCurrentGroup();
569         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
570         CNetCdfInterface::putAttType(grpid, varid, name, value.size(), value.c_str());
571      }
572
573      //---------------------------------------------------------------
574
575      template <>
576      void CONetCDF4::addAttribute(const StdString& name, const double& value, const StdString* varname)
577      {
578         int grpid = this->getCurrentGroup();
579         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
580         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
581      }
582
583      template <>
584      void CONetCDF4::addAttribute(const StdString& name, const CArray<double,1>& value, const StdString* varname)
585      {
586         int grpid = this->getCurrentGroup();
587         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
588         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
589      }
590      //---------------------------------------------------------------
591
592      template <>
593      void CONetCDF4::addAttribute(const StdString& name, const float& value, const StdString* varname)
594      {
595         int grpid = this->getCurrentGroup();
596         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
597         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
598      }
599
600      template <>
601      void CONetCDF4::addAttribute(const StdString& name, const CArray<float,1>& value, const StdString* varname)
602      {
603         int grpid = this->getCurrentGroup();
604         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
605         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
606      }
607
608      //---------------------------------------------------------------
609
610      template <>
611      void CONetCDF4::addAttribute(const StdString& name, const int& value, const StdString* varname)
612      {
613         int grpid = this->getCurrentGroup();
614         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
615         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
616      }
617
618      template <>
619      void CONetCDF4::addAttribute(const StdString& name, const CArray<int,1>& value, const StdString* varname)
620      {
621         int grpid = this->getCurrentGroup();
622         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
623         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
624      }
625
626      template <>
627      void CONetCDF4::addAttribute(const StdString& name, const short int& value, const StdString* varname)
628      {
629         int grpid = this->getCurrentGroup();
630         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
631         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
632      }
633
634      template <>
635      void CONetCDF4::addAttribute(const StdString& name, const CArray<short int,1>& value, const StdString* varname)
636      {
637         int grpid = this->getCurrentGroup();
638         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
639         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
640      }
641
642      template <>
643      void CONetCDF4::addAttribute(const StdString& name, const long int& value, const StdString* varname)
644      {
645         int grpid = this->getCurrentGroup();
646         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
647         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
648      }
649
650      template <>
651      void CONetCDF4::addAttribute(const StdString& name, const CArray<long int,1>& value, const StdString* varname)
652      {
653         int grpid = this->getCurrentGroup();
654         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
655         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
656      }
657
658      //---------------------------------------------------------------
659
660      void CONetCDF4::getWriteDataInfos(const StdString& name, StdSize record, StdSize& array_size,
661                                        std::vector<StdSize>& sstart,
662                                        std::vector<StdSize>& scount,
663                                        const std::vector<StdSize>* start,
664                                        const std::vector<StdSize>* count)
665      {
666         std::vector<std::size_t> sizes  = this->getDimensions(name);
667         if (sizes.size()==0) 
668         {
669           
670            if ((start != NULL) && (count != NULL) && start->size()==1 && count->size()==1) // pur scalar case
671              array_size*=(*count)[0] ;
672            else array_size=1 ;
673         }
674         else
675         {
676           std::vector<std::string> iddims = this->getDimensionsIdList (&name);
677           std::vector<std::size_t>::const_iterator
678           it  = sizes.begin(), end = sizes.end();
679           int i = 0;
680
681           if (iddims.begin()->compare(timeCounterName) == 0)
682           {
683             sstart.push_back(record);
684             scount.push_back(1);
685             if ((start == NULL) && (count == NULL)) i++;
686             it++;
687             if (it==end)
688             {
689               if ((start != NULL) && (count != NULL) && start->size()==1 && count->size()==1) // pur scalar case
690               {
691                 scount[0]=(*count)[0] ;
692                 array_size *= (*count)[0];
693               }
694             }
695           }
696           
697           for (;it != end; it++)
698           {
699              if ((start != NULL) && (count != NULL))
700              {
701                 sstart.push_back((*start)[i]);
702                 scount.push_back((*count)[i]);
703                 array_size *= (*count)[i];
704                 i++;
705              }
706              else
707              {
708                 sstart.push_back(0);
709                 scount.push_back(sizes[i]);
710                 array_size *= sizes[i];
711                 i++;
712              }
713           }
714
715         }
716      }
717
718
719      template <>
720      void CONetCDF4::writeData_(int grpid, int varid,
721                                 const std::vector<StdSize>& sstart,
722                                 const std::vector<StdSize>& scount, const double* data)
723      {
724         CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
725      }
726
727      //---------------------------------------------------------------
728
729      template <>
730      void CONetCDF4::writeData_(int grpid, int varid,
731                                 const std::vector<StdSize>& sstart,
732                                 const std::vector<StdSize>& scount, char* data)
733      {
734          CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
735      }
736     
737      template <>
738      void CONetCDF4::writeData_(int grpid, int varid,
739                                 const std::vector<StdSize>& sstart,
740                                 const std::vector<StdSize>& scount, const short* data)
741      {
742          CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
743      }
744   
745      template <>
746      void CONetCDF4::writeData_(int grpid, int varid,
747                                 const std::vector<StdSize>& sstart,
748                                 const std::vector<StdSize>& scount, const int* data)
749      {
750          CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
751      }
752      //---------------------------------------------------------------
753
754      template <>
755      void CONetCDF4::writeData_(int grpid, int varid,
756                                 const std::vector<StdSize>& sstart,
757                                 const std::vector<StdSize>& scount, const size_t* data)
758      {
759          CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
760      }
761      //---------------------------------------------------------------
762
763      template <>
764      void CONetCDF4::writeData_(int grpid, int varid,
765                                 const std::vector<StdSize>& sstart,
766                                 const std::vector<StdSize>& scount, const float* data)
767      {
768          CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
769      }
770
771      //---------------------------------------------------------------
772
773      void CONetCDF4::writeData(const CArray<int, 2>& data, const StdString& name)
774      {
775         int grpid = this->getCurrentGroup();
776         int varid = this->getVariable(name);
777         
778         StdSize array_size = 1;
779         std::vector<StdSize> sstart, scount;
780
781         this->getWriteDataInfos(name, 0, array_size,  sstart, scount, NULL, NULL);
782
783         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
784
785      }
786
787      void CONetCDF4::writeTimeAxisData(const CArray<double, 1>& data, const StdString& name,
788                                        bool collective, StdSize record, bool isRoot)
789      {
790         int grpid = this->getCurrentGroup();
791         int varid = this->getVariable(name);
792
793         map<int,size_t>::iterator it=timeAxis.find(varid);
794         if (it == timeAxis.end()) timeAxis[varid] = record;
795         else
796         {
797           if (it->second >= record) return;
798           else it->second =record;
799         }
800
801         StdSize array_size = 1;
802         std::vector<StdSize> sstart, scount;
803
804         if (this->wmpi && collective)
805            CNetCdfInterface::varParAccess(grpid, varid, NC_COLLECTIVE);
806         if (this->wmpi && !collective)
807            CNetCdfInterface::varParAccess(grpid, varid, NC_INDEPENDENT);
808
809         this->getWriteDataInfos(name, record, array_size,  sstart, scount, NULL, NULL);
810         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
811       }
812
813      void CONetCDF4::writeTimeAxisDataBounds(const CArray<double, 1>& data, const StdString& name,
814                                        bool collective, StdSize record, bool isRoot)
815      {
816         int grpid = this->getCurrentGroup();
817         int varid = this->getVariable(name);
818
819         map<int,size_t>::iterator it=timeAxis.find(varid);
820         if (it == timeAxis.end()) timeAxis[varid] = record;
821         else
822         {
823           if (it->second >= record) return;
824           else it->second =record;
825         }
826
827         StdSize array_size = 1;
828         std::vector<StdSize> sstart, scount;
829
830         if (this->wmpi && collective)
831            CNetCdfInterface::varParAccess(grpid, varid, NC_COLLECTIVE);
832         if (this->wmpi && !collective)
833            CNetCdfInterface::varParAccess(grpid, varid, NC_INDEPENDENT);
834
835         this->getWriteDataInfos(name, record, array_size,  sstart, scount, NULL, NULL);
836         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
837       }
838
839
840      //---------------------------------------------------------------
841
842      bool CONetCDF4::varExist(const StdString& varname)
843      {
844         int grpid = this->getCurrentGroup();
845         return CNetCdfInterface::isVarExisted(grpid, varname);
846      }
847
848      bool CONetCDF4::dimExist(const StdString& dimname)
849      {
850         int grpid = this->getCurrentGroup();
851         return CNetCdfInterface::isDimExisted(grpid, dimname);
852      }
853
854      void CONetCDF4::sync(void)
855      {
856         CNetCdfInterface::sync(this->ncidp);
857      }
858      ///--------------------------------------------------------------
859 } // namespace xios
Note: See TracBrowser for help on using the repository browser.