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

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

Adding rectilinear and curvilinear domain for expand_domain transformation
-) Rectilinear/curvilinear is expanded not only locally but also globally, its global size ni_glo, nj_glo become ni_glo+2 and nj_glo+2
-) Two attributes i_periodic, j_periodic are only used for rectilinear/curvilinear to process priodic condition

+) Do some minor modification

Test
+) Add test_connectivity_expand
+) On Curie
+) Work (but need more real tests)

  • 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), 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), 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     
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(getNbGlob(), 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  std::vector<int> CDomain::getNbGlob()
1590  {
1591     std::vector<int> nbGlob(2);
1592     nbGlob[0] = ni_glo.getValue();
1593     nbGlob[1] = nj_glo.getValue();
1594
1595     return nbGlob;
1596  }
1597
1598  void CDomain::computeConnectedServer(void)
1599  {
1600    CContext* context=CContext::getCurrent() ;
1601    CContextClient* client=context->client ;
1602    int nbServer=client->serverSize;
1603    int rank = client->clientRank;
1604    bool doComputeGlobalIndexServer = true;
1605
1606    int i,j,i_ind,j_ind, nbIndex;
1607    int global_zoom_iend=global_zoom_ibegin+global_zoom_ni-1 ;
1608    int global_zoom_jend=global_zoom_jbegin+global_zoom_nj-1 ;
1609
1610    // Precompute number of index
1611    int globalIndexCountZoom = 0;
1612    nbIndex = i_index.numElements();
1613    for (i = 0; i < nbIndex; ++i)
1614    {
1615      i_ind=i_index(i);
1616      j_ind=j_index(i);
1617
1618      if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1619      {
1620        ++globalIndexCountZoom;
1621      }
1622    }
1623
1624    int globalIndexWrittenCount = 0;
1625    if (isCompressible_)
1626    {
1627      for (i = 0; i < data_i_index.numElements(); ++i)
1628      {
1629        i_ind = CDistributionClient::getDomainIndex(data_i_index(i), data_j_index(i),
1630                                                    data_ibegin, data_jbegin, data_dim, ni,
1631                                                    j_ind);
1632        if (i_ind >= 0 && i_ind < ni && j_ind >= 0 && j_ind < nj && mask_1d(i_ind + j_ind * ni))
1633        {
1634          i_ind += ibegin;
1635          j_ind += jbegin;
1636          if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1637            ++globalIndexWrittenCount;
1638        }
1639      }
1640    }
1641
1642    // Fill in index
1643    CArray<size_t,1> globalIndexDomainZoom(globalIndexCountZoom);
1644    CArray<size_t,1> localIndexDomainZoom(globalIndexCountZoom);
1645    CArray<size_t,1> globalIndexDomain(nbIndex);
1646    size_t globalIndex;
1647    int globalIndexCount = 0;
1648    globalIndexCountZoom = 0;
1649
1650    for (i = 0; i < nbIndex; ++i)
1651    {
1652      i_ind=i_index(i);
1653      j_ind=j_index(i);
1654      globalIndex = i_ind + j_ind * ni_glo;
1655      globalIndexDomain(globalIndexCount) = globalIndex;
1656      ++globalIndexCount;
1657      if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1658      {
1659        globalIndexDomainZoom(globalIndexCountZoom) = globalIndex;
1660        localIndexDomainZoom(globalIndexCountZoom) = i;
1661        ++globalIndexCountZoom;
1662      }
1663    }
1664
1665    CArray<int,1> globalIndexWrittenDomain(globalIndexWrittenCount);
1666    if (isCompressible_)
1667    {
1668      globalIndexWrittenCount = 0;
1669      for (i = 0; i < data_i_index.numElements(); ++i)
1670      {
1671        i_ind = CDistributionClient::getDomainIndex(data_i_index(i), data_j_index(i),
1672                                                    data_ibegin, data_jbegin, data_dim, ni,
1673                                                    j_ind);
1674        if (i_ind >= 0 && i_ind < ni && j_ind >= 0 && j_ind < nj && mask_1d(i_ind + j_ind * ni))
1675        {
1676          i_ind += ibegin;
1677          j_ind += jbegin;
1678          if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1679          {
1680            globalIndexWrittenDomain(globalIndexWrittenCount) = i_ind + j_ind * ni_glo;
1681            ++globalIndexWrittenCount;
1682          }
1683        }
1684      }
1685    }
1686
1687    size_t globalSizeIndex = 1, indexBegin, indexEnd;
1688    int range, clientSize = client->clientSize;
1689    for (int i = 0; i < getNbGlob().size(); ++i) globalSizeIndex *= getNbGlob()[i];
1690    indexBegin = 0;
1691    if (globalSizeIndex <= clientSize)
1692    {
1693      indexBegin = rank%globalSizeIndex;
1694      indexEnd = indexBegin;
1695    }
1696    else
1697    {
1698      for (int i = 0; i < clientSize; ++i)
1699      {
1700        range = globalSizeIndex / clientSize;
1701        if (i < (globalSizeIndex%clientSize)) ++range;
1702        if (i == client->clientRank) break;
1703        indexBegin += range;
1704      }
1705      indexEnd = indexBegin + range - 1;
1706    }
1707
1708    CServerDistributionDescription serverDescription(getNbGlob(), nbServer);
1709    if (isUnstructed_) serverDescription.computeServerGlobalIndexInRange(std::make_pair<size_t,size_t>(indexBegin, indexEnd), 0);
1710    else serverDescription.computeServerGlobalIndexInRange(std::make_pair<size_t,size_t>(indexBegin, indexEnd), 1);
1711
1712    CClientServerMapping* clientServerMap = new CClientServerMappingDistributed(serverDescription.getGlobalIndexRange(),
1713                                                                                client->intraComm);
1714    clientServerMap->computeServerIndexMapping(globalIndexDomain);
1715    const CClientServerMapping::GlobalIndexMap& globalIndexDomainOnServer = clientServerMap->getGlobalIndexOnServer();
1716
1717    CClientServerMapping::GlobalIndexMap::const_iterator it  = globalIndexDomainOnServer.begin(),
1718                                                         ite = globalIndexDomainOnServer.end();
1719    typedef XIOSBinarySearchWithIndex<size_t> BinarySearch;
1720    std::vector<int>::iterator itVec;
1721
1722    indSrv_.clear();
1723    indWrittenSrv_.clear();
1724    for (; it != ite; ++it)
1725    {
1726      int rank = it->first;
1727      int indexSize = it->second.size();
1728      std::vector<int> permutIndex(indexSize);
1729      XIOSAlgorithms::fillInIndex(indexSize, permutIndex);
1730      XIOSAlgorithms::sortWithIndex<size_t, CVectorStorage>(it->second, permutIndex);
1731      BinarySearch binSearch(it->second);
1732      int nb = globalIndexDomainZoom.numElements();
1733      for (int i = 0; i < nb; ++i)
1734      {
1735        if (binSearch.search(permutIndex.begin(), permutIndex.end(), globalIndexDomainZoom(i), itVec))
1736        {
1737          indSrv_[rank].push_back(localIndexDomainZoom(i));
1738        }
1739      }
1740      for (int i = 0; i < globalIndexWrittenDomain.numElements(); ++i)
1741      {
1742        if (binSearch.search(permutIndex.begin(), permutIndex.end(), globalIndexWrittenDomain(i), itVec))
1743        {
1744          indWrittenSrv_[rank].push_back(globalIndexWrittenDomain(i));
1745        }
1746      }
1747    }
1748
1749    connectedServerRank_.clear();
1750    for (it = globalIndexDomainOnServer.begin(); it != ite; ++it) {
1751      connectedServerRank_.push_back(it->first);
1752    }
1753
1754    nbConnectedClients_ = clientServerMap->computeConnectedClients(client->serverSize, client->clientSize, client->intraComm, connectedServerRank_);
1755
1756    delete clientServerMap;
1757  }
1758
1759  const std::map<int, vector<size_t> >& CDomain::getIndexServer() const
1760  {
1761    return indSrv_;
1762  }
1763
1764  /*!
1765    Send index from client to server(s)
1766  */
1767  void CDomain::sendIndex()
1768  {
1769    int ns, n, i, j, ind, nv, idx;
1770    CContext* context = CContext::getCurrent();
1771    CContextClient* client=context->client;
1772
1773    CEventClient eventIndex(getType(), EVENT_ID_INDEX);
1774
1775    list<CMessage> list_msgsIndex;
1776    list<CArray<int,1> > list_indi, list_indj, list_writtenInd;
1777
1778    std::map<int, std::vector<size_t> >::const_iterator it, iteMap;
1779    iteMap = indSrv_.end();
1780    for (int k = 0; k < connectedServerRank_.size(); ++k)
1781    {
1782      int nbData = 0;
1783      int rank = connectedServerRank_[k];
1784      it = indSrv_.find(rank);
1785      if (iteMap != it)
1786        nbData = it->second.size();
1787
1788      list_indi.push_back(CArray<int,1>(nbData));
1789      list_indj.push_back(CArray<int,1>(nbData));
1790
1791      CArray<int,1>& indi = list_indi.back();
1792      CArray<int,1>& indj = list_indj.back();
1793      const std::vector<size_t>& temp = it->second;
1794      for (n = 0; n < nbData; ++n)
1795      {
1796        idx = static_cast<int>(it->second[n]);
1797        indi(n) = i_index(idx);
1798        indj(n) = j_index(idx);
1799      }
1800
1801      list_msgsIndex.push_back(CMessage());
1802
1803      list_msgsIndex.back() << this->getId() << (int)type; // enum ne fonctionne pour les message => ToFix
1804      list_msgsIndex.back() << isCurvilinear;
1805      list_msgsIndex.back() << list_indi.back() << list_indj.back();
1806
1807      if (isCompressible_)
1808      {
1809        std::vector<int>& writtenIndSrc = indWrittenSrv_[rank];
1810        list_writtenInd.push_back(CArray<int,1>(writtenIndSrc.size()));
1811        CArray<int,1>& writtenInd = list_writtenInd.back();
1812
1813        for (n = 0; n < writtenInd.numElements(); ++n)
1814          writtenInd(n) = writtenIndSrc[n];
1815
1816        list_msgsIndex.back() << writtenInd;
1817      }
1818
1819      eventIndex.push(rank, nbConnectedClients_[rank], list_msgsIndex.back());
1820    }
1821
1822    client->sendEvent(eventIndex);
1823  }
1824
1825  /*!
1826    Send area from client to server(s)
1827  */
1828  void CDomain::sendArea()
1829  {
1830    if (!hasArea) return;
1831
1832    int ns, n, i, j, ind, nv, idx;
1833    CContext* context = CContext::getCurrent();
1834    CContextClient* client=context->client;
1835
1836    // send area for each connected server
1837    CEventClient eventArea(getType(), EVENT_ID_AREA);
1838
1839    list<CMessage> list_msgsArea;
1840    list<CArray<double,1> > list_area;
1841
1842    std::map<int, std::vector<size_t> >::const_iterator it, iteMap;
1843    iteMap = indSrv_.end();
1844    for (int k = 0; k < connectedServerRank_.size(); ++k)
1845    {
1846      int nbData = 0;
1847      int rank = connectedServerRank_[k];
1848      it = indSrv_.find(rank);
1849      if (iteMap != it)
1850        nbData = it->second.size();
1851      list_area.push_back(CArray<double,1>(nbData));
1852
1853      const std::vector<size_t>& temp = it->second;
1854      for (n = 0; n < nbData; ++n)
1855      {
1856        idx = static_cast<int>(it->second[n]);
1857        i = i_index(idx);
1858        j = j_index(idx);
1859        if (hasArea)
1860          list_area.back()(n) = area(i - ibegin, j - jbegin);
1861      }
1862
1863      list_msgsArea.push_back(CMessage());
1864      list_msgsArea.back() << this->getId() << list_area.back();
1865      eventArea.push(rank, nbConnectedClients_[rank], list_msgsArea.back());
1866    }
1867    client->sendEvent(eventArea);
1868  }
1869
1870  /*!
1871    Send longitude and latitude from client to servers
1872    Each client send long and lat information to corresponding connected server(s).
1873    Because longitude and latitude are optional, this function only called if latitude and longitude exist
1874  */
1875  void CDomain::sendLonLat()
1876  {
1877    if (!hasLonLat) return;
1878
1879    int ns, n, i, j, ind, nv, idx;
1880    CContext* context = CContext::getCurrent();
1881    CContextClient* client=context->client;
1882
1883    // send lon lat for each connected server
1884    CEventClient eventLon(getType(), EVENT_ID_LON);
1885    CEventClient eventLat(getType(), EVENT_ID_LAT);
1886
1887    list<CMessage> list_msgsLon, list_msgsLat;
1888    list<CArray<double,1> > list_lon, list_lat;
1889    list<CArray<double,2> > list_boundslon, list_boundslat;
1890
1891    std::map<int, std::vector<size_t> >::const_iterator it, iteMap;
1892    iteMap = indSrv_.end();
1893    for (int k = 0; k < connectedServerRank_.size(); ++k)
1894    {
1895      int nbData = 0;
1896      int rank = connectedServerRank_[k];
1897      it = indSrv_.find(rank);
1898      if (iteMap != it)
1899        nbData = it->second.size();
1900
1901      list_lon.push_back(CArray<double,1>(nbData));
1902      list_lat.push_back(CArray<double,1>(nbData));
1903
1904      if (hasBounds)
1905      {
1906        list_boundslon.push_back(CArray<double,2>(nvertex, nbData));
1907        list_boundslat.push_back(CArray<double,2>(nvertex, nbData));
1908      }
1909
1910      CArray<double,1>& lon = list_lon.back();
1911      CArray<double,1>& lat = list_lat.back();
1912      const std::vector<size_t>& temp = it->second;
1913      for (n = 0; n < nbData; ++n)
1914      {
1915        idx = static_cast<int>(it->second[n]);
1916        lon(n) = lonvalue_client(idx);
1917        lat(n) = latvalue_client(idx);
1918
1919        if (hasBounds)
1920        {
1921          CArray<double,2>& boundslon = list_boundslon.back();
1922          CArray<double,2>& boundslat = list_boundslat.back();
1923
1924          for (nv = 0; nv < nvertex; ++nv)
1925          {
1926            boundslon(nv, n) = bounds_lon_client(nv, idx);
1927            boundslat(nv, n) = bounds_lat_client(nv, idx);
1928          }
1929        }
1930      }
1931
1932      list_msgsLon.push_back(CMessage());
1933      list_msgsLat.push_back(CMessage());
1934
1935      list_msgsLon.back() << this->getId() << list_lon.back();
1936      list_msgsLat.back() << this->getId() << list_lat.back();
1937
1938      if (hasBounds)
1939      {
1940        list_msgsLon.back() << list_boundslon.back();
1941        list_msgsLat.back() << list_boundslat.back();
1942      }
1943
1944      eventLon.push(rank, nbConnectedClients_[rank], list_msgsLon.back());
1945      eventLat.push(rank, nbConnectedClients_[rank], list_msgsLat.back());
1946    }
1947
1948    client->sendEvent(eventLon);
1949    client->sendEvent(eventLat);
1950  }
1951
1952  /*!
1953    Send some optional information to server(s)
1954    In the future, this function can be extended with more optional information to send
1955  */
1956  void CDomain::sendLonLatArea(void)
1957  {
1958    sendIndex();
1959    sendLonLat();
1960    sendArea();
1961  }
1962
1963  bool CDomain::dispatchEvent(CEventServer& event)
1964  {
1965    if (SuperClass::dispatchEvent(event)) return true;
1966    else
1967    {
1968      switch(event.type)
1969      {
1970        case EVENT_ID_SERVER_ATTRIBUT:
1971          recvServerAttribut(event);
1972          return true;
1973          break;
1974        case EVENT_ID_INDEX:
1975          recvIndex(event);
1976          return true;
1977          break;
1978        case EVENT_ID_LON:
1979          recvLon(event);
1980          return true;
1981          break;
1982        case EVENT_ID_LAT:
1983          recvLat(event);
1984          return true;
1985          break;
1986        case EVENT_ID_AREA:
1987          recvArea(event);
1988          return true;
1989          break;
1990        default:
1991          ERROR("bool CDomain::dispatchEvent(CEventServer& event)",
1992                << "Unknown Event");
1993          return false;
1994       }
1995    }
1996  }
1997
1998  /*!
1999    Receive attributes event from clients(s)
2000    \param[in] event event contain info about rank and associated attributes
2001  */
2002  void CDomain::recvServerAttribut(CEventServer& event)
2003  {
2004    CBufferIn* buffer=event.subEvents.begin()->buffer;
2005    string domainId ;
2006    *buffer>>domainId ;
2007    get(domainId)->recvServerAttribut(*buffer) ;
2008  }
2009
2010  /*!
2011    Receive attributes from client(s): zoom info and begin and n of each server
2012    \param[in] rank rank of client source
2013    \param[in] buffer message containing attributes info
2014  */
2015  void CDomain::recvServerAttribut(CBufferIn& buffer)
2016  {
2017    int global_zoom_ni_tmp, global_zoom_ibegin_tmp, global_zoom_nj_tmp, global_zoom_jbegin_tmp;
2018    buffer >> ni_srv >> ibegin_srv >> iend_srv >> nj_srv >> jbegin_srv >> jend_srv
2019           >> global_zoom_ni_tmp >> global_zoom_ibegin_tmp >> global_zoom_nj_tmp >> global_zoom_jbegin_tmp
2020           >> isCompressible_;
2021
2022    global_zoom_ni.setValue(global_zoom_ni_tmp);
2023    global_zoom_ibegin.setValue(global_zoom_ibegin_tmp);
2024    global_zoom_nj.setValue(global_zoom_nj_tmp);
2025    global_zoom_jbegin.setValue(global_zoom_jbegin_tmp);
2026
2027    int zoom_iend = global_zoom_ibegin + global_zoom_ni - 1;
2028    int zoom_jend = global_zoom_jbegin + global_zoom_nj - 1;
2029
2030    zoom_ibegin_srv = global_zoom_ibegin > ibegin_srv ? global_zoom_ibegin : ibegin_srv ;
2031    zoom_iend_srv = zoom_iend < iend_srv ? zoom_iend : iend_srv ;
2032    zoom_ni_srv=zoom_iend_srv-zoom_ibegin_srv+1 ;
2033
2034    zoom_jbegin_srv = global_zoom_jbegin > jbegin_srv ? global_zoom_jbegin : jbegin_srv ;
2035    zoom_jend_srv = zoom_jend < jend_srv ? zoom_jend : jend_srv ;
2036    zoom_nj_srv=zoom_jend_srv-zoom_jbegin_srv+1 ;
2037
2038    if (zoom_ni_srv<=0 || zoom_nj_srv<=0)
2039    {
2040      zoom_ibegin_srv=0 ; zoom_iend_srv=0 ; zoom_ni_srv=0 ;
2041      zoom_jbegin_srv=0 ; zoom_jend_srv=0 ; zoom_nj_srv=0 ;
2042    }
2043    lonvalue_srv.resize(zoom_ni_srv*zoom_nj_srv) ;
2044    lonvalue_srv = 0. ;
2045    latvalue_srv.resize(zoom_ni_srv*zoom_nj_srv) ;
2046    latvalue_srv = 0. ;
2047    if (hasBounds)
2048    {
2049      bounds_lon_srv.resize(nvertex,zoom_ni_srv*zoom_nj_srv) ;
2050      bounds_lon_srv = 0. ;
2051      bounds_lat_srv.resize(nvertex,zoom_ni_srv*zoom_nj_srv) ;
2052      bounds_lat_srv = 0. ;
2053    }
2054
2055    if (hasArea)
2056    {
2057      area_srv.resize(zoom_ni_srv * zoom_nj_srv);
2058      area_srv = 0.;
2059    }
2060
2061  }
2062
2063  /*!
2064    Receive index event from clients(s)
2065    \param[in] event event contain info about rank and associated index
2066  */
2067  void CDomain::recvIndex(CEventServer& event)
2068  {
2069    CDomain* domain;
2070
2071    list<CEventServer::SSubEvent>::iterator it;
2072    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2073    {
2074      CBufferIn* buffer = it->buffer;
2075      string domainId;
2076      *buffer >> domainId;
2077      domain = get(domainId);
2078      domain->recvIndex(it->rank, *buffer);
2079    }
2080
2081    if (domain->isCompressible_)
2082    {
2083      std::sort(domain->indexesToWrite.begin(), domain->indexesToWrite.end());
2084
2085      CContextServer* server = CContext::getCurrent()->server;
2086      domain->numberWrittenIndexes_ = domain->indexesToWrite.size();
2087      MPI_Allreduce(&domain->numberWrittenIndexes_, &domain->totalNumberWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
2088      MPI_Scan(&domain->numberWrittenIndexes_, &domain->offsetWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
2089      domain->offsetWrittenIndexes_ -= domain->numberWrittenIndexes_;
2090    }
2091  }
2092
2093  /*!
2094    Receive index information from client(s)
2095    \param[in] rank rank of client source
2096    \param[in] buffer message containing index info
2097  */
2098  void CDomain::recvIndex(int rank, CBufferIn& buffer)
2099  {
2100    int type_int;
2101    buffer >> type_int >> isCurvilinear >> indiSrv[rank] >> indjSrv[rank];
2102    type.setValue((type_attr::t_enum)type_int); // probleme des type enum avec les buffers : ToFix
2103
2104    if (isCompressible_)
2105    {
2106      CArray<int, 1> writtenIndexes;
2107      buffer >> writtenIndexes;
2108      indexesToWrite.reserve(indexesToWrite.size() + writtenIndexes.numElements());
2109      for (int i = 0; i < writtenIndexes.numElements(); ++i)
2110        indexesToWrite.push_back(writtenIndexes(i));
2111    }
2112  }
2113
2114  /*!
2115    Receive longitude event from clients(s)
2116    \param[in] event event contain info about rank and associated longitude
2117  */
2118  void CDomain::recvLon(CEventServer& event)
2119  {
2120    list<CEventServer::SSubEvent>::iterator it;
2121    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2122    {
2123      CBufferIn* buffer = it->buffer;
2124      string domainId;
2125      *buffer >> domainId;
2126      get(domainId)->recvLon(it->rank, *buffer);
2127    }
2128  }
2129
2130  /*!
2131    Receive longitude information from client(s)
2132    \param[in] rank rank of client source
2133    \param[in] buffer message containing longitude info
2134  */
2135  void CDomain::recvLon(int rank, CBufferIn& buffer)
2136  {
2137    CArray<int,1> &indi = indiSrv[rank], &indj = indjSrv[rank];
2138    CArray<double,1> lon;
2139    CArray<double,2> boundslon;
2140
2141    buffer >> lon;
2142
2143    if (hasBounds) buffer >> boundslon;
2144
2145    int i, j, ind_srv;
2146    for (int ind = 0; ind < indi.numElements(); ind++)
2147    {
2148      i = indi(ind); j = indj(ind);
2149      ind_srv = (i - zoom_ibegin_srv) + (j - zoom_jbegin_srv) * zoom_ni_srv;
2150      lonvalue_srv(ind_srv) = lon(ind);
2151      if (hasBounds)
2152      {
2153        for (int nv = 0; nv < nvertex; ++nv)
2154          bounds_lon_srv(nv, ind_srv) = boundslon(nv, ind);
2155      }
2156    }
2157  }
2158
2159  /*!
2160    Receive latitude event from clients(s)
2161    \param[in] event event contain info about rank and associated latitude
2162  */
2163  void CDomain::recvLat(CEventServer& event)
2164  {
2165    list<CEventServer::SSubEvent>::iterator it;
2166    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2167    {
2168      CBufferIn* buffer = it->buffer;
2169      string domainId;
2170      *buffer >> domainId;
2171      get(domainId)->recvLat(it->rank, *buffer);
2172    }
2173  }
2174
2175  /*!
2176    Receive latitude information from client(s)
2177    \param[in] rank rank of client source
2178    \param[in] buffer message containing latitude info
2179  */
2180  void CDomain::recvLat(int rank, CBufferIn& buffer)
2181  {
2182    CArray<int,1> &indi = indiSrv[rank], &indj = indjSrv[rank];
2183    CArray<double,1> lat;
2184    CArray<double,2> boundslat;
2185
2186    buffer >> lat;
2187    if (hasBounds) buffer >> boundslat;
2188
2189    int i, j, ind_srv;
2190    for (int ind = 0; ind < indi.numElements(); ind++)
2191    {
2192      i = indi(ind); j = indj(ind);
2193      ind_srv = (i - zoom_ibegin_srv) + (j - zoom_jbegin_srv) * zoom_ni_srv;
2194      latvalue_srv(ind_srv) = lat(ind);
2195      if (hasBounds)
2196      {
2197        for (int nv = 0; nv < nvertex; nv++)
2198          bounds_lat_srv(nv, ind_srv) = boundslat(nv, ind);
2199      }
2200    }
2201  }
2202
2203  /*!
2204    Receive area event from clients(s)
2205    \param[in] event event contain info about rank and associated area
2206  */
2207  void CDomain::recvArea(CEventServer& event)
2208  {
2209    list<CEventServer::SSubEvent>::iterator it;
2210    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2211    {
2212      CBufferIn* buffer = it->buffer;
2213      string domainId;
2214      *buffer >> domainId;
2215      get(domainId)->recvArea(it->rank, *buffer);
2216    }
2217  }
2218
2219  /*!
2220    Receive area information from client(s)
2221    \param[in] rank rank of client source
2222    \param[in] buffer message containing area info
2223  */
2224  void CDomain::recvArea(int rank, CBufferIn& buffer)
2225  {
2226    CArray<int,1> &indi = indiSrv[rank], &indj = indjSrv[rank];
2227    CArray<double,1> clientArea;
2228
2229    buffer >> clientArea;
2230
2231    int i, j, ind_srv;
2232    for (int ind = 0; ind < indi.numElements(); ind++)
2233    {
2234      i = indi(ind); j = indj(ind);
2235      ind_srv = (i - zoom_ibegin_srv) + (j - zoom_jbegin_srv) * zoom_ni_srv;
2236      area_srv(ind_srv) = clientArea(ind);
2237    }
2238  }
2239
2240  CTransformation<CDomain>* CDomain::addTransformation(ETranformationType transType, const StdString& id)
2241  {
2242    transformationMap_.push_back(std::make_pair(transType, CTransformation<CDomain>::createTransformation(transType,id)));
2243    return transformationMap_.back().second;
2244  }
2245
2246  /*!
2247    Check whether a domain has transformation
2248    \return true if domain has transformation
2249  */
2250  bool CDomain::hasTransformation()
2251  {
2252    return (!transformationMap_.empty());
2253  }
2254
2255  /*!
2256    Set transformation for current domain. It's the method to move transformation in hierarchy
2257    \param [in] domTrans transformation on domain
2258  */
2259  void CDomain::setTransformations(const TransMapTypes& domTrans)
2260  {
2261    transformationMap_ = domTrans;
2262  }
2263
2264  /*!
2265    Get all transformation current domain has
2266    \return all transformation
2267  */
2268  CDomain::TransMapTypes CDomain::getAllTransformations(void)
2269  {
2270    return transformationMap_;
2271  }
2272
2273  /*!
2274    Check the validity of all transformations applied on domain
2275  This functions is called AFTER all inherited attributes are solved
2276  */
2277  void CDomain::checkTransformations()
2278  {
2279    TransMapTypes::const_iterator itb = transformationMap_.begin(), it,
2280                                  ite = transformationMap_.end();
2281//    for (it = itb; it != ite; ++it)
2282//    {
2283//      (it->second)->checkValid(this);
2284//    }
2285  }
2286
2287  void CDomain::duplicateTransformation(CDomain* src)
2288  {
2289    if (src->hasTransformation())
2290    {
2291      this->setTransformations(src->getAllTransformations());
2292    }
2293  }
2294
2295  /*!
2296   * Go through the hierarchy to find the domain from which the transformations must be inherited
2297   */
2298  void CDomain::solveInheritanceTransformation()
2299  {
2300    if (hasTransformation() || !hasDirectDomainReference())
2301      return;
2302
2303    CDomain* domain = this;
2304    std::vector<CDomain*> refDomains;
2305    while (!domain->hasTransformation() && domain->hasDirectDomainReference())
2306    {
2307      refDomains.push_back(domain);
2308      domain = domain->getDirectDomainReference();
2309    }
2310
2311    if (domain->hasTransformation())
2312      for (size_t i = 0; i < refDomains.size(); ++i)
2313        refDomains[i]->setTransformations(domain->getAllTransformations());
2314  }
2315
2316  /*!
2317    Parse children nodes of a domain in xml file.
2318    Whenver there is a new transformation, its type and name should be added into this function
2319    \param node child node to process
2320  */
2321  void CDomain::parse(xml::CXMLNode & node)
2322  {
2323    SuperClass::parse(node);
2324
2325    if (node.goToChildElement())
2326    {
2327      StdString nodeElementName;
2328      do
2329      {
2330        StdString nodeId("");
2331        if (node.getAttributes().end() != node.getAttributes().find("id"))
2332        { nodeId = node.getAttributes()["id"]; }
2333
2334        nodeElementName = node.getElementName();
2335        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
2336        it = transformationMapList_.find(nodeElementName);
2337        if (ite != it)
2338        {
2339          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CDomain>::createTransformation(it->second,
2340                                                                                                                nodeId,
2341                                                                                                                &node)));
2342        }
2343        else
2344        {
2345          ERROR("void CDomain::parse(xml::CXMLNode & node)",
2346                << "The transformation " << nodeElementName << " has not been supported yet.");
2347        }
2348      } while (node.goToNextElement()) ;
2349      node.goToParentElement();
2350    }
2351  }
2352   //----------------------------------------------------------------
2353
2354   DEFINE_REF_FUNC(Domain,domain)
2355
2356   ///---------------------------------------------------------------
2357
2358} // namespace xios
Note: See TracBrowser for help on using the repository browser.