OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
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  if (Mg.part != NULL)
147  {delete[] Mg.part;}
148  Mg.part = new idx_t[nvertex];
149 
150  size_t nedge = 0;
151  size_t i = 0;
152  for (rid j = first; i < nvertex; i++, ++j)
153  {
154  Mg.part[i] = p_id;
155  nedge += g.getNChilds(m2g.find(j)->second.id);
156  }
157 
158  // create xadj, adjlist, vwgt, adjwgt and vsize
159  if (Mg.xadj != NULL)
160  {delete[] Mg.xadj;}
161  if (Mg.adjncy != NULL)
162  {delete[] Mg.adjncy;}
163  if (Mg.vwgt != NULL)
164  {delete[] Mg.vwgt;}
165  if (Mg.adjwgt != NULL)
166  {delete[] Mg.adjwgt;}
167  if (Mg.vsize != NULL)
168  {delete[] Mg.vsize;}
169  Mg.xadj = new idx_t[nvertex + 1];
170  Mg.adjncy = new idx_t[nedge];
171  Mg.vwgt = new idx_t[nvertex];
172  Mg.adjwgt = new idx_t[nedge];
173  Mg.vsize = new idx_t[nvertex];
174 
176  size_t prev = 0;
177 
178  // actual position
179  size_t id = 0;
180 
181  size_t j = 0;
182 
183  // for each vertex calculate the position of the starting point in the adjacency list
184  for (rid i = first; i <= last; ++i, j++)
185  {
186  gid idx = m2g.find(i)->second;
187 
188  // Add weight to vertex and migration cost
189  Mg.vwgt[j] = g.vertex(idx.id).template get<nm_v_computation>();
190  Mg.vsize[j] = g.vertex(idx.id).template get<nm_v_migration>();
191 
192  // Calculate the starting point in the adjacency list
193  Mg.xadj[id] = prev;
194 
195  // Create the adjacency list and the weights for edges
196  for (size_t s = 0; s < g.getNChilds(idx.id); s++)
197  {
198 
199  size_t child = g.getChild(idx.id, s);
200 
201  Mg.adjncy[prev + s] = g.vertex(child).template get<nm_v_id>();
202  Mg.adjwgt[prev + s] = g.getChildEdge(idx.id, s).template get<nm_e::communication>();
203  }
204 
205  // update the position for the next vertex
206  prev += g.getNChilds(idx.id);
207 
208  id++;
209  }
210 
211  // Fill the last point
212  Mg.xadj[id] = prev;
213  }
214 
215 public:
216 
226  :v_cl(v_cl), nc(nc),n_dec(0)
227  {
228 #ifdef SE_CLASS1
229 
230  if (sizeof(idx_t) != 8)
231  {
232  std::cerr << __FILE__ << ":" << __LINE__ << " Error detected invalid installation of Parmetis. OpenFPM support Parmetis/Metis version with 64 bit idx_t" << std::endl;
233  ACTION_ON_ERROR(PARMETIS_ERROR_OBJECT);
234  }
235 
236 #endif
237 
238  // TODO Move into VCluster
239  MPI_Comm_dup(MPI_COMM_WORLD, &comm);
240 
241  // Nullify Mg
242  Mg.nvtxs = NULL;
243  Mg.ncon = NULL;
244  Mg.xadj = NULL;
245  Mg.adjncy = NULL;
246  Mg.vwgt = NULL;
247  Mg.vsize = NULL;
248  Mg.adjwgt = NULL;
249  Mg.nparts = NULL;
250  Mg.tpwgts = NULL;
251  Mg.ubvec = NULL;
252  Mg.options = NULL;
253  Mg.objval = NULL;
254  Mg.part = NULL;
255  Mg.edgecut = NULL;
256  Mg.itr = NULL;
257  Mg.numflag = NULL;
258  Mg.wgtflag = NULL;
259  first.id = 0;
260  last.id = 0;
261  nvertex = 0;
262  }
263 
270  {
271  // Deallocate the Mg structure
272  if (Mg.nvtxs != NULL)
273  {
274  delete[] Mg.nvtxs;
275  }
276 
277  if (Mg.ncon != NULL)
278  {
279  delete[] Mg.ncon;
280  }
281 
282  if (Mg.xadj != NULL)
283  {
284  delete[] Mg.xadj;
285  }
286 
287  if (Mg.adjncy != NULL)
288  {
289  delete[] Mg.adjncy;
290  }
291 
292  if (Mg.vwgt != NULL)
293  {
294  delete[] Mg.vwgt;
295  }
296 
297  if (Mg.adjwgt != NULL)
298  {
299  delete[] Mg.adjwgt;
300  }
301 
302  if (Mg.nparts != NULL)
303  {
304  delete[] Mg.nparts;
305  }
306 
307  if (Mg.tpwgts != NULL)
308  {
309  delete[] Mg.tpwgts;
310  }
311 
312  if (Mg.ubvec != NULL)
313  {
314  delete[] Mg.ubvec;
315  }
316 
317  if (Mg.options != NULL)
318  {
319  delete[] Mg.options;
320  }
321 
322  if (Mg.part != NULL)
323  {
324  delete[] Mg.part;
325  }
326 
327  if (Mg.edgecut != NULL)
328  {
329  delete[] Mg.edgecut;
330  }
331 
332  if (Mg.numflag != NULL)
333  {
334  delete[] Mg.numflag;
335  }
336 
337  if (Mg.wgtflag != NULL)
338  {
339  delete[] Mg.wgtflag;
340  }
341 
342  if (Mg.itr != NULL)
343  {
344  delete[] Mg.itr;
345  }
346 
347  if (Mg.vsize != NULL)
348  {
349  delete[] Mg.vsize;
350  }
351 
352  if (Mg.objval != NULL)
353  {
354  delete[] Mg.objval;
355  }
356 
357  if (is_openfpm_init() == true)
358  {MPI_Comm_free(&comm);}
359  }
360 
369  void initSubGraph(Graph & g,
370  const openfpm::vector<rid> & vtxdist,
371  const std::unordered_map<rid, gid> & m2g,
372  bool w)
373  {
375 
376  first = vtxdist.get(p_id);
377  last = vtxdist.get(p_id + 1) - 1;
378  nvertex = last.id - first.id + 1;
379 
381 
382  // construct the adjacency list
383  constructAdjList(g, m2g);
384  }
385 
391  void decompose(const openfpm::vector<rid> & vtxdist)
392  {
393  // Decompose
394 
395  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);
396 
397  n_dec++;
398  }
399 
405  void refine(openfpm::vector<rid> & vtxdist)
406  {
407  // Refine
408 
409  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);
410 
411  n_dec++;
412  }
413 
420  {
421  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);
422 
423  n_dec++;
424  }
425 
429  idx_t* getPartition()
430  {
431  return Mg.part;
432  }
433 
441  void reset(Graph & g, const openfpm::vector<rid> & vtxdist, const std::unordered_map<rid, gid> & m2g, bool vgw)
442  {
443  first = vtxdist.get(p_id);
444  last = vtxdist.get(p_id + 1) - 1;
445  nvertex = last.id - first.id + 1;
446 
447  // Deallocate the graph structures
448 
450 
451  // construct the adjacency list
452  constructAdjList(g, m2g);
453  }
454 
459  void setDefaultParameters(bool w)
460  {
461  if (Mg.nvtxs != NULL)
462  {delete[] Mg.nvtxs;}
463  Mg.nvtxs = new idx_t[1];
464 
465  // Set the number of constrains
466  if (Mg.ncon != NULL)
467  {delete[] Mg.ncon;}
468  Mg.ncon = new idx_t[1];
469  Mg.ncon[0] = 1;
470 
471  // Set to null the weight of the vertex (init after in constructAdjList) (can be removed)
472  if (Mg.vwgt != NULL)
473  {delete[] Mg.vwgt;}
474  Mg.vwgt = NULL;
475 
476  // Set to null the weight of the edge (init after in constructAdjList) (can be removed)
477  if (Mg.adjwgt != NULL)
478  {delete[] Mg.adjwgt;}
479  Mg.adjwgt = NULL;
480 
481  // Set the total number of partitions
482  if (Mg.nparts != NULL)
483  {delete[] Mg.nparts;}
484  Mg.nparts = new idx_t[1];
485  Mg.nparts[0] = nc;
486 
488 
489  if (Mg.options != NULL)
490  {delete[] Mg.options;}
491  Mg.options = new idx_t[4];
492  Mg.options[0] = 0;
493  Mg.options[1] = 0;
494  Mg.options[2] = 0;
495  Mg.options[3] = 0;
496 
498 
500  if(Mg.itr != NULL)
501  {delete[] Mg.itr;}
502  Mg.itr = new real_t[1];
503  Mg.itr[0] = 1000.0;
504 
505  if (Mg.objval != NULL)
506  {delete[] Mg.objval;}
507  Mg.objval = new idx_t[1];
508 
510 
511  if (Mg.tpwgts != NULL)
512  {delete[] Mg.tpwgts;}
513  if (Mg.ubvec != NULL)
514  {delete[] Mg.ubvec;}
515  Mg.tpwgts = new real_t[Mg.nparts[0]];
516  Mg.ubvec = new real_t[Mg.nparts[0]];
517 
518  for (size_t s = 0; s < (size_t) Mg.nparts[0]; s++)
519  {
520  Mg.tpwgts[s] = 1.0 / Mg.nparts[0];
521  Mg.ubvec[s] = dist_tol;
522  }
523 
524  if (Mg.edgecut != NULL)
525  {delete[] Mg.edgecut;}
526  Mg.edgecut = new idx_t[1];
527  Mg.edgecut[0] = 0;
528 
530  if (Mg.numflag != NULL)
531  {delete[] Mg.numflag;}
532  Mg.numflag = new idx_t[1];
533  Mg.numflag[0] = 0;
534 
536  if (Mg.wgtflag != NULL)
537  {delete[] Mg.wgtflag;}
538  Mg.wgtflag = new idx_t[1];
539 
540  if (w)
541  Mg.wgtflag[0] = 3;
542  else
543  Mg.wgtflag[0] = 0;
544  }
545 
554  {
555  if (comm != MPI_COMM_NULL){MPI_Comm_free(&comm);}
556  MPI_Comm_dup(pm.comm, &comm);
557  p_id = pm.p_id;
558  nc = pm.nc;
559  n_dec = pm.n_dec;
560  dist_tol = pm.dist_tol;
561 
562  setDefaultParameters(pm.Mg.wgtflag[0] == 3);
563 
564  return *this;
565  }
566 
575  {
576  // TODO Move into VCluster
577  if (comm != MPI_COMM_NULL){MPI_Comm_free(&comm);}
578  MPI_Comm_dup(pm.comm, &comm);
579  p_id = pm.p_id;
580  nc = pm.nc;
581  n_dec = pm.n_dec;
582  dist_tol = pm.dist_tol;
583 
584  setDefaultParameters(pm.Mg.wgtflag[0] == 3);
585 
586  return *this;
587  }
588 
594  size_t get_ndec()
595  {
596  return n_dec;
597  }
598 
604  void setDistTol(real_t tol)
605  {
606  dist_tol = tol;
607  }
608 };
609 
610 #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.
size_t getProcessUnitID()
Get the process unit id.
rid last
last re-mapped id
idx_t * xadj
For each vertex it store the adjacency lost start for the vertex i.
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:58
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