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

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

Fixing bug: Ticket 98

+) Correct the way to distribute index of domain (axis) in case there are more
clients than number of index

Test
+) On Curie
+) Small grid (2x2x1) and 6 clients - 1 server: Pass

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