OpenFPM_pdata  1.1.0
Project that contain the implementation of distributed structures
 All Data Structures Namespaces Functions Variables Typedefs Enumerations Friends Pages
parmetis_util.hpp
1 /*
2  * parmetis_util.hpp
3  *
4  * Created on: Oct 07, 2015
5  * Author: Antonio Leo
6  */
7 
8 #ifndef PARMETIS_UTIL_HPP
9 #define PARMETIS_UTIL_HPP
10 
11 #include <iostream>
12 #include "parmetis.h"
13 #include "VTKWriter/VTKWriter.hpp"
14 #include "VCluster/VCluster.hpp"
15 #include "Graph/ids.hpp"
16 
17 #define PARMETIS_ERROR_OBJECT std::runtime_error("Runtime Parmetis error");
18 
19 
26 {
28  idx_t * nvtxs;
29 
34  idx_t * ncon;
35 
37  idx_t * xadj;
38 
40  idx_t * adjncy;
41 
43  idx_t * vwgt;
44 
46  idx_t * vsize;
47 
49  idx_t * adjwgt;
50 
52  idx_t * nparts;
53 
55  real_t * tpwgts;
56 
58  real_t * ubvec;
59 
61  idx_t * options;
62 
64  idx_t * objval;
65 
67  idx_t * part;
68 
70  idx_t * edgecut;
71 
73  real_t * itr;
74 
76  idx_t * numflag;
77 
79  // 0 No weights (vwgt and adjwgt are both NULL).
80  // 1 Weights on the edges only (vwgt is NULL).
81  // 2 Weights on the vertices only (adjwgt is NULL).
82  // 3 Weights on both the vertices and edges.
83  idx_t * wgtflag;
84 };
85 
87 #define BALANCE_CC 1
88 #define BALANCE_CCM 2
90 #define BALANCE_CC_O(c) c+1
92 
98 template<typename Graph>
99 class Parmetis
100 {
103 
104  // Original graph
105  // Graph & g;
106 
108  MPI_Comm comm = (MPI_Comm)NULL;
109 
112 
114  int p_id = 0;
115 
117  size_t nc = 0;
118 
121 
124 
126  size_t nvertex;
127 
129  size_t n_dec;
130 
132  real_t dist_tol = 1.05;
133 
140  void constructAdjList(Graph &g, const std::unordered_map<rid, gid> & m2g)
141  {
142  // init basic graph informations and part vector
143  // Put the total communication size to NULL
144 
145  Mg.nvtxs[0] = nvertex;
146  Mg.part = new idx_t[nvertex];
147 
148  size_t nedge = 0;
149  size_t i = 0;
150  for (rid j = first; i < nvertex; i++, ++j)
151  {
152  Mg.part[i] = p_id;
153  nedge += g.getNChilds(m2g.find(j)->second.id);
154  }
155 
156  // create xadj, adjlist, vwgt, adjwgt and vsize
157  Mg.xadj = new idx_t[nvertex + 1];
158  Mg.adjncy = new idx_t[nedge];
159  Mg.vwgt = new idx_t[nvertex];
160  Mg.adjwgt = new idx_t[nedge];
161  Mg.vsize = new idx_t[nvertex];
162 
164  size_t prev = 0;
165 
166  // actual position
167  size_t id = 0;
168 
169  size_t j = 0;
170 
171  // for each vertex calculate the position of the starting point in the adjacency list
172  for (rid i = first; i <= last; ++i, j++)
173  {
174  gid idx = m2g.find(i)->second;
175 
176  // Add weight to vertex and migration cost
177  Mg.vwgt[j] = g.vertex(idx.id).template get<nm_v::computation>();
178  Mg.vsize[j] = g.vertex(idx.id).template get<nm_v::migration>();
179 
180  // Calculate the starting point in the adjacency list
181  Mg.xadj[id] = prev;
182 
183  // Create the adjacency list and the weights for edges
184  for (size_t s = 0; s < g.getNChilds(idx.id); s++)
185  {
186 
187  size_t child = g.getChild(idx.id, s);
188 
189  Mg.adjncy[prev + s] = g.vertex(child).template get<nm_v::id>();
190  Mg.adjwgt[prev + s] = g.getChildEdge(idx.id, s).template get<nm_e::communication>();
191  }
192 
193  // update the position for the next vertex
194  prev += g.getNChilds(idx.id);
195 
196  id++;
197  }
198 
199  // Fill the last point
200  Mg.xadj[id] = prev;
201  }
202 
203 public:
204 
214  :v_cl(v_cl), nc(nc),n_dec(0)
215  {
216 #ifdef SE_CLASS1
217 
218  if (sizeof(idx_t) != 8)
219  {
220  std::cerr << __FILE__ << ":" << __LINE__ << " Error detected invalid installation of Parmetis. OpenFPM support Parmetis/Metis version with 64 bit idx_t" << std::endl;
221  ACTION_ON_ERROR(PARMETIS_ERROR_OBJECT);
222  }
223 
224 #endif
225 
226  // TODO Move into VCluster
227  MPI_Comm_dup(MPI_COMM_WORLD, &comm);
228 
229  // Nullify Mg
230  Mg.nvtxs = NULL;
231  Mg.ncon = NULL;
232  Mg.xadj = NULL;
233  Mg.adjncy = NULL;
234  Mg.vwgt = NULL;
235  Mg.vsize = NULL;
236  Mg.adjwgt = NULL;
237  Mg.nparts = NULL;
238  Mg.tpwgts = NULL;
239  Mg.ubvec = NULL;
240  Mg.options = NULL;
241  Mg.objval = NULL;
242  Mg.part = NULL;
243  Mg.edgecut = NULL;
244  Mg.itr = NULL;
245  Mg.numflag = NULL;
246  Mg.wgtflag = NULL;
247  first.id = 0;
248  last.id = 0;
249  nvertex = 0;
250  }
251 
258  {
259  // Deallocate the Mg structure
260  if (Mg.nvtxs != NULL)
261  {
262  delete[] Mg.nvtxs;
263  }
264 
265  if (Mg.ncon != NULL)
266  {
267  delete[] Mg.ncon;
268  }
269 
270  if (Mg.xadj != NULL)
271  {
272  delete[] Mg.xadj;
273  }
274 
275  if (Mg.adjncy != NULL)
276  {
277  delete[] Mg.adjncy;
278  }
279 
280  if (Mg.vwgt != NULL)
281  {
282  delete[] Mg.vwgt;
283  }
284 
285  if (Mg.adjwgt != NULL)
286  {
287  delete[] Mg.adjwgt;
288  }
289 
290  if (Mg.nparts != NULL)
291  {
292  delete[] Mg.nparts;
293  }
294 
295  if (Mg.tpwgts != NULL)
296  {
297  delete[] Mg.tpwgts;
298  }
299 
300  if (Mg.ubvec != NULL)
301  {
302  delete[] Mg.ubvec;
303  }
304 
305  if (Mg.options != NULL)
306  {
307  delete[] Mg.options;
308  }
309 
310  if (Mg.part != NULL)
311  {
312  delete[] Mg.part;
313  }
314 
315  if (Mg.edgecut != NULL)
316  {
317  delete[] Mg.edgecut;
318  }
319 
320  if (Mg.numflag != NULL)
321  {
322  delete[] Mg.numflag;
323  }
324 
325  if (Mg.wgtflag != NULL)
326  {
327  delete[] Mg.wgtflag;
328  }
329 
330  if (is_openfpm_init() == true)
331  MPI_Comm_free(&comm);
332  }
333 
342  void initSubGraph(Graph & g,
343  const openfpm::vector<rid> & vtxdist,
344  const std::unordered_map<rid, gid> & m2g,
345  bool w)
346  {
348 
349  first = vtxdist.get(p_id);
350  last = vtxdist.get(p_id + 1) - 1;
351  nvertex = last.id - first.id + 1;
352 
354 
355  // construct the adjacency list
356  constructAdjList(g, m2g);
357 
358  //reset(g, vtxdist, m2g, w);
359  }
360 
366  void decompose(const openfpm::vector<rid> & vtxdist)
367  {
368  // Decompose
369 
370  ParMETIS_V3_PartKway((idx_t *) vtxdist.getPointer(), Mg.xadj, Mg.adjncy, Mg.vwgt, Mg.adjwgt, Mg.wgtflag, Mg.numflag, Mg.ncon, Mg.nparts, Mg.tpwgts, Mg.ubvec, Mg.options, Mg.edgecut, Mg.part, &comm);
371 
372  n_dec++;
373  }
374 
380  void refine(openfpm::vector<rid> & vtxdist)
381  {
382  // Refine
383 
384  ParMETIS_V3_RefineKway((idx_t *) vtxdist.getPointer(), Mg.xadj, Mg.adjncy, Mg.vwgt, Mg.adjwgt, Mg.wgtflag, Mg.numflag, Mg.ncon, Mg.nparts, Mg.tpwgts, Mg.ubvec, Mg.options, Mg.edgecut, Mg.part, &comm);
385 
386  n_dec++;
387  }
388 
395  {
396  ParMETIS_V3_AdaptiveRepart((idx_t *)vtxdist.getPointer(), Mg.xadj, Mg.adjncy, Mg.vwgt, Mg.vsize, Mg.adjwgt, Mg.wgtflag, Mg.numflag, Mg.ncon, Mg.nparts, Mg.tpwgts, Mg.ubvec, Mg.itr, Mg.options, Mg.edgecut, Mg.part, &comm);
397 
398  n_dec++;
399  }
400 
404  idx_t* getPartition()
405  {
406  return Mg.part;
407  }
408 
416  void reset(Graph & g, const openfpm::vector<rid> & vtxdist, const std::unordered_map<rid, gid> & m2g, bool vgw)
417  {
418  first = vtxdist.get(p_id);
419  last = vtxdist.get(p_id + 1) - 1;
420  nvertex = last.id - first.id + 1;
421 
422  // Deallocate the graph structures
423 
424  if (Mg.xadj != NULL)
425  {
426  delete[] Mg.xadj;
427  }
428 
429  if (Mg.adjncy != NULL)
430  {
431  delete[] Mg.adjncy;
432  }
433 
434  if (Mg.vwgt != NULL)
435  {
436  delete[] Mg.vwgt;
437  }
438 
439  if (Mg.adjwgt != NULL)
440  {
441  delete[] Mg.adjwgt;
442  }
443 
444  if (Mg.part != NULL)
445  {
446  delete[] Mg.part;
447  }
448 
450 
451  // construct the adjacency list
452  constructAdjList(g, m2g);
453  }
454 
459  void setDefaultParameters(bool w)
460  {
461  Mg.nvtxs = new idx_t[1];
462 
463  // Set the number of constrains
464  Mg.ncon = new idx_t[1];
465  Mg.ncon[0] = 1;
466 
467  // Set to null the weight of the vertex (init after in constructAdjList) (can be removed)
468  Mg.vwgt = NULL;
469 
470  // Set to null the weight of the edge (init after in constructAdjList) (can be removed)
471  Mg.adjwgt = NULL;
472 
473  // Set the total number of partitions
474  Mg.nparts = new idx_t[1];
475  Mg.nparts[0] = nc;
476 
478 
479  Mg.options = new idx_t[4];
480  Mg.options[0] = 0;
481  Mg.options[1] = 0;
482  Mg.options[2] = 0;
483  Mg.options[3] = 0;
484 
486 
488  Mg.itr = new real_t[1];
489  Mg.itr[0] = 1000.0;
490 
491  Mg.objval = new idx_t[1];
492 
494 
495  Mg.tpwgts = new real_t[Mg.nparts[0]];
496  Mg.ubvec = new real_t[Mg.nparts[0]];
497 
498  for (size_t s = 0; s < (size_t) Mg.nparts[0]; s++)
499  {
500  Mg.tpwgts[s] = 1.0 / Mg.nparts[0];
501  Mg.ubvec[s] = dist_tol;
502  }
503 
504  Mg.edgecut = new idx_t[1];
505  Mg.edgecut[0] = 0;
506 
508  Mg.numflag = new idx_t[1];
509  Mg.numflag[0] = 0;
510 
512  Mg.wgtflag = new idx_t[1];
513 
514  if (w)
515  Mg.wgtflag[0] = 3;
516  else
517  Mg.wgtflag[0] = 0;
518  }
519 
528  {
529  MPI_Comm_dup(pm.comm, &comm);
530  p_id = pm.p_id;
531  nc = pm.nc;
532  n_dec = pm.n_dec;
533  dist_tol = pm.dist_tol;
534 
535  setDefaultParameters(pm.Mg.wgtflag[0] == 3);
536 
537  return *this;
538  }
539 
548  {
549  // TODO Move into VCluster
550  MPI_Comm_dup(pm.comm, &comm);
551  p_id = pm.p_id;
552  nc = pm.nc;
553  n_dec = pm.n_dec;
554  dist_tol = pm.dist_tol;
555 
556  setDefaultParameters(pm.Mg.wgtflag[0] == 3);
557 
558  return *this;
559  }
560 
566  size_t get_ndec()
567  {
568  return n_dec;
569  }
570 
576  void setDistTol(real_t tol)
577  {
578  dist_tol = tol;
579  }
580 };
581 
582 #endif
const Parmetis< Graph > & operator=(Parmetis< Graph > &&pm)
Copy the object.
void refine(openfpm::vector< rid > &vtxdist)
Refine the graph.
void decompose(const openfpm::vector< rid > &vtxdist)
Decompose the graph.
rid last
last re-mapped id
idx_t * xadj
For each vertex it store the adjacency lost start for the vertex i.
size_t getProcessUnitID()
Get the process unit id.
idx_t * part
Is a output vector containing the partition for each vertex.
void setDistTol(real_t tol)
Distribution tolerance.
idx_t * adjncy
For each vertex it store a list of all neighborhood vertex.
void initSubGraph(Graph &g, const openfpm::vector< rid > &vtxdist, const std::unordered_map< rid, gid > &m2g, bool w)
Set the Sub-graph.
const Parmetis< Graph > & operator=(const Parmetis< Graph > &pm)
Copy the object.
size_t get_ndec()
Get the decomposition counter.
idx_t * vsize
Array of the vertex size, basically is the total communication amount.
Helper class to define Metis graph.
void redecompose(openfpm::vector< rid > &vtxdist)
Redecompose the graph.
real_t * itr
This parameter describes the ratio of inter-processor communication time compared to data redistri- b...
idx_t * adjwgt
The weight of the edge.
Implementation of VCluster class.
Definition: VCluster.hpp:36
idx_t * nvtxs
The number of vertices in the graph.
idx_t * wgtflag
This is used to indicate if the graph is weighted. wgtflag can take one of four values: ...
size_t nc
nc Number of partition
idx_t * options
Additional option for the graph partitioning.
void reset(Graph &g, const openfpm::vector< rid > &vtxdist, const std::unordered_map< rid, gid > &m2g, bool vgw)
Reset graph and reconstruct it.
idx_t * edgecut
Upon successful completion, the number of edges that are cut by the partitioning is written to this p...
Metis graph structure.
idx_t * numflag
This is used to indicate the numbering scheme that is used for the vtxdist, xadj, adjncy...
real_t * ubvec
For each partition load imbalance tollerated.
idx_t * nparts
number of part to partition the graph
void constructAdjList(Graph &g, const std::unordered_map< rid, gid > &m2g)
Construct Adjacency list.
rid first
first re-mapped id
idx_t * objval
return the total comunication cost for each partition
Vcluster & v_cl
VCluster.
size_t nvertex
number of vertices that the processor has
real_t * tpwgts
Desired weight for each partition (one for each constrain)
Parmetis_graph Mg
Graph in metis reppresentation.
idx_t * vwgt
Array that store the weight for each vertex.
real_t dist_tol
Distribution tolerance.
idx_t id
id
Definition: ids.hpp:21
Definition: ids.hpp:18
Definition: ids.hpp:148
MPI_Comm comm
Communticator for OpenMPI.
Parmetis(Vcluster &v_cl, size_t nc)
Constructor.
void setDefaultParameters(bool w)
Seth the default parameters for parmetis.
int p_id
Process rank information.
~Parmetis()
destructor
idx_t * getPartition()
Get graph partition vector.
size_t n_dec
indicate how many time decompose/refine/re-decompose has been called