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

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

Fixing the blocking problem where there are more servers than the number of grid band distribution

+) Correct this problem not only for writing but also for reading
+) Allow "zero-size" domain, axis (i.e: domain, axis with ni = 0, and/or nj=0)

Test
+) On Curie
+) Work in both cases: Read and Write data

  • 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: 113.6 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       // Even if servers have no index, they must received something from client
1813       // We only use several client to send "empty" message to these servers
1814      CServerDistributionDescription serverDescription(nGlobDomain, nbServer);
1815      std::vector<int> serverZeroIndex;
1816      if (isUnstructed_) serverZeroIndex = serverDescription.computeServerGlobalIndexInRange(std::make_pair<size_t,size_t>(indexBegin, indexEnd), 0);
1817      else serverZeroIndex = serverDescription.computeServerGlobalIndexInRange(std::make_pair<size_t,size_t>(indexBegin, indexEnd), 1);
1818
1819       std::list<int> serverZeroIndexLeader;
1820       std::list<int> serverZeroIndexNotLeader; 
1821       CContextClient::computeLeader(client->clientRank, client->clientSize, serverZeroIndex.size(), serverZeroIndexLeader, serverZeroIndexNotLeader);
1822       for (std::list<int>::iterator it = serverZeroIndexLeader.begin(); it != serverZeroIndexLeader.end(); ++it)
1823         *it = serverZeroIndex[*it];
1824
1825      CClientServerMapping* clientServerMap = new CClientServerMappingDistributed(serverDescription.getGlobalIndexRange(),
1826                                                                                  client->intraComm);
1827      clientServerMap->computeServerIndexMapping(globalIndexDomain);
1828      CClientServerMapping::GlobalIndexMap& globalIndexDomainOnServer = clientServerMap->getGlobalIndexOnServer();
1829
1830      CClientServerMapping::GlobalIndexMap::const_iterator it  = globalIndexDomainOnServer.begin(),
1831                                                           ite = globalIndexDomainOnServer.end();
1832      indSrv_.swap(globalIndexDomainOnServer);
1833      connectedServerRank_.clear();
1834      for (it = indSrv_.begin(); it != ite; ++it) 
1835        connectedServerRank_.push_back(it->first);
1836
1837      for (std::list<int>::const_iterator it = serverZeroIndexLeader.begin(); it != serverZeroIndexLeader.end(); ++it)
1838        connectedServerRank_.push_back(*it);
1839
1840       // Even if a client has no index, it must connect to at least one server and
1841       // send an "empty" data to this server
1842       if (connectedServerRank_.empty())
1843        connectedServerRank_.push_back(client->clientRank % client->serverSize);
1844
1845      nbConnectedClients_ = clientServerMap->computeConnectedClients(client->serverSize, client->clientSize, client->intraComm, connectedServerRank_);
1846
1847     //  clientServerMap->computeServerIndexMapping(globalIndexDomainZoom);
1848     //  CClientServerMapping::GlobalIndexMap& globalIndexDomainZoomOnServer = clientServerMap->getGlobalIndexOnServer();
1849     //  indZoomSrv_.swap(globalIndexDomainZoomOnServer);
1850     
1851     // for (it = indZoomSrv_.begin(); it != indZoomSrv_.end(); ++it)
1852     //   connectedServerZoomRank_.push_back(it->first);
1853
1854     //  nbConnectedClientsZoom_ = clientServerMap->computeConnectedClients(client->serverSize, client->clientSize, client->intraComm, connectedServerZoomRank_);
1855
1856      delete clientServerMap;
1857    }
1858  }
1859
1860   /*!
1861     Compute index to write data. We only write data on the zoomed region, therefore, there should
1862     be a map between the complete grid and the reduced grid where we write data.
1863     By using global index we can easily create this kind of mapping.
1864   */
1865   void CDomain::computeWrittenIndex()
1866   { 
1867      if (computedWrittenIndex_) return;
1868      computedWrittenIndex_ = true;
1869
1870      CContext* context=CContext::getCurrent();     
1871      CContextServer* server = context->server; 
1872
1873      std::vector<int> nBegin(2), nSize(2), nBeginGlobal(2), nGlob(2);
1874      nBegin[0]       = zoom_ibegin;  nBegin[1] = zoom_jbegin;
1875      nSize[0]        = zoom_ni;      nSize[1]  = zoom_nj;
1876      nBeginGlobal[0] = 0; nBeginGlobal[1] = 0;
1877      nGlob[0]        = ni_glo;   nGlob[1] = nj_glo;
1878      CDistributionServer srvDist(server->intraCommSize, nBegin, nSize, nBeginGlobal, nGlob); 
1879      const CArray<size_t,1>& writtenGlobalIndex  = srvDist.getGlobalIndex();
1880
1881      size_t nbWritten = 0, indGlo;     
1882      boost::unordered_map<size_t,size_t>::const_iterator itb = globalLocalIndexMap_.begin(),
1883                                                          ite = globalLocalIndexMap_.end(), it;         
1884      CArray<size_t,1>::const_iterator itSrvb = writtenGlobalIndex.begin(),
1885                                       itSrve = writtenGlobalIndex.end(), itSrv;
1886
1887      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
1888      {
1889        indGlo = *itSrv;
1890        if (ite != globalLocalIndexMap_.find(indGlo))
1891        {         
1892          ++nbWritten;
1893        }                 
1894      }
1895
1896      localIndexToWriteOnServer.resize(nbWritten);
1897
1898      nbWritten = 0;
1899      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
1900      {
1901        indGlo = *itSrv;
1902        if (ite != globalLocalIndexMap_.find(indGlo))
1903        {
1904          localIndexToWriteOnServer(nbWritten) = globalLocalIndexMap_[indGlo];
1905          ++nbWritten;
1906        }                 
1907      }
1908     
1909      if (isCompressible())
1910      {
1911        nbWritten = 0;
1912        boost::unordered_map<size_t,size_t> localGlobalIndexMap;
1913        for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
1914        {
1915          indGlo = *itSrv;
1916          if (ite != globalLocalIndexMap_.find(indGlo))
1917          {
1918            localGlobalIndexMap[localIndexToWriteOnServer(nbWritten)] = indGlo;
1919            ++nbWritten;
1920          }                 
1921        }
1922
1923        nbWritten = 0;
1924        for (int idx = 0; idx < data_i_index.numElements(); ++idx)
1925        {
1926          if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_i_index(idx)))
1927          {
1928            ++nbWritten;
1929          }
1930        }
1931
1932        compressedIndexToWriteOnServer.resize(nbWritten);
1933        nbWritten = 0;
1934        for (int idx = 0; idx < data_i_index.numElements(); ++idx)
1935        {
1936          if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_i_index(idx)))
1937          {
1938            compressedIndexToWriteOnServer(nbWritten) = localGlobalIndexMap[data_i_index(idx)];
1939            ++nbWritten;
1940          }
1941        }
1942
1943        numberWrittenIndexes_ = nbWritten;
1944        if (isDistributed())
1945        {           
1946          MPI_Allreduce(&numberWrittenIndexes_, &totalNumberWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
1947          MPI_Scan(&numberWrittenIndexes_, &offsetWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
1948          offsetWrittenIndexes_ -= numberWrittenIndexes_;
1949        }
1950        else
1951          totalNumberWrittenIndexes_ = numberWrittenIndexes_;
1952      }     
1953   }
1954
1955  /*!
1956    Send all attributes from client to connected clients
1957    The attributes will be rebuilt on receiving side
1958  */
1959  void CDomain::sendAttributes()
1960  {
1961    sendDistributionAttributes();
1962    sendIndex();   
1963    // sendIndexZoom();
1964    sendMask();
1965    sendLonLat();
1966    sendArea();   
1967    sendDataIndex();
1968  }
1969
1970  /*!
1971    Send global index and zoom index from client to connected client(s)
1972    zoom index can be smaller than global index
1973  */
1974  void CDomain::sendIndex()
1975  {
1976    int ns, n, i, j, ind, nv, idx;
1977    CContext* context = CContext::getCurrent();
1978
1979    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
1980    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
1981    for (int p = 0; p < nbSrvPools; ++p)
1982    {
1983      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
1984
1985      CEventClient eventIndex(getType(), EVENT_ID_INDEX);
1986
1987      list<CMessage> list_msgsIndex;
1988      list<CArray<int,1> > list_indZoom, list_writtenInd, list_indGlob;
1989
1990      boost::unordered_map<int, vector<size_t> >::const_iterator itIndex, iteIndex;
1991      iteIndex = indSrv_.end();
1992      for (int k = 0; k < connectedServerRank_.size(); ++k)
1993      {
1994        int nbIndGlob = 0;
1995        int rank = connectedServerRank_[k];
1996        itIndex = indSrv_.find(rank);
1997        if (iteIndex != itIndex)
1998          nbIndGlob = itIndex->second.size();
1999
2000        list_indGlob.push_back(CArray<int,1>(nbIndGlob));       
2001
2002        CArray<int,1>& indGlob = list_indGlob.back();
2003        for (n = 0; n < nbIndGlob; ++n)
2004        {
2005          indGlob(n) = static_cast<int>(itIndex->second[n]);
2006        }
2007
2008        list_msgsIndex.push_back(CMessage());
2009        list_msgsIndex.back() << this->getId() << (int)type; // enum ne fonctionne pour les message => ToFix
2010        list_msgsIndex.back() << isCurvilinear;
2011        list_msgsIndex.back() << list_indGlob.back(); //list_indi.back() << list_indj.back();
2012       
2013        eventIndex.push(rank, nbConnectedClients_[rank], list_msgsIndex.back());
2014      }
2015
2016      client->sendEvent(eventIndex);
2017    }
2018  }
2019
2020  /*!
2021    Send global index and zoom index from client to connected client(s)
2022    zoom index can be smaller than global index.
2023    This function can be used in the future???
2024  */
2025  // void CDomain::sendIndexZoom()
2026  // {
2027  //   int ns, n, i, j, ind, nv, idx;
2028  //   CContext* context = CContext::getCurrent();
2029
2030  //   // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2031  //   int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2032  //   for (int p = 0; p < nbSrvPools; ++p)
2033  //   {
2034  //     CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
2035  //     CEventClient eventIndexZoom(getType(), EVENT_ID_INDEX_ZOOM);
2036
2037  //     list<CMessage> list_msgsIndex;
2038  //     list<CArray<int,1> > list_indZoom;
2039
2040  //     boost::unordered_map<int, vector<size_t> >::const_iterator itZoom, iteZoom;
2041  //     iteZoom = indZoomSrv_.end();
2042  //     for (int k = 0; k < connectedServerZoomRank_.size(); ++k)
2043  //     {
2044  //       int nbIndGlob = 0;
2045  //       int rank = connectedServerZoomRank_[k];
2046  //       int nbIndZoom = 0;
2047  //       itZoom = indZoomSrv_.find(rank);
2048  //       if (iteZoom != itZoom)
2049  //         nbIndZoom = itZoom->second.size();
2050       
2051  //       list_indZoom.push_back(CArray<int,1>(nbIndZoom));
2052  //       CArray<int,1>& indZoom = list_indZoom.back();
2053  //       for (n = 0; n < nbIndZoom; ++n)
2054  //       {
2055  //         indZoom(n) = static_cast<int>(itZoom->second[n]);
2056  //       }
2057
2058  //       list_msgsIndex.push_back(CMessage());
2059  //       list_msgsIndex.back() << this->getId(); // enum ne fonctionne pour les message => ToFix       
2060  //       list_msgsIndex.back() << list_indZoom.back() << doZoomByIndex_; //list_indi.back() << list_indj.back     
2061
2062  //       eventIndexZoom.push(rank, nbConnectedClientsZoom_[rank], list_msgsIndex.back());
2063  //     }
2064
2065  //     client->sendEvent(eventIndexZoom);
2066  //   }
2067  // }
2068
2069  /*!
2070    Send distribution from client to other clients
2071    Because a client in a level knows correctly the grid distribution of client on the next level
2072    it calculates this distribution then sends it to the corresponding clients on the next level
2073  */
2074  void CDomain::sendDistributionAttributes(void)
2075  {
2076    CContext* context = CContext::getCurrent();
2077     // Use correct context client to send message
2078    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2079    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2080    for (int i = 0; i < nbSrvPools; ++i)
2081    {
2082      CContextClient* contextClientTmp = (context->hasServer) ? context->clientPrimServer[i]
2083                                                                         : context->client;   
2084      int nbServer = contextClientTmp->serverSize;
2085      std::vector<int> nGlobDomain(2);
2086      nGlobDomain[0] = this->ni_glo;
2087      nGlobDomain[1] = this->nj_glo;
2088
2089      CServerDistributionDescription serverDescription(nGlobDomain, nbServer);
2090      if (isUnstructed_) serverDescription.computeServerDistribution(false, 0);
2091      else serverDescription.computeServerDistribution(false, 1);
2092
2093      std::vector<std::vector<int> > serverIndexBegin = serverDescription.getServerIndexBegin();
2094      std::vector<std::vector<int> > serverDimensionSizes = serverDescription.getServerDimensionSizes();
2095
2096      CEventClient event(getType(),EVENT_ID_SERVER_ATTRIBUT);
2097      if (contextClientTmp->isServerLeader())
2098      {
2099        std::list<CMessage> msgs;
2100
2101        const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
2102        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
2103        {
2104          // Use const int to ensure CMessage holds a copy of the value instead of just a reference
2105          const int ibegin_srv = serverIndexBegin[*itRank][0];
2106          const int jbegin_srv = serverIndexBegin[*itRank][1];
2107          const int ni_srv = serverDimensionSizes[*itRank][0];
2108          const int nj_srv = serverDimensionSizes[*itRank][1];
2109
2110          msgs.push_back(CMessage());
2111          CMessage& msg = msgs.back();
2112          msg << this->getId() ;
2113          msg << ni_srv << ibegin_srv << nj_srv << jbegin_srv;
2114          msg << global_zoom_ni.getValue() << global_zoom_ibegin.getValue() << global_zoom_nj.getValue() << global_zoom_jbegin.getValue();       
2115          msg << isCompressible_;
2116
2117          event.push(*itRank,1,msg);
2118        }
2119        contextClientTmp->sendEvent(event);
2120      }
2121      else contextClientTmp->sendEvent(event);
2122    }
2123  }
2124
2125  /*!
2126    Send mask index from client to connected(s) clients   
2127  */
2128  void CDomain::sendMask()
2129  {
2130    int ns, n, i, j, ind, nv, idx;
2131    CContext* context = CContext::getCurrent();
2132
2133    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2134    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2135    for (int p = 0; p < nbSrvPools; ++p)
2136    {
2137      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
2138
2139      // send area for each connected server
2140      CEventClient eventMask(getType(), EVENT_ID_MASK);
2141
2142      list<CMessage> list_msgsMask;
2143      list<CArray<bool,1> > list_mask;
2144
2145      boost::unordered_map<int, vector<size_t> >::const_iterator it, iteMap;
2146      iteMap = indSrv_.end();
2147      for (int k = 0; k < connectedServerRank_.size(); ++k)
2148      {
2149        int nbData = 0;
2150        int rank = connectedServerRank_[k];
2151        it = indSrv_.find(rank);
2152        if (iteMap != it)
2153          nbData = it->second.size();
2154        list_mask.push_back(CArray<bool,1>(nbData));
2155
2156        const std::vector<size_t>& temp = it->second;
2157        for (n = 0; n < nbData; ++n)
2158        {
2159          idx = static_cast<int>(it->second[n]);
2160          list_mask.back()(n) = mask_1d(globalLocalIndexMap_[idx]);
2161        }
2162
2163        list_msgsMask.push_back(CMessage());
2164        list_msgsMask.back() << this->getId() << list_mask.back();
2165        eventMask.push(rank, nbConnectedClients_[rank], list_msgsMask.back());
2166      }
2167      client->sendEvent(eventMask);
2168    }
2169  }
2170
2171  /*!
2172    Send area from client to connected client(s)
2173  */
2174  void CDomain::sendArea()
2175  {
2176    if (!hasArea) return;
2177
2178    int ns, n, i, j, ind, nv, idx;
2179    CContext* context = CContext::getCurrent();
2180
2181    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2182    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2183    for (int p = 0; p < nbSrvPools; ++p)
2184    {
2185      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
2186
2187      // send area for each connected server
2188      CEventClient eventArea(getType(), EVENT_ID_AREA);
2189
2190      list<CMessage> list_msgsArea;
2191      list<CArray<double,1> > list_area;
2192
2193      boost::unordered_map<int, vector<size_t> >::const_iterator it, iteMap;
2194      iteMap = indSrv_.end();
2195      for (int k = 0; k < connectedServerRank_.size(); ++k)
2196      {
2197        int nbData = 0;
2198        int rank = connectedServerRank_[k];
2199        it = indSrv_.find(rank);
2200        if (iteMap != it)
2201          nbData = it->second.size();
2202        list_area.push_back(CArray<double,1>(nbData));
2203
2204        const std::vector<size_t>& temp = it->second;
2205        for (n = 0; n < nbData; ++n)
2206        {
2207          idx = static_cast<int>(it->second[n]);
2208          list_area.back()(n) = areavalue(globalLocalIndexMap_[idx]);
2209        }
2210
2211        list_msgsArea.push_back(CMessage());
2212        list_msgsArea.back() << this->getId() << hasArea;
2213        list_msgsArea.back() << list_area.back();
2214        eventArea.push(rank, nbConnectedClients_[rank], list_msgsArea.back());
2215      }
2216      client->sendEvent(eventArea);
2217    }
2218  }
2219
2220  /*!
2221    Send longitude and latitude from client to servers
2222    Each client send long and lat information to corresponding connected clients(s).
2223    Because longitude and latitude are optional, this function only called if latitude and longitude exist
2224  */
2225  void CDomain::sendLonLat()
2226  {
2227    if (!hasLonLat) return;
2228
2229    int ns, n, i, j, ind, nv, idx;
2230    CContext* context = CContext::getCurrent();
2231
2232    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2233    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2234    for (int p = 0; p < nbSrvPools; ++p)
2235    {
2236      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
2237
2238      // send lon lat for each connected server
2239      CEventClient eventLon(getType(), EVENT_ID_LON);
2240      CEventClient eventLat(getType(), EVENT_ID_LAT);
2241
2242      list<CMessage> list_msgsLon, list_msgsLat;
2243      list<CArray<double,1> > list_lon, list_lat;
2244      list<CArray<double,2> > list_boundslon, list_boundslat;
2245
2246      boost::unordered_map<int, vector<size_t> >::const_iterator it, iteMap;
2247      iteMap = indSrv_.end();
2248      for (int k = 0; k < connectedServerRank_.size(); ++k)
2249      {
2250        int nbData = 0;
2251        int rank = connectedServerRank_[k];
2252        it = indSrv_.find(rank);
2253        if (iteMap != it)
2254          nbData = it->second.size();
2255
2256        list_lon.push_back(CArray<double,1>(nbData));
2257        list_lat.push_back(CArray<double,1>(nbData));
2258
2259        if (hasBounds)
2260        {
2261          list_boundslon.push_back(CArray<double,2>(nvertex, nbData));
2262          list_boundslat.push_back(CArray<double,2>(nvertex, nbData));
2263        }
2264
2265        CArray<double,1>& lon = list_lon.back();
2266        CArray<double,1>& lat = list_lat.back();
2267        const std::vector<size_t>& temp = it->second;
2268        for (n = 0; n < nbData; ++n)
2269        {
2270          idx = static_cast<int>(it->second[n]);
2271          int localInd = globalLocalIndexMap_[idx];
2272          lon(n) = lonvalue(localInd);
2273          lat(n) = latvalue(localInd);
2274
2275          if (hasBounds)
2276          {
2277            CArray<double,2>& boundslon = list_boundslon.back();
2278            CArray<double,2>& boundslat = list_boundslat.back();
2279
2280            for (nv = 0; nv < nvertex; ++nv)
2281            {
2282              boundslon(nv, n) = bounds_lonvalue(nv, localInd);
2283              boundslat(nv, n) = bounds_latvalue(nv, localInd);
2284            }
2285          }
2286        }
2287
2288        list_msgsLon.push_back(CMessage());
2289        list_msgsLat.push_back(CMessage());
2290
2291        list_msgsLon.back() << this->getId() << hasLonLat;
2292        if (hasLonLat) 
2293          list_msgsLon.back() << list_lon.back();
2294        list_msgsLon.back()  << hasBounds;
2295        if (hasBounds)
2296        {
2297          list_msgsLon.back() << list_boundslon.back();
2298        }
2299
2300        list_msgsLat.back() << this->getId() << hasLonLat;
2301        if (hasLonLat)
2302          list_msgsLat.back() << list_lat.back();
2303        list_msgsLat.back() << hasBounds;
2304        if (hasBounds)
2305        {         
2306          list_msgsLat.back() << list_boundslat.back();
2307        }
2308
2309        eventLon.push(rank, nbConnectedClients_[rank], list_msgsLon.back());
2310        eventLat.push(rank, nbConnectedClients_[rank], list_msgsLat.back());
2311      }
2312      client->sendEvent(eventLon);
2313      client->sendEvent(eventLat);
2314    }
2315  }
2316
2317  /*!
2318    Send data index to corresponding connected clients.
2319    Data index can be compressed however, we always send decompressed data index
2320    and they will be compressed on receiving.
2321    The compressed index are represented with 1 and others are represented with -1
2322  */
2323  void CDomain::sendDataIndex()
2324  {
2325    int ns, n, i, j, ind, nv, idx;
2326    CContext* context = CContext::getCurrent();
2327
2328    // int nbSrvPools = (context->hasServer) ? context->clientPrimServer.size() : 1;
2329    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
2330    for (int p = 0; p < nbSrvPools; ++p)
2331    {
2332      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
2333
2334      // send area for each connected server
2335      CEventClient eventDataIndex(getType(), EVENT_ID_DATA_INDEX);
2336
2337      list<CMessage> list_msgsDataIndex;
2338      list<CArray<int,1> > list_data_i_index, list_data_j_index;
2339
2340      int nbIndex = i_index.numElements();
2341      int niByIndex = max(i_index) - min(i_index) + 1;
2342      int njByIndex = max(j_index) - min(j_index) + 1; 
2343      int dataIindexBound = (1 == data_dim) ? (niByIndex * njByIndex) : niByIndex;
2344      int dataJindexBound = (1 == data_dim) ? (niByIndex * njByIndex) : njByIndex;
2345
2346     
2347      CArray<int,1> dataIIndex(nbIndex), dataJIndex(nbIndex);
2348      dataIIndex = -1; 
2349      dataJIndex = -1;
2350      ind = 0;
2351
2352      for (idx = 0; idx < data_i_index.numElements(); ++idx)
2353      {
2354        int dataIidx = data_i_index(idx) + data_ibegin;
2355        int dataJidx = data_j_index(idx) + data_jbegin;
2356        if ((0 <= dataIidx) && (dataIidx < dataIindexBound) &&
2357            (0 <= dataJidx) && (dataJidx < dataJindexBound))
2358        {
2359          dataIIndex((1 == data_dim) ? dataIidx : dataJidx * ni + dataIidx) = 1; //i_index(dataIidx);//dataIidx;
2360          dataJIndex((1 == data_dim) ? dataIidx : dataJidx * ni + dataIidx) = 1; //j_index(dataJidx);//         
2361        }
2362      }
2363
2364      boost::unordered_map<int, vector<size_t> >::const_iterator it, iteMap;
2365      iteMap = indSrv_.end();
2366      for (int k = 0; k < connectedServerRank_.size(); ++k)
2367      {
2368        int nbData = 0;
2369        int rank = connectedServerRank_[k];
2370        it = indSrv_.find(rank);
2371        if (iteMap != it)
2372          nbData = it->second.size();
2373        list_data_i_index.push_back(CArray<int,1>(nbData));
2374        list_data_j_index.push_back(CArray<int,1>(nbData));
2375
2376        const std::vector<size_t>& temp = it->second;
2377        for (n = 0; n < nbData; ++n)
2378        {
2379          idx = static_cast<int>(it->second[n]);
2380          i = globalLocalIndexMap_[idx];
2381          list_data_i_index.back()(n) = dataIIndex(i);
2382          list_data_j_index.back()(n) = dataJIndex(i);
2383        }
2384
2385        list_msgsDataIndex.push_back(CMessage());
2386        list_msgsDataIndex.back() << this->getId();
2387        list_msgsDataIndex.back() << list_data_i_index.back() << list_data_j_index.back();
2388        eventDataIndex.push(rank, nbConnectedClients_[rank], list_msgsDataIndex.back());
2389      }
2390      client->sendEvent(eventDataIndex);
2391    }
2392  }
2393 
2394  bool CDomain::dispatchEvent(CEventServer& event)
2395  {
2396    if (SuperClass::dispatchEvent(event)) return true;
2397    else
2398    {
2399      switch(event.type)
2400      {
2401        case EVENT_ID_SERVER_ATTRIBUT:
2402          recvDistributionAttributes(event);
2403          return true;
2404          break;
2405        case EVENT_ID_INDEX:
2406          recvIndex(event);
2407          return true;
2408          break;
2409        case EVENT_ID_INDEX_ZOOM:
2410          recvIndexZoom(event);
2411          return true;
2412          break;
2413        case EVENT_ID_MASK:
2414          recvMask(event);
2415          return true;
2416          break;
2417        case EVENT_ID_LON:
2418          recvLon(event);
2419          return true;
2420          break;
2421        case EVENT_ID_LAT:
2422          recvLat(event);
2423          return true;
2424          break;
2425        case EVENT_ID_AREA:
2426          recvArea(event);
2427          return true;
2428          break; 
2429        case EVENT_ID_DATA_INDEX:
2430          recvDataIndex(event);
2431          return true;
2432          break;
2433        default:
2434          ERROR("bool CDomain::dispatchEvent(CEventServer& event)",
2435                << "Unknown Event");
2436          return false;
2437       }
2438    }
2439  }
2440
2441  /*!
2442    Receive index event from clients(s)
2443    \param[in] event event contain info about rank and associated index
2444  */
2445  void CDomain::recvIndex(CEventServer& event)
2446  {
2447    string domainId;
2448    std::map<int, CBufferIn*> rankBuffers;
2449
2450    list<CEventServer::SSubEvent>::iterator it;
2451    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2452    {     
2453      CBufferIn* buffer = it->buffer;
2454      *buffer >> domainId;
2455      rankBuffers[it->rank] = buffer;       
2456    }
2457    get(domainId)->recvIndex(rankBuffers);
2458  }
2459
2460  /*!
2461    Receive index information from client(s). We use the global index for mapping index between
2462    sending clients and receiving clients.
2463    \param[in] rankBuffers rank of sending client and the corresponding receive buffer 
2464  */
2465  void CDomain::recvIndex(std::map<int, CBufferIn*>& rankBuffers)
2466  {
2467    int nbReceived = rankBuffers.size(), i, ind, index, type_int;
2468    recvClientRanks_.resize(nbReceived);       
2469
2470    std::map<int, CBufferIn*>::iterator it = rankBuffers.begin(), ite = rankBuffers.end();
2471    ind = 0;
2472    for (ind = 0; it != ite; ++it, ++ind)
2473    {       
2474       recvClientRanks_[ind] = it->first;
2475       CBufferIn& buffer = *(it->second);
2476       buffer >> type_int >> isCurvilinear >> indGlob_[it->first]; 
2477       type.setValue((type_attr::t_enum)type_int); // probleme des type enum avec les buffers : ToFix
2478    }
2479    int nbIndGlob = 0;
2480    for (i = 0; i < nbReceived; ++i)
2481    {
2482      nbIndGlob += indGlob_[recvClientRanks_[i]].numElements();
2483    }
2484   
2485    globalLocalIndexMap_.rehash(std::ceil(nbIndGlob/globalLocalIndexMap_.max_load_factor()));
2486    i_index.resize(nbIndGlob);
2487    j_index.resize(nbIndGlob);   
2488    nbIndGlob = 0;
2489    for (i = 0; i < nbReceived; ++i)
2490    {
2491      CArray<int,1>& tmp = indGlob_[recvClientRanks_[i]];
2492      for (ind = 0; ind < tmp.numElements(); ++ind)
2493      {
2494         index = tmp(ind);
2495         if (0 == globalLocalIndexMap_.count(index))
2496         {
2497           i_index(nbIndGlob) = index % ni_glo;
2498           j_index(nbIndGlob) = index / ni_glo;
2499           globalLocalIndexMap_[index] = nbIndGlob; 
2500           ++nbIndGlob;
2501         } 
2502      } 
2503    } 
2504
2505    i_index.resizeAndPreserve(nbIndGlob);
2506    j_index.resizeAndPreserve(nbIndGlob);
2507  }
2508
2509  /*!
2510    Receive index event from clients(s)
2511    \param[in] event event contain info about rank and associated index
2512  */
2513  void CDomain::recvIndexZoom(CEventServer& event)
2514  {
2515    string domainId;
2516    std::map<int, CBufferIn*> rankBuffers;
2517
2518    list<CEventServer::SSubEvent>::iterator it;
2519    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2520    {     
2521      CBufferIn* buffer = it->buffer;
2522      *buffer >> domainId;
2523      rankBuffers[it->rank] = buffer;       
2524    }
2525    get(domainId)->recvIndexZoom(rankBuffers);
2526  }
2527
2528  /*!
2529    Receive index information from client(s)
2530    \param[in] rankBuffers rank of sending client and the corresponding receive buffer 
2531  */
2532  void CDomain::recvIndexZoom(std::map<int, CBufferIn*>& rankBuffers)
2533  {
2534    int nbReceived = rankBuffers.size(), i, ind, index, type_int;
2535    recvClientZoomRanks_.resize(nbReceived);   
2536    int ni_zoom_tmp, ibegin_zoom_tmp, nj_zoom_tmp, jbegin_zoom_tmp;
2537
2538    std::map<int, CBufferIn*>::iterator it = rankBuffers.begin(), ite = rankBuffers.end();
2539    ind = 0;
2540    for (ind = 0; it != ite; ++it, ++ind)
2541    {       
2542       recvClientZoomRanks_[ind] = it->first;
2543       CBufferIn& buffer = *(it->second);
2544       buffer >> indGlobZoom_[it->first] >> doZoomByIndex_;       
2545    }
2546
2547    int nbZoomInd = 0;
2548    for (i = 0; i < nbReceived; ++i)
2549    {
2550      nbZoomInd += indGlobZoom_[recvClientZoomRanks_[i]].numElements();
2551    }
2552
2553    if (doZoomByIndex_)
2554    {
2555      zoom_i_index.resize(nbZoomInd);
2556      zoom_j_index.resize(nbZoomInd);
2557     
2558      nbZoomInd = 0;
2559      for (i = 0; i < nbReceived; ++i)
2560      {
2561        CArray<int,1>& tmp = indGlobZoom_[recvClientRanks_[i]];
2562        for (ind = 0; ind < tmp.numElements(); ++ind)
2563        {
2564           index = tmp(ind);
2565           zoom_i_index(nbZoomInd) = index % ni_glo;
2566           zoom_j_index(nbZoomInd) = index / ni_glo;
2567           ++nbZoomInd;
2568        } 
2569      }     
2570    }
2571    else 
2572    {
2573    }
2574  }
2575
2576  /*!
2577    Receive attributes event from clients(s)
2578    \param[in] event event contain info about rank and associated attributes
2579  */
2580  void CDomain::recvDistributionAttributes(CEventServer& event)
2581  {
2582    CBufferIn* buffer=event.subEvents.begin()->buffer;
2583    string domainId ;
2584    *buffer>>domainId ;
2585    get(domainId)->recvDistributionAttributes(*buffer);
2586  }
2587
2588  /*!
2589    Receive attributes from client(s): zoom info and begin and n of each server
2590    \param[in] rank rank of client source
2591    \param[in] buffer message containing attributes info
2592  */
2593  void CDomain::recvDistributionAttributes(CBufferIn& buffer)
2594  {
2595    int ni_tmp, ibegin_tmp, nj_tmp, jbegin_tmp;
2596    int global_zoom_ni_tmp, global_zoom_ibegin_tmp, global_zoom_nj_tmp, global_zoom_jbegin_tmp;
2597    buffer >> ni_tmp >> ibegin_tmp >> nj_tmp >> jbegin_tmp
2598           >> global_zoom_ni_tmp >> global_zoom_ibegin_tmp >> global_zoom_nj_tmp >> global_zoom_jbegin_tmp           
2599           >> isCompressible_;
2600    ni.setValue(ni_tmp);
2601    ibegin.setValue(ibegin_tmp);
2602    nj.setValue(nj_tmp);
2603    jbegin.setValue(jbegin_tmp);
2604
2605    global_zoom_ni.setValue(global_zoom_ni_tmp);
2606    global_zoom_ibegin.setValue(global_zoom_ibegin_tmp);
2607    global_zoom_nj.setValue(global_zoom_nj_tmp);
2608    global_zoom_jbegin.setValue(global_zoom_jbegin_tmp);
2609
2610    int iend = ibegin + ni  - 1;
2611    int jend = jbegin + nj  - 1;
2612    int zoom_iend_glob = global_zoom_ibegin + global_zoom_ni - 1;
2613    int zoom_jend_glob = global_zoom_jbegin + global_zoom_nj - 1;
2614
2615    zoom_ibegin.setValue(global_zoom_ibegin > ibegin ? global_zoom_ibegin : ibegin);
2616    int zoom_iend = zoom_iend_glob < iend ? zoom_iend_glob : iend ;
2617    zoom_ni.setValue(zoom_iend-zoom_ibegin+1);
2618
2619    zoom_jbegin.setValue(global_zoom_jbegin > jbegin ? global_zoom_jbegin : jbegin);
2620    int zoom_jend = zoom_jend_glob < jend ? zoom_jend_glob : jend ;
2621    zoom_nj.setValue(zoom_jend-zoom_jbegin+1);
2622
2623    if (zoom_ni<=0 || zoom_nj<=0)
2624    {
2625      zoom_ibegin=0 ; zoom_iend=0 ; zoom_ni=0 ;
2626      zoom_jbegin=0 ; zoom_jend=0 ; zoom_nj=0 ;
2627    }
2628
2629  }
2630
2631  /*!
2632    Receive area event from clients(s)
2633    \param[in] event event contain info about rank and associated area
2634  */
2635  void CDomain::recvMask(CEventServer& event)
2636  {
2637    string domainId;
2638    std::map<int, CBufferIn*> rankBuffers;
2639
2640    list<CEventServer::SSubEvent>::iterator it;
2641    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2642    {     
2643      CBufferIn* buffer = it->buffer;
2644      *buffer >> domainId;
2645      rankBuffers[it->rank] = buffer;     
2646    }
2647    get(domainId)->recvMask(rankBuffers);
2648  }
2649
2650
2651  /*!
2652    Receive mask information from client(s)
2653    \param[in] rankBuffers rank of sending client and the corresponding receive buffer 
2654  */
2655  void CDomain::recvMask(std::map<int, CBufferIn*>& rankBuffers)
2656  {
2657    int nbReceived = rankBuffers.size(), i, ind, index, lInd;
2658    if (nbReceived != recvClientRanks_.size())
2659      ERROR("void CDomain::recvMask(std::map<int, CBufferIn*>& rankBuffers)",
2660           << "The number of sending clients is not correct."
2661           << "Expected number: " << recvClientRanks_.size() << " but received " << nbReceived);
2662
2663    vector<CArray<bool,1> > recvMaskValue(nbReceived);     
2664    for (i = 0; i < recvClientRanks_.size(); ++i)
2665    {
2666      int rank = recvClientRanks_[i];
2667      CBufferIn& buffer = *(rankBuffers[rank]);     
2668      buffer >> recvMaskValue[i];
2669    }
2670
2671    int nbMaskInd = 0;
2672    for (i = 0; i < nbReceived; ++i)
2673    {
2674      nbMaskInd += recvMaskValue[i].numElements();
2675    }
2676 
2677    if (nbMaskInd != globalLocalIndexMap_.size())
2678      info (0) << "If the domain " << this->getDomainOutputName() <<" does not have overlapped region between processes."
2679               << "Something must be wrong with mask index "<< std::endl;
2680
2681    nbMaskInd = globalLocalIndexMap_.size();
2682    mask_1d.resize(nbMaskInd);
2683   
2684    for (i = 0; i < nbReceived; ++i)
2685    {
2686      CArray<int,1>& tmpInd = indGlob_[recvClientRanks_[i]];
2687      CArray<bool,1>& tmp = recvMaskValue[i];
2688      for (ind = 0; ind < tmp.numElements(); ++ind)
2689      {
2690        lInd = globalLocalIndexMap_[size_t(tmpInd(ind))];
2691        if (!mask_1d(lInd)) // Only rewrite mask_1d if it's not true
2692          mask_1d(lInd) = tmp(ind);
2693      }
2694    }   
2695  }
2696
2697  /*!
2698    Receive longitude event from clients(s)
2699    \param[in] event event contain info about rank and associated longitude
2700  */
2701  void CDomain::recvLon(CEventServer& event)
2702  {
2703    string domainId;
2704    std::map<int, CBufferIn*> rankBuffers;
2705
2706    list<CEventServer::SSubEvent>::iterator it;
2707    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2708    {     
2709      CBufferIn* buffer = it->buffer;
2710      *buffer >> domainId;
2711      rankBuffers[it->rank] = buffer;       
2712    }
2713    get(domainId)->recvLon(rankBuffers);
2714  }
2715
2716  /*!
2717    Receive longitude information from client(s)
2718    \param[in] rankBuffers rank of sending client and the corresponding receive buffer 
2719  */
2720  void CDomain::recvLon(std::map<int, CBufferIn*>& rankBuffers)
2721  {
2722    int nbReceived = rankBuffers.size(), i, ind, index, iindex, jindex, lInd;
2723    if (nbReceived != recvClientRanks_.size())
2724      ERROR("void CDomain::recvLon(std::map<int, CBufferIn*>& rankBuffers)",
2725           << "The number of sending clients is not correct."
2726           << "Expected number: " << recvClientRanks_.size() << " but received " << nbReceived);
2727
2728    vector<CArray<double,1> > recvLonValue(nbReceived);
2729    vector<CArray<double,2> > recvBoundsLonValue(nbReceived);   
2730    for (i = 0; i < recvClientRanks_.size(); ++i)
2731    {
2732      int rank = recvClientRanks_[i];
2733      CBufferIn& buffer = *(rankBuffers[rank]);
2734      buffer >> hasLonLat;
2735      if (hasLonLat)
2736        buffer >> recvLonValue[i];
2737      buffer >> hasBounds;
2738      if (hasBounds)
2739        buffer >> recvBoundsLonValue[i];
2740    }
2741
2742    if (hasLonLat)
2743    {
2744      int nbLonInd = 0;
2745      for (i = 0; i < nbReceived; ++i)
2746      {
2747        nbLonInd += recvLonValue[i].numElements();
2748      }
2749   
2750      if (nbLonInd != globalLocalIndexMap_.size())
2751        info (0) << "If the domain " << this->getDomainOutputName() <<" does not have overlapped region between processes."
2752                 << "Something must be wrong with longitude index "<< std::endl;
2753
2754      nbLonInd = globalLocalIndexMap_.size();
2755      lonvalue.resize(nbLonInd);
2756      if (hasBounds)
2757      {
2758        bounds_lonvalue.resize(nvertex,nbLonInd);
2759        bounds_lonvalue = 0.;
2760      }
2761
2762      nbLonInd = 0;
2763      for (i = 0; i < nbReceived; ++i)
2764      {
2765        CArray<int,1>& tmpInd = indGlob_[recvClientRanks_[i]];
2766        CArray<double,1>& tmp = recvLonValue[i];
2767        for (ind = 0; ind < tmp.numElements(); ++ind)
2768        {
2769          lInd = globalLocalIndexMap_[size_t(tmpInd(ind))];
2770          lonvalue(lInd) = tmp(ind); 
2771           if (hasBounds)
2772           {         
2773            for (int nv = 0; nv < nvertex; ++nv)
2774              bounds_lonvalue(nv, lInd) = recvBoundsLonValue[i](nv, ind);
2775           }                 
2776        }
2777      }       
2778    }
2779  }
2780
2781  /*!
2782    Receive latitude event from clients(s)
2783    \param[in] event event contain info about rank and associated latitude
2784  */
2785  void CDomain::recvLat(CEventServer& event)
2786  {
2787    string domainId;
2788    std::map<int, CBufferIn*> rankBuffers;
2789
2790    list<CEventServer::SSubEvent>::iterator it;
2791    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2792    {     
2793      CBufferIn* buffer = it->buffer;
2794      *buffer >> domainId;
2795      rankBuffers[it->rank] = buffer;   
2796    }
2797    get(domainId)->recvLat(rankBuffers);
2798  }
2799
2800  /*!
2801    Receive latitude information from client(s)
2802    \param[in] rankBuffers rank of sending client and the corresponding receive buffer 
2803  */
2804  void CDomain::recvLat(std::map<int, CBufferIn*>& rankBuffers)
2805  {
2806    int nbReceived = rankBuffers.size(), i, ind, index, iindex, jindex, lInd;
2807    if (nbReceived != recvClientRanks_.size())
2808      ERROR("void CDomain::recvLat(std::map<int, CBufferIn*>& rankBuffers)",
2809           << "The number of sending clients is not correct."
2810           << "Expected number: " << recvClientRanks_.size() << " but received " << nbReceived);
2811
2812    vector<CArray<double,1> > recvLatValue(nbReceived);
2813    vector<CArray<double,2> > recvBoundsLatValue(nbReceived);   
2814    for (i = 0; i < recvClientRanks_.size(); ++i)
2815    {
2816      int rank = recvClientRanks_[i];
2817      CBufferIn& buffer = *(rankBuffers[rank]);
2818      buffer >> hasLonLat;
2819      if (hasLonLat)
2820        buffer >> recvLatValue[i];
2821      buffer >> hasBounds;
2822      if (hasBounds)
2823        buffer >> recvBoundsLatValue[i];
2824    }
2825
2826    if (hasLonLat)
2827    {
2828      int nbLatInd = 0;
2829      for (i = 0; i < nbReceived; ++i)
2830      {
2831        nbLatInd += recvLatValue[i].numElements();
2832      }
2833   
2834      if (nbLatInd != globalLocalIndexMap_.size())
2835        info (0) << "If the domain " << this->getDomainOutputName() <<" does not have overlapped region between processes."
2836                << "Something must be wrong with latitude index "<< std::endl;
2837
2838      nbLatInd = globalLocalIndexMap_.size();
2839      latvalue.resize(nbLatInd);
2840      if (hasBounds)
2841      {
2842        bounds_latvalue.resize(nvertex,nbLatInd);
2843        bounds_latvalue = 0. ;
2844      }
2845
2846      nbLatInd = 0;
2847      for (i = 0; i < nbReceived; ++i)
2848      {
2849        CArray<int,1>& tmpInd = indGlob_[recvClientRanks_[i]];
2850        CArray<double,1>& tmp = recvLatValue[i];
2851        for (ind = 0; ind < tmp.numElements(); ++ind)
2852        {
2853          lInd = globalLocalIndexMap_[size_t(tmpInd(ind))];
2854          latvalue(lInd) = tmp(ind);   
2855           if (hasBounds)
2856           {
2857            CArray<double,2>& boundslat = recvBoundsLatValue[i];
2858            for (int nv = 0; nv < nvertex; ++nv)
2859              bounds_latvalue(nv, lInd) = boundslat(nv, ind);
2860           }   
2861          ++nbLatInd;
2862        }
2863      }       
2864    }
2865  }
2866
2867  /*!
2868    Receive area event from clients(s)
2869    \param[in] event event contain info about rank and associated area
2870  */
2871  void CDomain::recvArea(CEventServer& event)
2872  {
2873    string domainId;
2874    std::map<int, CBufferIn*> rankBuffers;
2875
2876    list<CEventServer::SSubEvent>::iterator it;
2877    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2878    {     
2879      CBufferIn* buffer = it->buffer;
2880      *buffer >> domainId;
2881      rankBuffers[it->rank] = buffer;     
2882    }
2883    get(domainId)->recvArea(rankBuffers);
2884  }
2885
2886  /*!
2887    Receive area information from client(s)
2888    \param[in] rankBuffers rank of sending client and the corresponding receive buffer     
2889  */
2890  void CDomain::recvArea(std::map<int, CBufferIn*>& rankBuffers)
2891  {
2892    int nbReceived = rankBuffers.size(), i, ind, index, lInd;
2893    if (nbReceived != recvClientRanks_.size())
2894      ERROR("void CDomain::recvArea(std::map<int, CBufferIn*>& rankBuffers)",
2895           << "The number of sending clients is not correct."
2896           << "Expected number: " << recvClientRanks_.size() << " but received " << nbReceived);
2897
2898    vector<CArray<double,1> > recvAreaValue(nbReceived);     
2899    for (i = 0; i < recvClientRanks_.size(); ++i)
2900    {
2901      int rank = recvClientRanks_[i];
2902      CBufferIn& buffer = *(rankBuffers[rank]);     
2903      buffer >> hasArea;
2904      if (hasArea)
2905        buffer >> recvAreaValue[i];
2906    }
2907
2908    if (hasArea)
2909    {
2910      int nbAreaInd = 0;
2911      for (i = 0; i < nbReceived; ++i)
2912      {     
2913        nbAreaInd += recvAreaValue[i].numElements();
2914      }
2915
2916      if (nbAreaInd != globalLocalIndexMap_.size())
2917        info (0) << "If the domain " << this->getDomainOutputName() <<" does not have overlapped region between processes."
2918                 << "Something must be wrong with area index "<< std::endl;
2919
2920      nbAreaInd = globalLocalIndexMap_.size();
2921      areavalue.resize(nbAreaInd);
2922      nbAreaInd = 0;     
2923      for (i = 0; i < nbReceived; ++i)
2924      {
2925        CArray<int,1>& tmpInd = indGlob_[recvClientRanks_[i]];
2926        CArray<double,1>& tmp = recvAreaValue[i];
2927        for (ind = 0; ind < tmp.numElements(); ++ind)
2928        {
2929          lInd = globalLocalIndexMap_[size_t(tmpInd(ind))];
2930          areavalue(lInd) = tmp(ind);         
2931        }
2932      }
2933     
2934    }
2935  }
2936
2937  /*!
2938    Compare two domain objects.
2939    They are equal if only if they have identical attributes as well as their values.
2940    Moreover, they must have the same transformations.
2941  \param [in] domain Compared domain
2942  \return result of the comparison
2943  */
2944  bool CDomain::isEqual(CDomain* obj)
2945  {
2946    vector<StdString> excludedAttr;
2947    excludedAttr.push_back("domain_ref");
2948    bool objEqual = SuperClass::isEqual(obj, excludedAttr);
2949    if (!objEqual) return objEqual;
2950
2951    TransMapTypes thisTrans = this->getAllTransformations();
2952    TransMapTypes objTrans  = obj->getAllTransformations();
2953
2954    TransMapTypes::const_iterator it, itb, ite;
2955    std::vector<ETranformationType> thisTransType, objTransType;
2956    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
2957      thisTransType.push_back(it->first);
2958    for (it = objTrans.begin(); it != objTrans.end(); ++it)
2959      objTransType.push_back(it->first);
2960
2961    if (thisTransType.size() != objTransType.size()) return false;
2962    for (int idx = 0; idx < thisTransType.size(); ++idx)
2963      objEqual &= (thisTransType[idx] == objTransType[idx]);
2964
2965    return objEqual;
2966  }
2967
2968  /*!
2969    Receive data index event from clients(s)
2970    \param[in] event event contain info about rank and associated index
2971  */
2972  void CDomain::recvDataIndex(CEventServer& event)
2973  {
2974    string domainId;
2975    std::map<int, CBufferIn*> rankBuffers;
2976
2977    list<CEventServer::SSubEvent>::iterator it;
2978    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
2979    {     
2980      CBufferIn* buffer = it->buffer;
2981      *buffer >> domainId;
2982      rankBuffers[it->rank] = buffer;       
2983    }
2984    get(domainId)->recvDataIndex(rankBuffers);
2985  }
2986
2987  /*!
2988    Receive data index information from client(s)
2989    A client receives data index from different clients to rebuild its own data index.
2990    Because the data index is local, to rebuild data index of received client, we should use global index along with.
2991    \param[in] rankBuffers rank of sending client and the corresponding receive buffer     
2992  */
2993  void CDomain::recvDataIndex(std::map<int, CBufferIn*>& rankBuffers)
2994  {
2995    int nbReceived = rankBuffers.size(), i, ind, index, indexI, indexJ, type_int, lInd;   
2996    if (nbReceived != recvClientRanks_.size())
2997      ERROR("void CDomain::recvDataIndex(std::map<int, CBufferIn*>& rankBuffers)",
2998           << "The number of sending clients is not correct."
2999           << "Expected number: " << recvClientRanks_.size() << " but received " << nbReceived);
3000
3001    vector<CArray<int,1> > recvDataIIndex(nbReceived),recvDataJIndex(nbReceived);     
3002    for (i = 0; i < recvClientRanks_.size(); ++i)
3003    {
3004      int rank = recvClientRanks_[i];
3005      CBufferIn& buffer = *(rankBuffers[rank]);
3006      buffer >> recvDataIIndex[i];
3007      buffer >> recvDataJIndex[i];
3008    }
3009   
3010    int nbIndex = i_index.numElements();
3011    CArray<int,1> dataIIndex(nbIndex), dataJIndex(nbIndex);
3012    dataIIndex = -1; dataJIndex = -1;
3013     
3014    nbIndex = 0;
3015    for (i = 0; i < nbReceived; ++i)
3016    {     
3017      CArray<int,1>& tmpInd = indGlob_[recvClientRanks_[i]];
3018      CArray<int,1>& tmpI = recvDataIIndex[i];   
3019      CArray<int,1>& tmpJ = recvDataJIndex[i];     
3020      if ((tmpI.numElements() != tmpInd.numElements()) || (tmpJ.numElements() != tmpInd.numElements()))
3021          ERROR("void CDomain::recvDataIndex(std::map<int, CBufferIn*>& rankBuffers)",
3022             << "The number of global received index is not coherent with the number of received data index."
3023             << "Expected number of global index: " << tmpI.numElements() << " but received " << tmpInd.numElements());
3024
3025      for (ind = 0; ind < tmpI.numElements(); ++ind)
3026      {
3027         lInd = globalLocalIndexMap_[size_t(tmpInd(ind))];
3028         dataIIndex(lInd) = (-1 == dataIIndex(lInd)) ? tmpI(ind) : dataIIndex(lInd); // Only fill in dataIndex if there is no data
3029         dataJIndex(lInd) = (-1 == dataJIndex(lInd)) ? tmpJ(ind) : dataJIndex(lInd);         
3030      } 
3031    }
3032
3033    int nbCompressedData = 0; 
3034    for (ind = 0; ind < dataIIndex.numElements(); ++ind)
3035    {
3036       indexI = dataIIndex(ind); indexJ = dataJIndex(ind);
3037       if ((0 <= indexI) && (0 <= indexJ))
3038         ++nbCompressedData;
3039    }       
3040 
3041    data_i_index.resize(nbCompressedData);
3042    data_j_index.resize(nbCompressedData);
3043
3044    nbCompressedData = 0; 
3045    for (ind = 0; ind < dataIIndex.numElements(); ++ind)
3046    {
3047       indexI = dataIIndex(ind); indexJ = dataJIndex(ind);
3048       if ((0 <= indexI) && (0 <= indexJ))
3049       {
3050          data_i_index(nbCompressedData) = (1 == data_dim) ? ind : ind % ni;
3051          data_j_index(nbCompressedData) = (1 == data_dim) ? 0   : ind / ni;
3052         ++nbCompressedData;
3053       }
3054    }
3055
3056    // Reset data_ibegin, data_jbegin
3057    data_ibegin.setValue(0);
3058    data_jbegin.setValue(0);
3059  }
3060
3061  CTransformation<CDomain>* CDomain::addTransformation(ETranformationType transType, const StdString& id)
3062  {
3063    transformationMap_.push_back(std::make_pair(transType, CTransformation<CDomain>::createTransformation(transType,id)));
3064    return transformationMap_.back().second;
3065  }
3066
3067  /*!
3068    Check whether a domain has transformation
3069    \return true if domain has transformation
3070  */
3071  bool CDomain::hasTransformation()
3072  {
3073    return (!transformationMap_.empty());
3074  }
3075
3076  /*!
3077    Set transformation for current domain. It's the method to move transformation in hierarchy
3078    \param [in] domTrans transformation on domain
3079  */
3080  void CDomain::setTransformations(const TransMapTypes& domTrans)
3081  {
3082    transformationMap_ = domTrans;
3083  }
3084
3085  /*!
3086    Get all transformation current domain has
3087    \return all transformation
3088  */
3089  CDomain::TransMapTypes CDomain::getAllTransformations(void)
3090  {
3091    return transformationMap_;
3092  }
3093
3094  void CDomain::duplicateTransformation(CDomain* src)
3095  {
3096    if (src->hasTransformation())
3097    {
3098      this->setTransformations(src->getAllTransformations());
3099    }
3100  }
3101
3102  /*!
3103   * Go through the hierarchy to find the domain from which the transformations must be inherited
3104   */
3105  void CDomain::solveInheritanceTransformation()
3106  {
3107    if (hasTransformation() || !hasDirectDomainReference())
3108      return;
3109
3110    CDomain* domain = this;
3111    std::vector<CDomain*> refDomains;
3112    while (!domain->hasTransformation() && domain->hasDirectDomainReference())
3113    {
3114      refDomains.push_back(domain);
3115      domain = domain->getDirectDomainReference();
3116    }
3117
3118    if (domain->hasTransformation())
3119      for (size_t i = 0; i < refDomains.size(); ++i)
3120        refDomains[i]->setTransformations(domain->getAllTransformations());
3121  }
3122
3123  /*!
3124    Parse children nodes of a domain in xml file.
3125    Whenver there is a new transformation, its type and name should be added into this function
3126    \param node child node to process
3127  */
3128  void CDomain::parse(xml::CXMLNode & node)
3129  {
3130    SuperClass::parse(node);
3131
3132    if (node.goToChildElement())
3133    {
3134      StdString nodeElementName;
3135      do
3136      {
3137        StdString nodeId("");
3138        if (node.getAttributes().end() != node.getAttributes().find("id"))
3139        { nodeId = node.getAttributes()["id"]; }
3140
3141        nodeElementName = node.getElementName();
3142        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
3143        it = transformationMapList_.find(nodeElementName);
3144        if (ite != it)
3145        {
3146          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CDomain>::createTransformation(it->second,
3147                                                                                                                nodeId,
3148                                                                                                                &node)));
3149        }
3150        else
3151        {
3152          ERROR("void CDomain::parse(xml::CXMLNode & node)",
3153                << "The transformation " << nodeElementName << " has not been supported yet.");
3154        }
3155      } while (node.goToNextElement()) ;
3156      node.goToParentElement();
3157    }
3158  }
3159   //----------------------------------------------------------------
3160
3161   DEFINE_REF_FUNC(Domain,domain)
3162
3163   ///---------------------------------------------------------------
3164
3165} // namespace xios
Note: See TracBrowser for help on using the repository browser.