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

Last change on this file since 809 was 809, checked in by ymipsl, 7 years ago

Fix problems for interpolation onto regular domain.

YM

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
  • Property svn:executable set to *
File size: 69.2 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#include "zoom_domain.hpp"
21#include "interpolate_domain.hpp"
22#include "generate_rectilinear_domain.hpp"
23
24#include <algorithm>
25
26namespace xios {
27
28   /// ////////////////////// Définitions ////////////////////// ///
29
30   CDomain::CDomain(void)
31      : CObjectTemplate<CDomain>(), CDomainAttributes()
32      , isChecked(false), relFiles(), isClientChecked(false), nbConnectedClients_(), indSrv_(), connectedServerRank_()
33      , hasBounds(false), hasArea(false), isDistributed_(false), nGlobDomain_(), isCompressible_(false), isUnstructed_(false)
34      , global_zoom_ni(0), global_zoom_ibegin(0), global_zoom_nj(0), global_zoom_jbegin(0)
35      , isClientAfterTransformationChecked(false), hasLonLat(false)
36      , lonvalue_client(), latvalue_client(), bounds_lon_client(), bounds_lat_client()
37      , isRedistributed_(false)
38   { /* Ne rien faire de plus */ }
39
40   CDomain::CDomain(const StdString & id)
41      : CObjectTemplate<CDomain>(id), CDomainAttributes()
42      , isChecked(false), relFiles(), isClientChecked(false), nbConnectedClients_(), indSrv_(), connectedServerRank_()
43      , hasBounds(false), hasArea(false), isDistributed_(false), nGlobDomain_(), isCompressible_(false), isUnstructed_(false)
44      , global_zoom_ni(0), global_zoom_ibegin(0), global_zoom_nj(0), global_zoom_jbegin(0)
45      , isClientAfterTransformationChecked(false), hasLonLat(false)
46      , lonvalue_client(), latvalue_client(), bounds_lon_client(), bounds_lat_client()
47      , isRedistributed_(false)
48   { /* Ne rien faire de plus */ }
49
50   CDomain::~CDomain(void)
51   {
52   }
53
54   ///---------------------------------------------------------------
55
56   CDomain* CDomain::createDomain()
57   {
58     CDomain* domain = CDomainGroup::get("domain_definition")->createChild();
59     return domain;
60   }
61
62   const std::set<StdString> & CDomain::getRelFiles(void) const
63   {
64      return (this->relFiles);
65   }
66
67   //----------------------------------------------------------------
68
69   const std::vector<int>& CDomain::getIndexesToWrite(void) const
70   {
71     return indexesToWrite;
72   }
73
74   /*!
75     Returns the number of indexes written by each server.
76     \return the number of indexes written by each server
77   */
78   int CDomain::getNumberWrittenIndexes() const
79   {
80     return numberWrittenIndexes_;
81   }
82
83   /*!
84     Returns the total number of indexes written by the servers.
85     \return the total number of indexes written by the servers
86   */
87   int CDomain::getTotalNumberWrittenIndexes() const
88   {
89     return totalNumberWrittenIndexes_;
90   }
91
92   /*!
93     Returns the offset of indexes written by each server.
94     \return the offset of indexes written by each server
95   */
96   int CDomain::getOffsetWrittenIndexes() const
97   {
98     return offsetWrittenIndexes_;
99   }
100
101   //----------------------------------------------------------------
102
103   /*!
104    * Compute the minimum buffer size required to send the attributes to the server(s).
105    *
106    * \return A map associating the server rank with its minimum buffer size.
107    */
108   std::map<int, StdSize> CDomain::getAttributesBufferSize()
109   {
110     CContextClient* client = CContext::getCurrent()->client;
111
112     std::map<int, StdSize> attributesSizes = getMinimumBufferSizeForAttributes();
113
114     if (client->isServerLeader())
115     {
116       // size estimation for sendServerAttribut
117       size_t size = 11 * sizeof(size_t);
118
119       const std::list<int>& ranks = client->getRanksServerLeader();
120       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
121       {
122         if (size > attributesSizes[*itRank])
123           attributesSizes[*itRank] = size;
124       }
125     }
126
127     std::map<int, std::vector<size_t> >::const_iterator itIndexEnd = indSrv_.end();
128     std::map<int, std::vector<int> >::const_iterator itWrittenIndexEnd = indWrittenSrv_.end();
129     for (size_t k = 0; k < connectedServerRank_.size(); ++k)
130     {
131       int rank = connectedServerRank_[k];
132       std::map<int, std::vector<size_t> >::const_iterator it = indSrv_.find(rank);
133       size_t idxCount = (it != itIndexEnd) ? it->second.size() : 0;
134
135       // size estimation for sendIndex (and sendArea which is always smaller or equal)
136       size_t sizeIndexEvent = 2 * sizeof(size_t) + 2 * CArray<int,1>::size(idxCount);
137       if (isCompressible_)
138       {
139         std::map<int, std::vector<int> >::const_iterator itWritten = indWrittenSrv_.find(rank);
140         size_t writtenIdxCount = (itWritten != itWrittenIndexEnd) ? itWritten->second.size() : 0;
141         sizeIndexEvent += CArray<int,1>::size(writtenIdxCount);
142       }
143
144       // size estimation for sendLonLat
145       size_t sizeLonLatEvent = CArray<double,1>::size(idxCount);
146       if (hasBounds)
147         sizeLonLatEvent += CArray<double,2>::size(nvertex * idxCount);
148
149       size_t size = CEventClient::headerSize + getId().size() + sizeof(size_t) + std::max(sizeIndexEvent, sizeLonLatEvent);
150       if (size > attributesSizes[rank])
151         attributesSizes[rank] = size;
152     }
153
154     return attributesSizes;
155   }
156
157   //----------------------------------------------------------------
158
159   bool CDomain::isEmpty(void) const
160   {
161      return ((this->zoom_ni_srv == 0) ||
162              (this->zoom_nj_srv == 0));
163   }
164
165   //----------------------------------------------------------------
166
167   bool CDomain::IsWritten(const StdString & filename) const
168   {
169      return (this->relFiles.find(filename) != this->relFiles.end());
170   }
171
172   bool CDomain::isWrittenCompressed(const StdString& filename) const
173   {
174      return (this->relFilesCompressed.find(filename) != this->relFilesCompressed.end());
175   }
176
177   //----------------------------------------------------------------
178
179   bool CDomain::isDistributed(void) const
180   {
181      return isDistributed_;
182   }
183
184   //----------------------------------------------------------------
185
186   /*!
187    * Test whether the data defined on the domain can be outputted in a compressed way.
188    *
189    * \return true if and only if a mask was defined for this domain
190    */
191   bool CDomain::isCompressible(void) const
192   {
193      return isCompressible_;
194   }
195
196   //----------------------------------------------------------------
197
198   void CDomain::addRelFile(const StdString & filename)
199   {
200      this->relFiles.insert(filename);
201   }
202
203   void CDomain::addRelFileCompressed(const StdString& filename)
204   {
205      this->relFilesCompressed.insert(filename);
206   }
207
208
209   StdString CDomain::GetName(void)   { return (StdString("domain")); }
210   StdString CDomain::GetDefName(void){ return (CDomain::GetName()); }
211   ENodeType CDomain::GetType(void)   { return (eDomain); }
212
213   //----------------------------------------------------------------
214
215   /*!
216     Redistribute RECTILINEAR domain with a number of local domains.
217   All attributes ni,nj,ibegin,jbegin (if defined) will be rewritten
218   The optional attributes lonvalue, latvalue will be added. Because this function only serves (for now)
219   for interpolation from unstructured domain to rectilinear one, range of latvalue is 0-360 and lonvalue is -90 - +90
220    \param [in] nbLocalDomain number of local domain on the domain destination
221   */
222   void CDomain::redistribute(int nbLocalDomain)
223   {
224     if (this->isRedistributed_) return;
225
226     this->isRedistributed_ = true;
227     CContext* context = CContext::getCurrent();
228     CContextClient* client = context->client;
229     int rankClient = client->clientRank;
230     int rankOnDomain = rankClient%nbLocalDomain;
231
232     if (ni_glo.isEmpty() || ni_glo <= 0 )
233     {
234        ERROR("CDomain::redistribute(int nbLocalDomain)",
235           << "[ Id = " << this->getId() << " ] "
236           << "The global domain is badly defined,"
237           << " check the \'ni_glo\'  value !")
238     }
239
240     if (nj_glo.isEmpty() || nj_glo <= 0 )
241     {
242        ERROR("CDomain::redistribute(int nbLocalDomain)",
243           << "[ Id = " << this->getId() << " ] "
244           << "The global domain is badly defined,"
245           << " check the \'nj_glo\'  value !")
246     }
247
248     if ((type_attr::rectilinear == type)  || (type_attr::curvilinear == type))
249     {
250        int globalDomainSize = ni_glo * nj_glo;
251        if (globalDomainSize <= nbLocalDomain)
252        {
253          for (int idx = 0; idx < nbLocalDomain; ++idx)
254          {
255            if (rankOnDomain < globalDomainSize)
256            {
257              int iIdx = rankOnDomain % ni_glo;
258              int jIdx = rankOnDomain / ni_glo;
259              ibegin.setValue(iIdx); jbegin.setValue(jIdx);
260              ni.setValue(1); nj.setValue(1);
261            }
262            else
263            {
264              ibegin.setValue(0); jbegin.setValue(0);
265              ni.setValue(0); nj.setValue(0);
266            }
267          }
268        }
269        else
270        {
271          float njGlo = nj_glo.getValue();
272          float niGlo = ni_glo.getValue();
273          int nbProcOnX, nbProcOnY, range;
274
275          // Compute (approximately) number of segment on x and y axis
276          float yOverXRatio = njGlo/niGlo;
277
278          nbProcOnX = std::ceil(std::sqrt(nbLocalDomain/yOverXRatio));
279          nbProcOnY = std::ceil(((float)nbLocalDomain)/nbProcOnX);
280
281          // Simple distribution: Sweep from top to bottom, left to right
282          // Calculate local begin on x
283          std::vector<int> ibeginVec(nbProcOnX,0), jbeginVec(nbProcOnY,0);
284          std::vector<int> niVec(nbProcOnX), njVec(nbProcOnY);
285          for (int i = 1; i < nbProcOnX; ++i)
286          {
287            range = ni_glo / nbProcOnX;
288            if (i < (ni_glo%nbProcOnX)) ++range;
289            niVec[i-1] = range;
290            ibeginVec[i] = ibeginVec[i-1] + niVec[i-1];
291          }
292          niVec[nbProcOnX-1] = ni_glo - ibeginVec[nbProcOnX-1];
293
294          // Calculate local begin on y
295          for (int j = 1; j < nbProcOnY; ++j)
296          {
297            range = nj_glo / nbProcOnY;
298            if (j < (nj_glo%nbProcOnY)) ++range;
299            njVec[j-1] = range;
300            jbeginVec[j] = jbeginVec[j-1] + njVec[j-1];
301          }
302          njVec[nbProcOnY-1] = nj_glo - jbeginVec[nbProcOnY-1];
303
304          // Now assign value to ni, ibegin, nj, jbegin
305          int iIdx = rankOnDomain % nbProcOnX;
306          int jIdx = rankOnDomain / nbProcOnX;
307
308          if (rankOnDomain != (nbLocalDomain-1))
309          {
310            ibegin.setValue(ibeginVec[iIdx]);
311            jbegin.setValue(jbeginVec[jIdx]);
312            nj.setValue(njVec[jIdx]);
313            ni.setValue(niVec[iIdx]);
314          }
315          else // just merge all the remaining rectangle into the last one
316          {
317            ibegin.setValue(ibeginVec[iIdx]);
318            jbegin.setValue(jbeginVec[jIdx]);
319            nj.setValue(njVec[jIdx]);
320            ni.setValue(ni_glo - ibeginVec[iIdx]);
321          }
322        }
323
324        // Now fill other attributes
325        if (type_attr::rectilinear == type) fillInRectilinearLonLat();
326     }
327     else  // unstructured domain
328     {
329       if (this->i_index.isEmpty())
330       {
331          int globalDomainSize = ni_glo * nj_glo;
332          if (globalDomainSize <= nbLocalDomain)
333          {
334            for (int idx = 0; idx < nbLocalDomain; ++idx)
335            {
336              if (rankOnDomain < globalDomainSize)
337              {
338                int iIdx = rankOnDomain % ni_glo;
339                int jIdx = rankOnDomain / ni_glo;
340                ibegin.setValue(iIdx); jbegin.setValue(jIdx);
341                ni.setValue(1); nj.setValue(1);
342              }
343              else
344              {
345                ibegin.setValue(0); jbegin.setValue(0);
346                ni.setValue(0); nj.setValue(0);
347              }
348            }
349          }
350          else
351          {
352            float njGlo = nj_glo.getValue();
353            float niGlo = ni_glo.getValue();
354            std::vector<int> ibeginVec(nbLocalDomain,0);
355            std::vector<int> niVec(nbLocalDomain);
356            for (int i = 1; i < nbLocalDomain; ++i)
357            {
358              int range = ni_glo / nbLocalDomain;
359              if (i < (ni_glo%nbLocalDomain)) ++range;
360              niVec[i-1] = range;
361              ibeginVec[i] = ibeginVec[i-1] + niVec[i-1];
362            }
363            niVec[nbLocalDomain-1] = ni_glo - ibeginVec[nbLocalDomain-1];
364
365            int iIdx = rankOnDomain % nbLocalDomain;
366            ibegin.setValue(ibeginVec[iIdx]);
367            jbegin.setValue(0);
368            ni.setValue(niVec[iIdx]);
369            nj.setValue(1);
370          }
371        }
372        else
373        {
374          ibegin.setValue(this->i_index(0));
375          jbegin.setValue(0);
376          ni.setValue(this->i_index.numElements());
377          nj.setValue(1);
378        }
379     }
380
381     checkDomain();
382   }
383
384   /*!
385     Fill in the values for lonvalue_1d and latvalue_1d of rectilinear domain
386     Range of longitude value from 0 - 360
387     Range of latitude value from -90 - +90
388   */
389   void CDomain::fillInRectilinearLonLat()
390   {
391     if (!lonvalue_rectilinear_read_from_file.isEmpty())
392     {
393       lonvalue_1d.resize(ni);
394       for (int idx = 0; idx < ni; ++idx)
395         lonvalue_1d(idx) = lonvalue_rectilinear_read_from_file(idx+ibegin);
396       lon_start.setValue(lonvalue_rectilinear_read_from_file(0));
397       lon_end.setValue(lonvalue_rectilinear_read_from_file(ni_glo-1));
398     }
399     else
400     {
401       if (!lonvalue_2d.isEmpty()) lonvalue_2d.free();
402       lonvalue_1d.resize(ni);
403       double lonRange = lon_end - lon_start;
404       double lonStep = (1 == ni_glo.getValue()) ? lonRange : lonRange/double(ni_glo.getValue()-1);
405
406        // Assign lon value
407       for (int i = 0; i < ni; ++i)
408       {
409         if (0 == (ibegin + i))
410         {
411           lonvalue_1d(i) = lon_start;
412         }
413         else if (ni_glo == (ibegin + i + 1))
414         {
415           lonvalue_1d(i) = lon_end;
416         }
417         else
418         {
419           lonvalue_1d(i) = (ibegin + i) * lonStep  + lon_start;
420         }
421       }
422     }
423
424
425     if (!latvalue_rectilinear_read_from_file.isEmpty())
426     {
427       latvalue_1d.resize(nj);
428       for (int idx = 0; idx < nj; ++idx)
429         latvalue_1d(idx) = latvalue_rectilinear_read_from_file(idx+jbegin);
430       lat_start.setValue(latvalue_rectilinear_read_from_file(0));
431       lat_end.setValue(latvalue_rectilinear_read_from_file(nj_glo-1));
432     }
433     else
434     {
435       if (!latvalue_2d.isEmpty()) latvalue_1d.free();
436       latvalue_1d.resize(nj);
437
438       double latRange = lat_end - lat_start;
439       double latStep = (1 == nj_glo.getValue()) ? latRange : latRange/double(nj_glo.getValue()-1);
440
441       for (int j = 0; j < nj; ++j)
442       {
443         if (0 == (jbegin + j))
444         {
445            latvalue_1d(j) = lat_start;
446         }
447         else if (nj_glo == (jbegin + j + 1))
448         {
449            latvalue_1d(j) = lat_end;
450         }
451         else
452         {
453           latvalue_1d(j) =  (jbegin + j) * latStep + lat_start;
454         }
455       }
456     }
457   }
458
459
460
461   void CDomain::AllgatherRectilinearLonLat(CArray<double,1>& lon, CArray<double,1>& lat, CArray<double,1>& lon_g, CArray<double,1>& lat_g)
462   {
463          CContext* context = CContext::getCurrent();
464      CContextClient* client = context->client;
465          lon_g.resize(ni_glo) ;
466          lat_g.resize(nj_glo) ;
467         
468         
469          int* ibegin_g = new int[client->clientSize] ;
470          int* jbegin_g = new int[client->clientSize] ;
471          int* ni_g = new int[client->clientSize] ;
472          int* nj_g = new int[client->clientSize] ;
473          int v ;
474          v=ibegin ;
475          MPI_Allgather(&v,1,MPI_INT,ibegin_g,1,MPI_INT,client->intraComm) ;
476          v=jbegin ;
477          MPI_Allgather(&v,1,MPI_INT,jbegin_g,1,MPI_INT,client->intraComm) ;
478          v=ni ;
479          MPI_Allgather(&v,1,MPI_INT,ni_g,1,MPI_INT,client->intraComm) ;
480          v=nj ;
481          MPI_Allgather(&v,1,MPI_INT,nj_g,1,MPI_INT,client->intraComm) ;
482         
483          MPI_Allgatherv(lon.dataFirst(),ni,MPI_DOUBLE,lon_g.dataFirst(),ni_g, ibegin_g,MPI_DOUBLE,client->intraComm) ;
484          MPI_Allgatherv(lat.dataFirst(),nj,MPI_DOUBLE,lat_g.dataFirst(),nj_g, jbegin_g,MPI_DOUBLE,client->intraComm) ;
485   
486      delete[] ibegin_g ;
487      delete[] jbegin_g ;
488      delete[] ni_g ;
489      delete[] nj_g ;
490   }
491
492   void CDomain::fillInRectilinearBoundLonLat(CArray<double,1>& lon, CArray<double,1>& lat,
493                                              CArray<double,2>& boundsLon, CArray<double,2>& boundsLat)
494   {
495     int i,j,k;
496     
497     const int nvertexValue = 4;
498     boundsLon.resize(nvertexValue,ni*nj);
499
500     double lonStepStart = lon(1)-lon(0);
501     bounds_lon_start=lon(0) - lonStepStart/2;
502     double lonStepEnd = lon(ni_glo-1)-lon(ni_glo-2);
503     bounds_lon_end=lon(ni_glo-1) + lonStepEnd/2;
504     double errorBoundsLon = std::abs(360-std::abs(bounds_lon_end-bounds_lon_start));
505     if (errorBoundsLon > NumTraits<double>::epsilon()) bounds_lon_end=bounds_lon_start+360;
506     for(j=0;j<nj;++j)
507       for(i=0;i<ni;++i)
508       {
509         k=j*ni+i;
510         boundsLon(0,k) = boundsLon(1,k) = (0 == (ibegin + i)) ? bounds_lon_start
511                                                               : (lon(ibegin + i)+lon(ibegin + i-1))/2;
512         boundsLon(2,k) = boundsLon(3,k) = ((ibegin + i + 1) == ni_glo) ? bounds_lon_end
513                                                                        : (lon(ibegin + i + 1)+lon(ibegin + i))/2;
514       }
515   
516
517    boundsLat.resize(nvertexValue,nj*ni);
518    bool isNorthPole, isSouthPole ;
519    if (std::abs(90 - std::abs(lat(0))) < NumTraits<double>::epsilon()) isNorthPole = true;
520    if (std::abs(90 - std::abs(lat(nj_glo-1))) < NumTraits<double>::epsilon()) isSouthPole = true;
521
522    double latStepStart = lat(1)-lat(0);
523    if (isNorthPole) bounds_lat_start=lat(0);
524    else bounds_lat_start=lat(0)-latStepStart/2;
525
526    double latStepEnd = lat(nj_glo-1)-lat(nj_glo-2);
527    if (isSouthPole) bounds_lat_end=lat(nj_glo-1);
528    else bounds_lat_end=lat(nj_glo-1)+latStepEnd/2;
529       
530// Work arround for small value close to pole, not too good for remapping   
531    if (bounds_lat_start > 90.-1e-3) bounds_lat_start=90 ;
532    if (bounds_lat_start < -90.+1e-3) bounds_lat_start=-90 ;
533    if (bounds_lat_end > 90.-1e-3) bounds_lat_end=90 ;
534    if (bounds_lat_end < -90.+1e-3) bounds_lat_end=-90 ;
535     
536    for(j=0;j<nj;++j)
537      for(i=0;i<ni;++i)
538      {
539        k=j*ni+i;
540        boundsLat(1,k) = boundsLat(2,k) = (0 == (jbegin + j)) ? bounds_lat_start
541                                                              : (lat(jbegin + j)+lat(jbegin + j-1))/2;
542        boundsLat(0,k) = boundsLat(3,k) = ((jbegin + j +1) == nj_glo) ? bounds_lat_end
543                                                                      : (lat(jbegin + j + 1)+lat(jbegin + j))/2;
544      }
545   }
546
547   void CDomain::checkDomain(void)
548   {
549     if (type.isEmpty())
550     {
551       ERROR("CDomain::checkDomain(void)",
552             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
553             << "The domain type is mandatory, "
554             << "please define the 'type' attribute.")
555     }
556
557     if (type == type_attr::unstructured)
558     {
559        if (ni_glo.isEmpty())
560        {
561          ERROR("CDomain::checkDomain(void)",
562                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
563                << "The global domain is badly defined, "
564                << "the mandatory 'ni_glo' attribute is missing.")
565        }
566        else if (ni_glo <= 0)
567        {
568          ERROR("CDomain::checkDomain(void)",
569                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
570                << "The global domain is badly defined, "
571                << "'ni_glo' attribute should be strictly positive so 'ni_glo = " << ni_glo.getValue() << "' is invalid.")
572        }
573        isUnstructed_ = true;
574        nj_glo = 1;
575        nj = 1;
576        jbegin = 0;
577        if (ni.isEmpty()) ni = i_index.numElements();
578        j_index.resize(ni);
579        for(int i=0;i<ni;++i) j_index(i)=0;
580
581        if (!area.isEmpty())
582          area.transposeSelf(1, 0);
583     }
584
585     if (ni_glo.isEmpty())
586     {
587       ERROR("CDomain::checkDomain(void)",
588             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
589             << "The global domain is badly defined, "
590             << "the mandatory 'ni_glo' attribute is missing.")
591     }
592     else if (ni_glo <= 0)
593     {
594       ERROR("CDomain::checkDomain(void)",
595             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
596             << "The global domain is badly defined, "
597             << "'ni_glo' attribute should be strictly positive so 'ni_glo = " << ni_glo.getValue() << "' is invalid.")
598     }
599
600     if (nj_glo.isEmpty())
601     {
602       ERROR("CDomain::checkDomain(void)",
603             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
604             << "The global domain is badly defined, "
605             << "the mandatory 'nj_glo' attribute is missing.")
606     }
607     else if (nj_glo <= 0)
608     {
609       ERROR("CDomain::checkDomain(void)",
610             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
611             << "The global domain is badly defined, "
612             << "'nj_glo' attribute should be strictly positive so 'nj_glo = " << nj_glo.getValue() << "' is invalid.")
613     }
614
615     isDistributed_ = !ibegin.isEmpty() || !ni.isEmpty() || !jbegin.isEmpty() || !nj.isEmpty();
616
617     checkLocalIDomain();
618     checkLocalJDomain();
619
620     if (i_index.isEmpty())
621     {
622       i_index.resize(ni*nj);
623       for (int j = 0; j < nj; ++j)
624         for (int i = 0; i < ni; ++i) i_index(i+j*ni) = i+ibegin;
625     }
626
627     if (j_index.isEmpty())
628     {
629       j_index.resize(ni*nj);
630       for (int j = 0; j < nj; ++j)
631         for (int i = 0; i < ni; ++i) j_index(i+j*ni) = j+jbegin;
632     }
633     computeNGlobDomain();
634
635     if (0 == global_zoom_ni) global_zoom_ni = ni_glo;
636     if (0 == global_zoom_nj) global_zoom_nj = nj_glo;
637   }
638
639   //----------------------------------------------------------------
640
641   void CDomain::checkLocalIDomain(void)
642   {
643      if (ibegin.isEmpty() && ni.isEmpty())
644      {
645        ibegin = 0;
646        ni = ni_glo;
647      }
648      else if (!i_index.isEmpty())
649      {
650        if (ibegin.isEmpty()) ibegin = i_index(0);
651      }
652
653      if (ni.getValue() < 0 || ibegin.getValue() < 0 ||
654         (ibegin.getValue() + ni.getValue()) > ni_glo.getValue())
655      {
656        ERROR("CDomain::checkLocalIDomain(void)",
657              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
658              << "The local domain is wrongly defined,"
659              << " check the attributes 'ni_glo' (" << ni_glo.getValue() << "), 'ni' (" << ni.getValue() << ") and 'ibegin' (" << ibegin.getValue() << ")");
660      }
661   }
662
663   void CDomain::checkLocalJDomain(void)
664   {
665     if (jbegin.isEmpty() && nj.isEmpty())
666     {
667       jbegin = 0;
668       nj = nj_glo;
669     }
670     else if (!j_index.isEmpty())
671     {
672       if (jbegin.isEmpty()) jbegin = j_index(0);
673     }
674
675      if (nj.getValue() < 0 || jbegin.getValue() < 0 ||
676         (jbegin.getValue() + nj.getValue()) > nj_glo.getValue())
677      {
678        ERROR("CDomain::checkLocalJDomain(void)",
679              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
680              << "The local domain is wrongly defined,"
681              << " check the attributes 'nj_glo' (" << nj_glo.getValue() << "), 'nj' (" << nj.getValue() << ") and 'jbegin' (" << jbegin.getValue() << ")");
682      }
683   }
684
685   //----------------------------------------------------------------
686
687   void CDomain::checkMask(void)
688   {
689      if (!mask_1d.isEmpty() && !mask_2d.isEmpty())
690        ERROR("CDomain::checkMask(void)",
691              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
692              << "Both mask_1d and mask_2d are defined but only one can be used at the same time." << std::endl
693              << "Please define only one mask: 'mask_1d' or 'mask_2d'.");
694
695      if (!mask_1d.isEmpty() && mask_2d.isEmpty())
696      {
697        if (mask_1d.numElements() != i_index.numElements())
698          ERROR("CDomain::checkMask(void)",
699                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
700                << "'mask_1d' does not have the same size as the local domain." << std::endl
701                << "Local size is " << i_index.numElements() << "." << std::endl
702                << "Mask size is " << mask_1d.numElements() << ".");
703      }
704
705      if (mask_1d.isEmpty() && !mask_2d.isEmpty())
706      {
707        if (mask_2d.extent(0) != ni || mask_2d.extent(1) != nj)
708          ERROR("CDomain::checkMask(void)",
709                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
710                << "The mask does not have the same size as the local domain." << std::endl
711                << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
712                << "Mask size is " << mask_2d.extent(0) << " x " << mask_2d.extent(1) << ".");
713      }
714
715      if (!mask_2d.isEmpty())
716      {
717        mask_1d.resize(mask_2d.extent(0) * mask_2d.extent(1));
718        for (int j = 0; j < nj; ++j)
719          for (int i = 0; i < ni; ++i) mask_1d(i+j*ni) = mask_2d(i,j);
720        mask_2d.free();
721      }
722      else if (mask_1d.isEmpty())
723      {
724        mask_1d.resize(i_index.numElements());
725        for (int i = 0; i < i_index.numElements(); ++i) mask_1d(i) = true;
726      }
727   }
728
729   //----------------------------------------------------------------
730
731   void CDomain::checkDomainData(void)
732   {
733      if (data_dim.isEmpty())
734      {
735        data_dim.setValue(1);
736      }
737      else if (!(data_dim.getValue() == 1 || data_dim.getValue() == 2))
738      {
739        ERROR("CDomain::checkDomainData(void)",
740              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
741              << "The data dimension is invalid, 'data_dim' must be 1 or 2 not << " << data_dim.getValue() << ".");
742      }
743
744      if (data_ibegin.isEmpty())
745         data_ibegin.setValue(0);
746      if (data_jbegin.isEmpty())
747         data_jbegin.setValue(0);
748
749      if (data_ni.isEmpty())
750      {
751        data_ni.setValue((data_dim == 1) ? (ni.getValue() * nj.getValue()) : ni.getValue());
752      }
753      else if (data_ni.getValue() < 0)
754      {
755        ERROR("CDomain::checkDomainData(void)",
756              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
757              << "The data size cannot be negative ('data_ni' = " << data_ni.getValue() << ").");
758      }
759
760      if (data_nj.isEmpty())
761      {
762        data_nj.setValue((data_dim.getValue() == 1) ? (ni.getValue() * nj.getValue()) : nj.getValue());
763      }
764      else if (data_nj.getValue() < 0)
765      {
766        ERROR("CDomain::checkDomainData(void)",
767              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
768              << "The data size cannot be negative ('data_nj' = " << data_nj.getValue() << ").");
769      }
770   }
771
772   //----------------------------------------------------------------
773
774   void CDomain::checkCompression(void)
775   {
776      if (!data_i_index.isEmpty())
777      {
778        if (!data_j_index.isEmpty() &&
779            data_j_index.numElements() != data_i_index.numElements())
780        {
781           ERROR("CDomain::checkCompression(void)",
782                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
783                 << "'data_i_index' and 'data_j_index' arrays must have the same size." << std::endl
784                 << "'data_i_index' size = " << data_i_index.numElements() << std::endl
785                 << "'data_j_index' size = " << data_j_index.numElements());
786        }
787
788        if (2 == data_dim)
789        {
790          if (data_j_index.isEmpty())
791          {
792             ERROR("CDomain::checkCompression(void)",
793                   << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
794                   << "'data_j_index' must be defined when 'data_i_index' is set and 'data_dim' is 2.");
795          }
796        }
797        else // (1 == data_dim)
798        {
799          if (data_j_index.isEmpty())
800          {
801            data_j_index.resize(data_ni);
802            for (int j = 0; j < data_ni; ++j) data_j_index(j) = 0;
803          }
804        }
805      }
806      else
807      {
808        if (data_dim == 2 && !data_j_index.isEmpty())
809          ERROR("CDomain::checkCompression(void)",
810                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
811                << "'data_i_index' must be defined when 'data_j_index' is set and 'data_dim' is 2.");
812
813        if (1 == data_dim)
814        {
815          data_i_index.resize(data_ni);
816          data_j_index.resize(data_ni);
817
818          for (int i = 0; i < data_ni; ++i)
819          {
820            data_i_index(i) = i;
821            data_j_index(i) = 0;
822          }
823        }
824        else // (data_dim == 2)
825        {
826          const int dsize = data_ni * data_nj;
827          data_i_index.resize(dsize);
828          data_j_index.resize(dsize);
829
830          for(int count = 0, j = 0; j < data_nj; ++j)
831          {
832            for(int i = 0; i < data_ni; ++i, ++count)
833            {
834              data_i_index(count) = i;
835              data_j_index(count) = j;
836            }
837          }
838        }
839      }
840   }
841
842   //----------------------------------------------------------------
843
844   void CDomain::checkEligibilityForCompressedOutput(void)
845   {
846     // We don't check if the mask or the indexes are valid here, just if they have been defined at this point.
847     isCompressible_ = !mask_1d.isEmpty() || !mask_2d.isEmpty() || !data_i_index.isEmpty();
848   }
849
850   //----------------------------------------------------------------
851
852   void CDomain::completeLonLatClient(void)
853   {
854     if (!lonvalue_2d.isEmpty())
855     {
856       lonvalue_client.resize(ni * nj);
857       latvalue_client.resize(ni * nj);
858       if (hasBounds)
859       {
860         bounds_lon_client.resize(nvertex, ni * nj);
861         bounds_lat_client.resize(nvertex, ni * nj);
862       }
863
864       for (int j = 0; j < nj; ++j)
865       {
866         for (int i = 0; i < ni; ++i)
867         {
868           int k = j * ni + i;
869
870           lonvalue_client(k) = lonvalue_2d(i,j);
871           latvalue_client(k) = latvalue_2d(i,j);
872
873           if (hasBounds)
874           {
875             for (int n = 0; n < nvertex; ++n)
876             {
877               bounds_lon_client(n,k) = bounds_lon_2d(n,i,j);
878               bounds_lat_client(n,k) = bounds_lat_2d(n,i,j);
879             }
880           }
881         }
882       }
883     }
884     else if (!lonvalue_1d.isEmpty())
885     {
886       if (type_attr::rectilinear == type)
887       {
888         if (ni == lonvalue_1d.numElements() && nj == latvalue_1d.numElements())
889         {
890           lonvalue_client.resize(ni * nj);
891           latvalue_client.resize(ni * nj);
892           if (hasBounds)
893           {
894             bounds_lon_client.resize(nvertex, ni * nj);
895             bounds_lat_client.resize(nvertex, ni * nj);
896           }
897
898           for (int j = 0; j < nj; ++j)
899           {
900             for (int i = 0; i < ni; ++i)
901             {
902               int k = j * ni + i;
903
904               lonvalue_client(k) = lonvalue_1d(i);
905               latvalue_client(k) = latvalue_1d(j);
906
907               if (hasBounds)
908               {
909                 for (int n = 0; n < nvertex; ++n)
910                 {
911                   bounds_lon_client(n,k) = bounds_lon_1d(n,i);
912                   bounds_lat_client(n,k) = bounds_lat_1d(n,j);
913                 }
914               }
915             }
916           }
917         }
918         else
919           ERROR("CDomain::completeLonClient(void)",
920                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
921                 << "'lonvalue_1d' and 'latvalue_1d' does not have the same size as the local domain." << std::endl
922                 << "'lonvalue_1d' size is " << lonvalue_1d.numElements() << " but it should be " << ni.getValue() << '.' << std::endl
923                 << "'latvalue_1d' size is " << latvalue_1d.numElements() << " but it should be " << nj.getValue() << '.');
924       }
925       else if (type == type_attr::curvilinear || type == type_attr::unstructured)
926       {
927         lonvalue_client.reference(lonvalue_1d);
928         latvalue_client.reference(latvalue_1d);
929         if (hasBounds)
930         {
931           bounds_lon_client.reference(bounds_lon_1d);
932           bounds_lat_client.reference(bounds_lat_1d);
933         }
934       }
935     }
936   }
937
938   void CDomain::checkBounds(void)
939   {
940     if (!nvertex.isEmpty() && nvertex > 0)
941     {
942       if (!bounds_lon_1d.isEmpty() && !bounds_lon_2d.isEmpty())
943         ERROR("CDomain::checkBounds(void)",
944               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
945               << "Only one longitude boundary attribute can be used but both 'bounds_lon_1d' and 'bounds_lon_2d' are defined." << std::endl
946               << "Define only one longitude boundary attribute: 'bounds_lon_1d' or 'bounds_lon_2d'.");
947
948       if (!bounds_lat_1d.isEmpty() && !bounds_lat_2d.isEmpty())
949         ERROR("CDomain::checkBounds(void)",
950               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
951               << "Only one latitude boundary attribute can be used but both 'bounds_lat_1d' and 'bounds_lat_2d' are defined." << std::endl
952               << "Define only one latitude boundary attribute: 'bounds_lat_1d' or 'bounds_lat_2d'.");
953
954       if ((!bounds_lon_1d.isEmpty() && bounds_lat_1d.isEmpty()) || (bounds_lon_1d.isEmpty() && !bounds_lat_1d.isEmpty()))
955       {
956         ERROR("CDomain::checkBounds(void)",
957               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
958               << "Only 'bounds_lon_1d' or 'bounds_lat_1d' is defined." << std::endl
959               << "Please define either both attributes or none.");
960       }
961
962       if ((!bounds_lon_2d.isEmpty() && bounds_lat_2d.isEmpty()) || (bounds_lon_2d.isEmpty() && !bounds_lat_2d.isEmpty()))
963       {
964         ERROR("CDomain::checkBounds(void)",
965               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
966               << "Only 'bounds_lon_2d' or 'bounds_lat_2d' is defined." << std::endl
967               << "Please define either both attributes or none.");
968       }
969
970       if (!bounds_lon_1d.isEmpty() && nvertex.getValue() != bounds_lon_1d.extent(0))
971         ERROR("CDomain::checkBounds(void)",
972               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
973               << "'bounds_lon_1d' dimension is not compatible with 'nvertex'." << std::endl
974               << "'bounds_lon_1d' dimension is " << bounds_lon_1d.extent(1)
975               << " but nvertex is " << nvertex.getValue() << ".");
976
977       if (!bounds_lon_2d.isEmpty() && nvertex.getValue() != bounds_lon_2d.extent(0))
978         ERROR("CDomain::checkBounds(void)",
979               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
980               << "'bounds_lon_2d' dimension is not compatible with 'nvertex'." << std::endl
981               << "'bounds_lon_2d' dimension is " << bounds_lon_2d.extent(2)
982               << " but nvertex is " << nvertex.getValue() << ".");
983
984       if (!bounds_lon_1d.isEmpty() && lonvalue_1d.isEmpty())
985         ERROR("CDomain::checkBounds(void)",
986               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
987               << "Since 'bounds_lon_1d' is defined, 'lonvalue_1d' must be defined too." << std::endl);
988
989       if (!bounds_lon_2d.isEmpty() && lonvalue_2d.isEmpty())
990         ERROR("CDomain::checkBounds(void)",
991               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
992               << "Since 'bounds_lon_2d' is defined, 'lonvalue_2d' must be defined too." << std::endl);
993
994       if (!bounds_lat_1d.isEmpty() && nvertex.getValue() != bounds_lat_1d.extent(0))
995         ERROR("CDomain::checkBounds(void)",
996               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
997               << "'bounds_lat_1d' dimension is not compatible with 'nvertex'." << std::endl
998               << "'bounds_lat_1d' dimension is " << bounds_lat_1d.extent(1)
999               << " but nvertex is " << nvertex.getValue() << ".");
1000
1001       if (!bounds_lat_2d.isEmpty() && nvertex.getValue() != bounds_lat_2d.extent(0))
1002         ERROR("CDomain::checkBounds(void)",
1003               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1004               << "'bounds_lat_2d' dimension is not compatible with 'nvertex'." << std::endl
1005               << "'bounds_lat_2d' dimension is " << bounds_lat_2d.extent(2)
1006               << " but nvertex is " << nvertex.getValue() << ".");
1007
1008       if (!bounds_lat_1d.isEmpty() && latvalue_1d.isEmpty())
1009         ERROR("CDomain::checkBounds(void)",
1010               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1011               << "Since 'bounds_lat_1d' is defined, 'latvalue_1d' must be defined too." << std::endl);
1012
1013       if (!bounds_lat_2d.isEmpty() && latvalue_2d.isEmpty())
1014         ERROR("CDomain::checkBounds(void)",
1015               << "Since 'bounds_lat_2d' is defined, 'latvalue_2d' must be defined too." << std::endl);
1016
1017       hasBounds = true;
1018     }
1019     else
1020     {
1021       hasBounds = false;
1022       nvertex = 0;
1023     }
1024   }
1025
1026   void CDomain::checkArea(void)
1027   {
1028     hasArea = !area.isEmpty();
1029     if (hasArea)
1030     {
1031       if (area.extent(0) != ni || area.extent(1) != nj)
1032       {
1033         ERROR("CDomain::checkArea(void)",
1034               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1035               << "The area does not have the same size as the local domain." << std::endl
1036               << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1037               << "Area size is " << area.extent(0) << " x " << area.extent(1) << ".");
1038       }
1039     }
1040   }
1041
1042   void CDomain::checkLonLat()
1043   {
1044     hasLonLat = (!latvalue_1d.isEmpty() && !lonvalue_1d.isEmpty()) ||
1045                 (!latvalue_2d.isEmpty() && !lonvalue_2d.isEmpty());
1046     if (hasLonLat)
1047     {
1048       if (!lonvalue_1d.isEmpty() && !lonvalue_2d.isEmpty())
1049         ERROR("CDomain::checkLonLat()",
1050               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1051               << "Only one longitude attribute can be used but both 'lonvalue_1d' and 'lonvalue_2d' are defined." << std::endl
1052               << "Define only one longitude attribute: 'lonvalue_1d' or 'lonvalue_2d'.");
1053
1054       if (!lonvalue_1d.isEmpty() && lonvalue_2d.isEmpty())
1055       {
1056         if ((type_attr::rectilinear != type) && (lonvalue_1d.numElements() != i_index.numElements()))
1057           ERROR("CDomain::checkLonLat()",
1058                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1059                 << "'lonvalue_1d' does not have the same size as the local domain." << std::endl
1060                 << "Local size is " << i_index.numElements() << "." << std::endl
1061                 << "'lonvalue_1d' size is " << lonvalue_1d.numElements() << ".");
1062       }
1063
1064       if (lonvalue_1d.isEmpty() && !lonvalue_2d.isEmpty())
1065       {
1066         if (lonvalue_2d.extent(0) != ni || lonvalue_2d.extent(1) != nj)
1067           ERROR("CDomain::checkLonLat()",
1068                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1069                 << "'lonvalue_2d' does not have the same size as the local domain." << std::endl
1070                 << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1071                 << "'lonvalue_2d' size is " << lonvalue_2d.extent(0) << " x " << lonvalue_2d.extent(1) << ".");
1072       }
1073
1074       if (!latvalue_1d.isEmpty() && !latvalue_2d.isEmpty())
1075         ERROR("CDomain::checkLonLat()",
1076               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1077               << "Only one latitude attribute can be used but both 'latvalue_1d' and 'latvalue_2d' are defined." << std::endl
1078               << "Define only one latitude attribute: 'latvalue_1d' or 'latvalue_2d'.");
1079
1080       if (!latvalue_1d.isEmpty() && latvalue_2d.isEmpty())
1081       {
1082         if ((type_attr::rectilinear != type) && (latvalue_1d.numElements() != i_index.numElements()))
1083           ERROR("CDomain::checkLonLat()",
1084                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1085                 << "'latvalue_1d' does not have the same size as the local domain." << std::endl
1086                 << "Local size is " << i_index.numElements() << "." << std::endl
1087                 << "'latvalue_1d' size is " << latvalue_1d.numElements() << ".");
1088       }
1089
1090       if (latvalue_1d.isEmpty() && !latvalue_2d.isEmpty())
1091       {
1092         if (latvalue_2d.extent(0) != ni || latvalue_2d.extent(1) != nj)
1093           ERROR("CDomain::checkLonLat()",
1094                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1095                 << "'latvalue_2d' does not have the same size as the local domain." << std::endl
1096                 << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1097                 << "'latvalue_2d' size is " << latvalue_2d.extent(0) << " x " << latvalue_2d.extent(1) << ".");
1098       }
1099     }
1100   }
1101
1102   void CDomain::checkAttributesOnClientAfterTransformation()
1103   {
1104     CContext* context=CContext::getCurrent() ;
1105
1106     if (this->isClientAfterTransformationChecked) return;
1107     if (context->hasClient)
1108     {
1109       this->checkMask();
1110       if (hasLonLat || hasArea || isCompressible_) this->computeConnectedServer();
1111       if (hasLonLat) this->completeLonLatClient();
1112     }
1113
1114     this->isClientAfterTransformationChecked = true;
1115   }
1116
1117   //----------------------------------------------------------------
1118   // Divide function checkAttributes into 2 seperate ones
1119   // This function only checks all attributes of current domain
1120   void CDomain::checkAttributesOnClient()
1121   {
1122     if (this->isClientChecked) return;
1123     CContext* context=CContext::getCurrent();
1124
1125      this->checkDomain();
1126      this->checkBounds();
1127      this->checkArea();
1128      this->checkLonLat();
1129
1130      if (context->hasClient)
1131      { // CÃŽté client uniquement
1132         this->checkMask();
1133         this->checkDomainData();
1134         this->checkCompression();
1135      }
1136      else
1137      { // CÃŽté serveur uniquement
1138      }
1139
1140      this->isClientChecked = true;
1141   }
1142
1143   // Send all checked attributes to server
1144   void CDomain::sendCheckedAttributes()
1145   {
1146     if (!this->isClientChecked) checkAttributesOnClient();
1147     if (!this->isClientAfterTransformationChecked) checkAttributesOnClientAfterTransformation();
1148     CContext* context=CContext::getCurrent() ;
1149
1150     if (this->isChecked) return;
1151     if (context->hasClient)
1152     {
1153       sendServerAttribut();
1154       if (hasLonLat || hasArea || isCompressible_) sendLonLatArea();
1155     }
1156     this->isChecked = true;
1157   }
1158
1159   void CDomain::checkAttributes(void)
1160   {
1161      if (this->isChecked) return;
1162      CContext* context=CContext::getCurrent() ;
1163
1164      this->checkDomain();
1165      this->checkLonLat();
1166      this->checkBounds();
1167      this->checkArea();
1168
1169      if (context->hasClient)
1170      { // CÃŽté client uniquement
1171         this->checkMask();
1172         this->checkDomainData();
1173         this->checkCompression();
1174
1175      }
1176      else
1177      { // CÃŽté serveur uniquement
1178      }
1179
1180      if (context->hasClient)
1181      {
1182        this->computeConnectedServer();
1183        this->completeLonLatClient();
1184        this->sendServerAttribut();
1185        this->sendLonLatArea();
1186      }
1187
1188      this->isChecked = true;
1189   }
1190
1191  void CDomain::sendServerAttribut(void)
1192  {
1193    CServerDistributionDescription serverDescription(nGlobDomain_);
1194
1195    CContext* context = CContext::getCurrent();
1196    CContextClient* client = context->client;
1197    int nbServer = client->serverSize;
1198
1199    if (isUnstructed_) serverDescription.computeServerDistribution(nbServer,0);
1200    else serverDescription.computeServerDistribution(nbServer,1);
1201
1202    std::vector<std::vector<int> > serverIndexBegin = serverDescription.getServerIndexBegin();
1203    std::vector<std::vector<int> > serverDimensionSizes = serverDescription.getServerDimensionSizes();
1204
1205    CEventClient event(getType(),EVENT_ID_SERVER_ATTRIBUT);
1206    if (client->isServerLeader())
1207    {
1208      std::list<CMessage> msgs;
1209
1210      const std::list<int>& ranks = client->getRanksServerLeader();
1211      for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1212      {
1213        // Use const int to ensure CMessage holds a copy of the value instead of just a reference
1214        const int ibegin_srv = serverIndexBegin[*itRank][0];
1215        const int jbegin_srv = serverIndexBegin[*itRank][1];
1216        const int ni_srv = serverDimensionSizes[*itRank][0];
1217        const int nj_srv = serverDimensionSizes[*itRank][1];
1218        const int iend_srv = ibegin_srv + ni_srv - 1;
1219        const int jend_srv = jbegin_srv + nj_srv - 1;
1220
1221        msgs.push_back(CMessage());
1222        CMessage& msg = msgs.back();
1223        msg << this->getId() ;
1224        msg << ni_srv << ibegin_srv << iend_srv << nj_srv << jbegin_srv << jend_srv;
1225        msg << global_zoom_ni << global_zoom_ibegin << global_zoom_nj << global_zoom_jbegin;
1226        msg << isCompressible_;
1227
1228        event.push(*itRank,1,msg);
1229      }
1230      client->sendEvent(event);
1231    }
1232    else client->sendEvent(event);
1233  }
1234
1235  void CDomain::computeNGlobDomain()
1236  {
1237    nGlobDomain_.resize(2);
1238    nGlobDomain_[0] = ni_glo.getValue();
1239    nGlobDomain_[1] = nj_glo.getValue();
1240  }
1241
1242  void CDomain::computeConnectedServer(void)
1243  {
1244    CContext* context=CContext::getCurrent() ;
1245    CContextClient* client=context->client ;
1246    int nbServer=client->serverSize;
1247    bool doComputeGlobalIndexServer = true;
1248
1249    int i,j,i_ind,j_ind, nbIndex;
1250    int global_zoom_iend=global_zoom_ibegin+global_zoom_ni-1 ;
1251    int global_zoom_jend=global_zoom_jbegin+global_zoom_nj-1 ;
1252
1253    // Precompute number of index
1254    int globalIndexCountZoom = 0;
1255    nbIndex = i_index.numElements();
1256    for (i = 0; i < nbIndex; ++i)
1257    {
1258      i_ind=i_index(i);
1259      j_ind=j_index(i);
1260
1261      if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1262      {
1263        ++globalIndexCountZoom;
1264      }
1265    }
1266
1267    int globalIndexWrittenCount = 0;
1268    if (isCompressible_)
1269    {
1270      for (i = 0; i < data_i_index.numElements(); ++i)
1271      {
1272        i_ind = CDistributionClient::getDomainIndex(data_i_index(i), data_j_index(i),
1273                                                    data_ibegin, data_jbegin, data_dim, ni,
1274                                                    j_ind);
1275        if (i_ind >= 0 && i_ind < ni && j_ind >= 0 && j_ind < nj && mask_1d(i_ind + j_ind * ni))
1276        {
1277          i_ind += ibegin;
1278          j_ind += jbegin;
1279          if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1280            ++globalIndexWrittenCount;
1281        }
1282      }
1283    }
1284
1285    // Fill in index
1286    CArray<size_t,1> globalIndexDomainZoom(globalIndexCountZoom);
1287    CArray<size_t,1> localIndexDomainZoom(globalIndexCountZoom);
1288    CArray<size_t,1> globalIndexDomain(nbIndex);
1289    size_t globalIndex;
1290    int globalIndexCount = 0;
1291    globalIndexCountZoom = 0;
1292
1293    for (i = 0; i < nbIndex; ++i)
1294    {
1295      i_ind=i_index(i);
1296      j_ind=j_index(i);
1297      globalIndex = i_ind + j_ind * ni_glo;
1298      globalIndexDomain(globalIndexCount) = globalIndex;
1299      ++globalIndexCount;
1300      if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1301      {
1302        globalIndexDomainZoom(globalIndexCountZoom) = globalIndex;
1303        localIndexDomainZoom(globalIndexCountZoom) = i;
1304        ++globalIndexCountZoom;
1305      }
1306    }
1307
1308    CArray<int,1> globalIndexWrittenDomain(globalIndexWrittenCount);
1309    if (isCompressible_)
1310    {
1311      globalIndexWrittenCount = 0;
1312      for (i = 0; i < data_i_index.numElements(); ++i)
1313      {
1314        i_ind = CDistributionClient::getDomainIndex(data_i_index(i), data_j_index(i),
1315                                                    data_ibegin, data_jbegin, data_dim, ni,
1316                                                    j_ind);
1317        if (i_ind >= 0 && i_ind < ni && j_ind >= 0 && j_ind < nj && mask_1d(i_ind + j_ind * ni))
1318        {
1319          i_ind += ibegin;
1320          j_ind += jbegin;
1321          if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1322          {
1323            globalIndexWrittenDomain(globalIndexWrittenCount) = i_ind + j_ind * ni_glo;
1324            ++globalIndexWrittenCount;
1325          }
1326        }
1327      }
1328    }
1329
1330    size_t globalSizeIndex = 1, indexBegin, indexEnd;
1331    int range, clientSize = client->clientSize;
1332    for (int i = 0; i < nGlobDomain_.size(); ++i) globalSizeIndex *= nGlobDomain_[i];
1333    indexBegin = 0;
1334    for (int i = 0; i < clientSize; ++i)
1335    {
1336      range = globalSizeIndex / clientSize;
1337      if (i < (globalSizeIndex%clientSize)) ++range;
1338      if (i == client->clientRank) break;
1339      indexBegin += range;
1340    }
1341    indexEnd = indexBegin + range - 1;
1342
1343    CServerDistributionDescription serverDescription(nGlobDomain_);
1344    if (isUnstructed_) serverDescription.computeServerGlobalIndexInRange(nbServer, std::make_pair<size_t,size_t>(indexBegin, indexEnd), 0);
1345    else serverDescription.computeServerGlobalIndexInRange(nbServer, std::make_pair<size_t,size_t>(indexBegin, indexEnd), 1);
1346
1347    CClientServerMapping* clientServerMap = new CClientServerMappingDistributed(serverDescription.getGlobalIndexRange(),
1348                                                                                client->intraComm);
1349    clientServerMap->computeServerIndexMapping(globalIndexDomain);
1350    const std::map<int, std::vector<size_t> >& globalIndexDomainOnServer = clientServerMap->getGlobalIndexOnServer();
1351
1352    std::map<int, std::vector<size_t> >::const_iterator it = globalIndexDomainOnServer.begin(),
1353                                                       ite = globalIndexDomainOnServer.end();
1354    typedef XIOSBinarySearchWithIndex<size_t> BinarySearch;
1355    std::vector<int>::iterator itVec;
1356
1357    indSrv_.clear();
1358    indWrittenSrv_.clear();
1359    for (; it != ite; ++it)
1360    {
1361      int rank = it->first;
1362      int indexSize = it->second.size();
1363      std::vector<int> permutIndex(indexSize);
1364      XIOSAlgorithms::fillInIndex(indexSize, permutIndex);
1365      XIOSAlgorithms::sortWithIndex<size_t, CVectorStorage>(it->second, permutIndex);
1366      BinarySearch binSearch(it->second);
1367      int nb = globalIndexDomainZoom.numElements();
1368      for (int i = 0; i < nb; ++i)
1369      {
1370        if (binSearch.search(permutIndex.begin(), permutIndex.end(), globalIndexDomainZoom(i), itVec))
1371        {
1372          indSrv_[rank].push_back(localIndexDomainZoom(i));
1373        }
1374      }
1375      for (int i = 0; i < globalIndexWrittenDomain.numElements(); ++i)
1376      {
1377        if (binSearch.search(permutIndex.begin(), permutIndex.end(), globalIndexWrittenDomain(i), itVec))
1378        {
1379          indWrittenSrv_[rank].push_back(globalIndexWrittenDomain(i));
1380        }
1381      }
1382    }
1383
1384    connectedServerRank_.clear();
1385    for (it = globalIndexDomainOnServer.begin(); it != ite; ++it) {
1386      connectedServerRank_.push_back(it->first);
1387    }
1388
1389    nbConnectedClients_ = clientServerMap->computeConnectedClients(client->serverSize, client->clientSize, client->intraComm, connectedServerRank_);
1390
1391    delete clientServerMap;
1392  }
1393
1394  const std::map<int, vector<size_t> >& CDomain::getIndexServer() const
1395  {
1396    return indSrv_;
1397  }
1398
1399  /*!
1400    Send index from client to server(s)
1401  */
1402  void CDomain::sendIndex()
1403  {
1404    int ns, n, i, j, ind, nv, idx;
1405    CContext* context = CContext::getCurrent();
1406    CContextClient* client=context->client;
1407
1408    CEventClient eventIndex(getType(), EVENT_ID_INDEX);
1409
1410    list<CMessage> list_msgsIndex;
1411    list<CArray<int,1> > list_indi, list_indj, list_writtenInd;
1412
1413    std::map<int, std::vector<size_t> >::const_iterator it, iteMap;
1414    iteMap = indSrv_.end();
1415    for (int k = 0; k < connectedServerRank_.size(); ++k)
1416    {
1417      int nbData = 0;
1418      int rank = connectedServerRank_[k];
1419      it = indSrv_.find(rank);
1420      if (iteMap != it)
1421        nbData = it->second.size();
1422
1423      list_indi.push_back(CArray<int,1>(nbData));
1424      list_indj.push_back(CArray<int,1>(nbData));
1425
1426      CArray<int,1>& indi = list_indi.back();
1427      CArray<int,1>& indj = list_indj.back();
1428      const std::vector<size_t>& temp = it->second;
1429      for (n = 0; n < nbData; ++n)
1430      {
1431        idx = static_cast<int>(it->second[n]);
1432        indi(n) = i_index(idx);
1433        indj(n) = j_index(idx);
1434      }
1435
1436      list_msgsIndex.push_back(CMessage());
1437
1438      list_msgsIndex.back() << this->getId() << (int)type; // enum ne fonctionne pour les message => ToFix
1439      list_msgsIndex.back() << isCurvilinear;
1440      list_msgsIndex.back() << list_indi.back() << list_indj.back();
1441
1442      if (isCompressible_)
1443      {
1444        std::vector<int>& writtenIndSrc = indWrittenSrv_[rank];
1445        list_writtenInd.push_back(CArray<int,1>(writtenIndSrc.size()));
1446        CArray<int,1>& writtenInd = list_writtenInd.back();
1447
1448        for (n = 0; n < writtenInd.numElements(); ++n)
1449          writtenInd(n) = writtenIndSrc[n];
1450
1451        list_msgsIndex.back() << writtenInd;
1452      }
1453
1454      eventIndex.push(rank, nbConnectedClients_[rank], list_msgsIndex.back());
1455    }
1456
1457    client->sendEvent(eventIndex);
1458  }
1459
1460  /*!
1461    Send area from client to server(s)
1462  */
1463  void CDomain::sendArea()
1464  {
1465    if (!hasArea) return;
1466
1467    int ns, n, i, j, ind, nv, idx;
1468    CContext* context = CContext::getCurrent();
1469    CContextClient* client=context->client;
1470
1471    // send area for each connected server
1472    CEventClient eventArea(getType(), EVENT_ID_AREA);
1473
1474    list<CMessage> list_msgsArea;
1475    list<CArray<double,1> > list_area;
1476
1477    std::map<int, std::vector<size_t> >::const_iterator it, iteMap;
1478    iteMap = indSrv_.end();
1479    for (int k = 0; k < connectedServerRank_.size(); ++k)
1480    {
1481      int nbData = 0;
1482      int rank = connectedServerRank_[k];
1483      it = indSrv_.find(rank);
1484      if (iteMap != it)
1485        nbData = it->second.size();
1486      list_area.push_back(CArray<double,1>(nbData));
1487
1488      const std::vector<size_t>& temp = it->second;
1489      for (n = 0; n < nbData; ++n)
1490      {
1491        idx = static_cast<int>(it->second[n]);
1492        i = i_index(idx);
1493        j = j_index(idx);
1494        if (hasArea)
1495          list_area.back()(n) = area(i - ibegin, j - jbegin);
1496      }
1497
1498      list_msgsArea.push_back(CMessage());
1499      list_msgsArea.back() << this->getId() << list_area.back();
1500      eventArea.push(rank, nbConnectedClients_[rank], list_msgsArea.back());
1501    }
1502    client->sendEvent(eventArea);
1503  }
1504
1505  /*!
1506    Send longitude and latitude from client to servers
1507    Each client send long and lat information to corresponding connected server(s).
1508    Because longitude and latitude are optional, this function only called if latitude and longitude exist
1509  */
1510  void CDomain::sendLonLat()
1511  {
1512    if (!hasLonLat) return;
1513
1514    int ns, n, i, j, ind, nv, idx;
1515    CContext* context = CContext::getCurrent();
1516    CContextClient* client=context->client;
1517
1518    // send lon lat for each connected server
1519    CEventClient eventLon(getType(), EVENT_ID_LON);
1520    CEventClient eventLat(getType(), EVENT_ID_LAT);
1521
1522    list<CMessage> list_msgsLon, list_msgsLat;
1523    list<CArray<double,1> > list_lon, list_lat;
1524    list<CArray<double,2> > list_boundslon, list_boundslat;
1525
1526    std::map<int, std::vector<size_t> >::const_iterator it, iteMap;
1527    iteMap = indSrv_.end();
1528    for (int k = 0; k < connectedServerRank_.size(); ++k)
1529    {
1530      int nbData = 0;
1531      int rank = connectedServerRank_[k];
1532      it = indSrv_.find(rank);
1533      if (iteMap != it)
1534        nbData = it->second.size();
1535
1536      list_lon.push_back(CArray<double,1>(nbData));
1537      list_lat.push_back(CArray<double,1>(nbData));
1538
1539      if (hasBounds)
1540      {
1541        list_boundslon.push_back(CArray<double,2>(nvertex, nbData));
1542        list_boundslat.push_back(CArray<double,2>(nvertex, nbData));
1543      }
1544
1545      CArray<double,1>& lon = list_lon.back();
1546      CArray<double,1>& lat = list_lat.back();
1547      const std::vector<size_t>& temp = it->second;
1548      for (n = 0; n < nbData; ++n)
1549      {
1550        idx = static_cast<int>(it->second[n]);
1551        lon(n) = lonvalue_client(idx);
1552        lat(n) = latvalue_client(idx);
1553
1554        if (hasBounds)
1555        {
1556          CArray<double,2>& boundslon = list_boundslon.back();
1557          CArray<double,2>& boundslat = list_boundslat.back();
1558
1559          for (nv = 0; nv < nvertex; ++nv)
1560          {
1561            boundslon(nv, n) = bounds_lon_client(nv, idx);
1562            boundslat(nv, n) = bounds_lat_client(nv, idx);
1563          }
1564        }
1565      }
1566
1567      list_msgsLon.push_back(CMessage());
1568      list_msgsLat.push_back(CMessage());
1569
1570      list_msgsLon.back() << this->getId() << list_lon.back();
1571      list_msgsLat.back() << this->getId() << list_lat.back();
1572
1573      if (hasBounds)
1574      {
1575        list_msgsLon.back() << list_boundslon.back();
1576        list_msgsLat.back() << list_boundslat.back();
1577      }
1578
1579      eventLon.push(rank, nbConnectedClients_[rank], list_msgsLon.back());
1580      eventLat.push(rank, nbConnectedClients_[rank], list_msgsLat.back());
1581    }
1582
1583    client->sendEvent(eventLon);
1584    client->sendEvent(eventLat);
1585  }
1586
1587  /*!
1588    Send some optional information to server(s)
1589    In the future, this function can be extended with more optional information to send
1590  */
1591  void CDomain::sendLonLatArea(void)
1592  {
1593    sendIndex();
1594    sendLonLat();
1595    sendArea();
1596  }
1597
1598  bool CDomain::dispatchEvent(CEventServer& event)
1599  {
1600    if (SuperClass::dispatchEvent(event)) return true;
1601    else
1602    {
1603      switch(event.type)
1604      {
1605        case EVENT_ID_SERVER_ATTRIBUT:
1606          recvServerAttribut(event);
1607          return true;
1608          break;
1609        case EVENT_ID_INDEX:
1610          recvIndex(event);
1611          return true;
1612          break;
1613        case EVENT_ID_LON:
1614          recvLon(event);
1615          return true;
1616          break;
1617        case EVENT_ID_LAT:
1618          recvLat(event);
1619          return true;
1620          break;
1621        case EVENT_ID_AREA:
1622          recvArea(event);
1623          return true;
1624          break;
1625        default:
1626          ERROR("bool CDomain::dispatchEvent(CEventServer& event)",
1627                << "Unknown Event");
1628          return false;
1629       }
1630    }
1631  }
1632
1633  /*!
1634    Receive attributes event from clients(s)
1635    \param[in] event event contain info about rank and associated attributes
1636  */
1637  void CDomain::recvServerAttribut(CEventServer& event)
1638  {
1639    CBufferIn* buffer=event.subEvents.begin()->buffer;
1640    string domainId ;
1641    *buffer>>domainId ;
1642    get(domainId)->recvServerAttribut(*buffer) ;
1643  }
1644
1645  /*!
1646    Receive attributes from client(s): zoom info and begin and n of each server
1647    \param[in] rank rank of client source
1648    \param[in] buffer message containing attributes info
1649  */
1650  void CDomain::recvServerAttribut(CBufferIn& buffer)
1651  {
1652    buffer >> ni_srv >> ibegin_srv >> iend_srv >> nj_srv >> jbegin_srv >> jend_srv
1653           >> global_zoom_ni >> global_zoom_ibegin >> global_zoom_nj >> global_zoom_jbegin
1654           >> isCompressible_;
1655
1656    int zoom_iend = global_zoom_ibegin + global_zoom_ni - 1;
1657    int zoom_jend = global_zoom_jbegin + global_zoom_nj - 1;
1658
1659    zoom_ibegin_srv = global_zoom_ibegin > ibegin_srv ? global_zoom_ibegin : ibegin_srv ;
1660    zoom_iend_srv = zoom_iend < iend_srv ? zoom_iend : iend_srv ;
1661    zoom_ni_srv=zoom_iend_srv-zoom_ibegin_srv+1 ;
1662
1663    zoom_jbegin_srv = global_zoom_jbegin > jbegin_srv ? global_zoom_jbegin : jbegin_srv ;
1664    zoom_jend_srv = zoom_jend < jend_srv ? zoom_jend : jend_srv ;
1665    zoom_nj_srv=zoom_jend_srv-zoom_jbegin_srv+1 ;
1666
1667    if (zoom_ni_srv<=0 || zoom_nj_srv<=0)
1668    {
1669      zoom_ibegin_srv=0 ; zoom_iend_srv=0 ; zoom_ni_srv=0 ;
1670      zoom_jbegin_srv=0 ; zoom_jend_srv=0 ; zoom_nj_srv=0 ;
1671    }
1672    lonvalue_srv.resize(zoom_ni_srv*zoom_nj_srv) ;
1673    lonvalue_srv = 0. ;
1674    latvalue_srv.resize(zoom_ni_srv*zoom_nj_srv) ;
1675    latvalue_srv = 0. ;
1676    if (hasBounds)
1677    {
1678      bounds_lon_srv.resize(nvertex,zoom_ni_srv*zoom_nj_srv) ;
1679      bounds_lon_srv = 0. ;
1680      bounds_lat_srv.resize(nvertex,zoom_ni_srv*zoom_nj_srv) ;
1681      bounds_lat_srv = 0. ;
1682    }
1683
1684    if (hasArea)
1685      area_srv.resize(zoom_ni_srv * zoom_nj_srv);
1686  }
1687
1688  /*!
1689    Receive index event from clients(s)
1690    \param[in] event event contain info about rank and associated index
1691  */
1692  void CDomain::recvIndex(CEventServer& event)
1693  {
1694    CDomain* domain;
1695
1696    list<CEventServer::SSubEvent>::iterator it;
1697    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1698    {
1699      CBufferIn* buffer = it->buffer;
1700      string domainId;
1701      *buffer >> domainId;
1702      domain = get(domainId);
1703      domain->recvIndex(it->rank, *buffer);
1704    }
1705
1706    if (domain->isCompressible_)
1707    {
1708      std::sort(domain->indexesToWrite.begin(), domain->indexesToWrite.end());
1709
1710      CContextServer* server = CContext::getCurrent()->server;
1711      domain->numberWrittenIndexes_ = domain->indexesToWrite.size();
1712      MPI_Allreduce(&domain->numberWrittenIndexes_, &domain->totalNumberWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
1713      MPI_Scan(&domain->numberWrittenIndexes_, &domain->offsetWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
1714      domain->offsetWrittenIndexes_ -= domain->numberWrittenIndexes_;
1715    }
1716  }
1717
1718  /*!
1719    Receive index information from client(s)
1720    \param[in] rank rank of client source
1721    \param[in] buffer message containing index info
1722  */
1723  void CDomain::recvIndex(int rank, CBufferIn& buffer)
1724  {
1725    int type_int;
1726    buffer >> type_int >> isCurvilinear >> indiSrv[rank] >> indjSrv[rank];
1727    type.setValue((type_attr::t_enum)type_int); // probleme des type enum avec les buffers : ToFix
1728
1729    if (isCompressible_)
1730    {
1731      CArray<int, 1> writtenIndexes;
1732      buffer >> writtenIndexes;
1733      indexesToWrite.reserve(indexesToWrite.size() + writtenIndexes.numElements());
1734      for (int i = 0; i < writtenIndexes.numElements(); ++i)
1735        indexesToWrite.push_back(writtenIndexes(i));
1736    }
1737  }
1738
1739  /*!
1740    Receive longitude event from clients(s)
1741    \param[in] event event contain info about rank and associated longitude
1742  */
1743  void CDomain::recvLon(CEventServer& event)
1744  {
1745    list<CEventServer::SSubEvent>::iterator it;
1746    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1747    {
1748      CBufferIn* buffer = it->buffer;
1749      string domainId;
1750      *buffer >> domainId;
1751      get(domainId)->recvLon(it->rank, *buffer);
1752    }
1753  }
1754
1755  /*!
1756    Receive longitude information from client(s)
1757    \param[in] rank rank of client source
1758    \param[in] buffer message containing longitude info
1759  */
1760  void CDomain::recvLon(int rank, CBufferIn& buffer)
1761  {
1762    CArray<int,1> &indi = indiSrv[rank], &indj = indjSrv[rank];
1763    CArray<double,1> lon;
1764    CArray<double,2> boundslon;
1765
1766    buffer >> lon;
1767    if (hasBounds) buffer >> boundslon;
1768
1769    int i, j, ind_srv;
1770    for (int ind = 0; ind < indi.numElements(); ind++)
1771    {
1772      i = indi(ind); j = indj(ind);
1773      ind_srv = (i - zoom_ibegin_srv) + (j - zoom_jbegin_srv) * zoom_ni_srv;
1774      lonvalue_srv(ind_srv) = lon(ind);
1775      if (hasBounds)
1776      {
1777        for (int nv = 0; nv < nvertex; ++nv)
1778          bounds_lon_srv(nv, ind_srv) = boundslon(nv, ind);
1779      }
1780    }
1781  }
1782
1783  /*!
1784    Receive latitude event from clients(s)
1785    \param[in] event event contain info about rank and associated latitude
1786  */
1787  void CDomain::recvLat(CEventServer& event)
1788  {
1789    list<CEventServer::SSubEvent>::iterator it;
1790    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1791    {
1792      CBufferIn* buffer = it->buffer;
1793      string domainId;
1794      *buffer >> domainId;
1795      get(domainId)->recvLat(it->rank, *buffer);
1796    }
1797  }
1798
1799  /*!
1800    Receive latitude information from client(s)
1801    \param[in] rank rank of client source
1802    \param[in] buffer message containing latitude info
1803  */
1804  void CDomain::recvLat(int rank, CBufferIn& buffer)
1805  {
1806    CArray<int,1> &indi = indiSrv[rank], &indj = indjSrv[rank];
1807    CArray<double,1> lat;
1808    CArray<double,2> boundslat;
1809
1810    buffer >> lat;
1811    if (hasBounds) buffer >> boundslat;
1812
1813    int i, j, ind_srv;
1814    for (int ind = 0; ind < indi.numElements(); ind++)
1815    {
1816      i = indi(ind); j = indj(ind);
1817      ind_srv = (i - zoom_ibegin_srv) + (j - zoom_jbegin_srv) * zoom_ni_srv;
1818      latvalue_srv(ind_srv) = lat(ind);
1819      if (hasBounds)
1820      {
1821        for (int nv = 0; nv < nvertex; nv++)
1822          bounds_lat_srv(nv, ind_srv) = boundslat(nv, ind);
1823      }
1824    }
1825  }
1826
1827  /*!
1828    Receive area event from clients(s)
1829    \param[in] event event contain info about rank and associated area
1830  */
1831  void CDomain::recvArea(CEventServer& event)
1832  {
1833    list<CEventServer::SSubEvent>::iterator it;
1834    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1835    {
1836      CBufferIn* buffer = it->buffer;
1837      string domainId;
1838      *buffer >> domainId;
1839      get(domainId)->recvArea(it->rank, *buffer);
1840    }
1841  }
1842
1843  /*!
1844    Receive area information from client(s)
1845    \param[in] rank rank of client source
1846    \param[in] buffer message containing area info
1847  */
1848  void CDomain::recvArea(int rank, CBufferIn& buffer)
1849  {
1850    CArray<int,1> &indi = indiSrv[rank], &indj = indjSrv[rank];
1851    CArray<double,1> clientArea;
1852
1853    buffer >> clientArea;
1854
1855    int i, j, ind_srv;
1856    for (int ind = 0; ind < indi.numElements(); ind++)
1857    {
1858      i = indi(ind); j = indj(ind);
1859      ind_srv = (i - zoom_ibegin_srv) + (j - zoom_jbegin_srv) * zoom_ni_srv;
1860      area_srv(ind_srv) = clientArea(ind);
1861    }
1862  }
1863
1864  /*!
1865    Check whether a domain has transformation
1866    \return true if domain has transformation
1867  */
1868  bool CDomain::hasTransformation()
1869  {
1870    return (!transformationMap_.empty());
1871  }
1872
1873  /*!
1874    Set transformation for current domain. It's the method to move transformation in hierarchy
1875    \param [in] domTrans transformation on domain
1876  */
1877  void CDomain::setTransformations(const TransMapTypes& domTrans)
1878  {
1879    transformationMap_ = domTrans;
1880  }
1881
1882  /*!
1883    Get all transformation current domain has
1884    \return all transformation
1885  */
1886  CDomain::TransMapTypes CDomain::getAllTransformations(void)
1887  {
1888    return transformationMap_;
1889  }
1890
1891  /*!
1892    Check the validity of all transformations applied on domain
1893  This functions is called AFTER all inherited attributes are solved
1894  */
1895  void CDomain::checkTransformations()
1896  {
1897    TransMapTypes::const_iterator itb = transformationMap_.begin(), it,
1898                                  ite = transformationMap_.end();
1899    for (it = itb; it != ite; ++it)
1900    {
1901      (it->second)->checkValid(this);
1902    }
1903  }
1904
1905  /*!
1906   * Go through the hierarchy to find the domain from which the transformations must be inherited
1907   */
1908  void CDomain::solveInheritanceTransformation()
1909  {
1910    if (hasTransformation() || !hasDirectDomainReference())
1911      return;
1912
1913    CDomain* domain = this;
1914    std::vector<CDomain*> refDomains;
1915    while (!domain->hasTransformation() && domain->hasDirectDomainReference())
1916    {
1917      refDomains.push_back(domain);
1918      domain = domain->getDirectDomainReference();
1919    }
1920
1921    if (domain->hasTransformation())
1922      for (size_t i = 0; i < refDomains.size(); ++i)
1923        refDomains[i]->setTransformations(domain->getAllTransformations());
1924  }
1925
1926  /*!
1927    Parse children nodes of a domain in xml file.
1928    Whenver there is a new transformation, its type and name should be added into this function
1929    \param node child node to process
1930  */
1931  void CDomain::parse(xml::CXMLNode & node)
1932  {
1933    SuperClass::parse(node);
1934
1935    if (node.goToChildElement())
1936    {
1937      StdString zoomDomainDefRoot("zoom_domain_definition");
1938      StdString zoom("zoom_domain");
1939      StdString interpDomainDefRoot("interpolate_domain_definition");
1940      StdString interpFromFile("interpolate_domain");
1941      StdString generateRectilinearDefRoot("generate_rectilinear_domain_definition");
1942      StdString generateRectilinear("generate_rectilinear_domain");
1943      do
1944      {
1945        StdString nodeId("");
1946        if (node.getAttributes().end() != node.getAttributes().find("id"))
1947        { nodeId = node.getAttributes()["id"]; }
1948
1949        if (node.getElementName() == zoom) {
1950          CZoomDomain* tmp = (CZoomDomainGroup::get(zoomDomainDefRoot))->createChild(nodeId);
1951          tmp->parse(node);
1952          transformationMap_.push_back(std::make_pair(TRANS_ZOOM_DOMAIN,tmp));
1953        }
1954        else if (node.getElementName() == interpFromFile)
1955        {
1956          CInterpolateDomain* tmp = (CInterpolateDomainGroup::get(interpDomainDefRoot))->createChild(nodeId);
1957          tmp->parse(node);
1958          transformationMap_.push_back(std::make_pair(TRANS_INTERPOLATE_DOMAIN,tmp));
1959        }
1960        else if (node.getElementName() == generateRectilinear)
1961        {
1962          CGenerateRectilinearDomain* tmp = (CGenerateRectilinearDomainGroup::get(generateRectilinearDefRoot))->createChild(nodeId);
1963          tmp->parse(node);
1964          transformationMap_.push_back(std::make_pair(TRANS_GENERATE_RECTILINEAR_DOMAIN,tmp));
1965        }
1966      } while (node.goToNextElement()) ;
1967      node.goToParentElement();
1968    }
1969  }
1970   //----------------------------------------------------------------
1971
1972   DEFINE_REF_FUNC(Domain,domain)
1973
1974   ///---------------------------------------------------------------
1975
1976} // namespace xios
Note: See TracBrowser for help on using the repository browser.