source: XIOS/dev/dev_ym/XIOS_COUPLING/src/io/nc4_data_output.cpp @ 1961

Last change on this file since 1961 was 1961, checked in by ymipsl, 4 years ago

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