Salome HOME
bece66a6863f3782743eb9c50d45c1b35c4211ca
[modules/med.git] / src / MEDPartitioner / MEDPARTITIONER_ParallelTopology.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "MEDPARTITIONER_MeshCollection.hxx"
21 #include "MEDPARTITIONER_Topology.hxx"
22 #include "MEDPARTITIONER_Graph.hxx"
23 #include "MEDPARTITIONER_ParallelTopology.hxx"
24 #include "MEDPARTITIONER_ConnectZone.hxx"
25 #include "MEDPARTITIONER_Utils.hxx"
26
27 #include "MEDCouplingUMesh.hxx"
28 #include "InterpKernelHashMap.hxx"
29
30 #include <set>
31 #include <map>
32 #include <vector>
33 #include <iostream>
34
35 #ifdef HAVE_MPI2
36 #include <mpi.h>
37 #endif
38
39 using namespace MEDPARTITIONER;
40
41 ParallelTopology::ParallelTopology():_nb_domain(0),_mesh_dimension(0)
42 {
43 }
44
45 //constructing topology according to mesh collection without global numerotation (use setGlobalNumerotation later)
46 ParallelTopology::ParallelTopology(const std::vector<ParaMEDMEM::MEDCouplingUMesh*>& meshes)
47 {
48   _nb_domain=meshes.size();
49   _nb_cells.resize(_nb_domain);
50   _nb_nodes.resize(_nb_domain);
51   //  _nb_faces.resize(_nb_domain);
52   
53   if (MyGlobals::_Is0verbose>100)
54     std::cout << "new ParallelTopology\n";
55   _loc_to_glob.resize(0);      //precaution, need gatherNbOf() setGlobalNumerotation()
56   _node_loc_to_glob.resize(0); //precaution, need gatherNbOf() setGlobalNumerotation()
57   //_face_loc_to_glob.resize(_nb_domain);
58   _mesh_dimension = -1;
59   bool parallel_mode = false;
60   for (int idomain=0; !parallel_mode && idomain<_nb_domain; idomain++)
61     parallel_mode = (!meshes[idomain]);
62
63   if (MyGlobals::_Is0verbose>20 && !parallel_mode)
64     std::cout << "WARNING : ParallelTopology contructor without parallel_mode" << std::endl;
65   for (int idomain=0; idomain<_nb_domain; idomain++)
66     {
67       if ( !meshes[idomain] ) continue;
68       if (_mesh_dimension==-1)
69         {
70           _mesh_dimension = meshes[idomain]->getMeshDimension();
71         }
72       else
73         {
74           if (_mesh_dimension!=meshes[idomain]->getMeshDimension())
75             throw INTERP_KERNEL::Exception("meshes dimensions incompatible");
76         }
77       _nb_cells[idomain]=meshes[idomain]->getNumberOfCells();
78       _nb_nodes[idomain]=meshes[idomain]->getNumberOfNodes();
79       //note: in parallel mode _nb_cells and _nb_nodes are not complete now, needs gatherNbOf()
80     }
81 }
82
83 //constructing _loc_to_glob etc by default, needs gatherNbOf() done
84 void ParallelTopology::setGlobalNumerotationDefault(ParaDomainSelector* domainSelector)
85 {
86   if (MyGlobals::_Is0verbose>100)
87     std::cout<< "setGlobalNumerotationDefault on " << _nb_domain << " domains\n";
88   if (_loc_to_glob.size()!=0) throw INTERP_KERNEL::Exception("a global numerotation is done yet");
89   _loc_to_glob.resize(_nb_domain);
90   _node_loc_to_glob.resize(_nb_domain);
91   
92   //warning because _nb_cells[idomain] is 0 if not my domain(s)
93   //we set loc_to_glob etc.. only for my domain(s)
94   if (MyGlobals::_Is0verbose>500)
95     std::cout << "(c)idomain|ilocalCell|iglobalCell" << std::endl;
96   for (int idomain=0; idomain<_nb_domain; idomain++)
97     {
98       _loc_to_glob[idomain].resize(_nb_cells[idomain]);
99       int domainCellShift=domainSelector->getDomainCellShift(idomain);
100       for (int i=0; i<_nb_cells[idomain]; i++)
101         {
102           int global=domainCellShift+i ;
103           _glob_to_loc.insert(std::make_pair(global,std::make_pair(idomain,i)));
104           _loc_to_glob[idomain][i]=global;
105           if (MyGlobals::_Verbose>500)
106             std::cout << "c" << idomain << "|" << i << "|" << global << " ";
107         }
108     }
109 #ifdef HAVE_MPI2
110   if (MyGlobals::_Verbose>500 && MyGlobals::_World_Size>1) MPI_Barrier(MPI_COMM_WORLD); //synchronize verbose trace
111 #endif
112   if (MyGlobals::_Is0verbose>500) std::cout << std::endl;
113   
114   if (MyGlobals::_Is0verbose>500) std::cout << "(n)idomain|ilocalNode|iglobalNode" << std::endl;
115   for (int idomain=0; idomain<_nb_domain; idomain++)
116     {
117       _node_loc_to_glob[idomain].resize(_nb_nodes[idomain]);
118       int domainNodeShift=domainSelector->getDomainNodeShift(idomain);
119       for (int i=0; i<_nb_nodes[idomain]; i++)
120         {
121           int global=domainNodeShift+i ;
122           _node_glob_to_loc.insert(std::make_pair(global,std::make_pair(idomain,i)));
123           _node_loc_to_glob[idomain][i]=global;
124           if (MyGlobals::_Verbose>500)
125             std::cout << "n" << idomain << "|" << i << "|" << global << " ";
126         }
127     }
128 #ifdef HAVE_MPI2
129   if (MyGlobals::_Verbose>500 && MyGlobals::_World_Size>1) MPI_Barrier(MPI_COMM_WORLD); //synchronize verbose trace
130 #endif
131   if (MyGlobals::_Is0verbose>500) std::cout << std::endl;
132   
133   _nb_total_cells=domainSelector->getNbTotalCells();
134   _nb_total_nodes=domainSelector->getNbTotalNodes();
135   _nb_total_faces=domainSelector->getNbTotalFaces();
136   if (MyGlobals::_Is0verbose>200)
137     std::cout << "globalNumerotation default done meshDimension " << _mesh_dimension << " nbTotalCells " << _nb_total_cells << " nbTotalNodes " << _nb_total_nodes << std::endl;
138 }
139
140 //constructing topology according to mesh collection
141 ParallelTopology::ParallelTopology(const std::vector<ParaMEDMEM::MEDCouplingUMesh*>& meshes, 
142                                    const std::vector<MEDPARTITIONER::ConnectZone*>& cz,
143                                    std::vector<int*>& cellglobal,
144                                    std::vector<int*>& nodeglobal,
145                                    std::vector<int*>& faceglobal)
146 {
147   _nb_domain=meshes.size();
148   int index_global=0;
149   int index_node_global=0;
150   int index_face_global=0;
151
152   _nb_cells.resize(_nb_domain);
153   _nb_nodes.resize(_nb_domain);
154   //  _nb_faces.resize(_nb_domain);
155   
156   _loc_to_glob.resize(_nb_domain);
157   _node_loc_to_glob.resize(_nb_domain);
158   //  _face_loc_to_glob.resize(_nb_domain);
159
160   bool parallel_mode = false;
161   for (int idomain=0; !parallel_mode && idomain<_nb_domain; idomain++)
162     parallel_mode = (!meshes[idomain]);
163
164   for (int idomain=0; idomain<_nb_domain; idomain++)
165     {
166       if ( !meshes[idomain] ) continue;
167       _mesh_dimension = meshes[idomain]->getMeshDimension();
168     
169       //creating cell maps
170       _nb_cells[idomain]=meshes[idomain]->getNumberOfCells();
171       //    cout << "Nb cells (domain "<<idomain<<") = "<<_nb_cells[idomain];
172       _loc_to_glob[idomain].resize(_nb_cells[idomain]);
173
174       if (cellglobal[idomain]==0 || parallel_mode)
175         {
176           //int cellDomainShift=_cell_shift_by_domain[idomain];
177           //creating global numbering from scratch
178           for (int i=0; i<_nb_cells[idomain]; i++)
179             {
180               int global=i ;//cellDomainShift+i;
181               _glob_to_loc.insert(std::make_pair(global,std::make_pair(idomain,i)));
182               _loc_to_glob[idomain][i]=global;
183               index_global++;
184             }
185         }
186       //using global numbering coming from a previous numbering
187       else
188         {
189           for (int i=0; i<_nb_cells[idomain]; i++)
190             {
191               int global=cellglobal[idomain][i];
192               _glob_to_loc.insert(std::make_pair(global,std::make_pair(idomain,i)));
193               //_loc_to_glob[make_pair(idomain,i+1)]=global;
194               _loc_to_glob[idomain][i]=global;
195               index_global++;
196             }
197         }
198
199       //cas sequentiel
200       if (_nb_domain==1)
201         {
202           _nb_total_cells=index_global;
203           _nb_cells[0]=index_global;
204           _node_loc_to_glob[idomain].resize(meshes[idomain]->getNumberOfNodes());
205           for (int i=0; i<meshes[idomain]->getNumberOfNodes(); i++)
206             {
207               _node_glob_to_loc.insert(std::make_pair(i,std::make_pair(0,i)));
208               _node_loc_to_glob[0][i]=i;
209             }
210           _nb_total_nodes=meshes[idomain]->getNumberOfNodes();   
211           _nb_nodes[0]=_nb_total_nodes; 
212           return;
213         }
214
215       //creating node maps
216       _nb_nodes[idomain]=meshes[idomain]->getNumberOfNodes();
217       INTERP_KERNEL::HashMap <int,std::pair<int,int> > local2distant;
218       _node_loc_to_glob[idomain].resize(_nb_nodes[idomain]);
219       for (std::size_t icz=0; icz<cz.size(); icz++)
220         {
221           if (cz[icz]->getLocalDomainNumber() == idomain && 
222               cz[icz]->getLocalDomainNumber()>cz[icz]->getDistantDomainNumber())
223             {
224               int nb_node= cz[icz]->getNodeNumber();
225               const int* node_corresp=cz[icz]->getNodeCorrespValue();
226               int distant_ip = cz[icz]->getDistantDomainNumber();
227               for (int i=0; i< nb_node; i++)
228                 {
229                   int local= node_corresp[i*2];
230                   int distant = node_corresp[i*2+1];
231                   local2distant.insert(std::make_pair(local, std::make_pair(distant_ip,distant)));    
232                 }
233             }
234         }
235       // setting mappings for all nodes
236       if (nodeglobal[idomain]==0)
237         {
238           for (int inode=0; inode<_nb_nodes[idomain]; inode++)
239             {
240               if (local2distant.find(inode)==local2distant.end())
241                 {
242                   index_node_global++;
243                   _node_glob_to_loc.insert(std::make_pair(index_node_global,std::make_pair(idomain,inode)));
244                   //_node_loc_to_glob[make_pair(idomain,inode+1)]=index_node_global;
245                   _node_loc_to_glob[idomain][inode]=index_node_global;
246                 }   
247               else
248                 {
249                   int ip = (local2distant.find(inode)->second).first;
250                   int distant = (local2distant.find(inode)->second).second;
251                   int global_number=_loc_to_glob[ip][distant];
252                   _node_glob_to_loc.insert(std::make_pair(global_number,std::make_pair(idomain,inode)));
253                   _node_loc_to_glob[idomain][inode]=global_number;
254                 } 
255             }
256         }
257       //using former node numbering
258       else
259         {
260           for (int inode=0; inode<_nb_nodes[idomain]; inode++)
261             {
262               int global_number=nodeglobal[idomain][inode];
263               _node_glob_to_loc.insert(std::make_pair(global_number,std::make_pair(idomain,inode)));
264               _node_loc_to_glob[idomain][inode]=global_number;
265             }
266         }
267     }
268
269   _nb_total_cells=index_global;
270   _nb_total_nodes=index_node_global;   
271   _nb_total_faces=index_face_global;
272 }
273
274
275 //constructing ParallelTopology from an old topology and a graph
276 ParallelTopology::ParallelTopology(Graph* graph, Topology* oldTopology, int nb_domain, int mesh_dimension)
277 {
278
279   _nb_domain=nb_domain;
280   _mesh_dimension=mesh_dimension;
281   
282   if (MyGlobals::_Verbose>200)
283     std::cout << "proc " << MyGlobals::_Rank << " : new topology oldNbDomain " <<
284       oldTopology->nbDomain() << " newNbDomain " << _nb_domain << std::endl;
285   _nb_cells.resize(_nb_domain,0);
286   _nb_nodes.resize(_nb_domain,0);
287   _nb_faces.resize(_nb_domain,0);
288
289   _loc_to_glob.resize(_nb_domain);
290   _node_loc_to_glob.resize(_nb_domain);
291   _face_loc_to_glob.resize(_nb_domain);
292   
293   const int* part=graph->getPart(); //all cells for this proc (may be more domains)
294   _nb_total_cells=graph->nbVertices(); //all cells for this proc (may be more domains)
295   if (MyGlobals::_Verbose>300)
296     std::cout << "proc " << MyGlobals::_Rank << " : topology from partition, nbTotalCells " << _nb_total_cells << std::endl;
297   
298   int icellProc=0; //all cells of my domains are concatenated in part
299   for (int iold=0; iold<oldTopology->nbDomain(); iold++)
300     {
301       int ioldNbCell=oldTopology->getCellNumber(iold);
302       //std::cout<<"proc "<<MyGlobals::_Rank<<" : cell number old domain "<<iold<<" : "<<ioldNbCell<<std::endl;
303       //if not my old domains getCellNumber is 0
304       std::vector<int> globalids(ioldNbCell);
305       oldTopology->getCellList(iold, &globalids[0]); //unique global numerotation
306       for (int icell=0; icell<ioldNbCell; icell++)
307         {
308           int idomain=part[icellProc];
309           _nb_cells[idomain]++;
310           icellProc++;
311           int iGlobalCell=globalids[icell];
312           _loc_to_glob[idomain].push_back(iGlobalCell);
313           _glob_to_loc.insert(std::make_pair(iGlobalCell, std::make_pair(idomain, _nb_cells[idomain])));
314         }
315     }
316
317   if (MyGlobals::_Verbose>300)
318     for (int idomain=0; idomain<_nb_domain; idomain++)
319       std::cout << "proc " << MyGlobals::_Rank << " : nbCells in new domain " << idomain << " : " << _nb_cells[idomain] << std::endl; 
320 }
321
322 ParallelTopology::~ParallelTopology()
323 {
324
325
326 /*!Converts a list of global node numbers
327  * to a distributed array with local cell numbers.
328  * 
329  * If a node in the list is represented on several domains,
330  * only the first value is returned
331  * */
332 void ParallelTopology::convertGlobalNodeList(const int* node_list, int nbnode, int* local, int* ip)
333 {
334   if (_node_glob_to_loc.empty()) 
335     throw INTERP_KERNEL::Exception("Node mapping has not yet been built");
336   for (int i=0; i< nbnode; i++)
337     {
338       std::pair<int,int> local_node = _node_glob_to_loc.find(node_list[i])->second;
339       ip[i]=local_node.first;
340       local[i]=local_node.second;
341     }
342 }
343
344 /*!Converts a list of global node numbers on domain ip
345  * to a distributed array with local cell numbers.
346  * 
347  * If a node in the list is represented on several domains,
348  * only the value with domain ip is returned
349  * 
350  * */
351 void ParallelTopology::convertGlobalNodeList(const int* node_list, int nbnode, int* local, int ip)
352 {
353   if (_node_glob_to_loc.empty()) 
354     throw INTERP_KERNEL::Exception("Node mapping has not yet been built");
355
356   for (int i=0; i< nbnode; i++)
357     {
358       typedef INTERP_KERNEL::HashMultiMap<int,std::pair<int,int> >::iterator mmiter;
359       std::pair<mmiter,mmiter> range=_node_glob_to_loc.equal_range(node_list[i]);
360       for (mmiter it=range.first; it !=range.second; it++)
361         { 
362           int ipfound=(it->second).first;
363           if (ipfound==ip)
364             local[i]=(it->second).second;
365         }
366     }
367
368
369 /*!Converts a list of global node numbers
370  * to a distributed array with local cell numbers.
371  * 
372  * If a node in the list is represented on several domains,
373  * all the values are put in the array
374  * */
375 void ParallelTopology::convertGlobalNodeListWithTwins(const int* node_list, int nbnode, int*& local, int*& ip,int*& full_array, int& size)
376 {
377   if (_node_glob_to_loc.empty()) 
378     throw INTERP_KERNEL::Exception("Node mapping has not yet been built");
379
380   size=0;
381   for (int i=0; i< nbnode; i++)
382     {
383       int count= _node_glob_to_loc.count(node_list[i]);
384       size+=count;
385     }
386   int index=0;
387   ip=new int[size];
388   local=new int[size];
389   full_array=new int[size];
390   for (int i=0; i< nbnode; i++)
391     {
392       typedef INTERP_KERNEL::HashMultiMap<int,std::pair<int,int> >::iterator mmiter;
393       std::pair<mmiter,mmiter> range=_node_glob_to_loc.equal_range(node_list[i]);
394       for (mmiter it=range.first; it !=range.second; it++)
395         { 
396           ip[index]=(it->second).first;
397           local[index]=(it->second).second;
398           full_array [index]=node_list[i];
399           index++;
400         }
401
402     }
403 }
404
405 /*!Converts a list of global face numbers
406  * to a distributed array with local face numbers.
407  * 
408  * If a face in the list is represented on several domains,
409  * all the values are put in the array
410  * */
411 void ParallelTopology::convertGlobalFaceListWithTwins(const int* face_list, int nbface, int*& local, int*& ip, int*& full_array,int& size)
412 {
413   size=0;
414   for (int i=0; i< nbface; i++)
415     {
416       //int count = _face_glob_to_loc.count(face_list[i]);
417       //if (count >1) MESSAGE_MED("face en doublon "<<face_list[i]);
418       size+= _face_glob_to_loc.count(face_list[i]);
419     }
420   int index=0;
421   ip=new int[size];
422   local=new int[size];
423   full_array=new int[size];
424   for (int i=0; i< nbface; i++)
425     {
426       typedef INTERP_KERNEL::HashMultiMap<int,std::pair<int,int> >::iterator mmiter;
427       std::pair<mmiter,mmiter> range=_face_glob_to_loc.equal_range(face_list[i]);
428       for (mmiter it=range.first; it !=range.second; it++)
429         { 
430           ip[index]=(it->second).first;
431           local[index]=(it->second).second;
432           full_array[index]=face_list[i];
433           index++;
434         }
435
436     }
437 }
438
439 //!converts a list of global cell numbers
440 //!to a distributed array with local cell numbers 
441 void ParallelTopology::convertGlobalCellList(const int* cell_list, int nbcell, int* local, int* ip)
442 {
443   for (int i=0; i<nbcell; i++)
444     {
445       INTERP_KERNEL::HashMap<int, std::pair<int,int> >::const_iterator iter = _glob_to_loc.find(cell_list[i]);
446       if (iter == _glob_to_loc.end())
447         {
448           std::cerr << "proc " << MyGlobals::_Rank << " : KO cell_list[" << i << "] : " << cell_list[i] << std::endl;
449           throw INTERP_KERNEL::Exception("ParallelTopology::convertGlobalCellList : Cell not found");
450         }
451       else
452         {
453           ip[i]=(iter->second).first;     //no domain
454           local[i]=(iter->second).second; //no local cell
455         }
456     }
457 }
458
459 /*!Converts a list of global face numbers
460  * to a distributed array with local face numbers
461  */ 
462 void ParallelTopology::convertGlobalFaceList(const int* face_list, int nbface, int* local, int* ip)
463 {
464   for (int i=0; i< nbface; i++)
465     {
466       INTERP_KERNEL::HashMap<int, std::pair<int,int> >::const_iterator iter = _face_glob_to_loc.find(face_list[i]);
467       if (iter == _face_glob_to_loc.end())
468         {
469           throw INTERP_KERNEL::Exception("ParallelTopology::convertGlobalFaceList : Face not found");
470         }
471       ip[i]=(iter->second).first;
472       local[i]=(iter->second).second;
473     }
474 }
475
476 /*!Converts a list of global node numbers on domain ip
477  * to a distributed array with local cell numbers.
478  * 
479  * If a node in the list is represented on several domains,
480  * only the value with domain ip is returned
481  * 
482  */
483 void ParallelTopology::convertGlobalFaceList(const int* face_list, int nbface, int* local, int ip)
484 {
485   for (int i=0; i< nbface; i++)
486     {
487       typedef INTERP_KERNEL::HashMultiMap<int,std::pair<int,int> >::iterator mmiter;
488       std::pair<mmiter,mmiter> range=_face_glob_to_loc.equal_range(face_list[i]);
489       for (mmiter it=range.first; it !=range.second; it++)
490         { 
491           int ipfound=(it->second).first;
492           if (ipfound==ip)
493             local[i]=(it->second).second; 
494
495         }
496     }
497
498
499 //replacing a table of global numbering with a table with local numberings
500 // type_connectivity contains global connectivity for each type in input
501 // type_connectivity contains local connectivity for each type in output
502 void ParallelTopology::convertToLocal2ndVersion(int* nodes, int nbnodes, int idomain)
503 {
504   for (int inode=0; inode<nbnodes; inode++)
505     {
506       //      cout <<" inode :"<<inode<< " global = "<<type_connectivity[type][inode];
507       int global = nodes[inode];
508       typedef INTERP_KERNEL::HashMultiMap<int,std::pair<int,int> >::iterator mmiter;
509       std::pair<mmiter,mmiter> range=_node_glob_to_loc.equal_range(global);
510       for (mmiter it=range.first; it !=range.second; it++)
511         {
512           if ((it->second).first==idomain)
513             nodes[inode]=(it->second).second;
514         }
515     }
516 }
517
518 /*!
519  * \brief Return max global face number
520  */
521 int ParallelTopology::getMaxGlobalFace() const
522 {
523   int max = 0;
524   TGlob2LocsMap::const_iterator g_l_l = _face_glob_to_loc.begin();
525   for ( ; g_l_l != _face_glob_to_loc.end(); ++g_l_l )
526     if ( g_l_l->first > max )
527       max = g_l_l->first;
528   return max;
529 }
530
531 int ParallelTopology::getNodeNumber() const
532 {
533   if (_node_glob_to_loc.empty()) return 0;
534   std::set <int> keys;
535   for (INTERP_KERNEL::HashMultiMap<int, std::pair<int,int> >::const_iterator iter= _node_glob_to_loc.begin(); iter!=_node_glob_to_loc.end(); iter++)
536     {
537       keys.insert(iter->first);
538     }
539   return keys.size();
540 }
541
542 /*!
543  * retrieving list of nodes in global numbers
544  */
545 void ParallelTopology::getNodeList(int idomain, int *list) const
546 {
547   for (int i=0; i<_nb_nodes[idomain]; i++) 
548     list[i]=_node_loc_to_glob[idomain][i];
549 }
550
551 /*!
552  * retrieving list of nodes in global numbers
553  */
554 void ParallelTopology::getCellList(int idomain, int *list) const
555 {
556   for (int i=0; i<_nb_cells[idomain];i++)
557     list[i]=_loc_to_glob[idomain][i];
558 }
559
560 int ParallelTopology::getFaceNumber() const
561 {
562   if (_face_glob_to_loc.empty())
563     return 0;
564   std::set <int> keys;
565   for (INTERP_KERNEL::HashMultiMap<int, std::pair<int,int> >::const_iterator iter= _face_glob_to_loc.begin(); iter!=_face_glob_to_loc.end(); iter++)
566     {
567       keys.insert(iter->first);
568     }
569   return keys.size();
570 }
571
572 /*!
573  * retrieving list of faces in global numbers
574  */
575 void ParallelTopology::getFaceList(int idomain, int *list) const
576 {
577   for (int i=0; i<_nb_faces[idomain];i++)   
578     list[i]=_face_loc_to_glob[idomain][i];
579 }
580
581 int ParallelTopology::convertGlobalFace(int iglobal, int idomain)
582 {
583   typedef INTERP_KERNEL::HashMultiMap<int, std::pair<int,int> >::const_iterator MMiter;
584   std::pair<MMiter,MMiter> eq = _face_glob_to_loc.equal_range(iglobal);
585   for (MMiter it=eq.first; it != eq.second; it++) 
586     if (it->second.first == idomain)
587       return it->second.second;   
588   return -1;
589 }
590
591 int ParallelTopology::convertGlobalNode(int iglobal, int idomain)
592 {
593   typedef INTERP_KERNEL::HashMultiMap<int, std::pair<int,int> >::const_iterator MMiter;
594   std::pair<MMiter,MMiter> eq = _node_glob_to_loc.equal_range(iglobal);
595   for (MMiter it=eq.first; it != eq.second; it++)
596     {
597       if (it->second.first == idomain)
598         return it->second.second;
599     }
600   return -1;
601 }
602
603 /*!
604  * adding a face to the topology
605  */
606 void ParallelTopology::appendFace(int idomain, int ilocal, int iglobal)
607 {
608   _face_loc_to_glob[idomain].push_back(iglobal);
609   _face_glob_to_loc.insert(std::make_pair(iglobal,std::make_pair(idomain,ilocal)));
610 }