xref: /petsc/src/vec/is/sf/utils/sfutils.c (revision e6d3c4ed1c11b3b5c034a54a6d566a42f9afdff6)
1 #include <petsc/private/sfimpl.h> /*I  "petscsf.h"   I*/
2 #include <petsc/private/sectionimpl.h>
3 
4 /*@
5    PetscSFSetGraphLayout - Set a parallel star forest via global indices and a PetscLayout
6 
7    Collective
8 
9    Input Parameters:
10 +  sf - star forest
11 .  layout - PetscLayout defining the global space for roots
12 .  nleaves - number of leaf vertices on the current process, each of these references a root on any process
13 .  ilocal - locations of leaves in leafdata buffers, pass NULL for contiguous storage
14 .  localmode - copy mode for ilocal
15 -  gremote - root vertices in global numbering corresponding to leaves in ilocal
16 
17    Level: intermediate
18 
19    Notes:
20    Global indices must lie in [0, N) where N is the global size of layout.
21    Leaf indices in ilocal get sorted; this means the user-provided array gets sorted if localmode is PETSC_OWN_POINTER.
22 
23    Developer Notes:
24    Local indices which are the identity permutation in the range [0,nleaves) are discarded as they
25    encode contiguous storage. In such case, if localmode is PETSC_OWN_POINTER, the memory is deallocated as it is not
26    needed
27 
28 .seealso: `PetscSFGetGraphLayout()`, `PetscSFCreate()`, `PetscSFView()`, `PetscSFSetGraph()`, `PetscSFGetGraph()`
29 @*/
30 PetscErrorCode PetscSFSetGraphLayout(PetscSF sf, PetscLayout layout, PetscInt nleaves, PetscInt *ilocal, PetscCopyMode localmode, const PetscInt *gremote)
31 {
32   const PetscInt *range;
33   PetscInt        i, nroots, ls = -1, ln = -1;
34   PetscMPIInt     lr = -1;
35   PetscSFNode    *remote;
36 
37   PetscFunctionBegin;
38   PetscCall(PetscLayoutGetLocalSize(layout, &nroots));
39   PetscCall(PetscLayoutGetRanges(layout, &range));
40   PetscCall(PetscMalloc1(nleaves, &remote));
41   if (nleaves) ls = gremote[0] + 1;
42   for (i = 0; i < nleaves; i++) {
43     const PetscInt idx = gremote[i] - ls;
44     if (idx < 0 || idx >= ln) { /* short-circuit the search */
45       PetscCall(PetscLayoutFindOwnerIndex(layout, gremote[i], &lr, &remote[i].index));
46       remote[i].rank = lr;
47       ls             = range[lr];
48       ln             = range[lr + 1] - ls;
49     } else {
50       remote[i].rank  = lr;
51       remote[i].index = idx;
52     }
53   }
54   PetscCall(PetscSFSetGraph(sf, nroots, nleaves, ilocal, localmode, remote, PETSC_OWN_POINTER));
55   PetscFunctionReturn(0);
56 }
57 
58 /*@C
59    PetscSFGetGraphLayout - Get the global indices and PetscLayout that describe this star forest
60 
61    Collective
62 
63    Input Parameter:
64 .  sf - star forest
65 
66    Output Parameters:
67 +  layout - PetscLayout defining the global space for roots
68 .  nleaves - number of leaf vertices on the current process, each of these references a root on any process
69 .  ilocal - locations of leaves in leafdata buffers, or NULL for contiguous storage
70 -  gremote - root vertices in global numbering corresponding to leaves in ilocal
71 
72    Level: intermediate
73 
74    Notes:
75    The outputs are such that passing them as inputs to `PetscSFSetGraphLayout()` would lead to the same star forest.
76    The outputs layout and gremote are freshly created each time this function is called,
77    so they need to be freed by user and cannot be qualified as const.
78 
79 .seealso: `PetscSFSetGraphLayout()`, `PetscSFCreate()`, `PetscSFView()`, `PetscSFSetGraph()`, `PetscSFGetGraph()`
80 @*/
81 PetscErrorCode PetscSFGetGraphLayout(PetscSF sf, PetscLayout *layout, PetscInt *nleaves, const PetscInt *ilocal[], PetscInt *gremote[])
82 {
83   PetscInt           nr, nl;
84   const PetscSFNode *ir;
85   PetscLayout        lt;
86 
87   PetscFunctionBegin;
88   PetscCall(PetscSFGetGraph(sf, &nr, &nl, ilocal, &ir));
89   PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)sf), nr, PETSC_DECIDE, 1, &lt));
90   if (gremote) {
91     PetscInt        i;
92     const PetscInt *range;
93     PetscInt       *gr;
94 
95     PetscCall(PetscLayoutGetRanges(lt, &range));
96     PetscCall(PetscMalloc1(nl, &gr));
97     for (i = 0; i < nl; i++) gr[i] = range[ir[i].rank] + ir[i].index;
98     *gremote = gr;
99   }
100   if (nleaves) *nleaves = nl;
101   if (layout) *layout = lt;
102   else PetscCall(PetscLayoutDestroy(&lt));
103   PetscFunctionReturn(0);
104 }
105 
106 /*@
107   PetscSFSetGraphSection - Sets the PetscSF graph encoding the parallel dof overlap based upon the PetscSections
108   describing the data layout.
109 
110   Input Parameters:
111 + sf - The SF
112 . localSection - PetscSection describing the local data layout
113 - globalSection - PetscSection describing the global data layout
114 
115   Level: developer
116 
117 .seealso: `PetscSFSetGraph()`, `PetscSFSetGraphLayout()`
118 @*/
119 PetscErrorCode PetscSFSetGraphSection(PetscSF sf, PetscSection localSection, PetscSection globalSection)
120 {
121   MPI_Comm        comm;
122   PetscLayout     layout;
123   const PetscInt *ranges;
124   PetscInt       *local;
125   PetscSFNode    *remote;
126   PetscInt        pStart, pEnd, p, nroots, nleaves = 0, l;
127   PetscMPIInt     size, rank;
128 
129   PetscFunctionBegin;
130   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
131   PetscValidHeaderSpecific(localSection, PETSC_SECTION_CLASSID, 2);
132   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
133 
134   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
135   PetscCallMPI(MPI_Comm_size(comm, &size));
136   PetscCallMPI(MPI_Comm_rank(comm, &rank));
137   PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd));
138   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots));
139   PetscCall(PetscLayoutCreate(comm, &layout));
140   PetscCall(PetscLayoutSetBlockSize(layout, 1));
141   PetscCall(PetscLayoutSetLocalSize(layout, nroots));
142   PetscCall(PetscLayoutSetUp(layout));
143   PetscCall(PetscLayoutGetRanges(layout, &ranges));
144   for (p = pStart; p < pEnd; ++p) {
145     PetscInt gdof, gcdof;
146 
147     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
148     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
149     PetscCheck(gcdof <= (gdof < 0 ? -(gdof + 1) : gdof), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " has %" PetscInt_FMT " constraints > %" PetscInt_FMT " dof", p, gcdof, (gdof < 0 ? -(gdof + 1) : gdof));
150     nleaves += gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
151   }
152   PetscCall(PetscMalloc1(nleaves, &local));
153   PetscCall(PetscMalloc1(nleaves, &remote));
154   for (p = pStart, l = 0; p < pEnd; ++p) {
155     const PetscInt *cind;
156     PetscInt        dof, cdof, off, gdof, gcdof, goff, gsize, d, c;
157 
158     PetscCall(PetscSectionGetDof(localSection, p, &dof));
159     PetscCall(PetscSectionGetOffset(localSection, p, &off));
160     PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof));
161     PetscCall(PetscSectionGetConstraintIndices(localSection, p, &cind));
162     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
163     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
164     PetscCall(PetscSectionGetOffset(globalSection, p, &goff));
165     if (!gdof) continue; /* Censored point */
166     gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
167     if (gsize != dof - cdof) {
168       PetscCheck(gsize == dof, comm, PETSC_ERR_ARG_WRONG, "Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " is neither the constrained size %" PetscInt_FMT ", nor the unconstrained %" PetscInt_FMT, gsize, p, dof - cdof, dof);
169       cdof = 0; /* Ignore constraints */
170     }
171     for (d = 0, c = 0; d < dof; ++d) {
172       if ((c < cdof) && (cind[c] == d)) {
173         ++c;
174         continue;
175       }
176       local[l + d - c] = off + d;
177     }
178     PetscCheck(d - c == gsize, comm, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT ": Global dof %" PetscInt_FMT " != %" PetscInt_FMT " size - number of constraints", p, gsize, d - c);
179     if (gdof < 0) {
180       for (d = 0; d < gsize; ++d, ++l) {
181         PetscInt offset = -(goff + 1) + d, r;
182 
183         PetscCall(PetscFindInt(offset, size + 1, ranges, &r));
184         if (r < 0) r = -(r + 2);
185         PetscCheck(!(r < 0) && !(r >= size), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")", p, r, gdof, goff);
186         remote[l].rank  = r;
187         remote[l].index = offset - ranges[r];
188       }
189     } else {
190       for (d = 0; d < gsize; ++d, ++l) {
191         remote[l].rank  = rank;
192         remote[l].index = goff + d - ranges[rank];
193       }
194     }
195   }
196   PetscCheck(l == nleaves, comm, PETSC_ERR_PLIB, "Iteration error, l %" PetscInt_FMT " != nleaves %" PetscInt_FMT, l, nleaves);
197   PetscCall(PetscLayoutDestroy(&layout));
198   PetscCall(PetscSFSetGraph(sf, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER));
199   PetscFunctionReturn(0);
200 }
201 
202 /*@C
203   PetscSFDistributeSection - Create a new PetscSection reorganized, moving from the root to the leaves of the SF
204 
205   Collective on sf
206 
207   Input Parameters:
208 + sf - The SF
209 - rootSection - Section defined on root space
210 
211   Output Parameters:
212 + remoteOffsets - root offsets in leaf storage, or NULL
213 - leafSection - Section defined on the leaf space
214 
215   Level: advanced
216 
217 .seealso: `PetscSFCreate()`
218 @*/
219 PetscErrorCode PetscSFDistributeSection(PetscSF sf, PetscSection rootSection, PetscInt **remoteOffsets, PetscSection leafSection)
220 {
221   PetscSF         embedSF;
222   const PetscInt *indices;
223   IS              selected;
224   PetscInt        numFields, nroots, rpStart, rpEnd, lpStart = PETSC_MAX_INT, lpEnd = -1, f, c;
225   PetscBool      *sub, hasc;
226 
227   PetscFunctionBegin;
228   PetscCall(PetscLogEventBegin(PETSCSF_DistSect, sf, 0, 0, 0));
229   PetscCall(PetscSectionGetNumFields(rootSection, &numFields));
230   if (numFields) {
231     IS perm;
232 
233     /* PetscSectionSetNumFields() calls PetscSectionReset(), which destroys
234        leafSection->perm. To keep this permutation set by the user, we grab
235        the reference before calling PetscSectionSetNumFields() and set it
236        back after. */
237     PetscCall(PetscSectionGetPermutation(leafSection, &perm));
238     PetscCall(PetscObjectReference((PetscObject)perm));
239     PetscCall(PetscSectionSetNumFields(leafSection, numFields));
240     PetscCall(PetscSectionSetPermutation(leafSection, perm));
241     PetscCall(ISDestroy(&perm));
242   }
243   PetscCall(PetscMalloc1(numFields + 2, &sub));
244   sub[1] = rootSection->bc ? PETSC_TRUE : PETSC_FALSE;
245   for (f = 0; f < numFields; ++f) {
246     PetscSectionSym sym, dsym = NULL;
247     const char     *name    = NULL;
248     PetscInt        numComp = 0;
249 
250     sub[2 + f] = rootSection->field[f]->bc ? PETSC_TRUE : PETSC_FALSE;
251     PetscCall(PetscSectionGetFieldComponents(rootSection, f, &numComp));
252     PetscCall(PetscSectionGetFieldName(rootSection, f, &name));
253     PetscCall(PetscSectionGetFieldSym(rootSection, f, &sym));
254     if (sym) PetscCall(PetscSectionSymDistribute(sym, sf, &dsym));
255     PetscCall(PetscSectionSetFieldComponents(leafSection, f, numComp));
256     PetscCall(PetscSectionSetFieldName(leafSection, f, name));
257     PetscCall(PetscSectionSetFieldSym(leafSection, f, dsym));
258     PetscCall(PetscSectionSymDestroy(&dsym));
259     for (c = 0; c < rootSection->numFieldComponents[f]; ++c) {
260       PetscCall(PetscSectionGetComponentName(rootSection, f, c, &name));
261       PetscCall(PetscSectionSetComponentName(leafSection, f, c, name));
262     }
263   }
264   PetscCall(PetscSectionGetChart(rootSection, &rpStart, &rpEnd));
265   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
266   rpEnd = PetscMin(rpEnd, nroots);
267   rpEnd = PetscMax(rpStart, rpEnd);
268   /* see if we can avoid creating the embedded SF, since it can cost more than an allreduce */
269   sub[0] = (PetscBool)(nroots != rpEnd - rpStart);
270   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, sub, 2 + numFields, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)sf)));
271   if (sub[0]) {
272     PetscCall(ISCreateStride(PETSC_COMM_SELF, rpEnd - rpStart, rpStart, 1, &selected));
273     PetscCall(ISGetIndices(selected, &indices));
274     PetscCall(PetscSFCreateEmbeddedRootSF(sf, rpEnd - rpStart, indices, &embedSF));
275     PetscCall(ISRestoreIndices(selected, &indices));
276     PetscCall(ISDestroy(&selected));
277   } else {
278     PetscCall(PetscObjectReference((PetscObject)sf));
279     embedSF = sf;
280   }
281   PetscCall(PetscSFGetLeafRange(embedSF, &lpStart, &lpEnd));
282   lpEnd++;
283 
284   PetscCall(PetscSectionSetChart(leafSection, lpStart, lpEnd));
285 
286   /* Constrained dof section */
287   hasc = sub[1];
288   for (f = 0; f < numFields; ++f) hasc = (PetscBool)(hasc || sub[2 + f]);
289 
290   /* Could fuse these at the cost of copies and extra allocation */
291   PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->atlasDof[-rpStart], &leafSection->atlasDof[-lpStart], MPI_REPLACE));
292   PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->atlasDof[-rpStart], &leafSection->atlasDof[-lpStart], MPI_REPLACE));
293   if (sub[1]) {
294     PetscCall(PetscSectionCheckConstraints_Private(rootSection));
295     PetscCall(PetscSectionCheckConstraints_Private(leafSection));
296     PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->bc->atlasDof[-rpStart], &leafSection->bc->atlasDof[-lpStart], MPI_REPLACE));
297     PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->bc->atlasDof[-rpStart], &leafSection->bc->atlasDof[-lpStart], MPI_REPLACE));
298   }
299   for (f = 0; f < numFields; ++f) {
300     PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->atlasDof[-rpStart], &leafSection->field[f]->atlasDof[-lpStart], MPI_REPLACE));
301     PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->atlasDof[-rpStart], &leafSection->field[f]->atlasDof[-lpStart], MPI_REPLACE));
302     if (sub[2 + f]) {
303       PetscCall(PetscSectionCheckConstraints_Private(rootSection->field[f]));
304       PetscCall(PetscSectionCheckConstraints_Private(leafSection->field[f]));
305       PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasDof[-rpStart], &leafSection->field[f]->bc->atlasDof[-lpStart], MPI_REPLACE));
306       PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasDof[-rpStart], &leafSection->field[f]->bc->atlasDof[-lpStart], MPI_REPLACE));
307     }
308   }
309   if (remoteOffsets) {
310     PetscCall(PetscMalloc1(lpEnd - lpStart, remoteOffsets));
311     PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart], MPI_REPLACE));
312     PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart], MPI_REPLACE));
313   }
314   PetscCall(PetscSectionInvalidateMaxDof_Internal(leafSection));
315   PetscCall(PetscSectionSetUp(leafSection));
316   if (hasc) { /* need to communicate bcIndices */
317     PetscSF   bcSF;
318     PetscInt *rOffBc;
319 
320     PetscCall(PetscMalloc1(lpEnd - lpStart, &rOffBc));
321     if (sub[1]) {
322       PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
323       PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
324       PetscCall(PetscSFCreateSectionSF(embedSF, rootSection->bc, rOffBc, leafSection->bc, &bcSF));
325       PetscCall(PetscSFBcastBegin(bcSF, MPIU_INT, rootSection->bcIndices, leafSection->bcIndices, MPI_REPLACE));
326       PetscCall(PetscSFBcastEnd(bcSF, MPIU_INT, rootSection->bcIndices, leafSection->bcIndices, MPI_REPLACE));
327       PetscCall(PetscSFDestroy(&bcSF));
328     }
329     for (f = 0; f < numFields; ++f) {
330       if (sub[2 + f]) {
331         PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
332         PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
333         PetscCall(PetscSFCreateSectionSF(embedSF, rootSection->field[f]->bc, rOffBc, leafSection->field[f]->bc, &bcSF));
334         PetscCall(PetscSFBcastBegin(bcSF, MPIU_INT, rootSection->field[f]->bcIndices, leafSection->field[f]->bcIndices, MPI_REPLACE));
335         PetscCall(PetscSFBcastEnd(bcSF, MPIU_INT, rootSection->field[f]->bcIndices, leafSection->field[f]->bcIndices, MPI_REPLACE));
336         PetscCall(PetscSFDestroy(&bcSF));
337       }
338     }
339     PetscCall(PetscFree(rOffBc));
340   }
341   PetscCall(PetscSFDestroy(&embedSF));
342   PetscCall(PetscFree(sub));
343   PetscCall(PetscLogEventEnd(PETSCSF_DistSect, sf, 0, 0, 0));
344   PetscFunctionReturn(0);
345 }
346 
347 /*@C
348   PetscSFCreateRemoteOffsets - Create offsets for point data on remote processes
349 
350   Collective on sf
351 
352   Input Parameters:
353 + sf          - The SF
354 . rootSection - Data layout of remote points for outgoing data (this is layout for SF roots)
355 - leafSection - Data layout of local points for incoming data  (this is layout for SF leaves)
356 
357   Output Parameter:
358 . remoteOffsets - Offsets for point data on remote processes (these are offsets from the root section), or NULL
359 
360   Level: developer
361 
362 .seealso: `PetscSFCreate()`
363 @*/
364 PetscErrorCode PetscSFCreateRemoteOffsets(PetscSF sf, PetscSection rootSection, PetscSection leafSection, PetscInt **remoteOffsets)
365 {
366   PetscSF         embedSF;
367   const PetscInt *indices;
368   IS              selected;
369   PetscInt        numRoots, rpStart = 0, rpEnd = 0, lpStart = 0, lpEnd = 0;
370 
371   PetscFunctionBegin;
372   *remoteOffsets = NULL;
373   PetscCall(PetscSFGetGraph(sf, &numRoots, NULL, NULL, NULL));
374   if (numRoots < 0) PetscFunctionReturn(0);
375   PetscCall(PetscLogEventBegin(PETSCSF_RemoteOff, sf, 0, 0, 0));
376   PetscCall(PetscSectionGetChart(rootSection, &rpStart, &rpEnd));
377   PetscCall(PetscSectionGetChart(leafSection, &lpStart, &lpEnd));
378   PetscCall(ISCreateStride(PETSC_COMM_SELF, rpEnd - rpStart, rpStart, 1, &selected));
379   PetscCall(ISGetIndices(selected, &indices));
380   PetscCall(PetscSFCreateEmbeddedRootSF(sf, rpEnd - rpStart, indices, &embedSF));
381   PetscCall(ISRestoreIndices(selected, &indices));
382   PetscCall(ISDestroy(&selected));
383   PetscCall(PetscCalloc1(lpEnd - lpStart, remoteOffsets));
384   PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart], MPI_REPLACE));
385   PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart], MPI_REPLACE));
386   PetscCall(PetscSFDestroy(&embedSF));
387   PetscCall(PetscLogEventEnd(PETSCSF_RemoteOff, sf, 0, 0, 0));
388   PetscFunctionReturn(0);
389 }
390 
391 /*@C
392   PetscSFCreateSectionSF - Create an expanded SF of dofs, assuming the input SF relates points
393 
394   Collective on sf
395 
396   Input Parameters:
397 + sf - The SF
398 . rootSection - Data layout of remote points for outgoing data (this is usually the serial section)
399 . remoteOffsets - Offsets for point data on remote processes (these are offsets from the root section), or NULL
400 - leafSection - Data layout of local points for incoming data  (this is the distributed section)
401 
402   Output Parameters:
403 - sectionSF - The new SF
404 
405   Note: Either rootSection or remoteOffsets can be specified
406 
407   Level: advanced
408 
409 .seealso: `PetscSFCreate()`
410 @*/
411 PetscErrorCode PetscSFCreateSectionSF(PetscSF sf, PetscSection rootSection, PetscInt remoteOffsets[], PetscSection leafSection, PetscSF *sectionSF)
412 {
413   MPI_Comm           comm;
414   const PetscInt    *localPoints;
415   const PetscSFNode *remotePoints;
416   PetscInt           lpStart, lpEnd;
417   PetscInt           numRoots, numSectionRoots, numPoints, numIndices = 0;
418   PetscInt          *localIndices;
419   PetscSFNode       *remoteIndices;
420   PetscInt           i, ind;
421 
422   PetscFunctionBegin;
423   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
424   PetscValidPointer(rootSection, 2);
425   /* Cannot check PetscValidIntPointer(remoteOffsets,3) because it can be NULL if sf does not reference any points in leafSection */
426   PetscValidPointer(leafSection, 4);
427   PetscValidPointer(sectionSF, 5);
428   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
429   PetscCall(PetscSFCreate(comm, sectionSF));
430   PetscCall(PetscSectionGetChart(leafSection, &lpStart, &lpEnd));
431   PetscCall(PetscSectionGetStorageSize(rootSection, &numSectionRoots));
432   PetscCall(PetscSFGetGraph(sf, &numRoots, &numPoints, &localPoints, &remotePoints));
433   if (numRoots < 0) PetscFunctionReturn(0);
434   PetscCall(PetscLogEventBegin(PETSCSF_SectSF, sf, 0, 0, 0));
435   for (i = 0; i < numPoints; ++i) {
436     PetscInt localPoint = localPoints ? localPoints[i] : i;
437     PetscInt dof;
438 
439     if ((localPoint >= lpStart) && (localPoint < lpEnd)) {
440       PetscCall(PetscSectionGetDof(leafSection, localPoint, &dof));
441       numIndices += dof < 0 ? 0 : dof;
442     }
443   }
444   PetscCall(PetscMalloc1(numIndices, &localIndices));
445   PetscCall(PetscMalloc1(numIndices, &remoteIndices));
446   /* Create new index graph */
447   for (i = 0, ind = 0; i < numPoints; ++i) {
448     PetscInt localPoint = localPoints ? localPoints[i] : i;
449     PetscInt rank       = remotePoints[i].rank;
450 
451     if ((localPoint >= lpStart) && (localPoint < lpEnd)) {
452       PetscInt remoteOffset = remoteOffsets[localPoint - lpStart];
453       PetscInt loff, dof, d;
454 
455       PetscCall(PetscSectionGetOffset(leafSection, localPoint, &loff));
456       PetscCall(PetscSectionGetDof(leafSection, localPoint, &dof));
457       for (d = 0; d < dof; ++d, ++ind) {
458         localIndices[ind]        = loff + d;
459         remoteIndices[ind].rank  = rank;
460         remoteIndices[ind].index = remoteOffset + d;
461       }
462     }
463   }
464   PetscCheck(numIndices == ind, comm, PETSC_ERR_PLIB, "Inconsistency in indices, %" PetscInt_FMT " should be %" PetscInt_FMT, ind, numIndices);
465   PetscCall(PetscSFSetGraph(*sectionSF, numSectionRoots, numIndices, localIndices, PETSC_OWN_POINTER, remoteIndices, PETSC_OWN_POINTER));
466   PetscCall(PetscSFSetUp(*sectionSF));
467   PetscCall(PetscLogEventEnd(PETSCSF_SectSF, sf, 0, 0, 0));
468   PetscFunctionReturn(0);
469 }
470 
471 /*@C
472    PetscSFCreateFromLayouts - Creates a parallel star forest mapping two PetscLayout objects
473 
474    Collective
475 
476    Input Parameters:
477 +  rmap - PetscLayout defining the global root space
478 -  lmap - PetscLayout defining the global leaf space
479 
480    Output Parameter:
481 .  sf - The parallel star forest
482 
483    Level: intermediate
484 
485 .seealso: `PetscSFCreate()`, `PetscLayoutCreate()`, `PetscSFSetGraphLayout()`
486 @*/
487 PetscErrorCode PetscSFCreateFromLayouts(PetscLayout rmap, PetscLayout lmap, PetscSF *sf)
488 {
489   PetscInt     i, nroots, nleaves = 0;
490   PetscInt     rN, lst, len;
491   PetscMPIInt  owner = -1;
492   PetscSFNode *remote;
493   MPI_Comm     rcomm = rmap->comm;
494   MPI_Comm     lcomm = lmap->comm;
495   PetscMPIInt  flg;
496 
497   PetscFunctionBegin;
498   PetscValidPointer(sf, 3);
499   PetscCheck(rmap->setupcalled, rcomm, PETSC_ERR_ARG_WRONGSTATE, "Root layout not setup");
500   PetscCheck(lmap->setupcalled, lcomm, PETSC_ERR_ARG_WRONGSTATE, "Leaf layout not setup");
501   PetscCallMPI(MPI_Comm_compare(rcomm, lcomm, &flg));
502   PetscCheck(flg == MPI_CONGRUENT || flg == MPI_IDENT, rcomm, PETSC_ERR_SUP, "cannot map two layouts with non-matching communicators");
503   PetscCall(PetscSFCreate(rcomm, sf));
504   PetscCall(PetscLayoutGetLocalSize(rmap, &nroots));
505   PetscCall(PetscLayoutGetSize(rmap, &rN));
506   PetscCall(PetscLayoutGetRange(lmap, &lst, &len));
507   PetscCall(PetscMalloc1(len - lst, &remote));
508   for (i = lst; i < len && i < rN; i++) {
509     if (owner < -1 || i >= rmap->range[owner + 1]) PetscCall(PetscLayoutFindOwner(rmap, i, &owner));
510     remote[nleaves].rank  = owner;
511     remote[nleaves].index = i - rmap->range[owner];
512     nleaves++;
513   }
514   PetscCall(PetscSFSetGraph(*sf, nroots, nleaves, NULL, PETSC_OWN_POINTER, remote, PETSC_COPY_VALUES));
515   PetscCall(PetscFree(remote));
516   PetscFunctionReturn(0);
517 }
518 
519 /* TODO: handle nooffprocentries like MatZeroRowsMapLocal_Private, since this code is the same */
520 PetscErrorCode PetscLayoutMapLocal(PetscLayout map, PetscInt N, const PetscInt idxs[], PetscInt *on, PetscInt **oidxs, PetscInt **ogidxs)
521 {
522   PetscInt    *owners = map->range;
523   PetscInt     n      = map->n;
524   PetscSF      sf;
525   PetscInt    *lidxs, *work = NULL;
526   PetscSFNode *ridxs;
527   PetscMPIInt  rank, p = 0;
528   PetscInt     r, len  = 0;
529 
530   PetscFunctionBegin;
531   if (on) *on = 0; /* squelch -Wmaybe-uninitialized */
532   /* Create SF where leaves are input idxs and roots are owned idxs */
533   PetscCallMPI(MPI_Comm_rank(map->comm, &rank));
534   PetscCall(PetscMalloc1(n, &lidxs));
535   for (r = 0; r < n; ++r) lidxs[r] = -1;
536   PetscCall(PetscMalloc1(N, &ridxs));
537   for (r = 0; r < N; ++r) {
538     const PetscInt idx = idxs[r];
539     PetscCheck(idx >= 0 && idx < map->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Index %" PetscInt_FMT " out of range [0,%" PetscInt_FMT ")", idx, map->N);
540     if (idx < owners[p] || owners[p + 1] <= idx) { /* short-circuit the search if the last p owns this idx too */
541       PetscCall(PetscLayoutFindOwner(map, idx, &p));
542     }
543     ridxs[r].rank  = p;
544     ridxs[r].index = idxs[r] - owners[p];
545   }
546   PetscCall(PetscSFCreate(map->comm, &sf));
547   PetscCall(PetscSFSetGraph(sf, n, N, NULL, PETSC_OWN_POINTER, ridxs, PETSC_OWN_POINTER));
548   PetscCall(PetscSFReduceBegin(sf, MPIU_INT, (PetscInt *)idxs, lidxs, MPI_LOR));
549   PetscCall(PetscSFReduceEnd(sf, MPIU_INT, (PetscInt *)idxs, lidxs, MPI_LOR));
550   if (ogidxs) { /* communicate global idxs */
551     PetscInt cum = 0, start, *work2;
552 
553     PetscCall(PetscMalloc1(n, &work));
554     PetscCall(PetscCalloc1(N, &work2));
555     for (r = 0; r < N; ++r)
556       if (idxs[r] >= 0) cum++;
557     PetscCallMPI(MPI_Scan(&cum, &start, 1, MPIU_INT, MPI_SUM, map->comm));
558     start -= cum;
559     cum = 0;
560     for (r = 0; r < N; ++r)
561       if (idxs[r] >= 0) work2[r] = start + cum++;
562     PetscCall(PetscSFReduceBegin(sf, MPIU_INT, work2, work, MPI_REPLACE));
563     PetscCall(PetscSFReduceEnd(sf, MPIU_INT, work2, work, MPI_REPLACE));
564     PetscCall(PetscFree(work2));
565   }
566   PetscCall(PetscSFDestroy(&sf));
567   /* Compress and put in indices */
568   for (r = 0; r < n; ++r)
569     if (lidxs[r] >= 0) {
570       if (work) work[len] = work[r];
571       lidxs[len++] = r;
572     }
573   if (on) *on = len;
574   if (oidxs) *oidxs = lidxs;
575   if (ogidxs) *ogidxs = work;
576   PetscFunctionReturn(0);
577 }
578 
579 /*@
580   PetscSFCreateByMatchingIndices - Create SF by matching root and leaf indices
581 
582   Collective
583 
584   Input Parameters:
585 + layout - PetscLayout defining the global index space and the rank that brokers each index
586 . numRootIndices - size of rootIndices
587 . rootIndices - PetscInt array of global indices of which this process requests ownership
588 . rootLocalIndices - root local index permutation (NULL if no permutation)
589 . rootLocalOffset - offset to be added to root local indices
590 . numLeafIndices - size of leafIndices
591 . leafIndices - PetscInt array of global indices with which this process requires data associated
592 . leafLocalIndices - leaf local index permutation (NULL if no permutation)
593 - leafLocalOffset - offset to be added to leaf local indices
594 
595   Output Parameters:
596 + sfA - star forest representing the communication pattern from the layout space to the leaf space (NULL if not needed)
597 - sf - star forest representing the communication pattern from the root space to the leaf space
598 
599   Example 1:
600 $
601 $  rank             : 0            1            2
602 $  rootIndices      : [1 0 2]      [3]          [3]
603 $  rootLocalOffset  : 100          200          300
604 $  layout           : [0 1]        [2]          [3]
605 $  leafIndices      : [0]          [2]          [0 3]
606 $  leafLocalOffset  : 400          500          600
607 $
608 would build the following SF
609 $
610 $  [0] 400 <- (0,101)
611 $  [1] 500 <- (0,102)
612 $  [2] 600 <- (0,101)
613 $  [2] 601 <- (2,300)
614 $
615   Example 2:
616 $
617 $  rank             : 0               1               2
618 $  rootIndices      : [1 0 2]         [3]             [3]
619 $  rootLocalOffset  : 100             200             300
620 $  layout           : [0 1]           [2]             [3]
621 $  leafIndices      : rootIndices     rootIndices     rootIndices
622 $  leafLocalOffset  : rootLocalOffset rootLocalOffset rootLocalOffset
623 $
624 would build the following SF
625 $
626 $  [1] 200 <- (2,300)
627 $
628   Example 3:
629 $
630 $  No process requests ownership of global index 1, but no process needs it.
631 $
632 $  rank             : 0            1            2
633 $  numRootIndices   : 2            1            1
634 $  rootIndices      : [0 2]        [3]          [3]
635 $  rootLocalOffset  : 100          200          300
636 $  layout           : [0 1]        [2]          [3]
637 $  numLeafIndices   : 1            1            2
638 $  leafIndices      : [0]          [2]          [0 3]
639 $  leafLocalOffset  : 400          500          600
640 $
641 would build the following SF
642 $
643 $  [0] 400 <- (0,100)
644 $  [1] 500 <- (0,101)
645 $  [2] 600 <- (0,100)
646 $  [2] 601 <- (2,300)
647 $
648 
649   Notes:
650   The layout parameter represents any partitioning of [0, N), where N is the total number of global indices, and its
651   local size can be set to PETSC_DECIDE.
652   If a global index x lies in the partition owned by process i, each process whose rootIndices contains x requests
653   ownership of x and sends its own rank and the local index of x to process i.
654   If multiple processes request ownership of x, the one with the highest rank is to own x.
655   Process i then broadcasts the ownership information, so that each process whose leafIndices contains x knows the
656   ownership information of x.
657   The output sf is constructed by associating each leaf point to a root point in this way.
658 
659   Suppose there is point data ordered according to the global indices and partitioned according to the given layout.
660   The optional output PetscSF object sfA can be used to push such data to leaf points.
661 
662   All indices in rootIndices and leafIndices must lie in the layout range. The union (over all processes) of rootIndices
663   must cover that of leafIndices, but need not cover the entire layout.
664 
665   If (leafIndices, leafLocalIndices, leafLocalOffset) == (rootIndices, rootLocalIndices, rootLocalOffset), the output
666   star forest is almost identity, so will only include non-trivial part of the map.
667 
668   Developer Notes:
669   Current approach of a process of the highest rank gaining the ownership may cause load imbalance; consider using
670   hash(rank, root_local_index) as the bid for the ownership determination.
671 
672   Level: advanced
673 
674 .seealso: `PetscSFCreate()`
675 @*/
676 PetscErrorCode PetscSFCreateByMatchingIndices(PetscLayout layout, PetscInt numRootIndices, const PetscInt *rootIndices, const PetscInt *rootLocalIndices, PetscInt rootLocalOffset, PetscInt numLeafIndices, const PetscInt *leafIndices, const PetscInt *leafLocalIndices, PetscInt leafLocalOffset, PetscSF *sfA, PetscSF *sf)
677 {
678   MPI_Comm     comm = layout->comm;
679   PetscMPIInt  size, rank;
680   PetscSF      sf1;
681   PetscSFNode *owners, *buffer, *iremote;
682   PetscInt    *ilocal, nleaves, N, n, i;
683 #if defined(PETSC_USE_DEBUG)
684   PetscInt N1;
685 #endif
686   PetscBool flag;
687 
688   PetscFunctionBegin;
689   if (rootIndices) PetscValidIntPointer(rootIndices, 3);
690   if (rootLocalIndices) PetscValidIntPointer(rootLocalIndices, 4);
691   if (leafIndices) PetscValidIntPointer(leafIndices, 7);
692   if (leafLocalIndices) PetscValidIntPointer(leafLocalIndices, 8);
693   if (sfA) PetscValidPointer(sfA, 10);
694   PetscValidPointer(sf, 11);
695   PetscCheck(numRootIndices >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numRootIndices (%" PetscInt_FMT ") must be non-negative", numRootIndices);
696   PetscCheck(numLeafIndices >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numLeafIndices (%" PetscInt_FMT ") must be non-negative", numLeafIndices);
697   PetscCallMPI(MPI_Comm_size(comm, &size));
698   PetscCallMPI(MPI_Comm_rank(comm, &rank));
699   PetscCall(PetscLayoutSetUp(layout));
700   PetscCall(PetscLayoutGetSize(layout, &N));
701   PetscCall(PetscLayoutGetLocalSize(layout, &n));
702   flag = (PetscBool)(leafIndices == rootIndices);
703   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &flag, 1, MPIU_BOOL, MPI_LAND, comm));
704   PetscCheck(!flag || numLeafIndices == numRootIndices, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "leafIndices == rootIndices, but numLeafIndices (%" PetscInt_FMT ") != numRootIndices(%" PetscInt_FMT ")", numLeafIndices, numRootIndices);
705 #if defined(PETSC_USE_DEBUG)
706   N1 = PETSC_MIN_INT;
707   for (i = 0; i < numRootIndices; i++)
708     if (rootIndices[i] > N1) N1 = rootIndices[i];
709   PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &N1, 1, MPIU_INT, MPI_MAX, comm));
710   PetscCheck(N1 < N, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Max. root index (%" PetscInt_FMT ") out of layout range [0,%" PetscInt_FMT ")", N1, N);
711   if (!flag) {
712     N1 = PETSC_MIN_INT;
713     for (i = 0; i < numLeafIndices; i++)
714       if (leafIndices[i] > N1) N1 = leafIndices[i];
715     PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &N1, 1, MPIU_INT, MPI_MAX, comm));
716     PetscCheck(N1 < N, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Max. leaf index (%" PetscInt_FMT ") out of layout range [0,%" PetscInt_FMT ")", N1, N);
717   }
718 #endif
719   /* Reduce: owners -> buffer */
720   PetscCall(PetscMalloc1(n, &buffer));
721   PetscCall(PetscSFCreate(comm, &sf1));
722   PetscCall(PetscSFSetFromOptions(sf1));
723   PetscCall(PetscSFSetGraphLayout(sf1, layout, numRootIndices, NULL, PETSC_OWN_POINTER, rootIndices));
724   PetscCall(PetscMalloc1(numRootIndices, &owners));
725   for (i = 0; i < numRootIndices; ++i) {
726     owners[i].rank  = rank;
727     owners[i].index = rootLocalOffset + (rootLocalIndices ? rootLocalIndices[i] : i);
728   }
729   for (i = 0; i < n; ++i) {
730     buffer[i].index = -1;
731     buffer[i].rank  = -1;
732   }
733   PetscCall(PetscSFReduceBegin(sf1, MPIU_2INT, owners, buffer, MPI_MAXLOC));
734   PetscCall(PetscSFReduceEnd(sf1, MPIU_2INT, owners, buffer, MPI_MAXLOC));
735   /* Bcast: buffer -> owners */
736   if (!flag) {
737     /* leafIndices is different from rootIndices */
738     PetscCall(PetscFree(owners));
739     PetscCall(PetscSFSetGraphLayout(sf1, layout, numLeafIndices, NULL, PETSC_OWN_POINTER, leafIndices));
740     PetscCall(PetscMalloc1(numLeafIndices, &owners));
741   }
742   PetscCall(PetscSFBcastBegin(sf1, MPIU_2INT, buffer, owners, MPI_REPLACE));
743   PetscCall(PetscSFBcastEnd(sf1, MPIU_2INT, buffer, owners, MPI_REPLACE));
744   for (i = 0; i < numLeafIndices; ++i) PetscCheck(owners[i].rank >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Global point %" PetscInt_FMT " was unclaimed", leafIndices[i]);
745   PetscCall(PetscFree(buffer));
746   if (sfA) {
747     *sfA = sf1;
748   } else PetscCall(PetscSFDestroy(&sf1));
749   /* Create sf */
750   if (flag && rootLocalIndices == leafLocalIndices && leafLocalOffset == rootLocalOffset) {
751     /* leaf space == root space */
752     for (i = 0, nleaves = 0; i < numLeafIndices; ++i)
753       if (owners[i].rank != rank) ++nleaves;
754     PetscCall(PetscMalloc1(nleaves, &ilocal));
755     PetscCall(PetscMalloc1(nleaves, &iremote));
756     for (i = 0, nleaves = 0; i < numLeafIndices; ++i) {
757       if (owners[i].rank != rank) {
758         ilocal[nleaves]        = leafLocalOffset + i;
759         iremote[nleaves].rank  = owners[i].rank;
760         iremote[nleaves].index = owners[i].index;
761         ++nleaves;
762       }
763     }
764     PetscCall(PetscFree(owners));
765   } else {
766     nleaves = numLeafIndices;
767     PetscCall(PetscMalloc1(nleaves, &ilocal));
768     for (i = 0; i < nleaves; ++i) ilocal[i] = leafLocalOffset + (leafLocalIndices ? leafLocalIndices[i] : i);
769     iremote = owners;
770   }
771   PetscCall(PetscSFCreate(comm, sf));
772   PetscCall(PetscSFSetFromOptions(*sf));
773   PetscCall(PetscSFSetGraph(*sf, rootLocalOffset + numRootIndices, nleaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
774   PetscFunctionReturn(0);
775 }
776