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

Last change on this file since 2561 was 2532, checked in by jderouillat, 12 months ago

Implement an API to use the ZFP compression plugin.

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