1 #include <petsc/private/sfimpl.h> /*I "petscsf.h" I*/ 2 #include <petsc/private/sectionimpl.h> 3 4 /*@ 5 PetscSFSetGraphLayout - Set a parallel star forest via global indices and a PetscLayout 6 7 Collective 8 9 Input Parameters: 10 + sf - star forest 11 . layout - PetscLayout defining the global space for roots 12 . nleaves - number of leaf vertices on the current process, each of these references a root on any process 13 . ilocal - locations of leaves in leafdata buffers, pass NULL for contiguous storage 14 . localmode - copy mode for ilocal 15 - gremote - root vertices in global numbering corresponding to leaves in ilocal 16 17 Level: intermediate 18 19 Notes: 20 Global indices must lie in [0, N) where N is the global size of layout. 21 Leaf indices in ilocal get sorted; this means the user-provided array gets sorted if localmode is PETSC_OWN_POINTER. 22 23 Developer Notes: 24 Local indices which are the identity permutation in the range [0,nleaves) are discarded as they 25 encode contiguous storage. In such case, if localmode is PETSC_OWN_POINTER, the memory is deallocated as it is not 26 needed 27 28 .seealso: `PetscSFGetGraphLayout()`, `PetscSFCreate()`, `PetscSFView()`, `PetscSFSetGraph()`, `PetscSFGetGraph()` 29 @*/ 30 PetscErrorCode PetscSFSetGraphLayout(PetscSF sf, PetscLayout layout, PetscInt nleaves, PetscInt *ilocal, PetscCopyMode localmode, const PetscInt *gremote) 31 { 32 const PetscInt *range; 33 PetscInt i, nroots, ls = -1, ln = -1; 34 PetscMPIInt lr = -1; 35 PetscSFNode *remote; 36 37 PetscFunctionBegin; 38 PetscCall(PetscLayoutGetLocalSize(layout, &nroots)); 39 PetscCall(PetscLayoutGetRanges(layout, &range)); 40 PetscCall(PetscMalloc1(nleaves, &remote)); 41 if (nleaves) ls = gremote[0] + 1; 42 for (i = 0; i < nleaves; i++) { 43 const PetscInt idx = gremote[i] - ls; 44 if (idx < 0 || idx >= ln) { /* short-circuit the search */ 45 PetscCall(PetscLayoutFindOwnerIndex(layout, gremote[i], &lr, &remote[i].index)); 46 remote[i].rank = lr; 47 ls = range[lr]; 48 ln = range[lr + 1] - ls; 49 } else { 50 remote[i].rank = lr; 51 remote[i].index = idx; 52 } 53 } 54 PetscCall(PetscSFSetGraph(sf, nroots, nleaves, ilocal, localmode, remote, PETSC_OWN_POINTER)); 55 PetscFunctionReturn(0); 56 } 57 58 /*@C 59 PetscSFGetGraphLayout - Get the global indices and PetscLayout that describe this star forest 60 61 Collective 62 63 Input Parameter: 64 . sf - star forest 65 66 Output Parameters: 67 + layout - PetscLayout defining the global space for roots 68 . nleaves - number of leaf vertices on the current process, each of these references a root on any process 69 . ilocal - locations of leaves in leafdata buffers, or NULL for contiguous storage 70 - gremote - root vertices in global numbering corresponding to leaves in ilocal 71 72 Level: intermediate 73 74 Notes: 75 The outputs are such that passing them as inputs to `PetscSFSetGraphLayout()` would lead to the same star forest. 76 The outputs layout and gremote are freshly created each time this function is called, 77 so they need to be freed by user and cannot be qualified as const. 78 79 .seealso: `PetscSFSetGraphLayout()`, `PetscSFCreate()`, `PetscSFView()`, `PetscSFSetGraph()`, `PetscSFGetGraph()` 80 @*/ 81 PetscErrorCode PetscSFGetGraphLayout(PetscSF sf, PetscLayout *layout, PetscInt *nleaves, const PetscInt *ilocal[], PetscInt *gremote[]) 82 { 83 PetscInt nr, nl; 84 const PetscSFNode *ir; 85 PetscLayout lt; 86 87 PetscFunctionBegin; 88 PetscCall(PetscSFGetGraph(sf, &nr, &nl, ilocal, &ir)); 89 PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)sf), nr, PETSC_DECIDE, 1, <)); 90 if (gremote) { 91 PetscInt i; 92 const PetscInt *range; 93 PetscInt *gr; 94 95 PetscCall(PetscLayoutGetRanges(lt, &range)); 96 PetscCall(PetscMalloc1(nl, &gr)); 97 for (i = 0; i < nl; i++) gr[i] = range[ir[i].rank] + ir[i].index; 98 *gremote = gr; 99 } 100 if (nleaves) *nleaves = nl; 101 if (layout) *layout = lt; 102 else PetscCall(PetscLayoutDestroy(<)); 103 PetscFunctionReturn(0); 104 } 105 106 /*@ 107 PetscSFSetGraphSection - Sets the PetscSF graph encoding the parallel dof overlap based upon the PetscSections 108 describing the data layout. 109 110 Input Parameters: 111 + sf - The SF 112 . localSection - PetscSection describing the local data layout 113 - globalSection - PetscSection describing the global data layout 114 115 Level: developer 116 117 .seealso: `PetscSFSetGraph()`, `PetscSFSetGraphLayout()` 118 @*/ 119 PetscErrorCode PetscSFSetGraphSection(PetscSF sf, PetscSection localSection, PetscSection globalSection) 120 { 121 MPI_Comm comm; 122 PetscLayout layout; 123 const PetscInt *ranges; 124 PetscInt *local; 125 PetscSFNode *remote; 126 PetscInt pStart, pEnd, p, nroots, nleaves = 0, l; 127 PetscMPIInt size, rank; 128 129 PetscFunctionBegin; 130 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1); 131 PetscValidHeaderSpecific(localSection, PETSC_SECTION_CLASSID, 2); 132 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 133 134 PetscCall(PetscObjectGetComm((PetscObject)sf, &comm)); 135 PetscCallMPI(MPI_Comm_size(comm, &size)); 136 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 137 PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd)); 138 PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots)); 139 PetscCall(PetscLayoutCreate(comm, &layout)); 140 PetscCall(PetscLayoutSetBlockSize(layout, 1)); 141 PetscCall(PetscLayoutSetLocalSize(layout, nroots)); 142 PetscCall(PetscLayoutSetUp(layout)); 143 PetscCall(PetscLayoutGetRanges(layout, &ranges)); 144 for (p = pStart; p < pEnd; ++p) { 145 PetscInt gdof, gcdof; 146 147 PetscCall(PetscSectionGetDof(globalSection, p, &gdof)); 148 PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof)); 149 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)); 150 nleaves += gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof; 151 } 152 PetscCall(PetscMalloc1(nleaves, &local)); 153 PetscCall(PetscMalloc1(nleaves, &remote)); 154 for (p = pStart, l = 0; p < pEnd; ++p) { 155 const PetscInt *cind; 156 PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d, c; 157 158 PetscCall(PetscSectionGetDof(localSection, p, &dof)); 159 PetscCall(PetscSectionGetOffset(localSection, p, &off)); 160 PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof)); 161 PetscCall(PetscSectionGetConstraintIndices(localSection, p, &cind)); 162 PetscCall(PetscSectionGetDof(globalSection, p, &gdof)); 163 PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof)); 164 PetscCall(PetscSectionGetOffset(globalSection, p, &goff)); 165 if (!gdof) continue; /* Censored point */ 166 gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof; 167 if (gsize != dof - cdof) { 168 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); 169 cdof = 0; /* Ignore constraints */ 170 } 171 for (d = 0, c = 0; d < dof; ++d) { 172 if ((c < cdof) && (cind[c] == d)) { 173 ++c; 174 continue; 175 } 176 local[l + d - c] = off + d; 177 } 178 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); 179 if (gdof < 0) { 180 for (d = 0; d < gsize; ++d, ++l) { 181 PetscInt offset = -(goff + 1) + d, r; 182 183 PetscCall(PetscFindInt(offset, size + 1, ranges, &r)); 184 if (r < 0) r = -(r + 2); 185 PetscCheck(!(r < 0) && !(r >= size), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")", p, r, gdof, goff); 186 remote[l].rank = r; 187 remote[l].index = offset - ranges[r]; 188 } 189 } else { 190 for (d = 0; d < gsize; ++d, ++l) { 191 remote[l].rank = rank; 192 remote[l].index = goff + d - ranges[rank]; 193 } 194 } 195 } 196 PetscCheck(l == nleaves, comm, PETSC_ERR_PLIB, "Iteration error, l %" PetscInt_FMT " != nleaves %" PetscInt_FMT, l, nleaves); 197 PetscCall(PetscLayoutDestroy(&layout)); 198 PetscCall(PetscSFSetGraph(sf, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER)); 199 PetscFunctionReturn(0); 200 } 201 202 /*@C 203 PetscSFDistributeSection - Create a new PetscSection reorganized, moving from the root to the leaves of the SF 204 205 Collective on sf 206 207 Input Parameters: 208 + sf - The SF 209 - rootSection - Section defined on root space 210 211 Output Parameters: 212 + remoteOffsets - root offsets in leaf storage, or NULL 213 - leafSection - Section defined on the leaf space 214 215 Level: advanced 216 217 .seealso: `PetscSFCreate()` 218 @*/ 219 PetscErrorCode PetscSFDistributeSection(PetscSF sf, PetscSection rootSection, PetscInt **remoteOffsets, PetscSection leafSection) 220 { 221 PetscSF embedSF; 222 const PetscInt *indices; 223 IS selected; 224 PetscInt numFields, nroots, rpStart, rpEnd, lpStart = PETSC_MAX_INT, lpEnd = -1, f, c; 225 PetscBool *sub, hasc; 226 227 PetscFunctionBegin; 228 PetscCall(PetscLogEventBegin(PETSCSF_DistSect, sf, 0, 0, 0)); 229 PetscCall(PetscSectionGetNumFields(rootSection, &numFields)); 230 if (numFields) { 231 IS perm; 232 233 /* PetscSectionSetNumFields() calls PetscSectionReset(), which destroys 234 leafSection->perm. To keep this permutation set by the user, we grab 235 the reference before calling PetscSectionSetNumFields() and set it 236 back after. */ 237 PetscCall(PetscSectionGetPermutation(leafSection, &perm)); 238 PetscCall(PetscObjectReference((PetscObject)perm)); 239 PetscCall(PetscSectionSetNumFields(leafSection, numFields)); 240 PetscCall(PetscSectionSetPermutation(leafSection, perm)); 241 PetscCall(ISDestroy(&perm)); 242 } 243 PetscCall(PetscMalloc1(numFields + 2, &sub)); 244 sub[1] = rootSection->bc ? PETSC_TRUE : PETSC_FALSE; 245 for (f = 0; f < numFields; ++f) { 246 PetscSectionSym sym, dsym = NULL; 247 const char *name = NULL; 248 PetscInt numComp = 0; 249 250 sub[2 + f] = rootSection->field[f]->bc ? PETSC_TRUE : PETSC_FALSE; 251 PetscCall(PetscSectionGetFieldComponents(rootSection, f, &numComp)); 252 PetscCall(PetscSectionGetFieldName(rootSection, f, &name)); 253 PetscCall(PetscSectionGetFieldSym(rootSection, f, &sym)); 254 if (sym) PetscCall(PetscSectionSymDistribute(sym, sf, &dsym)); 255 PetscCall(PetscSectionSetFieldComponents(leafSection, f, numComp)); 256 PetscCall(PetscSectionSetFieldName(leafSection, f, name)); 257 PetscCall(PetscSectionSetFieldSym(leafSection, f, dsym)); 258 PetscCall(PetscSectionSymDestroy(&dsym)); 259 for (c = 0; c < rootSection->numFieldComponents[f]; ++c) { 260 PetscCall(PetscSectionGetComponentName(rootSection, f, c, &name)); 261 PetscCall(PetscSectionSetComponentName(leafSection, f, c, name)); 262 } 263 } 264 PetscCall(PetscSectionGetChart(rootSection, &rpStart, &rpEnd)); 265 PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL)); 266 rpEnd = PetscMin(rpEnd, nroots); 267 rpEnd = PetscMax(rpStart, rpEnd); 268 /* see if we can avoid creating the embedded SF, since it can cost more than an allreduce */ 269 sub[0] = (PetscBool)(nroots != rpEnd - rpStart); 270 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, sub, 2 + numFields, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)sf))); 271 if (sub[0]) { 272 PetscCall(ISCreateStride(PETSC_COMM_SELF, rpEnd - rpStart, rpStart, 1, &selected)); 273 PetscCall(ISGetIndices(selected, &indices)); 274 PetscCall(PetscSFCreateEmbeddedRootSF(sf, rpEnd - rpStart, indices, &embedSF)); 275 PetscCall(ISRestoreIndices(selected, &indices)); 276 PetscCall(ISDestroy(&selected)); 277 } else { 278 PetscCall(PetscObjectReference((PetscObject)sf)); 279 embedSF = sf; 280 } 281 PetscCall(PetscSFGetLeafRange(embedSF, &lpStart, &lpEnd)); 282 lpEnd++; 283 284 PetscCall(PetscSectionSetChart(leafSection, lpStart, lpEnd)); 285 286 /* Constrained dof section */ 287 hasc = sub[1]; 288 for (f = 0; f < numFields; ++f) hasc = (PetscBool)(hasc || sub[2 + f]); 289 290 /* Could fuse these at the cost of copies and extra allocation */ 291 PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->atlasDof[-rpStart], &leafSection->atlasDof[-lpStart], MPI_REPLACE)); 292 PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->atlasDof[-rpStart], &leafSection->atlasDof[-lpStart], MPI_REPLACE)); 293 if (sub[1]) { 294 PetscCall(PetscSectionCheckConstraints_Private(rootSection)); 295 PetscCall(PetscSectionCheckConstraints_Private(leafSection)); 296 PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->bc->atlasDof[-rpStart], &leafSection->bc->atlasDof[-lpStart], MPI_REPLACE)); 297 PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->bc->atlasDof[-rpStart], &leafSection->bc->atlasDof[-lpStart], MPI_REPLACE)); 298 } 299 for (f = 0; f < numFields; ++f) { 300 PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->atlasDof[-rpStart], &leafSection->field[f]->atlasDof[-lpStart], MPI_REPLACE)); 301 PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->atlasDof[-rpStart], &leafSection->field[f]->atlasDof[-lpStart], MPI_REPLACE)); 302 if (sub[2 + f]) { 303 PetscCall(PetscSectionCheckConstraints_Private(rootSection->field[f])); 304 PetscCall(PetscSectionCheckConstraints_Private(leafSection->field[f])); 305 PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasDof[-rpStart], &leafSection->field[f]->bc->atlasDof[-lpStart], MPI_REPLACE)); 306 PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasDof[-rpStart], &leafSection->field[f]->bc->atlasDof[-lpStart], MPI_REPLACE)); 307 } 308 } 309 if (remoteOffsets) { 310 PetscCall(PetscMalloc1(lpEnd - lpStart, remoteOffsets)); 311 PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart], MPI_REPLACE)); 312 PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart], MPI_REPLACE)); 313 } 314 PetscCall(PetscSectionInvalidateMaxDof_Internal(leafSection)); 315 PetscCall(PetscSectionSetUp(leafSection)); 316 if (hasc) { /* need to communicate bcIndices */ 317 PetscSF bcSF; 318 PetscInt *rOffBc; 319 320 PetscCall(PetscMalloc1(lpEnd - lpStart, &rOffBc)); 321 if (sub[1]) { 322 PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE)); 323 PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE)); 324 PetscCall(PetscSFCreateSectionSF(embedSF, rootSection->bc, rOffBc, leafSection->bc, &bcSF)); 325 PetscCall(PetscSFBcastBegin(bcSF, MPIU_INT, rootSection->bcIndices, leafSection->bcIndices, MPI_REPLACE)); 326 PetscCall(PetscSFBcastEnd(bcSF, MPIU_INT, rootSection->bcIndices, leafSection->bcIndices, MPI_REPLACE)); 327 PetscCall(PetscSFDestroy(&bcSF)); 328 } 329 for (f = 0; f < numFields; ++f) { 330 if (sub[2 + f]) { 331 PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE)); 332 PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasOff[-rpStart], &rOffBc[-lpStart], MPI_REPLACE)); 333 PetscCall(PetscSFCreateSectionSF(embedSF, rootSection->field[f]->bc, rOffBc, leafSection->field[f]->bc, &bcSF)); 334 PetscCall(PetscSFBcastBegin(bcSF, MPIU_INT, rootSection->field[f]->bcIndices, leafSection->field[f]->bcIndices, MPI_REPLACE)); 335 PetscCall(PetscSFBcastEnd(bcSF, MPIU_INT, rootSection->field[f]->bcIndices, leafSection->field[f]->bcIndices, MPI_REPLACE)); 336 PetscCall(PetscSFDestroy(&bcSF)); 337 } 338 } 339 PetscCall(PetscFree(rOffBc)); 340 } 341 PetscCall(PetscSFDestroy(&embedSF)); 342 PetscCall(PetscFree(sub)); 343 PetscCall(PetscLogEventEnd(PETSCSF_DistSect, sf, 0, 0, 0)); 344 PetscFunctionReturn(0); 345 } 346 347 /*@C 348 PetscSFCreateRemoteOffsets - Create offsets for point data on remote processes 349 350 Collective on sf 351 352 Input Parameters: 353 + sf - The SF 354 . rootSection - Data layout of remote points for outgoing data (this is layout for SF roots) 355 - leafSection - Data layout of local points for incoming data (this is layout for SF leaves) 356 357 Output Parameter: 358 . remoteOffsets - Offsets for point data on remote processes (these are offsets from the root section), or NULL 359 360 Level: developer 361 362 .seealso: `PetscSFCreate()` 363 @*/ 364 PetscErrorCode PetscSFCreateRemoteOffsets(PetscSF sf, PetscSection rootSection, PetscSection leafSection, PetscInt **remoteOffsets) 365 { 366 PetscSF embedSF; 367 const PetscInt *indices; 368 IS selected; 369 PetscInt numRoots, rpStart = 0, rpEnd = 0, lpStart = 0, lpEnd = 0; 370 371 PetscFunctionBegin; 372 *remoteOffsets = NULL; 373 PetscCall(PetscSFGetGraph(sf, &numRoots, NULL, NULL, NULL)); 374 if (numRoots < 0) PetscFunctionReturn(0); 375 PetscCall(PetscLogEventBegin(PETSCSF_RemoteOff, sf, 0, 0, 0)); 376 PetscCall(PetscSectionGetChart(rootSection, &rpStart, &rpEnd)); 377 PetscCall(PetscSectionGetChart(leafSection, &lpStart, &lpEnd)); 378 PetscCall(ISCreateStride(PETSC_COMM_SELF, rpEnd - rpStart, rpStart, 1, &selected)); 379 PetscCall(ISGetIndices(selected, &indices)); 380 PetscCall(PetscSFCreateEmbeddedRootSF(sf, rpEnd - rpStart, indices, &embedSF)); 381 PetscCall(ISRestoreIndices(selected, &indices)); 382 PetscCall(ISDestroy(&selected)); 383 PetscCall(PetscCalloc1(lpEnd - lpStart, remoteOffsets)); 384 PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart], MPI_REPLACE)); 385 PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart], MPI_REPLACE)); 386 PetscCall(PetscSFDestroy(&embedSF)); 387 PetscCall(PetscLogEventEnd(PETSCSF_RemoteOff, sf, 0, 0, 0)); 388 PetscFunctionReturn(0); 389 } 390 391 /*@C 392 PetscSFCreateSectionSF - Create an expanded SF of dofs, assuming the input SF relates points 393 394 Collective on sf 395 396 Input Parameters: 397 + sf - The SF 398 . rootSection - Data layout of remote points for outgoing data (this is usually the serial section) 399 . remoteOffsets - Offsets for point data on remote processes (these are offsets from the root section), or NULL 400 - leafSection - Data layout of local points for incoming data (this is the distributed section) 401 402 Output Parameters: 403 - sectionSF - The new SF 404 405 Note: Either rootSection or remoteOffsets can be specified 406 407 Level: advanced 408 409 .seealso: `PetscSFCreate()` 410 @*/ 411 PetscErrorCode PetscSFCreateSectionSF(PetscSF sf, PetscSection rootSection, PetscInt remoteOffsets[], PetscSection leafSection, PetscSF *sectionSF) 412 { 413 MPI_Comm comm; 414 const PetscInt *localPoints; 415 const PetscSFNode *remotePoints; 416 PetscInt lpStart, lpEnd; 417 PetscInt numRoots, numSectionRoots, numPoints, numIndices = 0; 418 PetscInt *localIndices; 419 PetscSFNode *remoteIndices; 420 PetscInt i, ind; 421 422 PetscFunctionBegin; 423 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1); 424 PetscValidPointer(rootSection, 2); 425 /* Cannot check PetscValidIntPointer(remoteOffsets,3) because it can be NULL if sf does not reference any points in leafSection */ 426 PetscValidPointer(leafSection, 4); 427 PetscValidPointer(sectionSF, 5); 428 PetscCall(PetscObjectGetComm((PetscObject)sf, &comm)); 429 PetscCall(PetscSFCreate(comm, sectionSF)); 430 PetscCall(PetscSectionGetChart(leafSection, &lpStart, &lpEnd)); 431 PetscCall(PetscSectionGetStorageSize(rootSection, &numSectionRoots)); 432 PetscCall(PetscSFGetGraph(sf, &numRoots, &numPoints, &localPoints, &remotePoints)); 433 if (numRoots < 0) PetscFunctionReturn(0); 434 PetscCall(PetscLogEventBegin(PETSCSF_SectSF, sf, 0, 0, 0)); 435 for (i = 0; i < numPoints; ++i) { 436 PetscInt localPoint = localPoints ? localPoints[i] : i; 437 PetscInt dof; 438 439 if ((localPoint >= lpStart) && (localPoint < lpEnd)) { 440 PetscCall(PetscSectionGetDof(leafSection, localPoint, &dof)); 441 numIndices += dof < 0 ? 0 : dof; 442 } 443 } 444 PetscCall(PetscMalloc1(numIndices, &localIndices)); 445 PetscCall(PetscMalloc1(numIndices, &remoteIndices)); 446 /* Create new index graph */ 447 for (i = 0, ind = 0; i < numPoints; ++i) { 448 PetscInt localPoint = localPoints ? localPoints[i] : i; 449 PetscInt rank = remotePoints[i].rank; 450 451 if ((localPoint >= lpStart) && (localPoint < lpEnd)) { 452 PetscInt remoteOffset = remoteOffsets[localPoint - lpStart]; 453 PetscInt loff, dof, d; 454 455 PetscCall(PetscSectionGetOffset(leafSection, localPoint, &loff)); 456 PetscCall(PetscSectionGetDof(leafSection, localPoint, &dof)); 457 for (d = 0; d < dof; ++d, ++ind) { 458 localIndices[ind] = loff + d; 459 remoteIndices[ind].rank = rank; 460 remoteIndices[ind].index = remoteOffset + d; 461 } 462 } 463 } 464 PetscCheck(numIndices == ind, comm, PETSC_ERR_PLIB, "Inconsistency in indices, %" PetscInt_FMT " should be %" PetscInt_FMT, ind, numIndices); 465 PetscCall(PetscSFSetGraph(*sectionSF, numSectionRoots, numIndices, localIndices, PETSC_OWN_POINTER, remoteIndices, PETSC_OWN_POINTER)); 466 PetscCall(PetscSFSetUp(*sectionSF)); 467 PetscCall(PetscLogEventEnd(PETSCSF_SectSF, sf, 0, 0, 0)); 468 PetscFunctionReturn(0); 469 } 470 471 /*@C 472 PetscSFCreateFromLayouts - Creates a parallel star forest mapping two PetscLayout objects 473 474 Collective 475 476 Input Parameters: 477 + rmap - PetscLayout defining the global root space 478 - lmap - PetscLayout defining the global leaf space 479 480 Output Parameter: 481 . sf - The parallel star forest 482 483 Level: intermediate 484 485 .seealso: `PetscSFCreate()`, `PetscLayoutCreate()`, `PetscSFSetGraphLayout()` 486 @*/ 487 PetscErrorCode PetscSFCreateFromLayouts(PetscLayout rmap, PetscLayout lmap, PetscSF *sf) 488 { 489 PetscInt i, nroots, nleaves = 0; 490 PetscInt rN, lst, len; 491 PetscMPIInt owner = -1; 492 PetscSFNode *remote; 493 MPI_Comm rcomm = rmap->comm; 494 MPI_Comm lcomm = lmap->comm; 495 PetscMPIInt flg; 496 497 PetscFunctionBegin; 498 PetscValidPointer(sf, 3); 499 PetscCheck(rmap->setupcalled, rcomm, PETSC_ERR_ARG_WRONGSTATE, "Root layout not setup"); 500 PetscCheck(lmap->setupcalled, lcomm, PETSC_ERR_ARG_WRONGSTATE, "Leaf layout not setup"); 501 PetscCallMPI(MPI_Comm_compare(rcomm, lcomm, &flg)); 502 PetscCheck(flg == MPI_CONGRUENT || flg == MPI_IDENT, rcomm, PETSC_ERR_SUP, "cannot map two layouts with non-matching communicators"); 503 PetscCall(PetscSFCreate(rcomm, sf)); 504 PetscCall(PetscLayoutGetLocalSize(rmap, &nroots)); 505 PetscCall(PetscLayoutGetSize(rmap, &rN)); 506 PetscCall(PetscLayoutGetRange(lmap, &lst, &len)); 507 PetscCall(PetscMalloc1(len - lst, &remote)); 508 for (i = lst; i < len && i < rN; i++) { 509 if (owner < -1 || i >= rmap->range[owner + 1]) PetscCall(PetscLayoutFindOwner(rmap, i, &owner)); 510 remote[nleaves].rank = owner; 511 remote[nleaves].index = i - rmap->range[owner]; 512 nleaves++; 513 } 514 PetscCall(PetscSFSetGraph(*sf, nroots, nleaves, NULL, PETSC_OWN_POINTER, remote, PETSC_COPY_VALUES)); 515 PetscCall(PetscFree(remote)); 516 PetscFunctionReturn(0); 517 } 518 519 /* TODO: handle nooffprocentries like MatZeroRowsMapLocal_Private, since this code is the same */ 520 PetscErrorCode PetscLayoutMapLocal(PetscLayout map, PetscInt N, const PetscInt idxs[], PetscInt *on, PetscInt **oidxs, PetscInt **ogidxs) 521 { 522 PetscInt *owners = map->range; 523 PetscInt n = map->n; 524 PetscSF sf; 525 PetscInt *lidxs, *work = NULL; 526 PetscSFNode *ridxs; 527 PetscMPIInt rank, p = 0; 528 PetscInt r, len = 0; 529 530 PetscFunctionBegin; 531 if (on) *on = 0; /* squelch -Wmaybe-uninitialized */ 532 /* Create SF where leaves are input idxs and roots are owned idxs */ 533 PetscCallMPI(MPI_Comm_rank(map->comm, &rank)); 534 PetscCall(PetscMalloc1(n, &lidxs)); 535 for (r = 0; r < n; ++r) lidxs[r] = -1; 536 PetscCall(PetscMalloc1(N, &ridxs)); 537 for (r = 0; r < N; ++r) { 538 const PetscInt idx = idxs[r]; 539 PetscCheck(idx >= 0 && idx < map->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Index %" PetscInt_FMT " out of range [0,%" PetscInt_FMT ")", idx, map->N); 540 if (idx < owners[p] || owners[p + 1] <= idx) { /* short-circuit the search if the last p owns this idx too */ 541 PetscCall(PetscLayoutFindOwner(map, idx, &p)); 542 } 543 ridxs[r].rank = p; 544 ridxs[r].index = idxs[r] - owners[p]; 545 } 546 PetscCall(PetscSFCreate(map->comm, &sf)); 547 PetscCall(PetscSFSetGraph(sf, n, N, NULL, PETSC_OWN_POINTER, ridxs, PETSC_OWN_POINTER)); 548 PetscCall(PetscSFReduceBegin(sf, MPIU_INT, (PetscInt *)idxs, lidxs, MPI_LOR)); 549 PetscCall(PetscSFReduceEnd(sf, MPIU_INT, (PetscInt *)idxs, lidxs, MPI_LOR)); 550 if (ogidxs) { /* communicate global idxs */ 551 PetscInt cum = 0, start, *work2; 552 553 PetscCall(PetscMalloc1(n, &work)); 554 PetscCall(PetscCalloc1(N, &work2)); 555 for (r = 0; r < N; ++r) 556 if (idxs[r] >= 0) cum++; 557 PetscCallMPI(MPI_Scan(&cum, &start, 1, MPIU_INT, MPI_SUM, map->comm)); 558 start -= cum; 559 cum = 0; 560 for (r = 0; r < N; ++r) 561 if (idxs[r] >= 0) work2[r] = start + cum++; 562 PetscCall(PetscSFReduceBegin(sf, MPIU_INT, work2, work, MPI_REPLACE)); 563 PetscCall(PetscSFReduceEnd(sf, MPIU_INT, work2, work, MPI_REPLACE)); 564 PetscCall(PetscFree(work2)); 565 } 566 PetscCall(PetscSFDestroy(&sf)); 567 /* Compress and put in indices */ 568 for (r = 0; r < n; ++r) 569 if (lidxs[r] >= 0) { 570 if (work) work[len] = work[r]; 571 lidxs[len++] = r; 572 } 573 if (on) *on = len; 574 if (oidxs) *oidxs = lidxs; 575 if (ogidxs) *ogidxs = work; 576 PetscFunctionReturn(0); 577 } 578 579 /*@ 580 PetscSFCreateByMatchingIndices - Create SF by matching root and leaf indices 581 582 Collective 583 584 Input Parameters: 585 + layout - PetscLayout defining the global index space and the rank that brokers each index 586 . numRootIndices - size of rootIndices 587 . rootIndices - PetscInt array of global indices of which this process requests ownership 588 . rootLocalIndices - root local index permutation (NULL if no permutation) 589 . rootLocalOffset - offset to be added to root local indices 590 . numLeafIndices - size of leafIndices 591 . leafIndices - PetscInt array of global indices with which this process requires data associated 592 . leafLocalIndices - leaf local index permutation (NULL if no permutation) 593 - leafLocalOffset - offset to be added to leaf local indices 594 595 Output Parameters: 596 + sfA - star forest representing the communication pattern from the layout space to the leaf space (NULL if not needed) 597 - sf - star forest representing the communication pattern from the root space to the leaf space 598 599 Example 1: 600 $ 601 $ rank : 0 1 2 602 $ rootIndices : [1 0 2] [3] [3] 603 $ rootLocalOffset : 100 200 300 604 $ layout : [0 1] [2] [3] 605 $ leafIndices : [0] [2] [0 3] 606 $ leafLocalOffset : 400 500 600 607 $ 608 would build the following SF 609 $ 610 $ [0] 400 <- (0,101) 611 $ [1] 500 <- (0,102) 612 $ [2] 600 <- (0,101) 613 $ [2] 601 <- (2,300) 614 $ 615 Example 2: 616 $ 617 $ rank : 0 1 2 618 $ rootIndices : [1 0 2] [3] [3] 619 $ rootLocalOffset : 100 200 300 620 $ layout : [0 1] [2] [3] 621 $ leafIndices : rootIndices rootIndices rootIndices 622 $ leafLocalOffset : rootLocalOffset rootLocalOffset rootLocalOffset 623 $ 624 would build the following SF 625 $ 626 $ [1] 200 <- (2,300) 627 $ 628 Example 3: 629 $ 630 $ No process requests ownership of global index 1, but no process needs it. 631 $ 632 $ rank : 0 1 2 633 $ numRootIndices : 2 1 1 634 $ rootIndices : [0 2] [3] [3] 635 $ rootLocalOffset : 100 200 300 636 $ layout : [0 1] [2] [3] 637 $ numLeafIndices : 1 1 2 638 $ leafIndices : [0] [2] [0 3] 639 $ leafLocalOffset : 400 500 600 640 $ 641 would build the following SF 642 $ 643 $ [0] 400 <- (0,100) 644 $ [1] 500 <- (0,101) 645 $ [2] 600 <- (0,100) 646 $ [2] 601 <- (2,300) 647 $ 648 649 Notes: 650 The layout parameter represents any partitioning of [0, N), where N is the total number of global indices, and its 651 local size can be set to PETSC_DECIDE. 652 If a global index x lies in the partition owned by process i, each process whose rootIndices contains x requests 653 ownership of x and sends its own rank and the local index of x to process i. 654 If multiple processes request ownership of x, the one with the highest rank is to own x. 655 Process i then broadcasts the ownership information, so that each process whose leafIndices contains x knows the 656 ownership information of x. 657 The output sf is constructed by associating each leaf point to a root point in this way. 658 659 Suppose there is point data ordered according to the global indices and partitioned according to the given layout. 660 The optional output PetscSF object sfA can be used to push such data to leaf points. 661 662 All indices in rootIndices and leafIndices must lie in the layout range. The union (over all processes) of rootIndices 663 must cover that of leafIndices, but need not cover the entire layout. 664 665 If (leafIndices, leafLocalIndices, leafLocalOffset) == (rootIndices, rootLocalIndices, rootLocalOffset), the output 666 star forest is almost identity, so will only include non-trivial part of the map. 667 668 Developer Notes: 669 Current approach of a process of the highest rank gaining the ownership may cause load imbalance; consider using 670 hash(rank, root_local_index) as the bid for the ownership determination. 671 672 Level: advanced 673 674 .seealso: `PetscSFCreate()` 675 @*/ 676 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) 677 { 678 MPI_Comm comm = layout->comm; 679 PetscMPIInt size, rank; 680 PetscSF sf1; 681 PetscSFNode *owners, *buffer, *iremote; 682 PetscInt *ilocal, nleaves, N, n, i; 683 #if defined(PETSC_USE_DEBUG) 684 PetscInt N1; 685 #endif 686 PetscBool flag; 687 688 PetscFunctionBegin; 689 if (rootIndices) PetscValidIntPointer(rootIndices, 3); 690 if (rootLocalIndices) PetscValidIntPointer(rootLocalIndices, 4); 691 if (leafIndices) PetscValidIntPointer(leafIndices, 7); 692 if (leafLocalIndices) PetscValidIntPointer(leafLocalIndices, 8); 693 if (sfA) PetscValidPointer(sfA, 10); 694 PetscValidPointer(sf, 11); 695 PetscCheck(numRootIndices >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numRootIndices (%" PetscInt_FMT ") must be non-negative", numRootIndices); 696 PetscCheck(numLeafIndices >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numLeafIndices (%" PetscInt_FMT ") must be non-negative", numLeafIndices); 697 PetscCallMPI(MPI_Comm_size(comm, &size)); 698 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 699 PetscCall(PetscLayoutSetUp(layout)); 700 PetscCall(PetscLayoutGetSize(layout, &N)); 701 PetscCall(PetscLayoutGetLocalSize(layout, &n)); 702 flag = (PetscBool)(leafIndices == rootIndices); 703 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &flag, 1, MPIU_BOOL, MPI_LAND, comm)); 704 PetscCheck(!flag || numLeafIndices == numRootIndices, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "leafIndices == rootIndices, but numLeafIndices (%" PetscInt_FMT ") != numRootIndices(%" PetscInt_FMT ")", numLeafIndices, numRootIndices); 705 #if defined(PETSC_USE_DEBUG) 706 N1 = PETSC_MIN_INT; 707 for (i = 0; i < numRootIndices; i++) 708 if (rootIndices[i] > N1) N1 = rootIndices[i]; 709 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &N1, 1, MPIU_INT, MPI_MAX, comm)); 710 PetscCheck(N1 < N, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Max. root index (%" PetscInt_FMT ") out of layout range [0,%" PetscInt_FMT ")", N1, N); 711 if (!flag) { 712 N1 = PETSC_MIN_INT; 713 for (i = 0; i < numLeafIndices; i++) 714 if (leafIndices[i] > N1) N1 = leafIndices[i]; 715 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &N1, 1, MPIU_INT, MPI_MAX, comm)); 716 PetscCheck(N1 < N, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Max. leaf index (%" PetscInt_FMT ") out of layout range [0,%" PetscInt_FMT ")", N1, N); 717 } 718 #endif 719 /* Reduce: owners -> buffer */ 720 PetscCall(PetscMalloc1(n, &buffer)); 721 PetscCall(PetscSFCreate(comm, &sf1)); 722 PetscCall(PetscSFSetFromOptions(sf1)); 723 PetscCall(PetscSFSetGraphLayout(sf1, layout, numRootIndices, NULL, PETSC_OWN_POINTER, rootIndices)); 724 PetscCall(PetscMalloc1(numRootIndices, &owners)); 725 for (i = 0; i < numRootIndices; ++i) { 726 owners[i].rank = rank; 727 owners[i].index = rootLocalOffset + (rootLocalIndices ? rootLocalIndices[i] : i); 728 } 729 for (i = 0; i < n; ++i) { 730 buffer[i].index = -1; 731 buffer[i].rank = -1; 732 } 733 PetscCall(PetscSFReduceBegin(sf1, MPIU_2INT, owners, buffer, MPI_MAXLOC)); 734 PetscCall(PetscSFReduceEnd(sf1, MPIU_2INT, owners, buffer, MPI_MAXLOC)); 735 /* Bcast: buffer -> owners */ 736 if (!flag) { 737 /* leafIndices is different from rootIndices */ 738 PetscCall(PetscFree(owners)); 739 PetscCall(PetscSFSetGraphLayout(sf1, layout, numLeafIndices, NULL, PETSC_OWN_POINTER, leafIndices)); 740 PetscCall(PetscMalloc1(numLeafIndices, &owners)); 741 } 742 PetscCall(PetscSFBcastBegin(sf1, MPIU_2INT, buffer, owners, MPI_REPLACE)); 743 PetscCall(PetscSFBcastEnd(sf1, MPIU_2INT, buffer, owners, MPI_REPLACE)); 744 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]); 745 PetscCall(PetscFree(buffer)); 746 if (sfA) { 747 *sfA = sf1; 748 } else PetscCall(PetscSFDestroy(&sf1)); 749 /* Create sf */ 750 if (flag && rootLocalIndices == leafLocalIndices && leafLocalOffset == rootLocalOffset) { 751 /* leaf space == root space */ 752 for (i = 0, nleaves = 0; i < numLeafIndices; ++i) 753 if (owners[i].rank != rank) ++nleaves; 754 PetscCall(PetscMalloc1(nleaves, &ilocal)); 755 PetscCall(PetscMalloc1(nleaves, &iremote)); 756 for (i = 0, nleaves = 0; i < numLeafIndices; ++i) { 757 if (owners[i].rank != rank) { 758 ilocal[nleaves] = leafLocalOffset + i; 759 iremote[nleaves].rank = owners[i].rank; 760 iremote[nleaves].index = owners[i].index; 761 ++nleaves; 762 } 763 } 764 PetscCall(PetscFree(owners)); 765 } else { 766 nleaves = numLeafIndices; 767 PetscCall(PetscMalloc1(nleaves, &ilocal)); 768 for (i = 0; i < nleaves; ++i) ilocal[i] = leafLocalOffset + (leafLocalIndices ? leafLocalIndices[i] : i); 769 iremote = owners; 770 } 771 PetscCall(PetscSFCreate(comm, sf)); 772 PetscCall(PetscSFSetFromOptions(*sf)); 773 PetscCall(PetscSFSetGraph(*sf, rootLocalOffset + numRootIndices, nleaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER)); 774 PetscFunctionReturn(0); 775 } 776