source: XIOS3/branches/xios-3.0-beta/src/io/onetcdf4.cpp @ 2478

Last change on this file since 2478 was 2478, checked in by jderouillat, 16 months ago

Add tunable output chunking. The user can specify a chunking_blocksize_target (in Mo, default = 20) as a field attribute, and the chunking dimensions in domain/axis definition through the attributes : (chunking_weight_i, chunking_weight_j)/chunking_weight. Weights are relativized for more or less chunking along the directions concerned

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