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

Last change on this file since 924 was 924, checked in by oabramkina, 8 years ago

Parallel version of UGRID norms.

The following connectivity parameters have been implemented:

edge_nodes
face_nodes
face_edges
edge_faces
face_faces.

Test with a regular(structured) quadrilateral mesh (test_regular) has been added.

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