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

Last change on this file since 2190 was 2190, checked in by jderouillat, 3 years ago

Add bound checking when the workflow view is scaned (highlighted by blitz check in debug mode)

  • 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.4 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()) 
808        {
809          ni = i_index.numElements();
810          j_index.resize(ni);
811          for(int i=0;i<ni;++i) j_index(i)=0;
812        }
813       
814
815        if (!area.isEmpty()) area.transposeSelf(1, 0); // => to be checked why is it transposed
816     }
817
818     if (ni_glo.isEmpty())
819     {
820       ERROR("CDomain::checkDomain(void)",
821             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
822             << "The global domain is badly defined, "
823             << "the mandatory 'ni_glo' attribute is missing.")
824     }
825     else if (ni_glo <= 0)
826     {
827       ERROR("CDomain::checkDomain(void)",
828             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
829             << "The global domain is badly defined, "
830             << "'ni_glo' attribute should be strictly positive so 'ni_glo = " << ni_glo.getValue() << "' is invalid.")
831     }
832
833     if (nj_glo.isEmpty())
834     {
835       ERROR("CDomain::checkDomain(void)",
836             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
837             << "The global domain is badly defined, "
838             << "the mandatory 'nj_glo' attribute is missing.")
839     }
840     else if (nj_glo <= 0)
841     {
842       ERROR("CDomain::checkDomain(void)",
843             << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
844             << "The global domain is badly defined, "
845             << "'nj_glo' attribute should be strictly positive so 'nj_glo = " << nj_glo.getValue() << "' is invalid.")
846     }
847
848     checkLocalIDomain();
849     checkLocalJDomain();
850
851     if (i_index.isEmpty())
852     {
853       i_index.resize(ni*nj);
854       for (int j = 0; j < nj; ++j)
855         for (int i = 0; i < ni; ++i) i_index(i+j*ni) = i+ibegin;
856     }
857
858     if (j_index.isEmpty())
859     {
860       j_index.resize(ni*nj);
861       for (int j = 0; j < nj; ++j)
862         for (int i = 0; i < ni; ++i) j_index(i+j*ni) = j+jbegin;
863     }
864   }
865   CATCH_DUMP_ATTR
866
867   size_t CDomain::getGlobalWrittenSize(void)
868   {
869     return ni_glo*nj_glo ;
870   }
871   //----------------------------------------------------------------
872
873   // Check validity of local domain on using the combination of 3 parameters: ibegin, ni and i_index
874   void CDomain::checkLocalIDomain(void)
875   TRY
876   {
877      // If ibegin and ni are provided then we use them to check the validity of local domain
878      if (i_index.isEmpty() && !ibegin.isEmpty() && !ni.isEmpty())
879      {
880        if ((ni.getValue() < 0 || ibegin.getValue() < 0) || ((ibegin.getValue() + ni.getValue()) > ni_glo.getValue()))
881        {
882          ERROR("CDomain::checkLocalIDomain(void)",
883                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
884                << "The local domain is wrongly defined,"
885                << " check the attributes 'ni_glo' (" << ni_glo.getValue() << "), 'ni' (" << ni.getValue() << ") and 'ibegin' (" << ibegin.getValue() << ")");
886        }
887      }
888
889      // i_index has higher priority than ibegin and ni
890      if (!i_index.isEmpty())
891      {
892        int minIIndex = (0 < i_index.numElements()) ? i_index(0) : 0;
893        if (ni.isEmpty()) 
894        {         
895         // No information about ni
896          int minIndex = ni_glo - 1;
897          int maxIndex = 0;
898          for (int idx = 0; idx < i_index.numElements(); ++idx)
899          {
900            if (i_index(idx) < minIndex) minIndex = i_index(idx);
901            if (i_index(idx) > maxIndex) maxIndex = i_index(idx);
902          }
903          if (i_index.numElements()) {
904            ni = maxIndex - minIndex + 1; 
905            minIIndex = minIndex;
906          }         
907          else {
908            ni = 0;
909          }
910        }
911
912        // It's not so correct but if ibegin is not the first value of i_index
913        // then data on local domain has user-defined distribution. In this case, ibegin, ni have no meaning.
914        if (ibegin.isEmpty()) ibegin = minIIndex;
915      }
916      else if (ibegin.isEmpty() && ni.isEmpty())
917      {
918        ibegin = 0;
919        ni = ni_glo;
920      }
921      else if ((!ibegin.isEmpty() && ni.isEmpty()) || (ibegin.isEmpty() && !ni.isEmpty()))
922      {
923        ERROR("CDomain::checkLocalIDomain(void)",
924              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
925              << "The local domain is wrongly defined," << endl
926              << "i_index is empty and either 'ni' or 'ibegin' is not defined. " 
927              << "If 'ni' and 'ibegin' are used to define a domain, both of them must not be empty.");
928      }
929       
930
931      if ((ni.getValue() < 0 || ibegin.getValue() < 0))
932      {
933        ERROR("CDomain::checkLocalIDomain(void)",
934              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
935              << "The local domain is wrongly defined,"
936              << " check the attributes 'ni_glo' (" << ni_glo.getValue() << "), 'ni' (" << ni.getValue() << ") and 'ibegin' (" << ibegin.getValue() << ")");
937      }
938   }
939   CATCH_DUMP_ATTR
940
941   // Check validity of local domain on using the combination of 3 parameters: jbegin, nj and j_index
942   void CDomain::checkLocalJDomain(void)
943   TRY
944   {
945    // If jbegin and nj are provided then we use them to check the validity of local domain
946     if (j_index.isEmpty() && !jbegin.isEmpty() && !nj.isEmpty())
947     {
948       if ((nj.getValue() < 0 || jbegin.getValue() < 0) || (jbegin.getValue() + nj.getValue()) > nj_glo.getValue())
949       {
950         ERROR("CDomain::checkLocalJDomain(void)",
951                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
952                << "The local domain is wrongly defined,"
953                << " check the attributes 'nj_glo' (" << nj_glo.getValue() << "), 'nj' (" << nj.getValue() << ") and 'jbegin' (" << jbegin.getValue() << ")");
954       }
955     }
956
957     if (!j_index.isEmpty())
958     {
959        int minJIndex = (0 < j_index.numElements()) ? j_index(0) : 0;
960        if (nj.isEmpty()) 
961        {
962          // No information about nj
963          int minIndex = nj_glo - 1;
964          int maxIndex = 0;
965          for (int idx = 0; idx < j_index.numElements(); ++idx)
966          {
967            if (j_index(idx) < minIndex) minIndex = j_index(idx);
968            if (j_index(idx) > maxIndex) maxIndex = j_index(idx);
969          }
970          if (j_index.numElements()) {
971            nj = maxIndex - minIndex + 1;
972            minJIndex = minIndex; 
973          }
974          else
975            nj = 0;
976        } 
977        // It's the same as checkLocalIDomain. It's not so correct but if jbegin is not the first value of j_index
978        // then data on local domain has user-defined distribution. In this case, jbegin has no meaning.
979       if (jbegin.isEmpty()) jbegin = minJIndex;       
980     }
981     else if (jbegin.isEmpty() && nj.isEmpty())
982     {
983       jbegin = 0;
984       nj = nj_glo;
985     }     
986
987
988     if ((nj.getValue() < 0 || jbegin.getValue() < 0))
989     {
990       ERROR("CDomain::checkLocalJDomain(void)",
991              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
992              << "The local domain is wrongly defined,"
993              << " check the attributes 'nj_glo' (" << nj_glo.getValue() << "), 'nj' (" << nj.getValue() << ") and 'jbegin' (" << jbegin.getValue() << ")");
994     }
995   }
996   CATCH_DUMP_ATTR
997
998   //----------------------------------------------------------------
999
1000   void CDomain::checkMask(void)
1001   TRY
1002   {
1003      if (!mask_1d.isEmpty() && !mask_2d.isEmpty())
1004        ERROR("CDomain::checkMask(void)",
1005              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1006              << "Both mask_1d and mask_2d are defined but only one can be used at the same time." << std::endl
1007              << "Please define only one mask: 'mask_1d' or 'mask_2d'.");
1008
1009      if (!mask_1d.isEmpty() && mask_2d.isEmpty())
1010      {
1011        if (mask_1d.numElements() != i_index.numElements())
1012          ERROR("CDomain::checkMask(void)",
1013                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1014                << "'mask_1d' does not have the same size as the local domain." << std::endl
1015                << "Local size is " << i_index.numElements() << "." << std::endl
1016                << "Mask size is " << mask_1d.numElements() << ".");
1017      }
1018
1019      if (mask_1d.isEmpty() && !mask_2d.isEmpty())
1020      {
1021        if (mask_2d.extent(0) != ni || mask_2d.extent(1) != nj)
1022          ERROR("CDomain::checkMask(void)",
1023                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1024                << "The mask does not have the same size as the local domain." << std::endl
1025                << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1026                << "Mask size is " << mask_2d.extent(0) << " x " << mask_2d.extent(1) << ".");
1027      }
1028
1029      if (!mask_2d.isEmpty())
1030      {
1031        domainMask.resize(mask_2d.extent(0) * mask_2d.extent(1));
1032        for (int j = 0; j < nj; ++j)
1033          for (int i = 0; i < ni; ++i) domainMask(i+j*ni) = mask_2d(i,j);
1034//        mask_2d.reset();
1035      }
1036      else if (mask_1d.isEmpty())
1037      {
1038        domainMask.resize(i_index.numElements());
1039        for (int i = 0; i < i_index.numElements(); ++i) domainMask(i) = true;
1040      }
1041      else
1042      {
1043      domainMask.resize(mask_1d.numElements());
1044      domainMask=mask_1d ;
1045     }
1046   }
1047   CATCH_DUMP_ATTR
1048
1049   //----------------------------------------------------------------
1050
1051   void CDomain::checkDomainData(void)
1052   TRY
1053   {
1054      if (data_dim.isEmpty())
1055      {
1056        data_dim.setValue(1);
1057      }
1058      else if (!(data_dim.getValue() == 1 || data_dim.getValue() == 2))
1059      {
1060        ERROR("CDomain::checkDomainData(void)",
1061              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1062              << "The data dimension is invalid, 'data_dim' must be 1 or 2 not << " << data_dim.getValue() << ".");
1063      }
1064
1065      if (data_ibegin.isEmpty())
1066         data_ibegin.setValue(0);
1067      if (data_jbegin.isEmpty())
1068         data_jbegin.setValue(0);
1069
1070      if (data_ni.isEmpty())
1071      {
1072        data_ni.setValue((data_dim == 1) ? (ni.getValue() * nj.getValue()) : ni.getValue());
1073      }
1074      else if (data_ni.getValue() < 0)
1075      {
1076        ERROR("CDomain::checkDomainData(void)",
1077              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1078              << "The data size cannot be negative ('data_ni' = " << data_ni.getValue() << ").");
1079      }
1080
1081      if (data_nj.isEmpty())
1082      {
1083        data_nj.setValue((data_dim.getValue() == 1) ? (ni.getValue() * nj.getValue()) : nj.getValue());
1084      }
1085      else if (data_nj.getValue() < 0)
1086      {
1087        ERROR("CDomain::checkDomainData(void)",
1088              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1089              << "The data size cannot be negative ('data_nj' = " << data_nj.getValue() << ").");
1090      }
1091   }
1092   CATCH_DUMP_ATTR
1093
1094   //----------------------------------------------------------------
1095
1096   void CDomain::checkCompression(void)
1097   TRY
1098   {
1099     int i,j,ind;
1100      if (!data_i_index.isEmpty())
1101      {
1102        if (!data_j_index.isEmpty() &&
1103            data_j_index.numElements() != data_i_index.numElements())
1104        {
1105           ERROR("CDomain::checkCompression(void)",
1106                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1107                 << "'data_i_index' and 'data_j_index' arrays must have the same size." << std::endl
1108                 << "'data_i_index' size = " << data_i_index.numElements() << std::endl
1109                 << "'data_j_index' size = " << data_j_index.numElements());
1110        }
1111
1112        if (2 == data_dim)
1113        {
1114          if (data_j_index.isEmpty())
1115          {
1116             ERROR("CDomain::checkCompression(void)",
1117                   << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1118                   << "'data_j_index' must be defined when 'data_i_index' is set and 'data_dim' is 2.");
1119          }
1120          for (int k=0; k<data_i_index.numElements(); ++k)
1121          {
1122            i = data_i_index(k)+data_ibegin ;
1123            j = data_j_index(k)+data_jbegin ;
1124            if (i>=0 && i<ni && j>=0 && j<nj)
1125            {
1126              ind=j*ni+i ;
1127              if ( (ind<0)||(!domainMask(ind)) )
1128              {
1129                data_i_index(k) = -1;
1130                data_j_index(k) = -1;
1131              }
1132            }
1133            else
1134            {
1135              data_i_index(k) = -1;
1136              data_j_index(k) = -1;
1137            }
1138          }
1139        }
1140        else // (1 == data_dim)
1141        {
1142          if (data_j_index.isEmpty())
1143          {
1144            data_j_index.resize(data_ni);
1145            data_j_index = 0;
1146          }
1147          for (int k=0; k<data_i_index.numElements(); ++k)
1148          {
1149            i=data_i_index(k)+data_ibegin ;
1150            if (i>=0 && i < domainMask.size())
1151            {
1152              if (!domainMask(i)) data_i_index(k) = -1;
1153            }
1154            else
1155              data_i_index(k) = -1;
1156
1157            if ( (i<0)||(!domainMask(i)) ) data_i_index(k) = -1;
1158          }
1159        }
1160      }
1161      else
1162      {
1163        if (data_dim == 2 && !data_j_index.isEmpty())
1164          ERROR("CDomain::checkCompression(void)",
1165                << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1166                << "'data_i_index' must be defined when 'data_j_index' is set and 'data_dim' is 2.");
1167
1168        if (1 == data_dim)
1169        {
1170          data_i_index.resize(data_ni);
1171          data_j_index.resize(data_ni);
1172          data_j_index = 0;
1173
1174          for (int k = 0; k < data_ni; ++k)
1175          {
1176            i=k+data_ibegin ;
1177            if (i>=0 && i < domainMask.size())
1178            {
1179              if ( (i<0)||(!domainMask(i)) )
1180                data_i_index(k) = -1;
1181              else
1182                data_i_index(k) = k;
1183            }
1184            else
1185              data_i_index(k) = -1;
1186          }
1187        }
1188        else // (data_dim == 2)
1189        {
1190          const int dsize = data_ni * data_nj;
1191          data_i_index.resize(dsize);
1192          data_j_index.resize(dsize);
1193
1194          for(int count = 0, kj = 0; kj < data_nj; ++kj)
1195          {
1196            for(int ki = 0; ki < data_ni; ++ki, ++count)
1197            {
1198              i = ki + data_ibegin;
1199              j = kj + data_jbegin;
1200              ind=j*ni+i ;
1201              if (i>=0 && i<ni && j>=0 && j<nj)
1202              {
1203                if ( (ind<0)||(!domainMask(ind)) )
1204                {
1205                  data_i_index(count) = -1;
1206                  data_j_index(count) = -1;
1207                }
1208                else
1209                {
1210                  data_i_index(count) = ki;
1211                  data_j_index(count) = kj;
1212                }
1213              }
1214              else
1215              {
1216                data_i_index(count) = -1;
1217                data_j_index(count) = -1;
1218              }
1219            }
1220          }
1221        }
1222      }
1223   }
1224   CATCH_DUMP_ATTR
1225
1226   //----------------------------------------------------------------
1227   void CDomain::computeLocalMask(void)
1228   TRY
1229   {
1230     localMask.resize(i_index.numElements()) ;
1231     localMask=false ;
1232
1233     size_t dn=data_i_index.numElements() ;
1234     int i,j ;
1235     size_t k,ind ;
1236
1237     for(k=0;k<dn;k++)
1238     {
1239       if (data_dim==2)
1240       {
1241          i=data_i_index(k)+data_ibegin ;
1242          j=data_j_index(k)+data_jbegin ;
1243          if (i>=0 && i<ni && j>=0 && j<nj)
1244          {
1245            ind=j*ni+i ;
1246            localMask(ind)=domainMask(ind) ;
1247          }
1248       }
1249       else
1250       {
1251          i=data_i_index(k)+data_ibegin ;
1252          if (i>=0 && i<i_index.numElements())
1253          {
1254            ind=i ;
1255            localMask(ind)=domainMask(ind) ;
1256          }
1257       }
1258     }
1259   }
1260   CATCH_DUMP_ATTR
1261
1262
1263   //----------------------------------------------------------------
1264
1265   /*
1266     Fill in longitude, latitude, bounds, and area into internal values (lonvalue, latvalue, bounds_lonvalue, bounds_latvalue, areavalue)
1267     which will be used by XIOS.
1268   */
1269   void CDomain::completeLonLatClient(void)
1270   TRY
1271   {
1272     bool lonlatValueExisted = (0 != lonvalue.numElements()) || (0 != latvalue.numElements());
1273     checkBounds() ;
1274     checkArea() ;
1275
1276     if (!lonvalue_2d.isEmpty() && !lonlatValueExisted)
1277     {
1278       lonvalue.resize(ni * nj);
1279       latvalue.resize(ni * nj);
1280       if (hasBounds)
1281       {
1282         bounds_lonvalue.resize(nvertex, ni * nj);
1283         bounds_latvalue.resize(nvertex, ni * nj);
1284       }
1285
1286       for (int j = 0; j < nj; ++j)
1287       {
1288         for (int i = 0; i < ni; ++i)
1289         {
1290           int k = j * ni + i;
1291
1292           lonvalue(k) = lonvalue_2d(i,j);
1293           latvalue(k) = latvalue_2d(i,j);
1294
1295           if (hasBounds)
1296           {
1297             for (int n = 0; n < nvertex; ++n)
1298             {
1299               bounds_lonvalue(n,k) = bounds_lon_2d(n,i,j);
1300               bounds_latvalue(n,k) = bounds_lat_2d(n,i,j);
1301             }
1302           }
1303         }
1304       }
1305     }
1306     else if (!lonvalue_1d.isEmpty()  && !lonlatValueExisted)
1307     {
1308       if (type_attr::rectilinear == type)
1309       {
1310         if (ni == lonvalue_1d.numElements() && nj == latvalue_1d.numElements())
1311         {
1312           lonvalue.resize(ni * nj);
1313           latvalue.resize(ni * nj);
1314           if (hasBounds)
1315           {
1316             bounds_lonvalue.resize(nvertex, ni * nj);
1317             bounds_latvalue.resize(nvertex, ni * nj);
1318           }
1319
1320           for (int j = 0; j < nj; ++j)
1321           {
1322             for (int i = 0; i < ni; ++i)
1323             {
1324               int k = j * ni + i;
1325
1326               lonvalue(k) = lonvalue_1d(i);
1327               latvalue(k) = latvalue_1d(j);
1328
1329               if (hasBounds)
1330               {
1331                 for (int n = 0; n < nvertex; ++n)
1332                 {
1333                   bounds_lonvalue(n,k) = bounds_lon_1d(n,i);
1334                   bounds_latvalue(n,k) = bounds_lat_1d(n,j);
1335                 }
1336               }
1337             }
1338           }
1339         }
1340         else if (i_index.numElements() == lonvalue_1d.numElements() && j_index.numElements() == latvalue_1d.numElements()  && !lonlatValueExisted)
1341         {
1342           lonvalue.reference(lonvalue_1d);
1343           latvalue.reference(latvalue_1d);
1344            if (hasBounds)
1345           {
1346             bounds_lonvalue.reference(bounds_lon_1d);
1347             bounds_latvalue.reference(bounds_lat_1d);
1348           }
1349         }
1350         else
1351           ERROR("CDomain::completeLonClient(void)",
1352                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1353                 << "'lonvalue_1d' and 'latvalue_1d' does not have the same size as the local domain." << std::endl
1354                 << "'lonvalue_1d' size is " << lonvalue_1d.numElements() 
1355                 << " and 'latvalue_1d' size is " << latvalue_1d.numElements() << std::endl
1356                 << " They should be correspondingly " << ni.getValue() << " and "  << nj.getValue() << " or " << std::endl
1357                 << i_index.numElements() << " and "  << j_index.numElements() << ".");
1358       }
1359       else if (type == type_attr::curvilinear || type == type_attr::unstructured  && !lonlatValueExisted)
1360       {
1361         lonvalue.reference(lonvalue_1d);
1362         latvalue.reference(latvalue_1d);
1363         if (hasBounds)
1364         {
1365           bounds_lonvalue.reference(bounds_lon_1d);
1366           bounds_latvalue.reference(bounds_lat_1d);
1367         }
1368       }
1369     }
1370
1371     if (!area.isEmpty() && areavalue.isEmpty())
1372     {
1373        areavalue.resize(ni*nj);
1374       for (int j = 0; j < nj; ++j)
1375       {
1376         for (int i = 0; i < ni; ++i)
1377         {
1378           int k = j * ni + i;
1379           areavalue(k) = area(i,j);
1380         }
1381       }
1382     }
1383   }
1384   CATCH_DUMP_ATTR
1385
1386   /*
1387     Convert internal longitude latitude value used by XIOS to "lonvalue_*" which can be retrieved with Fortran interface
1388   */
1389   void CDomain::convertLonLatValue(void)
1390   TRY
1391   {
1392     bool lonlatValueExisted = (0 != lonvalue.numElements()) || (0 != latvalue.numElements());
1393     if (!lonvalue_2d.isEmpty() && lonlatValueExisted)
1394     {
1395       lonvalue_2d.resize(ni,nj);
1396       latvalue_2d.resize(ni,nj);
1397       if (hasBounds)
1398       {
1399         bounds_lon_2d.resize(nvertex, ni, nj);
1400         bounds_lat_2d.resize(nvertex, ni, nj);
1401       }
1402
1403       for (int j = 0; j < nj; ++j)
1404       {
1405         for (int i = 0; i < ni; ++i)
1406         {
1407           int k = j * ni + i;
1408
1409           lonvalue_2d(i,j) = lonvalue(k);
1410           latvalue_2d(i,j) = latvalue(k);
1411
1412           if (hasBounds)
1413           {
1414             for (int n = 0; n < nvertex; ++n)
1415             {
1416               bounds_lon_2d(n,i,j) = bounds_lonvalue(n,k);
1417               bounds_lat_2d(n,i,j) = bounds_latvalue(n,k);
1418             }
1419           }
1420         }
1421       }
1422     }
1423     else if (!lonvalue_1d.isEmpty()  && lonlatValueExisted)
1424     {
1425       if (type_attr::rectilinear == type)
1426       {
1427         if (ni == lonvalue_1d.numElements() && nj == latvalue_1d.numElements())
1428         {
1429           lonvalue.resize(ni * nj);
1430           latvalue.resize(ni * nj);
1431           if (hasBounds)
1432           {
1433             bounds_lonvalue.resize(nvertex, ni * nj);
1434             bounds_latvalue.resize(nvertex, ni * nj);
1435           }
1436
1437           for (int j = 0; j < nj; ++j)
1438           {
1439             for (int i = 0; i < ni; ++i)
1440             {
1441               int k = j * ni + i;
1442
1443               lonvalue(k) = lonvalue_1d(i);
1444               latvalue(k) = latvalue_1d(j);
1445
1446               if (hasBounds)
1447               {
1448                 for (int n = 0; n < nvertex; ++n)
1449                 {
1450                   bounds_lonvalue(n,k) = bounds_lon_1d(n,i);
1451                   bounds_latvalue(n,k) = bounds_lat_1d(n,j);
1452                 }
1453               }
1454             }
1455           }
1456         }
1457         else if (i_index.numElements() == lonvalue_1d.numElements() && j_index.numElements() == latvalue_1d.numElements()  && !lonlatValueExisted)
1458         {
1459           lonvalue.reference(lonvalue_1d);
1460           latvalue.reference(latvalue_1d);
1461            if (hasBounds)
1462           {
1463             bounds_lonvalue.reference(bounds_lon_1d);
1464             bounds_latvalue.reference(bounds_lat_1d);
1465           }
1466         }
1467         else
1468           ERROR("CDomain::completeLonClient(void)",
1469                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1470                 << "'lonvalue_1d' and 'latvalue_1d' does not have the same size as the local domain." << std::endl
1471                 << "'lonvalue_1d' size is " << lonvalue_1d.numElements() 
1472                 << " and 'latvalue_1d' size is " << latvalue_1d.numElements() << std::endl
1473                 << " They should be correspondingly " << ni.getValue() << " and "  << nj.getValue() << " or " << std::endl
1474                 << i_index.numElements() << " and "  << j_index.numElements() << ".");
1475       }
1476       else if (type == type_attr::curvilinear || type == type_attr::unstructured  && !lonlatValueExisted)
1477       {
1478         lonvalue.reference(lonvalue_1d);
1479         latvalue.reference(latvalue_1d);
1480         if (hasBounds)
1481         {
1482           bounds_lonvalue.reference(bounds_lon_1d);
1483           bounds_latvalue.reference(bounds_lat_1d);
1484         }
1485       }
1486     }
1487   }
1488   CATCH_DUMP_ATTR
1489
1490   void CDomain::checkBounds(void)
1491   TRY
1492   {
1493     bool hasBoundValues = (0 != bounds_lonvalue.numElements()) || (0 != bounds_latvalue.numElements());
1494     if (!nvertex.isEmpty() && nvertex > 0 && !hasBoundValues)
1495     {
1496       if (!bounds_lon_1d.isEmpty() && !bounds_lon_2d.isEmpty())
1497         ERROR("CDomain::checkBounds(void)",
1498               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1499               << "Only one longitude boundary attribute can be used but both 'bounds_lon_1d' and 'bounds_lon_2d' are defined." << std::endl
1500               << "Define only one longitude boundary attribute: 'bounds_lon_1d' or 'bounds_lon_2d'.");
1501
1502       if (!bounds_lat_1d.isEmpty() && !bounds_lat_2d.isEmpty())
1503         ERROR("CDomain::checkBounds(void)",
1504               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1505               << "Only one latitude boundary attribute can be used but both 'bounds_lat_1d' and 'bounds_lat_2d' are defined." << std::endl
1506               << "Define only one latitude boundary attribute: 'bounds_lat_1d' or 'bounds_lat_2d'.");
1507
1508       if ((!bounds_lon_1d.isEmpty() && bounds_lat_1d.isEmpty()) || (bounds_lon_1d.isEmpty() && !bounds_lat_1d.isEmpty()))
1509       {
1510         ERROR("CDomain::checkBounds(void)",
1511               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1512               << "Only 'bounds_lon_1d' or 'bounds_lat_1d' is defined." << std::endl
1513               << "Please define either both attributes or none.");
1514       }
1515
1516       if ((!bounds_lon_2d.isEmpty() && bounds_lat_2d.isEmpty()) || (bounds_lon_2d.isEmpty() && !bounds_lat_2d.isEmpty()))
1517       {
1518         ERROR("CDomain::checkBounds(void)",
1519               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1520               << "Only 'bounds_lon_2d' or 'bounds_lat_2d' is defined." << std::endl
1521               << "Please define either both attributes or none.");
1522       }
1523
1524       if (!bounds_lon_1d.isEmpty() && nvertex.getValue() != bounds_lon_1d.extent(0))
1525         ERROR("CDomain::checkBounds(void)",
1526               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1527               << "'bounds_lon_1d' dimension is not compatible with 'nvertex'." << std::endl
1528               << "'bounds_lon_1d' dimension is " << bounds_lon_1d.extent(0)
1529               << " but nvertex is " << nvertex.getValue() << ".");
1530
1531       if (!bounds_lon_2d.isEmpty() && nvertex.getValue() != bounds_lon_2d.extent(0))
1532         ERROR("CDomain::checkBounds(void)",
1533               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1534               << "'bounds_lon_2d' dimension is not compatible with 'nvertex'." << std::endl
1535               << "'bounds_lon_2d' dimension is " << bounds_lon_2d.extent(0)
1536               << " but nvertex is " << nvertex.getValue() << ".");
1537
1538       if (!bounds_lon_1d.isEmpty() && lonvalue_1d.isEmpty())
1539         ERROR("CDomain::checkBounds(void)",
1540               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1541               << "Since 'bounds_lon_1d' is defined, 'lonvalue_1d' must be defined too." << std::endl);
1542
1543       if (!bounds_lon_2d.isEmpty() && lonvalue_2d.isEmpty())
1544         ERROR("CDomain::checkBounds(void)",
1545               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1546               << "Since 'bounds_lon_2d' is defined, 'lonvalue_2d' must be defined too." << std::endl);
1547
1548       if (!bounds_lat_1d.isEmpty() && nvertex.getValue() != bounds_lat_1d.extent(0))
1549         ERROR("CDomain::checkBounds(void)",
1550               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1551               << "'bounds_lat_1d' dimension is not compatible with 'nvertex'." << std::endl
1552               << "'bounds_lat_1d' dimension is " << bounds_lat_1d.extent(0)
1553               << " but nvertex is " << nvertex.getValue() << ".");
1554
1555       if (!bounds_lat_2d.isEmpty() && nvertex.getValue() != bounds_lat_2d.extent(0))
1556         ERROR("CDomain::checkBounds(void)",
1557               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1558               << "'bounds_lat_2d' dimension is not compatible with 'nvertex'." << std::endl
1559               << "'bounds_lat_2d' dimension is " << bounds_lat_2d.extent(0)
1560               << " but nvertex is " << nvertex.getValue() << ".");
1561
1562       if (!bounds_lat_1d.isEmpty() && latvalue_1d.isEmpty())
1563         ERROR("CDomain::checkBounds(void)",
1564               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1565               << "Since 'bounds_lat_1d' is defined, 'latvalue_1d' must be defined too." << std::endl);
1566
1567       if (!bounds_lat_2d.isEmpty() && latvalue_2d.isEmpty())
1568         ERROR("CDomain::checkBounds(void)",
1569               << "Since 'bounds_lat_2d' is defined, 'latvalue_2d' must be defined too." << std::endl);
1570
1571       // In case of reading UGRID bounds values are not required
1572       hasBounds = (!bounds_lat_1d.isEmpty() || !bounds_lat_2d.isEmpty() );
1573     }
1574     else if (hasBoundValues)
1575     {
1576       hasBounds = true;       
1577     }
1578     else
1579     {
1580       hasBounds = false;
1581     }
1582   }
1583   CATCH_DUMP_ATTR
1584
1585   void CDomain::checkArea(void)
1586   TRY
1587   {
1588     bool hasAreaValue = (!areavalue.isEmpty() && 0 != areavalue.numElements());
1589     hasArea = !area.isEmpty();
1590     if (hasArea && !hasAreaValue)
1591     {
1592       if (area.extent(0) != ni || area.extent(1) != nj)
1593       {
1594         ERROR("CDomain::checkArea(void)",
1595               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1596               << "The area does not have the same size as the local domain." << std::endl
1597               << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1598               << "Area size is " << area.extent(0) << " x " << area.extent(1) << ".");
1599       }
1600//       if (areavalue.isEmpty())
1601//       {
1602//          areavalue.resize(ni*nj);
1603//         for (int j = 0; j < nj; ++j)
1604//         {
1605//           for (int i = 0; i < ni; ++i)
1606//           {
1607//             int k = j * ni + i;
1608//             areavalue(k) = area(i,j);
1609//           }
1610//         }
1611//       }
1612     }
1613   }
1614   CATCH_DUMP_ATTR
1615
1616   void CDomain::checkLonLat()
1617   TRY
1618   {
1619     if (!hasLonLat) hasLonLat = (!latvalue_1d.isEmpty() && !lonvalue_1d.isEmpty()) ||
1620                                 (!latvalue_2d.isEmpty() && !lonvalue_2d.isEmpty());
1621     bool hasLonLatValue = (0 != lonvalue.numElements()) || (0 != latvalue.numElements());
1622     if (hasLonLat && !hasLonLatValue)
1623     {
1624       if (!lonvalue_1d.isEmpty() && !lonvalue_2d.isEmpty())
1625         ERROR("CDomain::checkLonLat()",
1626               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1627               << "Only one longitude attribute can be used but both 'lonvalue_1d' and 'lonvalue_2d' are defined." << std::endl
1628               << "Define only one longitude attribute: 'lonvalue_1d' or 'lonvalue_2d'.");
1629
1630       if (!lonvalue_1d.isEmpty() && lonvalue_2d.isEmpty())
1631       {
1632         if ((type_attr::rectilinear != type) && (lonvalue_1d.numElements() != i_index.numElements()))
1633           ERROR("CDomain::checkLonLat()",
1634                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1635                 << "'lonvalue_1d' does not have the same size as the local domain." << std::endl
1636                 << "Local size is " << i_index.numElements() << "." << std::endl
1637                 << "'lonvalue_1d' size is " << lonvalue_1d.numElements() << ".");
1638       }
1639
1640       if (lonvalue_1d.isEmpty() && !lonvalue_2d.isEmpty())
1641       {
1642         if (lonvalue_2d.extent(0) != ni || lonvalue_2d.extent(1) != nj)
1643           ERROR("CDomain::checkLonLat()",
1644                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1645                 << "'lonvalue_2d' does not have the same size as the local domain." << std::endl
1646                 << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1647                 << "'lonvalue_2d' size is " << lonvalue_2d.extent(0) << " x " << lonvalue_2d.extent(1) << ".");
1648       }
1649
1650       if (!latvalue_1d.isEmpty() && !latvalue_2d.isEmpty())
1651         ERROR("CDomain::checkLonLat()",
1652               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1653               << "Only one latitude attribute can be used but both 'latvalue_1d' and 'latvalue_2d' are defined." << std::endl
1654               << "Define only one latitude attribute: 'latvalue_1d' or 'latvalue_2d'.");
1655
1656       if (!latvalue_1d.isEmpty() && latvalue_2d.isEmpty())
1657       {
1658         if ((type_attr::rectilinear != type) && (latvalue_1d.numElements() != i_index.numElements()))
1659           ERROR("CDomain::checkLonLat()",
1660                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1661                 << "'latvalue_1d' does not have the same size as the local domain." << std::endl
1662                 << "Local size is " << i_index.numElements() << "." << std::endl
1663                 << "'latvalue_1d' size is " << latvalue_1d.numElements() << ".");
1664       }
1665
1666       if (latvalue_1d.isEmpty() && !latvalue_2d.isEmpty())
1667       {
1668         if (latvalue_2d.extent(0) != ni || latvalue_2d.extent(1) != nj)
1669           ERROR("CDomain::checkLonLat()",
1670                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1671                 << "'latvalue_2d' does not have the same size as the local domain." << std::endl
1672                 << "Local size is " << ni.getValue() << " x " << nj.getValue() << "." << std::endl
1673                 << "'latvalue_2d' size is " << latvalue_2d.extent(0) << " x " << latvalue_2d.extent(1) << ".");
1674       }
1675     }
1676   }
1677   CATCH_DUMP_ATTR
1678
1679   void CDomain::checkAttributes(void)
1680   TRY
1681   {
1682      if (this->checkAttributes_done_) return;
1683      this->checkDomain();
1684      this->checkLonLat();
1685      this->checkBounds();
1686      this->checkArea();
1687      this->checkMask();
1688      this->checkDomainData();
1689      this->checkCompression();
1690      this->computeLocalMask() ;
1691      this->completeLonLatClient();
1692      this->initializeLocalElement() ;
1693      this->addFullView() ; // probably do not automatically add View, but only if requested
1694      this->addWorkflowView() ; // probably do not automatically add View, but only if requested
1695      this->addModelView() ; // probably do not automatically add View, but only if requested
1696      // testing ?
1697     /*
1698      CLocalView* local = localElement_->getView(CElementView::WORKFLOW) ;
1699      CLocalView* model = localElement_->getView(CElementView::MODEL) ;
1700
1701      CLocalConnector test1(model, local) ;
1702      test1.computeConnector() ;
1703      CLocalConnector test2(local, model) ;
1704      test2.computeConnector() ;
1705      CGridLocalConnector gridTest1(vector<CLocalConnector*>{&test1}) ;
1706      CGridLocalConnector gridTest2(vector<CLocalConnector*>{&test2}) ;
1707     
1708     
1709      CArray<int,1> out1 ;
1710      CArray<int,1> out2 ;
1711      test1.transfer(data_i_index,out1,-111) ;
1712      test2.transfer(out1,out2,-111) ;
1713     
1714      out1 = 0 ;
1715      out2 = 0 ;
1716      gridTest1.transfer(data_i_index,out1,-111) ;
1717      gridTest2.transfer(out1, out2,-111) ;
1718    */ 
1719      this->checkAttributes_done_ = true;
1720   }
1721   CATCH_DUMP_ATTR
1722
1723
1724   void CDomain::initializeLocalElement(void)
1725   {
1726      // after checkDomain i_index and j_index of size (ni*nj)
1727      int nij = ni*nj ;
1728      CArray<size_t, 1> ij_index(ni*nj) ;
1729      for(int ij=0; ij<nij ; ij++) ij_index(ij) = i_index(ij)+j_index(ij)*ni_glo ;
1730      int rank = CContext::getCurrent()->getIntraCommRank() ;
1731      localElement_ = new CLocalElement(rank, ni_glo*nj_glo, ij_index) ;
1732   }
1733
1734   void CDomain::addFullView(void)
1735   {
1736      CArray<int,1> index(ni*nj) ;
1737      int nij=ni*nj ;
1738      for(int ij=0; ij<nij ; ij++) index(ij)=ij ;
1739      localElement_ -> addView(CElementView::FULL, index) ;
1740   }
1741
1742   void CDomain::addWorkflowView(void)
1743   {
1744     // information for workflow view is stored in localMask
1745     int nij=ni*nj ;
1746     int nMask=0 ;
1747     for(int ij=0; ij<nij ; ij++) if (localMask(ij)) nMask++ ;
1748     CArray<int,1> index(nMask) ;
1749
1750     nMask=0 ;
1751     for(int ij=0; ij<nij ; ij++) 
1752      if (localMask(ij))
1753      {
1754        index(nMask)=ij ;
1755        nMask++ ;
1756      }
1757      localElement_ -> addView(CElementView::WORKFLOW, index) ;
1758   }
1759
1760   void CDomain::addModelView(void)
1761   {
1762     // information for model view is stored in data_i_index/data_j_index
1763     // very weird, do not mix data_i_index and data_i_begin => in future only keep data_i_index
1764     int dataSize = data_i_index.numElements() ;
1765     CArray<int,1> index(dataSize) ;
1766     int i,j ;
1767     for(int k=0;k<dataSize;k++)
1768     {
1769        if (data_dim==2)
1770        {
1771          i=data_i_index(k)+data_ibegin ; // bad
1772          j=data_j_index(k)+data_jbegin ; // bad
1773          if (i>=0 && i<ni && j>=0 && j<nj) index(k)=i+j*ni ;
1774          else index(k)=-1 ;
1775        }
1776        else if (data_dim==1)
1777        {
1778          i=data_i_index(k)+data_ibegin ; // bad
1779          if (i>=0 && i<ni*nj) index(k)=i ;
1780          else index(k)=-1 ;
1781        }
1782     }
1783     localElement_->addView(CElementView::MODEL, index) ;
1784   }
1785       
1786   void CDomain::computeModelToWorkflowConnector(void)
1787   { 
1788     CLocalView* srcView=getLocalView(CElementView::MODEL) ;
1789     CLocalView* dstView=getLocalView(CElementView::WORKFLOW) ;
1790     modelToWorkflowConnector_ = new CLocalConnector(srcView, dstView); 
1791     modelToWorkflowConnector_->computeConnector() ;
1792   }
1793
1794
1795  string CDomain::getCouplingAlias(const string& fieldId, int posInGrid)
1796  {
1797    return "_domain["+std::to_string(posInGrid)+"]_of_"+fieldId ;
1798  }
1799   
1800  /* to be removed later when coupling will be reimplemented, just to  not forget */
1801  void CDomain::sendDomainToCouplerOut(CContextClient* client, const string& fieldId, int posInGrid)
1802  {
1803    if (sendDomainToFileServer_done_.count(client)!=0) return ;
1804    else sendDomainToFileServer_done_.insert(client) ;
1805   
1806    const string domainId = getCouplingAlias(fieldId, posInGrid) ;
1807   
1808    if (!domain_ref.isEmpty())
1809    {
1810      auto domain_ref_tmp=domain_ref.getValue() ;
1811      domain_ref.reset() ; // remove the reference, find an other way to do that more cleanly
1812      this->sendAllAttributesToServer(client, domainId)  ;
1813      domain_ref = domain_ref_tmp ;
1814    }
1815    else this->sendAllAttributesToServer(client, domainId)  ;
1816  }
1817
1818
1819
1820
1821  void CDomain::makeAliasForCoupling(const string& fieldId, int posInGrid)
1822  {
1823    const string domainId = getCouplingAlias(fieldId, posInGrid);
1824    this->createAlias(domainId) ;
1825  }
1826
1827
1828  void CDomain::computeRemoteElement(CContextClient* client, EDistributionType type)
1829  TRY
1830  {
1831    CContext* context = CContext::getCurrent();
1832    map<int, CArray<size_t,1>> globalIndex ;
1833
1834    if (type==EDistributionType::BANDS) // Bands distribution to send to file server
1835    {
1836      int nbServer = client->serverSize;
1837      std::vector<int> nGlobDomain(2);
1838      nGlobDomain[0] = this->ni_glo;
1839      nGlobDomain[1] = this->nj_glo;
1840
1841      // to be changed in future, need to rewrite more simply domain distribution
1842      CServerDistributionDescription serverDescription(nGlobDomain, nbServer);
1843      int distributedPosition ;
1844      if (isUnstructed_) distributedPosition = 0 ;
1845      else distributedPosition = 1 ;
1846     
1847      std::vector<std::vector<int> > serverIndexBegin = serverDescription.getServerIndexBegin();
1848      std::vector<std::vector<int> > serverDimensionSizes = serverDescription.getServerDimensionSizes();
1849      vector<unordered_map<size_t,vector<int>>> indexServerOnElement ;
1850      CArray<int,1> axisDomainOrder(1) ; axisDomainOrder(0)=2 ;
1851      auto zeroIndex=serverDescription.computeServerGlobalByElement(indexServerOnElement, context->getIntraCommRank(), context->getIntraCommSize(),
1852                                                                  axisDomainOrder,distributedPosition) ;
1853      // distribution is very bad => to redo
1854      // convert indexServerOnElement => map<int,CArray<size_t,1>> - need to be changed later
1855      map<int, vector<size_t>> vectGlobalIndex ;
1856      for(auto& indexRanks : indexServerOnElement[0])
1857      {
1858        size_t index=indexRanks.first ;
1859        auto& ranks=indexRanks.second ;
1860        for(int rank : ranks) vectGlobalIndex[rank].push_back(index) ;
1861      }
1862      for(auto& vect : vectGlobalIndex ) globalIndex.emplace(vect.first, CArray<size_t,1>(vect.second.data(), shape(vect.second.size()),duplicateData)) ;
1863    // some servers receves no index (zeroIndex array) => root process take them into account.
1864      if (context->getIntraCommRank()==0) 
1865        for(auto& rank : zeroIndex) globalIndex[rank] = CArray<size_t,1>() ; 
1866    }
1867    else if (type==EDistributionType::NONE) // domain is not distributed ie all servers get the same local domain
1868    {
1869      int nbServer = client->serverSize;
1870      int nglo=ni_glo*nj_glo ;
1871      CArray<size_t,1> indGlo ;
1872      for(size_t i=0;i<nglo;i++) indGlo(i) = i ;
1873      for (auto& rankServer : client->getRanksServerLeader()) globalIndex[rankServer] = indGlo ; 
1874    }
1875    remoteElement_[client] = new CDistributedElement(ni_glo*nj_glo, globalIndex) ;
1876    remoteElement_[client]->addFullView() ;
1877  }
1878  CATCH
1879
1880 
1881
1882  void CDomain::distributeToServer(CContextClient* client, map<int, CArray<size_t,1>>& globalIndex,
1883                                   CScattererConnector* &scattererConnector, const string& domainId)
1884  TRY
1885  {
1886    string serverDomainId = domainId.empty() ? this->getId() : domainId ;
1887    CContext* context = CContext::getCurrent();
1888
1889    this->sendAllAttributesToServer(client, serverDomainId)  ;
1890
1891    CDistributedElement scatteredElement(ni_glo*nj_glo, globalIndex) ;
1892    scatteredElement.addFullView() ;
1893    scattererConnector = new CScattererConnector(localElement_->getView(CElementView::FULL), scatteredElement.getView(CElementView::FULL), 
1894                                           context->getIntraComm(), client->getRemoteSize()) ;
1895    scattererConnector->computeConnector() ;
1896
1897    // phase 0
1898    // send remote element to construct the full view on server, ie without hole
1899    CEventClient event0(getType(), EVENT_ID_DOMAIN_DISTRIBUTION);
1900    CMessage message0 ;
1901    message0<<serverDomainId<<0 ; 
1902    remoteElement_[client]->sendToServer(client,event0,message0) ; 
1903   
1904    // phase 1
1905    // send the full view of element to construct the connector which connect distributed data coming from client to the full local view
1906    CEventClient event1(getType(), EVENT_ID_DOMAIN_DISTRIBUTION);
1907    CMessage message1 ;
1908    message1<<serverDomainId<<1<<localElement_->getView(CElementView::FULL)->getGlobalSize() ; 
1909    scattererConnector->transfer(localElement_->getView(CElementView::FULL)->getGlobalIndex(),client,event1,message1) ;
1910   
1911    sendDistributedAttributes(client, *scattererConnector, domainId) ;
1912
1913 
1914    // phase 2 send the mask : data index + mask2D
1915    CArray<bool,1> maskIn(localElement_->getView(CElementView::WORKFLOW)->getSize());
1916    CArray<bool,1> maskOut ;
1917    CLocalConnector workflowToFull(localElement_->getView(CElementView::WORKFLOW), localElement_->getView(CElementView::FULL)) ;
1918    workflowToFull.computeConnector() ;
1919    maskIn=true ;
1920    workflowToFull.transfer(maskIn,maskOut,false) ;
1921
1922
1923    // phase 3 : prepare grid scatterer connector to send data from client to server
1924    map<int,CArray<size_t,1>> workflowGlobalIndex ;
1925    map<int,CArray<bool,1>> maskOut2 ; 
1926    scattererConnector->transfer(maskOut, maskOut2, false) ;
1927    scatteredElement.addView(CElementView::WORKFLOW, maskOut2) ;
1928    scatteredElement.getView(CElementView::WORKFLOW)->getGlobalIndexView(workflowGlobalIndex) ;
1929    // create new workflow view for scattered element
1930    CDistributedElement clientToServerElement(scatteredElement.getGlobalSize(), workflowGlobalIndex) ;
1931    clientToServerElement.addFullView() ;
1932    CEventClient event2(getType(), EVENT_ID_DOMAIN_DISTRIBUTION);
1933    CMessage message2 ;
1934    message2<<serverDomainId<<2 ; 
1935    clientToServerElement.sendToServer(client, event2, message2) ; 
1936    clientToServerConnector_[client] = new CScattererConnector(localElement_->getView(CElementView::WORKFLOW), clientToServerElement.getView(CElementView::FULL),
1937                                                               context->getIntraComm(), client->getRemoteSize()) ;
1938    clientToServerConnector_[client]->computeConnector() ;
1939
1940    clientFromServerConnector_[client] = new CGathererConnector(clientToServerElement.getView(CElementView::FULL), localElement_->getView(CElementView::WORKFLOW));
1941    clientFromServerConnector_[client]->computeConnector() ;
1942
1943  }
1944  CATCH
1945 
1946  void CDomain::recvDomainDistribution(CEventServer& event)
1947  TRY
1948  {
1949    string domainId;
1950    int phasis ;
1951    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> domainId >> phasis ;
1952    get(domainId)->receivedDomainDistribution(event, phasis);
1953  }
1954  CATCH
1955
1956  void CDomain::receivedDomainDistribution(CEventServer& event, int phasis)
1957  TRY
1958  {
1959    CContext* context = CContext::getCurrent();
1960    if (phasis==0) // receive the remote element to construct the full view
1961    {
1962      localElement_ = new  CLocalElement(context->getIntraCommRank(),event) ;
1963      localElement_->addFullView() ;
1964      // construct the local dimension and indexes
1965      auto& globalIndex=localElement_->getGlobalIndex() ;
1966      int nij=globalIndex.numElements() ;
1967      int minI=ni_glo,maxI=-1,minJ=nj_glo,maxJ=-1 ;
1968      int i,j ;
1969      int niGlo=ni_glo, njGlo=njGlo ;
1970      for(int ij=0;ij<nij;ij++)
1971      {
1972        j=globalIndex(ij)/niGlo ;
1973        i=globalIndex(ij)%niGlo ;
1974        if (i<minI) minI=i ;
1975        if (i>maxI) maxI=i ;
1976        if (j<minJ) minJ=j ;
1977        if (j>maxJ) maxJ=j ;
1978      } 
1979      if (maxI>=minI) { ibegin=minI ; ni=maxI-minI+1 ; }
1980      else {ibegin=0; ni=0 ;}
1981      if (maxJ>=minJ) { jbegin=minJ ; nj=maxJ-minJ+1 ; }
1982      else {jbegin=0; nj=0 ;}
1983
1984    }
1985    else if (phasis==1) // receive the sent view from client to construct the full distributed full view on server
1986    {
1987      CContext* context = CContext::getCurrent();
1988      CDistributedElement* elementFrom = new  CDistributedElement(event) ;
1989      elementFrom->addFullView() ;
1990      gathererConnector_ = new CGathererConnector(elementFrom->getView(CElementView::FULL), localElement_->getView(CElementView::FULL)) ;
1991      gathererConnector_->computeConnector() ; 
1992    }
1993    else if (phasis==2)
1994    {
1995//      delete gathererConnector_ ;
1996      elementFrom_ = new  CDistributedElement(event) ;
1997      elementFrom_->addFullView() ;
1998//      gathererConnector_ =  new CGathererConnector(elementFrom_->getView(CElementView::FULL), localElement_->getView(CElementView::FULL)) ;
1999//      gathererConnector_ -> computeConnector() ;
2000    }
2001  }
2002  CATCH
2003
2004  void CDomain::setServerMask(CArray<bool,1>& serverMask, CContextClient* client)
2005  TRY
2006  {
2007    // nota : the client is needed to get the remote size for the scatterer connector. Maybe it is not the good place for this
2008    // Later, server to client connector can be computed on demand, with "client" as argument
2009    CContext* context = CContext::getCurrent();
2010    localElement_->addView(CElementView::WORKFLOW, serverMask) ;
2011    mask_1d.reference(serverMask.copy()) ;
2012 
2013    serverFromClientConnector_ = new CGathererConnector(elementFrom_->getView(CElementView::FULL), localElement_->getView(CElementView::WORKFLOW)) ;
2014    serverFromClientConnector_->computeConnector() ;
2015     
2016    serverToClientConnector_ = new CScattererConnector(localElement_->getView(CElementView::WORKFLOW), elementFrom_->getView(CElementView::FULL),
2017                                                       context->getIntraComm(), client->getRemoteSize()) ;
2018    serverToClientConnector_->computeConnector() ;
2019  }
2020  CATCH_DUMP_ATTR
2021
2022
2023  void CDomain::sendDistributedAttributes(CContextClient* client, CScattererConnector& scattererConnector,  const string& domainId)
2024  {
2025    string serverDomainId = domainId.empty() ? this->getId() : domainId ;
2026    CContext* context = CContext::getCurrent();
2027
2028    if (hasLonLat)
2029    {
2030      { // send longitude
2031        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
2032        CMessage message ;
2033        message<<serverDomainId<<string("lon") ; 
2034        scattererConnector.transfer(lonvalue, client, event,message) ;
2035      }
2036     
2037      { // send latitude
2038        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
2039        CMessage message ;
2040        message<<serverDomainId<<string("lat") ; 
2041        scattererConnector.transfer(latvalue, client, event, message) ;
2042      }
2043    }
2044
2045    if (hasBounds)
2046    { 
2047      { // send longitude boudaries
2048        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
2049        CMessage message ;
2050        message<<serverDomainId<<string("boundslon") ; 
2051        scattererConnector.transfer(nvertex, bounds_lonvalue, client, event, message ) ;
2052      }
2053
2054      { // send latitude boudaries
2055        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
2056        CMessage message ;
2057        message<<serverDomainId<<string("boundslat") ; 
2058        scattererConnector.transfer(nvertex, bounds_latvalue, client, event, message ) ;
2059      }
2060    }
2061
2062    if (hasArea)
2063    {  // send area
2064      CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
2065      CMessage message ;
2066      message<<serverDomainId<<string("area") ; 
2067      scattererConnector.transfer(areavalue, client, event,message) ;
2068    }
2069  }
2070
2071  void CDomain::recvDistributedAttributes(CEventServer& event)
2072  TRY
2073  {
2074    string domainId;
2075    string type ;
2076    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> domainId >> type ;
2077    get(domainId)->recvDistributedAttributes(event, type);
2078  }
2079  CATCH
2080
2081  void CDomain::recvDistributedAttributes(CEventServer& event, const string& type)
2082  TRY
2083  {
2084    if (type=="lon") 
2085    {
2086      CArray<double,1> value ;
2087      gathererConnector_->transfer(event, value, 0.); 
2088      lonvalue_2d.resize(ni,nj) ;
2089      if (lonvalue_2d.numElements()>0) lonvalue_2d=CArray<double,2>(value.dataFirst(),shape(ni,nj),neverDeleteData) ; 
2090    }
2091    else if (type=="lat")
2092    {
2093      CArray<double,1> value ;
2094      gathererConnector_->transfer(event, value, 0.); 
2095      latvalue_2d.resize(ni,nj) ;
2096      if (latvalue_2d.numElements()>0) latvalue_2d=CArray<double,2>(value.dataFirst(),shape(ni,nj),neverDeleteData) ; 
2097    }
2098    else if (type=="boundslon")
2099    {
2100      CArray<double,1> value ;
2101      gathererConnector_->transfer(event, nvertex, value, 0.); 
2102      bounds_lon_2d.resize(nvertex,ni,nj) ;
2103      if (bounds_lon_2d.numElements()>0) bounds_lon_2d=CArray<double,3>(value.dataFirst(),shape(nvertex,ni,nj),neverDeleteData) ; 
2104    }
2105    else if (type=="boundslat")
2106    {
2107      CArray<double,1> value ;
2108      gathererConnector_->transfer(event, nvertex, value, 0.); 
2109      bounds_lat_2d.resize(nvertex,ni,nj) ;
2110      if (bounds_lat_2d.numElements()>0) bounds_lat_2d=CArray<double,3>(value.dataFirst(),shape(nvertex,ni,nj),neverDeleteData) ; 
2111    }
2112    else if (type=="area") 
2113    {
2114      CArray<double,1> value ;
2115      gathererConnector_->transfer(event, value, 0.); 
2116      area.resize(ni,nj) ;
2117      if (area.numElements()>0) area=CArray<double,2>(value.dataFirst(),shape(ni,nj),neverDeleteData) ; 
2118    }
2119  }
2120  CATCH
2121   
2122  bool CDomain::dispatchEvent(CEventServer& event)
2123  TRY
2124  {
2125    if (SuperClass::dispatchEvent(event)) return true;
2126    else
2127    {
2128      switch(event.type)
2129      {
2130        case EVENT_ID_DOMAIN_DISTRIBUTION:
2131          recvDomainDistribution(event);
2132          return true;
2133          break;
2134        case EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE:
2135          recvDistributedAttributes(event);
2136          return true;
2137          break; 
2138        default:
2139          ERROR("bool CDomain::dispatchEvent(CEventServer& event)",
2140                << "Unknown Event");
2141          return false;
2142       }
2143    }
2144  }
2145  CATCH
2146
2147 
2148  /*!
2149    Compare two domain objects.
2150    They are equal if only if they have identical attributes as well as their values.
2151    Moreover, they must have the same transformations.
2152  \param [in] domain Compared domain
2153  \return result of the comparison
2154  */
2155  bool CDomain::isEqual(CDomain* obj)
2156  TRY
2157  {
2158    vector<StdString> excludedAttr;
2159    excludedAttr.push_back("domain_ref");
2160    bool objEqual = SuperClass::isEqual(obj, excludedAttr);
2161    if (!objEqual) return objEqual;
2162
2163    TransMapTypes thisTrans = this->getAllTransformations();
2164    TransMapTypes objTrans  = obj->getAllTransformations();
2165
2166    TransMapTypes::const_iterator it, itb, ite;
2167    std::vector<ETranformationType> thisTransType, objTransType;
2168    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
2169      thisTransType.push_back(it->first);
2170    for (it = objTrans.begin(); it != objTrans.end(); ++it)
2171      objTransType.push_back(it->first);
2172
2173    if (thisTransType.size() != objTransType.size()) return false;
2174    for (int idx = 0; idx < thisTransType.size(); ++idx)
2175      objEqual &= (thisTransType[idx] == objTransType[idx]);
2176
2177    return objEqual;
2178  }
2179  CATCH_DUMP_ATTR
2180
2181/////////////////////////////////////////////////////////////////////////
2182///////////////             TRANSFORMATIONS                    //////////
2183/////////////////////////////////////////////////////////////////////////
2184
2185  std::map<StdString, ETranformationType> CDomain::transformationMapList_ = std::map<StdString, ETranformationType>();
2186  bool CDomain::dummyTransformationMapList_ = CDomain::initializeTransformationMap(CDomain::transformationMapList_);
2187
2188  bool CDomain::initializeTransformationMap(std::map<StdString, ETranformationType>& m)
2189  TRY
2190  {
2191    m["zoom_domain"] = TRANS_ZOOM_DOMAIN;
2192    m["interpolate_domain"] = TRANS_INTERPOLATE_DOMAIN;
2193    m["generate_rectilinear_domain"] = TRANS_GENERATE_RECTILINEAR_DOMAIN;
2194    m["compute_connectivity_domain"] = TRANS_COMPUTE_CONNECTIVITY_DOMAIN;
2195    m["expand_domain"] = TRANS_EXPAND_DOMAIN;
2196    m["reorder_domain"] = TRANS_REORDER_DOMAIN;
2197    m["extract_domain"] = TRANS_EXTRACT_DOMAIN;
2198  }
2199  CATCH
2200
2201
2202  CTransformation<CDomain>* CDomain::addTransformation(ETranformationType transType, const StdString& id)
2203  TRY
2204  {
2205    transformationMap_.push_back(std::make_pair(transType, CTransformation<CDomain>::createTransformation(transType,id)));
2206    return transformationMap_.back().second;
2207  }
2208  CATCH_DUMP_ATTR
2209
2210  CTransformation<CDomain>* CDomain::addTransformation(ETranformationType transType, CTransformation<CDomain>* transformation)
2211  TRY
2212  {
2213    transformationMap_.push_back(std::make_pair(transType, transformation));
2214    return transformationMap_.back().second;
2215  }
2216  CATCH_DUMP_ATTR
2217  /*!
2218    Check whether a domain has transformation
2219    \return true if domain has transformation
2220  */
2221  bool CDomain::hasTransformation()
2222  TRY
2223  {
2224    return (!transformationMap_.empty());
2225  }
2226  CATCH_DUMP_ATTR
2227
2228  /*!
2229    Set transformation for current domain. It's the method to move transformation in hierarchy
2230    \param [in] domTrans transformation on domain
2231  */
2232  void CDomain::setTransformations(const TransMapTypes& domTrans)
2233  TRY
2234  {
2235    transformationMap_ = domTrans;
2236  }
2237  CATCH_DUMP_ATTR
2238
2239  /*!
2240    Get all transformation current domain has
2241    \return all transformation
2242  */
2243  CDomain::TransMapTypes CDomain::getAllTransformations(void)
2244  TRY
2245  {
2246    return transformationMap_;
2247  }
2248  CATCH_DUMP_ATTR
2249
2250  void CDomain::duplicateTransformation(CDomain* src)
2251  TRY
2252  {
2253    if (src->hasTransformation())
2254    {
2255      this->setTransformations(src->getAllTransformations());
2256    }
2257  }
2258  CATCH_DUMP_ATTR
2259   
2260  /*!
2261   * Go through the hierarchy to find the domain from which the transformations must be inherited
2262   */
2263  void CDomain::solveInheritanceTransformation_old()
2264  TRY
2265  {
2266    if (hasTransformation() || !hasDirectDomainReference())
2267      return;
2268
2269    CDomain* domain = this;
2270    std::vector<CDomain*> refDomains;
2271    while (!domain->hasTransformation() && domain->hasDirectDomainReference())
2272    {
2273      refDomains.push_back(domain);
2274      domain = domain->getDirectDomainReference();
2275    }
2276
2277    if (domain->hasTransformation())
2278      for (size_t i = 0; i < refDomains.size(); ++i)
2279        refDomains[i]->setTransformations(domain->getAllTransformations());
2280  }
2281  CATCH_DUMP_ATTR
2282
2283
2284  void CDomain::solveInheritanceTransformation()
2285  TRY
2286  {
2287    if (solveInheritanceTransformation_done_) return;
2288    else solveInheritanceTransformation_done_=true ;
2289
2290    CDomain* domain = this;
2291    CDomain* Lastdomain ;
2292    std::list<CDomain*> refDomains;
2293    bool out=false ;
2294    vector<StdString> excludedAttr;
2295    excludedAttr.push_back("domain_ref");
2296   
2297    refDomains.push_front(domain) ;
2298    while (domain->hasDirectDomainReference() && !out)
2299    {
2300      CDomain* lastDomain=domain ;
2301      domain = domain->getDirectDomainReference();
2302      domain->solveRefInheritance() ;
2303      if (!domain->SuperClass::isEqual(lastDomain,excludedAttr)) out=true ;
2304      refDomains.push_front(domain) ;
2305    }
2306
2307    CTransformationPaths::TPath path ;
2308    auto& pathList = std::get<2>(path) ;
2309    std::get<0>(path) = EElement::DOMAIN ;
2310    std::get<1>(path) = refDomains.front()->getId() ;
2311    for (auto& domain : refDomains)
2312    {
2313      CDomain::TransMapTypes transformations = domain->getAllTransformations();
2314      for(auto& transformation : transformations) pathList.push_back({transformation.second->getTransformationType(), 
2315                                                                      transformation.second->getId()}) ;
2316    }
2317    transformationPaths_.addPath(path) ;
2318
2319  }
2320  CATCH_DUMP_ATTR
2321 
2322/////////////////////////////////////////////////////////////////////////////////////////////
2323/////////////////////////////////////////////////////////////////////////////////////////////
2324
2325  void CDomain::setContextClient(CContextClient* contextClient)
2326  TRY
2327  {
2328    if (clientsSet.find(contextClient)==clientsSet.end())
2329    {
2330      clients.push_back(contextClient) ;
2331      clientsSet.insert(contextClient);
2332    }
2333  }
2334  CATCH_DUMP_ATTR
2335
2336  /*!
2337    Parse children nodes of a domain in xml file.
2338    Whenver there is a new transformation, its type and name should be added into this function
2339    \param node child node to process
2340  */
2341  void CDomain::parse(xml::CXMLNode & node)
2342  TRY
2343  {
2344    SuperClass::parse(node);
2345
2346    if (node.goToChildElement())
2347    {
2348      StdString nodeElementName;
2349      do
2350      {
2351        StdString nodeId("");
2352        if (node.getAttributes().end() != node.getAttributes().find("id"))
2353        { nodeId = node.getAttributes()["id"]; }
2354
2355        nodeElementName = node.getElementName();
2356        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
2357        it = transformationMapList_.find(nodeElementName);
2358        if (ite != it)
2359        {
2360          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CDomain>::createTransformation(it->second,
2361                                                                                                                nodeId,
2362                                                                                                                &node)));
2363        }
2364        else
2365        {
2366          ERROR("void CDomain::parse(xml::CXMLNode & node)",
2367                << "The transformation " << nodeElementName << " has not been supported yet.");
2368        }
2369      } while (node.goToNextElement()) ;
2370      node.goToParentElement();
2371    }
2372  }
2373  CATCH_DUMP_ATTR
2374   //----------------------------------------------------------------
2375
2376   DEFINE_REF_FUNC(Domain,domain)
2377
2378   ///---------------------------------------------------------------
2379
2380} // namespace xios
Note: See TracBrowser for help on using the repository browser.