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

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

Exposing transformation to Fortran interface

+) Export zoom and axis transformation to Fortran interface

Test
+) On Curie
+) All work

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