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

Last change on this file since 2612 was 2600, checked in by jderouillat, 8 months ago

Add a field attribute, conversion_by_NetCDF, to operate type conversion in XIOS, and not in NetCDF

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