source: XIOS/dev/dev_ym/XIOS_COUPLING/src/io/nc4_data_output.cpp @ 2010

Last change on this file since 2010 was 1962, checked in by ymipsl, 4 years ago

Xios coupling
some cleaning...
YM

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