LifeV
GraphCutterZoltan.hpp
Go to the documentation of this file.
1 //@HEADER
2 /*
3 *******************************************************************************
4 
5  Copyright (C) 2004, 2005, 2007 EPFL, Politecnico di Milano, INRIA
6  Copyright (C) 2010, 2011, 2012 EPFL, Politecnico di Milano, Emory University
7 
8  This file is part of LifeV.
9 
10  LifeV is free software; you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  LifeV is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with LifeV. If not, see <http://www.gnu.org/licenses/>.
22 
23 *******************************************************************************
24 */
25 //@HEADER
26 
27 /*!
28  @file
29  @brief Class that partitions the graph associated with a mesh.
30  Uses the Zoltan graph processing library
31 
32  @date 17-11-2011
33  @author Radu Popescu <radu.popescu@epfl.ch>
34  */
35 
36 #ifndef GRAPH_PARTITION_TOOL_ZOLTAN_H
37 #define GRAPH_PARTITION_TOOL_ZOLTAN_H 1
38 
39 #pragma GCC diagnostic ignored "-Wunused-variable"
40 #pragma GCC diagnostic ignored "-Wunused-parameter"
41 
42 #include <vector>
43 #include <map>
44 #include <boost/shared_ptr.hpp>
45 #include <boost/lexical_cast.hpp>
46 #include <Epetra_Comm.h>
47 #include <Teuchos_ParameterList.hpp>
48 #include <zoltan.h>
49 
50 #pragma GCC diagnostic warning "-Wunused-variable"
51 #pragma GCC diagnostic warning "-Wunused-parameter"
52 
53 #include <lifev/core/LifeV.hpp>
54 #include <lifev/core/mesh/GraphCutterBase.hpp>
55 #include <lifev/core/mesh/GraphUtil.hpp>
56 
57 namespace LifeV
58 {
59 
60 using namespace GraphUtil;
61 
62 //! This structure is used to pack objects in the Zoltan migration phase
63 /*!
64  @author Radu Popescu <radu.popescu@epfl.ch>
65  */
67 {
68  // The gid of the object
69  int gid;
70  // The partition to which it belongs
71  int part;
72 };
73 
74 //! Class that partitions the graph associated with a mesh
75 /*!
76  @author Radu Popescu <radu.popescu@epfl.ch>
77 
78  This class uses the Zoltan package to partition the graph associated
79  with a mesh. This class builds the dual graph of the mesh, partitions
80  it according to a set of parameters and the stores the partitioning
81  in a table (vector of vectors).
82  At the end of the partition process, each vector will contain the
83  GID of the elements in a part.
84 
85  While this class can be used stand-alone, it is used automatically by the
86  MeshPartitionTool class during the mesh partition process.
87 
88  More on class functionality to follow. Stay tuned...
89  */
90 template<typename MeshType>
91 class GraphCutterZoltan : public GraphCutterBase<MeshType>
92 {
93 public:
94  //! @name Public Types
95  //@{
98  typedef MeshType mesh_Type;
100 
102  //@}
103 
104  //! @name Constructor & Destructor
105  //! Constructor taking the original mesh, the MPI comm and parameters
106  /*!
107  This constructor can be used to build the object and perform the
108  graph partitioning in one shot.
109 
110  @param mesh The original mesh whose graph this object will partition
111  @param comm The Epetra MPI comm object which contains the processes
112  which participate
113  @param parameters The Teuchos parameter list which contains the
114  partitioning parameters
115  */
117  commPtr_Type& comm,
118  pList_Type& parameters);
119 
120  //! Destructor
121  virtual ~GraphCutterZoltan() {}
122  //@}
123 
124  //! @name Public methods
125  //@{
126  //! Performs the graph partitioning
127  virtual Int run();
128  //@}
129 
130  //! @name Get Methods
131  //@{
132  //! Get a pointer to one of the parts
133  virtual const idListPtr_Type& getPart (const UInt i) const
134  {
135  return M_partitionTable.find (i)->second;
136  }
137  virtual idListPtr_Type& getPart (const UInt i)
138  {
139  return M_partitionTable.find (i)->second;
140  }
141 
142  //! Get the entire partitioned graph, wrapped in a smart pointer
143  virtual const idTablePtr_Type getGraph() const
144  {
145  idTablePtr_Type graph (new idTable_Type (numParts() ) );
146  for (UInt i = 0; i < numParts(); ++i)
147  {
148  graph->at (i) = getPart (i);
149  }
150  return graph;
151  }
152 
153  //! Return the number of parts
154  virtual const UInt numParts() const
155  {
156  return M_partitionTable.size();
157  }
158 
159  //! Get number of stored graph elements
161  {
162  return static_cast<UInt> (M_elementList.size() );
163  }
164 
165  //! First global index that is initially assigned to process i
166  Int firstIndex (const Int i) const
167  {
168  return M_indexBounds[i];
169  }
170 
171  //! Last global index that is initially assigned to process i
172  Int lastIndex (const Int i) const
173  {
174  return M_indexBounds[i + 1] - 1;
175  }
176 
177  //! The internally stored dual graph of the mesh
178  const table_Type& graph() const
179  {
180  return M_graph;
181  }
182 
183  //! The vector of stored element GIDs
184  const std::vector<Int>& elementList() const
185  {
186  return M_elementList;
187  }
188 
189  //! The vector of stored element GIDs (non-const)
191  {
192  return M_elementList;
193  }
194 
195  //! The vector of stored element partitions
196  const std::vector<Int>& elementParts() const
197  {
198  return M_elementParts;
199  }
200 
201  //! The vector of stored element partitions (non-const)
203  {
204  return M_elementParts;
205  }
206 
207  //! The PID of the process
208  Int myPID() const
209  {
210  return M_myPID;
211  }
212 
213  //! The number of processes in the comm
215  {
216  return M_numProcessors;
217  }
218  //@}
219 
220  //! @name Static methods
221  //@{
222  static int getNumElements (void* data, int* ierr);
223  static void getElementList (void* data, int sizeGID, int sizeLID,
224  ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
225  int wgt_dim, float* obj_wgts, int* ierr);
226  static void getNumNeighboursList (void* data, int sizeGID, int sizeLID,
227  int num_obj,
228  ZOLTAN_ID_PTR globalID,
229  ZOLTAN_ID_PTR localID,
230  int* numEdges, int* ierr);
231  static void getNeighbourList (void* data, int sizeGID, int sizeLID,
232  int num_obj, ZOLTAN_ID_PTR globalID,
233  ZOLTAN_ID_PTR localID, int* num_edges,
234  ZOLTAN_ID_PTR nborGID, int* nborProc,
235  int wgt_dim, float* ewgts, int* ierr);
236  static void getTransferObjectSizes (void* data, int num_gid_entries,
237  int num_lid_entries, int num_ids,
238  ZOLTAN_ID_PTR global_ids,
239  ZOLTAN_ID_PTR local_ids,
240  int* sizes, int* ierr);
241  static void packObjects (void* data, int num_gid_entries,
242  int num_lid_entries, int num_ids,
243  ZOLTAN_ID_PTR global_ids,
244  ZOLTAN_ID_PTR local_ids,
245  int* dest, int* sizes, int* idx,
246  char* buf, int* ierr);
247  static void unpackObjects (void* data, int num_gid_entries,
248  int num_ids, ZOLTAN_ID_PTR global_ids,
249  int* sizes, int* idx, char* buf, int* ierr);
250 
251 private:
252  //! @name Private methods
253  //@{
254  //! Set values for all the parameters, with default values where needed
255  virtual void setParameters (pList_Type& parameters);
256  //@}
257 
258  // Private copy constructor and assignment operator are disabled
261 
262  //! @name Private Methods
263  //@{
264  //! Distribute the partitions among available processors
265  void distributePartitions();
266 
267  //! Build the dual graph of the unpartitioned mesh
268  void buildGraph();
269 
270  //! Migrate elements between locally stored partitions
271  void localMigrate (int numExport,
272  ZOLTAN_ID_PTR exportLocalGids,
273  int* exportProcs, int* exportToPart);
274 
275  //! Build the partition table that can be exported to the mesh builder
276  void buildPartitionTable();
277 
278  //! Partition the graph
279  void partitionGraph();
280  //@}
281 
294  // TODO: possible improvement (memory-wise) is to implement a bidirectional
295  // map instead of using these two vectors and M_partitionTable
296  // MeshPartitionTool expects a partition-to-element map, while in the graph
297  // cutting routine an element-to-partition map is needed
300 
301  struct Zoltan_Struct* M_zoltanStruct;
302 };
303 
304 //
305 // IMPLEMENTATION
306 //
307 
308 // =================================
309 // Constructors and Destructor
310 // =================================
311 
312 template<typename MeshType>
314  commPtr_Type& comm,
315  pList_Type& parameters) :
316  M_comm (comm),
317  M_myPID (M_comm->MyPID() ),
319  M_numParts (0),
321  M_myFirstPart (0),
322  M_myLastPart (0),
323  M_parameters(),
324  M_mesh (mesh),
325  M_zoltanStruct (0)
326 {
327  setParameters (parameters);
328 }
329 
330 template<typename MeshType>
331 void GraphCutterZoltan<MeshType>::setParameters (pList_Type& parameters)
332 {
333  // Here put some default values for the parameters and then import
334  // the user supplied list, overwriting the corresponding parameters
335  M_parameters.set ("num-parts", static_cast<Int> (M_comm->NumProc() ),
336  "The desired number of parts");
337  M_parameters.set ("topology", "1",
338  "The topology of the mesh partition process.");
339  M_parameters.set ("debug_level", 0, "Verbosity of Zoltan");
340  M_parameters.set ("hier_debug_level", 0, "Verbosity (hier. partition)");
341  M_parameters.set ("lb_method", "GRAPH",
342  "Graph partition method: GRAPH or HIER");
343  M_parameters.set ("lb_approach", "PARTITION",
344  "Partition approach: PARTITION or REPARTITION");
345 
346  M_parameters.setParameters (parameters);
347 
348  M_numParts = M_parameters.get<Int> ("num-parts");
350 }
351 
352 template<typename MeshType>
354 {
356  buildGraph();
358 
359  return 0;
360 }
361 
362 // =================
363 // Static methods
364 // =================
365 
366 template<typename MeshType>
367 int GraphCutterZoltan<MeshType>::getNumElements (void* data, int* ierr)
368 {
369  GraphCutterZoltan<MeshType>* object = (GraphCutterZoltan<MeshType>*) data;
370 
371  *ierr = ZOLTAN_OK;
372  return object->numStoredElements();
373 }
374 
375 template<typename MeshType>
376 void GraphCutterZoltan<MeshType>::getElementList (void* data,
377  int /*sizeGID*/,
378  int /*sizeLID*/,
379  ZOLTAN_ID_PTR globalID,
380  ZOLTAN_ID_PTR localID,
381  int /*wgt_dim*/,
382  float* /*obj_wgts*/,
383  int* ierr)
384 {
385  GraphCutterZoltan<MeshType>* object = (GraphCutterZoltan<MeshType>*) data;
386 
387  UInt k = 0;
388  for (UInt i = 0; i < object->numStoredElements(); ++i)
389  {
390  globalID[i] = object->elementList() [i];
391  localID[i] = k;
392  k++;
393  }
394 
395  *ierr = ZOLTAN_OK;
396 }
397 
398 template<typename MeshType>
399 void GraphCutterZoltan<MeshType>::getNumNeighboursList (void* data,
400  int /*sizeGID*/,
401  int /*sizeLID*/,
402  int num_obj,
403  ZOLTAN_ID_PTR globalID,
404  ZOLTAN_ID_PTR /*lID*/,
405  int* numEdges,
406  int* ierr)
407 {
408  GraphCutterZoltan<MeshType>* object = (GraphCutterZoltan<MeshType>*) data;
409 
410  for (int element = 0; element < num_obj; ++element)
411  {
412  numEdges[element]
413  = object->graph().find (globalID[element])->second->size();
414  }
415 
416  *ierr = ZOLTAN_OK;
417 }
418 
419 template<typename MeshType>
420 void GraphCutterZoltan<MeshType>::getNeighbourList (void* data,
421  int /*sizeGID*/,
422  int /*sizeLID*/,
423  int num_obj,
424  ZOLTAN_ID_PTR globalID,
425  ZOLTAN_ID_PTR /*localID*/,
426  int* num_edges,
427  ZOLTAN_ID_PTR nborGID,
428  int* nborProc,
429  int /*wgt_dim*/,
430  float* /*ewgts*/,
431  int* ierr)
432 {
433  GraphCutterZoltan<MeshType>* object = (GraphCutterZoltan<MeshType>*) data;
434 
435  std::vector<Int>::const_iterator iter;
436  int pos = 0;
437  for (int element = 0; element < num_obj; ++element)
438  {
439  iter = object->graph().find (globalID[element])->second->begin();
440  for (int k = 0; k < num_edges[element]; ++k)
441  {
442  nborGID[pos] = *iter;
443  int pid = 0;
444  for (int i = 0; i < object->numProcessors(); ++i)
445  {
446  Int ie = *iter;
447  if (ie >= object->firstIndex (i)
448  &&
449  ie <= object->lastIndex (i) )
450  {
451  pid = i;
452  break;
453  }
454  }
455  nborProc[pos] = pid;
456  ++pos;
457  ++iter;
458  }
459  }
460 
461  *ierr = ZOLTAN_OK;
462 }
463 
464 template<typename MeshType>
465 void GraphCutterZoltan<MeshType>::getTransferObjectSizes (
466  void* /*data*/, int /*num_gid_entries*/, int /*num_lid_entries*/,
467  int num_ids, ZOLTAN_ID_PTR /*global_ids*/, ZOLTAN_ID_PTR /*local_ids*/,
468  int* sizes, int* ierr)
469 {
470  int sizeOfBuffer = sizeof (TransportBuffer);
471  for (int i = 0; i < num_ids; ++i)
472  {
473  sizes[i] = sizeOfBuffer;
474  }
475 
476  *ierr = ZOLTAN_OK;
477 }
478 
479 template<typename MeshType>
480 void GraphCutterZoltan<MeshType>::packObjects (void* data,
481  int /*num_gid_entries*/,
482  int /*num_lid_entries*/,
483  int num_ids,
484  ZOLTAN_ID_PTR global_ids,
485  ZOLTAN_ID_PTR local_ids,
486  int* dest,
487  int* /*sizes*/,
488  int* idx,
489  char* buf,
490  int* ierr)
491 {
492  GraphCutterZoltan<MeshType>* object = (GraphCutterZoltan<MeshType>*) data;
493 
494  // Pack gids and part numbers in the buffer
495  for (int i = 0; i < num_ids; ++i)
496  {
497  TransportBuffer* buffer = (TransportBuffer*) &buf[idx[i]];
498  buffer->gid = global_ids[i];
499  buffer->part = dest[i];
500 
501  // Remove the objects from the local storage
502  // TODO: find better solution. This will be slow and inefficient !!!
503  object->elementList() [local_ids[i]] = -1;
504  object->elementParts() [local_ids[i]] = -1;
505  }
506 
507  *ierr = ZOLTAN_OK;
508 }
509 
510 template<typename MeshType>
511 void GraphCutterZoltan<MeshType>::unpackObjects (void* data,
512  int /*num_gid_entries*/,
513  int num_ids,
514  ZOLTAN_ID_PTR /*global_ids*/,
515  int* /*sizes*/,
516  int* idx,
517  char* buf,
518  int* ierr)
519 {
520  GraphCutterZoltan<MeshType>* object = (GraphCutterZoltan<MeshType>*) data;
521 
522  // Unpack gids and part numbers from the buffer
523  for (int i = 0; i < num_ids; ++i)
524  {
525  TransportBuffer* buffer = (TransportBuffer*) &buf[idx[i]];
526  object->elementList().push_back (buffer->gid);
527  object->elementParts().push_back (buffer->part);
528  }
529 
530  *ierr = ZOLTAN_OK;
531 }
532 
533 // =======================
534 // Private methods
535 // =======================
536 
537 template<typename MeshType>
539 {
540  // The algorithm to distribute partitions isn't clever at all.
541  // We assume the number of partitions is a multiple of the
542  // number of processes.
543 
546 
547  for (Int i = M_myFirstPart; i <= M_myLastPart; ++i)
548  {
549  M_partitionTable[i].reset (new idList_Type (0) );
550  }
551 }
552 
553 template<typename MeshType>
554 void GraphCutterZoltan<MeshType>::buildGraph()
555 {
556  // This next part computes the first and last element global index
557  // that the processor has to handle and makes a local vector of
558  // all the GIDs that the process owns
559 
560  Int k = M_mesh->numElements();
561 
562  M_indexBounds.resize (M_numProcessors + 1);
563  M_indexBounds[0] = 0;
564 
565  for (Int i = 0; i < M_numProcessors; ++i)
566  {
567  UInt l = k / (M_numProcessors - i);
568  M_indexBounds[i + 1] = M_indexBounds[i] + l;
569  k -= l;
570  }
571 
572  M_elementList.resize (M_indexBounds[M_myPID + 1] - M_indexBounds[M_myPID]);
573  Int startIndex = firstIndex (M_myPID);
574  for (UInt i = 0; i < numStoredElements(); ++i)
575  {
576  M_elementList[i] = startIndex + i;
577  }
578 
579  M_elementParts.resize (numStoredElements() );
580 
582  std::vector<Int> partitionBounds (M_numPartsPerProcessor + 1);
583  partitionBounds[0] = 0;
584  for (Int i = 0; i < M_numPartsPerProcessor; ++i)
585  {
586  UInt l = k / (M_numPartsPerProcessor - i);
587  partitionBounds[i + 1] = partitionBounds[i] + l;
588  k -= l;
589  }
590  for (Int i = 0; i < M_numPartsPerProcessor; ++i)
591  {
592  for (Int lid = partitionBounds[i];
593  lid < partitionBounds[i + 1]; ++lid)
594  {
595  M_elementParts[lid] = M_myFirstPart + i;
596  }
597  }
598 
599  // Build the graph of the local elements
600  Int numDimensions = MeshType::elementShape_Type::S_nDimensions;
601  int numNeighbours;
602  switch (numDimensions)
603  {
604  case 2:
605  numNeighbours = 3;
606  break;
607  case 3:
608  numNeighbours = 4;
609  break;
610  default:
611  numNeighbours = 0;
612  break;
613  }
614 
615  UInt numElementFacets = MeshType::elementShape_Type::S_numFacets;
616 
617  for (UInt i = 0; i < numStoredElements(); ++i)
618  {
619  UInt ie = M_elementList[i];
620  M_graph.insert (std::pair<Int, idListPtr_Type >
621  (ie, idListPtr_Type() )
622  );
623  M_graph[ie].reset (new idList_Type (0) );
624  M_graph[ie]->reserve (numNeighbours);
625  for (UInt ifacet = 0; ifacet < numElementFacets; ++ifacet)
626  {
627  UInt facet = M_mesh->localFacetId (ie, ifacet);
628  UInt elem = M_mesh->facet (facet).firstAdjacentElementIdentity();
629  if (elem == ie)
630  {
631  elem = M_mesh->facet (facet).secondAdjacentElementIdentity();
632  }
633  if (elem != NotAnId)
634  {
635  M_graph[ie]->push_back (elem);
636  }
637  }
638  }
639 }
640 
641 template<typename MeshType>
642 void GraphCutterZoltan<MeshType>::localMigrate (int numExport,
643  ZOLTAN_ID_PTR exportLocalGids,
644  int* exportProcs,
645  int* exportToPart)
646 {
647  for (int i = 0; i < numExport; ++i)
648  {
649  if (exportProcs[i] == M_myPID)
650  {
651  // We shouldn't need to check this, still ...
652  if (M_elementParts[exportLocalGids[i]] != exportToPart[i])
653  {
654  M_elementParts[exportLocalGids[i]] = exportToPart[i];
655  }
656  }
657  }
658 }
659 
660 template<typename MeshType>
662 {
663  for (table_Type::iterator it = M_partitionTable.begin();
664  it != M_partitionTable.end(); ++it)
665  {
666  // it->second.reset(new idList_Type(0));
667  it->second->reserve (numStoredElements() / M_numPartsPerProcessor);
668  }
669 
670  for (UInt i = 0; i < numStoredElements(); ++i)
671  {
672  // We marked elements that were moved to a different processor with -1
673  if (static_cast<Int> (M_elementList[i]) != -1)
674  {
675  M_partitionTable[M_elementParts[i]]->push_back (M_elementList[i]);
676  }
677  }
678  for (table_Type::iterator it = M_partitionTable.begin();
679  it != M_partitionTable.end(); ++it)
680  {
681  std::sort (it->second->begin(), it->second->end() );
682  }
683 
684  // Distribute the graph parts to all the processes
685  M_comm->Barrier();
686  if (numProcessors() > 1)
687  {
688  for (Int i = 0; i < numProcessors(); ++i)
689  {
690  int currentSize = 0;
691  if (i == M_myPID)
692  {
693  currentSize = M_partitionTable[i]->size();
694  }
695  M_comm->Broadcast (&currentSize, 1, i);
696  if (i != M_myPID)
697  {
698  M_partitionTable[i].reset (new idList_Type (currentSize) );
699  }
700  M_comm->Broadcast (& (M_partitionTable[i]->at (0) ), currentSize, i);
701  }
702  }
703 }
704 
705 template<typename MeshType>
707 {
708  int argc = 1;
709  char* argv;
710  float ver;
711  std::shared_ptr<Epetra_MpiComm> mpiComm
712  = std::dynamic_pointer_cast<Epetra_MpiComm> (M_comm);
713 
714  Zoltan_Initialize (argc, &argv, &ver);
715  M_zoltanStruct = Zoltan_Create (mpiComm->Comm() );
716 
717  int debug_level = M_parameters.get<int> ("debug_level");
718  int hier_debug_level = M_parameters.get<int> ("hier_debug_level");
719  Zoltan_Set_Param (M_zoltanStruct,
720  "DEBUG_LEVEL",
721  std::to_string (debug_level).c_str() );
722 
723  Zoltan_Set_Param (M_zoltanStruct,
724  "HIER_DEBUG_LEVEL",
725  std::to_string (hier_debug_level).c_str() );
726 
727  Zoltan_Set_Param (M_zoltanStruct, "LB_METHOD",
728  M_parameters.get<std::string> ("lb_method").c_str() );
729 
730  Zoltan_Set_Param (M_zoltanStruct, "LB_APPROACH",
731  M_parameters.get<std::string> ("lb_approach").c_str() );
732 
733  Zoltan_Set_Param (M_zoltanStruct, "HIER_ASSIST", "1");
734  Zoltan_Set_Param (M_zoltanStruct, "NUM_GID_ENTRIES", "1");
735  Zoltan_Set_Param (M_zoltanStruct, "NUM_LID_ENTRIES", "1");
736  Zoltan_Set_Param (M_zoltanStruct, "RETURN_LISTS", "EXPORT");
737  // We don't want remapping enabled since we need the best quality
738  // partitioning available
739  Zoltan_Set_Param (M_zoltanStruct, "REMAP", "0");
740  // Let the Zoltan_Migrate function only handle off processor transfers
741  // We move the elements between same-processor parts manually, to avoid
742  // MPI calls (??)
743  Zoltan_Set_Param (M_zoltanStruct, "MIGRATE_ONLY_PROC_CHANGES", "1");
744  Zoltan_Set_Param (M_zoltanStruct, "TOPOLOGY",
745  M_parameters.get<std::string> ("topology").c_str() );
746  Zoltan_Set_Param (M_zoltanStruct, "NUM_GLOBAL_PARTS",
747  (std::to_string
748  (M_numParts) ).c_str() );
749  Zoltan_Set_Param (M_zoltanStruct, "NUM_LOCAL_PARTS",
750  (std::to_string
751  (M_numPartsPerProcessor) ).c_str() );
752 
753  Zoltan_Set_Num_Obj_Fn (M_zoltanStruct,
755  this);
756  Zoltan_Set_Obj_List_Fn (M_zoltanStruct,
757  GraphCutterZoltan::getElementList,
758  this);
759  Zoltan_Set_Num_Edges_Multi_Fn (M_zoltanStruct,
760  GraphCutterZoltan::getNumNeighboursList,
761  this);
762  Zoltan_Set_Edge_List_Multi_Fn (M_zoltanStruct,
763  GraphCutterZoltan::getNeighbourList,
764  this);
765  Zoltan_Set_Obj_Size_Multi_Fn (M_zoltanStruct,
766  GraphCutterZoltan::getTransferObjectSizes,
767  this);
768  Zoltan_Set_Pack_Obj_Multi_Fn (M_zoltanStruct,
769  GraphCutterZoltan::packObjects,
770  this);
771  Zoltan_Set_Unpack_Obj_Multi_Fn (M_zoltanStruct,
772  GraphCutterZoltan::unpackObjects,
773  this);
774 
775  int changes, numGidEntries, numLidEntries, numImport, numExport;
776  ZOLTAN_ID_PTR importGlobalGids, importLocalGids;
777  ZOLTAN_ID_PTR exportGlobalGids, exportLocalGids;
778  int* importProcs, *importToPart, *exportProcs, *exportToPart;
779 
780  // Partition the graph
781  Zoltan_LB_Partition (M_zoltanStruct,
782  &changes,
783  &numGidEntries,
784  &numLidEntries,
785  &numImport,
786  &importGlobalGids,
787  &importLocalGids,
788  &importProcs,
789  &importToPart,
790  &numExport,
791  &exportGlobalGids,
792  &exportLocalGids,
793  &exportProcs,
794  &exportToPart);
795 
796  // We first need to migrate elements between locally stored parts.
797  // Aftewards, Zoltan can handle data movement between processors.
798  localMigrate (numExport, exportLocalGids, exportProcs, exportToPart);
799 
800  M_comm->Barrier();
801 
802  // Migrate data after partitioning
803  // WARNING! After Zoltan does the migration, the M_elementList and
804  // M_elementParts vectors are NOT ordered in ascending order of LID and GID.
805  // Make no assumptions about the order of local elements. Elements that have
806  // been migrated to other processors are marked with -1 in M_elementList
807  // and M_elementParts
808  Zoltan_Migrate (M_zoltanStruct,
809  -1,
810  NULL,
811  NULL,
812  NULL,
813  NULL,
814  numExport,
815  exportGlobalGids,
816  exportLocalGids,
817  exportProcs,
818  exportToPart);
819 
820  // Clean up after partitioning and migration
821  Zoltan_LB_Free_Part (&importGlobalGids, &importLocalGids,
822  &importProcs, &importToPart);
823  Zoltan_LB_Free_Part (&exportGlobalGids, &exportLocalGids,
824  &exportProcs, &exportToPart);
825  Zoltan_Destroy (&M_zoltanStruct);
826 
827  // Build the partition->element table that can be exported to the mesh
828  // partitioner
830 }
831 
832 } // Namespace LifeV
833 
834 #endif // GRAPH_PARTITION_TOOL_ZOLTAN_H
GraphCutterZoltan & operator=(const GraphCutterZoltan &)
This structure is used to pack objects in the Zoltan migration phase.
Int myPID() const
The PID of the process.
std::vector< Int > & elementParts()
The vector of stored element partitions (non-const)
std::map< Int, idListPtr_Type > table_Type
std::vector< Int > M_elementList
virtual const idTablePtr_Type getGraph() const
Get the entire partitioned graph, wrapped in a smart pointer.
Graph cutter base class (abstract)
int32_type Int
Generic integer data.
Definition: LifeV.hpp:188
static void getElementList(void *data, int sizeGID, int sizeLID, ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID, int wgt_dim, float *obj_wgts, int *ierr)
void distributePartitions()
Distribute the partitions among available processors.
virtual const idListPtr_Type & getPart(const UInt i) const
Get a pointer to one of the parts.
static void unpackObjects(void *data, int num_gid_entries, int num_ids, ZOLTAN_ID_PTR global_ids, int *sizes, int *idx, char *buf, int *ierr)
void updateInverseJacobian(const UInt &iQuadPt)
GraphCutterZoltan(const GraphCutterZoltan &)
void buildPartitionTable()
Build the partition table that can be exported to the mesh builder.
Teuchos::ParameterList pList_Type
std::vector< Int > M_elementParts
std::vector< LifeV::Int > idList_Type
Definition: GraphUtil.hpp:60
virtual const UInt numParts() const
Return the number of parts.
Int numProcessors() const
The number of processes in the comm.
Int firstIndex(const Int i) const
First global index that is initially assigned to process i.
const std::vector< Int > & elementParts() const
The vector of stored element partitions.
void localMigrate(int numExport, ZOLTAN_ID_PTR exportLocalGids, int *exportProcs, int *exportToPart)
Migrate elements between locally stored partitions.
GraphCutterZoltan(meshPtr_Type &mesh, commPtr_Type &comm, pList_Type &parameters)
std::vector< Int > M_indexBounds
UInt numStoredElements() const
Get number of stored graph elements.
std::vector< Int > & elementList()
The vector of stored element GIDs (non-const)
void buildGraph()
Build the dual graph of the unpartitioned mesh.
static void getNumNeighboursList(void *data, int sizeGID, int sizeLID, int num_obj, ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID, int *numEdges, int *ierr)
virtual Int run()
Performs the graph partitioning.
Class that partitions the graph associated with a mesh.
virtual void setParameters(pList_Type &parameters)
Set values for all the parameters, with default values where needed.
const ID NotAnId
Definition: LifeV.hpp:264
static void getNeighbourList(void *data, int sizeGID, int sizeLID, int num_obj, ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID, int *num_edges, ZOLTAN_ID_PTR nborGID, int *nborProc, int wgt_dim, float *ewgts, int *ierr)
std::shared_ptr< idTable_Type > idTablePtr_Type
Definition: GraphUtil.hpp:63
Int lastIndex(const Int i) const
Last global index that is initially assigned to process i.
static int getNumElements(void *data, int *ierr)
static void packObjects(void *data, int num_gid_entries, int num_lid_entries, int num_ids, ZOLTAN_ID_PTR global_ids, ZOLTAN_ID_PTR local_ids, int *dest, int *sizes, int *idx, char *buf, int *ierr)
void partitionGraph()
Partition the graph.
struct Zoltan_Struct * M_zoltanStruct
virtual idListPtr_Type & getPart(const UInt i)
std::shared_ptr< Epetra_Comm > commPtr_Type
const std::vector< Int > & elementList() const
The vector of stored element GIDs.
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191
const table_Type & graph() const
The internally stored dual graph of the mesh.
virtual ~GraphCutterZoltan()
Destructor.
std::shared_ptr< idList_Type > idListPtr_Type
Definition: GraphUtil.hpp:61
static void getTransferObjectSizes(void *data, int num_gid_entries, int num_lid_entries, int num_ids, ZOLTAN_ID_PTR global_ids, ZOLTAN_ID_PTR local_ids, int *sizes, int *ierr)
std::shared_ptr< mesh_Type > meshPtr_Type