xref: /petsc/src/vec/is/sf/utils/sfutils.c (revision d61846d356a261b2bfaae1cc2b5666d49c4aef7e)
1b0c7db22SLisandro Dalcin #include <petsc/private/sfimpl.h> /*I  "petscsf.h"   I*/
2b0c7db22SLisandro Dalcin #include <petsc/private/sectionimpl.h>
3b0c7db22SLisandro Dalcin 
4eb58282aSVaclav Hapla /*@
5cab54364SBarry Smith   PetscSFSetGraphLayout - Set a parallel star forest via global indices and a `PetscLayout`
6b0c7db22SLisandro Dalcin 
7b0c7db22SLisandro Dalcin   Collective
8b0c7db22SLisandro Dalcin 
94165533cSJose E. Roman   Input Parameters:
10b0c7db22SLisandro Dalcin + sf        - star forest
11cab54364SBarry Smith . layout    - `PetscLayout` defining the global space for roots
12b0c7db22SLisandro Dalcin . nleaves   - number of leaf vertices on the current process, each of these references a root on any process
13b0c7db22SLisandro Dalcin . ilocal    - locations of leaves in leafdata buffers, pass NULL for contiguous storage
14b0c7db22SLisandro Dalcin . localmode - copy mode for ilocal
15eb58282aSVaclav Hapla - gremote   - root vertices in global numbering corresponding to leaves in ilocal
16b0c7db22SLisandro Dalcin 
17b0c7db22SLisandro Dalcin   Level: intermediate
18b0c7db22SLisandro Dalcin 
19cab54364SBarry Smith   Note:
2086c56f52SVaclav Hapla   Global indices must lie in [0, N) where N is the global size of layout.
21cab54364SBarry Smith   Leaf indices in ilocal get sorted; this means the user-provided array gets sorted if localmode is `PETSC_OWN_POINTER`.
2286c56f52SVaclav Hapla 
2338b5cf2dSJacob Faibussowitsch   Developer Notes:
2486c56f52SVaclav Hapla   Local indices which are the identity permutation in the range [0,nleaves) are discarded as they
25cab54364SBarry Smith   encode contiguous storage. In such case, if localmode is `PETSC_OWN_POINTER`, the memory is deallocated as it is not
26b0c7db22SLisandro Dalcin   needed
27b0c7db22SLisandro Dalcin 
28cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFGetGraphLayout()`, `PetscSFCreate()`, `PetscSFView()`, `PetscSFSetGraph()`, `PetscSFGetGraph()`
29b0c7db22SLisandro Dalcin @*/
30d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFSetGraphLayout(PetscSF sf, PetscLayout layout, PetscInt nleaves, PetscInt *ilocal, PetscCopyMode localmode, const PetscInt *gremote)
31d71ae5a4SJacob Faibussowitsch {
3238a25198SStefano Zampini   const PetscInt *range;
3338a25198SStefano Zampini   PetscInt        i, nroots, ls = -1, ln = -1;
3438a25198SStefano Zampini   PetscMPIInt     lr = -1;
35b0c7db22SLisandro Dalcin   PetscSFNode    *remote;
36b0c7db22SLisandro Dalcin 
37b0c7db22SLisandro Dalcin   PetscFunctionBegin;
38da0802e2SStefano Zampini   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
39b114984aSVaclav Hapla   PetscCall(PetscLayoutSetUp(layout));
409566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetLocalSize(layout, &nroots));
419566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRanges(layout, &range));
429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nleaves, &remote));
43eb58282aSVaclav Hapla   if (nleaves) ls = gremote[0] + 1;
44b0c7db22SLisandro Dalcin   for (i = 0; i < nleaves; i++) {
45eb58282aSVaclav Hapla     const PetscInt idx = gremote[i] - ls;
4638a25198SStefano Zampini     if (idx < 0 || idx >= ln) { /* short-circuit the search */
47eb58282aSVaclav Hapla       PetscCall(PetscLayoutFindOwnerIndex(layout, gremote[i], &lr, &remote[i].index));
4838a25198SStefano Zampini       remote[i].rank = lr;
4938a25198SStefano Zampini       ls             = range[lr];
5038a25198SStefano Zampini       ln             = range[lr + 1] - ls;
5138a25198SStefano Zampini     } else {
5238a25198SStefano Zampini       remote[i].rank  = lr;
5338a25198SStefano Zampini       remote[i].index = idx;
5438a25198SStefano Zampini     }
55b0c7db22SLisandro Dalcin   }
569566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, nroots, nleaves, ilocal, localmode, remote, PETSC_OWN_POINTER));
573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
58b0c7db22SLisandro Dalcin }
59b0c7db22SLisandro Dalcin 
60eb58282aSVaclav Hapla /*@C
61cab54364SBarry Smith   PetscSFGetGraphLayout - Get the global indices and `PetscLayout` that describe this star forest
62eb58282aSVaclav Hapla 
63eb58282aSVaclav Hapla   Collective
64eb58282aSVaclav Hapla 
65eb58282aSVaclav Hapla   Input Parameter:
66eb58282aSVaclav Hapla . sf - star forest
67eb58282aSVaclav Hapla 
68eb58282aSVaclav Hapla   Output Parameters:
69cab54364SBarry Smith + layout  - `PetscLayout` defining the global space for roots
70eb58282aSVaclav Hapla . nleaves - number of leaf vertices on the current process, each of these references a root on any process
71f13dfd9eSBarry Smith . ilocal  - locations of leaves in leafdata buffers, or `NULL` for contiguous storage
72eb58282aSVaclav Hapla - gremote - root vertices in global numbering corresponding to leaves in ilocal
73eb58282aSVaclav Hapla 
74eb58282aSVaclav Hapla   Level: intermediate
75eb58282aSVaclav Hapla 
76eb58282aSVaclav Hapla   Notes:
77eb58282aSVaclav Hapla   The outputs are such that passing them as inputs to `PetscSFSetGraphLayout()` would lead to the same star forest.
78f13dfd9eSBarry Smith   The outputs `layout` and `gremote` are freshly created each time this function is called,
79f13dfd9eSBarry Smith   so they need to be freed (with `PetscLayoutDestroy()` and `PetscFree()`) by the user.
80eb58282aSVaclav Hapla 
81cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFSetGraphLayout()`, `PetscSFCreate()`, `PetscSFView()`, `PetscSFSetGraph()`, `PetscSFGetGraph()`
82eb58282aSVaclav Hapla @*/
83d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFGetGraphLayout(PetscSF sf, PetscLayout *layout, PetscInt *nleaves, const PetscInt *ilocal[], PetscInt *gremote[])
84d71ae5a4SJacob Faibussowitsch {
85eb58282aSVaclav Hapla   PetscInt           nr, nl;
86eb58282aSVaclav Hapla   const PetscSFNode *ir;
87eb58282aSVaclav Hapla   PetscLayout        lt;
88eb58282aSVaclav Hapla 
89eb58282aSVaclav Hapla   PetscFunctionBegin;
90eb58282aSVaclav Hapla   PetscCall(PetscSFGetGraph(sf, &nr, &nl, ilocal, &ir));
91eb58282aSVaclav Hapla   PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)sf), nr, PETSC_DECIDE, 1, &lt));
92eb58282aSVaclav Hapla   if (gremote) {
93eb58282aSVaclav Hapla     PetscInt        i;
94eb58282aSVaclav Hapla     const PetscInt *range;
95eb58282aSVaclav Hapla     PetscInt       *gr;
96eb58282aSVaclav Hapla 
97eb58282aSVaclav Hapla     PetscCall(PetscLayoutGetRanges(lt, &range));
98eb58282aSVaclav Hapla     PetscCall(PetscMalloc1(nl, &gr));
99eb58282aSVaclav Hapla     for (i = 0; i < nl; i++) gr[i] = range[ir[i].rank] + ir[i].index;
100eb58282aSVaclav Hapla     *gremote = gr;
101eb58282aSVaclav Hapla   }
102eb58282aSVaclav Hapla   if (nleaves) *nleaves = nl;
103eb58282aSVaclav Hapla   if (layout) *layout = lt;
104eb58282aSVaclav Hapla   else PetscCall(PetscLayoutDestroy(&lt));
1053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
106eb58282aSVaclav Hapla }
107eb58282aSVaclav Hapla 
108b0c7db22SLisandro Dalcin /*@
109cab54364SBarry Smith   PetscSFSetGraphSection - Sets the `PetscSF` graph encoding the parallel dof overlap based upon the `PetscSection` describing the data layout.
110b0c7db22SLisandro Dalcin 
111b0c7db22SLisandro Dalcin   Input Parameters:
112cab54364SBarry Smith + sf            - The `PetscSF`
113cab54364SBarry Smith . localSection  - `PetscSection` describing the local data layout
114cab54364SBarry Smith - globalSection - `PetscSection` describing the global data layout
115b0c7db22SLisandro Dalcin 
116b0c7db22SLisandro Dalcin   Level: developer
117b0c7db22SLisandro Dalcin 
118cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFSetGraph()`, `PetscSFSetGraphLayout()`
119b0c7db22SLisandro Dalcin @*/
120d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFSetGraphSection(PetscSF sf, PetscSection localSection, PetscSection globalSection)
121d71ae5a4SJacob Faibussowitsch {
122b0c7db22SLisandro Dalcin   MPI_Comm        comm;
123b0c7db22SLisandro Dalcin   PetscLayout     layout;
124b0c7db22SLisandro Dalcin   const PetscInt *ranges;
125b0c7db22SLisandro Dalcin   PetscInt       *local;
126b0c7db22SLisandro Dalcin   PetscSFNode    *remote;
127b0c7db22SLisandro Dalcin   PetscInt        pStart, pEnd, p, nroots, nleaves = 0, l;
128b0c7db22SLisandro Dalcin   PetscMPIInt     size, rank;
129b0c7db22SLisandro Dalcin 
130b0c7db22SLisandro Dalcin   PetscFunctionBegin;
131b0c7db22SLisandro Dalcin   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
132b0c7db22SLisandro Dalcin   PetscValidHeaderSpecific(localSection, PETSC_SECTION_CLASSID, 2);
133b0c7db22SLisandro Dalcin   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
134b0c7db22SLisandro Dalcin 
1359566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
1369566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
1379566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1389566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd));
1399566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots));
1409566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &layout));
1419566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(layout, 1));
1429566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(layout, nroots));
1439566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(layout));
1449566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRanges(layout, &ranges));
145b0c7db22SLisandro Dalcin   for (p = pStart; p < pEnd; ++p) {
146b0c7db22SLisandro Dalcin     PetscInt gdof, gcdof;
147b0c7db22SLisandro Dalcin 
1489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
1499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
15057508eceSPierre Jolivet     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);
151b0c7db22SLisandro Dalcin     nleaves += gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
152b0c7db22SLisandro Dalcin   }
1539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nleaves, &local));
1549566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nleaves, &remote));
155b0c7db22SLisandro Dalcin   for (p = pStart, l = 0; p < pEnd; ++p) {
156b0c7db22SLisandro Dalcin     const PetscInt *cind;
157b0c7db22SLisandro Dalcin     PetscInt        dof, cdof, off, gdof, gcdof, goff, gsize, d, c;
158b0c7db22SLisandro Dalcin 
1599566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(localSection, p, &dof));
1609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(localSection, p, &off));
1619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof));
1629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(localSection, p, &cind));
1639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
1649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
1659566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalSection, p, &goff));
166b0c7db22SLisandro Dalcin     if (!gdof) continue; /* Censored point */
167b0c7db22SLisandro Dalcin     gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
168b0c7db22SLisandro Dalcin     if (gsize != dof - cdof) {
16908401ef6SPierre Jolivet       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);
170b0c7db22SLisandro Dalcin       cdof = 0; /* Ignore constraints */
171b0c7db22SLisandro Dalcin     }
172b0c7db22SLisandro Dalcin     for (d = 0, c = 0; d < dof; ++d) {
1739371c9d4SSatish Balay       if ((c < cdof) && (cind[c] == d)) {
1749371c9d4SSatish Balay         ++c;
1759371c9d4SSatish Balay         continue;
1769371c9d4SSatish Balay       }
177b0c7db22SLisandro Dalcin       local[l + d - c] = off + d;
178b0c7db22SLisandro Dalcin     }
17908401ef6SPierre Jolivet     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);
180b0c7db22SLisandro Dalcin     if (gdof < 0) {
181b0c7db22SLisandro Dalcin       for (d = 0; d < gsize; ++d, ++l) {
1826497c311SBarry Smith         PetscInt    offset = -(goff + 1) + d, ir;
1836497c311SBarry Smith         PetscMPIInt r;
184b0c7db22SLisandro Dalcin 
1856497c311SBarry Smith         PetscCall(PetscFindInt(offset, size + 1, ranges, &ir));
1866497c311SBarry Smith         PetscCall(PetscMPIIntCast(ir, &r));
187b0c7db22SLisandro Dalcin         if (r < 0) r = -(r + 2);
1886497c311SBarry Smith         PetscCheck(!(r < 0) && !(r >= size), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " mapped to invalid process %d (%" PetscInt_FMT ", %" PetscInt_FMT ")", p, r, gdof, goff);
189b0c7db22SLisandro Dalcin         remote[l].rank  = r;
190b0c7db22SLisandro Dalcin         remote[l].index = offset - ranges[r];
191b0c7db22SLisandro Dalcin       }
192b0c7db22SLisandro Dalcin     } else {
193b0c7db22SLisandro Dalcin       for (d = 0; d < gsize; ++d, ++l) {
194b0c7db22SLisandro Dalcin         remote[l].rank  = rank;
195b0c7db22SLisandro Dalcin         remote[l].index = goff + d - ranges[rank];
196b0c7db22SLisandro Dalcin       }
197b0c7db22SLisandro Dalcin     }
198b0c7db22SLisandro Dalcin   }
19908401ef6SPierre Jolivet   PetscCheck(l == nleaves, comm, PETSC_ERR_PLIB, "Iteration error, l %" PetscInt_FMT " != nleaves %" PetscInt_FMT, l, nleaves);
2009566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&layout));
2019566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER));
2023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
203b0c7db22SLisandro Dalcin }
204b0c7db22SLisandro Dalcin 
205b0c7db22SLisandro Dalcin /*@C
206cab54364SBarry Smith   PetscSFDistributeSection - Create a new `PetscSection` reorganized, moving from the root to the leaves of the `PetscSF`
207b0c7db22SLisandro Dalcin 
208c3339decSBarry Smith   Collective
209b0c7db22SLisandro Dalcin 
210b0c7db22SLisandro Dalcin   Input Parameters:
211cab54364SBarry Smith + sf          - The `PetscSF`
212b0c7db22SLisandro Dalcin - rootSection - Section defined on root space
213b0c7db22SLisandro Dalcin 
214b0c7db22SLisandro Dalcin   Output Parameters:
215ce78bad3SBarry Smith + remoteOffsets - root offsets in leaf storage, or `NULL`, its length will be the size of the chart of `leafSection`
216b0c7db22SLisandro Dalcin - leafSection   - Section defined on the leaf space
217b0c7db22SLisandro Dalcin 
218b0c7db22SLisandro Dalcin   Level: advanced
219b0c7db22SLisandro Dalcin 
220ce78bad3SBarry Smith   Note:
221ce78bad3SBarry Smith   Caller must `PetscFree()` `remoteOffsets` if it was requested
222ce78bad3SBarry Smith 
223ce78bad3SBarry Smith   Fortran Note:
224ce78bad3SBarry Smith   Use `PetscSFDestroyRemoteOffsets()` when `remoteOffsets` is no longer needed.
22523e9620eSJunchao Zhang 
226cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFCreate()`
227b0c7db22SLisandro Dalcin @*/
228ce78bad3SBarry Smith PetscErrorCode PetscSFDistributeSection(PetscSF sf, PetscSection rootSection, PetscInt *remoteOffsets[], PetscSection leafSection)
229d71ae5a4SJacob Faibussowitsch {
230b0c7db22SLisandro Dalcin   PetscSF         embedSF;
231b0c7db22SLisandro Dalcin   const PetscInt *indices;
232b0c7db22SLisandro Dalcin   IS              selected;
2331690c2aeSBarry Smith   PetscInt        numFields, nroots, rpStart, rpEnd, lpStart = PETSC_INT_MAX, lpEnd = -1, f, c;
234b0c7db22SLisandro Dalcin   PetscBool      *sub, hasc;
235b0c7db22SLisandro Dalcin 
236b0c7db22SLisandro Dalcin   PetscFunctionBegin;
2379566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_DistSect, sf, 0, 0, 0));
2389566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(rootSection, &numFields));
239029e8818Sksagiyam   if (numFields) {
240029e8818Sksagiyam     IS perm;
241029e8818Sksagiyam 
242029e8818Sksagiyam     /* PetscSectionSetNumFields() calls PetscSectionReset(), which destroys
243029e8818Sksagiyam        leafSection->perm. To keep this permutation set by the user, we grab
244029e8818Sksagiyam        the reference before calling PetscSectionSetNumFields() and set it
245029e8818Sksagiyam        back after. */
2469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPermutation(leafSection, &perm));
2479566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)perm));
2489566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(leafSection, numFields));
2499566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetPermutation(leafSection, perm));
2509566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&perm));
251029e8818Sksagiyam   }
2529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numFields + 2, &sub));
253b0c7db22SLisandro Dalcin   sub[1] = rootSection->bc ? PETSC_TRUE : PETSC_FALSE;
254b0c7db22SLisandro Dalcin   for (f = 0; f < numFields; ++f) {
2552ee82556SMatthew G. Knepley     PetscSectionSym sym, dsym = NULL;
256b0c7db22SLisandro Dalcin     const char     *name    = NULL;
257b0c7db22SLisandro Dalcin     PetscInt        numComp = 0;
258b0c7db22SLisandro Dalcin 
259b0c7db22SLisandro Dalcin     sub[2 + f] = rootSection->field[f]->bc ? PETSC_TRUE : PETSC_FALSE;
2609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldComponents(rootSection, f, &numComp));
2619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldName(rootSection, f, &name));
2629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldSym(rootSection, f, &sym));
2639566063dSJacob Faibussowitsch     if (sym) PetscCall(PetscSectionSymDistribute(sym, sf, &dsym));
2649566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldComponents(leafSection, f, numComp));
2659566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldName(leafSection, f, name));
2669566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldSym(leafSection, f, dsym));
2679566063dSJacob Faibussowitsch     PetscCall(PetscSectionSymDestroy(&dsym));
268b0c7db22SLisandro Dalcin     for (c = 0; c < rootSection->numFieldComponents[f]; ++c) {
2699566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetComponentName(rootSection, f, c, &name));
2709566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetComponentName(leafSection, f, c, name));
271b0c7db22SLisandro Dalcin     }
272b0c7db22SLisandro Dalcin   }
2739566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(rootSection, &rpStart, &rpEnd));
2749566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
275b0c7db22SLisandro Dalcin   rpEnd = PetscMin(rpEnd, nroots);
276b0c7db22SLisandro Dalcin   rpEnd = PetscMax(rpStart, rpEnd);
277b0c7db22SLisandro Dalcin   /* see if we can avoid creating the embedded SF, since it can cost more than an allreduce */
278b0c7db22SLisandro Dalcin   sub[0] = (PetscBool)(nroots != rpEnd - rpStart);
279e91c04dfSPierre Jolivet   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, sub, 2 + numFields, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)sf)));
280b0c7db22SLisandro Dalcin   if (sub[0]) {
2819566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, rpEnd - rpStart, rpStart, 1, &selected));
2829566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(selected, &indices));
2839566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedRootSF(sf, rpEnd - rpStart, indices, &embedSF));
2849566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(selected, &indices));
2859566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&selected));
286b0c7db22SLisandro Dalcin   } else {
2879566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)sf));
288b0c7db22SLisandro Dalcin     embedSF = sf;
289b0c7db22SLisandro Dalcin   }
2909566063dSJacob Faibussowitsch   PetscCall(PetscSFGetLeafRange(embedSF, &lpStart, &lpEnd));
291b0c7db22SLisandro Dalcin   lpEnd++;
292b0c7db22SLisandro Dalcin 
2939566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(leafSection, lpStart, lpEnd));
294b0c7db22SLisandro Dalcin 
295b0c7db22SLisandro Dalcin   /* Constrained dof section */
296b0c7db22SLisandro Dalcin   hasc = sub[1];
297b0c7db22SLisandro Dalcin   for (f = 0; f < numFields; ++f) hasc = (PetscBool)(hasc || sub[2 + f]);
298b0c7db22SLisandro Dalcin 
299b0c7db22SLisandro Dalcin   /* Could fuse these at the cost of copies and extra allocation */
30016cd844bSPierre Jolivet   PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasDof, -rpStart), PetscSafePointerPlusOffset(leafSection->atlasDof, -lpStart), MPI_REPLACE));
30116cd844bSPierre Jolivet   PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasDof, -rpStart), PetscSafePointerPlusOffset(leafSection->atlasDof, -lpStart), MPI_REPLACE));
302b0c7db22SLisandro Dalcin   if (sub[1]) {
3037c0883d5SVaclav Hapla     PetscCall(PetscSectionCheckConstraints_Private(rootSection));
3047c0883d5SVaclav Hapla     PetscCall(PetscSectionCheckConstraints_Private(leafSection));
3059566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->bc->atlasDof[-rpStart], &leafSection->bc->atlasDof[-lpStart], MPI_REPLACE));
3069566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->bc->atlasDof[-rpStart], &leafSection->bc->atlasDof[-lpStart], MPI_REPLACE));
307b0c7db22SLisandro Dalcin   }
308b0c7db22SLisandro Dalcin   for (f = 0; f < numFields; ++f) {
30916cd844bSPierre Jolivet     PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->field[f]->atlasDof, -rpStart), PetscSafePointerPlusOffset(leafSection->field[f]->atlasDof, -lpStart), MPI_REPLACE));
31016cd844bSPierre Jolivet     PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->field[f]->atlasDof, -rpStart), PetscSafePointerPlusOffset(leafSection->field[f]->atlasDof, -lpStart), MPI_REPLACE));
311b0c7db22SLisandro Dalcin     if (sub[2 + f]) {
3127c0883d5SVaclav Hapla       PetscCall(PetscSectionCheckConstraints_Private(rootSection->field[f]));
3137c0883d5SVaclav Hapla       PetscCall(PetscSectionCheckConstraints_Private(leafSection->field[f]));
3149566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasDof[-rpStart], &leafSection->field[f]->bc->atlasDof[-lpStart], MPI_REPLACE));
3159566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasDof[-rpStart], &leafSection->field[f]->bc->atlasDof[-lpStart], MPI_REPLACE));
316b0c7db22SLisandro Dalcin     }
317b0c7db22SLisandro Dalcin   }
318b0c7db22SLisandro Dalcin   if (remoteOffsets) {
3199566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(lpEnd - lpStart, remoteOffsets));
32016cd844bSPierre Jolivet     PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasOff, -rpStart), PetscSafePointerPlusOffset(*remoteOffsets, -lpStart), MPI_REPLACE));
32116cd844bSPierre Jolivet     PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasOff, -rpStart), PetscSafePointerPlusOffset(*remoteOffsets, -lpStart), MPI_REPLACE));
322b0c7db22SLisandro Dalcin   }
32369c11d05SVaclav Hapla   PetscCall(PetscSectionInvalidateMaxDof_Internal(leafSection));
3249566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(leafSection));
325b0c7db22SLisandro Dalcin   if (hasc) { /* need to communicate bcIndices */
326b0c7db22SLisandro Dalcin     PetscSF   bcSF;
327b0c7db22SLisandro Dalcin     PetscInt *rOffBc;
328b0c7db22SLisandro Dalcin 
3299566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(lpEnd - lpStart, &rOffBc));
330b0c7db22SLisandro Dalcin     if (sub[1]) {
3319566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
3329566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
3339566063dSJacob Faibussowitsch       PetscCall(PetscSFCreateSectionSF(embedSF, rootSection->bc, rOffBc, leafSection->bc, &bcSF));
3349566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(bcSF, MPIU_INT, rootSection->bcIndices, leafSection->bcIndices, MPI_REPLACE));
3359566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(bcSF, MPIU_INT, rootSection->bcIndices, leafSection->bcIndices, MPI_REPLACE));
3369566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&bcSF));
337b0c7db22SLisandro Dalcin     }
338b0c7db22SLisandro Dalcin     for (f = 0; f < numFields; ++f) {
339b0c7db22SLisandro Dalcin       if (sub[2 + f]) {
3409566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
3419566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
3429566063dSJacob Faibussowitsch         PetscCall(PetscSFCreateSectionSF(embedSF, rootSection->field[f]->bc, rOffBc, leafSection->field[f]->bc, &bcSF));
3439566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(bcSF, MPIU_INT, rootSection->field[f]->bcIndices, leafSection->field[f]->bcIndices, MPI_REPLACE));
3449566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(bcSF, MPIU_INT, rootSection->field[f]->bcIndices, leafSection->field[f]->bcIndices, MPI_REPLACE));
3459566063dSJacob Faibussowitsch         PetscCall(PetscSFDestroy(&bcSF));
346b0c7db22SLisandro Dalcin       }
347b0c7db22SLisandro Dalcin     }
3489566063dSJacob Faibussowitsch     PetscCall(PetscFree(rOffBc));
349b0c7db22SLisandro Dalcin   }
3509566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&embedSF));
3519566063dSJacob Faibussowitsch   PetscCall(PetscFree(sub));
3529566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_DistSect, sf, 0, 0, 0));
3533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
354b0c7db22SLisandro Dalcin }
355b0c7db22SLisandro Dalcin 
356b0c7db22SLisandro Dalcin /*@C
357b0c7db22SLisandro Dalcin   PetscSFCreateRemoteOffsets - Create offsets for point data on remote processes
358b0c7db22SLisandro Dalcin 
359c3339decSBarry Smith   Collective
360b0c7db22SLisandro Dalcin 
361b0c7db22SLisandro Dalcin   Input Parameters:
362cab54364SBarry Smith + sf          - The `PetscSF`
363ce78bad3SBarry Smith . rootSection - Data layout of remote points for outgoing data (this is layout for roots)
364ce78bad3SBarry Smith - leafSection - Data layout of local points for incoming data  (this is layout for leaves)
365b0c7db22SLisandro Dalcin 
366b0c7db22SLisandro Dalcin   Output Parameter:
367ce78bad3SBarry Smith . remoteOffsets - Offsets for point data on remote processes (these are offsets from the root section), or `NULL`
368b0c7db22SLisandro Dalcin 
369b0c7db22SLisandro Dalcin   Level: developer
370b0c7db22SLisandro Dalcin 
371ce78bad3SBarry Smith   Note:
372ce78bad3SBarry Smith   Caller must `PetscFree()` `remoteOffsets` if it was requested
373ce78bad3SBarry Smith 
374ce78bad3SBarry Smith   Fortran Note:
375ce78bad3SBarry Smith   Use `PetscSFDestroyRemoteOffsets()` when `remoteOffsets` is no longer needed.
37623e9620eSJunchao Zhang 
377cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFCreate()`
378b0c7db22SLisandro Dalcin @*/
379ce78bad3SBarry Smith PetscErrorCode PetscSFCreateRemoteOffsets(PetscSF sf, PetscSection rootSection, PetscSection leafSection, PetscInt *remoteOffsets[])
380d71ae5a4SJacob Faibussowitsch {
381b0c7db22SLisandro Dalcin   PetscSF         embedSF;
382b0c7db22SLisandro Dalcin   const PetscInt *indices;
383b0c7db22SLisandro Dalcin   IS              selected;
384b0c7db22SLisandro Dalcin   PetscInt        numRoots, rpStart = 0, rpEnd = 0, lpStart = 0, lpEnd = 0;
385b0c7db22SLisandro Dalcin 
386b0c7db22SLisandro Dalcin   PetscFunctionBegin;
387b0c7db22SLisandro Dalcin   *remoteOffsets = NULL;
3889566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &numRoots, NULL, NULL, NULL));
3893ba16761SJacob Faibussowitsch   if (numRoots < 0) PetscFunctionReturn(PETSC_SUCCESS);
3909566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_RemoteOff, sf, 0, 0, 0));
3919566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(rootSection, &rpStart, &rpEnd));
3929566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(leafSection, &lpStart, &lpEnd));
3939566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, rpEnd - rpStart, rpStart, 1, &selected));
3949566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(selected, &indices));
3959566063dSJacob Faibussowitsch   PetscCall(PetscSFCreateEmbeddedRootSF(sf, rpEnd - rpStart, indices, &embedSF));
3969566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(selected, &indices));
3979566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&selected));
3989566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(lpEnd - lpStart, remoteOffsets));
3998e3a54c0SPierre Jolivet   PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasOff, -rpStart), PetscSafePointerPlusOffset(*remoteOffsets, -lpStart), MPI_REPLACE));
4008e3a54c0SPierre Jolivet   PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasOff, -rpStart), PetscSafePointerPlusOffset(*remoteOffsets, -lpStart), MPI_REPLACE));
4019566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&embedSF));
4029566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_RemoteOff, sf, 0, 0, 0));
4033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
404b0c7db22SLisandro Dalcin }
405b0c7db22SLisandro Dalcin 
406ce78bad3SBarry Smith /*@
407cab54364SBarry Smith   PetscSFCreateSectionSF - Create an expanded `PetscSF` of dofs, assuming the input `PetscSF` relates points
408b0c7db22SLisandro Dalcin 
409c3339decSBarry Smith   Collective
410b0c7db22SLisandro Dalcin 
411b0c7db22SLisandro Dalcin   Input Parameters:
412cab54364SBarry Smith + sf            - The `PetscSF`
413b0c7db22SLisandro Dalcin . rootSection   - Data layout of remote points for outgoing data (this is usually the serial section)
414b0c7db22SLisandro Dalcin . remoteOffsets - Offsets for point data on remote processes (these are offsets from the root section), or NULL
415b0c7db22SLisandro Dalcin - leafSection   - Data layout of local points for incoming data  (this is the distributed section)
416b0c7db22SLisandro Dalcin 
4172fe279fdSBarry Smith   Output Parameter:
4182fe279fdSBarry Smith . sectionSF - The new `PetscSF`
419b0c7db22SLisandro Dalcin 
420b0c7db22SLisandro Dalcin   Level: advanced
421b0c7db22SLisandro Dalcin 
42223e9620eSJunchao Zhang   Notes:
423ce78bad3SBarry Smith   `remoteOffsets` can be `NULL` if `sf` does not reference any points in leafSection
42423e9620eSJunchao Zhang 
425cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFCreate()`
426b0c7db22SLisandro Dalcin @*/
427d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFCreateSectionSF(PetscSF sf, PetscSection rootSection, PetscInt remoteOffsets[], PetscSection leafSection, PetscSF *sectionSF)
428d71ae5a4SJacob Faibussowitsch {
429b0c7db22SLisandro Dalcin   MPI_Comm           comm;
430b0c7db22SLisandro Dalcin   const PetscInt    *localPoints;
431b0c7db22SLisandro Dalcin   const PetscSFNode *remotePoints;
432b0c7db22SLisandro Dalcin   PetscInt           lpStart, lpEnd;
433b0c7db22SLisandro Dalcin   PetscInt           numRoots, numSectionRoots, numPoints, numIndices = 0;
434b0c7db22SLisandro Dalcin   PetscInt          *localIndices;
435b0c7db22SLisandro Dalcin   PetscSFNode       *remoteIndices;
436b0c7db22SLisandro Dalcin   PetscInt           i, ind;
437b0c7db22SLisandro Dalcin 
438b0c7db22SLisandro Dalcin   PetscFunctionBegin;
439b0c7db22SLisandro Dalcin   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
4404f572ea9SToby Isaac   PetscAssertPointer(rootSection, 2);
4414f572ea9SToby Isaac   /* Cannot check PetscAssertPointer(remoteOffsets,3) because it can be NULL if sf does not reference any points in leafSection */
4424f572ea9SToby Isaac   PetscAssertPointer(leafSection, 4);
4434f572ea9SToby Isaac   PetscAssertPointer(sectionSF, 5);
4449566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
4459566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, sectionSF));
4469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(leafSection, &lpStart, &lpEnd));
4479566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(rootSection, &numSectionRoots));
4489566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &numRoots, &numPoints, &localPoints, &remotePoints));
4493ba16761SJacob Faibussowitsch   if (numRoots < 0) PetscFunctionReturn(PETSC_SUCCESS);
4509566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_SectSF, sf, 0, 0, 0));
451b0c7db22SLisandro Dalcin   for (i = 0; i < numPoints; ++i) {
452b0c7db22SLisandro Dalcin     PetscInt localPoint = localPoints ? localPoints[i] : i;
453b0c7db22SLisandro Dalcin     PetscInt dof;
454b0c7db22SLisandro Dalcin 
455b0c7db22SLisandro Dalcin     if ((localPoint >= lpStart) && (localPoint < lpEnd)) {
4569566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafSection, localPoint, &dof));
45722a18c9fSMatthew G. Knepley       numIndices += dof < 0 ? 0 : dof;
458b0c7db22SLisandro Dalcin     }
459b0c7db22SLisandro Dalcin   }
4609566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numIndices, &localIndices));
4619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numIndices, &remoteIndices));
462b0c7db22SLisandro Dalcin   /* Create new index graph */
463b0c7db22SLisandro Dalcin   for (i = 0, ind = 0; i < numPoints; ++i) {
464b0c7db22SLisandro Dalcin     PetscInt localPoint = localPoints ? localPoints[i] : i;
465835f2295SStefano Zampini     PetscInt rank       = remotePoints[i].rank;
466b0c7db22SLisandro Dalcin 
467b0c7db22SLisandro Dalcin     if ((localPoint >= lpStart) && (localPoint < lpEnd)) {
468b0c7db22SLisandro Dalcin       PetscInt remoteOffset = remoteOffsets[localPoint - lpStart];
469b0c7db22SLisandro Dalcin       PetscInt loff, dof, d;
470b0c7db22SLisandro Dalcin 
4719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafSection, localPoint, &loff));
4729566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafSection, localPoint, &dof));
473b0c7db22SLisandro Dalcin       for (d = 0; d < dof; ++d, ++ind) {
474b0c7db22SLisandro Dalcin         localIndices[ind]        = loff + d;
475b0c7db22SLisandro Dalcin         remoteIndices[ind].rank  = rank;
476b0c7db22SLisandro Dalcin         remoteIndices[ind].index = remoteOffset + d;
477b0c7db22SLisandro Dalcin       }
478b0c7db22SLisandro Dalcin     }
479b0c7db22SLisandro Dalcin   }
48008401ef6SPierre Jolivet   PetscCheck(numIndices == ind, comm, PETSC_ERR_PLIB, "Inconsistency in indices, %" PetscInt_FMT " should be %" PetscInt_FMT, ind, numIndices);
4819566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sectionSF, numSectionRoots, numIndices, localIndices, PETSC_OWN_POINTER, remoteIndices, PETSC_OWN_POINTER));
4829566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(*sectionSF));
4839566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_SectSF, sf, 0, 0, 0));
4843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
485b0c7db22SLisandro Dalcin }
4868fa9e22eSVaclav Hapla 
4878fa9e22eSVaclav Hapla /*@C
488cab54364SBarry Smith   PetscSFCreateFromLayouts - Creates a parallel star forest mapping two `PetscLayout` objects
4898fa9e22eSVaclav Hapla 
4908fa9e22eSVaclav Hapla   Collective
4918fa9e22eSVaclav Hapla 
4924165533cSJose E. Roman   Input Parameters:
493cab54364SBarry Smith + rmap - `PetscLayout` defining the global root space
494cab54364SBarry Smith - lmap - `PetscLayout` defining the global leaf space
4958fa9e22eSVaclav Hapla 
4964165533cSJose E. Roman   Output Parameter:
4978fa9e22eSVaclav Hapla . sf - The parallel star forest
4988fa9e22eSVaclav Hapla 
4998fa9e22eSVaclav Hapla   Level: intermediate
5008fa9e22eSVaclav Hapla 
501cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFCreate()`, `PetscLayoutCreate()`, `PetscSFSetGraphLayout()`
5028fa9e22eSVaclav Hapla @*/
503d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFCreateFromLayouts(PetscLayout rmap, PetscLayout lmap, PetscSF *sf)
504d71ae5a4SJacob Faibussowitsch {
5058fa9e22eSVaclav Hapla   PetscInt     i, nroots, nleaves = 0;
5068fa9e22eSVaclav Hapla   PetscInt     rN, lst, len;
5078fa9e22eSVaclav Hapla   PetscMPIInt  owner = -1;
5088fa9e22eSVaclav Hapla   PetscSFNode *remote;
5098fa9e22eSVaclav Hapla   MPI_Comm     rcomm = rmap->comm;
5108fa9e22eSVaclav Hapla   MPI_Comm     lcomm = lmap->comm;
5118fa9e22eSVaclav Hapla   PetscMPIInt  flg;
5128fa9e22eSVaclav Hapla 
5138fa9e22eSVaclav Hapla   PetscFunctionBegin;
5144f572ea9SToby Isaac   PetscAssertPointer(sf, 3);
51528b400f6SJacob Faibussowitsch   PetscCheck(rmap->setupcalled, rcomm, PETSC_ERR_ARG_WRONGSTATE, "Root layout not setup");
51628b400f6SJacob Faibussowitsch   PetscCheck(lmap->setupcalled, lcomm, PETSC_ERR_ARG_WRONGSTATE, "Leaf layout not setup");
5179566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_compare(rcomm, lcomm, &flg));
518c9cc58a2SBarry Smith   PetscCheck(flg == MPI_CONGRUENT || flg == MPI_IDENT, rcomm, PETSC_ERR_SUP, "cannot map two layouts with non-matching communicators");
5199566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(rcomm, sf));
5209566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetLocalSize(rmap, &nroots));
5219566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetSize(rmap, &rN));
5229566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(lmap, &lst, &len));
5239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(len - lst, &remote));
5248fa9e22eSVaclav Hapla   for (i = lst; i < len && i < rN; i++) {
52548a46eb9SPierre Jolivet     if (owner < -1 || i >= rmap->range[owner + 1]) PetscCall(PetscLayoutFindOwner(rmap, i, &owner));
5268fa9e22eSVaclav Hapla     remote[nleaves].rank  = owner;
5278fa9e22eSVaclav Hapla     remote[nleaves].index = i - rmap->range[owner];
5288fa9e22eSVaclav Hapla     nleaves++;
5298fa9e22eSVaclav Hapla   }
5309566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sf, nroots, nleaves, NULL, PETSC_OWN_POINTER, remote, PETSC_COPY_VALUES));
5319566063dSJacob Faibussowitsch   PetscCall(PetscFree(remote));
5323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5338fa9e22eSVaclav Hapla }
5348fa9e22eSVaclav Hapla 
5358fa9e22eSVaclav Hapla /* TODO: handle nooffprocentries like MatZeroRowsMapLocal_Private, since this code is the same */
536ce78bad3SBarry Smith PetscErrorCode PetscLayoutMapLocal(PetscLayout map, PetscInt N, const PetscInt idxs[], PetscInt *on, PetscInt *oidxs[], PetscInt *ogidxs[])
537d71ae5a4SJacob Faibussowitsch {
5388fa9e22eSVaclav Hapla   PetscInt    *owners = map->range;
5398fa9e22eSVaclav Hapla   PetscInt     n      = map->n;
5408fa9e22eSVaclav Hapla   PetscSF      sf;
541*d61846d3SStefano Zampini   PetscInt    *lidxs, *work = NULL, *ilocal;
5428fa9e22eSVaclav Hapla   PetscSFNode *ridxs;
5438fa9e22eSVaclav Hapla   PetscMPIInt  rank, p = 0;
544*d61846d3SStefano Zampini   PetscInt     r, len = 0, nleaves = 0;
5458fa9e22eSVaclav Hapla 
5468fa9e22eSVaclav Hapla   PetscFunctionBegin;
5478fa9e22eSVaclav Hapla   if (on) *on = 0; /* squelch -Wmaybe-uninitialized */
5488fa9e22eSVaclav Hapla   /* Create SF where leaves are input idxs and roots are owned idxs */
5499566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(map->comm, &rank));
5509566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &lidxs));
5518fa9e22eSVaclav Hapla   for (r = 0; r < n; ++r) lidxs[r] = -1;
5529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(N, &ridxs));
553*d61846d3SStefano Zampini   PetscCall(PetscMalloc1(N, &ilocal));
5548fa9e22eSVaclav Hapla   for (r = 0; r < N; ++r) {
5558fa9e22eSVaclav Hapla     const PetscInt idx = idxs[r];
556*d61846d3SStefano Zampini 
557*d61846d3SStefano Zampini     if (idx < 0) continue;
558*d61846d3SStefano Zampini     PetscCheck(idx < map->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Index %" PetscInt_FMT " out of range [0,%" PetscInt_FMT ")", idx, map->N);
5598fa9e22eSVaclav Hapla     if (idx < owners[p] || owners[p + 1] <= idx) { /* short-circuit the search if the last p owns this idx too */
5609566063dSJacob Faibussowitsch       PetscCall(PetscLayoutFindOwner(map, idx, &p));
5618fa9e22eSVaclav Hapla     }
562*d61846d3SStefano Zampini     ridxs[nleaves].rank  = p;
563*d61846d3SStefano Zampini     ridxs[nleaves].index = idxs[r] - owners[p];
564*d61846d3SStefano Zampini     ilocal[nleaves]      = r;
565*d61846d3SStefano Zampini     nleaves++;
5668fa9e22eSVaclav Hapla   }
5679566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(map->comm, &sf));
568*d61846d3SStefano Zampini   PetscCall(PetscSFSetGraph(sf, n, nleaves, ilocal, PETSC_OWN_POINTER, ridxs, PETSC_OWN_POINTER));
5699566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(sf, MPIU_INT, (PetscInt *)idxs, lidxs, MPI_LOR));
5709566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(sf, MPIU_INT, (PetscInt *)idxs, lidxs, MPI_LOR));
5718fa9e22eSVaclav Hapla   if (ogidxs) { /* communicate global idxs */
5728fa9e22eSVaclav Hapla     PetscInt cum = 0, start, *work2;
5738fa9e22eSVaclav Hapla 
5749566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &work));
5759566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(N, &work2));
5769371c9d4SSatish Balay     for (r = 0; r < N; ++r)
5779371c9d4SSatish Balay       if (idxs[r] >= 0) cum++;
5789566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&cum, &start, 1, MPIU_INT, MPI_SUM, map->comm));
5798fa9e22eSVaclav Hapla     start -= cum;
5808fa9e22eSVaclav Hapla     cum = 0;
5819371c9d4SSatish Balay     for (r = 0; r < N; ++r)
5829371c9d4SSatish Balay       if (idxs[r] >= 0) work2[r] = start + cum++;
5839566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(sf, MPIU_INT, work2, work, MPI_REPLACE));
5849566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(sf, MPIU_INT, work2, work, MPI_REPLACE));
5859566063dSJacob Faibussowitsch     PetscCall(PetscFree(work2));
5868fa9e22eSVaclav Hapla   }
5879566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sf));
5888fa9e22eSVaclav Hapla   /* Compress and put in indices */
5898fa9e22eSVaclav Hapla   for (r = 0; r < n; ++r)
5908fa9e22eSVaclav Hapla     if (lidxs[r] >= 0) {
5918fa9e22eSVaclav Hapla       if (work) work[len] = work[r];
5928fa9e22eSVaclav Hapla       lidxs[len++] = r;
5938fa9e22eSVaclav Hapla     }
5948fa9e22eSVaclav Hapla   if (on) *on = len;
5958fa9e22eSVaclav Hapla   if (oidxs) *oidxs = lidxs;
5968fa9e22eSVaclav Hapla   if (ogidxs) *ogidxs = work;
5973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5988fa9e22eSVaclav Hapla }
599deffd5ebSksagiyam 
600deffd5ebSksagiyam /*@
601cab54364SBarry Smith   PetscSFCreateByMatchingIndices - Create `PetscSF` by matching root and leaf indices
602deffd5ebSksagiyam 
603deffd5ebSksagiyam   Collective
604deffd5ebSksagiyam 
605deffd5ebSksagiyam   Input Parameters:
606cab54364SBarry Smith + layout           - `PetscLayout` defining the global index space and the rank that brokers each index
607deffd5ebSksagiyam . numRootIndices   - size of rootIndices
608cab54364SBarry Smith . rootIndices      - `PetscInt` array of global indices of which this process requests ownership
609deffd5ebSksagiyam . rootLocalIndices - root local index permutation (NULL if no permutation)
610deffd5ebSksagiyam . rootLocalOffset  - offset to be added to root local indices
611deffd5ebSksagiyam . numLeafIndices   - size of leafIndices
612cab54364SBarry Smith . leafIndices      - `PetscInt` array of global indices with which this process requires data associated
613deffd5ebSksagiyam . leafLocalIndices - leaf local index permutation (NULL if no permutation)
614deffd5ebSksagiyam - leafLocalOffset  - offset to be added to leaf local indices
615deffd5ebSksagiyam 
616d8d19677SJose E. Roman   Output Parameters:
617deffd5ebSksagiyam + sfA - star forest representing the communication pattern from the layout space to the leaf space (NULL if not needed)
618deffd5ebSksagiyam - sf  - star forest representing the communication pattern from the root space to the leaf space
619deffd5ebSksagiyam 
620cab54364SBarry Smith   Level: advanced
621cab54364SBarry Smith 
622deffd5ebSksagiyam   Example 1:
623cab54364SBarry Smith .vb
624cab54364SBarry Smith   rank             : 0            1            2
625cab54364SBarry Smith   rootIndices      : [1 0 2]      [3]          [3]
626cab54364SBarry Smith   rootLocalOffset  : 100          200          300
627cab54364SBarry Smith   layout           : [0 1]        [2]          [3]
628cab54364SBarry Smith   leafIndices      : [0]          [2]          [0 3]
629cab54364SBarry Smith   leafLocalOffset  : 400          500          600
630cab54364SBarry Smith 
631cab54364SBarry Smith would build the following PetscSF
632cab54364SBarry Smith 
633cab54364SBarry Smith   [0] 400 <- (0,101)
634cab54364SBarry Smith   [1] 500 <- (0,102)
635cab54364SBarry Smith   [2] 600 <- (0,101)
636cab54364SBarry Smith   [2] 601 <- (2,300)
637cab54364SBarry Smith .ve
638cab54364SBarry Smith 
639deffd5ebSksagiyam   Example 2:
640cab54364SBarry Smith .vb
641cab54364SBarry Smith   rank             : 0               1               2
642cab54364SBarry Smith   rootIndices      : [1 0 2]         [3]             [3]
643cab54364SBarry Smith   rootLocalOffset  : 100             200             300
644cab54364SBarry Smith   layout           : [0 1]           [2]             [3]
645cab54364SBarry Smith   leafIndices      : rootIndices     rootIndices     rootIndices
646cab54364SBarry Smith   leafLocalOffset  : rootLocalOffset rootLocalOffset rootLocalOffset
647cab54364SBarry Smith 
648cab54364SBarry Smith would build the following PetscSF
649cab54364SBarry Smith 
650cab54364SBarry Smith   [1] 200 <- (2,300)
651cab54364SBarry Smith .ve
652cab54364SBarry Smith 
653deffd5ebSksagiyam   Example 3:
654cab54364SBarry Smith .vb
655cab54364SBarry Smith   No process requests ownership of global index 1, but no process needs it.
656cab54364SBarry Smith 
657cab54364SBarry Smith   rank             : 0            1            2
658cab54364SBarry Smith   numRootIndices   : 2            1            1
659cab54364SBarry Smith   rootIndices      : [0 2]        [3]          [3]
660cab54364SBarry Smith   rootLocalOffset  : 100          200          300
661cab54364SBarry Smith   layout           : [0 1]        [2]          [3]
662cab54364SBarry Smith   numLeafIndices   : 1            1            2
663cab54364SBarry Smith   leafIndices      : [0]          [2]          [0 3]
664cab54364SBarry Smith   leafLocalOffset  : 400          500          600
665cab54364SBarry Smith 
666cab54364SBarry Smith would build the following PetscSF
667cab54364SBarry Smith 
668cab54364SBarry Smith   [0] 400 <- (0,100)
669cab54364SBarry Smith   [1] 500 <- (0,101)
670cab54364SBarry Smith   [2] 600 <- (0,100)
671cab54364SBarry Smith   [2] 601 <- (2,300)
672cab54364SBarry Smith .ve
673deffd5ebSksagiyam 
674deffd5ebSksagiyam   Notes:
675deffd5ebSksagiyam   The layout parameter represents any partitioning of [0, N), where N is the total number of global indices, and its
676cab54364SBarry Smith   local size can be set to `PETSC_DECIDE`.
677cab54364SBarry Smith 
678deffd5ebSksagiyam   If a global index x lies in the partition owned by process i, each process whose rootIndices contains x requests
679deffd5ebSksagiyam   ownership of x and sends its own rank and the local index of x to process i.
680deffd5ebSksagiyam   If multiple processes request ownership of x, the one with the highest rank is to own x.
681deffd5ebSksagiyam   Process i then broadcasts the ownership information, so that each process whose leafIndices contains x knows the
682deffd5ebSksagiyam   ownership information of x.
683deffd5ebSksagiyam   The output sf is constructed by associating each leaf point to a root point in this way.
684deffd5ebSksagiyam 
685deffd5ebSksagiyam   Suppose there is point data ordered according to the global indices and partitioned according to the given layout.
686cab54364SBarry Smith   The optional output `PetscSF` object sfA can be used to push such data to leaf points.
687deffd5ebSksagiyam 
688deffd5ebSksagiyam   All indices in rootIndices and leafIndices must lie in the layout range. The union (over all processes) of rootIndices
689deffd5ebSksagiyam   must cover that of leafIndices, but need not cover the entire layout.
690deffd5ebSksagiyam 
691deffd5ebSksagiyam   If (leafIndices, leafLocalIndices, leafLocalOffset) == (rootIndices, rootLocalIndices, rootLocalOffset), the output
692deffd5ebSksagiyam   star forest is almost identity, so will only include non-trivial part of the map.
693deffd5ebSksagiyam 
69438b5cf2dSJacob Faibussowitsch   Developer Notes:
695deffd5ebSksagiyam   Current approach of a process of the highest rank gaining the ownership may cause load imbalance; consider using
696deffd5ebSksagiyam   hash(rank, root_local_index) as the bid for the ownership determination.
697deffd5ebSksagiyam 
698cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFCreate()`
699deffd5ebSksagiyam @*/
700d71ae5a4SJacob Faibussowitsch 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)
701d71ae5a4SJacob Faibussowitsch {
702deffd5ebSksagiyam   MPI_Comm     comm = layout->comm;
703deffd5ebSksagiyam   PetscMPIInt  size, rank;
704deffd5ebSksagiyam   PetscSF      sf1;
705deffd5ebSksagiyam   PetscSFNode *owners, *buffer, *iremote;
706deffd5ebSksagiyam   PetscInt    *ilocal, nleaves, N, n, i;
707deffd5ebSksagiyam #if defined(PETSC_USE_DEBUG)
708deffd5ebSksagiyam   PetscInt N1;
709deffd5ebSksagiyam #endif
710deffd5ebSksagiyam   PetscBool flag;
711deffd5ebSksagiyam 
712deffd5ebSksagiyam   PetscFunctionBegin;
7134f572ea9SToby Isaac   if (rootIndices) PetscAssertPointer(rootIndices, 3);
7144f572ea9SToby Isaac   if (rootLocalIndices) PetscAssertPointer(rootLocalIndices, 4);
7154f572ea9SToby Isaac   if (leafIndices) PetscAssertPointer(leafIndices, 7);
7164f572ea9SToby Isaac   if (leafLocalIndices) PetscAssertPointer(leafLocalIndices, 8);
7174f572ea9SToby Isaac   if (sfA) PetscAssertPointer(sfA, 10);
7184f572ea9SToby Isaac   PetscAssertPointer(sf, 11);
71908401ef6SPierre Jolivet   PetscCheck(numRootIndices >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numRootIndices (%" PetscInt_FMT ") must be non-negative", numRootIndices);
72008401ef6SPierre Jolivet   PetscCheck(numLeafIndices >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numLeafIndices (%" PetscInt_FMT ") must be non-negative", numLeafIndices);
7219566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
7229566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7239566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(layout));
7249566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetSize(layout, &N));
7259566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetLocalSize(layout, &n));
726deffd5ebSksagiyam   flag = (PetscBool)(leafIndices == rootIndices);
727462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &flag, 1, MPIU_BOOL, MPI_LAND, comm));
728c9cc58a2SBarry Smith   PetscCheck(!flag || numLeafIndices == numRootIndices, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "leafIndices == rootIndices, but numLeafIndices (%" PetscInt_FMT ") != numRootIndices(%" PetscInt_FMT ")", numLeafIndices, numRootIndices);
729deffd5ebSksagiyam #if defined(PETSC_USE_DEBUG)
7301690c2aeSBarry Smith   N1 = PETSC_INT_MIN;
7319371c9d4SSatish Balay   for (i = 0; i < numRootIndices; i++)
7329371c9d4SSatish Balay     if (rootIndices[i] > N1) N1 = rootIndices[i];
733462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &N1, 1, MPIU_INT, MPI_MAX, comm));
73408401ef6SPierre Jolivet   PetscCheck(N1 < N, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Max. root index (%" PetscInt_FMT ") out of layout range [0,%" PetscInt_FMT ")", N1, N);
735deffd5ebSksagiyam   if (!flag) {
7361690c2aeSBarry Smith     N1 = PETSC_INT_MIN;
7379371c9d4SSatish Balay     for (i = 0; i < numLeafIndices; i++)
7389371c9d4SSatish Balay       if (leafIndices[i] > N1) N1 = leafIndices[i];
739462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &N1, 1, MPIU_INT, MPI_MAX, comm));
74008401ef6SPierre Jolivet     PetscCheck(N1 < N, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Max. leaf index (%" PetscInt_FMT ") out of layout range [0,%" PetscInt_FMT ")", N1, N);
741deffd5ebSksagiyam   }
742deffd5ebSksagiyam #endif
743deffd5ebSksagiyam   /* Reduce: owners -> buffer */
7449566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &buffer));
7459566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &sf1));
7469566063dSJacob Faibussowitsch   PetscCall(PetscSFSetFromOptions(sf1));
7479566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(sf1, layout, numRootIndices, NULL, PETSC_OWN_POINTER, rootIndices));
7489566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numRootIndices, &owners));
749deffd5ebSksagiyam   for (i = 0; i < numRootIndices; ++i) {
750deffd5ebSksagiyam     owners[i].rank  = rank;
751deffd5ebSksagiyam     owners[i].index = rootLocalOffset + (rootLocalIndices ? rootLocalIndices[i] : i);
752deffd5ebSksagiyam   }
753deffd5ebSksagiyam   for (i = 0; i < n; ++i) {
754deffd5ebSksagiyam     buffer[i].index = -1;
755deffd5ebSksagiyam     buffer[i].rank  = -1;
756deffd5ebSksagiyam   }
7576497c311SBarry Smith   PetscCall(PetscSFReduceBegin(sf1, MPIU_SF_NODE, owners, buffer, MPI_MAXLOC));
7586497c311SBarry Smith   PetscCall(PetscSFReduceEnd(sf1, MPIU_SF_NODE, owners, buffer, MPI_MAXLOC));
759deffd5ebSksagiyam   /* Bcast: buffer -> owners */
760deffd5ebSksagiyam   if (!flag) {
761deffd5ebSksagiyam     /* leafIndices is different from rootIndices */
7629566063dSJacob Faibussowitsch     PetscCall(PetscFree(owners));
7639566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(sf1, layout, numLeafIndices, NULL, PETSC_OWN_POINTER, leafIndices));
7649566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeafIndices, &owners));
765deffd5ebSksagiyam   }
7666497c311SBarry Smith   PetscCall(PetscSFBcastBegin(sf1, MPIU_SF_NODE, buffer, owners, MPI_REPLACE));
7676497c311SBarry Smith   PetscCall(PetscSFBcastEnd(sf1, MPIU_SF_NODE, buffer, owners, MPI_REPLACE));
76808401ef6SPierre Jolivet   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]);
7699566063dSJacob Faibussowitsch   PetscCall(PetscFree(buffer));
7709371c9d4SSatish Balay   if (sfA) {
7719371c9d4SSatish Balay     *sfA = sf1;
7729371c9d4SSatish Balay   } else PetscCall(PetscSFDestroy(&sf1));
773deffd5ebSksagiyam   /* Create sf */
774deffd5ebSksagiyam   if (flag && rootLocalIndices == leafLocalIndices && leafLocalOffset == rootLocalOffset) {
775deffd5ebSksagiyam     /* leaf space == root space */
7769371c9d4SSatish Balay     for (i = 0, nleaves = 0; i < numLeafIndices; ++i)
7779371c9d4SSatish Balay       if (owners[i].rank != rank) ++nleaves;
7789566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &ilocal));
7799566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &iremote));
780deffd5ebSksagiyam     for (i = 0, nleaves = 0; i < numLeafIndices; ++i) {
781deffd5ebSksagiyam       if (owners[i].rank != rank) {
782deffd5ebSksagiyam         ilocal[nleaves]        = leafLocalOffset + i;
783deffd5ebSksagiyam         iremote[nleaves].rank  = owners[i].rank;
784deffd5ebSksagiyam         iremote[nleaves].index = owners[i].index;
785deffd5ebSksagiyam         ++nleaves;
786deffd5ebSksagiyam       }
787deffd5ebSksagiyam     }
7889566063dSJacob Faibussowitsch     PetscCall(PetscFree(owners));
789deffd5ebSksagiyam   } else {
790deffd5ebSksagiyam     nleaves = numLeafIndices;
7919566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &ilocal));
792ad540459SPierre Jolivet     for (i = 0; i < nleaves; ++i) ilocal[i] = leafLocalOffset + (leafLocalIndices ? leafLocalIndices[i] : i);
793deffd5ebSksagiyam     iremote = owners;
794deffd5ebSksagiyam   }
7959566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, sf));
7969566063dSJacob Faibussowitsch   PetscCall(PetscSFSetFromOptions(*sf));
7979566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sf, rootLocalOffset + numRootIndices, nleaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
7983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
799deffd5ebSksagiyam }
800fbc7033fSJed Brown 
801fbc7033fSJed Brown /*@
80253c0d4aeSBarry Smith   PetscSFMerge - append/merge indices of `sfb` into `sfa`, with preference for `sfb`
803fbc7033fSJed Brown 
804fbc7033fSJed Brown   Collective
805fbc7033fSJed Brown 
80638b5cf2dSJacob Faibussowitsch   Input Parameters:
807fbc7033fSJed Brown + sfa - default `PetscSF`
808fbc7033fSJed Brown - sfb - additional edges to add/replace edges in sfa
809fbc7033fSJed Brown 
81038b5cf2dSJacob Faibussowitsch   Output Parameter:
811fbc7033fSJed Brown . merged - new `PetscSF` with combined edges
812fbc7033fSJed Brown 
81353c0d4aeSBarry Smith   Level: intermediate
81453c0d4aeSBarry Smith 
81538b5cf2dSJacob Faibussowitsch .seealso: `PetscSFCompose()`
816fbc7033fSJed Brown @*/
817fbc7033fSJed Brown PetscErrorCode PetscSFMerge(PetscSF sfa, PetscSF sfb, PetscSF *merged)
818fbc7033fSJed Brown {
819fbc7033fSJed Brown   PetscInt maxleaf;
820fbc7033fSJed Brown 
821fbc7033fSJed Brown   PetscFunctionBegin;
822fbc7033fSJed Brown   PetscValidHeaderSpecific(sfa, PETSCSF_CLASSID, 1);
823fbc7033fSJed Brown   PetscValidHeaderSpecific(sfb, PETSCSF_CLASSID, 2);
824fbc7033fSJed Brown   PetscCheckSameComm(sfa, 1, sfb, 2);
8254f572ea9SToby Isaac   PetscAssertPointer(merged, 3);
826fbc7033fSJed Brown   {
827fbc7033fSJed Brown     PetscInt aleaf, bleaf;
828fbc7033fSJed Brown     PetscCall(PetscSFGetLeafRange(sfa, NULL, &aleaf));
829fbc7033fSJed Brown     PetscCall(PetscSFGetLeafRange(sfb, NULL, &bleaf));
830fbc7033fSJed Brown     maxleaf = PetscMax(aleaf, bleaf) + 1; // One more than the last index
831fbc7033fSJed Brown   }
832fbc7033fSJed Brown   PetscInt          *clocal, aroots, aleaves, broots, bleaves;
833fbc7033fSJed Brown   PetscSFNode       *cremote;
834fbc7033fSJed Brown   const PetscInt    *alocal, *blocal;
835fbc7033fSJed Brown   const PetscSFNode *aremote, *bremote;
836fbc7033fSJed Brown   PetscCall(PetscMalloc2(maxleaf, &clocal, maxleaf, &cremote));
837fbc7033fSJed Brown   for (PetscInt i = 0; i < maxleaf; i++) clocal[i] = -1;
838fbc7033fSJed Brown   PetscCall(PetscSFGetGraph(sfa, &aroots, &aleaves, &alocal, &aremote));
839fbc7033fSJed Brown   PetscCall(PetscSFGetGraph(sfb, &broots, &bleaves, &blocal, &bremote));
840fbc7033fSJed Brown   PetscCheck(aroots == broots, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Both sfa and sfb must have the same root space");
841fbc7033fSJed Brown   for (PetscInt i = 0; i < aleaves; i++) {
842fbc7033fSJed Brown     PetscInt a = alocal ? alocal[i] : i;
843fbc7033fSJed Brown     clocal[a]  = a;
844fbc7033fSJed Brown     cremote[a] = aremote[i];
845fbc7033fSJed Brown   }
846fbc7033fSJed Brown   for (PetscInt i = 0; i < bleaves; i++) {
847fbc7033fSJed Brown     PetscInt b = blocal ? blocal[i] : i;
848fbc7033fSJed Brown     clocal[b]  = b;
849fbc7033fSJed Brown     cremote[b] = bremote[i];
850fbc7033fSJed Brown   }
851fbc7033fSJed Brown   PetscInt nleaves = 0;
852fbc7033fSJed Brown   for (PetscInt i = 0; i < maxleaf; i++) {
853fbc7033fSJed Brown     if (clocal[i] < 0) continue;
854fbc7033fSJed Brown     clocal[nleaves]  = clocal[i];
855fbc7033fSJed Brown     cremote[nleaves] = cremote[i];
856fbc7033fSJed Brown     nleaves++;
857fbc7033fSJed Brown   }
858fbc7033fSJed Brown   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)sfa), merged));
859fbc7033fSJed Brown   PetscCall(PetscSFSetGraph(*merged, aroots, nleaves, clocal, PETSC_COPY_VALUES, cremote, PETSC_COPY_VALUES));
860fbc7033fSJed Brown   PetscCall(PetscFree2(clocal, cremote));
8613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
862fbc7033fSJed Brown }
8630dd791a8SStefano Zampini 
8640dd791a8SStefano Zampini /*@
8650dd791a8SStefano Zampini   PetscSFCreateStridedSF - Create an `PetscSF` to communicate interleaved blocks of data
8660dd791a8SStefano Zampini 
8670dd791a8SStefano Zampini   Collective
8680dd791a8SStefano Zampini 
8690dd791a8SStefano Zampini   Input Parameters:
8700dd791a8SStefano Zampini + sf  - star forest
8710dd791a8SStefano Zampini . bs  - stride
8720dd791a8SStefano Zampini . ldr - leading dimension of root space
8730dd791a8SStefano Zampini - ldl - leading dimension of leaf space
8740dd791a8SStefano Zampini 
8750dd791a8SStefano Zampini   Output Parameter:
8760dd791a8SStefano Zampini . vsf - the new `PetscSF`
8770dd791a8SStefano Zampini 
8780dd791a8SStefano Zampini   Level: intermediate
8790dd791a8SStefano Zampini 
8800dd791a8SStefano Zampini   Notes:
8810dd791a8SStefano Zampini   This can be useful to perform communications on blocks of right-hand sides. For example, the calling sequence
8820dd791a8SStefano Zampini .vb
8830dd791a8SStefano Zampini   c_datatype *roots, *leaves;
8840dd791a8SStefano Zampini   for i in [0,bs) do
8850dd791a8SStefano Zampini     PetscSFBcastBegin(sf, mpi_datatype, roots + i*ldr, leaves + i*ldl, op)
8860dd791a8SStefano Zampini     PetscSFBcastEnd(sf, mpi_datatype, roots + i*ldr, leaves + i*ldl, op)
8870dd791a8SStefano Zampini .ve
8880dd791a8SStefano Zampini   is equivalent to
8890dd791a8SStefano Zampini .vb
8900dd791a8SStefano Zampini   c_datatype *roots, *leaves;
8910dd791a8SStefano Zampini   PetscSFCreateStridedSF(sf, bs, ldr, ldl, &vsf)
8920dd791a8SStefano Zampini   PetscSFBcastBegin(vsf, mpi_datatype, roots, leaves, op)
8930dd791a8SStefano Zampini   PetscSFBcastEnd(vsf, mpi_datatype, roots, leaves, op)
8940dd791a8SStefano Zampini .ve
8950dd791a8SStefano Zampini 
8960dd791a8SStefano Zampini   Developer Notes:
8970dd791a8SStefano Zampini   Should this functionality be handled with a new API instead of creating a new object?
8980dd791a8SStefano Zampini 
8990dd791a8SStefano Zampini .seealso: `PetscSF`, `PetscSFCreate()`, `PetscSFSetGraph()`
9000dd791a8SStefano Zampini @*/
9010dd791a8SStefano Zampini PetscErrorCode PetscSFCreateStridedSF(PetscSF sf, PetscInt bs, PetscInt ldr, PetscInt ldl, PetscSF *vsf)
9020dd791a8SStefano Zampini {
9030dd791a8SStefano Zampini   PetscSF            rankssf;
9040dd791a8SStefano Zampini   const PetscSFNode *iremote, *sfrremote;
9050dd791a8SStefano Zampini   PetscSFNode       *viremote;
9060dd791a8SStefano Zampini   const PetscInt    *ilocal;
9070dd791a8SStefano Zampini   PetscInt          *vilocal = NULL, *ldrs;
9080dd791a8SStefano Zampini   PetscInt           nranks, nr, nl, vnr, vnl, maxl;
9090dd791a8SStefano Zampini   PetscMPIInt        rank;
9100dd791a8SStefano Zampini   MPI_Comm           comm;
9110dd791a8SStefano Zampini   PetscSFType        sftype;
9120dd791a8SStefano Zampini 
9130dd791a8SStefano Zampini   PetscFunctionBegin;
9140dd791a8SStefano Zampini   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
9150dd791a8SStefano Zampini   PetscValidLogicalCollectiveInt(sf, bs, 2);
9160dd791a8SStefano Zampini   PetscAssertPointer(vsf, 5);
9170dd791a8SStefano Zampini   if (bs == 1) {
9180dd791a8SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)sf));
9190dd791a8SStefano Zampini     *vsf = sf;
9200dd791a8SStefano Zampini     PetscFunctionReturn(PETSC_SUCCESS);
9210dd791a8SStefano Zampini   }
9220dd791a8SStefano Zampini   PetscCall(PetscSFSetUp(sf));
9230dd791a8SStefano Zampini   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
9240dd791a8SStefano Zampini   PetscCallMPI(MPI_Comm_rank(comm, &rank));
9250dd791a8SStefano Zampini   PetscCall(PetscSFGetGraph(sf, &nr, &nl, &ilocal, &iremote));
9260dd791a8SStefano Zampini   PetscCall(PetscSFGetLeafRange(sf, NULL, &maxl));
9270dd791a8SStefano Zampini   maxl += 1;
9280dd791a8SStefano Zampini   if (ldl == PETSC_DECIDE) ldl = maxl;
9290dd791a8SStefano Zampini   if (ldr == PETSC_DECIDE) ldr = nr;
9300dd791a8SStefano Zampini   PetscCheck(ldr >= nr, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid leading dimension %" PetscInt_FMT " must be smaller than number of roots %" PetscInt_FMT, ldr, nr);
9310dd791a8SStefano Zampini   PetscCheck(ldl >= maxl, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid leading dimension %" PetscInt_FMT " must be larger than leaf range %" PetscInt_FMT, ldl, maxl - 1);
9320dd791a8SStefano Zampini   vnr = nr * bs;
9330dd791a8SStefano Zampini   vnl = nl * bs;
9340dd791a8SStefano Zampini   PetscCall(PetscMalloc1(vnl, &viremote));
9350dd791a8SStefano Zampini   PetscCall(PetscMalloc1(vnl, &vilocal));
9360dd791a8SStefano Zampini 
9370dd791a8SStefano Zampini   /* Communicate root leading dimensions to leaf ranks */
9380dd791a8SStefano Zampini   PetscCall(PetscSFGetRanksSF(sf, &rankssf));
9390dd791a8SStefano Zampini   PetscCall(PetscSFGetGraph(rankssf, NULL, &nranks, NULL, &sfrremote));
9400dd791a8SStefano Zampini   PetscCall(PetscMalloc1(nranks, &ldrs));
9410dd791a8SStefano Zampini   PetscCall(PetscSFBcastBegin(rankssf, MPIU_INT, &ldr, ldrs, MPI_REPLACE));
9420dd791a8SStefano Zampini   PetscCall(PetscSFBcastEnd(rankssf, MPIU_INT, &ldr, ldrs, MPI_REPLACE));
9430dd791a8SStefano Zampini 
9440dd791a8SStefano Zampini   for (PetscInt i = 0, rold = -1, lda = -1; i < nl; i++) {
945835f2295SStefano Zampini     const PetscInt r  = iremote[i].rank;
9460dd791a8SStefano Zampini     const PetscInt ii = iremote[i].index;
9470dd791a8SStefano Zampini 
9480dd791a8SStefano Zampini     if (r == rank) lda = ldr;
9490dd791a8SStefano Zampini     else if (rold != r) {
9500dd791a8SStefano Zampini       PetscInt j;
9510dd791a8SStefano Zampini 
9520dd791a8SStefano Zampini       for (j = 0; j < nranks; j++)
9530dd791a8SStefano Zampini         if (sfrremote[j].rank == r) break;
954835f2295SStefano Zampini       PetscCheck(j < nranks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unable to locate neighbor rank %" PetscInt_FMT, r);
9550dd791a8SStefano Zampini       lda = ldrs[j];
9560dd791a8SStefano Zampini     }
9570dd791a8SStefano Zampini     rold = r;
9580dd791a8SStefano Zampini     for (PetscInt v = 0; v < bs; v++) {
9590dd791a8SStefano Zampini       viremote[v * nl + i].rank  = r;
9600dd791a8SStefano Zampini       viremote[v * nl + i].index = v * lda + ii;
9610dd791a8SStefano Zampini       vilocal[v * nl + i]        = v * ldl + (ilocal ? ilocal[i] : i);
9620dd791a8SStefano Zampini     }
9630dd791a8SStefano Zampini   }
9640dd791a8SStefano Zampini   PetscCall(PetscFree(ldrs));
9650dd791a8SStefano Zampini   PetscCall(PetscSFCreate(comm, vsf));
9660dd791a8SStefano Zampini   PetscCall(PetscSFGetType(sf, &sftype));
9670dd791a8SStefano Zampini   PetscCall(PetscSFSetType(*vsf, sftype));
9680dd791a8SStefano Zampini   PetscCall(PetscSFSetGraph(*vsf, vnr, vnl, vilocal, PETSC_OWN_POINTER, viremote, PETSC_OWN_POINTER));
9690dd791a8SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
9700dd791a8SStefano Zampini }
971