source: XIOS2/trunk/src/io/nc4_data_output.cpp @ 2440

Last change on this file since 2440 was 2440, checked in by ymipsl, 19 months ago

Add bounds management for rectilinear domain.
First try.
YM

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