source: XIOS/dev/dev_olga/src/node/domain.cpp @ 1600

Last change on this file since 1600 was 1600, checked in by oabramkina, 5 years ago

Dev: removing traces of sending mask on domain and axis.

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