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

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

New functionnality : domain, axis and scalar can now be retrieve with new syntax id :
ex. for domain :

id="domainId" : old syntax, working as before
id="fieldId::domainId" : get the domain related to "domainId" associated to the field "fieldId", work if only 1 domain related to domainId is associated to the field.
id="fieldId::domainId[n]" : get the nth domain related to "domainId" associated to the field "fieldId"
id="fieldId::" : get the domain associated the the field "fieldId, work if grid associated to th field is composed with exactly 1 domain (and possibly other components axis or scalars)
id="fieldId::[n] : get the nth domain composing the grid associated to the field

YM

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