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

Last change on this file since 1457 was 1457, checked in by ymipsl, 6 years ago

Add new domain filter : reorder_domain
Reoder the data along the global domain but works only for rectilinear domain

  • invert_lat : invert the latitute axis
  • shift_lon_fraction : shift the longitude axis of a fration of global size
  • lon_min/lon_max : fixe the range of longitude value (ex : -180:180 or 0:360)

YM

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