OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
 
Loading...
Searching...
No Matches
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
89#define BALANCE_CCM 2
91#define BALANCE_CC_O(c) c+1
92
98template<typename Graph>
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
215public:
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
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
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
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
Helper class to define Metis graph.
MPI_Comm comm
Communticator for OpenMPI.
size_t nc
nc Number of partition
void constructAdjList(Graph &g, const std::unordered_map< rid, gid > &m2g)
Construct Adjacency list.
size_t get_ndec()
Get the decomposition counter.
void redecompose(openfpm::vector< rid > &vtxdist)
Redecompose the graph.
size_t nvertex
number of vertices that the processor has
~Parmetis()
destructor
Parmetis(Vcluster<> &v_cl, size_t nc)
Constructor.
real_t dist_tol
Distribution tolerance.
void reset(Graph &g, const openfpm::vector< rid > &vtxdist, const std::unordered_map< rid, gid > &m2g, bool vgw)
Reset graph and reconstruct it.
rid first
first re-mapped id
const Parmetis< Graph > & operator=(Parmetis< Graph > &&pm)
Copy the object.
const Parmetis< Graph > & operator=(const Parmetis< Graph > &pm)
Copy the object.
Vcluster & v_cl
VCluster.
size_t n_dec
indicate how many time decompose/refine/re-decompose has been called
idx_t * getPartition()
Get graph partition vector.
void setDefaultParameters(bool w)
Seth the default parameters for parmetis.
void setDistTol(real_t tol)
Distribution tolerance.
void refine(openfpm::vector< rid > &vtxdist)
Refine the graph.
void initSubGraph(Graph &g, const openfpm::vector< rid > &vtxdist, const std::unordered_map< rid, gid > &m2g, bool w)
Set the Sub-graph.
void decompose(const openfpm::vector< rid > &vtxdist)
Decompose the graph.
rid last
last re-mapped id
int p_id
Process rank information.
Parmetis_graph Mg
Graph in metis reppresentation.
size_t getProcessUnitID()
Get the process unit id.
Implementation of VCluster class.
Definition VCluster.hpp:59
Implementation of 1-D std::vector like structure.
Metis graph structure.
idx_t * adjncy
For each vertex it store a list of all neighborhood vertex.
real_t * itr
This parameter describes the ratio of inter-processor communication time compared to data redistri- b...
idx_t * part
Is a output vector containing the partition for each vertex.
idx_t * edgecut
Upon successful completion, the number of edges that are cut by the partitioning is written to this p...
idx_t * vwgt
Array that store the weight for each vertex.
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 * vsize
Array of the vertex size, basically is the total communication amount.
idx_t * adjwgt
The weight of the edge.
idx_t * nvtxs
The number of vertices in the graph.
idx_t * xadj
For each vertex it store the adjacency lost start for the vertex i.
idx_t * wgtflag
This is used to indicate if the graph is weighted. wgtflag can take one of four values:
idx_t * options
Additional option for the graph partitioning.
idx_t * objval
return the total comunication cost for each partition
real_t * tpwgts
Desired weight for each partition (one for each constrain)
idx_t * nparts
number of part to partition the graph
Definition ids.hpp:149
Definition ids.hpp:19
idx_t id
id
Definition ids.hpp:21