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