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, <));
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(<));
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