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

Last change on this file since 1456 was 1456, checked in by ymipsl, 6 years ago

Add compression for lon, lat and axis.
Activated only if file attribute compression_level>0.

YM

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