xref: /petsc/src/dm/impls/plex/plexpreallocate.c (revision a69119a591a03a9d906b29c0a4e9802e4d7c9795)
1 #include <petsc/private/dmpleximpl.h> /*I      "petscdmplex.h"   I*/
2 #include <petsc/private/isimpl.h>
3 #include <petscsf.h>
4 #include <petscds.h>
5 
6 /* get adjacencies due to point-to-point constraints that can't be found with DMPlexGetAdjacency() */
7 static PetscErrorCode DMPlexComputeAnchorAdjacencies(DM dm, PetscBool useCone, PetscBool useClosure, PetscSection *anchorSectionAdj, PetscInt *anchorAdj[]) {
8   PetscInt     pStart, pEnd;
9   PetscSection section, sectionGlobal, adjSec, aSec;
10   IS           aIS;
11 
12   PetscFunctionBegin;
13   PetscCall(DMGetLocalSection(dm, &section));
14   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
15   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &adjSec));
16   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
17   PetscCall(PetscSectionSetChart(adjSec, pStart, pEnd));
18 
19   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
20   if (aSec) {
21     const PetscInt *anchors;
22     PetscInt        p, q, a, aSize, *offsets, aStart, aEnd, *inverse, iSize, *adj, adjSize;
23     PetscInt       *tmpAdjP = NULL, *tmpAdjQ = NULL;
24     PetscSection    inverseSec;
25 
26     /* invert the constraint-to-anchor map */
27     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)aSec), &inverseSec));
28     PetscCall(PetscSectionSetChart(inverseSec, pStart, pEnd));
29     PetscCall(ISGetLocalSize(aIS, &aSize));
30     PetscCall(ISGetIndices(aIS, &anchors));
31 
32     for (p = 0; p < aSize; p++) {
33       PetscInt a = anchors[p];
34 
35       PetscCall(PetscSectionAddDof(inverseSec, a, 1));
36     }
37     PetscCall(PetscSectionSetUp(inverseSec));
38     PetscCall(PetscSectionGetStorageSize(inverseSec, &iSize));
39     PetscCall(PetscMalloc1(iSize, &inverse));
40     PetscCall(PetscCalloc1(pEnd - pStart, &offsets));
41     PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
42     for (p = aStart; p < aEnd; p++) {
43       PetscInt dof, off;
44 
45       PetscCall(PetscSectionGetDof(aSec, p, &dof));
46       PetscCall(PetscSectionGetOffset(aSec, p, &off));
47 
48       for (q = 0; q < dof; q++) {
49         PetscInt iOff;
50 
51         a = anchors[off + q];
52         PetscCall(PetscSectionGetOffset(inverseSec, a, &iOff));
53         inverse[iOff + offsets[a - pStart]++] = p;
54       }
55     }
56     PetscCall(ISRestoreIndices(aIS, &anchors));
57     PetscCall(PetscFree(offsets));
58 
59     /* construct anchorAdj and adjSec
60      *
61      * loop over anchors:
62      *   construct anchor adjacency
63      *   loop over constrained:
64      *     construct constrained adjacency
65      *     if not in anchor adjacency, add to dofs
66      * setup adjSec, allocate anchorAdj
67      * loop over anchors:
68      *   construct anchor adjacency
69      *   loop over constrained:
70      *     construct constrained adjacency
71      *     if not in anchor adjacency
72      *       if not already in list, put in list
73      *   sort, unique, reduce dof count
74      * optional: compactify
75      */
76     for (p = pStart; p < pEnd; p++) {
77       PetscInt iDof, iOff, i, r, s, numAdjP = PETSC_DETERMINE;
78 
79       PetscCall(PetscSectionGetDof(inverseSec, p, &iDof));
80       if (!iDof) continue;
81       PetscCall(PetscSectionGetOffset(inverseSec, p, &iOff));
82       PetscCall(DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, PETSC_TRUE, &numAdjP, &tmpAdjP));
83       for (i = 0; i < iDof; i++) {
84         PetscInt iNew = 0, qAdj, qAdjDof, qAdjCDof, numAdjQ = PETSC_DETERMINE;
85 
86         q = inverse[iOff + i];
87         PetscCall(DMPlexGetAdjacency_Internal(dm, q, useCone, useClosure, PETSC_TRUE, &numAdjQ, &tmpAdjQ));
88         for (r = 0; r < numAdjQ; r++) {
89           qAdj = tmpAdjQ[r];
90           if ((qAdj < pStart) || (qAdj >= pEnd)) continue;
91           for (s = 0; s < numAdjP; s++) {
92             if (qAdj == tmpAdjP[s]) break;
93           }
94           if (s < numAdjP) continue;
95           PetscCall(PetscSectionGetDof(section, qAdj, &qAdjDof));
96           PetscCall(PetscSectionGetConstraintDof(section, qAdj, &qAdjCDof));
97           iNew += qAdjDof - qAdjCDof;
98         }
99         PetscCall(PetscSectionAddDof(adjSec, p, iNew));
100       }
101     }
102 
103     PetscCall(PetscSectionSetUp(adjSec));
104     PetscCall(PetscSectionGetStorageSize(adjSec, &adjSize));
105     PetscCall(PetscMalloc1(adjSize, &adj));
106 
107     for (p = pStart; p < pEnd; p++) {
108       PetscInt iDof, iOff, i, r, s, aOff, aOffOrig, aDof, numAdjP = PETSC_DETERMINE;
109 
110       PetscCall(PetscSectionGetDof(inverseSec, p, &iDof));
111       if (!iDof) continue;
112       PetscCall(PetscSectionGetOffset(inverseSec, p, &iOff));
113       PetscCall(DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, PETSC_TRUE, &numAdjP, &tmpAdjP));
114       PetscCall(PetscSectionGetDof(adjSec, p, &aDof));
115       PetscCall(PetscSectionGetOffset(adjSec, p, &aOff));
116       aOffOrig = aOff;
117       for (i = 0; i < iDof; i++) {
118         PetscInt qAdj, qAdjDof, qAdjCDof, qAdjOff, nd, numAdjQ = PETSC_DETERMINE;
119 
120         q = inverse[iOff + i];
121         PetscCall(DMPlexGetAdjacency_Internal(dm, q, useCone, useClosure, PETSC_TRUE, &numAdjQ, &tmpAdjQ));
122         for (r = 0; r < numAdjQ; r++) {
123           qAdj = tmpAdjQ[r];
124           if ((qAdj < pStart) || (qAdj >= pEnd)) continue;
125           for (s = 0; s < numAdjP; s++) {
126             if (qAdj == tmpAdjP[s]) break;
127           }
128           if (s < numAdjP) continue;
129           PetscCall(PetscSectionGetDof(section, qAdj, &qAdjDof));
130           PetscCall(PetscSectionGetConstraintDof(section, qAdj, &qAdjCDof));
131           PetscCall(PetscSectionGetOffset(sectionGlobal, qAdj, &qAdjOff));
132           for (nd = 0; nd < qAdjDof - qAdjCDof; ++nd) adj[aOff++] = (qAdjOff < 0 ? -(qAdjOff + 1) : qAdjOff) + nd;
133         }
134       }
135       PetscCall(PetscSortRemoveDupsInt(&aDof, &adj[aOffOrig]));
136       PetscCall(PetscSectionSetDof(adjSec, p, aDof));
137     }
138     *anchorAdj = adj;
139 
140     /* clean up */
141     PetscCall(PetscSectionDestroy(&inverseSec));
142     PetscCall(PetscFree(inverse));
143     PetscCall(PetscFree(tmpAdjP));
144     PetscCall(PetscFree(tmpAdjQ));
145   } else {
146     *anchorAdj = NULL;
147     PetscCall(PetscSectionSetUp(adjSec));
148   }
149   *anchorSectionAdj = adjSec;
150   PetscFunctionReturn(0);
151 }
152 
153 static PetscErrorCode DMPlexCreateAdjacencySection_Static(DM dm, PetscInt bs, PetscSF sfDof, PetscBool useCone, PetscBool useClosure, PetscBool useAnchors, PetscSection *sA, PetscInt **colIdx) {
154   MPI_Comm           comm;
155   PetscMPIInt        size;
156   PetscBool          doCommLocal, doComm, debug = PETSC_FALSE;
157   PetscSF            sf, sfAdj;
158   PetscSection       section, sectionGlobal, leafSectionAdj, rootSectionAdj, sectionAdj, anchorSectionAdj;
159   PetscInt           nroots, nleaves, l, p, r;
160   const PetscInt    *leaves;
161   const PetscSFNode *remotes;
162   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
163   PetscInt          *tmpAdj = NULL, *adj, *rootAdj, *anchorAdj = NULL, *cols, *remoteOffsets;
164   PetscInt           adjSize;
165 
166   PetscFunctionBegin;
167   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
168   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_view_preallocation", &debug, NULL));
169   PetscCallMPI(MPI_Comm_size(comm, &size));
170   PetscCall(DMGetDimension(dm, &dim));
171   PetscCall(DMGetPointSF(dm, &sf));
172   PetscCall(DMGetLocalSection(dm, &section));
173   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
174   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
175   doCommLocal = (size > 1) && (nroots >= 0) ? PETSC_TRUE : PETSC_FALSE;
176   PetscCall(MPIU_Allreduce(&doCommLocal, &doComm, 1, MPIU_BOOL, MPI_LAND, comm));
177   /* Create section for dof adjacency (dof ==> # adj dof) */
178   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
179   PetscCall(PetscSectionGetStorageSize(section, &numDof));
180   PetscCall(PetscSectionCreate(comm, &leafSectionAdj));
181   PetscCall(PetscSectionSetChart(leafSectionAdj, 0, numDof));
182   PetscCall(PetscSectionCreate(comm, &rootSectionAdj));
183   PetscCall(PetscSectionSetChart(rootSectionAdj, 0, numDof));
184   /*   Fill in the ghost dofs on the interface */
185   PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, &remotes));
186   /*
187    section        - maps points to (# dofs, local dofs)
188    sectionGlobal  - maps points to (# dofs, global dofs)
189    leafSectionAdj - maps unowned local dofs to # adj dofs
190    rootSectionAdj - maps   owned local dofs to # adj dofs
191    adj            - adj global dofs indexed by leafSectionAdj
192    rootAdj        - adj global dofs indexed by rootSectionAdj
193    sf    - describes shared points across procs
194    sfDof - describes shared dofs across procs
195    sfAdj - describes shared adjacent dofs across procs
196    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
197   (0). If there are point-to-point constraints, add the adjacencies of constrained points to anchors in anchorAdj
198        (This is done in DMPlexComputeAnchorAdjacencies())
199     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
200        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
201     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
202        Create sfAdj connecting rootSectionAdj and leafSectionAdj
203     3. Visit unowned points on interface, write adjacencies to adj
204        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
205     4. Visit owned points on interface, write adjacencies to rootAdj
206        Remove redundancy in rootAdj
207    ** The last two traversals use transitive closure
208     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
209        Allocate memory addressed by sectionAdj (cols)
210     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
211    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
212   */
213   PetscCall(DMPlexComputeAnchorAdjacencies(dm, useCone, useClosure, &anchorSectionAdj, &anchorAdj));
214   for (l = 0; l < nleaves; ++l) {
215     PetscInt dof, off, d, q, anDof;
216     PetscInt p = leaves[l], numAdj = PETSC_DETERMINE;
217 
218     if ((p < pStart) || (p >= pEnd)) continue;
219     PetscCall(PetscSectionGetDof(section, p, &dof));
220     PetscCall(PetscSectionGetOffset(section, p, &off));
221     PetscCall(DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, useAnchors, &numAdj, &tmpAdj));
222     for (q = 0; q < numAdj; ++q) {
223       const PetscInt padj = tmpAdj[q];
224       PetscInt       ndof, ncdof;
225 
226       if ((padj < pStart) || (padj >= pEnd)) continue;
227       PetscCall(PetscSectionGetDof(section, padj, &ndof));
228       PetscCall(PetscSectionGetConstraintDof(section, padj, &ncdof));
229       for (d = off; d < off + dof; ++d) PetscCall(PetscSectionAddDof(leafSectionAdj, d, ndof - ncdof));
230     }
231     PetscCall(PetscSectionGetDof(anchorSectionAdj, p, &anDof));
232     if (anDof) {
233       for (d = off; d < off + dof; ++d) PetscCall(PetscSectionAddDof(leafSectionAdj, d, anDof));
234     }
235   }
236   PetscCall(PetscSectionSetUp(leafSectionAdj));
237   if (debug) {
238     PetscCall(PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n"));
239     PetscCall(PetscSectionView(leafSectionAdj, NULL));
240   }
241   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
242   if (doComm) {
243     PetscCall(PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM));
244     PetscCall(PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM));
245     PetscCall(PetscSectionInvalidateMaxDof_Internal(rootSectionAdj));
246   }
247   if (debug) {
248     PetscCall(PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n"));
249     PetscCall(PetscSectionView(rootSectionAdj, NULL));
250   }
251   /* Add in local adjacency sizes for owned dofs on interface (roots) */
252   for (p = pStart; p < pEnd; ++p) {
253     PetscInt numAdj = PETSC_DETERMINE, adof, dof, off, d, q, anDof;
254 
255     PetscCall(PetscSectionGetDof(section, p, &dof));
256     PetscCall(PetscSectionGetOffset(section, p, &off));
257     if (!dof) continue;
258     PetscCall(PetscSectionGetDof(rootSectionAdj, off, &adof));
259     if (adof <= 0) continue;
260     PetscCall(DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, useAnchors, &numAdj, &tmpAdj));
261     for (q = 0; q < numAdj; ++q) {
262       const PetscInt padj = tmpAdj[q];
263       PetscInt       ndof, ncdof;
264 
265       if ((padj < pStart) || (padj >= pEnd)) continue;
266       PetscCall(PetscSectionGetDof(section, padj, &ndof));
267       PetscCall(PetscSectionGetConstraintDof(section, padj, &ncdof));
268       for (d = off; d < off + dof; ++d) PetscCall(PetscSectionAddDof(rootSectionAdj, d, ndof - ncdof));
269     }
270     PetscCall(PetscSectionGetDof(anchorSectionAdj, p, &anDof));
271     if (anDof) {
272       for (d = off; d < off + dof; ++d) PetscCall(PetscSectionAddDof(rootSectionAdj, d, anDof));
273     }
274   }
275   PetscCall(PetscSectionSetUp(rootSectionAdj));
276   if (debug) {
277     PetscCall(PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n"));
278     PetscCall(PetscSectionView(rootSectionAdj, NULL));
279   }
280   /* Create adj SF based on dof SF */
281   PetscCall(PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets));
282   PetscCall(PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj));
283   PetscCall(PetscFree(remoteOffsets));
284   if (debug && size > 1) {
285     PetscCall(PetscPrintf(comm, "Adjacency SF for Preallocation:\n"));
286     PetscCall(PetscSFView(sfAdj, NULL));
287   }
288   /* Create leaf adjacency */
289   PetscCall(PetscSectionSetUp(leafSectionAdj));
290   PetscCall(PetscSectionGetStorageSize(leafSectionAdj, &adjSize));
291   PetscCall(PetscCalloc1(adjSize, &adj));
292   for (l = 0; l < nleaves; ++l) {
293     PetscInt dof, off, d, q, anDof, anOff;
294     PetscInt p = leaves[l], numAdj = PETSC_DETERMINE;
295 
296     if ((p < pStart) || (p >= pEnd)) continue;
297     PetscCall(PetscSectionGetDof(section, p, &dof));
298     PetscCall(PetscSectionGetOffset(section, p, &off));
299     PetscCall(DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, useAnchors, &numAdj, &tmpAdj));
300     PetscCall(PetscSectionGetDof(anchorSectionAdj, p, &anDof));
301     PetscCall(PetscSectionGetOffset(anchorSectionAdj, p, &anOff));
302     for (d = off; d < off + dof; ++d) {
303       PetscInt aoff, i = 0;
304 
305       PetscCall(PetscSectionGetOffset(leafSectionAdj, d, &aoff));
306       for (q = 0; q < numAdj; ++q) {
307         const PetscInt padj = tmpAdj[q];
308         PetscInt       ndof, ncdof, ngoff, nd;
309 
310         if ((padj < pStart) || (padj >= pEnd)) continue;
311         PetscCall(PetscSectionGetDof(section, padj, &ndof));
312         PetscCall(PetscSectionGetConstraintDof(section, padj, &ncdof));
313         PetscCall(PetscSectionGetOffset(sectionGlobal, padj, &ngoff));
314         for (nd = 0; nd < ndof - ncdof; ++nd) {
315           adj[aoff + i] = (ngoff < 0 ? -(ngoff + 1) : ngoff) + nd;
316           ++i;
317         }
318       }
319       for (q = 0; q < anDof; q++) {
320         adj[aoff + i] = anchorAdj[anOff + q];
321         ++i;
322       }
323     }
324   }
325   /* Debugging */
326   if (debug) {
327     IS tmp;
328     PetscCall(PetscPrintf(comm, "Leaf adjacency indices\n"));
329     PetscCall(ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp));
330     PetscCall(ISView(tmp, NULL));
331     PetscCall(ISDestroy(&tmp));
332   }
333   /* Gather adjacent indices to root */
334   PetscCall(PetscSectionGetStorageSize(rootSectionAdj, &adjSize));
335   PetscCall(PetscMalloc1(adjSize, &rootAdj));
336   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
337   if (doComm) {
338     const PetscInt *indegree;
339     PetscInt       *remoteadj, radjsize = 0;
340 
341     PetscCall(PetscSFComputeDegreeBegin(sfAdj, &indegree));
342     PetscCall(PetscSFComputeDegreeEnd(sfAdj, &indegree));
343     for (p = 0; p < adjSize; ++p) radjsize += indegree[p];
344     PetscCall(PetscMalloc1(radjsize, &remoteadj));
345     PetscCall(PetscSFGatherBegin(sfAdj, MPIU_INT, adj, remoteadj));
346     PetscCall(PetscSFGatherEnd(sfAdj, MPIU_INT, adj, remoteadj));
347     for (p = 0, l = 0, r = 0; p < adjSize; ++p, l = PetscMax(p, l + indegree[p - 1])) {
348       PetscInt s;
349       for (s = 0; s < indegree[p]; ++s, ++r) rootAdj[l + s] = remoteadj[r];
350     }
351     PetscCheck(r == radjsize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistency in communication %" PetscInt_FMT " != %" PetscInt_FMT, r, radjsize);
352     PetscCheck(l == adjSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistency in communication %" PetscInt_FMT " != %" PetscInt_FMT, l, adjSize);
353     PetscCall(PetscFree(remoteadj));
354   }
355   PetscCall(PetscSFDestroy(&sfAdj));
356   PetscCall(PetscFree(adj));
357   /* Debugging */
358   if (debug) {
359     IS tmp;
360     PetscCall(PetscPrintf(comm, "Root adjacency indices after gather\n"));
361     PetscCall(ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp));
362     PetscCall(ISView(tmp, NULL));
363     PetscCall(ISDestroy(&tmp));
364   }
365   /* Add in local adjacency indices for owned dofs on interface (roots) */
366   for (p = pStart; p < pEnd; ++p) {
367     PetscInt numAdj = PETSC_DETERMINE, adof, dof, off, d, q, anDof, anOff;
368 
369     PetscCall(PetscSectionGetDof(section, p, &dof));
370     PetscCall(PetscSectionGetOffset(section, p, &off));
371     if (!dof) continue;
372     PetscCall(PetscSectionGetDof(rootSectionAdj, off, &adof));
373     if (adof <= 0) continue;
374     PetscCall(DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, useAnchors, &numAdj, &tmpAdj));
375     PetscCall(PetscSectionGetDof(anchorSectionAdj, p, &anDof));
376     PetscCall(PetscSectionGetOffset(anchorSectionAdj, p, &anOff));
377     for (d = off; d < off + dof; ++d) {
378       PetscInt adof, aoff, i;
379 
380       PetscCall(PetscSectionGetDof(rootSectionAdj, d, &adof));
381       PetscCall(PetscSectionGetOffset(rootSectionAdj, d, &aoff));
382       i = adof - 1;
383       for (q = 0; q < anDof; q++) {
384         rootAdj[aoff + i] = anchorAdj[anOff + q];
385         --i;
386       }
387       for (q = 0; q < numAdj; ++q) {
388         const PetscInt padj = tmpAdj[q];
389         PetscInt       ndof, ncdof, ngoff, nd;
390 
391         if ((padj < pStart) || (padj >= pEnd)) continue;
392         PetscCall(PetscSectionGetDof(section, padj, &ndof));
393         PetscCall(PetscSectionGetConstraintDof(section, padj, &ncdof));
394         PetscCall(PetscSectionGetOffset(sectionGlobal, padj, &ngoff));
395         for (nd = 0; nd < ndof - ncdof; ++nd) {
396           rootAdj[aoff + i] = ngoff < 0 ? -(ngoff + 1) + nd : ngoff + nd;
397           --i;
398         }
399       }
400     }
401   }
402   /* Debugging */
403   if (debug) {
404     IS tmp;
405     PetscCall(PetscPrintf(comm, "Root adjacency indices\n"));
406     PetscCall(ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp));
407     PetscCall(ISView(tmp, NULL));
408     PetscCall(ISDestroy(&tmp));
409   }
410   /* Compress indices */
411   PetscCall(PetscSectionSetUp(rootSectionAdj));
412   for (p = pStart; p < pEnd; ++p) {
413     PetscInt dof, cdof, off, d;
414     PetscInt adof, aoff;
415 
416     PetscCall(PetscSectionGetDof(section, p, &dof));
417     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
418     PetscCall(PetscSectionGetOffset(section, p, &off));
419     if (!dof) continue;
420     PetscCall(PetscSectionGetDof(rootSectionAdj, off, &adof));
421     if (adof <= 0) continue;
422     for (d = off; d < off + dof - cdof; ++d) {
423       PetscCall(PetscSectionGetDof(rootSectionAdj, d, &adof));
424       PetscCall(PetscSectionGetOffset(rootSectionAdj, d, &aoff));
425       PetscCall(PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]));
426       PetscCall(PetscSectionSetDof(rootSectionAdj, d, adof));
427     }
428   }
429   /* Debugging */
430   if (debug) {
431     IS tmp;
432     PetscCall(PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n"));
433     PetscCall(PetscSectionView(rootSectionAdj, NULL));
434     PetscCall(PetscPrintf(comm, "Root adjacency indices after compression\n"));
435     PetscCall(ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp));
436     PetscCall(ISView(tmp, NULL));
437     PetscCall(ISDestroy(&tmp));
438   }
439   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
440   PetscCall(PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd));
441   PetscCall(PetscSectionCreate(comm, &sectionAdj));
442   PetscCall(PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd));
443   for (p = pStart; p < pEnd; ++p) {
444     PetscInt  numAdj = PETSC_DETERMINE, dof, cdof, off, goff, d, q, anDof;
445     PetscBool found  = PETSC_TRUE;
446 
447     PetscCall(PetscSectionGetDof(section, p, &dof));
448     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
449     PetscCall(PetscSectionGetOffset(section, p, &off));
450     PetscCall(PetscSectionGetOffset(sectionGlobal, p, &goff));
451     for (d = 0; d < dof - cdof; ++d) {
452       PetscInt ldof, rdof;
453 
454       PetscCall(PetscSectionGetDof(leafSectionAdj, off + d, &ldof));
455       PetscCall(PetscSectionGetDof(rootSectionAdj, off + d, &rdof));
456       if (ldof > 0) {
457         /* We do not own this point */
458       } else if (rdof > 0) {
459         PetscCall(PetscSectionSetDof(sectionAdj, goff + d, rdof));
460       } else {
461         found = PETSC_FALSE;
462       }
463     }
464     if (found) continue;
465     PetscCall(PetscSectionGetDof(section, p, &dof));
466     PetscCall(PetscSectionGetOffset(sectionGlobal, p, &goff));
467     PetscCall(DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, useAnchors, &numAdj, &tmpAdj));
468     for (q = 0; q < numAdj; ++q) {
469       const PetscInt padj = tmpAdj[q];
470       PetscInt       ndof, ncdof, noff;
471 
472       if ((padj < pStart) || (padj >= pEnd)) continue;
473       PetscCall(PetscSectionGetDof(section, padj, &ndof));
474       PetscCall(PetscSectionGetConstraintDof(section, padj, &ncdof));
475       PetscCall(PetscSectionGetOffset(section, padj, &noff));
476       for (d = goff; d < goff + dof - cdof; ++d) PetscCall(PetscSectionAddDof(sectionAdj, d, ndof - ncdof));
477     }
478     PetscCall(PetscSectionGetDof(anchorSectionAdj, p, &anDof));
479     if (anDof) {
480       for (d = goff; d < goff + dof - cdof; ++d) PetscCall(PetscSectionAddDof(sectionAdj, d, anDof));
481     }
482   }
483   PetscCall(PetscSectionSetUp(sectionAdj));
484   if (debug) {
485     PetscCall(PetscPrintf(comm, "Adjacency Section for Preallocation:\n"));
486     PetscCall(PetscSectionView(sectionAdj, NULL));
487   }
488   /* Get adjacent indices */
489   PetscCall(PetscSectionGetStorageSize(sectionAdj, &numCols));
490   PetscCall(PetscMalloc1(numCols, &cols));
491   for (p = pStart; p < pEnd; ++p) {
492     PetscInt  numAdj = PETSC_DETERMINE, dof, cdof, off, goff, d, q, anDof, anOff;
493     PetscBool found  = PETSC_TRUE;
494 
495     PetscCall(PetscSectionGetDof(section, p, &dof));
496     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
497     PetscCall(PetscSectionGetOffset(section, p, &off));
498     PetscCall(PetscSectionGetOffset(sectionGlobal, p, &goff));
499     for (d = 0; d < dof - cdof; ++d) {
500       PetscInt ldof, rdof;
501 
502       PetscCall(PetscSectionGetDof(leafSectionAdj, off + d, &ldof));
503       PetscCall(PetscSectionGetDof(rootSectionAdj, off + d, &rdof));
504       if (ldof > 0) {
505         /* We do not own this point */
506       } else if (rdof > 0) {
507         PetscInt aoff, roff;
508 
509         PetscCall(PetscSectionGetOffset(sectionAdj, goff + d, &aoff));
510         PetscCall(PetscSectionGetOffset(rootSectionAdj, off + d, &roff));
511         PetscCall(PetscArraycpy(&cols[aoff], &rootAdj[roff], rdof));
512       } else {
513         found = PETSC_FALSE;
514       }
515     }
516     if (found) continue;
517     PetscCall(DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, useAnchors, &numAdj, &tmpAdj));
518     PetscCall(PetscSectionGetDof(anchorSectionAdj, p, &anDof));
519     PetscCall(PetscSectionGetOffset(anchorSectionAdj, p, &anOff));
520     for (d = goff; d < goff + dof - cdof; ++d) {
521       PetscInt adof, aoff, i = 0;
522 
523       PetscCall(PetscSectionGetDof(sectionAdj, d, &adof));
524       PetscCall(PetscSectionGetOffset(sectionAdj, d, &aoff));
525       for (q = 0; q < numAdj; ++q) {
526         const PetscInt  padj = tmpAdj[q];
527         PetscInt        ndof, ncdof, ngoff, nd;
528         const PetscInt *ncind;
529 
530         /* Adjacent points may not be in the section chart */
531         if ((padj < pStart) || (padj >= pEnd)) continue;
532         PetscCall(PetscSectionGetDof(section, padj, &ndof));
533         PetscCall(PetscSectionGetConstraintDof(section, padj, &ncdof));
534         PetscCall(PetscSectionGetConstraintIndices(section, padj, &ncind));
535         PetscCall(PetscSectionGetOffset(sectionGlobal, padj, &ngoff));
536         for (nd = 0; nd < ndof - ncdof; ++nd, ++i) cols[aoff + i] = ngoff < 0 ? -(ngoff + 1) + nd : ngoff + nd;
537       }
538       for (q = 0; q < anDof; q++, i++) cols[aoff + i] = anchorAdj[anOff + q];
539       PetscCheck(i == adof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %" PetscInt_FMT " != %" PetscInt_FMT " for dof %" PetscInt_FMT " (point %" PetscInt_FMT ")", i, adof, d, p);
540     }
541   }
542   PetscCall(PetscSectionDestroy(&anchorSectionAdj));
543   PetscCall(PetscSectionDestroy(&leafSectionAdj));
544   PetscCall(PetscSectionDestroy(&rootSectionAdj));
545   PetscCall(PetscFree(anchorAdj));
546   PetscCall(PetscFree(rootAdj));
547   PetscCall(PetscFree(tmpAdj));
548   /* Debugging */
549   if (debug) {
550     IS tmp;
551     PetscCall(PetscPrintf(comm, "Column indices\n"));
552     PetscCall(ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp));
553     PetscCall(ISView(tmp, NULL));
554     PetscCall(ISDestroy(&tmp));
555   }
556 
557   *sA     = sectionAdj;
558   *colIdx = cols;
559   PetscFunctionReturn(0);
560 }
561 
562 static PetscErrorCode DMPlexUpdateAllocation_Static(DM dm, PetscLayout rLayout, PetscInt bs, PetscInt f, PetscSection sectionAdj, const PetscInt cols[], PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[]) {
563   PetscSection section;
564   PetscInt     rStart, rEnd, r, pStart, pEnd, p;
565 
566   PetscFunctionBegin;
567   /* This loop needs to change to a loop over points, then field dofs, which means we need to look both sections */
568   PetscCall(PetscLayoutGetRange(rLayout, &rStart, &rEnd));
569   PetscCheck((rStart % bs) == 0 && (rEnd % bs) == 0, PetscObjectComm((PetscObject)rLayout), PETSC_ERR_ARG_WRONG, "Invalid layout [%" PetscInt_FMT ", %" PetscInt_FMT ") for matrix, must be divisible by block size %" PetscInt_FMT, rStart, rEnd, bs);
570   if (f >= 0 && bs == 1) {
571     PetscCall(DMGetLocalSection(dm, &section));
572     PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
573     for (p = pStart; p < pEnd; ++p) {
574       PetscInt rS, rE;
575 
576       PetscCall(DMGetGlobalFieldOffset_Private(dm, p, f, &rS, &rE));
577       for (r = rS; r < rE; ++r) {
578         PetscInt numCols, cStart, c;
579 
580         PetscCall(PetscSectionGetDof(sectionAdj, r, &numCols));
581         PetscCall(PetscSectionGetOffset(sectionAdj, r, &cStart));
582         for (c = cStart; c < cStart + numCols; ++c) {
583           if ((cols[c] >= rStart) && (cols[c] < rEnd)) {
584             ++dnz[r - rStart];
585             if (cols[c] >= r) ++dnzu[r - rStart];
586           } else {
587             ++onz[r - rStart];
588             if (cols[c] >= r) ++onzu[r - rStart];
589           }
590         }
591       }
592     }
593   } else {
594     /* Only loop over blocks of rows */
595     for (r = rStart / bs; r < rEnd / bs; ++r) {
596       const PetscInt row = r * bs;
597       PetscInt       numCols, cStart, c;
598 
599       PetscCall(PetscSectionGetDof(sectionAdj, row, &numCols));
600       PetscCall(PetscSectionGetOffset(sectionAdj, row, &cStart));
601       for (c = cStart; c < cStart + numCols; ++c) {
602         if ((cols[c] >= rStart) && (cols[c] < rEnd)) {
603           ++dnz[r - rStart / bs];
604           if (cols[c] >= row) ++dnzu[r - rStart / bs];
605         } else {
606           ++onz[r - rStart / bs];
607           if (cols[c] >= row) ++onzu[r - rStart / bs];
608         }
609       }
610     }
611     for (r = 0; r < (rEnd - rStart) / bs; ++r) {
612       dnz[r] /= bs;
613       onz[r] /= bs;
614       dnzu[r] /= bs;
615       onzu[r] /= bs;
616     }
617   }
618   PetscFunctionReturn(0);
619 }
620 
621 static PetscErrorCode DMPlexFillMatrix_Static(DM dm, PetscLayout rLayout, PetscInt bs, PetscInt f, PetscSection sectionAdj, const PetscInt cols[], Mat A) {
622   PetscSection section;
623   PetscScalar *values;
624   PetscInt     rStart, rEnd, r, pStart, pEnd, p, len, maxRowLen = 0;
625 
626   PetscFunctionBegin;
627   PetscCall(PetscLayoutGetRange(rLayout, &rStart, &rEnd));
628   for (r = rStart; r < rEnd; ++r) {
629     PetscCall(PetscSectionGetDof(sectionAdj, r, &len));
630     maxRowLen = PetscMax(maxRowLen, len);
631   }
632   PetscCall(PetscCalloc1(maxRowLen, &values));
633   if (f >= 0 && bs == 1) {
634     PetscCall(DMGetLocalSection(dm, &section));
635     PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
636     for (p = pStart; p < pEnd; ++p) {
637       PetscInt rS, rE;
638 
639       PetscCall(DMGetGlobalFieldOffset_Private(dm, p, f, &rS, &rE));
640       for (r = rS; r < rE; ++r) {
641         PetscInt numCols, cStart;
642 
643         PetscCall(PetscSectionGetDof(sectionAdj, r, &numCols));
644         PetscCall(PetscSectionGetOffset(sectionAdj, r, &cStart));
645         PetscCall(MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES));
646       }
647     }
648   } else {
649     for (r = rStart; r < rEnd; ++r) {
650       PetscInt numCols, cStart;
651 
652       PetscCall(PetscSectionGetDof(sectionAdj, r, &numCols));
653       PetscCall(PetscSectionGetOffset(sectionAdj, r, &cStart));
654       PetscCall(MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES));
655     }
656   }
657   PetscCall(PetscFree(values));
658   PetscFunctionReturn(0);
659 }
660 
661 /*@C
662   DMPlexPreallocateOperator - Calculate the matrix nonzero pattern based upon the information in the DM,
663   the PetscDS it contains, and the default PetscSection.
664 
665   Collective
666 
667   Input Parameters:
668 + dm   - The DMPlex
669 . bs   - The matrix blocksize
670 . dnz  - An array to hold the number of nonzeros in the diagonal block
671 . onz  - An array to hold the number of nonzeros in the off-diagonal block
672 . dnzu - An array to hold the number of nonzeros in the upper triangle of the diagonal block
673 . onzu - An array to hold the number of nonzeros in the upper triangle of the off-diagonal block
674 - fillMatrix - If PETSC_TRUE, fill the matrix with zeros
675 
676   Output Parameter:
677 . A - The preallocated matrix
678 
679   Level: advanced
680 
681 .seealso: `DMCreateMatrix()`
682 @*/
683 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix) {
684   MPI_Comm     comm;
685   PetscDS      prob;
686   MatType      mtype;
687   PetscSF      sf, sfDof;
688   PetscSection section;
689   PetscInt    *remoteOffsets;
690   PetscSection sectionAdj[4] = {NULL, NULL, NULL, NULL};
691   PetscInt    *cols[4]       = {NULL, NULL, NULL, NULL};
692   PetscBool    useCone, useClosure;
693   PetscInt     Nf, f, idx, locRows;
694   PetscLayout  rLayout;
695   PetscBool    isSymBlock, isSymSeqBlock, isSymMPIBlock, debug = PETSC_FALSE;
696   PetscMPIInt  size;
697 
698   PetscFunctionBegin;
699   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
700   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
701   if (dnz) PetscValidIntPointer(dnz, 3);
702   if (onz) PetscValidIntPointer(onz, 4);
703   if (dnzu) PetscValidIntPointer(dnzu, 5);
704   if (onzu) PetscValidIntPointer(onzu, 6);
705   PetscCall(DMGetDS(dm, &prob));
706   PetscCall(DMGetPointSF(dm, &sf));
707   PetscCall(DMGetLocalSection(dm, &section));
708   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_view_preallocation", &debug, NULL));
709   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
710   PetscCallMPI(MPI_Comm_size(comm, &size));
711   PetscCall(PetscLogEventBegin(DMPLEX_Preallocate, dm, 0, 0, 0));
712   /* Create dof SF based on point SF */
713   if (debug) {
714     PetscSection section, sectionGlobal;
715     PetscSF      sf;
716 
717     PetscCall(DMGetPointSF(dm, &sf));
718     PetscCall(DMGetLocalSection(dm, &section));
719     PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
720     PetscCall(PetscPrintf(comm, "Input Section for Preallocation:\n"));
721     PetscCall(PetscSectionView(section, NULL));
722     PetscCall(PetscPrintf(comm, "Input Global Section for Preallocation:\n"));
723     PetscCall(PetscSectionView(sectionGlobal, NULL));
724     if (size > 1) {
725       PetscCall(PetscPrintf(comm, "Input SF for Preallocation:\n"));
726       PetscCall(PetscSFView(sf, NULL));
727     }
728   }
729   PetscCall(PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets));
730   PetscCall(PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof));
731   PetscCall(PetscFree(remoteOffsets));
732   if (debug && size > 1) {
733     PetscCall(PetscPrintf(comm, "Dof SF for Preallocation:\n"));
734     PetscCall(PetscSFView(sfDof, NULL));
735   }
736   /* Create allocation vectors from adjacency graph */
737   PetscCall(MatGetLocalSize(A, &locRows, NULL));
738   PetscCall(PetscLayoutCreate(comm, &rLayout));
739   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
740   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
741   PetscCall(PetscLayoutSetUp(rLayout));
742   /* There are 4 types of adjacency */
743   PetscCall(PetscSectionGetNumFields(section, &Nf));
744   if (Nf < 1 || bs > 1) {
745     PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
746     idx = (useCone ? 1 : 0) + (useClosure ? 2 : 0);
747     PetscCall(DMPlexCreateAdjacencySection_Static(dm, bs, sfDof, useCone, useClosure, PETSC_TRUE, &sectionAdj[idx], &cols[idx]));
748     PetscCall(DMPlexUpdateAllocation_Static(dm, rLayout, bs, -1, sectionAdj[idx], cols[idx], dnz, onz, dnzu, onzu));
749   } else {
750     for (f = 0; f < Nf; ++f) {
751       PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure));
752       idx = (useCone ? 1 : 0) + (useClosure ? 2 : 0);
753       if (!sectionAdj[idx]) PetscCall(DMPlexCreateAdjacencySection_Static(dm, bs, sfDof, useCone, useClosure, PETSC_TRUE, &sectionAdj[idx], &cols[idx]));
754       PetscCall(DMPlexUpdateAllocation_Static(dm, rLayout, bs, f, sectionAdj[idx], cols[idx], dnz, onz, dnzu, onzu));
755     }
756   }
757   PetscCall(PetscSFDestroy(&sfDof));
758   /* Set matrix pattern */
759   PetscCall(MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu));
760   PetscCall(MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
761   /* Check for symmetric storage */
762   PetscCall(MatGetType(A, &mtype));
763   PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
764   PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
765   PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
766   if (isSymBlock || isSymSeqBlock || isSymMPIBlock) PetscCall(MatSetOption(A, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE));
767   /* Fill matrix with zeros */
768   if (fillMatrix) {
769     if (Nf < 1 || bs > 1) {
770       PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
771       idx = (useCone ? 1 : 0) + (useClosure ? 2 : 0);
772       PetscCall(DMPlexFillMatrix_Static(dm, rLayout, bs, -1, sectionAdj[idx], cols[idx], A));
773     } else {
774       for (f = 0; f < Nf; ++f) {
775         PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure));
776         idx = (useCone ? 1 : 0) + (useClosure ? 2 : 0);
777         PetscCall(DMPlexFillMatrix_Static(dm, rLayout, bs, f, sectionAdj[idx], cols[idx], A));
778       }
779     }
780     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
781     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
782   }
783   PetscCall(PetscLayoutDestroy(&rLayout));
784   for (idx = 0; idx < 4; ++idx) {
785     PetscCall(PetscSectionDestroy(&sectionAdj[idx]));
786     PetscCall(PetscFree(cols[idx]));
787   }
788   PetscCall(PetscLogEventEnd(DMPLEX_Preallocate, dm, 0, 0, 0));
789   PetscFunctionReturn(0);
790 }
791 
792 #if 0
793 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
794 {
795   PetscInt       *tmpClosure,*tmpAdj,*visits;
796   PetscInt        c,cStart,cEnd,pStart,pEnd;
797 
798   PetscFunctionBegin;
799   PetscCall(DMGetDimension(dm, &dim));
800   PetscCall(DMPlexGetDepth(dm, &depth));
801   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
802 
803   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1));
804 
805   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
806   npoints = pEnd - pStart;
807 
808   PetscCall(PetscMalloc3(maxClosureSize,&tmpClosure,npoints,&lvisits,npoints,&visits));
809   PetscCall(PetscArrayzero(lvisits,pEnd-pStart));
810   PetscCall(PetscArrayzero(visits,pEnd-pStart));
811   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
812   for (c=cStart; c<cEnd; c++) {
813     PetscInt *support = tmpClosure;
814     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support));
815     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
816   }
817   PetscCall(PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM));
818   PetscCall(PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM));
819   PetscCall(PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits,MPI_REPLACE));
820   PetscCall(PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits));
821 
822   PetscCall(PetscSFGetRootRanks());
823 
824   PetscCall(PetscMalloc2(maxClosureSize*maxClosureSize,&cellmat,npoints,&owner));
825   for (c=cStart; c<cEnd; c++) {
826     PetscCall(PetscArrayzero(cellmat,maxClosureSize*maxClosureSize));
827     /*
828      Depth-first walk of transitive closure.
829      At each leaf frame f of transitive closure that we see, add 1/visits[f] to each pair (p,q) not marked as done in cellmat.
830      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
831      */
832   }
833 
834   PetscCall(PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM));
835   PetscCall(PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM));
836   PetscFunctionReturn(0);
837 }
838 #endif
839