source: XIOS3/trunk/src/io/nc4_data_output.cpp @ 2529

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

Enable parallel compression regarding NetCDF & HDF5 configurations at compile time. Implement an API to use HDF5 lossy compression plugins (SZ is available for now).

  • 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
  • Property svn:executable set to *
File size: 126.4 KB
Line 
1#include "nc4_data_output.hpp"
2
3#include "attribute_template.hpp"
4#include "group_template.hpp"
5
6#include "file.hpp"
7#include "calendar.hpp"
8#include "context.hpp"
9#include "context_server.hpp"
10#include "netCdfException.hpp"
11#include "exception.hpp"
12#include "timer.hpp"
13#include "uuid.hpp"
14namespace xios
15{
16      /// ////////////////////// Dfinitions ////////////////////// ///
17      CNc4DataOutput::CNc4DataOutput
18         (CFile* file, const StdString & filename, bool exist)
19            : SuperClass()
20            , SuperClassWriter(filename, exist)
21            , filename(filename)
22            , file(file),hasTimeInstant(false),hasTimeCentered(false), timeCounterType(none), relAxis_(), relDomains_()
23      {
24        SuperClass::type = MULTI_FILE;
25        compressionLevel= file->compression_level.isEmpty() ? 0 :file->compression_level ;
26      }
27
28      CNc4DataOutput::CNc4DataOutput
29         (CFile* file, const StdString & filename, bool exist, bool useClassicFormat, bool useCFConvention,
30          MPI_Comm comm_file, bool multifile, bool isCollective, const StdString& timeCounterName)
31            : SuperClass()
32            , SuperClassWriter(filename, exist, useClassicFormat, useCFConvention, &comm_file, multifile, timeCounterName)
33            , comm_file(comm_file)
34            , filename(filename)
35            , isCollective(isCollective)
36            , file(file),hasTimeInstant(false),hasTimeCentered(false), timeCounterType(none), relAxis_(), relDomains_()
37      {
38        SuperClass::type = (multifile) ? MULTI_FILE : ONE_FILE;
39        if (file==NULL) compressionLevel = 0 ;
40        else compressionLevel= file->compression_level.isEmpty() ? 0 :file->compression_level ;
41      }
42
43      CNc4DataOutput::~CNc4DataOutput(void)
44    { /* Ne rien faire de plus */ }
45
46      ///--------------------------------------------------------------
47
48      const StdString & CNc4DataOutput::getFileName(void) const
49      {
50         return (this->filename);
51      }
52
53      //---------------------------------------------------------------
54
55      void CNc4DataOutput::writeDomain_(CDomain* domain)
56      TRY
57      {
58        StdString lonName,latName ;
59
60        // Check that the name associated to the current element is not in conflict with an existing element (due to CGrid::duplicateSentGrid)
61        if (!domain->lonvalue.isEmpty() )
62        {
63          // The hash of the element will be associated to the default element name (= map key), and to the name really written
64          int globalHash = domain->computeAttributesHash( comm_file ); // Need a MPI_Comm to distribute without redundancy some attributs (value)
65       
66          StdString defaultNameKey = domain->getDomainOutputName();
67          if ( !relDomains_.count ( defaultNameKey ) )
68          {
69            // if defaultNameKey not in the map, write the element such as it is defined
70            relDomains_.insert( make_pair( defaultNameKey, make_pair(globalHash, domain) ) );
71          }
72          else // look if a hash associated this key is equal
73          {
74            bool elementIsInMap(false);
75            auto defaultNameKeyElements = relDomains_.equal_range( defaultNameKey );
76            for (auto it = defaultNameKeyElements.first; it != defaultNameKeyElements.second; it++)
77            {
78              if ( it->second.first == globalHash )
79              {
80                // if yes, associate the same ids to current element
81                domain->renameAttributesBeforeWriting( it->second.second );
82                elementIsInMap = true;
83              }
84            }
85            // if no : inheritance has been excessive, define new names and store it (could be used by another grid)
86            if (!elementIsInMap)  // ! in MAP
87            {
88              domain->renameAttributesBeforeWriting();
89              relDomains_.insert( make_pair( defaultNameKey, make_pair(globalHash, domain) ) ) ;         
90            }
91          }
92        }
93
94        if (domain->type == CDomain::type_attr::unstructured)
95        {
96          if (SuperClassWriter::useCFConvention)
97            writeUnstructuredDomain(domain) ;
98          else
99            writeUnstructuredDomainUgrid(domain) ;
100          return ;
101        }
102
103         CContext* context = CContext::getCurrent() ;
104         if (domain->IsWritten(this->filename)) return;
105         domain->checkAttributes();
106
107         if (domain->isEmpty())
108           if (SuperClass::type==MULTI_FILE) return;
109
110         
111         std::vector<StdString> dim0, dim1;
112         StdString domid = domain->getDomainOutputName();
113         StdString appendDomid  = (singleDomain) ? "" : "_"+domid ;
114         if (isWrittenDomain(domid)) return ;
115         else setWrittenDomain(domid);
116       
117         int nvertex = (domain->nvertex.isEmpty()) ? 0 : domain->nvertex;
118
119
120        StdString dimXid, dimYid ;
121
122        nc_type typePrec ;
123        if (domain->prec.isEmpty()) typePrec =  NC_FLOAT ;
124        else if (domain->prec==4)  typePrec =  NC_FLOAT ;
125        else if (domain->prec==8)   typePrec =  NC_DOUBLE ;
126         
127         bool isRegularDomain = (domain->type == CDomain::type_attr::rectilinear);
128         switch (domain->type)
129         {
130           case CDomain::type_attr::curvilinear :
131
132             if (domain->lon_name.isEmpty()) lonName = "nav_lon";
133             else lonName = domain->lon_name;
134
135             if (domain->lat_name.isEmpty()) latName = "nav_lat";
136             else latName = domain->lat_name;
137
138             if (domain->dim_i_name.isEmpty()) dimXid=StdString("x").append(appendDomid);
139             else dimXid=domain->dim_i_name.getValue() + appendDomid;
140
141             if (domain->dim_j_name.isEmpty()) dimYid=StdString("y").append(appendDomid);
142             else dimYid=domain->dim_j_name.getValue() + appendDomid;
143
144             break ;
145
146           case CDomain::type_attr::rectilinear :
147
148             if (domain->lon_name.isEmpty())
149             {
150               if (domain->dim_i_name.isEmpty())
151                   lonName = "lon";
152               else
153                 lonName = domain->dim_i_name.getValue();
154             }
155             else lonName = domain->lon_name;
156
157             if (domain->lat_name.isEmpty())
158             {
159               if (domain->dim_j_name.isEmpty())
160                 latName = "lat";
161               else
162                 latName = domain->dim_j_name.getValue();
163             }
164             else latName = domain->lat_name;
165             
166             if (domain->dim_i_name.isEmpty()) dimXid = lonName+appendDomid;
167             else dimXid = domain->dim_i_name.getValue()+appendDomid;
168
169             if (domain->dim_j_name.isEmpty()) dimYid = latName+appendDomid;
170             else dimYid = domain->dim_j_name.getValue()+appendDomid;
171             break;
172         }
173
174         StdString dimVertId = StdString("nvertex").append(appendDomid);
175
176         string lonid,latid,bounds_lonid,bounds_latid ;
177         string areaId = "area" + appendDomid;
178
179         try
180         {
181           switch (SuperClass::type)
182           {
183              case (MULTI_FILE) :
184              {
185                 switch (domain->type)
186                 {
187                   case CDomain::type_attr::curvilinear :
188                     dim0.push_back(dimYid); dim0.push_back(dimXid);
189                     lonid = lonName+appendDomid;
190                     latid = latName+appendDomid;
191                     break ;
192                   case CDomain::type_attr::rectilinear :
193                     lonid = lonName+appendDomid;
194                     latid = latName+appendDomid;
195                     dim0.push_back(dimYid);
196                     dim1.push_back(dimXid);
197                     break;
198                 }
199                 if (!domain->bounds_lon_name.isEmpty()) bounds_lonid = domain->bounds_lon_name;
200                 else bounds_lonid = "bounds_"+lonName+appendDomid;
201                 if (!domain->bounds_lat_name.isEmpty()) bounds_latid = domain->bounds_lat_name;
202                 else bounds_latid = "bounds_"+latName+appendDomid;
203
204                 SuperClassWriter::addDimension(dimXid, domain->niValue_);
205                 SuperClassWriter::addDimension(dimYid, domain->njValue_);
206
207                 if (domain->hasBounds)
208                   SuperClassWriter::addDimension(dimVertId, domain->nvertex);
209
210                 if (context->intraCommSize_ > 1)
211                 {
212                   this->writeLocalAttributes(domain->ibeginValue_,
213                                              domain->niValue_,
214                                              domain->jbeginValue_,
215                                              domain->njValue_,
216                                              appendDomid);
217
218                   if (singleDomain)
219                    this->writeLocalAttributes_IOIPSL(dimXid, dimYid,
220                                                      domain->ibeginValue_,
221                                                      domain->niValue_,
222                                                      domain->jbeginValue_,
223                                                      domain->njValue_,
224                                                      domain->ni_glo,domain->nj_glo,
225                                                      context->intraCommRank_,context->intraCommSize_);
226                 }
227
228                 if (domain->hasLonLat)
229                 {
230                   switch (domain->type)
231                   {
232                     case CDomain::type_attr::curvilinear :
233                       SuperClassWriter::addVariable(latid, typePrec, dim0, compressionLevel);
234                       SuperClassWriter::addVariable(lonid, typePrec, dim0, compressionLevel);
235                       break ;
236                      case CDomain::type_attr::rectilinear :
237                        SuperClassWriter::addVariable(latid, typePrec, dim0, compressionLevel);
238                        SuperClassWriter::addVariable(lonid, typePrec, dim1, compressionLevel);
239                        break ;
240                   }
241
242                   this->writeAxisAttributes(lonid, isRegularDomain ? "X" : "", "longitude", "Longitude", "degrees_east", domid);
243                   this->writeAxisAttributes(latid, isRegularDomain ? "Y" : "", "latitude", "Latitude", "degrees_north", domid);
244
245                   if (domain->hasBounds)
246                   {
247                     SuperClassWriter::addAttribute("bounds", bounds_lonid, &lonid);
248                     SuperClassWriter::addAttribute("bounds", bounds_latid, &latid);
249
250                     dim0.clear();
251                     dim0.push_back(dimYid);
252                     dim0.push_back(dimXid);
253                     dim0.push_back(dimVertId);
254                     SuperClassWriter::addVariable(bounds_lonid, typePrec, dim0, compressionLevel);
255                     SuperClassWriter::addVariable(bounds_latid, typePrec, dim0, compressionLevel);
256                   }
257                 }
258
259                 dim0.clear();
260                 dim0.push_back(dimYid);
261                 dim0.push_back(dimXid);
262
263                 if (domain->hasArea)
264                 {
265                   SuperClassWriter::addVariable(areaId, typePrec, dim0, compressionLevel);
266                   SuperClassWriter::addAttribute("standard_name", StdString("cell_area"), &areaId);
267                   SuperClassWriter::addAttribute("units", StdString("m2"), &areaId);
268                 }
269
270                 SuperClassWriter::definition_end();
271
272                 if (domain->hasLonLat)
273                 {
274                   switch (domain->type)
275                   {
276                     case CDomain::type_attr::curvilinear :                       
277                       SuperClassWriter::writeData(domain->latvalue, latid, isCollective, 0);
278                       SuperClassWriter::writeData(domain->lonvalue, lonid, isCollective, 0);
279                       break;
280                     case CDomain::type_attr::rectilinear :
281                       CArray<double,1> lat = domain->latvalue(Range(fromStart,toEnd,domain->ni)) ;
282                       SuperClassWriter::writeData(CArray<double,1>(lat.copy()), latid, isCollective, 0);
283                       CArray<double,1> lon = domain->lonvalue(Range(0,domain->ni-1)) ;
284                       SuperClassWriter::writeData(CArray<double,1>(lon.copy()), lonid, isCollective, 0);
285                       break;
286                   }
287
288                   if (domain->hasBounds)
289                   {
290                     SuperClassWriter::writeData(domain->bounds_lonvalue, bounds_lonid, isCollective, 0);
291                     SuperClassWriter::writeData(domain->bounds_latvalue, bounds_latid, isCollective, 0);
292                   }
293                 }
294
295                 if (domain->hasArea)
296                 {
297                   SuperClassWriter::writeData(domain->areavalue, areaId, isCollective, 0);                   
298                 }
299
300                 SuperClassWriter::definition_start();
301
302                 break;
303              }
304              case (ONE_FILE) :
305              {
306                SuperClassWriter::addDimension(dimXid, domain->ni_glo);
307                SuperClassWriter::addDimension(dimYid, domain->nj_glo);
308
309                 if (domain->hasBounds)
310                   SuperClassWriter::addDimension(dimVertId, domain->nvertex);
311
312                 if (domain->hasLonLat)
313                 {
314                   switch (domain->type)
315                   {
316                     case CDomain::type_attr::curvilinear :
317                       dim0.push_back(dimYid); dim0.push_back(dimXid);
318                       lonid = lonName+appendDomid;
319                       latid = latName+appendDomid;
320                       SuperClassWriter::addVariable(latid, typePrec, dim0, compressionLevel);
321                       SuperClassWriter::addVariable(lonid, typePrec, dim0, compressionLevel);
322                       break;
323
324                     case CDomain::type_attr::rectilinear :
325                       dim0.push_back(dimYid);
326                       dim1.push_back(dimXid);
327                       lonid = lonName+appendDomid;
328                       latid = latName+appendDomid;
329                       SuperClassWriter::addVariable(latid, typePrec, dim0, compressionLevel);
330                       SuperClassWriter::addVariable(lonid, typePrec, dim1, compressionLevel);
331                       break;
332                   }
333                   if (!domain->bounds_lon_name.isEmpty()) bounds_lonid = domain->bounds_lon_name;
334                   else bounds_lonid = "bounds_"+lonName+appendDomid;
335                   if (!domain->bounds_lat_name.isEmpty()) bounds_latid = domain->bounds_lat_name;
336                   else bounds_latid = "bounds_"+latName+appendDomid;
337
338                   this->writeAxisAttributes
339                      (lonid, isRegularDomain ? "X" : "", "longitude", "Longitude", "degrees_east", domid);
340                   this->writeAxisAttributes
341                      (latid, isRegularDomain ? "Y" : "", "latitude", "Latitude", "degrees_north", domid);
342
343                   if (domain->hasBounds)
344                   {
345                     SuperClassWriter::addAttribute("bounds", bounds_lonid, &lonid);
346                     SuperClassWriter::addAttribute("bounds", bounds_latid, &latid);
347
348                     dim0.clear();
349                     dim0.push_back(dimYid);
350                     dim0.push_back(dimXid);
351                     dim0.push_back(dimVertId);
352                     SuperClassWriter::addVariable(bounds_lonid, typePrec, dim0, compressionLevel);
353                     SuperClassWriter::addVariable(bounds_latid, typePrec, dim0, compressionLevel);
354                   }
355                 }
356
357                 if (domain->hasArea)
358                 {
359                   dim0.clear();
360                   dim0.push_back(dimYid); dim0.push_back(dimXid);
361                   SuperClassWriter::addVariable(areaId, typePrec, dim0, compressionLevel);
362                   SuperClassWriter::addAttribute("standard_name", StdString("cell_area"), &areaId);
363                   SuperClassWriter::addAttribute("units", StdString("m2"), &areaId);
364                   dim0.clear();
365                 }
366
367                 SuperClassWriter::definition_end();
368
369                 switch (domain->type)
370                 {
371                   case CDomain::type_attr::curvilinear :
372                   {
373                     std::vector<StdSize> start(2) ;
374                     std::vector<StdSize> count(2) ;
375                     start[1]=domain->ibeginValue_;
376                     start[0]=domain->jbeginValue_;
377                     count[1]=domain->niValue_ ; count[0]=domain->njValue_ ;
378
379                     if (domain->hasLonLat)
380                     {
381                       SuperClassWriter::writeData(domain->latvalue, latid, isCollective, 0,&start,&count);
382                       SuperClassWriter::writeData(domain->lonvalue, lonid, isCollective, 0,&start,&count);
383                     }
384                     break;
385                   }
386                   case CDomain::type_attr::rectilinear :
387                   {
388                     if (domain->hasLonLat)
389                     {
390                       std::vector<StdSize> start(1) ;
391                       std::vector<StdSize> count(1) ;
392                       
393                       start[0]=domain->jbeginValue_;
394                       count[0]=domain->njValue_;
395                       CArray<double,1> lat;
396                       lat.resize( domain->njValue_);
397                       for (int j=0;j<domain->njValue_;j++) lat(j) = domain->latvalue(j*domain->niValue_);
398                       SuperClassWriter::writeData(CArray<double,1>(lat.copy()), latid, isCollective, 0,&start,&count);
399
400                       start[0]=domain->ibeginValue_;
401                       count[0]=domain->niValue_;
402                       CArray<double,1> lon = domain->lonvalue(Range(0,domain->niValue_-1));
403                       SuperClassWriter::writeData(CArray<double,1>(lon.copy()), lonid, isCollective, 0,&start,&count);
404                     }
405                     break;
406                   }
407                 }
408
409                 if (domain->hasBounds)
410                 {
411                   std::vector<StdSize> start(3);
412                   std::vector<StdSize> count(3);
413                   if (domain->isEmpty())
414                   {
415                     start[2] = start[1] = start[0] = 0;
416                     count[2] = count[1] = count[0] = 0;
417                   }
418                   else
419                   {
420                     start[2] = 0;
421                     start[1] = domain->ibeginValue_;
422                     start[0] = domain->jbeginValue_;
423                     count[2] = domain->nvertex;
424                     count[1] = domain->niValue_;
425                     count[0] = domain->njValue_;
426                   }
427                 
428                   SuperClassWriter::writeData(domain->bounds_lonvalue, bounds_lonid, isCollective, 0, &start, &count); // will probably not working for rectilinear
429                   SuperClassWriter::writeData(domain->bounds_latvalue, bounds_latid, isCollective, 0, &start, &count);
430                 }
431
432                 if (domain->hasArea)
433                 {
434                   std::vector<StdSize> start(2);
435                   std::vector<StdSize> count(2);
436
437                   start[1] = domain->ibeginValue_;
438                   start[0] = domain->jbeginValue_;
439                   count[1] = domain->niValue_;
440                   count[0] = domain->njValue_;
441                   
442                   SuperClassWriter::writeData(domain->areavalue, areaId, isCollective, 0, &start, &count);
443                 }
444
445                 SuperClassWriter::definition_start();
446                 break;
447              }
448              default :
449                 ERROR("CNc4DataOutput::writeDomain(domain)",
450                       << "[ type = " << SuperClass::type << "]"
451                       << " not implemented yet !");
452           }
453         }
454         catch (CNetCdfException& e)
455         {
456           StdString msg("On writing the domain : ");
457           msg.append(domid); msg.append("\n");
458           msg.append("In the context : ");
459           msg.append(context->getId()); msg.append("\n");
460           msg.append(e.what());
461           ERROR("CNc4DataOutput::writeDomain_(CDomain* domain)", << msg);
462         }
463
464         domain->addRelFile(this->filename);
465      }
466      CATCH
467
468    //--------------------------------------------------------------
469
470    void CNc4DataOutput::writeUnstructuredDomainUgrid(CDomain* domain)
471    {
472      CContext* context = CContext::getCurrent() ;
473
474      if (domain->IsWritten(this->filename)) return;
475
476      StdString domid = domain->getDomainOutputName();
477
478      // The first domain for the same mesh that will be written is that with the highest value of nvertex.
479      // Thus the entire mesh connectivity will be generated at once.
480      if (isWrittenDomain(domid)) return ;
481      else setWrittenDomain(domid);
482
483      domain->checkAttributes();
484      if (domain->isEmpty())
485        if (SuperClass::type==MULTI_FILE) return ;
486
487     nc_type typePrec ;
488     if (domain->prec.isEmpty()) typePrec =  NC_FLOAT ;
489     else if (domain->prec==4)  typePrec =  NC_FLOAT ;
490     else if (domain->prec==8)   typePrec =  NC_DOUBLE ;
491
492      std::vector<StdString> dim0;
493      StdString domainName = domain->name;
494
495      StdString node_x = domainName + "_node_x";
496      StdString node_y = domainName + "_node_y";
497
498      StdString edge_x = domainName + "_edge_x";
499      StdString edge_y = domainName + "_edge_y";
500      StdString edge_nodes = domainName + "_edge_nodes";
501
502      StdString face_x = domainName + "_face_x";
503      StdString face_y = domainName + "_face_y";
504      StdString face_nodes = domainName + "_face_nodes";
505      StdString face_edges = domainName + "_face_edges";
506      StdString edge_faces = domainName + "_edge_face_links";
507      StdString face_faces = domainName + "_face_links";
508
509      StdString dimNode = "n" + domainName + "_node";
510      StdString dimEdge = "n" + domainName + "_edge";
511      StdString dimFace = "n" + domainName + "_face";
512      StdString dimVertex = "n" + domainName + "_vertex";
513      StdString dimTwo = "Two";
514
515      if (!SuperClassWriter::dimExist(dimTwo)) SuperClassWriter::addDimension(dimTwo, 2);
516      dim0.clear();
517      SuperClassWriter::addVariable(domainName, NC_INT, dim0, compressionLevel);
518      SuperClassWriter::addAttribute("cf_role", StdString("mesh_topology"), &domainName);
519      SuperClassWriter::addAttribute("long_name", StdString("Topology data of 2D unstructured mesh"), &domainName);
520      SuperClassWriter::addAttribute("topology_dimension", 2, &domainName);
521      SuperClassWriter::addAttribute("node_coordinates", node_x + " " + node_y, &domainName);
522
523      try
524      {
525        switch (SuperClass::type)
526        {
527          case (ONE_FILE) :
528          {
529            // Adding nodes
530            if (domain->nvertex == 1)
531            {
532              if (!SuperClassWriter::varExist(node_x) || !SuperClassWriter::varExist(node_y))
533              {
534                SuperClassWriter::addDimension(dimNode, domain->ni_glo);
535                dim0.clear();
536                dim0.push_back(dimNode);
537                SuperClassWriter::addVariable(node_x, typePrec, dim0, compressionLevel);
538                SuperClassWriter::addAttribute("standard_name", StdString("longitude"), &node_x);
539                SuperClassWriter::addAttribute("long_name", StdString("Longitude of mesh nodes."), &node_x);
540                SuperClassWriter::addAttribute("units", StdString("degrees_east"), &node_x);
541                SuperClassWriter::addVariable(node_y, typePrec, dim0, compressionLevel);
542                SuperClassWriter::addAttribute("standard_name", StdString("latitude"), &node_y);
543                SuperClassWriter::addAttribute("long_name", StdString("Latitude of mesh nodes."), &node_y);
544                SuperClassWriter::addAttribute("units", StdString("degrees_north"), &node_y);
545              }
546            } // domain->nvertex == 1
547
548            // Adding edges and nodes, if nodes have not been defined previously
549            if (domain->nvertex == 2)
550            {
551              if (!SuperClassWriter::varExist(node_x) || !SuperClassWriter::varExist(node_y))
552              {
553                SuperClassWriter::addDimension(dimNode, domain->mesh->nbNodesGlo);
554                dim0.clear();
555                dim0.push_back(dimNode);
556                SuperClassWriter::addVariable(node_x, typePrec, dim0, compressionLevel);
557                SuperClassWriter::addAttribute("standard_name", StdString("longitude"), &node_x);
558                SuperClassWriter::addAttribute("long_name", StdString("Longitude of mesh nodes."), &node_x);
559                SuperClassWriter::addAttribute("units", StdString("degrees_east"), &node_x);
560                SuperClassWriter::addVariable(node_y, typePrec, dim0, compressionLevel);
561                SuperClassWriter::addAttribute("standard_name", StdString("latitude"), &node_y);
562                SuperClassWriter::addAttribute("long_name", StdString("Latitude of mesh nodes."), &node_y);
563                SuperClassWriter::addAttribute("units", StdString("degrees_north"), &node_y);
564              }
565              SuperClassWriter::addAttribute("edge_node_connectivity", edge_nodes, &domainName);
566              SuperClassWriter::addAttribute("edge_coordinates", edge_x + " " + edge_y, &domainName);
567              SuperClassWriter::addDimension(dimEdge, domain->ni_glo);
568              dim0.clear();
569              dim0.push_back(dimEdge);
570              SuperClassWriter::addVariable(edge_x, typePrec, dim0, compressionLevel);
571              SuperClassWriter::addAttribute("standard_name", StdString("longitude"), &edge_x);
572              SuperClassWriter::addAttribute("long_name", StdString("Characteristic longitude of mesh edges."), &edge_x);
573              SuperClassWriter::addAttribute("units", StdString("degrees_east"), &edge_x);
574              SuperClassWriter::addVariable(edge_y, typePrec, dim0, compressionLevel);
575              SuperClassWriter::addAttribute("standard_name", StdString("latitude"), &edge_y);
576              SuperClassWriter::addAttribute("long_name", StdString("Characteristic latitude of mesh edges."), &edge_y);
577              SuperClassWriter::addAttribute("units", StdString("degrees_north"), &edge_y);
578              dim0.clear();
579              dim0.push_back(dimEdge);
580              dim0.push_back(dimTwo);
581              SuperClassWriter::addVariable(edge_nodes, NC_INT, dim0, compressionLevel);
582              SuperClassWriter::addAttribute("cf_role", StdString("edge_node_connectivity"), &edge_nodes);
583              SuperClassWriter::addAttribute("long_name", StdString("Maps every edge/link to two nodes that it connects."), &edge_nodes);
584              SuperClassWriter::addAttribute("start_index", 0, &edge_nodes);
585            } // domain->nvertex == 2
586
587            // Adding faces, edges, and nodes, if edges and nodes have not been defined previously
588            if (domain->nvertex > 2)
589            {
590              // Nodes
591              if (!SuperClassWriter::varExist(node_x) || !SuperClassWriter::varExist(node_y))
592              {
593                SuperClassWriter::addDimension(dimNode, domain->mesh->nbNodesGlo);
594                dim0.clear();
595                dim0.push_back(dimNode);
596                SuperClassWriter::addVariable(node_x, typePrec, dim0, compressionLevel);
597                SuperClassWriter::addAttribute("standard_name", StdString("longitude"), &node_x);
598                SuperClassWriter::addAttribute("long_name", StdString("Longitude of mesh nodes."), &node_x);
599                SuperClassWriter::addAttribute("units", StdString("degrees_east"), &node_x);
600                SuperClassWriter::addVariable(node_y, typePrec, dim0, compressionLevel);
601                SuperClassWriter::addAttribute("standard_name", StdString("latitude"), &node_y);
602                SuperClassWriter::addAttribute("long_name", StdString("Latitude of mesh nodes."), &node_y);
603                SuperClassWriter::addAttribute("units", StdString("degrees_north"), &node_y);
604              }
605              if (!SuperClassWriter::varExist(edge_x) || !SuperClassWriter::varExist(edge_y))
606              {
607                SuperClassWriter::addAttribute("edge_coordinates", edge_x + " " + edge_y, &domainName);
608                SuperClassWriter::addAttribute("edge_node_connectivity", edge_nodes, &domainName);
609                SuperClassWriter::addAttribute("face_edge_connectivity", face_edges, &domainName);
610                SuperClassWriter::addAttribute("edge_face_connectivity", edge_faces, &domainName);
611                SuperClassWriter::addDimension(dimEdge, domain->mesh->nbEdgesGlo);
612                dim0.clear();
613                dim0.push_back(dimEdge);
614                SuperClassWriter::addVariable(edge_x, typePrec, dim0, compressionLevel);
615                SuperClassWriter::addAttribute("standard_name", StdString("longitude"), &edge_x);
616                SuperClassWriter::addAttribute("long_name", StdString("Characteristic longitude of mesh edges."), &edge_x);
617                SuperClassWriter::addAttribute("units", StdString("degrees_east"), &edge_x);
618                SuperClassWriter::addVariable(edge_y, typePrec, dim0, compressionLevel);
619                SuperClassWriter::addAttribute("standard_name", StdString("latitude"), &edge_y);
620                SuperClassWriter::addAttribute("long_name", StdString("Characteristic latitude of mesh edges."), &edge_y);
621                SuperClassWriter::addAttribute("units", StdString("degrees_north"), &edge_y);
622                dim0.clear();
623                dim0.push_back(dimEdge);
624                dim0.push_back(dimTwo);
625                SuperClassWriter::addVariable(edge_nodes, NC_INT, dim0, compressionLevel);
626                SuperClassWriter::addAttribute("cf_role", StdString("edge_node_connectivity"), &edge_nodes);
627                SuperClassWriter::addAttribute("long_name", StdString("Maps every edge/link to two nodes that it connects."), &edge_nodes);
628                SuperClassWriter::addAttribute("start_index", 0, &edge_nodes);
629              }
630              SuperClassWriter::addAttribute("face_face_connectivity", face_faces, &domainName);
631              SuperClassWriter::addAttribute("face_coordinates", face_x + " " + face_y, &domainName);
632              SuperClassWriter::addAttribute("face_node_connectivity", face_nodes, &domainName);
633              SuperClassWriter::addDimension(dimFace, domain->ni_glo);
634              SuperClassWriter::addDimension(dimVertex, domain->nvertex);
635              dim0.clear();
636              dim0.push_back(dimFace);
637              SuperClassWriter::addVariable(face_x, typePrec, dim0, compressionLevel);
638              SuperClassWriter::addAttribute("standard_name", StdString("longitude"), &face_x);
639              SuperClassWriter::addAttribute("long_name", StdString("Characteristic longitude of mesh faces."), &face_x);
640              SuperClassWriter::addAttribute("units", StdString("degrees_east"), &face_x);
641              SuperClassWriter::addVariable(face_y, typePrec, dim0, compressionLevel);
642              SuperClassWriter::addAttribute("standard_name", StdString("latitude"), &face_y);
643              SuperClassWriter::addAttribute("long_name", StdString("Characteristic latitude of mesh faces."), &face_y);
644              SuperClassWriter::addAttribute("units", StdString("degrees_north"), &face_y);
645              dim0.clear();
646              dim0.push_back(dimFace);
647              dim0.push_back(dimVertex);
648              SuperClassWriter::addVariable(face_nodes, NC_INT, dim0, compressionLevel);
649              SuperClassWriter::addAttribute("cf_role", StdString("face_node_connectivity"), &face_nodes);
650              SuperClassWriter::addAttribute("long_name", StdString("Maps every face to its corner nodes."), &face_nodes);
651              SuperClassWriter::addAttribute("start_index", 0, &face_nodes);
652              dim0.clear();
653              dim0.push_back(dimFace);
654              dim0.push_back(dimVertex);
655              SuperClassWriter::addVariable(face_edges, NC_INT, dim0, compressionLevel);
656              SuperClassWriter::addAttribute("cf_role", StdString("face_edge_connectivity"), &face_edges);
657              SuperClassWriter::addAttribute("long_name", StdString("Maps every face to its edges."), &face_edges);
658              SuperClassWriter::addAttribute("start_index", 0, &face_edges);
659              SuperClassWriter::addAttribute("_FillValue", 999999, &face_edges);
660              dim0.clear();
661              dim0.push_back(dimEdge);
662              dim0.push_back(dimTwo);
663              SuperClassWriter::addVariable(edge_faces, NC_INT, dim0, compressionLevel);
664              SuperClassWriter::addAttribute("cf_role", StdString("edge_face_connectivity"), &edge_faces);
665              SuperClassWriter::addAttribute("long_name", StdString("neighbor faces for edges"), &edge_faces);
666              SuperClassWriter::addAttribute("start_index", 0, &edge_faces);
667              SuperClassWriter::addAttribute("_FillValue", -999, &edge_faces);
668              SuperClassWriter::addAttribute("comment", StdString("missing neighbor faces are indicated using _FillValue"), &edge_faces);
669              dim0.clear();
670              dim0.push_back(dimFace);
671              dim0.push_back(dimVertex);
672              SuperClassWriter::addVariable(face_faces, NC_INT, dim0, compressionLevel);
673              SuperClassWriter::addAttribute("cf_role", StdString("face_face_connectivity"), &face_faces);
674              SuperClassWriter::addAttribute("long_name", StdString("Indicates which other faces neighbor each face"), &face_faces);
675              SuperClassWriter::addAttribute("start_index", 0, &face_faces);
676              SuperClassWriter::addAttribute("_FillValue", 999999, &face_faces);
677              SuperClassWriter::addAttribute("flag_values", -1, &face_faces);
678              SuperClassWriter::addAttribute("flag_meanings", StdString("out_of_mesh"), &face_faces);
679            } // domain->nvertex > 2
680
681            SuperClassWriter::definition_end();
682
683            std::vector<StdSize> startEdges(1) ;
684            std::vector<StdSize> countEdges(1) ;
685            std::vector<StdSize> startNodes(1) ;
686            std::vector<StdSize> countNodes(1) ;
687            std::vector<StdSize> startFaces(1) ;
688            std::vector<StdSize> countFaces(1) ;
689            std::vector<StdSize> startEdgeNodes(2) ;
690            std::vector<StdSize> countEdgeNodes(2) ;
691            std::vector<StdSize> startEdgeFaces(2) ;
692            std::vector<StdSize> countEdgeFaces(2) ;
693            std::vector<StdSize> startFaceConctv(2) ;
694            std::vector<StdSize> countFaceConctv(2) ;
695
696            if (domain->nvertex == 1)
697            {
698              if (domain->isEmpty())
699               {
700                 startNodes[0]=0 ;
701                 countNodes[0]=0 ;
702               }
703               else
704               {
705                 startNodes[0] = domain->ibeginValue_;
706                 countNodes[0] = domain->niValue_ ;
707               }
708
709              SuperClassWriter::writeData(domain->mesh->node_lat, node_y, isCollective, 0, &startNodes, &countNodes);
710              SuperClassWriter::writeData(domain->mesh->node_lon, node_x, isCollective, 0, &startNodes, &countNodes);
711            }
712            else if (domain->nvertex == 2)
713            {
714              if (domain->isEmpty())
715               {
716                startEdges[0]=0 ;
717                countEdges[0]=0 ;
718                startNodes[0]=0 ;
719                countNodes[0]=0 ;
720                startEdgeNodes[0]=0;
721                startEdgeNodes[1]=0;
722                countEdgeNodes[0]=0;
723                countEdgeNodes[1]=0;
724
725               }
726               else
727               {
728                 startEdges[0] = domain->ibeginValue_;
729                 countEdges[0] = domain->niValue_;
730                 startNodes[0] = domain->mesh->node_start;
731                 countNodes[0] = domain->mesh->node_count;
732                 if (countNodes[0]==0) startNodes[0]=0 ; // for netcdf error
733                 startEdgeNodes[0] = domain->ibeginValue_;
734                 startEdgeNodes[1] = 0;
735                 countEdgeNodes[0] = domain->niValue_;
736                 countEdgeNodes[1] = 2;
737               }
738              SuperClassWriter::writeData(domain->mesh->node_lat, node_y, isCollective, 0, &startNodes, &countNodes);
739              SuperClassWriter::writeData(domain->mesh->node_lon, node_x, isCollective, 0, &startNodes, &countNodes);
740              SuperClassWriter::writeData(domain->mesh->edge_lat, edge_y, isCollective, 0, &startEdges, &countEdges);
741              SuperClassWriter::writeData(domain->mesh->edge_lon, edge_x, isCollective, 0, &startEdges, &countEdges);
742              SuperClassWriter::writeData(domain->mesh->edge_nodes, edge_nodes, isCollective, 0, &startEdgeNodes, &countEdgeNodes);
743            }
744            else
745            {
746              if (domain->isEmpty())
747               {
748                 startFaces[0] = 0 ;
749                 countFaces[0] = 0 ;
750                 startNodes[0] = 0;
751                 countNodes[0] = 0;
752                 startEdges[0] = 0;
753                 countEdges[0] = 0;
754                 startEdgeFaces[0] = 0;
755                 startEdgeFaces[1] = 0;
756                 countEdgeFaces[0] = 0;
757                 countEdgeFaces[1] = 0;
758                 startFaceConctv[0] = 0;
759                 startFaceConctv[1] = 0;
760                 countFaceConctv[0] = 0;
761                 countFaceConctv[1] = 0;
762               }
763               else
764               {
765                 startFaces[0] = domain->ibeginValue_;
766                 countFaces[0] = domain->niValue_ ;
767                 startNodes[0] = domain->mesh->node_start;
768                 countNodes[0] = domain->mesh->node_count;
769                 if (countNodes[0]==0) startNodes[0]=0;
770
771                 startEdges[0] = domain->mesh->edge_start;
772                 countEdges[0] = domain->mesh->edge_count;
773                 if (countEdges[0]==0) startEdges[0]=0 ; // for netcdf error
774
775                 startEdgeNodes[0] = domain->mesh->edge_start;
776                 countEdgeNodes[0] = domain->mesh->edge_count;
777                 if (countEdgeNodes[0]==0) startEdgeNodes[0]=0; // for netcdf error
778                 startEdgeNodes[1] = 0;
779                 countEdgeNodes[1]= 2;
780                 
781                 startEdgeFaces[0] = domain->mesh->edge_start;
782                 countEdgeFaces[0] = domain->mesh->edge_count;
783                 if (countEdgeFaces[0]==0) startEdgeFaces[0]=0 ; // for netcdf error
784                 startEdgeFaces[1]= 0;
785                 countEdgeFaces[1]= 2;
786                 
787                 startFaceConctv[0] = domain->ibeginValue_;
788                 countFaceConctv[0] = domain->niValue_;
789                 startFaceConctv[1] = 0;
790                 countFaceConctv[1] = domain->nvertex;
791               }
792              SuperClassWriter::writeData(domain->mesh->node_lat, node_y, isCollective, 0, &startNodes, &countNodes);
793              SuperClassWriter::writeData(domain->mesh->node_lon, node_x, isCollective, 0, &startNodes, &countNodes);
794              SuperClassWriter::writeData(domain->mesh->edge_lat, edge_y, isCollective, 0, &startEdges, &countEdges);
795              SuperClassWriter::writeData(domain->mesh->edge_lon, edge_x, isCollective, 0, &startEdges, &countEdges);
796              SuperClassWriter::writeData(domain->mesh->edge_nodes, edge_nodes, isCollective, 0, &startEdgeNodes, &countEdgeNodes);
797              SuperClassWriter::writeData(domain->mesh->face_lat, face_y, isCollective, 0, &startFaces, &countFaces);
798              SuperClassWriter::writeData(domain->mesh->face_lon, face_x, isCollective, 0, &startFaces, &countFaces);
799              SuperClassWriter::writeData(domain->mesh->face_nodes, face_nodes, isCollective, 0, &startFaceConctv, &countFaceConctv);
800              SuperClassWriter::writeData(domain->mesh->face_edges, face_edges, isCollective, 0, &startFaceConctv, &countFaceConctv);
801              SuperClassWriter::writeData(domain->mesh->edge_faces, edge_faces, isCollective, 0, &startEdgeFaces, &countEdgeFaces);
802              SuperClassWriter::writeData(domain->mesh->face_faces, face_faces, isCollective, 0, &startFaceConctv, &countFaceConctv);
803            }
804            SuperClassWriter::definition_start();
805
806            break;
807          } // ONE_FILE
808
809          case (MULTI_FILE) :
810          {
811            ERROR("CNc4DataOutput::writeDomain(domain)",
812            << "[ type = multiple_file ]"
813            << " is not yet implemented for UGRID files !");
814            break;
815          }
816
817          default :
818          ERROR("CNc4DataOutput::writeDomain(domain)",
819          << "[ type = " << SuperClass::type << "]"
820          << " not implemented yet !");
821          } // switch
822        } // try
823
824        catch (CNetCdfException& e)
825        {
826          StdString msg("On writing the domain : ");
827          msg.append(domid); msg.append("\n");
828          msg.append("In the context : ");
829          msg.append(context->getId()); msg.append("\n");
830          msg.append(e.what());
831          ERROR("CNc4DataOutput::writeUnstructuredDomainUgrid(CDomain* domain)", << msg);
832        }
833
834  domain->addRelFile(this->filename);
835  }
836
837    //--------------------------------------------------------------
838
839    void CNc4DataOutput::writeUnstructuredDomain(CDomain* domain)
840      {
841         CContext* context = CContext::getCurrent() ;
842
843         if (domain->IsWritten(this->filename)) return;
844         domain->checkAttributes();
845
846         if (domain->isEmpty())
847           if (SuperClass::type==MULTI_FILE) return ;
848
849         std::vector<StdString> dim0, dim1;
850         StdString domid = domain->getDomainOutputName();
851         if (isWrittenDomain(domid)) return ;
852         else setWrittenDomain(domid);
853
854         StdString appendDomid  = (singleDomain) ? "" : "_"+domid ;
855
856         StdString lonName,latName, cellName ;
857         if (domain->lon_name.isEmpty()) lonName = "lon";
858         else lonName = domain->lon_name;
859
860         if (domain->lat_name.isEmpty()) latName = "lat";
861         else latName = domain->lat_name;
862
863         if (!domain->dim_i_name.isEmpty()) cellName=domain->dim_i_name;
864         else cellName="cell";
865         StdString dimXid = cellName+appendDomid;
866         StdString dimVertId;
867         if (domain->nvertex_name.isEmpty()) dimVertId = "nvertex";
868         else dimVertId = domain->nvertex_name;
869
870         string lonid,latid,bounds_lonid,bounds_latid ;
871         string areaId = "area" + appendDomid;
872
873         nc_type typePrec ;
874         if (domain->prec.isEmpty()) typePrec =  NC_FLOAT ;
875         else if (domain->prec==4)  typePrec =  NC_FLOAT ;
876         else if (domain->prec==8)   typePrec =  NC_DOUBLE ;
877
878         int nvertex = (domain->nvertex.isEmpty()) ? 0 : domain->nvertex;
879
880         try
881         {
882           switch (SuperClass::type)
883           {
884              case (MULTI_FILE) :
885              {
886                 dim0.push_back(dimXid);
887                 SuperClassWriter::addDimension(dimXid, domain->ni);
888
889                 lonid = lonName+appendDomid;
890                 latid = latName+appendDomid;
891                 if (!domain->bounds_lon_name.isEmpty()) bounds_lonid = domain->bounds_lon_name;
892                 else bounds_lonid = "bounds_"+lonName+appendDomid;
893                 if (!domain->bounds_lat_name.isEmpty()) bounds_latid = domain->bounds_lat_name;
894                 else bounds_latid = "bounds_"+latName+appendDomid;
895
896                 if (domain->hasLonLat)
897                 {
898                   SuperClassWriter::addVariable(latid, typePrec, dim0, compressionLevel);
899                   SuperClassWriter::addVariable(lonid, typePrec, dim0, compressionLevel);
900                   this->writeAxisAttributes(lonid, "", "longitude", "Longitude", "degrees_east", domid);
901                   if (domain->hasBounds) SuperClassWriter::addAttribute("bounds",bounds_lonid, &lonid);
902                   this->writeAxisAttributes(latid, "", "latitude", "Latitude", "degrees_north", domid);
903                   if (domain->hasBounds) SuperClassWriter::addAttribute("bounds",bounds_latid, &latid);
904                   if (domain->hasBounds) SuperClassWriter::addDimension(dimVertId, domain->nvertex);
905                 }
906                 dim0.clear();
907                 if (domain->hasBounds)
908                 {
909                   dim0.push_back(dimXid);
910                   dim0.push_back(dimVertId);
911                   SuperClassWriter::addVariable(bounds_lonid, typePrec, dim0, compressionLevel);
912                   SuperClassWriter::addVariable(bounds_latid, typePrec, dim0, compressionLevel);
913                 }
914
915                 dim0.clear();
916                 dim0.push_back(dimXid);
917                 if (domain->hasArea)
918                 {
919                   SuperClassWriter::addVariable(areaId, typePrec, dim0, compressionLevel);
920                   SuperClassWriter::addAttribute("standard_name", StdString("cell_area"), &areaId);
921                   SuperClassWriter::addAttribute("units", StdString("m2"), &areaId);
922                 }
923
924                 SuperClassWriter::definition_end();
925
926                 if (domain->hasLonLat)
927                 {
928                   SuperClassWriter::writeData(domain->latvalue, latid, isCollective, 0);
929                   SuperClassWriter::writeData(domain->lonvalue, lonid, isCollective, 0);
930                   if (domain->hasBounds)
931                   {
932                     SuperClassWriter::writeData(domain->bounds_lonvalue, bounds_lonid, isCollective, 0);
933                     SuperClassWriter::writeData(domain->bounds_latvalue, bounds_latid, isCollective, 0);
934                   }
935                 }
936
937                 if (domain->hasArea)
938                   SuperClassWriter::writeData(domain->areavalue, areaId, isCollective, 0);
939
940                 SuperClassWriter::definition_start();
941                 break ;
942              }
943
944              case (ONE_FILE) :
945              {
946                 lonid = lonName+appendDomid;
947                 latid = latName+appendDomid;
948                 if (!domain->bounds_lon_name.isEmpty()) bounds_lonid = domain->bounds_lon_name;
949                 else bounds_lonid = "bounds_"+lonName+appendDomid;
950                 if (!domain->bounds_lat_name.isEmpty()) bounds_latid = domain->bounds_lat_name;
951                 else bounds_latid = "bounds_"+latName+appendDomid;
952
953                 dim0.push_back(dimXid);
954                 SuperClassWriter::addDimension(dimXid, domain->ni_glo);
955                 if (domain->hasLonLat)
956                 {
957                   SuperClassWriter::addVariable(latid, typePrec, dim0, compressionLevel);
958                   SuperClassWriter::addVariable(lonid, typePrec, dim0, compressionLevel);
959
960                   this->writeAxisAttributes(lonid, "", "longitude", "Longitude", "degrees_east", domid);
961                   if (domain->hasBounds) SuperClassWriter::addAttribute("bounds",bounds_lonid, &lonid);
962                   this->writeAxisAttributes(latid, "", "latitude", "Latitude", "degrees_north", domid);
963                   if (domain->hasBounds) SuperClassWriter::addAttribute("bounds",bounds_latid, &latid);
964                   if (domain->hasBounds) SuperClassWriter::addDimension(dimVertId, nvertex);
965                 }
966                 dim0.clear();
967
968                 if (domain->hasBounds)
969                 {
970                   dim0.push_back(dimXid);
971                   dim0.push_back(dimVertId);
972                   SuperClassWriter::addVariable(bounds_lonid, typePrec, dim0, compressionLevel);
973                   SuperClassWriter::addVariable(bounds_latid, typePrec, dim0, compressionLevel);
974                 }
975
976                 if (domain->hasArea)
977                 {
978                   dim0.clear();
979                   dim0.push_back(dimXid);
980                   SuperClassWriter::addVariable(areaId, typePrec, dim0, compressionLevel);
981                   SuperClassWriter::addAttribute("standard_name", StdString("cell_area"), &areaId);
982                   SuperClassWriter::addAttribute("units", StdString("m2"), &areaId);
983                 }
984
985                 SuperClassWriter::definition_end();
986
987                 std::vector<StdSize> start(1), startBounds(2) ;
988                 std::vector<StdSize> count(1), countBounds(2) ;
989                 if (domain->isEmpty())
990                 {
991                   start[0]=0 ;
992                   count[0]=0 ;
993                   startBounds[1]=0 ;
994                   countBounds[1]=nvertex ;
995                   startBounds[0]=0 ;
996                   countBounds[0]=0 ;
997                 }
998                 else
999                 {
1000                   start[0]=domain->ibeginValue_;
1001                   count[0]=domain->niValue_;
1002                   startBounds[0]=domain->ibeginValue_;
1003                   startBounds[1]=0 ;
1004                   countBounds[0]=domain->niValue_;
1005                   countBounds[1]=nvertex ;
1006                 }
1007
1008                 if (domain->hasLonLat)
1009                 {
1010                   SuperClassWriter::writeData(domain->latvalue, latid, isCollective, 0,&start,&count);
1011                   SuperClassWriter::writeData(domain->lonvalue, lonid, isCollective, 0,&start,&count);
1012                   if (domain->hasBounds)
1013                   {
1014                     SuperClassWriter::writeData(domain->bounds_lonvalue, bounds_lonid, isCollective, 0,&startBounds,&countBounds);
1015                     SuperClassWriter::writeData(domain->bounds_latvalue, bounds_latid, isCollective, 0,&startBounds,&countBounds);
1016                   }
1017                 }
1018
1019                 if (domain->hasArea)
1020                   SuperClassWriter::writeData(domain->areavalue, areaId, isCollective, 0, &start, &count);
1021
1022                 SuperClassWriter::definition_start();
1023
1024                 break;
1025              }
1026              default :
1027                 ERROR("CNc4DataOutput::writeDomain(domain)",
1028                       << "[ type = " << SuperClass::type << "]"
1029                       << " not implemented yet !");
1030           }
1031         }
1032         catch (CNetCdfException& e)
1033         {
1034           StdString msg("On writing the domain : ");
1035           msg.append(domid); msg.append("\n");
1036           msg.append("In the context : ");
1037           msg.append(context->getId()); msg.append("\n");
1038           msg.append(e.what());
1039           ERROR("CNc4DataOutput::writeUnstructuredDomain(CDomain* domain)", << msg);
1040         }
1041         domain->addRelFile(this->filename);
1042      }
1043      //--------------------------------------------------------------
1044
1045      void CNc4DataOutput::writeAxis_(CAxis* axis)
1046      {
1047        if (axis->IsWritten(this->filename)) return;
1048
1049        // Check that the name associated to the current element is not in conflict with an existing element (due to CGrid::duplicateSentGrid)
1050        if (!axis->value.isEmpty() )
1051        {
1052          // The hash of the element will be associated to the default element name (= map key), and to the name really written
1053          int globalHash = axis->computeAttributesHash( comm_file ); // Need a MPI_Comm to distribute without redundancy some attributs (value)
1054
1055          StdString defaultNameKey = axis->getAxisOutputName();
1056          if ( !relAxis_.count ( defaultNameKey ) )
1057          {
1058            // if defaultNameKey not in the map, write the element such as it is defined
1059            relAxis_.insert( make_pair( defaultNameKey, make_pair(globalHash, axis) ) );
1060          }
1061          else // look if a hash associated this key is equal
1062          {
1063            bool elementIsInMap(false);
1064            auto defaultNameKeyElements = relAxis_.equal_range( defaultNameKey );
1065            for (auto it = defaultNameKeyElements.first; it != defaultNameKeyElements.second; it++)
1066            {
1067              if ( it->second.first == globalHash )
1068              {
1069                // if yes, associate the same ids to current element
1070                axis->renameAttributesBeforeWriting( it->second.second );
1071                elementIsInMap = true;
1072              }
1073            }
1074             // if no : inheritance has been excessive, define new names and store it (could be used by another grid)
1075            if (!elementIsInMap)  // ! in MAP
1076            {
1077              axis->renameAttributesBeforeWriting();
1078              relAxis_.insert( make_pair( defaultNameKey, make_pair(globalHash, axis) ) ) ;// = axis->getId()         
1079            }
1080          }
1081        }
1082
1083        axis->checkAttributes();
1084
1085        int size  = (MULTI_FILE == SuperClass::type) ? axis->n.getValue()
1086                                                          : axis->n_glo.getValue();
1087
1088        if ((0 == axis->n) && (MULTI_FILE == SuperClass::type)) return;
1089
1090        std::vector<StdString> dims;
1091        StdString axisid = axis->getAxisOutputName();
1092        StdString axisDim, axisBoundsId;
1093        if (isWrittenAxis(axisid)) return ;
1094        else setWrittenAxis(axisid);
1095
1096        nc_type typePrec ;
1097        if (axis->prec.isEmpty()) typePrec =  NC_FLOAT ;
1098        else if (axis->prec==4)   typePrec =  NC_FLOAT ;
1099        else if (axis->prec==8)   typePrec =  NC_DOUBLE ;
1100         
1101        if (!axis->label.isEmpty()) typePrec = NC_CHAR ;
1102        string strId="str_len" ;
1103        try
1104        {
1105          if (axis->dim_name.isEmpty()) axisDim = axisid;
1106          else axisDim=axis->dim_name.getValue();
1107          SuperClassWriter::addDimension(axisDim, size);
1108          dims.push_back(axisDim);
1109
1110          if (!axis->label.isEmpty() && !SuperClassWriter::dimExist(strId)) SuperClassWriter::addDimension(strId, stringArrayLen);
1111
1112          if (axis->hasValue() || !axis->label.isEmpty())
1113          {
1114            if (!axis->label.isEmpty()) dims.push_back(strId);
1115
1116            SuperClassWriter::addVariable(axisid, typePrec, dims, compressionLevel);
1117
1118            if (!axis->name.isEmpty())
1119              SuperClassWriter::addAttribute("name", axis->name.getValue(), &axisid);
1120
1121            if (!axis->standard_name.isEmpty())
1122              SuperClassWriter::addAttribute("standard_name", axis->standard_name.getValue(), &axisid);
1123
1124            if (!axis->long_name.isEmpty())
1125              SuperClassWriter::addAttribute("long_name", axis->long_name.getValue(), &axisid);
1126
1127            if (!axis->unit.isEmpty())
1128              SuperClassWriter::addAttribute("units", axis->unit.getValue(), &axisid);
1129
1130            if (!axis->axis_type.isEmpty())
1131            {
1132              switch(axis->axis_type)
1133              {
1134              case CAxis::axis_type_attr::X :
1135                SuperClassWriter::addAttribute("axis", string("X"), &axisid);
1136                break;
1137              case CAxis::axis_type_attr::Y :
1138                SuperClassWriter::addAttribute("axis", string("Y"), &axisid);
1139                break;
1140              case CAxis::axis_type_attr::Z :
1141                SuperClassWriter::addAttribute("axis", string("Z"), &axisid);
1142                break;
1143              case CAxis::axis_type_attr::T :
1144                SuperClassWriter::addAttribute("axis", string("T"), &axisid);
1145                break;
1146              }
1147            }
1148
1149            if (!axis->positive.isEmpty())
1150            {
1151              SuperClassWriter::addAttribute("positive",
1152                                             (axis->positive == CAxis::positive_attr::up) ? string("up") : string("down"),
1153                                             &axisid);
1154            }
1155
1156            if (!axis->formula.isEmpty())
1157              SuperClassWriter::addAttribute("formula", axis->formula.getValue(), &axisid);
1158
1159            if (!axis->formula_term.isEmpty())
1160              SuperClassWriter::addAttribute("formula_terms", axis->formula_term.getValue(), &axisid);
1161             
1162            axisBoundsId = (axis->bounds_name.isEmpty()) ? axisid + "_bounds" : axis->bounds_name;
1163            if (!axis->bounds.isEmpty() && axis->label.isEmpty())
1164            {
1165              dims.push_back("axis_nbounds");
1166              SuperClassWriter::addVariable(axisBoundsId, typePrec, dims, compressionLevel);
1167              SuperClassWriter::addAttribute("bounds", axisBoundsId, &axisid);
1168
1169              if (!axis->standard_name.isEmpty())
1170                SuperClassWriter::addAttribute("standard_name", axis->standard_name.getValue(), &axisBoundsId);
1171
1172              if (!axis->unit.isEmpty())
1173                SuperClassWriter::addAttribute("units", axis->unit.getValue(), &axisBoundsId);
1174
1175              if (!axis->formula_bounds.isEmpty())
1176                SuperClassWriter::addAttribute("formula", axis->formula_bounds.getValue(), &axisBoundsId);
1177
1178              if (!axis->formula_term_bounds.isEmpty())
1179                SuperClassWriter::addAttribute("formula_terms", axis->formula_term_bounds.getValue(), &axisBoundsId);
1180            }
1181          }
1182
1183          SuperClassWriter::definition_end();
1184         
1185          switch (SuperClass::type)
1186          {
1187            case MULTI_FILE:
1188            {
1189              if (axis->label.isEmpty())
1190              {
1191                if (!axis->value.isEmpty())
1192                  SuperClassWriter::writeData(axis->value, axisid, isCollective, 0);
1193
1194                if (!axis->bounds.isEmpty())
1195                  SuperClassWriter::writeData(axis->bounds, axisBoundsId, isCollective, 0);
1196              }
1197              else
1198                SuperClassWriter::writeData(axis->label, axisid, isCollective, 0);
1199
1200              SuperClassWriter::definition_start();
1201              break;
1202            }
1203            case ONE_FILE:
1204            {
1205              std::vector<StdSize> start(1), startBounds(2) ;
1206              std::vector<StdSize> count(1), countBounds(2) ;
1207              start[0] = startBounds[0] = axis->begin;
1208              count[0] = countBounds[0] = axis->n;
1209              startBounds[1] = 0;
1210              countBounds[1] = 2;
1211
1212              if (axis->label.isEmpty())
1213              {
1214                if (!axis->value.isEmpty())
1215                  SuperClassWriter::writeData(axis->value, axisid, isCollective, 0, &start, &count);
1216
1217                if (!axis->bounds.isEmpty())
1218                  SuperClassWriter::writeData(axis->bounds, axisBoundsId, isCollective, 0, &startBounds, &countBounds);
1219              }
1220              else
1221              {
1222                std::vector<StdSize> startLabel(2), countLabel(2);
1223                startLabel[0] = start[0]; startLabel[1] = 0;
1224                countLabel[0] = count[0]; countLabel[1] = stringArrayLen;
1225                SuperClassWriter::writeData(axis->label, axisid, isCollective, 0, &startLabel, &countLabel);
1226              }
1227
1228              SuperClassWriter::definition_start();
1229
1230              break;
1231            }
1232            default :
1233              ERROR("CNc4DataOutput::writeAxis_(CAxis* axis)",
1234                    << "[ type = " << SuperClass::type << "]"
1235                    << " not implemented yet !");
1236          }
1237        }
1238        catch (CNetCdfException& e)
1239        {
1240          StdString msg("On writing the axis : ");
1241          msg.append(axisid); msg.append("\n");
1242          msg.append("In the context : ");
1243          CContext* context = CContext::getCurrent() ;
1244          msg.append(context->getId()); msg.append("\n");
1245          msg.append(e.what());
1246          ERROR("CNc4DataOutput::writeAxis_(CAxis* axis)", << msg);
1247        }
1248        axis->addRelFile(this->filename);
1249     }
1250
1251      void CNc4DataOutput::writeScalar_(CScalar* scalar)
1252      {
1253        if (scalar->IsWritten(this->filename)) return;
1254        scalar->checkAttributes();
1255        int scalarSize = 1;
1256
1257        StdString scalaId = scalar->getScalarOutputName();
1258        StdString boundsId;
1259        if (isWrittenAxis(scalaId)) return ;
1260        else setWrittenAxis(scalaId);
1261
1262        nc_type typePrec ;
1263        if (scalar->prec.isEmpty()) typePrec =  NC_FLOAT ;
1264        else if (scalar->prec==4)  typePrec =  NC_FLOAT ;
1265        else if (scalar->prec==8)   typePrec =  NC_DOUBLE ;
1266
1267        if (!scalar->label.isEmpty()) typePrec = NC_CHAR ;
1268        string strId="str_len" ;
1269
1270        try
1271        {
1272          if (!scalar->label.isEmpty() && !SuperClassWriter::dimExist(strId)) SuperClassWriter::addDimension(strId, stringArrayLen);
1273
1274          if (!scalar->value.isEmpty() || !scalar->label.isEmpty())
1275          {
1276            std::vector<StdString> dims;
1277            StdString scalarDim = scalaId;
1278
1279            if (!scalar->label.isEmpty()) dims.push_back(strId);
1280
1281            SuperClassWriter::addVariable(scalaId, typePrec, dims);
1282
1283            if (!scalar->name.isEmpty())
1284              SuperClassWriter::addAttribute("name", scalar->name.getValue(), &scalaId);
1285
1286            if (!scalar->standard_name.isEmpty())
1287              SuperClassWriter::addAttribute("standard_name", scalar->standard_name.getValue(), &scalaId);
1288
1289            if (!scalar->long_name.isEmpty())
1290              SuperClassWriter::addAttribute("long_name", scalar->long_name.getValue(), &scalaId);
1291
1292            if (!scalar->unit.isEmpty())
1293              SuperClassWriter::addAttribute("units", scalar->unit.getValue(), &scalaId);
1294
1295            if (!scalar->axis_type.isEmpty())
1296            {
1297              switch(scalar->axis_type)
1298              {
1299              case CScalar::axis_type_attr::X :
1300                SuperClassWriter::addAttribute("axis", string("X"), &scalaId);
1301                break;
1302              case CScalar::axis_type_attr::Y :
1303                SuperClassWriter::addAttribute("axis", string("Y"), &scalaId);
1304                break;
1305              case CScalar::axis_type_attr::Z :
1306                SuperClassWriter::addAttribute("axis", string("Z"), &scalaId);
1307                break;
1308              case CScalar::axis_type_attr::T :
1309                SuperClassWriter::addAttribute("axis", string("T"), &scalaId);
1310                break;
1311              }
1312            }
1313
1314            if (!scalar->positive.isEmpty())
1315            {
1316              SuperClassWriter::addAttribute("positive",
1317                                             (scalar->positive == CScalar::positive_attr::up) ? string("up") : string("down"),
1318                                             &scalaId);
1319            }
1320
1321            if (!scalar->bounds.isEmpty() && scalar->label.isEmpty())
1322            {
1323              dims.clear();
1324              dims.push_back("axis_nbounds");
1325              boundsId = (scalar->bounds_name.isEmpty()) ? (scalaId + "_bounds") : scalar->bounds_name.getValue();
1326              SuperClassWriter::addVariable(boundsId, typePrec, dims);
1327              SuperClassWriter::addAttribute("bounds", boundsId, &scalaId);
1328            }
1329
1330            SuperClassWriter::definition_end();
1331
1332            switch (SuperClass::type)
1333            {
1334              case MULTI_FILE:
1335              {
1336                CArray<double,1> scalarValue(scalarSize);
1337                CArray<string,1> scalarLabel(scalarSize);
1338                CArray<double,1> scalarBounds(scalarSize*2);
1339
1340                if (!scalar->value.isEmpty() && scalar->label.isEmpty())
1341                {
1342                  scalarValue(0) = scalar->value;
1343                  SuperClassWriter::writeData(scalarValue, scalaId, isCollective, 0);
1344                }
1345
1346                if (!scalar->bounds.isEmpty() && scalar->label.isEmpty())
1347                {
1348                  scalarBounds(0) = scalar->bounds(0);
1349                  scalarBounds(1) = scalar->bounds(1);
1350                  SuperClassWriter::writeData(scalarBounds, boundsId, isCollective, 0);
1351                }
1352
1353                if (!scalar->label.isEmpty())
1354                {
1355                  scalarLabel(0) = scalar->label;
1356                  SuperClassWriter::writeData(scalarLabel, scalaId, isCollective, 0);
1357                }
1358
1359                SuperClassWriter::definition_start();
1360
1361                break;
1362              }
1363              case ONE_FILE:
1364              {
1365                CArray<double,1> scalarValue(scalarSize);
1366                CArray<string,1> scalarLabel(scalarSize);
1367                CArray<double,1> scalarBounds(scalarSize*2);
1368
1369                std::vector<StdSize> start(1);
1370                std::vector<StdSize> count(1);
1371                start[0] = 0;
1372                count[0] = 1;
1373                if (!scalar->value.isEmpty() && scalar->label.isEmpty())
1374                {
1375                  scalarValue(0) = scalar->value;
1376                  SuperClassWriter::writeData(scalarValue, scalaId, isCollective, 0, &start, &count);
1377                }
1378                if (!scalar->bounds.isEmpty() && scalar->label.isEmpty())
1379                {
1380                  scalarBounds(0) = scalar->bounds(0);
1381                  scalarBounds(1) = scalar->bounds(1);
1382                  count[0] = 2;
1383                  SuperClassWriter::writeData(scalarBounds, boundsId, isCollective, 0, &start, &count);
1384                }
1385                if (!scalar->label.isEmpty())
1386                {
1387                  scalarLabel(0) = scalar->label;
1388                  count[0] = stringArrayLen;
1389                  SuperClassWriter::writeData(scalarLabel, scalaId, isCollective, 0, &start, &count);
1390                }
1391
1392                SuperClassWriter::definition_start();
1393
1394                break;
1395              }
1396              default :
1397                ERROR("CNc4DataOutput::writeAxis_(CAxis* scalar)",
1398                      << "[ type = " << SuperClass::type << "]"
1399                      << " not implemented yet !");
1400            }
1401          }
1402        }
1403        catch (CNetCdfException& e)
1404        {
1405          StdString msg("On writing the scalar : ");
1406          msg.append(scalaId); msg.append("\n");
1407          msg.append("In the context : ");
1408          CContext* context = CContext::getCurrent() ;
1409          msg.append(context->getId()); msg.append("\n");
1410          msg.append(e.what());
1411          ERROR("CNc4DataOutput::writeScalar_(CScalar* scalar)", << msg);
1412        }
1413        scalar->addRelFile(this->filename);
1414     }
1415
1416     //--------------------------------------------------------------
1417
1418     void CNc4DataOutput::writeGridCompressed_(CGrid* grid)
1419     {
1420        if (grid->isScalarGrid() || grid->isWrittenCompressed(this->filename)) return;
1421       
1422        // NOTA : The cuurent algorithm to write compress elements of the grid
1423        //        will work pretting well when on server side you dont't get
1424        //        partial overlap on elements between differents participating process
1425        //        So the element must be totally distributed or non distributed
1426        //        If an element is partially overlaping betwwen process then the
1427        //        total compressed part will apear artificially greater than expected
1428        //        For the current implementation of writer which is decomposed only on
1429        //        one element, it will work as expected, but for future, it must be
1430        //        reconsidered again.
1431        try
1432        {
1433          CArray<int,1> axisDomainOrder = grid->axis_domain_order;
1434          std::vector<StdString> domainList = grid->getDomainList();
1435          std::vector<StdString> axisList   = grid->getAxisList();
1436          std::vector<StdString> scalarList = grid->getScalarList();
1437          int numElement = axisDomainOrder.numElements(), idxDomain = 0, idxAxis = 0, idxScalar = 0;
1438          int commRank ;
1439          MPI_Comm_rank(comm_file,&commRank) ;
1440
1441          std::vector<StdString> dims;
1442
1443          for (int i = 0; i < numElement; ++i)
1444          {
1445            StdString varId, compress;
1446            CArray<size_t, 1> indexes;
1447            bool isDistributed;
1448            size_t nbIndexes, totalNbIndexes, offset;
1449            size_t firstGlobalIndex;
1450           
1451            if (2 == axisDomainOrder(i))
1452            {
1453              CDomain* domain = CDomain::get(domainList[idxDomain]);
1454              StdString domId = domain->getDomainOutputName();
1455
1456              if (!domain->isCompressible()
1457                  || domain->type == CDomain::type_attr::unstructured
1458                  || domain->isWrittenCompressed(this->filename)
1459                  || isWrittenCompressedDomain(domId))
1460                continue;
1461           
1462              // unstructured grid seems not be taken into account why ?
1463
1464              string lonName,latName ;
1465
1466              if (domain->lon_name.isEmpty())
1467              { 
1468                if (domain->type==CDomain::type_attr::curvilinear) lonName = "nav_lon";
1469                else lonName = "lon";
1470              }
1471              else lonName = domain->lon_name;
1472
1473              if (domain->lat_name.isEmpty())
1474              {
1475                if (domain->type==CDomain::type_attr::curvilinear) latName = "nav_lat";
1476                else latName = "lat";
1477              }
1478              else latName = domain->lat_name;
1479             
1480              StdString appendDomId  = singleDomain ? "" : "_" + domId;
1481
1482              varId = domId + "_points";
1483              compress = latName + appendDomId + " " + lonName + appendDomId;
1484     
1485              shared_ptr<CLocalView> workflowView = domain->getLocalView(CElementView::WORKFLOW) ;
1486              workflowView->getGlobalIndexView(indexes) ;
1487              nbIndexes = workflowView->getSize() ;
1488              isDistributed = domain->isDistributed();
1489              if (isDistributed)
1490              {
1491                MPI_Exscan(&nbIndexes, &offset, 1, MPI_SIZE_T, MPI_SUM, comm_file) ;
1492                if (commRank==0) offset=0 ;
1493                MPI_Allreduce(&nbIndexes,&totalNbIndexes,1 , MPI_SIZE_T, MPI_SUM, comm_file) ;
1494              }
1495              else
1496              {
1497                offset=0 ;
1498                totalNbIndexes = nbIndexes ;
1499              }
1500
1501              firstGlobalIndex = domain->ibeginValue_ + domain->jbeginValue_ * domain->ni_glo;
1502
1503              domain->addRelFileCompressed(this->filename);
1504              setWrittenCompressedDomain(domId);
1505              ++idxDomain;
1506            }
1507            else if (1 == axisDomainOrder(i))
1508            {
1509              CAxis* axis = CAxis::get(axisList[idxAxis]);
1510              StdString axisId = axis->getAxisOutputName();
1511
1512              if (!axis->isCompressible()
1513                  || axis->isWrittenCompressed(this->filename)
1514                  || isWrittenCompressedAxis(axisId))
1515                continue;
1516
1517              varId = axisId + "_points";
1518              compress = axisId;
1519
1520              shared_ptr<CLocalView> workflowView = axis->getLocalView(CElementView::WORKFLOW) ;
1521              workflowView->getGlobalIndexView(indexes) ;
1522              nbIndexes = workflowView->getSize() ;
1523              isDistributed = axis->isDistributed();
1524              if (isDistributed)
1525              {
1526                MPI_Exscan(&nbIndexes, &offset, 1, MPI_SIZE_T, MPI_SUM, comm_file) ;
1527                if (commRank==0) offset=0 ;
1528                MPI_Allreduce(&nbIndexes,&totalNbIndexes,1 , MPI_SIZE_T, MPI_SUM, comm_file) ;
1529              }
1530              else
1531              {
1532                offset=0 ;
1533                totalNbIndexes = nbIndexes ;
1534              }
1535              firstGlobalIndex = axis->begin;
1536             
1537              axis->addRelFileCompressed(this->filename);
1538              setWrittenCompressedAxis(axisId);
1539              ++idxAxis;
1540            }
1541            else
1542            {
1543              //for scalar
1544            }
1545
1546            if (!varId.empty())
1547            {
1548              SuperClassWriter::addDimension(varId, (SuperClass::type == MULTI_FILE) ? nbIndexes : totalNbIndexes);
1549
1550              dims.clear();
1551              dims.push_back(varId);
1552              SuperClassWriter::addVariable(varId, NC_UINT64, dims);
1553
1554              SuperClassWriter::addAttribute("compress", compress, &varId);
1555
1556              switch (SuperClass::type)
1557              {
1558                case (MULTI_FILE):
1559                {
1560                  indexes -= firstGlobalIndex;
1561                  SuperClassWriter::writeData(indexes, varId, isCollective, 0);
1562                  break;
1563                }
1564                case (ONE_FILE):
1565                {
1566                  std::vector<StdSize> start, count;
1567                  start.push_back(offset);
1568                  count.push_back(nbIndexes);
1569
1570                  SuperClassWriter::writeData(indexes, varId, isCollective, 0, &start, &count);
1571                  break;
1572                }
1573              }
1574            }
1575          }
1576
1577          grid->addRelFileCompressed(this->filename);
1578        }
1579        catch (CNetCdfException& e)
1580        {
1581          StdString msg("On writing compressed grid : ");
1582          msg.append(grid->getId()); msg.append("\n");
1583          msg.append("In the context : ");
1584          CContext* context = CContext::getCurrent();
1585          msg.append(context->getId()); msg.append("\n");
1586          msg.append(e.what());
1587          ERROR("CNc4DataOutput::writeGridCompressed_(CGrid* grid)", << msg);
1588        }
1589      }
1590
1591     //--------------------------------------------------------------
1592
1593     void CNc4DataOutput::writeTimeDimension_(void)
1594     {
1595       try
1596       {
1597        SuperClassWriter::addDimension(getTimeCounterName());
1598       }
1599       catch (CNetCdfException& e)
1600       {
1601         StdString msg("On writing time dimension : time_couter\n");
1602         msg.append("In the context : ");
1603         CContext* context = CContext::getCurrent() ;
1604         msg.append(context->getId()); msg.append("\n");
1605         msg.append(e.what());
1606         ERROR("CNc4DataOutput::writeTimeDimension_(void)", << msg);
1607       }
1608     }
1609
1610      //--------------------------------------------------------------
1611
1612      void CNc4DataOutput::writeField_(CField* field)
1613      {
1614        CContext* context = CContext::getCurrent() ;
1615
1616        std::vector<StdString> dims, coodinates;
1617        CGrid* grid = field->getGrid();
1618        if (!grid->doGridHaveDataToWrite())
1619          if (SuperClass::type==MULTI_FILE) return ;
1620
1621        CArray<int,1> axisDomainOrder = grid->axis_domain_order;
1622        int numElement = axisDomainOrder.numElements(), idxDomain = 0, idxAxis = 0, idxScalar = 0;
1623        std::vector<StdString> domainList = grid->getDomainList();
1624        std::vector<StdString> axisList   = grid->getAxisList();
1625        std::vector<StdString> scalarList = grid->getScalarList();       
1626
1627        StdString timeid  = getTimeCounterName();
1628        StdString dimXid,dimYid;
1629        std::deque<StdString> dimIdList, dimCoordList;
1630        bool hasArea = false;
1631        StdString cellMeasures = "area:";
1632        bool compressedOutput = !field->indexed_output.isEmpty() && field->indexed_output;
1633
1634        for (int i = 0; i < numElement; ++i)
1635        {
1636          if (2 == axisDomainOrder(i))
1637          {
1638            CDomain* domain = CDomain::get(domainList[idxDomain]);
1639            StdString domId = domain->getDomainOutputName();
1640            StdString appendDomId  = singleDomain ? "" : "_" + domId ;
1641            StdString lonName,latName ;
1642            StdString dimIname,dimJname ;
1643
1644            if (domain->lon_name.isEmpty())
1645            { 
1646              if (domain->type==CDomain::type_attr::curvilinear) lonName = "nav_lon";
1647              else lonName = "lon";
1648            }
1649            else lonName = domain->lon_name;
1650
1651            if (domain->lat_name.isEmpty())
1652            {
1653              if (domain->type==CDomain::type_attr::curvilinear) latName = "nav_lat";
1654              else latName = "lat";
1655            }
1656            else latName = domain->lat_name;
1657
1658            if (domain->dim_i_name.isEmpty())
1659            {
1660              if (domain->type==CDomain::type_attr::curvilinear) dimIname = "x";
1661              else if (domain->type==CDomain::type_attr::unstructured) dimIname = "cell";
1662              else dimIname = lonName;
1663            }
1664            else dimIname = domain->dim_i_name;
1665
1666            if (domain->dim_j_name.isEmpty())
1667            {
1668              if (domain->type==CDomain::type_attr::curvilinear) dimJname = "y";
1669              else dimJname = latName;
1670            }
1671            else dimJname = domain->dim_j_name;
1672       
1673            if (compressedOutput && domain->isCompressible() && domain->type != CDomain::type_attr::unstructured)
1674            {
1675              dimIdList.push_back(domId + "_points");
1676              field->setUseCompressedOutput();
1677            }
1678
1679            switch (domain->type)
1680            {
1681              case CDomain::type_attr::curvilinear:
1682                if (!compressedOutput || !domain->isCompressible())
1683                {
1684                  dimXid=dimIname+appendDomId;
1685                  dimYid=dimJname+appendDomId;
1686                  dimIdList.push_back(dimXid);
1687                  dimIdList.push_back(dimYid);
1688                }
1689                dimCoordList.push_back(lonName+appendDomId);
1690                dimCoordList.push_back(latName+appendDomId);
1691              break ;
1692              case CDomain::type_attr::rectilinear:
1693                if (!compressedOutput || !domain->isCompressible())
1694                {
1695                  dimXid     = dimIname+appendDomId;
1696                  dimYid     = dimJname+appendDomId;
1697                  dimIdList.push_back(dimXid);
1698                  dimIdList.push_back(dimYid);
1699                }
1700                if (lonName != dimIname)  dimCoordList.push_back(lonName+appendDomId);
1701                if (latName != dimJname)  dimCoordList.push_back(latName+appendDomId);
1702
1703              break ;
1704              case CDomain::type_attr::unstructured:
1705              {
1706                if (SuperClassWriter::useCFConvention)
1707                {
1708                  dimXid     = dimIname + appendDomId;
1709                  dimIdList.push_back(dimXid);
1710                  dimCoordList.push_back(lonName+appendDomId);
1711                  dimCoordList.push_back(latName+appendDomId);
1712                }
1713                else
1714                {
1715                  StdString domainName = domain->name;
1716                  if (domain->nvertex == 1)
1717                  {
1718                    dimXid     = "n" + domainName + "_node";
1719                    dimIdList.push_back(dimXid);
1720                    dimCoordList.push_back(StdString(domainName + "_node_x"));
1721                    dimCoordList.push_back(StdString(domainName + "_node_y"));
1722                  }
1723                  else if (domain->nvertex == 2)
1724                  {
1725                    dimXid     = "n" + domainName + "_edge";
1726                    dimIdList.push_back(dimXid);
1727                    dimCoordList.push_back(StdString(domainName + "_edge_x"));
1728                    dimCoordList.push_back(StdString(domainName + "_edge_y"));
1729                  }
1730                  else
1731                  {
1732                    dimXid     = "n" + domainName + "_face";
1733                    dimIdList.push_back(dimXid);
1734                    dimCoordList.push_back(StdString(domainName + "_face_x"));
1735                    dimCoordList.push_back(StdString(domainName + "_face_y"));
1736                  }
1737                }  // ugrid convention
1738              }  // case unstructured domain
1739            }
1740
1741            if (domain->hasArea)
1742            {
1743              hasArea = true;
1744              cellMeasures += " area" + appendDomId;
1745            }
1746            ++idxDomain;
1747          }
1748          else if (1 == axisDomainOrder(i))
1749          {
1750            CAxis* axis = CAxis::get(axisList[idxAxis]);
1751            StdString axisId = axis->getAxisOutputName();
1752            StdString axisDim;
1753
1754            if (axis->dim_name.isEmpty()) axisDim = axisId;
1755            else axisDim=axis->dim_name.getValue();
1756
1757            if (compressedOutput && axis->isCompressible())
1758            {
1759              dimIdList.push_back(axisDim + "_points");
1760              field->setUseCompressedOutput();
1761            }
1762            else
1763              dimIdList.push_back(axisDim);
1764
1765            if (axisDim != axisId) dimCoordList.push_back(axisId);
1766            ++idxAxis;
1767          }
1768          else
1769          {
1770            CScalar* scalar = CScalar::get(scalarList[idxScalar]);
1771            StdString scalarId = scalar->getScalarOutputName();
1772            if (!scalar->value.isEmpty() || !scalar->label.isEmpty())
1773              dimCoordList.push_back(scalarId);
1774            ++idxScalar;
1775          }
1776        }
1777
1778        StdString fieldid = field->getFieldOutputName();
1779
1780        nc_type type ;
1781        if (field->prec.isEmpty()) type =  NC_FLOAT ;
1782        else
1783        {
1784          if (field->prec==2) type = NC_SHORT ;
1785          else if (field->prec==4)  type =  NC_FLOAT ;
1786          else if (field->prec==8)   type =  NC_DOUBLE ;
1787        }
1788
1789        bool wtime   = !(!field->operation.isEmpty() && field->getOperationTimeType() == func::CFunctor::once);
1790
1791        if (wtime)
1792        {
1793          if (field->hasTimeInstant && hasTimeInstant) coodinates.push_back(string("time_instant"));
1794          else if (field->hasTimeCentered && hasTimeCentered)  coodinates.push_back(string("time_centered"));
1795          dims.push_back(timeid);
1796        }
1797
1798        while (!dimIdList.empty())
1799        {
1800          dims.push_back(dimIdList.back());
1801          dimIdList.pop_back();
1802        }
1803
1804        while (!dimCoordList.empty())
1805        {
1806          coodinates.push_back(dimCoordList.back());
1807          dimCoordList.pop_back();
1808        }
1809
1810        try
1811        {
1812           SuperClassWriter::addVariable(fieldid, type, dims, false);
1813           SuperClassWriter::addChunk(field, type, dims);
1814
1815           if (!field->standard_name.isEmpty())
1816              SuperClassWriter::addAttribute
1817                 ("standard_name",  field->standard_name.getValue(), &fieldid);
1818
1819           if (!field->long_name.isEmpty())
1820              SuperClassWriter::addAttribute
1821                 ("long_name", field->long_name.getValue(), &fieldid);
1822
1823           if (!field->unit.isEmpty())
1824              SuperClassWriter::addAttribute
1825                 ("units", field->unit.getValue(), &fieldid);
1826
1827           // Ugrid field attributes "mesh" and "location"
1828           if (!SuperClassWriter::useCFConvention)
1829           {
1830            if (!domainList.empty())
1831            {
1832              CDomain* domain = CDomain::get(domainList[0]); // Suppose that we have only domain
1833              StdString mesh = domain->name;
1834              SuperClassWriter::addAttribute("mesh", mesh, &fieldid);
1835              StdString location;
1836              if (domain->nvertex == 1)
1837                location = "node";
1838              else if (domain->nvertex == 2)
1839                location = "edge";
1840              else if (domain->nvertex > 2)
1841                location = "face";
1842              SuperClassWriter::addAttribute("location", location, &fieldid);
1843            }
1844
1845           }
1846
1847           if (!field->valid_min.isEmpty())
1848              SuperClassWriter::addAttribute
1849                 ("valid_min", field->valid_min.getValue(), &fieldid);
1850
1851           if (!field->valid_max.isEmpty())
1852              SuperClassWriter::addAttribute
1853                 ("valid_max", field->valid_max.getValue(), &fieldid);
1854
1855            if (!field->scale_factor.isEmpty())
1856              SuperClassWriter::addAttribute
1857                 ("scale_factor", field->scale_factor.getValue(), &fieldid);
1858
1859             if (!field->add_offset.isEmpty())
1860              SuperClassWriter::addAttribute
1861                 ("add_offset", field->add_offset.getValue(), &fieldid);
1862
1863           SuperClassWriter::addAttribute
1864                 ("online_operation", field->operation.getValue(), &fieldid);
1865
1866          // write child variables as attributes
1867
1868
1869           bool alreadyAddCellMethod = false;
1870           StdString cellMethodsPrefix(""), cellMethodsSuffix("");
1871           if (!field->cell_methods.isEmpty())
1872           {
1873              StdString cellMethodString = field->cell_methods;
1874              if (field->cell_methods_mode.isEmpty() ||
1875                 (CField::cell_methods_mode_attr::overwrite == field->cell_methods_mode))
1876              {
1877                SuperClassWriter::addAttribute("cell_methods", cellMethodString, &fieldid);
1878                alreadyAddCellMethod = true;
1879              }
1880              else
1881              {
1882                switch (field->cell_methods_mode)
1883                {
1884                  case (CField::cell_methods_mode_attr::prefix):
1885                    cellMethodsPrefix = cellMethodString;
1886                    cellMethodsPrefix += " ";
1887                    break;
1888                  case (CField::cell_methods_mode_attr::suffix):
1889                    cellMethodsSuffix = " ";
1890                    cellMethodsSuffix += cellMethodString;
1891                    break;
1892                  case (CField::cell_methods_mode_attr::none):
1893                    break;
1894                  default:
1895                    break;
1896                }
1897              }
1898           }
1899
1900
1901           if (wtime)
1902           {
1903              CDuration freqOp = field->freq_op.getValue();
1904              freqOp.solveTimeStep(*context->calendar);
1905              StdString freqOpStr = freqOp.toStringUDUnits();
1906              SuperClassWriter::addAttribute("interval_operation", freqOpStr, &fieldid);
1907
1908              CDuration freqOut = field->getRelFile()->output_freq.getValue();
1909              freqOut.solveTimeStep(*context->calendar);
1910              SuperClassWriter::addAttribute("interval_write", freqOut.toStringUDUnits(), &fieldid);
1911
1912              StdString cellMethods(cellMethodsPrefix + "time: ");
1913              if (field->operation.getValue() == "instant") cellMethods += "point";
1914              else if (field->operation.getValue() == "average") cellMethods += "mean";
1915              else if (field->operation.getValue() == "accumulate") cellMethods += "sum";
1916              else cellMethods += field->operation;
1917              if (freqOp.resolve(*context->calendar) != freqOut.resolve(*context->calendar))
1918                cellMethods += " (interval: " + freqOpStr + ")";
1919              cellMethods += cellMethodsSuffix;
1920              if (!alreadyAddCellMethod)
1921                SuperClassWriter::addAttribute("cell_methods", cellMethods, &fieldid);
1922           }
1923
1924           if (hasArea)
1925             SuperClassWriter::addAttribute("cell_measures", cellMeasures, &fieldid);
1926
1927           if (!field->default_value.isEmpty())
1928           {
1929             double default_value = field->default_value.getValue();
1930             if (type == NC_DOUBLE)
1931             {
1932               SuperClassWriter::setDefaultValue(fieldid, &default_value);
1933             }
1934             else if (type == NC_SHORT)
1935             {
1936               short sdefault_value = (short)default_value;
1937               SuperClassWriter::setDefaultValue(fieldid, &sdefault_value);
1938             }
1939             else
1940             {
1941               float fdefault_value = (float)default_value;
1942               SuperClassWriter::setDefaultValue(fieldid, &fdefault_value);
1943             }
1944           }
1945           else
1946              SuperClassWriter::setDefaultValue(fieldid, (double*)NULL);
1947
1948            if (field->compression_level.isEmpty())
1949              field->compression_level = field->getRelFile()->compression_level.isEmpty() ? 0 : field->getRelFile()->compression_level;
1950            else
1951              field->compression_type.setValue( "gzip" );
1952            if (field->compression_type.isEmpty())
1953              field->compression_type = "None";
1954            if (field->compression_params.isEmpty())
1955              field->compression_params.resize( 0 );
1956            SuperClassWriter::setCompressionLevel(fieldid, field->compression_type, field->compression_level, field->compression_params);
1957
1958           {  // Ecriture des coordonnes
1959
1960              StdString coordstr; //boost::algorithm::join(coodinates, " ")
1961              std::vector<StdString>::iterator
1962                 itc = coodinates.begin(), endc = coodinates.end();
1963
1964              for (; itc!= endc; itc++)
1965              {
1966                 StdString & coord = *itc;
1967                 if (itc+1 != endc)
1968                       coordstr.append(coord).append(" ");
1969                 else  coordstr.append(coord);
1970              }
1971
1972              SuperClassWriter::addAttribute("coordinates", coordstr, &fieldid);
1973
1974           }
1975
1976           vector<CVariable*> listVars = field->getAllVariables() ;
1977           for (vector<CVariable*>::iterator it = listVars.begin() ;it != listVars.end(); it++) writeAttribute_(*it, fieldid) ;
1978
1979         }
1980         catch (CNetCdfException& e)
1981         {
1982           StdString msg("On writing field : ");
1983           msg.append(fieldid); msg.append("\n");
1984           msg.append("In the context : ");
1985           msg.append(context->getId()); msg.append("\n");
1986           msg.append(e.what());
1987           ERROR("CNc4DataOutput::writeField_(CField* field)", << msg);
1988         }
1989      } // writeField_()
1990
1991      //--------------------------------------------------------------
1992
1993      void CNc4DataOutput::writeFile_ (CFile* file)
1994      {
1995         StdString filename = file->getFileOutputName();
1996         StdString description = (!file->description.isEmpty())
1997                               ? file->description.getValue()
1998                               : StdString("Created by xios");
1999
2000         singleDomain = (file->nbDomains == 1);
2001
2002         StdString conv_str ;
2003         if (file->convention_str.isEmpty())
2004         {
2005            if (SuperClassWriter::useCFConvention) conv_str="CF-1.6" ;
2006            else conv_str="UGRID" ;
2007         }
2008         else conv_str=file->convention_str ;
2009           
2010         try
2011         {
2012           if (!appendMode) this->writeFileAttributes(filename, description,
2013                                                      conv_str,
2014                                                      StdString("An IPSL model"),
2015                                                      this->getTimeStamp());
2016
2017           if (!appendMode)
2018             SuperClassWriter::addDimension("axis_nbounds", 2);
2019         }
2020         catch (CNetCdfException& e)
2021         {
2022           StdString msg("On writing file : ");
2023           msg.append(filename); msg.append("\n");
2024           msg.append("In the context : ");
2025           CContext* context = CContext::getCurrent() ;
2026           msg.append(context->getId()); msg.append("\n");
2027           msg.append(e.what());
2028           ERROR("CNc4DataOutput::writeFile_ (CFile* file)", << msg);
2029         }
2030      }
2031
2032      void CNc4DataOutput::writeAttribute_ (CVariable* var, const string& fieldId)
2033      {
2034        StdString name = var->getVariableOutputName();
2035
2036        try
2037        {
2038          if (var->type.getValue() == CVariable::type_attr::t_int || var->type.getValue() == CVariable::type_attr::t_int32)
2039            addAttribute(name, var->getData<int>(), &fieldId);
2040          else if (var->type.getValue() == CVariable::type_attr::t_int16)
2041            addAttribute(name, var->getData<short int>(), &fieldId);
2042          else if (var->type.getValue() == CVariable::type_attr::t_float)
2043            addAttribute(name, var->getData<float>(), &fieldId);
2044          else if (var->type.getValue() == CVariable::type_attr::t_double)
2045            addAttribute(name, var->getData<double>(), &fieldId);
2046          else if (var->type.getValue() == CVariable::type_attr::t_string)
2047            addAttribute(name, var->getData<string>(), &fieldId);
2048          else
2049            ERROR("CNc4DataOutput::writeAttribute_ (CVariable* var, const string& fieldId)",
2050                  << "Unsupported variable of type " << var->type.getStringValue());
2051        }
2052       catch (CNetCdfException& e)
2053       {
2054         StdString msg("On writing attributes of variable with name : ");
2055         msg.append(name); msg.append("in the field "); msg.append(fieldId); msg.append("\n");
2056         msg.append("In the context : ");
2057         CContext* context = CContext::getCurrent() ;
2058         msg.append(context->getId()); msg.append("\n");
2059         msg.append(e.what());
2060         ERROR("CNc4DataOutput::writeAttribute_ (CVariable* var, const string& fieldId)", << msg);
2061       }
2062     }
2063
2064     void CNc4DataOutput::writeAttribute_ (CVariable* var)
2065     {
2066        StdString name = var->getVariableOutputName();
2067
2068        try
2069        {
2070          if (var->type.getValue() == CVariable::type_attr::t_int || var->type.getValue() == CVariable::type_attr::t_int32)
2071            addAttribute(name, var->getData<int>());
2072          else if (var->type.getValue() == CVariable::type_attr::t_int16)
2073            addAttribute(name, var->getData<short int>());
2074          else if (var->type.getValue() == CVariable::type_attr::t_float)
2075            addAttribute(name, var->getData<float>());
2076          else if (var->type.getValue() == CVariable::type_attr::t_double)
2077            addAttribute(name, var->getData<double>());
2078          else if (var->type.getValue() == CVariable::type_attr::t_string)
2079            addAttribute(name, var->getData<string>());
2080          else
2081            ERROR("CNc4DataOutput::writeAttribute_ (CVariable* var)",
2082                  << "Unsupported variable of type " << var->type.getStringValue());
2083        }
2084       catch (CNetCdfException& e)
2085       {
2086         StdString msg("On writing attributes of variable with name : ");
2087         msg.append(name); msg.append("\n");
2088         msg.append("In the context : ");
2089         CContext* context = CContext::getCurrent() ;
2090         msg.append(context->getId()); msg.append("\n");
2091         msg.append(e.what());
2092         ERROR("CNc4DataOutput::writeAttribute_ (CVariable* var)", << msg);
2093       }
2094     }
2095
2096      void CNc4DataOutput::syncFile_ (void)
2097      {
2098        try
2099        {
2100          SuperClassWriter::sync() ;
2101        }
2102        catch (CNetCdfException& e)
2103        {
2104         StdString msg("On synchronizing the write among processes");
2105         msg.append("In the context : ");
2106         CContext* context = CContext::getCurrent() ;
2107         msg.append(context->getId()); msg.append("\n");
2108         msg.append(e.what());
2109         ERROR("CNc4DataOutput::syncFile_ (void)", << msg);
2110        }
2111      }
2112
2113      void CNc4DataOutput::closeFile_ (void)
2114      {
2115        try
2116        {
2117          SuperClassWriter::close() ;
2118        }
2119        catch (CNetCdfException& e)
2120        {
2121         StdString msg("On closing file");
2122         msg.append("In the context : ");
2123         CContext* context = CContext::getCurrent() ;
2124         msg.append(context->getId()); msg.append("\n");
2125         msg.append(e.what());
2126         ERROR("CNc4DataOutput::syncFile_ (void)", << msg);
2127        }
2128
2129      }
2130
2131      //---------------------------------------------------------------
2132
2133      StdString CNc4DataOutput::getTimeStamp(void) const
2134      {
2135         const int buffer_size = 100;
2136         time_t rawtime;
2137         struct tm * timeinfo = NULL;
2138         char buffer [buffer_size];
2139         StdString formatStr;
2140         if (file->time_stamp_format.isEmpty()) formatStr="%Y-%b-%d %H:%M:%S %Z" ;
2141         else formatStr=file->time_stamp_format;
2142
2143//         time ( &rawtime );
2144//         timeinfo = localtime ( &rawtime );
2145         time ( &rawtime );
2146         timeinfo = gmtime ( &rawtime );
2147         strftime (buffer, buffer_size, formatStr.c_str(), timeinfo);
2148
2149         return (StdString(buffer));
2150      }
2151
2152      //---------------------------------------------------------------
2153
2154      int CNc4DataOutput::writeFieldData_ (CField*  field, const CArray<double,1>& data, const CDate& lastWrite,
2155                                           const CDate& currentWrite, int nstep)
2156      {
2157        CContext* context = CContext::getCurrent();
2158        CGrid* grid = field->getGrid();
2159       
2160        if (nstep<1) 
2161        {
2162          return nstep;
2163        }
2164       
2165        if (!grid->doGridHaveDataToWrite())
2166          if (SuperClass::type == MULTI_FILE || !isCollective)
2167          {
2168            return nstep;
2169          }
2170
2171        StdString fieldid = field->getFieldOutputName();
2172
2173        StdOStringStream oss;
2174        string timeAxisId;
2175        if (field->hasTimeInstant) timeAxisId = "time_instant";
2176        else if (field->hasTimeCentered) timeAxisId = "time_centered";
2177
2178        StdString timeBoundId = getTimeCounterName() + "_bounds";
2179
2180        StdString timeAxisBoundId;
2181        if (field->hasTimeInstant) timeAxisBoundId = "time_instant_bounds";
2182        else if (field->hasTimeCentered) timeAxisBoundId = "time_centered_bounds";
2183
2184        if (!field->wasWritten())
2185        {
2186          if (appendMode && field->getRelFile()->record_offset.isEmpty() && 
2187              field->getOperationTimeType() != func::CFunctor::once)
2188          {
2189            double factorUnit;
2190            if (!field->getRelFile()->time_units.isEmpty() && field->getRelFile()->time_units==CFile::time_units_attr::days)
2191            factorUnit=context->getCalendar()->getDayLengthInSeconds() ;
2192            else factorUnit=1 ;
2193            nstep = getRecordFromTime(currentWrite,factorUnit) + 1;
2194          }
2195
2196          field->setWritten();
2197        }
2198
2199
2200        CArray<double,1> time_data(1);
2201        CArray<double,1> time_data_bound(2);
2202        CArray<double,1> time_counter(1);
2203        CArray<double,1> time_counter_bound(2);
2204
2205        bool wtime = (field->getOperationTimeType() != func::CFunctor::once);
2206        bool wtimeCounter =false ;
2207        bool wtimeData =false ;
2208       
2209
2210        if (wtime)
2211        {
2212         
2213          if (field->hasTimeInstant)
2214          {
2215            time_data(0) = time_data_bound(1) = (Time) lastWrite;
2216            time_data_bound(0) = time_data_bound(1) = (Time) currentWrite;
2217            if (timeCounterType==instant)
2218            {
2219              time_counter(0) = time_data(0);
2220              time_counter_bound(0) = time_data_bound(0);
2221              time_counter_bound(1) = time_data_bound(1);
2222              wtimeCounter=true ;
2223            }
2224            if (hasTimeInstant) wtimeData=true ;
2225          }
2226          else if (field->hasTimeCentered)
2227          {
2228            time_data(0) = ((Time)currentWrite + (Time)lastWrite) / 2;
2229            time_data_bound(0) = (Time)lastWrite;
2230            time_data_bound(1) = (Time)currentWrite;
2231            if (timeCounterType==centered)
2232            {
2233              time_counter(0) = time_data(0) ;
2234              time_counter_bound(0) = time_data_bound(0) ;
2235              time_counter_bound(1) = time_data_bound(1) ;
2236              wtimeCounter=true ;
2237            }
2238            if (hasTimeCentered) wtimeData=true ;
2239          }
2240
2241          if (timeCounterType==record)
2242          {
2243            time_counter(0) = nstep - 1;
2244            time_counter_bound(0) = time_counter_bound(1) = nstep - 1;
2245            wtimeCounter=true ;
2246          }
2247
2248          if (!field->getRelFile()->time_units.isEmpty() && field->getRelFile()->time_units==CFile::time_units_attr::days)
2249          {
2250            double secByDay=context->getCalendar()->getDayLengthInSeconds() ;
2251            time_data/=secByDay;
2252            time_data_bound/=secByDay;
2253            time_counter/=secByDay;
2254            time_counter_bound/=secByDay;
2255          }
2256        }
2257
2258         bool isRoot = (context->intraCommRank_ == 0);
2259
2260         try
2261         {
2262           switch (SuperClass::type)
2263           {
2264              case (MULTI_FILE) :
2265              {
2266                 CTimer::get("Files : writing data").resume();
2267                 SuperClassWriter::writeData(data, fieldid, isCollective, nstep - 1);
2268                 CTimer::get("Files : writing data").suspend();
2269                 if (wtime)
2270                 {
2271                   CTimer::get("Files : writing time axis").resume();
2272                   if ( wtimeData)
2273                   {
2274                       SuperClassWriter::writeTimeAxisData(time_data, timeAxisId, isCollective, nstep - 1, isRoot);
2275                       SuperClassWriter::writeTimeAxisDataBounds(time_data_bound, timeAxisBoundId, isCollective, nstep - 1, isRoot);
2276                  }
2277                   if (wtimeCounter)
2278                   {
2279                     SuperClassWriter::writeTimeAxisData(time_counter, getTimeCounterName(), isCollective, nstep - 1,isRoot);
2280                     if (timeCounterType!=record) SuperClassWriter::writeTimeAxisDataBounds(time_counter_bound, timeBoundId, isCollective, nstep - 1, isRoot);
2281                   }
2282                   CTimer::get("Files : writing time axis").suspend();
2283                 }
2284                 break;
2285              }
2286              case (ONE_FILE) :
2287              {
2288
2289                std::vector<StdSize> start, count;
2290
2291                if (field->getUseCompressedOutput())
2292                {
2293                  CArray<int,1> axisDomainOrder = grid->axis_domain_order;
2294                  std::vector<StdString> domainList = grid->getDomainList();
2295                  std::vector<StdString> axisList   = grid->getAxisList();
2296                  int numElement = axisDomainOrder.numElements();
2297                  int idxDomain = domainList.size() - 1, idxAxis = axisList.size() - 1;
2298                  int idx = domainList.size() * 2 + axisList.size() - 1;
2299                  int commRank ;
2300
2301                  MPI_Comm_rank(comm_file,&commRank) ;
2302
2303                  start.reserve(idx+1);
2304                  count.reserve(idx+1);
2305
2306                  for (int i = numElement - 1; i >= 0; --i)
2307                  {
2308                    if (2 == axisDomainOrder(i))
2309                    {
2310                      CDomain* domain = CDomain::get(domainList[idxDomain]);
2311
2312                      if (domain->isCompressible())
2313                      {
2314                        size_t offset ;
2315                        size_t nbIndexes = domain->getLocalView(CElementView::WORKFLOW)->getSize() ;
2316                        if (domain->isDistributed())
2317                        {
2318                          MPI_Exscan(&nbIndexes, &offset, 1, MPI_SIZE_T, MPI_SUM, comm_file) ;
2319                          if (commRank==0) offset=0 ;
2320                        }
2321                        else offset=0 ;
2322
2323                        start.push_back(offset);
2324                        count.push_back(nbIndexes);
2325                        idx -= 2;
2326                      }
2327                      else
2328                      {
2329                        if ((domain->type) != CDomain::type_attr::unstructured)
2330                        {
2331                          start.push_back(domain->jbeginValue_);
2332                          count.push_back(domain->njValue_);
2333                        }
2334                        --idx;
2335                        start.push_back(domain->ibeginValue_);
2336                        count.push_back(domain->niValue_);
2337                        --idx;
2338                      }
2339                      --idxDomain;
2340                    }
2341                    else if (1 == axisDomainOrder(i))
2342                    {
2343                      CAxis* axis = CAxis::get(axisList[idxAxis]);
2344
2345                      if (axis->isCompressible())
2346                      {
2347                        size_t offset ;
2348                        size_t nbIndexes = axis->getLocalView(CElementView::WORKFLOW)->getSize() ;
2349                        if (axis->isDistributed())
2350                        {
2351                          MPI_Exscan(&nbIndexes, &offset, 1, MPI_SIZE_T, MPI_SUM, comm_file) ;
2352                          if (commRank==0) offset=0 ;
2353                        }
2354                        else offset=0 ;
2355
2356                        start.push_back(offset);
2357                        count.push_back(nbIndexes);
2358                      }
2359                      else
2360                      {
2361                        start.push_back(axis->begin);
2362                        count.push_back(axis->n);
2363                      }
2364                      --idxAxis;
2365                      --idx;
2366                    }
2367                  }
2368                }
2369                else
2370                {
2371                  CArray<int,1> axisDomainOrder = grid->axis_domain_order;
2372                  std::vector<StdString> domainList = grid->getDomainList();
2373                  std::vector<StdString> axisList   = grid->getAxisList();
2374                  std::vector<StdString> scalarList  = grid->getScalarList() ;
2375                  int numElement = axisDomainOrder.numElements();
2376                  int idxDomain = domainList.size() - 1 ;
2377                  int idxAxis = axisList.size() - 1 ;
2378                  int idxScalar = scalarList.size() - 1 ;
2379                  int idx = domainList.size() * 2 + axisList.size() - 1;
2380
2381                  start.reserve(idx+1);
2382                  count.reserve(idx+1);
2383
2384                  for (int i = numElement - 1; i >= 0; --i)
2385                  {
2386                    if (2 == axisDomainOrder(i))
2387                    {
2388                      CDomain* domain = CDomain::get(domainList[idxDomain]);
2389                      if ((domain->type) != CDomain::type_attr::unstructured)
2390                      {
2391                        start.push_back(domain->jbeginValue_);
2392                        count.push_back(domain->njValue_);
2393                      }
2394                      --idx ;
2395
2396                        start.push_back(domain->ibeginValue_);
2397                        count.push_back(domain->niValue_);
2398                      --idx ;
2399                      --idxDomain;
2400                    }
2401                    else if (1 == axisDomainOrder(i))
2402                    {
2403                        CAxis* axis = CAxis::get(axisList[idxAxis]);
2404                        start.push_back(axis->begin);
2405                        count.push_back(axis->n);
2406                      --idx;
2407                      --idxAxis;
2408                    }
2409                    else
2410                    {
2411                      if (idx ==-1) 
2412                      {
2413                        CScalar* scalar = CScalar::get(scalarList[idxScalar]);
2414                        start.push_back(0);
2415                        count.push_back(scalar->n);
2416                        idx-- ;
2417                      }
2418                      else if (idx<-1)
2419                      {
2420                        CScalar* scalar = CScalar::get(scalarList[idxScalar]);
2421                        count.back()*=scalar->n;
2422                        idx-- ;
2423                      }
2424                      --idxScalar;
2425                    }
2426                  }
2427                }
2428
2429
2430                CTimer::get("Files : writing data").resume();
2431                SuperClassWriter::writeData(data, fieldid, isCollective, nstep - 1, &start, &count);
2432                CTimer::get("Files : writing data").suspend();
2433
2434                 if (wtime)
2435                 {
2436                   CTimer::get("Files : writing time axis").resume();
2437                   if ( wtimeData)
2438                   {
2439                     SuperClassWriter::writeTimeAxisData(time_data, timeAxisId, isCollective, nstep - 1, isRoot);
2440                     SuperClassWriter::writeTimeAxisDataBounds(time_data_bound, timeAxisBoundId, isCollective, nstep - 1, isRoot);
2441                   }
2442                   if (wtimeCounter)
2443                   {
2444                     SuperClassWriter::writeTimeAxisData(time_counter, getTimeCounterName(), isCollective, nstep - 1,isRoot);
2445                     if (timeCounterType!=record) SuperClassWriter::writeTimeAxisDataBounds(time_counter_bound, timeBoundId, isCollective, nstep - 1, isRoot);
2446
2447                   }
2448                   CTimer::get("Files : writing time axis").suspend(); 
2449                 }
2450
2451                break;
2452              }
2453            }
2454            return nstep ;
2455         }
2456         catch (CNetCdfException& e)
2457         {
2458           StdString msg("On writing field data: ");
2459           msg.append(fieldid); msg.append("\n");
2460           msg.append("In the context : ");
2461           msg.append(context->getId()); msg.append("\n");
2462           msg.append(e.what());
2463           ERROR("CNc4DataOutput::writeFieldData_ (CField*  field)", << msg);
2464         }
2465      }
2466
2467      //---------------------------------------------------------------
2468
2469      void CNc4DataOutput::writeTimeAxis_
2470                  (CField*    field,
2471                   const std::shared_ptr<CCalendar> cal)
2472      {
2473         StdOStringStream oss;
2474         bool createInstantAxis=false ;
2475         bool createCenteredAxis=false ;
2476         bool createTimeCounterAxis=false ;
2477         
2478         if (field->getOperationTimeType() == func::CFunctor::once) return ;
2479
2480
2481         StdString axisId ;
2482         StdString axisBoundId;
2483         StdString timeid(getTimeCounterName());
2484         StdString timeBoundId("axis_nbounds");
2485
2486         StdString strTimeUnits ;
2487         if (!field->getRelFile()->time_units.isEmpty() && field->getRelFile()->time_units==CFile::time_units_attr::days) strTimeUnits="days since " ;
2488         else  strTimeUnits="seconds since " ;
2489 
2490         if (field->getOperationTimeType() == func::CFunctor::instant) field->hasTimeInstant = true;
2491         if (field->getOperationTimeType() == func::CFunctor::centered) field->hasTimeCentered = true;
2492
2493
2494         if (field->getRelFile()->time_counter.isEmpty())
2495         {
2496           if (timeCounterType==none) createTimeCounterAxis=true ;
2497           if (field->hasTimeCentered)
2498           {
2499             timeCounterType=centered ;
2500             if (!hasTimeCentered) createCenteredAxis=true ;
2501           }
2502           if (field->hasTimeInstant)
2503           {
2504             if (timeCounterType==none) timeCounterType=instant ;
2505             if (!hasTimeInstant) createInstantAxis=true ;
2506           }
2507         }
2508         else if (field->getRelFile()->time_counter==CFile::time_counter_attr::instant)
2509         {
2510           if (field->hasTimeCentered)
2511           {
2512             if (!hasTimeCentered) createCenteredAxis=true ;
2513           }
2514           if (field->hasTimeInstant)
2515           {
2516             if (timeCounterType==none) createTimeCounterAxis=true ;
2517             timeCounterType=instant ;
2518             if (!hasTimeInstant) createInstantAxis=true ;
2519           }
2520         }
2521         else if (field->getRelFile()->time_counter==CFile::time_counter_attr::centered)
2522         {
2523           if (field->hasTimeCentered)
2524           {
2525             if (timeCounterType==none) createTimeCounterAxis=true ;
2526             timeCounterType=centered ;
2527             if (!hasTimeCentered) createCenteredAxis=true ;
2528           }
2529           if (field->hasTimeInstant)
2530           {
2531             if (!hasTimeInstant) createInstantAxis=true ;
2532           }
2533         }
2534         else if (field->getRelFile()->time_counter==CFile::time_counter_attr::instant_exclusive)
2535         {
2536           if (field->hasTimeCentered)
2537           {
2538             if (!hasTimeCentered) createCenteredAxis=true ;
2539           }
2540           if (field->hasTimeInstant)
2541           {
2542             if (timeCounterType==none) createTimeCounterAxis=true ;
2543             timeCounterType=instant ;
2544           }
2545         }
2546         else if (field->getRelFile()->time_counter==CFile::time_counter_attr::centered_exclusive)
2547         {
2548           if (field->hasTimeCentered)
2549           {
2550             if (timeCounterType==none) createTimeCounterAxis=true ;
2551             timeCounterType=centered ;
2552           }
2553           if (field->hasTimeInstant)
2554           {
2555             if (!hasTimeInstant) createInstantAxis=true ;
2556           }
2557         }
2558         else if (field->getRelFile()->time_counter==CFile::time_counter_attr::exclusive)
2559         {
2560           if (field->hasTimeCentered)
2561           {
2562             if (timeCounterType==none) createTimeCounterAxis=true ;
2563             if (timeCounterType==instant) createInstantAxis=true ;
2564             timeCounterType=centered ;
2565           }
2566           if (field->hasTimeInstant)
2567           {
2568             if (timeCounterType==none)
2569             {
2570               createTimeCounterAxis=true ;
2571               timeCounterType=instant ;
2572             }
2573             if (timeCounterType==centered)
2574             {
2575               if (!hasTimeInstant) createInstantAxis=true ;
2576             }
2577           }
2578         }
2579         else if (field->getRelFile()->time_counter==CFile::time_counter_attr::none)
2580         {
2581           if (field->hasTimeCentered)
2582           {
2583             if (!hasTimeCentered) createCenteredAxis=true ;
2584           }
2585           if (field->hasTimeInstant)
2586           {
2587             if (!hasTimeInstant) createInstantAxis=true ;
2588           }
2589         }
2590         else if (field->getRelFile()->time_counter==CFile::time_counter_attr::record)
2591         {
2592           if (timeCounterType==none) createTimeCounterAxis=true ;
2593           timeCounterType=record ;
2594           if (field->hasTimeCentered)
2595           {
2596             if (!hasTimeCentered) createCenteredAxis=true ;
2597           }
2598           if (field->hasTimeInstant)
2599           {
2600             if (!hasTimeInstant) createInstantAxis=true ;
2601           }
2602         }
2603         
2604         if (createInstantAxis)
2605         {
2606           axisId="time_instant" ;
2607           axisBoundId="time_instant_bounds";
2608           hasTimeInstant=true ;
2609         }
2610
2611         if (createCenteredAxis)
2612         {
2613           axisId="time_centered" ;
2614           axisBoundId="time_centered_bounds";
2615           hasTimeCentered=true ;
2616         }
2617
2618         
2619         try
2620         {
2621            std::vector<StdString> dims;
2622           
2623            if (createInstantAxis || createCenteredAxis)
2624            {
2625              // Adding time_instant or time_centered
2626              dims.push_back(timeid);
2627              if (!SuperClassWriter::varExist(axisId))
2628              {
2629                SuperClassWriter::addVariable(axisId, NC_DOUBLE, dims);
2630
2631                CDate timeOrigin=cal->getTimeOrigin() ;
2632                StdOStringStream oss2;
2633                StdString strInitdate=oss2.str() ;
2634                StdString strTimeOrigin=timeOrigin.toString() ;
2635                this->writeTimeAxisAttributes(axisId, cal->getType(),strTimeUnits+strTimeOrigin,
2636                                              strTimeOrigin, axisBoundId);
2637             }
2638
2639             // Adding time_instant_bounds or time_centered_bounds variables
2640             if (!SuperClassWriter::varExist(axisBoundId))
2641             {
2642                dims.clear() ;
2643                dims.push_back(timeid);
2644                dims.push_back(timeBoundId);
2645                SuperClassWriter::addVariable(axisBoundId, NC_DOUBLE, dims);
2646             }
2647           }
2648
2649           if (createTimeCounterAxis)
2650           {
2651             // Adding time_counter
2652             axisId = getTimeCounterName();
2653             axisBoundId = getTimeCounterName() + "_bounds";
2654             dims.clear();
2655             dims.push_back(timeid);
2656             if (!SuperClassWriter::varExist(axisId))
2657             {
2658                SuperClassWriter::addVariable(axisId, NC_DOUBLE, dims);
2659                SuperClassWriter::addAttribute("axis", string("T"), &axisId);
2660
2661                if (field->getRelFile()->time_counter.isEmpty() || 
2662                   (field->getRelFile()->time_counter != CFile::time_counter_attr::record))
2663                {
2664                  CDate timeOrigin = cal->getTimeOrigin();
2665                  StdString strTimeOrigin = timeOrigin.toString();
2666
2667                  this->writeTimeAxisAttributes(axisId, cal->getType(),
2668                                                strTimeUnits+strTimeOrigin,
2669                                                strTimeOrigin, axisBoundId);
2670                }
2671             }
2672
2673             // Adding time_counter_bound dimension
2674             if (field->getRelFile()->time_counter.isEmpty() || (field->getRelFile()->time_counter != CFile::time_counter_attr::record))
2675             {
2676                if (!SuperClassWriter::varExist(axisBoundId))
2677                {
2678                  dims.clear();
2679                  dims.push_back(timeid);
2680                  dims.push_back(timeBoundId);
2681                  SuperClassWriter::addVariable(axisBoundId, NC_DOUBLE, dims);
2682                }
2683             }
2684           }
2685         }
2686         catch (CNetCdfException& e)
2687         {
2688           StdString msg("On writing time axis data: ");
2689           msg.append("In the context : ");
2690           CContext* context = CContext::getCurrent() ;
2691           msg.append(context->getId()); msg.append("\n");
2692           msg.append(e.what());
2693           ERROR("CNc4DataOutput::writeTimeAxis_ (CField*    field, \
2694                  const std::shared_ptr<CCalendar> cal)", << msg);
2695         }
2696      }
2697
2698      //---------------------------------------------------------------
2699
2700      void CNc4DataOutput::writeTimeAxisAttributes(const StdString & axis_name,
2701                                                   const StdString & calendar,
2702                                                   const StdString & units,
2703                                                   const StdString & time_origin,
2704                                                   const StdString & time_bounds,
2705                                                   const StdString & standard_name,
2706                                                   const StdString & long_name)
2707      {
2708         try
2709         {
2710           SuperClassWriter::addAttribute("standard_name", standard_name, &axis_name);
2711           SuperClassWriter::addAttribute("long_name",     long_name    , &axis_name);
2712           SuperClassWriter::addAttribute("calendar",      calendar     , &axis_name);
2713           SuperClassWriter::addAttribute("units",         units        , &axis_name);
2714           SuperClassWriter::addAttribute("time_origin",   time_origin  , &axis_name);
2715           SuperClassWriter::addAttribute("bounds",        time_bounds  , &axis_name);
2716         }
2717         catch (CNetCdfException& e)
2718         {
2719           StdString msg("On writing time axis Attribute: ");
2720           msg.append("In the context : ");
2721           CContext* context = CContext::getCurrent() ;
2722           msg.append(context->getId()); msg.append("\n");
2723           msg.append(e.what());
2724           ERROR("CNc4DataOutput::writeTimeAxisAttributes(const StdString & axis_name, \
2725                                                          const StdString & calendar,\
2726                                                          const StdString & units, \
2727                                                          const StdString & time_origin, \
2728                                                          const StdString & time_bounds, \
2729                                                          const StdString & standard_name, \
2730                                                          const StdString & long_name)", << msg);
2731         }
2732      }
2733
2734      //---------------------------------------------------------------
2735
2736      void CNc4DataOutput::writeAxisAttributes(const StdString & axis_name,
2737                                               const StdString & axis,
2738                                               const StdString & standard_name,
2739                                               const StdString & long_name,
2740                                               const StdString & units,
2741                                               const StdString & nav_model)
2742      {
2743         try
2744         {
2745          if (!axis.empty())
2746            SuperClassWriter::addAttribute("axis"       , axis         , &axis_name);
2747
2748          SuperClassWriter::addAttribute("standard_name", standard_name, &axis_name);
2749          SuperClassWriter::addAttribute("long_name"    , long_name    , &axis_name);
2750          SuperClassWriter::addAttribute("units"        , units        , &axis_name);
2751//          SuperClassWriter::addAttribute("nav_model"    , nav_model    , &axis_name);
2752         }
2753         catch (CNetCdfException& e)
2754         {
2755           StdString msg("On writing Axis Attribute: ");
2756           msg.append("In the context : ");
2757           CContext* context = CContext::getCurrent() ;
2758           msg.append(context->getId()); msg.append("\n");
2759           msg.append(e.what());
2760           ERROR("CNc4DataOutput::writeAxisAttributes(const StdString & axis_name, \
2761                                                      const StdString & axis, \
2762                                                      const StdString & standard_name, \
2763                                                      const StdString & long_name, \
2764                                                      const StdString & units, \
2765                                                      const StdString & nav_model)", << msg);
2766         }
2767      }
2768
2769      //---------------------------------------------------------------
2770
2771      void CNc4DataOutput::writeLocalAttributes
2772         (int ibegin, int ni, int jbegin, int nj, StdString domid)
2773      {
2774        try
2775        {
2776         SuperClassWriter::addAttribute(StdString("ibegin").append(domid), ibegin);
2777         SuperClassWriter::addAttribute(StdString("ni"    ).append(domid), ni);
2778         SuperClassWriter::addAttribute(StdString("jbegin").append(domid), jbegin);
2779         SuperClassWriter::addAttribute(StdString("nj"    ).append(domid), nj);
2780        }
2781        catch (CNetCdfException& e)
2782        {
2783           StdString msg("On writing Local Attributes: ");
2784           msg.append("In the context : ");
2785           CContext* context = CContext::getCurrent() ;
2786           msg.append(context->getId()); msg.append("\n");
2787           msg.append(e.what());
2788           ERROR("CNc4DataOutput::writeLocalAttributes \
2789                  (int ibegin, int ni, int jbegin, int nj, StdString domid)", << msg);
2790        }
2791
2792      }
2793
2794      void CNc4DataOutput::writeLocalAttributes_IOIPSL(const StdString& dimXid, const StdString& dimYid,
2795                                                       int ibegin, int ni, int jbegin, int nj, int ni_glo, int nj_glo, int rank, int size)
2796      {
2797         CArray<int,1> array(2) ;
2798
2799         try
2800         {
2801           SuperClassWriter::addAttribute("DOMAIN_number_total",size ) ;
2802           SuperClassWriter::addAttribute("DOMAIN_number", rank) ;
2803           array = SuperClassWriter::getDimension(dimXid) + 1, SuperClassWriter::getDimension(dimYid) + 1;
2804           SuperClassWriter::addAttribute("DOMAIN_dimensions_ids",array) ;
2805           array=ni_glo,nj_glo ;
2806           SuperClassWriter::addAttribute("DOMAIN_size_global", array) ;
2807           array=ni,nj ;
2808           SuperClassWriter::addAttribute("DOMAIN_size_local", array) ;
2809           array=ibegin+1,jbegin+1 ;
2810           SuperClassWriter::addAttribute("DOMAIN_position_first", array) ;
2811           array=ibegin+ni-1+1,jbegin+nj-1+1 ;
2812           SuperClassWriter::addAttribute("DOMAIN_position_last",array) ;
2813           array=0,0 ;
2814           SuperClassWriter::addAttribute("DOMAIN_halo_size_start", array) ;
2815           SuperClassWriter::addAttribute("DOMAIN_halo_size_end", array);
2816           SuperClassWriter::addAttribute("DOMAIN_type",string("box")) ;
2817  /*
2818           SuperClassWriter::addAttribute("DOMAIN_DIM_N001",string("x")) ;
2819           SuperClassWriter::addAttribute("DOMAIN_DIM_N002",string("y")) ;
2820           SuperClassWriter::addAttribute("DOMAIN_DIM_N003",string("axis_A")) ;
2821           SuperClassWriter::addAttribute("DOMAIN_DIM_N004",string("time_counter")) ;
2822  */
2823         }
2824         catch (CNetCdfException& e)
2825         {
2826           StdString msg("On writing Local Attributes IOIPSL \n");
2827           msg.append("In the context : ");
2828           CContext* context = CContext::getCurrent() ;
2829           msg.append(context->getId()); msg.append("\n");
2830           msg.append(e.what());
2831           ERROR("CNc4DataOutput::writeLocalAttributes_IOIPSL \
2832                  (int ibegin, int ni, int jbegin, int nj, int ni_glo, int nj_glo, int rank, int size)", << msg);
2833         }
2834      }
2835      //---------------------------------------------------------------
2836
2837      void CNc4DataOutput:: writeFileAttributes(const StdString & name,
2838                                                const StdString & description,
2839                                                const StdString & conventions,
2840                                                const StdString & production,
2841                                                const StdString & timeStamp)
2842      {
2843         try
2844         {
2845           SuperClassWriter::addAttribute("name"       , name);
2846           SuperClassWriter::addAttribute("description", description);
2847           SuperClassWriter::addAttribute("title"      , description);
2848           SuperClassWriter::addAttribute("Conventions", conventions);
2849           // SuperClassWriter::addAttribute("production" , production);
2850
2851           StdString timeStampStr ;
2852           if (file->time_stamp_name.isEmpty()) timeStampStr="timeStamp" ;
2853           else timeStampStr=file->time_stamp_name ;
2854           SuperClassWriter::addAttribute(timeStampStr, timeStamp);
2855
2856           StdString uuidName ;
2857           if (file->uuid_name.isEmpty()) uuidName="uuid" ;
2858           else uuidName=file->uuid_name ;
2859
2860           if (file->uuid_format.isEmpty()) SuperClassWriter::addAttribute(uuidName, getUuidStr());
2861           else SuperClassWriter::addAttribute(uuidName, getUuidStr(file->uuid_format));
2862         
2863         }
2864         catch (CNetCdfException& e)
2865         {
2866           StdString msg("On writing File Attributes \n ");
2867           msg.append("In the context : ");
2868           CContext* context = CContext::getCurrent() ;
2869           msg.append(context->getId()); msg.append("\n");
2870           msg.append(e.what());
2871           ERROR("CNc4DataOutput:: writeFileAttributes(const StdString & name, \
2872                                                const StdString & description, \
2873                                                const StdString & conventions, \
2874                                                const StdString & production, \
2875                                                const StdString & timeStamp)", << msg);
2876         }
2877      }
2878
2879      //---------------------------------------------------------------
2880
2881      void CNc4DataOutput::writeMaskAttributes(const StdString & mask_name,
2882                                               int data_dim,
2883                                               int data_ni,
2884                                               int data_nj,
2885                                               int data_ibegin,
2886                                               int data_jbegin)
2887      {
2888         try
2889         {
2890           SuperClassWriter::addAttribute("data_dim"   , data_dim   , &mask_name);
2891           SuperClassWriter::addAttribute("data_ni"    , data_ni    , &mask_name);
2892           SuperClassWriter::addAttribute("data_nj"    , data_nj    , &mask_name);
2893           SuperClassWriter::addAttribute("data_ibegin", data_ibegin, &mask_name);
2894           SuperClassWriter::addAttribute("data_jbegin", data_jbegin, &mask_name);
2895         }
2896         catch (CNetCdfException& e)
2897         {
2898           StdString msg("On writing Mask Attributes \n ");
2899           msg.append("In the context : ");
2900           CContext* context = CContext::getCurrent() ;
2901           msg.append(context->getId()); msg.append("\n");
2902           msg.append(e.what());
2903           ERROR("CNc4DataOutput::writeMaskAttributes(const StdString & mask_name, \
2904                                               int data_dim, \
2905                                               int data_ni, \
2906                                               int data_nj, \
2907                                               int data_ibegin, \
2908                                               int data_jbegin)", << msg);
2909         }
2910      }
2911
2912      ///--------------------------------------------------------------
2913
2914      StdSize CNc4DataOutput::getRecordFromTime(Time time, double factorUnit)
2915      {
2916        std::map<Time, StdSize>::const_iterator it = timeToRecordCache.find(time);
2917        if (it == timeToRecordCache.end())
2918        {
2919          StdString timeAxisBoundsId(getTimeCounterName() + "_bounds");
2920          if (!SuperClassWriter::varExist(timeAxisBoundsId)) timeAxisBoundsId = "time_centered_bounds";
2921          if (!SuperClassWriter::varExist(timeAxisBoundsId)) timeAxisBoundsId = "time_instant_bounds";
2922
2923          CArray<double,2> timeAxisBounds;
2924          std::vector<StdSize> dimSize(SuperClassWriter::getDimensions(timeAxisBoundsId)) ;
2925         
2926          StdSize record = 0;
2927          double dtime(time);
2928          for (int n = dimSize[0] - 1; n >= 0; n--)
2929          {
2930            SuperClassWriter::getTimeAxisBounds(timeAxisBounds, timeAxisBoundsId, isCollective, n);
2931            timeAxisBounds*=factorUnit ;
2932            if (timeAxisBounds(1, 0) < dtime)
2933            {
2934              record = n + 1;
2935              break;
2936            }
2937          }
2938          it = timeToRecordCache.insert(std::make_pair(time, record)).first;
2939        }
2940        return it->second;
2941      }
2942
2943      ///--------------------------------------------------------------
2944
2945      bool CNc4DataOutput::isWrittenDomain(const std::string& domainName) const
2946      {
2947        return (this->writtenDomains.find(domainName) != this->writtenDomains.end());
2948      }
2949
2950      bool CNc4DataOutput::isWrittenCompressedDomain(const std::string& domainName) const
2951      {
2952        return (this->writtenCompressedDomains.find(domainName) != this->writtenCompressedDomains.end());
2953      }
2954
2955      bool CNc4DataOutput::isWrittenAxis(const std::string& axisName) const
2956      {
2957        return (this->writtenAxis.find(axisName) != this->writtenAxis.end());
2958      }
2959
2960      bool CNc4DataOutput::isWrittenCompressedAxis(const std::string& axisName) const
2961      {
2962        return (this->writtenCompressedAxis.find(axisName) != this->writtenCompressedAxis.end());
2963      }
2964
2965      bool CNc4DataOutput::isWrittenScalar(const std::string& scalarName) const
2966      {
2967        return (this->writtenScalar.find(scalarName) != this->writtenScalar.end());
2968      }
2969
2970      void CNc4DataOutput::setWrittenDomain(const std::string& domainName)
2971      {
2972        this->writtenDomains.insert(domainName);
2973      }
2974
2975      void CNc4DataOutput::setWrittenCompressedDomain(const std::string& domainName)
2976      {
2977        this->writtenCompressedDomains.insert(domainName);
2978      }
2979
2980      void CNc4DataOutput::setWrittenAxis(const std::string& axisName)
2981      {
2982        this->writtenAxis.insert(axisName);
2983      }
2984
2985      void CNc4DataOutput::setWrittenCompressedAxis(const std::string& axisName)
2986      {
2987        this->writtenCompressedAxis.insert(axisName);
2988      }
2989
2990      void CNc4DataOutput::setWrittenScalar(const std::string& scalarName)
2991      {
2992        this->writtenScalar.insert(scalarName);
2993      }
2994} // namespace xios
Note: See TracBrowser for help on using the repository browser.