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

Last change on this file since 1227 was 1223, checked in by oabramkina, 7 years ago

Fixing a bug in case of overlapping domains with masked values. Tested with the IPSL model.

  • 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: 112.4 KB
Line 
1#include "domain.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6
7#include "xios_spl.hpp"
8#include "event_client.hpp"
9#include "event_server.hpp"
10#include "buffer_in.hpp"
11#include "message.hpp"
12#include "type.hpp"
13#include "context.hpp"
14#include "context_client.hpp"
15#include "context_server.hpp"
16#include "array_new.hpp"
17#include "distribution_client.hpp"
18#include "server_distribution_description.hpp"
19#include "client_server_mapping_distributed.hpp"
20#include "zoom_domain.hpp"
21#include "interpolate_domain.hpp"
22#include "generate_rectilinear_domain.hpp"
23
24#include <algorithm>
25
26namespace xios {
27
28   /// ////////////////////// Définitions ////////////////////// ///
29
30   CDomain::CDomain(void)
31      : CObjectTemplate<CDomain>(), CDomainAttributes()
32      , isChecked(false), relFiles(), isClientChecked(false), nbConnectedClients_(), indSrv_(), connectedServerRank_(), connectedServerZoomRank_()
33      , hasBounds(false), hasArea(false), isCompressible_(false), isUnstructed_(false)
34      , isClientAfterTransformationChecked(false), hasLonLat(false)
35      , isRedistributed_(false), hasPole(false), doZoomByIndex_(false)
36      , lonvalue(), latvalue(), bounds_lonvalue(), bounds_latvalue()
37      , globalLocalIndexMap_(), computedWrittenIndex_(false)
38   {
39   }
40
41   CDomain::CDomain(const StdString & id)
42      : CObjectTemplate<CDomain>(id), CDomainAttributes()
43      , isChecked(false), relFiles(), isClientChecked(false), nbConnectedClients_(), indSrv_(), connectedServerRank_(), connectedServerZoomRank_()
44      , hasBounds(false), hasArea(false), isCompressible_(false), isUnstructed_(false)
45      , isClientAfterTransformationChecked(false), hasLonLat(false)
46      , isRedistributed_(false), hasPole(false), doZoomByIndex_(false)
47      , lonvalue(), latvalue(), bounds_lonvalue(), bounds_latvalue()
48      , globalLocalIndexMap_(), computedWrittenIndex_(false)
49   {
50         }
51
52   CDomain::~CDomain(void)
53   {
54   }
55
56   ///---------------------------------------------------------------
57
58   void CDomain::assignMesh(const StdString meshName, const int nvertex)
59   {
60     mesh = CMesh::getMesh(meshName, nvertex);
61   }
62
63   CDomain* CDomain::createDomain()
64   {
65     CDomain* domain = CDomainGroup::get("domain_definition")->createChild();
66     return domain;
67   }
68
69   std::map<StdString, ETranformationType> CDomain::transformationMapList_ = std::map<StdString, ETranformationType>();
70   bool CDomain::_dummyTransformationMapList = CDomain::initializeTransformationMap(CDomain::transformationMapList_);
71
72   bool CDomain::initializeTransformationMap(std::map<StdString, ETranformationType>& m)
73   {
74     m["zoom_domain"] = TRANS_ZOOM_DOMAIN;
75     m["interpolate_domain"] = TRANS_INTERPOLATE_DOMAIN;
76     m["generate_rectilinear_domain"] = TRANS_GENERATE_RECTILINEAR_DOMAIN;
77     m["compute_connectivity_domain"] = TRANS_COMPUTE_CONNECTIVITY_DOMAIN;
78     m["expand_domain"] = TRANS_EXPAND_DOMAIN;
79   }
80
81   const std::set<StdString> & CDomain::getRelFiles(void) const
82   {
83      return (this->relFiles);
84   }
85
86
87   /*!
88     Returns the number of indexes written by each server.
89     \return the number of indexes written by each server
90   */
91   int CDomain::getNumberWrittenIndexes() const
92   {
93     return numberWrittenIndexes_;
94   }
95
96   /*!
97     Returns the total number of indexes written by the servers.
98     \return the total number of indexes written by the servers
99   */
100   int CDomain::getTotalNumberWrittenIndexes() const
101   {
102     return totalNumberWrittenIndexes_;
103   }
104
105   /*!
106     Returns the offset of indexes written by each server.
107     \return the offset of indexes written by each server
108   */
109   int CDomain::getOffsetWrittenIndexes() const
110   {
111     return offsetWrittenIndexes_;
112   }
113
114   //----------------------------------------------------------------
115
116   /*!
117    * Compute the minimum buffer size required to send the attributes to the server(s).
118    *
119    * \return A map associating the server rank with its minimum buffer size.
120    */
121   std::map<int, StdSize> CDomain::getAttributesBufferSize()
122   {
123     CContext* context = CContext::getCurrent();
124     // For now the assumption is that secondary server pools consist of the same number of procs.
125     // CHANGE the line below if the assumption changes.
126     CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[0] : context->client;
127
128     std::map<int, StdSize> attributesSizes = getMinimumBufferSizeForAttributes();
129
130     if (client->isServerLeader())
131     {
132       // size estimation for sendDistributionAttribut
133       size_t size = 11 * sizeof(size_t);
134
135       const std::list<int>& ranks = client->getRanksServerLeader();
136       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
137       {
138         if (size > attributesSizes[*itRank])
139           attributesSizes[*itRank] = size;
140       }
141     }
142
143     boost::unordered_map<int, vector<size_t> >::const_iterator itIndexEnd = indSrv_.end();
144     std::map<int, std::vector<int> >::const_iterator itWrittenIndexEnd = indWrittenSrv_.end();
145     for (size_t k = 0; k < connectedServerRank_.size(); ++k)
146     {
147       int rank = connectedServerRank_[k];
148       boost::unordered_map<int, std::vector<size_t> >::const_iterator it = indSrv_.find(rank);
149       size_t idxCount = (it != itIndexEnd) ? it->second.size() : 0;
150
151       // size estimation for sendIndex (and sendArea which is always smaller or equal)
152       size_t sizeIndexEvent = 2 * sizeof(size_t) + 2 * CArray<int,1>::size(idxCount);
153       if (isCompressible_)
154       {
155         std::map<int, std::vector<int> >::const_iterator itWritten = indWrittenSrv_.find(rank);
156         size_t writtenIdxCount = (itWritten != itWrittenIndexEnd) ? itWritten->second.size() : 0;
157         sizeIndexEvent += CArray<int,1>::size(writtenIdxCount);
158       }
159
160       // size estimation for sendLonLat
161       size_t sizeLonLatEvent = CArray<double,1>::size(idxCount);
162       if (hasBounds)
163         sizeLonLatEvent += CArray<double,2>::size(nvertex * idxCount);
164
165       size_t size = CEventClient::headerSize + getId().size() + sizeof(size_t) + std::max(sizeIndexEvent, sizeLonLatEvent);
166       if (size > attributesSizes[rank])
167         attributesSizes[rank] = size;
168     }
169
170     return attributesSizes;
171   }
172
173   //----------------------------------------------------------------
174
175   bool CDomain::isEmpty(void) const
176   {
177      return ((this->zoom_i_index.isEmpty()) || (0 == this->zoom_i_index.numElements()));
178
179   }
180
181   //----------------------------------------------------------------
182
183   bool CDomain::IsWritten(const StdString & filename) const
184   {
185      return (this->relFiles.find(filename) != this->relFiles.end());
186   }
187
188   bool CDomain::isWrittenCompressed(const StdString& filename) const
189   {
190      return (this->relFilesCompressed.find(filename) != this->relFilesCompressed.end());
191   }
192
193   //----------------------------------------------------------------
194
195   bool CDomain::isDistributed(void) const
196   {
197      bool distributed =  !((!ni.isEmpty() && (ni == ni_glo) && !nj.isEmpty() && (nj == nj_glo)) ||
198              (!i_index.isEmpty() && i_index.numElements() == ni_glo*nj_glo));
199      distributed |= (1 == CContext::getCurrent()->client->clientSize);
200
201      return distributed;
202   }
203
204   //----------------------------------------------------------------
205
206   /*!
207    * Test whether the data defined on the domain can be outputted in a compressed way.
208    *
209    * \return true if and only if a mask was defined for this domain
210    */
211   bool CDomain::isCompressible(void) const
212   {
213      return isCompressible_;
214   }
215
216   void CDomain::addRelFile(const StdString & filename)
217   {
218      this->relFiles.insert(filename);
219   }
220
221   void CDomain::addRelFileCompressed(const StdString& filename)
222   {
223      this->relFilesCompressed.insert(filename);
224   }
225
226   StdString CDomain::GetName(void)   { return (StdString("domain")); }
227   StdString CDomain::GetDefName(void){ return (CDomain::GetName()); }
228   ENodeType CDomain::GetType(void)   { return (eDomain); }
229
230   //----------------------------------------------------------------
231
232   /*!
233      Verify if all distribution information of a domain are available
234      This checking verifies the definition of distribution attributes (ni, nj, ibegin, jbegin)
235   */
236   bool CDomain::distributionAttributesHaveValue() const
237   {
238      bool hasValues = true;
239
240      if (ni.isEmpty() && ibegin.isEmpty() && i_index.isEmpty())
241      {
242        hasValues = false;
243        return hasValues;
244      }
245
246      return hasValues;
247   }
248
249   /*!
250     Redistribute RECTILINEAR domain with a number of local domains.
251   All attributes ni,nj,ibegin,jbegin (if defined) will be rewritten
252   The optional attributes lonvalue, latvalue will be added. Because this function only serves (for now)
253   for interpolation from unstructured domain to rectilinear one, range of latvalue is 0-360 and lonvalue is -90 - +90
254    \param [in] nbLocalDomain number of local domain on the domain destination
255   */
256   void CDomain::redistribute(int nbLocalDomain)
257   {
258     if (this->isRedistributed_) return;
259
260     this->isRedistributed_ = true;
261     CContext* context = CContext::getCurrent();
262     // For now the assumption is that secondary server pools consist of the same number of procs.
263     // CHANGE the line below if the assumption changes.
264     CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[0] : context->client;
265     int rankClient = client->clientRank;
266     int rankOnDomain = rankClient%nbLocalDomain;
267
268     if (ni_glo.isEmpty() || ni_glo <= 0 )
269     {
270        ERROR("CDomain::redistribute(int nbLocalDomain)",
271           << "[ Id = " << this->getId() << " ] "
272           << "The global domain is badly defined,"
273           << " check the \'ni_glo\'  value !")
274     }
275
276     if (nj_glo.isEmpty() || nj_glo <= 0 )
277     {
278        ERROR("CDomain::redistribute(int nbLocalDomain)",
279           << "[ Id = " << this->getId() << " ] "
280           << "The global domain is badly defined,"
281           << " check the \'nj_glo\'  value !")
282     }
283
284     if ((type_attr::rectilinear == type)  || (type_attr::curvilinear == type))
285     {
286        int globalDomainSize = ni_glo * nj_glo;
287        if (globalDomainSize <= nbLocalDomain)
288        {
289          for (int idx = 0; idx < nbLocalDomain; ++idx)
290          {
291            if (rankOnDomain < globalDomainSize)
292            {
293              int iIdx = rankOnDomain % ni_glo;
294              int jIdx = rankOnDomain / ni_glo;
295              ibegin.setValue(iIdx); jbegin.setValue(jIdx);
296              ni.setValue(1); nj.setValue(1);
297            }
298            else
299            {
300              ibegin.setValue(0); jbegin.setValue(0);
301              ni.setValue(0); nj.setValue(0);
302            }
303          }
304        }
305        else
306        {
307          float njGlo = nj_glo.getValue();
308          float niGlo = ni_glo.getValue();
309          int nbProcOnX, nbProcOnY, range;
310
311          // Compute (approximately) number of segment on x and y axis
312          float yOverXRatio = njGlo/niGlo;
313
314          nbProcOnX = std::ceil(std::sqrt(nbLocalDomain/yOverXRatio));
315          nbProcOnY = std::ceil(((float)nbLocalDomain)/nbProcOnX);
316
317          // Simple distribution: Sweep from top to bottom, left to right
318          // Calculate local begin on x
319          std::vector<int> ibeginVec(nbProcOnX,0), jbeginVec(nbProcOnY,0);
320          std::vector<int> niVec(nbProcOnX), njVec(nbProcOnY);
321          for (int i = 1; i < nbProcOnX; ++i)
322          {
323            range = ni_glo / nbProcOnX;
324            if (i < (ni_glo%nbProcOnX)) ++range;
325            niVec[i-1] = range;
326            ibeginVec[i] = ibeginVec[i-1] + niVec[i-1];
327          }
328          niVec[nbProcOnX-1] = ni_glo - ibeginVec[nbProcOnX-1];
329
330          // Calculate local begin on y
331          for (int j = 1; j < nbProcOnY; ++j)
332          {
333            range = nj_glo / nbProcOnY;
334            if (j < (nj_glo%nbProcOnY)) ++range;
335            njVec[j-1] = range;
336            jbeginVec[j] = jbeginVec[j-1] + njVec[j-1];
337          }
338          njVec[nbProcOnY-1] = nj_glo - jbeginVec[nbProcOnY-1];
339
340          // Now assign value to ni, ibegin, nj, jbegin
341          int iIdx = rankOnDomain % nbProcOnX;
342          int jIdx = rankOnDomain / nbProcOnX;
343
344          if (rankOnDomain != (nbLocalDomain-1))
345          {
346            ibegin.setValue(ibeginVec[iIdx]);
347            jbegin.setValue(jbeginVec[jIdx]);
348            nj.setValue(njVec[jIdx]);
349            ni.setValue(niVec[iIdx]);
350          }
351          else // just merge all the remaining rectangle into the last one
352          {
353            ibegin.setValue(ibeginVec[iIdx]);
354            jbegin.setValue(jbeginVec[jIdx]);
355            nj.setValue(njVec[jIdx]);
356            ni.setValue(ni_glo - ibeginVec[iIdx]);
357          }
358        } 
359     }
360     else  // unstructured domain
361     {
362       if (this->i_index.isEmpty())
363       {
364          int globalDomainSize = ni_glo * nj_glo;
365          if (globalDomainSize <= nbLocalDomain)
366          {
367            for (int idx = 0; idx < nbLocalDomain; ++idx)
368            {
369              if (rankOnDomain < globalDomainSize)
370              {
371                int iIdx = rankOnDomain % ni_glo;
372                int jIdx = rankOnDomain / ni_glo;
373                ibegin.setValue(iIdx); jbegin.setValue(jIdx);
374                ni.setValue(1); nj.setValue(1);
375              }
376              else
377              {
378                ibegin.setValue(0); jbegin.setValue(0);
379                ni.setValue(0); nj.setValue(0);
380              }
381            }
382          }
383          else
384          {
385            float njGlo = nj_glo.getValue();
386            float niGlo = ni_glo.getValue();
387            std::vector<int> ibeginVec(nbLocalDomain,0);
388            std::vector<int> niVec(nbLocalDomain);
389            for (int i = 1; i < nbLocalDomain; ++i)
390            {
391              int range = ni_glo / nbLocalDomain;
392              if (i < (ni_glo%nbLocalDomain)) ++range;
393              niVec[i-1] = range;
394              ibeginVec[i] = ibeginVec[i-1] + niVec[i-1];
395            }
396            niVec[nbLocalDomain-1] = ni_glo - ibeginVec[nbLocalDomain-1];
397
398            int iIdx = rankOnDomain % nbLocalDomain;
399            ibegin.setValue(ibeginVec[iIdx]);
400            jbegin.setValue(0);
401            ni.setValue(niVec[iIdx]);
402            nj.setValue(1);
403          }
404
405          i_index.resize(ni);         
406          for(int idx = 0; idx < ni; ++idx) i_index(idx)=ibegin+idx;
407        }
408        else
409        {
410          ibegin.setValue(this->i_index(0));
411          jbegin.setValue(0);
412          ni.setValue(this->i_index.numElements());
413          nj.setValue(1);
414        }
415     }
416
417     checkDomain();
418   }
419
420   /*!
421     Fill in longitude and latitude whose values are read from file
422   */
423   void CDomain::fillInLonLat()
424   {
425     switch (type)
426     {
427      case type_attr::rectilinear:
428        fillInRectilinearLonLat();
429        break;
430      case type_attr::curvilinear:
431        fillInCurvilinearLonLat();
432        break;
433      case type_attr::unstructured:
434        fillInUnstructuredLonLat();
435        break;
436
437      default:
438      break;
439     }
440
441   }
442
443   /*!
444     Fill in the values for lonvalue_1d and latvalue_1d of rectilinear domain
445     Range of longitude value from 0 - 360
446     Range of latitude value from -90 - +90
447   */
448   void CDomain::fillInRectilinearLonLat()
449   {
450     if (!lonvalue_rectilinear_read_from_file.isEmpty())
451     {
452       lonvalue_1d.resize(ni);
453       for (int idx = 0; idx < ni; ++idx)
454         lonvalue_1d(idx) = lonvalue_rectilinear_read_from_file(idx+ibegin);
455       lon_start.setValue(lonvalue_rectilinear_read_from_file(0));
456       lon_end.setValue(lonvalue_rectilinear_read_from_file(ni_glo-1));
457     }
458     else
459     {
460       if (!lonvalue_2d.isEmpty()) lonvalue_2d.free();
461       lonvalue_1d.resize(ni);
462       double lonRange = lon_end - lon_start;
463       double lonStep = (1 == ni_glo.getValue()) ? lonRange : lonRange/double(ni_glo.getValue()-1);
464
465        // Assign lon value
466       for (int i = 0; i < ni; ++i)
467       {
468         if (0 == (ibegin + i))
469         {
470           lonvalue_1d(i) = lon_start;
471         }
472         else if (ni_glo == (ibegin + i + 1))
473         {
474           lonvalue_1d(i) = lon_end;
475         }
476         else
477         {
478           lonvalue_1d(i) = (ibegin + i) * lonStep  + lon_start;
479         }
480       }
481     }
482
483
484     if (!latvalue_rectilinear_read_from_file.isEmpty())
485     {
486       latvalue_1d.resize(nj);
487       for (int idx = 0; idx < nj; ++idx)
488         latvalue_1d(idx) = latvalue_rectilinear_read_from_file(idx+jbegin);
489       lat_start.setValue(latvalue_rectilinear_read_from_file(0));
490       lat_end.setValue(latvalue_rectilinear_read_from_file(nj_glo-1));
491     }
492     else
493     {
494       if (!latvalue_2d.isEmpty()) latvalue_1d.free();
495       latvalue_1d.resize(nj);
496
497       double latRange = lat_end - lat_start;
498       double latStep = (1 == nj_glo.getValue()) ? latRange : latRange/double(nj_glo.getValue()-1);
499
500       for (int j = 0; j < nj; ++j)
501       {
502         if (0 == (jbegin + j))
503         {
504            latvalue_1d(j) = lat_start;
505         }
506         else if (nj_glo == (jbegin + j + 1))
507         {
508            latvalue_1d(j) = lat_end;
509         }
510         else
511         {
512           latvalue_1d(j) =  (jbegin + j) * latStep + lat_start;
513         }
514       }
515     }
516   }
517
518    /*
519      Fill in longitude and latitude of curvilinear domain read from a file
520      If there are already longitude and latitude defined by model. We just igonore reading value.
521    */
522   void CDomain::fillInCurvilinearLonLat()
523   {
524     if (!lonvalue_curvilinear_read_from_file.isEmpty() && lonvalue_2d.isEmpty())
525     {
526       lonvalue_2d.resize(ni,nj);
527       for (int jdx = 0; jdx < nj; ++jdx)
528        for (int idx = 0; idx < ni; ++idx)
529         lonvalue_2d(idx,jdx) = lonvalue_curvilinear_read_from_file(idx+ibegin, jdx+jbegin);
530
531       lonvalue_curvilinear_read_from_file.free();
532     }
533
534     if (!latvalue_curvilinear_read_from_file.isEmpty() && latvalue_2d.isEmpty())
535     {
536       latvalue_2d.resize(ni,nj);
537       for (int jdx = 0; jdx < nj; ++jdx)
538        for (int idx = 0; idx < ni; ++idx)
539         latvalue_2d(idx,jdx) = latvalue_curvilinear_read_from_file(idx+ibegin, jdx+jbegin);
540
541       latvalue_curvilinear_read_from_file.free();
542     }
543
544     if (!bounds_lonvalue_curvilinear_read_from_file.isEmpty() && bounds_lon_2d.isEmpty())
545     {
546       bounds_lon_2d.resize(nvertex,ni,nj);
547       for (int jdx = 0; jdx < nj; ++jdx)
548        for (int idx = 0; idx < ni; ++idx)
549          for (int ndx = 0; ndx < nvertex; ++ndx)
550         bounds_lon_2d(ndx,idx,jdx) = bounds_lonvalue_curvilinear_read_from_file(ndx,idx+ibegin, jdx+jbegin);
551
552       bounds_lonvalue_curvilinear_read_from_file.free();
553     }
554
555     if (!bounds_latvalue_curvilinear_read_from_file.isEmpty() && bounds_lat_2d.isEmpty())
556     {
557       bounds_lat_2d.resize(nvertex,ni,nj);
558       for (int jdx = 0; jdx < nj; ++jdx)
559        for (int idx = 0; idx < ni; ++idx)
560          for (int ndx = 0; ndx < nvertex; ++ndx)
561            bounds_lat_2d(ndx,idx,jdx) = bounds_latvalue_curvilinear_read_from_file(ndx,idx+ibegin, jdx+jbegin);
562
563       bounds_latvalue_curvilinear_read_from_file.free();
564     }
565
566   }
567
568    /*
569      Fill in longitude and latitude of unstructured domain read from a file
570      If there are already longitude and latitude defined by model. We just igonore reading value.
571    */
572   void CDomain::fillInUnstructuredLonLat()
573   {
574     if (i_index.isEmpty())
575     {
576       i_index.resize(ni);
577       for(int idx = 0; idx < ni; ++idx) i_index(idx)=ibegin+idx;
578     }
579
580     if (!lonvalue_unstructured_read_from_file.isEmpty() && lonvalue_1d.isEmpty())
581     {
582        lonvalue_1d.resize(ni);
583        for (int idx = 0; idx < ni; ++idx)
584          lonvalue_1d(idx) = lonvalue_unstructured_read_from_file(i_index(idx));
585
586        // We dont need these values anymore, so just delete them
587        lonvalue_unstructured_read_from_file.free();
588     } 
589
590     if (!latvalue_unstructured_read_from_file.isEmpty() && latvalue_1d.isEmpty())
591     {
592        latvalue_1d.resize(ni);
593        for (int idx = 0; idx < ni; ++idx)
594          latvalue_1d(idx) =  latvalue_unstructured_read_from_file(i_index(idx));
595
596        // We dont need these values anymore, so just delete them
597        latvalue_unstructured_read_from_file.free();
598     }
599
600     if (!bounds_lonvalue_unstructured_read_from_file.isEmpty() && bounds_lon_1d.isEmpty())
601     {
602        int nbVertex = nvertex;
603        bounds_lon_1d.resize(nbVertex,ni);
604        for (int idx = 0; idx < ni; ++idx)
605          for (int jdx = 0; jdx < nbVertex; ++jdx)
606            bounds_lon_1d(jdx,idx) = bounds_lonvalue_unstructured_read_from_file(jdx, i_index(idx));
607
608        // We dont need these values anymore, so just delete them
609        lonvalue_unstructured_read_from_file.free();
610     }
611
612     if (!bounds_latvalue_unstructured_read_from_file.isEmpty() && bounds_lat_1d.isEmpty())
613     {
614        int nbVertex = nvertex;
615        bounds_lat_1d.resize(nbVertex,ni);
616        for (int idx = 0; idx < ni; ++idx)
617          for (int jdx = 0; jdx < nbVertex; ++jdx)
618            bounds_lat_1d(jdx,idx) = bounds_latvalue_unstructured_read_from_file(jdx, i_index(idx));
619
620        // We dont need these values anymore, so just delete them
621        lonvalue_unstructured_read_from_file.free();
622     }
623   }
624
625  /*
626    Get global longitude and latitude of rectilinear domain.
627  */
628   void CDomain::AllgatherRectilinearLonLat(CArray<double,1>& lon, CArray<double,1>& lat, CArray<double,1>& lon_g, CArray<double,1>& lat_g)
629   {
630          CContext* context = CContext::getCurrent();
631    // For now the assumption is that secondary server pools consist of the same number of procs.
632    // CHANGE the line below if the assumption changes.
633    CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[0] : context->client;
634          lon_g.resize(ni_glo) ;
635          lat_g.resize(nj_glo) ;
636
637
638          int* ibegin_g = new int[client->clientSize] ;
639          int* jbegin_g = new int[client->clientSize] ;
640          int* ni_g = new int[client->clientSize] ;
641          int* nj_g = new int[client->clientSize] ;
642          int v ;
643          v=ibegin ;
644          MPI_Allgather(&v,1,MPI_INT,ibegin_g,1,MPI_INT,client->intraComm) ;
645          v=jbegin ;
646          MPI_Allgather(&v,1,MPI_INT,jbegin_g,1,MPI_INT,client->intraComm) ;
647          v=ni ;
648          MPI_Allgather(&v,1,MPI_INT,ni_g,1,MPI_INT,client->intraComm) ;
649          v=nj ;
650          MPI_Allgather(&v,1,MPI_INT,nj_g,1,MPI_INT,client->intraComm) ;
651
652          MPI_Allgatherv(lon.dataFirst(),ni,MPI_DOUBLE,lon_g.dataFirst(),ni_g, ibegin_g,MPI_DOUBLE,client->intraComm) ;
653          MPI_Allgatherv(lat.dataFirst(),nj,MPI_DOUBLE,lat_g.dataFirst(),nj_g, jbegin_g,MPI_DOUBLE,client->intraComm) ;
654
655      delete[] ibegin_g ;
656      delete[] jbegin_g ;
657      delete[] ni_g ;
658      delete[] nj_g ;
659   }
660
661   void CDomain::fillInRectilinearBoundLonLat(CArray<double,1>& lon, CArray<double,1>& lat,
662                                              CArray<double,2>& boundsLon, CArray<double,2>& boundsLat)
663   {
664     int i,j,k;
665
666     const int nvertexValue = 4;
667     boundsLon.resize(nvertexValue,ni*nj);
668
669     if (ni_glo>1)
670     {
671       double lonStepStart = lon(1)-lon(0);
672       bounds_lon_start=lon(0) - lonStepStart/2;
673       double lonStepEnd = lon(ni_glo-1)-lon(ni_glo-2);
674       bounds_lon_end=lon(ni_glo-1) + lonStepEnd/2;
675       double errorBoundsLon = std::abs(360-std::abs(bounds_lon_end-bounds_lon_start));
676
677       // if errorBoundsLon is reasonably small (0.1 x cell size) consider it as closed in longitude
678       if (errorBoundsLon < std::abs(lonStepStart)*1e-1 || errorBoundsLon < std::abs(lonStepEnd)*1e-1 )
679       {
680         bounds_lon_start= (lon(0) + lon(ni_glo-1)-360)/2 ;
681         bounds_lon_end= (lon(0) +360 + lon(ni_glo-1))/2 ;
682       }
683     }
684     else
685     {
686       if (bounds_lon_start.isEmpty()) bounds_lon_start=-180. ;
687       if (bounds_lon_end.isEmpty()) bounds_lon_end=180.-1e-8 ;
688     }
689
690     for(j=0;j<nj;++j)
691       for(i=0;i<ni;++i)
692       {
693         k=j*ni+i;
694         boundsLon(0,k) = boundsLon(1,k) = (0 == (ibegin + i)) ? bounds_lon_start
695                                                               : (lon(ibegin + i)+lon(ibegin + i-1))/2;
696         boundsLon(2,k) = boundsLon(3,k) = ((ibegin + i + 1) == ni_glo) ? bounds_lon_end
697                                                                        : (lon(ibegin + i + 1)+lon(ibegin + i))/2;
698       }
699
700
701    boundsLat.resize(nvertexValue,nj*ni);
702    bool isNorthPole=false ;
703    bool isSouthPole=false ;
704    if (std::abs(90 - std::abs(lat(0))) < NumTraits<double>::epsilon()) isNorthPole = true;
705    if (std::abs(90 - std::abs(lat(nj_glo-1))) < NumTraits<double>::epsilon()) isSouthPole = true;
706
707    // lat boundaries beyond pole the assimilate it to pole
708    // lat boundarie is relativelly close to pole (0.1 x cell size) assimilate it to pole
709    if (nj_glo>1)
710    {
711      double latStepStart = lat(1)-lat(0);
712      if (isNorthPole) bounds_lat_start=lat(0);
713      else
714      {
715        bounds_lat_start=lat(0)-latStepStart/2;
716        if (bounds_lat_start >= 90 ) bounds_lat_start=90 ;
717        else if (bounds_lat_start <= -90 ) bounds_lat_start=-90 ;
718        else if (bounds_lat_start <= 90 && bounds_lat_start >= lat(0))
719        {
720          if ( std::abs(90-bounds_lat_start) <= 0.1*std::abs(latStepStart)) bounds_lat_start=90 ;
721        }
722        else if (bounds_lat_start >= -90 && bounds_lat_start <= lat(0))
723        {
724          if ( std::abs(-90 - bounds_lat_start) <= 0.1*std::abs(latStepStart)) bounds_lat_start=-90 ;
725        }
726      }
727
728      double latStepEnd = lat(nj_glo-1)-lat(nj_glo-2);
729      if (isSouthPole) bounds_lat_end=lat(nj_glo-1);
730      else
731      {
732        bounds_lat_end=lat(nj_glo-1)+latStepEnd/2;
733
734        if (bounds_lat_end >= 90 ) bounds_lat_end=90 ;
735        else if (bounds_lat_end <= -90 ) bounds_lat_end=-90 ;
736        else if (bounds_lat_end <= 90 && bounds_lat_end >= lat(nj_glo-1))
737        {
738          if ( std::abs(90-bounds_lat_end) <= 0.1*std::abs(latStepEnd)) bounds_lat_end=90 ;
739        }
740        else if (bounds_lat_end >= -90 && bounds_lat_end <= lat(nj_glo-1))
741        {
742          if ( std::abs(-90 - bounds_lat_end) <= 0.1*std::abs(latStepEnd)) bounds_lat_end=-90 ;
743        }
744      }
745    }
746    else
747    {
748      if (bounds_lat_start.isEmpty()) bounds_lat_start=-90. ;
749      if (bounds_lat_end.isEmpty()) bounds_lat_end=90 ;
750    }
751
752    for(j=0;j<nj;++j)
753      for(i=0;i<ni;++i)
754      {
755        k=j*ni+i;
756        boundsLat(1,k) = boundsLat(2,k) = (0 == (jbegin + j)) ? bounds_lat_start
757                                                              : (lat(jbegin + j)+lat(jbegin + j-1))/2;
758        boundsLat(0,k) = boundsLat(3,k) = ((jbegin + j +1) == nj_glo) ? bounds_lat_end
759                                                                      : (lat(jbegin + j + 1)+lat(jbegin + j))/2;
760      }
761   }
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    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
1690    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
1691    for (int p = 0; p < nbSrvPools; ++p)
1692    {
1693      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
1694      int nbServer = client->serverSize;
1695      int rank     = client->clientRank;
1696      bool doComputeGlobalIndexServer = true;
1697
1698      int i,j,i_ind,j_ind, nbIndex, nbIndexZoom;
1699      int global_zoom_iend=global_zoom_ibegin+global_zoom_ni-1;
1700      int global_zoom_jend=global_zoom_jbegin+global_zoom_nj-1;
1701
1702      // Precompute number of index
1703      int globalIndexCountZoom = 0;
1704      nbIndex = i_index.numElements();
1705
1706      if (doZoomByIndex_) 
1707      {
1708        globalIndexCountZoom = zoom_i_index.numElements();
1709      }
1710      else 
1711      {
1712        for (i = 0; i < nbIndex; ++i)
1713        {
1714          i_ind=i_index(i);
1715          j_ind=j_index(i);
1716
1717          if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1718          {
1719            ++globalIndexCountZoom;
1720          }
1721        }
1722      }
1723
1724
1725      // Fill in index
1726      CArray<size_t,1> globalIndexDomainZoom(globalIndexCountZoom);
1727      CArray<size_t,1> localIndexDomainZoom(globalIndexCountZoom);
1728      CArray<size_t,1> globalIndexDomain(nbIndex);
1729      size_t globalIndex;
1730      int globalIndexCount = 0;
1731
1732      for (i = 0; i < nbIndex; ++i)
1733      {
1734        i_ind=i_index(i);
1735        j_ind=j_index(i);
1736        globalIndex = i_ind + j_ind * ni_glo;
1737        globalIndexDomain(i) = globalIndex;               
1738      }
1739
1740      if (globalLocalIndexMap_.empty())
1741      {
1742        for (i = 0; i < nbIndex; ++i)
1743          globalLocalIndexMap_[globalIndexDomain(i)] = i;
1744      }
1745
1746      globalIndexCountZoom = 0;
1747      if (doZoomByIndex_) 
1748      {
1749        int nbIndexZoom = zoom_i_index.numElements();       
1750       
1751        for (i = 0; i < nbIndexZoom; ++i)
1752        {
1753          i_ind=zoom_i_index(i);
1754          j_ind=zoom_j_index(i);
1755          globalIndex = i_ind + j_ind * ni_glo;
1756          globalIndexDomainZoom(globalIndexCountZoom) = globalIndex;
1757          ++globalIndexCountZoom;
1758        }
1759      }
1760      else 
1761      {
1762          int global_zoom_iend=global_zoom_ibegin+global_zoom_ni-1;
1763          int global_zoom_jend=global_zoom_jbegin+global_zoom_nj-1;
1764          for (i = 0; i < nbIndex; ++i)
1765          {
1766            i_ind=i_index(i);
1767            j_ind=j_index(i);
1768            globalIndex = i_ind + j_ind * ni_glo;
1769            if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1770            {
1771              globalIndexDomainZoom(globalIndexCountZoom) = globalIndex;
1772              ++globalIndexCountZoom;
1773            }
1774          }
1775
1776          int iend = ibegin + ni -1;
1777          int jend = jbegin + nj -1;
1778          zoom_ibegin = global_zoom_ibegin > ibegin ? global_zoom_ibegin : ibegin;
1779          int zoom_iend  = global_zoom_iend < iend ? zoom_iend : iend ;
1780          zoom_ni     = zoom_iend-zoom_ibegin+1 ;
1781
1782          zoom_jbegin = global_zoom_jbegin > jbegin ? global_zoom_jbegin : jbegin ;
1783          int zoom_jend   = global_zoom_jend < jend ? zoom_jend : jend;
1784          zoom_nj     = zoom_jend-zoom_jbegin+1;
1785      }
1786
1787
1788      size_t globalSizeIndex = 1, indexBegin, indexEnd;
1789      int range, clientSize = client->clientSize;
1790      std::vector<int> nGlobDomain(2);
1791      nGlobDomain[0] = this->ni_glo;
1792      nGlobDomain[1] = this->nj_glo;
1793      for (int i = 0; i < nGlobDomain.size(); ++i) globalSizeIndex *= nGlobDomain[i];
1794      indexBegin = 0;
1795      if (globalSizeIndex <= clientSize)
1796      {
1797        indexBegin = rank%globalSizeIndex;
1798        indexEnd = indexBegin;
1799      }
1800      else
1801      {
1802        for (int i = 0; i < clientSize; ++i)
1803        {
1804          range = globalSizeIndex / clientSize;
1805          if (i < (globalSizeIndex%clientSize)) ++range;
1806          if (i == client->clientRank) break;
1807          indexBegin += range;
1808        }
1809        indexEnd = indexBegin + range - 1;
1810      }
1811
1812      CServerDistributionDescription serverDescription(nGlobDomain, nbServer);
1813      if (isUnstructed_) serverDescription.computeServerGlobalIndexInRange(std::make_pair<size_t,size_t>(indexBegin, indexEnd), 0);
1814      else serverDescription.computeServerGlobalIndexInRange(std::make_pair<size_t,size_t>(indexBegin, indexEnd), 1);
1815
1816      CClientServerMapping* clientServerMap = new CClientServerMappingDistributed(serverDescription.getGlobalIndexRange(),
1817                                                                                  client->intraComm);
1818      clientServerMap->computeServerIndexMapping(globalIndexDomain);
1819      CClientServerMapping::GlobalIndexMap& globalIndexDomainOnServer = clientServerMap->getGlobalIndexOnServer();
1820
1821      CClientServerMapping::GlobalIndexMap::const_iterator it  = globalIndexDomainOnServer.begin(),
1822                                                           ite = globalIndexDomainOnServer.end();
1823      connectedServerRank_.clear();
1824      for (it = globalIndexDomainOnServer.begin(); it != ite; ++it) {
1825        connectedServerRank_.push_back(it->first);
1826      }
1827
1828      indSrv_.swap(globalIndexDomainOnServer);
1829      nbConnectedClients_ = clientServerMap->computeConnectedClients(client->serverSize, client->clientSize, client->intraComm, connectedServerRank_);
1830
1831      clientServerMap->computeServerIndexMapping(globalIndexDomainZoom);
1832      CClientServerMapping::GlobalIndexMap& globalIndexDomainZoomOnServer = clientServerMap->getGlobalIndexOnServer();
1833      indZoomSrv_.swap(globalIndexDomainZoomOnServer);
1834     
1835     for (it = indZoomSrv_.begin(); it != indZoomSrv_.end(); ++it)
1836       connectedServerZoomRank_.push_back(it->first);
1837
1838      nbConnectedClientsZoom_ = clientServerMap->computeConnectedClients(client->serverSize, client->clientSize, client->intraComm, connectedServerZoomRank_);
1839
1840      delete clientServerMap;
1841    }
1842  }
1843
1844   /*!
1845     Compute index to write data. We only write data on the zoomed region, therefore, there should
1846     be a map between the complete grid and the reduced grid where we write data.
1847     By using global index we can easily create this kind of mapping.
1848   */
1849   void CDomain::computeWrittenIndex()
1850   { 
1851      if (computedWrittenIndex_) return;
1852      computedWrittenIndex_ = true;
1853
1854      CContext* context=CContext::getCurrent();     
1855      CContextServer* server = context->server; 
1856
1857      std::vector<int> nBegin(2), nSize(2), nBeginGlobal(2), nGlob(2);
1858      nBegin[0]       = zoom_ibegin;  nBegin[1] = zoom_jbegin;
1859      nSize[0]        = zoom_ni;      nSize[1]  = zoom_nj;
1860      nBeginGlobal[0] = 0; nBeginGlobal[1] = 0;
1861      nGlob[0]        = ni_glo;   nGlob[1] = nj_glo;
1862      CDistributionServer srvDist(server->intraCommSize, nBegin, nSize, nBeginGlobal, nGlob); 
1863      const CArray<size_t,1>& writtenGlobalIndex  = srvDist.getGlobalIndex();
1864
1865      size_t nbWritten = 0, indGlo;     
1866      boost::unordered_map<size_t,size_t>::const_iterator itb = globalLocalIndexMap_.begin(),
1867                                                          ite = globalLocalIndexMap_.end(), it;         
1868      CArray<size_t,1>::const_iterator itSrvb = writtenGlobalIndex.begin(),
1869                                       itSrve = writtenGlobalIndex.end(), itSrv;
1870
1871      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
1872      {
1873        indGlo = *itSrv;
1874        if (ite != globalLocalIndexMap_.find(indGlo))
1875        {         
1876          ++nbWritten;
1877        }                 
1878      }
1879
1880      localIndexToWriteOnServer.resize(nbWritten);
1881
1882      nbWritten = 0;
1883      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
1884      {
1885        indGlo = *itSrv;
1886        if (ite != globalLocalIndexMap_.find(indGlo))
1887        {
1888          localIndexToWriteOnServer(nbWritten) = globalLocalIndexMap_[indGlo];
1889          ++nbWritten;
1890        }                 
1891      }
1892     
1893      if (isCompressible())
1894      {
1895        nbWritten = 0;
1896        boost::unordered_map<size_t,size_t> localGlobalIndexMap;
1897        for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
1898        {
1899          indGlo = *itSrv;
1900          if (ite != globalLocalIndexMap_.find(indGlo))
1901          {
1902            localGlobalIndexMap[localIndexToWriteOnServer(nbWritten)] = indGlo;
1903            ++nbWritten;
1904          }                 
1905        }
1906
1907        nbWritten = 0;
1908        for (int idx = 0; idx < data_i_index.numElements(); ++idx)
1909        {
1910          if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_i_index(idx)))
1911          {
1912            ++nbWritten;
1913          }
1914        }
1915
1916        compressedIndexToWriteOnServer.resize(nbWritten);
1917        nbWritten = 0;
1918        for (int idx = 0; idx < data_i_index.numElements(); ++idx)
1919        {
1920          if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_i_index(idx)))
1921          {
1922            compressedIndexToWriteOnServer(nbWritten) = localGlobalIndexMap[data_i_index(idx)];
1923            ++nbWritten;
1924          }
1925        }
1926
1927        numberWrittenIndexes_ = nbWritten;
1928        if (isDistributed())
1929        {           
1930          MPI_Allreduce(&numberWrittenIndexes_, &totalNumberWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
1931          MPI_Scan(&numberWrittenIndexes_, &offsetWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
1932          offsetWrittenIndexes_ -= numberWrittenIndexes_;
1933        }
1934        else
1935          totalNumberWrittenIndexes_ = numberWrittenIndexes_;
1936      }     
1937   }
1938
1939  /*!
1940    Send all attributes from client to connected clients
1941    The attributes will be rebuilt on receiving side
1942  */
1943  void CDomain::sendAttributes()
1944  {
1945    sendDistributionAttributes();
1946    sendIndex();   
1947    // sendIndexZoom();
1948    sendMask();
1949    sendLonLat();
1950    sendArea();   
1951    sendDataIndex();
1952  }
1953
1954  /*!
1955    Send global index and zoom index from client to connected client(s)
1956    zoom index can be smaller than global index
1957  */
1958  void CDomain::sendIndex()
1959  {
1960    int ns, n, i, j, ind, nv, idx;
1961    CContext* context = CContext::getCurrent();
1962
1963    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
1964    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
1965    for (int p = 0; p < nbSrvPools; ++p)
1966    {
1967      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
1968
1969      CEventClient eventIndex(getType(), EVENT_ID_INDEX);
1970
1971      list<CMessage> list_msgsIndex;
1972      list<CArray<int,1> > list_indZoom, list_writtenInd, list_indGlob;
1973
1974      boost::unordered_map<int, vector<size_t> >::const_iterator itIndex, iteIndex;
1975      iteIndex = indSrv_.end();
1976      for (int k = 0; k < connectedServerRank_.size(); ++k)
1977      {
1978        int nbIndGlob = 0;
1979        int rank = connectedServerRank_[k];
1980        itIndex = indSrv_.find(rank);
1981        if (iteIndex != itIndex)
1982          nbIndGlob = itIndex->second.size();
1983
1984        list_indGlob.push_back(CArray<int,1>(nbIndGlob));       
1985
1986        CArray<int,1>& indGlob = list_indGlob.back();
1987        for (n = 0; n < nbIndGlob; ++n)
1988        {
1989          indGlob(n) = static_cast<int>(itIndex->second[n]);
1990        }
1991
1992        list_msgsIndex.push_back(CMessage());
1993        list_msgsIndex.back() << this->getId() << (int)type; // enum ne fonctionne pour les message => ToFix
1994        list_msgsIndex.back() << isCurvilinear;
1995        list_msgsIndex.back() << list_indGlob.back(); //list_indi.back() << list_indj.back();
1996       
1997        eventIndex.push(rank, nbConnectedClients_[rank], list_msgsIndex.back());
1998      }
1999
2000      client->sendEvent(eventIndex);
2001    }
2002  }
2003
2004  /*!
2005    Send global index and zoom index from client to connected client(s)
2006    zoom index can be smaller than global index.
2007    This function can be used in the future???
2008  */
2009  void CDomain::sendIndexZoom()
2010  {
2011    int ns, n, i, j, ind, nv, idx;
2012    CContext* context = CContext::getCurrent();
2013
2014    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2015    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2016    for (int p = 0; p < nbSrvPools; ++p)
2017    {
2018      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
2019      CEventClient eventIndexZoom(getType(), EVENT_ID_INDEX_ZOOM);
2020
2021      list<CMessage> list_msgsIndex;
2022      list<CArray<int,1> > list_indZoom;
2023
2024      boost::unordered_map<int, vector<size_t> >::const_iterator itZoom, iteZoom;
2025      iteZoom = indZoomSrv_.end();
2026      for (int k = 0; k < connectedServerZoomRank_.size(); ++k)
2027      {
2028        int nbIndGlob = 0;
2029        int rank = connectedServerZoomRank_[k];
2030        int nbIndZoom = 0;
2031        itZoom = indZoomSrv_.find(rank);
2032        if (iteZoom != itZoom)
2033          nbIndZoom = itZoom->second.size();
2034       
2035        list_indZoom.push_back(CArray<int,1>(nbIndZoom));
2036        CArray<int,1>& indZoom = list_indZoom.back();
2037        for (n = 0; n < nbIndZoom; ++n)
2038        {
2039          indZoom(n) = static_cast<int>(itZoom->second[n]);
2040        }
2041
2042        list_msgsIndex.push_back(CMessage());
2043        list_msgsIndex.back() << this->getId(); // enum ne fonctionne pour les message => ToFix       
2044        list_msgsIndex.back() << list_indZoom.back() << doZoomByIndex_; //list_indi.back() << list_indj.back     
2045
2046        eventIndexZoom.push(rank, nbConnectedClientsZoom_[rank], list_msgsIndex.back());
2047      }
2048
2049      client->sendEvent(eventIndexZoom);
2050    }
2051  }
2052
2053  /*!
2054    Send distribution from client to other clients
2055    Because a client in a level knows correctly the grid distribution of client on the next level
2056    it calculates this distribution then sends it to the corresponding clients on the next level
2057  */
2058  void CDomain::sendDistributionAttributes(void)
2059  {
2060    CContext* context = CContext::getCurrent();
2061     // Use correct context client to send message
2062    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2063    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2064    for (int i = 0; i < nbSrvPools; ++i)
2065    {
2066      CContextClient* contextClientTmp = (context->hasServer) ? context->clientPrimServer[i]
2067                                                                         : context->client;   
2068      int nbServer = contextClientTmp->serverSize;
2069      std::vector<int> nGlobDomain(2);
2070      nGlobDomain[0] = this->ni_glo;
2071      nGlobDomain[1] = this->nj_glo;
2072
2073      CServerDistributionDescription serverDescription(nGlobDomain, nbServer);
2074      if (isUnstructed_) serverDescription.computeServerDistribution(false, 0);
2075      else serverDescription.computeServerDistribution(false, 1);
2076
2077      std::vector<std::vector<int> > serverIndexBegin = serverDescription.getServerIndexBegin();
2078      std::vector<std::vector<int> > serverDimensionSizes = serverDescription.getServerDimensionSizes();
2079
2080      CEventClient event(getType(),EVENT_ID_SERVER_ATTRIBUT);
2081      if (contextClientTmp->isServerLeader())
2082      {
2083        std::list<CMessage> msgs;
2084
2085        const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
2086        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
2087        {
2088          // Use const int to ensure CMessage holds a copy of the value instead of just a reference
2089          const int ibegin_srv = serverIndexBegin[*itRank][0];
2090          const int jbegin_srv = serverIndexBegin[*itRank][1];
2091          const int ni_srv = serverDimensionSizes[*itRank][0];
2092          const int nj_srv = serverDimensionSizes[*itRank][1];
2093
2094          msgs.push_back(CMessage());
2095          CMessage& msg = msgs.back();
2096          msg << this->getId() ;
2097          msg << ni_srv << ibegin_srv << nj_srv << jbegin_srv;
2098          msg << global_zoom_ni.getValue() << global_zoom_ibegin.getValue() << global_zoom_nj.getValue() << global_zoom_jbegin.getValue();       
2099          msg << isCompressible_;
2100
2101          event.push(*itRank,1,msg);
2102        }
2103        contextClientTmp->sendEvent(event);
2104      }
2105      else contextClientTmp->sendEvent(event);
2106    }
2107  }
2108
2109  /*!
2110    Send mask index from client to connected(s) clients   
2111  */
2112  void CDomain::sendMask()
2113  {
2114    int ns, n, i, j, ind, nv, idx;
2115    CContext* context = CContext::getCurrent();
2116
2117    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2118    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2119    for (int p = 0; p < nbSrvPools; ++p)
2120    {
2121      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
2122
2123      // send area for each connected server
2124      CEventClient eventMask(getType(), EVENT_ID_MASK);
2125
2126      list<CMessage> list_msgsMask;
2127      list<CArray<bool,1> > list_mask;
2128
2129      boost::unordered_map<int, vector<size_t> >::const_iterator it, iteMap;
2130      iteMap = indSrv_.end();
2131      for (int k = 0; k < connectedServerRank_.size(); ++k)
2132      {
2133        int nbData = 0;
2134        int rank = connectedServerRank_[k];
2135        it = indSrv_.find(rank);
2136        if (iteMap != it)
2137          nbData = it->second.size();
2138        list_mask.push_back(CArray<bool,1>(nbData));
2139
2140        const std::vector<size_t>& temp = it->second;
2141        for (n = 0; n < nbData; ++n)
2142        {
2143          idx = static_cast<int>(it->second[n]);
2144          list_mask.back()(n) = mask_1d(globalLocalIndexMap_[idx]);
2145        }
2146
2147        list_msgsMask.push_back(CMessage());
2148        list_msgsMask.back() << this->getId() << list_mask.back();
2149        eventMask.push(rank, nbConnectedClients_[rank], list_msgsMask.back());
2150      }
2151      client->sendEvent(eventMask);
2152    }
2153  }
2154
2155  /*!
2156    Send area from client to connected client(s)
2157  */
2158  void CDomain::sendArea()
2159  {
2160    if (!hasArea) return;
2161
2162    int ns, n, i, j, ind, nv, idx;
2163    CContext* context = CContext::getCurrent();
2164
2165    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2166    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2167    for (int p = 0; p < nbSrvPools; ++p)
2168    {
2169      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
2170
2171      // send area for each connected server
2172      CEventClient eventArea(getType(), EVENT_ID_AREA);
2173
2174      list<CMessage> list_msgsArea;
2175      list<CArray<double,1> > list_area;
2176
2177      boost::unordered_map<int, vector<size_t> >::const_iterator it, iteMap;
2178      iteMap = indSrv_.end();
2179      for (int k = 0; k < connectedServerRank_.size(); ++k)
2180      {
2181        int nbData = 0;
2182        int rank = connectedServerRank_[k];
2183        it = indSrv_.find(rank);
2184        if (iteMap != it)
2185          nbData = it->second.size();
2186        list_area.push_back(CArray<double,1>(nbData));
2187
2188        const std::vector<size_t>& temp = it->second;
2189        for (n = 0; n < nbData; ++n)
2190        {
2191          idx = static_cast<int>(it->second[n]);
2192          list_area.back()(n) = areavalue(globalLocalIndexMap_[idx]);
2193        }
2194
2195        list_msgsArea.push_back(CMessage());
2196        list_msgsArea.back() << this->getId() << hasArea;
2197        list_msgsArea.back() << list_area.back();
2198        eventArea.push(rank, nbConnectedClients_[rank], list_msgsArea.back());
2199      }
2200      client->sendEvent(eventArea);
2201    }
2202  }
2203
2204  /*!
2205    Send longitude and latitude from client to servers
2206    Each client send long and lat information to corresponding connected clients(s).
2207    Because longitude and latitude are optional, this function only called if latitude and longitude exist
2208  */
2209  void CDomain::sendLonLat()
2210  {
2211    if (!hasLonLat) return;
2212
2213    int ns, n, i, j, ind, nv, idx;
2214    CContext* context = CContext::getCurrent();
2215
2216    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2217    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2218    for (int p = 0; p < nbSrvPools; ++p)
2219    {
2220      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
2221
2222      // send lon lat for each connected server
2223      CEventClient eventLon(getType(), EVENT_ID_LON);
2224      CEventClient eventLat(getType(), EVENT_ID_LAT);
2225
2226      list<CMessage> list_msgsLon, list_msgsLat;
2227      list<CArray<double,1> > list_lon, list_lat;
2228      list<CArray<double,2> > list_boundslon, list_boundslat;
2229
2230      boost::unordered_map<int, vector<size_t> >::const_iterator it, iteMap;
2231      iteMap = indSrv_.end();
2232      for (int k = 0; k < connectedServerRank_.size(); ++k)
2233      {
2234        int nbData = 0;
2235        int rank = connectedServerRank_[k];
2236        it = indSrv_.find(rank);
2237        if (iteMap != it)
2238          nbData = it->second.size();
2239
2240        list_lon.push_back(CArray<double,1>(nbData));
2241        list_lat.push_back(CArray<double,1>(nbData));
2242
2243        if (hasBounds)
2244        {
2245          list_boundslon.push_back(CArray<double,2>(nvertex, nbData));
2246          list_boundslat.push_back(CArray<double,2>(nvertex, nbData));
2247        }
2248
2249        CArray<double,1>& lon = list_lon.back();
2250        CArray<double,1>& lat = list_lat.back();
2251        const std::vector<size_t>& temp = it->second;
2252        for (n = 0; n < nbData; ++n)
2253        {
2254          idx = static_cast<int>(it->second[n]);
2255          int localInd = globalLocalIndexMap_[idx];
2256          lon(n) = lonvalue(localInd);
2257          lat(n) = latvalue(localInd);
2258
2259          if (hasBounds)
2260          {
2261            CArray<double,2>& boundslon = list_boundslon.back();
2262            CArray<double,2>& boundslat = list_boundslat.back();
2263
2264            for (nv = 0; nv < nvertex; ++nv)
2265            {
2266              boundslon(nv, n) = bounds_lonvalue(nv, localInd);
2267              boundslat(nv, n) = bounds_latvalue(nv, localInd);
2268            }
2269          }
2270        }
2271
2272        list_msgsLon.push_back(CMessage());
2273        list_msgsLat.push_back(CMessage());
2274
2275        list_msgsLon.back() << this->getId() << hasLonLat;
2276        if (hasLonLat) 
2277          list_msgsLon.back() << list_lon.back();
2278        list_msgsLon.back()  << hasBounds;
2279        if (hasBounds)
2280        {
2281          list_msgsLon.back() << list_boundslon.back();
2282        }
2283
2284        list_msgsLat.back() << this->getId() << hasLonLat;
2285        if (hasLonLat)
2286          list_msgsLat.back() << list_lat.back();
2287        list_msgsLat.back() << hasBounds;
2288        if (hasBounds)
2289        {         
2290          list_msgsLat.back() << list_boundslat.back();
2291        }
2292
2293        eventLon.push(rank, nbConnectedClients_[rank], list_msgsLon.back());
2294        eventLat.push(rank, nbConnectedClients_[rank], list_msgsLat.back());
2295      }
2296      client->sendEvent(eventLon);
2297      client->sendEvent(eventLat);
2298    }
2299  }
2300
2301  /*!
2302    Send data index to corresponding connected clients.
2303    Data index can be compressed however, we always send decompressed data index
2304    and they will be compressed on receiving.
2305    The compressed index are represented with 1 and others are represented with -1
2306  */
2307  void CDomain::sendDataIndex()
2308  {
2309    int ns, n, i, j, ind, nv, idx;
2310    CContext* context = CContext::getCurrent();
2311
2312    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2313    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2314    for (int p = 0; p < nbSrvPools; ++p)
2315    {
2316      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
2317
2318      // send area for each connected server
2319      CEventClient eventDataIndex(getType(), EVENT_ID_DATA_INDEX);
2320
2321      list<CMessage> list_msgsDataIndex;
2322      list<CArray<int,1> > list_data_i_index, list_data_j_index;
2323
2324      int nbIndex = i_index.numElements();
2325      int niByIndex = max(i_index) - min(i_index) + 1;
2326      int njByIndex = max(j_index) - min(j_index) + 1; 
2327      int dataIindexBound = (1 == data_dim) ? (niByIndex * njByIndex) : niByIndex;
2328      int dataJindexBound = (1 == data_dim) ? (niByIndex * njByIndex) : njByIndex;
2329
2330     
2331      CArray<int,1> dataIIndex(nbIndex), dataJIndex(nbIndex);
2332      dataIIndex = -1; 
2333      dataJIndex = -1;
2334      ind = 0;
2335
2336      for (idx = 0; idx < data_i_index.numElements(); ++idx)
2337      {
2338        int dataIidx = data_i_index(idx) + data_ibegin;
2339        int dataJidx = data_j_index(idx) + data_jbegin;
2340        if ((0 <= dataIidx) && (dataIidx < dataIindexBound) &&
2341            (0 <= dataJidx) && (dataJidx < dataJindexBound))
2342        {
2343          dataIIndex((1 == data_dim) ? dataIidx : dataJidx * ni + dataIidx) = 1; //i_index(dataIidx);//dataIidx;
2344          dataJIndex((1 == data_dim) ? dataIidx : dataJidx * ni + dataIidx) = 1; //j_index(dataJidx);//         
2345        }
2346      }
2347
2348      boost::unordered_map<int, vector<size_t> >::const_iterator it, iteMap;
2349      iteMap = indSrv_.end();
2350      for (int k = 0; k < connectedServerRank_.size(); ++k)
2351      {
2352        int nbData = 0;
2353        int rank = connectedServerRank_[k];
2354        it = indSrv_.find(rank);
2355        if (iteMap != it)
2356          nbData = it->second.size();
2357        list_data_i_index.push_back(CArray<int,1>(nbData));
2358        list_data_j_index.push_back(CArray<int,1>(nbData));
2359
2360        const std::vector<size_t>& temp = it->second;
2361        for (n = 0; n < nbData; ++n)
2362        {
2363          idx = static_cast<int>(it->second[n]);
2364          i = globalLocalIndexMap_[idx];
2365          list_data_i_index.back()(n) = dataIIndex(i);
2366          list_data_j_index.back()(n) = dataJIndex(i);
2367        }
2368
2369        list_msgsDataIndex.push_back(CMessage());
2370        list_msgsDataIndex.back() << this->getId();
2371        list_msgsDataIndex.back() << list_data_i_index.back() << list_data_j_index.back();
2372        eventDataIndex.push(rank, nbConnectedClients_[rank], list_msgsDataIndex.back());
2373      }
2374      client->sendEvent(eventDataIndex);
2375    }
2376  }
2377 
2378  bool CDomain::dispatchEvent(CEventServer& event)
2379  {
2380    if (SuperClass::dispatchEvent(event)) return true;
2381    else
2382    {
2383      switch(event.type)
2384      {
2385        case EVENT_ID_SERVER_ATTRIBUT:
2386          recvDistributionAttributes(event);
2387          return true;
2388          break;
2389        case EVENT_ID_INDEX:
2390          recvIndex(event);
2391          return true;
2392          break;
2393        case EVENT_ID_INDEX_ZOOM:
2394          recvIndexZoom(event);
2395          return true;
2396          break;
2397        case EVENT_ID_MASK:
2398          recvMask(event);
2399          return true;
2400          break;
2401        case EVENT_ID_LON:
2402          recvLon(event);
2403          return true;
2404          break;
2405        case EVENT_ID_LAT:
2406          recvLat(event);
2407          return true;
2408          break;
2409        case EVENT_ID_AREA:
2410          recvArea(event);
2411          return true;
2412          break; 
2413        case EVENT_ID_DATA_INDEX:
2414          recvDataIndex(event);
2415          return true;
2416          break;
2417        default:
2418          ERROR("bool CDomain::dispatchEvent(CEventServer& event)",
2419                << "Unknown Event");
2420          return false;
2421       }
2422    }
2423  }
2424
2425  /*!
2426    Receive index event from clients(s)
2427    \param[in] event event contain info about rank and associated index
2428  */
2429  void CDomain::recvIndex(CEventServer& event)
2430  {
2431    string domainId;
2432    std::map<int, CBufferIn*> rankBuffers;
2433
2434    list<CEventServer::SSubEvent>::iterator it;
2435    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2436    {     
2437      CBufferIn* buffer = it->buffer;
2438      *buffer >> domainId;
2439      rankBuffers[it->rank] = buffer;       
2440    }
2441    get(domainId)->recvIndex(rankBuffers);
2442  }
2443
2444  /*!
2445    Receive index information from client(s). We use the global index for mapping index between
2446    sending clients and receiving clients.
2447    \param[in] rankBuffers rank of sending client and the corresponding receive buffer 
2448  */
2449  void CDomain::recvIndex(std::map<int, CBufferIn*>& rankBuffers)
2450  {
2451    int nbReceived = rankBuffers.size(), i, ind, index, type_int;
2452    recvClientRanks_.resize(nbReceived);       
2453
2454    std::map<int, CBufferIn*>::iterator it = rankBuffers.begin(), ite = rankBuffers.end();
2455    ind = 0;
2456    for (ind = 0; it != ite; ++it, ++ind)
2457    {       
2458       recvClientRanks_[ind] = it->first;
2459       CBufferIn& buffer = *(it->second);
2460       buffer >> type_int >> isCurvilinear >> indGlob_[it->first]; 
2461       type.setValue((type_attr::t_enum)type_int); // probleme des type enum avec les buffers : ToFix
2462    }
2463    int nbIndGlob = 0;
2464    for (i = 0; i < nbReceived; ++i)
2465    {
2466      nbIndGlob += indGlob_[recvClientRanks_[i]].numElements();
2467    }
2468   
2469    globalLocalIndexMap_.rehash(std::ceil(nbIndGlob/globalLocalIndexMap_.max_load_factor()));
2470    i_index.resize(nbIndGlob);
2471    j_index.resize(nbIndGlob);   
2472    nbIndGlob = 0;
2473    for (i = 0; i < nbReceived; ++i)
2474    {
2475      CArray<int,1>& tmp = indGlob_[recvClientRanks_[i]];
2476      for (ind = 0; ind < tmp.numElements(); ++ind)
2477      {
2478         index = tmp(ind);
2479         if (0 == globalLocalIndexMap_.count(index))
2480         {
2481           i_index(nbIndGlob) = index % ni_glo;
2482           j_index(nbIndGlob) = index / ni_glo;
2483           globalLocalIndexMap_[index] = nbIndGlob; 
2484           ++nbIndGlob;
2485         } 
2486      } 
2487    } 
2488
2489    i_index.resizeAndPreserve(nbIndGlob);
2490    j_index.resizeAndPreserve(nbIndGlob);
2491  }
2492
2493  /*!
2494    Receive index event from clients(s)
2495    \param[in] event event contain info about rank and associated index
2496  */
2497  void CDomain::recvIndexZoom(CEventServer& event)
2498  {
2499    string domainId;
2500    std::map<int, CBufferIn*> rankBuffers;
2501
2502    list<CEventServer::SSubEvent>::iterator it;
2503    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2504    {     
2505      CBufferIn* buffer = it->buffer;
2506      *buffer >> domainId;
2507      rankBuffers[it->rank] = buffer;       
2508    }
2509    get(domainId)->recvIndexZoom(rankBuffers);
2510  }
2511
2512  /*!
2513    Receive index information from client(s)
2514    \param[in] rankBuffers rank of sending client and the corresponding receive buffer 
2515  */
2516  void CDomain::recvIndexZoom(std::map<int, CBufferIn*>& rankBuffers)
2517  {
2518    int nbReceived = rankBuffers.size(), i, ind, index, type_int;
2519    recvClientZoomRanks_.resize(nbReceived);   
2520    int ni_zoom_tmp, ibegin_zoom_tmp, nj_zoom_tmp, jbegin_zoom_tmp;
2521
2522    std::map<int, CBufferIn*>::iterator it = rankBuffers.begin(), ite = rankBuffers.end();
2523    ind = 0;
2524    for (ind = 0; it != ite; ++it, ++ind)
2525    {       
2526       recvClientZoomRanks_[ind] = it->first;
2527       CBufferIn& buffer = *(it->second);
2528       buffer >> indGlobZoom_[it->first] >> doZoomByIndex_;       
2529    }
2530
2531    int nbZoomInd = 0;
2532    for (i = 0; i < nbReceived; ++i)
2533    {
2534      nbZoomInd += indGlobZoom_[recvClientZoomRanks_[i]].numElements();
2535    }
2536
2537    if (doZoomByIndex_)
2538    {
2539      zoom_i_index.resize(nbZoomInd);
2540      zoom_j_index.resize(nbZoomInd);
2541     
2542      nbZoomInd = 0;
2543      for (i = 0; i < nbReceived; ++i)
2544      {
2545        CArray<int,1>& tmp = indGlobZoom_[recvClientRanks_[i]];
2546        for (ind = 0; ind < tmp.numElements(); ++ind)
2547        {
2548           index = tmp(ind);
2549           zoom_i_index(nbZoomInd) = index % ni_glo;
2550           zoom_j_index(nbZoomInd) = index / ni_glo;
2551           ++nbZoomInd;
2552        } 
2553      }     
2554    }
2555    else 
2556    {
2557    }
2558  }
2559
2560  /*!
2561    Receive attributes event from clients(s)
2562    \param[in] event event contain info about rank and associated attributes
2563  */
2564  void CDomain::recvDistributionAttributes(CEventServer& event)
2565  {
2566    CBufferIn* buffer=event.subEvents.begin()->buffer;
2567    string domainId ;
2568    *buffer>>domainId ;
2569    get(domainId)->recvDistributionAttributes(*buffer);
2570  }
2571
2572  /*!
2573    Receive attributes from client(s): zoom info and begin and n of each server
2574    \param[in] rank rank of client source
2575    \param[in] buffer message containing attributes info
2576  */
2577  void CDomain::recvDistributionAttributes(CBufferIn& buffer)
2578  {
2579    int ni_tmp, ibegin_tmp, nj_tmp, jbegin_tmp;
2580    int global_zoom_ni_tmp, global_zoom_ibegin_tmp, global_zoom_nj_tmp, global_zoom_jbegin_tmp;
2581    buffer >> ni_tmp >> ibegin_tmp >> nj_tmp >> jbegin_tmp
2582           >> global_zoom_ni_tmp >> global_zoom_ibegin_tmp >> global_zoom_nj_tmp >> global_zoom_jbegin_tmp           
2583           >> isCompressible_;
2584    ni.setValue(ni_tmp);
2585    ibegin.setValue(ibegin_tmp);
2586    nj.setValue(nj_tmp);
2587    jbegin.setValue(jbegin_tmp);
2588
2589    global_zoom_ni.setValue(global_zoom_ni_tmp);
2590    global_zoom_ibegin.setValue(global_zoom_ibegin_tmp);
2591    global_zoom_nj.setValue(global_zoom_nj_tmp);
2592    global_zoom_jbegin.setValue(global_zoom_jbegin_tmp);
2593
2594    int iend = ibegin + ni  - 1;
2595    int jend = jbegin + nj  - 1;
2596    int zoom_iend_glob = global_zoom_ibegin + global_zoom_ni - 1;
2597    int zoom_jend_glob = global_zoom_jbegin + global_zoom_nj - 1;
2598
2599    zoom_ibegin.setValue(global_zoom_ibegin > ibegin ? global_zoom_ibegin : ibegin);
2600    int zoom_iend = zoom_iend_glob < iend ? zoom_iend_glob : iend ;
2601    zoom_ni.setValue(zoom_iend-zoom_ibegin+1);
2602
2603    zoom_jbegin.setValue(global_zoom_jbegin > jbegin ? global_zoom_jbegin : jbegin);
2604    int zoom_jend = zoom_jend_glob < jend ? zoom_jend_glob : jend ;
2605    zoom_nj.setValue(zoom_jend-zoom_jbegin+1);
2606
2607    if (zoom_ni<=0 || zoom_nj<=0)
2608    {
2609      zoom_ibegin=0 ; zoom_iend=0 ; zoom_ni=0 ;
2610      zoom_jbegin=0 ; zoom_jend=0 ; zoom_nj=0 ;
2611    }
2612
2613  }
2614
2615  /*!
2616    Receive area event from clients(s)
2617    \param[in] event event contain info about rank and associated area
2618  */
2619  void CDomain::recvMask(CEventServer& event)
2620  {
2621    string domainId;
2622    std::map<int, CBufferIn*> rankBuffers;
2623
2624    list<CEventServer::SSubEvent>::iterator it;
2625    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2626    {     
2627      CBufferIn* buffer = it->buffer;
2628      *buffer >> domainId;
2629      rankBuffers[it->rank] = buffer;     
2630    }
2631    get(domainId)->recvMask(rankBuffers);
2632  }
2633
2634
2635  /*!
2636    Receive mask information from client(s)
2637    \param[in] rankBuffers rank of sending client and the corresponding receive buffer 
2638  */
2639  void CDomain::recvMask(std::map<int, CBufferIn*>& rankBuffers)
2640  {
2641    int nbReceived = rankBuffers.size(), i, ind, index, lInd;
2642    if (nbReceived != recvClientRanks_.size())
2643      ERROR("void CDomain::recvMask(std::map<int, CBufferIn*>& rankBuffers)",
2644           << "The number of sending clients is not correct."
2645           << "Expected number: " << recvClientRanks_.size() << " but received " << nbReceived);
2646
2647    vector<CArray<bool,1> > recvMaskValue(nbReceived);     
2648    for (i = 0; i < recvClientRanks_.size(); ++i)
2649    {
2650      int rank = recvClientRanks_[i];
2651      CBufferIn& buffer = *(rankBuffers[rank]);     
2652      buffer >> recvMaskValue[i];
2653    }
2654
2655    int nbMaskInd = 0;
2656    for (i = 0; i < nbReceived; ++i)
2657    {
2658      nbMaskInd += recvMaskValue[i].numElements();
2659    }
2660 
2661    if (nbMaskInd != globalLocalIndexMap_.size())
2662      info (0) << "If the domain " << this->getDomainOutputName() <<" does not have overlapped region between processes."
2663               << "Something must be wrong with mask index "<< std::endl;
2664
2665    nbMaskInd = globalLocalIndexMap_.size();
2666    mask_1d.resize(nbMaskInd);
2667   
2668    for (i = 0; i < nbReceived; ++i)
2669    {
2670      CArray<int,1>& tmpInd = indGlob_[recvClientRanks_[i]];
2671      CArray<bool,1>& tmp = recvMaskValue[i];
2672      for (ind = 0; ind < tmp.numElements(); ++ind)
2673      {
2674        lInd = globalLocalIndexMap_[size_t(tmpInd(ind))];
2675        if (!mask_1d(lInd))
2676         mask_1d(lInd) = tmp(ind);
2677      }
2678    }   
2679  }
2680
2681  /*!
2682    Receive longitude event from clients(s)
2683    \param[in] event event contain info about rank and associated longitude
2684  */
2685  void CDomain::recvLon(CEventServer& event)
2686  {
2687    string domainId;
2688    std::map<int, CBufferIn*> rankBuffers;
2689
2690    list<CEventServer::SSubEvent>::iterator it;
2691    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2692    {     
2693      CBufferIn* buffer = it->buffer;
2694      *buffer >> domainId;
2695      rankBuffers[it->rank] = buffer;       
2696    }
2697    get(domainId)->recvLon(rankBuffers);
2698  }
2699
2700  /*!
2701    Receive longitude information from client(s)
2702    \param[in] rankBuffers rank of sending client and the corresponding receive buffer 
2703  */
2704  void CDomain::recvLon(std::map<int, CBufferIn*>& rankBuffers)
2705  {
2706    int nbReceived = rankBuffers.size(), i, ind, index, iindex, jindex, lInd;
2707    if (nbReceived != recvClientRanks_.size())
2708      ERROR("void CDomain::recvLon(std::map<int, CBufferIn*>& rankBuffers)",
2709           << "The number of sending clients is not correct."
2710           << "Expected number: " << recvClientRanks_.size() << " but received " << nbReceived);
2711
2712    vector<CArray<double,1> > recvLonValue(nbReceived);
2713    vector<CArray<double,2> > recvBoundsLonValue(nbReceived);   
2714    for (i = 0; i < recvClientRanks_.size(); ++i)
2715    {
2716      int rank = recvClientRanks_[i];
2717      CBufferIn& buffer = *(rankBuffers[rank]);
2718      buffer >> hasLonLat;
2719      if (hasLonLat)
2720        buffer >> recvLonValue[i];
2721      buffer >> hasBounds;
2722      if (hasBounds)
2723        buffer >> recvBoundsLonValue[i];
2724    }
2725
2726    if (hasLonLat)
2727    {
2728      int nbLonInd = 0;
2729      for (i = 0; i < nbReceived; ++i)
2730      {
2731        nbLonInd += recvLonValue[i].numElements();
2732      }
2733   
2734      if (nbLonInd != globalLocalIndexMap_.size())
2735        info (0) << "If the domain " << this->getDomainOutputName() <<" does not have overlapped region between processes."
2736                 << "Something must be wrong with longitude index "<< std::endl;
2737
2738      nbLonInd = globalLocalIndexMap_.size();
2739      lonvalue.resize(nbLonInd);
2740      if (hasBounds)
2741      {
2742        bounds_lonvalue.resize(nvertex,nbLonInd);
2743        bounds_lonvalue = 0.;
2744      }
2745
2746      nbLonInd = 0;
2747      for (i = 0; i < nbReceived; ++i)
2748      {
2749        CArray<int,1>& tmpInd = indGlob_[recvClientRanks_[i]];
2750        CArray<double,1>& tmp = recvLonValue[i];
2751        for (ind = 0; ind < tmp.numElements(); ++ind)
2752        {
2753          lInd = globalLocalIndexMap_[size_t(tmpInd(ind))];
2754          lonvalue(lInd) = tmp(ind); 
2755           if (hasBounds)
2756           {         
2757            for (int nv = 0; nv < nvertex; ++nv)
2758              bounds_lonvalue(nv, lInd) = recvBoundsLonValue[i](nv, ind);
2759           }                 
2760        }
2761      }       
2762    }
2763  }
2764
2765  /*!
2766    Receive latitude event from clients(s)
2767    \param[in] event event contain info about rank and associated latitude
2768  */
2769  void CDomain::recvLat(CEventServer& event)
2770  {
2771    string domainId;
2772    std::map<int, CBufferIn*> rankBuffers;
2773
2774    list<CEventServer::SSubEvent>::iterator it;
2775    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2776    {     
2777      CBufferIn* buffer = it->buffer;
2778      *buffer >> domainId;
2779      rankBuffers[it->rank] = buffer;   
2780    }
2781    get(domainId)->recvLat(rankBuffers);
2782  }
2783
2784  /*!
2785    Receive latitude information from client(s)
2786    \param[in] rankBuffers rank of sending client and the corresponding receive buffer 
2787  */
2788  void CDomain::recvLat(std::map<int, CBufferIn*>& rankBuffers)
2789  {
2790    int nbReceived = rankBuffers.size(), i, ind, index, iindex, jindex, lInd;
2791    if (nbReceived != recvClientRanks_.size())
2792      ERROR("void CDomain::recvLat(std::map<int, CBufferIn*>& rankBuffers)",
2793           << "The number of sending clients is not correct."
2794           << "Expected number: " << recvClientRanks_.size() << " but received " << nbReceived);
2795
2796    vector<CArray<double,1> > recvLatValue(nbReceived);
2797    vector<CArray<double,2> > recvBoundsLatValue(nbReceived);   
2798    for (i = 0; i < recvClientRanks_.size(); ++i)
2799    {
2800      int rank = recvClientRanks_[i];
2801      CBufferIn& buffer = *(rankBuffers[rank]);
2802      buffer >> hasLonLat;
2803      if (hasLonLat)
2804        buffer >> recvLatValue[i];
2805      buffer >> hasBounds;
2806      if (hasBounds)
2807        buffer >> recvBoundsLatValue[i];
2808    }
2809
2810    if (hasLonLat)
2811    {
2812      int nbLatInd = 0;
2813      for (i = 0; i < nbReceived; ++i)
2814      {
2815        nbLatInd += recvLatValue[i].numElements();
2816      }
2817   
2818      if (nbLatInd != globalLocalIndexMap_.size())
2819        info (0) << "If the domain " << this->getDomainOutputName() <<" does not have overlapped region between processes."
2820                << "Something must be wrong with latitude index "<< std::endl;
2821
2822      nbLatInd = globalLocalIndexMap_.size();
2823      latvalue.resize(nbLatInd);
2824      if (hasBounds)
2825      {
2826        bounds_latvalue.resize(nvertex,nbLatInd);
2827        bounds_latvalue = 0. ;
2828      }
2829
2830      nbLatInd = 0;
2831      for (i = 0; i < nbReceived; ++i)
2832      {
2833        CArray<int,1>& tmpInd = indGlob_[recvClientRanks_[i]];
2834        CArray<double,1>& tmp = recvLatValue[i];
2835        for (ind = 0; ind < tmp.numElements(); ++ind)
2836        {
2837          lInd = globalLocalIndexMap_[size_t(tmpInd(ind))];
2838          latvalue(lInd) = tmp(ind);   
2839           if (hasBounds)
2840           {
2841            CArray<double,2>& boundslat = recvBoundsLatValue[i];
2842            for (int nv = 0; nv < nvertex; ++nv)
2843              bounds_latvalue(nv, lInd) = boundslat(nv, ind);
2844           }   
2845          ++nbLatInd;
2846        }
2847      }       
2848    }
2849  }
2850
2851  /*!
2852    Receive area event from clients(s)
2853    \param[in] event event contain info about rank and associated area
2854  */
2855  void CDomain::recvArea(CEventServer& event)
2856  {
2857    string domainId;
2858    std::map<int, CBufferIn*> rankBuffers;
2859
2860    list<CEventServer::SSubEvent>::iterator it;
2861    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2862    {     
2863      CBufferIn* buffer = it->buffer;
2864      *buffer >> domainId;
2865      rankBuffers[it->rank] = buffer;     
2866    }
2867    get(domainId)->recvArea(rankBuffers);
2868  }
2869
2870  /*!
2871    Receive area information from client(s)
2872    \param[in] rankBuffers rank of sending client and the corresponding receive buffer     
2873  */
2874  void CDomain::recvArea(std::map<int, CBufferIn*>& rankBuffers)
2875  {
2876    int nbReceived = rankBuffers.size(), i, ind, index, lInd;
2877    if (nbReceived != recvClientRanks_.size())
2878      ERROR("void CDomain::recvArea(std::map<int, CBufferIn*>& rankBuffers)",
2879           << "The number of sending clients is not correct."
2880           << "Expected number: " << recvClientRanks_.size() << " but received " << nbReceived);
2881
2882    vector<CArray<double,1> > recvAreaValue(nbReceived);     
2883    for (i = 0; i < recvClientRanks_.size(); ++i)
2884    {
2885      int rank = recvClientRanks_[i];
2886      CBufferIn& buffer = *(rankBuffers[rank]);     
2887      buffer >> hasArea;
2888      if (hasArea)
2889        buffer >> recvAreaValue[i];
2890    }
2891
2892    if (hasArea)
2893    {
2894      int nbAreaInd = 0;
2895      for (i = 0; i < nbReceived; ++i)
2896      {     
2897        nbAreaInd += recvAreaValue[i].numElements();
2898      }
2899
2900      if (nbAreaInd != globalLocalIndexMap_.size())
2901        info (0) << "If the domain " << this->getDomainOutputName() <<" does not have overlapped region between processes."
2902                 << "Something must be wrong with area index "<< std::endl;
2903
2904      nbAreaInd = globalLocalIndexMap_.size();
2905      areavalue.resize(nbAreaInd);
2906      nbAreaInd = 0;     
2907      for (i = 0; i < nbReceived; ++i)
2908      {
2909        CArray<int,1>& tmpInd = indGlob_[recvClientRanks_[i]];
2910        CArray<double,1>& tmp = recvAreaValue[i];
2911        for (ind = 0; ind < tmp.numElements(); ++ind)
2912        {
2913          lInd = globalLocalIndexMap_[size_t(tmpInd(ind))];
2914          areavalue(lInd) = tmp(ind);         
2915        }
2916      }
2917     
2918    }
2919  }
2920
2921  /*!
2922    Compare two domain objects.
2923    They are equal if only if they have identical attributes as well as their values.
2924    Moreover, they must have the same transformations.
2925  \param [in] domain Compared domain
2926  \return result of the comparison
2927  */
2928  bool CDomain::isEqual(CDomain* obj)
2929  {
2930    vector<StdString> excludedAttr;
2931    excludedAttr.push_back("domain_ref");
2932    bool objEqual = SuperClass::isEqual(obj, excludedAttr);
2933    if (!objEqual) return objEqual;
2934
2935    TransMapTypes thisTrans = this->getAllTransformations();
2936    TransMapTypes objTrans  = obj->getAllTransformations();
2937
2938    TransMapTypes::const_iterator it, itb, ite;
2939    std::vector<ETranformationType> thisTransType, objTransType;
2940    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
2941      thisTransType.push_back(it->first);
2942    for (it = objTrans.begin(); it != objTrans.end(); ++it)
2943      objTransType.push_back(it->first);
2944
2945    if (thisTransType.size() != objTransType.size()) return false;
2946    for (int idx = 0; idx < thisTransType.size(); ++idx)
2947      objEqual &= (thisTransType[idx] == objTransType[idx]);
2948
2949    return objEqual;
2950  }
2951
2952  /*!
2953    Receive data index event from clients(s)
2954    \param[in] event event contain info about rank and associated index
2955  */
2956  void CDomain::recvDataIndex(CEventServer& event)
2957  {
2958    string domainId;
2959    std::map<int, CBufferIn*> rankBuffers;
2960
2961    list<CEventServer::SSubEvent>::iterator it;
2962    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2963    {     
2964      CBufferIn* buffer = it->buffer;
2965      *buffer >> domainId;
2966      rankBuffers[it->rank] = buffer;       
2967    }
2968    get(domainId)->recvDataIndex(rankBuffers);
2969  }
2970
2971  /*!
2972    Receive data index information from client(s)
2973    A client receives data index from different clients to rebuild its own data index.
2974    Because the data index is local, to rebuild data index of received client, we should use global index along with.
2975    \param[in] rankBuffers rank of sending client and the corresponding receive buffer     
2976  */
2977  void CDomain::recvDataIndex(std::map<int, CBufferIn*>& rankBuffers)
2978  {
2979    int nbReceived = rankBuffers.size(), i, ind, index, indexI, indexJ, type_int, lInd;   
2980    if (nbReceived != recvClientRanks_.size())
2981      ERROR("void CDomain::recvDataIndex(std::map<int, CBufferIn*>& rankBuffers)",
2982           << "The number of sending clients is not correct."
2983           << "Expected number: " << recvClientRanks_.size() << " but received " << nbReceived);
2984
2985    vector<CArray<int,1> > recvDataIIndex(nbReceived),recvDataJIndex(nbReceived);     
2986    for (i = 0; i < recvClientRanks_.size(); ++i)
2987    {
2988      int rank = recvClientRanks_[i];
2989      CBufferIn& buffer = *(rankBuffers[rank]);
2990      buffer >> recvDataIIndex[i];
2991      buffer >> recvDataJIndex[i];
2992    }
2993   
2994    int nbIndex = i_index.numElements();
2995    CArray<int,1> dataIIndex(nbIndex), dataJIndex(nbIndex);
2996    dataIIndex = -1; dataJIndex = -1;
2997     
2998    nbIndex = 0;
2999    for (i = 0; i < nbReceived; ++i)
3000    {     
3001      CArray<int,1>& tmpInd = indGlob_[recvClientRanks_[i]];
3002      CArray<int,1>& tmpI = recvDataIIndex[i];   
3003      CArray<int,1>& tmpJ = recvDataJIndex[i];     
3004      if ((tmpI.numElements() != tmpInd.numElements()) || (tmpJ.numElements() != tmpInd.numElements()))
3005          ERROR("void CDomain::recvDataIndex(std::map<int, CBufferIn*>& rankBuffers)",
3006             << "The number of global received index is not coherent with the number of received data index."
3007             << "Expected number of global index: " << tmpI.numElements() << " but received " << tmpInd.numElements());
3008
3009      for (ind = 0; ind < tmpI.numElements(); ++ind)
3010      {
3011         lInd = globalLocalIndexMap_[size_t(tmpInd(ind))];
3012         dataIIndex(lInd) = (-1 == dataIIndex(lInd)) ? tmpI(ind) : dataIIndex(lInd); // Only fill in dataIndex if there is no data
3013         dataJIndex(lInd) = (-1 == dataJIndex(lInd)) ? tmpJ(ind) : dataJIndex(lInd);         
3014      } 
3015    }
3016
3017    int nbCompressedData = 0; 
3018    for (ind = 0; ind < dataIIndex.numElements(); ++ind)
3019    {
3020       indexI = dataIIndex(ind); indexJ = dataJIndex(ind);
3021       if ((0 <= indexI) && (0 <= indexJ))
3022         ++nbCompressedData;
3023    }       
3024 
3025    data_i_index.resize(nbCompressedData);
3026    data_j_index.resize(nbCompressedData);
3027
3028    nbCompressedData = 0; 
3029    for (ind = 0; ind < dataIIndex.numElements(); ++ind)
3030    {
3031       indexI = dataIIndex(ind); indexJ = dataJIndex(ind);
3032       if ((0 <= indexI) && (0 <= indexJ))
3033       {
3034          data_i_index(nbCompressedData) = (1 == data_dim) ? ind : ind % ni;
3035          data_j_index(nbCompressedData) = (1 == data_dim) ? 0   : ind / ni;
3036         ++nbCompressedData;
3037       }
3038    }
3039
3040    // Reset data_ibegin, data_jbegin
3041    data_ibegin.setValue(0);
3042    data_jbegin.setValue(0);
3043  }
3044
3045  CTransformation<CDomain>* CDomain::addTransformation(ETranformationType transType, const StdString& id)
3046  {
3047    transformationMap_.push_back(std::make_pair(transType, CTransformation<CDomain>::createTransformation(transType,id)));
3048    return transformationMap_.back().second;
3049  }
3050
3051  /*!
3052    Check whether a domain has transformation
3053    \return true if domain has transformation
3054  */
3055  bool CDomain::hasTransformation()
3056  {
3057    return (!transformationMap_.empty());
3058  }
3059
3060  /*!
3061    Set transformation for current domain. It's the method to move transformation in hierarchy
3062    \param [in] domTrans transformation on domain
3063  */
3064  void CDomain::setTransformations(const TransMapTypes& domTrans)
3065  {
3066    transformationMap_ = domTrans;
3067  }
3068
3069  /*!
3070    Get all transformation current domain has
3071    \return all transformation
3072  */
3073  CDomain::TransMapTypes CDomain::getAllTransformations(void)
3074  {
3075    return transformationMap_;
3076  }
3077
3078  void CDomain::duplicateTransformation(CDomain* src)
3079  {
3080    if (src->hasTransformation())
3081    {
3082      this->setTransformations(src->getAllTransformations());
3083    }
3084  }
3085
3086  /*!
3087   * Go through the hierarchy to find the domain from which the transformations must be inherited
3088   */
3089  void CDomain::solveInheritanceTransformation()
3090  {
3091    if (hasTransformation() || !hasDirectDomainReference())
3092      return;
3093
3094    CDomain* domain = this;
3095    std::vector<CDomain*> refDomains;
3096    while (!domain->hasTransformation() && domain->hasDirectDomainReference())
3097    {
3098      refDomains.push_back(domain);
3099      domain = domain->getDirectDomainReference();
3100    }
3101
3102    if (domain->hasTransformation())
3103      for (size_t i = 0; i < refDomains.size(); ++i)
3104        refDomains[i]->setTransformations(domain->getAllTransformations());
3105  }
3106
3107  /*!
3108    Parse children nodes of a domain in xml file.
3109    Whenver there is a new transformation, its type and name should be added into this function
3110    \param node child node to process
3111  */
3112  void CDomain::parse(xml::CXMLNode & node)
3113  {
3114    SuperClass::parse(node);
3115
3116    if (node.goToChildElement())
3117    {
3118      StdString nodeElementName;
3119      do
3120      {
3121        StdString nodeId("");
3122        if (node.getAttributes().end() != node.getAttributes().find("id"))
3123        { nodeId = node.getAttributes()["id"]; }
3124
3125        nodeElementName = node.getElementName();
3126        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
3127        it = transformationMapList_.find(nodeElementName);
3128        if (ite != it)
3129        {
3130          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CDomain>::createTransformation(it->second,
3131                                                                                                                nodeId,
3132                                                                                                                &node)));
3133        }
3134        else
3135        {
3136          ERROR("void CDomain::parse(xml::CXMLNode & node)",
3137                << "The transformation " << nodeElementName << " has not been supported yet.");
3138        }
3139      } while (node.goToNextElement()) ;
3140      node.goToParentElement();
3141    }
3142  }
3143   //----------------------------------------------------------------
3144
3145   DEFINE_REF_FUNC(Domain,domain)
3146
3147   ///---------------------------------------------------------------
3148
3149} // namespace xios
Note: See TracBrowser for help on using the repository browser.