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

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

Improve generation of boundaries for rectilinear grid

YM

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