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

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

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

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