source: XIOS/trunk/src/node/domain.cpp @ 878

Last change on this file since 878 was 878, checked in by oabramkina, 5 years ago

Sequential version for UGRID norms. File attribute "convention" has been added with two possible values "CF" and "UGRID". The default value is "CF".

  • 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: 70.8 KB
Line 
1#include "domain.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6
7#include "xios_spl.hpp"
8#include "event_client.hpp"
9#include "event_server.hpp"
10#include "buffer_in.hpp"
11#include "message.hpp"
12#include "type.hpp"
13#include "context.hpp"
14#include "context_client.hpp"
15#include "context_server.hpp"
16#include "array_new.hpp"
17#include "distribution_client.hpp"
18#include "server_distribution_description.hpp"
19#include "client_server_mapping_distributed.hpp"
20#include "zoom_domain.hpp"
21#include "interpolate_domain.hpp"
22#include "generate_rectilinear_domain.hpp"
23
24#include <algorithm>
25
26namespace xios {
27
28   /// ////////////////////// Définitions ////////////////////// ///
29
30   CDomain::CDomain(void)
31      : CObjectTemplate<CDomain>(), CDomainAttributes()
32      , isChecked(false), relFiles(), isClientChecked(false), nbConnectedClients_(), indSrv_(), connectedServerRank_()
33      , hasBounds(false), hasArea(false), isDistributed_(false), nGlobDomain_(), isCompressible_(false), isUnstructed_(false)
34      , isClientAfterTransformationChecked(false), hasLonLat(false)
35      , lonvalue_client(), latvalue_client(), bounds_lon_client(), bounds_lat_client()
36      , isRedistributed_(false)
37   {
38           mesh = new CMesh();
39        }
40
41   CDomain::CDomain(const StdString & id)
42      : CObjectTemplate<CDomain>(id), CDomainAttributes()
43      , isChecked(false), relFiles(), isClientChecked(false), nbConnectedClients_(), indSrv_(), connectedServerRank_()
44      , hasBounds(false), hasArea(false), isDistributed_(false), nGlobDomain_(), isCompressible_(false), isUnstructed_(false)
45      , isClientAfterTransformationChecked(false), hasLonLat(false)
46      , lonvalue_client(), latvalue_client(), bounds_lon_client(), bounds_lat_client()
47      , isRedistributed_(false)
48   {
49           mesh = new CMesh();
50        }
51
52   CDomain::~CDomain(void)
53   {
54           delete mesh;
55   }
56
57   ///---------------------------------------------------------------
58
59   CDomain* CDomain::createDomain()
60   {
61     CDomain* domain = CDomainGroup::get("domain_definition")->createChild();
62     return domain;
63   }
64
65   std::map<StdString, ETranformationType> CDomain::transformationMapList_ = std::map<StdString, ETranformationType>();
66   bool CDomain::_dummyTransformationMapList = CDomain::initializeTransformationMap(CDomain::transformationMapList_);
67
68   bool CDomain::initializeTransformationMap(std::map<StdString, ETranformationType>& m)
69   {
70     m["zoom_domain"] = TRANS_ZOOM_DOMAIN;
71     m["interpolate_domain"] = TRANS_INTERPOLATE_DOMAIN;
72     m["generate_rectilinear_domain"] = TRANS_GENERATE_RECTILINEAR_DOMAIN;
73   }
74
75   const std::set<StdString> & CDomain::getRelFiles(void) const
76   {
77      return (this->relFiles);
78   }
79
80 
81   const std::vector<int>& CDomain::getIndexesToWrite(void) const
82   {
83     return indexesToWrite;
84   }
85
86   /*!
87     Returns the number of indexes written by each server.
88     \return the number of indexes written by each server
89   */
90   int CDomain::getNumberWrittenIndexes() const
91   {
92     return numberWrittenIndexes_;
93   }
94
95   /*!
96     Returns the total number of indexes written by the servers.
97     \return the total number of indexes written by the servers
98   */
99   int CDomain::getTotalNumberWrittenIndexes() const
100   {
101     return totalNumberWrittenIndexes_;
102   }
103
104   /*!
105     Returns the offset of indexes written by each server.
106     \return the offset of indexes written by each server
107   */
108   int CDomain::getOffsetWrittenIndexes() const
109   {
110     return offsetWrittenIndexes_;
111   }
112
113   //----------------------------------------------------------------
114
115   /*!
116    * Compute the minimum buffer size required to send the attributes to the server(s).
117    *
118    * \return A map associating the server rank with its minimum buffer size.
119    */
120   std::map<int, StdSize> CDomain::getAttributesBufferSize()
121   {
122     CContextClient* client = CContext::getCurrent()->client;
123
124     std::map<int, StdSize> attributesSizes = getMinimumBufferSizeForAttributes();
125
126     if (client->isServerLeader())
127     {
128       // size estimation for sendServerAttribut
129       size_t size = 11 * sizeof(size_t);
130
131       const std::list<int>& ranks = client->getRanksServerLeader();
132       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
133       {
134         if (size > attributesSizes[*itRank])
135           attributesSizes[*itRank] = size;
136       }
137     }
138
139     std::map<int, std::vector<size_t> >::const_iterator itIndexEnd = indSrv_.end();
140     std::map<int, std::vector<int> >::const_iterator itWrittenIndexEnd = indWrittenSrv_.end();
141     for (size_t k = 0; k < connectedServerRank_.size(); ++k)
142     {
143       int rank = connectedServerRank_[k];
144       std::map<int, std::vector<size_t> >::const_iterator it = indSrv_.find(rank);
145       size_t idxCount = (it != itIndexEnd) ? it->second.size() : 0;
146
147       // size estimation for sendIndex (and sendArea which is always smaller or equal)
148       size_t sizeIndexEvent = 2 * sizeof(size_t) + 2 * CArray<int,1>::size(idxCount);
149       if (isCompressible_)
150       {
151         std::map<int, std::vector<int> >::const_iterator itWritten = indWrittenSrv_.find(rank);
152         size_t writtenIdxCount = (itWritten != itWrittenIndexEnd) ? itWritten->second.size() : 0;
153         sizeIndexEvent += CArray<int,1>::size(writtenIdxCount);
154       }
155
156       // size estimation for sendLonLat
157       size_t sizeLonLatEvent = CArray<double,1>::size(idxCount);
158       if (hasBounds)
159         sizeLonLatEvent += CArray<double,2>::size(nvertex * idxCount);
160
161       size_t size = CEventClient::headerSize + getId().size() + sizeof(size_t) + std::max(sizeIndexEvent, sizeLonLatEvent);
162       if (size > attributesSizes[rank])
163         attributesSizes[rank] = size;
164     }
165
166     return attributesSizes;
167   }
168
169   //----------------------------------------------------------------
170
171   bool CDomain::isEmpty(void) const
172   {
173      return ((this->zoom_ni_srv == 0) ||
174              (this->zoom_nj_srv == 0));
175   }
176
177   //----------------------------------------------------------------
178
179   bool CDomain::IsWritten(const StdString & filename) const
180   {
181      return (this->relFiles.find(filename) != this->relFiles.end());
182   }
183
184   bool CDomain::isWrittenCompressed(const StdString& filename) const
185   {
186      return (this->relFilesCompressed.find(filename) != this->relFilesCompressed.end());
187   }
188
189   //----------------------------------------------------------------
190
191   bool CDomain::isDistributed(void) const
192   {
193      return isDistributed_;
194   }
195
196   //----------------------------------------------------------------
197
198   /*!
199    * Test whether the data defined on the domain can be outputted in a compressed way.
200    *
201    * \return true if and only if a mask was defined for this domain
202    */
203   bool CDomain::isCompressible(void) const
204   {
205      return isCompressible_;
206   }
207
208   void CDomain::addRelFile(const StdString & filename)
209   {
210      this->relFiles.insert(filename);
211   }
212 
213   void CDomain::addRelFileCompressed(const StdString& filename)
214   {
215      this->relFilesCompressed.insert(filename);
216   }
217
218   StdString CDomain::GetName(void)   { return (StdString("domain")); }
219   StdString CDomain::GetDefName(void){ return (CDomain::GetName()); }
220   ENodeType CDomain::GetType(void)   { return (eDomain); }
221
222   //----------------------------------------------------------------
223
224   /*!
225     Redistribute RECTILINEAR domain with a number of local domains.
226   All attributes ni,nj,ibegin,jbegin (if defined) will be rewritten
227   The optional attributes lonvalue, latvalue will be added. Because this function only serves (for now)
228   for interpolation from unstructured domain to rectilinear one, range of latvalue is 0-360 and lonvalue is -90 - +90
229    \param [in] nbLocalDomain number of local domain on the domain destination
230   */
231   void CDomain::redistribute(int nbLocalDomain)
232   {
233     if (this->isRedistributed_) return;
234
235     this->isRedistributed_ = true;
236     CContext* context = CContext::getCurrent();
237     CContextClient* client = context->client;
238     int rankClient = client->clientRank;
239     int rankOnDomain = rankClient%nbLocalDomain;
240
241     if (ni_glo.isEmpty() || ni_glo <= 0 )
242     {
243        ERROR("CDomain::redistribute(int nbLocalDomain)",
244           << "[ Id = " << this->getId() << " ] "
245           << "The global domain is badly defined,"
246           << " check the \'ni_glo\'  value !")
247     }
248
249     if (nj_glo.isEmpty() || nj_glo <= 0 )
250     {
251        ERROR("CDomain::redistribute(int nbLocalDomain)",
252           << "[ Id = " << this->getId() << " ] "
253           << "The global domain is badly defined,"
254           << " check the \'nj_glo\'  value !")
255     }
256
257     if ((type_attr::rectilinear == type)  || (type_attr::curvilinear == type))
258     {
259        int globalDomainSize = ni_glo * nj_glo;
260        if (globalDomainSize <= nbLocalDomain)
261        {
262          for (int idx = 0; idx < nbLocalDomain; ++idx)
263          {
264            if (rankOnDomain < globalDomainSize)
265            {
266              int iIdx = rankOnDomain % ni_glo;
267              int jIdx = rankOnDomain / ni_glo;
268              ibegin.setValue(iIdx); jbegin.setValue(jIdx);
269              ni.setValue(1); nj.setValue(1);
270            }
271            else
272            {
273              ibegin.setValue(0); jbegin.setValue(0);
274              ni.setValue(0); nj.setValue(0);
275            }
276          }
277        }
278        else
279        {
280          float njGlo = nj_glo.getValue();
281          float niGlo = ni_glo.getValue();
282          int nbProcOnX, nbProcOnY, range;
283
284          // Compute (approximately) number of segment on x and y axis
285          float yOverXRatio = njGlo/niGlo;
286
287          nbProcOnX = std::ceil(std::sqrt(nbLocalDomain/yOverXRatio));
288          nbProcOnY = std::ceil(((float)nbLocalDomain)/nbProcOnX);
289
290          // Simple distribution: Sweep from top to bottom, left to right
291          // Calculate local begin on x
292          std::vector<int> ibeginVec(nbProcOnX,0), jbeginVec(nbProcOnY,0);
293          std::vector<int> niVec(nbProcOnX), njVec(nbProcOnY);
294          for (int i = 1; i < nbProcOnX; ++i)
295          {
296            range = ni_glo / nbProcOnX;
297            if (i < (ni_glo%nbProcOnX)) ++range;
298            niVec[i-1] = range;
299            ibeginVec[i] = ibeginVec[i-1] + niVec[i-1];
300          }
301          niVec[nbProcOnX-1] = ni_glo - ibeginVec[nbProcOnX-1];
302
303          // Calculate local begin on y
304          for (int j = 1; j < nbProcOnY; ++j)
305          {
306            range = nj_glo / nbProcOnY;
307            if (j < (nj_glo%nbProcOnY)) ++range;
308            njVec[j-1] = range;
309            jbeginVec[j] = jbeginVec[j-1] + njVec[j-1];
310          }
311          njVec[nbProcOnY-1] = nj_glo - jbeginVec[nbProcOnY-1];
312
313          // Now assign value to ni, ibegin, nj, jbegin
314          int iIdx = rankOnDomain % nbProcOnX;
315          int jIdx = rankOnDomain / nbProcOnX;
316
317          if (rankOnDomain != (nbLocalDomain-1))
318          {
319            ibegin.setValue(ibeginVec[iIdx]);
320            jbegin.setValue(jbeginVec[jIdx]);
321            nj.setValue(njVec[jIdx]);
322            ni.setValue(niVec[iIdx]);
323          }
324          else // just merge all the remaining rectangle into the last one
325          {
326            ibegin.setValue(ibeginVec[iIdx]);
327            jbegin.setValue(jbeginVec[jIdx]);
328            nj.setValue(njVec[jIdx]);
329            ni.setValue(ni_glo - ibeginVec[iIdx]);
330          }
331        }
332
333        // Now fill other attributes
334        if (type_attr::rectilinear == type) fillInRectilinearLonLat();
335     }
336     else  // unstructured domain
337     {
338       if (this->i_index.isEmpty())
339       {
340          int globalDomainSize = ni_glo * nj_glo;
341          if (globalDomainSize <= nbLocalDomain)
342          {
343            for (int idx = 0; idx < nbLocalDomain; ++idx)
344            {
345              if (rankOnDomain < globalDomainSize)
346              {
347                int iIdx = rankOnDomain % ni_glo;
348                int jIdx = rankOnDomain / ni_glo;
349                ibegin.setValue(iIdx); jbegin.setValue(jIdx);
350                ni.setValue(1); nj.setValue(1);
351              }
352              else
353              {
354                ibegin.setValue(0); jbegin.setValue(0);
355                ni.setValue(0); nj.setValue(0);
356              }
357            }
358          }
359          else
360          {
361            float njGlo = nj_glo.getValue();
362            float niGlo = ni_glo.getValue();
363            std::vector<int> ibeginVec(nbLocalDomain,0);
364            std::vector<int> niVec(nbLocalDomain);
365            for (int i = 1; i < nbLocalDomain; ++i)
366            {
367              int range = ni_glo / nbLocalDomain;
368              if (i < (ni_glo%nbLocalDomain)) ++range;
369              niVec[i-1] = range;
370              ibeginVec[i] = ibeginVec[i-1] + niVec[i-1];
371            }
372            niVec[nbLocalDomain-1] = ni_glo - ibeginVec[nbLocalDomain-1];
373
374            int iIdx = rankOnDomain % nbLocalDomain;
375            ibegin.setValue(ibeginVec[iIdx]);
376            jbegin.setValue(0);
377            ni.setValue(niVec[iIdx]);
378            nj.setValue(1);
379          }
380        }
381        else
382        {
383          ibegin.setValue(this->i_index(0));
384          jbegin.setValue(0);
385          ni.setValue(this->i_index.numElements());
386          nj.setValue(1);
387        }
388     }
389
390     checkDomain();
391   }
392
393   /*!
394     Fill in the values for lonvalue_1d and latvalue_1d of rectilinear domain
395     Range of longitude value from 0 - 360
396     Range of latitude value from -90 - +90
397   */
398   void CDomain::fillInRectilinearLonLat()
399   {
400     if (!lonvalue_rectilinear_read_from_file.isEmpty())
401     {
402       lonvalue_1d.resize(ni);
403       for (int idx = 0; idx < ni; ++idx)
404         lonvalue_1d(idx) = lonvalue_rectilinear_read_from_file(idx+ibegin);
405       lon_start.setValue(lonvalue_rectilinear_read_from_file(0));
406       lon_end.setValue(lonvalue_rectilinear_read_from_file(ni_glo-1));
407     }
408     else
409     {
410       if (!lonvalue_2d.isEmpty()) lonvalue_2d.free();
411       lonvalue_1d.resize(ni);
412       double lonRange = lon_end - lon_start;
413       double lonStep = (1 == ni_glo.getValue()) ? lonRange : lonRange/double(ni_glo.getValue()-1);
414
415        // Assign lon value
416       for (int i = 0; i < ni; ++i)
417       {
418         if (0 == (ibegin + i))
419         {
420           lonvalue_1d(i) = lon_start;
421         }
422         else if (ni_glo == (ibegin + i + 1))
423         {
424           lonvalue_1d(i) = lon_end;
425         }
426         else
427         {
428           lonvalue_1d(i) = (ibegin + i) * lonStep  + lon_start;
429         }
430       }
431     }
432
433
434     if (!latvalue_rectilinear_read_from_file.isEmpty())
435     {
436       latvalue_1d.resize(nj);
437       for (int idx = 0; idx < nj; ++idx)
438         latvalue_1d(idx) = latvalue_rectilinear_read_from_file(idx+jbegin);
439       lat_start.setValue(latvalue_rectilinear_read_from_file(0));
440       lat_end.setValue(latvalue_rectilinear_read_from_file(nj_glo-1));
441     }
442     else
443     {
444       if (!latvalue_2d.isEmpty()) latvalue_1d.free();
445       latvalue_1d.resize(nj);
446
447       double latRange = lat_end - lat_start;
448       double latStep = (1 == nj_glo.getValue()) ? latRange : latRange/double(nj_glo.getValue()-1);
449
450       for (int j = 0; j < nj; ++j)
451       {
452         if (0 == (jbegin + j))
453         {
454            latvalue_1d(j) = lat_start;
455         }
456         else if (nj_glo == (jbegin + j + 1))
457         {
458            latvalue_1d(j) = lat_end;
459         }
460         else
461         {
462           latvalue_1d(j) =  (jbegin + j) * latStep + lat_start;
463         }
464       }
465     }
466   }
467
468
469
470   void CDomain::AllgatherRectilinearLonLat(CArray<double,1>& lon, CArray<double,1>& lat, CArray<double,1>& lon_g, CArray<double,1>& lat_g)
471   {
472          CContext* context = CContext::getCurrent();
473      CContextClient* client = context->client;
474          lon_g.resize(ni_glo) ;
475          lat_g.resize(nj_glo) ;
476
477
478          int* ibegin_g = new int[client->clientSize] ;
479          int* jbegin_g = new int[client->clientSize] ;
480          int* ni_g = new int[client->clientSize] ;
481          int* nj_g = new int[client->clientSize] ;
482          int v ;
483          v=ibegin ;
484          MPI_Allgather(&v,1,MPI_INT,ibegin_g,1,MPI_INT,client->intraComm) ;
485          v=jbegin ;
486          MPI_Allgather(&v,1,MPI_INT,jbegin_g,1,MPI_INT,client->intraComm) ;
487          v=ni ;
488          MPI_Allgather(&v,1,MPI_INT,ni_g,1,MPI_INT,client->intraComm) ;
489          v=nj ;
490          MPI_Allgather(&v,1,MPI_INT,nj_g,1,MPI_INT,client->intraComm) ;
491
492          MPI_Allgatherv(lon.dataFirst(),ni,MPI_DOUBLE,lon_g.dataFirst(),ni_g, ibegin_g,MPI_DOUBLE,client->intraComm) ;
493          MPI_Allgatherv(lat.dataFirst(),nj,MPI_DOUBLE,lat_g.dataFirst(),nj_g, jbegin_g,MPI_DOUBLE,client->intraComm) ;
494
495      delete[] ibegin_g ;
496      delete[] jbegin_g ;
497      delete[] ni_g ;
498      delete[] nj_g ;
499   }
500
501   void CDomain::fillInRectilinearBoundLonLat(CArray<double,1>& lon, CArray<double,1>& lat,
502                                              CArray<double,2>& boundsLon, CArray<double,2>& boundsLat)
503   {
504     int i,j,k;
505
506     const int nvertexValue = 4;
507     boundsLon.resize(nvertexValue,ni*nj);
508
509     double lonStepStart = lon(1)-lon(0);
510     bounds_lon_start=lon(0) - lonStepStart/2;
511     double lonStepEnd = lon(ni_glo-1)-lon(ni_glo-2);
512     bounds_lon_end=lon(ni_glo-1) + lonStepEnd/2;
513     double errorBoundsLon = std::abs(360-std::abs(bounds_lon_end-bounds_lon_start));
514
515     // if errorBoundsLon is reasonably small (0.1 x cell size) consider it as closed in longitude
516     if (errorBoundsLon < std::abs(lonStepStart)*1e-1 || errorBoundsLon < std::abs(lonStepEnd)*1e-1 )
517     {
518       bounds_lon_start= (lon(0) + lon(ni_glo-1)-360)/2 ;
519       bounds_lon_end= (lon(0) +360 + lon(ni_glo-1))/2 ;
520     }
521
522     for(j=0;j<nj;++j)
523       for(i=0;i<ni;++i)
524       {
525         k=j*ni+i;
526         boundsLon(0,k) = boundsLon(1,k) = (0 == (ibegin + i)) ? bounds_lon_start
527                                                               : (lon(ibegin + i)+lon(ibegin + i-1))/2;
528         boundsLon(2,k) = boundsLon(3,k) = ((ibegin + i + 1) == ni_glo) ? bounds_lon_end
529                                                                        : (lon(ibegin + i + 1)+lon(ibegin + i))/2;
530       }
531
532
533    boundsLat.resize(nvertexValue,nj*ni);
534    bool isNorthPole=false ;
535    bool isSouthPole=false ;
536    if (std::abs(90 - std::abs(lat(0))) < NumTraits<double>::epsilon()) isNorthPole = true;
537    if (std::abs(90 - std::abs(lat(nj_glo-1))) < NumTraits<double>::epsilon()) isSouthPole = true;
538
539    // lat boundaries beyond pole the assimilate it to pole
540    // lat boundarie is relativelly close to pole (0.1 x cell size) assimilate it to pole
541    double latStepStart = lat(1)-lat(0);
542    if (isNorthPole) bounds_lat_start=lat(0);
543    else
544    {
545      bounds_lat_start=lat(0)-latStepStart/2;
546      if (bounds_lat_start >= 90 ) bounds_lat_start=90 ;
547      else if (bounds_lat_start <= -90 ) bounds_lat_start=-90 ;
548      else if (bounds_lat_start <= 90 && bounds_lat_start >= lat(0))
549      {
550        if ( std::abs(90-bounds_lat_start) <= 0.1*std::abs(latStepStart)) bounds_lat_start=90 ;
551      }
552      else if (bounds_lat_start >= -90 && bounds_lat_start <= lat(0))
553      {
554        if ( std::abs(-90 - bounds_lat_start) <= 0.1*std::abs(latStepStart)) bounds_lat_start=-90 ;
555      }
556    }
557
558    double latStepEnd = lat(nj_glo-1)-lat(nj_glo-2);
559    if (isSouthPole) bounds_lat_end=lat(nj_glo-1);
560    else
561    {
562      bounds_lat_end=lat(nj_glo-1)+latStepEnd/2;
563
564      if (bounds_lat_end >= 90 ) bounds_lat_end=90 ;
565      else if (bounds_lat_end <= -90 ) bounds_lat_end=-90 ;
566      else if (bounds_lat_end <= 90 && bounds_lat_end >= lat(nj_glo-1))
567      {
568        if ( std::abs(90-bounds_lat_end) <= 0.1*std::abs(latStepEnd)) bounds_lat_end=90 ;
569      }
570      else if (bounds_lat_end >= -90 && bounds_lat_end <= lat(nj_glo-1))
571      {
572        if ( std::abs(-90 - bounds_lat_end) <= 0.1*std::abs(latStepEnd)) bounds_lat_end=-90 ;
573      }
574    }
575
576    for(j=0;j<nj;++j)
577      for(i=0;i<ni;++i)
578      {
579        k=j*ni+i;
580        boundsLat(1,k) = boundsLat(2,k) = (0 == (jbegin + j)) ? bounds_lat_start
581                                                              : (lat(jbegin + j)+lat(jbegin + j-1))/2;
582        boundsLat(0,k) = boundsLat(3,k) = ((jbegin + j +1) == nj_glo) ? bounds_lat_end
583                                                                      : (lat(jbegin + j + 1)+lat(jbegin + j))/2;
584      }
585   }
586
587   void CDomain::checkDomain(void)
588   {
589     if (type.isEmpty())
590     {
591       ERROR("CDomain::checkDomain(void)",
592             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
593             << "The domain type is mandatory, "
594             << "please define the 'type' attribute.")
595     }
596
597     if (type == type_attr::unstructured)
598     {
599        if (ni_glo.isEmpty())
600        {
601          ERROR("CDomain::checkDomain(void)",
602                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
603                << "The global domain is badly defined, "
604                << "the mandatory 'ni_glo' attribute is missing.")
605        }
606        else if (ni_glo <= 0)
607        {
608          ERROR("CDomain::checkDomain(void)",
609                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
610                << "The global domain is badly defined, "
611                << "'ni_glo' attribute should be strictly positive so 'ni_glo = " << ni_glo.getValue() << "' is invalid.")
612        }
613        isUnstructed_ = true;
614        nj_glo = 1;
615        nj = 1;
616        jbegin = 0;
617        if (ni.isEmpty()) ni = i_index.numElements();
618        j_index.resize(ni);
619        for(int i=0;i<ni;++i) j_index(i)=0;
620
621        if (!area.isEmpty())
622          area.transposeSelf(1, 0);
623     }
624
625     if (ni_glo.isEmpty())
626     {
627       ERROR("CDomain::checkDomain(void)",
628             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
629             << "The global domain is badly defined, "
630             << "the mandatory 'ni_glo' attribute is missing.")
631     }
632     else if (ni_glo <= 0)
633     {
634       ERROR("CDomain::checkDomain(void)",
635             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
636             << "The global domain is badly defined, "
637             << "'ni_glo' attribute should be strictly positive so 'ni_glo = " << ni_glo.getValue() << "' is invalid.")
638     }
639
640     if (nj_glo.isEmpty())
641     {
642       ERROR("CDomain::checkDomain(void)",
643             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
644             << "The global domain is badly defined, "
645             << "the mandatory 'nj_glo' attribute is missing.")
646     }
647     else if (nj_glo <= 0)
648     {
649       ERROR("CDomain::checkDomain(void)",
650             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
651             << "The global domain is badly defined, "
652             << "'nj_glo' attribute should be strictly positive so 'nj_glo = " << nj_glo.getValue() << "' is invalid.")
653     }
654
655     isDistributed_ = !ibegin.isEmpty() || !ni.isEmpty() || !jbegin.isEmpty() || !nj.isEmpty();
656
657     checkLocalIDomain();
658     checkLocalJDomain();
659
660     if (i_index.isEmpty())
661     {
662       i_index.resize(ni*nj);
663       for (int j = 0; j < nj; ++j)
664         for (int i = 0; i < ni; ++i) i_index(i+j*ni) = i+ibegin;
665     }
666
667     if (j_index.isEmpty())
668     {
669       j_index.resize(ni*nj);
670       for (int j = 0; j < nj; ++j)
671         for (int i = 0; i < ni; ++i) j_index(i+j*ni) = j+jbegin;
672     }
673     computeNGlobDomain();
674     checkZoom();
675   }
676
677   void CDomain::checkZoom(void)
678   {
679     if (global_zoom_ibegin.isEmpty())
680      global_zoom_ibegin.setValue(0);
681     if (global_zoom_ni.isEmpty())
682      global_zoom_ni.setValue(ni_glo);
683     if (global_zoom_jbegin.isEmpty())
684      global_zoom_jbegin.setValue(0);
685     if (global_zoom_nj.isEmpty())
686      global_zoom_nj.setValue(nj_glo);
687   }
688
689   //----------------------------------------------------------------
690
691   void CDomain::checkLocalIDomain(void)
692   {
693      if (ibegin.isEmpty() && ni.isEmpty())
694      {
695        ibegin = 0;
696        ni = ni_glo;
697      }
698      else if (!i_index.isEmpty())
699      {
700        if (ibegin.isEmpty()) ibegin = i_index(0);
701      }
702
703      if (ni.getValue() < 0 || ibegin.getValue() < 0 ||
704         (ibegin.getValue() + ni.getValue()) > ni_glo.getValue())
705      {
706        ERROR("CDomain::checkLocalIDomain(void)",
707              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
708              << "The local domain is wrongly defined,"
709              << " check the attributes 'ni_glo' (" << ni_glo.getValue() << "), 'ni' (" << ni.getValue() << ") and 'ibegin' (" << ibegin.getValue() << ")");
710      }
711   }
712
713   void CDomain::checkLocalJDomain(void)
714   {
715     if (jbegin.isEmpty() && nj.isEmpty())
716     {
717       jbegin = 0;
718       nj = nj_glo;
719     }
720     else if (!j_index.isEmpty())
721     {
722       if (jbegin.isEmpty()) jbegin = j_index(0);
723     }
724
725      if (nj.getValue() < 0 || jbegin.getValue() < 0 ||
726         (jbegin.getValue() + nj.getValue()) > nj_glo.getValue())
727      {
728        ERROR("CDomain::checkLocalJDomain(void)",
729              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
730              << "The local domain is wrongly defined,"
731              << " check the attributes 'nj_glo' (" << nj_glo.getValue() << "), 'nj' (" << nj.getValue() << ") and 'jbegin' (" << jbegin.getValue() << ")");
732      }
733   }
734
735   //----------------------------------------------------------------
736
737   void CDomain::checkMask(void)
738   {
739      if (!mask_1d.isEmpty() && !mask_2d.isEmpty())
740        ERROR("CDomain::checkMask(void)",
741              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
742              << "Both mask_1d and mask_2d are defined but only one can be used at the same time." << std::endl
743              << "Please define only one mask: 'mask_1d' or 'mask_2d'.");
744
745      if (!mask_1d.isEmpty() && mask_2d.isEmpty())
746      {
747        if (mask_1d.numElements() != i_index.numElements())
748          ERROR("CDomain::checkMask(void)",
749                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
750                << "'mask_1d' does not have the same size as the local domain." << std::endl
751                << "Local size is " << i_index.numElements() << "." << std::endl
752                << "Mask size is " << mask_1d.numElements() << ".");
753      }
754
755      if (mask_1d.isEmpty() && !mask_2d.isEmpty())
756      {
757        if (mask_2d.extent(0) != ni || mask_2d.extent(1) != nj)
758          ERROR("CDomain::checkMask(void)",
759                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
760                << "The mask does not have the same size as the local domain." << std::endl
761                << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
762                << "Mask size is " << mask_2d.extent(0) << " x " << mask_2d.extent(1) << ".");
763      }
764
765      if (!mask_2d.isEmpty())
766      {
767        mask_1d.resize(mask_2d.extent(0) * mask_2d.extent(1));
768        for (int j = 0; j < nj; ++j)
769          for (int i = 0; i < ni; ++i) mask_1d(i+j*ni) = mask_2d(i,j);
770        mask_2d.reset();
771      }
772      else if (mask_1d.isEmpty())
773      {
774        mask_1d.resize(i_index.numElements());
775        for (int i = 0; i < i_index.numElements(); ++i) mask_1d(i) = true;
776      }
777   }
778
779   //----------------------------------------------------------------
780
781   void CDomain::checkDomainData(void)
782   {
783      if (data_dim.isEmpty())
784      {
785        data_dim.setValue(1);
786      }
787      else if (!(data_dim.getValue() == 1 || data_dim.getValue() == 2))
788      {
789        ERROR("CDomain::checkDomainData(void)",
790              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
791              << "The data dimension is invalid, 'data_dim' must be 1 or 2 not << " << data_dim.getValue() << ".");
792      }
793
794      if (data_ibegin.isEmpty())
795         data_ibegin.setValue(0);
796      if (data_jbegin.isEmpty())
797         data_jbegin.setValue(0);
798
799      if (data_ni.isEmpty())
800      {
801        data_ni.setValue((data_dim == 1) ? (ni.getValue() * nj.getValue()) : ni.getValue());
802      }
803      else if (data_ni.getValue() < 0)
804      {
805        ERROR("CDomain::checkDomainData(void)",
806              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
807              << "The data size cannot be negative ('data_ni' = " << data_ni.getValue() << ").");
808      }
809
810      if (data_nj.isEmpty())
811      {
812        data_nj.setValue((data_dim.getValue() == 1) ? (ni.getValue() * nj.getValue()) : nj.getValue());
813      }
814      else if (data_nj.getValue() < 0)
815      {
816        ERROR("CDomain::checkDomainData(void)",
817              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
818              << "The data size cannot be negative ('data_nj' = " << data_nj.getValue() << ").");
819      }
820   }
821
822   //----------------------------------------------------------------
823
824   void CDomain::checkCompression(void)
825   {
826      if (!data_i_index.isEmpty())
827      {
828        if (!data_j_index.isEmpty() &&
829            data_j_index.numElements() != data_i_index.numElements())
830        {
831           ERROR("CDomain::checkCompression(void)",
832                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
833                 << "'data_i_index' and 'data_j_index' arrays must have the same size." << std::endl
834                 << "'data_i_index' size = " << data_i_index.numElements() << std::endl
835                 << "'data_j_index' size = " << data_j_index.numElements());
836        }
837
838        if (2 == data_dim)
839        {
840          if (data_j_index.isEmpty())
841          {
842             ERROR("CDomain::checkCompression(void)",
843                   << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
844                   << "'data_j_index' must be defined when 'data_i_index' is set and 'data_dim' is 2.");
845          }
846        }
847        else // (1 == data_dim)
848        {
849          if (data_j_index.isEmpty())
850          {
851            data_j_index.resize(data_ni);
852            for (int j = 0; j < data_ni; ++j) data_j_index(j) = 0;
853          }
854        }
855      }
856      else
857      {
858        if (data_dim == 2 && !data_j_index.isEmpty())
859          ERROR("CDomain::checkCompression(void)",
860                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
861                << "'data_i_index' must be defined when 'data_j_index' is set and 'data_dim' is 2.");
862
863        if (1 == data_dim)
864        {
865          data_i_index.resize(data_ni);
866          data_j_index.resize(data_ni);
867
868          for (int i = 0; i < data_ni; ++i)
869          {
870            data_i_index(i) = i;
871            data_j_index(i) = 0;
872          }
873        }
874        else // (data_dim == 2)
875        {
876          const int dsize = data_ni * data_nj;
877          data_i_index.resize(dsize);
878          data_j_index.resize(dsize);
879
880          for(int count = 0, j = 0; j < data_nj; ++j)
881          {
882            for(int i = 0; i < data_ni; ++i, ++count)
883            {
884              data_i_index(count) = i;
885              data_j_index(count) = j;
886            }
887          }
888        }
889      }
890   }
891
892   //----------------------------------------------------------------
893
894   void CDomain::checkEligibilityForCompressedOutput(void)
895   {
896     // We don't check if the mask or the indexes are valid here, just if they have been defined at this point.
897     isCompressible_ = !mask_1d.isEmpty() || !mask_2d.isEmpty() || !data_i_index.isEmpty();
898   }
899
900   //----------------------------------------------------------------
901
902   void CDomain::completeLonLatClient(void)
903   {
904     if (!lonvalue_2d.isEmpty())
905     {
906       lonvalue_client.resize(ni * nj);
907       latvalue_client.resize(ni * nj);
908       if (hasBounds)
909       {
910         bounds_lon_client.resize(nvertex, ni * nj);
911         bounds_lat_client.resize(nvertex, ni * nj);
912       }
913
914       for (int j = 0; j < nj; ++j)
915       {
916         for (int i = 0; i < ni; ++i)
917         {
918           int k = j * ni + i;
919
920           lonvalue_client(k) = lonvalue_2d(i,j);
921           latvalue_client(k) = latvalue_2d(i,j);
922
923           if (hasBounds)
924           {
925             for (int n = 0; n < nvertex; ++n)
926             {
927               bounds_lon_client(n,k) = bounds_lon_2d(n,i,j);
928               bounds_lat_client(n,k) = bounds_lat_2d(n,i,j);
929             }
930           }
931         }
932       }
933     }
934     else if (!lonvalue_1d.isEmpty())
935     {
936       if (type_attr::rectilinear == type)
937       {
938         if (ni == lonvalue_1d.numElements() && nj == latvalue_1d.numElements())
939         {
940           lonvalue_client.resize(ni * nj);
941           latvalue_client.resize(ni * nj);
942           if (hasBounds)
943           {
944             bounds_lon_client.resize(nvertex, ni * nj);
945             bounds_lat_client.resize(nvertex, ni * nj);
946           }
947
948           for (int j = 0; j < nj; ++j)
949           {
950             for (int i = 0; i < ni; ++i)
951             {
952               int k = j * ni + i;
953
954               lonvalue_client(k) = lonvalue_1d(i);
955               latvalue_client(k) = latvalue_1d(j);
956
957               if (hasBounds)
958               {
959                 for (int n = 0; n < nvertex; ++n)
960                 {
961                   bounds_lon_client(n,k) = bounds_lon_1d(n,i);
962                   bounds_lat_client(n,k) = bounds_lat_1d(n,j);
963                 }
964               }
965             }
966           }
967         }
968         else
969           ERROR("CDomain::completeLonClient(void)",
970                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
971                 << "'lonvalue_1d' and 'latvalue_1d' does not have the same size as the local domain." << std::endl
972                 << "'lonvalue_1d' size is " << lonvalue_1d.numElements() << " but it should be " << ni.getValue() << '.' << std::endl
973                 << "'latvalue_1d' size is " << latvalue_1d.numElements() << " but it should be " << nj.getValue() << '.');
974       }
975       else if (type == type_attr::curvilinear || type == type_attr::unstructured)
976       {
977         lonvalue_client.reference(lonvalue_1d);
978         latvalue_client.reference(latvalue_1d);
979         if (hasBounds)
980         {
981           bounds_lon_client.reference(bounds_lon_1d);
982           bounds_lat_client.reference(bounds_lat_1d);
983         }
984       }
985     }
986   }
987
988   void CDomain::checkBounds(void)
989   {
990     if (!nvertex.isEmpty() && nvertex > 0)
991     {
992       if (!bounds_lon_1d.isEmpty() && !bounds_lon_2d.isEmpty())
993         ERROR("CDomain::checkBounds(void)",
994               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
995               << "Only one longitude boundary attribute can be used but both 'bounds_lon_1d' and 'bounds_lon_2d' are defined." << std::endl
996               << "Define only one longitude boundary attribute: 'bounds_lon_1d' or 'bounds_lon_2d'.");
997
998       if (!bounds_lat_1d.isEmpty() && !bounds_lat_2d.isEmpty())
999         ERROR("CDomain::checkBounds(void)",
1000               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1001               << "Only one latitude boundary attribute can be used but both 'bounds_lat_1d' and 'bounds_lat_2d' are defined." << std::endl
1002               << "Define only one latitude boundary attribute: 'bounds_lat_1d' or 'bounds_lat_2d'.");
1003
1004       if ((!bounds_lon_1d.isEmpty() && bounds_lat_1d.isEmpty()) || (bounds_lon_1d.isEmpty() && !bounds_lat_1d.isEmpty()))
1005       {
1006         ERROR("CDomain::checkBounds(void)",
1007               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1008               << "Only 'bounds_lon_1d' or 'bounds_lat_1d' is defined." << std::endl
1009               << "Please define either both attributes or none.");
1010       }
1011
1012       if ((!bounds_lon_2d.isEmpty() && bounds_lat_2d.isEmpty()) || (bounds_lon_2d.isEmpty() && !bounds_lat_2d.isEmpty()))
1013       {
1014         ERROR("CDomain::checkBounds(void)",
1015               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1016               << "Only 'bounds_lon_2d' or 'bounds_lat_2d' is defined." << std::endl
1017               << "Please define either both attributes or none.");
1018       }
1019
1020       if (!bounds_lon_1d.isEmpty() && nvertex.getValue() != bounds_lon_1d.extent(0))
1021         ERROR("CDomain::checkBounds(void)",
1022               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1023               << "'bounds_lon_1d' dimension is not compatible with 'nvertex'." << std::endl
1024               << "'bounds_lon_1d' dimension is " << bounds_lon_1d.extent(1)
1025               << " but nvertex is " << nvertex.getValue() << ".");
1026
1027       if (!bounds_lon_2d.isEmpty() && nvertex.getValue() != bounds_lon_2d.extent(0))
1028         ERROR("CDomain::checkBounds(void)",
1029               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1030               << "'bounds_lon_2d' dimension is not compatible with 'nvertex'." << std::endl
1031               << "'bounds_lon_2d' dimension is " << bounds_lon_2d.extent(2)
1032               << " but nvertex is " << nvertex.getValue() << ".");
1033
1034       if (!bounds_lon_1d.isEmpty() && lonvalue_1d.isEmpty())
1035         ERROR("CDomain::checkBounds(void)",
1036               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1037               << "Since 'bounds_lon_1d' is defined, 'lonvalue_1d' must be defined too." << std::endl);
1038
1039       if (!bounds_lon_2d.isEmpty() && lonvalue_2d.isEmpty())
1040         ERROR("CDomain::checkBounds(void)",
1041               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1042               << "Since 'bounds_lon_2d' is defined, 'lonvalue_2d' must be defined too." << std::endl);
1043
1044       if (!bounds_lat_1d.isEmpty() && nvertex.getValue() != bounds_lat_1d.extent(0))
1045         ERROR("CDomain::checkBounds(void)",
1046               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1047               << "'bounds_lat_1d' dimension is not compatible with 'nvertex'." << std::endl
1048               << "'bounds_lat_1d' dimension is " << bounds_lat_1d.extent(1)
1049               << " but nvertex is " << nvertex.getValue() << ".");
1050
1051       if (!bounds_lat_2d.isEmpty() && nvertex.getValue() != bounds_lat_2d.extent(0))
1052         ERROR("CDomain::checkBounds(void)",
1053               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1054               << "'bounds_lat_2d' dimension is not compatible with 'nvertex'." << std::endl
1055               << "'bounds_lat_2d' dimension is " << bounds_lat_2d.extent(2)
1056               << " but nvertex is " << nvertex.getValue() << ".");
1057
1058       if (!bounds_lat_1d.isEmpty() && latvalue_1d.isEmpty())
1059         ERROR("CDomain::checkBounds(void)",
1060               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1061               << "Since 'bounds_lat_1d' is defined, 'latvalue_1d' must be defined too." << std::endl);
1062
1063       if (!bounds_lat_2d.isEmpty() && latvalue_2d.isEmpty())
1064         ERROR("CDomain::checkBounds(void)",
1065               << "Since 'bounds_lat_2d' is defined, 'latvalue_2d' must be defined too." << std::endl);
1066
1067       hasBounds = true;
1068     }
1069     else
1070     {
1071       hasBounds = false;
1072       nvertex = 0;
1073     }
1074   }
1075
1076   void CDomain::checkArea(void)
1077   {
1078     hasArea = !area.isEmpty();
1079     if (hasArea)
1080     {
1081       if (area.extent(0) != ni || area.extent(1) != nj)
1082       {
1083         ERROR("CDomain::checkArea(void)",
1084               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1085               << "The area does not have the same size as the local domain." << std::endl
1086               << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1087               << "Area size is " << area.extent(0) << " x " << area.extent(1) << ".");
1088       }
1089     }
1090   }
1091
1092   void CDomain::checkLonLat()
1093   {
1094     hasLonLat = (!latvalue_1d.isEmpty() && !lonvalue_1d.isEmpty()) ||
1095                 (!latvalue_2d.isEmpty() && !lonvalue_2d.isEmpty());
1096     if (hasLonLat)
1097     {
1098       if (!lonvalue_1d.isEmpty() && !lonvalue_2d.isEmpty())
1099         ERROR("CDomain::checkLonLat()",
1100               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1101               << "Only one longitude attribute can be used but both 'lonvalue_1d' and 'lonvalue_2d' are defined." << std::endl
1102               << "Define only one longitude attribute: 'lonvalue_1d' or 'lonvalue_2d'.");
1103
1104       if (!lonvalue_1d.isEmpty() && lonvalue_2d.isEmpty())
1105       {
1106         if ((type_attr::rectilinear != type) && (lonvalue_1d.numElements() != i_index.numElements()))
1107           ERROR("CDomain::checkLonLat()",
1108                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1109                 << "'lonvalue_1d' does not have the same size as the local domain." << std::endl
1110                 << "Local size is " << i_index.numElements() << "." << std::endl
1111                 << "'lonvalue_1d' size is " << lonvalue_1d.numElements() << ".");
1112       }
1113
1114       if (lonvalue_1d.isEmpty() && !lonvalue_2d.isEmpty())
1115       {
1116         if (lonvalue_2d.extent(0) != ni || lonvalue_2d.extent(1) != nj)
1117           ERROR("CDomain::checkLonLat()",
1118                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1119                 << "'lonvalue_2d' does not have the same size as the local domain." << std::endl
1120                 << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1121                 << "'lonvalue_2d' size is " << lonvalue_2d.extent(0) << " x " << lonvalue_2d.extent(1) << ".");
1122       }
1123
1124       if (!latvalue_1d.isEmpty() && !latvalue_2d.isEmpty())
1125         ERROR("CDomain::checkLonLat()",
1126               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1127               << "Only one latitude attribute can be used but both 'latvalue_1d' and 'latvalue_2d' are defined." << std::endl
1128               << "Define only one latitude attribute: 'latvalue_1d' or 'latvalue_2d'.");
1129
1130       if (!latvalue_1d.isEmpty() && latvalue_2d.isEmpty())
1131       {
1132         if ((type_attr::rectilinear != type) && (latvalue_1d.numElements() != i_index.numElements()))
1133           ERROR("CDomain::checkLonLat()",
1134                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1135                 << "'latvalue_1d' does not have the same size as the local domain." << std::endl
1136                 << "Local size is " << i_index.numElements() << "." << std::endl
1137                 << "'latvalue_1d' size is " << latvalue_1d.numElements() << ".");
1138       }
1139
1140       if (latvalue_1d.isEmpty() && !latvalue_2d.isEmpty())
1141       {
1142         if (latvalue_2d.extent(0) != ni || latvalue_2d.extent(1) != nj)
1143           ERROR("CDomain::checkLonLat()",
1144                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1145                 << "'latvalue_2d' does not have the same size as the local domain." << std::endl
1146                 << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1147                 << "'latvalue_2d' size is " << latvalue_2d.extent(0) << " x " << latvalue_2d.extent(1) << ".");
1148       }
1149     }
1150   }
1151
1152   void CDomain::checkAttributesOnClientAfterTransformation()
1153   {
1154     CContext* context=CContext::getCurrent() ;
1155
1156     if (this->isClientAfterTransformationChecked) return;
1157     if (context->hasClient)
1158     {
1159       this->checkMask();
1160       if (hasLonLat || hasArea || isCompressible_) this->computeConnectedServer();
1161       if (hasLonLat) this->completeLonLatClient();
1162     }
1163
1164     this->isClientAfterTransformationChecked = true;
1165   }
1166
1167   //----------------------------------------------------------------
1168   // Divide function checkAttributes into 2 seperate ones
1169   // This function only checks all attributes of current domain
1170   void CDomain::checkAttributesOnClient()
1171   {
1172     if (this->isClientChecked) return;
1173     CContext* context=CContext::getCurrent();
1174
1175      this->checkDomain();
1176      this->checkBounds();
1177      this->checkArea();
1178      this->checkLonLat();
1179
1180      if (context->hasClient)
1181      { // CÃŽté client uniquement
1182         this->checkMask();
1183         this->checkDomainData();
1184         this->checkCompression();
1185      }
1186      else
1187      { // CÃŽté serveur uniquement
1188      }
1189
1190      this->isClientChecked = true;
1191   }
1192
1193   // Send all checked attributes to server
1194   void CDomain::sendCheckedAttributes()
1195   {
1196     if (!this->isClientChecked) checkAttributesOnClient();
1197     if (!this->isClientAfterTransformationChecked) checkAttributesOnClientAfterTransformation();
1198     CContext* context=CContext::getCurrent() ;
1199
1200     if (this->isChecked) return;
1201     if (context->hasClient)
1202     {
1203       sendServerAttribut();
1204       if (hasLonLat || hasArea || isCompressible_) sendLonLatArea();
1205     }
1206     this->isChecked = true;
1207   }
1208
1209   void CDomain::checkAttributes(void)
1210   {
1211      if (this->isChecked) return;
1212      CContext* context=CContext::getCurrent() ;
1213
1214      this->checkDomain();
1215      this->checkLonLat();
1216      this->checkBounds();
1217      this->checkArea();
1218
1219      if (context->hasClient)
1220      { // CÃŽté client uniquement
1221         this->checkMask();
1222         this->checkDomainData();
1223         this->checkCompression();
1224
1225      }
1226      else
1227      { // CÃŽté serveur uniquement
1228      }
1229
1230      if (context->hasClient)
1231      {
1232        this->computeConnectedServer();
1233        this->completeLonLatClient();
1234        this->sendServerAttribut();
1235        this->sendLonLatArea();
1236      }
1237
1238      this->isChecked = true;
1239   }
1240
1241  void CDomain::sendServerAttribut(void)
1242  {
1243    CContext* context = CContext::getCurrent();
1244    CContextClient* client = context->client;
1245    int nbServer = client->serverSize;
1246
1247    CServerDistributionDescription serverDescription(nGlobDomain_, nbServer);
1248    if (isUnstructed_) serverDescription.computeServerDistribution(false, 0);
1249    else serverDescription.computeServerDistribution(false, 1);
1250
1251    std::vector<std::vector<int> > serverIndexBegin = serverDescription.getServerIndexBegin();
1252    std::vector<std::vector<int> > serverDimensionSizes = serverDescription.getServerDimensionSizes();
1253
1254    CEventClient event(getType(),EVENT_ID_SERVER_ATTRIBUT);
1255    if (client->isServerLeader())
1256    {
1257      std::list<CMessage> msgs;
1258
1259      const std::list<int>& ranks = client->getRanksServerLeader();
1260      for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1261      {
1262        // Use const int to ensure CMessage holds a copy of the value instead of just a reference
1263        const int ibegin_srv = serverIndexBegin[*itRank][0];
1264        const int jbegin_srv = serverIndexBegin[*itRank][1];
1265        const int ni_srv = serverDimensionSizes[*itRank][0];
1266        const int nj_srv = serverDimensionSizes[*itRank][1];
1267        const int iend_srv = ibegin_srv + ni_srv - 1;
1268        const int jend_srv = jbegin_srv + nj_srv - 1;
1269
1270        msgs.push_back(CMessage());
1271        CMessage& msg = msgs.back();
1272        msg << this->getId() ;
1273        msg << ni_srv << ibegin_srv << iend_srv << nj_srv << jbegin_srv << jend_srv;
1274        msg << global_zoom_ni.getValue() << global_zoom_ibegin.getValue() << global_zoom_nj.getValue() << global_zoom_jbegin.getValue();
1275        msg << isCompressible_;
1276
1277        event.push(*itRank,1,msg);
1278      }
1279      client->sendEvent(event);
1280    }
1281    else client->sendEvent(event);
1282  }
1283
1284  void CDomain::computeNGlobDomain()
1285  {
1286    nGlobDomain_.resize(2);
1287    nGlobDomain_[0] = ni_glo.getValue();
1288    nGlobDomain_[1] = nj_glo.getValue();
1289  }
1290
1291  void CDomain::computeConnectedServer(void)
1292  {
1293    CContext* context=CContext::getCurrent() ;
1294    CContextClient* client=context->client ;
1295    int nbServer=client->serverSize;
1296    bool doComputeGlobalIndexServer = true;
1297
1298    int i,j,i_ind,j_ind, nbIndex;
1299    int global_zoom_iend=global_zoom_ibegin+global_zoom_ni-1 ;
1300    int global_zoom_jend=global_zoom_jbegin+global_zoom_nj-1 ;
1301
1302    // Precompute number of index
1303    int globalIndexCountZoom = 0;
1304    nbIndex = i_index.numElements();
1305    for (i = 0; i < nbIndex; ++i)
1306    {
1307      i_ind=i_index(i);
1308      j_ind=j_index(i);
1309
1310      if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1311      {
1312        ++globalIndexCountZoom;
1313      }
1314    }
1315
1316    int globalIndexWrittenCount = 0;
1317    if (isCompressible_)
1318    {
1319      for (i = 0; i < data_i_index.numElements(); ++i)
1320      {
1321        i_ind = CDistributionClient::getDomainIndex(data_i_index(i), data_j_index(i),
1322                                                    data_ibegin, data_jbegin, data_dim, ni,
1323                                                    j_ind);
1324        if (i_ind >= 0 && i_ind < ni && j_ind >= 0 && j_ind < nj && mask_1d(i_ind + j_ind * ni))
1325        {
1326          i_ind += ibegin;
1327          j_ind += jbegin;
1328          if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1329            ++globalIndexWrittenCount;
1330        }
1331      }
1332    }
1333
1334    // Fill in index
1335    CArray<size_t,1> globalIndexDomainZoom(globalIndexCountZoom);
1336    CArray<size_t,1> localIndexDomainZoom(globalIndexCountZoom);
1337    CArray<size_t,1> globalIndexDomain(nbIndex);
1338    size_t globalIndex;
1339    int globalIndexCount = 0;
1340    globalIndexCountZoom = 0;
1341
1342    for (i = 0; i < nbIndex; ++i)
1343    {
1344      i_ind=i_index(i);
1345      j_ind=j_index(i);
1346      globalIndex = i_ind + j_ind * ni_glo;
1347      globalIndexDomain(globalIndexCount) = globalIndex;
1348      ++globalIndexCount;
1349      if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1350      {
1351        globalIndexDomainZoom(globalIndexCountZoom) = globalIndex;
1352        localIndexDomainZoom(globalIndexCountZoom) = i;
1353        ++globalIndexCountZoom;
1354      }
1355    }
1356
1357    CArray<int,1> globalIndexWrittenDomain(globalIndexWrittenCount);
1358    if (isCompressible_)
1359    {
1360      globalIndexWrittenCount = 0;
1361      for (i = 0; i < data_i_index.numElements(); ++i)
1362      {
1363        i_ind = CDistributionClient::getDomainIndex(data_i_index(i), data_j_index(i),
1364                                                    data_ibegin, data_jbegin, data_dim, ni,
1365                                                    j_ind);
1366        if (i_ind >= 0 && i_ind < ni && j_ind >= 0 && j_ind < nj && mask_1d(i_ind + j_ind * ni))
1367        {
1368          i_ind += ibegin;
1369          j_ind += jbegin;
1370          if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1371          {
1372            globalIndexWrittenDomain(globalIndexWrittenCount) = i_ind + j_ind * ni_glo;
1373            ++globalIndexWrittenCount;
1374          }
1375        }
1376      }
1377    }
1378
1379    size_t globalSizeIndex = 1, indexBegin, indexEnd;
1380    int range, clientSize = client->clientSize;
1381    for (int i = 0; i < nGlobDomain_.size(); ++i) globalSizeIndex *= nGlobDomain_[i];
1382    indexBegin = 0;
1383    for (int i = 0; i < clientSize; ++i)
1384    {
1385      range = globalSizeIndex / clientSize;
1386      if (i < (globalSizeIndex%clientSize)) ++range;
1387      if (i == client->clientRank) break;
1388      indexBegin += range;
1389    }
1390    indexEnd = indexBegin + range - 1;
1391
1392    CServerDistributionDescription serverDescription(nGlobDomain_, nbServer);
1393    if (isUnstructed_) serverDescription.computeServerGlobalIndexInRange(std::make_pair<size_t,size_t>(indexBegin, indexEnd), 0);
1394    else serverDescription.computeServerGlobalIndexInRange(std::make_pair<size_t,size_t>(indexBegin, indexEnd), 1);
1395
1396    CClientServerMapping* clientServerMap = new CClientServerMappingDistributed(serverDescription.getGlobalIndexRange(),
1397                                                                                client->intraComm);
1398    clientServerMap->computeServerIndexMapping(globalIndexDomain);
1399    const CClientServerMapping::GlobalIndexMap& globalIndexDomainOnServer = clientServerMap->getGlobalIndexOnServer();
1400
1401    CClientServerMapping::GlobalIndexMap::const_iterator it  = globalIndexDomainOnServer.begin(),
1402                                                         ite = globalIndexDomainOnServer.end();
1403    typedef XIOSBinarySearchWithIndex<size_t> BinarySearch;
1404    std::vector<int>::iterator itVec;
1405
1406    indSrv_.clear();
1407    indWrittenSrv_.clear();
1408    for (; it != ite; ++it)
1409    {
1410      int rank = it->first;
1411      int indexSize = it->second.size();
1412      std::vector<int> permutIndex(indexSize);
1413      XIOSAlgorithms::fillInIndex(indexSize, permutIndex);
1414      XIOSAlgorithms::sortWithIndex<size_t, CVectorStorage>(it->second, permutIndex);
1415      BinarySearch binSearch(it->second);
1416      int nb = globalIndexDomainZoom.numElements();
1417      for (int i = 0; i < nb; ++i)
1418      {
1419        if (binSearch.search(permutIndex.begin(), permutIndex.end(), globalIndexDomainZoom(i), itVec))
1420        {
1421          indSrv_[rank].push_back(localIndexDomainZoom(i));
1422        }
1423      }
1424      for (int i = 0; i < globalIndexWrittenDomain.numElements(); ++i)
1425      {
1426        if (binSearch.search(permutIndex.begin(), permutIndex.end(), globalIndexWrittenDomain(i), itVec))
1427        {
1428          indWrittenSrv_[rank].push_back(globalIndexWrittenDomain(i));
1429        }
1430      }
1431    }
1432
1433    connectedServerRank_.clear();
1434    for (it = globalIndexDomainOnServer.begin(); it != ite; ++it) {
1435      connectedServerRank_.push_back(it->first);
1436    }
1437
1438    nbConnectedClients_ = clientServerMap->computeConnectedClients(client->serverSize, client->clientSize, client->intraComm, connectedServerRank_);
1439
1440    delete clientServerMap;
1441  }
1442
1443  const std::map<int, vector<size_t> >& CDomain::getIndexServer() const
1444  {
1445    return indSrv_;
1446  }
1447
1448  /*!
1449    Send index from client to server(s)
1450  */
1451  void CDomain::sendIndex()
1452  {
1453    int ns, n, i, j, ind, nv, idx;
1454    CContext* context = CContext::getCurrent();
1455    CContextClient* client=context->client;
1456
1457    CEventClient eventIndex(getType(), EVENT_ID_INDEX);
1458
1459    list<CMessage> list_msgsIndex;
1460    list<CArray<int,1> > list_indi, list_indj, list_writtenInd;
1461
1462    std::map<int, std::vector<size_t> >::const_iterator it, iteMap;
1463    iteMap = indSrv_.end();
1464    for (int k = 0; k < connectedServerRank_.size(); ++k)
1465    {
1466      int nbData = 0;
1467      int rank = connectedServerRank_[k];
1468      it = indSrv_.find(rank);
1469      if (iteMap != it)
1470        nbData = it->second.size();
1471
1472      list_indi.push_back(CArray<int,1>(nbData));
1473      list_indj.push_back(CArray<int,1>(nbData));
1474
1475      CArray<int,1>& indi = list_indi.back();
1476      CArray<int,1>& indj = list_indj.back();
1477      const std::vector<size_t>& temp = it->second;
1478      for (n = 0; n < nbData; ++n)
1479      {
1480        idx = static_cast<int>(it->second[n]);
1481        indi(n) = i_index(idx);
1482        indj(n) = j_index(idx);
1483      }
1484
1485      list_msgsIndex.push_back(CMessage());
1486
1487      list_msgsIndex.back() << this->getId() << (int)type; // enum ne fonctionne pour les message => ToFix
1488      list_msgsIndex.back() << isCurvilinear;
1489      list_msgsIndex.back() << list_indi.back() << list_indj.back();
1490
1491      if (isCompressible_)
1492      {
1493        std::vector<int>& writtenIndSrc = indWrittenSrv_[rank];
1494        list_writtenInd.push_back(CArray<int,1>(writtenIndSrc.size()));
1495        CArray<int,1>& writtenInd = list_writtenInd.back();
1496
1497        for (n = 0; n < writtenInd.numElements(); ++n)
1498          writtenInd(n) = writtenIndSrc[n];
1499
1500        list_msgsIndex.back() << writtenInd;
1501      }
1502
1503      eventIndex.push(rank, nbConnectedClients_[rank], list_msgsIndex.back());
1504    }
1505
1506    client->sendEvent(eventIndex);
1507  }
1508
1509  /*!
1510    Send area from client to server(s)
1511  */
1512  void CDomain::sendArea()
1513  {
1514    if (!hasArea) return;
1515
1516    int ns, n, i, j, ind, nv, idx;
1517    CContext* context = CContext::getCurrent();
1518    CContextClient* client=context->client;
1519
1520    // send area for each connected server
1521    CEventClient eventArea(getType(), EVENT_ID_AREA);
1522
1523    list<CMessage> list_msgsArea;
1524    list<CArray<double,1> > list_area;
1525
1526    std::map<int, std::vector<size_t> >::const_iterator it, iteMap;
1527    iteMap = indSrv_.end();
1528    for (int k = 0; k < connectedServerRank_.size(); ++k)
1529    {
1530      int nbData = 0;
1531      int rank = connectedServerRank_[k];
1532      it = indSrv_.find(rank);
1533      if (iteMap != it)
1534        nbData = it->second.size();
1535      list_area.push_back(CArray<double,1>(nbData));
1536
1537      const std::vector<size_t>& temp = it->second;
1538      for (n = 0; n < nbData; ++n)
1539      {
1540        idx = static_cast<int>(it->second[n]);
1541        i = i_index(idx);
1542        j = j_index(idx);
1543        if (hasArea)
1544          list_area.back()(n) = area(i - ibegin, j - jbegin);
1545      }
1546
1547      list_msgsArea.push_back(CMessage());
1548      list_msgsArea.back() << this->getId() << list_area.back();
1549      eventArea.push(rank, nbConnectedClients_[rank], list_msgsArea.back());
1550    }
1551    client->sendEvent(eventArea);
1552  }
1553
1554  /*!
1555    Send longitude and latitude from client to servers
1556    Each client send long and lat information to corresponding connected server(s).
1557    Because longitude and latitude are optional, this function only called if latitude and longitude exist
1558  */
1559  void CDomain::sendLonLat()
1560  {
1561    if (!hasLonLat) return;
1562
1563    int ns, n, i, j, ind, nv, idx;
1564    CContext* context = CContext::getCurrent();
1565    CContextClient* client=context->client;
1566
1567    // send lon lat for each connected server
1568    CEventClient eventLon(getType(), EVENT_ID_LON);
1569    CEventClient eventLat(getType(), EVENT_ID_LAT);
1570
1571    list<CMessage> list_msgsLon, list_msgsLat;
1572    list<CArray<double,1> > list_lon, list_lat;
1573    list<CArray<double,2> > list_boundslon, list_boundslat;
1574
1575    std::map<int, std::vector<size_t> >::const_iterator it, iteMap;
1576    iteMap = indSrv_.end();
1577    for (int k = 0; k < connectedServerRank_.size(); ++k)
1578    {
1579      int nbData = 0;
1580      int rank = connectedServerRank_[k];
1581      it = indSrv_.find(rank);
1582      if (iteMap != it)
1583        nbData = it->second.size();
1584
1585      list_lon.push_back(CArray<double,1>(nbData));
1586      list_lat.push_back(CArray<double,1>(nbData));
1587
1588      if (hasBounds)
1589      {
1590        list_boundslon.push_back(CArray<double,2>(nvertex, nbData));
1591        list_boundslat.push_back(CArray<double,2>(nvertex, nbData));
1592      }
1593
1594      CArray<double,1>& lon = list_lon.back();
1595      CArray<double,1>& lat = list_lat.back();
1596      const std::vector<size_t>& temp = it->second;
1597      for (n = 0; n < nbData; ++n)
1598      {
1599        idx = static_cast<int>(it->second[n]);
1600        lon(n) = lonvalue_client(idx);
1601        lat(n) = latvalue_client(idx);
1602
1603        if (hasBounds)
1604        {
1605          CArray<double,2>& boundslon = list_boundslon.back();
1606          CArray<double,2>& boundslat = list_boundslat.back();
1607
1608          for (nv = 0; nv < nvertex; ++nv)
1609          {
1610            boundslon(nv, n) = bounds_lon_client(nv, idx);
1611            boundslat(nv, n) = bounds_lat_client(nv, idx);
1612          }
1613        }
1614      }
1615
1616      list_msgsLon.push_back(CMessage());
1617      list_msgsLat.push_back(CMessage());
1618
1619      list_msgsLon.back() << this->getId() << list_lon.back();
1620      list_msgsLat.back() << this->getId() << list_lat.back();
1621
1622      if (hasBounds)
1623      {
1624        list_msgsLon.back() << list_boundslon.back();
1625        list_msgsLat.back() << list_boundslat.back();
1626      }
1627
1628      eventLon.push(rank, nbConnectedClients_[rank], list_msgsLon.back());
1629      eventLat.push(rank, nbConnectedClients_[rank], list_msgsLat.back());
1630    }
1631
1632    client->sendEvent(eventLon);
1633    client->sendEvent(eventLat);
1634  }
1635
1636  /*!
1637    Send some optional information to server(s)
1638    In the future, this function can be extended with more optional information to send
1639  */
1640  void CDomain::sendLonLatArea(void)
1641  {
1642    sendIndex();
1643    sendLonLat();
1644    sendArea();
1645  }
1646
1647  bool CDomain::dispatchEvent(CEventServer& event)
1648  {
1649    if (SuperClass::dispatchEvent(event)) return true;
1650    else
1651    {
1652      switch(event.type)
1653      {
1654        case EVENT_ID_SERVER_ATTRIBUT:
1655          recvServerAttribut(event);
1656          return true;
1657          break;
1658        case EVENT_ID_INDEX:
1659          recvIndex(event);
1660          return true;
1661          break;
1662        case EVENT_ID_LON:
1663          recvLon(event);
1664          return true;
1665          break;
1666        case EVENT_ID_LAT:
1667          recvLat(event);
1668          return true;
1669          break;
1670        case EVENT_ID_AREA:
1671          recvArea(event);
1672          return true;
1673          break;
1674        default:
1675          ERROR("bool CDomain::dispatchEvent(CEventServer& event)",
1676                << "Unknown Event");
1677          return false;
1678       }
1679    }
1680  }
1681
1682  /*!
1683    Receive attributes event from clients(s)
1684    \param[in] event event contain info about rank and associated attributes
1685  */
1686  void CDomain::recvServerAttribut(CEventServer& event)
1687  {
1688    CBufferIn* buffer=event.subEvents.begin()->buffer;
1689    string domainId ;
1690    *buffer>>domainId ;
1691    get(domainId)->recvServerAttribut(*buffer) ;
1692  }
1693
1694  /*!
1695    Receive attributes from client(s): zoom info and begin and n of each server
1696    \param[in] rank rank of client source
1697    \param[in] buffer message containing attributes info
1698  */
1699  void CDomain::recvServerAttribut(CBufferIn& buffer)
1700  {
1701    int global_zoom_ni_tmp, global_zoom_ibegin_tmp, global_zoom_nj_tmp, global_zoom_jbegin_tmp;
1702    buffer >> ni_srv >> ibegin_srv >> iend_srv >> nj_srv >> jbegin_srv >> jend_srv
1703           >> global_zoom_ni_tmp >> global_zoom_ibegin_tmp >> global_zoom_nj_tmp >> global_zoom_jbegin_tmp
1704           >> isCompressible_;
1705
1706    global_zoom_ni.setValue(global_zoom_ni_tmp);
1707    global_zoom_ibegin.setValue(global_zoom_ibegin_tmp);
1708    global_zoom_nj.setValue(global_zoom_nj_tmp);
1709    global_zoom_jbegin.setValue(global_zoom_jbegin_tmp);
1710
1711    int zoom_iend = global_zoom_ibegin + global_zoom_ni - 1;
1712    int zoom_jend = global_zoom_jbegin + global_zoom_nj - 1;
1713
1714    zoom_ibegin_srv = global_zoom_ibegin > ibegin_srv ? global_zoom_ibegin : ibegin_srv ;
1715    zoom_iend_srv = zoom_iend < iend_srv ? zoom_iend : iend_srv ;
1716    zoom_ni_srv=zoom_iend_srv-zoom_ibegin_srv+1 ;
1717
1718    zoom_jbegin_srv = global_zoom_jbegin > jbegin_srv ? global_zoom_jbegin : jbegin_srv ;
1719    zoom_jend_srv = zoom_jend < jend_srv ? zoom_jend : jend_srv ;
1720    zoom_nj_srv=zoom_jend_srv-zoom_jbegin_srv+1 ;
1721
1722    if (zoom_ni_srv<=0 || zoom_nj_srv<=0)
1723    {
1724      zoom_ibegin_srv=0 ; zoom_iend_srv=0 ; zoom_ni_srv=0 ;
1725      zoom_jbegin_srv=0 ; zoom_jend_srv=0 ; zoom_nj_srv=0 ;
1726    }
1727    lonvalue_srv.resize(zoom_ni_srv*zoom_nj_srv) ;
1728    lonvalue_srv = 0. ;
1729    latvalue_srv.resize(zoom_ni_srv*zoom_nj_srv) ;
1730    latvalue_srv = 0. ;
1731    if (hasBounds)
1732    {
1733      bounds_lon_srv.resize(nvertex,zoom_ni_srv*zoom_nj_srv) ;
1734      bounds_lon_srv = 0. ;
1735      bounds_lat_srv.resize(nvertex,zoom_ni_srv*zoom_nj_srv) ;
1736      bounds_lat_srv = 0. ;
1737    }
1738
1739    if (hasArea)
1740      area_srv.resize(zoom_ni_srv * zoom_nj_srv);
1741  }
1742
1743  /*!
1744    Receive index event from clients(s)
1745    \param[in] event event contain info about rank and associated index
1746  */
1747  void CDomain::recvIndex(CEventServer& event)
1748  {
1749    CDomain* domain;
1750
1751    list<CEventServer::SSubEvent>::iterator it;
1752    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1753    {
1754      CBufferIn* buffer = it->buffer;
1755      string domainId;
1756      *buffer >> domainId;
1757      domain = get(domainId);
1758      domain->recvIndex(it->rank, *buffer);
1759    }
1760
1761    if (domain->isCompressible_)
1762    {
1763      std::sort(domain->indexesToWrite.begin(), domain->indexesToWrite.end());
1764
1765      CContextServer* server = CContext::getCurrent()->server;
1766      domain->numberWrittenIndexes_ = domain->indexesToWrite.size();
1767      MPI_Allreduce(&domain->numberWrittenIndexes_, &domain->totalNumberWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
1768      MPI_Scan(&domain->numberWrittenIndexes_, &domain->offsetWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
1769      domain->offsetWrittenIndexes_ -= domain->numberWrittenIndexes_;
1770    }
1771  }
1772
1773  /*!
1774    Receive index information from client(s)
1775    \param[in] rank rank of client source
1776    \param[in] buffer message containing index info
1777  */
1778  void CDomain::recvIndex(int rank, CBufferIn& buffer)
1779  {
1780    int type_int;
1781    buffer >> type_int >> isCurvilinear >> indiSrv[rank] >> indjSrv[rank];
1782    type.setValue((type_attr::t_enum)type_int); // probleme des type enum avec les buffers : ToFix
1783
1784    if (isCompressible_)
1785    {
1786      CArray<int, 1> writtenIndexes;
1787      buffer >> writtenIndexes;
1788      indexesToWrite.reserve(indexesToWrite.size() + writtenIndexes.numElements());
1789      for (int i = 0; i < writtenIndexes.numElements(); ++i)
1790        indexesToWrite.push_back(writtenIndexes(i));
1791    }
1792  }
1793
1794  /*!
1795    Receive longitude event from clients(s)
1796    \param[in] event event contain info about rank and associated longitude
1797  */
1798  void CDomain::recvLon(CEventServer& event)
1799  {
1800    list<CEventServer::SSubEvent>::iterator it;
1801    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1802    {
1803      CBufferIn* buffer = it->buffer;
1804      string domainId;
1805      *buffer >> domainId;
1806      get(domainId)->recvLon(it->rank, *buffer);
1807    }
1808  }
1809
1810  /*!
1811    Receive longitude information from client(s)
1812    \param[in] rank rank of client source
1813    \param[in] buffer message containing longitude info
1814  */
1815  void CDomain::recvLon(int rank, CBufferIn& buffer)
1816  {
1817    CArray<int,1> &indi = indiSrv[rank], &indj = indjSrv[rank];
1818    CArray<double,1> lon;
1819    CArray<double,2> boundslon;
1820
1821    buffer >> lon;
1822    if (hasBounds) buffer >> boundslon;
1823
1824    int i, j, ind_srv;
1825    for (int ind = 0; ind < indi.numElements(); ind++)
1826    {
1827      i = indi(ind); j = indj(ind);
1828      ind_srv = (i - zoom_ibegin_srv) + (j - zoom_jbegin_srv) * zoom_ni_srv;
1829      lonvalue_srv(ind_srv) = lon(ind);
1830      if (hasBounds)
1831      {
1832        for (int nv = 0; nv < nvertex; ++nv)
1833          bounds_lon_srv(nv, ind_srv) = boundslon(nv, ind);
1834      }
1835    }
1836  }
1837
1838  /*!
1839    Receive latitude event from clients(s)
1840    \param[in] event event contain info about rank and associated latitude
1841  */
1842  void CDomain::recvLat(CEventServer& event)
1843  {
1844    list<CEventServer::SSubEvent>::iterator it;
1845    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1846    {
1847      CBufferIn* buffer = it->buffer;
1848      string domainId;
1849      *buffer >> domainId;
1850      get(domainId)->recvLat(it->rank, *buffer);
1851    }
1852  }
1853
1854  /*!
1855    Receive latitude information from client(s)
1856    \param[in] rank rank of client source
1857    \param[in] buffer message containing latitude info
1858  */
1859  void CDomain::recvLat(int rank, CBufferIn& buffer)
1860  {
1861    CArray<int,1> &indi = indiSrv[rank], &indj = indjSrv[rank];
1862    CArray<double,1> lat;
1863    CArray<double,2> boundslat;
1864
1865    buffer >> lat;
1866    if (hasBounds) buffer >> boundslat;
1867
1868    int i, j, ind_srv;
1869    for (int ind = 0; ind < indi.numElements(); ind++)
1870    {
1871      i = indi(ind); j = indj(ind);
1872      ind_srv = (i - zoom_ibegin_srv) + (j - zoom_jbegin_srv) * zoom_ni_srv;
1873      latvalue_srv(ind_srv) = lat(ind);
1874      if (hasBounds)
1875      {
1876        for (int nv = 0; nv < nvertex; nv++)
1877          bounds_lat_srv(nv, ind_srv) = boundslat(nv, ind);
1878      }
1879    }
1880  }
1881
1882  /*!
1883    Receive area event from clients(s)
1884    \param[in] event event contain info about rank and associated area
1885  */
1886  void CDomain::recvArea(CEventServer& event)
1887  {
1888    list<CEventServer::SSubEvent>::iterator it;
1889    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1890    {
1891      CBufferIn* buffer = it->buffer;
1892      string domainId;
1893      *buffer >> domainId;
1894      get(domainId)->recvArea(it->rank, *buffer);
1895    }
1896  }
1897
1898  /*!
1899    Receive area information from client(s)
1900    \param[in] rank rank of client source
1901    \param[in] buffer message containing area info
1902  */
1903  void CDomain::recvArea(int rank, CBufferIn& buffer)
1904  {
1905    CArray<int,1> &indi = indiSrv[rank], &indj = indjSrv[rank];
1906    CArray<double,1> clientArea;
1907
1908    buffer >> clientArea;
1909
1910    int i, j, ind_srv;
1911    for (int ind = 0; ind < indi.numElements(); ind++)
1912    {
1913      i = indi(ind); j = indj(ind);
1914      ind_srv = (i - zoom_ibegin_srv) + (j - zoom_jbegin_srv) * zoom_ni_srv;
1915      area_srv(ind_srv) = clientArea(ind);
1916    }
1917  }
1918
1919  CTransformation<CDomain>* CDomain::addTransformation(ETranformationType transType, const StdString& id)
1920  {
1921    transformationMap_.push_back(std::make_pair(transType, CTransformation<CDomain>::createTransformation(transType,id)));
1922    return transformationMap_.back().second;
1923  }
1924
1925  /*!
1926    Check whether a domain has transformation
1927    \return true if domain has transformation
1928  */
1929  bool CDomain::hasTransformation()
1930  {
1931    return (!transformationMap_.empty());
1932  }
1933
1934  /*!
1935    Set transformation for current domain. It's the method to move transformation in hierarchy
1936    \param [in] domTrans transformation on domain
1937  */
1938  void CDomain::setTransformations(const TransMapTypes& domTrans)
1939  {
1940    transformationMap_ = domTrans;
1941  }
1942
1943  /*!
1944    Get all transformation current domain has
1945    \return all transformation
1946  */
1947  CDomain::TransMapTypes CDomain::getAllTransformations(void)
1948  {
1949    return transformationMap_;
1950  }
1951
1952  /*!
1953    Check the validity of all transformations applied on domain
1954  This functions is called AFTER all inherited attributes are solved
1955  */
1956  void CDomain::checkTransformations()
1957  {
1958    TransMapTypes::const_iterator itb = transformationMap_.begin(), it,
1959                                  ite = transformationMap_.end();
1960    for (it = itb; it != ite; ++it)
1961    {
1962      (it->second)->checkValid(this);
1963    }
1964  }
1965
1966  void CDomain::duplicateTransformation(CDomain* src)
1967  {
1968    if (src->hasTransformation())
1969    {
1970      this->setTransformations(src->getAllTransformations());
1971    }
1972  }
1973
1974  /*!
1975   * Go through the hierarchy to find the domain from which the transformations must be inherited
1976   */
1977  void CDomain::solveInheritanceTransformation()
1978  {
1979    if (hasTransformation() || !hasDirectDomainReference())
1980      return;
1981
1982    CDomain* domain = this;
1983    std::vector<CDomain*> refDomains;
1984    while (!domain->hasTransformation() && domain->hasDirectDomainReference())
1985    {
1986      refDomains.push_back(domain);
1987      domain = domain->getDirectDomainReference();
1988    }
1989
1990    if (domain->hasTransformation())
1991      for (size_t i = 0; i < refDomains.size(); ++i)
1992        refDomains[i]->setTransformations(domain->getAllTransformations());
1993  }
1994
1995  /*!
1996    Parse children nodes of a domain in xml file.
1997    Whenver there is a new transformation, its type and name should be added into this function
1998    \param node child node to process
1999  */
2000  void CDomain::parse(xml::CXMLNode & node)
2001  {
2002    SuperClass::parse(node);
2003
2004    if (node.goToChildElement())
2005    {
2006      StdString nodeElementName;
2007      do
2008      {
2009        StdString nodeId("");
2010        if (node.getAttributes().end() != node.getAttributes().find("id"))
2011        { nodeId = node.getAttributes()["id"]; }
2012
2013        nodeElementName = node.getElementName();
2014        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
2015        it = transformationMapList_.find(nodeElementName);
2016        if (ite != it)
2017        {
2018          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CDomain>::createTransformation(it->second,
2019                                                                                                                nodeId,
2020                                                                                                                &node)));
2021        }
2022      } while (node.goToNextElement()) ;
2023      node.goToParentElement();
2024    }
2025  }
2026   //----------------------------------------------------------------
2027
2028   DEFINE_REF_FUNC(Domain,domain)
2029
2030   ///---------------------------------------------------------------
2031
2032} // namespace xios
Note: See TracBrowser for help on using the repository browser.