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

Last change on this file since 2481 was 2481, checked in by jderouillat, 15 months ago

Chunk must be defined for non fields variables too in parallel write

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