Actual source code: partmatpart.c

  1: #include <petscmat.h>
  2: #include <petsc/private/partitionerimpl.h>

  4: typedef struct {
  5:   MatPartitioning mp;
  6: } PetscPartitioner_MatPartitioning;

  8: static PetscErrorCode PetscPartitionerMatPartitioningGetMatPartitioning_MatPartitioning(PetscPartitioner part, MatPartitioning *mp)
  9: {
 10:   PetscPartitioner_MatPartitioning *p = (PetscPartitioner_MatPartitioning *)part->data;

 12:   PetscFunctionBegin;
 13:   *mp = p->mp;
 14:   PetscFunctionReturn(PETSC_SUCCESS);
 15: }

 17: /*@C
 18:   PetscPartitionerMatPartitioningGetMatPartitioning - Get a MatPartitioning instance wrapped by this PetscPartitioner.

 20:   Not Collective

 22:   Input Parameter:
 23: . part - The PetscPartitioner

 25:   Output Parameter:
 26: . mp - The MatPartitioning

 28:   Level: developer

 30: .seealso: `DMPlexDistribute()`, `PetscPartitionerCreate()`
 31: @*/
 32: PetscErrorCode PetscPartitionerMatPartitioningGetMatPartitioning(PetscPartitioner part, MatPartitioning *mp)
 33: {
 34:   PetscFunctionBegin;
 36:   PetscAssertPointer(mp, 2);
 37:   PetscUseMethod(part, "PetscPartitionerMatPartitioningGetMatPartitioning_C", (PetscPartitioner, MatPartitioning *), (part, mp));
 38:   PetscFunctionReturn(PETSC_SUCCESS);
 39: }

 41: static PetscErrorCode PetscPartitionerDestroy_MatPartitioning(PetscPartitioner part)
 42: {
 43:   PetscPartitioner_MatPartitioning *p = (PetscPartitioner_MatPartitioning *)part->data;

 45:   PetscFunctionBegin;
 46:   PetscCall(MatPartitioningDestroy(&p->mp));
 47:   PetscCall(PetscObjectComposeFunction((PetscObject)part, "PetscPartitionerMatPartitioningGetMatPartitioning_C", NULL));
 48:   PetscCall(PetscFree(part->data));
 49:   PetscFunctionReturn(PETSC_SUCCESS);
 50: }

 52: static PetscErrorCode PetscPartitionerView_MatPartitioning_ASCII(PetscPartitioner part, PetscViewer viewer)
 53: {
 54:   PetscPartitioner_MatPartitioning *p = (PetscPartitioner_MatPartitioning *)part->data;
 55:   PetscViewerFormat                 format;

 57:   PetscFunctionBegin;
 58:   PetscCall(PetscViewerGetFormat(viewer, &format));
 59:   PetscCall(PetscViewerASCIIPrintf(viewer, "MatPartitioning Graph Partitioner:\n"));
 60:   PetscCall(PetscViewerASCIIPushTab(viewer));
 61:   if (p->mp) PetscCall(MatPartitioningView(p->mp, viewer));
 62:   PetscCall(PetscViewerASCIIPopTab(viewer));
 63:   PetscFunctionReturn(PETSC_SUCCESS);
 64: }

 66: static PetscErrorCode PetscPartitionerView_MatPartitioning(PetscPartitioner part, PetscViewer viewer)
 67: {
 68:   PetscBool iascii;

 70:   PetscFunctionBegin;
 73:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
 74:   if (iascii) PetscCall(PetscPartitionerView_MatPartitioning_ASCII(part, viewer));
 75:   PetscFunctionReturn(PETSC_SUCCESS);
 76: }

 78: static PetscErrorCode PetscPartitionerSetFromOptions_MatPartitioning(PetscPartitioner part, PetscOptionItems *PetscOptionsObject)
 79: {
 80:   PetscPartitioner_MatPartitioning *p = (PetscPartitioner_MatPartitioning *)part->data;

 82:   PetscFunctionBegin;
 83:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)p->mp, ((PetscObject)part)->prefix));
 84:   PetscCall(MatPartitioningSetFromOptions(p->mp));
 85:   PetscFunctionReturn(PETSC_SUCCESS);
 86: }

 88: static PetscErrorCode PetscPartitionerPartition_MatPartitioning(PetscPartitioner part, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection vertSection, PetscSection edgeSection, PetscSection targetSection, PetscSection partSection, IS *is)
 89: {
 90:   PetscPartitioner_MatPartitioning *p = (PetscPartitioner_MatPartitioning *)part->data;
 91:   Mat                               matadj;
 92:   IS                                is1, is2, is3;
 93:   PetscReal                        *tpwgts = NULL;
 94:   PetscInt                          numVerticesGlobal, numEdges;
 95:   PetscInt                         *i, *j, *vwgt = NULL;
 96:   MPI_Comm                          comm;

 98:   PetscFunctionBegin;
 99:   PetscCall(PetscObjectGetComm((PetscObject)part, &comm));

101:   /* TODO: MatCreateMPIAdj should maybe take global number of ROWS */
102:   /* TODO: And vertex distribution in PetscPartitionerPartition_ParMetis should be done using PetscSplitOwnership */
103:   numVerticesGlobal = PETSC_DECIDE;
104:   PetscCall(PetscSplitOwnership(comm, &numVertices, &numVerticesGlobal));

106:   /* copy arrays to avoid memory errors because MatMPIAdjSetPreallocation copies just pointers */
107:   numEdges = start[numVertices];
108:   PetscCall(PetscMalloc1(numVertices + 1, &i));
109:   PetscCall(PetscMalloc1(numEdges, &j));
110:   PetscCall(PetscArraycpy(i, start, numVertices + 1));
111:   PetscCall(PetscArraycpy(j, adjacency, numEdges));

113:   /* construct the adjacency matrix */
114:   PetscCall(MatCreateMPIAdj(comm, numVertices, numVerticesGlobal, i, j, NULL, &matadj));
115:   PetscCall(MatPartitioningSetAdjacency(p->mp, matadj));
116:   PetscCall(MatPartitioningSetNParts(p->mp, nparts));

118:   /* calculate partition weights */
119:   if (targetSection) {
120:     PetscReal sumt;
121:     PetscInt  p;

123:     sumt = 0.0;
124:     PetscCall(PetscMalloc1(nparts, &tpwgts));
125:     for (p = 0; p < nparts; ++p) {
126:       PetscInt tpd;

128:       PetscCall(PetscSectionGetDof(targetSection, p, &tpd));
129:       sumt += tpd;
130:       tpwgts[p] = tpd;
131:     }
132:     if (sumt) { /* METIS/ParMETIS do not like exactly zero weight */
133:       for (p = 0, sumt = 0.0; p < nparts; ++p) {
134:         tpwgts[p] = PetscMax(tpwgts[p], PETSC_SMALL);
135:         sumt += tpwgts[p];
136:       }
137:       for (p = 0; p < nparts; ++p) tpwgts[p] /= sumt;
138:       for (p = 0, sumt = 0.0; p < nparts - 1; ++p) sumt += tpwgts[p];
139:       tpwgts[nparts - 1] = 1. - sumt;
140:     } else {
141:       PetscCall(PetscFree(tpwgts));
142:     }
143:   }
144:   PetscCall(MatPartitioningSetPartitionWeights(p->mp, tpwgts));

146:   /* calculate vertex weights */
147:   if (vertSection) {
148:     PetscInt v;

150:     PetscCall(PetscMalloc1(numVertices, &vwgt));
151:     for (v = 0; v < numVertices; ++v) PetscCall(PetscSectionGetDof(vertSection, v, &vwgt[v]));
152:   }
153:   PetscCall(MatPartitioningSetVertexWeights(p->mp, vwgt));

155:   /* apply the partitioning */
156:   PetscCall(MatPartitioningApply(p->mp, &is1));

158:   /* construct the PetscSection */
159:   {
160:     PetscInt        v;
161:     const PetscInt *assignment_arr;

163:     PetscCall(ISGetIndices(is1, &assignment_arr));
164:     for (v = 0; v < numVertices; ++v) PetscCall(PetscSectionAddDof(partSection, assignment_arr[v], 1));
165:     PetscCall(ISRestoreIndices(is1, &assignment_arr));
166:   }

168:   /* convert assignment IS to global numbering IS */
169:   PetscCall(ISPartitioningToNumbering(is1, &is2));
170:   PetscCall(ISDestroy(&is1));

172:   /* renumber IS into local numbering */
173:   PetscCall(ISOnComm(is2, PETSC_COMM_SELF, PETSC_USE_POINTER, &is1));
174:   PetscCall(ISRenumber(is1, NULL, NULL, &is3));
175:   PetscCall(ISDestroy(&is1));
176:   PetscCall(ISDestroy(&is2));

178:   /* invert IS */
179:   PetscCall(ISSetPermutation(is3));
180:   PetscCall(ISInvertPermutation(is3, numVertices, &is1));
181:   PetscCall(ISDestroy(&is3));

183:   PetscCall(MatDestroy(&matadj));
184:   *is = is1;
185:   PetscFunctionReturn(PETSC_SUCCESS);
186: }

188: static PetscErrorCode PetscPartitionerInitialize_MatPartitioning(PetscPartitioner part)
189: {
190:   PetscFunctionBegin;
191:   part->ops->view           = PetscPartitionerView_MatPartitioning;
192:   part->ops->setfromoptions = PetscPartitionerSetFromOptions_MatPartitioning;
193:   part->ops->destroy        = PetscPartitionerDestroy_MatPartitioning;
194:   part->ops->partition      = PetscPartitionerPartition_MatPartitioning;
195:   PetscCall(PetscObjectComposeFunction((PetscObject)part, "PetscPartitionerMatPartitioningGetMatPartitioning_C", PetscPartitionerMatPartitioningGetMatPartitioning_MatPartitioning));
196:   PetscFunctionReturn(PETSC_SUCCESS);
197: }

199: /*MC
200:   PETSCPARTITIONERMATPARTITIONING = "matpartitioning" - A PetscPartitioner object

202:   Level: developer

204: .seealso: `PetscPartitionerType`, `PetscPartitionerCreate()`, `PetscPartitionerSetType()`
205: M*/

207: PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_MatPartitioning(PetscPartitioner part)
208: {
209:   PetscPartitioner_MatPartitioning *p;

211:   PetscFunctionBegin;
213:   PetscCall(PetscNew(&p));
214:   part->data = p;
215:   PetscCall(PetscPartitionerInitialize_MatPartitioning(part));
216:   PetscCall(MatPartitioningCreate(PetscObjectComm((PetscObject)part), &p->mp));
217:   PetscFunctionReturn(PETSC_SUCCESS);
218: }