LifeV
GraphUtil.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 Utilitary functions and type definitions for graph partitioning
30 
31  @date 2013-12-03
32  @author Radu Popescu <radu.popescu@epfl.ch>
33  */
34 
35 #ifndef GRAPH_UTIL_H
36 #define GRAPH_UTIL_H 1
37 
38 #include <vector>
39 
40 #include <parmetis.h>
41 
42 #include <boost/shared_ptr.hpp>
43 #include <boost/bimap.hpp>
44 #include <Epetra_MpiComm.h>
45 #include <Epetra_SerialComm.h>
46 #include <Epetra_BlockMap.h>
47 #include <Epetra_CrsGraph.h>
48 #include <Teuchos_ParameterList.hpp>
49 #include <Teuchos_RCP.hpp>
50 
51 #include <lifev/core/LifeV.hpp>
52 
53 namespace LifeV
54 {
55 namespace GraphUtil
56 {
57 
58 // Public typedefs
64 typedef std::set<Int> idSet_Type;
70 
71 //! Function that partitions a graph of a subset of elements in a mesh
72 /*!
73  @author Radu Popescu <radu.popescu@epfl.ch>
74 
75  This function partitions a graph (described by a list of mesh element IDs
76  and a mesh object) into a given number of parts, using ParMETIS.
77 
78  Serial or parallel operation is imposed by passing a pointer to an
79  Epetra_Comm object.
80 
81  \param vertexList - list (as an idListPtr_Type) of mesh element GIDs representing
82  the graph vertices of the graph which is partitioned
83  \param mesh - mesh object which is used for computing the connectivity of the
84  graph
85  \param params - Teuchos::ParameterList with the configuration parameters. Currently
86  only "num-parts" (Int) is used, but the parameter list container
87  allows for introducing new configuration parameters
88  \param vertexPartition - table with the vertex ids in each graph part
89  */
90 template <typename MeshType>
91 void partitionGraphParMETIS (const idListPtr_Type& vertexList,
92  const MeshType& mesh,
93  const Teuchos::ParameterList& params,
94  idTablePtr_Type& vertexPartition,
95  commPtr_Type& comm);
96 
97 template <typename MeshType>
98 void partitionGraphParMETIS (const idListPtr_Type& vertexList,
99  const MeshType& mesh,
100  const Teuchos::ParameterList& params,
101  idTablePtr_Type& vertexPartition,
102  commPtr_Type& comm)
103 {
104  Int numProc = comm->NumProc();
105  Int myPID = comm->MyPID();
106 
107  // We build a bidirectional map of vertex Id, for local-to-global and
108  // global-to-local lookups
109  UInt numVertices = vertexList->size();
110  biMap_Type vertexIdMap;
111  for (UInt i = 0; i < numVertices; ++i)
112  {
113  vertexIdMap.insert (biMapValue_Type (i, vertexList->at (i) ) );
114  }
115 
116  // A graph is built over the data structure to be split, each vertex being
117  // a mesh element so hereby a "vertex" is actually a _graph_ vertex,
118  // i. e. a mesh element
119  std::vector<Int> vertexDistribution (numProc + 1);
120  vertexDistribution[0] = 0;
121  UInt k = numVertices;
122  // Evenly distributed graph vertices
123  for (Int i = 0; i < numProc; ++i)
124  {
125  UInt l = k / (numProc - i);
126  vertexDistribution[i + 1] = vertexDistribution[i] + l;
127  k -= l;
128  }
129 
130  /*
131  * Partition Graph
132  * This array's size is equal to the number of locally-stored vertices:
133  * at the end of the partitioning process, "M_graphVertexLocations" will
134  * contain the partitioning array:
135  * M_graphVertexLocations[m] = n; means that graph vertex m belongs to
136  * subdomain n
137  */
138  std::vector<Int> vertexLocations (vertexDistribution[numProc]
139  - vertexDistribution[0], numProc);
140  UInt localStart = vertexDistribution[myPID];
141  UInt localEnd = vertexDistribution[myPID + 1];
142 
143 
144  // this vector contains the weights for the edges of the graph,
145  // it is set to null if it is not used.
146  std::vector<Int> graphEdgeWeights;
147  std::vector<Int> adjacencyGraphKeys (1, 0);
148  std::vector<Int> adjacencyGraphValues (0);
149 
150  UInt sum = 0;
151 
152  UInt elementFacets = MeshType::elementShape_Type::S_numFacets;
153 
154  for (UInt lid = localStart; lid < localEnd; ++lid)
155  {
156  for (UInt ifacet = 0; ifacet < elementFacets; ++ifacet)
157  {
158  UInt gid = vertexIdMap.left.at (lid);
159  // global ID of the ifacet-th facet in element ie
160  UInt facet = mesh.localFacetId (gid, ifacet);
161  // first adjacent element to face "facet"
162  UInt elem = mesh.facet (facet).firstAdjacentElementIdentity();
163  if (elem == gid)
164  {
165  elem = mesh.facet (facet).secondAdjacentElementIdentity();
166  }
167  biMap_Type::right_const_iterator it = vertexIdMap.right.find (elem);
168 
169  bool inSubGraph = (vertexIdMap.right.end() != it);
170  if ( (elem != NotAnId) && (inSubGraph) )
171  {
172  // this is the list of adjacency
173  // for each graph vertex, push back the ID of its neighbors
174  //adjacencyGraphValues.push_back(it - vertexMap.right.begin());
175  adjacencyGraphValues.push_back (it->second);
176  ++sum;
177  }
178  }
179  // this is the list of "keys" to access M_adjacencyGraphValues
180  // graph element i has neighbors M_adjacencyGraphValues[ k ],
181  // with M_adjacencyGraphKeys[i] <= k < M_adjacencyGraphKeys[i+1]
182  adjacencyGraphKeys.push_back (sum);
183  }
184 
185  // **************
186  // parMetis part
187 
188  Int* weightVector = 0;
189  Int weightFlag = 0;
190  Int ncon = 1;
191  Int numflag = 0;
192  Int cutGraphEdges;
193 
194  // additional options
195  Int options[3] = {1, 3, 1};
196 
197  // fraction of vertex weight to be distributed to each subdomain.
198  // here we want the subdomains to be of the same size
199  Int numParts = params.get<Int> ("num-parts");
200  std::vector<float> tpwgts (ncon * numParts, 1. / numParts);
201  // imbalance tolerance for each vertex weight
202  std::vector<float> ubvec (ncon, 1.05);
203 
204  std::shared_ptr<Epetra_MpiComm> mpiComm
205  = std::dynamic_pointer_cast <Epetra_MpiComm> (comm);
206  MPI_Comm MPIcomm = mpiComm->Comm();
207 
208  Int* adjwgtPtr (0);
209  if (graphEdgeWeights.size() > 0)
210  {
211  adjwgtPtr = static_cast<Int*> (&graphEdgeWeights[0]);
212  }
213  ParMETIS_V3_PartKway (static_cast<Int*> (&vertexDistribution[0]),
214  static_cast<Int*> (&adjacencyGraphKeys[0]),
215  static_cast<Int*> (&adjacencyGraphValues[0]),
216  weightVector, adjwgtPtr, &weightFlag, &numflag,
217  &ncon, &numParts, &tpwgts[0], &ubvec[0],
218  &options[0], &cutGraphEdges,
219  &vertexLocations[localStart],
220  &MPIcomm);
221 
222  // distribute the resulting partitioning stored in M_graphVertexLocations
223  // to all processors
224  if (numProc != 1)
225  {
226  comm->Barrier();
227  for (Int proc = 0; proc < numProc; proc++)
228  {
229  UInt procStart = vertexDistribution[proc];
230  UInt procLength = vertexDistribution[proc + 1]
231  - vertexDistribution[proc];
232  comm->Broadcast (&vertexLocations[procStart], procLength, proc);
233  }
234  }
235 
236  idTablePtr_Type vertexIds (new idTable_Type (numParts) );
237  // cycling on locally stored vertices
238  for (Int i = 0; i < numParts; ++i)
239  {
240  vertexIds->at (i).reset (new idList_Type (0) );
241  vertexIds->at (i)->reserve (vertexLocations.size() / numParts);
242  }
243  for (UInt ii = 0; ii < vertexLocations.size(); ++ii)
244  {
245  // here we are associating the vertex global ID to the subdomain ID
246  vertexIds->at (vertexLocations[ii])->push_back (vertexIdMap.left.at (ii) );
247  }
248 
249  vertexPartition = vertexIds;
250 }
251 
252 } // Namespace GraphUtil
253 
254 } // Namepsace LifeV
255 
256 #endif // GRAPH_UTIL_H
biMap_Type::value_type biMapValue_Type
Definition: GraphUtil.hpp:69
std::set< Int > idSet_Type
Definition: GraphUtil.hpp:64
std::shared_ptr< Epetra_Comm > commPtr_Type
Definition: GraphUtil.hpp:59
std::vector< idListPtr_Type > idTable_Type
Definition: GraphUtil.hpp:62
int32_type Int
Generic integer data.
Definition: LifeV.hpp:188
void updateInverseJacobian(const UInt &iQuadPt)
std::vector< LifeV::Int > idList_Type
Definition: GraphUtil.hpp:60
void partitionGraphParMETIS(const idListPtr_Type &vertexList, const MeshType &mesh, const Teuchos::ParameterList &params, idTablePtr_Type &vertexPartition, commPtr_Type &comm)
Function that partitions a graph of a subset of elements in a mesh.
Definition: GraphUtil.hpp:98
std::vector< idSetPtr_Type > idSetGroup_Type
Definition: GraphUtil.hpp:66
boost::bimap< LifeV::UInt, LifeV::UInt > biMap_Type
Definition: GraphUtil.hpp:68
std::shared_ptr< idSetGroup_Type > idSetGroupPtr_Type
Definition: GraphUtil.hpp:67
std::shared_ptr< idSet_Type > idSetPtr_Type
Definition: GraphUtil.hpp:65
const ID NotAnId
Definition: LifeV.hpp:264
std::shared_ptr< idTable_Type > idTablePtr_Type
Definition: GraphUtil.hpp:63
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191
std::shared_ptr< idList_Type > idListPtr_Type
Definition: GraphUtil.hpp:61