source: XIOS3/trunk/src/io/nc4_data_output.cpp @ 2542

Last change on this file since 2542 was 2542, checked in by ymipsl, 10 months ago

fix problem for instant value output, time axis was decaled of one record.
YM

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