source: XIOS/dev/dev_ym/XIOS_COUPLING/src/node/domain.cpp @ 2116

Last change on this file since 2116 was 2022, checked in by ymipsl, 3 years ago

Reimplement coupling in the new infrastructure.
Tested for 2-way coupling toy model.

YM

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
  • Property svn:executable set to *
File size: 85.1 KB
Line 
1#include "domain.hpp"
2#include "attribute_template.hpp"
3#include "object_template.hpp"
4#include "group_template.hpp"
5
6#include "xios_spl.hpp"
7#include "event_client.hpp"
8#include "event_server.hpp"
9#include "buffer_in.hpp"
10#include "message.hpp"
11#include "type.hpp"
12#include "context.hpp"
13#include "context_client.hpp"
14#include "context_server.hpp"
15#include "array_new.hpp"
16#include "distribution_client.hpp"
17#include "server_distribution_description.hpp"
18#include "client_server_mapping_distributed.hpp"
19#include "local_connector.hpp"
20#include "grid_local_connector.hpp"
21#include "remote_connector.hpp"
22#include "gatherer_connector.hpp"
23#include "scatterer_connector.hpp"
24#include "grid_scatterer_connector.hpp"
25#include "grid_gatherer_connector.hpp"
26#include "transformation_path.hpp"
27
28
29
30
31#include <algorithm>
32
33namespace xios {
34
35   /// ////////////////////// Définitions ////////////////////// ///
36
37   CDomain::CDomain(void)
38      : CObjectTemplate<CDomain>(), CDomainAttributes()
39      , isChecked(false), relFiles(),  indSrv_(), connectedServerRank_()
40      , hasBounds(false), hasArea(false), isCompressible_(false), isUnstructed_(false)
41      , hasLonLat(false)
42      , isRedistributed_(false), hasPole(false)
43      , lonvalue(), latvalue(), bounds_lonvalue(), bounds_latvalue()
44      , clients(), hasLatInReadFile_(false), hasBoundsLatInReadFile_(false)
45      , hasLonInReadFile_(false), hasBoundsLonInReadFile_(false)
46   {
47   }
48
49   CDomain::CDomain(const StdString & id)
50      : CObjectTemplate<CDomain>(id), CDomainAttributes()
51      , isChecked(false), relFiles(), indSrv_(), connectedServerRank_() 
52      , hasBounds(false), hasArea(false), isCompressible_(false), isUnstructed_(false)
53      , hasLonLat(false)
54      , isRedistributed_(false), hasPole(false)
55      , lonvalue(), latvalue(), bounds_lonvalue(), bounds_latvalue()
56      , clients(), hasLatInReadFile_(false), hasBoundsLatInReadFile_(false)
57      , hasLonInReadFile_(false), hasBoundsLonInReadFile_(false)
58   {
59    }
60
61   CDomain::~CDomain(void)
62   {
63   }
64
65   ///---------------------------------------------------------------
66
67   void CDomain::assignMesh(const StdString meshName, const int nvertex)
68   TRY
69   {
70     mesh = CMesh::getMesh(meshName, nvertex);
71   }
72   CATCH_DUMP_ATTR
73
74   CDomain* CDomain::createDomain()
75   TRY
76   {
77     CDomain* domain = CDomainGroup::get("domain_definition")->createChild();
78     return domain;
79   }
80   CATCH
81
82   const std::set<StdString> & CDomain::getRelFiles(void) const
83   TRY
84   {
85      return (this->relFiles);
86   }
87   CATCH
88
89     //----------------------------------------------------------------
90
91   /*!
92    * Compute the minimum buffer size required to send the attributes to the server(s).
93    *
94    * \return A map associating the server rank with its minimum buffer size.
95    */
96   std::map<int, StdSize> CDomain::getAttributesBufferSize(CContextClient* client, bool bufferForWriting /*= false*/)
97   TRY
98   {
99
100     std::map<int, StdSize> attributesSizes = getMinimumBufferSizeForAttributes(client);
101
102     if (client->isServerLeader())
103     {
104       // size estimation for sendDistributionAttribut
105       size_t size = 11 * sizeof(size_t);
106
107       const std::list<int>& ranks = client->getRanksServerLeader();
108       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
109       {
110         if (size > attributesSizes[*itRank])
111           attributesSizes[*itRank] = size;
112       }
113     }
114
115     std::unordered_map<int, vector<size_t> >::const_iterator itIndexEnd = indSrv_[client->serverSize].end();
116     // std::map<int, std::vector<int> >::const_iterator itWrittenIndexEnd = indWrittenSrv_.end();
117     for (size_t k = 0; k < connectedServerRank_[client->serverSize].size(); ++k)
118     {
119       int rank = connectedServerRank_[client->serverSize][k];
120       std::unordered_map<int, std::vector<size_t> >::const_iterator it = indSrv_[client->serverSize].find(rank);
121       size_t idxCount = (it != itIndexEnd) ? it->second.size() : 0;
122
123       // size estimation for sendIndex (and sendArea which is always smaller or equal)
124       size_t sizeIndexEvent = 2 * sizeof(size_t) + 2 * CArray<int,1>::size(idxCount);
125
126       // size estimation for sendLonLat
127       size_t sizeLonLatEvent = CArray<double,1>::size(idxCount);
128       if (hasBounds)
129         sizeLonLatEvent += CArray<double,2>::size(nvertex * idxCount);
130
131       size_t size = CEventClient::headerSize + getId().size() + sizeof(size_t) + std::max(sizeIndexEvent, sizeLonLatEvent);
132       if (size > attributesSizes[rank])
133         attributesSizes[rank] = size;
134     }
135
136     return attributesSizes;
137   }
138   CATCH_DUMP_ATTR
139
140   //----------------------------------------------------------------
141
142   bool CDomain::isEmpty(void) const
143   TRY
144   {
145     return ((this->i_index.isEmpty()) || (0 == this->i_index.numElements()));
146   }
147   CATCH
148
149   //----------------------------------------------------------------
150
151   bool CDomain::IsWritten(const StdString & filename) const
152   TRY
153   {
154      return (this->relFiles.find(filename) != this->relFiles.end());
155   }
156   CATCH
157
158   bool CDomain::isWrittenCompressed(const StdString& filename) const
159   TRY
160   {
161      return (this->relFilesCompressed.find(filename) != this->relFilesCompressed.end());
162   }
163   CATCH
164
165   //----------------------------------------------------------------
166
167   bool CDomain::isDistributed(void) const
168   TRY
169   {
170      bool distributed =  !((!ni.isEmpty() && (ni == ni_glo) && !nj.isEmpty() && (nj == nj_glo)) ||
171              (!i_index.isEmpty() && i_index.numElements() == ni_glo*nj_glo));
172      bool distributed_glo ;
173      distributed |= (1 == CContext::getCurrent()->intraCommSize_);
174
175      return distributed;
176   }
177   CATCH
178
179   //----------------------------------------------------------------
180
181   /*!
182    * Compute if the domain can be ouput in a compressed way.
183    * In this case the workflow view on server side must be the same
184    * than the full view for all context rank. The result is stored on
185    * internal isCompressible_ attribute.
186    */
187   void CDomain::computeIsCompressible(void)
188   TRY
189   {
190     // mesh is compressible contains some masked or indexed value, ie if full view is different of workflow view.
191     // But now assume that the size of the 2 view must be equal for everybody. True on server side
192     int isSameView = getLocalView(CElementView::FULL)->getSize() ==  getLocalView(CElementView::WORKFLOW)->getSize();
193     MPI_Allreduce(MPI_IN_PLACE, &isSameView, 1, MPI_INT, MPI_LAND, CContext::getCurrent()->getIntraComm()) ;
194     if (isSameView) isCompressible_ = false ;
195     else isCompressible_ = true ;
196     isCompressibleComputed_=true ;
197   }
198   CATCH
199
200   void CDomain::addRelFile(const StdString & filename)
201   TRY
202   {
203      this->relFiles.insert(filename);
204   }
205   CATCH_DUMP_ATTR
206
207   void CDomain::addRelFileCompressed(const StdString& filename)
208   TRY
209   {
210      this->relFilesCompressed.insert(filename);
211   }
212   CATCH_DUMP_ATTR
213
214   StdString CDomain::GetName(void)   { return (StdString("domain")); }
215   StdString CDomain::GetDefName(void){ return (CDomain::GetName()); }
216   ENodeType CDomain::GetType(void)   { return (eDomain); }
217
218   //----------------------------------------------------------------
219
220   /*!
221      Verify if all distribution information of a domain are available
222      This checking verifies the definition of distribution attributes (ni, nj, ibegin, jbegin)
223   */
224   bool CDomain::distributionAttributesHaveValue() const
225   TRY
226   {
227      bool hasValues = true;
228
229      if (ni.isEmpty() && ibegin.isEmpty() && i_index.isEmpty())
230      {
231        hasValues = false;
232        return hasValues;
233      }
234
235      return hasValues;
236   }
237   CATCH
238
239   /*!
240     Redistribute RECTILINEAR or CURVILINEAR domain with a number of local domains.
241   All attributes ni,nj,ibegin,jbegin (if defined) will be rewritten
242   The optional attributes lonvalue, latvalue will be added. Because this function only serves (for now)
243   for interpolation from unstructured domain to rectilinear one, range of latvalue is 0-360 and lonvalue is -90 - +90
244    \param [in] nbLocalDomain number of local domain on the domain destination
245   */
246   void CDomain::redistribute(int nbLocalDomain)
247   TRY
248   {
249     if (this->isRedistributed_) return;
250
251     this->isRedistributed_ = true;
252     CContext* context = CContext::getCurrent();
253     // For now the assumption is that secondary server pools consist of the same number of procs.
254     // CHANGE the line below if the assumption changes.
255
256     int rankClient = context->intraCommRank_;
257     int rankOnDomain = rankClient%nbLocalDomain;
258
259     if (ni_glo.isEmpty() || ni_glo <= 0 )
260     {
261        ERROR("CDomain::redistribute(int nbLocalDomain)",
262           << "[ Id = " << this->getId() << " ] "
263           << "The global domain is badly defined,"
264           << " check the \'ni_glo\'  value !")
265     }
266
267     if (nj_glo.isEmpty() || nj_glo <= 0 )
268     {
269        ERROR("CDomain::redistribute(int nbLocalDomain)",
270           << "[ Id = " << this->getId() << " ] "
271           << "The global domain is badly defined,"
272           << " check the \'nj_glo\'  value !")
273     }
274
275     if ((type_attr::rectilinear == type)  || (type_attr::curvilinear == type))
276     {
277        int globalDomainSize = ni_glo * nj_glo;
278        if (globalDomainSize <= nbLocalDomain)
279        {
280          for (int idx = 0; idx < nbLocalDomain; ++idx)
281          {
282            if (rankOnDomain < globalDomainSize)
283            {
284              int iIdx = rankOnDomain % ni_glo;
285              int jIdx = rankOnDomain / ni_glo;
286              ibegin.setValue(iIdx); jbegin.setValue(jIdx);
287              ni.setValue(1); nj.setValue(1);
288            }
289            else
290            {
291              ibegin.setValue(0); jbegin.setValue(0);
292              ni.setValue(0); nj.setValue(0);
293            }
294          }
295        }
296        else
297        {
298          float njGlo = nj_glo.getValue();
299          float niGlo = ni_glo.getValue();
300          int nbProcOnX, nbProcOnY, range;
301
302          // Compute (approximately) number of segment on x and y axis
303          float yOverXRatio = njGlo/niGlo;
304
305          nbProcOnX = std::ceil(std::sqrt(nbLocalDomain/yOverXRatio));
306          nbProcOnY = std::ceil(((float)nbLocalDomain)/nbProcOnX);
307
308          // Simple distribution: Sweep from top to bottom, left to right
309          // Calculate local begin on x
310          std::vector<int> ibeginVec(nbProcOnX,0), jbeginVec(nbProcOnY,0);
311          std::vector<int> niVec(nbProcOnX), njVec(nbProcOnY);
312          for (int i = 1; i < nbProcOnX; ++i)
313          {
314            range = ni_glo / nbProcOnX;
315            if (i < (ni_glo%nbProcOnX)) ++range;
316            niVec[i-1] = range;
317            ibeginVec[i] = ibeginVec[i-1] + niVec[i-1];
318          }
319          niVec[nbProcOnX-1] = ni_glo - ibeginVec[nbProcOnX-1];
320
321          // Calculate local begin on y
322          for (int j = 1; j < nbProcOnY; ++j)
323          {
324            range = nj_glo / nbProcOnY;
325            if (j < (nj_glo%nbProcOnY)) ++range;
326            njVec[j-1] = range;
327            jbeginVec[j] = jbeginVec[j-1] + njVec[j-1];
328          }
329          njVec[nbProcOnY-1] = nj_glo - jbeginVec[nbProcOnY-1];
330
331          // Now assign value to ni, ibegin, nj, jbegin
332          int iIdx = rankOnDomain % nbProcOnX;
333          int jIdx = rankOnDomain / nbProcOnX;
334
335          if (rankOnDomain != (nbLocalDomain-1))
336          {
337            ibegin.setValue(ibeginVec[iIdx]);
338            jbegin.setValue(jbeginVec[jIdx]);
339            nj.setValue(njVec[jIdx]);
340            ni.setValue(niVec[iIdx]);
341          }
342          else // just merge all the remaining rectangle into the last one
343          {
344            ibegin.setValue(ibeginVec[iIdx]);
345            jbegin.setValue(jbeginVec[jIdx]);
346            nj.setValue(njVec[jIdx]);
347            ni.setValue(ni_glo - ibeginVec[iIdx]);
348          }
349        } 
350     }
351     else  // unstructured domain
352     {
353       if (this->i_index.isEmpty())
354       {
355          int globalDomainSize = ni_glo * nj_glo;
356          if (globalDomainSize <= nbLocalDomain)
357          {
358            for (int idx = 0; idx < nbLocalDomain; ++idx)
359            {
360              if (rankOnDomain < globalDomainSize)
361              {
362                int iIdx = rankOnDomain % ni_glo;
363                int jIdx = rankOnDomain / ni_glo;
364                ibegin.setValue(iIdx); jbegin.setValue(jIdx);
365                ni.setValue(1); nj.setValue(1);
366              }
367              else
368              {
369                ibegin.setValue(0); jbegin.setValue(0);
370                ni.setValue(0); nj.setValue(0);
371              }
372            }
373          }
374          else
375          {
376            float njGlo = nj_glo.getValue();
377            float niGlo = ni_glo.getValue();
378            std::vector<int> ibeginVec(nbLocalDomain,0);
379            std::vector<int> niVec(nbLocalDomain);
380            for (int i = 1; i < nbLocalDomain; ++i)
381            {
382              int range = ni_glo / nbLocalDomain;
383              if (i < (ni_glo%nbLocalDomain)) ++range;
384              niVec[i-1] = range;
385              ibeginVec[i] = ibeginVec[i-1] + niVec[i-1];
386            }
387            niVec[nbLocalDomain-1] = ni_glo - ibeginVec[nbLocalDomain-1];
388
389            int iIdx = rankOnDomain % nbLocalDomain;
390            ibegin.setValue(ibeginVec[iIdx]);
391            jbegin.setValue(0);
392            ni.setValue(niVec[iIdx]);
393            nj.setValue(1);
394          }
395
396          i_index.resize(ni);         
397          for(int idx = 0; idx < ni; ++idx) i_index(idx)=ibegin+idx;
398        }
399        else
400        {
401          ibegin.setValue(this->i_index(0));
402          jbegin.setValue(0);
403          ni.setValue(this->i_index.numElements());
404          nj.setValue(1);
405        }
406     }
407
408     checkDomain();
409   }
410   CATCH_DUMP_ATTR
411
412   /*!
413     Fill in longitude and latitude whose values are read from file
414   */
415   void CDomain::fillInLonLat()
416   TRY
417   {
418     switch (type)
419     {
420      case type_attr::rectilinear:
421        fillInRectilinearLonLat();
422        break;
423      case type_attr::curvilinear:
424        fillInCurvilinearLonLat();
425        break;
426      case type_attr::unstructured:
427        fillInUnstructuredLonLat();
428        break;
429
430      default:
431      break;
432     }
433     completeLonLatClient() ;
434   }
435   CATCH_DUMP_ATTR
436
437   /*!
438     Fill in the values for lonvalue_1d and latvalue_1d of rectilinear domain
439     Range of longitude value from 0 - 360
440     Range of latitude value from -90 - +90
441   */
442   void CDomain::fillInRectilinearLonLat()
443   TRY
444   {
445     if (!lonvalue_rectilinear_read_from_file.isEmpty() && lonvalue_2d.isEmpty() && lonvalue_1d.isEmpty())
446     {
447       lonvalue_1d.resize(ni);
448       for (int idx = 0; idx < ni; ++idx)
449         lonvalue_1d(idx) = lonvalue_rectilinear_read_from_file(idx+ibegin);
450       lon_start.setValue(lonvalue_rectilinear_read_from_file(0));
451       lon_end.setValue(lonvalue_rectilinear_read_from_file(ni_glo-1));
452     }
453     else if (!hasLonInReadFile_)
454     {
455       if (!lonvalue_2d.isEmpty()) lonvalue_2d.free();
456       lonvalue_1d.resize(ni);
457       double lonRange = lon_end - lon_start;
458       double lonStep = (1 == ni_glo.getValue()) ? lonRange : lonRange/double(ni_glo.getValue()-1);
459
460        // Assign lon value
461       for (int i = 0; i < ni; ++i)
462       {
463         if (0 == (ibegin + i))
464         {
465           lonvalue_1d(i) = lon_start;
466         }
467         else if (ni_glo == (ibegin + i + 1))
468         {
469           lonvalue_1d(i) = lon_end;
470         }
471         else
472         {
473           lonvalue_1d(i) = (ibegin + i) * lonStep  + lon_start;
474         }
475       }
476     }
477
478
479     if (!latvalue_rectilinear_read_from_file.isEmpty() && latvalue_2d.isEmpty() && latvalue_1d.isEmpty())
480     {
481       latvalue_1d.resize(nj);
482       for (int idx = 0; idx < nj; ++idx)
483         latvalue_1d(idx) = latvalue_rectilinear_read_from_file(idx+jbegin);
484       lat_start.setValue(latvalue_rectilinear_read_from_file(0));
485       lat_end.setValue(latvalue_rectilinear_read_from_file(nj_glo-1));
486     }
487     else if (!hasLatInReadFile_)
488     {
489       if (!latvalue_2d.isEmpty()) latvalue_1d.free();
490       latvalue_1d.resize(nj);
491
492       double latRange = lat_end - lat_start;
493       double latStep = (1 == nj_glo.getValue()) ? latRange : latRange/double(nj_glo.getValue()-1);
494
495       for (int j = 0; j < nj; ++j)
496       {
497         if (0 == (jbegin + j))
498         {
499            latvalue_1d(j) = lat_start;
500         }
501         else if (nj_glo == (jbegin + j + 1))
502         {
503            latvalue_1d(j) = lat_end;
504         }
505         else
506         {
507           latvalue_1d(j) =  (jbegin + j) * latStep + lat_start;
508         }
509       }
510     }
511   }
512   CATCH_DUMP_ATTR
513
514    /*
515      Fill in 2D longitude and latitude of curvilinear domain read from a file.
516      If there are already longitude and latitude defined by model. We just ignore read value.
517    */
518   void CDomain::fillInCurvilinearLonLat()
519   TRY
520   {
521     if (!lonvalue_curvilinear_read_from_file.isEmpty() && lonvalue_2d.isEmpty() && lonvalue_1d.isEmpty())
522     {
523       lonvalue_2d.resize(ni,nj);
524       for (int jdx = 0; jdx < nj; ++jdx)
525        for (int idx = 0; idx < ni; ++idx)
526         lonvalue_2d(idx,jdx) = lonvalue_curvilinear_read_from_file(idx, jdx);
527
528       lonvalue_curvilinear_read_from_file.free();
529     }
530
531     if (!latvalue_curvilinear_read_from_file.isEmpty() && latvalue_2d.isEmpty() && latvalue_1d.isEmpty())
532     {
533       latvalue_2d.resize(ni,nj);
534       for (int jdx = 0; jdx < nj; ++jdx)
535        for (int idx = 0; idx < ni; ++idx)
536           latvalue_2d(idx,jdx) = latvalue_curvilinear_read_from_file(idx, jdx);
537
538       latvalue_curvilinear_read_from_file.free();
539     }
540
541     if (!bounds_lonvalue_curvilinear_read_from_file.isEmpty() && bounds_lon_2d.isEmpty() && bounds_lon_1d.isEmpty())
542     {
543       bounds_lon_2d.resize(nvertex,ni,nj);
544       for (int jdx = 0; jdx < nj; ++jdx)
545        for (int idx = 0; idx < ni; ++idx)
546          for (int ndx = 0; ndx < nvertex; ++ndx)
547            bounds_lon_2d(ndx,idx,jdx) = bounds_lonvalue_curvilinear_read_from_file(ndx,idx, jdx);
548
549       bounds_lonvalue_curvilinear_read_from_file.free();
550     }
551
552     if (!bounds_latvalue_curvilinear_read_from_file.isEmpty() && bounds_lat_2d.isEmpty() && bounds_lat_1d.isEmpty())
553     {
554       bounds_lat_2d.resize(nvertex,ni,nj);
555       for (int jdx = 0; jdx < nj; ++jdx)
556        for (int idx = 0; idx < ni; ++idx)
557          for (int ndx = 0; ndx < nvertex; ++ndx)
558            bounds_lat_2d(ndx,idx,jdx) = bounds_latvalue_curvilinear_read_from_file(ndx,idx, jdx);
559
560       bounds_latvalue_curvilinear_read_from_file.free();
561     }
562   }
563   CATCH_DUMP_ATTR
564
565    /*
566      Fill in longitude and latitude of unstructured domain read from a file
567      If there are already longitude and latitude defined by model. We just igonore reading value.
568    */
569   void CDomain::fillInUnstructuredLonLat()
570   TRY
571   {
572     if (i_index.isEmpty())
573     {
574       i_index.resize(ni);
575       for(int idx = 0; idx < ni; ++idx) i_index(idx)=ibegin+idx;
576     }
577
578     if (!lonvalue_unstructured_read_from_file.isEmpty() && lonvalue_1d.isEmpty())
579     {
580        lonvalue_1d.resize(ni);
581        for (int idx = 0; idx < ni; ++idx)
582          lonvalue_1d(idx) = lonvalue_unstructured_read_from_file(idx);
583
584        // We dont need these values anymore, so just delete them
585        lonvalue_unstructured_read_from_file.free();
586     } 
587
588     if (!latvalue_unstructured_read_from_file.isEmpty() && latvalue_1d.isEmpty())
589     {
590        latvalue_1d.resize(ni);
591        for (int idx = 0; idx < ni; ++idx)
592          latvalue_1d(idx) =  latvalue_unstructured_read_from_file(idx);
593
594        // We dont need these values anymore, so just delete them
595        latvalue_unstructured_read_from_file.free();
596     }
597
598     if (!bounds_lonvalue_unstructured_read_from_file.isEmpty() && bounds_lon_1d.isEmpty())
599     {
600        int nbVertex = nvertex;
601        bounds_lon_1d.resize(nbVertex,ni);
602        for (int idx = 0; idx < ni; ++idx)
603          for (int jdx = 0; jdx < nbVertex; ++jdx)
604            bounds_lon_1d(jdx,idx) = bounds_lonvalue_unstructured_read_from_file(jdx, idx);
605
606        // We dont need these values anymore, so just delete them
607        bounds_lonvalue_unstructured_read_from_file.free();
608     }
609
610     if (!bounds_latvalue_unstructured_read_from_file.isEmpty() && bounds_lat_1d.isEmpty())
611     {
612        int nbVertex = nvertex;
613        bounds_lat_1d.resize(nbVertex,ni);
614        for (int idx = 0; idx < ni; ++idx)
615          for (int jdx = 0; jdx < nbVertex; ++jdx)
616            bounds_lat_1d(jdx,idx) = bounds_latvalue_unstructured_read_from_file(jdx, idx);
617
618        // We dont need these values anymore, so just delete them
619        bounds_latvalue_unstructured_read_from_file.free();
620     }
621   }
622   CATCH_DUMP_ATTR
623
624  /*
625    Get global longitude and latitude of rectilinear domain.
626  */
627   void CDomain::AllgatherRectilinearLonLat(CArray<double,1>& lon, CArray<double,1>& lat, CArray<double,1>& lon_g, CArray<double,1>& lat_g)
628   TRY
629   {
630     CContext* context = CContext::getCurrent();
631    // For now the assumption is that secondary server pools consist of the same number of procs.
632    // CHANGE the line below if the assumption changes.
633     int clientSize = context->intraCommSize_ ;
634     lon_g.resize(ni_glo) ;
635     lat_g.resize(nj_glo) ;
636
637
638     int* ibegin_g = new int[clientSize] ;
639     int* jbegin_g = new int[clientSize] ;
640     int* ni_g = new int[clientSize] ;
641     int* nj_g = new int[clientSize] ;
642     int v ;
643     v=ibegin ;
644     MPI_Allgather(&v,1,MPI_INT,ibegin_g,1,MPI_INT,context->intraComm_) ;
645     v=jbegin ;
646     MPI_Allgather(&v,1,MPI_INT,jbegin_g,1,MPI_INT,context->intraComm_) ;
647     v=ni ;
648     MPI_Allgather(&v,1,MPI_INT,ni_g,1,MPI_INT,context->intraComm_) ;
649     v=nj ;
650     MPI_Allgather(&v,1,MPI_INT,nj_g,1,MPI_INT,context->intraComm_) ;
651
652     MPI_Allgatherv(lon.dataFirst(),ni,MPI_DOUBLE,lon_g.dataFirst(),ni_g, ibegin_g,MPI_DOUBLE,context->intraComm_) ;
653     MPI_Allgatherv(lat.dataFirst(),nj,MPI_DOUBLE,lat_g.dataFirst(),nj_g, jbegin_g,MPI_DOUBLE,context->intraComm_) ;
654
655      delete[] ibegin_g ;
656      delete[] jbegin_g ;
657      delete[] ni_g ;
658      delete[] nj_g ;
659   }
660   CATCH_DUMP_ATTR
661
662   void CDomain::fillInRectilinearBoundLonLat(CArray<double,1>& lon, CArray<double,1>& lat,
663                                              CArray<double,2>& boundsLon, CArray<double,2>& boundsLat)
664   TRY
665  {
666     int i,j,k;
667
668     const int nvertexValue = 4;
669     boundsLon.resize(nvertexValue,ni*nj);
670
671     if (ni_glo>1)
672     {
673       double lonStepStart = lon(1)-lon(0);
674       bounds_lon_start=lon(0) - lonStepStart/2;
675       double lonStepEnd = lon(ni_glo-1)-lon(ni_glo-2);
676       bounds_lon_end=lon(ni_glo-1) + lonStepEnd/2;
677       double errorBoundsLon = std::abs(360-std::abs(bounds_lon_end-bounds_lon_start));
678
679       // if errorBoundsLon is reasonably small (0.1 x cell size) consider it as closed in longitude
680       if (errorBoundsLon < std::abs(lonStepStart)*1e-1 || errorBoundsLon < std::abs(lonStepEnd)*1e-1 )
681       {
682         bounds_lon_start= (lon(0) + lon(ni_glo-1)-360)/2 ;
683         bounds_lon_end= (lon(0) +360 + lon(ni_glo-1))/2 ;
684       }
685     }
686     else
687     {
688       if (bounds_lon_start.isEmpty()) bounds_lon_start=-180. ;
689       if (bounds_lon_end.isEmpty()) bounds_lon_end=180.-1e-8 ;
690     }
691
692     for(j=0;j<nj;++j)
693       for(i=0;i<ni;++i)
694       {
695         k=j*ni+i;
696         boundsLon(0,k) = boundsLon(1,k) = (0 == (ibegin + i)) ? bounds_lon_start
697                                                               : (lon(ibegin + i)+lon(ibegin + i-1))/2;
698         boundsLon(2,k) = boundsLon(3,k) = ((ibegin + i + 1) == ni_glo) ? bounds_lon_end
699                                                                        : (lon(ibegin + i + 1)+lon(ibegin + i))/2;
700       }
701
702
703    boundsLat.resize(nvertexValue,nj*ni);
704    bool isNorthPole=false ;
705    bool isSouthPole=false ;
706    if (std::abs(90 - std::abs(lat(0))) < NumTraits<double>::epsilon()) isNorthPole = true;
707    if (std::abs(90 - std::abs(lat(nj_glo-1))) < NumTraits<double>::epsilon()) isSouthPole = true;
708
709    // lat boundaries beyond pole the assimilate it to pole
710    // lat boundarie is relativelly close to pole (0.1 x cell size) assimilate it to pole
711    if (nj_glo>1)
712    {
713      double latStepStart = lat(1)-lat(0);
714      if (isNorthPole) bounds_lat_start=lat(0);
715      else
716      {
717        bounds_lat_start=lat(0)-latStepStart/2;
718        if (bounds_lat_start >= 90 ) bounds_lat_start=90 ;
719        else if (bounds_lat_start <= -90 ) bounds_lat_start=-90 ;
720        else if (bounds_lat_start <= 90 && bounds_lat_start >= lat(0))
721        {
722          if ( std::abs(90-bounds_lat_start) <= 0.1*std::abs(latStepStart)) bounds_lat_start=90 ;
723        }
724        else if (bounds_lat_start >= -90 && bounds_lat_start <= lat(0))
725        {
726          if ( std::abs(-90 - bounds_lat_start) <= 0.1*std::abs(latStepStart)) bounds_lat_start=-90 ;
727        }
728      }
729
730      double latStepEnd = lat(nj_glo-1)-lat(nj_glo-2);
731      if (isSouthPole) bounds_lat_end=lat(nj_glo-1);
732      else
733      {
734        bounds_lat_end=lat(nj_glo-1)+latStepEnd/2;
735
736        if (bounds_lat_end >= 90 ) bounds_lat_end=90 ;
737        else if (bounds_lat_end <= -90 ) bounds_lat_end=-90 ;
738        else if (bounds_lat_end <= 90 && bounds_lat_end >= lat(nj_glo-1))
739        {
740          if ( std::abs(90-bounds_lat_end) <= 0.1*std::abs(latStepEnd)) bounds_lat_end=90 ;
741        }
742        else if (bounds_lat_end >= -90 && bounds_lat_end <= lat(nj_glo-1))
743        {
744          if ( std::abs(-90 - bounds_lat_end) <= 0.1*std::abs(latStepEnd)) bounds_lat_end=-90 ;
745        }
746      }
747    }
748    else
749    {
750      if (bounds_lat_start.isEmpty()) bounds_lat_start=-90. ;
751      if (bounds_lat_end.isEmpty()) bounds_lat_end=90 ;
752    }
753
754    for(j=0;j<nj;++j)
755      for(i=0;i<ni;++i)
756      {
757        k=j*ni+i;
758        boundsLat(1,k) = boundsLat(2,k) = (0 == (jbegin + j)) ? bounds_lat_start
759                                                              : (lat(jbegin + j)+lat(jbegin + j-1))/2;
760        boundsLat(0,k) = boundsLat(3,k) = ((jbegin + j +1) == nj_glo) ? bounds_lat_end
761                                                                      : (lat(jbegin + j + 1)+lat(jbegin + j))/2;
762      }
763   }
764   CATCH_DUMP_ATTR
765
766   /*
767     General check of the domain to verify its mandatory attributes
768   */
769   void CDomain::checkDomain(void)
770   TRY
771   {
772     if (type.isEmpty())
773     {
774       ERROR("CDomain::checkDomain(void)",
775             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
776             << "The domain type is mandatory, "
777             << "please define the 'type' attribute.")
778     }
779
780     if (type == type_attr::gaussian) 
781     {
782        hasPole=true ;
783        type.setValue(type_attr::unstructured) ;
784      }
785      else if (type == type_attr::rectilinear) hasPole=true ;
786
787     if (type == type_attr::unstructured)
788     {
789        if (ni_glo.isEmpty())
790        {
791          ERROR("CDomain::checkDomain(void)",
792                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
793                << "The global domain is badly defined, "
794                << "the mandatory 'ni_glo' attribute is missing.")
795        }
796        else if (ni_glo <= 0)
797        {
798          ERROR("CDomain::checkDomain(void)",
799                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
800                << "The global domain is badly defined, "
801                << "'ni_glo' attribute should be strictly positive so 'ni_glo = " << ni_glo.getValue() << "' is invalid.")
802        }
803        isUnstructed_ = true;
804        nj_glo = 1;
805        nj = 1;
806        jbegin = 0;
807        if (!i_index.isEmpty()) ni = i_index.numElements();
808        j_index.resize(ni);
809        for(int i=0;i<ni;++i) j_index(i)=0;
810
811        if (!area.isEmpty())
812          area.transposeSelf(1, 0);
813     }
814
815     if (ni_glo.isEmpty())
816     {
817       ERROR("CDomain::checkDomain(void)",
818             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
819             << "The global domain is badly defined, "
820             << "the mandatory 'ni_glo' attribute is missing.")
821     }
822     else if (ni_glo <= 0)
823     {
824       ERROR("CDomain::checkDomain(void)",
825             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
826             << "The global domain is badly defined, "
827             << "'ni_glo' attribute should be strictly positive so 'ni_glo = " << ni_glo.getValue() << "' is invalid.")
828     }
829
830     if (nj_glo.isEmpty())
831     {
832       ERROR("CDomain::checkDomain(void)",
833             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
834             << "The global domain is badly defined, "
835             << "the mandatory 'nj_glo' attribute is missing.")
836     }
837     else if (nj_glo <= 0)
838     {
839       ERROR("CDomain::checkDomain(void)",
840             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
841             << "The global domain is badly defined, "
842             << "'nj_glo' attribute should be strictly positive so 'nj_glo = " << nj_glo.getValue() << "' is invalid.")
843     }
844
845     checkLocalIDomain();
846     checkLocalJDomain();
847
848     if (i_index.isEmpty())
849     {
850       i_index.resize(ni*nj);
851       for (int j = 0; j < nj; ++j)
852         for (int i = 0; i < ni; ++i) i_index(i+j*ni) = i+ibegin;
853     }
854
855     if (j_index.isEmpty())
856     {
857       j_index.resize(ni*nj);
858       for (int j = 0; j < nj; ++j)
859         for (int i = 0; i < ni; ++i) j_index(i+j*ni) = j+jbegin;
860     }
861   }
862   CATCH_DUMP_ATTR
863
864   size_t CDomain::getGlobalWrittenSize(void)
865   {
866     return ni_glo*nj_glo ;
867   }
868   //----------------------------------------------------------------
869
870   // Check validity of local domain on using the combination of 3 parameters: ibegin, ni and i_index
871   void CDomain::checkLocalIDomain(void)
872   TRY
873   {
874      // If ibegin and ni are provided then we use them to check the validity of local domain
875      if (i_index.isEmpty() && !ibegin.isEmpty() && !ni.isEmpty())
876      {
877        if ((ni.getValue() < 0 || ibegin.getValue() < 0) || ((ibegin.getValue() + ni.getValue()) > ni_glo.getValue()))
878        {
879          ERROR("CDomain::checkLocalIDomain(void)",
880                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
881                << "The local domain is wrongly defined,"
882                << " check the attributes 'ni_glo' (" << ni_glo.getValue() << "), 'ni' (" << ni.getValue() << ") and 'ibegin' (" << ibegin.getValue() << ")");
883        }
884      }
885
886      // i_index has higher priority than ibegin and ni
887      if (!i_index.isEmpty())
888      {
889        int minIIndex = (0 < i_index.numElements()) ? i_index(0) : 0;
890        if (ni.isEmpty()) 
891        {         
892         // No information about ni
893          int minIndex = ni_glo - 1;
894          int maxIndex = 0;
895          for (int idx = 0; idx < i_index.numElements(); ++idx)
896          {
897            if (i_index(idx) < minIndex) minIndex = i_index(idx);
898            if (i_index(idx) > maxIndex) maxIndex = i_index(idx);
899          }
900          ni = maxIndex - minIndex + 1; 
901          minIIndex = minIIndex;         
902        }
903
904        // It's not so correct but if ibegin is not the first value of i_index
905        // then data on local domain has user-defined distribution. In this case, ibegin, ni have no meaning.
906        if (ibegin.isEmpty()) ibegin = minIIndex;
907      }
908      else if (ibegin.isEmpty() && ni.isEmpty())
909      {
910        ibegin = 0;
911        ni = ni_glo;
912      }
913      else if ((!ibegin.isEmpty() && ni.isEmpty()) || (ibegin.isEmpty() && !ni.isEmpty()))
914      {
915        ERROR("CDomain::checkLocalIDomain(void)",
916              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
917              << "The local domain is wrongly defined," << endl
918              << "i_index is empty and either 'ni' or 'ibegin' is not defined. " 
919              << "If 'ni' and 'ibegin' are used to define a domain, both of them must not be empty.");
920      }
921       
922
923      if ((ni.getValue() < 0 || ibegin.getValue() < 0))
924      {
925        ERROR("CDomain::checkLocalIDomain(void)",
926              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
927              << "The local domain is wrongly defined,"
928              << " check the attributes 'ni_glo' (" << ni_glo.getValue() << "), 'ni' (" << ni.getValue() << ") and 'ibegin' (" << ibegin.getValue() << ")");
929      }
930   }
931   CATCH_DUMP_ATTR
932
933   // Check validity of local domain on using the combination of 3 parameters: jbegin, nj and j_index
934   void CDomain::checkLocalJDomain(void)
935   TRY
936   {
937    // If jbegin and nj are provided then we use them to check the validity of local domain
938     if (j_index.isEmpty() && !jbegin.isEmpty() && !nj.isEmpty())
939     {
940       if ((nj.getValue() < 0 || jbegin.getValue() < 0) || (jbegin.getValue() + nj.getValue()) > nj_glo.getValue())
941       {
942         ERROR("CDomain::checkLocalJDomain(void)",
943                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
944                << "The local domain is wrongly defined,"
945                << " check the attributes 'nj_glo' (" << nj_glo.getValue() << "), 'nj' (" << nj.getValue() << ") and 'jbegin' (" << jbegin.getValue() << ")");
946       }
947     }
948
949     if (!j_index.isEmpty())
950     {
951        int minJIndex = (0 < j_index.numElements()) ? j_index(0) : 0;
952        if (nj.isEmpty()) 
953        {
954          // No information about nj
955          int minIndex = nj_glo - 1;
956          int maxIndex = 0;
957          for (int idx = 0; idx < j_index.numElements(); ++idx)
958          {
959            if (j_index(idx) < minIndex) minIndex = j_index(idx);
960            if (j_index(idx) > maxIndex) maxIndex = j_index(idx);
961          }
962          nj = maxIndex - minIndex + 1;
963          minJIndex = minIndex; 
964        } 
965        // It's the same as checkLocalIDomain. It's not so correct but if jbegin is not the first value of j_index
966        // then data on local domain has user-defined distribution. In this case, jbegin has no meaning.
967       if (jbegin.isEmpty()) jbegin = minJIndex;       
968     }
969     else if (jbegin.isEmpty() && nj.isEmpty())
970     {
971       jbegin = 0;
972       nj = nj_glo;
973     }     
974
975
976     if ((nj.getValue() < 0 || jbegin.getValue() < 0))
977     {
978       ERROR("CDomain::checkLocalJDomain(void)",
979              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
980              << "The local domain is wrongly defined,"
981              << " check the attributes 'nj_glo' (" << nj_glo.getValue() << "), 'nj' (" << nj.getValue() << ") and 'jbegin' (" << jbegin.getValue() << ")");
982     }
983   }
984   CATCH_DUMP_ATTR
985
986   //----------------------------------------------------------------
987
988   void CDomain::checkMask(void)
989   TRY
990   {
991      if (!mask_1d.isEmpty() && !mask_2d.isEmpty())
992        ERROR("CDomain::checkMask(void)",
993              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
994              << "Both mask_1d and mask_2d are defined but only one can be used at the same time." << std::endl
995              << "Please define only one mask: 'mask_1d' or 'mask_2d'.");
996
997      if (!mask_1d.isEmpty() && mask_2d.isEmpty())
998      {
999        if (mask_1d.numElements() != i_index.numElements())
1000          ERROR("CDomain::checkMask(void)",
1001                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1002                << "'mask_1d' does not have the same size as the local domain." << std::endl
1003                << "Local size is " << i_index.numElements() << "." << std::endl
1004                << "Mask size is " << mask_1d.numElements() << ".");
1005      }
1006
1007      if (mask_1d.isEmpty() && !mask_2d.isEmpty())
1008      {
1009        if (mask_2d.extent(0) != ni || mask_2d.extent(1) != nj)
1010          ERROR("CDomain::checkMask(void)",
1011                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1012                << "The mask does not have the same size as the local domain." << std::endl
1013                << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1014                << "Mask size is " << mask_2d.extent(0) << " x " << mask_2d.extent(1) << ".");
1015      }
1016
1017      if (!mask_2d.isEmpty())
1018      {
1019        domainMask.resize(mask_2d.extent(0) * mask_2d.extent(1));
1020        for (int j = 0; j < nj; ++j)
1021          for (int i = 0; i < ni; ++i) domainMask(i+j*ni) = mask_2d(i,j);
1022//        mask_2d.reset();
1023      }
1024      else if (mask_1d.isEmpty())
1025      {
1026        domainMask.resize(i_index.numElements());
1027        for (int i = 0; i < i_index.numElements(); ++i) domainMask(i) = true;
1028      }
1029      else
1030      {
1031      domainMask.resize(mask_1d.numElements());
1032      domainMask=mask_1d ;
1033     }
1034   }
1035   CATCH_DUMP_ATTR
1036
1037   //----------------------------------------------------------------
1038
1039   void CDomain::checkDomainData(void)
1040   TRY
1041   {
1042      if (data_dim.isEmpty())
1043      {
1044        data_dim.setValue(1);
1045      }
1046      else if (!(data_dim.getValue() == 1 || data_dim.getValue() == 2))
1047      {
1048        ERROR("CDomain::checkDomainData(void)",
1049              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1050              << "The data dimension is invalid, 'data_dim' must be 1 or 2 not << " << data_dim.getValue() << ".");
1051      }
1052
1053      if (data_ibegin.isEmpty())
1054         data_ibegin.setValue(0);
1055      if (data_jbegin.isEmpty())
1056         data_jbegin.setValue(0);
1057
1058      if (data_ni.isEmpty())
1059      {
1060        data_ni.setValue((data_dim == 1) ? (ni.getValue() * nj.getValue()) : ni.getValue());
1061      }
1062      else if (data_ni.getValue() < 0)
1063      {
1064        ERROR("CDomain::checkDomainData(void)",
1065              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1066              << "The data size cannot be negative ('data_ni' = " << data_ni.getValue() << ").");
1067      }
1068
1069      if (data_nj.isEmpty())
1070      {
1071        data_nj.setValue((data_dim.getValue() == 1) ? (ni.getValue() * nj.getValue()) : nj.getValue());
1072      }
1073      else if (data_nj.getValue() < 0)
1074      {
1075        ERROR("CDomain::checkDomainData(void)",
1076              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1077              << "The data size cannot be negative ('data_nj' = " << data_nj.getValue() << ").");
1078      }
1079   }
1080   CATCH_DUMP_ATTR
1081
1082   //----------------------------------------------------------------
1083
1084   void CDomain::checkCompression(void)
1085   TRY
1086   {
1087     int i,j,ind;
1088      if (!data_i_index.isEmpty())
1089      {
1090        if (!data_j_index.isEmpty() &&
1091            data_j_index.numElements() != data_i_index.numElements())
1092        {
1093           ERROR("CDomain::checkCompression(void)",
1094                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1095                 << "'data_i_index' and 'data_j_index' arrays must have the same size." << std::endl
1096                 << "'data_i_index' size = " << data_i_index.numElements() << std::endl
1097                 << "'data_j_index' size = " << data_j_index.numElements());
1098        }
1099
1100        if (2 == data_dim)
1101        {
1102          if (data_j_index.isEmpty())
1103          {
1104             ERROR("CDomain::checkCompression(void)",
1105                   << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1106                   << "'data_j_index' must be defined when 'data_i_index' is set and 'data_dim' is 2.");
1107          }
1108          for (int k=0; k<data_i_index.numElements(); ++k)
1109          {
1110            i = data_i_index(k)+data_ibegin ;
1111            j = data_j_index(k)+data_jbegin ;
1112            if (i>=0 && i<ni && j>=0 && j<nj)
1113            {
1114              ind=j*ni+i ;
1115              if (!domainMask(ind))
1116              {
1117                data_i_index(k) = -1;
1118                data_j_index(k) = -1;
1119              }
1120            }
1121            else
1122            {
1123              data_i_index(k) = -1;
1124              data_j_index(k) = -1;
1125            }
1126          }
1127        }
1128        else // (1 == data_dim)
1129        {
1130          if (data_j_index.isEmpty())
1131          {
1132            data_j_index.resize(data_ni);
1133            data_j_index = 0;
1134          }
1135          for (int k=0; k<data_i_index.numElements(); ++k)
1136          {
1137            i=data_i_index(k)+data_ibegin ;
1138            if (i>=0 && i < domainMask.size())
1139            {
1140              if (!domainMask(i)) data_i_index(k) = -1;
1141            }
1142            else
1143              data_i_index(k) = -1;
1144
1145            if (!domainMask(i)) data_i_index(k) = -1;
1146          }
1147        }
1148      }
1149      else
1150      {
1151        if (data_dim == 2 && !data_j_index.isEmpty())
1152          ERROR("CDomain::checkCompression(void)",
1153                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1154                << "'data_i_index' must be defined when 'data_j_index' is set and 'data_dim' is 2.");
1155
1156        if (1 == data_dim)
1157        {
1158          data_i_index.resize(data_ni);
1159          data_j_index.resize(data_ni);
1160          data_j_index = 0;
1161
1162          for (int k = 0; k < data_ni; ++k)
1163          {
1164            i=k+data_ibegin ;
1165            if (i>=0 && i < domainMask.size())
1166            {
1167              if (domainMask(i))
1168                data_i_index(k) = k;
1169              else
1170                data_i_index(k) = -1;
1171            }
1172            else
1173              data_i_index(k) = -1;
1174          }
1175        }
1176        else // (data_dim == 2)
1177        {
1178          const int dsize = data_ni * data_nj;
1179          data_i_index.resize(dsize);
1180          data_j_index.resize(dsize);
1181
1182          for(int count = 0, kj = 0; kj < data_nj; ++kj)
1183          {
1184            for(int ki = 0; ki < data_ni; ++ki, ++count)
1185            {
1186              i = ki + data_ibegin;
1187              j = kj + data_jbegin;
1188              ind=j*ni+i ;
1189              if (i>=0 && i<ni && j>=0 && j<nj)
1190              {
1191                if (domainMask(ind))
1192                {
1193                  data_i_index(count) = ki;
1194                  data_j_index(count) = kj;
1195                }
1196                else
1197                {
1198                  data_i_index(count) = -1;
1199                  data_j_index(count) = -1;
1200                }
1201              }
1202              else
1203              {
1204                data_i_index(count) = -1;
1205                data_j_index(count) = -1;
1206              }
1207            }
1208          }
1209        }
1210      }
1211   }
1212   CATCH_DUMP_ATTR
1213
1214   //----------------------------------------------------------------
1215   void CDomain::computeLocalMask(void)
1216   TRY
1217   {
1218     localMask.resize(i_index.numElements()) ;
1219     localMask=false ;
1220
1221     size_t dn=data_i_index.numElements() ;
1222     int i,j ;
1223     size_t k,ind ;
1224
1225     for(k=0;k<dn;k++)
1226     {
1227       if (data_dim==2)
1228       {
1229          i=data_i_index(k)+data_ibegin ;
1230          j=data_j_index(k)+data_jbegin ;
1231          if (i>=0 && i<ni && j>=0 && j<nj)
1232          {
1233            ind=j*ni+i ;
1234            localMask(ind)=domainMask(ind) ;
1235          }
1236       }
1237       else
1238       {
1239          i=data_i_index(k)+data_ibegin ;
1240          if (i>=0 && i<i_index.numElements())
1241          {
1242            ind=i ;
1243            localMask(ind)=domainMask(ind) ;
1244          }
1245       }
1246     }
1247   }
1248   CATCH_DUMP_ATTR
1249
1250
1251   //----------------------------------------------------------------
1252
1253   /*
1254     Fill in longitude, latitude, bounds, and area into internal values (lonvalue, latvalue, bounds_lonvalue, bounds_latvalue, areavalue)
1255     which will be used by XIOS.
1256   */
1257   void CDomain::completeLonLatClient(void)
1258   TRY
1259   {
1260     bool lonlatValueExisted = (0 != lonvalue.numElements()) || (0 != latvalue.numElements());
1261     checkBounds() ;
1262     checkArea() ;
1263
1264     if (!lonvalue_2d.isEmpty() && !lonlatValueExisted)
1265     {
1266       lonvalue.resize(ni * nj);
1267       latvalue.resize(ni * nj);
1268       if (hasBounds)
1269       {
1270         bounds_lonvalue.resize(nvertex, ni * nj);
1271         bounds_latvalue.resize(nvertex, ni * nj);
1272       }
1273
1274       for (int j = 0; j < nj; ++j)
1275       {
1276         for (int i = 0; i < ni; ++i)
1277         {
1278           int k = j * ni + i;
1279
1280           lonvalue(k) = lonvalue_2d(i,j);
1281           latvalue(k) = latvalue_2d(i,j);
1282
1283           if (hasBounds)
1284           {
1285             for (int n = 0; n < nvertex; ++n)
1286             {
1287               bounds_lonvalue(n,k) = bounds_lon_2d(n,i,j);
1288               bounds_latvalue(n,k) = bounds_lat_2d(n,i,j);
1289             }
1290           }
1291         }
1292       }
1293     }
1294     else if (!lonvalue_1d.isEmpty()  && !lonlatValueExisted)
1295     {
1296       if (type_attr::rectilinear == type)
1297       {
1298         if (ni == lonvalue_1d.numElements() && nj == latvalue_1d.numElements())
1299         {
1300           lonvalue.resize(ni * nj);
1301           latvalue.resize(ni * nj);
1302           if (hasBounds)
1303           {
1304             bounds_lonvalue.resize(nvertex, ni * nj);
1305             bounds_latvalue.resize(nvertex, ni * nj);
1306           }
1307
1308           for (int j = 0; j < nj; ++j)
1309           {
1310             for (int i = 0; i < ni; ++i)
1311             {
1312               int k = j * ni + i;
1313
1314               lonvalue(k) = lonvalue_1d(i);
1315               latvalue(k) = latvalue_1d(j);
1316
1317               if (hasBounds)
1318               {
1319                 for (int n = 0; n < nvertex; ++n)
1320                 {
1321                   bounds_lonvalue(n,k) = bounds_lon_1d(n,i);
1322                   bounds_latvalue(n,k) = bounds_lat_1d(n,j);
1323                 }
1324               }
1325             }
1326           }
1327         }
1328         else if (i_index.numElements() == lonvalue_1d.numElements() && j_index.numElements() == latvalue_1d.numElements()  && !lonlatValueExisted)
1329         {
1330           lonvalue.reference(lonvalue_1d);
1331           latvalue.reference(latvalue_1d);
1332            if (hasBounds)
1333           {
1334             bounds_lonvalue.reference(bounds_lon_1d);
1335             bounds_latvalue.reference(bounds_lat_1d);
1336           }
1337         }
1338         else
1339           ERROR("CDomain::completeLonClient(void)",
1340                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1341                 << "'lonvalue_1d' and 'latvalue_1d' does not have the same size as the local domain." << std::endl
1342                 << "'lonvalue_1d' size is " << lonvalue_1d.numElements() 
1343                 << " and 'latvalue_1d' size is " << latvalue_1d.numElements() << std::endl
1344                 << " They should be correspondingly " << ni.getValue() << " and "  << nj.getValue() << " or " << std::endl
1345                 << i_index.numElements() << " and "  << j_index.numElements() << ".");
1346       }
1347       else if (type == type_attr::curvilinear || type == type_attr::unstructured  && !lonlatValueExisted)
1348       {
1349         lonvalue.reference(lonvalue_1d);
1350         latvalue.reference(latvalue_1d);
1351         if (hasBounds)
1352         {
1353           bounds_lonvalue.reference(bounds_lon_1d);
1354           bounds_latvalue.reference(bounds_lat_1d);
1355         }
1356       }
1357     }
1358
1359     if (!area.isEmpty() && areavalue.isEmpty())
1360     {
1361        areavalue.resize(ni*nj);
1362       for (int j = 0; j < nj; ++j)
1363       {
1364         for (int i = 0; i < ni; ++i)
1365         {
1366           int k = j * ni + i;
1367           areavalue(k) = area(i,j);
1368         }
1369       }
1370     }
1371   }
1372   CATCH_DUMP_ATTR
1373
1374   /*
1375     Convert internal longitude latitude value used by XIOS to "lonvalue_*" which can be retrieved with Fortran interface
1376   */
1377   void CDomain::convertLonLatValue(void)
1378   TRY
1379   {
1380     bool lonlatValueExisted = (0 != lonvalue.numElements()) || (0 != latvalue.numElements());
1381     if (!lonvalue_2d.isEmpty() && lonlatValueExisted)
1382     {
1383       lonvalue_2d.resize(ni,nj);
1384       latvalue_2d.resize(ni,nj);
1385       if (hasBounds)
1386       {
1387         bounds_lon_2d.resize(nvertex, ni, nj);
1388         bounds_lat_2d.resize(nvertex, ni, nj);
1389       }
1390
1391       for (int j = 0; j < nj; ++j)
1392       {
1393         for (int i = 0; i < ni; ++i)
1394         {
1395           int k = j * ni + i;
1396
1397           lonvalue_2d(i,j) = lonvalue(k);
1398           latvalue_2d(i,j) = latvalue(k);
1399
1400           if (hasBounds)
1401           {
1402             for (int n = 0; n < nvertex; ++n)
1403             {
1404               bounds_lon_2d(n,i,j) = bounds_lonvalue(n,k);
1405               bounds_lat_2d(n,i,j) = bounds_latvalue(n,k);
1406             }
1407           }
1408         }
1409       }
1410     }
1411     else if (!lonvalue_1d.isEmpty()  && lonlatValueExisted)
1412     {
1413       if (type_attr::rectilinear == type)
1414       {
1415         if (ni == lonvalue_1d.numElements() && nj == latvalue_1d.numElements())
1416         {
1417           lonvalue.resize(ni * nj);
1418           latvalue.resize(ni * nj);
1419           if (hasBounds)
1420           {
1421             bounds_lonvalue.resize(nvertex, ni * nj);
1422             bounds_latvalue.resize(nvertex, ni * nj);
1423           }
1424
1425           for (int j = 0; j < nj; ++j)
1426           {
1427             for (int i = 0; i < ni; ++i)
1428             {
1429               int k = j * ni + i;
1430
1431               lonvalue(k) = lonvalue_1d(i);
1432               latvalue(k) = latvalue_1d(j);
1433
1434               if (hasBounds)
1435               {
1436                 for (int n = 0; n < nvertex; ++n)
1437                 {
1438                   bounds_lonvalue(n,k) = bounds_lon_1d(n,i);
1439                   bounds_latvalue(n,k) = bounds_lat_1d(n,j);
1440                 }
1441               }
1442             }
1443           }
1444         }
1445         else if (i_index.numElements() == lonvalue_1d.numElements() && j_index.numElements() == latvalue_1d.numElements()  && !lonlatValueExisted)
1446         {
1447           lonvalue.reference(lonvalue_1d);
1448           latvalue.reference(latvalue_1d);
1449            if (hasBounds)
1450           {
1451             bounds_lonvalue.reference(bounds_lon_1d);
1452             bounds_latvalue.reference(bounds_lat_1d);
1453           }
1454         }
1455         else
1456           ERROR("CDomain::completeLonClient(void)",
1457                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1458                 << "'lonvalue_1d' and 'latvalue_1d' does not have the same size as the local domain." << std::endl
1459                 << "'lonvalue_1d' size is " << lonvalue_1d.numElements() 
1460                 << " and 'latvalue_1d' size is " << latvalue_1d.numElements() << std::endl
1461                 << " They should be correspondingly " << ni.getValue() << " and "  << nj.getValue() << " or " << std::endl
1462                 << i_index.numElements() << " and "  << j_index.numElements() << ".");
1463       }
1464       else if (type == type_attr::curvilinear || type == type_attr::unstructured  && !lonlatValueExisted)
1465       {
1466         lonvalue.reference(lonvalue_1d);
1467         latvalue.reference(latvalue_1d);
1468         if (hasBounds)
1469         {
1470           bounds_lonvalue.reference(bounds_lon_1d);
1471           bounds_latvalue.reference(bounds_lat_1d);
1472         }
1473       }
1474     }
1475   }
1476   CATCH_DUMP_ATTR
1477
1478   void CDomain::checkBounds(void)
1479   TRY
1480   {
1481     bool hasBoundValues = (0 != bounds_lonvalue.numElements()) || (0 != bounds_latvalue.numElements());
1482     if (!nvertex.isEmpty() && nvertex > 0 && !hasBoundValues)
1483     {
1484       if (!bounds_lon_1d.isEmpty() && !bounds_lon_2d.isEmpty())
1485         ERROR("CDomain::checkBounds(void)",
1486               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1487               << "Only one longitude boundary attribute can be used but both 'bounds_lon_1d' and 'bounds_lon_2d' are defined." << std::endl
1488               << "Define only one longitude boundary attribute: 'bounds_lon_1d' or 'bounds_lon_2d'.");
1489
1490       if (!bounds_lat_1d.isEmpty() && !bounds_lat_2d.isEmpty())
1491         ERROR("CDomain::checkBounds(void)",
1492               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1493               << "Only one latitude boundary attribute can be used but both 'bounds_lat_1d' and 'bounds_lat_2d' are defined." << std::endl
1494               << "Define only one latitude boundary attribute: 'bounds_lat_1d' or 'bounds_lat_2d'.");
1495
1496       if ((!bounds_lon_1d.isEmpty() && bounds_lat_1d.isEmpty()) || (bounds_lon_1d.isEmpty() && !bounds_lat_1d.isEmpty()))
1497       {
1498         ERROR("CDomain::checkBounds(void)",
1499               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1500               << "Only 'bounds_lon_1d' or 'bounds_lat_1d' is defined." << std::endl
1501               << "Please define either both attributes or none.");
1502       }
1503
1504       if ((!bounds_lon_2d.isEmpty() && bounds_lat_2d.isEmpty()) || (bounds_lon_2d.isEmpty() && !bounds_lat_2d.isEmpty()))
1505       {
1506         ERROR("CDomain::checkBounds(void)",
1507               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1508               << "Only 'bounds_lon_2d' or 'bounds_lat_2d' is defined." << std::endl
1509               << "Please define either both attributes or none.");
1510       }
1511
1512       if (!bounds_lon_1d.isEmpty() && nvertex.getValue() != bounds_lon_1d.extent(0))
1513         ERROR("CDomain::checkBounds(void)",
1514               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1515               << "'bounds_lon_1d' dimension is not compatible with 'nvertex'." << std::endl
1516               << "'bounds_lon_1d' dimension is " << bounds_lon_1d.extent(0)
1517               << " but nvertex is " << nvertex.getValue() << ".");
1518
1519       if (!bounds_lon_2d.isEmpty() && nvertex.getValue() != bounds_lon_2d.extent(0))
1520         ERROR("CDomain::checkBounds(void)",
1521               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1522               << "'bounds_lon_2d' dimension is not compatible with 'nvertex'." << std::endl
1523               << "'bounds_lon_2d' dimension is " << bounds_lon_2d.extent(0)
1524               << " but nvertex is " << nvertex.getValue() << ".");
1525
1526       if (!bounds_lon_1d.isEmpty() && lonvalue_1d.isEmpty())
1527         ERROR("CDomain::checkBounds(void)",
1528               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1529               << "Since 'bounds_lon_1d' is defined, 'lonvalue_1d' must be defined too." << std::endl);
1530
1531       if (!bounds_lon_2d.isEmpty() && lonvalue_2d.isEmpty())
1532         ERROR("CDomain::checkBounds(void)",
1533               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1534               << "Since 'bounds_lon_2d' is defined, 'lonvalue_2d' must be defined too." << std::endl);
1535
1536       if (!bounds_lat_1d.isEmpty() && nvertex.getValue() != bounds_lat_1d.extent(0))
1537         ERROR("CDomain::checkBounds(void)",
1538               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1539               << "'bounds_lat_1d' dimension is not compatible with 'nvertex'." << std::endl
1540               << "'bounds_lat_1d' dimension is " << bounds_lat_1d.extent(0)
1541               << " but nvertex is " << nvertex.getValue() << ".");
1542
1543       if (!bounds_lat_2d.isEmpty() && nvertex.getValue() != bounds_lat_2d.extent(0))
1544         ERROR("CDomain::checkBounds(void)",
1545               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1546               << "'bounds_lat_2d' dimension is not compatible with 'nvertex'." << std::endl
1547               << "'bounds_lat_2d' dimension is " << bounds_lat_2d.extent(0)
1548               << " but nvertex is " << nvertex.getValue() << ".");
1549
1550       if (!bounds_lat_1d.isEmpty() && latvalue_1d.isEmpty())
1551         ERROR("CDomain::checkBounds(void)",
1552               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1553               << "Since 'bounds_lat_1d' is defined, 'latvalue_1d' must be defined too." << std::endl);
1554
1555       if (!bounds_lat_2d.isEmpty() && latvalue_2d.isEmpty())
1556         ERROR("CDomain::checkBounds(void)",
1557               << "Since 'bounds_lat_2d' is defined, 'latvalue_2d' must be defined too." << std::endl);
1558
1559       // In case of reading UGRID bounds values are not required
1560       hasBounds = (!bounds_lat_1d.isEmpty() || !bounds_lat_2d.isEmpty() );
1561     }
1562     else if (hasBoundValues)
1563     {
1564       hasBounds = true;       
1565     }
1566     else
1567     {
1568       hasBounds = false;
1569     }
1570   }
1571   CATCH_DUMP_ATTR
1572
1573   void CDomain::checkArea(void)
1574   TRY
1575   {
1576     bool hasAreaValue = (!areavalue.isEmpty() && 0 != areavalue.numElements());
1577     hasArea = !area.isEmpty();
1578     if (hasArea && !hasAreaValue)
1579     {
1580       if (area.extent(0) != ni || area.extent(1) != nj)
1581       {
1582         ERROR("CDomain::checkArea(void)",
1583               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1584               << "The area does not have the same size as the local domain." << std::endl
1585               << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1586               << "Area size is " << area.extent(0) << " x " << area.extent(1) << ".");
1587       }
1588//       if (areavalue.isEmpty())
1589//       {
1590//          areavalue.resize(ni*nj);
1591//         for (int j = 0; j < nj; ++j)
1592//         {
1593//           for (int i = 0; i < ni; ++i)
1594//           {
1595//             int k = j * ni + i;
1596//             areavalue(k) = area(i,j);
1597//           }
1598//         }
1599//       }
1600     }
1601   }
1602   CATCH_DUMP_ATTR
1603
1604   void CDomain::checkLonLat()
1605   TRY
1606   {
1607     if (!hasLonLat) hasLonLat = (!latvalue_1d.isEmpty() && !lonvalue_1d.isEmpty()) ||
1608                                 (!latvalue_2d.isEmpty() && !lonvalue_2d.isEmpty());
1609     bool hasLonLatValue = (0 != lonvalue.numElements()) || (0 != latvalue.numElements());
1610     if (hasLonLat && !hasLonLatValue)
1611     {
1612       if (!lonvalue_1d.isEmpty() && !lonvalue_2d.isEmpty())
1613         ERROR("CDomain::checkLonLat()",
1614               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1615               << "Only one longitude attribute can be used but both 'lonvalue_1d' and 'lonvalue_2d' are defined." << std::endl
1616               << "Define only one longitude attribute: 'lonvalue_1d' or 'lonvalue_2d'.");
1617
1618       if (!lonvalue_1d.isEmpty() && lonvalue_2d.isEmpty())
1619       {
1620         if ((type_attr::rectilinear != type) && (lonvalue_1d.numElements() != i_index.numElements()))
1621           ERROR("CDomain::checkLonLat()",
1622                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1623                 << "'lonvalue_1d' does not have the same size as the local domain." << std::endl
1624                 << "Local size is " << i_index.numElements() << "." << std::endl
1625                 << "'lonvalue_1d' size is " << lonvalue_1d.numElements() << ".");
1626       }
1627
1628       if (lonvalue_1d.isEmpty() && !lonvalue_2d.isEmpty())
1629       {
1630         if (lonvalue_2d.extent(0) != ni || lonvalue_2d.extent(1) != nj)
1631           ERROR("CDomain::checkLonLat()",
1632                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1633                 << "'lonvalue_2d' does not have the same size as the local domain." << std::endl
1634                 << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1635                 << "'lonvalue_2d' size is " << lonvalue_2d.extent(0) << " x " << lonvalue_2d.extent(1) << ".");
1636       }
1637
1638       if (!latvalue_1d.isEmpty() && !latvalue_2d.isEmpty())
1639         ERROR("CDomain::checkLonLat()",
1640               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1641               << "Only one latitude attribute can be used but both 'latvalue_1d' and 'latvalue_2d' are defined." << std::endl
1642               << "Define only one latitude attribute: 'latvalue_1d' or 'latvalue_2d'.");
1643
1644       if (!latvalue_1d.isEmpty() && latvalue_2d.isEmpty())
1645       {
1646         if ((type_attr::rectilinear != type) && (latvalue_1d.numElements() != i_index.numElements()))
1647           ERROR("CDomain::checkLonLat()",
1648                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1649                 << "'latvalue_1d' does not have the same size as the local domain." << std::endl
1650                 << "Local size is " << i_index.numElements() << "." << std::endl
1651                 << "'latvalue_1d' size is " << latvalue_1d.numElements() << ".");
1652       }
1653
1654       if (latvalue_1d.isEmpty() && !latvalue_2d.isEmpty())
1655       {
1656         if (latvalue_2d.extent(0) != ni || latvalue_2d.extent(1) != nj)
1657           ERROR("CDomain::checkLonLat()",
1658                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1659                 << "'latvalue_2d' does not have the same size as the local domain." << std::endl
1660                 << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1661                 << "'latvalue_2d' size is " << latvalue_2d.extent(0) << " x " << latvalue_2d.extent(1) << ".");
1662       }
1663     }
1664   }
1665   CATCH_DUMP_ATTR
1666
1667   void CDomain::checkAttributes(void)
1668   TRY
1669   {
1670      if (this->checkAttributes_done_) return;
1671      this->checkDomain();
1672      this->checkLonLat();
1673      this->checkBounds();
1674      this->checkArea();
1675      this->checkMask();
1676      this->checkDomainData();
1677      this->checkCompression();
1678      this->computeLocalMask() ;
1679      this->completeLonLatClient();
1680      this->initializeLocalElement() ;
1681      this->addFullView() ; // probably do not automatically add View, but only if requested
1682      this->addWorkflowView() ; // probably do not automatically add View, but only if requested
1683      this->addModelView() ; // probably do not automatically add View, but only if requested
1684      // testing ?
1685     /*
1686      CLocalView* local = localElement_->getView(CElementView::WORKFLOW) ;
1687      CLocalView* model = localElement_->getView(CElementView::MODEL) ;
1688
1689      CLocalConnector test1(model, local) ;
1690      test1.computeConnector() ;
1691      CLocalConnector test2(local, model) ;
1692      test2.computeConnector() ;
1693      CGridLocalConnector gridTest1(vector<CLocalConnector*>{&test1}) ;
1694      CGridLocalConnector gridTest2(vector<CLocalConnector*>{&test2}) ;
1695     
1696     
1697      CArray<int,1> out1 ;
1698      CArray<int,1> out2 ;
1699      test1.transfer(data_i_index,out1,-111) ;
1700      test2.transfer(out1,out2,-111) ;
1701     
1702      out1 = 0 ;
1703      out2 = 0 ;
1704      gridTest1.transfer(data_i_index,out1,-111) ;
1705      gridTest2.transfer(out1, out2,-111) ;
1706    */ 
1707      this->checkAttributes_done_ = true;
1708   }
1709   CATCH_DUMP_ATTR
1710
1711
1712   void CDomain::initializeLocalElement(void)
1713   {
1714      // after checkDomain i_index and j_index of size (ni*nj)
1715      int nij = ni*nj ;
1716      CArray<size_t, 1> ij_index(ni*nj) ;
1717      for(int ij=0; ij<nij ; ij++) ij_index(ij) = i_index(ij)+j_index(ij)*ni_glo ;
1718      int rank = CContext::getCurrent()->getIntraCommRank() ;
1719      localElement_ = new CLocalElement(rank, ni_glo*nj_glo, ij_index) ;
1720   }
1721
1722   void CDomain::addFullView(void)
1723   {
1724      CArray<int,1> index(ni*nj) ;
1725      int nij=ni*nj ;
1726      for(int ij=0; ij<nij ; ij++) index(ij)=ij ;
1727      localElement_ -> addView(CElementView::FULL, index) ;
1728   }
1729
1730   void CDomain::addWorkflowView(void)
1731   {
1732     // information for workflow view is stored in localMask
1733     int nij=ni*nj ;
1734     int nMask=0 ;
1735     for(int ij=0; ij<nij ; ij++) if (localMask(ij)) nMask++ ;
1736     CArray<int,1> index(nMask) ;
1737
1738     nMask=0 ;
1739     for(int ij=0; ij<nij ; ij++) 
1740      if (localMask(ij))
1741      {
1742        index(nMask)=ij ;
1743        nMask++ ;
1744      }
1745      localElement_ -> addView(CElementView::WORKFLOW, index) ;
1746   }
1747
1748   void CDomain::addModelView(void)
1749   {
1750     // information for model view is stored in data_i_index/data_j_index
1751     // very weird, do not mix data_i_index and data_i_begin => in future only keep data_i_index
1752     int dataSize = data_i_index.numElements() ;
1753     CArray<int,1> index(dataSize) ;
1754     int i,j ;
1755     for(int k=0;k<dataSize;k++)
1756     {
1757        if (data_dim==2)
1758        {
1759          i=data_i_index(k)+data_ibegin ; // bad
1760          j=data_j_index(k)+data_jbegin ; // bad
1761          if (i>=0 && i<ni && j>=0 && j<nj) index(k)=i+j*ni ;
1762          else index(k)=-1 ;
1763        }
1764        else if (data_dim==1)
1765        {
1766          i=data_i_index(k)+data_ibegin ; // bad
1767          if (i>=0 && i<ni*nj) index(k)=i ;
1768          else index(k)=-1 ;
1769        }
1770     }
1771     localElement_->addView(CElementView::MODEL, index) ;
1772   }
1773       
1774   void CDomain::computeModelToWorkflowConnector(void)
1775   { 
1776     CLocalView* srcView=getLocalView(CElementView::MODEL) ;
1777     CLocalView* dstView=getLocalView(CElementView::WORKFLOW) ;
1778     modelToWorkflowConnector_ = new CLocalConnector(srcView, dstView); 
1779     modelToWorkflowConnector_->computeConnector() ;
1780   }
1781
1782
1783  string CDomain::getCouplingAlias(const string& fieldId, int posInGrid)
1784  {
1785    return "_domain["+std::to_string(posInGrid)+"]_of_"+fieldId ;
1786  }
1787   
1788  /* to be removed later when coupling will be reimplemented, just to  not forget */
1789  void CDomain::sendDomainToCouplerOut(CContextClient* client, const string& fieldId, int posInGrid)
1790  {
1791    if (sendDomainToFileServer_done_.count(client)!=0) return ;
1792    else sendDomainToFileServer_done_.insert(client) ;
1793   
1794    const string domainId = getCouplingAlias(fieldId, posInGrid) ;
1795   
1796    if (!domain_ref.isEmpty())
1797    {
1798      auto domain_ref_tmp=domain_ref.getValue() ;
1799      domain_ref.reset() ; // remove the reference, find an other way to do that more cleanly
1800      this->sendAllAttributesToServer(client, domainId)  ;
1801      domain_ref = domain_ref_tmp ;
1802    }
1803    else this->sendAllAttributesToServer(client, domainId)  ;
1804  }
1805
1806
1807
1808
1809  void CDomain::makeAliasForCoupling(const string& fieldId, int posInGrid)
1810  {
1811    const string domainId = getCouplingAlias(fieldId, posInGrid);
1812    this->createAlias(domainId) ;
1813  }
1814
1815
1816  void CDomain::computeRemoteElement(CContextClient* client, EDistributionType type)
1817  TRY
1818  {
1819    CContext* context = CContext::getCurrent();
1820    map<int, CArray<size_t,1>> globalIndex ;
1821
1822    if (type==EDistributionType::BANDS) // Bands distribution to send to file server
1823    {
1824      int nbServer = client->serverSize;
1825      std::vector<int> nGlobDomain(2);
1826      nGlobDomain[0] = this->ni_glo;
1827      nGlobDomain[1] = this->nj_glo;
1828
1829      // to be changed in future, need to rewrite more simply domain distribution
1830      CServerDistributionDescription serverDescription(nGlobDomain, nbServer);
1831      int distributedPosition ;
1832      if (isUnstructed_) distributedPosition = 0 ;
1833      else distributedPosition = 1 ;
1834     
1835      std::vector<std::vector<int> > serverIndexBegin = serverDescription.getServerIndexBegin();
1836      std::vector<std::vector<int> > serverDimensionSizes = serverDescription.getServerDimensionSizes();
1837      vector<unordered_map<size_t,vector<int>>> indexServerOnElement ;
1838      CArray<int,1> axisDomainOrder(1) ; axisDomainOrder(0)=2 ;
1839      auto zeroIndex=serverDescription.computeServerGlobalByElement(indexServerOnElement, context->getIntraCommRank(), context->getIntraCommSize(),
1840                                                                  axisDomainOrder,distributedPosition) ;
1841      // distribution is very bad => to redo
1842      // convert indexServerOnElement => map<int,CArray<size_t,1>> - need to be changed later
1843      map<int, vector<size_t>> vectGlobalIndex ;
1844      for(auto& indexRanks : indexServerOnElement[0])
1845      {
1846        size_t index=indexRanks.first ;
1847        auto& ranks=indexRanks.second ;
1848        for(int rank : ranks) vectGlobalIndex[rank].push_back(index) ;
1849      }
1850      for(auto& vect : vectGlobalIndex ) globalIndex.emplace(vect.first, CArray<size_t,1>(vect.second.data(), shape(vect.second.size()),duplicateData)) ;
1851    // some servers receves no index (zeroIndex array) => root process take them into account.
1852      if (context->getIntraCommRank()==0) 
1853        for(auto& rank : zeroIndex) globalIndex[rank] = CArray<size_t,1>() ; 
1854    }
1855    else if (type==EDistributionType::NONE) // domain is not distributed ie all servers get the same local domain
1856    {
1857      int nbServer = client->serverSize;
1858      int nglo=ni_glo*nj_glo ;
1859      CArray<size_t,1> indGlo ;
1860      for(size_t i=0;i<nglo;i++) indGlo(i) = i ;
1861      for (auto& rankServer : client->getRanksServerLeader()) globalIndex[rankServer] = indGlo ; 
1862    }
1863    remoteElement_[client] = new CDistributedElement(ni_glo*nj_glo, globalIndex) ;
1864    remoteElement_[client]->addFullView() ;
1865  }
1866  CATCH
1867
1868 
1869
1870  void CDomain::distributeToServer(CContextClient* client, map<int, CArray<size_t,1>>& globalIndex,
1871                                   CScattererConnector* &scattererConnector, const string& domainId)
1872  TRY
1873  {
1874    string serverDomainId = domainId.empty() ? this->getId() : domainId ;
1875    CContext* context = CContext::getCurrent();
1876
1877    this->sendAllAttributesToServer(client, serverDomainId)  ;
1878
1879    CDistributedElement scatteredElement(ni_glo*nj_glo, globalIndex) ;
1880    scatteredElement.addFullView() ;
1881    scattererConnector = new CScattererConnector(localElement_->getView(CElementView::FULL), scatteredElement.getView(CElementView::FULL), 
1882                                           context->getIntraComm(), client->getRemoteSize()) ;
1883    scattererConnector->computeConnector() ;
1884
1885    // phase 0
1886    // send remote element to construct the full view on server, ie without hole
1887    CEventClient event0(getType(), EVENT_ID_DOMAIN_DISTRIBUTION);
1888    CMessage message0 ;
1889    message0<<serverDomainId<<0 ; 
1890    remoteElement_[client]->sendToServer(client,event0,message0) ; 
1891   
1892    // phase 1
1893    // send the full view of element to construct the connector which connect distributed data coming from client to the full local view
1894    CEventClient event1(getType(), EVENT_ID_DOMAIN_DISTRIBUTION);
1895    CMessage message1 ;
1896    message1<<serverDomainId<<1<<localElement_->getView(CElementView::FULL)->getGlobalSize() ; 
1897    scattererConnector->transfer(localElement_->getView(CElementView::FULL)->getGlobalIndex(),client,event1,message1) ;
1898   
1899    sendDistributedAttributes(client, *scattererConnector, domainId) ;
1900
1901 
1902    // phase 2 send the mask : data index + mask2D
1903    CArray<bool,1> maskIn(localElement_->getView(CElementView::WORKFLOW)->getSize());
1904    CArray<bool,1> maskOut ;
1905    CLocalConnector workflowToFull(localElement_->getView(CElementView::WORKFLOW), localElement_->getView(CElementView::FULL)) ;
1906    workflowToFull.computeConnector() ;
1907    maskIn=true ;
1908    workflowToFull.transfer(maskIn,maskOut,false) ;
1909
1910
1911    // phase 3 : prepare grid scatterer connector to send data from client to server
1912    map<int,CArray<size_t,1>> workflowGlobalIndex ;
1913    map<int,CArray<bool,1>> maskOut2 ; 
1914    scattererConnector->transfer(maskOut, maskOut2, false) ;
1915    scatteredElement.addView(CElementView::WORKFLOW, maskOut2) ;
1916    scatteredElement.getView(CElementView::WORKFLOW)->getGlobalIndexView(workflowGlobalIndex) ;
1917    // create new workflow view for scattered element
1918    CDistributedElement clientToServerElement(scatteredElement.getGlobalSize(), workflowGlobalIndex) ;
1919    clientToServerElement.addFullView() ;
1920    CEventClient event2(getType(), EVENT_ID_DOMAIN_DISTRIBUTION);
1921    CMessage message2 ;
1922    message2<<serverDomainId<<2 ; 
1923    clientToServerElement.sendToServer(client, event2, message2) ; 
1924    clientToServerConnector_[client] = new CScattererConnector(localElement_->getView(CElementView::WORKFLOW), clientToServerElement.getView(CElementView::FULL),
1925                                                               context->getIntraComm(), client->getRemoteSize()) ;
1926    clientToServerConnector_[client]->computeConnector() ;
1927
1928    clientFromServerConnector_[client] = new CGathererConnector(clientToServerElement.getView(CElementView::FULL), localElement_->getView(CElementView::WORKFLOW));
1929    clientFromServerConnector_[client]->computeConnector() ;
1930
1931  }
1932  CATCH
1933 
1934  void CDomain::recvDomainDistribution(CEventServer& event)
1935  TRY
1936  {
1937    string domainId;
1938    int phasis ;
1939    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> domainId >> phasis ;
1940    get(domainId)->receivedDomainDistribution(event, phasis);
1941  }
1942  CATCH
1943
1944  void CDomain::receivedDomainDistribution(CEventServer& event, int phasis)
1945  TRY
1946  {
1947    CContext* context = CContext::getCurrent();
1948    if (phasis==0) // receive the remote element to construct the full view
1949    {
1950      localElement_ = new  CLocalElement(context->getIntraCommRank(),event) ;
1951      localElement_->addFullView() ;
1952      // construct the local dimension and indexes
1953      auto& globalIndex=localElement_->getGlobalIndex() ;
1954      int nij=globalIndex.numElements() ;
1955      int minI=ni_glo,maxI=-1,minJ=nj_glo,maxJ=-1 ;
1956      int i,j ;
1957      int niGlo=ni_glo, njGlo=njGlo ;
1958      for(int ij=0;ij<nij;ij++)
1959      {
1960        j=globalIndex(ij)/niGlo ;
1961        i=globalIndex(ij)%niGlo ;
1962        if (i<minI) minI=i ;
1963        if (i>maxI) maxI=i ;
1964        if (j<minJ) minJ=j ;
1965        if (j>maxJ) maxJ=j ;
1966      } 
1967      if (maxI>=minI) { ibegin=minI ; ni=maxI-minI+1 ; }
1968      else {ibegin=0; ni=0 ;}
1969      if (maxJ>=minJ) { jbegin=minJ ; nj=maxJ-minJ+1 ; }
1970      else {jbegin=0; nj=0 ;}
1971
1972    }
1973    else if (phasis==1) // receive the sent view from client to construct the full distributed full view on server
1974    {
1975      CContext* context = CContext::getCurrent();
1976      CDistributedElement* elementFrom = new  CDistributedElement(event) ;
1977      elementFrom->addFullView() ;
1978      gathererConnector_ = new CGathererConnector(elementFrom->getView(CElementView::FULL), localElement_->getView(CElementView::FULL)) ;
1979      gathererConnector_->computeConnector() ; 
1980    }
1981    else if (phasis==2)
1982    {
1983//      delete gathererConnector_ ;
1984      elementFrom_ = new  CDistributedElement(event) ;
1985      elementFrom_->addFullView() ;
1986//      gathererConnector_ =  new CGathererConnector(elementFrom_->getView(CElementView::FULL), localElement_->getView(CElementView::FULL)) ;
1987//      gathererConnector_ -> computeConnector() ;
1988    }
1989  }
1990  CATCH
1991
1992  void CDomain::setServerMask(CArray<bool,1>& serverMask, CContextClient* client)
1993  TRY
1994  {
1995    // nota : the client is needed to get the remote size for the scatterer connector. Maybe it is not the good place for this
1996    // Later, server to client connector can be computed on demand, with "client" as argument
1997    CContext* context = CContext::getCurrent();
1998    localElement_->addView(CElementView::WORKFLOW, serverMask) ;
1999    mask_1d.reference(serverMask.copy()) ;
2000 
2001    serverFromClientConnector_ = new CGathererConnector(elementFrom_->getView(CElementView::FULL), localElement_->getView(CElementView::WORKFLOW)) ;
2002    serverFromClientConnector_->computeConnector() ;
2003     
2004    serverToClientConnector_ = new CScattererConnector(localElement_->getView(CElementView::WORKFLOW), elementFrom_->getView(CElementView::FULL),
2005                                                       context->getIntraComm(), client->getRemoteSize()) ;
2006    serverToClientConnector_->computeConnector() ;
2007  }
2008  CATCH_DUMP_ATTR
2009
2010
2011  void CDomain::sendDistributedAttributes(CContextClient* client, CScattererConnector& scattererConnector,  const string& domainId)
2012  {
2013    string serverDomainId = domainId.empty() ? this->getId() : domainId ;
2014    CContext* context = CContext::getCurrent();
2015
2016    if (hasLonLat)
2017    {
2018      { // send longitude
2019        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
2020        CMessage message ;
2021        message<<serverDomainId<<string("lon") ; 
2022        scattererConnector.transfer(lonvalue, client, event,message) ;
2023      }
2024     
2025      { // send latitude
2026        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
2027        CMessage message ;
2028        message<<serverDomainId<<string("lat") ; 
2029        scattererConnector.transfer(latvalue, client, event, message) ;
2030      }
2031    }
2032
2033    if (hasBounds)
2034    { 
2035      { // send longitude boudaries
2036        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
2037        CMessage message ;
2038        message<<serverDomainId<<string("boundslon") ; 
2039        scattererConnector.transfer(nvertex, bounds_lonvalue, client, event, message ) ;
2040      }
2041
2042      { // send latitude boudaries
2043        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
2044        CMessage message ;
2045        message<<serverDomainId<<string("boundslat") ; 
2046        scattererConnector.transfer(nvertex, bounds_latvalue, client, event, message ) ;
2047      }
2048    }
2049
2050    if (hasArea)
2051    {  // send area
2052      CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
2053      CMessage message ;
2054      message<<serverDomainId<<string("area") ; 
2055      scattererConnector.transfer(areavalue, client, event,message) ;
2056    }
2057  }
2058
2059  void CDomain::recvDistributedAttributes(CEventServer& event)
2060  TRY
2061  {
2062    string domainId;
2063    string type ;
2064    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> domainId >> type ;
2065    get(domainId)->recvDistributedAttributes(event, type);
2066  }
2067  CATCH
2068
2069  void CDomain::recvDistributedAttributes(CEventServer& event, const string& type)
2070  TRY
2071  {
2072    if (type=="lon") 
2073    {
2074      CArray<double,1> value ;
2075      gathererConnector_->transfer(event, value, 0.); 
2076      lonvalue_2d.resize(ni,nj) ;
2077      if (lonvalue_2d.numElements()>0) lonvalue_2d=CArray<double,2>(value.dataFirst(),shape(ni,nj),neverDeleteData) ; 
2078    }
2079    else if (type=="lat")
2080    {
2081      CArray<double,1> value ;
2082      gathererConnector_->transfer(event, value, 0.); 
2083      latvalue_2d.resize(ni,nj) ;
2084      if (latvalue_2d.numElements()>0) latvalue_2d=CArray<double,2>(value.dataFirst(),shape(ni,nj),neverDeleteData) ; 
2085    }
2086    else if (type=="boundslon")
2087    {
2088      CArray<double,1> value ;
2089      gathererConnector_->transfer(event, nvertex, value, 0.); 
2090      bounds_lon_2d.resize(nvertex,ni,nj) ;
2091      if (bounds_lon_2d.numElements()>0) bounds_lon_2d=CArray<double,3>(value.dataFirst(),shape(nvertex,ni,nj),neverDeleteData) ; 
2092    }
2093    else if (type=="boundslat")
2094    {
2095      CArray<double,1> value ;
2096      gathererConnector_->transfer(event, nvertex, value, 0.); 
2097      bounds_lat_2d.resize(nvertex,ni,nj) ;
2098      if (bounds_lat_2d.numElements()>0) bounds_lat_2d=CArray<double,3>(value.dataFirst(),shape(nvertex,ni,nj),neverDeleteData) ; 
2099    }
2100    else if (type=="area") 
2101    {
2102      CArray<double,1> value ;
2103      gathererConnector_->transfer(event, value, 0.); 
2104      area.resize(ni,nj) ;
2105      if (area.numElements()>0) area=CArray<double,2>(value.dataFirst(),shape(ni,nj),neverDeleteData) ; 
2106    }
2107  }
2108  CATCH
2109   
2110  bool CDomain::dispatchEvent(CEventServer& event)
2111  TRY
2112  {
2113    if (SuperClass::dispatchEvent(event)) return true;
2114    else
2115    {
2116      switch(event.type)
2117      {
2118        case EVENT_ID_DOMAIN_DISTRIBUTION:
2119          recvDomainDistribution(event);
2120          return true;
2121          break;
2122        case EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE:
2123          recvDistributedAttributes(event);
2124          return true;
2125          break; 
2126        default:
2127          ERROR("bool CDomain::dispatchEvent(CEventServer& event)",
2128                << "Unknown Event");
2129          return false;
2130       }
2131    }
2132  }
2133  CATCH
2134
2135 
2136  /*!
2137    Compare two domain objects.
2138    They are equal if only if they have identical attributes as well as their values.
2139    Moreover, they must have the same transformations.
2140  \param [in] domain Compared domain
2141  \return result of the comparison
2142  */
2143  bool CDomain::isEqual(CDomain* obj)
2144  TRY
2145  {
2146    vector<StdString> excludedAttr;
2147    excludedAttr.push_back("domain_ref");
2148    bool objEqual = SuperClass::isEqual(obj, excludedAttr);
2149    if (!objEqual) return objEqual;
2150
2151    TransMapTypes thisTrans = this->getAllTransformations();
2152    TransMapTypes objTrans  = obj->getAllTransformations();
2153
2154    TransMapTypes::const_iterator it, itb, ite;
2155    std::vector<ETranformationType> thisTransType, objTransType;
2156    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
2157      thisTransType.push_back(it->first);
2158    for (it = objTrans.begin(); it != objTrans.end(); ++it)
2159      objTransType.push_back(it->first);
2160
2161    if (thisTransType.size() != objTransType.size()) return false;
2162    for (int idx = 0; idx < thisTransType.size(); ++idx)
2163      objEqual &= (thisTransType[idx] == objTransType[idx]);
2164
2165    return objEqual;
2166  }
2167  CATCH_DUMP_ATTR
2168
2169/////////////////////////////////////////////////////////////////////////
2170///////////////             TRANSFORMATIONS                    //////////
2171/////////////////////////////////////////////////////////////////////////
2172
2173  std::map<StdString, ETranformationType> CDomain::transformationMapList_ = std::map<StdString, ETranformationType>();
2174  bool CDomain::dummyTransformationMapList_ = CDomain::initializeTransformationMap(CDomain::transformationMapList_);
2175
2176  bool CDomain::initializeTransformationMap(std::map<StdString, ETranformationType>& m)
2177  TRY
2178  {
2179    m["zoom_domain"] = TRANS_ZOOM_DOMAIN;
2180    m["interpolate_domain"] = TRANS_INTERPOLATE_DOMAIN;
2181    m["generate_rectilinear_domain"] = TRANS_GENERATE_RECTILINEAR_DOMAIN;
2182    m["compute_connectivity_domain"] = TRANS_COMPUTE_CONNECTIVITY_DOMAIN;
2183    m["expand_domain"] = TRANS_EXPAND_DOMAIN;
2184    m["reorder_domain"] = TRANS_REORDER_DOMAIN;
2185    m["extract_domain"] = TRANS_EXTRACT_DOMAIN;
2186  }
2187  CATCH
2188
2189
2190  CTransformation<CDomain>* CDomain::addTransformation(ETranformationType transType, const StdString& id)
2191  TRY
2192  {
2193    transformationMap_.push_back(std::make_pair(transType, CTransformation<CDomain>::createTransformation(transType,id)));
2194    return transformationMap_.back().second;
2195  }
2196  CATCH_DUMP_ATTR
2197
2198  CTransformation<CDomain>* CDomain::addTransformation(ETranformationType transType, CTransformation<CDomain>* transformation)
2199  TRY
2200  {
2201    transformationMap_.push_back(std::make_pair(transType, transformation));
2202    return transformationMap_.back().second;
2203  }
2204  CATCH_DUMP_ATTR
2205  /*!
2206    Check whether a domain has transformation
2207    \return true if domain has transformation
2208  */
2209  bool CDomain::hasTransformation()
2210  TRY
2211  {
2212    return (!transformationMap_.empty());
2213  }
2214  CATCH_DUMP_ATTR
2215
2216  /*!
2217    Set transformation for current domain. It's the method to move transformation in hierarchy
2218    \param [in] domTrans transformation on domain
2219  */
2220  void CDomain::setTransformations(const TransMapTypes& domTrans)
2221  TRY
2222  {
2223    transformationMap_ = domTrans;
2224  }
2225  CATCH_DUMP_ATTR
2226
2227  /*!
2228    Get all transformation current domain has
2229    \return all transformation
2230  */
2231  CDomain::TransMapTypes CDomain::getAllTransformations(void)
2232  TRY
2233  {
2234    return transformationMap_;
2235  }
2236  CATCH_DUMP_ATTR
2237
2238  void CDomain::duplicateTransformation(CDomain* src)
2239  TRY
2240  {
2241    if (src->hasTransformation())
2242    {
2243      this->setTransformations(src->getAllTransformations());
2244    }
2245  }
2246  CATCH_DUMP_ATTR
2247   
2248  /*!
2249   * Go through the hierarchy to find the domain from which the transformations must be inherited
2250   */
2251  void CDomain::solveInheritanceTransformation_old()
2252  TRY
2253  {
2254    if (hasTransformation() || !hasDirectDomainReference())
2255      return;
2256
2257    CDomain* domain = this;
2258    std::vector<CDomain*> refDomains;
2259    while (!domain->hasTransformation() && domain->hasDirectDomainReference())
2260    {
2261      refDomains.push_back(domain);
2262      domain = domain->getDirectDomainReference();
2263    }
2264
2265    if (domain->hasTransformation())
2266      for (size_t i = 0; i < refDomains.size(); ++i)
2267        refDomains[i]->setTransformations(domain->getAllTransformations());
2268  }
2269  CATCH_DUMP_ATTR
2270
2271
2272  void CDomain::solveInheritanceTransformation()
2273  TRY
2274  {
2275    if (solveInheritanceTransformation_done_) return;
2276    else solveInheritanceTransformation_done_=true ;
2277
2278    CDomain* domain = this;
2279    CDomain* Lastdomain ;
2280    std::list<CDomain*> refDomains;
2281    bool out=false ;
2282    vector<StdString> excludedAttr;
2283    excludedAttr.push_back("domain_ref");
2284   
2285    refDomains.push_front(domain) ;
2286    while (domain->hasDirectDomainReference() && !out)
2287    {
2288      CDomain* lastDomain=domain ;
2289      domain = domain->getDirectDomainReference();
2290      domain->solveRefInheritance() ;
2291      if (!domain->SuperClass::isEqual(lastDomain,excludedAttr)) out=true ;
2292      refDomains.push_front(domain) ;
2293    }
2294
2295    CTransformationPaths::TPath path ;
2296    auto& pathList = std::get<2>(path) ;
2297    std::get<0>(path) = EElement::DOMAIN ;
2298    std::get<1>(path) = refDomains.front()->getId() ;
2299    for (auto& domain : refDomains)
2300    {
2301      CDomain::TransMapTypes transformations = domain->getAllTransformations();
2302      for(auto& transformation : transformations) pathList.push_back({transformation.second->getTransformationType(), 
2303                                                                      transformation.second->getId()}) ;
2304    }
2305    transformationPaths_.addPath(path) ;
2306
2307  }
2308  CATCH_DUMP_ATTR
2309 
2310/////////////////////////////////////////////////////////////////////////////////////////////
2311/////////////////////////////////////////////////////////////////////////////////////////////
2312
2313  void CDomain::setContextClient(CContextClient* contextClient)
2314  TRY
2315  {
2316    if (clientsSet.find(contextClient)==clientsSet.end())
2317    {
2318      clients.push_back(contextClient) ;
2319      clientsSet.insert(contextClient);
2320    }
2321  }
2322  CATCH_DUMP_ATTR
2323
2324  /*!
2325    Parse children nodes of a domain in xml file.
2326    Whenver there is a new transformation, its type and name should be added into this function
2327    \param node child node to process
2328  */
2329  void CDomain::parse(xml::CXMLNode & node)
2330  TRY
2331  {
2332    SuperClass::parse(node);
2333
2334    if (node.goToChildElement())
2335    {
2336      StdString nodeElementName;
2337      do
2338      {
2339        StdString nodeId("");
2340        if (node.getAttributes().end() != node.getAttributes().find("id"))
2341        { nodeId = node.getAttributes()["id"]; }
2342
2343        nodeElementName = node.getElementName();
2344        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
2345        it = transformationMapList_.find(nodeElementName);
2346        if (ite != it)
2347        {
2348          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CDomain>::createTransformation(it->second,
2349                                                                                                                nodeId,
2350                                                                                                                &node)));
2351        }
2352        else
2353        {
2354          ERROR("void CDomain::parse(xml::CXMLNode & node)",
2355                << "The transformation " << nodeElementName << " has not been supported yet.");
2356        }
2357      } while (node.goToNextElement()) ;
2358      node.goToParentElement();
2359    }
2360  }
2361  CATCH_DUMP_ATTR
2362   //----------------------------------------------------------------
2363
2364   DEFINE_REF_FUNC(Domain,domain)
2365
2366   ///---------------------------------------------------------------
2367
2368} // namespace xios
Note: See TracBrowser for help on using the repository browser.