source: XIOS/dev/XIOS_DEV_CMIP6/src/io/nc4_data_output.cpp @ 1494

Last change on this file since 1494 was 1494, checked in by oabramkina, 6 years ago

Bigfix for UGRID: fields describing the same mesh (= fields defined on domains with the same name) are sorted in the decreasing order of nvertex. The first, and the only, domain to be written is that with the highest value of nvertex. The entire mesh connectivity will be generated according to this domain.

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