Salome HOME
0022875: EDF 7690 MED: Creating joints with medpartitioner in the MEDCoupling API
[tools/medcoupling.git] / src / MEDPartitioner / MEDPARTITIONER_ParallelTopology.cxx
1 // Copyright (C) 2007-2015  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, or (at your option) any later version.
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_MPI
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_MPI
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_MPI
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   // JOINTs
322
323   if ( MyGlobals::_Create_Joints && nb_domain > 1 )
324     {
325       std::vector< std::vector< std::vector< int > > > cellCorresp( nb_domain );
326       for ( int idomain = 0; idomain < nb_domain; ++idomain )
327         {
328           cellCorresp[ idomain ].resize( nb_domain );
329         }
330       const ParaMEDMEM::MEDCouplingSkyLineArray* skylinegraph = graph->getGraph();
331       const int*  index = skylinegraph->getIndex();
332       const int*  value = skylinegraph->getValue();
333       const int nbCells = skylinegraph->getNumberOf();
334
335       for ( int iGlob = 0; iGlob < nbCells; ++iGlob )
336         {
337           int iGlobDom = part[ iGlob ];
338           for ( int i = index[ iGlob ]; i < index[ iGlob+1 ]; i++ )
339             {
340               int iGlobNear = value[ i ];
341               if ( iGlob > iGlobNear )
342                 continue; // treat ( iGlob, iGlobNear ) pair once
343               int iGlobNearDom = part[ iGlobNear ];
344               if ( iGlobDom != iGlobNearDom )
345                 {
346                   int iLoc     = convertGlobalCell( iGlob ).second     - 1; // to MEDCoupling fmt
347                   int iLocNear = convertGlobalCell( iGlobNear ).second - 1;
348                   cellCorresp[ iGlobDom ][ iGlobNearDom ].push_back( iLoc );
349                   cellCorresp[ iGlobDom ][ iGlobNearDom ].push_back( iLocNear );
350                   cellCorresp[ iGlobNearDom ][ iGlobDom ].push_back( iLocNear );
351                   cellCorresp[ iGlobNearDom ][ iGlobDom ].push_back( iLoc );
352                 }
353             }
354         }
355       for ( int idomain = 0; idomain < nb_domain; ++idomain )
356         {
357           for ( int idomainNear = 0; idomainNear < nb_domain; ++idomainNear )
358             {
359               std::vector< int > & corresp = cellCorresp[ idomain ][ idomainNear ];
360               if ( corresp.empty() )
361                 continue;
362               MEDPARTITIONER::ConnectZone* cz = new MEDPARTITIONER::ConnectZone();
363               cz->setName( "Connect Zone defined by MEDPARTITIONER" );
364               cz->setDistantDomainNumber( idomainNear );
365               cz->setLocalDomainNumber  ( idomain );
366               cz->setEntityCorresp( 0,0, &corresp[0], corresp.size()/2 );
367               _connect_zones.push_back( cz );
368             }
369         }
370     }
371 }
372
373 ParallelTopology::~ParallelTopology()
374 {
375   for ( size_t i = 0; i < _connect_zones.size(); ++i )
376     {
377       delete _connect_zones[i];
378       _connect_zones[i] = 0;
379     }
380   _connect_zones.clear();
381 }
382
383 /*!Converts a list of global node numbers
384  * to a distributed array with local cell numbers.
385  *
386  * If a node in the list is represented on several domains,
387  * only the first value is returned
388  * */
389 void ParallelTopology::convertGlobalNodeList(const int* node_list, int nbnode, int* local, int* ip)
390 {
391   if (_node_glob_to_loc.empty())
392     throw INTERP_KERNEL::Exception("Node mapping has not yet been built");
393   for (int i=0; i< nbnode; i++)
394     {
395       std::pair<int,int> local_node = _node_glob_to_loc.find(node_list[i])->second;
396       ip[i]=local_node.first;
397       local[i]=local_node.second;
398     }
399 }
400
401 /*!Converts a list of global node numbers on domain ip
402  * to a distributed array with local cell numbers.
403  * 
404  * If a node in the list is represented on several domains,
405  * only the value with domain ip is returned
406  * 
407  * */
408 void ParallelTopology::convertGlobalNodeList(const int* node_list, int nbnode, int* local, int ip)
409 {
410   if (_node_glob_to_loc.empty()) 
411     throw INTERP_KERNEL::Exception("Node mapping has not yet been built");
412
413   for (int i=0; i< nbnode; i++)
414     {
415       typedef INTERP_KERNEL::HashMultiMap<int,std::pair<int,int> >::iterator mmiter;
416       std::pair<mmiter,mmiter> range=_node_glob_to_loc.equal_range(node_list[i]);
417       for (mmiter it=range.first; it !=range.second; it++)
418         { 
419           int ipfound=(it->second).first;
420           if (ipfound==ip)
421             local[i]=(it->second).second;
422         }
423     }
424
425
426 /*!Converts a list of global node numbers
427  * to a distributed array with local cell numbers.
428  * 
429  * If a node in the list is represented on several domains,
430  * all the values are put in the array
431  * */
432 void ParallelTopology::convertGlobalNodeListWithTwins(const int* node_list, int nbnode, int*& local, int*& ip,int*& full_array, int& size)
433 {
434   if (_node_glob_to_loc.empty()) 
435     throw INTERP_KERNEL::Exception("Node mapping has not yet been built");
436
437   size=0;
438   for (int i=0; i< nbnode; i++)
439     {
440       int count= _node_glob_to_loc.count(node_list[i]);
441       size+=count;
442     }
443   int index=0;
444   ip=new int[size];
445   local=new int[size];
446   full_array=new int[size];
447   for (int i=0; i< nbnode; i++)
448     {
449       typedef INTERP_KERNEL::HashMultiMap<int,std::pair<int,int> >::iterator mmiter;
450       std::pair<mmiter,mmiter> range=_node_glob_to_loc.equal_range(node_list[i]);
451       for (mmiter it=range.first; it !=range.second; it++)
452         { 
453           ip[index]=(it->second).first;
454           local[index]=(it->second).second;
455           full_array [index]=node_list[i];
456           index++;
457         }
458
459     }
460 }
461
462 /*!Converts a list of global face numbers
463  * to a distributed array with local face numbers.
464  * 
465  * If a face in the list is represented on several domains,
466  * all the values are put in the array
467  * */
468 void ParallelTopology::convertGlobalFaceListWithTwins(const int* face_list, int nbface, int*& local, int*& ip, int*& full_array,int& size)
469 {
470   size=0;
471   for (int i=0; i< nbface; i++)
472     {
473       //int count = _face_glob_to_loc.count(face_list[i]);
474       //if (count >1) MESSAGE_MED("face en doublon "<<face_list[i]);
475       size+= _face_glob_to_loc.count(face_list[i]);
476     }
477   int index=0;
478   ip=new int[size];
479   local=new int[size];
480   full_array=new int[size];
481   for (int i=0; i< nbface; i++)
482     {
483       typedef INTERP_KERNEL::HashMultiMap<int,std::pair<int,int> >::iterator mmiter;
484       std::pair<mmiter,mmiter> range=_face_glob_to_loc.equal_range(face_list[i]);
485       for (mmiter it=range.first; it !=range.second; it++)
486         { 
487           ip[index]=(it->second).first;
488           local[index]=(it->second).second;
489           full_array[index]=face_list[i];
490           index++;
491         }
492
493     }
494 }
495
496 //!converts a list of global cell numbers
497 //!to a distributed array with local cell numbers 
498 void ParallelTopology::convertGlobalCellList(const int* cell_list, int nbcell, int* local, int* ip)
499 {
500   for (int i=0; i<nbcell; i++)
501     {
502       INTERP_KERNEL::HashMap<int, std::pair<int,int> >::const_iterator iter = _glob_to_loc.find(cell_list[i]);
503       if (iter == _glob_to_loc.end())
504         {
505           std::cerr << "proc " << MyGlobals::_Rank << " : KO cell_list[" << i << "] : " << cell_list[i] << std::endl;
506           throw INTERP_KERNEL::Exception("ParallelTopology::convertGlobalCellList : Cell not found");
507         }
508       else
509         {
510           ip[i]=(iter->second).first;     //no domain
511           local[i]=(iter->second).second; //no local cell
512         }
513     }
514 }
515
516 /*!Converts a list of global face numbers
517  * to a distributed array with local face numbers
518  */ 
519 void ParallelTopology::convertGlobalFaceList(const int* face_list, int nbface, int* local, int* ip)
520 {
521   for (int i=0; i< nbface; i++)
522     {
523       INTERP_KERNEL::HashMap<int, std::pair<int,int> >::const_iterator iter = _face_glob_to_loc.find(face_list[i]);
524       if (iter == _face_glob_to_loc.end())
525         {
526           throw INTERP_KERNEL::Exception("ParallelTopology::convertGlobalFaceList : Face not found");
527         }
528       ip[i]=(iter->second).first;
529       local[i]=(iter->second).second;
530     }
531 }
532
533 /*!Converts a list of global node numbers on domain ip
534  * to a distributed array with local cell numbers.
535  * 
536  * If a node in the list is represented on several domains,
537  * only the value with domain ip is returned
538  * 
539  */
540 void ParallelTopology::convertGlobalFaceList(const int* face_list, int nbface, int* local, int ip)
541 {
542   for (int i=0; i< nbface; i++)
543     {
544       typedef INTERP_KERNEL::HashMultiMap<int,std::pair<int,int> >::iterator mmiter;
545       std::pair<mmiter,mmiter> range=_face_glob_to_loc.equal_range(face_list[i]);
546       for (mmiter it=range.first; it !=range.second; it++)
547         { 
548           int ipfound=(it->second).first;
549           if (ipfound==ip)
550             local[i]=(it->second).second; 
551
552         }
553     }
554
555
556 //replacing a table of global numbering with a table with local numberings
557 // type_connectivity contains global connectivity for each type in input
558 // type_connectivity contains local connectivity for each type in output
559 void ParallelTopology::convertToLocal2ndVersion(int* nodes, int nbnodes, int idomain)
560 {
561   for (int inode=0; inode<nbnodes; inode++)
562     {
563       //      cout <<" inode :"<<inode<< " global = "<<type_connectivity[type][inode];
564       int global = nodes[inode];
565       typedef INTERP_KERNEL::HashMultiMap<int,std::pair<int,int> >::iterator mmiter;
566       std::pair<mmiter,mmiter> range=_node_glob_to_loc.equal_range(global);
567       for (mmiter it=range.first; it !=range.second; it++)
568         {
569           if ((it->second).first==idomain)
570             nodes[inode]=(it->second).second;
571         }
572     }
573 }
574
575 /*!
576  * \brief Return max global face number
577  */
578 int ParallelTopology::getMaxGlobalFace() const
579 {
580   int max = 0;
581   TGlob2LocsMap::const_iterator g_l_l = _face_glob_to_loc.begin();
582   for ( ; g_l_l != _face_glob_to_loc.end(); ++g_l_l )
583     if ( g_l_l->first > max )
584       max = g_l_l->first;
585   return max;
586 }
587
588 int ParallelTopology::getNodeNumber() const
589 {
590   if (_node_glob_to_loc.empty()) return 0;
591   std::set <int> keys;
592   for (INTERP_KERNEL::HashMultiMap<int, std::pair<int,int> >::const_iterator iter= _node_glob_to_loc.begin(); iter!=_node_glob_to_loc.end(); iter++)
593     {
594       keys.insert(iter->first);
595     }
596   return keys.size();
597 }
598
599 /*!
600  * retrieving list of nodes in global numbers
601  */
602 void ParallelTopology::getNodeList(int idomain, int *list) const
603 {
604   for (int i=0; i<_nb_nodes[idomain]; i++) 
605     list[i]=_node_loc_to_glob[idomain][i];
606 }
607
608 /*!
609  * retrieving list of nodes in global numbers
610  */
611 void ParallelTopology::getCellList(int idomain, int *list) const
612 {
613   for (int i=0; i<_nb_cells[idomain];i++)
614     list[i]=_loc_to_glob[idomain][i];
615 }
616
617 int ParallelTopology::getFaceNumber() const
618 {
619   if (_face_glob_to_loc.empty())
620     return 0;
621   std::set <int> keys;
622   for (INTERP_KERNEL::HashMultiMap<int, std::pair<int,int> >::const_iterator iter= _face_glob_to_loc.begin(); iter!=_face_glob_to_loc.end(); iter++)
623     {
624       keys.insert(iter->first);
625     }
626   return keys.size();
627 }
628
629 /*!
630  * retrieving list of faces in global numbers
631  */
632 void ParallelTopology::getFaceList(int idomain, int *list) const
633 {
634   for (int i=0; i<_nb_faces[idomain];i++)   
635     list[i]=_face_loc_to_glob[idomain][i];
636 }
637
638 int ParallelTopology::convertGlobalFace(int iglobal, int idomain)
639 {
640   typedef INTERP_KERNEL::HashMultiMap<int, std::pair<int,int> >::const_iterator MMiter;
641   std::pair<MMiter,MMiter> eq = _face_glob_to_loc.equal_range(iglobal);
642   for (MMiter it=eq.first; it != eq.second; it++) 
643     if (it->second.first == idomain)
644       return it->second.second;   
645   return -1;
646 }
647
648 int ParallelTopology::convertGlobalNode(int iglobal, int idomain)
649 {
650   typedef INTERP_KERNEL::HashMultiMap<int, std::pair<int,int> >::const_iterator MMiter;
651   std::pair<MMiter,MMiter> eq = _node_glob_to_loc.equal_range(iglobal);
652   for (MMiter it=eq.first; it != eq.second; it++)
653     {
654       if (it->second.first == idomain)
655         return it->second.second;
656     }
657   return -1;
658 }
659
660 std::vector<MEDPARTITIONER::ConnectZone*>& ParallelTopology::getCZ()
661 {
662   return _connect_zones;
663 }
664
665 /*!
666  * adding a face to the topology
667  */
668 void ParallelTopology::appendFace(int idomain, int ilocal, int iglobal)
669 {
670   _face_loc_to_glob[idomain].push_back(iglobal);
671   _face_glob_to_loc.insert(std::make_pair(iglobal,std::make_pair(idomain,ilocal)));
672 }