xref: /petsc/src/dm/partitioner/impls/ptscotch/partptscotch.c (revision abe9303e6325b68e0d8957680d58b261e7a295d5)
1*abe9303eSLisandro Dalcin #include <petsc/private/partitionerimpl.h>        /*I "petscpartitioner.h" I*/
2*abe9303eSLisandro Dalcin 
3*abe9303eSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
4*abe9303eSLisandro Dalcin EXTERN_C_BEGIN
5*abe9303eSLisandro Dalcin #include <ptscotch.h>
6*abe9303eSLisandro Dalcin EXTERN_C_END
7*abe9303eSLisandro Dalcin #endif
8*abe9303eSLisandro Dalcin 
9*abe9303eSLisandro Dalcin PetscBool  PTScotchPartitionerCite = PETSC_FALSE;
10*abe9303eSLisandro Dalcin const char PTScotchPartitionerCitation[] =
11*abe9303eSLisandro Dalcin   "@article{PTSCOTCH,\n"
12*abe9303eSLisandro Dalcin   "  author  = {C. Chevalier and F. Pellegrini},\n"
13*abe9303eSLisandro Dalcin   "  title   = {{PT-SCOTCH}: a tool for efficient parallel graph ordering},\n"
14*abe9303eSLisandro Dalcin   "  journal = {Parallel Computing},\n"
15*abe9303eSLisandro Dalcin   "  volume  = {34},\n"
16*abe9303eSLisandro Dalcin   "  number  = {6},\n"
17*abe9303eSLisandro Dalcin   "  pages   = {318--331},\n"
18*abe9303eSLisandro Dalcin   "  year    = {2008},\n"
19*abe9303eSLisandro Dalcin   "  doi     = {https://doi.org/10.1016/j.parco.2007.12.001}\n"
20*abe9303eSLisandro Dalcin   "}\n";
21*abe9303eSLisandro Dalcin 
22*abe9303eSLisandro Dalcin typedef struct {
23*abe9303eSLisandro Dalcin   MPI_Comm  pcomm;
24*abe9303eSLisandro Dalcin   PetscInt  strategy;
25*abe9303eSLisandro Dalcin   PetscReal imbalance;
26*abe9303eSLisandro Dalcin } PetscPartitioner_PTScotch;
27*abe9303eSLisandro Dalcin 
28*abe9303eSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
29*abe9303eSLisandro Dalcin 
30*abe9303eSLisandro Dalcin #define CHKERRPTSCOTCH(ierr) do { if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error calling PT-Scotch library"); } while(0)
31*abe9303eSLisandro Dalcin 
32*abe9303eSLisandro Dalcin static int PTScotch_Strategy(PetscInt strategy)
33*abe9303eSLisandro Dalcin {
34*abe9303eSLisandro Dalcin   switch (strategy) {
35*abe9303eSLisandro Dalcin   case  0: return SCOTCH_STRATDEFAULT;
36*abe9303eSLisandro Dalcin   case  1: return SCOTCH_STRATQUALITY;
37*abe9303eSLisandro Dalcin   case  2: return SCOTCH_STRATSPEED;
38*abe9303eSLisandro Dalcin   case  3: return SCOTCH_STRATBALANCE;
39*abe9303eSLisandro Dalcin   case  4: return SCOTCH_STRATSAFETY;
40*abe9303eSLisandro Dalcin   case  5: return SCOTCH_STRATSCALABILITY;
41*abe9303eSLisandro Dalcin   case  6: return SCOTCH_STRATRECURSIVE;
42*abe9303eSLisandro Dalcin   case  7: return SCOTCH_STRATREMAP;
43*abe9303eSLisandro Dalcin   default: return SCOTCH_STRATDEFAULT;
44*abe9303eSLisandro Dalcin   }
45*abe9303eSLisandro Dalcin }
46*abe9303eSLisandro Dalcin 
47*abe9303eSLisandro Dalcin static PetscErrorCode PTScotch_PartGraph_Seq(SCOTCH_Num strategy, double imbalance, SCOTCH_Num n, SCOTCH_Num xadj[], SCOTCH_Num adjncy[],
48*abe9303eSLisandro Dalcin                                              SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num tpart[], SCOTCH_Num part[])
49*abe9303eSLisandro Dalcin {
50*abe9303eSLisandro Dalcin   SCOTCH_Graph   grafdat;
51*abe9303eSLisandro Dalcin   SCOTCH_Strat   stradat;
52*abe9303eSLisandro Dalcin   SCOTCH_Num     vertnbr = n;
53*abe9303eSLisandro Dalcin   SCOTCH_Num     edgenbr = xadj[n];
54*abe9303eSLisandro Dalcin   SCOTCH_Num*    velotab = vtxwgt;
55*abe9303eSLisandro Dalcin   SCOTCH_Num*    edlotab = adjwgt;
56*abe9303eSLisandro Dalcin   SCOTCH_Num     flagval = strategy;
57*abe9303eSLisandro Dalcin   double         kbalval = imbalance;
58*abe9303eSLisandro Dalcin   PetscErrorCode ierr;
59*abe9303eSLisandro Dalcin 
60*abe9303eSLisandro Dalcin   PetscFunctionBegin;
61*abe9303eSLisandro Dalcin   {
62*abe9303eSLisandro Dalcin     PetscBool flg = PETSC_TRUE;
63*abe9303eSLisandro Dalcin     ierr = PetscOptionsDeprecatedNoObject("-petscpartititoner_ptscotch_vertex_weight",NULL,"3.13","Use -petscpartitioner_use_vertex_weights");CHKERRQ(ierr);
64*abe9303eSLisandro Dalcin     ierr = PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_ptscotch_vertex_weight", &flg, NULL);CHKERRQ(ierr);
65*abe9303eSLisandro Dalcin     if (!flg) velotab = NULL;
66*abe9303eSLisandro Dalcin   }
67*abe9303eSLisandro Dalcin   ierr = SCOTCH_graphInit(&grafdat);CHKERRPTSCOTCH(ierr);
68*abe9303eSLisandro Dalcin   ierr = SCOTCH_graphBuild(&grafdat, 0, vertnbr, xadj, xadj + 1, velotab, NULL, edgenbr, adjncy, edlotab);CHKERRPTSCOTCH(ierr);
69*abe9303eSLisandro Dalcin   ierr = SCOTCH_stratInit(&stradat);CHKERRPTSCOTCH(ierr);
70*abe9303eSLisandro Dalcin   ierr = SCOTCH_stratGraphMapBuild(&stradat, flagval, nparts, kbalval);CHKERRPTSCOTCH(ierr);
71*abe9303eSLisandro Dalcin   if (tpart) {
72*abe9303eSLisandro Dalcin     SCOTCH_Arch archdat;
73*abe9303eSLisandro Dalcin     ierr = SCOTCH_archInit(&archdat);CHKERRPTSCOTCH(ierr);
74*abe9303eSLisandro Dalcin     ierr = SCOTCH_archCmpltw(&archdat, nparts, tpart);CHKERRPTSCOTCH(ierr);
75*abe9303eSLisandro Dalcin     ierr = SCOTCH_graphMap(&grafdat, &archdat, &stradat, part);CHKERRPTSCOTCH(ierr);
76*abe9303eSLisandro Dalcin     SCOTCH_archExit(&archdat);
77*abe9303eSLisandro Dalcin   } else {
78*abe9303eSLisandro Dalcin     ierr = SCOTCH_graphPart(&grafdat, nparts, &stradat, part);CHKERRPTSCOTCH(ierr);
79*abe9303eSLisandro Dalcin   }
80*abe9303eSLisandro Dalcin   SCOTCH_stratExit(&stradat);
81*abe9303eSLisandro Dalcin   SCOTCH_graphExit(&grafdat);
82*abe9303eSLisandro Dalcin   PetscFunctionReturn(0);
83*abe9303eSLisandro Dalcin }
84*abe9303eSLisandro Dalcin 
85*abe9303eSLisandro Dalcin static PetscErrorCode PTScotch_PartGraph_MPI(SCOTCH_Num strategy, double imbalance, SCOTCH_Num vtxdist[], SCOTCH_Num xadj[], SCOTCH_Num adjncy[],
86*abe9303eSLisandro Dalcin                                              SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num tpart[], SCOTCH_Num part[], MPI_Comm comm)
87*abe9303eSLisandro Dalcin {
88*abe9303eSLisandro Dalcin   PetscMPIInt     procglbnbr;
89*abe9303eSLisandro Dalcin   PetscMPIInt     proclocnum;
90*abe9303eSLisandro Dalcin   SCOTCH_Arch     archdat;
91*abe9303eSLisandro Dalcin   SCOTCH_Dgraph   grafdat;
92*abe9303eSLisandro Dalcin   SCOTCH_Dmapping mappdat;
93*abe9303eSLisandro Dalcin   SCOTCH_Strat    stradat;
94*abe9303eSLisandro Dalcin   SCOTCH_Num      vertlocnbr;
95*abe9303eSLisandro Dalcin   SCOTCH_Num      edgelocnbr;
96*abe9303eSLisandro Dalcin   SCOTCH_Num*     veloloctab = vtxwgt;
97*abe9303eSLisandro Dalcin   SCOTCH_Num*     edloloctab = adjwgt;
98*abe9303eSLisandro Dalcin   SCOTCH_Num      flagval = strategy;
99*abe9303eSLisandro Dalcin   double          kbalval = imbalance;
100*abe9303eSLisandro Dalcin   PetscErrorCode  ierr;
101*abe9303eSLisandro Dalcin 
102*abe9303eSLisandro Dalcin   PetscFunctionBegin;
103*abe9303eSLisandro Dalcin   {
104*abe9303eSLisandro Dalcin     PetscBool flg = PETSC_TRUE;
105*abe9303eSLisandro Dalcin     ierr = PetscOptionsDeprecatedNoObject("-petscpartititoner_ptscotch_vertex_weight",NULL,"3.13","Use -petscpartitioner_use_vertex_weights");CHKERRQ(ierr);
106*abe9303eSLisandro Dalcin     ierr = PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_ptscotch_vertex_weight", &flg, NULL);CHKERRQ(ierr);
107*abe9303eSLisandro Dalcin     if (!flg) veloloctab = NULL;
108*abe9303eSLisandro Dalcin   }
109*abe9303eSLisandro Dalcin   ierr = MPI_Comm_size(comm, &procglbnbr);CHKERRQ(ierr);
110*abe9303eSLisandro Dalcin   ierr = MPI_Comm_rank(comm, &proclocnum);CHKERRQ(ierr);
111*abe9303eSLisandro Dalcin   vertlocnbr = vtxdist[proclocnum + 1] - vtxdist[proclocnum];
112*abe9303eSLisandro Dalcin   edgelocnbr = xadj[vertlocnbr];
113*abe9303eSLisandro Dalcin 
114*abe9303eSLisandro Dalcin   ierr = SCOTCH_dgraphInit(&grafdat, comm);CHKERRPTSCOTCH(ierr);
115*abe9303eSLisandro Dalcin   ierr = SCOTCH_dgraphBuild(&grafdat, 0, vertlocnbr, vertlocnbr, xadj, xadj + 1, veloloctab, NULL, edgelocnbr, edgelocnbr, adjncy, NULL, edloloctab);CHKERRPTSCOTCH(ierr);
116*abe9303eSLisandro Dalcin   ierr = SCOTCH_stratInit(&stradat);CHKERRPTSCOTCH(ierr);
117*abe9303eSLisandro Dalcin   ierr = SCOTCH_stratDgraphMapBuild(&stradat, flagval, procglbnbr, nparts, kbalval);CHKERRQ(ierr);
118*abe9303eSLisandro Dalcin   ierr = SCOTCH_archInit(&archdat);CHKERRPTSCOTCH(ierr);
119*abe9303eSLisandro Dalcin   if (tpart) { /* target partition weights */
120*abe9303eSLisandro Dalcin     ierr = SCOTCH_archCmpltw(&archdat, nparts, tpart);CHKERRPTSCOTCH(ierr);
121*abe9303eSLisandro Dalcin   } else {
122*abe9303eSLisandro Dalcin     ierr = SCOTCH_archCmplt(&archdat, nparts);CHKERRPTSCOTCH(ierr);
123*abe9303eSLisandro Dalcin   }
124*abe9303eSLisandro Dalcin   ierr = SCOTCH_dgraphMapInit(&grafdat, &mappdat, &archdat, part);CHKERRPTSCOTCH(ierr);
125*abe9303eSLisandro Dalcin 
126*abe9303eSLisandro Dalcin   ierr = SCOTCH_dgraphMapCompute(&grafdat, &mappdat, &stradat);CHKERRPTSCOTCH(ierr);
127*abe9303eSLisandro Dalcin   SCOTCH_dgraphMapExit(&grafdat, &mappdat);
128*abe9303eSLisandro Dalcin   SCOTCH_archExit(&archdat);
129*abe9303eSLisandro Dalcin   SCOTCH_stratExit(&stradat);
130*abe9303eSLisandro Dalcin   SCOTCH_dgraphExit(&grafdat);
131*abe9303eSLisandro Dalcin   PetscFunctionReturn(0);
132*abe9303eSLisandro Dalcin }
133*abe9303eSLisandro Dalcin 
134*abe9303eSLisandro Dalcin #endif /* PETSC_HAVE_PTSCOTCH */
135*abe9303eSLisandro Dalcin 
136*abe9303eSLisandro Dalcin static const char *const
137*abe9303eSLisandro Dalcin PTScotchStrategyList[] = {
138*abe9303eSLisandro Dalcin   "DEFAULT",
139*abe9303eSLisandro Dalcin   "QUALITY",
140*abe9303eSLisandro Dalcin   "SPEED",
141*abe9303eSLisandro Dalcin   "BALANCE",
142*abe9303eSLisandro Dalcin   "SAFETY",
143*abe9303eSLisandro Dalcin   "SCALABILITY",
144*abe9303eSLisandro Dalcin   "RECURSIVE",
145*abe9303eSLisandro Dalcin   "REMAP"
146*abe9303eSLisandro Dalcin };
147*abe9303eSLisandro Dalcin 
148*abe9303eSLisandro Dalcin static PetscErrorCode PetscPartitionerDestroy_PTScotch(PetscPartitioner part)
149*abe9303eSLisandro Dalcin {
150*abe9303eSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
151*abe9303eSLisandro Dalcin   PetscErrorCode             ierr;
152*abe9303eSLisandro Dalcin 
153*abe9303eSLisandro Dalcin   PetscFunctionBegin;
154*abe9303eSLisandro Dalcin   ierr = MPI_Comm_free(&p->pcomm);CHKERRQ(ierr);
155*abe9303eSLisandro Dalcin   ierr = PetscFree(part->data);CHKERRQ(ierr);
156*abe9303eSLisandro Dalcin   PetscFunctionReturn(0);
157*abe9303eSLisandro Dalcin }
158*abe9303eSLisandro Dalcin 
159*abe9303eSLisandro Dalcin static PetscErrorCode PetscPartitionerView_PTScotch_ASCII(PetscPartitioner part, PetscViewer viewer)
160*abe9303eSLisandro Dalcin {
161*abe9303eSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
162*abe9303eSLisandro Dalcin   PetscErrorCode            ierr;
163*abe9303eSLisandro Dalcin 
164*abe9303eSLisandro Dalcin   PetscFunctionBegin;
165*abe9303eSLisandro Dalcin   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
166*abe9303eSLisandro Dalcin   ierr = PetscViewerASCIIPrintf(viewer,"using partitioning strategy %s\n",PTScotchStrategyList[p->strategy]);CHKERRQ(ierr);
167*abe9303eSLisandro Dalcin   ierr = PetscViewerASCIIPrintf(viewer,"using load imbalance ratio %g\n",(double)p->imbalance);CHKERRQ(ierr);
168*abe9303eSLisandro Dalcin   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
169*abe9303eSLisandro Dalcin   PetscFunctionReturn(0);
170*abe9303eSLisandro Dalcin }
171*abe9303eSLisandro Dalcin 
172*abe9303eSLisandro Dalcin static PetscErrorCode PetscPartitionerView_PTScotch(PetscPartitioner part, PetscViewer viewer)
173*abe9303eSLisandro Dalcin {
174*abe9303eSLisandro Dalcin   PetscBool      iascii;
175*abe9303eSLisandro Dalcin   PetscErrorCode ierr;
176*abe9303eSLisandro Dalcin 
177*abe9303eSLisandro Dalcin   PetscFunctionBegin;
178*abe9303eSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
179*abe9303eSLisandro Dalcin   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
180*abe9303eSLisandro Dalcin   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
181*abe9303eSLisandro Dalcin   if (iascii) {ierr = PetscPartitionerView_PTScotch_ASCII(part, viewer);CHKERRQ(ierr);}
182*abe9303eSLisandro Dalcin   PetscFunctionReturn(0);
183*abe9303eSLisandro Dalcin }
184*abe9303eSLisandro Dalcin 
185*abe9303eSLisandro Dalcin static PetscErrorCode PetscPartitionerSetFromOptions_PTScotch(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
186*abe9303eSLisandro Dalcin {
187*abe9303eSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
188*abe9303eSLisandro Dalcin   const char *const         *slist = PTScotchStrategyList;
189*abe9303eSLisandro Dalcin   PetscInt                  nlist = (PetscInt)(sizeof(PTScotchStrategyList)/sizeof(PTScotchStrategyList[0]));
190*abe9303eSLisandro Dalcin   PetscBool                 flag;
191*abe9303eSLisandro Dalcin   PetscErrorCode            ierr;
192*abe9303eSLisandro Dalcin 
193*abe9303eSLisandro Dalcin   PetscFunctionBegin;
194*abe9303eSLisandro Dalcin   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner PTScotch Options");CHKERRQ(ierr);
195*abe9303eSLisandro Dalcin   ierr = PetscOptionsEList("-petscpartitioner_ptscotch_strategy","Partitioning strategy","",slist,nlist,slist[p->strategy],&p->strategy,&flag);CHKERRQ(ierr);
196*abe9303eSLisandro Dalcin   ierr = PetscOptionsReal("-petscpartitioner_ptscotch_imbalance","Load imbalance ratio","",p->imbalance,&p->imbalance,&flag);CHKERRQ(ierr);
197*abe9303eSLisandro Dalcin   ierr = PetscOptionsTail();CHKERRQ(ierr);
198*abe9303eSLisandro Dalcin   PetscFunctionReturn(0);
199*abe9303eSLisandro Dalcin }
200*abe9303eSLisandro Dalcin 
201*abe9303eSLisandro Dalcin static PetscErrorCode PetscPartitionerPartition_PTScotch(PetscPartitioner part, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection vertSection, PetscSection targetSection, PetscSection partSection, IS *partition)
202*abe9303eSLisandro Dalcin {
203*abe9303eSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
204*abe9303eSLisandro Dalcin   MPI_Comm       comm;
205*abe9303eSLisandro Dalcin   PetscInt       nvtxs = numVertices;   /* The number of vertices in full graph */
206*abe9303eSLisandro Dalcin   PetscInt       *vtxdist;              /* Distribution of vertices across processes */
207*abe9303eSLisandro Dalcin   PetscInt       *xadj   = start;       /* Start of edge list for each vertex */
208*abe9303eSLisandro Dalcin   PetscInt       *adjncy = adjacency;   /* Edge lists for all vertices */
209*abe9303eSLisandro Dalcin   PetscInt       *vwgt   = NULL;        /* Vertex weights */
210*abe9303eSLisandro Dalcin   PetscInt       *adjwgt = NULL;        /* Edge weights */
211*abe9303eSLisandro Dalcin   PetscInt       v, i, *assignment, *points;
212*abe9303eSLisandro Dalcin   PetscMPIInt    size, rank, p;
213*abe9303eSLisandro Dalcin   PetscBool      hasempty = PETSC_FALSE;
214*abe9303eSLisandro Dalcin   PetscInt       *tpwgts = NULL;
215*abe9303eSLisandro Dalcin   PetscErrorCode ierr;
216*abe9303eSLisandro Dalcin 
217*abe9303eSLisandro Dalcin   PetscFunctionBegin;
218*abe9303eSLisandro Dalcin   ierr = PetscObjectGetComm((PetscObject)part,&comm);CHKERRQ(ierr);
219*abe9303eSLisandro Dalcin   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
220*abe9303eSLisandro Dalcin   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
221*abe9303eSLisandro Dalcin   ierr = PetscMalloc2(size+1,&vtxdist,PetscMax(nvtxs,1),&assignment);CHKERRQ(ierr);
222*abe9303eSLisandro Dalcin   /* Calculate vertex distribution */
223*abe9303eSLisandro Dalcin   vtxdist[0] = 0;
224*abe9303eSLisandro Dalcin   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
225*abe9303eSLisandro Dalcin   for (p = 2; p <= size; ++p) {
226*abe9303eSLisandro Dalcin     hasempty = (PetscBool)(hasempty || !vtxdist[p-1] || !vtxdist[p]);
227*abe9303eSLisandro Dalcin     vtxdist[p] += vtxdist[p-1];
228*abe9303eSLisandro Dalcin   }
229*abe9303eSLisandro Dalcin   /* null graph */
230*abe9303eSLisandro Dalcin   if (vtxdist[size] == 0) {
231*abe9303eSLisandro Dalcin     ierr = PetscFree2(vtxdist, assignment);CHKERRQ(ierr);
232*abe9303eSLisandro Dalcin     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
233*abe9303eSLisandro Dalcin     PetscFunctionReturn(0);
234*abe9303eSLisandro Dalcin   }
235*abe9303eSLisandro Dalcin 
236*abe9303eSLisandro Dalcin   /* Calculate vertex weights */
237*abe9303eSLisandro Dalcin   if (vertSection) {
238*abe9303eSLisandro Dalcin     ierr = PetscMalloc1(nvtxs,&vwgt);CHKERRQ(ierr);
239*abe9303eSLisandro Dalcin     for (v = 0; v < nvtxs; ++v) {
240*abe9303eSLisandro Dalcin       ierr = PetscSectionGetDof(vertSection, v, &vwgt[v]);CHKERRQ(ierr);
241*abe9303eSLisandro Dalcin     }
242*abe9303eSLisandro Dalcin   }
243*abe9303eSLisandro Dalcin 
244*abe9303eSLisandro Dalcin   /* Calculate partition weights */
245*abe9303eSLisandro Dalcin   if (targetSection) {
246*abe9303eSLisandro Dalcin     PetscInt sumw;
247*abe9303eSLisandro Dalcin 
248*abe9303eSLisandro Dalcin     ierr = PetscCalloc1(nparts,&tpwgts);CHKERRQ(ierr);
249*abe9303eSLisandro Dalcin     for (p = 0, sumw = 0; p < nparts; ++p) {
250*abe9303eSLisandro Dalcin       ierr = PetscSectionGetDof(targetSection,p,&tpwgts[p]);CHKERRQ(ierr);
251*abe9303eSLisandro Dalcin       sumw += tpwgts[p];
252*abe9303eSLisandro Dalcin     }
253*abe9303eSLisandro Dalcin     if (!sumw) {
254*abe9303eSLisandro Dalcin       ierr = PetscFree(tpwgts);CHKERRQ(ierr);
255*abe9303eSLisandro Dalcin     }
256*abe9303eSLisandro Dalcin   }
257*abe9303eSLisandro Dalcin 
258*abe9303eSLisandro Dalcin   {
259*abe9303eSLisandro Dalcin     PetscPartitioner_PTScotch *pts = (PetscPartitioner_PTScotch *) part->data;
260*abe9303eSLisandro Dalcin     int                       strat = PTScotch_Strategy(pts->strategy);
261*abe9303eSLisandro Dalcin     double                    imbal = (double)pts->imbalance;
262*abe9303eSLisandro Dalcin 
263*abe9303eSLisandro Dalcin     for (p = 0; !vtxdist[p+1] && p < size; ++p);
264*abe9303eSLisandro Dalcin     if (vtxdist[p+1] == vtxdist[size]) {
265*abe9303eSLisandro Dalcin       if (rank == p) {
266*abe9303eSLisandro Dalcin         ierr = PTScotch_PartGraph_Seq(strat, imbal, nvtxs, xadj, adjncy, vwgt, adjwgt, nparts, tpwgts, assignment);CHKERRQ(ierr);
267*abe9303eSLisandro Dalcin       }
268*abe9303eSLisandro Dalcin     } else {
269*abe9303eSLisandro Dalcin       MPI_Comm pcomm = pts->pcomm;
270*abe9303eSLisandro Dalcin 
271*abe9303eSLisandro Dalcin       if (hasempty) {
272*abe9303eSLisandro Dalcin         PetscInt cnt;
273*abe9303eSLisandro Dalcin 
274*abe9303eSLisandro Dalcin         ierr = MPI_Comm_split(pts->pcomm,!!nvtxs,rank,&pcomm);CHKERRQ(ierr);
275*abe9303eSLisandro Dalcin         for (p=0,cnt=0;p<size;p++) {
276*abe9303eSLisandro Dalcin           if (vtxdist[p+1] != vtxdist[p]) {
277*abe9303eSLisandro Dalcin             vtxdist[cnt+1] = vtxdist[p+1];
278*abe9303eSLisandro Dalcin             cnt++;
279*abe9303eSLisandro Dalcin           }
280*abe9303eSLisandro Dalcin         }
281*abe9303eSLisandro Dalcin       };
282*abe9303eSLisandro Dalcin       if (nvtxs) {
283*abe9303eSLisandro Dalcin         ierr = PTScotch_PartGraph_MPI(strat, imbal, vtxdist, xadj, adjncy, vwgt, adjwgt, nparts, tpwgts, assignment, pcomm);CHKERRQ(ierr);
284*abe9303eSLisandro Dalcin       }
285*abe9303eSLisandro Dalcin       if (hasempty) {
286*abe9303eSLisandro Dalcin         ierr = MPI_Comm_free(&pcomm);CHKERRQ(ierr);
287*abe9303eSLisandro Dalcin       }
288*abe9303eSLisandro Dalcin     }
289*abe9303eSLisandro Dalcin   }
290*abe9303eSLisandro Dalcin   ierr = PetscFree(vwgt);CHKERRQ(ierr);
291*abe9303eSLisandro Dalcin   ierr = PetscFree(tpwgts);CHKERRQ(ierr);
292*abe9303eSLisandro Dalcin 
293*abe9303eSLisandro Dalcin   /* Convert to PetscSection+IS */
294*abe9303eSLisandro Dalcin   for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);}
295*abe9303eSLisandro Dalcin   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
296*abe9303eSLisandro Dalcin   for (p = 0, i = 0; p < nparts; ++p) {
297*abe9303eSLisandro Dalcin     for (v = 0; v < nvtxs; ++v) {
298*abe9303eSLisandro Dalcin       if (assignment[v] == p) points[i++] = v;
299*abe9303eSLisandro Dalcin     }
300*abe9303eSLisandro Dalcin   }
301*abe9303eSLisandro Dalcin   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
302*abe9303eSLisandro Dalcin   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
303*abe9303eSLisandro Dalcin 
304*abe9303eSLisandro Dalcin   ierr = PetscFree2(vtxdist,assignment);CHKERRQ(ierr);
305*abe9303eSLisandro Dalcin   PetscFunctionReturn(0);
306*abe9303eSLisandro Dalcin #else
307*abe9303eSLisandro Dalcin   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-ptscotch.");
308*abe9303eSLisandro Dalcin #endif
309*abe9303eSLisandro Dalcin }
310*abe9303eSLisandro Dalcin 
311*abe9303eSLisandro Dalcin static PetscErrorCode PetscPartitionerInitialize_PTScotch(PetscPartitioner part)
312*abe9303eSLisandro Dalcin {
313*abe9303eSLisandro Dalcin   PetscFunctionBegin;
314*abe9303eSLisandro Dalcin   part->noGraph             = PETSC_FALSE;
315*abe9303eSLisandro Dalcin   part->ops->view           = PetscPartitionerView_PTScotch;
316*abe9303eSLisandro Dalcin   part->ops->destroy        = PetscPartitionerDestroy_PTScotch;
317*abe9303eSLisandro Dalcin   part->ops->partition      = PetscPartitionerPartition_PTScotch;
318*abe9303eSLisandro Dalcin   part->ops->setfromoptions = PetscPartitionerSetFromOptions_PTScotch;
319*abe9303eSLisandro Dalcin   PetscFunctionReturn(0);
320*abe9303eSLisandro Dalcin }
321*abe9303eSLisandro Dalcin 
322*abe9303eSLisandro Dalcin /*MC
323*abe9303eSLisandro Dalcin   PETSCPARTITIONERPTSCOTCH = "ptscotch" - A PetscPartitioner object using the PT-Scotch library
324*abe9303eSLisandro Dalcin 
325*abe9303eSLisandro Dalcin   Level: intermediate
326*abe9303eSLisandro Dalcin 
327*abe9303eSLisandro Dalcin   Options Database Keys:
328*abe9303eSLisandro Dalcin +  -petscpartitioner_ptscotch_strategy <string> - PT-Scotch strategy. Choose one of default quality speed balance safety scalability recursive remap
329*abe9303eSLisandro Dalcin -  -petscpartitioner_ptscotch_imbalance <val> - Load imbalance ratio
330*abe9303eSLisandro Dalcin 
331*abe9303eSLisandro Dalcin   Notes: when the graph is on a single process, this partitioner actually uses Scotch and not PT-Scotch
332*abe9303eSLisandro Dalcin 
333*abe9303eSLisandro Dalcin .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
334*abe9303eSLisandro Dalcin M*/
335*abe9303eSLisandro Dalcin 
336*abe9303eSLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_PTScotch(PetscPartitioner part)
337*abe9303eSLisandro Dalcin {
338*abe9303eSLisandro Dalcin   PetscPartitioner_PTScotch *p;
339*abe9303eSLisandro Dalcin   PetscErrorCode          ierr;
340*abe9303eSLisandro Dalcin 
341*abe9303eSLisandro Dalcin   PetscFunctionBegin;
342*abe9303eSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
343*abe9303eSLisandro Dalcin   ierr = PetscNewLog(part, &p);CHKERRQ(ierr);
344*abe9303eSLisandro Dalcin   part->data = p;
345*abe9303eSLisandro Dalcin 
346*abe9303eSLisandro Dalcin   ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)part),&p->pcomm);CHKERRQ(ierr);
347*abe9303eSLisandro Dalcin   p->strategy  = 0;
348*abe9303eSLisandro Dalcin   p->imbalance = 0.01;
349*abe9303eSLisandro Dalcin 
350*abe9303eSLisandro Dalcin   ierr = PetscPartitionerInitialize_PTScotch(part);CHKERRQ(ierr);
351*abe9303eSLisandro Dalcin   ierr = PetscCitationsRegister(PTScotchPartitionerCitation, &PTScotchPartitionerCite);CHKERRQ(ierr);
352*abe9303eSLisandro Dalcin   PetscFunctionReturn(0);
353*abe9303eSLisandro Dalcin }
354