source: XIOS/dev/XIOS_DEV_CMIP6/src/node/domain.cpp @ 1236

Last change on this file since 1236 was 1236, checked in by mhnguyen, 7 years ago

Making some changes to allow pools with different number of server

+) Associate context client to each grid distribution (This should be changed in the future)
+) Correct some buffer size estimation
+) Clean some redundant code and add comments

  • 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: 109.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
21#include <algorithm>
22
23namespace xios {
24
25   /// ////////////////////// Définitions ////////////////////// ///
26
27   CDomain::CDomain(void)
28      : CObjectTemplate<CDomain>(), CDomainAttributes()
29      , isChecked(false), relFiles(), isClientChecked(false), nbSenders(), indSrv_(), connectedServerRank_()
30      , hasBounds(false), hasArea(false), isCompressible_(false), isUnstructed_(false)
31      , isClientAfterTransformationChecked(false), hasLonLat(false)
32      , isRedistributed_(false), hasPole(false), doZoomByIndex_(false)
33      , lonvalue(), latvalue(), bounds_lonvalue(), bounds_latvalue()
34      , globalLocalIndexMap_(), computedWrittenIndex_(false)
35   {
36   }
37
38   CDomain::CDomain(const StdString & id)
39      : CObjectTemplate<CDomain>(id), CDomainAttributes()
40      , isChecked(false), relFiles(), isClientChecked(false), nbSenders(), indSrv_(), connectedServerRank_() 
41      , hasBounds(false), hasArea(false), isCompressible_(false), isUnstructed_(false)
42      , isClientAfterTransformationChecked(false), hasLonLat(false)
43      , isRedistributed_(false), hasPole(false), doZoomByIndex_(false)
44      , lonvalue(), latvalue(), bounds_lonvalue(), bounds_latvalue()
45      , globalLocalIndexMap_(), computedWrittenIndex_(false)
46   {
47         }
48
49   CDomain::~CDomain(void)
50   {
51   }
52
53   ///---------------------------------------------------------------
54
55   void CDomain::assignMesh(const StdString meshName, const int nvertex)
56   {
57     mesh = CMesh::getMesh(meshName, nvertex);
58   }
59
60   CDomain* CDomain::createDomain()
61   {
62     CDomain* domain = CDomainGroup::get("domain_definition")->createChild();
63     return domain;
64   }
65
66   std::map<StdString, ETranformationType> CDomain::transformationMapList_ = std::map<StdString, ETranformationType>();
67   bool CDomain::_dummyTransformationMapList = CDomain::initializeTransformationMap(CDomain::transformationMapList_);
68
69   bool CDomain::initializeTransformationMap(std::map<StdString, ETranformationType>& m)
70   {
71     m["zoom_domain"] = TRANS_ZOOM_DOMAIN;
72     m["interpolate_domain"] = TRANS_INTERPOLATE_DOMAIN;
73     m["generate_rectilinear_domain"] = TRANS_GENERATE_RECTILINEAR_DOMAIN;
74     m["compute_connectivity_domain"] = TRANS_COMPUTE_CONNECTIVITY_DOMAIN;
75     m["expand_domain"] = TRANS_EXPAND_DOMAIN;
76   }
77
78   const std::set<StdString> & CDomain::getRelFiles(void) const
79   {
80      return (this->relFiles);
81   }
82
83
84   /*!
85     Returns the number of indexes written by each server.
86     \return the number of indexes written by each server
87   */
88   int CDomain::getNumberWrittenIndexes() const
89   {
90     return numberWrittenIndexes_;
91   }
92
93   /*!
94     Returns the total number of indexes written by the servers.
95     \return the total number of indexes written by the servers
96   */
97   int CDomain::getTotalNumberWrittenIndexes() const
98   {
99     return totalNumberWrittenIndexes_;
100   }
101
102   /*!
103     Returns the offset of indexes written by each server.
104     \return the offset of indexes written by each server
105   */
106   int CDomain::getOffsetWrittenIndexes() const
107   {
108     return offsetWrittenIndexes_;
109   }
110
111   //----------------------------------------------------------------
112
113   /*!
114    * Compute the minimum buffer size required to send the attributes to the server(s).
115    *
116    * \return A map associating the server rank with its minimum buffer size.
117    */
118   std::map<int, StdSize> CDomain::getAttributesBufferSize(CContextClient* client)
119   {
120     CContext* context = CContext::getCurrent();
121     // For now the assumption is that secondary server pools consist of the same number of procs.
122     // CHANGE the line below if the assumption changes.
123     // CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[0] : context->client;
124
125     std::map<int, StdSize> attributesSizes = getMinimumBufferSizeForAttributes();
126
127     if (client->isServerLeader())
128     {
129       // size estimation for sendDistributionAttribut
130       size_t size = 11 * sizeof(size_t);
131
132       const std::list<int>& ranks = client->getRanksServerLeader();
133       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
134       {
135         if (size > attributesSizes[*itRank])
136           attributesSizes[*itRank] = size;
137       }
138     }
139
140     boost::unordered_map<int, vector<size_t> >::const_iterator itIndexEnd = indSrv_[client].end();
141     // std::map<int, std::vector<int> >::const_iterator itWrittenIndexEnd = indWrittenSrv_.end();
142     for (size_t k = 0; k < connectedServerRank_[client].size(); ++k)
143     {
144       int rank = connectedServerRank_[client][k];
145       boost::unordered_map<int, std::vector<size_t> >::const_iterator it = indSrv_[client].find(rank);
146       size_t idxCount = (it != itIndexEnd) ? it->second.size() : 0;
147
148       // size estimation for sendIndex (and sendArea which is always smaller or equal)
149       size_t sizeIndexEvent = 2 * sizeof(size_t) + 2 * CArray<int,1>::size(idxCount);
150       // if (isCompressible_)
151       // {
152       //   std::map<int, std::vector<int> >::const_iterator itWritten = indWrittenSrv_.find(rank);
153       //   size_t writtenIdxCount = (itWritten != itWrittenIndexEnd) ? itWritten->second.size() : 0;
154       //   sizeIndexEvent += CArray<int,1>::size(writtenIdxCount);
155       // }
156
157       // size estimation for sendLonLat
158       size_t sizeLonLatEvent = CArray<double,1>::size(idxCount);
159       if (hasBounds)
160         sizeLonLatEvent += CArray<double,2>::size(nvertex * idxCount);
161
162       size_t size = CEventClient::headerSize + getId().size() + sizeof(size_t) + std::max(sizeIndexEvent, sizeLonLatEvent);
163       if (size > attributesSizes[rank])
164         attributesSizes[rank] = size;
165     }
166
167     return attributesSizes;
168   }
169
170   //----------------------------------------------------------------
171
172   bool CDomain::isEmpty(void) const
173   {
174      return ((this->zoom_i_index.isEmpty()) || (0 == this->zoom_i_index.numElements()));
175
176   }
177
178   //----------------------------------------------------------------
179
180   bool CDomain::IsWritten(const StdString & filename) const
181   {
182      return (this->relFiles.find(filename) != this->relFiles.end());
183   }
184
185   bool CDomain::isWrittenCompressed(const StdString& filename) const
186   {
187      return (this->relFilesCompressed.find(filename) != this->relFilesCompressed.end());
188   }
189
190   //----------------------------------------------------------------
191
192   bool CDomain::isDistributed(void) const
193   {
194      bool distributed =  !((!ni.isEmpty() && (ni == ni_glo) && !nj.isEmpty() && (nj == nj_glo)) ||
195              (!i_index.isEmpty() && i_index.numElements() == ni_glo*nj_glo));
196      distributed |= (1 == CContext::getCurrent()->client->clientSize);
197
198      return distributed;
199   }
200
201   //----------------------------------------------------------------
202
203   /*!
204    * Test whether the data defined on the domain can be outputted in a compressed way.
205    *
206    * \return true if and only if a mask was defined for this domain
207    */
208   bool CDomain::isCompressible(void) const
209   {
210      return isCompressible_;
211   }
212
213   void CDomain::addRelFile(const StdString & filename)
214   {
215      this->relFiles.insert(filename);
216   }
217
218   void CDomain::addRelFileCompressed(const StdString& filename)
219   {
220      this->relFilesCompressed.insert(filename);
221   }
222
223   StdString CDomain::GetName(void)   { return (StdString("domain")); }
224   StdString CDomain::GetDefName(void){ return (CDomain::GetName()); }
225   ENodeType CDomain::GetType(void)   { return (eDomain); }
226
227   //----------------------------------------------------------------
228
229   /*!
230      Verify if all distribution information of a domain are available
231      This checking verifies the definition of distribution attributes (ni, nj, ibegin, jbegin)
232   */
233   bool CDomain::distributionAttributesHaveValue() const
234   {
235      bool hasValues = true;
236
237      if (ni.isEmpty() && ibegin.isEmpty() && i_index.isEmpty())
238      {
239        hasValues = false;
240        return hasValues;
241      }
242
243      return hasValues;
244   }
245
246   /*!
247     Redistribute RECTILINEAR domain with a number of local domains.
248   All attributes ni,nj,ibegin,jbegin (if defined) will be rewritten
249   The optional attributes lonvalue, latvalue will be added. Because this function only serves (for now)
250   for interpolation from unstructured domain to rectilinear one, range of latvalue is 0-360 and lonvalue is -90 - +90
251    \param [in] nbLocalDomain number of local domain on the domain destination
252   */
253   void CDomain::redistribute(int nbLocalDomain)
254   {
255     if (this->isRedistributed_) return;
256
257     this->isRedistributed_ = true;
258     CContext* context = CContext::getCurrent();
259     // For now the assumption is that secondary server pools consist of the same number of procs.
260     // CHANGE the line below if the assumption changes.
261     CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[0] : context->client;
262     int rankClient = client->clientRank;
263     int rankOnDomain = rankClient%nbLocalDomain;
264
265     if (ni_glo.isEmpty() || ni_glo <= 0 )
266     {
267        ERROR("CDomain::redistribute(int nbLocalDomain)",
268           << "[ Id = " << this->getId() << " ] "
269           << "The global domain is badly defined,"
270           << " check the \'ni_glo\'  value !")
271     }
272
273     if (nj_glo.isEmpty() || nj_glo <= 0 )
274     {
275        ERROR("CDomain::redistribute(int nbLocalDomain)",
276           << "[ Id = " << this->getId() << " ] "
277           << "The global domain is badly defined,"
278           << " check the \'nj_glo\'  value !")
279     }
280
281     if ((type_attr::rectilinear == type)  || (type_attr::curvilinear == type))
282     {
283        int globalDomainSize = ni_glo * nj_glo;
284        if (globalDomainSize <= nbLocalDomain)
285        {
286          for (int idx = 0; idx < nbLocalDomain; ++idx)
287          {
288            if (rankOnDomain < globalDomainSize)
289            {
290              int iIdx = rankOnDomain % ni_glo;
291              int jIdx = rankOnDomain / ni_glo;
292              ibegin.setValue(iIdx); jbegin.setValue(jIdx);
293              ni.setValue(1); nj.setValue(1);
294            }
295            else
296            {
297              ibegin.setValue(0); jbegin.setValue(0);
298              ni.setValue(0); nj.setValue(0);
299            }
300          }
301        }
302        else
303        {
304          float njGlo = nj_glo.getValue();
305          float niGlo = ni_glo.getValue();
306          int nbProcOnX, nbProcOnY, range;
307
308          // Compute (approximately) number of segment on x and y axis
309          float yOverXRatio = njGlo/niGlo;
310
311          nbProcOnX = std::ceil(std::sqrt(nbLocalDomain/yOverXRatio));
312          nbProcOnY = std::ceil(((float)nbLocalDomain)/nbProcOnX);
313
314          // Simple distribution: Sweep from top to bottom, left to right
315          // Calculate local begin on x
316          std::vector<int> ibeginVec(nbProcOnX,0), jbeginVec(nbProcOnY,0);
317          std::vector<int> niVec(nbProcOnX), njVec(nbProcOnY);
318          for (int i = 1; i < nbProcOnX; ++i)
319          {
320            range = ni_glo / nbProcOnX;
321            if (i < (ni_glo%nbProcOnX)) ++range;
322            niVec[i-1] = range;
323            ibeginVec[i] = ibeginVec[i-1] + niVec[i-1];
324          }
325          niVec[nbProcOnX-1] = ni_glo - ibeginVec[nbProcOnX-1];
326
327          // Calculate local begin on y
328          for (int j = 1; j < nbProcOnY; ++j)
329          {
330            range = nj_glo / nbProcOnY;
331            if (j < (nj_glo%nbProcOnY)) ++range;
332            njVec[j-1] = range;
333            jbeginVec[j] = jbeginVec[j-1] + njVec[j-1];
334          }
335          njVec[nbProcOnY-1] = nj_glo - jbeginVec[nbProcOnY-1];
336
337          // Now assign value to ni, ibegin, nj, jbegin
338          int iIdx = rankOnDomain % nbProcOnX;
339          int jIdx = rankOnDomain / nbProcOnX;
340
341          if (rankOnDomain != (nbLocalDomain-1))
342          {
343            ibegin.setValue(ibeginVec[iIdx]);
344            jbegin.setValue(jbeginVec[jIdx]);
345            nj.setValue(njVec[jIdx]);
346            ni.setValue(niVec[iIdx]);
347          }
348          else // just merge all the remaining rectangle into the last one
349          {
350            ibegin.setValue(ibeginVec[iIdx]);
351            jbegin.setValue(jbeginVec[jIdx]);
352            nj.setValue(njVec[jIdx]);
353            ni.setValue(ni_glo - ibeginVec[iIdx]);
354          }
355        } 
356     }
357     else  // unstructured domain
358     {
359       if (this->i_index.isEmpty())
360       {
361          int globalDomainSize = ni_glo * nj_glo;
362          if (globalDomainSize <= nbLocalDomain)
363          {
364            for (int idx = 0; idx < nbLocalDomain; ++idx)
365            {
366              if (rankOnDomain < globalDomainSize)
367              {
368                int iIdx = rankOnDomain % ni_glo;
369                int jIdx = rankOnDomain / ni_glo;
370                ibegin.setValue(iIdx); jbegin.setValue(jIdx);
371                ni.setValue(1); nj.setValue(1);
372              }
373              else
374              {
375                ibegin.setValue(0); jbegin.setValue(0);
376                ni.setValue(0); nj.setValue(0);
377              }
378            }
379          }
380          else
381          {
382            float njGlo = nj_glo.getValue();
383            float niGlo = ni_glo.getValue();
384            std::vector<int> ibeginVec(nbLocalDomain,0);
385            std::vector<int> niVec(nbLocalDomain);
386            for (int i = 1; i < nbLocalDomain; ++i)
387            {
388              int range = ni_glo / nbLocalDomain;
389              if (i < (ni_glo%nbLocalDomain)) ++range;
390              niVec[i-1] = range;
391              ibeginVec[i] = ibeginVec[i-1] + niVec[i-1];
392            }
393            niVec[nbLocalDomain-1] = ni_glo - ibeginVec[nbLocalDomain-1];
394
395            int iIdx = rankOnDomain % nbLocalDomain;
396            ibegin.setValue(ibeginVec[iIdx]);
397            jbegin.setValue(0);
398            ni.setValue(niVec[iIdx]);
399            nj.setValue(1);
400          }
401
402          i_index.resize(ni);         
403          for(int idx = 0; idx < ni; ++idx) i_index(idx)=ibegin+idx;
404        }
405        else
406        {
407          ibegin.setValue(this->i_index(0));
408          jbegin.setValue(0);
409          ni.setValue(this->i_index.numElements());
410          nj.setValue(1);
411        }
412     }
413
414     checkDomain();
415   }
416
417   /*!
418     Fill in longitude and latitude whose values are read from file
419   */
420   void CDomain::fillInLonLat()
421   {
422     switch (type)
423     {
424      case type_attr::rectilinear:
425        fillInRectilinearLonLat();
426        break;
427      case type_attr::curvilinear:
428        fillInCurvilinearLonLat();
429        break;
430      case type_attr::unstructured:
431        fillInUnstructuredLonLat();
432        break;
433
434      default:
435      break;
436     }
437
438   }
439
440   /*!
441     Fill in the values for lonvalue_1d and latvalue_1d of rectilinear domain
442     Range of longitude value from 0 - 360
443     Range of latitude value from -90 - +90
444   */
445   void CDomain::fillInRectilinearLonLat()
446   {
447     if (!lonvalue_rectilinear_read_from_file.isEmpty())
448     {
449       lonvalue_1d.resize(ni);
450       for (int idx = 0; idx < ni; ++idx)
451         lonvalue_1d(idx) = lonvalue_rectilinear_read_from_file(idx+ibegin);
452       lon_start.setValue(lonvalue_rectilinear_read_from_file(0));
453       lon_end.setValue(lonvalue_rectilinear_read_from_file(ni_glo-1));
454     }
455     else
456     {
457       if (!lonvalue_2d.isEmpty()) lonvalue_2d.free();
458       lonvalue_1d.resize(ni);
459       double lonRange = lon_end - lon_start;
460       double lonStep = (1 == ni_glo.getValue()) ? lonRange : lonRange/double(ni_glo.getValue()-1);
461
462        // Assign lon value
463       for (int i = 0; i < ni; ++i)
464       {
465         if (0 == (ibegin + i))
466         {
467           lonvalue_1d(i) = lon_start;
468         }
469         else if (ni_glo == (ibegin + i + 1))
470         {
471           lonvalue_1d(i) = lon_end;
472         }
473         else
474         {
475           lonvalue_1d(i) = (ibegin + i) * lonStep  + lon_start;
476         }
477       }
478     }
479
480
481     if (!latvalue_rectilinear_read_from_file.isEmpty())
482     {
483       latvalue_1d.resize(nj);
484       for (int idx = 0; idx < nj; ++idx)
485         latvalue_1d(idx) = latvalue_rectilinear_read_from_file(idx+jbegin);
486       lat_start.setValue(latvalue_rectilinear_read_from_file(0));
487       lat_end.setValue(latvalue_rectilinear_read_from_file(nj_glo-1));
488     }
489     else
490     {
491       if (!latvalue_2d.isEmpty()) latvalue_1d.free();
492       latvalue_1d.resize(nj);
493
494       double latRange = lat_end - lat_start;
495       double latStep = (1 == nj_glo.getValue()) ? latRange : latRange/double(nj_glo.getValue()-1);
496
497       for (int j = 0; j < nj; ++j)
498       {
499         if (0 == (jbegin + j))
500         {
501            latvalue_1d(j) = lat_start;
502         }
503         else if (nj_glo == (jbegin + j + 1))
504         {
505            latvalue_1d(j) = lat_end;
506         }
507         else
508         {
509           latvalue_1d(j) =  (jbegin + j) * latStep + lat_start;
510         }
511       }
512     }
513   }
514
515    /*
516      Fill in longitude and latitude of curvilinear domain read from a file
517      If there are already longitude and latitude defined by model. We just igonore reading value.
518    */
519   void CDomain::fillInCurvilinearLonLat()
520   {
521     if (!lonvalue_curvilinear_read_from_file.isEmpty() && lonvalue_2d.isEmpty())
522     {
523       lonvalue_2d.resize(ni,nj);
524       for (int jdx = 0; jdx < nj; ++jdx)
525        for (int idx = 0; idx < ni; ++idx)
526         lonvalue_2d(idx,jdx) = lonvalue_curvilinear_read_from_file(idx+ibegin, jdx+jbegin);
527
528       lonvalue_curvilinear_read_from_file.free();
529     }
530
531     if (!latvalue_curvilinear_read_from_file.isEmpty() && latvalue_2d.isEmpty())
532     {
533       latvalue_2d.resize(ni,nj);
534       for (int jdx = 0; jdx < nj; ++jdx)
535        for (int idx = 0; idx < ni; ++idx)
536         latvalue_2d(idx,jdx) = latvalue_curvilinear_read_from_file(idx+ibegin, jdx+jbegin);
537
538       latvalue_curvilinear_read_from_file.free();
539     }
540
541     if (!bounds_lonvalue_curvilinear_read_from_file.isEmpty() && bounds_lon_2d.isEmpty())
542     {
543       bounds_lon_2d.resize(nvertex,ni,nj);
544       for (int jdx = 0; jdx < nj; ++jdx)
545        for (int idx = 0; idx < ni; ++idx)
546          for (int ndx = 0; ndx < nvertex; ++ndx)
547         bounds_lon_2d(ndx,idx,jdx) = bounds_lonvalue_curvilinear_read_from_file(ndx,idx+ibegin, jdx+jbegin);
548
549       bounds_lonvalue_curvilinear_read_from_file.free();
550     }
551
552     if (!bounds_latvalue_curvilinear_read_from_file.isEmpty() && bounds_lat_2d.isEmpty())
553     {
554       bounds_lat_2d.resize(nvertex,ni,nj);
555       for (int jdx = 0; jdx < nj; ++jdx)
556        for (int idx = 0; idx < ni; ++idx)
557          for (int ndx = 0; ndx < nvertex; ++ndx)
558            bounds_lat_2d(ndx,idx,jdx) = bounds_latvalue_curvilinear_read_from_file(ndx,idx+ibegin, jdx+jbegin);
559
560       bounds_latvalue_curvilinear_read_from_file.free();
561     }
562
563   }
564
565    /*
566      Fill in longitude and latitude of unstructured domain read from a file
567      If there are already longitude and latitude defined by model. We just igonore reading value.
568    */
569   void CDomain::fillInUnstructuredLonLat()
570   {
571     if (i_index.isEmpty())
572     {
573       i_index.resize(ni);
574       for(int idx = 0; idx < ni; ++idx) i_index(idx)=ibegin+idx;
575     }
576
577     if (!lonvalue_unstructured_read_from_file.isEmpty() && lonvalue_1d.isEmpty())
578     {
579        lonvalue_1d.resize(ni);
580        for (int idx = 0; idx < ni; ++idx)
581          lonvalue_1d(idx) = lonvalue_unstructured_read_from_file(i_index(idx));
582
583        // We dont need these values anymore, so just delete them
584        lonvalue_unstructured_read_from_file.free();
585     } 
586
587     if (!latvalue_unstructured_read_from_file.isEmpty() && latvalue_1d.isEmpty())
588     {
589        latvalue_1d.resize(ni);
590        for (int idx = 0; idx < ni; ++idx)
591          latvalue_1d(idx) =  latvalue_unstructured_read_from_file(i_index(idx));
592
593        // We dont need these values anymore, so just delete them
594        latvalue_unstructured_read_from_file.free();
595     }
596
597     if (!bounds_lonvalue_unstructured_read_from_file.isEmpty() && bounds_lon_1d.isEmpty())
598     {
599        int nbVertex = nvertex;
600        bounds_lon_1d.resize(nbVertex,ni);
601        for (int idx = 0; idx < ni; ++idx)
602          for (int jdx = 0; jdx < nbVertex; ++jdx)
603            bounds_lon_1d(jdx,idx) = bounds_lonvalue_unstructured_read_from_file(jdx, i_index(idx));
604
605        // We dont need these values anymore, so just delete them
606        lonvalue_unstructured_read_from_file.free();
607     }
608
609     if (!bounds_latvalue_unstructured_read_from_file.isEmpty() && bounds_lat_1d.isEmpty())
610     {
611        int nbVertex = nvertex;
612        bounds_lat_1d.resize(nbVertex,ni);
613        for (int idx = 0; idx < ni; ++idx)
614          for (int jdx = 0; jdx < nbVertex; ++jdx)
615            bounds_lat_1d(jdx,idx) = bounds_latvalue_unstructured_read_from_file(jdx, i_index(idx));
616
617        // We dont need these values anymore, so just delete them
618        lonvalue_unstructured_read_from_file.free();
619     }
620   }
621
622  /*
623    Get global longitude and latitude of rectilinear domain.
624  */
625   void CDomain::AllgatherRectilinearLonLat(CArray<double,1>& lon, CArray<double,1>& lat, CArray<double,1>& lon_g, CArray<double,1>& lat_g)
626   {
627          CContext* context = CContext::getCurrent();
628    // For now the assumption is that secondary server pools consist of the same number of procs.
629    // CHANGE the line below if the assumption changes.
630    CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[0] : context->client;
631          lon_g.resize(ni_glo) ;
632          lat_g.resize(nj_glo) ;
633
634
635          int* ibegin_g = new int[client->clientSize] ;
636          int* jbegin_g = new int[client->clientSize] ;
637          int* ni_g = new int[client->clientSize] ;
638          int* nj_g = new int[client->clientSize] ;
639          int v ;
640          v=ibegin ;
641          MPI_Allgather(&v,1,MPI_INT,ibegin_g,1,MPI_INT,client->intraComm) ;
642          v=jbegin ;
643          MPI_Allgather(&v,1,MPI_INT,jbegin_g,1,MPI_INT,client->intraComm) ;
644          v=ni ;
645          MPI_Allgather(&v,1,MPI_INT,ni_g,1,MPI_INT,client->intraComm) ;
646          v=nj ;
647          MPI_Allgather(&v,1,MPI_INT,nj_g,1,MPI_INT,client->intraComm) ;
648
649          MPI_Allgatherv(lon.dataFirst(),ni,MPI_DOUBLE,lon_g.dataFirst(),ni_g, ibegin_g,MPI_DOUBLE,client->intraComm) ;
650          MPI_Allgatherv(lat.dataFirst(),nj,MPI_DOUBLE,lat_g.dataFirst(),nj_g, jbegin_g,MPI_DOUBLE,client->intraComm) ;
651
652      delete[] ibegin_g ;
653      delete[] jbegin_g ;
654      delete[] ni_g ;
655      delete[] nj_g ;
656   }
657
658   void CDomain::fillInRectilinearBoundLonLat(CArray<double,1>& lon, CArray<double,1>& lat,
659                                              CArray<double,2>& boundsLon, CArray<double,2>& boundsLat)
660   {
661     int i,j,k;
662
663     const int nvertexValue = 4;
664     boundsLon.resize(nvertexValue,ni*nj);
665
666     if (ni_glo>1)
667     {
668       double lonStepStart = lon(1)-lon(0);
669       bounds_lon_start=lon(0) - lonStepStart/2;
670       double lonStepEnd = lon(ni_glo-1)-lon(ni_glo-2);
671       bounds_lon_end=lon(ni_glo-1) + lonStepEnd/2;
672       double errorBoundsLon = std::abs(360-std::abs(bounds_lon_end-bounds_lon_start));
673
674       // if errorBoundsLon is reasonably small (0.1 x cell size) consider it as closed in longitude
675       if (errorBoundsLon < std::abs(lonStepStart)*1e-1 || errorBoundsLon < std::abs(lonStepEnd)*1e-1 )
676       {
677         bounds_lon_start= (lon(0) + lon(ni_glo-1)-360)/2 ;
678         bounds_lon_end= (lon(0) +360 + lon(ni_glo-1))/2 ;
679       }
680     }
681     else
682     {
683       if (bounds_lon_start.isEmpty()) bounds_lon_start=-180. ;
684       if (bounds_lon_end.isEmpty()) bounds_lon_end=180.-1e-8 ;
685     }
686
687     for(j=0;j<nj;++j)
688       for(i=0;i<ni;++i)
689       {
690         k=j*ni+i;
691         boundsLon(0,k) = boundsLon(1,k) = (0 == (ibegin + i)) ? bounds_lon_start
692                                                               : (lon(ibegin + i)+lon(ibegin + i-1))/2;
693         boundsLon(2,k) = boundsLon(3,k) = ((ibegin + i + 1) == ni_glo) ? bounds_lon_end
694                                                                        : (lon(ibegin + i + 1)+lon(ibegin + i))/2;
695       }
696
697
698    boundsLat.resize(nvertexValue,nj*ni);
699    bool isNorthPole=false ;
700    bool isSouthPole=false ;
701    if (std::abs(90 - std::abs(lat(0))) < NumTraits<double>::epsilon()) isNorthPole = true;
702    if (std::abs(90 - std::abs(lat(nj_glo-1))) < NumTraits<double>::epsilon()) isSouthPole = true;
703
704    // lat boundaries beyond pole the assimilate it to pole
705    // lat boundarie is relativelly close to pole (0.1 x cell size) assimilate it to pole
706    if (nj_glo>1)
707    {
708      double latStepStart = lat(1)-lat(0);
709      if (isNorthPole) bounds_lat_start=lat(0);
710      else
711      {
712        bounds_lat_start=lat(0)-latStepStart/2;
713        if (bounds_lat_start >= 90 ) bounds_lat_start=90 ;
714        else if (bounds_lat_start <= -90 ) bounds_lat_start=-90 ;
715        else if (bounds_lat_start <= 90 && bounds_lat_start >= lat(0))
716        {
717          if ( std::abs(90-bounds_lat_start) <= 0.1*std::abs(latStepStart)) bounds_lat_start=90 ;
718        }
719        else if (bounds_lat_start >= -90 && bounds_lat_start <= lat(0))
720        {
721          if ( std::abs(-90 - bounds_lat_start) <= 0.1*std::abs(latStepStart)) bounds_lat_start=-90 ;
722        }
723      }
724
725      double latStepEnd = lat(nj_glo-1)-lat(nj_glo-2);
726      if (isSouthPole) bounds_lat_end=lat(nj_glo-1);
727      else
728      {
729        bounds_lat_end=lat(nj_glo-1)+latStepEnd/2;
730
731        if (bounds_lat_end >= 90 ) bounds_lat_end=90 ;
732        else if (bounds_lat_end <= -90 ) bounds_lat_end=-90 ;
733        else if (bounds_lat_end <= 90 && bounds_lat_end >= lat(nj_glo-1))
734        {
735          if ( std::abs(90-bounds_lat_end) <= 0.1*std::abs(latStepEnd)) bounds_lat_end=90 ;
736        }
737        else if (bounds_lat_end >= -90 && bounds_lat_end <= lat(nj_glo-1))
738        {
739          if ( std::abs(-90 - bounds_lat_end) <= 0.1*std::abs(latStepEnd)) bounds_lat_end=-90 ;
740        }
741      }
742    }
743    else
744    {
745      if (bounds_lat_start.isEmpty()) bounds_lat_start=-90. ;
746      if (bounds_lat_end.isEmpty()) bounds_lat_end=90 ;
747    }
748
749    for(j=0;j<nj;++j)
750      for(i=0;i<ni;++i)
751      {
752        k=j*ni+i;
753        boundsLat(1,k) = boundsLat(2,k) = (0 == (jbegin + j)) ? bounds_lat_start
754                                                              : (lat(jbegin + j)+lat(jbegin + j-1))/2;
755        boundsLat(0,k) = boundsLat(3,k) = ((jbegin + j +1) == nj_glo) ? bounds_lat_end
756                                                                      : (lat(jbegin + j + 1)+lat(jbegin + j))/2;
757      }
758   }
759
760   /*
761     General check of the domain to verify its mandatory attributes
762   */
763   void CDomain::checkDomain(void)
764   {
765     if (type.isEmpty())
766     {
767       ERROR("CDomain::checkDomain(void)",
768             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
769             << "The domain type is mandatory, "
770             << "please define the 'type' attribute.")
771     }
772
773     if (type == type_attr::gaussian) 
774     {
775           hasPole=true ;
776             type.setValue(type_attr::unstructured) ;
777           }
778           else if (type == type_attr::rectilinear) hasPole=true ;
779         
780     if (type == type_attr::unstructured)
781     {
782        if (ni_glo.isEmpty())
783        {
784          ERROR("CDomain::checkDomain(void)",
785                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
786                << "The global domain is badly defined, "
787                << "the mandatory 'ni_glo' attribute is missing.")
788        }
789        else if (ni_glo <= 0)
790        {
791          ERROR("CDomain::checkDomain(void)",
792                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
793                << "The global domain is badly defined, "
794                << "'ni_glo' attribute should be strictly positive so 'ni_glo = " << ni_glo.getValue() << "' is invalid.")
795        }
796        isUnstructed_ = true;
797        nj_glo = 1;
798        nj = 1;
799        jbegin = 0;
800        if (!i_index.isEmpty()) ni = i_index.numElements();
801        j_index.resize(ni);
802        for(int i=0;i<ni;++i) j_index(i)=0;
803
804        if (!area.isEmpty())
805          area.transposeSelf(1, 0);
806     }
807
808     if (ni_glo.isEmpty())
809     {
810       ERROR("CDomain::checkDomain(void)",
811             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
812             << "The global domain is badly defined, "
813             << "the mandatory 'ni_glo' attribute is missing.")
814     }
815     else if (ni_glo <= 0)
816     {
817       ERROR("CDomain::checkDomain(void)",
818             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
819             << "The global domain is badly defined, "
820             << "'ni_glo' attribute should be strictly positive so 'ni_glo = " << ni_glo.getValue() << "' is invalid.")
821     }
822
823     if (nj_glo.isEmpty())
824     {
825       ERROR("CDomain::checkDomain(void)",
826             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
827             << "The global domain is badly defined, "
828             << "the mandatory 'nj_glo' attribute is missing.")
829     }
830     else if (nj_glo <= 0)
831     {
832       ERROR("CDomain::checkDomain(void)",
833             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
834             << "The global domain is badly defined, "
835             << "'nj_glo' attribute should be strictly positive so 'nj_glo = " << nj_glo.getValue() << "' is invalid.")
836     }
837
838     checkLocalIDomain();
839     checkLocalJDomain();
840
841     if (i_index.isEmpty())
842     {
843       i_index.resize(ni*nj);
844       for (int j = 0; j < nj; ++j)
845         for (int i = 0; i < ni; ++i) i_index(i+j*ni) = i+ibegin;
846     }
847
848     if (j_index.isEmpty())
849     {
850       j_index.resize(ni*nj);
851       for (int j = 0; j < nj; ++j)
852         for (int i = 0; i < ni; ++i) j_index(i+j*ni) = j+jbegin;
853     }
854     
855     checkZoom();
856   }
857
858   // Check global zoom of a domain
859   // If there is no zoom defined for the domain, zoom will have value of global doamin
860   void CDomain::checkZoom(void)
861   {
862     if (global_zoom_ibegin.isEmpty())
863      global_zoom_ibegin.setValue(0);
864     if (global_zoom_ni.isEmpty())
865      global_zoom_ni.setValue(ni_glo);
866     if (global_zoom_jbegin.isEmpty())
867      global_zoom_jbegin.setValue(0);
868     if (global_zoom_nj.isEmpty())
869      global_zoom_nj.setValue(nj_glo);
870    if (zoom_i_index.isEmpty()) zoom_i_index.setValue(i_index.getValue());
871    if (zoom_j_index.isEmpty()) zoom_j_index.setValue(j_index.getValue());
872    if (zoom_ibegin.isEmpty()) zoom_ibegin.setValue(ibegin);
873    if (zoom_ni.isEmpty()) zoom_ni.setValue(ni);
874    if (zoom_jbegin.isEmpty()) zoom_jbegin.setValue(jbegin);
875    if (zoom_nj.isEmpty()) zoom_nj.setValue(nj);
876   }
877
878   size_t CDomain::getGlobalWrittenSize(void)
879   {
880      return global_zoom_ni*global_zoom_nj ;
881   }
882   //----------------------------------------------------------------
883
884   // Check validity of local domain on using the combination of 3 parameters: ibegin, ni and i_index
885   void CDomain::checkLocalIDomain(void)
886   {
887      // If ibegin and ni are provided then we use them to check the validity of local domain
888      if (i_index.isEmpty() && !ibegin.isEmpty() && !ni.isEmpty())
889      {
890        if ((ni.getValue() < 0 || ibegin.getValue() < 0) || ((ibegin.getValue() + ni.getValue()) > ni_glo.getValue()))
891        {
892          ERROR("CDomain::checkLocalIDomain(void)",
893                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
894                << "The local domain is wrongly defined,"
895                << " check the attributes 'ni_glo' (" << ni_glo.getValue() << "), 'ni' (" << ni.getValue() << ") and 'ibegin' (" << ibegin.getValue() << ")");
896        }
897      }
898
899      // i_index has higher priority than ibegin and ni
900      if (!i_index.isEmpty())
901      {
902        int minIIndex = (0 < i_index.numElements()) ? i_index(0) : 0;
903        if (ni.isEmpty()) 
904        {         
905         // No information about ni
906          int minIndex = ni_glo - 1;
907          int maxIndex = 0;
908          for (int idx = 0; idx < i_index.numElements(); ++idx)
909          {
910            if (i_index(idx) < minIndex) minIndex = i_index(idx);
911            if (i_index(idx) > maxIndex) maxIndex = i_index(idx);
912          }
913          ni = maxIndex - minIndex + 1; 
914          minIIndex = minIIndex;         
915        }
916
917        // It's not so correct but if ibegin is not the first value of i_index
918        // then data on local domain has user-defined distribution. In this case, ibegin, ni have no meaning.
919        if (ibegin.isEmpty()) ibegin = minIIndex;
920      }
921      else if (ibegin.isEmpty() && ni.isEmpty())
922      {
923        ibegin = 0;
924        ni = ni_glo;
925      }
926      else if ((!ibegin.isEmpty() && ni.isEmpty()) || (ibegin.isEmpty() && !ni.isEmpty()))
927      {
928        ERROR("CDomain::checkLocalIDomain(void)",
929              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
930              << "The local domain is wrongly defined," << endl
931              << "i_index is empty and either 'ni' or 'ibegin' is not defined. " 
932              << "If 'ni' and 'ibegin' are used to define a domain, both of them must not be empty.");
933      }
934       
935
936      if ((ni.getValue() < 0 || ibegin.getValue() < 0))
937      {
938        ERROR("CDomain::checkLocalIDomain(void)",
939              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
940              << "The local domain is wrongly defined,"
941              << " check the attributes 'ni_glo' (" << ni_glo.getValue() << "), 'ni' (" << ni.getValue() << ") and 'ibegin' (" << ibegin.getValue() << ")");
942      }
943   }
944
945   // Check validity of local domain on using the combination of 3 parameters: jbegin, nj and j_index
946   void CDomain::checkLocalJDomain(void)
947   {
948    // If jbegin and nj are provided then we use them to check the validity of local domain
949     if (j_index.isEmpty() && !jbegin.isEmpty() && !nj.isEmpty())
950     {
951       if ((nj.getValue() < 0 || jbegin.getValue() < 0) || (jbegin.getValue() + nj.getValue()) > nj_glo.getValue())
952       {
953         ERROR("CDomain::checkLocalJDomain(void)",
954                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
955                << "The local domain is wrongly defined,"
956                << " check the attributes 'nj_glo' (" << nj_glo.getValue() << "), 'nj' (" << nj.getValue() << ") and 'jbegin' (" << jbegin.getValue() << ")");
957       }
958     }
959
960     if (!j_index.isEmpty())
961     {
962        int minJIndex = (0 < j_index.numElements()) ? j_index(0) : 0;
963        if (nj.isEmpty()) 
964        {
965          // No information about nj
966          int minIndex = nj_glo - 1;
967          int maxIndex = 0;
968          for (int idx = 0; idx < j_index.numElements(); ++idx)
969          {
970            if (j_index(idx) < minIndex) minIndex = j_index(idx);
971            if (j_index(idx) > maxIndex) maxIndex = j_index(idx);
972          }
973          nj = maxIndex - minIndex + 1;
974          minJIndex = minIndex; 
975        } 
976        // It's the same as checkLocalIDomain. It's not so correct but if jbegin is not the first value of j_index
977        // then data on local domain has user-defined distribution. In this case, jbegin has no meaning.
978       if (jbegin.isEmpty()) jbegin = minJIndex;       
979     }
980     else if (jbegin.isEmpty() && nj.isEmpty())
981     {
982       jbegin = 0;
983       nj = nj_glo;
984     }     
985
986
987     if ((nj.getValue() < 0 || jbegin.getValue() < 0))
988     {
989       ERROR("CDomain::checkLocalJDomain(void)",
990              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
991              << "The local domain is wrongly defined,"
992              << " check the attributes 'nj_glo' (" << nj_glo.getValue() << "), 'nj' (" << nj.getValue() << ") and 'jbegin' (" << jbegin.getValue() << ")");
993     }
994   }
995
996   //----------------------------------------------------------------
997
998   void CDomain::checkMask(void)
999   {
1000      if (!mask_1d.isEmpty() && !mask_2d.isEmpty())
1001        ERROR("CDomain::checkMask(void)",
1002              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1003              << "Both mask_1d and mask_2d are defined but only one can be used at the same time." << std::endl
1004              << "Please define only one mask: 'mask_1d' or 'mask_2d'.");
1005
1006      if (!mask_1d.isEmpty() && mask_2d.isEmpty())
1007      {
1008        if (mask_1d.numElements() != i_index.numElements())
1009          ERROR("CDomain::checkMask(void)",
1010                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1011                << "'mask_1d' does not have the same size as the local domain." << std::endl
1012                << "Local size is " << i_index.numElements() << "." << std::endl
1013                << "Mask size is " << mask_1d.numElements() << ".");
1014      }
1015
1016      if (mask_1d.isEmpty() && !mask_2d.isEmpty())
1017      {
1018        if (mask_2d.extent(0) != ni || mask_2d.extent(1) != nj)
1019          ERROR("CDomain::checkMask(void)",
1020                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1021                << "The mask does not have the same size as the local domain." << std::endl
1022                << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1023                << "Mask size is " << mask_2d.extent(0) << " x " << mask_2d.extent(1) << ".");
1024      }
1025
1026      if (!mask_2d.isEmpty())
1027      {
1028        mask_1d.resize(mask_2d.extent(0) * mask_2d.extent(1));
1029        for (int j = 0; j < nj; ++j)
1030          for (int i = 0; i < ni; ++i) mask_1d(i+j*ni) = mask_2d(i,j);
1031        mask_2d.reset();
1032      }
1033      else if (mask_1d.isEmpty())
1034      {
1035        mask_1d.resize(i_index.numElements());
1036        for (int i = 0; i < i_index.numElements(); ++i) mask_1d(i) = true;
1037      }
1038   }
1039
1040   //----------------------------------------------------------------
1041
1042   void CDomain::checkDomainData(void)
1043   {
1044      if (data_dim.isEmpty())
1045      {
1046        data_dim.setValue(1);
1047      }
1048      else if (!(data_dim.getValue() == 1 || data_dim.getValue() == 2))
1049      {
1050        ERROR("CDomain::checkDomainData(void)",
1051              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1052              << "The data dimension is invalid, 'data_dim' must be 1 or 2 not << " << data_dim.getValue() << ".");
1053      }
1054
1055      if (data_ibegin.isEmpty())
1056         data_ibegin.setValue(0);
1057      if (data_jbegin.isEmpty())
1058         data_jbegin.setValue(0);
1059
1060      if (data_ni.isEmpty())
1061      {
1062        data_ni.setValue((data_dim == 1) ? (ni.getValue() * nj.getValue()) : ni.getValue());
1063      }
1064      else if (data_ni.getValue() < 0)
1065      {
1066        ERROR("CDomain::checkDomainData(void)",
1067              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1068              << "The data size cannot be negative ('data_ni' = " << data_ni.getValue() << ").");
1069      }
1070
1071      if (data_nj.isEmpty())
1072      {
1073        data_nj.setValue((data_dim.getValue() == 1) ? (ni.getValue() * nj.getValue()) : nj.getValue());
1074      }
1075      else if (data_nj.getValue() < 0)
1076      {
1077        ERROR("CDomain::checkDomainData(void)",
1078              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1079              << "The data size cannot be negative ('data_nj' = " << data_nj.getValue() << ").");
1080      }
1081   }
1082
1083   //----------------------------------------------------------------
1084
1085   void CDomain::checkCompression(void)
1086   {
1087      if (!data_i_index.isEmpty())
1088      {
1089        if (!data_j_index.isEmpty() &&
1090            data_j_index.numElements() != data_i_index.numElements())
1091        {
1092           ERROR("CDomain::checkCompression(void)",
1093                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1094                 << "'data_i_index' and 'data_j_index' arrays must have the same size." << std::endl
1095                 << "'data_i_index' size = " << data_i_index.numElements() << std::endl
1096                 << "'data_j_index' size = " << data_j_index.numElements());
1097        }
1098
1099        if (2 == data_dim)
1100        {
1101          if (data_j_index.isEmpty())
1102          {
1103             ERROR("CDomain::checkCompression(void)",
1104                   << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1105                   << "'data_j_index' must be defined when 'data_i_index' is set and 'data_dim' is 2.");
1106          }
1107        }
1108        else // (1 == data_dim)
1109        {
1110          if (data_j_index.isEmpty())
1111          {
1112            data_j_index.resize(data_ni);
1113            for (int j = 0; j < data_ni; ++j) data_j_index(j) = 0;
1114          }
1115        }
1116      }
1117      else
1118      {
1119        if (data_dim == 2 && !data_j_index.isEmpty())
1120          ERROR("CDomain::checkCompression(void)",
1121                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1122                << "'data_i_index' must be defined when 'data_j_index' is set and 'data_dim' is 2.");
1123
1124        if (1 == data_dim)
1125        {
1126          data_i_index.resize(data_ni);
1127          data_j_index.resize(data_ni);
1128
1129          for (int i = 0; i < data_ni; ++i)
1130          {
1131            data_i_index(i) = i;
1132            data_j_index(i) = 0;
1133          }
1134        }
1135        else // (data_dim == 2)
1136        {
1137          const int dsize = data_ni * data_nj;
1138          data_i_index.resize(dsize);
1139          data_j_index.resize(dsize);
1140
1141          for(int count = 0, j = 0; j < data_nj; ++j)
1142          {
1143            for(int i = 0; i < data_ni; ++i, ++count)
1144            {
1145              data_i_index(count) = i;
1146              data_j_index(count) = j;
1147            }
1148          }
1149        }
1150      }
1151   }
1152
1153   //----------------------------------------------------------------
1154   void CDomain::computeLocalMask(void)
1155   {
1156     localMask.resize(ni*nj) ;
1157     localMask=false ;
1158     size_t zoom_ibegin= global_zoom_ibegin ;
1159     size_t zoom_iend= global_zoom_ibegin+global_zoom_ni-1 ;
1160     size_t zoom_jbegin= global_zoom_jbegin ;
1161     size_t zoom_jend= global_zoom_jbegin+global_zoom_nj-1 ;
1162
1163
1164     size_t dn=data_i_index.numElements() ;
1165     int i,j ;
1166     size_t k,ind ;
1167
1168     for(k=0;k<dn;k++)
1169     {
1170       if (data_dim==2)
1171       {
1172          i=data_i_index(k)+data_ibegin ;
1173          j=data_j_index(k)+data_jbegin ;
1174       }
1175       else
1176       {
1177          i=(data_i_index(k)+data_ibegin)%ni ;
1178          j=(data_i_index(k)+data_ibegin)/ni ;
1179       }
1180
1181       if (i>=0 && i<ni && j>=0 && j<nj)
1182         if (i+ibegin>=zoom_ibegin && i+ibegin<=zoom_iend && j+jbegin>=zoom_jbegin && j+jbegin<=zoom_jend)
1183         {
1184           ind=i+ni*j ;
1185           localMask(ind)=mask_1d(ind) ;
1186         }
1187     }
1188   }
1189
1190   void CDomain::checkEligibilityForCompressedOutput(void)
1191   {
1192     // We don't check if the mask or the indexes are valid here, just if they have been defined at this point.
1193     isCompressible_ = !mask_1d.isEmpty() || !mask_2d.isEmpty() || !data_i_index.isEmpty();
1194   }
1195
1196   //----------------------------------------------------------------
1197
1198   /*
1199     Fill in longitude and latitude value from clients (or models) into internal values lonvalue, latvalue which
1200     will be used by XIOS.
1201   */
1202   void CDomain::completeLonLatClient(void)
1203   {
1204     bool lonlatValueExisted = (0 != lonvalue.numElements()) || (0 != latvalue.numElements());
1205     if (!lonvalue_2d.isEmpty() && !lonlatValueExisted)
1206     {
1207       lonvalue.resize(ni * nj);
1208       latvalue.resize(ni * nj);
1209       if (hasBounds)
1210       {
1211         bounds_lonvalue.resize(nvertex, ni * nj);
1212         bounds_latvalue.resize(nvertex, ni * nj);
1213       }
1214
1215       for (int j = 0; j < nj; ++j)
1216       {
1217         for (int i = 0; i < ni; ++i)
1218         {
1219           int k = j * ni + i;
1220
1221           lonvalue(k) = lonvalue_2d(i,j);
1222           latvalue(k) = latvalue_2d(i,j);
1223
1224           if (hasBounds)
1225           {
1226             for (int n = 0; n < nvertex; ++n)
1227             {
1228               bounds_lonvalue(n,k) = bounds_lon_2d(n,i,j);
1229               bounds_latvalue(n,k) = bounds_lat_2d(n,i,j);
1230             }
1231           }
1232         }
1233       }
1234     }
1235     else if (!lonvalue_1d.isEmpty()  && !lonlatValueExisted)
1236     {
1237       if (type_attr::rectilinear == type)
1238       {
1239         if (ni == lonvalue_1d.numElements() && nj == latvalue_1d.numElements())
1240         {
1241           lonvalue.resize(ni * nj);
1242           latvalue.resize(ni * nj);
1243           if (hasBounds)
1244           {
1245             bounds_lonvalue.resize(nvertex, ni * nj);
1246             bounds_latvalue.resize(nvertex, ni * nj);
1247           }
1248
1249           for (int j = 0; j < nj; ++j)
1250           {
1251             for (int i = 0; i < ni; ++i)
1252             {
1253               int k = j * ni + i;
1254
1255               lonvalue(k) = lonvalue_1d(i);
1256               latvalue(k) = latvalue_1d(j);
1257
1258               if (hasBounds)
1259               {
1260                 for (int n = 0; n < nvertex; ++n)
1261                 {
1262                   bounds_lonvalue(n,k) = bounds_lon_1d(n,i);
1263                   bounds_latvalue(n,k) = bounds_lat_1d(n,j);
1264                 }
1265               }
1266             }
1267           }
1268         }
1269         else if (i_index.numElements() == lonvalue_1d.numElements() && j_index.numElements() == latvalue_1d.numElements()  && !lonlatValueExisted)
1270         {
1271           lonvalue.reference(lonvalue_1d);
1272           latvalue.reference(latvalue_1d);
1273            if (hasBounds)
1274           {
1275             bounds_lonvalue.reference(bounds_lon_1d);
1276             bounds_latvalue.reference(bounds_lat_1d);
1277           }
1278         }
1279         else
1280           ERROR("CDomain::completeLonClient(void)",
1281                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1282                 << "'lonvalue_1d' and 'latvalue_1d' does not have the same size as the local domain." << std::endl
1283                 << "'lonvalue_1d' size is " << lonvalue_1d.numElements() 
1284                 << " and 'latvalue_1d' size is " << latvalue_1d.numElements() << std::endl
1285                 << " They should be correspondingly " << ni.getValue() << " and "  << nj.getValue() << " or " << std::endl
1286                 << i_index.numElements() << " and "  << j_index.numElements() << ".");
1287       }
1288       else if (type == type_attr::curvilinear || type == type_attr::unstructured  && !lonlatValueExisted)
1289       {
1290         lonvalue.reference(lonvalue_1d);
1291         latvalue.reference(latvalue_1d);
1292         if (hasBounds)
1293         {
1294           bounds_lonvalue.reference(bounds_lon_1d);
1295           bounds_latvalue.reference(bounds_lat_1d);
1296         }
1297       }
1298     }
1299   }
1300
1301   /*
1302     Convert internal longitude latitude value used by XIOS to "lonvalue_*" which can be retrieved with Fortran interface
1303   */
1304   void CDomain::convertLonLatValue(void)
1305   {
1306     bool lonlatValueExisted = (0 != lonvalue.numElements()) || (0 != latvalue.numElements());
1307     if (!lonvalue_2d.isEmpty() && lonlatValueExisted)
1308     {
1309       lonvalue_2d.resize(ni,nj);
1310       latvalue_2d.resize(ni,nj);
1311       if (hasBounds)
1312       {
1313         bounds_lon_2d.resize(nvertex, ni, nj);
1314         bounds_lat_2d.resize(nvertex, ni, nj);
1315       }
1316
1317       for (int j = 0; j < nj; ++j)
1318       {
1319         for (int i = 0; i < ni; ++i)
1320         {
1321           int k = j * ni + i;
1322
1323           lonvalue_2d(i,j) = lonvalue(k);
1324           latvalue_2d(i,j) = latvalue(k);
1325
1326           if (hasBounds)
1327           {
1328             for (int n = 0; n < nvertex; ++n)
1329             {
1330               bounds_lon_2d(n,i,j) = bounds_lonvalue(n,k);
1331               bounds_lat_2d(n,i,j) = bounds_latvalue(n,k);
1332             }
1333           }
1334         }
1335       }
1336     }
1337     else if (!lonvalue_1d.isEmpty()  && lonlatValueExisted)
1338     {
1339       if (type_attr::rectilinear == type)
1340       {
1341         if (ni == lonvalue_1d.numElements() && nj == latvalue_1d.numElements())
1342         {
1343           lonvalue.resize(ni * nj);
1344           latvalue.resize(ni * nj);
1345           if (hasBounds)
1346           {
1347             bounds_lonvalue.resize(nvertex, ni * nj);
1348             bounds_latvalue.resize(nvertex, ni * nj);
1349           }
1350
1351           for (int j = 0; j < nj; ++j)
1352           {
1353             for (int i = 0; i < ni; ++i)
1354             {
1355               int k = j * ni + i;
1356
1357               lonvalue(k) = lonvalue_1d(i);
1358               latvalue(k) = latvalue_1d(j);
1359
1360               if (hasBounds)
1361               {
1362                 for (int n = 0; n < nvertex; ++n)
1363                 {
1364                   bounds_lonvalue(n,k) = bounds_lon_1d(n,i);
1365                   bounds_latvalue(n,k) = bounds_lat_1d(n,j);
1366                 }
1367               }
1368             }
1369           }
1370         }
1371         else if (i_index.numElements() == lonvalue_1d.numElements() && j_index.numElements() == latvalue_1d.numElements()  && !lonlatValueExisted)
1372         {
1373           lonvalue.reference(lonvalue_1d);
1374           latvalue.reference(latvalue_1d);
1375            if (hasBounds)
1376           {
1377             bounds_lonvalue.reference(bounds_lon_1d);
1378             bounds_latvalue.reference(bounds_lat_1d);
1379           }
1380         }
1381         else
1382           ERROR("CDomain::completeLonClient(void)",
1383                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1384                 << "'lonvalue_1d' and 'latvalue_1d' does not have the same size as the local domain." << std::endl
1385                 << "'lonvalue_1d' size is " << lonvalue_1d.numElements() 
1386                 << " and 'latvalue_1d' size is " << latvalue_1d.numElements() << std::endl
1387                 << " They should be correspondingly " << ni.getValue() << " and "  << nj.getValue() << " or " << std::endl
1388                 << i_index.numElements() << " and "  << j_index.numElements() << ".");
1389       }
1390       else if (type == type_attr::curvilinear || type == type_attr::unstructured  && !lonlatValueExisted)
1391       {
1392         lonvalue.reference(lonvalue_1d);
1393         latvalue.reference(latvalue_1d);
1394         if (hasBounds)
1395         {
1396           bounds_lonvalue.reference(bounds_lon_1d);
1397           bounds_latvalue.reference(bounds_lat_1d);
1398         }
1399       }
1400     }
1401   }
1402
1403
1404   void CDomain::checkBounds(void)
1405   {
1406     bool hasBoundValues = (0 != bounds_lonvalue.numElements()) || (0 != bounds_latvalue.numElements());
1407     if (!nvertex.isEmpty() && nvertex > 0 && !hasBoundValues)
1408     {
1409       if (!bounds_lon_1d.isEmpty() && !bounds_lon_2d.isEmpty())
1410         ERROR("CDomain::checkBounds(void)",
1411               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1412               << "Only one longitude boundary attribute can be used but both 'bounds_lon_1d' and 'bounds_lon_2d' are defined." << std::endl
1413               << "Define only one longitude boundary attribute: 'bounds_lon_1d' or 'bounds_lon_2d'.");
1414
1415       if (!bounds_lat_1d.isEmpty() && !bounds_lat_2d.isEmpty())
1416         ERROR("CDomain::checkBounds(void)",
1417               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1418               << "Only one latitude boundary attribute can be used but both 'bounds_lat_1d' and 'bounds_lat_2d' are defined." << std::endl
1419               << "Define only one latitude boundary attribute: 'bounds_lat_1d' or 'bounds_lat_2d'.");
1420
1421       if ((!bounds_lon_1d.isEmpty() && bounds_lat_1d.isEmpty()) || (bounds_lon_1d.isEmpty() && !bounds_lat_1d.isEmpty()))
1422       {
1423         ERROR("CDomain::checkBounds(void)",
1424               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1425               << "Only 'bounds_lon_1d' or 'bounds_lat_1d' is defined." << std::endl
1426               << "Please define either both attributes or none.");
1427       }
1428
1429       if ((!bounds_lon_2d.isEmpty() && bounds_lat_2d.isEmpty()) || (bounds_lon_2d.isEmpty() && !bounds_lat_2d.isEmpty()))
1430       {
1431         ERROR("CDomain::checkBounds(void)",
1432               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1433               << "Only 'bounds_lon_2d' or 'bounds_lat_2d' is defined." << std::endl
1434               << "Please define either both attributes or none.");
1435       }
1436
1437       if (!bounds_lon_1d.isEmpty() && nvertex.getValue() != bounds_lon_1d.extent(0))
1438         ERROR("CDomain::checkBounds(void)",
1439               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1440               << "'bounds_lon_1d' dimension is not compatible with 'nvertex'." << std::endl
1441               << "'bounds_lon_1d' dimension is " << bounds_lon_1d.extent(1)
1442               << " but nvertex is " << nvertex.getValue() << ".");
1443
1444       if (!bounds_lon_2d.isEmpty() && nvertex.getValue() != bounds_lon_2d.extent(0))
1445         ERROR("CDomain::checkBounds(void)",
1446               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1447               << "'bounds_lon_2d' dimension is not compatible with 'nvertex'." << std::endl
1448               << "'bounds_lon_2d' dimension is " << bounds_lon_2d.extent(2)
1449               << " but nvertex is " << nvertex.getValue() << ".");
1450
1451       if (!bounds_lon_1d.isEmpty() && lonvalue_1d.isEmpty())
1452         ERROR("CDomain::checkBounds(void)",
1453               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1454               << "Since 'bounds_lon_1d' is defined, 'lonvalue_1d' must be defined too." << std::endl);
1455
1456       if (!bounds_lon_2d.isEmpty() && lonvalue_2d.isEmpty())
1457         ERROR("CDomain::checkBounds(void)",
1458               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1459               << "Since 'bounds_lon_2d' is defined, 'lonvalue_2d' must be defined too." << std::endl);
1460
1461       if (!bounds_lat_1d.isEmpty() && nvertex.getValue() != bounds_lat_1d.extent(0))
1462         ERROR("CDomain::checkBounds(void)",
1463               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1464               << "'bounds_lat_1d' dimension is not compatible with 'nvertex'." << std::endl
1465               << "'bounds_lat_1d' dimension is " << bounds_lat_1d.extent(1)
1466               << " but nvertex is " << nvertex.getValue() << ".");
1467
1468       if (!bounds_lat_2d.isEmpty() && nvertex.getValue() != bounds_lat_2d.extent(0))
1469         ERROR("CDomain::checkBounds(void)",
1470               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1471               << "'bounds_lat_2d' dimension is not compatible with 'nvertex'." << std::endl
1472               << "'bounds_lat_2d' dimension is " << bounds_lat_2d.extent(2)
1473               << " but nvertex is " << nvertex.getValue() << ".");
1474
1475       if (!bounds_lat_1d.isEmpty() && latvalue_1d.isEmpty())
1476         ERROR("CDomain::checkBounds(void)",
1477               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1478               << "Since 'bounds_lat_1d' is defined, 'latvalue_1d' must be defined too." << std::endl);
1479
1480       if (!bounds_lat_2d.isEmpty() && latvalue_2d.isEmpty())
1481         ERROR("CDomain::checkBounds(void)",
1482               << "Since 'bounds_lat_2d' is defined, 'latvalue_2d' must be defined too." << std::endl);
1483
1484       hasBounds = true;
1485     }
1486     else if (hasBoundValues)
1487     {
1488       hasBounds = true;       
1489     }
1490     else
1491     {
1492       hasBounds = false;
1493       nvertex = 0;
1494     }
1495   }
1496
1497   void CDomain::checkArea(void)
1498   {
1499     bool hasAreaValue = (0 != areavalue.numElements());
1500     hasArea = !area.isEmpty() || !areavalue.isEmpty();
1501     if (hasArea)
1502     {
1503       if (area.extent(0) != ni || area.extent(1) != nj)
1504       {
1505         ERROR("CDomain::checkArea(void)",
1506               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1507               << "The area does not have the same size as the local domain." << std::endl
1508               << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1509               << "Area size is " << area.extent(0) << " x " << area.extent(1) << ".");
1510       }
1511       if (areavalue.isEmpty())
1512       {
1513          areavalue.resize(ni*nj);
1514         for (int j = 0; j < nj; ++j)
1515         {
1516           for (int i = 0; i < ni; ++i)
1517           {
1518             int k = j * ni + i;
1519             areavalue(k) = area(i,j);
1520           }
1521         }
1522       }
1523     }
1524   }
1525
1526   void CDomain::checkLonLat()
1527   {
1528     hasLonLat = (!latvalue_1d.isEmpty() && !lonvalue_1d.isEmpty()) ||
1529                 (!latvalue_2d.isEmpty() && !lonvalue_2d.isEmpty());
1530     bool hasLonLatValue = (0 != lonvalue.numElements()) || (0 != latvalue.numElements());
1531     if (hasLonLat && !hasLonLatValue)
1532     {
1533       if (!lonvalue_1d.isEmpty() && !lonvalue_2d.isEmpty())
1534         ERROR("CDomain::checkLonLat()",
1535               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1536               << "Only one longitude attribute can be used but both 'lonvalue_1d' and 'lonvalue_2d' are defined." << std::endl
1537               << "Define only one longitude attribute: 'lonvalue_1d' or 'lonvalue_2d'.");
1538
1539       if (!lonvalue_1d.isEmpty() && lonvalue_2d.isEmpty())
1540       {
1541         if ((type_attr::rectilinear != type) && (lonvalue_1d.numElements() != i_index.numElements()))
1542           ERROR("CDomain::checkLonLat()",
1543                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1544                 << "'lonvalue_1d' does not have the same size as the local domain." << std::endl
1545                 << "Local size is " << i_index.numElements() << "." << std::endl
1546                 << "'lonvalue_1d' size is " << lonvalue_1d.numElements() << ".");
1547       }
1548
1549       if (lonvalue_1d.isEmpty() && !lonvalue_2d.isEmpty())
1550       {
1551         if (lonvalue_2d.extent(0) != ni || lonvalue_2d.extent(1) != nj)
1552           ERROR("CDomain::checkLonLat()",
1553                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1554                 << "'lonvalue_2d' does not have the same size as the local domain." << std::endl
1555                 << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1556                 << "'lonvalue_2d' size is " << lonvalue_2d.extent(0) << " x " << lonvalue_2d.extent(1) << ".");
1557       }
1558
1559       if (!latvalue_1d.isEmpty() && !latvalue_2d.isEmpty())
1560         ERROR("CDomain::checkLonLat()",
1561               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1562               << "Only one latitude attribute can be used but both 'latvalue_1d' and 'latvalue_2d' are defined." << std::endl
1563               << "Define only one latitude attribute: 'latvalue_1d' or 'latvalue_2d'.");
1564
1565       if (!latvalue_1d.isEmpty() && latvalue_2d.isEmpty())
1566       {
1567         if ((type_attr::rectilinear != type) && (latvalue_1d.numElements() != i_index.numElements()))
1568           ERROR("CDomain::checkLonLat()",
1569                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1570                 << "'latvalue_1d' does not have the same size as the local domain." << std::endl
1571                 << "Local size is " << i_index.numElements() << "." << std::endl
1572                 << "'latvalue_1d' size is " << latvalue_1d.numElements() << ".");
1573       }
1574
1575       if (latvalue_1d.isEmpty() && !latvalue_2d.isEmpty())
1576       {
1577         if (latvalue_2d.extent(0) != ni || latvalue_2d.extent(1) != nj)
1578           ERROR("CDomain::checkLonLat()",
1579                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1580                 << "'latvalue_2d' does not have the same size as the local domain." << std::endl
1581                 << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1582                 << "'latvalue_2d' size is " << latvalue_2d.extent(0) << " x " << latvalue_2d.extent(1) << ".");
1583       }
1584     }
1585   }
1586
1587   void CDomain::checkAttributesOnClientAfterTransformation()
1588   {
1589     CContext* context=CContext::getCurrent() ;
1590
1591     if (this->isClientAfterTransformationChecked) return;
1592     if (context->hasClient)
1593     {
1594      this->computeConnectedClients();
1595       if (hasLonLat)
1596         if (!context->hasServer)
1597           this->completeLonLatClient();
1598     }
1599
1600     this->isClientAfterTransformationChecked = true;
1601   }
1602
1603   //----------------------------------------------------------------
1604   // Divide function checkAttributes into 2 seperate ones
1605   // This function only checks all attributes of current domain
1606   void CDomain::checkAttributesOnClient()
1607   {
1608     if (this->isClientChecked) return;
1609     CContext* context=CContext::getCurrent();
1610
1611      if (context->hasClient && !context->hasServer)
1612      {
1613        this->checkDomain();
1614        this->checkBounds();
1615        this->checkArea();
1616        this->checkLonLat();
1617      }
1618
1619      if (context->hasClient && !context->hasServer)
1620      { // Ct client uniquement
1621         this->checkMask();
1622         this->checkDomainData();
1623         this->checkCompression();
1624         this->computeLocalMask() ;
1625      }
1626      else
1627      { // Ct serveur uniquement
1628      }
1629
1630      this->isClientChecked = true;
1631   }
1632
1633   // Send all checked attributes to server
1634   void CDomain::sendCheckedAttributes()
1635   {
1636     if (!this->isClientChecked) checkAttributesOnClient();
1637     if (!this->isClientAfterTransformationChecked) checkAttributesOnClientAfterTransformation();
1638     CContext* context=CContext::getCurrent() ;
1639
1640     if (this->isChecked) return;
1641     if (context->hasClient)
1642     {
1643       sendAttributes();
1644     }
1645     this->isChecked = true;
1646   }
1647
1648   void CDomain::checkAttributes(void)
1649   {
1650      if (this->isChecked) return;
1651      CContext* context=CContext::getCurrent() ;
1652
1653      this->checkDomain();
1654      this->checkLonLat();
1655      this->checkBounds();
1656      this->checkArea();
1657
1658      if (context->hasClient)
1659      { // Ct client uniquement
1660         this->checkMask();
1661         this->checkDomainData();
1662         this->checkCompression();
1663         this->computeLocalMask() ;
1664
1665      }
1666      else
1667      { // Ct serveur uniquement
1668      }
1669
1670      if (context->hasClient)
1671      {
1672        this->computeConnectedClients();
1673        this->completeLonLatClient();
1674      }
1675
1676      this->isChecked = true;
1677   }
1678
1679  /*!
1680     Compute the connection of a client to other clients to determine which clients to send attributes to.
1681     The sending clients are supposed to already know the distribution of receiving clients (In simple cases, it's band)
1682     The connection among clients is calculated by using global index.
1683     A client connects to other clients which holds the same global index as it.     
1684  */
1685  void CDomain::computeConnectedClients()
1686  {
1687    CContext* context=CContext::getCurrent() ;
1688   
1689    // This line should be changed soon.
1690    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
1691
1692    nbSenders.clear();
1693    connectedServerRank_.clear();
1694
1695    for (int p = 0; p < nbSrvPools; ++p)
1696    {
1697      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
1698      int nbServer = client->serverSize;
1699      int rank     = client->clientRank;
1700      bool doComputeGlobalIndexServer = true;
1701
1702      int i,j,i_ind,j_ind, nbIndex, nbIndexZoom;
1703      int global_zoom_iend=global_zoom_ibegin+global_zoom_ni-1;
1704      int global_zoom_jend=global_zoom_jbegin+global_zoom_nj-1;
1705
1706      // Precompute number of index
1707      int globalIndexCountZoom = 0;
1708      nbIndex = i_index.numElements();
1709
1710      if (doZoomByIndex_) 
1711      {
1712        globalIndexCountZoom = zoom_i_index.numElements();
1713      }
1714      else 
1715      {
1716        for (i = 0; i < nbIndex; ++i)
1717        {
1718          i_ind=i_index(i);
1719          j_ind=j_index(i);
1720
1721          if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1722          {
1723            ++globalIndexCountZoom;
1724          }
1725        }
1726      }
1727
1728
1729      // Fill in index
1730      CArray<size_t,1> globalIndexDomainZoom(globalIndexCountZoom);
1731      CArray<size_t,1> localIndexDomainZoom(globalIndexCountZoom);
1732      CArray<size_t,1> globalIndexDomain(nbIndex);
1733      size_t globalIndex;
1734      int globalIndexCount = 0;
1735
1736      for (i = 0; i < nbIndex; ++i)
1737      {
1738        i_ind=i_index(i);
1739        j_ind=j_index(i);
1740        globalIndex = i_ind + j_ind * ni_glo;
1741        globalIndexDomain(i) = globalIndex;               
1742      }
1743
1744      if (globalLocalIndexMap_.empty())
1745      {
1746        for (i = 0; i < nbIndex; ++i)
1747          globalLocalIndexMap_[globalIndexDomain(i)] = i;
1748      }
1749
1750      globalIndexCountZoom = 0;
1751      if (doZoomByIndex_) 
1752      {
1753        int nbIndexZoom = zoom_i_index.numElements();       
1754       
1755        for (i = 0; i < nbIndexZoom; ++i)
1756        {
1757          i_ind=zoom_i_index(i);
1758          j_ind=zoom_j_index(i);
1759          globalIndex = i_ind + j_ind * ni_glo;
1760          globalIndexDomainZoom(globalIndexCountZoom) = globalIndex;
1761          ++globalIndexCountZoom;
1762        }
1763      }
1764      else 
1765      {
1766          int global_zoom_iend=global_zoom_ibegin+global_zoom_ni-1;
1767          int global_zoom_jend=global_zoom_jbegin+global_zoom_nj-1;
1768          for (i = 0; i < nbIndex; ++i)
1769          {
1770            i_ind=i_index(i);
1771            j_ind=j_index(i);
1772            globalIndex = i_ind + j_ind * ni_glo;
1773            if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1774            {
1775              globalIndexDomainZoom(globalIndexCountZoom) = globalIndex;
1776              ++globalIndexCountZoom;
1777            }
1778          }
1779
1780          int iend = ibegin + ni -1;
1781          int jend = jbegin + nj -1;
1782          zoom_ibegin = global_zoom_ibegin > ibegin ? global_zoom_ibegin : ibegin;
1783          int zoom_iend  = global_zoom_iend < iend ? zoom_iend : iend ;
1784          zoom_ni     = zoom_iend-zoom_ibegin+1 ;
1785
1786          zoom_jbegin = global_zoom_jbegin > jbegin ? global_zoom_jbegin : jbegin ;
1787          int zoom_jend   = global_zoom_jend < jend ? zoom_jend : jend;
1788          zoom_nj     = zoom_jend-zoom_jbegin+1;
1789      }
1790
1791
1792      size_t globalSizeIndex = 1, indexBegin, indexEnd;
1793      int range, clientSize = client->clientSize;
1794      std::vector<int> nGlobDomain(2);
1795      nGlobDomain[0] = this->ni_glo;
1796      nGlobDomain[1] = this->nj_glo;
1797      for (int i = 0; i < nGlobDomain.size(); ++i) globalSizeIndex *= nGlobDomain[i];
1798      indexBegin = 0;
1799      if (globalSizeIndex <= clientSize)
1800      {
1801        indexBegin = rank%globalSizeIndex;
1802        indexEnd = indexBegin;
1803      }
1804      else
1805      {
1806        for (int i = 0; i < clientSize; ++i)
1807        {
1808          range = globalSizeIndex / clientSize;
1809          if (i < (globalSizeIndex%clientSize)) ++range;
1810          if (i == client->clientRank) break;
1811          indexBegin += range;
1812        }
1813        indexEnd = indexBegin + range - 1;
1814      }
1815
1816       // Even if servers have no index, they must received something from client
1817       // We only use several client to send "empty" message to these servers
1818      CServerDistributionDescription serverDescription(nGlobDomain, nbServer);
1819      std::vector<int> serverZeroIndex;
1820      if (isUnstructed_) serverZeroIndex = serverDescription.computeServerGlobalIndexInRange(std::make_pair<size_t,size_t>(indexBegin, indexEnd), 0);
1821      else serverZeroIndex = serverDescription.computeServerGlobalIndexInRange(std::make_pair<size_t,size_t>(indexBegin, indexEnd), 1);
1822
1823       std::list<int> serverZeroIndexLeader;
1824       std::list<int> serverZeroIndexNotLeader; 
1825       CContextClient::computeLeader(client->clientRank, client->clientSize, serverZeroIndex.size(), serverZeroIndexLeader, serverZeroIndexNotLeader);
1826       for (std::list<int>::iterator it = serverZeroIndexLeader.begin(); it != serverZeroIndexLeader.end(); ++it)
1827         *it = serverZeroIndex[*it];
1828
1829      CClientServerMapping* clientServerMap = new CClientServerMappingDistributed(serverDescription.getGlobalIndexRange(),
1830                                                                                  client->intraComm);
1831      clientServerMap->computeServerIndexMapping(globalIndexDomain);
1832      CClientServerMapping::GlobalIndexMap& globalIndexDomainOnServer = clientServerMap->getGlobalIndexOnServer();
1833
1834      CClientServerMapping::GlobalIndexMap::const_iterator it  = globalIndexDomainOnServer.begin(),
1835                                                           ite = globalIndexDomainOnServer.end();
1836      indSrv_[client].swap(globalIndexDomainOnServer);
1837      connectedServerRank_[client].clear();
1838      for (it = indSrv_[client].begin(); it != ite; ++it) 
1839        connectedServerRank_[client].push_back(it->first);
1840
1841      for (std::list<int>::const_iterator it = serverZeroIndexLeader.begin(); it != serverZeroIndexLeader.end(); ++it)
1842        connectedServerRank_[client].push_back(*it);
1843
1844       // Even if a client has no index, it must connect to at least one server and
1845       // send an "empty" data to this server
1846       if (connectedServerRank_[client].empty())
1847        connectedServerRank_[client].push_back(client->clientRank % client->serverSize);
1848
1849      nbSenders[client] = clientServerMap->computeConnectedClients(client->serverSize, client->clientSize, client->intraComm, connectedServerRank_[client]);
1850
1851      delete clientServerMap;
1852    }
1853  }
1854
1855   /*!
1856     Compute index to write data. We only write data on the zoomed region, therefore, there should
1857     be a map between the complete grid and the reduced grid where we write data.
1858     By using global index we can easily create this kind of mapping.
1859   */
1860   void CDomain::computeWrittenIndex()
1861   { 
1862      if (computedWrittenIndex_) return;
1863      computedWrittenIndex_ = true;
1864
1865      CContext* context=CContext::getCurrent();     
1866      CContextServer* server = context->server; 
1867
1868      std::vector<int> nBegin(2), nSize(2), nBeginGlobal(2), nGlob(2);
1869      nBegin[0]       = zoom_ibegin;  nBegin[1] = zoom_jbegin;
1870      nSize[0]        = zoom_ni;      nSize[1]  = zoom_nj;
1871      nBeginGlobal[0] = 0; nBeginGlobal[1] = 0;
1872      nGlob[0]        = ni_glo;   nGlob[1] = nj_glo;
1873      CDistributionServer srvDist(server->intraCommSize, nBegin, nSize, nBeginGlobal, nGlob); 
1874      const CArray<size_t,1>& writtenGlobalIndex  = srvDist.getGlobalIndex();
1875
1876      size_t nbWritten = 0, indGlo;     
1877      boost::unordered_map<size_t,size_t>::const_iterator itb = globalLocalIndexMap_.begin(),
1878                                                          ite = globalLocalIndexMap_.end(), it;         
1879      CArray<size_t,1>::const_iterator itSrvb = writtenGlobalIndex.begin(),
1880                                       itSrve = writtenGlobalIndex.end(), itSrv;
1881
1882      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
1883      {
1884        indGlo = *itSrv;
1885        if (ite != globalLocalIndexMap_.find(indGlo))
1886        {         
1887          ++nbWritten;
1888        }                 
1889      }
1890
1891      localIndexToWriteOnServer.resize(nbWritten);
1892
1893      nbWritten = 0;
1894      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
1895      {
1896        indGlo = *itSrv;
1897        if (ite != globalLocalIndexMap_.find(indGlo))
1898        {
1899          localIndexToWriteOnServer(nbWritten) = globalLocalIndexMap_[indGlo];
1900          ++nbWritten;
1901        }                 
1902      }
1903     
1904      if (isCompressible())
1905      {
1906        nbWritten = 0;
1907        boost::unordered_map<size_t,size_t> localGlobalIndexMap;
1908        for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
1909        {
1910          indGlo = *itSrv;
1911          if (ite != globalLocalIndexMap_.find(indGlo))
1912          {
1913            localGlobalIndexMap[localIndexToWriteOnServer(nbWritten)] = indGlo;
1914            ++nbWritten;
1915          }                 
1916        }
1917
1918        nbWritten = 0;
1919        for (int idx = 0; idx < data_i_index.numElements(); ++idx)
1920        {
1921          if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_i_index(idx)))
1922          {
1923            ++nbWritten;
1924          }
1925        }
1926
1927        compressedIndexToWriteOnServer.resize(nbWritten);
1928        nbWritten = 0;
1929        for (int idx = 0; idx < data_i_index.numElements(); ++idx)
1930        {
1931          if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_i_index(idx)))
1932          {
1933            compressedIndexToWriteOnServer(nbWritten) = localGlobalIndexMap[data_i_index(idx)];
1934            ++nbWritten;
1935          }
1936        }
1937
1938        numberWrittenIndexes_ = nbWritten;
1939        if (isDistributed())
1940        {           
1941          MPI_Allreduce(&numberWrittenIndexes_, &totalNumberWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
1942          MPI_Scan(&numberWrittenIndexes_, &offsetWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
1943          offsetWrittenIndexes_ -= numberWrittenIndexes_;
1944        }
1945        else
1946          totalNumberWrittenIndexes_ = numberWrittenIndexes_;
1947      }     
1948   }
1949
1950  /*!
1951    Send all attributes from client to connected clients
1952    The attributes will be rebuilt on receiving side
1953  */
1954  void CDomain::sendAttributes()
1955  {
1956    sendDistributionAttributes();
1957    sendIndex();       
1958    sendMask();
1959    sendLonLat();
1960    sendArea();   
1961    sendDataIndex();
1962  }
1963
1964  /*!
1965    Send global index and zoom index from client to connected client(s)
1966    zoom index can be smaller than global index
1967  */
1968  void CDomain::sendIndex()
1969  {
1970    int ns, n, i, j, ind, nv, idx;
1971    CContext* context = CContext::getCurrent();
1972
1973    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
1974    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
1975    for (int p = 0; p < nbSrvPools; ++p)
1976    {
1977      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
1978
1979      CEventClient eventIndex(getType(), EVENT_ID_INDEX);
1980
1981      list<CMessage> list_msgsIndex;
1982      list<CArray<int,1> > list_indZoom, list_writtenInd, list_indGlob;
1983
1984      boost::unordered_map<int, vector<size_t> >::const_iterator itIndex, iteIndex;
1985      iteIndex = indSrv_[client].end();
1986      for (int k = 0; k < connectedServerRank_[client].size(); ++k)
1987      {
1988        int nbIndGlob = 0;
1989        int rank = connectedServerRank_[client][k];
1990        itIndex = indSrv_[client].find(rank);
1991        if (iteIndex != itIndex)
1992          nbIndGlob = itIndex->second.size();
1993
1994        list_indGlob.push_back(CArray<int,1>(nbIndGlob));       
1995
1996        CArray<int,1>& indGlob = list_indGlob.back();
1997        for (n = 0; n < nbIndGlob; ++n)
1998        {
1999          indGlob(n) = static_cast<int>(itIndex->second[n]);
2000        }
2001
2002        list_msgsIndex.push_back(CMessage());
2003        list_msgsIndex.back() << this->getId() << (int)type; // enum ne fonctionne pour les message => ToFix
2004        list_msgsIndex.back() << isCurvilinear;
2005        list_msgsIndex.back() << list_indGlob.back(); //list_indi.back() << list_indj.back();
2006       
2007        eventIndex.push(rank, nbSenders[client][rank], list_msgsIndex.back());
2008      }
2009
2010      client->sendEvent(eventIndex);
2011    }
2012  }
2013
2014  /*!
2015    Send distribution from client to other clients
2016    Because a client in a level knows correctly the grid distribution of client on the next level
2017    it calculates this distribution then sends it to the corresponding clients on the next level
2018  */
2019  void CDomain::sendDistributionAttributes(void)
2020  {
2021    CContext* context = CContext::getCurrent();
2022     // Use correct context client to send message
2023    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2024    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2025    for (int i = 0; i < nbSrvPools; ++i)
2026    {
2027      CContextClient* contextClientTmp = (context->hasServer) ? context->clientPrimServer[i]
2028                                                                         : context->client;   
2029      int nbServer = contextClientTmp->serverSize;
2030      std::vector<int> nGlobDomain(2);
2031      nGlobDomain[0] = this->ni_glo;
2032      nGlobDomain[1] = this->nj_glo;
2033
2034      CServerDistributionDescription serverDescription(nGlobDomain, nbServer);
2035      if (isUnstructed_) serverDescription.computeServerDistribution(false, 0);
2036      else serverDescription.computeServerDistribution(false, 1);
2037
2038      std::vector<std::vector<int> > serverIndexBegin = serverDescription.getServerIndexBegin();
2039      std::vector<std::vector<int> > serverDimensionSizes = serverDescription.getServerDimensionSizes();
2040
2041      CEventClient event(getType(),EVENT_ID_SERVER_ATTRIBUT);
2042      if (contextClientTmp->isServerLeader())
2043      {
2044        std::list<CMessage> msgs;
2045
2046        const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
2047        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
2048        {
2049          // Use const int to ensure CMessage holds a copy of the value instead of just a reference
2050          const int ibegin_srv = serverIndexBegin[*itRank][0];
2051          const int jbegin_srv = serverIndexBegin[*itRank][1];
2052          const int ni_srv = serverDimensionSizes[*itRank][0];
2053          const int nj_srv = serverDimensionSizes[*itRank][1];
2054
2055          msgs.push_back(CMessage());
2056          CMessage& msg = msgs.back();
2057          msg << this->getId() ;
2058          msg << ni_srv << ibegin_srv << nj_srv << jbegin_srv;
2059          msg << global_zoom_ni.getValue() << global_zoom_ibegin.getValue() << global_zoom_nj.getValue() << global_zoom_jbegin.getValue();       
2060          msg << isCompressible_;
2061
2062          event.push(*itRank,1,msg);
2063        }
2064        contextClientTmp->sendEvent(event);
2065      }
2066      else contextClientTmp->sendEvent(event);
2067    }
2068  }
2069
2070  /*!
2071    Send mask index from client to connected(s) clients   
2072  */
2073  void CDomain::sendMask()
2074  {
2075    int ns, n, i, j, ind, nv, idx;
2076    CContext* context = CContext::getCurrent();
2077
2078    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2079    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2080    for (int p = 0; p < nbSrvPools; ++p)
2081    {
2082      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
2083
2084      // send area for each connected server
2085      CEventClient eventMask(getType(), EVENT_ID_MASK);
2086
2087      list<CMessage> list_msgsMask;
2088      list<CArray<bool,1> > list_mask;
2089
2090      boost::unordered_map<int, vector<size_t> >::const_iterator it, iteMap;
2091      iteMap = indSrv_[client].end();
2092      for (int k = 0; k < connectedServerRank_[client].size(); ++k)
2093      {
2094        int nbData = 0;
2095        int rank = connectedServerRank_[client][k];
2096        it = indSrv_[client].find(rank);
2097        if (iteMap != it)
2098          nbData = it->second.size();
2099        list_mask.push_back(CArray<bool,1>(nbData));
2100
2101        const std::vector<size_t>& temp = it->second;
2102        for (n = 0; n < nbData; ++n)
2103        {
2104          idx = static_cast<int>(it->second[n]);
2105          list_mask.back()(n) = mask_1d(globalLocalIndexMap_[idx]);
2106        }
2107
2108        list_msgsMask.push_back(CMessage());
2109        list_msgsMask.back() << this->getId() << list_mask.back();
2110        eventMask.push(rank, nbSenders[client][rank], list_msgsMask.back());
2111      }
2112      client->sendEvent(eventMask);
2113    }
2114  }
2115
2116  /*!
2117    Send area from client to connected client(s)
2118  */
2119  void CDomain::sendArea()
2120  {
2121    if (!hasArea) return;
2122
2123    int ns, n, i, j, ind, nv, idx;
2124    CContext* context = CContext::getCurrent();
2125
2126    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2127    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2128    for (int p = 0; p < nbSrvPools; ++p)
2129    {
2130      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
2131
2132      // send area for each connected server
2133      CEventClient eventArea(getType(), EVENT_ID_AREA);
2134
2135      list<CMessage> list_msgsArea;
2136      list<CArray<double,1> > list_area;
2137
2138      boost::unordered_map<int, vector<size_t> >::const_iterator it, iteMap;
2139      iteMap = indSrv_[client].end();
2140      for (int k = 0; k < connectedServerRank_[client].size(); ++k)
2141      {
2142        int nbData = 0;
2143        int rank = connectedServerRank_[client][k];
2144        it = indSrv_[client].find(rank);
2145        if (iteMap != it)
2146          nbData = it->second.size();
2147        list_area.push_back(CArray<double,1>(nbData));
2148
2149        const std::vector<size_t>& temp = it->second;
2150        for (n = 0; n < nbData; ++n)
2151        {
2152          idx = static_cast<int>(it->second[n]);
2153          list_area.back()(n) = areavalue(globalLocalIndexMap_[idx]);
2154        }
2155
2156        list_msgsArea.push_back(CMessage());
2157        list_msgsArea.back() << this->getId() << hasArea;
2158        list_msgsArea.back() << list_area.back();
2159        eventArea.push(rank, nbSenders[client][rank], list_msgsArea.back());
2160      }
2161      client->sendEvent(eventArea);
2162    }
2163  }
2164
2165  /*!
2166    Send longitude and latitude from client to servers
2167    Each client send long and lat information to corresponding connected clients(s).
2168    Because longitude and latitude are optional, this function only called if latitude and longitude exist
2169  */
2170  void CDomain::sendLonLat()
2171  {
2172    if (!hasLonLat) return;
2173
2174    int ns, n, i, j, ind, nv, idx;
2175    CContext* context = CContext::getCurrent();
2176
2177    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2178    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2179    for (int p = 0; p < nbSrvPools; ++p)
2180    {
2181      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
2182
2183      // send lon lat for each connected server
2184      CEventClient eventLon(getType(), EVENT_ID_LON);
2185      CEventClient eventLat(getType(), EVENT_ID_LAT);
2186
2187      list<CMessage> list_msgsLon, list_msgsLat;
2188      list<CArray<double,1> > list_lon, list_lat;
2189      list<CArray<double,2> > list_boundslon, list_boundslat;
2190
2191      boost::unordered_map<int, vector<size_t> >::const_iterator it, iteMap;
2192      iteMap = indSrv_[client].end();
2193      for (int k = 0; k < connectedServerRank_[client].size(); ++k)
2194      {
2195        int nbData = 0;
2196        int rank = connectedServerRank_[client][k];
2197        it = indSrv_[client].find(rank);
2198        if (iteMap != it)
2199          nbData = it->second.size();
2200
2201        list_lon.push_back(CArray<double,1>(nbData));
2202        list_lat.push_back(CArray<double,1>(nbData));
2203
2204        if (hasBounds)
2205        {
2206          list_boundslon.push_back(CArray<double,2>(nvertex, nbData));
2207          list_boundslat.push_back(CArray<double,2>(nvertex, nbData));
2208        }
2209
2210        CArray<double,1>& lon = list_lon.back();
2211        CArray<double,1>& lat = list_lat.back();
2212        const std::vector<size_t>& temp = it->second;
2213        for (n = 0; n < nbData; ++n)
2214        {
2215          idx = static_cast<int>(it->second[n]);
2216          int localInd = globalLocalIndexMap_[idx];
2217          lon(n) = lonvalue(localInd);
2218          lat(n) = latvalue(localInd);
2219
2220          if (hasBounds)
2221          {
2222            CArray<double,2>& boundslon = list_boundslon.back();
2223            CArray<double,2>& boundslat = list_boundslat.back();
2224
2225            for (nv = 0; nv < nvertex; ++nv)
2226            {
2227              boundslon(nv, n) = bounds_lonvalue(nv, localInd);
2228              boundslat(nv, n) = bounds_latvalue(nv, localInd);
2229            }
2230          }
2231        }
2232
2233        list_msgsLon.push_back(CMessage());
2234        list_msgsLat.push_back(CMessage());
2235
2236        list_msgsLon.back() << this->getId() << hasLonLat;
2237        if (hasLonLat) 
2238          list_msgsLon.back() << list_lon.back();
2239        list_msgsLon.back()  << hasBounds;
2240        if (hasBounds)
2241        {
2242          list_msgsLon.back() << list_boundslon.back();
2243        }
2244
2245        list_msgsLat.back() << this->getId() << hasLonLat;
2246        if (hasLonLat)
2247          list_msgsLat.back() << list_lat.back();
2248        list_msgsLat.back() << hasBounds;
2249        if (hasBounds)
2250        {         
2251          list_msgsLat.back() << list_boundslat.back();
2252        }
2253
2254        eventLon.push(rank, nbSenders[client][rank], list_msgsLon.back());
2255        eventLat.push(rank, nbSenders[client][rank], list_msgsLat.back());
2256      }
2257      client->sendEvent(eventLon);
2258      client->sendEvent(eventLat);
2259    }
2260  }
2261
2262  /*!
2263    Send data index to corresponding connected clients.
2264    Data index can be compressed however, we always send decompressed data index
2265    and they will be compressed on receiving.
2266    The compressed index are represented with 1 and others are represented with -1
2267  */
2268  void CDomain::sendDataIndex()
2269  {
2270    int ns, n, i, j, ind, nv, idx;
2271    CContext* context = CContext::getCurrent();
2272
2273    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2274    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2275    for (int p = 0; p < nbSrvPools; ++p)
2276    {
2277      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
2278
2279      // send area for each connected server
2280      CEventClient eventDataIndex(getType(), EVENT_ID_DATA_INDEX);
2281
2282      list<CMessage> list_msgsDataIndex;
2283      list<CArray<int,1> > list_data_i_index, list_data_j_index;
2284
2285      int nbIndex = i_index.numElements();
2286      int niByIndex = max(i_index) - min(i_index) + 1;
2287      int njByIndex = max(j_index) - min(j_index) + 1; 
2288      int dataIindexBound = (1 == data_dim) ? (niByIndex * njByIndex) : niByIndex;
2289      int dataJindexBound = (1 == data_dim) ? (niByIndex * njByIndex) : njByIndex;
2290
2291     
2292      CArray<int,1> dataIIndex(nbIndex), dataJIndex(nbIndex);
2293      dataIIndex = -1; 
2294      dataJIndex = -1;
2295      ind = 0;
2296
2297      for (idx = 0; idx < data_i_index.numElements(); ++idx)
2298      {
2299        int dataIidx = data_i_index(idx) + data_ibegin;
2300        int dataJidx = data_j_index(idx) + data_jbegin;
2301        if ((0 <= dataIidx) && (dataIidx < dataIindexBound) &&
2302            (0 <= dataJidx) && (dataJidx < dataJindexBound))
2303        {
2304          dataIIndex((1 == data_dim) ? dataIidx : dataJidx * ni + dataIidx) = 1; //i_index(dataIidx);//dataIidx;
2305          dataJIndex((1 == data_dim) ? dataIidx : dataJidx * ni + dataIidx) = 1; //j_index(dataJidx);//         
2306        }
2307      }
2308
2309      boost::unordered_map<int, vector<size_t> >::const_iterator it, iteMap;
2310      iteMap = indSrv_[client].end();
2311      for (int k = 0; k < connectedServerRank_[client].size(); ++k)
2312      {
2313        int nbData = 0;
2314        int rank = connectedServerRank_[client][k];
2315        it = indSrv_[client].find(rank);
2316        if (iteMap != it)
2317          nbData = it->second.size();
2318        list_data_i_index.push_back(CArray<int,1>(nbData));
2319        list_data_j_index.push_back(CArray<int,1>(nbData));
2320
2321        const std::vector<size_t>& temp = it->second;
2322        for (n = 0; n < nbData; ++n)
2323        {
2324          idx = static_cast<int>(it->second[n]);
2325          i = globalLocalIndexMap_[idx];
2326          list_data_i_index.back()(n) = dataIIndex(i);
2327          list_data_j_index.back()(n) = dataJIndex(i);
2328        }
2329
2330        list_msgsDataIndex.push_back(CMessage());
2331        list_msgsDataIndex.back() << this->getId();
2332        list_msgsDataIndex.back() << list_data_i_index.back() << list_data_j_index.back();
2333        eventDataIndex.push(rank, nbSenders[client][rank], list_msgsDataIndex.back());
2334      }
2335      client->sendEvent(eventDataIndex);
2336    }
2337  }
2338 
2339  bool CDomain::dispatchEvent(CEventServer& event)
2340  {
2341    if (SuperClass::dispatchEvent(event)) return true;
2342    else
2343    {
2344      switch(event.type)
2345      {
2346        case EVENT_ID_SERVER_ATTRIBUT:
2347          recvDistributionAttributes(event);
2348          return true;
2349          break;
2350        case EVENT_ID_INDEX:
2351          recvIndex(event);
2352          return true;
2353          break;
2354        case EVENT_ID_MASK:
2355          recvMask(event);
2356          return true;
2357          break;
2358        case EVENT_ID_LON:
2359          recvLon(event);
2360          return true;
2361          break;
2362        case EVENT_ID_LAT:
2363          recvLat(event);
2364          return true;
2365          break;
2366        case EVENT_ID_AREA:
2367          recvArea(event);
2368          return true;
2369          break; 
2370        case EVENT_ID_DATA_INDEX:
2371          recvDataIndex(event);
2372          return true;
2373          break;
2374        default:
2375          ERROR("bool CDomain::dispatchEvent(CEventServer& event)",
2376                << "Unknown Event");
2377          return false;
2378       }
2379    }
2380  }
2381
2382  /*!
2383    Receive index event from clients(s)
2384    \param[in] event event contain info about rank and associated index
2385  */
2386  void CDomain::recvIndex(CEventServer& event)
2387  {
2388    string domainId;
2389    std::map<int, CBufferIn*> rankBuffers;
2390
2391    list<CEventServer::SSubEvent>::iterator it;
2392    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2393    {     
2394      CBufferIn* buffer = it->buffer;
2395      *buffer >> domainId;
2396      rankBuffers[it->rank] = buffer;       
2397    }
2398    get(domainId)->recvIndex(rankBuffers);
2399  }
2400
2401  /*!
2402    Receive index information from client(s). We use the global index for mapping index between
2403    sending clients and receiving clients.
2404    \param[in] rankBuffers rank of sending client and the corresponding receive buffer 
2405  */
2406  void CDomain::recvIndex(std::map<int, CBufferIn*>& rankBuffers)
2407  {
2408    int nbReceived = rankBuffers.size(), i, ind, index, type_int;
2409    recvClientRanks_.resize(nbReceived);       
2410
2411    std::map<int, CBufferIn*>::iterator it = rankBuffers.begin(), ite = rankBuffers.end();
2412    ind = 0;
2413    for (ind = 0; it != ite; ++it, ++ind)
2414    {       
2415       recvClientRanks_[ind] = it->first;
2416       CBufferIn& buffer = *(it->second);
2417       buffer >> type_int >> isCurvilinear >> indGlob_[it->first]; 
2418       type.setValue((type_attr::t_enum)type_int); // probleme des type enum avec les buffers : ToFix
2419    }
2420    int nbIndGlob = 0;
2421    for (i = 0; i < nbReceived; ++i)
2422    {
2423      nbIndGlob += indGlob_[recvClientRanks_[i]].numElements();
2424    }
2425   
2426    globalLocalIndexMap_.rehash(std::ceil(nbIndGlob/globalLocalIndexMap_.max_load_factor()));
2427    i_index.resize(nbIndGlob);
2428    j_index.resize(nbIndGlob);   
2429    nbIndGlob = 0;
2430    for (i = 0; i < nbReceived; ++i)
2431    {
2432      CArray<int,1>& tmp = indGlob_[recvClientRanks_[i]];
2433      for (ind = 0; ind < tmp.numElements(); ++ind)
2434      {
2435         index = tmp(ind);
2436         if (0 == globalLocalIndexMap_.count(index))
2437         {
2438           i_index(nbIndGlob) = index % ni_glo;
2439           j_index(nbIndGlob) = index / ni_glo;
2440           globalLocalIndexMap_[index] = nbIndGlob; 
2441           ++nbIndGlob;
2442         } 
2443      } 
2444    } 
2445
2446    i_index.resizeAndPreserve(nbIndGlob);
2447    j_index.resizeAndPreserve(nbIndGlob);
2448  }
2449
2450  /*!
2451    Receive attributes event from clients(s)
2452    \param[in] event event contain info about rank and associated attributes
2453  */
2454  void CDomain::recvDistributionAttributes(CEventServer& event)
2455  {
2456    CBufferIn* buffer=event.subEvents.begin()->buffer;
2457    string domainId ;
2458    *buffer>>domainId ;
2459    get(domainId)->recvDistributionAttributes(*buffer);
2460  }
2461
2462  /*!
2463    Receive attributes from client(s): zoom info and begin and n of each server
2464    \param[in] rank rank of client source
2465    \param[in] buffer message containing attributes info
2466  */
2467  void CDomain::recvDistributionAttributes(CBufferIn& buffer)
2468  {
2469    int ni_tmp, ibegin_tmp, nj_tmp, jbegin_tmp;
2470    int global_zoom_ni_tmp, global_zoom_ibegin_tmp, global_zoom_nj_tmp, global_zoom_jbegin_tmp;
2471    buffer >> ni_tmp >> ibegin_tmp >> nj_tmp >> jbegin_tmp
2472           >> global_zoom_ni_tmp >> global_zoom_ibegin_tmp >> global_zoom_nj_tmp >> global_zoom_jbegin_tmp           
2473           >> isCompressible_;
2474    ni.setValue(ni_tmp);
2475    ibegin.setValue(ibegin_tmp);
2476    nj.setValue(nj_tmp);
2477    jbegin.setValue(jbegin_tmp);
2478
2479    global_zoom_ni.setValue(global_zoom_ni_tmp);
2480    global_zoom_ibegin.setValue(global_zoom_ibegin_tmp);
2481    global_zoom_nj.setValue(global_zoom_nj_tmp);
2482    global_zoom_jbegin.setValue(global_zoom_jbegin_tmp);
2483
2484    int iend = ibegin + ni  - 1;
2485    int jend = jbegin + nj  - 1;
2486    int zoom_iend_glob = global_zoom_ibegin + global_zoom_ni - 1;
2487    int zoom_jend_glob = global_zoom_jbegin + global_zoom_nj - 1;
2488
2489    zoom_ibegin.setValue(global_zoom_ibegin > ibegin ? global_zoom_ibegin : ibegin);
2490    int zoom_iend = zoom_iend_glob < iend ? zoom_iend_glob : iend ;
2491    zoom_ni.setValue(zoom_iend-zoom_ibegin+1);
2492
2493    zoom_jbegin.setValue(global_zoom_jbegin > jbegin ? global_zoom_jbegin : jbegin);
2494    int zoom_jend = zoom_jend_glob < jend ? zoom_jend_glob : jend ;
2495    zoom_nj.setValue(zoom_jend-zoom_jbegin+1);
2496
2497    if (zoom_ni<=0 || zoom_nj<=0)
2498    {
2499      zoom_ibegin=0 ; zoom_iend=0 ; zoom_ni=0 ;
2500      zoom_jbegin=0 ; zoom_jend=0 ; zoom_nj=0 ;
2501    }
2502
2503  }
2504
2505  /*!
2506    Receive area event from clients(s)
2507    \param[in] event event contain info about rank and associated area
2508  */
2509  void CDomain::recvMask(CEventServer& event)
2510  {
2511    string domainId;
2512    std::map<int, CBufferIn*> rankBuffers;
2513
2514    list<CEventServer::SSubEvent>::iterator it;
2515    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2516    {     
2517      CBufferIn* buffer = it->buffer;
2518      *buffer >> domainId;
2519      rankBuffers[it->rank] = buffer;     
2520    }
2521    get(domainId)->recvMask(rankBuffers);
2522  }
2523
2524
2525  /*!
2526    Receive mask information from client(s)
2527    \param[in] rankBuffers rank of sending client and the corresponding receive buffer 
2528  */
2529  void CDomain::recvMask(std::map<int, CBufferIn*>& rankBuffers)
2530  {
2531    int nbReceived = rankBuffers.size(), i, ind, index, lInd;
2532    if (nbReceived != recvClientRanks_.size())
2533      ERROR("void CDomain::recvMask(std::map<int, CBufferIn*>& rankBuffers)",
2534           << "The number of sending clients is not correct."
2535           << "Expected number: " << recvClientRanks_.size() << " but received " << nbReceived);
2536
2537    vector<CArray<bool,1> > recvMaskValue(nbReceived);     
2538    for (i = 0; i < recvClientRanks_.size(); ++i)
2539    {
2540      int rank = recvClientRanks_[i];
2541      CBufferIn& buffer = *(rankBuffers[rank]);     
2542      buffer >> recvMaskValue[i];
2543    }
2544
2545    int nbMaskInd = 0;
2546    for (i = 0; i < nbReceived; ++i)
2547    {
2548      nbMaskInd += recvMaskValue[i].numElements();
2549    }
2550 
2551    if (nbMaskInd != globalLocalIndexMap_.size())
2552      info (0) << "If the domain " << this->getDomainOutputName() <<" does not have overlapped region between processes."
2553               << "Something must be wrong with mask index "<< std::endl;
2554
2555    nbMaskInd = globalLocalIndexMap_.size();
2556    mask_1d.resize(nbMaskInd);
2557   
2558    for (i = 0; i < nbReceived; ++i)
2559    {
2560      CArray<int,1>& tmpInd = indGlob_[recvClientRanks_[i]];
2561      CArray<bool,1>& tmp = recvMaskValue[i];
2562      for (ind = 0; ind < tmp.numElements(); ++ind)
2563      {
2564        lInd = globalLocalIndexMap_[size_t(tmpInd(ind))];
2565        if (!mask_1d(lInd)) // Only rewrite mask_1d if it's not true
2566          mask_1d(lInd) = tmp(ind);
2567      }
2568    }   
2569  }
2570
2571  /*!
2572    Receive longitude event from clients(s)
2573    \param[in] event event contain info about rank and associated longitude
2574  */
2575  void CDomain::recvLon(CEventServer& event)
2576  {
2577    string domainId;
2578    std::map<int, CBufferIn*> rankBuffers;
2579
2580    list<CEventServer::SSubEvent>::iterator it;
2581    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2582    {     
2583      CBufferIn* buffer = it->buffer;
2584      *buffer >> domainId;
2585      rankBuffers[it->rank] = buffer;       
2586    }
2587    get(domainId)->recvLon(rankBuffers);
2588  }
2589
2590  /*!
2591    Receive longitude information from client(s)
2592    \param[in] rankBuffers rank of sending client and the corresponding receive buffer 
2593  */
2594  void CDomain::recvLon(std::map<int, CBufferIn*>& rankBuffers)
2595  {
2596    int nbReceived = rankBuffers.size(), i, ind, index, iindex, jindex, lInd;
2597    if (nbReceived != recvClientRanks_.size())
2598      ERROR("void CDomain::recvLon(std::map<int, CBufferIn*>& rankBuffers)",
2599           << "The number of sending clients is not correct."
2600           << "Expected number: " << recvClientRanks_.size() << " but received " << nbReceived);
2601
2602    vector<CArray<double,1> > recvLonValue(nbReceived);
2603    vector<CArray<double,2> > recvBoundsLonValue(nbReceived);   
2604    for (i = 0; i < recvClientRanks_.size(); ++i)
2605    {
2606      int rank = recvClientRanks_[i];
2607      CBufferIn& buffer = *(rankBuffers[rank]);
2608      buffer >> hasLonLat;
2609      if (hasLonLat)
2610        buffer >> recvLonValue[i];
2611      buffer >> hasBounds;
2612      if (hasBounds)
2613        buffer >> recvBoundsLonValue[i];
2614    }
2615
2616    if (hasLonLat)
2617    {
2618      int nbLonInd = 0;
2619      for (i = 0; i < nbReceived; ++i)
2620      {
2621        nbLonInd += recvLonValue[i].numElements();
2622      }
2623   
2624      if (nbLonInd != globalLocalIndexMap_.size())
2625        info (0) << "If the domain " << this->getDomainOutputName() <<" does not have overlapped region between processes."
2626                 << "Something must be wrong with longitude index "<< std::endl;
2627
2628      nbLonInd = globalLocalIndexMap_.size();
2629      lonvalue.resize(nbLonInd);
2630      if (hasBounds)
2631      {
2632        bounds_lonvalue.resize(nvertex,nbLonInd);
2633        bounds_lonvalue = 0.;
2634      }
2635
2636      nbLonInd = 0;
2637      for (i = 0; i < nbReceived; ++i)
2638      {
2639        CArray<int,1>& tmpInd = indGlob_[recvClientRanks_[i]];
2640        CArray<double,1>& tmp = recvLonValue[i];
2641        for (ind = 0; ind < tmp.numElements(); ++ind)
2642        {
2643          lInd = globalLocalIndexMap_[size_t(tmpInd(ind))];
2644          lonvalue(lInd) = tmp(ind); 
2645           if (hasBounds)
2646           {         
2647            for (int nv = 0; nv < nvertex; ++nv)
2648              bounds_lonvalue(nv, lInd) = recvBoundsLonValue[i](nv, ind);
2649           }                 
2650        }
2651      }       
2652    }
2653  }
2654
2655  /*!
2656    Receive latitude event from clients(s)
2657    \param[in] event event contain info about rank and associated latitude
2658  */
2659  void CDomain::recvLat(CEventServer& event)
2660  {
2661    string domainId;
2662    std::map<int, CBufferIn*> rankBuffers;
2663
2664    list<CEventServer::SSubEvent>::iterator it;
2665    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2666    {     
2667      CBufferIn* buffer = it->buffer;
2668      *buffer >> domainId;
2669      rankBuffers[it->rank] = buffer;   
2670    }
2671    get(domainId)->recvLat(rankBuffers);
2672  }
2673
2674  /*!
2675    Receive latitude information from client(s)
2676    \param[in] rankBuffers rank of sending client and the corresponding receive buffer 
2677  */
2678  void CDomain::recvLat(std::map<int, CBufferIn*>& rankBuffers)
2679  {
2680    int nbReceived = rankBuffers.size(), i, ind, index, iindex, jindex, lInd;
2681    if (nbReceived != recvClientRanks_.size())
2682      ERROR("void CDomain::recvLat(std::map<int, CBufferIn*>& rankBuffers)",
2683           << "The number of sending clients is not correct."
2684           << "Expected number: " << recvClientRanks_.size() << " but received " << nbReceived);
2685
2686    vector<CArray<double,1> > recvLatValue(nbReceived);
2687    vector<CArray<double,2> > recvBoundsLatValue(nbReceived);   
2688    for (i = 0; i < recvClientRanks_.size(); ++i)
2689    {
2690      int rank = recvClientRanks_[i];
2691      CBufferIn& buffer = *(rankBuffers[rank]);
2692      buffer >> hasLonLat;
2693      if (hasLonLat)
2694        buffer >> recvLatValue[i];
2695      buffer >> hasBounds;
2696      if (hasBounds)
2697        buffer >> recvBoundsLatValue[i];
2698    }
2699
2700    if (hasLonLat)
2701    {
2702      int nbLatInd = 0;
2703      for (i = 0; i < nbReceived; ++i)
2704      {
2705        nbLatInd += recvLatValue[i].numElements();
2706      }
2707   
2708      if (nbLatInd != globalLocalIndexMap_.size())
2709        info (0) << "If the domain " << this->getDomainOutputName() <<" does not have overlapped region between processes."
2710                << "Something must be wrong with latitude index "<< std::endl;
2711
2712      nbLatInd = globalLocalIndexMap_.size();
2713      latvalue.resize(nbLatInd);
2714      if (hasBounds)
2715      {
2716        bounds_latvalue.resize(nvertex,nbLatInd);
2717        bounds_latvalue = 0. ;
2718      }
2719
2720      nbLatInd = 0;
2721      for (i = 0; i < nbReceived; ++i)
2722      {
2723        CArray<int,1>& tmpInd = indGlob_[recvClientRanks_[i]];
2724        CArray<double,1>& tmp = recvLatValue[i];
2725        for (ind = 0; ind < tmp.numElements(); ++ind)
2726        {
2727          lInd = globalLocalIndexMap_[size_t(tmpInd(ind))];
2728          latvalue(lInd) = tmp(ind);   
2729           if (hasBounds)
2730           {
2731            CArray<double,2>& boundslat = recvBoundsLatValue[i];
2732            for (int nv = 0; nv < nvertex; ++nv)
2733              bounds_latvalue(nv, lInd) = boundslat(nv, ind);
2734           }   
2735          ++nbLatInd;
2736        }
2737      }       
2738    }
2739  }
2740
2741  /*!
2742    Receive area event from clients(s)
2743    \param[in] event event contain info about rank and associated area
2744  */
2745  void CDomain::recvArea(CEventServer& event)
2746  {
2747    string domainId;
2748    std::map<int, CBufferIn*> rankBuffers;
2749
2750    list<CEventServer::SSubEvent>::iterator it;
2751    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2752    {     
2753      CBufferIn* buffer = it->buffer;
2754      *buffer >> domainId;
2755      rankBuffers[it->rank] = buffer;     
2756    }
2757    get(domainId)->recvArea(rankBuffers);
2758  }
2759
2760  /*!
2761    Receive area information from client(s)
2762    \param[in] rankBuffers rank of sending client and the corresponding receive buffer     
2763  */
2764  void CDomain::recvArea(std::map<int, CBufferIn*>& rankBuffers)
2765  {
2766    int nbReceived = rankBuffers.size(), i, ind, index, lInd;
2767    if (nbReceived != recvClientRanks_.size())
2768      ERROR("void CDomain::recvArea(std::map<int, CBufferIn*>& rankBuffers)",
2769           << "The number of sending clients is not correct."
2770           << "Expected number: " << recvClientRanks_.size() << " but received " << nbReceived);
2771
2772    vector<CArray<double,1> > recvAreaValue(nbReceived);     
2773    for (i = 0; i < recvClientRanks_.size(); ++i)
2774    {
2775      int rank = recvClientRanks_[i];
2776      CBufferIn& buffer = *(rankBuffers[rank]);     
2777      buffer >> hasArea;
2778      if (hasArea)
2779        buffer >> recvAreaValue[i];
2780    }
2781
2782    if (hasArea)
2783    {
2784      int nbAreaInd = 0;
2785      for (i = 0; i < nbReceived; ++i)
2786      {     
2787        nbAreaInd += recvAreaValue[i].numElements();
2788      }
2789
2790      if (nbAreaInd != globalLocalIndexMap_.size())
2791        info (0) << "If the domain " << this->getDomainOutputName() <<" does not have overlapped region between processes."
2792                 << "Something must be wrong with area index "<< std::endl;
2793
2794      nbAreaInd = globalLocalIndexMap_.size();
2795      areavalue.resize(nbAreaInd);
2796      nbAreaInd = 0;     
2797      for (i = 0; i < nbReceived; ++i)
2798      {
2799        CArray<int,1>& tmpInd = indGlob_[recvClientRanks_[i]];
2800        CArray<double,1>& tmp = recvAreaValue[i];
2801        for (ind = 0; ind < tmp.numElements(); ++ind)
2802        {
2803          lInd = globalLocalIndexMap_[size_t(tmpInd(ind))];
2804          areavalue(lInd) = tmp(ind);         
2805        }
2806      }
2807     
2808    }
2809  }
2810
2811  /*!
2812    Compare two domain objects.
2813    They are equal if only if they have identical attributes as well as their values.
2814    Moreover, they must have the same transformations.
2815  \param [in] domain Compared domain
2816  \return result of the comparison
2817  */
2818  bool CDomain::isEqual(CDomain* obj)
2819  {
2820    vector<StdString> excludedAttr;
2821    excludedAttr.push_back("domain_ref");
2822    bool objEqual = SuperClass::isEqual(obj, excludedAttr);
2823    if (!objEqual) return objEqual;
2824
2825    TransMapTypes thisTrans = this->getAllTransformations();
2826    TransMapTypes objTrans  = obj->getAllTransformations();
2827
2828    TransMapTypes::const_iterator it, itb, ite;
2829    std::vector<ETranformationType> thisTransType, objTransType;
2830    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
2831      thisTransType.push_back(it->first);
2832    for (it = objTrans.begin(); it != objTrans.end(); ++it)
2833      objTransType.push_back(it->first);
2834
2835    if (thisTransType.size() != objTransType.size()) return false;
2836    for (int idx = 0; idx < thisTransType.size(); ++idx)
2837      objEqual &= (thisTransType[idx] == objTransType[idx]);
2838
2839    return objEqual;
2840  }
2841
2842  /*!
2843    Receive data index event from clients(s)
2844    \param[in] event event contain info about rank and associated index
2845  */
2846  void CDomain::recvDataIndex(CEventServer& event)
2847  {
2848    string domainId;
2849    std::map<int, CBufferIn*> rankBuffers;
2850
2851    list<CEventServer::SSubEvent>::iterator it;
2852    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2853    {     
2854      CBufferIn* buffer = it->buffer;
2855      *buffer >> domainId;
2856      rankBuffers[it->rank] = buffer;       
2857    }
2858    get(domainId)->recvDataIndex(rankBuffers);
2859  }
2860
2861  /*!
2862    Receive data index information from client(s)
2863    A client receives data index from different clients to rebuild its own data index.
2864    Because the data index is local, to rebuild data index of received client, we should use global index along with.
2865    \param[in] rankBuffers rank of sending client and the corresponding receive buffer     
2866  */
2867  void CDomain::recvDataIndex(std::map<int, CBufferIn*>& rankBuffers)
2868  {
2869    int nbReceived = rankBuffers.size(), i, ind, index, indexI, indexJ, type_int, lInd;   
2870    if (nbReceived != recvClientRanks_.size())
2871      ERROR("void CDomain::recvDataIndex(std::map<int, CBufferIn*>& rankBuffers)",
2872           << "The number of sending clients is not correct."
2873           << "Expected number: " << recvClientRanks_.size() << " but received " << nbReceived);
2874
2875    vector<CArray<int,1> > recvDataIIndex(nbReceived),recvDataJIndex(nbReceived);     
2876    for (i = 0; i < recvClientRanks_.size(); ++i)
2877    {
2878      int rank = recvClientRanks_[i];
2879      CBufferIn& buffer = *(rankBuffers[rank]);
2880      buffer >> recvDataIIndex[i];
2881      buffer >> recvDataJIndex[i];
2882    }
2883   
2884    int nbIndex = i_index.numElements();
2885    CArray<int,1> dataIIndex(nbIndex), dataJIndex(nbIndex);
2886    dataIIndex = -1; dataJIndex = -1;
2887     
2888    nbIndex = 0;
2889    for (i = 0; i < nbReceived; ++i)
2890    {     
2891      CArray<int,1>& tmpInd = indGlob_[recvClientRanks_[i]];
2892      CArray<int,1>& tmpI = recvDataIIndex[i];   
2893      CArray<int,1>& tmpJ = recvDataJIndex[i];     
2894      if ((tmpI.numElements() != tmpInd.numElements()) || (tmpJ.numElements() != tmpInd.numElements()))
2895          ERROR("void CDomain::recvDataIndex(std::map<int, CBufferIn*>& rankBuffers)",
2896             << "The number of global received index is not coherent with the number of received data index."
2897             << "Expected number of global index: " << tmpI.numElements() << " but received " << tmpInd.numElements());
2898
2899      for (ind = 0; ind < tmpI.numElements(); ++ind)
2900      {
2901         lInd = globalLocalIndexMap_[size_t(tmpInd(ind))];
2902         dataIIndex(lInd) = (-1 == dataIIndex(lInd)) ? tmpI(ind) : dataIIndex(lInd); // Only fill in dataIndex if there is no data
2903         dataJIndex(lInd) = (-1 == dataJIndex(lInd)) ? tmpJ(ind) : dataJIndex(lInd);         
2904      } 
2905    }
2906
2907    int nbCompressedData = 0; 
2908    for (ind = 0; ind < dataIIndex.numElements(); ++ind)
2909    {
2910       indexI = dataIIndex(ind); indexJ = dataJIndex(ind);
2911       if ((0 <= indexI) && (0 <= indexJ))
2912         ++nbCompressedData;
2913    }       
2914 
2915    data_i_index.resize(nbCompressedData);
2916    data_j_index.resize(nbCompressedData);
2917
2918    nbCompressedData = 0; 
2919    for (ind = 0; ind < dataIIndex.numElements(); ++ind)
2920    {
2921       indexI = dataIIndex(ind); indexJ = dataJIndex(ind);
2922       if ((0 <= indexI) && (0 <= indexJ))
2923       {
2924          data_i_index(nbCompressedData) = (1 == data_dim) ? ind : ind % ni;
2925          data_j_index(nbCompressedData) = (1 == data_dim) ? 0   : ind / ni;
2926         ++nbCompressedData;
2927       }
2928    }
2929
2930    // Reset data_ibegin, data_jbegin
2931    data_ibegin.setValue(0);
2932    data_jbegin.setValue(0);
2933  }
2934
2935  CTransformation<CDomain>* CDomain::addTransformation(ETranformationType transType, const StdString& id)
2936  {
2937    transformationMap_.push_back(std::make_pair(transType, CTransformation<CDomain>::createTransformation(transType,id)));
2938    return transformationMap_.back().second;
2939  }
2940
2941  /*!
2942    Check whether a domain has transformation
2943    \return true if domain has transformation
2944  */
2945  bool CDomain::hasTransformation()
2946  {
2947    return (!transformationMap_.empty());
2948  }
2949
2950  /*!
2951    Set transformation for current domain. It's the method to move transformation in hierarchy
2952    \param [in] domTrans transformation on domain
2953  */
2954  void CDomain::setTransformations(const TransMapTypes& domTrans)
2955  {
2956    transformationMap_ = domTrans;
2957  }
2958
2959  /*!
2960    Get all transformation current domain has
2961    \return all transformation
2962  */
2963  CDomain::TransMapTypes CDomain::getAllTransformations(void)
2964  {
2965    return transformationMap_;
2966  }
2967
2968  void CDomain::duplicateTransformation(CDomain* src)
2969  {
2970    if (src->hasTransformation())
2971    {
2972      this->setTransformations(src->getAllTransformations());
2973    }
2974  }
2975
2976  /*!
2977   * Go through the hierarchy to find the domain from which the transformations must be inherited
2978   */
2979  void CDomain::solveInheritanceTransformation()
2980  {
2981    if (hasTransformation() || !hasDirectDomainReference())
2982      return;
2983
2984    CDomain* domain = this;
2985    std::vector<CDomain*> refDomains;
2986    while (!domain->hasTransformation() && domain->hasDirectDomainReference())
2987    {
2988      refDomains.push_back(domain);
2989      domain = domain->getDirectDomainReference();
2990    }
2991
2992    if (domain->hasTransformation())
2993      for (size_t i = 0; i < refDomains.size(); ++i)
2994        refDomains[i]->setTransformations(domain->getAllTransformations());
2995  }
2996
2997  /*!
2998    Parse children nodes of a domain in xml file.
2999    Whenver there is a new transformation, its type and name should be added into this function
3000    \param node child node to process
3001  */
3002  void CDomain::parse(xml::CXMLNode & node)
3003  {
3004    SuperClass::parse(node);
3005
3006    if (node.goToChildElement())
3007    {
3008      StdString nodeElementName;
3009      do
3010      {
3011        StdString nodeId("");
3012        if (node.getAttributes().end() != node.getAttributes().find("id"))
3013        { nodeId = node.getAttributes()["id"]; }
3014
3015        nodeElementName = node.getElementName();
3016        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
3017        it = transformationMapList_.find(nodeElementName);
3018        if (ite != it)
3019        {
3020          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CDomain>::createTransformation(it->second,
3021                                                                                                                nodeId,
3022                                                                                                                &node)));
3023        }
3024        else
3025        {
3026          ERROR("void CDomain::parse(xml::CXMLNode & node)",
3027                << "The transformation " << nodeElementName << " has not been supported yet.");
3028        }
3029      } while (node.goToNextElement()) ;
3030      node.goToParentElement();
3031    }
3032  }
3033   //----------------------------------------------------------------
3034
3035   DEFINE_REF_FUNC(Domain,domain)
3036
3037   ///---------------------------------------------------------------
3038
3039} // namespace xios
Note: See TracBrowser for help on using the repository browser.