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

Last change on this file since 1064 was 1064, checked in by mhnguyen, 5 years ago

Auto-distribution of unstructured grid read from a file.

+ Unstructured grid read from a file is now distributed automatically among clients if there is
no distribution information provided.
+ Attributes of grid can be setup: From model (highest priority), from file (reading), or auto-generation (lowest priority).
If an attribute can be setup by several ways, it will be setup by one with the higher priority.

Test
+ On Curie
+ Tests pass

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