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