1b0c7db22SLisandro Dalcin #include <petsc/private/sfimpl.h> /*I "petscsf.h" I*/ 2b0c7db22SLisandro Dalcin #include <petsc/private/sectionimpl.h> 3b0c7db22SLisandro Dalcin 4eb58282aSVaclav Hapla /*@ 52f04c522SBarry Smith PetscSFSetGraphLayout - Set a `PetscSF` communication pattern using global indices and a `PetscLayout` 6b0c7db22SLisandro Dalcin 7b0c7db22SLisandro Dalcin Collective 8b0c7db22SLisandro Dalcin 94165533cSJose E. Roman Input Parameters: 10b0c7db22SLisandro Dalcin + sf - star forest 112f04c522SBarry Smith . layout - `PetscLayout` defining the global space for roots, i.e. which roots are owned by each MPI process 122f04c522SBarry Smith . nleaves - number of leaf vertices on the current process, each of these references a root on any MPI process 132f04c522SBarry Smith . ilocal - locations of leaves in leafdata buffers, pass `NULL` for contiguous storage, that is the locations are in [0,`nleaves`) 142f04c522SBarry Smith . localmode - copy mode for `ilocal` 152f04c522SBarry Smith - gremote - root vertices in global numbering corresponding to the leaves 16b0c7db22SLisandro Dalcin 17b0c7db22SLisandro Dalcin Level: intermediate 18b0c7db22SLisandro Dalcin 19cab54364SBarry Smith Note: 202f04c522SBarry Smith Global indices must lie in [0, N) where N is the global size of `layout`. 212f04c522SBarry Smith Leaf indices in `ilocal` get sorted; this means the user-provided array gets sorted if localmode is `PETSC_OWN_POINTER`. 2286c56f52SVaclav Hapla 2338b5cf2dSJacob Faibussowitsch Developer Notes: 242f04c522SBarry Smith Local indices which are the identity permutation in the range [0,`nleaves`) are discarded as they 25cab54364SBarry Smith encode contiguous storage. In such case, if localmode is `PETSC_OWN_POINTER`, the memory is deallocated as it is not 26b0c7db22SLisandro Dalcin needed 27b0c7db22SLisandro Dalcin 282f04c522SBarry Smith .seealso: [](sec_petscsf), `PetscSF`, `PetscSFGetGraphLayout()`, `PetscSFCreate()`, `PetscSFView()`, `PetscSFSetGraph()`, `PetscSFGetGraph()` 29b0c7db22SLisandro Dalcin @*/ 30cf84bf9eSBarry Smith PetscErrorCode PetscSFSetGraphLayout(PetscSF sf, PetscLayout layout, PetscInt nleaves, PetscInt ilocal[], PetscCopyMode localmode, const PetscInt gremote[]) 31d71ae5a4SJacob Faibussowitsch { 3238a25198SStefano Zampini const PetscInt *range; 3338a25198SStefano Zampini PetscInt i, nroots, ls = -1, ln = -1; 3438a25198SStefano Zampini PetscMPIInt lr = -1; 35b0c7db22SLisandro Dalcin PetscSFNode *remote; 36b0c7db22SLisandro Dalcin 37b0c7db22SLisandro Dalcin PetscFunctionBegin; 38da0802e2SStefano Zampini PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1); 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 @*/ 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 @*/ 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 @*/ 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 @*/ 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 @*/ 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 @*/ 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 */ 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 @*/ 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 @*/ 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 @*/ 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