xref: /petsc/src/dm/partitioner/impls/ptscotch/partptscotch.c (revision 4ead3382d1c3ee6a63aa1fefc216a02767a017e6)
1abe9303eSLisandro Dalcin #include <petsc/private/partitionerimpl.h> /*I "petscpartitioner.h" I*/
2abe9303eSLisandro Dalcin 
3abe9303eSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
4abe9303eSLisandro Dalcin EXTERN_C_BEGIN
5abe9303eSLisandro Dalcin   #include <ptscotch.h>
6abe9303eSLisandro Dalcin EXTERN_C_END
7abe9303eSLisandro Dalcin #endif
8abe9303eSLisandro Dalcin 
9abe9303eSLisandro Dalcin PetscBool  PTScotchPartitionerCite       = PETSC_FALSE;
109371c9d4SSatish Balay const char PTScotchPartitionerCitation[] = "@article{PTSCOTCH,\n"
11abe9303eSLisandro Dalcin                                            "  author  = {C. Chevalier and F. Pellegrini},\n"
12abe9303eSLisandro Dalcin                                            "  title   = {{PT-SCOTCH}: a tool for efficient parallel graph ordering},\n"
13abe9303eSLisandro Dalcin                                            "  journal = {Parallel Computing},\n"
14abe9303eSLisandro Dalcin                                            "  volume  = {34},\n"
15abe9303eSLisandro Dalcin                                            "  number  = {6},\n"
16abe9303eSLisandro Dalcin                                            "  pages   = {318--331},\n"
17abe9303eSLisandro Dalcin                                            "  year    = {2008},\n"
18abe9303eSLisandro Dalcin                                            "  doi     = {https://doi.org/10.1016/j.parco.2007.12.001}\n"
19abe9303eSLisandro Dalcin                                            "}\n";
20abe9303eSLisandro Dalcin 
21abe9303eSLisandro Dalcin typedef struct {
22abe9303eSLisandro Dalcin   MPI_Comm  pcomm;
23abe9303eSLisandro Dalcin   PetscInt  strategy;
24abe9303eSLisandro Dalcin   PetscReal imbalance;
25abe9303eSLisandro Dalcin } PetscPartitioner_PTScotch;
26abe9303eSLisandro Dalcin 
27abe9303eSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
28abe9303eSLisandro Dalcin 
299371c9d4SSatish Balay   #define PetscCallPTSCOTCH(...) \
30d71ae5a4SJacob Faibussowitsch     do { \
31d71ae5a4SJacob Faibussowitsch       PetscCheck(!(__VA_ARGS__), PETSC_COMM_SELF, PETSC_ERR_LIB, "Error calling PT-Scotch library"); \
32d71ae5a4SJacob Faibussowitsch     } while (0)
33abe9303eSLisandro Dalcin 
34d71ae5a4SJacob Faibussowitsch static int PTScotch_Strategy(PetscInt strategy)
35d71ae5a4SJacob Faibussowitsch {
36abe9303eSLisandro Dalcin   switch (strategy) {
37d71ae5a4SJacob Faibussowitsch   case 0:
38d71ae5a4SJacob Faibussowitsch     return SCOTCH_STRATDEFAULT;
39d71ae5a4SJacob Faibussowitsch   case 1:
40d71ae5a4SJacob Faibussowitsch     return SCOTCH_STRATQUALITY;
41d71ae5a4SJacob Faibussowitsch   case 2:
42d71ae5a4SJacob Faibussowitsch     return SCOTCH_STRATSPEED;
43d71ae5a4SJacob Faibussowitsch   case 3:
44d71ae5a4SJacob Faibussowitsch     return SCOTCH_STRATBALANCE;
45d71ae5a4SJacob Faibussowitsch   case 4:
46d71ae5a4SJacob Faibussowitsch     return SCOTCH_STRATSAFETY;
47d71ae5a4SJacob Faibussowitsch   case 5:
48d71ae5a4SJacob Faibussowitsch     return SCOTCH_STRATSCALABILITY;
49d71ae5a4SJacob Faibussowitsch   case 6:
50d71ae5a4SJacob Faibussowitsch     return SCOTCH_STRATRECURSIVE;
51d71ae5a4SJacob Faibussowitsch   case 7:
52d71ae5a4SJacob Faibussowitsch     return SCOTCH_STRATREMAP;
53d71ae5a4SJacob Faibussowitsch   default:
54d71ae5a4SJacob Faibussowitsch     return SCOTCH_STRATDEFAULT;
55abe9303eSLisandro Dalcin   }
56abe9303eSLisandro Dalcin }
57abe9303eSLisandro Dalcin 
58d71ae5a4SJacob Faibussowitsch static PetscErrorCode PTScotch_PartGraph_Seq(SCOTCH_Num strategy, double imbalance, SCOTCH_Num n, SCOTCH_Num xadj[], SCOTCH_Num adjncy[], SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num tpart[], SCOTCH_Num part[])
59d71ae5a4SJacob Faibussowitsch {
60d7cc930eSLisandro Dalcin   SCOTCH_Arch  archdat;
61abe9303eSLisandro Dalcin   SCOTCH_Graph grafdat;
62abe9303eSLisandro Dalcin   SCOTCH_Strat stradat;
63abe9303eSLisandro Dalcin   SCOTCH_Num   vertnbr = n;
64abe9303eSLisandro Dalcin   SCOTCH_Num   edgenbr = xadj[n];
65abe9303eSLisandro Dalcin   SCOTCH_Num  *velotab = vtxwgt;
66abe9303eSLisandro Dalcin   SCOTCH_Num  *edlotab = adjwgt;
67abe9303eSLisandro Dalcin   SCOTCH_Num   flagval = strategy;
68abe9303eSLisandro Dalcin   double       kbalval = imbalance;
69abe9303eSLisandro Dalcin 
70abe9303eSLisandro Dalcin   PetscFunctionBegin;
71abe9303eSLisandro Dalcin   {
72abe9303eSLisandro Dalcin     PetscBool flg = PETSC_TRUE;
73*4ead3382SBarry Smith     PetscCall(PetscOptionsDeprecatedNoObject("-petscpartititoner_ptscotch_vertex_weight", "-petscpartitioner_use_vertex_weights", "3.13", NULL));
74*4ead3382SBarry Smith     /*
75*4ead3382SBarry Smith        Cannot remove the PetscOptionsGetBool() below since the PetscOptionsDeprecatedNoObject() above is called after the non-deprecated version
76*4ead3382SBarry Smith        has already been checked in PetscPartitionerSetFromOptions().
77*4ead3382SBarry Smith     */
78*4ead3382SBarry Smith     PetscCall(PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_use_vertex_weight", &flg, NULL));
79abe9303eSLisandro Dalcin     if (!flg) velotab = NULL;
80abe9303eSLisandro Dalcin   }
819566063dSJacob Faibussowitsch   PetscCallPTSCOTCH(SCOTCH_graphInit(&grafdat));
829566063dSJacob Faibussowitsch   PetscCallPTSCOTCH(SCOTCH_graphBuild(&grafdat, 0, vertnbr, xadj, xadj + 1, velotab, NULL, edgenbr, adjncy, edlotab));
839566063dSJacob Faibussowitsch   PetscCallPTSCOTCH(SCOTCH_stratInit(&stradat));
849566063dSJacob Faibussowitsch   PetscCallPTSCOTCH(SCOTCH_stratGraphMapBuild(&stradat, flagval, nparts, kbalval));
859566063dSJacob Faibussowitsch   PetscCallPTSCOTCH(SCOTCH_archInit(&archdat));
86d7cc930eSLisandro Dalcin   if (tpart) {
879566063dSJacob Faibussowitsch     PetscCallPTSCOTCH(SCOTCH_archCmpltw(&archdat, nparts, tpart));
88d7cc930eSLisandro Dalcin   } else {
899566063dSJacob Faibussowitsch     PetscCallPTSCOTCH(SCOTCH_archCmplt(&archdat, nparts));
90d7cc930eSLisandro Dalcin   }
919566063dSJacob Faibussowitsch   PetscCallPTSCOTCH(SCOTCH_graphMap(&grafdat, &archdat, &stradat, part));
92abe9303eSLisandro Dalcin   SCOTCH_archExit(&archdat);
93abe9303eSLisandro Dalcin   SCOTCH_stratExit(&stradat);
94abe9303eSLisandro Dalcin   SCOTCH_graphExit(&grafdat);
953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
96abe9303eSLisandro Dalcin }
97abe9303eSLisandro Dalcin 
98d71ae5a4SJacob Faibussowitsch static PetscErrorCode PTScotch_PartGraph_MPI(SCOTCH_Num strategy, double imbalance, SCOTCH_Num vtxdist[], SCOTCH_Num xadj[], SCOTCH_Num adjncy[], SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num tpart[], SCOTCH_Num part[], MPI_Comm comm)
99d71ae5a4SJacob Faibussowitsch {
100abe9303eSLisandro Dalcin   PetscMPIInt     procglbnbr;
101abe9303eSLisandro Dalcin   PetscMPIInt     proclocnum;
102abe9303eSLisandro Dalcin   SCOTCH_Arch     archdat;
103abe9303eSLisandro Dalcin   SCOTCH_Dgraph   grafdat;
104abe9303eSLisandro Dalcin   SCOTCH_Dmapping mappdat;
105abe9303eSLisandro Dalcin   SCOTCH_Strat    stradat;
106abe9303eSLisandro Dalcin   SCOTCH_Num      vertlocnbr;
107abe9303eSLisandro Dalcin   SCOTCH_Num      edgelocnbr;
108abe9303eSLisandro Dalcin   SCOTCH_Num     *veloloctab = vtxwgt;
109abe9303eSLisandro Dalcin   SCOTCH_Num     *edloloctab = adjwgt;
110abe9303eSLisandro Dalcin   SCOTCH_Num      flagval    = strategy;
111abe9303eSLisandro Dalcin   double          kbalval    = imbalance;
112abe9303eSLisandro Dalcin 
113abe9303eSLisandro Dalcin   PetscFunctionBegin;
114abe9303eSLisandro Dalcin   {
115abe9303eSLisandro Dalcin     PetscBool flg = PETSC_TRUE;
116*4ead3382SBarry Smith     PetscCall(PetscOptionsDeprecatedNoObject("-petscpartititoner_ptscotch_vertex_weight", "-petscpartitioner_use_vertex_weights", "3.13", NULL));
117*4ead3382SBarry Smith     /*
118*4ead3382SBarry Smith        Cannot remove the PetscOptionsGetBool() below since the PetscOptionsDeprecatedNoObject() above is called after the non-deprecated version
119*4ead3382SBarry Smith        has already been checked in PetscPartitionerSetFromOptions().
120*4ead3382SBarry Smith     */
121*4ead3382SBarry Smith     PetscCall(PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_use_vertex_weight", &flg, NULL));
122abe9303eSLisandro Dalcin     if (!flg) veloloctab = NULL;
123abe9303eSLisandro Dalcin   }
1249566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &procglbnbr));
1259566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &proclocnum));
126abe9303eSLisandro Dalcin   vertlocnbr = vtxdist[proclocnum + 1] - vtxdist[proclocnum];
127abe9303eSLisandro Dalcin   edgelocnbr = xadj[vertlocnbr];
128abe9303eSLisandro Dalcin 
1299566063dSJacob Faibussowitsch   PetscCallPTSCOTCH(SCOTCH_dgraphInit(&grafdat, comm));
1309566063dSJacob Faibussowitsch   PetscCallPTSCOTCH(SCOTCH_dgraphBuild(&grafdat, 0, vertlocnbr, vertlocnbr, xadj, xadj + 1, veloloctab, NULL, edgelocnbr, edgelocnbr, adjncy, NULL, edloloctab));
1319566063dSJacob Faibussowitsch   PetscCallPTSCOTCH(SCOTCH_stratInit(&stradat));
1323ba16761SJacob Faibussowitsch   PetscCallPTSCOTCH(SCOTCH_stratDgraphMapBuild(&stradat, flagval, procglbnbr, nparts, kbalval));
1339566063dSJacob Faibussowitsch   PetscCallPTSCOTCH(SCOTCH_archInit(&archdat));
134abe9303eSLisandro Dalcin   if (tpart) { /* target partition weights */
1359566063dSJacob Faibussowitsch     PetscCallPTSCOTCH(SCOTCH_archCmpltw(&archdat, nparts, tpart));
136abe9303eSLisandro Dalcin   } else {
1379566063dSJacob Faibussowitsch     PetscCallPTSCOTCH(SCOTCH_archCmplt(&archdat, nparts));
138abe9303eSLisandro Dalcin   }
1399566063dSJacob Faibussowitsch   PetscCallPTSCOTCH(SCOTCH_dgraphMapInit(&grafdat, &mappdat, &archdat, part));
1409566063dSJacob Faibussowitsch   PetscCallPTSCOTCH(SCOTCH_dgraphMapCompute(&grafdat, &mappdat, &stradat));
141abe9303eSLisandro Dalcin   SCOTCH_dgraphMapExit(&grafdat, &mappdat);
142abe9303eSLisandro Dalcin   SCOTCH_archExit(&archdat);
143abe9303eSLisandro Dalcin   SCOTCH_stratExit(&stradat);
144abe9303eSLisandro Dalcin   SCOTCH_dgraphExit(&grafdat);
1453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
146abe9303eSLisandro Dalcin }
147abe9303eSLisandro Dalcin 
148abe9303eSLisandro Dalcin #endif /* PETSC_HAVE_PTSCOTCH */
149abe9303eSLisandro Dalcin 
1509371c9d4SSatish Balay static const char *const PTScotchStrategyList[] = {"DEFAULT", "QUALITY", "SPEED", "BALANCE", "SAFETY", "SCALABILITY", "RECURSIVE", "REMAP"};
151abe9303eSLisandro Dalcin 
152d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscPartitionerDestroy_PTScotch(PetscPartitioner part)
153d71ae5a4SJacob Faibussowitsch {
154abe9303eSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *)part->data;
155abe9303eSLisandro Dalcin 
156abe9303eSLisandro Dalcin   PetscFunctionBegin;
1579566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_free(&p->pcomm));
1589566063dSJacob Faibussowitsch   PetscCall(PetscFree(part->data));
1593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
160abe9303eSLisandro Dalcin }
161abe9303eSLisandro Dalcin 
162d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscPartitionerView_PTScotch_ASCII(PetscPartitioner part, PetscViewer viewer)
163d71ae5a4SJacob Faibussowitsch {
164abe9303eSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *)part->data;
165abe9303eSLisandro Dalcin 
166abe9303eSLisandro Dalcin   PetscFunctionBegin;
1679566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPushTab(viewer));
1689566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "using partitioning strategy %s\n", PTScotchStrategyList[p->strategy]));
1699566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "using load imbalance ratio %g\n", (double)p->imbalance));
1709566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPopTab(viewer));
1713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
172abe9303eSLisandro Dalcin }
173abe9303eSLisandro Dalcin 
174d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscPartitionerView_PTScotch(PetscPartitioner part, PetscViewer viewer)
175d71ae5a4SJacob Faibussowitsch {
176abe9303eSLisandro Dalcin   PetscBool iascii;
177abe9303eSLisandro Dalcin 
178abe9303eSLisandro Dalcin   PetscFunctionBegin;
179abe9303eSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
180abe9303eSLisandro Dalcin   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1819566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1829566063dSJacob Faibussowitsch   if (iascii) PetscCall(PetscPartitionerView_PTScotch_ASCII(part, viewer));
1833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
184abe9303eSLisandro Dalcin }
185abe9303eSLisandro Dalcin 
186d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscPartitionerSetFromOptions_PTScotch(PetscPartitioner part, PetscOptionItems *PetscOptionsObject)
187d71ae5a4SJacob Faibussowitsch {
188abe9303eSLisandro Dalcin   PetscPartitioner_PTScotch *p     = (PetscPartitioner_PTScotch *)part->data;
189abe9303eSLisandro Dalcin   const char *const         *slist = PTScotchStrategyList;
190dd39110bSPierre Jolivet   PetscInt                   nlist = PETSC_STATIC_ARRAY_LENGTH(PTScotchStrategyList);
191abe9303eSLisandro Dalcin   PetscBool                  flag;
192abe9303eSLisandro Dalcin 
193abe9303eSLisandro Dalcin   PetscFunctionBegin;
194d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "PetscPartitioner PTScotch Options");
1959566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEList("-petscpartitioner_ptscotch_strategy", "Partitioning strategy", "", slist, nlist, slist[p->strategy], &p->strategy, &flag));
1969566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-petscpartitioner_ptscotch_imbalance", "Load imbalance ratio", "", p->imbalance, &p->imbalance, &flag));
197d0609cedSBarry Smith   PetscOptionsHeadEnd();
1983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
199abe9303eSLisandro Dalcin }
200abe9303eSLisandro Dalcin 
201d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscPartitionerPartition_PTScotch(PetscPartitioner part, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection vertSection, PetscSection targetSection, PetscSection partSection, IS *partition)
202d71ae5a4SJacob Faibussowitsch {
203abe9303eSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
204abe9303eSLisandro Dalcin   MPI_Comm    comm;
205abe9303eSLisandro Dalcin   PetscInt    nvtxs = numVertices; /* The number of vertices in full graph */
206abe9303eSLisandro Dalcin   PetscInt   *vtxdist;             /* Distribution of vertices across processes */
207abe9303eSLisandro Dalcin   PetscInt   *xadj   = start;      /* Start of edge list for each vertex */
208abe9303eSLisandro Dalcin   PetscInt   *adjncy = adjacency;  /* Edge lists for all vertices */
209abe9303eSLisandro Dalcin   PetscInt   *vwgt   = NULL;       /* Vertex weights */
210abe9303eSLisandro Dalcin   PetscInt   *adjwgt = NULL;       /* Edge weights */
211abe9303eSLisandro Dalcin   PetscInt    v, i, *assignment, *points;
212abe9303eSLisandro Dalcin   PetscMPIInt size, rank, p;
213abe9303eSLisandro Dalcin   PetscBool   hasempty = PETSC_FALSE;
214abe9303eSLisandro Dalcin   PetscInt   *tpwgts   = NULL;
215abe9303eSLisandro Dalcin 
216abe9303eSLisandro Dalcin   PetscFunctionBegin;
2179566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)part, &comm));
2189566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
2199566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
2209566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(size + 1, &vtxdist, PetscMax(nvtxs, 1), &assignment));
221abe9303eSLisandro Dalcin   /* Calculate vertex distribution */
222abe9303eSLisandro Dalcin   vtxdist[0] = 0;
2239566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm));
224abe9303eSLisandro Dalcin   for (p = 2; p <= size; ++p) {
225abe9303eSLisandro Dalcin     hasempty = (PetscBool)(hasempty || !vtxdist[p - 1] || !vtxdist[p]);
226abe9303eSLisandro Dalcin     vtxdist[p] += vtxdist[p - 1];
227abe9303eSLisandro Dalcin   }
228abe9303eSLisandro Dalcin   /* null graph */
229abe9303eSLisandro Dalcin   if (vtxdist[size] == 0) {
2309566063dSJacob Faibussowitsch     PetscCall(PetscFree2(vtxdist, assignment));
2319566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition));
2323ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
233abe9303eSLisandro Dalcin   }
234abe9303eSLisandro Dalcin 
235abe9303eSLisandro Dalcin   /* Calculate vertex weights */
236abe9303eSLisandro Dalcin   if (vertSection) {
2379566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nvtxs, &vwgt));
2389566063dSJacob Faibussowitsch     for (v = 0; v < nvtxs; ++v) PetscCall(PetscSectionGetDof(vertSection, v, &vwgt[v]));
239abe9303eSLisandro Dalcin   }
240abe9303eSLisandro Dalcin 
241abe9303eSLisandro Dalcin   /* Calculate partition weights */
242abe9303eSLisandro Dalcin   if (targetSection) {
243abe9303eSLisandro Dalcin     PetscInt sumw;
244abe9303eSLisandro Dalcin 
2459566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nparts, &tpwgts));
246abe9303eSLisandro Dalcin     for (p = 0, sumw = 0; p < nparts; ++p) {
2479566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(targetSection, p, &tpwgts[p]));
248abe9303eSLisandro Dalcin       sumw += tpwgts[p];
249abe9303eSLisandro Dalcin     }
2509566063dSJacob Faibussowitsch     if (!sumw) PetscCall(PetscFree(tpwgts));
251abe9303eSLisandro Dalcin   }
252abe9303eSLisandro Dalcin 
253abe9303eSLisandro Dalcin   {
254abe9303eSLisandro Dalcin     PetscPartitioner_PTScotch *pts   = (PetscPartitioner_PTScotch *)part->data;
255abe9303eSLisandro Dalcin     int                        strat = PTScotch_Strategy(pts->strategy);
256abe9303eSLisandro Dalcin     double                     imbal = (double)pts->imbalance;
257abe9303eSLisandro Dalcin 
2589371c9d4SSatish Balay     for (p = 0; !vtxdist[p + 1] && p < size; ++p)
2599371c9d4SSatish Balay       ;
260abe9303eSLisandro Dalcin     if (vtxdist[p + 1] == vtxdist[size]) {
2619566063dSJacob Faibussowitsch       if (rank == p) PetscCall(PTScotch_PartGraph_Seq(strat, imbal, nvtxs, xadj, adjncy, vwgt, adjwgt, nparts, tpwgts, assignment));
262abe9303eSLisandro Dalcin     } else {
263abe9303eSLisandro Dalcin       MPI_Comm pcomm = pts->pcomm;
264abe9303eSLisandro Dalcin 
265abe9303eSLisandro Dalcin       if (hasempty) {
266abe9303eSLisandro Dalcin         PetscInt cnt;
267abe9303eSLisandro Dalcin 
2689566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_split(pts->pcomm, !!nvtxs, rank, &pcomm));
269abe9303eSLisandro Dalcin         for (p = 0, cnt = 0; p < size; p++) {
270abe9303eSLisandro Dalcin           if (vtxdist[p + 1] != vtxdist[p]) {
271abe9303eSLisandro Dalcin             vtxdist[cnt + 1] = vtxdist[p + 1];
272abe9303eSLisandro Dalcin             cnt++;
273abe9303eSLisandro Dalcin           }
274abe9303eSLisandro Dalcin         }
275abe9303eSLisandro Dalcin       };
2769566063dSJacob Faibussowitsch       if (nvtxs) PetscCall(PTScotch_PartGraph_MPI(strat, imbal, vtxdist, xadj, adjncy, vwgt, adjwgt, nparts, tpwgts, assignment, pcomm));
2779566063dSJacob Faibussowitsch       if (hasempty) PetscCallMPI(MPI_Comm_free(&pcomm));
278abe9303eSLisandro Dalcin     }
279abe9303eSLisandro Dalcin   }
2809566063dSJacob Faibussowitsch   PetscCall(PetscFree(vwgt));
2819566063dSJacob Faibussowitsch   PetscCall(PetscFree(tpwgts));
282abe9303eSLisandro Dalcin 
283abe9303eSLisandro Dalcin   /* Convert to PetscSection+IS */
2849566063dSJacob Faibussowitsch   for (v = 0; v < nvtxs; ++v) PetscCall(PetscSectionAddDof(partSection, assignment[v], 1));
2859566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nvtxs, &points));
286abe9303eSLisandro Dalcin   for (p = 0, i = 0; p < nparts; ++p) {
287abe9303eSLisandro Dalcin     for (v = 0; v < nvtxs; ++v) {
288abe9303eSLisandro Dalcin       if (assignment[v] == p) points[i++] = v;
289abe9303eSLisandro Dalcin     }
290abe9303eSLisandro Dalcin   }
29163a3b9bcSJacob Faibussowitsch   PetscCheck(i == nvtxs, comm, PETSC_ERR_PLIB, "Number of points %" PetscInt_FMT " should be %" PetscInt_FMT, i, nvtxs);
2929566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition));
293abe9303eSLisandro Dalcin 
2949566063dSJacob Faibussowitsch   PetscCall(PetscFree2(vtxdist, assignment));
2953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
296abe9303eSLisandro Dalcin #else
297abe9303eSLisandro Dalcin   SETERRQ(PetscObjectComm((PetscObject)part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-ptscotch.");
298abe9303eSLisandro Dalcin #endif
299abe9303eSLisandro Dalcin }
300abe9303eSLisandro Dalcin 
301d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscPartitionerInitialize_PTScotch(PetscPartitioner part)
302d71ae5a4SJacob Faibussowitsch {
303abe9303eSLisandro Dalcin   PetscFunctionBegin;
304abe9303eSLisandro Dalcin   part->noGraph             = PETSC_FALSE;
305abe9303eSLisandro Dalcin   part->ops->view           = PetscPartitionerView_PTScotch;
306abe9303eSLisandro Dalcin   part->ops->destroy        = PetscPartitionerDestroy_PTScotch;
307abe9303eSLisandro Dalcin   part->ops->partition      = PetscPartitionerPartition_PTScotch;
308abe9303eSLisandro Dalcin   part->ops->setfromoptions = PetscPartitionerSetFromOptions_PTScotch;
3093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
310abe9303eSLisandro Dalcin }
311abe9303eSLisandro Dalcin 
312abe9303eSLisandro Dalcin /*MC
313abe9303eSLisandro Dalcin   PETSCPARTITIONERPTSCOTCH = "ptscotch" - A PetscPartitioner object using the PT-Scotch library
314abe9303eSLisandro Dalcin 
315abe9303eSLisandro Dalcin   Level: intermediate
316abe9303eSLisandro Dalcin 
317abe9303eSLisandro Dalcin   Options Database Keys:
318abe9303eSLisandro Dalcin +  -petscpartitioner_ptscotch_strategy <string> - PT-Scotch strategy. Choose one of default quality speed balance safety scalability recursive remap
319abe9303eSLisandro Dalcin -  -petscpartitioner_ptscotch_imbalance <val> - Load imbalance ratio
320abe9303eSLisandro Dalcin 
321abe9303eSLisandro Dalcin   Notes: when the graph is on a single process, this partitioner actually uses Scotch and not PT-Scotch
322abe9303eSLisandro Dalcin 
323db781477SPatrick Sanan .seealso: `PetscPartitionerType`, `PetscPartitionerCreate()`, `PetscPartitionerSetType()`
324abe9303eSLisandro Dalcin M*/
325abe9303eSLisandro Dalcin 
326d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_PTScotch(PetscPartitioner part)
327d71ae5a4SJacob Faibussowitsch {
328abe9303eSLisandro Dalcin   PetscPartitioner_PTScotch *p;
329abe9303eSLisandro Dalcin 
330abe9303eSLisandro Dalcin   PetscFunctionBegin;
331abe9303eSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
3324dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&p));
333abe9303eSLisandro Dalcin   part->data = p;
334abe9303eSLisandro Dalcin 
3359566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_dup(PetscObjectComm((PetscObject)part), &p->pcomm));
336abe9303eSLisandro Dalcin   p->strategy  = 0;
337abe9303eSLisandro Dalcin   p->imbalance = 0.01;
338abe9303eSLisandro Dalcin 
3399566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerInitialize_PTScotch(part));
3409566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(PTScotchPartitionerCitation, &PTScotchPartitionerCite));
3413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
342abe9303eSLisandro Dalcin }
343