source: XIOS/dev/dev_olga/src/io/nc4_data_output.cpp @ 1590

Last change on this file since 1590 was 1590, checked in by oabramkina, 21 months ago

Backporting recent changes to dev before merging it to trunk.

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