xref: /petsc/src/vec/is/sf/utils/sfutils.c (revision 6964b6c77a90c4f41cea8bd11467778ed0d5483a)
1b0c7db22SLisandro Dalcin #include <petsc/private/sfimpl.h> /*I  "petscsf.h"   I*/
2b0c7db22SLisandro Dalcin #include <petsc/private/sectionimpl.h>
3b0c7db22SLisandro Dalcin 
4eb58282aSVaclav Hapla /*@
52f04c522SBarry Smith   PetscSFSetGraphLayout - Set a `PetscSF` communication pattern using global indices and a `PetscLayout`
6b0c7db22SLisandro Dalcin 
7b0c7db22SLisandro Dalcin   Collective
8b0c7db22SLisandro Dalcin 
94165533cSJose E. Roman   Input Parameters:
10b0c7db22SLisandro Dalcin + sf        - star forest
112f04c522SBarry Smith . layout    - `PetscLayout` defining the global space for roots, i.e. which roots are owned by each MPI process
122f04c522SBarry Smith . nleaves   - number of leaf vertices on the current process, each of these references a root on any MPI process
132f04c522SBarry Smith . ilocal    - locations of leaves in leafdata buffers, pass `NULL` for contiguous storage, that is the locations are in [0,`nleaves`)
142f04c522SBarry Smith . localmode - copy mode for `ilocal`
152f04c522SBarry Smith - gremote   - root vertices in global numbering corresponding to the leaves
16b0c7db22SLisandro Dalcin 
17b0c7db22SLisandro Dalcin   Level: intermediate
18b0c7db22SLisandro Dalcin 
19cab54364SBarry Smith   Note:
202f04c522SBarry Smith   Global indices must lie in [0, N) where N is the global size of `layout`.
212f04c522SBarry 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:
242f04c522SBarry Smith   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 
282f04c522SBarry Smith .seealso: [](sec_petscsf), `PetscSF`, `PetscSFGetGraphLayout()`, `PetscSFCreate()`, `PetscSFView()`, `PetscSFSetGraph()`, `PetscSFGetGraph()`
29b0c7db22SLisandro Dalcin @*/
30cf84bf9eSBarry Smith 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
612f04c522SBarry Smith   PetscSFGetGraphLayout - Get the global indices and `PetscLayout` that describe a `PetscSF`
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
722f04c522SBarry Smith - gremote - root vertices in global numbering corresponding to the leaves
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 
812f04c522SBarry Smith .seealso: [](sec_petscsf), `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 /*@
1092f04c522SBarry Smith   PetscSFSetGraphSection - Sets the `PetscSF` graph (communication pattern) 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 
1182f04c522SBarry Smith .seealso: [](sec_petscsf), `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 
223*6964b6c7SJames Wright   To distribute data from the `rootSection` to the `leafSection`, see  `PetscSFCreateSectionSF()` or `PetscSectionMigrateData()`.
224*6964b6c7SJames Wright 
225ce78bad3SBarry Smith   Fortran Note:
226ce78bad3SBarry Smith   Use `PetscSFDestroyRemoteOffsets()` when `remoteOffsets` is no longer needed.
22723e9620eSJunchao Zhang 
228*6964b6c7SJames Wright .seealso: [](sec_petscsf), `PetscSF`, `PetscSFCreate()`, `PetscSFCreateSectionSF()`
229b0c7db22SLisandro Dalcin @*/
230ce78bad3SBarry Smith PetscErrorCode PetscSFDistributeSection(PetscSF sf, PetscSection rootSection, PetscInt *remoteOffsets[], PetscSection leafSection)
231d71ae5a4SJacob Faibussowitsch {
232b0c7db22SLisandro Dalcin   PetscSF         embedSF;
233b0c7db22SLisandro Dalcin   const PetscInt *indices;
234b0c7db22SLisandro Dalcin   IS              selected;
2351690c2aeSBarry Smith   PetscInt        numFields, nroots, rpStart, rpEnd, lpStart = PETSC_INT_MAX, lpEnd = -1, f, c;
236b0c7db22SLisandro Dalcin   PetscBool      *sub, hasc;
237b0c7db22SLisandro Dalcin 
238b0c7db22SLisandro Dalcin   PetscFunctionBegin;
2399566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_DistSect, sf, 0, 0, 0));
2409566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(rootSection, &numFields));
241029e8818Sksagiyam   if (numFields) {
242029e8818Sksagiyam     IS perm;
243029e8818Sksagiyam 
244029e8818Sksagiyam     /* PetscSectionSetNumFields() calls PetscSectionReset(), which destroys
245029e8818Sksagiyam        leafSection->perm. To keep this permutation set by the user, we grab
246029e8818Sksagiyam        the reference before calling PetscSectionSetNumFields() and set it
247029e8818Sksagiyam        back after. */
2489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPermutation(leafSection, &perm));
2499566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)perm));
2509566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(leafSection, numFields));
2519566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetPermutation(leafSection, perm));
2529566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&perm));
253029e8818Sksagiyam   }
2549566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numFields + 2, &sub));
255b0c7db22SLisandro Dalcin   sub[1] = rootSection->bc ? PETSC_TRUE : PETSC_FALSE;
256b0c7db22SLisandro Dalcin   for (f = 0; f < numFields; ++f) {
2572ee82556SMatthew G. Knepley     PetscSectionSym sym, dsym = NULL;
258b0c7db22SLisandro Dalcin     const char     *name    = NULL;
259b0c7db22SLisandro Dalcin     PetscInt        numComp = 0;
260b0c7db22SLisandro Dalcin 
261b0c7db22SLisandro Dalcin     sub[2 + f] = rootSection->field[f]->bc ? PETSC_TRUE : PETSC_FALSE;
2629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldComponents(rootSection, f, &numComp));
2639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldName(rootSection, f, &name));
2649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldSym(rootSection, f, &sym));
2659566063dSJacob Faibussowitsch     if (sym) PetscCall(PetscSectionSymDistribute(sym, sf, &dsym));
2669566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldComponents(leafSection, f, numComp));
2679566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldName(leafSection, f, name));
2689566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldSym(leafSection, f, dsym));
2699566063dSJacob Faibussowitsch     PetscCall(PetscSectionSymDestroy(&dsym));
270b0c7db22SLisandro Dalcin     for (c = 0; c < rootSection->numFieldComponents[f]; ++c) {
2719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetComponentName(rootSection, f, c, &name));
2729566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetComponentName(leafSection, f, c, name));
273b0c7db22SLisandro Dalcin     }
274b0c7db22SLisandro Dalcin   }
2759566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(rootSection, &rpStart, &rpEnd));
2769566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
277b0c7db22SLisandro Dalcin   rpEnd = PetscMin(rpEnd, nroots);
278b0c7db22SLisandro Dalcin   rpEnd = PetscMax(rpStart, rpEnd);
279b0c7db22SLisandro Dalcin   /* see if we can avoid creating the embedded SF, since it can cost more than an allreduce */
280b0c7db22SLisandro Dalcin   sub[0] = (PetscBool)(nroots != rpEnd - rpStart);
2815440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, sub, 2 + numFields, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)sf)));
282b0c7db22SLisandro Dalcin   if (sub[0]) {
2839566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, rpEnd - rpStart, rpStart, 1, &selected));
2849566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(selected, &indices));
2859566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedRootSF(sf, rpEnd - rpStart, indices, &embedSF));
2869566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(selected, &indices));
2879566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&selected));
288b0c7db22SLisandro Dalcin   } else {
2899566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)sf));
290b0c7db22SLisandro Dalcin     embedSF = sf;
291b0c7db22SLisandro Dalcin   }
2929566063dSJacob Faibussowitsch   PetscCall(PetscSFGetLeafRange(embedSF, &lpStart, &lpEnd));
293b0c7db22SLisandro Dalcin   lpEnd++;
294b0c7db22SLisandro Dalcin 
2959566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(leafSection, lpStart, lpEnd));
296b0c7db22SLisandro Dalcin 
297b0c7db22SLisandro Dalcin   /* Constrained dof section */
298b0c7db22SLisandro Dalcin   hasc = sub[1];
299b0c7db22SLisandro Dalcin   for (f = 0; f < numFields; ++f) hasc = (PetscBool)(hasc || sub[2 + f]);
300b0c7db22SLisandro Dalcin 
301b0c7db22SLisandro Dalcin   /* Could fuse these at the cost of copies and extra allocation */
30216cd844bSPierre Jolivet   PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasDof, -rpStart), PetscSafePointerPlusOffset(leafSection->atlasDof, -lpStart), MPI_REPLACE));
30316cd844bSPierre Jolivet   PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasDof, -rpStart), PetscSafePointerPlusOffset(leafSection->atlasDof, -lpStart), MPI_REPLACE));
304b0c7db22SLisandro Dalcin   if (sub[1]) {
3057c0883d5SVaclav Hapla     PetscCall(PetscSectionCheckConstraints_Private(rootSection));
3067c0883d5SVaclav Hapla     PetscCall(PetscSectionCheckConstraints_Private(leafSection));
3079566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->bc->atlasDof[-rpStart], &leafSection->bc->atlasDof[-lpStart], MPI_REPLACE));
3089566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->bc->atlasDof[-rpStart], &leafSection->bc->atlasDof[-lpStart], MPI_REPLACE));
309b0c7db22SLisandro Dalcin   }
310b0c7db22SLisandro Dalcin   for (f = 0; f < numFields; ++f) {
31116cd844bSPierre Jolivet     PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->field[f]->atlasDof, -rpStart), PetscSafePointerPlusOffset(leafSection->field[f]->atlasDof, -lpStart), MPI_REPLACE));
31216cd844bSPierre Jolivet     PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->field[f]->atlasDof, -rpStart), PetscSafePointerPlusOffset(leafSection->field[f]->atlasDof, -lpStart), MPI_REPLACE));
313b0c7db22SLisandro Dalcin     if (sub[2 + f]) {
3147c0883d5SVaclav Hapla       PetscCall(PetscSectionCheckConstraints_Private(rootSection->field[f]));
3157c0883d5SVaclav Hapla       PetscCall(PetscSectionCheckConstraints_Private(leafSection->field[f]));
3169566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasDof[-rpStart], &leafSection->field[f]->bc->atlasDof[-lpStart], MPI_REPLACE));
3179566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasDof[-rpStart], &leafSection->field[f]->bc->atlasDof[-lpStart], MPI_REPLACE));
318b0c7db22SLisandro Dalcin     }
319b0c7db22SLisandro Dalcin   }
320b0c7db22SLisandro Dalcin   if (remoteOffsets) {
3219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(lpEnd - lpStart, remoteOffsets));
32216cd844bSPierre Jolivet     PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasOff, -rpStart), PetscSafePointerPlusOffset(*remoteOffsets, -lpStart), MPI_REPLACE));
32316cd844bSPierre Jolivet     PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasOff, -rpStart), PetscSafePointerPlusOffset(*remoteOffsets, -lpStart), MPI_REPLACE));
324b0c7db22SLisandro Dalcin   }
32569c11d05SVaclav Hapla   PetscCall(PetscSectionInvalidateMaxDof_Internal(leafSection));
3269566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(leafSection));
327b0c7db22SLisandro Dalcin   if (hasc) { /* need to communicate bcIndices */
328b0c7db22SLisandro Dalcin     PetscSF   bcSF;
329b0c7db22SLisandro Dalcin     PetscInt *rOffBc;
330b0c7db22SLisandro Dalcin 
3319566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(lpEnd - lpStart, &rOffBc));
332b0c7db22SLisandro Dalcin     if (sub[1]) {
3339566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
3349566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
3359566063dSJacob Faibussowitsch       PetscCall(PetscSFCreateSectionSF(embedSF, rootSection->bc, rOffBc, leafSection->bc, &bcSF));
3369566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(bcSF, MPIU_INT, rootSection->bcIndices, leafSection->bcIndices, MPI_REPLACE));
3379566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(bcSF, MPIU_INT, rootSection->bcIndices, leafSection->bcIndices, MPI_REPLACE));
3389566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&bcSF));
339b0c7db22SLisandro Dalcin     }
340b0c7db22SLisandro Dalcin     for (f = 0; f < numFields; ++f) {
341b0c7db22SLisandro Dalcin       if (sub[2 + f]) {
3429566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
3439566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
3449566063dSJacob Faibussowitsch         PetscCall(PetscSFCreateSectionSF(embedSF, rootSection->field[f]->bc, rOffBc, leafSection->field[f]->bc, &bcSF));
3459566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(bcSF, MPIU_INT, rootSection->field[f]->bcIndices, leafSection->field[f]->bcIndices, MPI_REPLACE));
3469566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(bcSF, MPIU_INT, rootSection->field[f]->bcIndices, leafSection->field[f]->bcIndices, MPI_REPLACE));
3479566063dSJacob Faibussowitsch         PetscCall(PetscSFDestroy(&bcSF));
348b0c7db22SLisandro Dalcin       }
349b0c7db22SLisandro Dalcin     }
3509566063dSJacob Faibussowitsch     PetscCall(PetscFree(rOffBc));
351b0c7db22SLisandro Dalcin   }
3529566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&embedSF));
3539566063dSJacob Faibussowitsch   PetscCall(PetscFree(sub));
3549566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_DistSect, sf, 0, 0, 0));
3553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
356b0c7db22SLisandro Dalcin }
357b0c7db22SLisandro Dalcin 
358b0c7db22SLisandro Dalcin /*@C
359b0c7db22SLisandro Dalcin   PetscSFCreateRemoteOffsets - Create offsets for point data on remote processes
360b0c7db22SLisandro Dalcin 
361c3339decSBarry Smith   Collective
362b0c7db22SLisandro Dalcin 
363b0c7db22SLisandro Dalcin   Input Parameters:
364cab54364SBarry Smith + sf          - The `PetscSF`
365ce78bad3SBarry Smith . rootSection - Data layout of remote points for outgoing data (this is layout for roots)
366ce78bad3SBarry Smith - leafSection - Data layout of local points for incoming data  (this is layout for leaves)
367b0c7db22SLisandro Dalcin 
368b0c7db22SLisandro Dalcin   Output Parameter:
369ce78bad3SBarry Smith . remoteOffsets - Offsets for point data on remote processes (these are offsets from the root section), or `NULL`
370b0c7db22SLisandro Dalcin 
371b0c7db22SLisandro Dalcin   Level: developer
372b0c7db22SLisandro Dalcin 
373ce78bad3SBarry Smith   Note:
374ce78bad3SBarry Smith   Caller must `PetscFree()` `remoteOffsets` if it was requested
375ce78bad3SBarry Smith 
376ce78bad3SBarry Smith   Fortran Note:
377ce78bad3SBarry Smith   Use `PetscSFDestroyRemoteOffsets()` when `remoteOffsets` is no longer needed.
37823e9620eSJunchao Zhang 
3792f04c522SBarry Smith .seealso: [](sec_petscsf), `PetscSF`, `PetscSFCreate()`
380b0c7db22SLisandro Dalcin @*/
381ce78bad3SBarry Smith PetscErrorCode PetscSFCreateRemoteOffsets(PetscSF sf, PetscSection rootSection, PetscSection leafSection, PetscInt *remoteOffsets[])
382d71ae5a4SJacob Faibussowitsch {
383b0c7db22SLisandro Dalcin   PetscSF         embedSF;
384b0c7db22SLisandro Dalcin   const PetscInt *indices;
385b0c7db22SLisandro Dalcin   IS              selected;
386b0c7db22SLisandro Dalcin   PetscInt        numRoots, rpStart = 0, rpEnd = 0, lpStart = 0, lpEnd = 0;
387b0c7db22SLisandro Dalcin 
388b0c7db22SLisandro Dalcin   PetscFunctionBegin;
389b0c7db22SLisandro Dalcin   *remoteOffsets = NULL;
3909566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &numRoots, NULL, NULL, NULL));
3913ba16761SJacob Faibussowitsch   if (numRoots < 0) PetscFunctionReturn(PETSC_SUCCESS);
3929566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_RemoteOff, sf, 0, 0, 0));
3939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(rootSection, &rpStart, &rpEnd));
3949566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(leafSection, &lpStart, &lpEnd));
3959566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, rpEnd - rpStart, rpStart, 1, &selected));
3969566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(selected, &indices));
3979566063dSJacob Faibussowitsch   PetscCall(PetscSFCreateEmbeddedRootSF(sf, rpEnd - rpStart, indices, &embedSF));
3989566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(selected, &indices));
3999566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&selected));
4009566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(lpEnd - lpStart, remoteOffsets));
4018e3a54c0SPierre Jolivet   PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasOff, -rpStart), PetscSafePointerPlusOffset(*remoteOffsets, -lpStart), MPI_REPLACE));
4028e3a54c0SPierre Jolivet   PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasOff, -rpStart), PetscSafePointerPlusOffset(*remoteOffsets, -lpStart), MPI_REPLACE));
4039566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&embedSF));
4049566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_RemoteOff, sf, 0, 0, 0));
4053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
406b0c7db22SLisandro Dalcin }
407b0c7db22SLisandro Dalcin 
408ce78bad3SBarry Smith /*@
409cab54364SBarry Smith   PetscSFCreateSectionSF - Create an expanded `PetscSF` of dofs, assuming the input `PetscSF` relates points
410b0c7db22SLisandro Dalcin 
411c3339decSBarry Smith   Collective
412b0c7db22SLisandro Dalcin 
413b0c7db22SLisandro Dalcin   Input Parameters:
414cab54364SBarry Smith + sf            - The `PetscSF`
415b0c7db22SLisandro Dalcin . rootSection   - Data layout of remote points for outgoing data (this is usually the serial section)
4162f04c522SBarry Smith . remoteOffsets - Offsets for point data on remote processes (these are offsets from the root section), or `NULL`
417b0c7db22SLisandro Dalcin - leafSection   - Data layout of local points for incoming data  (this is the distributed section)
418b0c7db22SLisandro Dalcin 
4192fe279fdSBarry Smith   Output Parameter:
4202fe279fdSBarry Smith . sectionSF - The new `PetscSF`
421b0c7db22SLisandro Dalcin 
422b0c7db22SLisandro Dalcin   Level: advanced
423b0c7db22SLisandro Dalcin 
42423e9620eSJunchao Zhang   Notes:
425*6964b6c7SJames Wright   `remoteOffsets` can be `NULL` if `sf` does not reference any points in `leafSection`
42623e9620eSJunchao Zhang 
427*6964b6c7SJames Wright .seealso: [](sec_petscsf), `PetscSF`, `PetscSFCreate()`, `PetscSFDistributeSection()`
428b0c7db22SLisandro Dalcin @*/
429d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFCreateSectionSF(PetscSF sf, PetscSection rootSection, PetscInt remoteOffsets[], PetscSection leafSection, PetscSF *sectionSF)
430d71ae5a4SJacob Faibussowitsch {
431b0c7db22SLisandro Dalcin   MPI_Comm           comm;
432b0c7db22SLisandro Dalcin   const PetscInt    *localPoints;
433b0c7db22SLisandro Dalcin   const PetscSFNode *remotePoints;
434b0c7db22SLisandro Dalcin   PetscInt           lpStart, lpEnd;
435b0c7db22SLisandro Dalcin   PetscInt           numRoots, numSectionRoots, numPoints, numIndices = 0;
436b0c7db22SLisandro Dalcin   PetscInt          *localIndices;
437b0c7db22SLisandro Dalcin   PetscSFNode       *remoteIndices;
438b0c7db22SLisandro Dalcin   PetscInt           i, ind;
439b0c7db22SLisandro Dalcin 
440b0c7db22SLisandro Dalcin   PetscFunctionBegin;
441b0c7db22SLisandro Dalcin   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
4424f572ea9SToby Isaac   PetscAssertPointer(rootSection, 2);
4434f572ea9SToby Isaac   /* Cannot check PetscAssertPointer(remoteOffsets,3) because it can be NULL if sf does not reference any points in leafSection */
4444f572ea9SToby Isaac   PetscAssertPointer(leafSection, 4);
4454f572ea9SToby Isaac   PetscAssertPointer(sectionSF, 5);
4469566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
4479566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, sectionSF));
4489566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(leafSection, &lpStart, &lpEnd));
4499566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(rootSection, &numSectionRoots));
4509566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &numRoots, &numPoints, &localPoints, &remotePoints));
4513ba16761SJacob Faibussowitsch   if (numRoots < 0) PetscFunctionReturn(PETSC_SUCCESS);
4529566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_SectSF, sf, 0, 0, 0));
453b0c7db22SLisandro Dalcin   for (i = 0; i < numPoints; ++i) {
454b0c7db22SLisandro Dalcin     PetscInt localPoint = localPoints ? localPoints[i] : i;
455b0c7db22SLisandro Dalcin     PetscInt dof;
456b0c7db22SLisandro Dalcin 
457b0c7db22SLisandro Dalcin     if ((localPoint >= lpStart) && (localPoint < lpEnd)) {
4589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafSection, localPoint, &dof));
45922a18c9fSMatthew G. Knepley       numIndices += dof < 0 ? 0 : dof;
460b0c7db22SLisandro Dalcin     }
461b0c7db22SLisandro Dalcin   }
4629566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numIndices, &localIndices));
4639566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numIndices, &remoteIndices));
464b0c7db22SLisandro Dalcin   /* Create new index graph */
465b0c7db22SLisandro Dalcin   for (i = 0, ind = 0; i < numPoints; ++i) {
466b0c7db22SLisandro Dalcin     PetscInt localPoint = localPoints ? localPoints[i] : i;
467835f2295SStefano Zampini     PetscInt rank       = remotePoints[i].rank;
468b0c7db22SLisandro Dalcin 
469b0c7db22SLisandro Dalcin     if ((localPoint >= lpStart) && (localPoint < lpEnd)) {
470b0c7db22SLisandro Dalcin       PetscInt remoteOffset = remoteOffsets[localPoint - lpStart];
471b0c7db22SLisandro Dalcin       PetscInt loff, dof, d;
472b0c7db22SLisandro Dalcin 
4739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafSection, localPoint, &loff));
4749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafSection, localPoint, &dof));
475b0c7db22SLisandro Dalcin       for (d = 0; d < dof; ++d, ++ind) {
476b0c7db22SLisandro Dalcin         localIndices[ind]        = loff + d;
477b0c7db22SLisandro Dalcin         remoteIndices[ind].rank  = rank;
478b0c7db22SLisandro Dalcin         remoteIndices[ind].index = remoteOffset + d;
479b0c7db22SLisandro Dalcin       }
480b0c7db22SLisandro Dalcin     }
481b0c7db22SLisandro Dalcin   }
48208401ef6SPierre Jolivet   PetscCheck(numIndices == ind, comm, PETSC_ERR_PLIB, "Inconsistency in indices, %" PetscInt_FMT " should be %" PetscInt_FMT, ind, numIndices);
4839566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sectionSF, numSectionRoots, numIndices, localIndices, PETSC_OWN_POINTER, remoteIndices, PETSC_OWN_POINTER));
4849566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(*sectionSF));
4859566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_SectSF, sf, 0, 0, 0));
4863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
487b0c7db22SLisandro Dalcin }
4888fa9e22eSVaclav Hapla 
4898fa9e22eSVaclav Hapla /*@C
4902f04c522SBarry Smith   PetscSFCreateFromLayouts - Creates a parallel star forest mapping between two `PetscLayout` objects
4918fa9e22eSVaclav Hapla 
4928fa9e22eSVaclav Hapla   Collective
4938fa9e22eSVaclav Hapla 
4944165533cSJose E. Roman   Input Parameters:
495cab54364SBarry Smith + rmap - `PetscLayout` defining the global root space
496cab54364SBarry Smith - lmap - `PetscLayout` defining the global leaf space
4978fa9e22eSVaclav Hapla 
4984165533cSJose E. Roman   Output Parameter:
4998fa9e22eSVaclav Hapla . sf - The parallel star forest
5008fa9e22eSVaclav Hapla 
5018fa9e22eSVaclav Hapla   Level: intermediate
5028fa9e22eSVaclav Hapla 
5032f04c522SBarry Smith   Notes:
5042f04c522SBarry Smith   If the global length of `lmap` differs from the global length of `rmap` then the excess entries are ignored.
5052f04c522SBarry Smith 
5062f04c522SBarry Smith   The resulting `sf` used with `PetscSFBcastBegin()` and `PetscSFBcastEnd()` merely copies the array entries of `rootdata` to
5072f04c522SBarry Smith   `leafdata`; moving them between MPI processes if needed. For example,
5082f04c522SBarry Smith   if rmap is [0, 3, 5) and lmap is [0, 2, 6) and `rootdata` is (1, 2, 3) on MPI rank 0 and (4, 5) on MPI rank 1 then the
5092f04c522SBarry Smith   `leafdata` would become (1, 2) on MPI rank 0 and (3, 4, 5, x) on MPI rank 1.
5102f04c522SBarry Smith 
5112f04c522SBarry Smith .seealso: [](sec_petscsf), `PetscSF`, `PetscLayout`, `PetscSFCreate()`, `PetscSFSetGraph()`, `PetscLayoutCreate()`, `PetscSFSetGraphLayout()`
5128fa9e22eSVaclav Hapla @*/
513d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFCreateFromLayouts(PetscLayout rmap, PetscLayout lmap, PetscSF *sf)
514d71ae5a4SJacob Faibussowitsch {
5158fa9e22eSVaclav Hapla   PetscInt     i, nroots, nleaves = 0;
5168fa9e22eSVaclav Hapla   PetscInt     rN, lst, len;
5178fa9e22eSVaclav Hapla   PetscMPIInt  owner = -1;
5188fa9e22eSVaclav Hapla   PetscSFNode *remote;
5198fa9e22eSVaclav Hapla   MPI_Comm     rcomm = rmap->comm;
5208fa9e22eSVaclav Hapla   MPI_Comm     lcomm = lmap->comm;
5218fa9e22eSVaclav Hapla   PetscMPIInt  flg;
5228fa9e22eSVaclav Hapla 
5238fa9e22eSVaclav Hapla   PetscFunctionBegin;
5244f572ea9SToby Isaac   PetscAssertPointer(sf, 3);
52528b400f6SJacob Faibussowitsch   PetscCheck(rmap->setupcalled, rcomm, PETSC_ERR_ARG_WRONGSTATE, "Root layout not setup");
52628b400f6SJacob Faibussowitsch   PetscCheck(lmap->setupcalled, lcomm, PETSC_ERR_ARG_WRONGSTATE, "Leaf layout not setup");
5279566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_compare(rcomm, lcomm, &flg));
528c9cc58a2SBarry Smith   PetscCheck(flg == MPI_CONGRUENT || flg == MPI_IDENT, rcomm, PETSC_ERR_SUP, "cannot map two layouts with non-matching communicators");
5299566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(rcomm, sf));
5309566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetLocalSize(rmap, &nroots));
5319566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetSize(rmap, &rN));
5329566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(lmap, &lst, &len));
5339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(len - lst, &remote));
5348fa9e22eSVaclav Hapla   for (i = lst; i < len && i < rN; i++) {
53548a46eb9SPierre Jolivet     if (owner < -1 || i >= rmap->range[owner + 1]) PetscCall(PetscLayoutFindOwner(rmap, i, &owner));
5368fa9e22eSVaclav Hapla     remote[nleaves].rank  = owner;
5378fa9e22eSVaclav Hapla     remote[nleaves].index = i - rmap->range[owner];
5388fa9e22eSVaclav Hapla     nleaves++;
5398fa9e22eSVaclav Hapla   }
5409566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sf, nroots, nleaves, NULL, PETSC_OWN_POINTER, remote, PETSC_COPY_VALUES));
5419566063dSJacob Faibussowitsch   PetscCall(PetscFree(remote));
5423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5438fa9e22eSVaclav Hapla }
5448fa9e22eSVaclav Hapla 
5458fa9e22eSVaclav Hapla /* TODO: handle nooffprocentries like MatZeroRowsMapLocal_Private, since this code is the same */
546ce78bad3SBarry Smith PetscErrorCode PetscLayoutMapLocal(PetscLayout map, PetscInt N, const PetscInt idxs[], PetscInt *on, PetscInt *oidxs[], PetscInt *ogidxs[])
547d71ae5a4SJacob Faibussowitsch {
5488fa9e22eSVaclav Hapla   PetscInt    *owners = map->range;
5498fa9e22eSVaclav Hapla   PetscInt     n      = map->n;
5508fa9e22eSVaclav Hapla   PetscSF      sf;
551d61846d3SStefano Zampini   PetscInt    *lidxs, *work = NULL, *ilocal;
5528fa9e22eSVaclav Hapla   PetscSFNode *ridxs;
5538fa9e22eSVaclav Hapla   PetscMPIInt  rank, p = 0;
554d61846d3SStefano Zampini   PetscInt     r, len = 0, nleaves = 0;
5558fa9e22eSVaclav Hapla 
5568fa9e22eSVaclav Hapla   PetscFunctionBegin;
5578fa9e22eSVaclav Hapla   if (on) *on = 0; /* squelch -Wmaybe-uninitialized */
5588fa9e22eSVaclav Hapla   /* Create SF where leaves are input idxs and roots are owned idxs */
5599566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(map->comm, &rank));
5609566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &lidxs));
5618fa9e22eSVaclav Hapla   for (r = 0; r < n; ++r) lidxs[r] = -1;
5629566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(N, &ridxs));
563d61846d3SStefano Zampini   PetscCall(PetscMalloc1(N, &ilocal));
5648fa9e22eSVaclav Hapla   for (r = 0; r < N; ++r) {
5658fa9e22eSVaclav Hapla     const PetscInt idx = idxs[r];
566d61846d3SStefano Zampini 
567d61846d3SStefano Zampini     if (idx < 0) continue;
568d61846d3SStefano Zampini     PetscCheck(idx < map->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Index %" PetscInt_FMT " out of range [0,%" PetscInt_FMT ")", idx, map->N);
5698fa9e22eSVaclav Hapla     if (idx < owners[p] || owners[p + 1] <= idx) { /* short-circuit the search if the last p owns this idx too */
5709566063dSJacob Faibussowitsch       PetscCall(PetscLayoutFindOwner(map, idx, &p));
5718fa9e22eSVaclav Hapla     }
572d61846d3SStefano Zampini     ridxs[nleaves].rank  = p;
573d61846d3SStefano Zampini     ridxs[nleaves].index = idxs[r] - owners[p];
574d61846d3SStefano Zampini     ilocal[nleaves]      = r;
575d61846d3SStefano Zampini     nleaves++;
5768fa9e22eSVaclav Hapla   }
5779566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(map->comm, &sf));
578d61846d3SStefano Zampini   PetscCall(PetscSFSetGraph(sf, n, nleaves, ilocal, PETSC_OWN_POINTER, ridxs, PETSC_OWN_POINTER));
5799566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(sf, MPIU_INT, (PetscInt *)idxs, lidxs, MPI_LOR));
5809566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(sf, MPIU_INT, (PetscInt *)idxs, lidxs, MPI_LOR));
5818fa9e22eSVaclav Hapla   if (ogidxs) { /* communicate global idxs */
5828fa9e22eSVaclav Hapla     PetscInt cum = 0, start, *work2;
5838fa9e22eSVaclav Hapla 
5849566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &work));
5859566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(N, &work2));
5869371c9d4SSatish Balay     for (r = 0; r < N; ++r)
5879371c9d4SSatish Balay       if (idxs[r] >= 0) cum++;
5889566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&cum, &start, 1, MPIU_INT, MPI_SUM, map->comm));
5898fa9e22eSVaclav Hapla     start -= cum;
5908fa9e22eSVaclav Hapla     cum = 0;
5919371c9d4SSatish Balay     for (r = 0; r < N; ++r)
5929371c9d4SSatish Balay       if (idxs[r] >= 0) work2[r] = start + cum++;
5939566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(sf, MPIU_INT, work2, work, MPI_REPLACE));
5949566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(sf, MPIU_INT, work2, work, MPI_REPLACE));
5959566063dSJacob Faibussowitsch     PetscCall(PetscFree(work2));
5968fa9e22eSVaclav Hapla   }
5979566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sf));
5988fa9e22eSVaclav Hapla   /* Compress and put in indices */
5998fa9e22eSVaclav Hapla   for (r = 0; r < n; ++r)
6008fa9e22eSVaclav Hapla     if (lidxs[r] >= 0) {
6018fa9e22eSVaclav Hapla       if (work) work[len] = work[r];
6028fa9e22eSVaclav Hapla       lidxs[len++] = r;
6038fa9e22eSVaclav Hapla     }
6048fa9e22eSVaclav Hapla   if (on) *on = len;
6058fa9e22eSVaclav Hapla   if (oidxs) *oidxs = lidxs;
6068fa9e22eSVaclav Hapla   if (ogidxs) *ogidxs = work;
6073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6088fa9e22eSVaclav Hapla }
609deffd5ebSksagiyam 
610deffd5ebSksagiyam /*@
611cab54364SBarry Smith   PetscSFCreateByMatchingIndices - Create `PetscSF` by matching root and leaf indices
612deffd5ebSksagiyam 
613deffd5ebSksagiyam   Collective
614deffd5ebSksagiyam 
615deffd5ebSksagiyam   Input Parameters:
616cf84bf9eSBarry Smith + layout           - `PetscLayout` defining the global index space and the MPI rank that brokers each index
617cf84bf9eSBarry Smith . numRootIndices   - size of `rootIndices`
618cf84bf9eSBarry Smith . rootIndices      - array of global indices of which this process requests ownership
619cf84bf9eSBarry Smith . rootLocalIndices - root local index permutation (`NULL` if no permutation)
620cf84bf9eSBarry Smith . rootLocalOffset  - offset to be added to `rootLocalIndices`
621cf84bf9eSBarry Smith . numLeafIndices   - size of `leafIndices`
622cf84bf9eSBarry Smith . leafIndices      - array of global indices with which this process requires data associated
623cf84bf9eSBarry Smith . leafLocalIndices - leaf local index permutation (`NULL` if no permutation)
624cf84bf9eSBarry Smith - leafLocalOffset  - offset to be added to `leafLocalIndices`
625deffd5ebSksagiyam 
626d8d19677SJose E. Roman   Output Parameters:
627cf84bf9eSBarry Smith + sfA - star forest representing the communication pattern from the layout space to the leaf space (`NULL` if not needed)
628deffd5ebSksagiyam - sf  - star forest representing the communication pattern from the root space to the leaf space
629deffd5ebSksagiyam 
630cab54364SBarry Smith   Level: advanced
631cab54364SBarry Smith 
632deffd5ebSksagiyam   Example 1:
633cab54364SBarry Smith .vb
634cab54364SBarry Smith   rank             : 0            1            2
635cab54364SBarry Smith   rootIndices      : [1 0 2]      [3]          [3]
636cab54364SBarry Smith   rootLocalOffset  : 100          200          300
637cab54364SBarry Smith   layout           : [0 1]        [2]          [3]
638cab54364SBarry Smith   leafIndices      : [0]          [2]          [0 3]
639cab54364SBarry Smith   leafLocalOffset  : 400          500          600
640cab54364SBarry Smith 
641cab54364SBarry Smith would build the following PetscSF
642cab54364SBarry Smith 
643cab54364SBarry Smith   [0] 400 <- (0,101)
644cab54364SBarry Smith   [1] 500 <- (0,102)
645cab54364SBarry Smith   [2] 600 <- (0,101)
646cab54364SBarry Smith   [2] 601 <- (2,300)
647cab54364SBarry Smith .ve
648cab54364SBarry Smith 
649deffd5ebSksagiyam   Example 2:
650cab54364SBarry Smith .vb
651cab54364SBarry Smith   rank             : 0               1               2
652cab54364SBarry Smith   rootIndices      : [1 0 2]         [3]             [3]
653cab54364SBarry Smith   rootLocalOffset  : 100             200             300
654cab54364SBarry Smith   layout           : [0 1]           [2]             [3]
655cab54364SBarry Smith   leafIndices      : rootIndices     rootIndices     rootIndices
656cab54364SBarry Smith   leafLocalOffset  : rootLocalOffset rootLocalOffset rootLocalOffset
657cab54364SBarry Smith 
658cab54364SBarry Smith would build the following PetscSF
659cab54364SBarry Smith 
660cab54364SBarry Smith   [1] 200 <- (2,300)
661cab54364SBarry Smith .ve
662cab54364SBarry Smith 
663deffd5ebSksagiyam   Example 3:
664cab54364SBarry Smith .vb
665cab54364SBarry Smith   No process requests ownership of global index 1, but no process needs it.
666cab54364SBarry Smith 
667cab54364SBarry Smith   rank             : 0            1            2
668cab54364SBarry Smith   numRootIndices   : 2            1            1
669cab54364SBarry Smith   rootIndices      : [0 2]        [3]          [3]
670cab54364SBarry Smith   rootLocalOffset  : 100          200          300
671cab54364SBarry Smith   layout           : [0 1]        [2]          [3]
672cab54364SBarry Smith   numLeafIndices   : 1            1            2
673cab54364SBarry Smith   leafIndices      : [0]          [2]          [0 3]
674cab54364SBarry Smith   leafLocalOffset  : 400          500          600
675cab54364SBarry Smith 
676cab54364SBarry Smith would build the following PetscSF
677cab54364SBarry Smith 
678cab54364SBarry Smith   [0] 400 <- (0,100)
679cab54364SBarry Smith   [1] 500 <- (0,101)
680cab54364SBarry Smith   [2] 600 <- (0,100)
681cab54364SBarry Smith   [2] 601 <- (2,300)
682cab54364SBarry Smith .ve
683deffd5ebSksagiyam 
684deffd5ebSksagiyam   Notes:
6852f04c522SBarry Smith   `layout` represents any partitioning of [0, N), where N is the total number of global indices, and its
686cab54364SBarry Smith   local size can be set to `PETSC_DECIDE`.
687cab54364SBarry Smith 
6882f04c522SBarry Smith   If a global index x lies in the partition owned by process i, each process whose `rootIndices` contains x requests
689deffd5ebSksagiyam   ownership of x and sends its own rank and the local index of x to process i.
690deffd5ebSksagiyam   If multiple processes request ownership of x, the one with the highest rank is to own x.
6912f04c522SBarry Smith   Process i then broadcasts the ownership information, so that each process whose `leafIndices` contains x knows the
692deffd5ebSksagiyam   ownership information of x.
6932f04c522SBarry Smith   The output `sf` is constructed by associating each leaf point to a root point in this way.
694deffd5ebSksagiyam 
695deffd5ebSksagiyam   Suppose there is point data ordered according to the global indices and partitioned according to the given layout.
6962f04c522SBarry Smith   The optional output `sfA` can be used to push such data to leaf points.
697deffd5ebSksagiyam 
6982f04c522SBarry Smith   All indices in `rootIndices` and `leafIndices` must lie in the layout range. The union (over all processes) of `rootIndices`
6992f04c522SBarry Smith   must cover that of `leafIndices`, but need not cover the entire layout.
700deffd5ebSksagiyam 
701deffd5ebSksagiyam   If (leafIndices, leafLocalIndices, leafLocalOffset) == (rootIndices, rootLocalIndices, rootLocalOffset), the output
702deffd5ebSksagiyam   star forest is almost identity, so will only include non-trivial part of the map.
703deffd5ebSksagiyam 
70438b5cf2dSJacob Faibussowitsch   Developer Notes:
705deffd5ebSksagiyam   Current approach of a process of the highest rank gaining the ownership may cause load imbalance; consider using
706deffd5ebSksagiyam   hash(rank, root_local_index) as the bid for the ownership determination.
707deffd5ebSksagiyam 
7082f04c522SBarry Smith .seealso: [](sec_petscsf), `PetscSF`, `PetscSFCreate()`
709deffd5ebSksagiyam @*/
710cf84bf9eSBarry Smith 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)
711d71ae5a4SJacob Faibussowitsch {
712deffd5ebSksagiyam   MPI_Comm     comm = layout->comm;
713011b1c65SJames Wright   PetscMPIInt  rank;
714deffd5ebSksagiyam   PetscSF      sf1;
715deffd5ebSksagiyam   PetscSFNode *owners, *buffer, *iremote;
716deffd5ebSksagiyam   PetscInt    *ilocal, nleaves, N, n, i;
717011b1c65SJames Wright   PetscBool    areIndicesSame;
718deffd5ebSksagiyam 
719deffd5ebSksagiyam   PetscFunctionBegin;
7204f572ea9SToby Isaac   if (rootIndices) PetscAssertPointer(rootIndices, 3);
7214f572ea9SToby Isaac   if (rootLocalIndices) PetscAssertPointer(rootLocalIndices, 4);
7224f572ea9SToby Isaac   if (leafIndices) PetscAssertPointer(leafIndices, 7);
7234f572ea9SToby Isaac   if (leafLocalIndices) PetscAssertPointer(leafLocalIndices, 8);
7244f572ea9SToby Isaac   if (sfA) PetscAssertPointer(sfA, 10);
7254f572ea9SToby Isaac   PetscAssertPointer(sf, 11);
72608401ef6SPierre Jolivet   PetscCheck(numRootIndices >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numRootIndices (%" PetscInt_FMT ") must be non-negative", numRootIndices);
72708401ef6SPierre Jolivet   PetscCheck(numLeafIndices >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numLeafIndices (%" PetscInt_FMT ") must be non-negative", numLeafIndices);
7289566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7299566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(layout));
7309566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetSize(layout, &N));
7319566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetLocalSize(layout, &n));
732011b1c65SJames Wright   areIndicesSame = (PetscBool)(leafIndices == rootIndices);
733011b1c65SJames Wright   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &areIndicesSame, 1, MPI_C_BOOL, MPI_LAND, comm));
734011b1c65SJames Wright   PetscCheck(!areIndicesSame || numLeafIndices == numRootIndices, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "leafIndices == rootIndices, but numLeafIndices (%" PetscInt_FMT ") != numRootIndices(%" PetscInt_FMT ")", numLeafIndices, numRootIndices);
735011b1c65SJames Wright   if (PetscDefined(USE_DEBUG)) {
736011b1c65SJames Wright     PetscInt N1 = PETSC_INT_MIN;
7379371c9d4SSatish Balay     for (i = 0; i < numRootIndices; i++)
7389371c9d4SSatish Balay       if (rootIndices[i] > N1) N1 = rootIndices[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. root index (%" PetscInt_FMT ") out of layout range [0,%" PetscInt_FMT ")", N1, N);
741011b1c65SJames Wright     if (!areIndicesSame) {
7421690c2aeSBarry Smith       N1 = PETSC_INT_MIN;
7439371c9d4SSatish Balay       for (i = 0; i < numLeafIndices; i++)
7449371c9d4SSatish Balay         if (leafIndices[i] > N1) N1 = leafIndices[i];
745462c564dSBarry Smith       PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &N1, 1, MPIU_INT, MPI_MAX, comm));
74608401ef6SPierre 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);
747deffd5ebSksagiyam     }
748011b1c65SJames Wright   }
749011b1c65SJames Wright 
750deffd5ebSksagiyam   /* Reduce: owners -> buffer */
7519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &buffer));
7529566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &sf1));
7539566063dSJacob Faibussowitsch   PetscCall(PetscSFSetFromOptions(sf1));
7549566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(sf1, layout, numRootIndices, NULL, PETSC_OWN_POINTER, rootIndices));
7559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numRootIndices, &owners));
756deffd5ebSksagiyam   for (i = 0; i < numRootIndices; ++i) {
757deffd5ebSksagiyam     owners[i].rank  = rank;
758deffd5ebSksagiyam     owners[i].index = rootLocalOffset + (rootLocalIndices ? rootLocalIndices[i] : i);
759deffd5ebSksagiyam   }
760deffd5ebSksagiyam   for (i = 0; i < n; ++i) {
761deffd5ebSksagiyam     buffer[i].index = -1;
762deffd5ebSksagiyam     buffer[i].rank  = -1;
763deffd5ebSksagiyam   }
7646497c311SBarry Smith   PetscCall(PetscSFReduceBegin(sf1, MPIU_SF_NODE, owners, buffer, MPI_MAXLOC));
7656497c311SBarry Smith   PetscCall(PetscSFReduceEnd(sf1, MPIU_SF_NODE, owners, buffer, MPI_MAXLOC));
766deffd5ebSksagiyam   /* Bcast: buffer -> owners */
767011b1c65SJames Wright   if (!areIndicesSame) {
7689566063dSJacob Faibussowitsch     PetscCall(PetscFree(owners));
7699566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(sf1, layout, numLeafIndices, NULL, PETSC_OWN_POINTER, leafIndices));
7709566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeafIndices, &owners));
771deffd5ebSksagiyam   }
7726497c311SBarry Smith   PetscCall(PetscSFBcastBegin(sf1, MPIU_SF_NODE, buffer, owners, MPI_REPLACE));
7736497c311SBarry Smith   PetscCall(PetscSFBcastEnd(sf1, MPIU_SF_NODE, buffer, owners, MPI_REPLACE));
77408401ef6SPierre 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]);
7759566063dSJacob Faibussowitsch   PetscCall(PetscFree(buffer));
7769371c9d4SSatish Balay   if (sfA) {
7779371c9d4SSatish Balay     *sfA = sf1;
7789371c9d4SSatish Balay   } else PetscCall(PetscSFDestroy(&sf1));
779deffd5ebSksagiyam   /* Create sf */
780011b1c65SJames Wright   if (areIndicesSame && rootLocalIndices == leafLocalIndices && leafLocalOffset == rootLocalOffset) {
781deffd5ebSksagiyam     /* leaf space == root space */
7829371c9d4SSatish Balay     for (i = 0, nleaves = 0; i < numLeafIndices; ++i)
7839371c9d4SSatish Balay       if (owners[i].rank != rank) ++nleaves;
7849566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &ilocal));
7859566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &iremote));
786deffd5ebSksagiyam     for (i = 0, nleaves = 0; i < numLeafIndices; ++i) {
787deffd5ebSksagiyam       if (owners[i].rank != rank) {
788deffd5ebSksagiyam         ilocal[nleaves]        = leafLocalOffset + i;
789deffd5ebSksagiyam         iremote[nleaves].rank  = owners[i].rank;
790deffd5ebSksagiyam         iremote[nleaves].index = owners[i].index;
791deffd5ebSksagiyam         ++nleaves;
792deffd5ebSksagiyam       }
793deffd5ebSksagiyam     }
7949566063dSJacob Faibussowitsch     PetscCall(PetscFree(owners));
795deffd5ebSksagiyam   } else {
796deffd5ebSksagiyam     nleaves = numLeafIndices;
7979566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &ilocal));
798ad540459SPierre Jolivet     for (i = 0; i < nleaves; ++i) ilocal[i] = leafLocalOffset + (leafLocalIndices ? leafLocalIndices[i] : i);
799deffd5ebSksagiyam     iremote = owners;
800deffd5ebSksagiyam   }
8019566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, sf));
8029566063dSJacob Faibussowitsch   PetscCall(PetscSFSetFromOptions(*sf));
8039566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sf, rootLocalOffset + numRootIndices, nleaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
8043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
805deffd5ebSksagiyam }
806fbc7033fSJed Brown 
807fbc7033fSJed Brown /*@
80853c0d4aeSBarry Smith   PetscSFMerge - append/merge indices of `sfb` into `sfa`, with preference for `sfb`
809fbc7033fSJed Brown 
810fbc7033fSJed Brown   Collective
811fbc7033fSJed Brown 
81238b5cf2dSJacob Faibussowitsch   Input Parameters:
813fbc7033fSJed Brown + sfa - default `PetscSF`
8142f04c522SBarry Smith - sfb - additional edges to add/replace edges in `sfa`
815fbc7033fSJed Brown 
81638b5cf2dSJacob Faibussowitsch   Output Parameter:
817fbc7033fSJed Brown . merged - new `PetscSF` with combined edges
818fbc7033fSJed Brown 
81953c0d4aeSBarry Smith   Level: intermediate
82053c0d4aeSBarry Smith 
8212f04c522SBarry Smith .seealso: [](sec_petscsf), `PetscSF`, `PetscSFCompose()`
822fbc7033fSJed Brown @*/
823fbc7033fSJed Brown PetscErrorCode PetscSFMerge(PetscSF sfa, PetscSF sfb, PetscSF *merged)
824fbc7033fSJed Brown {
825fbc7033fSJed Brown   PetscInt maxleaf;
826fbc7033fSJed Brown 
827fbc7033fSJed Brown   PetscFunctionBegin;
828fbc7033fSJed Brown   PetscValidHeaderSpecific(sfa, PETSCSF_CLASSID, 1);
829fbc7033fSJed Brown   PetscValidHeaderSpecific(sfb, PETSCSF_CLASSID, 2);
830fbc7033fSJed Brown   PetscCheckSameComm(sfa, 1, sfb, 2);
8314f572ea9SToby Isaac   PetscAssertPointer(merged, 3);
832fbc7033fSJed Brown   {
833fbc7033fSJed Brown     PetscInt aleaf, bleaf;
834fbc7033fSJed Brown     PetscCall(PetscSFGetLeafRange(sfa, NULL, &aleaf));
835fbc7033fSJed Brown     PetscCall(PetscSFGetLeafRange(sfb, NULL, &bleaf));
836fbc7033fSJed Brown     maxleaf = PetscMax(aleaf, bleaf) + 1; // One more than the last index
837fbc7033fSJed Brown   }
838fbc7033fSJed Brown   PetscInt          *clocal, aroots, aleaves, broots, bleaves;
839fbc7033fSJed Brown   PetscSFNode       *cremote;
840fbc7033fSJed Brown   const PetscInt    *alocal, *blocal;
841fbc7033fSJed Brown   const PetscSFNode *aremote, *bremote;
842fbc7033fSJed Brown   PetscCall(PetscMalloc2(maxleaf, &clocal, maxleaf, &cremote));
843fbc7033fSJed Brown   for (PetscInt i = 0; i < maxleaf; i++) clocal[i] = -1;
844fbc7033fSJed Brown   PetscCall(PetscSFGetGraph(sfa, &aroots, &aleaves, &alocal, &aremote));
845fbc7033fSJed Brown   PetscCall(PetscSFGetGraph(sfb, &broots, &bleaves, &blocal, &bremote));
846fbc7033fSJed Brown   PetscCheck(aroots == broots, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Both sfa and sfb must have the same root space");
847fbc7033fSJed Brown   for (PetscInt i = 0; i < aleaves; i++) {
848fbc7033fSJed Brown     PetscInt a = alocal ? alocal[i] : i;
849fbc7033fSJed Brown     clocal[a]  = a;
850fbc7033fSJed Brown     cremote[a] = aremote[i];
851fbc7033fSJed Brown   }
852fbc7033fSJed Brown   for (PetscInt i = 0; i < bleaves; i++) {
853fbc7033fSJed Brown     PetscInt b = blocal ? blocal[i] : i;
854fbc7033fSJed Brown     clocal[b]  = b;
855fbc7033fSJed Brown     cremote[b] = bremote[i];
856fbc7033fSJed Brown   }
857fbc7033fSJed Brown   PetscInt nleaves = 0;
858fbc7033fSJed Brown   for (PetscInt i = 0; i < maxleaf; i++) {
859fbc7033fSJed Brown     if (clocal[i] < 0) continue;
860fbc7033fSJed Brown     clocal[nleaves]  = clocal[i];
861fbc7033fSJed Brown     cremote[nleaves] = cremote[i];
862fbc7033fSJed Brown     nleaves++;
863fbc7033fSJed Brown   }
864fbc7033fSJed Brown   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)sfa), merged));
865fbc7033fSJed Brown   PetscCall(PetscSFSetGraph(*merged, aroots, nleaves, clocal, PETSC_COPY_VALUES, cremote, PETSC_COPY_VALUES));
866fbc7033fSJed Brown   PetscCall(PetscFree2(clocal, cremote));
8673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
868fbc7033fSJed Brown }
8690dd791a8SStefano Zampini 
8700dd791a8SStefano Zampini /*@
8710dd791a8SStefano Zampini   PetscSFCreateStridedSF - Create an `PetscSF` to communicate interleaved blocks of data
8720dd791a8SStefano Zampini 
8730dd791a8SStefano Zampini   Collective
8740dd791a8SStefano Zampini 
8750dd791a8SStefano Zampini   Input Parameters:
8760dd791a8SStefano Zampini + sf  - star forest
8770dd791a8SStefano Zampini . bs  - stride
8780dd791a8SStefano Zampini . ldr - leading dimension of root space
8790dd791a8SStefano Zampini - ldl - leading dimension of leaf space
8800dd791a8SStefano Zampini 
8810dd791a8SStefano Zampini   Output Parameter:
8820dd791a8SStefano Zampini . vsf - the new `PetscSF`
8830dd791a8SStefano Zampini 
8840dd791a8SStefano Zampini   Level: intermediate
8850dd791a8SStefano Zampini 
8860dd791a8SStefano Zampini   Notes:
8872f04c522SBarry Smith   This can be useful to perform communications on multiple right-hand sides stored in a Fortran-style two dimensional array.
8882f04c522SBarry Smith   For example, the calling sequence
8890dd791a8SStefano Zampini .vb
8900dd791a8SStefano Zampini   c_datatype *roots, *leaves;
8910dd791a8SStefano Zampini   for i in [0,bs) do
8920dd791a8SStefano Zampini     PetscSFBcastBegin(sf, mpi_datatype, roots + i*ldr, leaves + i*ldl, op)
8930dd791a8SStefano Zampini     PetscSFBcastEnd(sf, mpi_datatype, roots + i*ldr, leaves + i*ldl, op)
8940dd791a8SStefano Zampini .ve
8950dd791a8SStefano Zampini   is equivalent to
8960dd791a8SStefano Zampini .vb
8970dd791a8SStefano Zampini   c_datatype *roots, *leaves;
8980dd791a8SStefano Zampini   PetscSFCreateStridedSF(sf, bs, ldr, ldl, &vsf)
8990dd791a8SStefano Zampini   PetscSFBcastBegin(vsf, mpi_datatype, roots, leaves, op)
9000dd791a8SStefano Zampini   PetscSFBcastEnd(vsf, mpi_datatype, roots, leaves, op)
9010dd791a8SStefano Zampini .ve
9020dd791a8SStefano Zampini 
9030dd791a8SStefano Zampini   Developer Notes:
9040dd791a8SStefano Zampini   Should this functionality be handled with a new API instead of creating a new object?
9050dd791a8SStefano Zampini 
9062f04c522SBarry Smith .seealso: [](sec_petscsf), `PetscSF`, `PetscSFCreate()`, `PetscSFSetGraph()`
9070dd791a8SStefano Zampini @*/
9080dd791a8SStefano Zampini PetscErrorCode PetscSFCreateStridedSF(PetscSF sf, PetscInt bs, PetscInt ldr, PetscInt ldl, PetscSF *vsf)
9090dd791a8SStefano Zampini {
9100dd791a8SStefano Zampini   PetscSF            rankssf;
9110dd791a8SStefano Zampini   const PetscSFNode *iremote, *sfrremote;
9120dd791a8SStefano Zampini   PetscSFNode       *viremote;
9130dd791a8SStefano Zampini   const PetscInt    *ilocal;
9140dd791a8SStefano Zampini   PetscInt          *vilocal = NULL, *ldrs;
9150dd791a8SStefano Zampini   PetscInt           nranks, nr, nl, vnr, vnl, maxl;
9160dd791a8SStefano Zampini   PetscMPIInt        rank;
9170dd791a8SStefano Zampini   MPI_Comm           comm;
9180dd791a8SStefano Zampini   PetscSFType        sftype;
9190dd791a8SStefano Zampini 
9200dd791a8SStefano Zampini   PetscFunctionBegin;
9210dd791a8SStefano Zampini   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
9220dd791a8SStefano Zampini   PetscValidLogicalCollectiveInt(sf, bs, 2);
9230dd791a8SStefano Zampini   PetscAssertPointer(vsf, 5);
9240dd791a8SStefano Zampini   if (bs == 1) {
9250dd791a8SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)sf));
9260dd791a8SStefano Zampini     *vsf = sf;
9270dd791a8SStefano Zampini     PetscFunctionReturn(PETSC_SUCCESS);
9280dd791a8SStefano Zampini   }
9290dd791a8SStefano Zampini   PetscCall(PetscSFSetUp(sf));
9300dd791a8SStefano Zampini   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
9310dd791a8SStefano Zampini   PetscCallMPI(MPI_Comm_rank(comm, &rank));
9320dd791a8SStefano Zampini   PetscCall(PetscSFGetGraph(sf, &nr, &nl, &ilocal, &iremote));
9330dd791a8SStefano Zampini   PetscCall(PetscSFGetLeafRange(sf, NULL, &maxl));
9340dd791a8SStefano Zampini   maxl += 1;
9350dd791a8SStefano Zampini   if (ldl == PETSC_DECIDE) ldl = maxl;
9360dd791a8SStefano Zampini   if (ldr == PETSC_DECIDE) ldr = nr;
9370dd791a8SStefano 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);
9380dd791a8SStefano 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);
9390dd791a8SStefano Zampini   vnr = nr * bs;
9400dd791a8SStefano Zampini   vnl = nl * bs;
9410dd791a8SStefano Zampini   PetscCall(PetscMalloc1(vnl, &viremote));
9420dd791a8SStefano Zampini   PetscCall(PetscMalloc1(vnl, &vilocal));
9430dd791a8SStefano Zampini 
9440dd791a8SStefano Zampini   /* Communicate root leading dimensions to leaf ranks */
9450dd791a8SStefano Zampini   PetscCall(PetscSFGetRanksSF(sf, &rankssf));
9460dd791a8SStefano Zampini   PetscCall(PetscSFGetGraph(rankssf, NULL, &nranks, NULL, &sfrremote));
9470dd791a8SStefano Zampini   PetscCall(PetscMalloc1(nranks, &ldrs));
9480dd791a8SStefano Zampini   PetscCall(PetscSFBcastBegin(rankssf, MPIU_INT, &ldr, ldrs, MPI_REPLACE));
9490dd791a8SStefano Zampini   PetscCall(PetscSFBcastEnd(rankssf, MPIU_INT, &ldr, ldrs, MPI_REPLACE));
9500dd791a8SStefano Zampini 
9510dd791a8SStefano Zampini   for (PetscInt i = 0, rold = -1, lda = -1; i < nl; i++) {
952835f2295SStefano Zampini     const PetscInt r  = iremote[i].rank;
9530dd791a8SStefano Zampini     const PetscInt ii = iremote[i].index;
9540dd791a8SStefano Zampini 
9550dd791a8SStefano Zampini     if (r == rank) lda = ldr;
9560dd791a8SStefano Zampini     else if (rold != r) {
9570dd791a8SStefano Zampini       PetscInt j;
9580dd791a8SStefano Zampini 
9590dd791a8SStefano Zampini       for (j = 0; j < nranks; j++)
9600dd791a8SStefano Zampini         if (sfrremote[j].rank == r) break;
961835f2295SStefano Zampini       PetscCheck(j < nranks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unable to locate neighbor rank %" PetscInt_FMT, r);
9620dd791a8SStefano Zampini       lda = ldrs[j];
9630dd791a8SStefano Zampini     }
9640dd791a8SStefano Zampini     rold = r;
9650dd791a8SStefano Zampini     for (PetscInt v = 0; v < bs; v++) {
9660dd791a8SStefano Zampini       viremote[v * nl + i].rank  = r;
9670dd791a8SStefano Zampini       viremote[v * nl + i].index = v * lda + ii;
9680dd791a8SStefano Zampini       vilocal[v * nl + i]        = v * ldl + (ilocal ? ilocal[i] : i);
9690dd791a8SStefano Zampini     }
9700dd791a8SStefano Zampini   }
9710dd791a8SStefano Zampini   PetscCall(PetscFree(ldrs));
9720dd791a8SStefano Zampini   PetscCall(PetscSFCreate(comm, vsf));
9730dd791a8SStefano Zampini   PetscCall(PetscSFGetType(sf, &sftype));
9740dd791a8SStefano Zampini   PetscCall(PetscSFSetType(*vsf, sftype));
9750dd791a8SStefano Zampini   PetscCall(PetscSFSetGraph(*vsf, vnr, vnl, vilocal, PETSC_OWN_POINTER, viremote, PETSC_OWN_POINTER));
9760dd791a8SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
9770dd791a8SStefano Zampini }
978