xref: /petsc/src/vec/is/sf/utils/sfutils.c (revision 4a2ec8787519e435f4a956e15037fe883e0879c6)
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 @*/
PetscSFSetGraphLayout(PetscSF sf,PetscLayout layout,PetscInt nleaves,PetscInt ilocal[],PetscCopyMode localmode,const PetscInt gremote[])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);
3918aa8208SJames Wright   PetscAssertPointer(layout, 2);
4018aa8208SJames Wright   if (nleaves > 0 && ilocal) PetscAssertPointer(ilocal, 4);
4118aa8208SJames Wright   if (nleaves > 0) PetscAssertPointer(gremote, 6);
42b114984aSVaclav Hapla   PetscCall(PetscLayoutSetUp(layout));
439566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetLocalSize(layout, &nroots));
449566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRanges(layout, &range));
459566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nleaves, &remote));
46eb58282aSVaclav Hapla   if (nleaves) ls = gremote[0] + 1;
47b0c7db22SLisandro Dalcin   for (i = 0; i < nleaves; i++) {
48eb58282aSVaclav Hapla     const PetscInt idx = gremote[i] - ls;
4938a25198SStefano Zampini     if (idx < 0 || idx >= ln) { /* short-circuit the search */
50eb58282aSVaclav Hapla       PetscCall(PetscLayoutFindOwnerIndex(layout, gremote[i], &lr, &remote[i].index));
5138a25198SStefano Zampini       remote[i].rank = lr;
5238a25198SStefano Zampini       ls             = range[lr];
5338a25198SStefano Zampini       ln             = range[lr + 1] - ls;
5438a25198SStefano Zampini     } else {
5538a25198SStefano Zampini       remote[i].rank  = lr;
5638a25198SStefano Zampini       remote[i].index = idx;
5738a25198SStefano Zampini     }
58b0c7db22SLisandro Dalcin   }
599566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, nroots, nleaves, ilocal, localmode, remote, PETSC_OWN_POINTER));
603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
61b0c7db22SLisandro Dalcin }
62b0c7db22SLisandro Dalcin 
63eb58282aSVaclav Hapla /*@C
642f04c522SBarry Smith   PetscSFGetGraphLayout - Get the global indices and `PetscLayout` that describe a `PetscSF`
65eb58282aSVaclav Hapla 
66eb58282aSVaclav Hapla   Collective
67eb58282aSVaclav Hapla 
68eb58282aSVaclav Hapla   Input Parameter:
69eb58282aSVaclav Hapla . sf - star forest
70eb58282aSVaclav Hapla 
71eb58282aSVaclav Hapla   Output Parameters:
72cab54364SBarry Smith + layout  - `PetscLayout` defining the global space for roots
73eb58282aSVaclav Hapla . nleaves - number of leaf vertices on the current process, each of these references a root on any process
74f13dfd9eSBarry Smith . ilocal  - locations of leaves in leafdata buffers, or `NULL` for contiguous storage
752f04c522SBarry Smith - gremote - root vertices in global numbering corresponding to the leaves
76eb58282aSVaclav Hapla 
77eb58282aSVaclav Hapla   Level: intermediate
78eb58282aSVaclav Hapla 
79eb58282aSVaclav Hapla   Notes:
80eb58282aSVaclav Hapla   The outputs are such that passing them as inputs to `PetscSFSetGraphLayout()` would lead to the same star forest.
81f13dfd9eSBarry Smith   The outputs `layout` and `gremote` are freshly created each time this function is called,
82f13dfd9eSBarry Smith   so they need to be freed (with `PetscLayoutDestroy()` and `PetscFree()`) by the user.
83eb58282aSVaclav Hapla 
842f04c522SBarry Smith .seealso: [](sec_petscsf), `PetscSF`, `PetscSFSetGraphLayout()`, `PetscSFCreate()`, `PetscSFView()`, `PetscSFSetGraph()`, `PetscSFGetGraph()`
85eb58282aSVaclav Hapla @*/
PetscSFGetGraphLayout(PetscSF sf,PetscLayout * layout,PetscInt * nleaves,const PetscInt * ilocal[],PetscInt * gremote[])86d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFGetGraphLayout(PetscSF sf, PetscLayout *layout, PetscInt *nleaves, const PetscInt *ilocal[], PetscInt *gremote[])
87d71ae5a4SJacob Faibussowitsch {
88eb58282aSVaclav Hapla   PetscInt           nr, nl;
89eb58282aSVaclav Hapla   const PetscSFNode *ir;
90eb58282aSVaclav Hapla   PetscLayout        lt;
91eb58282aSVaclav Hapla 
92eb58282aSVaclav Hapla   PetscFunctionBegin;
9318aa8208SJames Wright   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
9418aa8208SJames Wright   if (layout) PetscAssertPointer(layout, 2);
9518aa8208SJames Wright   if (nleaves) PetscAssertPointer(nleaves, 3);
9618aa8208SJames Wright   if (ilocal) PetscAssertPointer(ilocal, 4);
9718aa8208SJames Wright   if (gremote) PetscAssertPointer(gremote, 5);
98eb58282aSVaclav Hapla   PetscCall(PetscSFGetGraph(sf, &nr, &nl, ilocal, &ir));
99eb58282aSVaclav Hapla   PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)sf), nr, PETSC_DECIDE, 1, &lt));
100eb58282aSVaclav Hapla   if (gremote) {
101eb58282aSVaclav Hapla     PetscInt        i;
102eb58282aSVaclav Hapla     const PetscInt *range;
103eb58282aSVaclav Hapla     PetscInt       *gr;
104eb58282aSVaclav Hapla 
105eb58282aSVaclav Hapla     PetscCall(PetscLayoutGetRanges(lt, &range));
106eb58282aSVaclav Hapla     PetscCall(PetscMalloc1(nl, &gr));
107eb58282aSVaclav Hapla     for (i = 0; i < nl; i++) gr[i] = range[ir[i].rank] + ir[i].index;
108eb58282aSVaclav Hapla     *gremote = gr;
109eb58282aSVaclav Hapla   }
110eb58282aSVaclav Hapla   if (nleaves) *nleaves = nl;
111eb58282aSVaclav Hapla   if (layout) *layout = lt;
112eb58282aSVaclav Hapla   else PetscCall(PetscLayoutDestroy(&lt));
1133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
114eb58282aSVaclav Hapla }
115eb58282aSVaclav Hapla 
116b0c7db22SLisandro Dalcin /*@
1172f04c522SBarry Smith   PetscSFSetGraphSection - Sets the `PetscSF` graph (communication pattern) encoding the parallel dof overlap based upon the `PetscSection` describing the data layout.
118b0c7db22SLisandro Dalcin 
119b0c7db22SLisandro Dalcin   Input Parameters:
120cab54364SBarry Smith + sf            - The `PetscSF`
121cab54364SBarry Smith . localSection  - `PetscSection` describing the local data layout
122cab54364SBarry Smith - globalSection - `PetscSection` describing the global data layout
123b0c7db22SLisandro Dalcin 
124b0c7db22SLisandro Dalcin   Level: developer
125b0c7db22SLisandro Dalcin 
1262f04c522SBarry Smith .seealso: [](sec_petscsf), `PetscSF`, `PetscSFSetGraph()`, `PetscSFSetGraphLayout()`
127b0c7db22SLisandro Dalcin @*/
PetscSFSetGraphSection(PetscSF sf,PetscSection localSection,PetscSection globalSection)128d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFSetGraphSection(PetscSF sf, PetscSection localSection, PetscSection globalSection)
129d71ae5a4SJacob Faibussowitsch {
130b0c7db22SLisandro Dalcin   MPI_Comm        comm;
131b0c7db22SLisandro Dalcin   PetscLayout     layout;
132b0c7db22SLisandro Dalcin   const PetscInt *ranges;
133b0c7db22SLisandro Dalcin   PetscInt       *local;
134b0c7db22SLisandro Dalcin   PetscSFNode    *remote;
135b0c7db22SLisandro Dalcin   PetscInt        pStart, pEnd, p, nroots, nleaves = 0, l;
136b0c7db22SLisandro Dalcin   PetscMPIInt     size, rank;
137b0c7db22SLisandro Dalcin 
138b0c7db22SLisandro Dalcin   PetscFunctionBegin;
139b0c7db22SLisandro Dalcin   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
140b0c7db22SLisandro Dalcin   PetscValidHeaderSpecific(localSection, PETSC_SECTION_CLASSID, 2);
141b0c7db22SLisandro Dalcin   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
142b0c7db22SLisandro Dalcin 
1439566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
1449566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
1459566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd));
1479566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots));
1489566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &layout));
1499566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(layout, 1));
1509566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(layout, nroots));
1519566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(layout));
1529566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRanges(layout, &ranges));
153b0c7db22SLisandro Dalcin   for (p = pStart; p < pEnd; ++p) {
154b0c7db22SLisandro Dalcin     PetscInt gdof, gcdof;
155b0c7db22SLisandro Dalcin 
1569566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
1579566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
15857508eceSPierre 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);
159b0c7db22SLisandro Dalcin     nleaves += gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
160b0c7db22SLisandro Dalcin   }
1619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nleaves, &local));
1629566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nleaves, &remote));
163b0c7db22SLisandro Dalcin   for (p = pStart, l = 0; p < pEnd; ++p) {
164b0c7db22SLisandro Dalcin     const PetscInt *cind;
165b0c7db22SLisandro Dalcin     PetscInt        dof, cdof, off, gdof, gcdof, goff, gsize, d, c;
166b0c7db22SLisandro Dalcin 
1679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(localSection, p, &dof));
1689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(localSection, p, &off));
1699566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof));
1709566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(localSection, p, &cind));
1719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
1729566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
1739566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalSection, p, &goff));
174b0c7db22SLisandro Dalcin     if (!gdof) continue; /* Censored point */
175b0c7db22SLisandro Dalcin     gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
176b0c7db22SLisandro Dalcin     if (gsize != dof - cdof) {
17708401ef6SPierre 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);
178b0c7db22SLisandro Dalcin       cdof = 0; /* Ignore constraints */
179b0c7db22SLisandro Dalcin     }
180b0c7db22SLisandro Dalcin     for (d = 0, c = 0; d < dof; ++d) {
1819371c9d4SSatish Balay       if ((c < cdof) && (cind[c] == d)) {
1829371c9d4SSatish Balay         ++c;
1839371c9d4SSatish Balay         continue;
1849371c9d4SSatish Balay       }
185b0c7db22SLisandro Dalcin       local[l + d - c] = off + d;
186b0c7db22SLisandro Dalcin     }
18708401ef6SPierre 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);
188b0c7db22SLisandro Dalcin     if (gdof < 0) {
189b0c7db22SLisandro Dalcin       for (d = 0; d < gsize; ++d, ++l) {
1906497c311SBarry Smith         PetscInt    offset = -(goff + 1) + d, ir;
1916497c311SBarry Smith         PetscMPIInt r;
192b0c7db22SLisandro Dalcin 
1936497c311SBarry Smith         PetscCall(PetscFindInt(offset, size + 1, ranges, &ir));
1946497c311SBarry Smith         PetscCall(PetscMPIIntCast(ir, &r));
195b0c7db22SLisandro Dalcin         if (r < 0) r = -(r + 2);
1966497c311SBarry 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);
197b0c7db22SLisandro Dalcin         remote[l].rank  = r;
198b0c7db22SLisandro Dalcin         remote[l].index = offset - ranges[r];
199b0c7db22SLisandro Dalcin       }
200b0c7db22SLisandro Dalcin     } else {
201b0c7db22SLisandro Dalcin       for (d = 0; d < gsize; ++d, ++l) {
202b0c7db22SLisandro Dalcin         remote[l].rank  = rank;
203b0c7db22SLisandro Dalcin         remote[l].index = goff + d - ranges[rank];
204b0c7db22SLisandro Dalcin       }
205b0c7db22SLisandro Dalcin     }
206b0c7db22SLisandro Dalcin   }
20708401ef6SPierre Jolivet   PetscCheck(l == nleaves, comm, PETSC_ERR_PLIB, "Iteration error, l %" PetscInt_FMT " != nleaves %" PetscInt_FMT, l, nleaves);
2089566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&layout));
2099566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER));
2103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
211b0c7db22SLisandro Dalcin }
212b0c7db22SLisandro Dalcin 
213b0c7db22SLisandro Dalcin /*@C
214cab54364SBarry Smith   PetscSFDistributeSection - Create a new `PetscSection` reorganized, moving from the root to the leaves of the `PetscSF`
215b0c7db22SLisandro Dalcin 
216c3339decSBarry Smith   Collective
217b0c7db22SLisandro Dalcin 
218b0c7db22SLisandro Dalcin   Input Parameters:
219cab54364SBarry Smith + sf          - The `PetscSF`
220b0c7db22SLisandro Dalcin - rootSection - Section defined on root space
221b0c7db22SLisandro Dalcin 
222b0c7db22SLisandro Dalcin   Output Parameters:
223ce78bad3SBarry Smith + remoteOffsets - root offsets in leaf storage, or `NULL`, its length will be the size of the chart of `leafSection`
224b0c7db22SLisandro Dalcin - leafSection   - Section defined on the leaf space
225b0c7db22SLisandro Dalcin 
226b0c7db22SLisandro Dalcin   Level: advanced
227b0c7db22SLisandro Dalcin 
228ce78bad3SBarry Smith   Note:
229ce78bad3SBarry Smith   Caller must `PetscFree()` `remoteOffsets` if it was requested
230ce78bad3SBarry Smith 
2316964b6c7SJames Wright   To distribute data from the `rootSection` to the `leafSection`, see  `PetscSFCreateSectionSF()` or `PetscSectionMigrateData()`.
2326964b6c7SJames Wright 
233ce78bad3SBarry Smith   Fortran Note:
234ce78bad3SBarry Smith   Use `PetscSFDestroyRemoteOffsets()` when `remoteOffsets` is no longer needed.
23523e9620eSJunchao Zhang 
2366964b6c7SJames Wright .seealso: [](sec_petscsf), `PetscSF`, `PetscSFCreate()`, `PetscSFCreateSectionSF()`
237b0c7db22SLisandro Dalcin @*/
PetscSFDistributeSection(PetscSF sf,PetscSection rootSection,PetscInt * remoteOffsets[],PetscSection leafSection)238ce78bad3SBarry Smith PetscErrorCode PetscSFDistributeSection(PetscSF sf, PetscSection rootSection, PetscInt *remoteOffsets[], PetscSection leafSection)
239d71ae5a4SJacob Faibussowitsch {
240b0c7db22SLisandro Dalcin   PetscSF         embedSF;
241b0c7db22SLisandro Dalcin   const PetscInt *indices;
242b0c7db22SLisandro Dalcin   IS              selected;
2431690c2aeSBarry Smith   PetscInt        numFields, nroots, rpStart, rpEnd, lpStart = PETSC_INT_MAX, lpEnd = -1, f, c;
244b0c7db22SLisandro Dalcin   PetscBool      *sub, hasc;
245b0c7db22SLisandro Dalcin 
246b0c7db22SLisandro Dalcin   PetscFunctionBegin;
24718aa8208SJames Wright   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
24818aa8208SJames Wright   PetscValidHeaderSpecific(rootSection, PETSC_SECTION_CLASSID, 2);
24918aa8208SJames Wright   if (remoteOffsets) PetscAssertPointer(remoteOffsets, 3);
25018aa8208SJames Wright   PetscValidHeaderSpecific(leafSection, PETSC_SECTION_CLASSID, 4);
2519566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_DistSect, sf, 0, 0, 0));
2529566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(rootSection, &numFields));
253029e8818Sksagiyam   if (numFields) {
254029e8818Sksagiyam     IS perm;
255029e8818Sksagiyam 
256029e8818Sksagiyam     /* PetscSectionSetNumFields() calls PetscSectionReset(), which destroys
257029e8818Sksagiyam        leafSection->perm. To keep this permutation set by the user, we grab
258029e8818Sksagiyam        the reference before calling PetscSectionSetNumFields() and set it
259029e8818Sksagiyam        back after. */
2609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPermutation(leafSection, &perm));
2619566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)perm));
2629566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(leafSection, numFields));
2639566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetPermutation(leafSection, perm));
2649566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&perm));
265029e8818Sksagiyam   }
2669566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numFields + 2, &sub));
267b0c7db22SLisandro Dalcin   sub[1] = rootSection->bc ? PETSC_TRUE : PETSC_FALSE;
268b0c7db22SLisandro Dalcin   for (f = 0; f < numFields; ++f) {
2692ee82556SMatthew G. Knepley     PetscSectionSym sym, dsym = NULL;
270b0c7db22SLisandro Dalcin     const char     *name    = NULL;
271b0c7db22SLisandro Dalcin     PetscInt        numComp = 0;
272b0c7db22SLisandro Dalcin 
273b0c7db22SLisandro Dalcin     sub[2 + f] = rootSection->field[f]->bc ? PETSC_TRUE : PETSC_FALSE;
2749566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldComponents(rootSection, f, &numComp));
2759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldName(rootSection, f, &name));
2769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldSym(rootSection, f, &sym));
2779566063dSJacob Faibussowitsch     if (sym) PetscCall(PetscSectionSymDistribute(sym, sf, &dsym));
2789566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldComponents(leafSection, f, numComp));
2799566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldName(leafSection, f, name));
2809566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldSym(leafSection, f, dsym));
2819566063dSJacob Faibussowitsch     PetscCall(PetscSectionSymDestroy(&dsym));
282b0c7db22SLisandro Dalcin     for (c = 0; c < rootSection->numFieldComponents[f]; ++c) {
2839566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetComponentName(rootSection, f, c, &name));
2849566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetComponentName(leafSection, f, c, name));
285b0c7db22SLisandro Dalcin     }
286b0c7db22SLisandro Dalcin   }
2879566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(rootSection, &rpStart, &rpEnd));
2889566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
289b0c7db22SLisandro Dalcin   rpEnd = PetscMin(rpEnd, nroots);
290b0c7db22SLisandro Dalcin   rpEnd = PetscMax(rpStart, rpEnd);
291b0c7db22SLisandro Dalcin   /* see if we can avoid creating the embedded SF, since it can cost more than an allreduce */
292b0c7db22SLisandro Dalcin   sub[0] = (PetscBool)(nroots != rpEnd - rpStart);
2935440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, sub, 2 + numFields, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)sf)));
294b0c7db22SLisandro Dalcin   if (sub[0]) {
2959566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, rpEnd - rpStart, rpStart, 1, &selected));
2969566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(selected, &indices));
2979566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedRootSF(sf, rpEnd - rpStart, indices, &embedSF));
2989566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(selected, &indices));
2999566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&selected));
300b0c7db22SLisandro Dalcin   } else {
3019566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)sf));
302b0c7db22SLisandro Dalcin     embedSF = sf;
303b0c7db22SLisandro Dalcin   }
3049566063dSJacob Faibussowitsch   PetscCall(PetscSFGetLeafRange(embedSF, &lpStart, &lpEnd));
305b0c7db22SLisandro Dalcin   lpEnd++;
306b0c7db22SLisandro Dalcin 
3079566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(leafSection, lpStart, lpEnd));
308b0c7db22SLisandro Dalcin 
309b0c7db22SLisandro Dalcin   /* Constrained dof section */
310b0c7db22SLisandro Dalcin   hasc = sub[1];
311b0c7db22SLisandro Dalcin   for (f = 0; f < numFields; ++f) hasc = (PetscBool)(hasc || sub[2 + f]);
312b0c7db22SLisandro Dalcin 
313b0c7db22SLisandro Dalcin   /* Could fuse these at the cost of copies and extra allocation */
31416cd844bSPierre Jolivet   PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasDof, -rpStart), PetscSafePointerPlusOffset(leafSection->atlasDof, -lpStart), MPI_REPLACE));
31516cd844bSPierre Jolivet   PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasDof, -rpStart), PetscSafePointerPlusOffset(leafSection->atlasDof, -lpStart), MPI_REPLACE));
316b0c7db22SLisandro Dalcin   if (sub[1]) {
3177c0883d5SVaclav Hapla     PetscCall(PetscSectionCheckConstraints_Private(rootSection));
3187c0883d5SVaclav Hapla     PetscCall(PetscSectionCheckConstraints_Private(leafSection));
3199566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->bc->atlasDof[-rpStart], &leafSection->bc->atlasDof[-lpStart], MPI_REPLACE));
3209566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->bc->atlasDof[-rpStart], &leafSection->bc->atlasDof[-lpStart], MPI_REPLACE));
321b0c7db22SLisandro Dalcin   }
322b0c7db22SLisandro Dalcin   for (f = 0; f < numFields; ++f) {
32316cd844bSPierre Jolivet     PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->field[f]->atlasDof, -rpStart), PetscSafePointerPlusOffset(leafSection->field[f]->atlasDof, -lpStart), MPI_REPLACE));
32416cd844bSPierre Jolivet     PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->field[f]->atlasDof, -rpStart), PetscSafePointerPlusOffset(leafSection->field[f]->atlasDof, -lpStart), MPI_REPLACE));
325b0c7db22SLisandro Dalcin     if (sub[2 + f]) {
3267c0883d5SVaclav Hapla       PetscCall(PetscSectionCheckConstraints_Private(rootSection->field[f]));
3277c0883d5SVaclav Hapla       PetscCall(PetscSectionCheckConstraints_Private(leafSection->field[f]));
3289566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasDof[-rpStart], &leafSection->field[f]->bc->atlasDof[-lpStart], MPI_REPLACE));
3299566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasDof[-rpStart], &leafSection->field[f]->bc->atlasDof[-lpStart], MPI_REPLACE));
330b0c7db22SLisandro Dalcin     }
331b0c7db22SLisandro Dalcin   }
332b0c7db22SLisandro Dalcin   if (remoteOffsets) {
3339566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(lpEnd - lpStart, remoteOffsets));
33416cd844bSPierre Jolivet     PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasOff, -rpStart), PetscSafePointerPlusOffset(*remoteOffsets, -lpStart), MPI_REPLACE));
33516cd844bSPierre Jolivet     PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasOff, -rpStart), PetscSafePointerPlusOffset(*remoteOffsets, -lpStart), MPI_REPLACE));
336b0c7db22SLisandro Dalcin   }
33769c11d05SVaclav Hapla   PetscCall(PetscSectionInvalidateMaxDof_Internal(leafSection));
3389566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(leafSection));
339b0c7db22SLisandro Dalcin   if (hasc) { /* need to communicate bcIndices */
340b0c7db22SLisandro Dalcin     PetscSF   bcSF;
341b0c7db22SLisandro Dalcin     PetscInt *rOffBc;
342b0c7db22SLisandro Dalcin 
3439566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(lpEnd - lpStart, &rOffBc));
344b0c7db22SLisandro Dalcin     if (sub[1]) {
3459566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
3469566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
3479566063dSJacob Faibussowitsch       PetscCall(PetscSFCreateSectionSF(embedSF, rootSection->bc, rOffBc, leafSection->bc, &bcSF));
3489566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(bcSF, MPIU_INT, rootSection->bcIndices, leafSection->bcIndices, MPI_REPLACE));
3499566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(bcSF, MPIU_INT, rootSection->bcIndices, leafSection->bcIndices, MPI_REPLACE));
3509566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&bcSF));
351b0c7db22SLisandro Dalcin     }
352b0c7db22SLisandro Dalcin     for (f = 0; f < numFields; ++f) {
353b0c7db22SLisandro Dalcin       if (sub[2 + f]) {
3549566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
3559566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE));
3569566063dSJacob Faibussowitsch         PetscCall(PetscSFCreateSectionSF(embedSF, rootSection->field[f]->bc, rOffBc, leafSection->field[f]->bc, &bcSF));
3579566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(bcSF, MPIU_INT, rootSection->field[f]->bcIndices, leafSection->field[f]->bcIndices, MPI_REPLACE));
3589566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(bcSF, MPIU_INT, rootSection->field[f]->bcIndices, leafSection->field[f]->bcIndices, MPI_REPLACE));
3599566063dSJacob Faibussowitsch         PetscCall(PetscSFDestroy(&bcSF));
360b0c7db22SLisandro Dalcin       }
361b0c7db22SLisandro Dalcin     }
3629566063dSJacob Faibussowitsch     PetscCall(PetscFree(rOffBc));
363b0c7db22SLisandro Dalcin   }
3649566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&embedSF));
3659566063dSJacob Faibussowitsch   PetscCall(PetscFree(sub));
3669566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_DistSect, sf, 0, 0, 0));
3673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
368b0c7db22SLisandro Dalcin }
369b0c7db22SLisandro Dalcin 
370b0c7db22SLisandro Dalcin /*@C
371b0c7db22SLisandro Dalcin   PetscSFCreateRemoteOffsets - Create offsets for point data on remote processes
372b0c7db22SLisandro Dalcin 
373c3339decSBarry Smith   Collective
374b0c7db22SLisandro Dalcin 
375b0c7db22SLisandro Dalcin   Input Parameters:
376cab54364SBarry Smith + sf          - The `PetscSF`
377ce78bad3SBarry Smith . rootSection - Data layout of remote points for outgoing data (this is layout for roots)
378ce78bad3SBarry Smith - leafSection - Data layout of local points for incoming data  (this is layout for leaves)
379b0c7db22SLisandro Dalcin 
380b0c7db22SLisandro Dalcin   Output Parameter:
381ce78bad3SBarry Smith . remoteOffsets - Offsets for point data on remote processes (these are offsets from the root section), or `NULL`
382b0c7db22SLisandro Dalcin 
383b0c7db22SLisandro Dalcin   Level: developer
384b0c7db22SLisandro Dalcin 
385ce78bad3SBarry Smith   Note:
386ce78bad3SBarry Smith   Caller must `PetscFree()` `remoteOffsets` if it was requested
387ce78bad3SBarry Smith 
388ce78bad3SBarry Smith   Fortran Note:
389ce78bad3SBarry Smith   Use `PetscSFDestroyRemoteOffsets()` when `remoteOffsets` is no longer needed.
39023e9620eSJunchao Zhang 
3912f04c522SBarry Smith .seealso: [](sec_petscsf), `PetscSF`, `PetscSFCreate()`
392b0c7db22SLisandro Dalcin @*/
PetscSFCreateRemoteOffsets(PetscSF sf,PetscSection rootSection,PetscSection leafSection,PetscInt * remoteOffsets[])393ce78bad3SBarry Smith PetscErrorCode PetscSFCreateRemoteOffsets(PetscSF sf, PetscSection rootSection, PetscSection leafSection, PetscInt *remoteOffsets[])
394d71ae5a4SJacob Faibussowitsch {
395b0c7db22SLisandro Dalcin   PetscSF         embedSF;
396b0c7db22SLisandro Dalcin   const PetscInt *indices;
397b0c7db22SLisandro Dalcin   IS              selected;
398b0c7db22SLisandro Dalcin   PetscInt        numRoots, rpStart = 0, rpEnd = 0, lpStart = 0, lpEnd = 0;
399b0c7db22SLisandro Dalcin 
400b0c7db22SLisandro Dalcin   PetscFunctionBegin;
40118aa8208SJames Wright   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
40218aa8208SJames Wright   PetscValidHeaderSpecific(rootSection, PETSC_SECTION_CLASSID, 2);
40318aa8208SJames Wright   PetscValidHeaderSpecific(leafSection, PETSC_SECTION_CLASSID, 3);
40418aa8208SJames Wright   PetscAssertPointer(remoteOffsets, 4);
405b0c7db22SLisandro Dalcin   *remoteOffsets = NULL;
4069566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &numRoots, NULL, NULL, NULL));
4073ba16761SJacob Faibussowitsch   if (numRoots < 0) PetscFunctionReturn(PETSC_SUCCESS);
4089566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_RemoteOff, sf, 0, 0, 0));
4099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(rootSection, &rpStart, &rpEnd));
4109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(leafSection, &lpStart, &lpEnd));
4119566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, rpEnd - rpStart, rpStart, 1, &selected));
4129566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(selected, &indices));
4139566063dSJacob Faibussowitsch   PetscCall(PetscSFCreateEmbeddedRootSF(sf, rpEnd - rpStart, indices, &embedSF));
4149566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(selected, &indices));
4159566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&selected));
4169566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(lpEnd - lpStart, remoteOffsets));
4178e3a54c0SPierre Jolivet   PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasOff, -rpStart), PetscSafePointerPlusOffset(*remoteOffsets, -lpStart), MPI_REPLACE));
4188e3a54c0SPierre Jolivet   PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, PetscSafePointerPlusOffset(rootSection->atlasOff, -rpStart), PetscSafePointerPlusOffset(*remoteOffsets, -lpStart), MPI_REPLACE));
4199566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&embedSF));
4209566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_RemoteOff, sf, 0, 0, 0));
4213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
422b0c7db22SLisandro Dalcin }
423b0c7db22SLisandro Dalcin 
424ce78bad3SBarry Smith /*@
425cab54364SBarry Smith   PetscSFCreateSectionSF - Create an expanded `PetscSF` of dofs, assuming the input `PetscSF` relates points
426b0c7db22SLisandro Dalcin 
427c3339decSBarry Smith   Collective
428b0c7db22SLisandro Dalcin 
429b0c7db22SLisandro Dalcin   Input Parameters:
430cab54364SBarry Smith + sf            - The `PetscSF`
431b0c7db22SLisandro Dalcin . rootSection   - Data layout of remote points for outgoing data (this is usually the serial section)
4322f04c522SBarry Smith . remoteOffsets - Offsets for point data on remote processes (these are offsets from the root section), or `NULL`
433b0c7db22SLisandro Dalcin - leafSection   - Data layout of local points for incoming data  (this is the distributed section)
434b0c7db22SLisandro Dalcin 
4352fe279fdSBarry Smith   Output Parameter:
4362fe279fdSBarry Smith . sectionSF - The new `PetscSF`
437b0c7db22SLisandro Dalcin 
438b0c7db22SLisandro Dalcin   Level: advanced
439b0c7db22SLisandro Dalcin 
44023e9620eSJunchao Zhang   Notes:
4416964b6c7SJames Wright   `remoteOffsets` can be `NULL` if `sf` does not reference any points in `leafSection`
44223e9620eSJunchao Zhang 
4436964b6c7SJames Wright .seealso: [](sec_petscsf), `PetscSF`, `PetscSFCreate()`, `PetscSFDistributeSection()`
444b0c7db22SLisandro Dalcin @*/
PetscSFCreateSectionSF(PetscSF sf,PetscSection rootSection,PetscInt remoteOffsets[],PetscSection leafSection,PetscSF * sectionSF)445d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFCreateSectionSF(PetscSF sf, PetscSection rootSection, PetscInt remoteOffsets[], PetscSection leafSection, PetscSF *sectionSF)
446d71ae5a4SJacob Faibussowitsch {
447b0c7db22SLisandro Dalcin   MPI_Comm           comm;
448b0c7db22SLisandro Dalcin   const PetscInt    *localPoints;
449b0c7db22SLisandro Dalcin   const PetscSFNode *remotePoints;
450b0c7db22SLisandro Dalcin   PetscInt           lpStart, lpEnd;
451b0c7db22SLisandro Dalcin   PetscInt           numRoots, numSectionRoots, numPoints, numIndices = 0;
452b0c7db22SLisandro Dalcin   PetscInt          *localIndices;
453b0c7db22SLisandro Dalcin   PetscSFNode       *remoteIndices;
454b0c7db22SLisandro Dalcin   PetscInt           i, ind;
455b0c7db22SLisandro Dalcin 
456b0c7db22SLisandro Dalcin   PetscFunctionBegin;
457b0c7db22SLisandro Dalcin   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
4584f572ea9SToby Isaac   PetscAssertPointer(rootSection, 2);
4594f572ea9SToby Isaac   /* Cannot check PetscAssertPointer(remoteOffsets,3) because it can be NULL if sf does not reference any points in leafSection */
4604f572ea9SToby Isaac   PetscAssertPointer(leafSection, 4);
4614f572ea9SToby Isaac   PetscAssertPointer(sectionSF, 5);
4629566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
4639566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, sectionSF));
4649566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(leafSection, &lpStart, &lpEnd));
4659566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(rootSection, &numSectionRoots));
4669566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &numRoots, &numPoints, &localPoints, &remotePoints));
4673ba16761SJacob Faibussowitsch   if (numRoots < 0) PetscFunctionReturn(PETSC_SUCCESS);
4689566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_SectSF, sf, 0, 0, 0));
469b0c7db22SLisandro Dalcin   for (i = 0; i < numPoints; ++i) {
470b0c7db22SLisandro Dalcin     PetscInt localPoint = localPoints ? localPoints[i] : i;
471b0c7db22SLisandro Dalcin     PetscInt dof;
472b0c7db22SLisandro Dalcin 
473b0c7db22SLisandro Dalcin     if ((localPoint >= lpStart) && (localPoint < lpEnd)) {
4749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafSection, localPoint, &dof));
47522a18c9fSMatthew G. Knepley       numIndices += dof < 0 ? 0 : dof;
476b0c7db22SLisandro Dalcin     }
477b0c7db22SLisandro Dalcin   }
4789566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numIndices, &localIndices));
4799566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numIndices, &remoteIndices));
480b0c7db22SLisandro Dalcin   /* Create new index graph */
481b0c7db22SLisandro Dalcin   for (i = 0, ind = 0; i < numPoints; ++i) {
482b0c7db22SLisandro Dalcin     PetscInt localPoint = localPoints ? localPoints[i] : i;
483835f2295SStefano Zampini     PetscInt rank       = remotePoints[i].rank;
484b0c7db22SLisandro Dalcin 
485b0c7db22SLisandro Dalcin     if ((localPoint >= lpStart) && (localPoint < lpEnd)) {
486b0c7db22SLisandro Dalcin       PetscInt remoteOffset = remoteOffsets[localPoint - lpStart];
487b0c7db22SLisandro Dalcin       PetscInt loff, dof, d;
488b0c7db22SLisandro Dalcin 
4899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafSection, localPoint, &loff));
4909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafSection, localPoint, &dof));
491b0c7db22SLisandro Dalcin       for (d = 0; d < dof; ++d, ++ind) {
492b0c7db22SLisandro Dalcin         localIndices[ind]        = loff + d;
493b0c7db22SLisandro Dalcin         remoteIndices[ind].rank  = rank;
494b0c7db22SLisandro Dalcin         remoteIndices[ind].index = remoteOffset + d;
495b0c7db22SLisandro Dalcin       }
496b0c7db22SLisandro Dalcin     }
497b0c7db22SLisandro Dalcin   }
49808401ef6SPierre Jolivet   PetscCheck(numIndices == ind, comm, PETSC_ERR_PLIB, "Inconsistency in indices, %" PetscInt_FMT " should be %" PetscInt_FMT, ind, numIndices);
4999566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sectionSF, numSectionRoots, numIndices, localIndices, PETSC_OWN_POINTER, remoteIndices, PETSC_OWN_POINTER));
5009566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(*sectionSF));
5019566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_SectSF, sf, 0, 0, 0));
5023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
503b0c7db22SLisandro Dalcin }
5048fa9e22eSVaclav Hapla 
5058fa9e22eSVaclav Hapla /*@C
5062f04c522SBarry Smith   PetscSFCreateFromLayouts - Creates a parallel star forest mapping between two `PetscLayout` objects
5078fa9e22eSVaclav Hapla 
5088fa9e22eSVaclav Hapla   Collective
5098fa9e22eSVaclav Hapla 
5104165533cSJose E. Roman   Input Parameters:
511cab54364SBarry Smith + rmap - `PetscLayout` defining the global root space
512cab54364SBarry Smith - lmap - `PetscLayout` defining the global leaf space
5138fa9e22eSVaclav Hapla 
5144165533cSJose E. Roman   Output Parameter:
5158fa9e22eSVaclav Hapla . sf - The parallel star forest
5168fa9e22eSVaclav Hapla 
5178fa9e22eSVaclav Hapla   Level: intermediate
5188fa9e22eSVaclav Hapla 
5192f04c522SBarry Smith   Notes:
5202f04c522SBarry Smith   If the global length of `lmap` differs from the global length of `rmap` then the excess entries are ignored.
5212f04c522SBarry Smith 
5222f04c522SBarry Smith   The resulting `sf` used with `PetscSFBcastBegin()` and `PetscSFBcastEnd()` merely copies the array entries of `rootdata` to
5232f04c522SBarry Smith   `leafdata`; moving them between MPI processes if needed. For example,
5242f04c522SBarry 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
5252f04c522SBarry Smith   `leafdata` would become (1, 2) on MPI rank 0 and (3, 4, 5, x) on MPI rank 1.
5262f04c522SBarry Smith 
5272f04c522SBarry Smith .seealso: [](sec_petscsf), `PetscSF`, `PetscLayout`, `PetscSFCreate()`, `PetscSFSetGraph()`, `PetscLayoutCreate()`, `PetscSFSetGraphLayout()`
5288fa9e22eSVaclav Hapla @*/
PetscSFCreateFromLayouts(PetscLayout rmap,PetscLayout lmap,PetscSF * sf)529d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFCreateFromLayouts(PetscLayout rmap, PetscLayout lmap, PetscSF *sf)
530d71ae5a4SJacob Faibussowitsch {
5318fa9e22eSVaclav Hapla   PetscInt     i, nroots, nleaves = 0;
5328fa9e22eSVaclav Hapla   PetscInt     rN, lst, len;
5338fa9e22eSVaclav Hapla   PetscMPIInt  owner = -1;
5348fa9e22eSVaclav Hapla   PetscSFNode *remote;
5358fa9e22eSVaclav Hapla   MPI_Comm     rcomm = rmap->comm;
5368fa9e22eSVaclav Hapla   MPI_Comm     lcomm = lmap->comm;
5378fa9e22eSVaclav Hapla   PetscMPIInt  flg;
5388fa9e22eSVaclav Hapla 
5398fa9e22eSVaclav Hapla   PetscFunctionBegin;
54018aa8208SJames Wright   PetscAssertPointer(rmap, 1);
54118aa8208SJames Wright   PetscAssertPointer(lmap, 2);
5424f572ea9SToby Isaac   PetscAssertPointer(sf, 3);
54328b400f6SJacob Faibussowitsch   PetscCheck(rmap->setupcalled, rcomm, PETSC_ERR_ARG_WRONGSTATE, "Root layout not setup");
54428b400f6SJacob Faibussowitsch   PetscCheck(lmap->setupcalled, lcomm, PETSC_ERR_ARG_WRONGSTATE, "Leaf layout not setup");
5459566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_compare(rcomm, lcomm, &flg));
546c9cc58a2SBarry Smith   PetscCheck(flg == MPI_CONGRUENT || flg == MPI_IDENT, rcomm, PETSC_ERR_SUP, "cannot map two layouts with non-matching communicators");
5479566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(rcomm, sf));
5489566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetLocalSize(rmap, &nroots));
5499566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetSize(rmap, &rN));
5509566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(lmap, &lst, &len));
5519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(len - lst, &remote));
5528fa9e22eSVaclav Hapla   for (i = lst; i < len && i < rN; i++) {
55348a46eb9SPierre Jolivet     if (owner < -1 || i >= rmap->range[owner + 1]) PetscCall(PetscLayoutFindOwner(rmap, i, &owner));
5548fa9e22eSVaclav Hapla     remote[nleaves].rank  = owner;
5558fa9e22eSVaclav Hapla     remote[nleaves].index = i - rmap->range[owner];
5568fa9e22eSVaclav Hapla     nleaves++;
5578fa9e22eSVaclav Hapla   }
5589566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sf, nroots, nleaves, NULL, PETSC_OWN_POINTER, remote, PETSC_COPY_VALUES));
5599566063dSJacob Faibussowitsch   PetscCall(PetscFree(remote));
5603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5618fa9e22eSVaclav Hapla }
5628fa9e22eSVaclav Hapla 
5638fa9e22eSVaclav Hapla /* TODO: handle nooffprocentries like MatZeroRowsMapLocal_Private, since this code is the same */
PetscLayoutMapLocal(PetscLayout map,PetscInt N,const PetscInt idxs[],PetscInt * on,PetscInt * oidxs[],PetscInt * ogidxs[])564ce78bad3SBarry Smith PetscErrorCode PetscLayoutMapLocal(PetscLayout map, PetscInt N, const PetscInt idxs[], PetscInt *on, PetscInt *oidxs[], PetscInt *ogidxs[])
565d71ae5a4SJacob Faibussowitsch {
5668fa9e22eSVaclav Hapla   PetscInt    *owners = map->range;
5678fa9e22eSVaclav Hapla   PetscInt     n      = map->n;
5688fa9e22eSVaclav Hapla   PetscSF      sf;
569d61846d3SStefano Zampini   PetscInt    *lidxs, *work = NULL, *ilocal;
5708fa9e22eSVaclav Hapla   PetscSFNode *ridxs;
5718fa9e22eSVaclav Hapla   PetscMPIInt  rank, p = 0;
572d61846d3SStefano Zampini   PetscInt     r, len = 0, nleaves = 0;
5738fa9e22eSVaclav Hapla 
5748fa9e22eSVaclav Hapla   PetscFunctionBegin;
5758fa9e22eSVaclav Hapla   if (on) *on = 0; /* squelch -Wmaybe-uninitialized */
5768fa9e22eSVaclav Hapla   /* Create SF where leaves are input idxs and roots are owned idxs */
5779566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(map->comm, &rank));
5789566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &lidxs));
5798fa9e22eSVaclav Hapla   for (r = 0; r < n; ++r) lidxs[r] = -1;
5809566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(N, &ridxs));
581d61846d3SStefano Zampini   PetscCall(PetscMalloc1(N, &ilocal));
5828fa9e22eSVaclav Hapla   for (r = 0; r < N; ++r) {
5838fa9e22eSVaclav Hapla     const PetscInt idx = idxs[r];
584d61846d3SStefano Zampini 
585d61846d3SStefano Zampini     if (idx < 0) continue;
586d61846d3SStefano Zampini     PetscCheck(idx < map->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Index %" PetscInt_FMT " out of range [0,%" PetscInt_FMT ")", idx, map->N);
5878fa9e22eSVaclav Hapla     if (idx < owners[p] || owners[p + 1] <= idx) { /* short-circuit the search if the last p owns this idx too */
5889566063dSJacob Faibussowitsch       PetscCall(PetscLayoutFindOwner(map, idx, &p));
5898fa9e22eSVaclav Hapla     }
590d61846d3SStefano Zampini     ridxs[nleaves].rank  = p;
591d61846d3SStefano Zampini     ridxs[nleaves].index = idxs[r] - owners[p];
592d61846d3SStefano Zampini     ilocal[nleaves]      = r;
593d61846d3SStefano Zampini     nleaves++;
5948fa9e22eSVaclav Hapla   }
5959566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(map->comm, &sf));
596d61846d3SStefano Zampini   PetscCall(PetscSFSetGraph(sf, n, nleaves, ilocal, PETSC_OWN_POINTER, ridxs, PETSC_OWN_POINTER));
5979566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(sf, MPIU_INT, (PetscInt *)idxs, lidxs, MPI_LOR));
5989566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(sf, MPIU_INT, (PetscInt *)idxs, lidxs, MPI_LOR));
5998fa9e22eSVaclav Hapla   if (ogidxs) { /* communicate global idxs */
6008fa9e22eSVaclav Hapla     PetscInt cum = 0, start, *work2;
6018fa9e22eSVaclav Hapla 
6029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &work));
6039566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(N, &work2));
6049371c9d4SSatish Balay     for (r = 0; r < N; ++r)
6059371c9d4SSatish Balay       if (idxs[r] >= 0) cum++;
6069566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&cum, &start, 1, MPIU_INT, MPI_SUM, map->comm));
6078fa9e22eSVaclav Hapla     start -= cum;
6088fa9e22eSVaclav Hapla     cum = 0;
6099371c9d4SSatish Balay     for (r = 0; r < N; ++r)
6109371c9d4SSatish Balay       if (idxs[r] >= 0) work2[r] = start + cum++;
6119566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(sf, MPIU_INT, work2, work, MPI_REPLACE));
6129566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(sf, MPIU_INT, work2, work, MPI_REPLACE));
6139566063dSJacob Faibussowitsch     PetscCall(PetscFree(work2));
6148fa9e22eSVaclav Hapla   }
6159566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sf));
6168fa9e22eSVaclav Hapla   /* Compress and put in indices */
6178fa9e22eSVaclav Hapla   for (r = 0; r < n; ++r)
6188fa9e22eSVaclav Hapla     if (lidxs[r] >= 0) {
6198fa9e22eSVaclav Hapla       if (work) work[len] = work[r];
6208fa9e22eSVaclav Hapla       lidxs[len++] = r;
6218fa9e22eSVaclav Hapla     }
6228fa9e22eSVaclav Hapla   if (on) *on = len;
6238fa9e22eSVaclav Hapla   if (oidxs) *oidxs = lidxs;
6248fa9e22eSVaclav Hapla   if (ogidxs) *ogidxs = work;
6253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6268fa9e22eSVaclav Hapla }
627deffd5ebSksagiyam 
628deffd5ebSksagiyam /*@
629cab54364SBarry Smith   PetscSFCreateByMatchingIndices - Create `PetscSF` by matching root and leaf indices
630deffd5ebSksagiyam 
631deffd5ebSksagiyam   Collective
632deffd5ebSksagiyam 
633deffd5ebSksagiyam   Input Parameters:
634cf84bf9eSBarry Smith + layout           - `PetscLayout` defining the global index space and the MPI rank that brokers each index
635cf84bf9eSBarry Smith . numRootIndices   - size of `rootIndices`
636cf84bf9eSBarry Smith . rootIndices      - array of global indices of which this process requests ownership
637cf84bf9eSBarry Smith . rootLocalIndices - root local index permutation (`NULL` if no permutation)
638cf84bf9eSBarry Smith . rootLocalOffset  - offset to be added to `rootLocalIndices`
639cf84bf9eSBarry Smith . numLeafIndices   - size of `leafIndices`
640cf84bf9eSBarry Smith . leafIndices      - array of global indices with which this process requires data associated
641cf84bf9eSBarry Smith . leafLocalIndices - leaf local index permutation (`NULL` if no permutation)
642cf84bf9eSBarry Smith - leafLocalOffset  - offset to be added to `leafLocalIndices`
643deffd5ebSksagiyam 
644d8d19677SJose E. Roman   Output Parameters:
645cf84bf9eSBarry Smith + sfA - star forest representing the communication pattern from the layout space to the leaf space (`NULL` if not needed)
646deffd5ebSksagiyam - sf  - star forest representing the communication pattern from the root space to the leaf space
647deffd5ebSksagiyam 
648cab54364SBarry Smith   Level: advanced
649cab54364SBarry Smith 
650deffd5ebSksagiyam   Example 1:
651cab54364SBarry Smith .vb
652cab54364SBarry Smith   rank             : 0            1            2
653cab54364SBarry Smith   rootIndices      : [1 0 2]      [3]          [3]
654cab54364SBarry Smith   rootLocalOffset  : 100          200          300
655cab54364SBarry Smith   layout           : [0 1]        [2]          [3]
656cab54364SBarry Smith   leafIndices      : [0]          [2]          [0 3]
657cab54364SBarry Smith   leafLocalOffset  : 400          500          600
658cab54364SBarry Smith 
659cab54364SBarry Smith would build the following PetscSF
660cab54364SBarry Smith 
661cab54364SBarry Smith   [0] 400 <- (0,101)
662cab54364SBarry Smith   [1] 500 <- (0,102)
663cab54364SBarry Smith   [2] 600 <- (0,101)
664cab54364SBarry Smith   [2] 601 <- (2,300)
665cab54364SBarry Smith .ve
666cab54364SBarry Smith 
667deffd5ebSksagiyam   Example 2:
668cab54364SBarry Smith .vb
669cab54364SBarry Smith   rank             : 0               1               2
670cab54364SBarry Smith   rootIndices      : [1 0 2]         [3]             [3]
671cab54364SBarry Smith   rootLocalOffset  : 100             200             300
672cab54364SBarry Smith   layout           : [0 1]           [2]             [3]
673cab54364SBarry Smith   leafIndices      : rootIndices     rootIndices     rootIndices
674cab54364SBarry Smith   leafLocalOffset  : rootLocalOffset rootLocalOffset rootLocalOffset
675cab54364SBarry Smith 
676cab54364SBarry Smith would build the following PetscSF
677cab54364SBarry Smith 
678cab54364SBarry Smith   [1] 200 <- (2,300)
679cab54364SBarry Smith .ve
680cab54364SBarry Smith 
681deffd5ebSksagiyam   Example 3:
682cab54364SBarry Smith .vb
683cab54364SBarry Smith   No process requests ownership of global index 1, but no process needs it.
684cab54364SBarry Smith 
685cab54364SBarry Smith   rank             : 0            1            2
686cab54364SBarry Smith   numRootIndices   : 2            1            1
687cab54364SBarry Smith   rootIndices      : [0 2]        [3]          [3]
688cab54364SBarry Smith   rootLocalOffset  : 100          200          300
689cab54364SBarry Smith   layout           : [0 1]        [2]          [3]
690cab54364SBarry Smith   numLeafIndices   : 1            1            2
691cab54364SBarry Smith   leafIndices      : [0]          [2]          [0 3]
692cab54364SBarry Smith   leafLocalOffset  : 400          500          600
693cab54364SBarry Smith 
694cab54364SBarry Smith would build the following PetscSF
695cab54364SBarry Smith 
696cab54364SBarry Smith   [0] 400 <- (0,100)
697cab54364SBarry Smith   [1] 500 <- (0,101)
698cab54364SBarry Smith   [2] 600 <- (0,100)
699cab54364SBarry Smith   [2] 601 <- (2,300)
700cab54364SBarry Smith .ve
701deffd5ebSksagiyam 
702deffd5ebSksagiyam   Notes:
7032f04c522SBarry Smith   `layout` represents any partitioning of [0, N), where N is the total number of global indices, and its
704cab54364SBarry Smith   local size can be set to `PETSC_DECIDE`.
705cab54364SBarry Smith 
7062f04c522SBarry Smith   If a global index x lies in the partition owned by process i, each process whose `rootIndices` contains x requests
707deffd5ebSksagiyam   ownership of x and sends its own rank and the local index of x to process i.
708deffd5ebSksagiyam   If multiple processes request ownership of x, the one with the highest rank is to own x.
7092f04c522SBarry Smith   Process i then broadcasts the ownership information, so that each process whose `leafIndices` contains x knows the
710deffd5ebSksagiyam   ownership information of x.
7112f04c522SBarry Smith   The output `sf` is constructed by associating each leaf point to a root point in this way.
712deffd5ebSksagiyam 
713deffd5ebSksagiyam   Suppose there is point data ordered according to the global indices and partitioned according to the given layout.
7142f04c522SBarry Smith   The optional output `sfA` can be used to push such data to leaf points.
715deffd5ebSksagiyam 
7162f04c522SBarry Smith   All indices in `rootIndices` and `leafIndices` must lie in the layout range. The union (over all processes) of `rootIndices`
7172f04c522SBarry Smith   must cover that of `leafIndices`, but need not cover the entire layout.
718deffd5ebSksagiyam 
719deffd5ebSksagiyam   If (leafIndices, leafLocalIndices, leafLocalOffset) == (rootIndices, rootLocalIndices, rootLocalOffset), the output
720deffd5ebSksagiyam   star forest is almost identity, so will only include non-trivial part of the map.
721deffd5ebSksagiyam 
72238b5cf2dSJacob Faibussowitsch   Developer Notes:
723deffd5ebSksagiyam   Current approach of a process of the highest rank gaining the ownership may cause load imbalance; consider using
724deffd5ebSksagiyam   hash(rank, root_local_index) as the bid for the ownership determination.
725deffd5ebSksagiyam 
7262f04c522SBarry Smith .seealso: [](sec_petscsf), `PetscSF`, `PetscSFCreate()`
727deffd5ebSksagiyam @*/
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)728cf84bf9eSBarry 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)
729d71ae5a4SJacob Faibussowitsch {
730deffd5ebSksagiyam   MPI_Comm     comm = layout->comm;
731011b1c65SJames Wright   PetscMPIInt  rank;
732deffd5ebSksagiyam   PetscSF      sf1;
733deffd5ebSksagiyam   PetscSFNode *owners, *buffer, *iremote;
734deffd5ebSksagiyam   PetscInt    *ilocal, nleaves, N, n, i;
735011b1c65SJames Wright   PetscBool    areIndicesSame;
736deffd5ebSksagiyam 
737deffd5ebSksagiyam   PetscFunctionBegin;
73818aa8208SJames Wright   PetscAssertPointer(layout, 1);
7394f572ea9SToby Isaac   if (rootIndices) PetscAssertPointer(rootIndices, 3);
7404f572ea9SToby Isaac   if (rootLocalIndices) PetscAssertPointer(rootLocalIndices, 4);
7414f572ea9SToby Isaac   if (leafIndices) PetscAssertPointer(leafIndices, 7);
7424f572ea9SToby Isaac   if (leafLocalIndices) PetscAssertPointer(leafLocalIndices, 8);
7434f572ea9SToby Isaac   if (sfA) PetscAssertPointer(sfA, 10);
7444f572ea9SToby Isaac   PetscAssertPointer(sf, 11);
74508401ef6SPierre Jolivet   PetscCheck(numRootIndices >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numRootIndices (%" PetscInt_FMT ") must be non-negative", numRootIndices);
74608401ef6SPierre Jolivet   PetscCheck(numLeafIndices >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numLeafIndices (%" PetscInt_FMT ") must be non-negative", numLeafIndices);
7479566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7489566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(layout));
7499566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetSize(layout, &N));
7509566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetLocalSize(layout, &n));
751011b1c65SJames Wright   areIndicesSame = (PetscBool)(leafIndices == rootIndices);
752011b1c65SJames Wright   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &areIndicesSame, 1, MPI_C_BOOL, MPI_LAND, comm));
753011b1c65SJames Wright   PetscCheck(!areIndicesSame || numLeafIndices == numRootIndices, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "leafIndices == rootIndices, but numLeafIndices (%" PetscInt_FMT ") != numRootIndices(%" PetscInt_FMT ")", numLeafIndices, numRootIndices);
754011b1c65SJames Wright   if (PetscDefined(USE_DEBUG)) {
755011b1c65SJames Wright     PetscInt N1 = PETSC_INT_MIN;
7569371c9d4SSatish Balay     for (i = 0; i < numRootIndices; i++)
7579371c9d4SSatish Balay       if (rootIndices[i] > N1) N1 = rootIndices[i];
758462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &N1, 1, MPIU_INT, MPI_MAX, comm));
75908401ef6SPierre 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);
760011b1c65SJames Wright     if (!areIndicesSame) {
7611690c2aeSBarry Smith       N1 = PETSC_INT_MIN;
7629371c9d4SSatish Balay       for (i = 0; i < numLeafIndices; i++)
7639371c9d4SSatish Balay         if (leafIndices[i] > N1) N1 = leafIndices[i];
764462c564dSBarry Smith       PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &N1, 1, MPIU_INT, MPI_MAX, comm));
76508401ef6SPierre 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);
766deffd5ebSksagiyam     }
767011b1c65SJames Wright   }
768011b1c65SJames Wright 
769deffd5ebSksagiyam   /* Reduce: owners -> buffer */
7709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &buffer));
7719566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &sf1));
7729566063dSJacob Faibussowitsch   PetscCall(PetscSFSetFromOptions(sf1));
7739566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(sf1, layout, numRootIndices, NULL, PETSC_OWN_POINTER, rootIndices));
7749566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numRootIndices, &owners));
775deffd5ebSksagiyam   for (i = 0; i < numRootIndices; ++i) {
776deffd5ebSksagiyam     owners[i].rank  = rank;
777deffd5ebSksagiyam     owners[i].index = rootLocalOffset + (rootLocalIndices ? rootLocalIndices[i] : i);
778deffd5ebSksagiyam   }
779deffd5ebSksagiyam   for (i = 0; i < n; ++i) {
780deffd5ebSksagiyam     buffer[i].index = -1;
781deffd5ebSksagiyam     buffer[i].rank  = -1;
782deffd5ebSksagiyam   }
7836497c311SBarry Smith   PetscCall(PetscSFReduceBegin(sf1, MPIU_SF_NODE, owners, buffer, MPI_MAXLOC));
7846497c311SBarry Smith   PetscCall(PetscSFReduceEnd(sf1, MPIU_SF_NODE, owners, buffer, MPI_MAXLOC));
785deffd5ebSksagiyam   /* Bcast: buffer -> owners */
786011b1c65SJames Wright   if (!areIndicesSame) {
7879566063dSJacob Faibussowitsch     PetscCall(PetscFree(owners));
7889566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(sf1, layout, numLeafIndices, NULL, PETSC_OWN_POINTER, leafIndices));
7899566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeafIndices, &owners));
790deffd5ebSksagiyam   }
7916497c311SBarry Smith   PetscCall(PetscSFBcastBegin(sf1, MPIU_SF_NODE, buffer, owners, MPI_REPLACE));
7926497c311SBarry Smith   PetscCall(PetscSFBcastEnd(sf1, MPIU_SF_NODE, buffer, owners, MPI_REPLACE));
79308401ef6SPierre 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]);
7949566063dSJacob Faibussowitsch   PetscCall(PetscFree(buffer));
7959371c9d4SSatish Balay   if (sfA) {
7969371c9d4SSatish Balay     *sfA = sf1;
7979371c9d4SSatish Balay   } else PetscCall(PetscSFDestroy(&sf1));
798deffd5ebSksagiyam   /* Create sf */
799011b1c65SJames Wright   if (areIndicesSame && rootLocalIndices == leafLocalIndices && leafLocalOffset == rootLocalOffset) {
800deffd5ebSksagiyam     /* leaf space == root space */
8019371c9d4SSatish Balay     for (i = 0, nleaves = 0; i < numLeafIndices; ++i)
8029371c9d4SSatish Balay       if (owners[i].rank != rank) ++nleaves;
8039566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &ilocal));
8049566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &iremote));
805deffd5ebSksagiyam     for (i = 0, nleaves = 0; i < numLeafIndices; ++i) {
806deffd5ebSksagiyam       if (owners[i].rank != rank) {
807deffd5ebSksagiyam         ilocal[nleaves]        = leafLocalOffset + i;
808deffd5ebSksagiyam         iremote[nleaves].rank  = owners[i].rank;
809deffd5ebSksagiyam         iremote[nleaves].index = owners[i].index;
810deffd5ebSksagiyam         ++nleaves;
811deffd5ebSksagiyam       }
812deffd5ebSksagiyam     }
8139566063dSJacob Faibussowitsch     PetscCall(PetscFree(owners));
814deffd5ebSksagiyam   } else {
815deffd5ebSksagiyam     nleaves = numLeafIndices;
8169566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &ilocal));
817ad540459SPierre Jolivet     for (i = 0; i < nleaves; ++i) ilocal[i] = leafLocalOffset + (leafLocalIndices ? leafLocalIndices[i] : i);
818deffd5ebSksagiyam     iremote = owners;
819deffd5ebSksagiyam   }
8209566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, sf));
8219566063dSJacob Faibussowitsch   PetscCall(PetscSFSetFromOptions(*sf));
8229566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sf, rootLocalOffset + numRootIndices, nleaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
8233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
824deffd5ebSksagiyam }
825fbc7033fSJed Brown 
826fbc7033fSJed Brown /*@
82753c0d4aeSBarry Smith   PetscSFMerge - append/merge indices of `sfb` into `sfa`, with preference for `sfb`
828fbc7033fSJed Brown 
829fbc7033fSJed Brown   Collective
830fbc7033fSJed Brown 
83138b5cf2dSJacob Faibussowitsch   Input Parameters:
832fbc7033fSJed Brown + sfa - default `PetscSF`
8332f04c522SBarry Smith - sfb - additional edges to add/replace edges in `sfa`
834fbc7033fSJed Brown 
83538b5cf2dSJacob Faibussowitsch   Output Parameter:
836fbc7033fSJed Brown . merged - new `PetscSF` with combined edges
837fbc7033fSJed Brown 
83853c0d4aeSBarry Smith   Level: intermediate
83953c0d4aeSBarry Smith 
8402f04c522SBarry Smith .seealso: [](sec_petscsf), `PetscSF`, `PetscSFCompose()`
841fbc7033fSJed Brown @*/
PetscSFMerge(PetscSF sfa,PetscSF sfb,PetscSF * merged)842fbc7033fSJed Brown PetscErrorCode PetscSFMerge(PetscSF sfa, PetscSF sfb, PetscSF *merged)
843fbc7033fSJed Brown {
844fbc7033fSJed Brown   PetscInt maxleaf;
845fbc7033fSJed Brown 
846fbc7033fSJed Brown   PetscFunctionBegin;
847fbc7033fSJed Brown   PetscValidHeaderSpecific(sfa, PETSCSF_CLASSID, 1);
848fbc7033fSJed Brown   PetscValidHeaderSpecific(sfb, PETSCSF_CLASSID, 2);
849fbc7033fSJed Brown   PetscCheckSameComm(sfa, 1, sfb, 2);
8504f572ea9SToby Isaac   PetscAssertPointer(merged, 3);
851fbc7033fSJed Brown   {
852fbc7033fSJed Brown     PetscInt aleaf, bleaf;
853fbc7033fSJed Brown     PetscCall(PetscSFGetLeafRange(sfa, NULL, &aleaf));
854fbc7033fSJed Brown     PetscCall(PetscSFGetLeafRange(sfb, NULL, &bleaf));
855fbc7033fSJed Brown     maxleaf = PetscMax(aleaf, bleaf) + 1; // One more than the last index
856fbc7033fSJed Brown   }
857fbc7033fSJed Brown   PetscInt          *clocal, aroots, aleaves, broots, bleaves;
858fbc7033fSJed Brown   PetscSFNode       *cremote;
859fbc7033fSJed Brown   const PetscInt    *alocal, *blocal;
860fbc7033fSJed Brown   const PetscSFNode *aremote, *bremote;
861fbc7033fSJed Brown   PetscCall(PetscMalloc2(maxleaf, &clocal, maxleaf, &cremote));
862fbc7033fSJed Brown   for (PetscInt i = 0; i < maxleaf; i++) clocal[i] = -1;
863fbc7033fSJed Brown   PetscCall(PetscSFGetGraph(sfa, &aroots, &aleaves, &alocal, &aremote));
864fbc7033fSJed Brown   PetscCall(PetscSFGetGraph(sfb, &broots, &bleaves, &blocal, &bremote));
865fbc7033fSJed Brown   PetscCheck(aroots == broots, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Both sfa and sfb must have the same root space");
866fbc7033fSJed Brown   for (PetscInt i = 0; i < aleaves; i++) {
867fbc7033fSJed Brown     PetscInt a = alocal ? alocal[i] : i;
868fbc7033fSJed Brown     clocal[a]  = a;
869fbc7033fSJed Brown     cremote[a] = aremote[i];
870fbc7033fSJed Brown   }
871fbc7033fSJed Brown   for (PetscInt i = 0; i < bleaves; i++) {
872fbc7033fSJed Brown     PetscInt b = blocal ? blocal[i] : i;
873fbc7033fSJed Brown     clocal[b]  = b;
874fbc7033fSJed Brown     cremote[b] = bremote[i];
875fbc7033fSJed Brown   }
876fbc7033fSJed Brown   PetscInt nleaves = 0;
877fbc7033fSJed Brown   for (PetscInt i = 0; i < maxleaf; i++) {
878fbc7033fSJed Brown     if (clocal[i] < 0) continue;
879fbc7033fSJed Brown     clocal[nleaves]  = clocal[i];
880fbc7033fSJed Brown     cremote[nleaves] = cremote[i];
881fbc7033fSJed Brown     nleaves++;
882fbc7033fSJed Brown   }
883fbc7033fSJed Brown   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)sfa), merged));
884fbc7033fSJed Brown   PetscCall(PetscSFSetGraph(*merged, aroots, nleaves, clocal, PETSC_COPY_VALUES, cremote, PETSC_COPY_VALUES));
885fbc7033fSJed Brown   PetscCall(PetscFree2(clocal, cremote));
8863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
887fbc7033fSJed Brown }
8880dd791a8SStefano Zampini 
8890dd791a8SStefano Zampini /*@
8900dd791a8SStefano Zampini   PetscSFCreateStridedSF - Create an `PetscSF` to communicate interleaved blocks of data
8910dd791a8SStefano Zampini 
8920dd791a8SStefano Zampini   Collective
8930dd791a8SStefano Zampini 
8940dd791a8SStefano Zampini   Input Parameters:
8950dd791a8SStefano Zampini + sf  - star forest
8960dd791a8SStefano Zampini . bs  - stride
8970dd791a8SStefano Zampini . ldr - leading dimension of root space
8980dd791a8SStefano Zampini - ldl - leading dimension of leaf space
8990dd791a8SStefano Zampini 
9000dd791a8SStefano Zampini   Output Parameter:
9010dd791a8SStefano Zampini . vsf - the new `PetscSF`
9020dd791a8SStefano Zampini 
9030dd791a8SStefano Zampini   Level: intermediate
9040dd791a8SStefano Zampini 
9050dd791a8SStefano Zampini   Notes:
9062f04c522SBarry Smith   This can be useful to perform communications on multiple right-hand sides stored in a Fortran-style two dimensional array.
9072f04c522SBarry Smith   For example, the calling sequence
9080dd791a8SStefano Zampini .vb
9090dd791a8SStefano Zampini   c_datatype *roots, *leaves;
9100dd791a8SStefano Zampini   for i in [0,bs) do
9110dd791a8SStefano Zampini     PetscSFBcastBegin(sf, mpi_datatype, roots + i*ldr, leaves + i*ldl, op)
9120dd791a8SStefano Zampini     PetscSFBcastEnd(sf, mpi_datatype, roots + i*ldr, leaves + i*ldl, op)
9130dd791a8SStefano Zampini .ve
9140dd791a8SStefano Zampini   is equivalent to
9150dd791a8SStefano Zampini .vb
9160dd791a8SStefano Zampini   c_datatype *roots, *leaves;
9170dd791a8SStefano Zampini   PetscSFCreateStridedSF(sf, bs, ldr, ldl, &vsf)
9180dd791a8SStefano Zampini   PetscSFBcastBegin(vsf, mpi_datatype, roots, leaves, op)
9190dd791a8SStefano Zampini   PetscSFBcastEnd(vsf, mpi_datatype, roots, leaves, op)
9200dd791a8SStefano Zampini .ve
9210dd791a8SStefano Zampini 
9220dd791a8SStefano Zampini   Developer Notes:
9230dd791a8SStefano Zampini   Should this functionality be handled with a new API instead of creating a new object?
9240dd791a8SStefano Zampini 
9252f04c522SBarry Smith .seealso: [](sec_petscsf), `PetscSF`, `PetscSFCreate()`, `PetscSFSetGraph()`
9260dd791a8SStefano Zampini @*/
PetscSFCreateStridedSF(PetscSF sf,PetscInt bs,PetscInt ldr,PetscInt ldl,PetscSF * vsf)9270dd791a8SStefano Zampini PetscErrorCode PetscSFCreateStridedSF(PetscSF sf, PetscInt bs, PetscInt ldr, PetscInt ldl, PetscSF *vsf)
9280dd791a8SStefano Zampini {
9290dd791a8SStefano Zampini   PetscSF            rankssf;
9300dd791a8SStefano Zampini   const PetscSFNode *iremote, *sfrremote;
9310dd791a8SStefano Zampini   PetscSFNode       *viremote;
9320dd791a8SStefano Zampini   const PetscInt    *ilocal;
9330dd791a8SStefano Zampini   PetscInt          *vilocal = NULL, *ldrs;
9340dd791a8SStefano Zampini   PetscInt           nranks, nr, nl, vnr, vnl, maxl;
9350dd791a8SStefano Zampini   PetscMPIInt        rank;
9360dd791a8SStefano Zampini   MPI_Comm           comm;
9370dd791a8SStefano Zampini   PetscSFType        sftype;
9380dd791a8SStefano Zampini 
9390dd791a8SStefano Zampini   PetscFunctionBegin;
9400dd791a8SStefano Zampini   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
9410dd791a8SStefano Zampini   PetscValidLogicalCollectiveInt(sf, bs, 2);
9420dd791a8SStefano Zampini   PetscAssertPointer(vsf, 5);
9430dd791a8SStefano Zampini   if (bs == 1) {
9440dd791a8SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)sf));
9450dd791a8SStefano Zampini     *vsf = sf;
9460dd791a8SStefano Zampini     PetscFunctionReturn(PETSC_SUCCESS);
9470dd791a8SStefano Zampini   }
9480dd791a8SStefano Zampini   PetscCall(PetscSFSetUp(sf));
9490dd791a8SStefano Zampini   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
9500dd791a8SStefano Zampini   PetscCallMPI(MPI_Comm_rank(comm, &rank));
9510dd791a8SStefano Zampini   PetscCall(PetscSFGetGraph(sf, &nr, &nl, &ilocal, &iremote));
9520dd791a8SStefano Zampini   PetscCall(PetscSFGetLeafRange(sf, NULL, &maxl));
9530dd791a8SStefano Zampini   maxl += 1;
9540dd791a8SStefano Zampini   if (ldl == PETSC_DECIDE) ldl = maxl;
9550dd791a8SStefano Zampini   if (ldr == PETSC_DECIDE) ldr = nr;
956*35409886SPierre Jolivet   ldl /= PetscMax(1, sf->vscat.bs); // SFs created from VecScatterCreate() may have a nonzero block size. If not 0, we need to scale ldl and ldr
957*35409886SPierre Jolivet   ldr /= PetscMax(1, sf->vscat.bs);
9580dd791a8SStefano 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);
9590dd791a8SStefano 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);
9600dd791a8SStefano Zampini   vnr = nr * bs;
9610dd791a8SStefano Zampini   vnl = nl * bs;
9620dd791a8SStefano Zampini   PetscCall(PetscMalloc1(vnl, &viremote));
9630dd791a8SStefano Zampini   PetscCall(PetscMalloc1(vnl, &vilocal));
9640dd791a8SStefano Zampini 
9650dd791a8SStefano Zampini   /* Communicate root leading dimensions to leaf ranks */
9660dd791a8SStefano Zampini   PetscCall(PetscSFGetRanksSF(sf, &rankssf));
9670dd791a8SStefano Zampini   PetscCall(PetscSFGetGraph(rankssf, NULL, &nranks, NULL, &sfrremote));
9680dd791a8SStefano Zampini   PetscCall(PetscMalloc1(nranks, &ldrs));
9690dd791a8SStefano Zampini   PetscCall(PetscSFBcastBegin(rankssf, MPIU_INT, &ldr, ldrs, MPI_REPLACE));
9700dd791a8SStefano Zampini   PetscCall(PetscSFBcastEnd(rankssf, MPIU_INT, &ldr, ldrs, MPI_REPLACE));
9710dd791a8SStefano Zampini 
9720dd791a8SStefano Zampini   for (PetscInt i = 0, rold = -1, lda = -1; i < nl; i++) {
973835f2295SStefano Zampini     const PetscInt r  = iremote[i].rank;
9740dd791a8SStefano Zampini     const PetscInt ii = iremote[i].index;
9750dd791a8SStefano Zampini 
9760dd791a8SStefano Zampini     if (r == rank) lda = ldr;
9770dd791a8SStefano Zampini     else if (rold != r) {
9780dd791a8SStefano Zampini       PetscInt j;
9790dd791a8SStefano Zampini 
9800dd791a8SStefano Zampini       for (j = 0; j < nranks; j++)
9810dd791a8SStefano Zampini         if (sfrremote[j].rank == r) break;
982835f2295SStefano Zampini       PetscCheck(j < nranks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unable to locate neighbor rank %" PetscInt_FMT, r);
9830dd791a8SStefano Zampini       lda = ldrs[j];
9840dd791a8SStefano Zampini     }
9850dd791a8SStefano Zampini     rold = r;
9860dd791a8SStefano Zampini     for (PetscInt v = 0; v < bs; v++) {
9870dd791a8SStefano Zampini       viremote[v * nl + i].rank  = r;
9880dd791a8SStefano Zampini       viremote[v * nl + i].index = v * lda + ii;
9890dd791a8SStefano Zampini       vilocal[v * nl + i]        = v * ldl + (ilocal ? ilocal[i] : i);
9900dd791a8SStefano Zampini     }
9910dd791a8SStefano Zampini   }
9920dd791a8SStefano Zampini   PetscCall(PetscFree(ldrs));
9930dd791a8SStefano Zampini   PetscCall(PetscSFCreate(comm, vsf));
994*35409886SPierre Jolivet   if (sf->vscat.bs > 1) {
995*35409886SPierre Jolivet     (*vsf)->vscat.bs = sf->vscat.bs;
996*35409886SPierre Jolivet     PetscCallMPI(MPI_Type_dup(sf->vscat.unit, &(*vsf)->vscat.unit));
997*35409886SPierre Jolivet     (*vsf)->vscat.to_n   = bs * sf->vscat.to_n;
998*35409886SPierre Jolivet     (*vsf)->vscat.from_n = bs * sf->vscat.from_n;
999*35409886SPierre Jolivet   }
10000dd791a8SStefano Zampini   PetscCall(PetscSFGetType(sf, &sftype));
10010dd791a8SStefano Zampini   PetscCall(PetscSFSetType(*vsf, sftype));
10020dd791a8SStefano Zampini   PetscCall(PetscSFSetGraph(*vsf, vnr, vnl, vilocal, PETSC_OWN_POINTER, viremote, PETSC_OWN_POINTER));
10030dd791a8SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
10040dd791a8SStefano Zampini }
1005