Salome HOME
e6beacf192a2575f0d9b1a9433598a912e0943e6
[modules/med.git] / src / MEDPartitioner / MEDPARTITIONER_ParaDomainSelector.cxx
1 // Copyright (C) 2007-2014  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_ParaDomainSelector.hxx"
21 #include "MEDPARTITIONER_UserGraph.hxx"
22 #include "MEDPARTITIONER_Utils.hxx"
23
24 #include "MEDCouplingUMesh.hxx"
25
26 #include <iostream>
27 #include <numeric>
28
29 #ifdef HAVE_MPI2
30 #include <mpi.h>
31 #endif
32
33 /*!
34  * \brief Constructor. Find out my rank and world size
35  */
36 MEDPARTITIONER::ParaDomainSelector::ParaDomainSelector(bool mesure_memory)
37   :_rank(0),_world_size(1), _nb_result_domains(-1), _init_time(0.0),
38    _mesure_memory(mesure_memory), _init_memory(0), _max_memory(0)
39 {
40 #ifdef HAVE_MPI2
41   if (MyGlobals::_Rank==-1)
42     {
43       MPI_Init(0,0);  //do once only
44       MPI_Comm_size(MPI_COMM_WORLD,&_world_size) ;
45       MPI_Comm_rank(MPI_COMM_WORLD,&_rank) ;
46     }
47   else
48     {
49       _world_size=MyGlobals::_World_Size;
50       _rank=MyGlobals::_Rank;
51     }
52   _init_time = MPI_Wtime();
53 #else
54   //sequential : no MPI
55   _world_size=1;
56   _rank=0;
57   if (MyGlobals::_Verbose>10)
58     std::cout << "WARNING : ParaDomainSelector contructor without parallel_mode World_Size=1 by default" << std::endl;
59 #endif
60   MyGlobals::_World_Size=_world_size;
61   MyGlobals::_Rank=_rank;
62   
63   if (MyGlobals::_Verbose>200) std::cout << "proc " << MyGlobals::_Rank << " of " << MyGlobals::_World_Size << std::endl;
64   evaluateMemory();
65 }
66
67 MEDPARTITIONER::ParaDomainSelector::~ParaDomainSelector()
68 {
69 }
70
71 /*!
72  * \brief Return true if is running on different hosts
73  */
74 bool MEDPARTITIONER::ParaDomainSelector::isOnDifferentHosts() const
75 {
76   evaluateMemory();
77   if ( _world_size < 2 ) return false;
78
79 #ifdef HAVE_MPI2
80   char name_here[ MPI_MAX_PROCESSOR_NAME+1 ], name_there[ MPI_MAX_PROCESSOR_NAME+1 ];
81   int size;
82   MPI_Get_processor_name( name_here, &size);
83
84   int next_proc = (rank() + 1) % nbProcs();
85   int prev_proc = (rank() - 1 + nbProcs()) % nbProcs();
86   int tag  = 1111111;
87
88   MPI_Status status;
89   MPI_Sendrecv((void*)&name_here[0],  MPI_MAX_PROCESSOR_NAME, MPI_CHAR, next_proc, tag,
90                (void*)&name_there[0], MPI_MAX_PROCESSOR_NAME, MPI_CHAR, prev_proc, tag,
91                MPI_COMM_WORLD, &status);
92                
93   //bug: (isOnDifferentHosts here and there) is not (isOnDifferentHosts somewhere)
94   //return string(name_here) != string(name_there);
95   
96   int sum_same = -1;
97   int same = 1;
98   if (std::string(name_here) != std::string(name_there))
99     same=0;
100   MPI_Allreduce( &same, &sum_same, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD );
101   return (sum_same != nbProcs());
102 #endif
103   return false;
104 }
105
106 /*!
107  * \brief Return true if the domain with domainIndex is to be loaded on this proc
108  *  \param domainIndex - index of mesh domain
109  *  \retval bool - to load or not
110  */
111 bool MEDPARTITIONER::ParaDomainSelector::isMyDomain(int domainIndex) const
112 {
113   evaluateMemory();
114   return (_rank == getProcessorID( domainIndex ));
115 }
116
117 /*!
118  * \brief Return processor id where the domain with domainIndex resides
119  *  \param domainIndex - index of mesh domain
120  *  \retval int - processor id
121  */
122 int MEDPARTITIONER::ParaDomainSelector::getProcessorID(int domainIndex) const
123 {
124   evaluateMemory();
125   return ( domainIndex % _world_size );
126 }
127
128 /*!
129  * \brief Gather info on nb of cell entities on each processor and return total nb.
130  *
131  * Is called
132  * 1) for MED_CELL to know global id shift for domains at graph construction;
133  * 2) for sub-entity to know total nb of sub-entities before creating those of joints
134  */
135 void MEDPARTITIONER::ParaDomainSelector::gatherNbOf(const std::vector<ParaMEDMEM::MEDCouplingUMesh*>& domain_meshes)
136 {
137   evaluateMemory();
138   // get nb of elems of each domain mesh
139   int nb_domains=domain_meshes.size();
140   std::vector<int> nb_elems(nb_domains*2, 0); //NumberOfCells & NumberOfNodes
141   for (int i=0; i<nb_domains; ++i)
142     if ( domain_meshes[i] )
143       {
144         nb_elems[i*2] = domain_meshes[i]->getNumberOfCells();
145         nb_elems[i*2+1] = domain_meshes[i]->getNumberOfNodes();
146       }
147   // receive nb of elems from other procs
148   std::vector<int> all_nb_elems;
149   if (MyGlobals::_World_Size==1)
150     {
151       all_nb_elems=nb_elems;
152     }
153   else
154     {
155 #ifdef HAVE_MPI2
156       all_nb_elems.resize( nb_domains*2 );
157       MPI_Allreduce((void*)&nb_elems[0], (void*)&all_nb_elems[0], nb_domains*2, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
158 #else
159       throw INTERP_KERNEL::Exception("not(HAVE_MPI2) incompatible with MPI_World_Size>1");
160 #endif
161    }
162   int total_nb_cells=0, total_nb_nodes=0;
163   for (int i=0; i<nb_domains; ++i)
164     {
165       total_nb_cells+=all_nb_elems[i*2];
166       total_nb_nodes+=all_nb_elems[i*2+1];
167     }
168   
169   if (MyGlobals::_Is0verbose>10)
170     std::cout << "totalNbCells " << total_nb_cells << " totalNbNodes " << total_nb_nodes << std::endl;
171   
172   std::vector<int>& cell_shift_by_domain=_cell_shift_by_domain;
173   std::vector<int>& node_shift_by_domain=_node_shift_by_domain;
174   std::vector<int>& face_shift_by_domain=_face_shift_by_domain;
175  
176   std::vector< int > ordered_nbs_cell, ordered_nbs_node, domain_order(nb_domains);
177   ordered_nbs_cell.push_back(0);
178   ordered_nbs_node.push_back(0);
179   for (int iproc=0; iproc<nbProcs(); ++iproc)
180     for (int idomain=0; idomain<nb_domains; ++idomain)
181       if (getProcessorID( idomain )==iproc)
182         {
183           domain_order[idomain] = ordered_nbs_cell.size() - 1;
184           ordered_nbs_cell.push_back( ordered_nbs_cell.back() + all_nb_elems[idomain*2] );
185           ordered_nbs_node.push_back( ordered_nbs_node.back() + all_nb_elems[idomain*2+1] );
186         }
187   cell_shift_by_domain.resize( nb_domains+1, 0 );
188   node_shift_by_domain.resize( nb_domains+1, 0 );
189   face_shift_by_domain.resize( nb_domains+1, 0 );
190   for (int idomain=0; idomain<nb_domains; ++idomain)
191     {
192       cell_shift_by_domain[ idomain ] = ordered_nbs_cell[ domain_order[ idomain ]];
193       node_shift_by_domain[ idomain ] = ordered_nbs_node[ domain_order[ idomain ]];
194     }
195   cell_shift_by_domain.back() = ordered_nbs_cell.back(); // to know total nb of elements
196   node_shift_by_domain.back() = ordered_nbs_node.back(); // to know total nb of elements
197   
198   if (MyGlobals::_Is0verbose>300)
199     {
200       std::cout << "proc " << MyGlobals::_Rank << " : cellShiftByDomain ";
201       for (int i=0; i<=nb_domains; ++i)
202         std::cout << cell_shift_by_domain[i] << "|";
203       std::cout << std::endl;
204       std::cout << "proc " << MyGlobals::_Rank << " : nodeShiftBy_domain ";
205       for (int i=0; i<=nb_domains; ++i)
206         std::cout << node_shift_by_domain[i] << "|";
207       std::cout << std::endl;
208     }
209   // fill _nb_vert_of_procs (is Vtxdist)
210   _nb_vert_of_procs.resize(_world_size+1);
211   _nb_vert_of_procs[0] = 0; // base = 0
212   for (int i=0; i<nb_domains; ++i)
213     {
214       int rankk = getProcessorID(i);
215       _nb_vert_of_procs[rankk+1] += all_nb_elems[i*2];
216     }
217   for (std::size_t i=1; i<_nb_vert_of_procs.size(); ++i)
218     _nb_vert_of_procs[i] += _nb_vert_of_procs[i-1]; // to CSR format : cumulated
219   
220   if (MyGlobals::_Is0verbose>200)
221     {
222       std::cout << "proc " << MyGlobals::_Rank << " : gatherNbOf : vtxdist is ";
223       for (int i = 0; i <= _world_size; ++i)
224         std::cout << _nb_vert_of_procs[i] << " ";
225       std::cout << std::endl;
226     }
227   
228   evaluateMemory();
229   return;
230 }
231
232 /*!
233  * \brief Return distribution of the graph vertices among the processors
234  *  \retval int* - array containing nb of vertices (=cells) on all processors
235  *
236  * gatherNbOf() must be called before.
237  * The result array is to be used as the first arg of ParMETIS_V3_PartKway() and
238  * is freed by ParaDomainSelector.
239  */
240 int *MEDPARTITIONER::ParaDomainSelector::getProcVtxdist() const
241 {
242   evaluateMemory();
243   if (_nb_vert_of_procs.empty())
244     throw INTERP_KERNEL::Exception("_nb_vert_of_procs not set");
245   return const_cast<int*>(& _nb_vert_of_procs[0]);
246 }
247
248 /*!
249  * \brief Return nb of cells in domains with lower index.
250  *
251  * gatherNbOf() must be called before.
252  * Result added to local id on given domain gives id in the whole distributed mesh
253  */
254 int MEDPARTITIONER::ParaDomainSelector::getDomainCellShift(int domainIndex) const
255 {
256   evaluateMemory();
257   if (_cell_shift_by_domain.empty())
258     throw INTERP_KERNEL::Exception("_cell_shift_by_domain not set");
259   return _cell_shift_by_domain[domainIndex];
260 }
261
262 int MEDPARTITIONER::ParaDomainSelector::getDomainNodeShift(int domainIndex) const
263 {
264   evaluateMemory();
265   if (_node_shift_by_domain.empty())
266     throw INTERP_KERNEL::Exception("_node_shift_by_domain not set");
267   return _node_shift_by_domain[domainIndex];
268 }
269
270 /*!
271  * \brief Return nb of nodes on processors with lower rank.
272  *
273  * gatherNbOf() must be called before.
274  * Result added to global id on this processor gives id in the whole distributed mesh
275  */
276 int MEDPARTITIONER::ParaDomainSelector::getProcNodeShift() const
277 {
278   evaluateMemory();
279   if (_nb_vert_of_procs.empty())
280     throw INTERP_KERNEL::Exception("_nb_vert_of_procs not set");
281   return _nb_vert_of_procs[_rank];
282 }
283
284 /*!
285  * \brief Gather graphs from all processors into one
286  */
287 std::auto_ptr<MEDPARTITIONER::Graph> MEDPARTITIONER::ParaDomainSelector::gatherGraph(const Graph* graph) const
288 {
289   Graph* glob_graph = 0;
290
291   evaluateMemory();
292 #ifdef HAVE_MPI2
293
294   // ---------------
295   // Gather indices
296   // ---------------
297
298   std::vector<int> index_size_of_proc( nbProcs() ); // index sizes - 1
299   for ( std::size_t i = 1; i < _nb_vert_of_procs.size(); ++i )
300     index_size_of_proc[i-1] = _nb_vert_of_procs[ i ] - _nb_vert_of_procs[ i-1 ];
301
302   int index_size = 1 + _cell_shift_by_domain.back();
303   int *graph_index = new int[ index_size ];
304   const int *index = graph->getGraph()->getIndex();
305   int *proc_index_displacement = const_cast<int*>( & _nb_vert_of_procs[0] );
306
307   MPI_Allgatherv((void*) (index+1),         // send local index except first 0 (or 1)
308                  index_size_of_proc[_rank], // index size on this proc
309                  MPI_INT,
310                  (void*) graph_index,       // receive indices
311                  & index_size_of_proc[0],   // index size on each proc
312                  proc_index_displacement,   // displacement of each proc index
313                  MPI_INT,
314                  MPI_COMM_WORLD);
315   graph_index[0] = index[0]; // it is not overwritten thanks to proc_index_displacement[0]==1
316
317   // get sizes of graph values on each proc by the got indices of graphs
318   std::vector< int > value_size_of_proc( nbProcs() ), proc_value_displacement(1,0);
319   for ( int i = 0; i < nbProcs(); ++i )
320     {
321       if ( index_size_of_proc[i] > 0 )
322         value_size_of_proc[i] = graph_index[ proc_index_displacement[ i+1 ]-1 ] - graph_index[0];
323       else
324         value_size_of_proc[i] = 0;
325       proc_value_displacement.push_back( proc_value_displacement.back() + value_size_of_proc[i] );
326     }
327   
328   // update graph_index
329   for ( int i = 1; i < nbProcs(); ++i )
330     {
331       int shift = graph_index[ proc_index_displacement[i]-1 ]-graph_index[0];
332       for ( int j = proc_index_displacement[i]; j < proc_index_displacement[i+1]; ++j )
333         graph_index[ j ] += shift;
334     }
335   
336   // --------------
337   // Gather values
338   // --------------
339
340   int value_size = graph_index[ index_size-1 ] - graph_index[ 0 ];
341   int *graph_value = new int[ value_size ];
342   const int *value = graph->getGraph()->getValue();
343
344   MPI_Allgatherv((void*) value,                // send local value
345                  value_size_of_proc[_rank],    // value size on this proc
346                  MPI_INT,
347                  (void*) graph_value,          // receive values
348                  & value_size_of_proc[0],      // value size on each proc
349                  & proc_value_displacement[0], // displacement of each proc value
350                  MPI_INT,
351                  MPI_COMM_WORLD);
352
353   // -----------------
354   // Gather partition
355   // -----------------
356
357   int * partition = new int[ _cell_shift_by_domain.back() ];
358   const int* part = graph->getPart();
359   
360   MPI_Allgatherv((void*) part,              // send local partition
361                  index_size_of_proc[_rank], // index size on this proc
362                  MPI_INT,
363                  (void*)(partition-1),      // -1 compensates proc_index_displacement[0]==1
364                  & index_size_of_proc[0],   // index size on each proc
365                  proc_index_displacement,   // displacement of each proc index
366                  MPI_INT,
367                  MPI_COMM_WORLD);
368
369   // -----------
370   // Make graph
371   // -----------
372
373   //   MEDPARTITIONER::SkyLineArray* array =
374   //     new MEDPARTITIONER::SkyLineArray( index_size-1, value_size, graph_index, graph_value, true );
375
376   //   glob_graph = new UserGraph( array, partition, index_size-1 );
377
378   evaluateMemory();
379
380   delete [] partition;
381
382 #endif // HAVE_MPI2
383
384   return std::auto_ptr<Graph>( glob_graph );
385 }
386
387
388 /*!
389  * \brief Set nb of cell/cell pairs in a joint between domains
390  */
391 void MEDPARTITIONER::ParaDomainSelector::setNbCellPairs( int nb_cell_pairs, int dist_domain, int loc_domain )
392 {
393   // This method is needed for further computing global numbers of faces in joint.
394   // Store if both domains are on this proc else on one of procs only
395   if ( isMyDomain( dist_domain ) || dist_domain < loc_domain )
396     {
397       if ( _nb_cell_pairs_by_joint.empty() )
398         _nb_cell_pairs_by_joint.resize( _nb_result_domains*(_nb_result_domains+1), 0);
399
400       int joint_id = jointId( loc_domain, dist_domain );
401       _nb_cell_pairs_by_joint[ joint_id ] = nb_cell_pairs;
402     }
403   evaluateMemory();
404 }
405
406 //================================================================================
407 /*!
408  * \brief Return nb of cell/cell pairs in a joint between domains on different procs
409  */
410 //================================================================================
411
412 int MEDPARTITIONER::ParaDomainSelector::getNbCellPairs( int dist_domain, int loc_domain ) const
413 {
414   evaluateMemory();
415
416   int joint_id = jointId( loc_domain, dist_domain );
417   return _nb_cell_pairs_by_joint[ joint_id ];
418 }
419
420 //================================================================================
421 /*!
422  * \brief Gather size of each joint
423  */
424 //================================================================================
425
426 void MEDPARTITIONER::ParaDomainSelector::gatherNbCellPairs()
427 {
428   if ( _nb_cell_pairs_by_joint.empty() )
429     _nb_cell_pairs_by_joint.resize( _nb_result_domains*(_nb_result_domains+1), 0);
430   evaluateMemory();
431
432   std::vector< int > send_buf = _nb_cell_pairs_by_joint;
433 #ifdef HAVE_MPI2
434   MPI_Allreduce((void*)&send_buf[0],
435                 (void*)&_nb_cell_pairs_by_joint[0],
436                 _nb_cell_pairs_by_joint.size(),
437                 MPI_INT, MPI_SUM, MPI_COMM_WORLD);
438 #endif
439   // check that the set nbs of cell pairs are correct,
440   // namely that each joint is treated on one proc only
441   for ( std::size_t j = 0; j < _nb_cell_pairs_by_joint.size(); ++j )
442     if ( _nb_cell_pairs_by_joint[j] != send_buf[j] && send_buf[j]>0 )
443       throw INTERP_KERNEL::Exception("invalid nb of cell pairs");
444 }
445
446 //================================================================================
447 /*!
448  * \brief Return the first global id of sub-entity for the joint
449  */
450 //================================================================================
451
452 int MEDPARTITIONER::ParaDomainSelector::getFisrtGlobalIdOfSubentity( int loc_domain, int dist_domain ) const
453 {
454   // total_nb_faces includes faces existing before creation of joint faces
455   // (got in gatherNbOf( MED_FACE )).
456   evaluateMemory();
457
458   int total_nb_faces = _face_shift_by_domain.empty() ? 0 : _face_shift_by_domain.back();
459   int id = total_nb_faces + 1;
460
461   if ( _nb_cell_pairs_by_joint.empty() )
462     throw INTERP_KERNEL::Exception("gatherNbCellPairs() must be called before");
463   int joint_id = jointId( loc_domain, dist_domain );
464   for ( int j = 0; j < joint_id; ++j )
465     id += _nb_cell_pairs_by_joint[ j ];
466
467   return id;
468 }
469
470 //================================================================================
471 /*!
472  * \brief Send-receive local ids of joint faces
473  */
474 //================================================================================
475
476 int *MEDPARTITIONER::ParaDomainSelector::exchangeSubentityIds( int loc_domain, int dist_domain,
477                                                const std::vector<int>& loc_ids_here ) const
478 {
479   int* loc_ids_dist = new int[ loc_ids_here.size()];
480 #ifdef HAVE_MPI2
481   int dest = getProcessorID( dist_domain );
482   int tag  = 2002 + jointId( loc_domain, dist_domain );
483   MPI_Status status;
484   MPI_Sendrecv((void*)&loc_ids_here[0], loc_ids_here.size(), MPI_INT, dest, tag,
485                (void*) loc_ids_dist,    loc_ids_here.size(), MPI_INT, dest, tag,
486                MPI_COMM_WORLD, &status);  
487 #endif
488   evaluateMemory();
489
490   return loc_ids_dist;
491 }
492
493 //================================================================================
494 /*!
495  * \brief Return identifier for a joint
496  */
497 //================================================================================
498
499 int MEDPARTITIONER::ParaDomainSelector::jointId( int local_domain, int distant_domain ) const
500 {
501   evaluateMemory();
502   if (_nb_result_domains < 0)
503     throw INTERP_KERNEL::Exception("setNbDomains() must be called before");
504
505   if ( local_domain < distant_domain )
506     std::swap( local_domain, distant_domain );
507   return local_domain * _nb_result_domains + distant_domain;
508 }
509
510
511 //================================================================================
512 /*!
513  * \brief Return time passed from construction in seconds
514  */
515 //================================================================================
516
517 double MEDPARTITIONER::ParaDomainSelector::getPassedTime() const
518 {
519 #ifdef HAVE_MPI2
520   return MPI_Wtime() - _init_time;
521 #else
522   return 0.0;
523 #endif
524 }
525
526 /*!
527   Sends content of \a mesh to processor \a target. To be used with \a recvMesh method.
528   \param mesh mesh to be sent
529   \param target processor id of the target
530 */
531
532 void MEDPARTITIONER::ParaDomainSelector::sendMesh(const ParaMEDMEM::MEDCouplingUMesh& mesh, int target) const
533 {
534 #ifndef HAVE_MPI2
535   throw INTERP_KERNEL::Exception("ParaDomainSelector::sendMesh : incoherent call in non_MPI mode");
536 #else
537   if (MyGlobals::_Verbose>600)
538     std::cout << "proc " << _rank << " : sendMesh '" << mesh.getName() << "' size " << mesh.getNumberOfCells() << " to " << target << std::endl;
539   // First stage : sending sizes
540   // ------------------------------
541   std::vector<int> tinyInfoLocal;
542   std::vector<std::string> tinyInfoLocalS;
543   std::vector<double> tinyInfoLocalD;
544   //Getting tiny info of local mesh to allow the distant proc to initialize and allocate
545   //the transmitted mesh.
546   mesh.getTinySerializationInformation(tinyInfoLocalD,tinyInfoLocal,tinyInfoLocalS);
547   tinyInfoLocal.push_back(mesh.getNumberOfCells());
548   int tinySize=tinyInfoLocal.size();
549   MPI_Send(&tinySize, 1, MPI_INT, target, 1113, MPI_COMM_WORLD);
550   MPI_Send(&tinyInfoLocal[0], tinyInfoLocal.size(), MPI_INT, target, 1112, MPI_COMM_WORLD);
551
552   if (mesh.getNumberOfCells()>0) //no sends if empty
553     {
554       ParaMEDMEM::DataArrayInt *v1Local=0;
555       ParaMEDMEM::DataArrayDouble *v2Local=0;
556       //serialization of local mesh to send data to distant proc.
557       mesh.serialize(v1Local,v2Local);
558       int nbLocalElems=0;
559       int* ptLocal=0;
560       if(v1Local) //if empty getNbOfElems() is 1!
561         {
562           nbLocalElems=v1Local->getNbOfElems(); // if empty be 1!
563           ptLocal=v1Local->getPointer();
564         }
565       MPI_Send(ptLocal, nbLocalElems, MPI_INT, target, 1111, MPI_COMM_WORLD);
566       int nbLocalElems2=0;
567       double *ptLocal2=0;
568       if(v2Local) //if empty be 0!
569         {
570           nbLocalElems2=v2Local->getNbOfElems();
571           ptLocal2=v2Local->getPointer();
572         }
573       MPI_Send(ptLocal2, nbLocalElems2, MPI_DOUBLE, target, 1110, MPI_COMM_WORLD);
574       if(v1Local) v1Local->decrRef();
575       if(v2Local) v2Local->decrRef();
576     }
577 #endif
578 }
579
580 /*! Receives messages from proc \a source to fill mesh \a mesh.
581   To be used with \a sendMesh method.
582   \param mesh  pointer to mesh that is filled
583   \param source processor id of the incoming messages
584 */
585 void MEDPARTITIONER::ParaDomainSelector::recvMesh(ParaMEDMEM::MEDCouplingUMesh*& mesh, int source)const
586 {
587 #ifndef HAVE_MPI2
588   throw INTERP_KERNEL::Exception("ParaDomainSelector::recvMesh : incoherent call in non_MPI mode");
589 #else
590   // First stage : exchanging sizes
591   // ------------------------------
592   std::vector<int> tinyInfoDistant;
593   std::vector<std::string> tinyInfoLocalS;
594   std::vector<double> tinyInfoDistantD(1);
595   //Getting tiny info of local mesh to allow the distant proc to initialize and allocate
596   //the transmitted mesh.
597   MPI_Status status; 
598   int tinyVecSize;
599   MPI_Recv(&tinyVecSize, 1, MPI_INT, source, 1113, MPI_COMM_WORLD, &status);
600   tinyInfoDistant.resize(tinyVecSize);
601   std::fill(tinyInfoDistant.begin(),tinyInfoDistant.end(),0);
602
603   MPI_Recv(&tinyInfoDistant[0], tinyVecSize, MPI_INT,source,1112,MPI_COMM_WORLD, &status);
604   //there was tinyInfoLocal.push_back(mesh.getNumberOfCells());
605   int NumberOfCells=tinyInfoDistant[tinyVecSize-1];
606   if (NumberOfCells>0)
607     {
608       ParaMEDMEM::DataArrayInt *v1Distant=ParaMEDMEM::DataArrayInt::New();
609       ParaMEDMEM::DataArrayDouble *v2Distant=ParaMEDMEM::DataArrayDouble::New();
610       //Building the right instance of copy of distant mesh.
611       ParaMEDMEM::MEDCouplingPointSet *distant_mesh_tmp=
612         ParaMEDMEM::MEDCouplingPointSet::BuildInstanceFromMeshType(
613                                                                    (ParaMEDMEM::MEDCouplingMeshType) tinyInfoDistant[0]);
614       std::vector<std::string> unusedTinyDistantSts;
615       mesh=dynamic_cast<ParaMEDMEM::MEDCouplingUMesh*> (distant_mesh_tmp);
616  
617       mesh->resizeForUnserialization(tinyInfoDistant,v1Distant,v2Distant,unusedTinyDistantSts);
618       int nbDistElem=0;
619       int *ptDist=0;
620       if(v1Distant)
621         {
622           nbDistElem=v1Distant->getNbOfElems();
623           ptDist=v1Distant->getPointer();
624         }
625       MPI_Recv(ptDist, nbDistElem, MPI_INT, source,1111, MPI_COMM_WORLD, &status);
626       double *ptDist2=0;
627       nbDistElem=0;
628       if(v2Distant)
629         {
630           nbDistElem=v2Distant->getNbOfElems();
631           ptDist2=v2Distant->getPointer();
632         }
633       MPI_Recv(ptDist2, nbDistElem, MPI_DOUBLE,source, 1110, MPI_COMM_WORLD, &status);
634       //finish unserialization
635       mesh->unserialization(tinyInfoDistantD,tinyInfoDistant,v1Distant,v2Distant,unusedTinyDistantSts);
636       if(v1Distant) v1Distant->decrRef();
637       if(v2Distant) v2Distant->decrRef();
638     }
639   else
640     {
641       mesh=CreateEmptyMEDCouplingUMesh();
642     }
643   if (MyGlobals::_Verbose>600)
644     std::cout << "proc " << _rank << " : recvMesh '" << mesh->getName() << "' size " << mesh->getNumberOfCells() << " from " << source << std::endl;
645 #endif
646 }
647
648 #ifndef WIN32
649 #include <sys/sysinfo.h>
650 #endif
651
652 /*!
653  * \brief Evaluate current memory usage and return the maximal one in KB
654  */
655 int MEDPARTITIONER::ParaDomainSelector::evaluateMemory() const
656 {
657   if ( _mesure_memory )
658     {
659       int used_memory = 0;
660 #ifndef WIN32
661       struct sysinfo si;
662       int err = sysinfo( &si );
663       if ( !err )
664         used_memory = (( si.totalram - si.freeram + si.totalswap - si.freeswap ) * si.mem_unit ) / 1024;
665 #endif
666       if ( used_memory > _max_memory )
667         _max_memory = used_memory;
668
669       if ( !_init_memory )
670         _init_memory = used_memory;
671     }
672   return _max_memory - _init_memory;
673 }