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

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

Adding interface for expand_domain

  • 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.7 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   }
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)
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::unstructured)
618     {
619        if (ni_glo.isEmpty())
620        {
621          ERROR("CDomain::checkDomain(void)",
622                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
623                << "The global domain is badly defined, "
624                << "the mandatory 'ni_glo' attribute is missing.")
625        }
626        else if (ni_glo <= 0)
627        {
628          ERROR("CDomain::checkDomain(void)",
629                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
630                << "The global domain is badly defined, "
631                << "'ni_glo' attribute should be strictly positive so 'ni_glo = " << ni_glo.getValue() << "' is invalid.")
632        }
633        isUnstructed_ = true;
634        nj_glo = 1;
635        nj = 1;
636        jbegin = 0;
637        if (ni.isEmpty()) ni = i_index.numElements();
638        j_index.resize(ni);
639        for(int i=0;i<ni;++i) j_index(i)=0;
640
641        if (!area.isEmpty())
642          area.transposeSelf(1, 0);
643     }
644
645     if (ni_glo.isEmpty())
646     {
647       ERROR("CDomain::checkDomain(void)",
648             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
649             << "The global domain is badly defined, "
650             << "the mandatory 'ni_glo' attribute is missing.")
651     }
652     else if (ni_glo <= 0)
653     {
654       ERROR("CDomain::checkDomain(void)",
655             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
656             << "The global domain is badly defined, "
657             << "'ni_glo' attribute should be strictly positive so 'ni_glo = " << ni_glo.getValue() << "' is invalid.")
658     }
659
660     if (nj_glo.isEmpty())
661     {
662       ERROR("CDomain::checkDomain(void)",
663             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
664             << "The global domain is badly defined, "
665             << "the mandatory 'nj_glo' attribute is missing.")
666     }
667     else if (nj_glo <= 0)
668     {
669       ERROR("CDomain::checkDomain(void)",
670             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
671             << "The global domain is badly defined, "
672             << "'nj_glo' attribute should be strictly positive so 'nj_glo = " << nj_glo.getValue() << "' is invalid.")
673     }
674
675     isDistributed_ = !ibegin.isEmpty() || !ni.isEmpty() || !jbegin.isEmpty() || !nj.isEmpty();
676
677     checkLocalIDomain();
678     checkLocalJDomain();
679
680     if (i_index.isEmpty())
681     {
682       i_index.resize(ni*nj);
683       for (int j = 0; j < nj; ++j)
684         for (int i = 0; i < ni; ++i) i_index(i+j*ni) = i+ibegin;
685     }
686
687     if (j_index.isEmpty())
688     {
689       j_index.resize(ni*nj);
690       for (int j = 0; j < nj; ++j)
691         for (int i = 0; i < ni; ++i) j_index(i+j*ni) = j+jbegin;
692     }
693     computeNGlobDomain();
694     checkZoom();
695   }
696
697   void CDomain::checkZoom(void)
698   {
699     if (global_zoom_ibegin.isEmpty())
700      global_zoom_ibegin.setValue(0);
701     if (global_zoom_ni.isEmpty())
702      global_zoom_ni.setValue(ni_glo);
703     if (global_zoom_jbegin.isEmpty())
704      global_zoom_jbegin.setValue(0);
705     if (global_zoom_nj.isEmpty())
706      global_zoom_nj.setValue(nj_glo);
707   }
708
709   //----------------------------------------------------------------
710
711   void CDomain::checkLocalIDomain(void)
712   {
713      if (ibegin.isEmpty() && ni.isEmpty())
714      {
715        ibegin = 0;
716        ni = ni_glo;
717      }
718      else if (!i_index.isEmpty())
719      {
720        if (ibegin.isEmpty()) ibegin = i_index(0);
721      }
722
723      if (ni.getValue() < 0 || ibegin.getValue() < 0 ||
724         (ibegin.getValue() + ni.getValue()) > ni_glo.getValue())
725      {
726        ERROR("CDomain::checkLocalIDomain(void)",
727              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
728              << "The local domain is wrongly defined,"
729              << " check the attributes 'ni_glo' (" << ni_glo.getValue() << "), 'ni' (" << ni.getValue() << ") and 'ibegin' (" << ibegin.getValue() << ")");
730      }
731   }
732
733   void CDomain::checkLocalJDomain(void)
734   {
735     if (jbegin.isEmpty() && nj.isEmpty())
736     {
737       jbegin = 0;
738       nj = nj_glo;
739     }
740     else if (!j_index.isEmpty())
741     {
742       if (jbegin.isEmpty()) jbegin = j_index(0);
743     }
744
745      if (nj.getValue() < 0 || jbegin.getValue() < 0 ||
746         (jbegin.getValue() + nj.getValue()) > nj_glo.getValue())
747      {
748        ERROR("CDomain::checkLocalJDomain(void)",
749              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
750              << "The local domain is wrongly defined,"
751              << " check the attributes 'nj_glo' (" << nj_glo.getValue() << "), 'nj' (" << nj.getValue() << ") and 'jbegin' (" << jbegin.getValue() << ")");
752      }
753   }
754
755   //----------------------------------------------------------------
756
757   void CDomain::checkMask(void)
758   {
759      if (!mask_1d.isEmpty() && !mask_2d.isEmpty())
760        ERROR("CDomain::checkMask(void)",
761              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
762              << "Both mask_1d and mask_2d are defined but only one can be used at the same time." << std::endl
763              << "Please define only one mask: 'mask_1d' or 'mask_2d'.");
764
765      if (!mask_1d.isEmpty() && mask_2d.isEmpty())
766      {
767        if (mask_1d.numElements() != i_index.numElements())
768          ERROR("CDomain::checkMask(void)",
769                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
770                << "'mask_1d' does not have the same size as the local domain." << std::endl
771                << "Local size is " << i_index.numElements() << "." << std::endl
772                << "Mask size is " << mask_1d.numElements() << ".");
773      }
774
775      if (mask_1d.isEmpty() && !mask_2d.isEmpty())
776      {
777        if (mask_2d.extent(0) != ni || mask_2d.extent(1) != nj)
778          ERROR("CDomain::checkMask(void)",
779                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
780                << "The mask does not have the same size as the local domain." << std::endl
781                << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
782                << "Mask size is " << mask_2d.extent(0) << " x " << mask_2d.extent(1) << ".");
783      }
784
785      if (!mask_2d.isEmpty())
786      {
787        mask_1d.resize(mask_2d.extent(0) * mask_2d.extent(1));
788        for (int j = 0; j < nj; ++j)
789          for (int i = 0; i < ni; ++i) mask_1d(i+j*ni) = mask_2d(i,j);
790        mask_2d.reset();
791      }
792      else if (mask_1d.isEmpty())
793      {
794        mask_1d.resize(i_index.numElements());
795        for (int i = 0; i < i_index.numElements(); ++i) mask_1d(i) = true;
796      }
797   }
798
799   //----------------------------------------------------------------
800
801   void CDomain::checkDomainData(void)
802   {
803      if (data_dim.isEmpty())
804      {
805        data_dim.setValue(1);
806      }
807      else if (!(data_dim.getValue() == 1 || data_dim.getValue() == 2))
808      {
809        ERROR("CDomain::checkDomainData(void)",
810              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
811              << "The data dimension is invalid, 'data_dim' must be 1 or 2 not << " << data_dim.getValue() << ".");
812      }
813
814      if (data_ibegin.isEmpty())
815         data_ibegin.setValue(0);
816      if (data_jbegin.isEmpty())
817         data_jbegin.setValue(0);
818
819      if (data_ni.isEmpty())
820      {
821        data_ni.setValue((data_dim == 1) ? (ni.getValue() * nj.getValue()) : ni.getValue());
822      }
823      else if (data_ni.getValue() < 0)
824      {
825        ERROR("CDomain::checkDomainData(void)",
826              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
827              << "The data size cannot be negative ('data_ni' = " << data_ni.getValue() << ").");
828      }
829
830      if (data_nj.isEmpty())
831      {
832        data_nj.setValue((data_dim.getValue() == 1) ? (ni.getValue() * nj.getValue()) : nj.getValue());
833      }
834      else if (data_nj.getValue() < 0)
835      {
836        ERROR("CDomain::checkDomainData(void)",
837              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
838              << "The data size cannot be negative ('data_nj' = " << data_nj.getValue() << ").");
839      }
840   }
841
842   //----------------------------------------------------------------
843
844   void CDomain::checkCompression(void)
845   {
846      if (!data_i_index.isEmpty())
847      {
848        if (!data_j_index.isEmpty() &&
849            data_j_index.numElements() != data_i_index.numElements())
850        {
851           ERROR("CDomain::checkCompression(void)",
852                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
853                 << "'data_i_index' and 'data_j_index' arrays must have the same size." << std::endl
854                 << "'data_i_index' size = " << data_i_index.numElements() << std::endl
855                 << "'data_j_index' size = " << data_j_index.numElements());
856        }
857
858        if (2 == data_dim)
859        {
860          if (data_j_index.isEmpty())
861          {
862             ERROR("CDomain::checkCompression(void)",
863                   << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
864                   << "'data_j_index' must be defined when 'data_i_index' is set and 'data_dim' is 2.");
865          }
866        }
867        else // (1 == data_dim)
868        {
869          if (data_j_index.isEmpty())
870          {
871            data_j_index.resize(data_ni);
872            for (int j = 0; j < data_ni; ++j) data_j_index(j) = 0;
873          }
874        }
875      }
876      else
877      {
878        if (data_dim == 2 && !data_j_index.isEmpty())
879          ERROR("CDomain::checkCompression(void)",
880                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
881                << "'data_i_index' must be defined when 'data_j_index' is set and 'data_dim' is 2.");
882
883        if (1 == data_dim)
884        {
885          data_i_index.resize(data_ni);
886          data_j_index.resize(data_ni);
887
888          for (int i = 0; i < data_ni; ++i)
889          {
890            data_i_index(i) = i;
891            data_j_index(i) = 0;
892          }
893        }
894        else // (data_dim == 2)
895        {
896          const int dsize = data_ni * data_nj;
897          data_i_index.resize(dsize);
898          data_j_index.resize(dsize);
899
900          for(int count = 0, j = 0; j < data_nj; ++j)
901          {
902            for(int i = 0; i < data_ni; ++i, ++count)
903            {
904              data_i_index(count) = i;
905              data_j_index(count) = j;
906            }
907          }
908        }
909      }
910   }
911
912   //----------------------------------------------------------------
913   void CDomain::computeLocalMask(void)
914   {
915     localMask.resize(ni*nj) ;
916     localMask=false ;
917     size_t zoom_ibegin=global_zoom_ibegin ;
918     size_t zoom_iend=global_zoom_ibegin+global_zoom_ni-1 ;
919     size_t zoom_jbegin=global_zoom_jbegin ;
920     size_t zoom_jend=global_zoom_jbegin+global_zoom_nj-1 ;
921
922
923     size_t dn=data_i_index.numElements() ;
924     int i,j ;
925     size_t k,ind ;
926
927     for(k=0;k<dn;k++)
928     {
929       if (data_dim==2)
930       {
931          i=data_i_index(k)+data_ibegin ;
932          j=data_j_index(k)+data_jbegin ;
933       }
934       else
935       {
936          i=(data_i_index(k)+data_ibegin)%ni ;
937          j=(data_i_index(k)+data_ibegin)/ni ;
938       }
939
940       if (i>=0 && i<ni && j>=0 && j<nj)
941         if (i+ibegin>=zoom_ibegin && i+ibegin<=zoom_iend && j+jbegin>=zoom_jbegin && j+jbegin<=zoom_jend)
942         {
943           ind=i+ni*j ;
944           localMask(ind)=mask_1d(ind) ;
945         }
946     }
947   }
948
949
950
951
952
953
954
955   void CDomain::checkEligibilityForCompressedOutput(void)
956   {
957     // We don't check if the mask or the indexes are valid here, just if they have been defined at this point.
958     isCompressible_ = !mask_1d.isEmpty() || !mask_2d.isEmpty() || !data_i_index.isEmpty();
959   }
960
961   //----------------------------------------------------------------
962
963   void CDomain::completeLonLatClient(void)
964   {
965     if (!lonvalue_2d.isEmpty())
966     {
967       lonvalue_client.resize(ni * nj);
968       latvalue_client.resize(ni * nj);
969       if (hasBounds)
970       {
971         bounds_lon_client.resize(nvertex, ni * nj);
972         bounds_lat_client.resize(nvertex, ni * nj);
973       }
974
975       for (int j = 0; j < nj; ++j)
976       {
977         for (int i = 0; i < ni; ++i)
978         {
979           int k = j * ni + i;
980
981           lonvalue_client(k) = lonvalue_2d(i,j);
982           latvalue_client(k) = latvalue_2d(i,j);
983
984           if (hasBounds)
985           {
986             for (int n = 0; n < nvertex; ++n)
987             {
988               bounds_lon_client(n,k) = bounds_lon_2d(n,i,j);
989               bounds_lat_client(n,k) = bounds_lat_2d(n,i,j);
990             }
991           }
992         }
993       }
994     }
995     else if (!lonvalue_1d.isEmpty())
996     {
997       if (type_attr::rectilinear == type)
998       {
999         if (ni == lonvalue_1d.numElements() && nj == latvalue_1d.numElements())
1000         {
1001           lonvalue_client.resize(ni * nj);
1002           latvalue_client.resize(ni * nj);
1003           if (hasBounds)
1004           {
1005             bounds_lon_client.resize(nvertex, ni * nj);
1006             bounds_lat_client.resize(nvertex, ni * nj);
1007           }
1008
1009           for (int j = 0; j < nj; ++j)
1010           {
1011             for (int i = 0; i < ni; ++i)
1012             {
1013               int k = j * ni + i;
1014
1015               lonvalue_client(k) = lonvalue_1d(i);
1016               latvalue_client(k) = latvalue_1d(j);
1017
1018               if (hasBounds)
1019               {
1020                 for (int n = 0; n < nvertex; ++n)
1021                 {
1022                   bounds_lon_client(n,k) = bounds_lon_1d(n,i);
1023                   bounds_lat_client(n,k) = bounds_lat_1d(n,j);
1024                 }
1025               }
1026             }
1027           }
1028         }
1029         else
1030           ERROR("CDomain::completeLonClient(void)",
1031                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1032                 << "'lonvalue_1d' and 'latvalue_1d' does not have the same size as the local domain." << std::endl
1033                 << "'lonvalue_1d' size is " << lonvalue_1d.numElements() << " but it should be " << ni.getValue() << '.' << std::endl
1034                 << "'latvalue_1d' size is " << latvalue_1d.numElements() << " but it should be " << nj.getValue() << '.');
1035       }
1036       else if (type == type_attr::curvilinear || type == type_attr::unstructured)
1037       {
1038         lonvalue_client.reference(lonvalue_1d);
1039         latvalue_client.reference(latvalue_1d);
1040         if (hasBounds)
1041         {
1042           bounds_lon_client.reference(bounds_lon_1d);
1043           bounds_lat_client.reference(bounds_lat_1d);
1044         }
1045       }
1046     }
1047   }
1048
1049   void CDomain::checkBounds(void)
1050   {
1051     if (!nvertex.isEmpty() && nvertex > 0)
1052     {
1053       if (!bounds_lon_1d.isEmpty() && !bounds_lon_2d.isEmpty())
1054         ERROR("CDomain::checkBounds(void)",
1055               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1056               << "Only one longitude boundary attribute can be used but both 'bounds_lon_1d' and 'bounds_lon_2d' are defined." << std::endl
1057               << "Define only one longitude boundary attribute: 'bounds_lon_1d' or 'bounds_lon_2d'.");
1058
1059       if (!bounds_lat_1d.isEmpty() && !bounds_lat_2d.isEmpty())
1060         ERROR("CDomain::checkBounds(void)",
1061               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1062               << "Only one latitude boundary attribute can be used but both 'bounds_lat_1d' and 'bounds_lat_2d' are defined." << std::endl
1063               << "Define only one latitude boundary attribute: 'bounds_lat_1d' or 'bounds_lat_2d'.");
1064
1065       if ((!bounds_lon_1d.isEmpty() && bounds_lat_1d.isEmpty()) || (bounds_lon_1d.isEmpty() && !bounds_lat_1d.isEmpty()))
1066       {
1067         ERROR("CDomain::checkBounds(void)",
1068               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1069               << "Only 'bounds_lon_1d' or 'bounds_lat_1d' is defined." << std::endl
1070               << "Please define either both attributes or none.");
1071       }
1072
1073       if ((!bounds_lon_2d.isEmpty() && bounds_lat_2d.isEmpty()) || (bounds_lon_2d.isEmpty() && !bounds_lat_2d.isEmpty()))
1074       {
1075         ERROR("CDomain::checkBounds(void)",
1076               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1077               << "Only 'bounds_lon_2d' or 'bounds_lat_2d' is defined." << std::endl
1078               << "Please define either both attributes or none.");
1079       }
1080
1081       if (!bounds_lon_1d.isEmpty() && nvertex.getValue() != bounds_lon_1d.extent(0))
1082         ERROR("CDomain::checkBounds(void)",
1083               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1084               << "'bounds_lon_1d' dimension is not compatible with 'nvertex'." << std::endl
1085               << "'bounds_lon_1d' dimension is " << bounds_lon_1d.extent(1)
1086               << " but nvertex is " << nvertex.getValue() << ".");
1087
1088       if (!bounds_lon_2d.isEmpty() && nvertex.getValue() != bounds_lon_2d.extent(0))
1089         ERROR("CDomain::checkBounds(void)",
1090               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1091               << "'bounds_lon_2d' dimension is not compatible with 'nvertex'." << std::endl
1092               << "'bounds_lon_2d' dimension is " << bounds_lon_2d.extent(2)
1093               << " but nvertex is " << nvertex.getValue() << ".");
1094
1095       if (!bounds_lon_1d.isEmpty() && lonvalue_1d.isEmpty())
1096         ERROR("CDomain::checkBounds(void)",
1097               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1098               << "Since 'bounds_lon_1d' is defined, 'lonvalue_1d' must be defined too." << std::endl);
1099
1100       if (!bounds_lon_2d.isEmpty() && lonvalue_2d.isEmpty())
1101         ERROR("CDomain::checkBounds(void)",
1102               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1103               << "Since 'bounds_lon_2d' is defined, 'lonvalue_2d' must be defined too." << std::endl);
1104
1105       if (!bounds_lat_1d.isEmpty() && nvertex.getValue() != bounds_lat_1d.extent(0))
1106         ERROR("CDomain::checkBounds(void)",
1107               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1108               << "'bounds_lat_1d' dimension is not compatible with 'nvertex'." << std::endl
1109               << "'bounds_lat_1d' dimension is " << bounds_lat_1d.extent(1)
1110               << " but nvertex is " << nvertex.getValue() << ".");
1111
1112       if (!bounds_lat_2d.isEmpty() && nvertex.getValue() != bounds_lat_2d.extent(0))
1113         ERROR("CDomain::checkBounds(void)",
1114               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1115               << "'bounds_lat_2d' dimension is not compatible with 'nvertex'." << std::endl
1116               << "'bounds_lat_2d' dimension is " << bounds_lat_2d.extent(2)
1117               << " but nvertex is " << nvertex.getValue() << ".");
1118
1119       if (!bounds_lat_1d.isEmpty() && latvalue_1d.isEmpty())
1120         ERROR("CDomain::checkBounds(void)",
1121               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1122               << "Since 'bounds_lat_1d' is defined, 'latvalue_1d' must be defined too." << std::endl);
1123
1124       if (!bounds_lat_2d.isEmpty() && latvalue_2d.isEmpty())
1125         ERROR("CDomain::checkBounds(void)",
1126               << "Since 'bounds_lat_2d' is defined, 'latvalue_2d' must be defined too." << std::endl);
1127
1128       hasBounds = true;
1129     }
1130     else
1131     {
1132       hasBounds = false;
1133       nvertex = 0;
1134     }
1135   }
1136
1137   void CDomain::checkArea(void)
1138   {
1139     hasArea = !area.isEmpty();
1140     if (hasArea)
1141     {
1142       if (area.extent(0) != ni || area.extent(1) != nj)
1143       {
1144         ERROR("CDomain::checkArea(void)",
1145               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1146               << "The area does not have the same size as the local domain." << std::endl
1147               << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1148               << "Area size is " << area.extent(0) << " x " << area.extent(1) << ".");
1149       }
1150     }
1151   }
1152
1153   void CDomain::checkLonLat()
1154   {
1155     hasLonLat = (!latvalue_1d.isEmpty() && !lonvalue_1d.isEmpty()) ||
1156                 (!latvalue_2d.isEmpty() && !lonvalue_2d.isEmpty());
1157     if (hasLonLat)
1158     {
1159       if (!lonvalue_1d.isEmpty() && !lonvalue_2d.isEmpty())
1160         ERROR("CDomain::checkLonLat()",
1161               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1162               << "Only one longitude attribute can be used but both 'lonvalue_1d' and 'lonvalue_2d' are defined." << std::endl
1163               << "Define only one longitude attribute: 'lonvalue_1d' or 'lonvalue_2d'.");
1164
1165       if (!lonvalue_1d.isEmpty() && lonvalue_2d.isEmpty())
1166       {
1167         if ((type_attr::rectilinear != type) && (lonvalue_1d.numElements() != i_index.numElements()))
1168           ERROR("CDomain::checkLonLat()",
1169                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1170                 << "'lonvalue_1d' does not have the same size as the local domain." << std::endl
1171                 << "Local size is " << i_index.numElements() << "." << std::endl
1172                 << "'lonvalue_1d' size is " << lonvalue_1d.numElements() << ".");
1173       }
1174
1175       if (lonvalue_1d.isEmpty() && !lonvalue_2d.isEmpty())
1176       {
1177         if (lonvalue_2d.extent(0) != ni || lonvalue_2d.extent(1) != nj)
1178           ERROR("CDomain::checkLonLat()",
1179                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1180                 << "'lonvalue_2d' does not have the same size as the local domain." << std::endl
1181                 << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1182                 << "'lonvalue_2d' size is " << lonvalue_2d.extent(0) << " x " << lonvalue_2d.extent(1) << ".");
1183       }
1184
1185       if (!latvalue_1d.isEmpty() && !latvalue_2d.isEmpty())
1186         ERROR("CDomain::checkLonLat()",
1187               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1188               << "Only one latitude attribute can be used but both 'latvalue_1d' and 'latvalue_2d' are defined." << std::endl
1189               << "Define only one latitude attribute: 'latvalue_1d' or 'latvalue_2d'.");
1190
1191       if (!latvalue_1d.isEmpty() && latvalue_2d.isEmpty())
1192       {
1193         if ((type_attr::rectilinear != type) && (latvalue_1d.numElements() != i_index.numElements()))
1194           ERROR("CDomain::checkLonLat()",
1195                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1196                 << "'latvalue_1d' does not have the same size as the local domain." << std::endl
1197                 << "Local size is " << i_index.numElements() << "." << std::endl
1198                 << "'latvalue_1d' size is " << latvalue_1d.numElements() << ".");
1199       }
1200
1201       if (latvalue_1d.isEmpty() && !latvalue_2d.isEmpty())
1202       {
1203         if (latvalue_2d.extent(0) != ni || latvalue_2d.extent(1) != nj)
1204           ERROR("CDomain::checkLonLat()",
1205                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1206                 << "'latvalue_2d' does not have the same size as the local domain." << std::endl
1207                 << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1208                 << "'latvalue_2d' size is " << latvalue_2d.extent(0) << " x " << latvalue_2d.extent(1) << ".");
1209       }
1210     }
1211   }
1212
1213   void CDomain::checkAttributesOnClientAfterTransformation()
1214   {
1215     CContext* context=CContext::getCurrent() ;
1216
1217     if (this->isClientAfterTransformationChecked) return;
1218     if (context->hasClient)
1219     {
1220       this->checkMask();
1221       if (hasLonLat || hasArea || isCompressible_) this->computeConnectedServer();
1222       if (hasLonLat) this->completeLonLatClient();
1223     }
1224
1225     this->isClientAfterTransformationChecked = true;
1226   }
1227
1228   //----------------------------------------------------------------
1229   // Divide function checkAttributes into 2 seperate ones
1230   // This function only checks all attributes of current domain
1231   void CDomain::checkAttributesOnClient()
1232   {
1233     if (this->isClientChecked) return;
1234     CContext* context=CContext::getCurrent();
1235
1236      this->checkDomain();
1237      this->checkBounds();
1238      this->checkArea();
1239      this->checkLonLat();
1240
1241      if (context->hasClient)
1242      { // CÃŽté client uniquement
1243         this->checkMask();
1244         this->checkDomainData();
1245         this->checkCompression();
1246         this->computeLocalMask() ;
1247      }
1248      else
1249      { // CÃŽté serveur uniquement
1250      }
1251
1252      this->isClientChecked = true;
1253   }
1254
1255   // Send all checked attributes to server
1256   void CDomain::sendCheckedAttributes()
1257   {
1258     if (!this->isClientChecked) checkAttributesOnClient();
1259     if (!this->isClientAfterTransformationChecked) checkAttributesOnClientAfterTransformation();
1260     CContext* context=CContext::getCurrent() ;
1261
1262     if (this->isChecked) return;
1263     if (context->hasClient)
1264     {
1265       sendServerAttribut();
1266       if (hasLonLat || hasArea || isCompressible_) sendLonLatArea();
1267     }
1268     this->isChecked = true;
1269   }
1270
1271   void CDomain::checkAttributes(void)
1272   {
1273      if (this->isChecked) return;
1274      CContext* context=CContext::getCurrent() ;
1275
1276      this->checkDomain();
1277      this->checkLonLat();
1278      this->checkBounds();
1279      this->checkArea();
1280
1281      if (context->hasClient)
1282      { // CÃŽté client uniquement
1283         this->checkMask();
1284         this->checkDomainData();
1285         this->checkCompression();
1286         this->computeLocalMask() ;
1287
1288      }
1289      else
1290      { // CÃŽté serveur uniquement
1291      }
1292
1293      if (context->hasClient)
1294      {
1295        this->computeConnectedServer();
1296        this->completeLonLatClient();
1297        this->sendServerAttribut();
1298        this->sendLonLatArea();
1299      }
1300
1301      this->isChecked = true;
1302   }
1303
1304  void CDomain::sendServerAttribut(void)
1305  {
1306    CContext* context = CContext::getCurrent();
1307    CContextClient* client = context->client;
1308    int nbServer = client->serverSize;
1309
1310    CServerDistributionDescription serverDescription(nGlobDomain_, nbServer);
1311    if (isUnstructed_) serverDescription.computeServerDistribution(false, 0);
1312    else serverDescription.computeServerDistribution(false, 1);
1313
1314    std::vector<std::vector<int> > serverIndexBegin = serverDescription.getServerIndexBegin();
1315    std::vector<std::vector<int> > serverDimensionSizes = serverDescription.getServerDimensionSizes();
1316
1317    CEventClient event(getType(),EVENT_ID_SERVER_ATTRIBUT);
1318    if (client->isServerLeader())
1319    {
1320      std::list<CMessage> msgs;
1321
1322      const std::list<int>& ranks = client->getRanksServerLeader();
1323      for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1324      {
1325        // Use const int to ensure CMessage holds a copy of the value instead of just a reference
1326        const int ibegin_srv = serverIndexBegin[*itRank][0];
1327        const int jbegin_srv = serverIndexBegin[*itRank][1];
1328        const int ni_srv = serverDimensionSizes[*itRank][0];
1329        const int nj_srv = serverDimensionSizes[*itRank][1];
1330        const int iend_srv = ibegin_srv + ni_srv - 1;
1331        const int jend_srv = jbegin_srv + nj_srv - 1;
1332
1333        msgs.push_back(CMessage());
1334        CMessage& msg = msgs.back();
1335        msg << this->getId() ;
1336        msg << ni_srv << ibegin_srv << iend_srv << nj_srv << jbegin_srv << jend_srv;
1337        msg << global_zoom_ni.getValue() << global_zoom_ibegin.getValue() << global_zoom_nj.getValue() << global_zoom_jbegin.getValue();
1338        msg << isCompressible_;
1339
1340        event.push(*itRank,1,msg);
1341      }
1342      client->sendEvent(event);
1343    }
1344    else client->sendEvent(event);
1345  }
1346
1347  void CDomain::computeNGlobDomain()
1348  {
1349    nGlobDomain_.resize(2);
1350    nGlobDomain_[0] = ni_glo.getValue();
1351    nGlobDomain_[1] = nj_glo.getValue();
1352  }
1353
1354  void CDomain::computeConnectedServer(void)
1355  {
1356    CContext* context=CContext::getCurrent() ;
1357    CContextClient* client=context->client ;
1358    int nbServer=client->serverSize;
1359    int rank = client->clientRank;
1360    bool doComputeGlobalIndexServer = true;
1361
1362    int i,j,i_ind,j_ind, nbIndex;
1363    int global_zoom_iend=global_zoom_ibegin+global_zoom_ni-1 ;
1364    int global_zoom_jend=global_zoom_jbegin+global_zoom_nj-1 ;
1365
1366    // Precompute number of index
1367    int globalIndexCountZoom = 0;
1368    nbIndex = i_index.numElements();
1369    for (i = 0; i < nbIndex; ++i)
1370    {
1371      i_ind=i_index(i);
1372      j_ind=j_index(i);
1373
1374      if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1375      {
1376        ++globalIndexCountZoom;
1377      }
1378    }
1379
1380    int globalIndexWrittenCount = 0;
1381    if (isCompressible_)
1382    {
1383      for (i = 0; i < data_i_index.numElements(); ++i)
1384      {
1385        i_ind = CDistributionClient::getDomainIndex(data_i_index(i), data_j_index(i),
1386                                                    data_ibegin, data_jbegin, data_dim, ni,
1387                                                    j_ind);
1388        if (i_ind >= 0 && i_ind < ni && j_ind >= 0 && j_ind < nj && mask_1d(i_ind + j_ind * ni))
1389        {
1390          i_ind += ibegin;
1391          j_ind += jbegin;
1392          if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1393            ++globalIndexWrittenCount;
1394        }
1395      }
1396    }
1397
1398    // Fill in index
1399    CArray<size_t,1> globalIndexDomainZoom(globalIndexCountZoom);
1400    CArray<size_t,1> localIndexDomainZoom(globalIndexCountZoom);
1401    CArray<size_t,1> globalIndexDomain(nbIndex);
1402    size_t globalIndex;
1403    int globalIndexCount = 0;
1404    globalIndexCountZoom = 0;
1405
1406    for (i = 0; i < nbIndex; ++i)
1407    {
1408      i_ind=i_index(i);
1409      j_ind=j_index(i);
1410      globalIndex = i_ind + j_ind * ni_glo;
1411      globalIndexDomain(globalIndexCount) = globalIndex;
1412      ++globalIndexCount;
1413      if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1414      {
1415        globalIndexDomainZoom(globalIndexCountZoom) = globalIndex;
1416        localIndexDomainZoom(globalIndexCountZoom) = i;
1417        ++globalIndexCountZoom;
1418      }
1419    }
1420
1421    CArray<int,1> globalIndexWrittenDomain(globalIndexWrittenCount);
1422    if (isCompressible_)
1423    {
1424      globalIndexWrittenCount = 0;
1425      for (i = 0; i < data_i_index.numElements(); ++i)
1426      {
1427        i_ind = CDistributionClient::getDomainIndex(data_i_index(i), data_j_index(i),
1428                                                    data_ibegin, data_jbegin, data_dim, ni,
1429                                                    j_ind);
1430        if (i_ind >= 0 && i_ind < ni && j_ind >= 0 && j_ind < nj && mask_1d(i_ind + j_ind * ni))
1431        {
1432          i_ind += ibegin;
1433          j_ind += jbegin;
1434          if (i_ind >= global_zoom_ibegin && i_ind <= global_zoom_iend && j_ind >= global_zoom_jbegin && j_ind <= global_zoom_jend)
1435          {
1436            globalIndexWrittenDomain(globalIndexWrittenCount) = i_ind + j_ind * ni_glo;
1437            ++globalIndexWrittenCount;
1438          }
1439        }
1440      }
1441    }
1442
1443    size_t globalSizeIndex = 1, indexBegin, indexEnd;
1444    int range, clientSize = client->clientSize;
1445    for (int i = 0; i < nGlobDomain_.size(); ++i) globalSizeIndex *= nGlobDomain_[i];
1446    indexBegin = 0;
1447    if (globalSizeIndex <= clientSize)
1448    {
1449      indexBegin = rank%globalSizeIndex;
1450      indexEnd = indexBegin;
1451    }
1452    else
1453    {
1454      for (int i = 0; i < clientSize; ++i)
1455      {
1456        range = globalSizeIndex / clientSize;
1457        if (i < (globalSizeIndex%clientSize)) ++range;
1458        if (i == client->clientRank) break;
1459        indexBegin += range;
1460      }
1461      indexEnd = indexBegin + range - 1;
1462    }
1463
1464    CServerDistributionDescription serverDescription(nGlobDomain_, nbServer);
1465    if (isUnstructed_) serverDescription.computeServerGlobalIndexInRange(std::make_pair<size_t,size_t>(indexBegin, indexEnd), 0);
1466    else serverDescription.computeServerGlobalIndexInRange(std::make_pair<size_t,size_t>(indexBegin, indexEnd), 1);
1467
1468    CClientServerMapping* clientServerMap = new CClientServerMappingDistributed(serverDescription.getGlobalIndexRange(),
1469                                                                                client->intraComm);
1470    clientServerMap->computeServerIndexMapping(globalIndexDomain);
1471    const CClientServerMapping::GlobalIndexMap& globalIndexDomainOnServer = clientServerMap->getGlobalIndexOnServer();
1472
1473    CClientServerMapping::GlobalIndexMap::const_iterator it  = globalIndexDomainOnServer.begin(),
1474                                                         ite = globalIndexDomainOnServer.end();
1475    typedef XIOSBinarySearchWithIndex<size_t> BinarySearch;
1476    std::vector<int>::iterator itVec;
1477
1478    indSrv_.clear();
1479    indWrittenSrv_.clear();
1480    for (; it != ite; ++it)
1481    {
1482      int rank = it->first;
1483      int indexSize = it->second.size();
1484      std::vector<int> permutIndex(indexSize);
1485      XIOSAlgorithms::fillInIndex(indexSize, permutIndex);
1486      XIOSAlgorithms::sortWithIndex<size_t, CVectorStorage>(it->second, permutIndex);
1487      BinarySearch binSearch(it->second);
1488      int nb = globalIndexDomainZoom.numElements();
1489      for (int i = 0; i < nb; ++i)
1490      {
1491        if (binSearch.search(permutIndex.begin(), permutIndex.end(), globalIndexDomainZoom(i), itVec))
1492        {
1493          indSrv_[rank].push_back(localIndexDomainZoom(i));
1494        }
1495      }
1496      for (int i = 0; i < globalIndexWrittenDomain.numElements(); ++i)
1497      {
1498        if (binSearch.search(permutIndex.begin(), permutIndex.end(), globalIndexWrittenDomain(i), itVec))
1499        {
1500          indWrittenSrv_[rank].push_back(globalIndexWrittenDomain(i));
1501        }
1502      }
1503    }
1504
1505    connectedServerRank_.clear();
1506    for (it = globalIndexDomainOnServer.begin(); it != ite; ++it) {
1507      connectedServerRank_.push_back(it->first);
1508    }
1509
1510    nbConnectedClients_ = clientServerMap->computeConnectedClients(client->serverSize, client->clientSize, client->intraComm, connectedServerRank_);
1511
1512    delete clientServerMap;
1513  }
1514
1515  const std::map<int, vector<size_t> >& CDomain::getIndexServer() const
1516  {
1517    return indSrv_;
1518  }
1519
1520  /*!
1521    Send index from client to server(s)
1522  */
1523  void CDomain::sendIndex()
1524  {
1525    int ns, n, i, j, ind, nv, idx;
1526    CContext* context = CContext::getCurrent();
1527    CContextClient* client=context->client;
1528
1529    CEventClient eventIndex(getType(), EVENT_ID_INDEX);
1530
1531    list<CMessage> list_msgsIndex;
1532    list<CArray<int,1> > list_indi, list_indj, list_writtenInd;
1533
1534    std::map<int, std::vector<size_t> >::const_iterator it, iteMap;
1535    iteMap = indSrv_.end();
1536    for (int k = 0; k < connectedServerRank_.size(); ++k)
1537    {
1538      int nbData = 0;
1539      int rank = connectedServerRank_[k];
1540      it = indSrv_.find(rank);
1541      if (iteMap != it)
1542        nbData = it->second.size();
1543
1544      list_indi.push_back(CArray<int,1>(nbData));
1545      list_indj.push_back(CArray<int,1>(nbData));
1546
1547      CArray<int,1>& indi = list_indi.back();
1548      CArray<int,1>& indj = list_indj.back();
1549      const std::vector<size_t>& temp = it->second;
1550      for (n = 0; n < nbData; ++n)
1551      {
1552        idx = static_cast<int>(it->second[n]);
1553        indi(n) = i_index(idx);
1554        indj(n) = j_index(idx);
1555      }
1556
1557      list_msgsIndex.push_back(CMessage());
1558
1559      list_msgsIndex.back() << this->getId() << (int)type; // enum ne fonctionne pour les message => ToFix
1560      list_msgsIndex.back() << isCurvilinear;
1561      list_msgsIndex.back() << list_indi.back() << list_indj.back();
1562
1563      if (isCompressible_)
1564      {
1565        std::vector<int>& writtenIndSrc = indWrittenSrv_[rank];
1566        list_writtenInd.push_back(CArray<int,1>(writtenIndSrc.size()));
1567        CArray<int,1>& writtenInd = list_writtenInd.back();
1568
1569        for (n = 0; n < writtenInd.numElements(); ++n)
1570          writtenInd(n) = writtenIndSrc[n];
1571
1572        list_msgsIndex.back() << writtenInd;
1573      }
1574
1575      eventIndex.push(rank, nbConnectedClients_[rank], list_msgsIndex.back());
1576    }
1577
1578    client->sendEvent(eventIndex);
1579  }
1580
1581  /*!
1582    Send area from client to server(s)
1583  */
1584  void CDomain::sendArea()
1585  {
1586    if (!hasArea) return;
1587
1588    int ns, n, i, j, ind, nv, idx;
1589    CContext* context = CContext::getCurrent();
1590    CContextClient* client=context->client;
1591
1592    // send area for each connected server
1593    CEventClient eventArea(getType(), EVENT_ID_AREA);
1594
1595    list<CMessage> list_msgsArea;
1596    list<CArray<double,1> > list_area;
1597
1598    std::map<int, std::vector<size_t> >::const_iterator it, iteMap;
1599    iteMap = indSrv_.end();
1600    for (int k = 0; k < connectedServerRank_.size(); ++k)
1601    {
1602      int nbData = 0;
1603      int rank = connectedServerRank_[k];
1604      it = indSrv_.find(rank);
1605      if (iteMap != it)
1606        nbData = it->second.size();
1607      list_area.push_back(CArray<double,1>(nbData));
1608
1609      const std::vector<size_t>& temp = it->second;
1610      for (n = 0; n < nbData; ++n)
1611      {
1612        idx = static_cast<int>(it->second[n]);
1613        i = i_index(idx);
1614        j = j_index(idx);
1615        if (hasArea)
1616          list_area.back()(n) = area(i - ibegin, j - jbegin);
1617      }
1618
1619      list_msgsArea.push_back(CMessage());
1620      list_msgsArea.back() << this->getId() << list_area.back();
1621      eventArea.push(rank, nbConnectedClients_[rank], list_msgsArea.back());
1622    }
1623    client->sendEvent(eventArea);
1624  }
1625
1626  /*!
1627    Send longitude and latitude from client to servers
1628    Each client send long and lat information to corresponding connected server(s).
1629    Because longitude and latitude are optional, this function only called if latitude and longitude exist
1630  */
1631  void CDomain::sendLonLat()
1632  {
1633    if (!hasLonLat) return;
1634
1635    int ns, n, i, j, ind, nv, idx;
1636    CContext* context = CContext::getCurrent();
1637    CContextClient* client=context->client;
1638
1639    // send lon lat for each connected server
1640    CEventClient eventLon(getType(), EVENT_ID_LON);
1641    CEventClient eventLat(getType(), EVENT_ID_LAT);
1642
1643    list<CMessage> list_msgsLon, list_msgsLat;
1644    list<CArray<double,1> > list_lon, list_lat;
1645    list<CArray<double,2> > list_boundslon, list_boundslat;
1646
1647    std::map<int, std::vector<size_t> >::const_iterator it, iteMap;
1648    iteMap = indSrv_.end();
1649    for (int k = 0; k < connectedServerRank_.size(); ++k)
1650    {
1651      int nbData = 0;
1652      int rank = connectedServerRank_[k];
1653      it = indSrv_.find(rank);
1654      if (iteMap != it)
1655        nbData = it->second.size();
1656
1657      list_lon.push_back(CArray<double,1>(nbData));
1658      list_lat.push_back(CArray<double,1>(nbData));
1659
1660      if (hasBounds)
1661      {
1662        list_boundslon.push_back(CArray<double,2>(nvertex, nbData));
1663        list_boundslat.push_back(CArray<double,2>(nvertex, nbData));
1664      }
1665
1666      CArray<double,1>& lon = list_lon.back();
1667      CArray<double,1>& lat = list_lat.back();
1668      const std::vector<size_t>& temp = it->second;
1669      for (n = 0; n < nbData; ++n)
1670      {
1671        idx = static_cast<int>(it->second[n]);
1672        lon(n) = lonvalue_client(idx);
1673        lat(n) = latvalue_client(idx);
1674
1675        if (hasBounds)
1676        {
1677          CArray<double,2>& boundslon = list_boundslon.back();
1678          CArray<double,2>& boundslat = list_boundslat.back();
1679
1680          for (nv = 0; nv < nvertex; ++nv)
1681          {
1682            boundslon(nv, n) = bounds_lon_client(nv, idx);
1683            boundslat(nv, n) = bounds_lat_client(nv, idx);
1684          }
1685        }
1686      }
1687
1688      list_msgsLon.push_back(CMessage());
1689      list_msgsLat.push_back(CMessage());
1690
1691      list_msgsLon.back() << this->getId() << list_lon.back();
1692      list_msgsLat.back() << this->getId() << list_lat.back();
1693
1694      if (hasBounds)
1695      {
1696        list_msgsLon.back() << list_boundslon.back();
1697        list_msgsLat.back() << list_boundslat.back();
1698      }
1699
1700      eventLon.push(rank, nbConnectedClients_[rank], list_msgsLon.back());
1701      eventLat.push(rank, nbConnectedClients_[rank], list_msgsLat.back());
1702    }
1703
1704    client->sendEvent(eventLon);
1705    client->sendEvent(eventLat);
1706  }
1707
1708  /*!
1709    Send some optional information to server(s)
1710    In the future, this function can be extended with more optional information to send
1711  */
1712  void CDomain::sendLonLatArea(void)
1713  {
1714    sendIndex();
1715    sendLonLat();
1716    sendArea();
1717  }
1718
1719  bool CDomain::dispatchEvent(CEventServer& event)
1720  {
1721    if (SuperClass::dispatchEvent(event)) return true;
1722    else
1723    {
1724      switch(event.type)
1725      {
1726        case EVENT_ID_SERVER_ATTRIBUT:
1727          recvServerAttribut(event);
1728          return true;
1729          break;
1730        case EVENT_ID_INDEX:
1731          recvIndex(event);
1732          return true;
1733          break;
1734        case EVENT_ID_LON:
1735          recvLon(event);
1736          return true;
1737          break;
1738        case EVENT_ID_LAT:
1739          recvLat(event);
1740          return true;
1741          break;
1742        case EVENT_ID_AREA:
1743          recvArea(event);
1744          return true;
1745          break;
1746        default:
1747          ERROR("bool CDomain::dispatchEvent(CEventServer& event)",
1748                << "Unknown Event");
1749          return false;
1750       }
1751    }
1752  }
1753
1754  /*!
1755    Receive attributes event from clients(s)
1756    \param[in] event event contain info about rank and associated attributes
1757  */
1758  void CDomain::recvServerAttribut(CEventServer& event)
1759  {
1760    CBufferIn* buffer=event.subEvents.begin()->buffer;
1761    string domainId ;
1762    *buffer>>domainId ;
1763    get(domainId)->recvServerAttribut(*buffer) ;
1764  }
1765
1766  /*!
1767    Receive attributes from client(s): zoom info and begin and n of each server
1768    \param[in] rank rank of client source
1769    \param[in] buffer message containing attributes info
1770  */
1771  void CDomain::recvServerAttribut(CBufferIn& buffer)
1772  {
1773    int global_zoom_ni_tmp, global_zoom_ibegin_tmp, global_zoom_nj_tmp, global_zoom_jbegin_tmp;
1774    buffer >> ni_srv >> ibegin_srv >> iend_srv >> nj_srv >> jbegin_srv >> jend_srv
1775           >> global_zoom_ni_tmp >> global_zoom_ibegin_tmp >> global_zoom_nj_tmp >> global_zoom_jbegin_tmp
1776           >> isCompressible_;
1777
1778    global_zoom_ni.setValue(global_zoom_ni_tmp);
1779    global_zoom_ibegin.setValue(global_zoom_ibegin_tmp);
1780    global_zoom_nj.setValue(global_zoom_nj_tmp);
1781    global_zoom_jbegin.setValue(global_zoom_jbegin_tmp);
1782
1783    int zoom_iend = global_zoom_ibegin + global_zoom_ni - 1;
1784    int zoom_jend = global_zoom_jbegin + global_zoom_nj - 1;
1785
1786    zoom_ibegin_srv = global_zoom_ibegin > ibegin_srv ? global_zoom_ibegin : ibegin_srv ;
1787    zoom_iend_srv = zoom_iend < iend_srv ? zoom_iend : iend_srv ;
1788    zoom_ni_srv=zoom_iend_srv-zoom_ibegin_srv+1 ;
1789
1790    zoom_jbegin_srv = global_zoom_jbegin > jbegin_srv ? global_zoom_jbegin : jbegin_srv ;
1791    zoom_jend_srv = zoom_jend < jend_srv ? zoom_jend : jend_srv ;
1792    zoom_nj_srv=zoom_jend_srv-zoom_jbegin_srv+1 ;
1793
1794    if (zoom_ni_srv<=0 || zoom_nj_srv<=0)
1795    {
1796      zoom_ibegin_srv=0 ; zoom_iend_srv=0 ; zoom_ni_srv=0 ;
1797      zoom_jbegin_srv=0 ; zoom_jend_srv=0 ; zoom_nj_srv=0 ;
1798    }
1799    lonvalue_srv.resize(zoom_ni_srv*zoom_nj_srv) ;
1800    lonvalue_srv = 0. ;
1801    latvalue_srv.resize(zoom_ni_srv*zoom_nj_srv) ;
1802    latvalue_srv = 0. ;
1803    if (hasBounds)
1804    {
1805      bounds_lon_srv.resize(nvertex,zoom_ni_srv*zoom_nj_srv) ;
1806      bounds_lon_srv = 0. ;
1807      bounds_lat_srv.resize(nvertex,zoom_ni_srv*zoom_nj_srv) ;
1808      bounds_lat_srv = 0. ;
1809    }
1810
1811    if (hasArea)
1812    {
1813      area_srv.resize(zoom_ni_srv * zoom_nj_srv);
1814      area_srv = 0.;
1815    }
1816
1817  }
1818
1819  /*!
1820    Receive index event from clients(s)
1821    \param[in] event event contain info about rank and associated index
1822  */
1823  void CDomain::recvIndex(CEventServer& event)
1824  {
1825    CDomain* domain;
1826
1827    list<CEventServer::SSubEvent>::iterator it;
1828    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1829    {
1830      CBufferIn* buffer = it->buffer;
1831      string domainId;
1832      *buffer >> domainId;
1833      domain = get(domainId);
1834      domain->recvIndex(it->rank, *buffer);
1835    }
1836
1837    if (domain->isCompressible_)
1838    {
1839      std::sort(domain->indexesToWrite.begin(), domain->indexesToWrite.end());
1840
1841      CContextServer* server = CContext::getCurrent()->server;
1842      domain->numberWrittenIndexes_ = domain->indexesToWrite.size();
1843      MPI_Allreduce(&domain->numberWrittenIndexes_, &domain->totalNumberWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
1844      MPI_Scan(&domain->numberWrittenIndexes_, &domain->offsetWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
1845      domain->offsetWrittenIndexes_ -= domain->numberWrittenIndexes_;
1846    }
1847  }
1848
1849  /*!
1850    Receive index information from client(s)
1851    \param[in] rank rank of client source
1852    \param[in] buffer message containing index info
1853  */
1854  void CDomain::recvIndex(int rank, CBufferIn& buffer)
1855  {
1856    int type_int;
1857    buffer >> type_int >> isCurvilinear >> indiSrv[rank] >> indjSrv[rank];
1858    type.setValue((type_attr::t_enum)type_int); // probleme des type enum avec les buffers : ToFix
1859
1860    if (isCompressible_)
1861    {
1862      CArray<int, 1> writtenIndexes;
1863      buffer >> writtenIndexes;
1864      indexesToWrite.reserve(indexesToWrite.size() + writtenIndexes.numElements());
1865      for (int i = 0; i < writtenIndexes.numElements(); ++i)
1866        indexesToWrite.push_back(writtenIndexes(i));
1867    }
1868  }
1869
1870  /*!
1871    Receive longitude event from clients(s)
1872    \param[in] event event contain info about rank and associated longitude
1873  */
1874  void CDomain::recvLon(CEventServer& event)
1875  {
1876    list<CEventServer::SSubEvent>::iterator it;
1877    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1878    {
1879      CBufferIn* buffer = it->buffer;
1880      string domainId;
1881      *buffer >> domainId;
1882      get(domainId)->recvLon(it->rank, *buffer);
1883    }
1884  }
1885
1886  /*!
1887    Receive longitude information from client(s)
1888    \param[in] rank rank of client source
1889    \param[in] buffer message containing longitude info
1890  */
1891  void CDomain::recvLon(int rank, CBufferIn& buffer)
1892  {
1893    CArray<int,1> &indi = indiSrv[rank], &indj = indjSrv[rank];
1894    CArray<double,1> lon;
1895    CArray<double,2> boundslon;
1896
1897    buffer >> lon;
1898
1899    if (hasBounds) buffer >> boundslon;
1900
1901    int i, j, ind_srv;
1902    for (int ind = 0; ind < indi.numElements(); ind++)
1903    {
1904      i = indi(ind); j = indj(ind);
1905      ind_srv = (i - zoom_ibegin_srv) + (j - zoom_jbegin_srv) * zoom_ni_srv;
1906      lonvalue_srv(ind_srv) = lon(ind);
1907      if (hasBounds)
1908      {
1909        for (int nv = 0; nv < nvertex; ++nv)
1910          bounds_lon_srv(nv, ind_srv) = boundslon(nv, ind);
1911      }
1912    }
1913  }
1914
1915  /*!
1916    Receive latitude event from clients(s)
1917    \param[in] event event contain info about rank and associated latitude
1918  */
1919  void CDomain::recvLat(CEventServer& event)
1920  {
1921    list<CEventServer::SSubEvent>::iterator it;
1922    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1923    {
1924      CBufferIn* buffer = it->buffer;
1925      string domainId;
1926      *buffer >> domainId;
1927      get(domainId)->recvLat(it->rank, *buffer);
1928    }
1929  }
1930
1931  /*!
1932    Receive latitude information from client(s)
1933    \param[in] rank rank of client source
1934    \param[in] buffer message containing latitude info
1935  */
1936  void CDomain::recvLat(int rank, CBufferIn& buffer)
1937  {
1938    CArray<int,1> &indi = indiSrv[rank], &indj = indjSrv[rank];
1939    CArray<double,1> lat;
1940    CArray<double,2> boundslat;
1941
1942    buffer >> lat;
1943    if (hasBounds) buffer >> boundslat;
1944
1945    int i, j, ind_srv;
1946    for (int ind = 0; ind < indi.numElements(); ind++)
1947    {
1948      i = indi(ind); j = indj(ind);
1949      ind_srv = (i - zoom_ibegin_srv) + (j - zoom_jbegin_srv) * zoom_ni_srv;
1950      latvalue_srv(ind_srv) = lat(ind);
1951      if (hasBounds)
1952      {
1953        for (int nv = 0; nv < nvertex; nv++)
1954          bounds_lat_srv(nv, ind_srv) = boundslat(nv, ind);
1955      }
1956    }
1957  }
1958
1959  /*!
1960    Receive area event from clients(s)
1961    \param[in] event event contain info about rank and associated area
1962  */
1963  void CDomain::recvArea(CEventServer& event)
1964  {
1965    list<CEventServer::SSubEvent>::iterator it;
1966    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1967    {
1968      CBufferIn* buffer = it->buffer;
1969      string domainId;
1970      *buffer >> domainId;
1971      get(domainId)->recvArea(it->rank, *buffer);
1972    }
1973  }
1974
1975  /*!
1976    Receive area information from client(s)
1977    \param[in] rank rank of client source
1978    \param[in] buffer message containing area info
1979  */
1980  void CDomain::recvArea(int rank, CBufferIn& buffer)
1981  {
1982    CArray<int,1> &indi = indiSrv[rank], &indj = indjSrv[rank];
1983    CArray<double,1> clientArea;
1984
1985    buffer >> clientArea;
1986
1987    int i, j, ind_srv;
1988    for (int ind = 0; ind < indi.numElements(); ind++)
1989    {
1990      i = indi(ind); j = indj(ind);
1991      ind_srv = (i - zoom_ibegin_srv) + (j - zoom_jbegin_srv) * zoom_ni_srv;
1992      area_srv(ind_srv) = clientArea(ind);
1993    }
1994  }
1995
1996  CTransformation<CDomain>* CDomain::addTransformation(ETranformationType transType, const StdString& id)
1997  {
1998    transformationMap_.push_back(std::make_pair(transType, CTransformation<CDomain>::createTransformation(transType,id)));
1999    return transformationMap_.back().second;
2000  }
2001
2002  /*!
2003    Check whether a domain has transformation
2004    \return true if domain has transformation
2005  */
2006  bool CDomain::hasTransformation()
2007  {
2008    return (!transformationMap_.empty());
2009  }
2010
2011  /*!
2012    Set transformation for current domain. It's the method to move transformation in hierarchy
2013    \param [in] domTrans transformation on domain
2014  */
2015  void CDomain::setTransformations(const TransMapTypes& domTrans)
2016  {
2017    transformationMap_ = domTrans;
2018  }
2019
2020  /*!
2021    Get all transformation current domain has
2022    \return all transformation
2023  */
2024  CDomain::TransMapTypes CDomain::getAllTransformations(void)
2025  {
2026    return transformationMap_;
2027  }
2028
2029  /*!
2030    Check the validity of all transformations applied on domain
2031  This functions is called AFTER all inherited attributes are solved
2032  */
2033  void CDomain::checkTransformations()
2034  {
2035    TransMapTypes::const_iterator itb = transformationMap_.begin(), it,
2036                                  ite = transformationMap_.end();
2037//    for (it = itb; it != ite; ++it)
2038//    {
2039//      (it->second)->checkValid(this);
2040//    }
2041  }
2042
2043  void CDomain::duplicateTransformation(CDomain* src)
2044  {
2045    if (src->hasTransformation())
2046    {
2047      this->setTransformations(src->getAllTransformations());
2048    }
2049  }
2050
2051  /*!
2052   * Go through the hierarchy to find the domain from which the transformations must be inherited
2053   */
2054  void CDomain::solveInheritanceTransformation()
2055  {
2056    if (hasTransformation() || !hasDirectDomainReference())
2057      return;
2058
2059    CDomain* domain = this;
2060    std::vector<CDomain*> refDomains;
2061    while (!domain->hasTransformation() && domain->hasDirectDomainReference())
2062    {
2063      refDomains.push_back(domain);
2064      domain = domain->getDirectDomainReference();
2065    }
2066
2067    if (domain->hasTransformation())
2068      for (size_t i = 0; i < refDomains.size(); ++i)
2069        refDomains[i]->setTransformations(domain->getAllTransformations());
2070  }
2071
2072  /*!
2073    Parse children nodes of a domain in xml file.
2074    Whenver there is a new transformation, its type and name should be added into this function
2075    \param node child node to process
2076  */
2077  void CDomain::parse(xml::CXMLNode & node)
2078  {
2079    SuperClass::parse(node);
2080
2081    if (node.goToChildElement())
2082    {
2083      StdString nodeElementName;
2084      do
2085      {
2086        StdString nodeId("");
2087        if (node.getAttributes().end() != node.getAttributes().find("id"))
2088        { nodeId = node.getAttributes()["id"]; }
2089
2090        nodeElementName = node.getElementName();
2091        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
2092        it = transformationMapList_.find(nodeElementName);
2093        if (ite != it)
2094        {
2095          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CDomain>::createTransformation(it->second,
2096                                                                                                                nodeId,
2097                                                                                                                &node)));
2098        }
2099      } while (node.goToNextElement()) ;
2100      node.goToParentElement();
2101    }
2102  }
2103   //----------------------------------------------------------------
2104
2105   DEFINE_REF_FUNC(Domain,domain)
2106
2107   ///---------------------------------------------------------------
2108
2109} // namespace xios
Note: See TracBrowser for help on using the repository browser.