source: XIOS3/dev/XIOS_ATTACHED/src/io/nc4_data_output.cpp @ 2482

Last change on this file since 2482 was 2482, checked in by ymipsl, 15 months ago

First guess in supression of attached mode replaced by online reader and write filters

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.0 KB
Line 
1#include "nc4_data_output.hpp"
2
3#include "attribute_template.hpp"
4#include "group_template.hpp"
5
6#include "file.hpp"
7#include "calendar.hpp"
8#include "context.hpp"
9#include "context_server.hpp"
10#include "netCdfException.hpp"
11#include "exception.hpp"
12#include "timer.hpp"
13#include "uuid.hpp"
14namespace xios
15{
16      /// ////////////////////// Dfinitions ////////////////////// ///
17      CNc4DataOutput::CNc4DataOutput
18         (CFile* file, const StdString & filename, bool exist)
19            : SuperClass()
20            , SuperClassWriter(filename, exist)
21            , filename(filename)
22            , file(file),hasTimeInstant(false),hasTimeCentered(false), timeCounterType(none), 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";
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);
1813
1814           if (!field->standard_name.isEmpty())
1815              SuperClassWriter::addAttribute
1816                 ("standard_name",  field->standard_name.getValue(), &fieldid);
1817
1818           if (!field->long_name.isEmpty())
1819              SuperClassWriter::addAttribute
1820                 ("long_name", field->long_name.getValue(), &fieldid);
1821
1822           if (!field->unit.isEmpty())
1823              SuperClassWriter::addAttribute
1824                 ("units", field->unit.getValue(), &fieldid);
1825
1826           // Ugrid field attributes "mesh" and "location"
1827           if (!SuperClassWriter::useCFConvention)
1828           {
1829            if (!domainList.empty())
1830            {
1831              CDomain* domain = CDomain::get(domainList[0]); // Suppose that we have only domain
1832              StdString mesh = domain->name;
1833              SuperClassWriter::addAttribute("mesh", mesh, &fieldid);
1834              StdString location;
1835              if (domain->nvertex == 1)
1836                location = "node";
1837              else if (domain->nvertex == 2)
1838                location = "edge";
1839              else if (domain->nvertex > 2)
1840                location = "face";
1841              SuperClassWriter::addAttribute("location", location, &fieldid);
1842            }
1843
1844           }
1845
1846           if (!field->valid_min.isEmpty())
1847              SuperClassWriter::addAttribute
1848                 ("valid_min", field->valid_min.getValue(), &fieldid);
1849
1850           if (!field->valid_max.isEmpty())
1851              SuperClassWriter::addAttribute
1852                 ("valid_max", field->valid_max.getValue(), &fieldid);
1853
1854            if (!field->scale_factor.isEmpty())
1855              SuperClassWriter::addAttribute
1856                 ("scale_factor", field->scale_factor.getValue(), &fieldid);
1857
1858             if (!field->add_offset.isEmpty())
1859              SuperClassWriter::addAttribute
1860                 ("add_offset", field->add_offset.getValue(), &fieldid);
1861
1862           SuperClassWriter::addAttribute
1863                 ("online_operation", field->operation.getValue(), &fieldid);
1864
1865          // write child variables as attributes
1866
1867
1868           bool alreadyAddCellMethod = false;
1869           StdString cellMethodsPrefix(""), cellMethodsSuffix("");
1870           if (!field->cell_methods.isEmpty())
1871           {
1872              StdString cellMethodString = field->cell_methods;
1873              if (field->cell_methods_mode.isEmpty() ||
1874                 (CField::cell_methods_mode_attr::overwrite == field->cell_methods_mode))
1875              {
1876                SuperClassWriter::addAttribute("cell_methods", cellMethodString, &fieldid);
1877                alreadyAddCellMethod = true;
1878              }
1879              else
1880              {
1881                switch (field->cell_methods_mode)
1882                {
1883                  case (CField::cell_methods_mode_attr::prefix):
1884                    cellMethodsPrefix = cellMethodString;
1885                    cellMethodsPrefix += " ";
1886                    break;
1887                  case (CField::cell_methods_mode_attr::suffix):
1888                    cellMethodsSuffix = " ";
1889                    cellMethodsSuffix += cellMethodString;
1890                    break;
1891                  case (CField::cell_methods_mode_attr::none):
1892                    break;
1893                  default:
1894                    break;
1895                }
1896              }
1897           }
1898
1899
1900           if (wtime)
1901           {
1902              CDuration freqOp = field->freq_op.getValue();
1903              freqOp.solveTimeStep(*context->calendar);
1904              StdString freqOpStr = freqOp.toStringUDUnits();
1905              SuperClassWriter::addAttribute("interval_operation", freqOpStr, &fieldid);
1906
1907              CDuration freqOut = field->getRelFile()->output_freq.getValue();
1908              freqOut.solveTimeStep(*context->calendar);
1909              SuperClassWriter::addAttribute("interval_write", freqOut.toStringUDUnits(), &fieldid);
1910
1911              StdString cellMethods(cellMethodsPrefix + "time: ");
1912              if (field->operation.getValue() == "instant") cellMethods += "point";
1913              else if (field->operation.getValue() == "average") cellMethods += "mean";
1914              else if (field->operation.getValue() == "accumulate") cellMethods += "sum";
1915              else cellMethods += field->operation;
1916              if (freqOp.resolve(*context->calendar) != freqOut.resolve(*context->calendar))
1917                cellMethods += " (interval: " + freqOpStr + ")";
1918              cellMethods += cellMethodsSuffix;
1919              if (!alreadyAddCellMethod)
1920                SuperClassWriter::addAttribute("cell_methods", cellMethods, &fieldid);
1921           }
1922
1923           if (hasArea)
1924             SuperClassWriter::addAttribute("cell_measures", cellMeasures, &fieldid);
1925
1926           if (!field->default_value.isEmpty())
1927           {
1928             double default_value = field->default_value.getValue();
1929             if (type == NC_DOUBLE)
1930             {
1931               SuperClassWriter::setDefaultValue(fieldid, &default_value);
1932             }
1933             else if (type == NC_SHORT)
1934             {
1935               short sdefault_value = (short)default_value;
1936               SuperClassWriter::setDefaultValue(fieldid, &sdefault_value);
1937             }
1938             else
1939             {
1940               float fdefault_value = (float)default_value;
1941               SuperClassWriter::setDefaultValue(fieldid, &fdefault_value);
1942             }
1943           }
1944           else
1945              SuperClassWriter::setDefaultValue(fieldid, (double*)NULL);
1946
1947            if (field->compression_level.isEmpty())
1948              field->compression_level = field->getRelFile()->compression_level.isEmpty() ? 0 : field->getRelFile()->compression_level;
1949            SuperClassWriter::setCompressionLevel(fieldid, field->compression_level);
1950
1951           {  // Ecriture des coordonnes
1952
1953              StdString coordstr; //boost::algorithm::join(coodinates, " ")
1954              std::vector<StdString>::iterator
1955                 itc = coodinates.begin(), endc = coodinates.end();
1956
1957              for (; itc!= endc; itc++)
1958              {
1959                 StdString & coord = *itc;
1960                 if (itc+1 != endc)
1961                       coordstr.append(coord).append(" ");
1962                 else  coordstr.append(coord);
1963              }
1964
1965              SuperClassWriter::addAttribute("coordinates", coordstr, &fieldid);
1966
1967           }
1968
1969           vector<CVariable*> listVars = field->getAllVariables() ;
1970           for (vector<CVariable*>::iterator it = listVars.begin() ;it != listVars.end(); it++) writeAttribute_(*it, fieldid) ;
1971
1972         }
1973         catch (CNetCdfException& e)
1974         {
1975           StdString msg("On writing field : ");
1976           msg.append(fieldid); msg.append("\n");
1977           msg.append("In the context : ");
1978           msg.append(context->getId()); msg.append("\n");
1979           msg.append(e.what());
1980           ERROR("CNc4DataOutput::writeField_(CField* field)", << msg);
1981         }
1982      } // writeField_()
1983
1984      //--------------------------------------------------------------
1985
1986      void CNc4DataOutput::writeFile_ (CFile* file)
1987      {
1988         StdString filename = file->getFileOutputName();
1989         StdString description = (!file->description.isEmpty())
1990                               ? file->description.getValue()
1991                               : StdString("Created by xios");
1992
1993         singleDomain = (file->nbDomains == 1);
1994
1995         StdString conv_str ;
1996         if (file->convention_str.isEmpty())
1997         {
1998            if (SuperClassWriter::useCFConvention) conv_str="CF-1.6" ;
1999            else conv_str="UGRID" ;
2000         }
2001         else conv_str=file->convention_str ;
2002           
2003         try
2004         {
2005           if (!appendMode) this->writeFileAttributes(filename, description,
2006                                                      conv_str,
2007                                                      StdString("An IPSL model"),
2008                                                      this->getTimeStamp());
2009
2010           if (!appendMode)
2011             SuperClassWriter::addDimension("axis_nbounds", 2);
2012         }
2013         catch (CNetCdfException& e)
2014         {
2015           StdString msg("On writing file : ");
2016           msg.append(filename); msg.append("\n");
2017           msg.append("In the context : ");
2018           CContext* context = CContext::getCurrent() ;
2019           msg.append(context->getId()); msg.append("\n");
2020           msg.append(e.what());
2021           ERROR("CNc4DataOutput::writeFile_ (CFile* file)", << msg);
2022         }
2023      }
2024
2025      void CNc4DataOutput::writeAttribute_ (CVariable* var, const string& fieldId)
2026      {
2027        StdString name = var->getVariableOutputName();
2028
2029        try
2030        {
2031          if (var->type.getValue() == CVariable::type_attr::t_int || var->type.getValue() == CVariable::type_attr::t_int32)
2032            addAttribute(name, var->getData<int>(), &fieldId);
2033          else if (var->type.getValue() == CVariable::type_attr::t_int16)
2034            addAttribute(name, var->getData<short int>(), &fieldId);
2035          else if (var->type.getValue() == CVariable::type_attr::t_float)
2036            addAttribute(name, var->getData<float>(), &fieldId);
2037          else if (var->type.getValue() == CVariable::type_attr::t_double)
2038            addAttribute(name, var->getData<double>(), &fieldId);
2039          else if (var->type.getValue() == CVariable::type_attr::t_string)
2040            addAttribute(name, var->getData<string>(), &fieldId);
2041          else
2042            ERROR("CNc4DataOutput::writeAttribute_ (CVariable* var, const string& fieldId)",
2043                  << "Unsupported variable of type " << var->type.getStringValue());
2044        }
2045       catch (CNetCdfException& e)
2046       {
2047         StdString msg("On writing attributes of variable with name : ");
2048         msg.append(name); msg.append("in the field "); msg.append(fieldId); msg.append("\n");
2049         msg.append("In the context : ");
2050         CContext* context = CContext::getCurrent() ;
2051         msg.append(context->getId()); msg.append("\n");
2052         msg.append(e.what());
2053         ERROR("CNc4DataOutput::writeAttribute_ (CVariable* var, const string& fieldId)", << msg);
2054       }
2055     }
2056
2057     void CNc4DataOutput::writeAttribute_ (CVariable* var)
2058     {
2059        StdString name = var->getVariableOutputName();
2060
2061        try
2062        {
2063          if (var->type.getValue() == CVariable::type_attr::t_int || var->type.getValue() == CVariable::type_attr::t_int32)
2064            addAttribute(name, var->getData<int>());
2065          else if (var->type.getValue() == CVariable::type_attr::t_int16)
2066            addAttribute(name, var->getData<short int>());
2067          else if (var->type.getValue() == CVariable::type_attr::t_float)
2068            addAttribute(name, var->getData<float>());
2069          else if (var->type.getValue() == CVariable::type_attr::t_double)
2070            addAttribute(name, var->getData<double>());
2071          else if (var->type.getValue() == CVariable::type_attr::t_string)
2072            addAttribute(name, var->getData<string>());
2073          else
2074            ERROR("CNc4DataOutput::writeAttribute_ (CVariable* var)",
2075                  << "Unsupported variable of type " << var->type.getStringValue());
2076        }
2077       catch (CNetCdfException& e)
2078       {
2079         StdString msg("On writing attributes of variable with name : ");
2080         msg.append(name); msg.append("\n");
2081         msg.append("In the context : ");
2082         CContext* context = CContext::getCurrent() ;
2083         msg.append(context->getId()); msg.append("\n");
2084         msg.append(e.what());
2085         ERROR("CNc4DataOutput::writeAttribute_ (CVariable* var)", << msg);
2086       }
2087     }
2088
2089      void CNc4DataOutput::syncFile_ (void)
2090      {
2091        try
2092        {
2093          SuperClassWriter::sync() ;
2094        }
2095        catch (CNetCdfException& e)
2096        {
2097         StdString msg("On synchronizing the write among processes");
2098         msg.append("In the context : ");
2099         CContext* context = CContext::getCurrent() ;
2100         msg.append(context->getId()); msg.append("\n");
2101         msg.append(e.what());
2102         ERROR("CNc4DataOutput::syncFile_ (void)", << msg);
2103        }
2104      }
2105
2106      void CNc4DataOutput::closeFile_ (void)
2107      {
2108        try
2109        {
2110          SuperClassWriter::close() ;
2111        }
2112        catch (CNetCdfException& e)
2113        {
2114         StdString msg("On closing file");
2115         msg.append("In the context : ");
2116         CContext* context = CContext::getCurrent() ;
2117         msg.append(context->getId()); msg.append("\n");
2118         msg.append(e.what());
2119         ERROR("CNc4DataOutput::syncFile_ (void)", << msg);
2120        }
2121
2122      }
2123
2124      //---------------------------------------------------------------
2125
2126      StdString CNc4DataOutput::getTimeStamp(void) const
2127      {
2128         const int buffer_size = 100;
2129         time_t rawtime;
2130         struct tm * timeinfo = NULL;
2131         char buffer [buffer_size];
2132         StdString formatStr;
2133         if (file->time_stamp_format.isEmpty()) formatStr="%Y-%b-%d %H:%M:%S %Z" ;
2134         else formatStr=file->time_stamp_format;
2135
2136//         time ( &rawtime );
2137//         timeinfo = localtime ( &rawtime );
2138         time ( &rawtime );
2139         timeinfo = gmtime ( &rawtime );
2140         strftime (buffer, buffer_size, formatStr.c_str(), timeinfo);
2141
2142         return (StdString(buffer));
2143      }
2144
2145      //---------------------------------------------------------------
2146
2147      int CNc4DataOutput::writeFieldData_ (CField*  field, const CArray<double,1>& data, const CDate& lastWrite,
2148                                           const CDate& currentWrite, int nstep)
2149      {
2150        CContext* context = CContext::getCurrent();
2151        CGrid* grid = field->getGrid();
2152       
2153        if (nstep<1) 
2154        {
2155          return nstep;
2156        }
2157       
2158        if (!grid->doGridHaveDataToWrite())
2159          if (SuperClass::type == MULTI_FILE || !isCollective)
2160          {
2161            return nstep;
2162          }
2163
2164        StdString fieldid = field->getFieldOutputName();
2165
2166        StdOStringStream oss;
2167        string timeAxisId;
2168        if (field->hasTimeInstant) timeAxisId = "time_instant";
2169        else if (field->hasTimeCentered) timeAxisId = "time_centered";
2170
2171        StdString timeBoundId = getTimeCounterName() + "_bounds";
2172
2173        StdString timeAxisBoundId;
2174        if (field->hasTimeInstant) timeAxisBoundId = "time_instant_bounds";
2175        else if (field->hasTimeCentered) timeAxisBoundId = "time_centered_bounds";
2176
2177        if (!field->wasWritten())
2178        {
2179          if (appendMode && field->getRelFile()->record_offset.isEmpty() && 
2180              field->getOperationTimeType() != func::CFunctor::once)
2181          {
2182            double factorUnit;
2183            if (!field->getRelFile()->time_units.isEmpty() && field->getRelFile()->time_units==CFile::time_units_attr::days)
2184            factorUnit=context->getCalendar()->getDayLengthInSeconds() ;
2185            else factorUnit=1 ;
2186            nstep = getRecordFromTime(currentWrite,factorUnit) + 1;
2187          }
2188
2189          field->setWritten();
2190        }
2191
2192
2193        CArray<double,1> time_data(1);
2194        CArray<double,1> time_data_bound(2);
2195        CArray<double,1> time_counter(1);
2196        CArray<double,1> time_counter_bound(2);
2197
2198        bool wtime = (field->getOperationTimeType() != func::CFunctor::once);
2199        bool wtimeCounter =false ;
2200        bool wtimeData =false ;
2201       
2202
2203        if (wtime)
2204        {
2205         
2206          if (field->hasTimeInstant)
2207          {
2208            time_data(0) = time_data_bound(1) = (Time) lastWrite;
2209            time_data_bound(0) = time_data_bound(1) = (Time) currentWrite;
2210            if (timeCounterType==instant)
2211            {
2212              time_counter(0) = time_data(0);
2213              time_counter_bound(0) = time_data_bound(0);
2214              time_counter_bound(1) = time_data_bound(1);
2215              wtimeCounter=true ;
2216            }
2217            if (hasTimeInstant) wtimeData=true ;
2218          }
2219          else if (field->hasTimeCentered)
2220          {
2221            time_data(0) = ((Time)currentWrite + (Time)lastWrite) / 2;
2222            time_data_bound(0) = (Time)lastWrite;
2223            time_data_bound(1) = (Time)currentWrite;
2224            if (timeCounterType==centered)
2225            {
2226              time_counter(0) = time_data(0) ;
2227              time_counter_bound(0) = time_data_bound(0) ;
2228              time_counter_bound(1) = time_data_bound(1) ;
2229              wtimeCounter=true ;
2230            }
2231            if (hasTimeCentered) wtimeData=true ;
2232          }
2233
2234          if (timeCounterType==record)
2235          {
2236            time_counter(0) = nstep - 1;
2237            time_counter_bound(0) = time_counter_bound(1) = nstep - 1;
2238            wtimeCounter=true ;
2239          }
2240
2241          if (!field->getRelFile()->time_units.isEmpty() && field->getRelFile()->time_units==CFile::time_units_attr::days)
2242          {
2243            double secByDay=context->getCalendar()->getDayLengthInSeconds() ;
2244            time_data/=secByDay;
2245            time_data_bound/=secByDay;
2246            time_counter/=secByDay;
2247            time_counter_bound/=secByDay;
2248          }
2249        }
2250
2251         bool isRoot = (context->intraCommRank_ == 0);
2252
2253         try
2254         {
2255           switch (SuperClass::type)
2256           {
2257              case (MULTI_FILE) :
2258              {
2259                 CTimer::get("Files : writing data").resume();
2260                 SuperClassWriter::writeData(data, fieldid, isCollective, nstep - 1);
2261                 CTimer::get("Files : writing data").suspend();
2262                 if (wtime)
2263                 {
2264                   CTimer::get("Files : writing time axis").resume();
2265                   if ( wtimeData)
2266                   {
2267                       SuperClassWriter::writeTimeAxisData(time_data, timeAxisId, isCollective, nstep - 1, isRoot);
2268                       SuperClassWriter::writeTimeAxisDataBounds(time_data_bound, timeAxisBoundId, isCollective, nstep - 1, isRoot);
2269                  }
2270                   if (wtimeCounter)
2271                   {
2272                     SuperClassWriter::writeTimeAxisData(time_counter, getTimeCounterName(), isCollective, nstep - 1,isRoot);
2273                     if (timeCounterType!=record) SuperClassWriter::writeTimeAxisDataBounds(time_counter_bound, timeBoundId, isCollective, nstep - 1, isRoot);
2274                   }
2275                   CTimer::get("Files : writing time axis").suspend();
2276                 }
2277                 break;
2278              }
2279              case (ONE_FILE) :
2280              {
2281
2282                std::vector<StdSize> start, count;
2283
2284                if (field->getUseCompressedOutput())
2285                {
2286                  CArray<int,1> axisDomainOrder = grid->axis_domain_order;
2287                  std::vector<StdString> domainList = grid->getDomainList();
2288                  std::vector<StdString> axisList   = grid->getAxisList();
2289                  int numElement = axisDomainOrder.numElements();
2290                  int idxDomain = domainList.size() - 1, idxAxis = axisList.size() - 1;
2291                  int idx = domainList.size() * 2 + axisList.size() - 1;
2292                  int commRank ;
2293
2294                  MPI_Comm_rank(comm_file,&commRank) ;
2295
2296                  start.reserve(idx+1);
2297                  count.reserve(idx+1);
2298
2299                  for (int i = numElement - 1; i >= 0; --i)
2300                  {
2301                    if (2 == axisDomainOrder(i))
2302                    {
2303                      CDomain* domain = CDomain::get(domainList[idxDomain]);
2304
2305                      if (domain->isCompressible())
2306                      {
2307                        size_t offset ;
2308                        size_t nbIndexes = domain->getLocalView(CElementView::WORKFLOW)->getSize() ;
2309                        if (domain->isDistributed())
2310                        {
2311                          MPI_Exscan(&nbIndexes, &offset, 1, MPI_SIZE_T, MPI_SUM, comm_file) ;
2312                          if (commRank==0) offset=0 ;
2313                        }
2314                        else offset=0 ;
2315
2316                        start.push_back(offset);
2317                        count.push_back(nbIndexes);
2318                        idx -= 2;
2319                      }
2320                      else
2321                      {
2322                        if ((domain->type) != CDomain::type_attr::unstructured)
2323                        {
2324                          start.push_back(domain->jbeginValue_);
2325                          count.push_back(domain->njValue_);
2326                        }
2327                        --idx;
2328                        start.push_back(domain->ibeginValue_);
2329                        count.push_back(domain->niValue_);
2330                        --idx;
2331                      }
2332                      --idxDomain;
2333                    }
2334                    else if (1 == axisDomainOrder(i))
2335                    {
2336                      CAxis* axis = CAxis::get(axisList[idxAxis]);
2337
2338                      if (axis->isCompressible())
2339                      {
2340                        size_t offset ;
2341                        size_t nbIndexes = axis->getLocalView(CElementView::WORKFLOW)->getSize() ;
2342                        if (axis->isDistributed())
2343                        {
2344                          MPI_Exscan(&nbIndexes, &offset, 1, MPI_SIZE_T, MPI_SUM, comm_file) ;
2345                          if (commRank==0) offset=0 ;
2346                        }
2347                        else offset=0 ;
2348
2349                        start.push_back(offset);
2350                        count.push_back(nbIndexes);
2351                      }
2352                      else
2353                      {
2354                        start.push_back(axis->begin);
2355                        count.push_back(axis->n);
2356                      }
2357                      --idxAxis;
2358                      --idx;
2359                    }
2360                  }
2361                }
2362                else
2363                {
2364                  CArray<int,1> axisDomainOrder = grid->axis_domain_order;
2365                  std::vector<StdString> domainList = grid->getDomainList();
2366                  std::vector<StdString> axisList   = grid->getAxisList();
2367                  std::vector<StdString> scalarList  = grid->getScalarList() ;
2368                  int numElement = axisDomainOrder.numElements();
2369                  int idxDomain = domainList.size() - 1 ;
2370                  int idxAxis = axisList.size() - 1 ;
2371                  int idxScalar = scalarList.size() - 1 ;
2372                  int idx = domainList.size() * 2 + axisList.size() - 1;
2373
2374                  start.reserve(idx+1);
2375                  count.reserve(idx+1);
2376
2377                  for (int i = numElement - 1; i >= 0; --i)
2378                  {
2379                    if (2 == axisDomainOrder(i))
2380                    {
2381                      CDomain* domain = CDomain::get(domainList[idxDomain]);
2382                      if ((domain->type) != CDomain::type_attr::unstructured)
2383                      {
2384                        start.push_back(domain->jbeginValue_);
2385                        count.push_back(domain->njValue_);
2386                      }
2387                      --idx ;
2388
2389                        start.push_back(domain->ibeginValue_);
2390                        count.push_back(domain->niValue_);
2391                      --idx ;
2392                      --idxDomain;
2393                    }
2394                    else if (1 == axisDomainOrder(i))
2395                    {
2396                        CAxis* axis = CAxis::get(axisList[idxAxis]);
2397                        start.push_back(axis->begin);
2398                        count.push_back(axis->n);
2399                      --idx;
2400                      --idxAxis;
2401                    }
2402                    else
2403                    {
2404                      if (idx ==-1) 
2405                      {
2406                        CScalar* scalar = CScalar::get(scalarList[idxScalar]);
2407                        start.push_back(0);
2408                        count.push_back(scalar->n);
2409                        idx-- ;
2410                      }
2411                      else if (idx<-1)
2412                      {
2413                        CScalar* scalar = CScalar::get(scalarList[idxScalar]);
2414                        count.back()*=scalar->n;
2415                        idx-- ;
2416                      }
2417                      --idxScalar;
2418                    }
2419                  }
2420                }
2421
2422
2423                CTimer::get("Files : writing data").resume();
2424                SuperClassWriter::writeData(data, fieldid, isCollective, nstep - 1, &start, &count);
2425                CTimer::get("Files : writing data").suspend();
2426
2427                 if (wtime)
2428                 {
2429                   CTimer::get("Files : writing time axis").resume();
2430                   if ( wtimeData)
2431                   {
2432                     SuperClassWriter::writeTimeAxisData(time_data, timeAxisId, isCollective, nstep - 1, isRoot);
2433                     SuperClassWriter::writeTimeAxisDataBounds(time_data_bound, timeAxisBoundId, isCollective, nstep - 1, isRoot);
2434                   }
2435                   if (wtimeCounter)
2436                   {
2437                     SuperClassWriter::writeTimeAxisData(time_counter, getTimeCounterName(), isCollective, nstep - 1,isRoot);
2438                     if (timeCounterType!=record) SuperClassWriter::writeTimeAxisDataBounds(time_counter_bound, timeBoundId, isCollective, nstep - 1, isRoot);
2439
2440                   }
2441                   CTimer::get("Files : writing time axis").suspend(); 
2442                 }
2443
2444                break;
2445              }
2446            }
2447            return nstep ;
2448         }
2449         catch (CNetCdfException& e)
2450         {
2451           StdString msg("On writing field data: ");
2452           msg.append(fieldid); msg.append("\n");
2453           msg.append("In the context : ");
2454           msg.append(context->getId()); msg.append("\n");
2455           msg.append(e.what());
2456           ERROR("CNc4DataOutput::writeFieldData_ (CField*  field)", << msg);
2457         }
2458      }
2459
2460      //---------------------------------------------------------------
2461
2462      void CNc4DataOutput::writeTimeAxis_
2463                  (CField*    field,
2464                   const std::shared_ptr<CCalendar> cal)
2465      {
2466         StdOStringStream oss;
2467         bool createInstantAxis=false ;
2468         bool createCenteredAxis=false ;
2469         bool createTimeCounterAxis=false ;
2470         
2471         if (field->getOperationTimeType() == func::CFunctor::once) return ;
2472
2473
2474         StdString axisId ;
2475         StdString axisBoundId;
2476         StdString timeid(getTimeCounterName());
2477         StdString timeBoundId("axis_nbounds");
2478
2479         StdString strTimeUnits ;
2480         if (!field->getRelFile()->time_units.isEmpty() && field->getRelFile()->time_units==CFile::time_units_attr::days) strTimeUnits="days since " ;
2481         else  strTimeUnits="seconds since " ;
2482 
2483         if (field->getOperationTimeType() == func::CFunctor::instant) field->hasTimeInstant = true;
2484         if (field->getOperationTimeType() == func::CFunctor::centered) field->hasTimeCentered = true;
2485
2486
2487         if (field->getRelFile()->time_counter.isEmpty())
2488         {
2489           if (timeCounterType==none) createTimeCounterAxis=true ;
2490           if (field->hasTimeCentered)
2491           {
2492             timeCounterType=centered ;
2493             if (!hasTimeCentered) createCenteredAxis=true ;
2494           }
2495           if (field->hasTimeInstant)
2496           {
2497             if (timeCounterType==none) timeCounterType=instant ;
2498             if (!hasTimeInstant) createInstantAxis=true ;
2499           }
2500         }
2501         else if (field->getRelFile()->time_counter==CFile::time_counter_attr::instant)
2502         {
2503           if (field->hasTimeCentered)
2504           {
2505             if (!hasTimeCentered) createCenteredAxis=true ;
2506           }
2507           if (field->hasTimeInstant)
2508           {
2509             if (timeCounterType==none) createTimeCounterAxis=true ;
2510             timeCounterType=instant ;
2511             if (!hasTimeInstant) createInstantAxis=true ;
2512           }
2513         }
2514         else if (field->getRelFile()->time_counter==CFile::time_counter_attr::centered)
2515         {
2516           if (field->hasTimeCentered)
2517           {
2518             if (timeCounterType==none) createTimeCounterAxis=true ;
2519             timeCounterType=centered ;
2520             if (!hasTimeCentered) createCenteredAxis=true ;
2521           }
2522           if (field->hasTimeInstant)
2523           {
2524             if (!hasTimeInstant) createInstantAxis=true ;
2525           }
2526         }
2527         else if (field->getRelFile()->time_counter==CFile::time_counter_attr::instant_exclusive)
2528         {
2529           if (field->hasTimeCentered)
2530           {
2531             if (!hasTimeCentered) createCenteredAxis=true ;
2532           }
2533           if (field->hasTimeInstant)
2534           {
2535             if (timeCounterType==none) createTimeCounterAxis=true ;
2536             timeCounterType=instant ;
2537           }
2538         }
2539         else if (field->getRelFile()->time_counter==CFile::time_counter_attr::centered_exclusive)
2540         {
2541           if (field->hasTimeCentered)
2542           {
2543             if (timeCounterType==none) createTimeCounterAxis=true ;
2544             timeCounterType=centered ;
2545           }
2546           if (field->hasTimeInstant)
2547           {
2548             if (!hasTimeInstant) createInstantAxis=true ;
2549           }
2550         }
2551         else if (field->getRelFile()->time_counter==CFile::time_counter_attr::exclusive)
2552         {
2553           if (field->hasTimeCentered)
2554           {
2555             if (timeCounterType==none) createTimeCounterAxis=true ;
2556             if (timeCounterType==instant) createInstantAxis=true ;
2557             timeCounterType=centered ;
2558           }
2559           if (field->hasTimeInstant)
2560           {
2561             if (timeCounterType==none)
2562             {
2563               createTimeCounterAxis=true ;
2564               timeCounterType=instant ;
2565             }
2566             if (timeCounterType==centered)
2567             {
2568               if (!hasTimeInstant) createInstantAxis=true ;
2569             }
2570           }
2571         }
2572         else if (field->getRelFile()->time_counter==CFile::time_counter_attr::none)
2573         {
2574           if (field->hasTimeCentered)
2575           {
2576             if (!hasTimeCentered) createCenteredAxis=true ;
2577           }
2578           if (field->hasTimeInstant)
2579           {
2580             if (!hasTimeInstant) createInstantAxis=true ;
2581           }
2582         }
2583         else if (field->getRelFile()->time_counter==CFile::time_counter_attr::record)
2584         {
2585           if (timeCounterType==none) createTimeCounterAxis=true ;
2586           timeCounterType=record ;
2587           if (field->hasTimeCentered)
2588           {
2589             if (!hasTimeCentered) createCenteredAxis=true ;
2590           }
2591           if (field->hasTimeInstant)
2592           {
2593             if (!hasTimeInstant) createInstantAxis=true ;
2594           }
2595         }
2596         
2597         if (createInstantAxis)
2598         {
2599           axisId="time_instant" ;
2600           axisBoundId="time_instant_bounds";
2601           hasTimeInstant=true ;
2602         }
2603
2604         if (createCenteredAxis)
2605         {
2606           axisId="time_centered" ;
2607           axisBoundId="time_centered_bounds";
2608           hasTimeCentered=true ;
2609         }
2610
2611         
2612         try
2613         {
2614            std::vector<StdString> dims;
2615           
2616            if (createInstantAxis || createCenteredAxis)
2617            {
2618              // Adding time_instant or time_centered
2619              dims.push_back(timeid);
2620              if (!SuperClassWriter::varExist(axisId))
2621              {
2622                SuperClassWriter::addVariable(axisId, NC_DOUBLE, dims);
2623
2624                CDate timeOrigin=cal->getTimeOrigin() ;
2625                StdOStringStream oss2;
2626                StdString strInitdate=oss2.str() ;
2627                StdString strTimeOrigin=timeOrigin.toString() ;
2628                this->writeTimeAxisAttributes(axisId, cal->getType(),strTimeUnits+strTimeOrigin,
2629                                              strTimeOrigin, axisBoundId);
2630             }
2631
2632             // Adding time_instant_bounds or time_centered_bounds variables
2633             if (!SuperClassWriter::varExist(axisBoundId))
2634             {
2635                dims.clear() ;
2636                dims.push_back(timeid);
2637                dims.push_back(timeBoundId);
2638                SuperClassWriter::addVariable(axisBoundId, NC_DOUBLE, dims);
2639             }
2640           }
2641
2642           if (createTimeCounterAxis)
2643           {
2644             // Adding time_counter
2645             axisId = getTimeCounterName();
2646             axisBoundId = getTimeCounterName() + "_bounds";
2647             dims.clear();
2648             dims.push_back(timeid);
2649             if (!SuperClassWriter::varExist(axisId))
2650             {
2651                SuperClassWriter::addVariable(axisId, NC_DOUBLE, dims);
2652                SuperClassWriter::addAttribute("axis", string("T"), &axisId);
2653
2654                if (field->getRelFile()->time_counter.isEmpty() || 
2655                   (field->getRelFile()->time_counter != CFile::time_counter_attr::record))
2656                {
2657                  CDate timeOrigin = cal->getTimeOrigin();
2658                  StdString strTimeOrigin = timeOrigin.toString();
2659
2660                  this->writeTimeAxisAttributes(axisId, cal->getType(),
2661                                                strTimeUnits+strTimeOrigin,
2662                                                strTimeOrigin, axisBoundId);
2663                }
2664             }
2665
2666             // Adding time_counter_bound dimension
2667             if (field->getRelFile()->time_counter.isEmpty() || (field->getRelFile()->time_counter != CFile::time_counter_attr::record))
2668             {
2669                if (!SuperClassWriter::varExist(axisBoundId))
2670                {
2671                  dims.clear();
2672                  dims.push_back(timeid);
2673                  dims.push_back(timeBoundId);
2674                  SuperClassWriter::addVariable(axisBoundId, NC_DOUBLE, dims);
2675                }
2676             }
2677           }
2678         }
2679         catch (CNetCdfException& e)
2680         {
2681           StdString msg("On writing time axis data: ");
2682           msg.append("In the context : ");
2683           CContext* context = CContext::getCurrent() ;
2684           msg.append(context->getId()); msg.append("\n");
2685           msg.append(e.what());
2686           ERROR("CNc4DataOutput::writeTimeAxis_ (CField*    field, \
2687                  const std::shared_ptr<CCalendar> cal)", << msg);
2688         }
2689      }
2690
2691      //---------------------------------------------------------------
2692
2693      void CNc4DataOutput::writeTimeAxisAttributes(const StdString & axis_name,
2694                                                   const StdString & calendar,
2695                                                   const StdString & units,
2696                                                   const StdString & time_origin,
2697                                                   const StdString & time_bounds,
2698                                                   const StdString & standard_name,
2699                                                   const StdString & long_name)
2700      {
2701         try
2702         {
2703           SuperClassWriter::addAttribute("standard_name", standard_name, &axis_name);
2704           SuperClassWriter::addAttribute("long_name",     long_name    , &axis_name);
2705           SuperClassWriter::addAttribute("calendar",      calendar     , &axis_name);
2706           SuperClassWriter::addAttribute("units",         units        , &axis_name);
2707           SuperClassWriter::addAttribute("time_origin",   time_origin  , &axis_name);
2708           SuperClassWriter::addAttribute("bounds",        time_bounds  , &axis_name);
2709         }
2710         catch (CNetCdfException& e)
2711         {
2712           StdString msg("On writing time axis Attribute: ");
2713           msg.append("In the context : ");
2714           CContext* context = CContext::getCurrent() ;
2715           msg.append(context->getId()); msg.append("\n");
2716           msg.append(e.what());
2717           ERROR("CNc4DataOutput::writeTimeAxisAttributes(const StdString & axis_name, \
2718                                                          const StdString & calendar,\
2719                                                          const StdString & units, \
2720                                                          const StdString & time_origin, \
2721                                                          const StdString & time_bounds, \
2722                                                          const StdString & standard_name, \
2723                                                          const StdString & long_name)", << msg);
2724         }
2725      }
2726
2727      //---------------------------------------------------------------
2728
2729      void CNc4DataOutput::writeAxisAttributes(const StdString & axis_name,
2730                                               const StdString & axis,
2731                                               const StdString & standard_name,
2732                                               const StdString & long_name,
2733                                               const StdString & units,
2734                                               const StdString & nav_model)
2735      {
2736         try
2737         {
2738          if (!axis.empty())
2739            SuperClassWriter::addAttribute("axis"       , axis         , &axis_name);
2740
2741          SuperClassWriter::addAttribute("standard_name", standard_name, &axis_name);
2742          SuperClassWriter::addAttribute("long_name"    , long_name    , &axis_name);
2743          SuperClassWriter::addAttribute("units"        , units        , &axis_name);
2744//          SuperClassWriter::addAttribute("nav_model"    , nav_model    , &axis_name);
2745         }
2746         catch (CNetCdfException& e)
2747         {
2748           StdString msg("On writing Axis Attribute: ");
2749           msg.append("In the context : ");
2750           CContext* context = CContext::getCurrent() ;
2751           msg.append(context->getId()); msg.append("\n");
2752           msg.append(e.what());
2753           ERROR("CNc4DataOutput::writeAxisAttributes(const StdString & axis_name, \
2754                                                      const StdString & axis, \
2755                                                      const StdString & standard_name, \
2756                                                      const StdString & long_name, \
2757                                                      const StdString & units, \
2758                                                      const StdString & nav_model)", << msg);
2759         }
2760      }
2761
2762      //---------------------------------------------------------------
2763
2764      void CNc4DataOutput::writeLocalAttributes
2765         (int ibegin, int ni, int jbegin, int nj, StdString domid)
2766      {
2767        try
2768        {
2769         SuperClassWriter::addAttribute(StdString("ibegin").append(domid), ibegin);
2770         SuperClassWriter::addAttribute(StdString("ni"    ).append(domid), ni);
2771         SuperClassWriter::addAttribute(StdString("jbegin").append(domid), jbegin);
2772         SuperClassWriter::addAttribute(StdString("nj"    ).append(domid), nj);
2773        }
2774        catch (CNetCdfException& e)
2775        {
2776           StdString msg("On writing Local Attributes: ");
2777           msg.append("In the context : ");
2778           CContext* context = CContext::getCurrent() ;
2779           msg.append(context->getId()); msg.append("\n");
2780           msg.append(e.what());
2781           ERROR("CNc4DataOutput::writeLocalAttributes \
2782                  (int ibegin, int ni, int jbegin, int nj, StdString domid)", << msg);
2783        }
2784
2785      }
2786
2787      void CNc4DataOutput::writeLocalAttributes_IOIPSL(const StdString& dimXid, const StdString& dimYid,
2788                                                       int ibegin, int ni, int jbegin, int nj, int ni_glo, int nj_glo, int rank, int size)
2789      {
2790         CArray<int,1> array(2) ;
2791
2792         try
2793         {
2794           SuperClassWriter::addAttribute("DOMAIN_number_total",size ) ;
2795           SuperClassWriter::addAttribute("DOMAIN_number", rank) ;
2796           array = SuperClassWriter::getDimension(dimXid) + 1, SuperClassWriter::getDimension(dimYid) + 1;
2797           SuperClassWriter::addAttribute("DOMAIN_dimensions_ids",array) ;
2798           array=ni_glo,nj_glo ;
2799           SuperClassWriter::addAttribute("DOMAIN_size_global", array) ;
2800           array=ni,nj ;
2801           SuperClassWriter::addAttribute("DOMAIN_size_local", array) ;
2802           array=ibegin+1,jbegin+1 ;
2803           SuperClassWriter::addAttribute("DOMAIN_position_first", array) ;
2804           array=ibegin+ni-1+1,jbegin+nj-1+1 ;
2805           SuperClassWriter::addAttribute("DOMAIN_position_last",array) ;
2806           array=0,0 ;
2807           SuperClassWriter::addAttribute("DOMAIN_halo_size_start", array) ;
2808           SuperClassWriter::addAttribute("DOMAIN_halo_size_end", array);
2809           SuperClassWriter::addAttribute("DOMAIN_type",string("box")) ;
2810  /*
2811           SuperClassWriter::addAttribute("DOMAIN_DIM_N001",string("x")) ;
2812           SuperClassWriter::addAttribute("DOMAIN_DIM_N002",string("y")) ;
2813           SuperClassWriter::addAttribute("DOMAIN_DIM_N003",string("axis_A")) ;
2814           SuperClassWriter::addAttribute("DOMAIN_DIM_N004",string("time_counter")) ;
2815  */
2816         }
2817         catch (CNetCdfException& e)
2818         {
2819           StdString msg("On writing Local Attributes IOIPSL \n");
2820           msg.append("In the context : ");
2821           CContext* context = CContext::getCurrent() ;
2822           msg.append(context->getId()); msg.append("\n");
2823           msg.append(e.what());
2824           ERROR("CNc4DataOutput::writeLocalAttributes_IOIPSL \
2825                  (int ibegin, int ni, int jbegin, int nj, int ni_glo, int nj_glo, int rank, int size)", << msg);
2826         }
2827      }
2828      //---------------------------------------------------------------
2829
2830      void CNc4DataOutput:: writeFileAttributes(const StdString & name,
2831                                                const StdString & description,
2832                                                const StdString & conventions,
2833                                                const StdString & production,
2834                                                const StdString & timeStamp)
2835      {
2836         try
2837         {
2838           SuperClassWriter::addAttribute("name"       , name);
2839           SuperClassWriter::addAttribute("description", description);
2840           SuperClassWriter::addAttribute("title"      , description);
2841           SuperClassWriter::addAttribute("Conventions", conventions);
2842           // SuperClassWriter::addAttribute("production" , production);
2843
2844           StdString timeStampStr ;
2845           if (file->time_stamp_name.isEmpty()) timeStampStr="timeStamp" ;
2846           else timeStampStr=file->time_stamp_name ;
2847           SuperClassWriter::addAttribute(timeStampStr, timeStamp);
2848
2849           StdString uuidName ;
2850           if (file->uuid_name.isEmpty()) uuidName="uuid" ;
2851           else uuidName=file->uuid_name ;
2852
2853           if (file->uuid_format.isEmpty()) SuperClassWriter::addAttribute(uuidName, getUuidStr());
2854           else SuperClassWriter::addAttribute(uuidName, getUuidStr(file->uuid_format));
2855         
2856         }
2857         catch (CNetCdfException& e)
2858         {
2859           StdString msg("On writing File Attributes \n ");
2860           msg.append("In the context : ");
2861           CContext* context = CContext::getCurrent() ;
2862           msg.append(context->getId()); msg.append("\n");
2863           msg.append(e.what());
2864           ERROR("CNc4DataOutput:: writeFileAttributes(const StdString & name, \
2865                                                const StdString & description, \
2866                                                const StdString & conventions, \
2867                                                const StdString & production, \
2868                                                const StdString & timeStamp)", << msg);
2869         }
2870      }
2871
2872      //---------------------------------------------------------------
2873
2874      void CNc4DataOutput::writeMaskAttributes(const StdString & mask_name,
2875                                               int data_dim,
2876                                               int data_ni,
2877                                               int data_nj,
2878                                               int data_ibegin,
2879                                               int data_jbegin)
2880      {
2881         try
2882         {
2883           SuperClassWriter::addAttribute("data_dim"   , data_dim   , &mask_name);
2884           SuperClassWriter::addAttribute("data_ni"    , data_ni    , &mask_name);
2885           SuperClassWriter::addAttribute("data_nj"    , data_nj    , &mask_name);
2886           SuperClassWriter::addAttribute("data_ibegin", data_ibegin, &mask_name);
2887           SuperClassWriter::addAttribute("data_jbegin", data_jbegin, &mask_name);
2888         }
2889         catch (CNetCdfException& e)
2890         {
2891           StdString msg("On writing Mask Attributes \n ");
2892           msg.append("In the context : ");
2893           CContext* context = CContext::getCurrent() ;
2894           msg.append(context->getId()); msg.append("\n");
2895           msg.append(e.what());
2896           ERROR("CNc4DataOutput::writeMaskAttributes(const StdString & mask_name, \
2897                                               int data_dim, \
2898                                               int data_ni, \
2899                                               int data_nj, \
2900                                               int data_ibegin, \
2901                                               int data_jbegin)", << msg);
2902         }
2903      }
2904
2905      ///--------------------------------------------------------------
2906
2907      StdSize CNc4DataOutput::getRecordFromTime(Time time, double factorUnit)
2908      {
2909        std::map<Time, StdSize>::const_iterator it = timeToRecordCache.find(time);
2910        if (it == timeToRecordCache.end())
2911        {
2912          StdString timeAxisBoundsId(getTimeCounterName() + "_bounds");
2913          if (!SuperClassWriter::varExist(timeAxisBoundsId)) timeAxisBoundsId = "time_centered_bounds";
2914          if (!SuperClassWriter::varExist(timeAxisBoundsId)) timeAxisBoundsId = "time_instant_bounds";
2915
2916          CArray<double,2> timeAxisBounds;
2917          std::vector<StdSize> dimSize(SuperClassWriter::getDimensions(timeAxisBoundsId)) ;
2918         
2919          StdSize record = 0;
2920          double dtime(time);
2921          for (int n = dimSize[0] - 1; n >= 0; n--)
2922          {
2923            SuperClassWriter::getTimeAxisBounds(timeAxisBounds, timeAxisBoundsId, isCollective, n);
2924            timeAxisBounds*=factorUnit ;
2925            if (timeAxisBounds(1, 0) < dtime)
2926            {
2927              record = n + 1;
2928              break;
2929            }
2930          }
2931          it = timeToRecordCache.insert(std::make_pair(time, record)).first;
2932        }
2933        return it->second;
2934      }
2935
2936      ///--------------------------------------------------------------
2937
2938      bool CNc4DataOutput::isWrittenDomain(const std::string& domainName) const
2939      {
2940        return (this->writtenDomains.find(domainName) != this->writtenDomains.end());
2941      }
2942
2943      bool CNc4DataOutput::isWrittenCompressedDomain(const std::string& domainName) const
2944      {
2945        return (this->writtenCompressedDomains.find(domainName) != this->writtenCompressedDomains.end());
2946      }
2947
2948      bool CNc4DataOutput::isWrittenAxis(const std::string& axisName) const
2949      {
2950        return (this->writtenAxis.find(axisName) != this->writtenAxis.end());
2951      }
2952
2953      bool CNc4DataOutput::isWrittenCompressedAxis(const std::string& axisName) const
2954      {
2955        return (this->writtenCompressedAxis.find(axisName) != this->writtenCompressedAxis.end());
2956      }
2957
2958      bool CNc4DataOutput::isWrittenScalar(const std::string& scalarName) const
2959      {
2960        return (this->writtenScalar.find(scalarName) != this->writtenScalar.end());
2961      }
2962
2963      void CNc4DataOutput::setWrittenDomain(const std::string& domainName)
2964      {
2965        this->writtenDomains.insert(domainName);
2966      }
2967
2968      void CNc4DataOutput::setWrittenCompressedDomain(const std::string& domainName)
2969      {
2970        this->writtenCompressedDomains.insert(domainName);
2971      }
2972
2973      void CNc4DataOutput::setWrittenAxis(const std::string& axisName)
2974      {
2975        this->writtenAxis.insert(axisName);
2976      }
2977
2978      void CNc4DataOutput::setWrittenCompressedAxis(const std::string& axisName)
2979      {
2980        this->writtenCompressedAxis.insert(axisName);
2981      }
2982
2983      void CNc4DataOutput::setWrittenScalar(const std::string& scalarName)
2984      {
2985        this->writtenScalar.insert(scalarName);
2986      }
2987} // namespace xios
Note: See TracBrowser for help on using the repository browser.