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

Last change on this file since 2381 was 2381, checked in by jderouillat, 2 years ago

Fix a bug on element names introduced in CGrid::duplicateSentGrid (commit 2351), the bug appeared with many grids in a file.

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