source: XIOS/trunk/src/output/onetcdf4.cpp @ 472

Last change on this file since 472 was 472, checked in by ymipsl, 9 years ago

Enhancement : user defined global and field attribute can be output in the netcdfcf file.
A variable child element inclosed into a file element will be output as a global file attribute.
A variable child element inclosed into a field element will be output as a field attribute.

+ variable fortran interface added

YM

File size: 18.7 KB
Line 
1#include "onetcdf4.hpp"
2#include "group_template.hpp"
3#include "mpi.hpp"
4#include "netcdf.hpp"
5
6namespace xios
7{
8      /// ////////////////////// Définitions ////////////////////// ///
9
10      CONetCDF4::CONetCDF4
11         (const StdString & filename, bool exist, const MPI_Comm * comm, bool multifile)
12            : path()
13      {
14         this->wmpi = (comm != NULL) && !multifile;
15         this->initialize(filename, exist, comm,multifile);
16      }
17     
18      //---------------------------------------------------------------
19     
20     
21
22      CONetCDF4::~CONetCDF4(void)
23      {
24//         CheckError(nc_close(this->ncidp));
25      }
26
27      ///--------------------------------------------------------------
28
29      void CONetCDF4::initialize
30         (const StdString & filename, bool exist, const MPI_Comm * comm, bool multifile)
31      {
32         if (!exist)
33         {
34            if (comm != NULL)
35            {
36               if (!multifile) CheckError(xios::nc_create_par(filename.c_str(), NC_NETCDF4|NC_MPIIO, *comm, MPI_INFO_NULL, &this->ncidp));
37               else CheckError(nc_create(filename.c_str(), NC_NETCDF4, &this->ncidp));
38            }
39            else CheckError(nc_create(filename.c_str(), NC_NETCDF4, &this->ncidp));
40         }
41         else
42         {
43            if (comm != NULL)
44            {
45               if (!multifile) CheckError(xios::nc_open_par(filename.c_str(), NC_NETCDF4|NC_MPIIO, *comm, MPI_INFO_NULL, &this->ncidp));
46               else CheckError(nc_open(filename.c_str(), NC_NETCDF4, &this->ncidp));
47            }
48            else  CheckError(nc_open(filename.c_str(), NC_NETCDF4, &this->ncidp));
49         }
50      }
51     
52      void CONetCDF4::close()
53      {
54        CheckError(nc_close(this->ncidp));
55      }
56     
57      //---------------------------------------------------------------
58     
59      void CONetCDF4::definition_start(void)
60      { 
61         CheckError(nc_redef(this->ncidp));
62      }
63     
64      //---------------------------------------------------------------
65     
66      void CONetCDF4::definition_end(void)
67      { 
68         CheckError(nc_enddef(this->ncidp));
69      }
70     
71      //---------------------------------------------------------------
72     
73      void CONetCDF4::CheckError(int status)
74      {
75         if (status != NC_NOERR)
76         {
77            StdString errormsg (nc_strerror(status)); // fuite mémoire ici ?
78            ERROR("CONetCDF4::CheckError(int status)",
79                  << "[ status = " << status << " ] " << errormsg);
80         }
81      }
82
83      //---------------------------------------------------------------
84     
85      int CONetCDF4::getCurrentGroup(void)
86      {
87         return (this->getGroup(this->getCurrentPath()));
88      }
89     
90      //---------------------------------------------------------------
91     
92      int CONetCDF4::getGroup(const CONetCDF4Path & path)
93      {
94         int retvalue = this->ncidp;
95         
96         CONetCDF4Path::const_iterator
97            it  = path.begin(), end = path.end();
98
99         for (;it != end; it++)
100         {
101            const StdString & groupid = *it;
102            CheckError(nc_inq_ncid(retvalue, const_cast<char*>(groupid.c_str()), &retvalue));
103         }
104         return (retvalue);
105      }
106     
107      //---------------------------------------------------------------
108     
109      int CONetCDF4::getVariable(const StdString & varname)
110      {
111         int varid = 0;
112         int grpid = this->getCurrentGroup();
113         CheckError(nc_inq_varid (grpid, varname.c_str(), &varid));
114         return (varid);
115      }
116     
117      //---------------------------------------------------------------
118     
119      int CONetCDF4::getDimension(const StdString & dimname)
120      {
121         int dimid = 0;
122         int grpid = this->getCurrentGroup();
123         CheckError(nc_inq_dimid (grpid, dimname.c_str(), &dimid));
124         return (dimid);
125      }
126     
127      //---------------------------------------------------------------
128     
129      int CONetCDF4::getUnlimitedDimension(void)
130      {
131         int dimid = 0;
132         int grpid = this->getCurrentGroup();
133         CheckError(nc_inq_unlimdim (grpid, &dimid));
134         return (dimid);
135      }
136     
137      StdString CONetCDF4::getUnlimitedDimensionName(void)
138      {
139         char full_name_in[NC_MAX_NAME +1];
140         int grpid = this->getGroup(path);
141         int dimid = this->getUnlimitedDimension();
142                             
143         if (dimid == -1) return (std::string());
144            CheckError(nc_inq_dimname(grpid, dimid, full_name_in));
145                                         
146         StdString dimname(full_name_in);
147         return (dimname);
148      }
149     
150      //---------------------------------------------------------------
151     
152      std::vector<StdSize> CONetCDF4::getDimensions(const StdString & varname)
153      {
154         StdSize size = 0;
155         std::vector<StdSize> retvalue;
156         int grpid = this->getCurrentGroup();
157         int varid = this->getVariable(varname);
158         int nbdim = 0, *dimid = NULL;
159
160         CheckError(nc_inq_varndims(grpid, varid, &nbdim));
161         dimid = new int[nbdim]();
162         CheckError(nc_inq_vardimid(grpid, varid, dimid));
163
164         for (int i = 0; i < nbdim; i++)
165         {
166            CheckError(nc_inq_dimlen (grpid, dimid[i], &size));
167            if (size == NC_UNLIMITED)
168                size = UNLIMITED_DIM;
169            retvalue.push_back(size);
170         }
171         delete [] dimid;
172         return (retvalue);
173      }
174
175      std::vector<std::string> CONetCDF4::getDimensionsIdList (const std::string * _varname)
176      {
177         char full_name_in[NC_MAX_NAME +1];
178         int nbdim = 0, *dimid = NULL;
179         int grpid = this->getCurrentGroup();
180         int varid = (_varname != NULL) ? this->getVariable(*_varname) : NC_GLOBAL;
181         std::vector<std::string> retvalue;
182                                   
183         if (_varname != NULL)
184         {
185            CheckError(nc_inq_varndims(grpid, varid, &nbdim));
186            dimid = new int[nbdim]();
187            CheckError(nc_inq_vardimid(grpid, varid, dimid));
188         }
189         else
190         {
191            CheckError(nc_inq_dimids(grpid, &nbdim, NULL, 1));
192            dimid = new int[nbdim]();
193            CheckError(nc_inq_dimids(grpid, NULL, dimid, 1));
194         }
195                                       
196         for (int i = 0; i < nbdim; i++)
197         {
198            CheckError(nc_inq_dimname(grpid, dimid[i], full_name_in));
199            std::string dimname(full_name_in);
200            retvalue.push_back(dimname);
201         }
202         delete [] dimid;
203                                                                                                                                                     
204         return (retvalue);
205      }
206
207
208      //---------------------------------------------------------------
209
210      const CONetCDF4::CONetCDF4Path & CONetCDF4::getCurrentPath(void) const
211      { return (this->path); }
212
213      void CONetCDF4::setCurrentPath(const CONetCDF4Path & path)
214      { this->path = path; }
215
216      //---------------------------------------------------------------
217
218      int CONetCDF4::addGroup(const StdString & name)
219      {
220         int retvalue = 0;
221         int grpid = this->getCurrentGroup();
222         CheckError(nc_def_grp(grpid, const_cast<char*>(name.c_str()), &retvalue));
223         return (retvalue);
224      }
225     
226      //---------------------------------------------------------------
227     
228      int CONetCDF4::addDimension(const StdString& name, const StdSize size)
229      {
230         int retvalue = 0;
231         int grpid = this->getCurrentGroup();
232         if (size != UNLIMITED_DIM)
233            CheckError(nc_def_dim (grpid, name.c_str(), size, &retvalue));
234         else
235            CheckError(nc_def_dim (grpid, name.c_str(), NC_UNLIMITED, &retvalue));
236         return (retvalue);
237      }
238     
239      //---------------------------------------------------------------
240     
241      int CONetCDF4::addVariable(const StdString & name, nc_type type,
242                                  const std::vector<StdString> & dim)
243      {
244         int varid = 0;
245         std::vector<int> dimids;
246         std::vector<StdSize> dimsizes ;
247         StdSize size ;
248         StdSize totalSize ;
249         StdSize maxSize=1024*1024*256 ; // == 2GB/8 if output double
250         
251         int grpid = this->getCurrentGroup();
252         
253         std::vector<StdString>::const_iterator
254            it  = dim.begin(), end = dim.end();
255
256         for (;it != end; it++)
257         {
258            const StdString & dimid = *it;
259            dimids.push_back(this->getDimension(dimid));
260            CheckError(nc_inq_dimlen (grpid, this->getDimension(dimid), &size));
261            if (size==NC_UNLIMITED) size=1 ;
262            dimsizes.push_back(size) ;
263         }
264         
265         CheckError(nc_def_var (grpid, name.c_str(), type, dimids.size(), &(dimids[0]), &varid));
266
267// set chunksize : size of one record
268// but must not be > 2GB (netcdf or HDF5 problem)
269         totalSize=1 ;
270         for(vector<StdSize>::reverse_iterator it=dimsizes.rbegin(); it!=dimsizes.rend();++it)
271         {
272           totalSize*= *it ;
273           if (totalSize>=maxSize) *it=1 ;
274         }
275
276         CheckError(nc_def_var_chunking (grpid, varid, NC_CHUNKED, &(dimsizes[0])));
277         CheckError(nc_def_var_fill(grpid, varid, true, NULL));
278         return (varid);
279      }
280
281      //---------------------------------------------------------------
282
283      template <>
284         void CONetCDF4::addAttribute
285            (const StdString & name, const StdString & value, const StdString * varname )
286      {
287         int grpid = this->getCurrentGroup();
288         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
289         CheckError(nc_put_att(grpid, varid, name.c_str(), NC_CHAR, value.size(), value.c_str()));
290         //CheckError(nc_put_att_string(grpid, varid, name.c_str(), 1, &str));
291      }
292     
293      //---------------------------------------------------------------
294     
295      template <>
296         void CONetCDF4::addAttribute
297            (const StdString & name, const double & value, const StdString * varname )
298      {
299         int grpid = this->getCurrentGroup();
300         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
301         CheckError(nc_put_att_double(grpid, varid, name.c_str(), NC_DOUBLE,1, &value));
302      }
303
304       template <>
305         void CONetCDF4::addAttribute
306            (const StdString & name, const CArray<double,1>& value, const StdString * varname )
307      {
308         int grpid = this->getCurrentGroup();
309         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
310         CheckError(nc_put_att_double(grpid, varid, name.c_str(), NC_DOUBLE,value.numElements(), value.dataFirst()));
311      }     
312      //---------------------------------------------------------------
313     
314      template <>
315         void CONetCDF4::addAttribute
316            (const StdString & name, const float & value, const StdString * varname )
317      {
318         int grpid = this->getCurrentGroup();
319         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
320         CheckError(nc_put_att_float(grpid, varid, name.c_str(), NC_FLOAT, 1, &value));
321      }
322
323       template <>
324         void CONetCDF4::addAttribute
325            (const StdString & name, const CArray<float,1>& value, const StdString * varname )
326      {
327         int grpid = this->getCurrentGroup();
328         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
329         CheckError(nc_put_att_float(grpid, varid, name.c_str(), NC_FLOAT,value.numElements(), value.dataFirst()));
330      }     
331     
332      //---------------------------------------------------------------
333     
334      template <>
335         void CONetCDF4::addAttribute
336            (const StdString & name, const int & value, const StdString * varname )
337      {
338         int grpid = this->getCurrentGroup();
339         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
340         CheckError(nc_put_att_int(grpid, varid, name.c_str(), NC_INT,1, &value));
341      }
342
343       template <>
344         void CONetCDF4::addAttribute
345            (const StdString & name, const CArray<int,1>& value, const StdString * varname )
346      {
347         int grpid = this->getCurrentGroup();
348         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
349         CheckError(nc_put_att_int(grpid, varid, name.c_str(), NC_INT,value.numElements(), value.dataFirst()));
350      }     
351     
352     
353 
354      template <>
355         void CONetCDF4::addAttribute
356            (const StdString & name, const short int & value, const StdString * varname )
357      {
358         int grpid = this->getCurrentGroup();
359         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
360         CheckError(nc_put_att_short(grpid, varid, name.c_str(), NC_SHORT,1, &value));
361      }
362
363       template <>
364         void CONetCDF4::addAttribute
365            (const StdString & name, const CArray<short int,1>& value, const StdString * varname )
366      {
367         int grpid = this->getCurrentGroup();
368         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
369         CheckError(nc_put_att_short(grpid, varid, name.c_str(), NC_SHORT,value.numElements(), value.dataFirst()));
370      }     
371     
372     
373     
374      template <>
375         void CONetCDF4::addAttribute
376            (const StdString & name, const long int & value, const StdString * varname )
377      {
378         int grpid = this->getCurrentGroup();
379         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
380         CheckError(nc_put_att_long(grpid, varid, name.c_str(), NC_LONG,1, &value));
381      }
382
383       template <>
384         void CONetCDF4::addAttribute
385            (const StdString & name, const CArray<long int,1>& value, const StdString * varname )
386      {
387         int grpid = this->getCurrentGroup();
388         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
389         CheckError(nc_put_att_long(grpid, varid, name.c_str(), NC_LONG, value.numElements(), value.dataFirst()));
390      } 
391     
392     
393     
394                //---------------------------------------------------------------
395
396      void CONetCDF4::getWriteDataInfos(const StdString & name, StdSize record, StdSize & array_size,
397                                        std::vector<StdSize> & sstart,
398                                        std::vector<StdSize> & scount,
399                                        const std::vector<StdSize> * start,
400                                        const std::vector<StdSize> * count)
401      {   
402         std::vector<std::size_t> sizes  = this->getDimensions(name);
403         std::vector<std::string> iddims = this->getDimensionsIdList (&name);   
404         std::vector<std::size_t>::const_iterator
405            it  = sizes.begin(), end = sizes.end();
406         int i = 0;
407
408         if (iddims.begin()->compare(this->getUnlimitedDimensionName()) == 0)
409         {
410            sstart.push_back(record);
411            scount.push_back(1); 
412            if ((start == NULL) &&
413                (count == NULL)) i++;
414            it++;
415         }
416
417         for (;it != end; it++)
418         {     
419            if ((start != NULL) && (count != NULL))
420            {
421               sstart.push_back((*start)[i]);
422               scount.push_back((*count)[i]);
423               array_size *= (*count)[i];
424               i++;
425            }
426            else
427            {
428               sstart.push_back(0);
429               scount.push_back(sizes[i]);
430               array_size *= sizes[i];
431               i++;
432            }
433         }
434         
435      }
436     
437                     
438 
439      template <>
440         void CONetCDF4::writeData_(int grpid, int varid,
441                                    const std::vector<StdSize> & sstart,
442                                    const std::vector<StdSize> & scount, const double * data)
443      {
444         CheckError(nc_put_vara_double(grpid, varid, &(sstart[0]), &(scount[0]), data));
445//         sync() ;
446      }
447     
448      //---------------------------------------------------------------
449     
450      template <>
451         void CONetCDF4::writeData_(int grpid, int varid,
452                                    const std::vector<StdSize> & sstart,
453                                    const std::vector<StdSize> & scount, const int * data)
454      {
455          CheckError(nc_put_vara_int(grpid, varid, &(sstart[0]), &(scount[0]), data));
456//          sync() ;
457      }
458     
459      //---------------------------------------------------------------
460     
461      template <>
462         void CONetCDF4::writeData_(int grpid, int varid,
463                                    const std::vector<StdSize> & sstart,
464                                    const std::vector<StdSize> & scount, const float * data)
465      {
466          CheckError(nc_put_vara_float(grpid, varid, &(sstart[0]), &(scount[0]), data));
467//          sync() ;
468      }
469
470      //---------------------------------------------------------------
471
472      void CONetCDF4::writeData(const CArray<int, 2>& data, const StdString & name)
473      {
474         int grpid = this->getCurrentGroup();
475         int varid = this->getVariable(name);
476         StdSize array_size = 1;
477         std::vector<StdSize> sstart, scount;
478
479         this->getWriteDataInfos(name, 0, array_size,  sstart, scount, NULL, NULL);
480         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
481      }
482
483      void CONetCDF4::writeTimeAxisData(const CArray<double, 1>& data, const StdString & name,
484                                        bool collective, StdSize record, bool isRoot)
485      {
486         int grpid = this->getCurrentGroup();
487         int varid = this->getVariable(name);
488         
489         map<int,size_t>::iterator it=timeAxis.find(varid) ;
490         if (it==timeAxis.end()) timeAxis[varid]=record ;
491         else 
492         {
493           if (it->second >= record) return ;
494           else it->second =record ;
495         }
496         
497         StdSize array_size = 1;
498         std::vector<StdSize> sstart, scount;
499         
500         if (this->wmpi && collective)
501         CheckError(nc_var_par_access(grpid, varid, NC_COLLECTIVE));
502         if (this->wmpi && !collective)
503         CheckError(nc_var_par_access(grpid, varid, NC_INDEPENDENT));
504         
505         this->getWriteDataInfos(name, record, array_size,  sstart, scount, NULL, NULL);
506         if (using_netcdf_internal)  if (!isRoot) { sstart[0]=sstart[0]+1 ; scount[0]=0 ;}
507         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
508       }
509
510      //---------------------------------------------------------------
511     
512      bool CONetCDF4::varExist(const StdString & varname)
513      {
514         int varid = 0;
515         int grpid = this->getCurrentGroup();
516         return (nc_inq_varid (grpid, varname.c_str(), &varid) == NC_NOERR);
517      }
518
519      void CONetCDF4::sync(void)
520      {
521         CheckError(nc_sync(this->ncidp)) ;
522      } 
523      ///--------------------------------------------------------------
524 } // namespace xios
Note: See TracBrowser for help on using the repository browser.