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

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

Various bug fixes on mask and zoom

+) Rearrange local index on the receiving side to be coherent global index
+) Include masking information in compress data (data_index) on the receiving side
+) Correct zoom to work in case there are several (not all) processes participating to write data

Test
+) On Curie
+) Simple test

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