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

Last change on this file since 829 was 829, checked in by mhnguyen, 6 years ago

Refactoring transformation code

+) On exchanging information during transformation, not only global index are sent but also local index
+) Correct a bug in distributed hash table (dht)
+) Add new type for dht
+) Clean up some redundant codes

Test
+) On Curie
+) Every test passes
+) Code runs faster in some cases (up to 30%)

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