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