source: XIOS/branchs/xios-2.5/src/node/domain.cpp @ 1850

Last change on this file since 1850 was 1850, checked in by ymipsl, 4 years ago

Compiler fix : solve the problem of crash occured with recent version of GCC, only in optimised mode > O1
It seems to be due to non return value from a non void function in case of early initialization (static initialization).
Thanks to A. Durocher who find the tip.

YM

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