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