source: XIOS2/trunk/src/io/nc4_data_output.cpp @ 2515

Last change on this file since 2515 was 2515, checked in by jderouillat, 13 months ago

Modified default fill values in UGRID (From A. Stirnemann)

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