source: XIOS/dev/dev_trunk_graph/src/node/domain.cpp @ 2019

Last change on this file since 2019 was 2019, checked in by yushan, 9 months ago

Graph intermedia commit to a tmp branch

  • 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.0 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   
1784  /* to be removed later when coupling will be reimplemented, just to  not forget */
1785  void CDomain::sendDomainToCouplerOut(CContextClient* client, const string& fieldId, int posInGrid)
1786  {
1787    if (sendDomainToFileServer_done_.count(client)!=0) return ;
1788    else sendDomainToFileServer_done_.insert(client) ;
1789   
1790    const string domainId = "_domain["+std::to_string(posInGrid)+"]_of_"+fieldId ;
1791   
1792    if (!domain_ref.isEmpty())
1793    {
1794      auto domain_ref_tmp=domain_ref.getValue() ;
1795      domain_ref.reset() ; // remove the reference, find an other way to do that more cleanly
1796      this->sendAllAttributesToServer(client, domainId)  ;
1797      domain_ref = domain_ref_tmp ;
1798    }
1799    else this->sendAllAttributesToServer(client, domainId)  ;
1800  }
1801
1802
1803
1804
1805  void CDomain::makeAliasForCoupling(const string& fieldId, int posInGrid)
1806  {
1807    const string domainId = "_domain["+std::to_string(posInGrid)+"]_of_"+fieldId ;
1808    this->createAlias(domainId) ;
1809  }
1810
1811
1812  void CDomain::computeRemoteElement(CContextClient* client, EDistributionType type)
1813  TRY
1814  {
1815    CContext* context = CContext::getCurrent();
1816    map<int, CArray<size_t,1>> globalIndex ;
1817
1818    if (type==EDistributionType::BANDS) // Bands distribution to send to file server
1819    {
1820      int nbServer = client->serverSize;
1821      std::vector<int> nGlobDomain(2);
1822      nGlobDomain[0] = this->ni_glo;
1823      nGlobDomain[1] = this->nj_glo;
1824
1825      // to be changed in future, need to rewrite more simply domain distribution
1826      CServerDistributionDescription serverDescription(nGlobDomain, nbServer);
1827      int distributedPosition ;
1828      if (isUnstructed_) distributedPosition = 0 ;
1829      else distributedPosition = 1 ;
1830     
1831      std::vector<std::vector<int> > serverIndexBegin = serverDescription.getServerIndexBegin();
1832      std::vector<std::vector<int> > serverDimensionSizes = serverDescription.getServerDimensionSizes();
1833      vector<unordered_map<size_t,vector<int>>> indexServerOnElement ;
1834      CArray<int,1> axisDomainOrder(1) ; axisDomainOrder(0)=2 ;
1835      auto zeroIndex=serverDescription.computeServerGlobalByElement(indexServerOnElement, context->getIntraCommRank(), context->getIntraCommSize(),
1836                                                                  axisDomainOrder,distributedPosition) ;
1837      // distribution is very bad => to redo
1838      // convert indexServerOnElement => map<int,CArray<size_t,1>> - need to be changed later
1839      map<int, vector<size_t>> vectGlobalIndex ;
1840      for(auto& indexRanks : indexServerOnElement[0])
1841      {
1842        size_t index=indexRanks.first ;
1843        auto& ranks=indexRanks.second ;
1844        for(int rank : ranks) vectGlobalIndex[rank].push_back(index) ;
1845      }
1846      for(auto& vect : vectGlobalIndex ) globalIndex.emplace(vect.first, CArray<size_t,1>(vect.second.data(), shape(vect.second.size()),duplicateData)) ;
1847    // some servers receves no index (zeroIndex array) => root process take them into account.
1848      if (context->getIntraCommRank()==0) 
1849        for(auto& rank : zeroIndex) globalIndex[rank] = CArray<size_t,1>() ; 
1850    }
1851    else if (type==EDistributionType::NONE) // domain is not distributed ie all servers get the same local domain
1852    {
1853      int nbServer = client->serverSize;
1854      int nglo=ni_glo*nj_glo ;
1855      CArray<size_t,1> indGlo ;
1856      for(size_t i=0;i<nglo;i++) indGlo(i) = i ;
1857      for (auto& rankServer : client->getRanksServerLeader()) globalIndex[rankServer] = indGlo ; 
1858    }
1859    remoteElement_[client] = new CDistributedElement(ni_glo*nj_glo, globalIndex) ;
1860    remoteElement_[client]->addFullView() ;
1861  }
1862  CATCH
1863
1864 
1865
1866  void CDomain::distributeToServer(CContextClient* client, map<int, CArray<size_t,1>>& globalIndex,
1867                                   CScattererConnector* &scattererConnector, const string& domainId)
1868  TRY
1869  {
1870    string serverDomainId = domainId.empty() ? this->getId() : domainId ;
1871    CContext* context = CContext::getCurrent();
1872
1873    this->sendAllAttributesToServer(client, serverDomainId)  ;
1874
1875    CDistributedElement scatteredElement(ni_glo*nj_glo, globalIndex) ;
1876    scatteredElement.addFullView() ;
1877    scattererConnector = new CScattererConnector(localElement_->getView(CElementView::FULL), scatteredElement.getView(CElementView::FULL), 
1878                                           context->getIntraComm(), client->getRemoteSize()) ;
1879    scattererConnector->computeConnector() ;
1880
1881    // phase 0
1882    // send remote element to construct the full view on server, ie without hole
1883    CEventClient event0(getType(), EVENT_ID_DOMAIN_DISTRIBUTION);
1884    CMessage message0 ;
1885    message0<<serverDomainId<<0 ; 
1886    remoteElement_[client]->sendToServer(client,event0,message0) ; 
1887   
1888    // phase 1
1889    // send the full view of element to construct the connector which connect distributed data coming from client to the full local view
1890    CEventClient event1(getType(), EVENT_ID_DOMAIN_DISTRIBUTION);
1891    CMessage message1 ;
1892    message1<<serverDomainId<<1<<localElement_->getView(CElementView::FULL)->getGlobalSize() ; 
1893    scattererConnector->transfer(localElement_->getView(CElementView::FULL)->getGlobalIndex(),client,event1,message1) ;
1894   
1895    sendDistributedAttributes(client, *scattererConnector, domainId) ;
1896
1897 
1898    // phase 2 send the mask : data index + mask2D
1899    CArray<bool,1> maskIn(localElement_->getView(CElementView::WORKFLOW)->getSize());
1900    CArray<bool,1> maskOut ;
1901    CLocalConnector workflowToFull(localElement_->getView(CElementView::WORKFLOW), localElement_->getView(CElementView::FULL)) ;
1902    workflowToFull.computeConnector() ;
1903    maskIn=true ;
1904    workflowToFull.transfer(maskIn,maskOut,false) ;
1905
1906
1907    // phase 3 : prepare grid scatterer connector to send data from client to server
1908    map<int,CArray<size_t,1>> workflowGlobalIndex ;
1909    map<int,CArray<bool,1>> maskOut2 ; 
1910    scattererConnector->transfer(maskOut, maskOut2, false) ;
1911    scatteredElement.addView(CElementView::WORKFLOW, maskOut2) ;
1912    scatteredElement.getView(CElementView::WORKFLOW)->getGlobalIndexView(workflowGlobalIndex) ;
1913    // create new workflow view for scattered element
1914    CDistributedElement clientToServerElement(scatteredElement.getGlobalSize(), workflowGlobalIndex) ;
1915    clientToServerElement.addFullView() ;
1916    CEventClient event2(getType(), EVENT_ID_DOMAIN_DISTRIBUTION);
1917    CMessage message2 ;
1918    message2<<serverDomainId<<2 ; 
1919    clientToServerElement.sendToServer(client, event2, message2) ; 
1920    clientToServerConnector_[client] = new CScattererConnector(localElement_->getView(CElementView::WORKFLOW), clientToServerElement.getView(CElementView::FULL),
1921                                                               context->getIntraComm(), client->getRemoteSize()) ;
1922    clientToServerConnector_[client]->computeConnector() ;
1923
1924    clientFromServerConnector_[client] = new CGathererConnector(clientToServerElement.getView(CElementView::FULL), localElement_->getView(CElementView::WORKFLOW));
1925    clientFromServerConnector_[client]->computeConnector() ;
1926
1927  }
1928  CATCH
1929 
1930  void CDomain::recvDomainDistribution(CEventServer& event)
1931  TRY
1932  {
1933    string domainId;
1934    int phasis ;
1935    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> domainId >> phasis ;
1936    get(domainId)->receivedDomainDistribution(event, phasis);
1937  }
1938  CATCH
1939
1940  void CDomain::receivedDomainDistribution(CEventServer& event, int phasis)
1941  TRY
1942  {
1943    CContext* context = CContext::getCurrent();
1944    if (phasis==0) // receive the remote element to construct the full view
1945    {
1946      localElement_ = new  CLocalElement(context->getIntraCommRank(),event) ;
1947      localElement_->addFullView() ;
1948      // construct the local dimension and indexes
1949      auto& globalIndex=localElement_->getGlobalIndex() ;
1950      int nij=globalIndex.numElements() ;
1951      int minI=ni_glo,maxI=-1,minJ=nj_glo,maxJ=-1 ;
1952      int i,j ;
1953      int niGlo=ni_glo, njGlo=njGlo ;
1954      for(int ij=0;ij<nij;ij++)
1955      {
1956        j=globalIndex(ij)/niGlo ;
1957        i=globalIndex(ij)%niGlo ;
1958        if (i<minI) minI=i ;
1959        if (i>maxI) maxI=i ;
1960        if (j<minJ) minJ=j ;
1961        if (j>maxJ) maxJ=j ;
1962      } 
1963      if (maxI>=minI) { ibegin=minI ; ni=maxI-minI+1 ; }
1964      else {ibegin=0; ni=0 ;}
1965      if (maxJ>=minJ) { jbegin=minJ ; nj=maxJ-minJ+1 ; }
1966      else {jbegin=0; nj=0 ;}
1967
1968    }
1969    else if (phasis==1) // receive the sent view from client to construct the full distributed full view on server
1970    {
1971      CContext* context = CContext::getCurrent();
1972      CDistributedElement* elementFrom = new  CDistributedElement(event) ;
1973      elementFrom->addFullView() ;
1974      gathererConnector_ = new CGathererConnector(elementFrom->getView(CElementView::FULL), localElement_->getView(CElementView::FULL)) ;
1975      gathererConnector_->computeConnector() ; 
1976    }
1977    else if (phasis==2)
1978    {
1979//      delete gathererConnector_ ;
1980      elementFrom_ = new  CDistributedElement(event) ;
1981      elementFrom_->addFullView() ;
1982//      gathererConnector_ =  new CGathererConnector(elementFrom_->getView(CElementView::FULL), localElement_->getView(CElementView::FULL)) ;
1983//      gathererConnector_ -> computeConnector() ;
1984    }
1985  }
1986  CATCH
1987
1988  void CDomain::setServerMask(CArray<bool,1>& serverMask, CContextClient* client)
1989  TRY
1990  {
1991    // nota : the client is needed to get the remote size for the scatterer connector. Maybe it is not the good place for this
1992    // Later, server to client connector can be computed on demand, with "client" as argument
1993    CContext* context = CContext::getCurrent();
1994    localElement_->addView(CElementView::WORKFLOW, serverMask) ;
1995    mask_1d.reference(serverMask.copy()) ;
1996 
1997    serverFromClientConnector_ = new CGathererConnector(elementFrom_->getView(CElementView::FULL), localElement_->getView(CElementView::WORKFLOW)) ;
1998    serverFromClientConnector_->computeConnector() ;
1999     
2000    serverToClientConnector_ = new CScattererConnector(localElement_->getView(CElementView::WORKFLOW), elementFrom_->getView(CElementView::FULL),
2001                                                       context->getIntraComm(), client->getRemoteSize()) ;
2002    serverToClientConnector_->computeConnector() ;
2003  }
2004  CATCH_DUMP_ATTR
2005
2006
2007  void CDomain::sendDistributedAttributes(CContextClient* client, CScattererConnector& scattererConnector,  const string& domainId)
2008  {
2009    string serverDomainId = domainId.empty() ? this->getId() : domainId ;
2010    CContext* context = CContext::getCurrent();
2011
2012    if (hasLonLat)
2013    {
2014      { // send longitude
2015        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
2016        CMessage message ;
2017        message<<serverDomainId<<string("lon") ; 
2018        scattererConnector.transfer(lonvalue, client, event,message) ;
2019      }
2020     
2021      { // send latitude
2022        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
2023        CMessage message ;
2024        message<<serverDomainId<<string("lat") ; 
2025        scattererConnector.transfer(latvalue, client, event, message) ;
2026      }
2027    }
2028
2029    if (hasBounds)
2030    { 
2031      { // send longitude boudaries
2032        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
2033        CMessage message ;
2034        message<<serverDomainId<<string("boundslon") ; 
2035        scattererConnector.transfer(nvertex, bounds_lonvalue, client, event, message ) ;
2036      }
2037
2038      { // send latitude boudaries
2039        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
2040        CMessage message ;
2041        message<<serverDomainId<<string("boundslat") ; 
2042        scattererConnector.transfer(nvertex, bounds_latvalue, client, event, message ) ;
2043      }
2044    }
2045
2046    if (hasArea)
2047    {  // send area
2048      CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
2049      CMessage message ;
2050      message<<serverDomainId<<string("area") ; 
2051      scattererConnector.transfer(areavalue, client, event,message) ;
2052    }
2053  }
2054
2055  void CDomain::recvDistributedAttributes(CEventServer& event)
2056  TRY
2057  {
2058    string domainId;
2059    string type ;
2060    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> domainId >> type ;
2061    get(domainId)->recvDistributedAttributes(event, type);
2062  }
2063  CATCH
2064
2065  void CDomain::recvDistributedAttributes(CEventServer& event, const string& type)
2066  TRY
2067  {
2068    if (type=="lon") 
2069    {
2070      CArray<double,1> value ;
2071      gathererConnector_->transfer(event, value, 0.); 
2072      lonvalue_2d.resize(ni,nj) ;
2073      if (lonvalue_2d.numElements()>0) lonvalue_2d=CArray<double,2>(value.dataFirst(),shape(ni,nj),neverDeleteData) ; 
2074    }
2075    else if (type=="lat")
2076    {
2077      CArray<double,1> value ;
2078      gathererConnector_->transfer(event, value, 0.); 
2079      latvalue_2d.resize(ni,nj) ;
2080      if (latvalue_2d.numElements()>0) latvalue_2d=CArray<double,2>(value.dataFirst(),shape(ni,nj),neverDeleteData) ; 
2081    }
2082    else if (type=="boundslon")
2083    {
2084      CArray<double,1> value ;
2085      gathererConnector_->transfer(event, nvertex, value, 0.); 
2086      bounds_lon_2d.resize(nvertex,ni,nj) ;
2087      if (bounds_lon_2d.numElements()>0) bounds_lon_2d=CArray<double,3>(value.dataFirst(),shape(nvertex,ni,nj),neverDeleteData) ; 
2088    }
2089    else if (type=="boundslat")
2090    {
2091      CArray<double,1> value ;
2092      gathererConnector_->transfer(event, nvertex, value, 0.); 
2093      bounds_lat_2d.resize(nvertex,ni,nj) ;
2094      if (bounds_lat_2d.numElements()>0) bounds_lat_2d=CArray<double,3>(value.dataFirst(),shape(nvertex,ni,nj),neverDeleteData) ; 
2095    }
2096    else if (type=="area") 
2097    {
2098      CArray<double,1> value ;
2099      gathererConnector_->transfer(event, value, 0.); 
2100      area.resize(ni,nj) ;
2101      if (area.numElements()>0) area=CArray<double,2>(value.dataFirst(),shape(ni,nj),neverDeleteData) ; 
2102    }
2103  }
2104  CATCH
2105   
2106  bool CDomain::dispatchEvent(CEventServer& event)
2107  TRY
2108  {
2109    if (SuperClass::dispatchEvent(event)) return true;
2110    else
2111    {
2112      switch(event.type)
2113      {
2114        case EVENT_ID_DOMAIN_DISTRIBUTION:
2115          recvDomainDistribution(event);
2116          return true;
2117          break;
2118        case EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE:
2119          recvDistributedAttributes(event);
2120          return true;
2121          break; 
2122        default:
2123          ERROR("bool CDomain::dispatchEvent(CEventServer& event)",
2124                << "Unknown Event");
2125          return false;
2126       }
2127    }
2128  }
2129  CATCH
2130
2131 
2132  /*!
2133    Compare two domain objects.
2134    They are equal if only if they have identical attributes as well as their values.
2135    Moreover, they must have the same transformations.
2136  \param [in] domain Compared domain
2137  \return result of the comparison
2138  */
2139  bool CDomain::isEqual(CDomain* obj)
2140  TRY
2141  {
2142    vector<StdString> excludedAttr;
2143    excludedAttr.push_back("domain_ref");
2144    bool objEqual = SuperClass::isEqual(obj, excludedAttr);
2145    if (!objEqual) return objEqual;
2146
2147    TransMapTypes thisTrans = this->getAllTransformations();
2148    TransMapTypes objTrans  = obj->getAllTransformations();
2149
2150    TransMapTypes::const_iterator it, itb, ite;
2151    std::vector<ETranformationType> thisTransType, objTransType;
2152    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
2153      thisTransType.push_back(it->first);
2154    for (it = objTrans.begin(); it != objTrans.end(); ++it)
2155      objTransType.push_back(it->first);
2156
2157    if (thisTransType.size() != objTransType.size()) return false;
2158    for (int idx = 0; idx < thisTransType.size(); ++idx)
2159      objEqual &= (thisTransType[idx] == objTransType[idx]);
2160
2161    return objEqual;
2162  }
2163  CATCH_DUMP_ATTR
2164
2165/////////////////////////////////////////////////////////////////////////
2166///////////////             TRANSFORMATIONS                    //////////
2167/////////////////////////////////////////////////////////////////////////
2168
2169  std::map<StdString, ETranformationType> CDomain::transformationMapList_ = std::map<StdString, ETranformationType>();
2170  bool CDomain::dummyTransformationMapList_ = CDomain::initializeTransformationMap(CDomain::transformationMapList_);
2171
2172  bool CDomain::initializeTransformationMap(std::map<StdString, ETranformationType>& m)
2173  TRY
2174  {
2175    m["zoom_domain"] = TRANS_ZOOM_DOMAIN;
2176    m["interpolate_domain"] = TRANS_INTERPOLATE_DOMAIN;
2177    m["generate_rectilinear_domain"] = TRANS_GENERATE_RECTILINEAR_DOMAIN;
2178    m["compute_connectivity_domain"] = TRANS_COMPUTE_CONNECTIVITY_DOMAIN;
2179    m["expand_domain"] = TRANS_EXPAND_DOMAIN;
2180    m["reorder_domain"] = TRANS_REORDER_DOMAIN;
2181    m["extract_domain"] = TRANS_EXTRACT_DOMAIN;
2182  }
2183  CATCH
2184
2185
2186  CTransformation<CDomain>* CDomain::addTransformation(ETranformationType transType, const StdString& id)
2187  TRY
2188  {
2189    transformationMap_.push_back(std::make_pair(transType, CTransformation<CDomain>::createTransformation(transType,id)));
2190    return transformationMap_.back().second;
2191  }
2192  CATCH_DUMP_ATTR
2193
2194  CTransformation<CDomain>* CDomain::addTransformation(ETranformationType transType, CTransformation<CDomain>* transformation)
2195  TRY
2196  {
2197    transformationMap_.push_back(std::make_pair(transType, transformation));
2198    return transformationMap_.back().second;
2199  }
2200  CATCH_DUMP_ATTR
2201  /*!
2202    Check whether a domain has transformation
2203    \return true if domain has transformation
2204  */
2205  bool CDomain::hasTransformation()
2206  TRY
2207  {
2208    return (!transformationMap_.empty());
2209  }
2210  CATCH_DUMP_ATTR
2211
2212  /*!
2213    Set transformation for current domain. It's the method to move transformation in hierarchy
2214    \param [in] domTrans transformation on domain
2215  */
2216  void CDomain::setTransformations(const TransMapTypes& domTrans)
2217  TRY
2218  {
2219    transformationMap_ = domTrans;
2220  }
2221  CATCH_DUMP_ATTR
2222
2223  /*!
2224    Get all transformation current domain has
2225    \return all transformation
2226  */
2227  CDomain::TransMapTypes CDomain::getAllTransformations(void)
2228  TRY
2229  {
2230    return transformationMap_;
2231  }
2232  CATCH_DUMP_ATTR
2233
2234  void CDomain::duplicateTransformation(CDomain* src)
2235  TRY
2236  {
2237    if (src->hasTransformation())
2238    {
2239      this->setTransformations(src->getAllTransformations());
2240    }
2241  }
2242  CATCH_DUMP_ATTR
2243   
2244  /*!
2245   * Go through the hierarchy to find the domain from which the transformations must be inherited
2246   */
2247  void CDomain::solveInheritanceTransformation_old()
2248  TRY
2249  {
2250    if (hasTransformation() || !hasDirectDomainReference())
2251      return;
2252
2253    CDomain* domain = this;
2254    std::vector<CDomain*> refDomains;
2255    while (!domain->hasTransformation() && domain->hasDirectDomainReference())
2256    {
2257      refDomains.push_back(domain);
2258      domain = domain->getDirectDomainReference();
2259    }
2260
2261    if (domain->hasTransformation())
2262      for (size_t i = 0; i < refDomains.size(); ++i)
2263        refDomains[i]->setTransformations(domain->getAllTransformations());
2264  }
2265  CATCH_DUMP_ATTR
2266
2267
2268  void CDomain::solveInheritanceTransformation()
2269  TRY
2270  {
2271    if (solveInheritanceTransformation_done_) return;
2272    else solveInheritanceTransformation_done_=true ;
2273
2274    CDomain* domain = this;
2275    CDomain* Lastdomain ;
2276    std::list<CDomain*> refDomains;
2277    bool out=false ;
2278    vector<StdString> excludedAttr;
2279    excludedAttr.push_back("domain_ref");
2280   
2281    refDomains.push_front(domain) ;
2282    while (domain->hasDirectDomainReference() && !out)
2283    {
2284      CDomain* lastDomain=domain ;
2285      domain = domain->getDirectDomainReference();
2286      domain->solveRefInheritance() ;
2287      if (!domain->SuperClass::isEqual(lastDomain,excludedAttr)) out=true ;
2288      refDomains.push_front(domain) ;
2289    }
2290
2291    CTransformationPaths::TPath path ;
2292    auto& pathList = std::get<2>(path) ;
2293    std::get<0>(path) = EElement::DOMAIN ;
2294    std::get<1>(path) = refDomains.front()->getId() ;
2295    for (auto& domain : refDomains)
2296    {
2297      CDomain::TransMapTypes transformations = domain->getAllTransformations();
2298      for(auto& transformation : transformations) pathList.push_back({transformation.second->getTransformationType(), 
2299                                                                      transformation.second->getId()}) ;
2300    }
2301    transformationPaths_.addPath(path) ;
2302
2303  }
2304  CATCH_DUMP_ATTR
2305 
2306/////////////////////////////////////////////////////////////////////////////////////////////
2307/////////////////////////////////////////////////////////////////////////////////////////////
2308
2309  void CDomain::setContextClient(CContextClient* contextClient)
2310  TRY
2311  {
2312    if (clientsSet.find(contextClient)==clientsSet.end())
2313    {
2314      clients.push_back(contextClient) ;
2315      clientsSet.insert(contextClient);
2316    }
2317  }
2318  CATCH_DUMP_ATTR
2319
2320  /*!
2321    Parse children nodes of a domain in xml file.
2322    Whenver there is a new transformation, its type and name should be added into this function
2323    \param node child node to process
2324  */
2325  void CDomain::parse(xml::CXMLNode & node)
2326  TRY
2327  {
2328    SuperClass::parse(node);
2329
2330    if (node.goToChildElement())
2331    {
2332      StdString nodeElementName;
2333      do
2334      {
2335        StdString nodeId("");
2336        if (node.getAttributes().end() != node.getAttributes().find("id"))
2337        { nodeId = node.getAttributes()["id"]; }
2338
2339        nodeElementName = node.getElementName();
2340        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
2341        it = transformationMapList_.find(nodeElementName);
2342        if (ite != it)
2343        {
2344          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CDomain>::createTransformation(it->second,
2345                                                                                                                nodeId,
2346                                                                                                                &node)));
2347        }
2348        else
2349        {
2350          ERROR("void CDomain::parse(xml::CXMLNode & node)",
2351                << "The transformation " << nodeElementName << " has not been supported yet.");
2352        }
2353      } while (node.goToNextElement()) ;
2354      node.goToParentElement();
2355    }
2356  }
2357  CATCH_DUMP_ATTR
2358   //----------------------------------------------------------------
2359
2360   DEFINE_REF_FUNC(Domain,domain)
2361
2362   ///---------------------------------------------------------------
2363
2364} // namespace xios
Note: See TracBrowser for help on using the repository browser.