source: XIOS/trunk/src/node/domain.cpp @ 1622

Last change on this file since 1622 was 1622, checked in by oabramkina, 6 years ago

Exception handling on trunk.

To activate it, compilation flag -DXIOS_EXCEPTION should be added.

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