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

Last change on this file since 2250 was 2133, checked in by jderouillat, 3 years ago

Fix getTileData(I/J)Size exception management

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