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

Last change on this file since 2559 was 2550, checked in by ymipsl, 10 months ago

Bug fix for multiple_file mode, update for one_file not had not been totally backported for multiple_file mode.
YM

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