source: XIOS/dev/branch_openmp/src/node/mesh.cpp @ 1552

Last change on this file since 1552 was 1545, checked in by yushan, 6 years ago

branch_openmp merged with trunk r1544

  • Property svn:executable set to *
File size: 75.9 KB
Line 
1/*!
2  \file mesh.cpp
3  \author Olga Abramkina
4  \brief Definition of class CMesh.
5*/
6
7#include "mesh.hpp"
8using namespace ep_lib;
9#include <boost/functional/hash.hpp>
10
11namespace xios {
12
13/// ////////////////////// Définitions ////////////////////// ///
14
15  CMesh::CMesh(void) :  nbNodesGlo(0), nbEdgesGlo(0)
16            ,  node_start(0), node_count(0)
17            ,  edge_start(0), edge_count(0)
18            ,  nbFaces_(0), nbNodes_(0), nbEdges_(0)
19            ,  nodesAreWritten(false), edgesAreWritten(false), facesAreWritten(false)
20            ,  node_lon(), node_lat()
21            ,  edge_lon(), edge_lat(), edge_nodes()
22            ,  face_lon(), face_lat()
23            ,  face_nodes()
24            ,  pNodeGlobalIndex(NULL), pEdgeGlobalIndex(NULL)
25  {
26  }
27
28
29  CMesh::~CMesh(void)
30  {
31    if (pNodeGlobalIndex != NULL) delete pNodeGlobalIndex;
32    if (pEdgeGlobalIndex != NULL) delete pEdgeGlobalIndex;
33  }
34
35  std::map <StdString, CMesh> *CMesh::meshList_ptr = 0;
36  std::map <StdString, vector<int> > *CMesh::domainList_ptr = 0;
37
38///---------------------------------------------------------------
39/*!
40 * \fn bool CMesh::getMesh (StdString meshName)
41 * Returns a pointer to a mesh. If a mesh has not been created, creates it and adds its name to the list of meshes meshList.
42 * \param [in] meshName  The name of a mesh ("name" attribute of a domain).
43 * \param [in] nvertex Number of verteces (1 for nodes, 2 for edges, 3 and up for faces).
44 */
45  CMesh* CMesh::getMesh (StdString meshName, int nvertex)
46  {
47    if(CMesh::domainList_ptr == NULL) CMesh::domainList_ptr = new std::map <StdString, vector<int> >();
48    if(CMesh::meshList_ptr == NULL)   CMesh::meshList_ptr   = new std::map <StdString, CMesh>();
49
50    CMesh::domainList_ptr->at(meshName).push_back(nvertex);
51
52    if ( CMesh::meshList_ptr->begin() != CMesh::meshList_ptr->end() )
53    {
54      for (std::map<StdString, CMesh>::iterator it=CMesh::meshList_ptr->begin(); it!=CMesh::meshList_ptr->end(); ++it)
55      {
56        if (it->first == meshName)
57          return &meshList_ptr->at(meshName);
58        else
59        {
60          CMesh newMesh;
61          CMesh::meshList_ptr->insert( make_pair(meshName, newMesh) );
62          return &meshList_ptr->at(meshName);
63        }
64      }
65    }
66    else
67    {
68      CMesh newMesh;
69      CMesh::meshList_ptr->insert( make_pair(meshName, newMesh) );
70      return &meshList_ptr->at(meshName);
71    }
72  }
73
74///----------------------------------------------------------------
75  size_t hashPair(size_t first, size_t second)
76  {
77    HashXIOS<size_t> sizetHash;
78    size_t seed = sizetHash(first) + 0x9e3779b9 ;
79    seed ^= sizetHash(second) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
80    return seed ;
81  }
82
83///----------------------------------------------------------------
84  size_t hashPairOrdered(size_t first, size_t second)
85  {
86    size_t seed;
87    HashXIOS<size_t> sizetHash;
88    if (first < second)
89    {
90      seed = sizetHash(first) + 0x9e3779b9 ;
91      seed ^= sizetHash(second) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
92    }
93    else
94    {
95      seed = sizetHash(second) + 0x9e3779b9 ;
96      seed ^= sizetHash(first) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
97    }
98    return seed ;
99  }
100
101///----------------------------------------------------------------
102/*!
103 * \fn size_t generateNodeIndex(vector<size_t>& valList, int rank)
104 * Generates a node index.
105 * If the same node is generated by two processes, each process will have its own node index.
106 * \param [in] valList Vector storing four node hashes.
107 * \param [in] rank MPI process rank.
108 */
109  size_t generateNodeIndex(vector<size_t>& valList, int rank)
110  {
111    // Sort is needed to avoid problems for nodes with lon = 0 generated by faces in east and west semisphere
112    vector<size_t> vec = valList;
113    sort (vec.begin(), vec.end());
114    size_t seed = rank ;
115    int it = 0;
116    for(; it != vec.size(); ++it)
117    {
118       seed = hashPair(seed, vec[it]);
119    }
120    return seed ;
121  }
122
123  ///----------------------------------------------------------------
124  /*!
125   * \fn size_t generateNodeIndex(vector<size_t>& valList)
126   * Generates a node index unique for all processes.
127   * \param [in] valList Vector storing four node hashes.
128   */
129    size_t generateNodeIndex(vector<size_t>& valList)
130    {
131      // Sort is needed to avoid problems for nodes with lon = 0 generated by faces in east and west semisphere
132      vector<size_t> vec = valList;
133      sort (vec.begin(), vec.end());
134      size_t seed = vec[0] ;
135      int it = 1;
136      for(; it != vec.size(); ++it)
137      {
138         seed = hashPair(seed, vec[it]);
139      }
140      return seed ;
141    }
142
143///----------------------------------------------------------------
144/*!
145 * \fn CArray<size_t,1>& CMesh::createHashes (const double longitude, const double latitude)
146 * Creates two hash values for each dimension, longitude and latitude.
147 * \param [in] longitude Node longitude in degrees.
148 * \param [in] latitude Node latitude in degrees ranged from 0 to 360.
149 */
150
151  vector<size_t> CMesh::createHashes (const double longitude, const double latitude)
152  {
153    double minBoundLon = 0. ;
154    double maxBoundLon = 360. ;
155    double minBoundLat = -90. ;
156    double maxBoundLat = 90. ;
157    double prec=1e-11 ;
158    double precLon=prec ;
159    double precLat=prec ;
160    double lon = longitude;
161    double lat = latitude;
162
163    if (lon > (360.- prec)) lon = 0.;
164
165    size_t maxsize_t=numeric_limits<size_t>::max() ;
166    if ( (maxBoundLon-minBoundLon)/maxsize_t > precLon) precLon=(maxBoundLon-minBoundLon)/maxsize_t ;
167    if ( (maxBoundLat-minBoundLat)/maxsize_t > precLat) precLat=(maxBoundLat-minBoundLat)/maxsize_t ;
168
169    size_t iMinLon=0 ;
170    size_t iMaxLon=(maxBoundLon-minBoundLon)/precLon ;
171    size_t iMinLat=0 ;
172    size_t iMaxLat=(maxBoundLat-minBoundLat)/precLat ;
173
174    vector<size_t> hash(4);
175    size_t lon0,lon1,lat0,lat1 ;
176
177    lon0=(lon-minBoundLon)/precLon ;
178    if ( ((lon0+1)*precLon + lon0*precLon)/2 > lon-minBoundLon)
179    {
180      if (lon0==iMinLon) lon1=iMaxLon ;
181      else lon1=lon0-1 ;
182    }
183    else
184    {
185      if (lon0==iMaxLon) lon1=iMinLon ;
186      else lon1=lon0+1 ;
187    }
188
189    lat0=(lat-minBoundLat)/precLat ;
190    if ( ((lat0+1)*precLat + lat0*precLat)/2 > lat-minBoundLat)
191    {
192      if (lat0==iMinLat) lat1=lat0 ;
193      else lat1=lat0-1 ;
194    }
195    else
196    {
197      if (lat0==iMaxLat) lat1=lat0 ;
198      else lat1=lat0+1 ;
199    }
200
201    hash[0] = hashPair(lon0,lat0) ;
202    hash[1] = hashPair(lon0,lat1) ;
203    hash[2] = hashPair(lon1,lat0) ;
204    hash[3] = hashPair(lon1,lat1) ;
205
206    return hash;
207
208  } // createHashes
209
210///----------------------------------------------------------------
211  std::pair<int,int> make_ordered_pair(int a, int b)
212  {
213    if ( a < b )
214      return std::pair<int,int>(a,b);
215    else
216      return std::pair<int,int>(b,a);
217  }
218
219///----------------------------------------------------------------
220/*!
221 * \fn void CMesh::createMesh(const CArray<double, 1>& lonvalue, const CArray<double, 1>& latvalue,
222            const CArray<double, 2>& bounds_lon, const CArray<double, 2>& bounds_lat)
223 * Creates or updates a mesh for the three types of mesh elements: nodes, edges, and faces.
224 * \param [in] lonvalue  Array of longitudes.
225 * \param [in] latvalue  Array of latitudes.
226 * \param [in] bounds_lon Array of boundary longitudes. Its size depends on the element type.
227 * \param [in] bounds_lat Array of boundary latitudes. Its size depends on the element type.
228 */
229
230///----------------------------------------------------------------
231/*!
232 * \fn void CMesh::createMeshEpsilon(const CArray<double, 1>& lonvalue, const CArray<double, 1>& latvalue,
233            const CArray<double, 2>& bounds_lon, const CArray<double, 2>& bounds_lat)
234 * Creates or updates a mesh for the three types of mesh elements: nodes, edges, and faces.
235 * Precision check is implemented with two hash values for each dimension, longitude and latitude.
236 * \param [in] comm
237 * \param [in] lonvalue  Array of longitudes.
238 * \param [in] latvalue  Array of latitudes.
239 * \param [in] bounds_lon Array of boundary longitudes. Its size depends on the element type.
240 * \param [in] bounds_lat Array of boundary latitudes. Its size depends on the element type.
241 */
242  void CMesh::createMeshEpsilon(const MPI_Comm& comm,
243                                const CArray<double, 1>& lonvalue, const CArray<double, 1>& latvalue,
244                                const CArray<double, 2>& bounds_lon, const CArray<double, 2>& bounds_lat)
245  {
246
247    int nvertex = (bounds_lon.numElements() == 0) ? 1 : bounds_lon.rows();
248    int mpiRank, mpiSize;
249    MPI_Comm_rank(comm, &mpiRank);
250    MPI_Comm_size(comm, &mpiSize);
251    double prec = 1e-11;  // used in calculations of edge_lon/lat
252
253    if (nvertex == 1)
254    {
255      nbNodes_ = lonvalue.numElements();
256      node_lon.resize(nbNodes_);
257      node_lat.resize(nbNodes_);
258      node_lon = lonvalue;
259      node_lat = latvalue;
260
261      // Global node indexes
262      vector<size_t> hashValues(4);
263      CClientClientDHTSizet::Index2VectorInfoTypeMap nodeHash2IdxGlo;
264      for (size_t nn = 0; nn < nbNodes_; ++nn)
265      {
266        hashValues = CMesh::createHashes(lonvalue(nn), latvalue(nn));
267        for (size_t nh = 0; nh < 4; ++nh)
268        {
269          nodeHash2IdxGlo[hashValues[nh]].push_back(mpiRank*nbNodes_ + nn);
270        }
271      }
272      pNodeGlobalIndex = new CClientClientDHTSizet (nodeHash2IdxGlo, comm);
273      nodesAreWritten = true;
274    }
275
276    else if (nvertex == 2)
277    {
278      nbEdges_ = bounds_lon.shape()[1];
279      edge_lon.resize(nbEdges_);
280      edge_lat.resize(nbEdges_);
281      edge_lon = lonvalue;
282      edge_lat = latvalue;
283      edge_nodes.resize(nvertex, nbEdges_);
284
285      // For determining the global edge index
286      unsigned long nbEdgesOnProc = nbEdges_;
287      unsigned long nbEdgesAccum;
288      MPI_Scan(&nbEdgesOnProc, &nbEdgesAccum, 1, MPI_UNSIGNED_LONG, MPI_SUM, comm);
289      nbEdgesAccum -= nbEdges_;
290
291      CClientClientDHTSizet::Index2VectorInfoTypeMap edgeHash2IdxGlo;
292      CClientClientDHTSizet::Index2VectorInfoTypeMap edgeHash2Idx;
293
294      // Case (1): node indexes have been generated by domain "nodes"
295      if (nodesAreWritten)
296      {
297        vector<size_t> hashValues(4);
298        CArray<size_t,1> nodeHashList(nbEdges_*nvertex*4);
299        for (int ne = 0; ne < nbEdges_; ++ne)      // size_t doesn't work with CArray<double, 2>
300        {
301          for (int nv = 0; nv < nvertex; ++nv)
302          {
303            hashValues = CMesh::createHashes(bounds_lon(nv, ne), bounds_lat(nv, ne));
304            for (int nh = 0; nh < 4; ++nh)
305            {
306              nodeHashList((ne*nvertex + nv)*4 + nh) = hashValues[nh];
307            }
308          }
309        }
310
311        // Recuperating the node global indexing and writing edge_nodes
312        // Creating map edgeHash2IdxGlo <hash, idxGlo>
313        pNodeGlobalIndex->computeIndexInfoMapping(nodeHashList);
314        CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeHash2IdxGlo = pNodeGlobalIndex->getInfoIndexMap();
315        CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it;
316        size_t nodeIdxGlo1, nodeIdxGlo2;
317        for (int ne = 0; ne < nbEdges_; ++ne)
318        {
319          for (int nv = 0; nv < nvertex; ++nv)
320          {
321            int nh = 0;
322            it = nodeHash2IdxGlo.find(nodeHashList((ne*nvertex + nv)*4 + nh));
323            // The loop below is needed in case if a hash generated by domain "edges" differs
324            // from that generated by domain "nodes" because of possible precision issues
325            while (it == nodeHash2IdxGlo.end())
326            {
327              ++nh;
328              it = nodeHash2IdxGlo.find(nodeHashList((ne*nvertex + nv)*4 + nh));
329            }
330            edge_nodes(nv,ne) = it->second[0];
331            if (nv ==0)
332              nodeIdxGlo1 = it->second[0];
333            else
334              nodeIdxGlo2 = it->second[0];
335          }
336          size_t edgeIdxGlo = nbEdgesAccum + ne;
337          edgeHash2IdxGlo[ hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2) ].push_back(edgeIdxGlo);
338        }
339      } // nodesAreWritten
340
341
342      // Case (2): node indexes have not been generated previously
343      else
344      {
345        // (2.1) Creating a list of hashes for each node and a map nodeHash2Idx <hash, <idx,rank> >
346        vector<size_t> hashValues(4);
347        CClientClientDHTSizet::Index2VectorInfoTypeMap nodeHash2Idx;
348        CArray<size_t,1> nodeHashList(nbEdges_*nvertex*4);
349        int nbHash = 0;
350        for (int ne = 0; ne < nbEdges_; ++ne)
351        {
352          for (int nv = 0; nv < nvertex; ++nv)
353          {
354            hashValues = CMesh::createHashes(bounds_lon(nv, ne), bounds_lat(nv, ne));
355            for (int nh = 0; nh < 4; ++nh)
356            {
357              if (nodeHash2Idx[hashValues[nh]].size() == 0)
358              {
359                nodeHash2Idx[hashValues[nh]].push_back(generateNodeIndex(hashValues));
360                nodeHash2Idx[hashValues[nh]].push_back(mpiRank);
361                nodeHashList(nbHash) = hashValues[nh];
362                ++nbHash;
363              }
364            }
365          }
366        }
367        nodeHashList.resizeAndPreserve(nbHash);
368
369        // (2.2) Generating global node indexes
370        // The ownership criterion: priority of the process of smaller index
371        // Maps generated in this step are:
372        // Maps generated in this step are:
373         // nodeHash2Info = <hash, [[idx, rankMin], [idx, rank1], [idx, rank3]..]>
374         // nodeIdx2Idx = <idx, <rankOwner, idx>>
375
376         CClientClientDHTSizet dhtNodeHash(nodeHash2Idx, comm);
377         dhtNodeHash.computeIndexInfoMapping(nodeHashList);
378         CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeHash2Info = dhtNodeHash.getInfoIndexMap();
379
380
381         CClientClientDHTSizet::Index2VectorInfoTypeMap nodeIdx2Idx;
382         CArray<size_t,1> nodeIdxList(nbEdges_*nvertex*4);
383         size_t nIdx = 0;
384
385         for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = nodeHash2Info.begin(); it != nodeHash2Info.end(); ++it)
386         {
387           size_t rankMin = (it->second)[1];
388           size_t idx = (it->second)[0];
389           for (int i = 2; i < (it->second).size();)
390           {
391             if ( (it->second)[i+1] < rankMin)
392             {
393               idx = (it->second)[i];
394               rankMin = (it->second)[i+1];
395               (it->second)[i+1] = (it->second)[i-1];
396             }
397             i += 2;
398           }
399           if (nodeIdx2Idx.count(idx) == 0)
400           {
401             if (mpiRank == rankMin)
402             {
403               nodeIdx2Idx[idx].push_back(rankMin);
404               nodeIdx2Idx[idx].push_back(idx);
405             }
406             nodeIdxList(nIdx) = idx;
407             ++nIdx;
408           }
409         }
410         nodeIdxList.resizeAndPreserve(nIdx);
411
412         // CDHTAutoIndexing will not give consistent node numbering for varying number of procs. =>
413         // Solution: global node indexing by hand.
414         // Maps modified in this step:
415         // nodeIdx2Idx = <idx, idxGlo>
416         unsigned long nodeCount = nodeIdx2Idx.size();
417         unsigned long nodeStart, nbNodes;
418         MPI_Scan(&nodeCount, &nodeStart, 1, MPI_UNSIGNED_LONG, MPI_SUM, comm);
419         int nNodes = nodeStart;
420         MPI_Bcast(&nNodes, 1, MPI_UNSIGNED_LONG, mpiSize-1, comm);
421         nbNodesGlo = nNodes;
422
423         nodeStart -= nodeCount;
424         node_start = nodeStart;
425         node_count = nodeCount;
426         CClientClientDHTSizet::Index2VectorInfoTypeMap dummyMap; // just a dummy map used to ensure that each node is numbered only once
427         size_t count = 0;
428
429         for (int ne = 0; ne < nbEdges_; ++ne)
430         {
431           for (int nv = 0; nv < nvertex; ++nv)
432           {
433             vector<size_t> hashValues = CMesh::createHashes(bounds_lon(nv, ne), bounds_lat(nv, ne));
434             size_t nodeIdx = generateNodeIndex(hashValues);
435             CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = nodeIdx2Idx.find(nodeIdx);
436             if (it != nodeIdx2Idx.end())
437             {
438               if (dummyMap.count(nodeIdx) == 0)
439               {
440                 dummyMap[nodeIdx].push_back(nodeIdx);
441                 (it->second)[1] = node_start + count;
442                 ++count;
443               }
444             }
445           }
446         }
447
448         CClientClientDHTSizet dhtNodeIdx(nodeIdx2Idx, comm);
449         dhtNodeIdx.computeIndexInfoMapping(nodeIdxList);
450         CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeIdx2IdxGlo = dhtNodeIdx.getInfoIndexMap();
451
452        // (2.3) Saving variables: node_lon, node_lat, edge_nodes
453        // Creating map nodeHash2IdxGlo <hash, idxGlo>
454        // Creating map edgeHash2IdxGlo <hash, idxGlo>
455//        nbNodesGlo = dhtNodeIdxGlo.getNbIndexesGlobal();
456//        node_count = dhtNodeIdxGlo.getIndexCount();
457//        node_start = dhtNodeIdxGlo.getIndexStart();
458        CClientClientDHTSizet::Index2VectorInfoTypeMap nodeHash2IdxGlo;
459        node_lon.resize(node_count);
460        node_lat.resize(node_count);
461        vector <size_t> edgeNodes;
462        size_t idxGlo = 0;
463
464        for (int ne = 0; ne < nbEdges_; ++ne)
465        {
466          for (int nv = 0; nv < nvertex; ++nv)
467          {
468            hashValues = CMesh::createHashes(bounds_lon(nv, ne), bounds_lat(nv, ne));
469            size_t myIdx = generateNodeIndex(hashValues);
470            CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itIdx = nodeIdx2IdxGlo.find(myIdx);
471            idxGlo = (itIdx->second)[1];
472
473            if (mpiRank == (itIdx->second)[0])
474            {
475//              node_lon(idxGlo - node_start) = (bounds_lon(nv, ne) == 360.) ? (0.) : (bounds_lon(nv, ne));
476              node_lon(idxGlo - node_start) = bounds_lon(nv, ne);
477              node_lat(idxGlo - node_start) = bounds_lat(nv, ne);
478            }
479            edge_nodes(nv,ne) = idxGlo;
480            for (int nh = 0; nh < 4; ++nh)
481              nodeHash2IdxGlo[hashValues[nh]].push_back(idxGlo);
482            edgeNodes.push_back(idxGlo);
483          }
484          if (edgeNodes[0] != edgeNodes[1])
485          {
486            size_t edgeIdxGlo = nbEdgesAccum + ne;
487            edgeHash2IdxGlo[ hashPairOrdered(edgeNodes[0], edgeNodes[1]) ].push_back(edgeIdxGlo);
488          }
489          edgeNodes.clear();
490        }
491        pNodeGlobalIndex = new CClientClientDHTSizet (nodeHash2IdxGlo, comm);
492      } // !nodesAreWritten
493
494      pEdgeGlobalIndex = new CClientClientDHTSizet (edgeHash2IdxGlo, comm);
495      edgesAreWritten = true;
496    } //nvertex = 2
497
498    else
499    {
500      nbFaces_ = bounds_lon.shape()[1];
501      face_lon.resize(nbFaces_);
502      face_lat.resize(nbFaces_);
503      face_lon = lonvalue;
504      face_lat = latvalue;
505      face_nodes.resize(nvertex, nbFaces_);
506      face_edges.resize(nvertex, nbFaces_);
507
508      // For determining the global face index
509      unsigned long nbFacesOnProc = nbFaces_;
510      unsigned long nbFacesAccum;
511      MPI_Scan(&nbFacesOnProc, &nbFacesAccum, 1, MPI_UNSIGNED_LONG, MPI_SUM, comm);
512      nbFacesAccum -= nbFaces_;
513
514      // Case (1): edges have been previously generated
515      if (edgesAreWritten)
516      {
517        // (1.1) Recuperating node global indexing and saving face_nodes
518        vector<size_t> hashValues(4);
519        CArray<size_t,1> nodeHashList(nbFaces_*nvertex*4);
520        for (int nf = 0; nf < nbFaces_; ++nf)
521        {
522          for (int nv = 0; nv < nvertex; ++nv)
523            {
524              hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf));
525              for (int nh = 0; nh < 4; ++nh)
526                nodeHashList((nf*nvertex + nv)*4 + nh) = hashValues[nh];
527            }
528        }
529        pNodeGlobalIndex->computeIndexInfoMapping(nodeHashList);
530        CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeHash2IdxGlo = pNodeGlobalIndex->getInfoIndexMap();
531        CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it1, it2;
532        CArray<size_t,1> edgeHashList(nbFaces_*nvertex);
533        size_t nEdge = 0;
534        for (int nf = 0; nf < nbFaces_; ++nf)
535        {
536          for (int nv1 = 0; nv1 < nvertex; ++nv1)
537          {
538            int nh1 = 0;
539            int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation
540            it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1));
541            while (it1 == nodeHash2IdxGlo.end())
542            {
543              ++nh1;
544              it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1));
545            }
546            int nh2 = 0;
547            it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv2)*4 + nh2));
548            while (it2 == nodeHash2IdxGlo.end())
549            {
550              ++nh2;
551              it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh2));
552            }
553            face_nodes(nv1,nf) = it1->second[0];
554            if (it1->second[0] != it2->second[0])
555            {
556              edgeHashList(nEdge) = hashPairOrdered(it1->second[0], it2->second[0]);
557              ++nEdge;
558            }
559          }
560        }
561        edgeHashList.resizeAndPreserve(nEdge);
562
563        // (1.2) Recuperating edge global indexing and saving face_edges
564        pEdgeGlobalIndex->computeIndexInfoMapping(edgeHashList);
565        CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeHash2IdxGlo = pEdgeGlobalIndex->getInfoIndexMap();
566        CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itEdgeHash;
567        CClientClientDHTSizet::Index2VectorInfoTypeMap edgeHash2Rank;
568        CClientClientDHTSizet::Index2VectorInfoTypeMap edgeIdxGlo2Face;
569        CArray<size_t,1> edgeIdxList(nbFaces_*nvertex);
570        size_t iIdx = 0;
571
572        for (int nf = 0; nf < nbFaces_; ++nf)
573        {
574          for (int nv1 = 0; nv1 < nvertex; ++nv1)
575          {
576            int nh1 = 0;
577            int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation
578            it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1));
579            while (it1 == nodeHash2IdxGlo.end())
580            {
581              ++nh1;
582              it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1));
583            }
584            int nh2 = 0;
585            it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv2)*4 + nh2));
586            while (it2 == nodeHash2IdxGlo.end())
587            {
588              ++nh2;
589              it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh2));
590            }
591            if (it1->second[0] != it2->second[0])
592            {
593              size_t faceIdxGlo = nbFacesAccum + nf;
594              size_t edgeHash = hashPairOrdered(it1->second[0], it2->second[0]);
595              itEdgeHash = edgeHash2IdxGlo.find(edgeHash);
596              size_t edgeIdxGlo = itEdgeHash->second[0];
597              face_edges(nv1,nf) = edgeIdxGlo;
598              if (edgeIdxGlo2Face.count(edgeIdxGlo) == 0)
599              {
600                edgeIdxList(iIdx) = edgeIdxGlo;
601                ++iIdx;
602              }
603              edgeIdxGlo2Face[edgeIdxGlo].push_back(faceIdxGlo);
604              edgeHash2Rank[edgeHash].push_back(mpiRank);
605              edgeHash2Rank[edgeHash].push_back(itEdgeHash->second[0]);
606            }
607            else
608            {
609              face_edges(nv1,nf) = 999999;
610            }
611          }
612        }
613        edgeIdxList.resizeAndPreserve(iIdx);
614
615        // (1.3) Saving remaining variables edge_faces and face_faces
616
617        // Establishing edge ownership
618        // The ownership criterion: priority of the process with smaller rank
619        CClientClientDHTSizet dhtEdgeHash (edgeHash2Rank, comm);
620        dhtEdgeHash.computeIndexInfoMapping(edgeHashList);
621        CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeHash2Info = dhtEdgeHash.getInfoIndexMap();
622
623        // edgeHash2Info = <edgeHash, < rank1, idxGlo, rank2, idxGlo>>
624        int edgeCount = 0;
625        for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = edgeHash2Info.begin(); it != edgeHash2Info.end(); ++it)
626        {
627          vector <size_t> edgeInfo = it->second;
628          if (edgeInfo[0] == mpiRank)
629          {
630            ++edgeCount;
631          }
632        }
633
634        unsigned long edgeStart, nbEdges;
635        MPI_Scan(&edgeCount, &edgeStart, 1, MPI_UNSIGNED_LONG, MPI_SUM, comm);
636        int nEdges = edgeStart;
637        MPI_Bcast(&nEdges, 1, MPI_UNSIGNED_LONG, mpiSize-1, comm);
638        nbEdgesGlo = nEdges;
639
640        // edges to be splitted equally between procs
641        if ( (nbEdgesGlo % mpiSize) == 0)
642        {
643          edge_count = nbEdgesGlo/mpiSize;
644          edge_start = mpiRank*edge_count;
645        }
646        else
647        {
648          if (mpiRank == (mpiSize - 1) )
649          {
650            edge_count = nbEdgesGlo/mpiSize;
651            edge_start = mpiRank*(nbEdgesGlo/mpiSize + 1);
652          }
653          else
654          {
655            edge_count = nbEdgesGlo/mpiSize + 1;
656            edge_start = mpiRank*edge_count;
657          }
658        }
659        CArray<size_t,1> edgeIdxGloList(edge_count);
660        for (int i = 0; i < edge_count; ++i)
661        {
662          edgeIdxGloList(i) = i + edge_start;
663        }
664
665        CClientClientDHTSizet dhtEdgeIdxGlo2Face (edgeIdxGlo2Face, comm);
666        CClientClientDHTSizet dhtEdge2Face (edgeIdxGlo2Face, comm);
667        dhtEdgeIdxGlo2Face.computeIndexInfoMapping(edgeIdxGloList);
668        CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeIdxGlo2FaceIdx = dhtEdgeIdxGlo2Face.getInfoIndexMap();
669        dhtEdge2Face.computeIndexInfoMapping(edgeIdxList);
670        CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeIdx2FaceIdx = dhtEdge2Face.getInfoIndexMap();
671
672
673        edge_faces.resize(2, edge_count);
674        for (int i = 0; i < edge_count; ++i)
675        {
676          CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = edgeIdxGlo2FaceIdx.find(i + edge_start);
677          int indexGlo = it->first;
678          vector<size_t> faces = it->second;
679          int face1 = faces[0];
680          edge_faces(0, indexGlo - edge_start) = face1;
681          if (faces.size() == 2)
682          {
683            int face2 = faces[1];
684            edge_faces(1, indexGlo - edge_start) = face2;
685          }
686          else
687          {
688            edge_faces(1, indexGlo - edge_start) = -999;
689          }
690        }
691
692        size_t tmp;
693        vector<size_t> tmpVec;
694        for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = edgeIdx2FaceIdx.begin(); it != edgeIdx2FaceIdx.end(); it++)
695        {
696          tmp = it->first;
697          tmpVec = it->second;
698          tmp++;
699        }
700
701        CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itFace1, itFace2, itIndex;
702        face_faces.resize(nvertex, nbFaces_);
703        for (int nf = 0; nf < nbFaces_; ++nf)
704        {
705          for (int nv1 = 0; nv1 < nvertex; ++nv1)
706          {
707            int nh1 = 0;
708            int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation
709            it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1));
710            while (it1 == nodeHash2IdxGlo.end())
711            {
712              ++nh1;
713              it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1));
714            }
715            int nh2 = 0;
716            it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv2)*4 + nh2));
717            while (it2 == nodeHash2IdxGlo.end())
718            {
719              ++nh2;
720              it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh2));
721            }
722
723            if (it1->second[0] != it2->second[0])
724            {
725              size_t faceIdxGlo = nbFacesAccum + nf;
726              size_t edgeHash = hashPairOrdered(it1->second[0], it2->second[0]);
727              itEdgeHash = edgeHash2Info.find(edgeHash);
728              int edgeIdxGlo = (itEdgeHash->second)[1];
729
730              if ( (itEdgeHash->second)[0] == mpiRank)
731              {
732                itFace1 = edgeIdx2FaceIdx.find(edgeIdxGlo);
733                int face1 = itFace1->second[0];
734                if (itFace1->second.size() == 1)
735                {
736                  face_faces(nv1, nf) = 999999;
737                }
738                else
739                {
740                  int face2 = itFace1->second[1];
741                  face_faces(nv1, nf) = (faceIdxGlo == face1 ? face2 : face1);
742                }
743              } // edge owner
744              else
745              {
746                itFace1 = edgeIdx2FaceIdx.find(edgeIdxGlo);
747                int face1 = itFace1->second[0];
748                int face2 = itFace1->second[1];
749                face_faces(nv1, nf) = (faceIdxGlo == face1 ? face2 : face1);
750              } // not an edge owner
751            } // node1 != node2
752            else
753            {
754              face_faces(nv1, nf) = 999999;
755            }
756          }
757        }
758      } // edgesAreWritten
759
760      // Case (2): nodes have been previously generated
761      else if (nodesAreWritten)
762      {
763        // (2.1) Generating nodeHashList
764        vector<size_t> hashValues(4);
765        CArray<size_t,1> nodeHashList(nbFaces_*nvertex*4);
766        for (int nf = 0; nf < nbFaces_; ++nf)
767        {
768          for (int nv = 0; nv < nvertex; ++nv)
769            {
770              hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf));
771              for (int nh = 0; nh < 4; ++nh)
772                nodeHashList((nf*nvertex + nv)*4 + nh) = hashValues[nh];
773            }
774        }
775
776        // (2.2) Recuperating node global indexing and saving face_nodes
777        // Generating edgeHash2Info = <hash, <idx, rank>> and edgeHashList
778        pNodeGlobalIndex->computeIndexInfoMapping(nodeHashList);
779        CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeHash2IdxGlo = pNodeGlobalIndex->getInfoIndexMap();
780        CClientClientDHTSizet::Index2VectorInfoTypeMap edgeHash2Idx;
781        CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it1, it2;
782        CArray<size_t,1> edgeHashList(nbFaces_*nvertex);
783        int nEdgeHash = 0;
784        for (int nf = 0; nf < nbFaces_; ++nf)
785        {
786          for (int nv1 = 0; nv1 < nvertex; ++nv1)
787          {
788            int nh1 = 0;
789            int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation
790            it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1));
791            while (it1 == nodeHash2IdxGlo.end())
792            {
793              ++nh1;
794              it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1));
795            }
796            int nh2 = 0;
797            it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv2)*4 + nh2));
798            while (it2 == nodeHash2IdxGlo.end())
799            {
800              ++nh2;
801              it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh2));
802            }
803            face_nodes(nv1,nf) = it1->second[0];
804            size_t edgeHash = hashPairOrdered(it1->second[0], it2->second[0]);
805            if (edgeHash2Idx.count(edgeHash) == 0)
806            {
807              edgeHash2Idx[edgeHash].push_back(edgeHash);
808              edgeHash2Idx[edgeHash].push_back(mpiRank);
809              edgeHashList(nEdgeHash) = edgeHash;
810              ++nEdgeHash;
811            }
812          }
813        }
814        edgeHashList.resizeAndPreserve(nEdgeHash);
815
816        // (2.3) Generating global edge indexes
817        // The ownership criterion: priority of the process with smaller rank
818        // Maps generated in this step are:
819        // edgeIdx2Idx = = <idx, <rankOwner, idx>>
820        // edgeIdx2IdxGlo = <idxMin, <rankOwner, idxGlo>>
821
822        CClientClientDHTSizet dhtEdgeHash(edgeHash2Idx, comm);
823        dhtEdgeHash.computeIndexInfoMapping(edgeHashList);
824        CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeHash2Info = dhtEdgeHash.getInfoIndexMap();
825        // edgeHash2Info = <hash, [[idx1, rank1], [idx2, rank2], [idx3, rank3]..]>
826
827        CClientClientDHTSizet::Index2VectorInfoTypeMap edgeIdx2Idx;
828
829        for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = edgeHash2Info.begin(); it != edgeHash2Info.end(); ++it)
830        {
831          size_t rankMin = (it->second)[1];
832          size_t idx = (it->second)[0];
833
834          for (int i = 2; i < (it->second).size();)
835          {
836            if ((it->second)[i+1] < rankMin)
837            {
838              rankMin = (it->second)[i+1];
839              idx = (it->second)[i];
840              (it->second)[i+1] = (it->second)[i-1];
841            }
842            i += 2;
843          }
844          if (edgeIdx2Idx.count(idx) == 0)
845          {
846            if (mpiRank == rankMin)
847            {
848              edgeIdx2Idx[idx].push_back(rankMin);
849              edgeIdx2Idx[idx].push_back(idx);
850            }
851          }
852        }
853
854        unsigned long edgeCount = edgeIdx2Idx.size();
855        unsigned long edgeStart, nbEdges;
856        MPI_Scan(&edgeCount, &edgeStart, 1, MPI_UNSIGNED_LONG, MPI_SUM, comm);
857        int nEdges = edgeStart;
858        MPI_Bcast(&nEdges, 1, MPI_UNSIGNED_LONG, mpiSize-1, comm);
859        nbEdgesGlo = nEdges;
860
861        edgeStart -= edgeCount;
862        edge_start = edgeStart;
863        edge_count = edgeCount;
864        CClientClientDHTSizet::Index2VectorInfoTypeMap dummyEdgeMap;
865        int count = 0;
866
867        for (int nf = 0; nf < nbFaces_; ++nf)
868        {
869          for (int nv1 = 0; nv1 < nvertex; ++nv1)
870          {
871            // Getting global indexes of edge's nodes
872            int nh1 = 0;
873            int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation
874            it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1));
875            while (it1 == nodeHash2IdxGlo.end())
876            {
877              ++nh1;
878              it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1));
879            }
880            int nh2 = 0;
881            it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv2)*4 + nh2));
882            while (it2 == nodeHash2IdxGlo.end())
883            {
884              ++nh2;
885              it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh2));
886            }
887            size_t nodeIdxGlo1 = it1->second[0];
888            size_t nodeIdxGlo2 = it2->second[0];
889
890            if (nodeIdxGlo1 != nodeIdxGlo2)
891            {
892              size_t edgeIdx = hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2);
893              CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = edgeIdx2Idx.find(edgeIdx);
894              if (it != edgeIdx2Idx.end())
895              {
896                if (dummyEdgeMap.count(edgeIdx) == 0)
897                {
898                  dummyEdgeMap[edgeIdx].push_back(edgeIdx);
899                  (it->second)[1] = edge_start + count;
900                  ++count;
901                }
902              }
903            }
904          }
905        }
906
907        CClientClientDHTSizet dhtEdgeIdx(edgeIdx2Idx, comm);
908        dhtEdgeIdx.computeIndexInfoMapping(edgeHashList);
909        CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeIdx2IdxGlo = dhtEdgeIdx.getInfoIndexMap();
910
911        // (2.4) Saving variables: edge_lon, edge_lat, face_edges
912        edge_lon.resize(edge_count);
913        edge_lat.resize(edge_count);
914        edge_nodes.resize(2, edge_count);
915        face_edges.resize(nvertex, nbFaces_);
916
917        CClientClientDHTSizet::Index2VectorInfoTypeMap edgeIdxGlo2Face;
918        CArray<size_t,1> edgeIdxGloList(nbFaces_*nvertex);
919        size_t iIdx = 0;
920
921        for (int nf = 0; nf < nbFaces_; ++nf)
922        {
923          for (int nv1 = 0; nv1 < nvertex; ++nv1)
924          {
925            // Getting global indexes of edge's nodes
926            int nh1 = 0;
927            int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation
928            it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1));
929            while (it1 == nodeHash2IdxGlo.end())
930            {
931              ++nh1;
932              it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1));
933            }
934            int nh2 = 0;
935            it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv2)*4 + nh2));
936            while (it2 == nodeHash2IdxGlo.end())
937            {
938              ++nh2;
939              it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh2));
940            }
941            // Getting edge global index
942            size_t nodeIdxGlo1 = it1->second[0];
943            size_t nodeIdxGlo2 = it2->second[0];
944            size_t myIdx = hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2);
945            if (nodeIdxGlo1 != nodeIdxGlo2)
946            {
947              CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itIdx = edgeIdx2IdxGlo.find(myIdx);
948              int edgeIdxGlo = (itIdx->second)[1];
949              size_t faceIdxGlo = nbFacesAccum + nf;
950
951              if (mpiRank == (itIdx->second)[0])
952              {
953                double edgeLon;
954                double diffLon = abs(bounds_lon(nv1, nf) - bounds_lon(nv2, nf));
955                if (diffLon < (180.- prec))
956                  edgeLon = ( bounds_lon(nv1, nf) + bounds_lon(nv2, nf)) * 0.5;
957                else if (diffLon > (180.+ prec))
958                  edgeLon = (bounds_lon(nv1, nf) + bounds_lon(nv2, nf)) * 0.5 -180.;
959                else
960                  edgeLon = 0.;
961                edge_lon(edgeIdxGlo - edge_start) = edgeLon;
962                edge_lat(edgeIdxGlo - edge_start) = ( bounds_lat(nv1, nf) + bounds_lat(nv2, nf) ) * 0.5;
963                edge_nodes(0, edgeIdxGlo - edge_start) = nodeIdxGlo1;
964                edge_nodes(1, edgeIdxGlo - edge_start) = nodeIdxGlo2;
965              }
966              face_edges(nv1,nf) = edgeIdxGlo;
967              if (edgeIdxGlo2Face.count(edgeIdxGlo) == 0)
968              {
969                edgeIdxGloList(iIdx) = edgeIdxGlo;
970                ++iIdx;
971              }
972              edgeIdxGlo2Face[edgeIdxGlo].push_back(faceIdxGlo);
973            } // nodeIdxGlo1 != nodeIdxGlo2
974            else
975            {
976              face_edges(nv1,nf) = 999999;
977            }
978          }
979        }
980        edgeIdxGloList.resizeAndPreserve(iIdx);
981
982        // (2.5) Saving remaining variables edge_faces and face_faces
983        edge_faces.resize(2, edge_count);
984        face_faces.resize(nvertex, nbFaces_);
985
986        CClientClientDHTSizet dhtEdge2Face (edgeIdxGlo2Face, comm);
987        dhtEdge2Face.computeIndexInfoMapping(edgeIdxGloList);
988        CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeIdxGlo2FaceIdx = dhtEdge2Face.getInfoIndexMap();
989        CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNodeIdxGlo1, itNodeIdxGlo2;
990        CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itIdx;
991
992        for (int nf = 0; nf < nbFaces_; ++nf)
993        {
994          for (int nv1 = 0; nv1 < nvertex; ++nv1)
995          {
996            // Getting global indexes of edge's nodes
997            int nh1 = 0;
998            int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation
999            it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1));
1000            while (it1 == nodeHash2IdxGlo.end())
1001            {
1002              ++nh1;
1003              it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1));
1004            }
1005            int nh2 = 0;
1006            it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv2)*4 + nh2));
1007            while (it2 == nodeHash2IdxGlo.end())
1008            {
1009              ++nh2;
1010              it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh2));
1011            }
1012            size_t nodeIdxGlo1 = it1->second[0];
1013            size_t nodeIdxGlo2 = it2->second[0];
1014
1015            size_t myIdx = hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2);
1016            itIdx = edgeIdx2IdxGlo.find(myIdx);
1017            size_t faceIdxGlo = nbFacesAccum + nf;
1018            int edgeIdxGlo = (itIdx->second)[1];
1019
1020            if (mpiRank == (itIdx->second)[0])
1021            {
1022              it1 = edgeIdxGlo2FaceIdx.find(edgeIdxGlo);
1023              int face1 = it1->second[0];
1024              if (it1->second.size() == 1)
1025              {
1026                edge_faces(0, edgeIdxGlo - edge_start) = face1;
1027                edge_faces(1, edgeIdxGlo - edge_start) = -999;
1028                face_faces(nv1, nf) = 999999;
1029              }
1030              else
1031              {
1032                int face2 = it1->second[1];
1033                edge_faces(0, edgeIdxGlo - edge_start) = face1;
1034                edge_faces(1, edgeIdxGlo - edge_start) = face2;
1035                face_faces(nv1, nf) = (faceIdxGlo == face1 ? face2 : face1);
1036              }
1037            }
1038            else
1039            {
1040              it1 = edgeIdxGlo2FaceIdx.find(edgeIdxGlo);
1041              int face1 = it1->second[0];
1042              int face2 = it1->second[1];
1043              face_faces(nv1, nf) = (faceIdxGlo == face1 ? face2 : face1);
1044            }
1045          }
1046        }
1047      } // nodesAreWritten
1048
1049      // Case (3): Neither nodes nor edges have been previously generated
1050      else
1051      {
1052        // (3.1) Creating a list of hashes for each node and a map nodeHash2Idx <hash, <idx,rank> >
1053        vector<size_t> hashValues(4);
1054        CClientClientDHTSizet::Index2VectorInfoTypeMap nodeHash2Idx;
1055        CArray<size_t,1> nodeHashList(nbFaces_*nvertex*4);
1056        size_t iHash = 0;
1057        for (int nf = 0; nf < nbFaces_; ++nf)
1058        {
1059          for (int nv = 0; nv < nvertex; ++nv)
1060          {
1061            hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf));
1062//            size_t nodeIndex = generateNodeIndex(hashValues, mpiRank);
1063            size_t nodeIndex = generateNodeIndex(hashValues);
1064            for (int nh = 0; nh < 4; ++nh)
1065            {
1066              if (nodeHash2Idx.count(hashValues[nh])==0)
1067              {
1068                nodeHash2Idx[hashValues[nh]].push_back(nodeIndex);
1069                nodeHash2Idx[hashValues[nh]].push_back(mpiRank);
1070                nodeHashList(iHash) = hashValues[nh];
1071                ++iHash;
1072              }
1073            }
1074          }
1075        }
1076        nodeHashList.resizeAndPreserve(iHash);
1077
1078        // (3.2) Generating global node indexes
1079        // The ownership criterion: priority of the process with smaller rank.
1080        // With any other criterion it is not possible to have consistent node indexing for different number of procs.
1081        // Maps generated in this step are:
1082        // nodeHash2Info = <hash, [[idx, rankMin], [idx, rank1], [idx, rank3]..]>
1083        // nodeIdx2Idx = <idx, <rankOwner, idx>>
1084
1085        CClientClientDHTSizet dhtNodeHash(nodeHash2Idx, comm);
1086        dhtNodeHash.computeIndexInfoMapping(nodeHashList);
1087        CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeHash2Info = dhtNodeHash.getInfoIndexMap();
1088
1089        CClientClientDHTSizet::Index2VectorInfoTypeMap nodeIdx2Idx;
1090        CArray<size_t,1> nodeIdxList(nbFaces_*nvertex*4);
1091        size_t nIdx = 0;
1092
1093        for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = nodeHash2Info.begin(); it != nodeHash2Info.end(); ++it)
1094        {
1095          size_t rankMin = (it->second)[1];
1096          size_t idx = (it->second)[0];
1097          for (int i = 2; i < (it->second).size();)
1098          {
1099            if ( (it->second)[i+1] < rankMin)
1100            {
1101              idx = (it->second)[i];
1102              rankMin = (it->second)[i+1];
1103              (it->second)[i+1] = (it->second)[i-1];
1104            }
1105            i += 2;
1106          }
1107          if (nodeIdx2Idx.count(idx) == 0)
1108          {
1109            if (mpiRank == rankMin)
1110            {
1111              nodeIdx2Idx[idx].push_back(rankMin);
1112              nodeIdx2Idx[idx].push_back(idx);
1113            }
1114            nodeIdxList(nIdx) = idx;
1115            ++nIdx;
1116          }
1117        }
1118
1119//        CDHTAutoIndexing dhtNodeIdxGlo = CDHTAutoIndexing(nodeIdx2Idx, comm);
1120        // CDHTAutoIndexing will not give consistent node numbering for varying number of procs. =>
1121        // Solution: global node indexing by hand.
1122        // Maps modified in this step:
1123        // nodeIdx2Idx = <idx, idxGlo>
1124        unsigned long nodeCount = nodeIdx2Idx.size();
1125        unsigned long nodeStart, nbNodes;
1126        MPI_Scan(&nodeCount, &nodeStart, 1, MPI_UNSIGNED_LONG, MPI_SUM, comm);
1127        int nNodes = nodeStart;
1128        MPI_Bcast(&nNodes, 1, MPI_UNSIGNED_LONG, mpiSize-1, comm);
1129        nbNodesGlo = nNodes;
1130
1131        nodeStart -= nodeCount;
1132        node_start = nodeStart;
1133        node_count = nodeCount;
1134        CClientClientDHTSizet::Index2VectorInfoTypeMap dummyMap; // just a dummy map used to ensure that each node is numbered only once
1135        size_t count = 0;
1136
1137        for (int nf = 0; nf < nbFaces_; ++nf)
1138        {
1139          for (int nv = 0; nv < nvertex; ++nv)
1140          {
1141            vector<size_t> hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf));
1142            size_t nodeIdx = generateNodeIndex(hashValues);
1143            CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = nodeIdx2Idx.find(nodeIdx);
1144            if (it != nodeIdx2Idx.end())
1145            {
1146              if (dummyMap.count(nodeIdx) == 0)
1147              {
1148                dummyMap[nodeIdx].push_back(nodeIdx);
1149                (it->second)[1] = node_start + count;
1150                ++count;
1151              }
1152            }
1153          }
1154        }
1155        nodeIdxList.resizeAndPreserve(nIdx);
1156        CClientClientDHTSizet dhtNodeIdx(nodeIdx2Idx, comm);
1157        dhtNodeIdx.computeIndexInfoMapping(nodeIdxList);
1158        CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeIdx2IdxGlo = dhtNodeIdx.getInfoIndexMap();
1159
1160        // (3.3) Saving node data: node_lon, node_lat, and face_nodes
1161        // Generating edgeHash2Info = <hash, <idx, rank>> and edgeHashList
1162//        nbNodesGlo = dhtNodeIdxGlo.getNbIndexesGlobal();
1163//        node_count = dhtNodeIdxGlo.getIndexCount();
1164//        node_start = dhtNodeIdxGlo.getIndexStart();
1165        node_lon.resize(node_count);
1166        node_lat.resize(node_count);
1167        size_t nodeIdxGlo1 = 0;
1168        size_t nodeIdxGlo2 = 0;
1169        CClientClientDHTSizet::Index2VectorInfoTypeMap edgeHash2Idx;
1170        CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNodeIdxGlo1, itNodeIdxGlo2;
1171        CArray<size_t,1> edgeHashList(nbFaces_*nvertex);
1172        size_t nEdgeHash = 0;
1173
1174        for (int nf = 0; nf < nbFaces_; ++nf)
1175        {
1176          for (int nv1 = 0; nv1 < nvertex; ++nv1)
1177          {
1178            int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation
1179            vector<size_t> hashValues1 = CMesh::createHashes(bounds_lon(nv1, nf), bounds_lat(nv1, nf));
1180            vector<size_t> hashValues2 = CMesh::createHashes(bounds_lon(nv2, nf), bounds_lat(nv2, nf));
1181            size_t nodeIdx1 = generateNodeIndex(hashValues1);
1182            size_t nodeIdx2 = generateNodeIndex(hashValues2);
1183            CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNodeIdx1 = nodeIdx2IdxGlo.find(nodeIdx1);
1184            CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNodeIdx2 = nodeIdx2IdxGlo.find(nodeIdx2);
1185            size_t ownerRank = (itNodeIdx1->second)[0];
1186            nodeIdxGlo1 = (itNodeIdx1->second)[1];
1187            nodeIdxGlo2 = (itNodeIdx2->second)[1];
1188
1189            if (mpiRank == ownerRank)
1190            {
1191              node_lon(nodeIdxGlo1 - node_start) = bounds_lon(nv1, nf);
1192              node_lat(nodeIdxGlo1 - node_start) = bounds_lat(nv1, nf);
1193            }
1194            if (nodeIdxGlo1 != nodeIdxGlo2)
1195            {
1196              size_t edgeHash = hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2);
1197              edgeHash2Idx[edgeHash].push_back(edgeHash);
1198              edgeHash2Idx[edgeHash].push_back(mpiRank);
1199              edgeHashList(nEdgeHash) = edgeHash;
1200              ++nEdgeHash;
1201            }
1202            face_nodes(nv1,nf) = nodeIdxGlo1;
1203          }
1204        }
1205        edgeHashList.resizeAndPreserve(nEdgeHash);
1206
1207        // (3.4) Generating global edge indexes
1208        // Maps generated in this step are:
1209        // edgeIdx2Idx = = <idx, <rankOwner, idx>>
1210        // edgeIdx2IdxGlo = <idxMin, <rankOwner, idxGlo>>
1211
1212        CClientClientDHTSizet dhtEdgeHash(edgeHash2Idx, comm);
1213        dhtEdgeHash.computeIndexInfoMapping(edgeHashList);
1214        CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeHash2Info = dhtEdgeHash.getInfoIndexMap();
1215        // edgeHash2Info = <hash, [[idx1, rank1], [idx2, rank2], [idx3, rank3]..]>
1216
1217        CClientClientDHTSizet::Index2VectorInfoTypeMap edgeIdx2Idx;
1218
1219        for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = edgeHash2Info.begin(); it != edgeHash2Info.end(); ++it)
1220        {
1221          size_t rankMin = (it->second)[1];
1222          size_t idx = (it->second)[0];
1223
1224          for (int i = 2; i < (it->second).size();)
1225          {
1226            if ((it->second)[i+1] < rankMin)
1227            {
1228              rankMin = (it->second)[i+1];
1229              idx = (it->second)[i];
1230              (it->second)[i+1] = (it->second)[i-1];
1231            }
1232            i += 2;
1233          }
1234          if (edgeIdx2Idx.count(idx) == 0)
1235          {
1236            if (mpiRank == rankMin)
1237            {
1238              edgeIdx2Idx[idx].push_back(rankMin);
1239              edgeIdx2Idx[idx].push_back(idx);
1240            }
1241          }
1242        }
1243
1244        unsigned long edgeCount = edgeIdx2Idx.size();
1245        unsigned long edgeStart, nbEdges;
1246        MPI_Scan(&edgeCount, &edgeStart, 1, MPI_UNSIGNED_LONG, MPI_SUM, comm);
1247        int nEdges = edgeStart;
1248        MPI_Bcast(&nEdges, 1, MPI_UNSIGNED_LONG, mpiSize-1, comm);
1249        nbEdgesGlo = nEdges;
1250
1251        edgeStart -= edgeCount;
1252        edge_start = edgeStart;
1253        edge_count = edgeCount;
1254        CClientClientDHTSizet::Index2VectorInfoTypeMap dummyEdgeMap;
1255        count = 0;
1256
1257        for (int nf = 0; nf < nbFaces_; ++nf)
1258        {
1259          for (int nv1 = 0; nv1 < nvertex; ++nv1)
1260          {
1261            int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation
1262            vector<size_t> hashValues1 = CMesh::createHashes(bounds_lon(nv1, nf), bounds_lat(nv1, nf));
1263            vector<size_t> hashValues2 = CMesh::createHashes(bounds_lon(nv2, nf), bounds_lat(nv2, nf));
1264            size_t nodeIdx1 = generateNodeIndex(hashValues1);
1265            size_t nodeIdx2 = generateNodeIndex(hashValues2);
1266            CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNodeIdx1 = nodeIdx2IdxGlo.find(nodeIdx1);
1267            CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNodeIdx2 = nodeIdx2IdxGlo.find(nodeIdx2);
1268            nodeIdxGlo1 = (itNodeIdx1->second)[1];
1269            nodeIdxGlo2 = (itNodeIdx2->second)[1];
1270
1271            if (nodeIdxGlo1 != nodeIdxGlo2)
1272            {
1273              size_t edgeIdx = hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2);
1274              CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = edgeIdx2Idx.find(edgeIdx);
1275              if (it != edgeIdx2Idx.end())
1276              {
1277                if (dummyEdgeMap.count(edgeIdx) == 0)
1278                {
1279                  dummyEdgeMap[edgeIdx].push_back(edgeIdx);
1280                  (it->second)[1] = edge_start + count;
1281                  ++count;
1282                }
1283              }
1284            }
1285          }
1286        }
1287        CClientClientDHTSizet dhtEdgeIdx(edgeIdx2Idx, comm);
1288        dhtEdgeIdx.computeIndexInfoMapping(edgeHashList);
1289        CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeIdx2IdxGlo = dhtEdgeIdx.getInfoIndexMap();
1290
1291        // (3.5) Saving variables: edge_lon, edge_lat, face_edges
1292        // Creating map edgeIdxGlo2Face <idxGlo, face>
1293//        nbEdgesGlo = dhtEdgeIdxGlo.getNbIndexesGlobal();
1294//        edge_count = dhtEdgeIdxGlo.getIndexCount();
1295//        edge_start = dhtEdgeIdxGlo.getIndexStart();
1296
1297        edge_lon.resize(edge_count);
1298        edge_lat.resize(edge_count);
1299        edge_nodes.resize(2, edge_count);
1300        face_edges.resize(nvertex, nbFaces_);
1301
1302        CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it1, it2;
1303        CClientClientDHTSizet::Index2VectorInfoTypeMap edgeIdxGlo2Face;
1304        CArray<size_t,1> edgeIdxGloList(nbFaces_*nvertex);
1305        size_t nEdge = 0;
1306
1307        for (int nf = 0; nf < nbFaces_; ++nf)
1308        {
1309          for (int nv1 = 0; nv1 < nvertex; ++nv1)
1310          {
1311            // Getting global indexes of edge's nodes
1312            int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation
1313            vector<size_t> hashValues1 = CMesh::createHashes(bounds_lon(nv1, nf), bounds_lat(nv1, nf));
1314            vector<size_t> hashValues2 = CMesh::createHashes(bounds_lon(nv2, nf), bounds_lat(nv2, nf));
1315
1316            size_t nodeIdx1 = generateNodeIndex(hashValues1);
1317            size_t nodeIdx2 = generateNodeIndex(hashValues2);
1318            it1 = nodeIdx2IdxGlo.find(nodeIdx1);
1319            it2 = nodeIdx2IdxGlo.find(nodeIdx2);
1320            size_t nodeIdxGlo1 = (it1->second)[1];
1321            size_t nodeIdxGlo2 = (it2->second)[1];
1322
1323            if (nodeIdxGlo1 != nodeIdxGlo2)
1324            {
1325              size_t myIdx = hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2);
1326              CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itIdx = edgeIdx2IdxGlo.find(myIdx);
1327              int edgeIdxGlo = (itIdx->second)[1];
1328              size_t faceIdxGlo = nbFacesAccum + nf;
1329
1330              if (mpiRank == (itIdx->second)[0])
1331              {
1332                double edgeLon;
1333                double diffLon = abs(bounds_lon(nv1, nf) - bounds_lon(nv2, nf));
1334                if (diffLon < (180.- prec))
1335                  edgeLon = ( bounds_lon(nv1, nf) + bounds_lon(nv2, nf)) * 0.5;
1336                else if (diffLon > (180.+ prec))
1337                  edgeLon = (bounds_lon(nv1, nf) + bounds_lon(nv2, nf)) * 0.5 -180.;
1338                else
1339                  edgeLon = 0.;
1340                edge_lon(edgeIdxGlo - edge_start) = edgeLon;
1341                edge_lat(edgeIdxGlo-edge_start) = ( bounds_lat(nv1, nf) + bounds_lat(nv2, nf) ) * 0.5;
1342                edge_nodes(0, edgeIdxGlo - edge_start) = nodeIdxGlo1;
1343                edge_nodes(1, edgeIdxGlo - edge_start) = nodeIdxGlo2;
1344              }
1345              face_edges(nv1,nf) = edgeIdxGlo;
1346              if (edgeIdxGlo2Face.count(edgeIdxGlo) == 0)
1347              {
1348                edgeIdxGloList(nEdge) = edgeIdxGlo;
1349                ++nEdge;
1350              }
1351              edgeIdxGlo2Face[edgeIdxGlo].push_back(faceIdxGlo);
1352            } // nodeIdxGlo1 != nodeIdxGlo2
1353            else
1354            {
1355              face_edges(nv1,nf) = 999999;
1356            }
1357          }
1358        }
1359        edgeIdxGloList.resizeAndPreserve(nEdge);
1360
1361        // (3.6) Saving remaining variables edge_faces and face_faces
1362        edge_faces.resize(2, edge_count);
1363        face_faces.resize(nvertex, nbFaces_);
1364
1365        CClientClientDHTSizet dhtEdge2Face (edgeIdxGlo2Face, comm);
1366        dhtEdge2Face.computeIndexInfoMapping(edgeIdxGloList);
1367        CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeIdxGlo2FaceIdx = dhtEdge2Face.getInfoIndexMap();
1368
1369        for (int nf = 0; nf < nbFaces_; ++nf)
1370        {
1371          for (int nv1 = 0; nv1 < nvertex; ++nv1)
1372          {
1373            // Getting global indexes of edge's nodes
1374            int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation
1375            vector<size_t> hashValues1 = CMesh::createHashes(bounds_lon(nv1, nf), bounds_lat(nv1, nf));
1376            vector<size_t> hashValues2 = CMesh::createHashes(bounds_lon(nv2, nf), bounds_lat(nv2, nf));
1377
1378            size_t myNodeIdx1 = generateNodeIndex(hashValues1);
1379            size_t myNodeIdx2 = generateNodeIndex(hashValues2);
1380            if (myNodeIdx1 != myNodeIdx2)
1381            {
1382              it1 = nodeIdx2IdxGlo.find(myNodeIdx1);
1383              it2 = nodeIdx2IdxGlo.find(myNodeIdx2);
1384              size_t nodeIdxGlo1 = (it1->second)[1];
1385              size_t nodeIdxGlo2 = (it2->second)[1];
1386              size_t myIdx = hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2);
1387              CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itIdx = edgeIdx2IdxGlo.find(myIdx);
1388              int edgeIdxGlo = (itIdx->second)[1];
1389
1390              size_t faceIdxGlo = nbFacesAccum + nf;
1391
1392              if (mpiRank == (itIdx->second)[0])
1393              {
1394                it1 = edgeIdxGlo2FaceIdx.find(edgeIdxGlo);
1395                int face1 = it1->second[0];
1396                if (it1->second.size() == 1)
1397                {
1398                  edge_faces(0, edgeIdxGlo - edge_start) = face1;
1399                  edge_faces(1, edgeIdxGlo - edge_start) = -999;
1400                  face_faces(nv1, nf) = 999999;
1401                }
1402                else
1403                {
1404                  size_t face2 = it1->second[1];
1405                  edge_faces(0, edgeIdxGlo - edge_start) = face1;
1406                  edge_faces(1, edgeIdxGlo - edge_start) = face2;
1407                  face_faces(nv1, nf) = (faceIdxGlo == face1 ? face2 : face1);
1408                }
1409              }
1410              else
1411              {
1412                it1 = edgeIdxGlo2FaceIdx.find(edgeIdxGlo);
1413                int face1 = it1->second[0];
1414                int face2 = it1->second[1];
1415                face_faces(nv1, nf) = (faceIdxGlo == face1 ? face2 : face1);
1416              }
1417            } // myNodeIdx1 != myNodeIdx2
1418            else
1419              face_faces(nv1, nf) = 999999;
1420          }
1421        }
1422
1423      }
1424      facesAreWritten = true;
1425    } // nvertex >= 3
1426
1427  } // createMeshEpsilon
1428
1429  ///----------------------------------------------------------------
1430  /*!
1431   * \fn  void CMesh::getGloNghbFacesNodeType(const MPI_Comm& comm, const CArray<int, 1>& face_idx,
1432                                              const CArray<double, 2>& bounds_lon, const CArray<double, 2>& bounds_lat,
1433                                              CArray<int, 2>& nghbFaces)
1434   * Finds neighboring cells of a local domain for node-type of neighbors.
1435   * \param [in] comm
1436   * \param [in] face_idx Array with global indexes.
1437   * \param [in] bounds_lon Array of boundary longitudes.
1438   * \param [in] bounds_lat Array of boundary latitudes.
1439   * \param [out] nghbFaces 2D array of storing global indexes of neighboring cells and their owner procs.
1440   */
1441
1442  void CMesh::getGloNghbFacesNodeType(const MPI_Comm& comm, const CArray<int, 1>& face_idx,
1443                               const CArray<double, 2>& bounds_lon, const CArray<double, 2>& bounds_lat,
1444                               CArray<int, 2>& nghbFaces)
1445  {
1446    int nvertex = bounds_lon.rows();
1447    int nbFaces = bounds_lon.shape()[1];
1448    nghbFaces.resize(2, nbFaces*10);    // some estimate on max number of neighbouring cells
1449
1450    int mpiRank, mpiSize;
1451    MPI_Comm_rank(comm, &mpiRank);
1452    MPI_Comm_size(comm, &mpiSize);
1453
1454    // (1) Generating unique node indexes
1455    // (1.1) Creating a list of hashes for each node and a map nodeHash2Idx <hash, <idx,rank> >
1456    vector<size_t> hashValues(4);
1457    CClientClientDHTSizet::Index2VectorInfoTypeMap nodeHash2Idx;
1458    CArray<size_t,1> nodeHashList(nbFaces*nvertex*4);
1459    size_t iIdx = 0;
1460    for (int nf = 0; nf < nbFaces; ++nf)
1461    {
1462      for (int nv = 0; nv < nvertex; ++nv)
1463      {
1464        hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf));
1465        size_t nodeIndex = generateNodeIndex(hashValues, mpiRank);
1466        for (int nh = 0; nh < 4; ++nh)
1467        {
1468          if (nodeHash2Idx.count(hashValues[nh])==0)
1469         {
1470            nodeHash2Idx[hashValues[nh]].push_back(nodeIndex);
1471            nodeHash2Idx[hashValues[nh]].push_back(mpiRank);
1472           nodeHashList(iIdx) = hashValues[nh];
1473           ++iIdx;
1474         }
1475        }
1476      }
1477    }
1478    nodeHashList.resizeAndPreserve(iIdx);
1479
1480    // (1.2) Generating node indexes
1481    // The ownership criterion: priority of the process holding the smaller index
1482    // Maps generated in this step are:
1483    // nodeHash2Info = <hash, idx1, idx2, idx3....>
1484    // nodeIdx2IdxMin = <idx, idxMin>
1485    // idxMin is a unique node identifier
1486
1487    CClientClientDHTSizet dhtNodeHash(nodeHash2Idx, comm);
1488    dhtNodeHash.computeIndexInfoMapping(nodeHashList);
1489    CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeHash2Info = dhtNodeHash.getInfoIndexMap();
1490
1491    CClientClientDHTSizet::Index2VectorInfoTypeMap nodeIdx2IdxMin;
1492
1493    for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = nodeHash2Info.begin(); it != nodeHash2Info.end(); ++it)
1494    {
1495      size_t idxMin = (it->second)[0];
1496      size_t idx = (it->second)[0];
1497      for (int i = 2; i < (it->second).size();)
1498      {
1499        if (mpiRank == (it->second)[i+1])
1500        {
1501          idx = (it->second)[i];
1502        }
1503        if ((it->second)[i] < idxMin)
1504        {
1505          idxMin = (it->second)[i];
1506          (it->second)[i] = (it->second)[i-2];
1507          (it->second)[i+1] = (it->second)[i-1];
1508        }
1509        i += 2;
1510      }
1511      (it->second)[0] = idxMin;
1512      if (nodeIdx2IdxMin.count(idx) == 0)
1513      {
1514        nodeIdx2IdxMin[idx].push_back(idxMin);
1515      }
1516    }
1517
1518    // (2) Creating maps nodeIdxMin2Face = <nodeIdxMin, [face1, face2, ...]>
1519    CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it;
1520    CClientClientDHTSizet::Index2VectorInfoTypeMap nodeIdxMin2Face;
1521    CArray<size_t,1> nodeIdxMinList(nbFaces*nvertex*4);
1522
1523    size_t nNode = 0;
1524
1525    for (int nf = 0; nf < nbFaces; ++nf)
1526    {
1527      for (int nv = 0; nv < nvertex; ++nv)
1528      {
1529        vector<size_t> hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf));
1530        size_t myNodeIdx = generateNodeIndex(hashValues, mpiRank);
1531        it = nodeIdx2IdxMin.find(myNodeIdx);
1532        size_t nodeIdxMin = (it->second)[0];
1533        size_t faceIdx = face_idx(nf);
1534        if (nodeIdxMin2Face.count(nodeIdxMin) == 0)
1535        {
1536          nodeIdxMinList(nNode) = nodeIdxMin;
1537          ++nNode;
1538        }
1539        nodeIdxMin2Face[nodeIdxMin].push_back(faceIdx);
1540        nodeIdxMin2Face[nodeIdxMin].push_back(mpiRank);
1541      }
1542    }
1543    nodeIdxMinList.resizeAndPreserve(nNode);
1544
1545    // (3) Face_face connectivity
1546
1547    // nodeIdxMin2Info = <nodeIdxMin, [face1, face2,...]>
1548    CClientClientDHTSizet dhtNode2Face (nodeIdxMin2Face, comm);
1549    dhtNode2Face.computeIndexInfoMapping(nodeIdxMinList);
1550    CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeIdxMin2Info = dhtNode2Face.getInfoIndexMap();
1551    CClientClientDHTSizet::Index2VectorInfoTypeMap mapFaces;  // auxiliar map
1552
1553    int nbNghb = 0;
1554    CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNode;
1555
1556    for (int nf = 0; nf < nbFaces; ++nf)
1557    {
1558      for (int nv = 0; nv < nvertex; ++nv)
1559      {
1560        vector<size_t> hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf));
1561        size_t myNodeIdx = generateNodeIndex(hashValues, mpiRank);
1562        itNode = nodeIdx2IdxMin.find(myNodeIdx);
1563        size_t nodeIdxMin = (itNode->second)[0];
1564
1565        itNode = nodeIdxMin2Info.find(nodeIdxMin);
1566        for (int i = 0; i < itNode->second.size();)
1567        {
1568          size_t face = itNode->second[i];
1569          size_t rank = itNode->second[i+1];
1570          if (rank != mpiRank)
1571            if (mapFaces.count(face) == 0)
1572            {
1573              nghbFaces(0, nbNghb) = face;
1574              nghbFaces(1, nbNghb) = rank;
1575              ++nbNghb;
1576              mapFaces[face].push_back(face);
1577            }
1578          i += 2;
1579        }
1580      }
1581    }
1582    nghbFaces.resizeAndPreserve(2, nbNghb);
1583  } // getGloNghbFacesNodeType
1584
1585  ///----------------------------------------------------------------
1586  /*!
1587   * \fn  void CMesh::getGloNghbFacesEdgeType(const MPI_Comm& comm, const CArray<int, 1>& face_idx,
1588                               const CArray<double, 2>& bounds_lon, const CArray<double, 2>& bounds_lat,
1589                               CArray<int, 2>& nghbFaces)
1590   * Finds neighboring cells of a local domain for edge-type of neighbors.
1591   * \param [in] comm
1592   * \param [in] face_idx Array with global indexes.
1593   * \param [in] bounds_lon Array of boundary longitudes.
1594   * \param [in] bounds_lat Array of boundary latitudes.
1595   * \param [out] nghbFaces 2D array of storing global indexes of neighboring cells and their owner procs.
1596   */
1597
1598  void CMesh::getGloNghbFacesEdgeType(const MPI_Comm& comm, const CArray<int, 1>& face_idx,
1599                               const CArray<double, 2>& bounds_lon, const CArray<double, 2>& bounds_lat,
1600                               CArray<int, 2>& nghbFaces)
1601  {
1602    int nvertex = bounds_lon.rows();
1603    int nbFaces = bounds_lon.shape()[1];
1604    nghbFaces.resize(2, nbFaces*10);    // estimate of max number of neighbouring cells
1605
1606    int mpiRank, mpiSize;
1607    MPI_Comm_rank(comm, &mpiRank);
1608    MPI_Comm_size(comm, &mpiSize);
1609
1610    // (1) Generating unique node indexes
1611    // (1.1) Creating a list of hashes for each node and a map nodeHash2Idx <hash, <idx,rank> >
1612    vector<size_t> hashValues(4);
1613    CClientClientDHTSizet::Index2VectorInfoTypeMap nodeHash2Idx;
1614    CArray<size_t,1> nodeHashList(nbFaces*nvertex*4);
1615    size_t iIdx = 0;
1616    for (int nf = 0; nf < nbFaces; ++nf)
1617    {
1618      for (int nv = 0; nv < nvertex; ++nv)
1619      {
1620        hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf));
1621        size_t nodeIndex = generateNodeIndex(hashValues, mpiRank);
1622        for (int nh = 0; nh < 4; ++nh)
1623        {
1624          if (nodeHash2Idx.count(hashValues[nh])==0)
1625          {
1626            nodeHash2Idx[hashValues[nh]].push_back(nodeIndex);
1627            nodeHash2Idx[hashValues[nh]].push_back(mpiRank);
1628            nodeHashList(iIdx) = hashValues[nh];
1629            ++iIdx;
1630          }
1631        }
1632      }
1633    }
1634    nodeHashList.resizeAndPreserve(iIdx);
1635
1636    // (1.2) Generating node indexes
1637    // The ownership criterion: priority of the process holding the smaller index
1638    // Maps generated in this step are:
1639    // nodeHash2Info = <hash, idx1, idx2, idx3....>
1640    // nodeIdx2IdxMin = <idx, idxMin>
1641    // idxMin is a unique node identifier
1642
1643    CClientClientDHTSizet dhtNodeHash(nodeHash2Idx, comm);
1644    dhtNodeHash.computeIndexInfoMapping(nodeHashList);
1645    CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeHash2Info = dhtNodeHash.getInfoIndexMap();
1646
1647    CClientClientDHTSizet::Index2VectorInfoTypeMap nodeIdx2IdxMin;
1648
1649    for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = nodeHash2Info.begin(); it != nodeHash2Info.end(); ++it)
1650    {
1651      size_t idxMin = (it->second)[0];
1652      size_t idx = (it->second)[0];
1653      for (int i = 2; i < (it->second).size();)
1654      {
1655        if (mpiRank == (it->second)[i+1])
1656        {
1657          idx = (it->second)[i];
1658        }
1659        if ((it->second)[i] < idxMin)
1660        {
1661          idxMin = (it->second)[i];
1662          (it->second)[i] = (it->second)[i-2];
1663          (it->second)[i+1] = (it->second)[i-1];
1664        }
1665        i += 2;
1666      }
1667      (it->second)[0] = idxMin;
1668      if (nodeIdx2IdxMin.count(idx) == 0)
1669      {
1670        nodeIdx2IdxMin[idx].push_back(idxMin);
1671      }
1672    }
1673
1674    // (2) Creating map edgeHash2Face = <edgeHash, [[face1, rank1], [face2, rank2]]>, where rank1 = rank2 = ...
1675
1676    CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it1, it2, it;
1677    CClientClientDHTSizet::Index2VectorInfoTypeMap edgeHash2Face;
1678    CArray<size_t,1> edgeHashList(nbFaces*nvertex);
1679
1680    size_t nEdge = 0;
1681
1682    for (int nf = 0; nf < nbFaces; ++nf)
1683    {
1684      for (int nv1 = 0; nv1 < nvertex; ++nv1)
1685      {
1686        // Getting indexes of edge's nodes
1687        int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation
1688        vector<size_t> hashValues1 = CMesh::createHashes(bounds_lon(nv1, nf), bounds_lat(nv1, nf));
1689        vector<size_t> hashValues2 = CMesh::createHashes(bounds_lon(nv2, nf), bounds_lat(nv2, nf));
1690        size_t myNodeIdx1 = generateNodeIndex(hashValues1, mpiRank);
1691        size_t myNodeIdx2 = generateNodeIndex(hashValues2, mpiRank);
1692        it1 = nodeIdx2IdxMin.find(myNodeIdx1);
1693        it2 = nodeIdx2IdxMin.find(myNodeIdx2);
1694        size_t nodeIdxMin1 = (it1->second)[0];
1695        size_t nodeIdxMin2 = (it2->second)[0];
1696        size_t faceIdx = face_idx(nf);
1697
1698        if (nodeIdxMin1 != nodeIdxMin2)
1699        {
1700          size_t edgeHash = hashPairOrdered(nodeIdxMin1, nodeIdxMin2);
1701          if (edgeHash2Face.count(edgeHash) == 0)
1702          {
1703            edgeHashList(nEdge) = edgeHash;
1704            ++nEdge;
1705          }
1706          edgeHash2Face[edgeHash].push_back(faceIdx);
1707          edgeHash2Face[edgeHash].push_back(mpiRank);
1708        } // nodeIdxMin1 != nodeIdxMin2
1709      }
1710    }
1711    edgeHashList.resizeAndPreserve(nEdge);
1712
1713    // (3) Face_face connectivity
1714
1715    int nbNghb = 0;
1716    CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNode1, itNode2;
1717
1718    // edgeHash2Info = <edgeHash, [[face1, rank1], [face2, rank2]]>
1719    CClientClientDHTSizet dhtEdge2Face (edgeHash2Face, comm);
1720    dhtEdge2Face.computeIndexInfoMapping(edgeHashList);
1721    CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeHash2Info = dhtEdge2Face.getInfoIndexMap();
1722    CClientClientDHTSizet::Index2VectorInfoTypeMap mapFaces;  // auxiliar map
1723
1724    for (int nf = 0; nf < nbFaces; ++nf)
1725    {
1726      for (int nv1 = 0; nv1 < nvertex; ++nv1)
1727      {
1728        // Getting indexes of edge's nodes
1729        int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation
1730        vector<size_t> hashValues1 = CMesh::createHashes(bounds_lon(nv1, nf), bounds_lat(nv1, nf));
1731        vector<size_t> hashValues2 = CMesh::createHashes(bounds_lon(nv2, nf), bounds_lat(nv2, nf));
1732
1733        size_t myNodeIdx1 = generateNodeIndex(hashValues1, mpiRank);
1734        size_t myNodeIdx2 = generateNodeIndex(hashValues2, mpiRank);
1735        itNode1 = nodeIdx2IdxMin.find(myNodeIdx1);
1736        itNode2 = nodeIdx2IdxMin.find(myNodeIdx2);
1737        size_t nodeIdxMin1 = (itNode1->second)[0];
1738        size_t nodeIdxMin2 = (itNode2->second)[0];
1739
1740        if (nodeIdxMin1 != nodeIdxMin2)
1741        {
1742          size_t edgeHash = hashPairOrdered(nodeIdxMin1, nodeIdxMin2);
1743          it1 = edgeHash2Info.find(edgeHash);
1744
1745          for (int i = 0; i < it1->second.size();)
1746          {
1747            size_t face = it1->second[i];
1748            size_t rank = it1->second[i+1];
1749            if (rank != mpiRank)
1750              if (mapFaces.count(face) == 0)
1751              {
1752                nghbFaces(0, nbNghb) = face;
1753                nghbFaces(1, nbNghb) = rank;
1754                ++nbNghb;
1755                mapFaces[face].push_back(face);
1756              }
1757            i += 2;
1758          }
1759        } // nodeIdxMin1 != nodeIdxMin2
1760      }
1761    }
1762    nghbFaces.resizeAndPreserve(2, nbNghb);
1763  } // getGloNghbFacesEdgeType
1764
1765  ///----------------------------------------------------------------
1766  /*!
1767   * \fn void getGlobalNghbFaces (const int nghbType, const MPI_Comm& comm, const CArray<int, 1>& face_idx,
1768                                  const CArray<double, 2>& bounds_lon, const CArray<double, 2>& bounds_lat,
1769                                  CArray<size_t, 1>& nghbFaces)
1770   * Finds neighboring faces owned by other procs.
1771   * \param [in] nghbType 0 for faces sharing nodes, otherwise for faces sharing edges.
1772   * \param [in] comm
1773   * \param [in] face_idx Array with global indexes.
1774   * \param [in] bounds_lon Array of boundary longitudes.
1775   * \param [in] bounds_lat Array of boundary latitudes.
1776   * \param [out] nghbFaces 2D array containing neighboring faces and owner ranks.
1777   */
1778
1779  void CMesh::getGlobalNghbFaces(const int nghbType, const MPI_Comm& comm,
1780                                 const CArray<int, 1>& face_idx,
1781                                 const CArray<double, 2>& bounds_lon, const CArray<double, 2>& bounds_lat,
1782                                 CArray<int, 2>& nghbFaces)
1783  {
1784    if (nghbType == 0)
1785      getGloNghbFacesNodeType(comm, face_idx, bounds_lon, bounds_lat, nghbFaces);
1786    else
1787      getGloNghbFacesEdgeType(comm, face_idx, bounds_lon, bounds_lat, nghbFaces);
1788  } // getGlobalNghbFaces
1789
1790  ///----------------------------------------------------------------
1791  /*!
1792   * \fn void getLocalNghbFaces (const int nghbType,
1793                                  const CArray<double, 2>& bounds_lon, const CArray<double, 2>& bounds_lat,
1794                                  CArray<size_t, 1>& nghbFaces)
1795   * \param [in] nghbType 0 for faces sharing nodes, otherwise for faces sharing edges.
1796   * \param [in] bounds_lon Array of boundary longitudes.
1797   * \param [in] bounds_lat Array of boundary latitudes.
1798   * \param [out] nghbFaces 1D array containing neighboring faces.
1799   */
1800
1801  void CMesh::getLocalNghbFaces(const int nghbType, const CArray<int, 1>& face_idx,
1802                                const CArray<double, 2>& bounds_lon, const CArray<double, 2>& bounds_lat,
1803                                CArray<int, 2>& nghbFaces, CArray<int, 1>& nbNghbFaces)
1804  {
1805    if (nghbType == 0)
1806      getLocNghbFacesNodeType(face_idx, bounds_lon, bounds_lat, nghbFaces, nbNghbFaces);
1807    else
1808      getLocNghbFacesEdgeType(face_idx, bounds_lon, bounds_lat, nghbFaces, nbNghbFaces);
1809  } // getLocalNghbFaces
1810
1811  ///----------------------------------------------------------------
1812  /*!
1813   * \fn void getLocNghbFacesNodeType (const CArray<double, 2>& bounds_lon, const CArray<double, 2>& bounds_lat,
1814                                       CArray<int, 2>& nghbFaces)
1815   * \param [in] face_idx Array with local face indexing.
1816   * \param [in] bounds_lon Array of boundary longitudes.
1817   * \param [in] bounds_lat Array of boundary latitudes.
1818   * \param [out] nghbFaces 2D array containing neighboring faces.
1819   * \param [out] nbNghbFaces Array containing number of neighboring faces.
1820   */
1821
1822  void CMesh::getLocNghbFacesNodeType (const CArray<int, 1>& face_idx,
1823                                       const CArray<double, 2>& bounds_lon, const CArray<double, 2>& bounds_lat,
1824                                       CArray<int, 2>& faceToFaces, CArray<int, 1>& nbNghbFaces)
1825  {
1826    int nvertex = bounds_lon.rows();
1827    int nbFaces = bounds_lon.shape()[1];
1828    int nbNodes = 0;
1829    nbNghbFaces.resize(nbFaces);
1830    nbNghbFaces = 0;
1831
1832    // nodeToFaces connectivity
1833    CClientClientDHTSizet::Index2VectorInfoTypeMap nodeToFaces;
1834    for (int nf = 0; nf < nbFaces; ++nf)
1835      for (int nv = 0; nv < nvertex; ++nv)
1836      {
1837        size_t nodeHash = (CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv ,nf)))[0];
1838        nodeToFaces[nodeHash].push_back(face_idx(nf));
1839      }
1840
1841    // faceToFaces connectivity
1842    std::unordered_map <int, int> mapFaces;  // mapFaces = < hash(face1, face2), hash> (the mapped value is irrelevant)
1843    int maxNb = 20;                            // some assumption on the max possible number of neighboring cells
1844    faceToFaces.resize(maxNb, nbFaces);
1845    CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it;
1846    for (it = nodeToFaces.begin(); it != nodeToFaces.end(); ++it)
1847    {
1848      int size = it->second.size();
1849      for (int i = 0; i < (size-1); ++i)
1850      {
1851        int face1 = it->second[i];
1852        for (int j = i+1; j < size; ++j)
1853        {
1854          int face2 = it->second[j];
1855          if (face2 != face1)
1856          {
1857            int hashFace = hashPairOrdered(face1, face2);
1858            if (mapFaces.count(hashFace) == 0)
1859            {
1860              faceToFaces(nbNghbFaces(face1), face1) = face2;
1861              faceToFaces(nbNghbFaces(face2), face2) = face1;
1862              ++nbNghbFaces(face1);
1863              ++nbNghbFaces(face2);
1864              mapFaces[hashFace] = hashFace;
1865            }
1866          }
1867        }
1868      }
1869    }
1870  } //getLocNghbFacesNodeType
1871
1872
1873  ///----------------------------------------------------------------
1874  /*!
1875   * \fn void getLocNghbFacesEdgeType (const CArray<int, 1>& face_idx,
1876   *                                   const CArray<double, 2>& bounds_lon, const CArray<double, 2>& bounds_lat,
1877   *                                   CArray<int, 2>& nghbFaces, CArray<int, 1>& nbNghbFaces)
1878   * \param [in] face_idx Array with local face indexing.
1879   * \param [in] bounds_lon Array of boundary longitudes.
1880   * \param [in] bounds_lat Array of boundary latitudes.
1881   * \param [out] nghbFaces 2D array containing neighboring faces.
1882   * \param [out] nbNghbFaces Array containing number of neighboring faces.
1883   */
1884
1885  void CMesh::getLocNghbFacesEdgeType (const CArray<int, 1>& face_idx,
1886                                       const CArray<double, 2>& bounds_lon, const CArray<double, 2>& bounds_lat,
1887                                       CArray<int, 2>& faceToFaces, CArray<int, 1>& nbNghbFaces)
1888  {
1889    int nvertex = bounds_lon.rows();
1890    int nbFaces = bounds_lon.shape()[1];
1891    int nbNodes = 0;
1892    int nbEdges = 0;
1893    nbNghbFaces.resize(nbFaces);
1894    nbNghbFaces = 0;
1895
1896    // faceToNodes connectivity
1897    CArray<double, 2> faceToNodes (nvertex, nbFaces);
1898
1899    std::unordered_map <pairDouble, int, boost::hash<pairDouble> > mapNodes;
1900
1901    for (int nf = 0; nf < nbFaces; ++nf)
1902      for (int nv = 0; nv < nvertex; ++nv)
1903      {
1904        if (mapNodes.find(make_pair (bounds_lon(nv, nf), bounds_lat(nv ,nf))) == mapNodes.end())
1905        {
1906          mapNodes[make_pair (bounds_lon(nv, nf), bounds_lat(nv, nf))] = nbNodes;
1907          faceToNodes(nv,nf) = nbNodes ;
1908          ++nbNodes ;
1909        }
1910        else
1911          faceToNodes(nv,nf) = mapNodes[make_pair (bounds_lon(nv, nf), bounds_lat(nv ,nf))];
1912      }
1913
1914    // faceToFaces connectivity
1915    std::unordered_map <pairInt, int, boost::hash<pairInt> > mapEdges;
1916    faceToFaces.resize(nvertex, nbFaces);
1917    CArray<int, 2> edgeToFaces(2, nbFaces*nvertex); // max possible
1918
1919    for (int nf = 0; nf < nbFaces; ++nf)
1920    {
1921      for (int nv1 = 0; nv1 < nvertex; ++nv1)
1922      {
1923        int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation
1924        int face = face_idx(nf);
1925        int node1 = faceToNodes(nv1,face);
1926        int node2 = faceToNodes(nv2,face);
1927        if (node1 != node2)
1928        {
1929          if (mapEdges.find(make_ordered_pair (node1, node2)) == mapEdges.end())
1930          {
1931            mapEdges[make_ordered_pair (node1, node2)] = nbEdges;
1932            edgeToFaces(0,nbEdges) = face;
1933            ++nbEdges;
1934          }
1935          else
1936          {
1937            int edge = mapEdges[make_ordered_pair (node1, node2)];
1938            edgeToFaces(1, edge) = face;
1939            int face1 = face;
1940            int face2 = edgeToFaces(0,edge);
1941            faceToFaces(nbNghbFaces(face1), face1) =  face2;
1942            faceToFaces(nbNghbFaces(face2), face2) =  face1;
1943            ++nbNghbFaces(face1);
1944            ++nbNghbFaces(face2);
1945          }
1946        } // node1 != node2
1947      } // nv
1948    } // nf
1949
1950  } //getLocNghbFacesEdgeType
1951
1952
1953} // namespace xios
Note: See TracBrowser for help on using the repository browser.