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
RevLine 
[528]1#include <fstream>
2
[219]3#include "onetcdf4.hpp"
[2529]4#include "onetcdf4_plugin.hpp"
[352]5#include "group_template.hpp"
[382]6#include "mpi.hpp"
[379]7#include "netcdf.hpp"
[498]8#include "netCdfInterface.hpp"
9#include "netCdfException.hpp"
[1158]10#include "timer.hpp"
[2579]11#include "file.hpp"
[219]12
[335]13namespace xios
[219]14{
[2628]15      extern CLogType logProfile ;
[219]16      /// ////////////////////// Définitions ////////////////////// ///
17
[686]18      CONetCDF4::CONetCDF4(const StdString& filename, bool append, bool useClassicFormat,
[878]19                                                        bool useCFConvention,
[1639]20                           const MPI_Comm* comm, bool multifile, const StdString& timeCounterName)
[686]21        : path()
22        , wmpi(false)
23        , useClassicFormat(useClassicFormat)
[878]24        , useCFConvention(useCFConvention)
[219]25      {
[878]26         this->initialize(filename, append, useClassicFormat, useCFConvention, comm, multifile, timeCounterName);
[219]27      }
[498]28
[219]29      //---------------------------------------------------------------
[286]30
[219]31      CONetCDF4::~CONetCDF4(void)
32      {
33      }
34
35      ///--------------------------------------------------------------
36
[878]37      void CONetCDF4::initialize(const StdString& filename, bool append, bool useClassicFormat, bool useCFConvention, 
[1639]38                                 const MPI_Comm* comm, bool multifile, const StdString& timeCounterName)
[219]39      {
[517]40         this->useClassicFormat = useClassicFormat;
[878]41         this->useCFConvention = useCFConvention;
[517]42
43         int mode = useClassicFormat ? 0 : NC_NETCDF4;
[605]44
45         // Don't use parallel mode if there is only one process
46         if (comm)
47         {
48            int commSize = 0;
[1639]49            MPI_Comm_size(*comm, &commSize);
[605]50            if (commSize <= 1)
51               comm = NULL;
52         }
53         wmpi = comm && !multifile;
54
55         if (wmpi)
[517]56            mode |= useClassicFormat ? NC_PNETCDF : NC_MPIIO;
57
[528]58         // If the file does not exist, we always create it
59         if (!append || !std::ifstream(filename.c_str()))
[219]60         {
[2628]61            if (info.isActive(logProfile)) CTimer::get("Files : create").resume();
[605]62            if (wmpi)
[1639]63               CNetCdfInterface::createPar(filename, mode, *comm, MPI_INFO_NULL, this->ncidp);
[605]64            else
65               CNetCdfInterface::create(filename, mode, this->ncidp);
[2628]66            if (info.isActive(logProfile)) CTimer::get("Files : create").suspend();
[1158]67 
[528]68            this->appendMode = false;
[219]69         }
70         else
71         {
[528]72            mode |= NC_WRITE;
[2628]73            if (info.isActive(logProfile)) CTimer::get("Files : open").resume();
[605]74            if (wmpi)
[1639]75               CNetCdfInterface::openPar(filename, mode, *comm, MPI_INFO_NULL, this->ncidp);
[605]76            else
77               CNetCdfInterface::open(filename, mode, this->ncidp);
[2628]78            if (info.isActive(logProfile)) CTimer::get("Files : open").suspend();
[528]79            this->appendMode = true;
[219]80         }
[517]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)
[606]85            CNetCdfInterface::setFill(this->ncidp, false);
[802]86
87         this->timeCounterName = timeCounterName;
[219]88      }
[498]89
[286]90      void CONetCDF4::close()
91      {
[2628]92        if (info.isActive(logProfile)) CTimer::get("Files : close").resume();
[686]93        CNetCdfInterface::close(this->ncidp);
[2628]94        if (info.isActive(logProfile)) CTimer::get("Files : close").suspend();
[286]95      }
[498]96
[219]97      //---------------------------------------------------------------
[498]98
[219]99      void CONetCDF4::definition_start(void)
[498]100      {
[686]101         CNetCdfInterface::reDef(this->ncidp);
[219]102      }
[498]103
[219]104      //---------------------------------------------------------------
[498]105
[219]106      void CONetCDF4::definition_end(void)
107      {
[686]108         CNetCdfInterface::endDef(this->ncidp);
[219]109      }
110
111      //---------------------------------------------------------------
[498]112
[219]113      int CONetCDF4::getCurrentGroup(void)
114      {
[686]115         return this->getGroup(this->getCurrentPath());
[219]116      }
[498]117
[219]118      //---------------------------------------------------------------
[498]119
[686]120      int CONetCDF4::getGroup(const CONetCDF4Path& path)
[219]121      {
122         int retvalue = this->ncidp;
[498]123
[686]124         CONetCDF4Path::const_iterator it = path.begin(), end = path.end();
[219]125
[686]126         for (; it != end; it++)
[219]127         {
[686]128            const StdString& groupid = *it;
129            CNetCdfInterface::inqNcId(retvalue, groupid, retvalue);
[219]130         }
[686]131         return retvalue;
[219]132      }
[498]133
[219]134      //---------------------------------------------------------------
[498]135
[686]136      int CONetCDF4::getVariable(const StdString& varname)
[219]137      {
138         int varid = 0;
139         int grpid = this->getCurrentGroup();
[686]140         CNetCdfInterface::inqVarId(grpid, varname, varid);
141         return varid;
[219]142      }
[498]143
[219]144      //---------------------------------------------------------------
[498]145
[686]146      int CONetCDF4::getDimension(const StdString& dimname)
[219]147      {
148         int dimid = 0;
149         int grpid = this->getCurrentGroup();
[686]150         CNetCdfInterface::inqDimId(grpid, dimname, dimid);
151         return dimid;
[219]152      }
[498]153
[219]154      //---------------------------------------------------------------
[498]155
[219]156      int CONetCDF4::getUnlimitedDimension(void)
157      {
158         int dimid = 0;
159         int grpid = this->getCurrentGroup();
[686]160         CNetCdfInterface::inqUnLimDim(grpid, dimid);
161         return dimid;
[219]162      }
[498]163
[266]164      StdString CONetCDF4::getUnlimitedDimensionName(void)
165      {
166         int grpid = this->getGroup(path);
167         int dimid = this->getUnlimitedDimension();
[498]168
169         StdString dimname;
[686]170         if (dimid != -1)
171           CNetCdfInterface::inqDimName(grpid, dimid, dimname);
172         return dimname;
[266]173      }
[498]174
[219]175      //---------------------------------------------------------------
[498]176
[686]177      std::vector<StdSize> CONetCDF4::getDimensions(const StdString& varname)
[219]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
[686]185         CNetCdfInterface::inqVarNDims(grpid, varid, nbdim);
[219]186         dimid = new int[nbdim]();
[686]187         CNetCdfInterface::inqVarDimId(grpid, varid, dimid);
[219]188
189         for (int i = 0; i < nbdim; i++)
190         {
[686]191            CNetCdfInterface::inqDimLen(grpid, dimid[i], size);
[219]192            if (size == NC_UNLIMITED)
193                size = UNLIMITED_DIM;
194            retvalue.push_back(size);
195         }
[401]196         delete [] dimid;
[686]197         return retvalue;
[219]198      }
199
[686]200      std::vector<std::string> CONetCDF4::getDimensionsIdList(const std::string* _varname)
[266]201      {
[498]202         int nDimNull = 0;
[266]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;
[498]207
[266]208         if (_varname != NULL)
209         {
[686]210            CNetCdfInterface::inqVarNDims(grpid, varid, nbdim);
[266]211            dimid = new int[nbdim]();
[686]212            CNetCdfInterface::inqVarDimId(grpid, varid, dimid);
[266]213         }
214         else
215         {
[686]216            CNetCdfInterface::inqDimIds(grpid, nbdim, NULL, 1);
[266]217            dimid = new int[nbdim]();
[686]218            CNetCdfInterface::inqDimIds(grpid, nDimNull, dimid, 1);
[266]219         }
[498]220
[266]221         for (int i = 0; i < nbdim; i++)
222         {
[498]223            std::string dimname;
[686]224            CNetCdfInterface::inqDimName(grpid, dimid[i], dimname);
[266]225            retvalue.push_back(dimname);
226         }
227         delete [] dimid;
[498]228
[686]229         return retvalue;
[266]230      }
231
[219]232      //---------------------------------------------------------------
233
[707]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
[1158]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);
[707]262
[1158]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
[686]281      const CONetCDF4::CONetCDF4Path& CONetCDF4::getCurrentPath(void) const
282      { return this->path; }
[219]283
[686]284      void CONetCDF4::setCurrentPath(const CONetCDF4Path& path)
[219]285      { this->path = path; }
286
287      //---------------------------------------------------------------
288
[686]289      int CONetCDF4::addGroup(const StdString& name)
[219]290      {
291         int retvalue = 0;
292         int grpid = this->getCurrentGroup();
[686]293         CNetCdfInterface::defGrp(grpid, name, retvalue);
294         return retvalue;
[219]295      }
[498]296
[219]297      //---------------------------------------------------------------
[498]298
[219]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)
[686]304            CNetCdfInterface::defDim(grpid, name, size, retvalue);
[219]305         else
[686]306            CNetCdfInterface::defDim(grpid, name, NC_UNLIMITED, retvalue);
307         return retvalue;
[219]308      }
[498]309
[219]310      //---------------------------------------------------------------
[498]311
[686]312      int CONetCDF4::addVariable(const StdString& name, nc_type type,
[2481]313                                 const std::vector<StdString>& dim, bool defineChunking)
[219]314      {
[350]315         int varid = 0;
[219]316         std::vector<int> dimids;
[606]317         std::vector<StdSize> dimsizes;
[857]318         int dimSize = dim.size();
[2479]319
[2481]320         StdSize size;
321
[2479]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));
[2481]330            CNetCdfInterface::inqDimLen(grpid, this->getDimension(dimid), size);
331            if (size == NC_UNLIMITED) size = 1;
332            dimsizes.push_back(size);
[2479]333         }
334
335         CNetCdfInterface::defVar(grpid, name, type, dimids.size(), &dimids[0], varid);
[2481]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
[878]343         
[2479]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         
[606]357         StdSize size;
358         StdSize totalSize;
[498]359
[2479]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
[219]371         int grpid = this->getCurrentGroup();
[498]372
[606]373         std::vector<StdString>::const_iterator it = dim.begin(), end = dim.end();
[219]374
[878]375         for (int idx = 0; it != end; it++, ++idx)
[219]376         {
[686]377            const StdString& dimid = *it;
[606]378            CNetCdfInterface::inqDimLen(grpid, this->getDimension(dimid), size);
379            if (size == NC_UNLIMITED) size = 1;
[2479]380            recordSize *= size;
[606]381            dimsizes.push_back(size);
[219]382         }
[2479]383         double chunkingRatio = (double)recordSize / (double)targetSize;
[453]384
[2479]385         varid = this->getVariable(name);
[498]386
[517]387         // The classic NetCDF format does not support chunking nor fill parameters
388         if (!useClassicFormat)
[453]389         {
[2479]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();
[2579]395            bool singleDomain = (field->getRelFile()->nbDomains == 1);
[2479]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)
[517]402            {
[2479]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                }
[2579]431                if (!singleDomain) axisDim+="_"+dom->getDomainOutputName();
[2479]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                }
[2579]446                if (!singleDomain) axisDim+="_"+dom->getDomainOutputName();
[2479]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              }
[517]461            }
[2479]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              }
[2613]481            if (normalizingWeight!=0) // no chunk for scalar
[2479]482            {
[2613]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++)
[2479]486              {
[2613]487                chunkingRatioPerDims.push_back( userChunkingWeights[i] / normalizingWeight );
488                if (chunkingRatioPerDims[i]) productRatios *= chunkingRatioPerDims[i];
[2479]489              }
[2613]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            }
[857]511            int storageType = (0 == dimSize) ? NC_CONTIGUOUS : NC_CHUNKED;
512            CNetCdfInterface::defVarChunking(grpid, varid, storageType, &dimsizes[0]);
[517]513            CNetCdfInterface::defVarFill(grpid, varid, true, NULL);
[453]514         }
[1456]515         
[606]516         return varid;
[219]517      }
518
519      //---------------------------------------------------------------
520
[2529]521      void CONetCDF4::setCompressionLevel(const StdString& varname, const StdString& compressionType, int compressionLevel, const CArray<double,1>& compressionParams)
[606]522      {
[607]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.");
[2529]526#ifndef PARALLEL_COMPRESSION
527         if ( ((compressionLevel)||(compressionParams.numElements())) && wmpi)
[607]528           ERROR("void CONetCDF4::setCompressionLevel(const StdString& varname, int compressionLevel)",
529                 "Impossible to use compression for variable \"" << varname << "\" when using parallel mode.");
[2529]530#endif
[606]531         int grpid = this->getCurrentGroup();
532         int varid = this->getVariable(varname);
[2529]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           }
[2532]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           }
[2529]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                     
[606]561      }
562
563      //---------------------------------------------------------------
564
[219]565      template <>
[686]566      void CONetCDF4::addAttribute(const StdString& name, const StdString& value, const StdString* varname)
[219]567      {
568         int grpid = this->getCurrentGroup();
569         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
[686]570         CNetCdfInterface::putAttType(grpid, varid, name, value.size(), value.c_str());
[219]571      }
[498]572
[219]573      //---------------------------------------------------------------
[498]574
[219]575      template <>
[686]576      void CONetCDF4::addAttribute(const StdString& name, const double& value, const StdString* varname)
[219]577      {
578         int grpid = this->getCurrentGroup();
579         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
[686]580         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
[219]581      }
[391]582
[686]583      template <>
584      void CONetCDF4::addAttribute(const StdString& name, const CArray<double,1>& value, const StdString* varname)
[391]585      {
586         int grpid = this->getCurrentGroup();
587         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
[686]588         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
[498]589      }
[219]590      //---------------------------------------------------------------
[498]591
[219]592      template <>
[686]593      void CONetCDF4::addAttribute(const StdString& name, const float& value, const StdString* varname)
[219]594      {
595         int grpid = this->getCurrentGroup();
596         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
[686]597         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
[219]598      }
[391]599
[686]600      template <>
601      void CONetCDF4::addAttribute(const StdString& name, const CArray<float,1>& value, const StdString* varname)
[391]602      {
603         int grpid = this->getCurrentGroup();
604         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
[686]605         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
[498]606      }
607
[219]608      //---------------------------------------------------------------
[498]609
[219]610      template <>
[686]611      void CONetCDF4::addAttribute(const StdString& name, const int& value, const StdString* varname)
[219]612      {
613         int grpid = this->getCurrentGroup();
614         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
[686]615         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
[219]616      }
617
[686]618      template <>
619      void CONetCDF4::addAttribute(const StdString& name, const CArray<int,1>& value, const StdString* varname)
[391]620      {
621         int grpid = this->getCurrentGroup();
622         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
[686]623         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
[498]624      }
625
[472]626      template <>
[686]627      void CONetCDF4::addAttribute(const StdString& name, const short int& value, const StdString* varname)
[472]628      {
629         int grpid = this->getCurrentGroup();
630         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
[686]631         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
[472]632      }
[219]633
[686]634      template <>
635      void CONetCDF4::addAttribute(const StdString& name, const CArray<short int,1>& value, const StdString* varname)
[472]636      {
637         int grpid = this->getCurrentGroup();
638         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
[686]639         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
[498]640      }
641
[472]642      template <>
[686]643      void CONetCDF4::addAttribute(const StdString& name, const long int& value, const StdString* varname)
[472]644      {
645         int grpid = this->getCurrentGroup();
646         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
[686]647         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
[472]648      }
649
[686]650      template <>
651      void CONetCDF4::addAttribute(const StdString& name, const CArray<long int,1>& value, const StdString* varname)
[472]652      {
653         int grpid = this->getCurrentGroup();
654         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
[686]655         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
[498]656      }
657
[686]658      //---------------------------------------------------------------
[498]659
[686]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)
[498]665      {
[266]666         std::vector<std::size_t> sizes  = this->getDimensions(name);
[857]667         if (sizes.size()==0) 
[266]668         {
[2264]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 ;
[266]673         }
[857]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;
[219]680
[857]681           if (iddims.begin()->compare(timeCounterName) == 0)
682           {
683             sstart.push_back(record);
684             scount.push_back(1);
[2264]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             }
[857]695           }
[2264]696           
[857]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
[219]715         }
716      }
[498]717
[857]718
[219]719      template <>
[686]720      void CONetCDF4::writeData_(int grpid, int varid,
721                                 const std::vector<StdSize>& sstart,
722                                 const std::vector<StdSize>& scount, const double* data)
[219]723      {
[686]724         CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
[219]725      }
[498]726
[219]727      //---------------------------------------------------------------
[498]728
[219]729      template <>
[686]730      void CONetCDF4::writeData_(int grpid, int varid,
731                                 const std::vector<StdSize>& sstart,
[1158]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,
[2600]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,
[686]748                                 const std::vector<StdSize>& scount, const int* data)
[219]749      {
[686]750          CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
[219]751      }
752      //---------------------------------------------------------------
[498]753
[219]754      template <>
[686]755      void CONetCDF4::writeData_(int grpid, int varid,
756                                 const std::vector<StdSize>& sstart,
[1957]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,
[686]766                                 const std::vector<StdSize>& scount, const float* data)
[219]767      {
[686]768          CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
[219]769      }
770
771      //---------------------------------------------------------------
772
[686]773      void CONetCDF4::writeData(const CArray<int, 2>& data, const StdString& name)
[219]774      {
775         int grpid = this->getCurrentGroup();
776         int varid = this->getVariable(name);
[2264]777         
[219]778         StdSize array_size = 1;
779         std::vector<StdSize> sstart, scount;
780
781         this->getWriteDataInfos(name, 0, array_size,  sstart, scount, NULL, NULL);
[1158]782
[369]783         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
[1158]784
[219]785      }
786
[686]787      void CONetCDF4::writeTimeAxisData(const CArray<double, 1>& data, const StdString& name,
[413]788                                        bool collective, StdSize record, bool isRoot)
789      {
790         int grpid = this->getCurrentGroup();
791         int varid = this->getVariable(name);
[498]792
[686]793         map<int,size_t>::iterator it=timeAxis.find(varid);
794         if (it == timeAxis.end()) timeAxis[varid] = record;
[498]795         else
[413]796         {
[686]797           if (it->second >= record) return;
798           else it->second =record;
[413]799         }
[498]800
[413]801         StdSize array_size = 1;
802         std::vector<StdSize> sstart, scount;
[498]803
[413]804         if (this->wmpi && collective)
[686]805            CNetCdfInterface::varParAccess(grpid, varid, NC_COLLECTIVE);
[413]806         if (this->wmpi && !collective)
[686]807            CNetCdfInterface::varParAccess(grpid, varid, NC_INDEPENDENT);
[498]808
[413]809         this->getWriteDataInfos(name, record, array_size,  sstart, scount, NULL, NULL);
[1158]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
[686]822         {
[1158]823           if (it->second >= record) return;
824           else it->second =record;
[686]825         }
[1158]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);
[413]836         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
837       }
838
[1158]839
[219]840      //---------------------------------------------------------------
[498]841
[686]842      bool CONetCDF4::varExist(const StdString& varname)
[219]843      {
844         int grpid = this->getCurrentGroup();
[686]845         return CNetCdfInterface::isVarExisted(grpid, varname);
[219]846      }
847
[878]848      bool CONetCDF4::dimExist(const StdString& dimname)
849      {
850         int grpid = this->getCurrentGroup();
851         return CNetCdfInterface::isDimExisted(grpid, dimname);
852      }
853
[286]854      void CONetCDF4::sync(void)
855      {
[686]856         CNetCdfInterface::sync(this->ncidp);
[498]857      }
[219]858      ///--------------------------------------------------------------
[337]859 } // namespace xios
Note: See TracBrowser for help on using the repository browser.