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

Last change on this file since 969 was 969, checked in by mhnguyen, 8 years ago

Ticket 111: Loosening the checking condition for domain with data_dim == 1

+) Validation of local domain distribution information not by domain type anymore
but by data_dim defined on this domain

Test
+) NO

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