1 #include <petsc/private/sfimpl.h> /*I "petscsf.h" I*/ 2 #include <petscctable.h> 3 4 #if defined(PETSC_USE_DEBUG) 5 # define PetscSFCheckGraphSet(sf,arg) do { \ 6 if (PetscUnlikely(!(sf)->graphset)) \ 7 SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call PetscSFSetGraph() on argument %D \"%s\" before %s()",(arg),#sf,PETSC_FUNCTION_NAME); \ 8 } while (0) 9 #else 10 # define PetscSFCheckGraphSet(sf,arg) do {} while (0) 11 #endif 12 13 const char *const PetscSFDuplicateOptions[] = {"CONFONLY","RANKS","GRAPH","PetscSFDuplicateOption","PETSCSF_DUPLICATE_",0}; 14 15 /*@ 16 PetscSFCreate - create a star forest communication context 17 18 Collective 19 20 Input Arguments: 21 . comm - communicator on which the star forest will operate 22 23 Output Arguments: 24 . sf - new star forest context 25 26 Level: intermediate 27 28 .seealso: PetscSFSetGraph(), PetscSFDestroy() 29 @*/ 30 PetscErrorCode PetscSFCreate(MPI_Comm comm,PetscSF *sf) 31 { 32 PetscErrorCode ierr; 33 PetscSF b; 34 35 PetscFunctionBegin; 36 PetscValidPointer(sf,2); 37 ierr = PetscSFInitializePackage();CHKERRQ(ierr); 38 39 ierr = PetscHeaderCreate(b,PETSCSF_CLASSID,"PetscSF","Star Forest","PetscSF",comm,PetscSFDestroy,PetscSFView);CHKERRQ(ierr); 40 41 b->nroots = -1; 42 b->nleaves = -1; 43 b->minleaf = PETSC_MAX_INT; 44 b->maxleaf = PETSC_MIN_INT; 45 b->nranks = -1; 46 b->rankorder = PETSC_TRUE; 47 b->ingroup = MPI_GROUP_NULL; 48 b->outgroup = MPI_GROUP_NULL; 49 b->graphset = PETSC_FALSE; 50 51 *sf = b; 52 PetscFunctionReturn(0); 53 } 54 55 /*@ 56 PetscSFReset - Reset a star forest so that different sizes or neighbors can be used 57 58 Collective 59 60 Input Arguments: 61 . sf - star forest 62 63 Level: advanced 64 65 .seealso: PetscSFCreate(), PetscSFSetGraph(), PetscSFDestroy() 66 @*/ 67 PetscErrorCode PetscSFReset(PetscSF sf) 68 { 69 PetscErrorCode ierr; 70 71 PetscFunctionBegin; 72 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 73 if (sf->ops->Reset) {ierr = (*sf->ops->Reset)(sf);CHKERRQ(ierr);} 74 sf->nroots = -1; 75 sf->nleaves = -1; 76 sf->minleaf = PETSC_MAX_INT; 77 sf->maxleaf = PETSC_MIN_INT; 78 sf->mine = NULL; 79 sf->remote = NULL; 80 sf->graphset = PETSC_FALSE; 81 ierr = PetscFree(sf->mine_alloc);CHKERRQ(ierr); 82 ierr = PetscFree(sf->remote_alloc);CHKERRQ(ierr); 83 sf->nranks = -1; 84 ierr = PetscFree4(sf->ranks,sf->roffset,sf->rmine,sf->rremote);CHKERRQ(ierr); 85 sf->degreeknown = PETSC_FALSE; 86 ierr = PetscFree(sf->degree);CHKERRQ(ierr); 87 if (sf->ingroup != MPI_GROUP_NULL) {ierr = MPI_Group_free(&sf->ingroup);CHKERRQ(ierr);} 88 if (sf->outgroup != MPI_GROUP_NULL) {ierr = MPI_Group_free(&sf->outgroup);CHKERRQ(ierr);} 89 ierr = PetscSFDestroy(&sf->multi);CHKERRQ(ierr); 90 sf->setupcalled = PETSC_FALSE; 91 PetscFunctionReturn(0); 92 } 93 94 /*@C 95 PetscSFSetType - Set the PetscSF communication implementation 96 97 Collective on PetscSF 98 99 Input Parameters: 100 + sf - the PetscSF context 101 - type - a known method 102 103 Options Database Key: 104 . -sf_type <type> - Sets the method; use -help for a list 105 of available methods (for instance, window, pt2pt, neighbor) 106 107 Notes: 108 See "include/petscsf.h" for available methods (for instance) 109 + PETSCSFWINDOW - MPI-2/3 one-sided 110 - PETSCSFBASIC - basic implementation using MPI-1 two-sided 111 112 Level: intermediate 113 114 .seealso: PetscSFType, PetscSFCreate() 115 @*/ 116 PetscErrorCode PetscSFSetType(PetscSF sf,PetscSFType type) 117 { 118 PetscErrorCode ierr,(*r)(PetscSF); 119 PetscBool match; 120 121 PetscFunctionBegin; 122 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 123 PetscValidCharPointer(type,2); 124 125 ierr = PetscObjectTypeCompare((PetscObject)sf,type,&match);CHKERRQ(ierr); 126 if (match) PetscFunctionReturn(0); 127 128 ierr = PetscFunctionListFind(PetscSFList,type,&r);CHKERRQ(ierr); 129 if (!r) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unable to find requested PetscSF type %s",type); 130 /* Destroy the previous PetscSF implementation context */ 131 if (sf->ops->Destroy) {ierr = (*(sf)->ops->Destroy)(sf);CHKERRQ(ierr);} 132 ierr = PetscMemzero(sf->ops,sizeof(*sf->ops));CHKERRQ(ierr); 133 ierr = PetscObjectChangeTypeName((PetscObject)sf,type);CHKERRQ(ierr); 134 ierr = (*r)(sf);CHKERRQ(ierr); 135 PetscFunctionReturn(0); 136 } 137 138 /*@C 139 PetscSFGetType - Get the PetscSF communication implementation 140 141 Not Collective 142 143 Input Parameter: 144 . sf - the PetscSF context 145 146 Output Parameter: 147 . type - the PetscSF type name 148 149 Level: intermediate 150 151 .seealso: PetscSFSetType(), PetscSFCreate() 152 @*/ 153 PetscErrorCode PetscSFGetType(PetscSF sf, PetscSFType *type) 154 { 155 PetscFunctionBegin; 156 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID,1); 157 PetscValidPointer(type,2); 158 *type = ((PetscObject)sf)->type_name; 159 PetscFunctionReturn(0); 160 } 161 162 /*@ 163 PetscSFDestroy - destroy star forest 164 165 Collective 166 167 Input Arguments: 168 . sf - address of star forest 169 170 Level: intermediate 171 172 .seealso: PetscSFCreate(), PetscSFReset() 173 @*/ 174 PetscErrorCode PetscSFDestroy(PetscSF *sf) 175 { 176 PetscErrorCode ierr; 177 178 PetscFunctionBegin; 179 if (!*sf) PetscFunctionReturn(0); 180 PetscValidHeaderSpecific((*sf),PETSCSF_CLASSID,1); 181 if (--((PetscObject)(*sf))->refct > 0) {*sf = NULL; PetscFunctionReturn(0);} 182 ierr = PetscSFReset(*sf);CHKERRQ(ierr); 183 if ((*sf)->ops->Destroy) {ierr = (*(*sf)->ops->Destroy)(*sf);CHKERRQ(ierr);} 184 ierr = PetscHeaderDestroy(sf);CHKERRQ(ierr); 185 PetscFunctionReturn(0); 186 } 187 188 /*@ 189 PetscSFSetUp - set up communication structures 190 191 Collective 192 193 Input Arguments: 194 . sf - star forest communication object 195 196 Level: beginner 197 198 .seealso: PetscSFSetFromOptions(), PetscSFSetType() 199 @*/ 200 PetscErrorCode PetscSFSetUp(PetscSF sf) 201 { 202 PetscErrorCode ierr; 203 204 PetscFunctionBegin; 205 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 206 PetscSFCheckGraphSet(sf,1); 207 if (sf->setupcalled) PetscFunctionReturn(0); 208 if (!((PetscObject)sf)->type_name) {ierr = PetscSFSetType(sf,PETSCSFBASIC);CHKERRQ(ierr);} 209 ierr = PetscLogEventBegin(PETSCSF_SetUp,sf,0,0,0);CHKERRQ(ierr); 210 if (sf->ops->SetUp) {ierr = (*sf->ops->SetUp)(sf);CHKERRQ(ierr);} 211 ierr = PetscLogEventEnd(PETSCSF_SetUp,sf,0,0,0);CHKERRQ(ierr); 212 sf->setupcalled = PETSC_TRUE; 213 PetscFunctionReturn(0); 214 } 215 216 /*@ 217 PetscSFSetFromOptions - set PetscSF options using the options database 218 219 Logically Collective 220 221 Input Arguments: 222 . sf - star forest 223 224 Options Database Keys: 225 + -sf_type - implementation type, see PetscSFSetType() 226 - -sf_rank_order - sort composite points for gathers and scatters in rank order, gathers are non-deterministic otherwise 227 228 Level: intermediate 229 230 .seealso: PetscSFWindowSetSyncType() 231 @*/ 232 PetscErrorCode PetscSFSetFromOptions(PetscSF sf) 233 { 234 PetscSFType deft; 235 char type[256]; 236 PetscErrorCode ierr; 237 PetscBool flg; 238 239 PetscFunctionBegin; 240 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 241 ierr = PetscObjectOptionsBegin((PetscObject)sf);CHKERRQ(ierr); 242 deft = ((PetscObject)sf)->type_name ? ((PetscObject)sf)->type_name : PETSCSFBASIC; 243 ierr = PetscOptionsFList("-sf_type","PetscSF implementation type","PetscSFSetType",PetscSFList,deft,type,sizeof(type),&flg);CHKERRQ(ierr); 244 ierr = PetscSFSetType(sf,flg ? type : deft);CHKERRQ(ierr); 245 ierr = PetscOptionsBool("-sf_rank_order","sort composite points for gathers and scatters in rank order, gathers are non-deterministic otherwise","PetscSFSetRankOrder",sf->rankorder,&sf->rankorder,NULL);CHKERRQ(ierr); 246 if (sf->ops->SetFromOptions) {ierr = (*sf->ops->SetFromOptions)(PetscOptionsObject,sf);CHKERRQ(ierr);} 247 ierr = PetscOptionsEnd();CHKERRQ(ierr); 248 PetscFunctionReturn(0); 249 } 250 251 /*@ 252 PetscSFSetRankOrder - sort multi-points for gathers and scatters by rank order 253 254 Logically Collective 255 256 Input Arguments: 257 + sf - star forest 258 - flg - PETSC_TRUE to sort, PETSC_FALSE to skip sorting (lower setup cost, but non-deterministic) 259 260 Level: advanced 261 262 .seealso: PetscSFGatherBegin(), PetscSFScatterBegin() 263 @*/ 264 PetscErrorCode PetscSFSetRankOrder(PetscSF sf,PetscBool flg) 265 { 266 267 PetscFunctionBegin; 268 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 269 PetscValidLogicalCollectiveBool(sf,flg,2); 270 if (sf->multi) SETERRQ(PetscObjectComm((PetscObject)sf),PETSC_ERR_ARG_WRONGSTATE,"Rank ordering must be set before first call to PetscSFGatherBegin() or PetscSFScatterBegin()"); 271 sf->rankorder = flg; 272 PetscFunctionReturn(0); 273 } 274 275 /*@ 276 PetscSFSetGraph - Set a parallel star forest 277 278 Collective 279 280 Input Arguments: 281 + sf - star forest 282 . nroots - number of root vertices on the current process (these are possible targets for other process to attach leaves) 283 . nleaves - number of leaf vertices on the current process, each of these references a root on any process 284 . ilocal - locations of leaves in leafdata buffers, pass NULL for contiguous storage 285 . localmode - copy mode for ilocal 286 . iremote - remote locations of root vertices for each leaf on the current process 287 - remotemode - copy mode for iremote 288 289 Level: intermediate 290 291 Notes: 292 In Fortran you must use PETSC_COPY_VALUES for localmode and remotemode 293 294 Developers Note: Local indices which are the identity permutation in the range [0,nleaves) are discarded as they 295 encode contiguous storage. In such case, if localmode is PETSC_OWN_POINTER, the memory is deallocated as it is not 296 needed 297 298 .seealso: PetscSFCreate(), PetscSFView(), PetscSFGetGraph() 299 @*/ 300 PetscErrorCode PetscSFSetGraph(PetscSF sf,PetscInt nroots,PetscInt nleaves,const PetscInt *ilocal,PetscCopyMode localmode,const PetscSFNode *iremote,PetscCopyMode remotemode) 301 { 302 PetscErrorCode ierr; 303 304 PetscFunctionBegin; 305 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 306 if (nleaves > 0 && ilocal) PetscValidIntPointer(ilocal,4); 307 if (nleaves > 0) PetscValidPointer(iremote,6); 308 if (nroots < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"nroots %D, cannot be negative",nroots); 309 if (nleaves < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"nleaves %D, cannot be negative",nleaves); 310 311 ierr = PetscSFReset(sf);CHKERRQ(ierr); 312 ierr = PetscLogEventBegin(PETSCSF_SetGraph,sf,0,0,0);CHKERRQ(ierr); 313 314 sf->nroots = nroots; 315 sf->nleaves = nleaves; 316 317 if (nleaves && ilocal) { 318 PetscInt i; 319 PetscInt minleaf = PETSC_MAX_INT; 320 PetscInt maxleaf = PETSC_MIN_INT; 321 int contiguous = 1; 322 for (i=0; i<nleaves; i++) { 323 minleaf = PetscMin(minleaf,ilocal[i]); 324 maxleaf = PetscMax(maxleaf,ilocal[i]); 325 contiguous &= (ilocal[i] == i); 326 } 327 sf->minleaf = minleaf; 328 sf->maxleaf = maxleaf; 329 if (contiguous) { 330 if (localmode == PETSC_OWN_POINTER) { 331 ierr = PetscFree(ilocal);CHKERRQ(ierr); 332 } 333 ilocal = NULL; 334 } 335 } else { 336 sf->minleaf = 0; 337 sf->maxleaf = nleaves - 1; 338 } 339 340 if (ilocal) { 341 switch (localmode) { 342 case PETSC_COPY_VALUES: 343 ierr = PetscMalloc1(nleaves,&sf->mine_alloc);CHKERRQ(ierr); 344 ierr = PetscArraycpy(sf->mine_alloc,ilocal,nleaves);CHKERRQ(ierr); 345 sf->mine = sf->mine_alloc; 346 break; 347 case PETSC_OWN_POINTER: 348 sf->mine_alloc = (PetscInt*)ilocal; 349 sf->mine = sf->mine_alloc; 350 break; 351 case PETSC_USE_POINTER: 352 sf->mine_alloc = NULL; 353 sf->mine = (PetscInt*)ilocal; 354 break; 355 default: SETERRQ(PetscObjectComm((PetscObject)sf),PETSC_ERR_ARG_OUTOFRANGE,"Unknown localmode"); 356 } 357 } 358 359 switch (remotemode) { 360 case PETSC_COPY_VALUES: 361 ierr = PetscMalloc1(nleaves,&sf->remote_alloc);CHKERRQ(ierr); 362 ierr = PetscArraycpy(sf->remote_alloc,iremote,nleaves);CHKERRQ(ierr); 363 sf->remote = sf->remote_alloc; 364 break; 365 case PETSC_OWN_POINTER: 366 sf->remote_alloc = (PetscSFNode*)iremote; 367 sf->remote = sf->remote_alloc; 368 break; 369 case PETSC_USE_POINTER: 370 sf->remote_alloc = NULL; 371 sf->remote = (PetscSFNode*)iremote; 372 break; 373 default: SETERRQ(PetscObjectComm((PetscObject)sf),PETSC_ERR_ARG_OUTOFRANGE,"Unknown remotemode"); 374 } 375 376 ierr = PetscLogEventEnd(PETSCSF_SetGraph,sf,0,0,0);CHKERRQ(ierr); 377 sf->graphset = PETSC_TRUE; 378 PetscFunctionReturn(0); 379 } 380 381 /*@ 382 PetscSFCreateInverseSF - given a PetscSF in which all vertices have degree 1, creates the inverse map 383 384 Collective 385 386 Input Arguments: 387 . sf - star forest to invert 388 389 Output Arguments: 390 . isf - inverse of sf 391 392 Level: advanced 393 394 Notes: 395 All roots must have degree 1. 396 397 The local space may be a permutation, but cannot be sparse. 398 399 .seealso: PetscSFSetGraph() 400 @*/ 401 PetscErrorCode PetscSFCreateInverseSF(PetscSF sf,PetscSF *isf) 402 { 403 PetscErrorCode ierr; 404 PetscMPIInt rank; 405 PetscInt i,nroots,nleaves,maxlocal,count,*newilocal; 406 const PetscInt *ilocal; 407 PetscSFNode *roots,*leaves; 408 409 PetscFunctionBegin; 410 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 411 PetscSFCheckGraphSet(sf,1); 412 PetscValidPointer(isf,2); 413 414 ierr = PetscSFGetGraph(sf,&nroots,&nleaves,&ilocal,NULL);CHKERRQ(ierr); 415 maxlocal = sf->maxleaf+1; /* TODO: We should use PetscSFGetLeafRange() */ 416 417 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)sf),&rank);CHKERRQ(ierr); 418 ierr = PetscMalloc2(nroots,&roots,maxlocal,&leaves);CHKERRQ(ierr); 419 for (i=0; i<maxlocal; i++) { 420 leaves[i].rank = rank; 421 leaves[i].index = i; 422 } 423 for (i=0; i <nroots; i++) { 424 roots[i].rank = -1; 425 roots[i].index = -1; 426 } 427 ierr = PetscSFReduceBegin(sf,MPIU_2INT,leaves,roots,MPIU_REPLACE);CHKERRQ(ierr); 428 ierr = PetscSFReduceEnd(sf,MPIU_2INT,leaves,roots,MPIU_REPLACE);CHKERRQ(ierr); 429 430 /* Check whether our leaves are sparse */ 431 for (i=0,count=0; i<nroots; i++) if (roots[i].rank >= 0) count++; 432 if (count == nroots) newilocal = NULL; 433 else { /* Index for sparse leaves and compact "roots" array (which is to become our leaves). */ 434 ierr = PetscMalloc1(count,&newilocal);CHKERRQ(ierr); 435 for (i=0,count=0; i<nroots; i++) { 436 if (roots[i].rank >= 0) { 437 newilocal[count] = i; 438 roots[count].rank = roots[i].rank; 439 roots[count].index = roots[i].index; 440 count++; 441 } 442 } 443 } 444 445 ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_CONFONLY,isf);CHKERRQ(ierr); 446 ierr = PetscSFSetGraph(*isf,maxlocal,count,newilocal,PETSC_OWN_POINTER,roots,PETSC_COPY_VALUES);CHKERRQ(ierr); 447 ierr = PetscFree2(roots,leaves);CHKERRQ(ierr); 448 PetscFunctionReturn(0); 449 } 450 451 /*@ 452 PetscSFDuplicate - duplicate a PetscSF, optionally preserving rank connectivity and graph 453 454 Collective 455 456 Input Arguments: 457 + sf - communication object to duplicate 458 - opt - PETSCSF_DUPLICATE_CONFONLY, PETSCSF_DUPLICATE_RANKS, or PETSCSF_DUPLICATE_GRAPH (see PetscSFDuplicateOption) 459 460 Output Arguments: 461 . newsf - new communication object 462 463 Level: beginner 464 465 .seealso: PetscSFCreate(), PetscSFSetType(), PetscSFSetGraph() 466 @*/ 467 PetscErrorCode PetscSFDuplicate(PetscSF sf,PetscSFDuplicateOption opt,PetscSF *newsf) 468 { 469 PetscSFType type; 470 PetscErrorCode ierr; 471 472 PetscFunctionBegin; 473 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 474 PetscValidLogicalCollectiveEnum(sf,opt,2); 475 PetscValidPointer(newsf,3); 476 ierr = PetscSFCreate(PetscObjectComm((PetscObject)sf),newsf);CHKERRQ(ierr); 477 ierr = PetscSFGetType(sf,&type);CHKERRQ(ierr); 478 if (type) {ierr = PetscSFSetType(*newsf,type);CHKERRQ(ierr);} 479 if (opt == PETSCSF_DUPLICATE_GRAPH) { 480 PetscInt nroots,nleaves; 481 const PetscInt *ilocal; 482 const PetscSFNode *iremote; 483 PetscSFCheckGraphSet(sf,1); 484 ierr = PetscSFGetGraph(sf,&nroots,&nleaves,&ilocal,&iremote);CHKERRQ(ierr); 485 ierr = PetscSFSetGraph(*newsf,nroots,nleaves,ilocal,PETSC_COPY_VALUES,iremote,PETSC_COPY_VALUES);CHKERRQ(ierr); 486 } 487 if (sf->ops->Duplicate) {ierr = (*sf->ops->Duplicate)(sf,opt,*newsf);CHKERRQ(ierr);} 488 PetscFunctionReturn(0); 489 } 490 491 /*@C 492 PetscSFGetGraph - Get the graph specifying a parallel star forest 493 494 Not Collective 495 496 Input Arguments: 497 . sf - star forest 498 499 Output Arguments: 500 + nroots - number of root vertices on the current process (these are possible targets for other process to attach leaves) 501 . nleaves - number of leaf vertices on the current process, each of these references a root on any process 502 . ilocal - locations of leaves in leafdata buffers 503 - iremote - remote locations of root vertices for each leaf on the current process 504 505 Notes: 506 We are not currently requiring that the graph is set, thus returning nroots=-1 if it has not been set yet 507 508 Level: intermediate 509 510 .seealso: PetscSFCreate(), PetscSFView(), PetscSFSetGraph() 511 @*/ 512 PetscErrorCode PetscSFGetGraph(PetscSF sf,PetscInt *nroots,PetscInt *nleaves,const PetscInt **ilocal,const PetscSFNode **iremote) 513 { 514 515 PetscFunctionBegin; 516 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 517 if (nroots) *nroots = sf->nroots; 518 if (nleaves) *nleaves = sf->nleaves; 519 if (ilocal) *ilocal = sf->mine; 520 if (iremote) *iremote = sf->remote; 521 PetscFunctionReturn(0); 522 } 523 524 /*@ 525 PetscSFGetLeafRange - Get the active leaf ranges 526 527 Not Collective 528 529 Input Arguments: 530 . sf - star forest 531 532 Output Arguments: 533 + minleaf - minimum active leaf on this process 534 - maxleaf - maximum active leaf on this process 535 536 Level: developer 537 538 .seealso: PetscSFCreate(), PetscSFView(), PetscSFSetGraph(), PetscSFGetGraph() 539 @*/ 540 PetscErrorCode PetscSFGetLeafRange(PetscSF sf,PetscInt *minleaf,PetscInt *maxleaf) 541 { 542 543 PetscFunctionBegin; 544 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 545 PetscSFCheckGraphSet(sf,1); 546 if (minleaf) *minleaf = sf->minleaf; 547 if (maxleaf) *maxleaf = sf->maxleaf; 548 PetscFunctionReturn(0); 549 } 550 551 /*@C 552 PetscSFView - view a star forest 553 554 Collective 555 556 Input Arguments: 557 + sf - star forest 558 - viewer - viewer to display graph, for example PETSC_VIEWER_STDOUT_WORLD 559 560 Level: beginner 561 562 .seealso: PetscSFCreate(), PetscSFSetGraph() 563 @*/ 564 PetscErrorCode PetscSFView(PetscSF sf,PetscViewer viewer) 565 { 566 PetscErrorCode ierr; 567 PetscBool iascii; 568 PetscViewerFormat format; 569 570 PetscFunctionBegin; 571 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 572 if (!viewer) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sf),&viewer);CHKERRQ(ierr);} 573 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 574 PetscCheckSameComm(sf,1,viewer,2); 575 if (sf->graphset) {ierr = PetscSFSetUp(sf);CHKERRQ(ierr);} 576 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 577 if (iascii) { 578 PetscMPIInt rank; 579 PetscInt ii,i,j; 580 581 ierr = PetscObjectPrintClassNamePrefixType((PetscObject)sf,viewer);CHKERRQ(ierr); 582 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 583 if (sf->ops->View) {ierr = (*sf->ops->View)(sf,viewer);CHKERRQ(ierr);} 584 if (!sf->graphset) { 585 ierr = PetscViewerASCIIPrintf(viewer,"PetscSFSetGraph() has not been called yet\n");CHKERRQ(ierr); 586 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 587 PetscFunctionReturn(0); 588 } 589 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)sf),&rank);CHKERRQ(ierr); 590 ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr); 591 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Number of roots=%D, leaves=%D, remote ranks=%D\n",rank,sf->nroots,sf->nleaves,sf->nranks);CHKERRQ(ierr); 592 for (i=0; i<sf->nleaves; i++) { 593 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] %D <- (%D,%D)\n",rank,sf->mine ? sf->mine[i] : i,sf->remote[i].rank,sf->remote[i].index);CHKERRQ(ierr); 594 } 595 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 596 ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr); 597 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 598 PetscMPIInt *tmpranks,*perm; 599 ierr = PetscMalloc2(sf->nranks,&tmpranks,sf->nranks,&perm);CHKERRQ(ierr); 600 ierr = PetscArraycpy(tmpranks,sf->ranks,sf->nranks);CHKERRQ(ierr); 601 for (i=0; i<sf->nranks; i++) perm[i] = i; 602 ierr = PetscSortMPIIntWithArray(sf->nranks,tmpranks,perm);CHKERRQ(ierr); 603 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Roots referenced by my leaves, by rank\n",rank);CHKERRQ(ierr); 604 for (ii=0; ii<sf->nranks; ii++) { 605 i = perm[ii]; 606 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] %d: %D edges\n",rank,sf->ranks[i],sf->roffset[i+1]-sf->roffset[i]);CHKERRQ(ierr); 607 for (j=sf->roffset[i]; j<sf->roffset[i+1]; j++) { 608 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] %D <- %D\n",rank,sf->rmine[j],sf->rremote[j]);CHKERRQ(ierr); 609 } 610 } 611 ierr = PetscFree2(tmpranks,perm);CHKERRQ(ierr); 612 } 613 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 614 ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr); 615 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 616 } 617 PetscFunctionReturn(0); 618 } 619 620 /*@C 621 PetscSFGetRootRanks - Get root ranks and number of vertices referenced by leaves on this process 622 623 Not Collective 624 625 Input Arguments: 626 . sf - star forest 627 628 Output Arguments: 629 + nranks - number of ranks referenced by local part 630 . ranks - array of ranks 631 . roffset - offset in rmine/rremote for each rank (length nranks+1) 632 . rmine - concatenated array holding local indices referencing each remote rank 633 - rremote - concatenated array holding remote indices referenced for each remote rank 634 635 Level: developer 636 637 .seealso: PetscSFGetLeafRanks() 638 @*/ 639 PetscErrorCode PetscSFGetRootRanks(PetscSF sf,PetscInt *nranks,const PetscMPIInt **ranks,const PetscInt **roffset,const PetscInt **rmine,const PetscInt **rremote) 640 { 641 PetscErrorCode ierr; 642 643 PetscFunctionBegin; 644 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 645 if (!sf->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call PetscSFSetUp() before obtaining ranks"); 646 if (sf->ops->GetRootRanks) { 647 ierr = (sf->ops->GetRootRanks)(sf,nranks,ranks,roffset,rmine,rremote);CHKERRQ(ierr); 648 } else { 649 /* The generic implementation */ 650 if (nranks) *nranks = sf->nranks; 651 if (ranks) *ranks = sf->ranks; 652 if (roffset) *roffset = sf->roffset; 653 if (rmine) *rmine = sf->rmine; 654 if (rremote) *rremote = sf->rremote; 655 } 656 PetscFunctionReturn(0); 657 } 658 659 /*@C 660 PetscSFGetLeafRanks - Get leaf ranks referencing roots on this process 661 662 Not Collective 663 664 Input Arguments: 665 . sf - star forest 666 667 Output Arguments: 668 + niranks - number of leaf ranks referencing roots on this process 669 . iranks - array of ranks 670 . ioffset - offset in irootloc for each rank (length niranks+1) 671 - irootloc - concatenated array holding local indices of roots referenced by each leaf rank 672 673 Level: developer 674 675 .seealso: PetscSFGetRootRanks() 676 @*/ 677 PetscErrorCode PetscSFGetLeafRanks(PetscSF sf,PetscInt *niranks,const PetscMPIInt **iranks,const PetscInt **ioffset,const PetscInt **irootloc) 678 { 679 PetscErrorCode ierr; 680 681 PetscFunctionBegin; 682 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 683 if (!sf->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call PetscSFSetUp() before obtaining ranks"); 684 if (sf->ops->GetLeafRanks) { 685 ierr = (sf->ops->GetLeafRanks)(sf,niranks,iranks,ioffset,irootloc);CHKERRQ(ierr); 686 } else { 687 PetscSFType type; 688 ierr = PetscSFGetType(sf,&type);CHKERRQ(ierr); 689 SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"PetscSFGetLeafRanks() is not supported on this StarForest type: %s", type); 690 } 691 PetscFunctionReturn(0); 692 } 693 694 static PetscBool InList(PetscMPIInt needle,PetscMPIInt n,const PetscMPIInt *list) { 695 PetscInt i; 696 for (i=0; i<n; i++) { 697 if (needle == list[i]) return PETSC_TRUE; 698 } 699 return PETSC_FALSE; 700 } 701 702 /*@C 703 PetscSFSetUpRanks - Set up data structures associated with ranks; this is for internal use by PetscSF implementations. 704 705 Collective 706 707 Input Arguments: 708 + sf - PetscSF to set up; PetscSFSetGraph() must have been called 709 - dgroup - MPI_Group of ranks to be distinguished (e.g., for self or shared memory exchange) 710 711 Level: developer 712 713 .seealso: PetscSFGetRootRanks() 714 @*/ 715 PetscErrorCode PetscSFSetUpRanks(PetscSF sf,MPI_Group dgroup) 716 { 717 PetscErrorCode ierr; 718 PetscTable table; 719 PetscTablePosition pos; 720 PetscMPIInt size,groupsize,*groupranks; 721 PetscInt *rcount,*ranks; 722 PetscInt i, irank = -1,orank = -1; 723 724 PetscFunctionBegin; 725 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 726 PetscSFCheckGraphSet(sf,1); 727 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)sf),&size);CHKERRQ(ierr); 728 ierr = PetscTableCreate(10,size,&table);CHKERRQ(ierr); 729 for (i=0; i<sf->nleaves; i++) { 730 /* Log 1-based rank */ 731 ierr = PetscTableAdd(table,sf->remote[i].rank+1,1,ADD_VALUES);CHKERRQ(ierr); 732 } 733 ierr = PetscTableGetCount(table,&sf->nranks);CHKERRQ(ierr); 734 ierr = PetscMalloc4(sf->nranks,&sf->ranks,sf->nranks+1,&sf->roffset,sf->nleaves,&sf->rmine,sf->nleaves,&sf->rremote);CHKERRQ(ierr); 735 ierr = PetscMalloc2(sf->nranks,&rcount,sf->nranks,&ranks);CHKERRQ(ierr); 736 ierr = PetscTableGetHeadPosition(table,&pos);CHKERRQ(ierr); 737 for (i=0; i<sf->nranks; i++) { 738 ierr = PetscTableGetNext(table,&pos,&ranks[i],&rcount[i]);CHKERRQ(ierr); 739 ranks[i]--; /* Convert back to 0-based */ 740 } 741 ierr = PetscTableDestroy(&table);CHKERRQ(ierr); 742 743 /* We expect that dgroup is reliably "small" while nranks could be large */ 744 { 745 MPI_Group group = MPI_GROUP_NULL; 746 PetscMPIInt *dgroupranks; 747 ierr = MPI_Comm_group(PetscObjectComm((PetscObject)sf),&group);CHKERRQ(ierr); 748 ierr = MPI_Group_size(dgroup,&groupsize);CHKERRQ(ierr); 749 ierr = PetscMalloc1(groupsize,&dgroupranks);CHKERRQ(ierr); 750 ierr = PetscMalloc1(groupsize,&groupranks);CHKERRQ(ierr); 751 for (i=0; i<groupsize; i++) dgroupranks[i] = i; 752 if (groupsize) {ierr = MPI_Group_translate_ranks(dgroup,groupsize,dgroupranks,group,groupranks);CHKERRQ(ierr);} 753 ierr = MPI_Group_free(&group);CHKERRQ(ierr); 754 ierr = PetscFree(dgroupranks);CHKERRQ(ierr); 755 } 756 757 /* Partition ranks[] into distinguished (first sf->ndranks) followed by non-distinguished */ 758 for (sf->ndranks=0,i=sf->nranks; sf->ndranks<i; ) { 759 for (i--; sf->ndranks<i; i--) { /* Scan i backward looking for distinguished rank */ 760 if (InList(ranks[i],groupsize,groupranks)) break; 761 } 762 for ( ; sf->ndranks<=i; sf->ndranks++) { /* Scan sf->ndranks forward looking for non-distinguished rank */ 763 if (!InList(ranks[sf->ndranks],groupsize,groupranks)) break; 764 } 765 if (sf->ndranks < i) { /* Swap ranks[sf->ndranks] with ranks[i] */ 766 PetscInt tmprank,tmpcount; 767 768 tmprank = ranks[i]; 769 tmpcount = rcount[i]; 770 ranks[i] = ranks[sf->ndranks]; 771 rcount[i] = rcount[sf->ndranks]; 772 ranks[sf->ndranks] = tmprank; 773 rcount[sf->ndranks] = tmpcount; 774 sf->ndranks++; 775 } 776 } 777 ierr = PetscFree(groupranks);CHKERRQ(ierr); 778 ierr = PetscSortIntWithArray(sf->ndranks,ranks,rcount);CHKERRQ(ierr); 779 ierr = PetscSortIntWithArray(sf->nranks-sf->ndranks,ranks+sf->ndranks,rcount+sf->ndranks);CHKERRQ(ierr); 780 sf->roffset[0] = 0; 781 for (i=0; i<sf->nranks; i++) { 782 ierr = PetscMPIIntCast(ranks[i],sf->ranks+i);CHKERRQ(ierr); 783 sf->roffset[i+1] = sf->roffset[i] + rcount[i]; 784 rcount[i] = 0; 785 } 786 for (i=0, irank = -1, orank = -1; i<sf->nleaves; i++) { 787 /* short circuit */ 788 if (orank != sf->remote[i].rank) { 789 /* Search for index of iremote[i].rank in sf->ranks */ 790 ierr = PetscFindMPIInt(sf->remote[i].rank,sf->ndranks,sf->ranks,&irank);CHKERRQ(ierr); 791 if (irank < 0) { 792 ierr = PetscFindMPIInt(sf->remote[i].rank,sf->nranks-sf->ndranks,sf->ranks+sf->ndranks,&irank);CHKERRQ(ierr); 793 if (irank >= 0) irank += sf->ndranks; 794 } 795 orank = sf->remote[i].rank; 796 } 797 if (irank < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not find rank %D in array",sf->remote[i].rank); 798 sf->rmine[sf->roffset[irank] + rcount[irank]] = sf->mine ? sf->mine[i] : i; 799 sf->rremote[sf->roffset[irank] + rcount[irank]] = sf->remote[i].index; 800 rcount[irank]++; 801 } 802 ierr = PetscFree2(rcount,ranks);CHKERRQ(ierr); 803 PetscFunctionReturn(0); 804 } 805 806 /*@C 807 PetscSFGetGroups - gets incoming and outgoing process groups 808 809 Collective 810 811 Input Argument: 812 . sf - star forest 813 814 Output Arguments: 815 + incoming - group of origin processes for incoming edges (leaves that reference my roots) 816 - outgoing - group of destination processes for outgoing edges (roots that I reference) 817 818 Level: developer 819 820 .seealso: PetscSFGetWindow(), PetscSFRestoreWindow() 821 @*/ 822 PetscErrorCode PetscSFGetGroups(PetscSF sf,MPI_Group *incoming,MPI_Group *outgoing) 823 { 824 PetscErrorCode ierr; 825 MPI_Group group = MPI_GROUP_NULL; 826 827 PetscFunctionBegin; 828 if (!sf->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call PetscSFSetUp() before obtaining groups"); 829 if (sf->ingroup == MPI_GROUP_NULL) { 830 PetscInt i; 831 const PetscInt *indegree; 832 PetscMPIInt rank,*outranks,*inranks; 833 PetscSFNode *remote; 834 PetscSF bgcount; 835 836 /* Compute the number of incoming ranks */ 837 ierr = PetscMalloc1(sf->nranks,&remote);CHKERRQ(ierr); 838 for (i=0; i<sf->nranks; i++) { 839 remote[i].rank = sf->ranks[i]; 840 remote[i].index = 0; 841 } 842 ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_CONFONLY,&bgcount);CHKERRQ(ierr); 843 ierr = PetscSFSetGraph(bgcount,1,sf->nranks,NULL,PETSC_COPY_VALUES,remote,PETSC_OWN_POINTER);CHKERRQ(ierr); 844 ierr = PetscSFComputeDegreeBegin(bgcount,&indegree);CHKERRQ(ierr); 845 ierr = PetscSFComputeDegreeEnd(bgcount,&indegree);CHKERRQ(ierr); 846 847 /* Enumerate the incoming ranks */ 848 ierr = PetscMalloc2(indegree[0],&inranks,sf->nranks,&outranks);CHKERRQ(ierr); 849 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)sf),&rank);CHKERRQ(ierr); 850 for (i=0; i<sf->nranks; i++) outranks[i] = rank; 851 ierr = PetscSFGatherBegin(bgcount,MPI_INT,outranks,inranks);CHKERRQ(ierr); 852 ierr = PetscSFGatherEnd(bgcount,MPI_INT,outranks,inranks);CHKERRQ(ierr); 853 ierr = MPI_Comm_group(PetscObjectComm((PetscObject)sf),&group);CHKERRQ(ierr); 854 ierr = MPI_Group_incl(group,indegree[0],inranks,&sf->ingroup);CHKERRQ(ierr); 855 ierr = MPI_Group_free(&group);CHKERRQ(ierr); 856 ierr = PetscFree2(inranks,outranks);CHKERRQ(ierr); 857 ierr = PetscSFDestroy(&bgcount);CHKERRQ(ierr); 858 } 859 *incoming = sf->ingroup; 860 861 if (sf->outgroup == MPI_GROUP_NULL) { 862 ierr = MPI_Comm_group(PetscObjectComm((PetscObject)sf),&group);CHKERRQ(ierr); 863 ierr = MPI_Group_incl(group,sf->nranks,sf->ranks,&sf->outgroup);CHKERRQ(ierr); 864 ierr = MPI_Group_free(&group);CHKERRQ(ierr); 865 } 866 *outgoing = sf->outgroup; 867 PetscFunctionReturn(0); 868 } 869 870 /*@ 871 PetscSFGetMultiSF - gets the inner SF implemeting gathers and scatters 872 873 Collective 874 875 Input Argument: 876 . sf - star forest that may contain roots with 0 or with more than 1 vertex 877 878 Output Arguments: 879 . multi - star forest with split roots, such that each root has degree exactly 1 880 881 Level: developer 882 883 Notes: 884 885 In most cases, users should use PetscSFGatherBegin() and PetscSFScatterBegin() instead of manipulating multi 886 directly. Since multi satisfies the stronger condition that each entry in the global space has exactly one incoming 887 edge, it is a candidate for future optimization that might involve its removal. 888 889 .seealso: PetscSFSetGraph(), PetscSFGatherBegin(), PetscSFScatterBegin(), PetscSFComputeMultiRootOriginalNumbering() 890 @*/ 891 PetscErrorCode PetscSFGetMultiSF(PetscSF sf,PetscSF *multi) 892 { 893 PetscErrorCode ierr; 894 895 PetscFunctionBegin; 896 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 897 PetscValidPointer(multi,2); 898 if (sf->nroots < 0) { /* Graph has not been set yet; why do we need this? */ 899 ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_RANKS,&sf->multi);CHKERRQ(ierr); 900 *multi = sf->multi; 901 PetscFunctionReturn(0); 902 } 903 if (!sf->multi) { 904 const PetscInt *indegree; 905 PetscInt i,*inoffset,*outones,*outoffset,maxlocal; 906 PetscSFNode *remote; 907 maxlocal = sf->maxleaf+1; /* TODO: We should use PetscSFGetLeafRange() */ 908 ierr = PetscSFComputeDegreeBegin(sf,&indegree);CHKERRQ(ierr); 909 ierr = PetscSFComputeDegreeEnd(sf,&indegree);CHKERRQ(ierr); 910 ierr = PetscMalloc3(sf->nroots+1,&inoffset,maxlocal,&outones,maxlocal,&outoffset);CHKERRQ(ierr); 911 inoffset[0] = 0; 912 for (i=0; i<sf->nroots; i++) inoffset[i+1] = inoffset[i] + indegree[i]; 913 for (i=0; i<maxlocal; i++) outones[i] = 1; 914 ierr = PetscSFFetchAndOpBegin(sf,MPIU_INT,inoffset,outones,outoffset,MPI_SUM);CHKERRQ(ierr); 915 ierr = PetscSFFetchAndOpEnd(sf,MPIU_INT,inoffset,outones,outoffset,MPI_SUM);CHKERRQ(ierr); 916 for (i=0; i<sf->nroots; i++) inoffset[i] -= indegree[i]; /* Undo the increment */ 917 #if 0 918 #if defined(PETSC_USE_DEBUG) /* Check that the expected number of increments occurred */ 919 for (i=0; i<sf->nroots; i++) { 920 if (inoffset[i] + indegree[i] != inoffset[i+1]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Incorrect result after PetscSFFetchAndOp"); 921 } 922 #endif 923 #endif 924 ierr = PetscMalloc1(sf->nleaves,&remote);CHKERRQ(ierr); 925 for (i=0; i<sf->nleaves; i++) { 926 remote[i].rank = sf->remote[i].rank; 927 remote[i].index = outoffset[sf->mine ? sf->mine[i] : i]; 928 } 929 ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_RANKS,&sf->multi);CHKERRQ(ierr); 930 ierr = PetscSFSetGraph(sf->multi,inoffset[sf->nroots],sf->nleaves,sf->mine,PETSC_COPY_VALUES,remote,PETSC_OWN_POINTER);CHKERRQ(ierr); 931 if (sf->rankorder) { /* Sort the ranks */ 932 PetscMPIInt rank; 933 PetscInt *inranks,*newoffset,*outranks,*newoutoffset,*tmpoffset,maxdegree; 934 PetscSFNode *newremote; 935 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)sf),&rank);CHKERRQ(ierr); 936 for (i=0,maxdegree=0; i<sf->nroots; i++) maxdegree = PetscMax(maxdegree,indegree[i]); 937 ierr = PetscMalloc5(sf->multi->nroots,&inranks,sf->multi->nroots,&newoffset,maxlocal,&outranks,maxlocal,&newoutoffset,maxdegree,&tmpoffset);CHKERRQ(ierr); 938 for (i=0; i<maxlocal; i++) outranks[i] = rank; 939 ierr = PetscSFReduceBegin(sf->multi,MPIU_INT,outranks,inranks,MPIU_REPLACE);CHKERRQ(ierr); 940 ierr = PetscSFReduceEnd(sf->multi,MPIU_INT,outranks,inranks,MPIU_REPLACE);CHKERRQ(ierr); 941 /* Sort the incoming ranks at each vertex, build the inverse map */ 942 for (i=0; i<sf->nroots; i++) { 943 PetscInt j; 944 for (j=0; j<indegree[i]; j++) tmpoffset[j] = j; 945 ierr = PetscSortIntWithArray(indegree[i],inranks+inoffset[i],tmpoffset);CHKERRQ(ierr); 946 for (j=0; j<indegree[i]; j++) newoffset[inoffset[i] + tmpoffset[j]] = inoffset[i] + j; 947 } 948 ierr = PetscSFBcastBegin(sf->multi,MPIU_INT,newoffset,newoutoffset);CHKERRQ(ierr); 949 ierr = PetscSFBcastEnd(sf->multi,MPIU_INT,newoffset,newoutoffset);CHKERRQ(ierr); 950 ierr = PetscMalloc1(sf->nleaves,&newremote);CHKERRQ(ierr); 951 for (i=0; i<sf->nleaves; i++) { 952 newremote[i].rank = sf->remote[i].rank; 953 newremote[i].index = newoutoffset[sf->mine ? sf->mine[i] : i]; 954 } 955 ierr = PetscSFSetGraph(sf->multi,inoffset[sf->nroots],sf->nleaves,sf->mine,PETSC_COPY_VALUES,newremote,PETSC_OWN_POINTER);CHKERRQ(ierr); 956 ierr = PetscFree5(inranks,newoffset,outranks,newoutoffset,tmpoffset);CHKERRQ(ierr); 957 } 958 ierr = PetscFree3(inoffset,outones,outoffset);CHKERRQ(ierr); 959 } 960 *multi = sf->multi; 961 PetscFunctionReturn(0); 962 } 963 964 /*@C 965 PetscSFCreateEmbeddedSF - removes edges from all but the selected roots, does not remap indices 966 967 Collective 968 969 Input Arguments: 970 + sf - original star forest 971 . nselected - number of selected roots on this process 972 - selected - indices of the selected roots on this process 973 974 Output Arguments: 975 . newsf - new star forest 976 977 Level: advanced 978 979 Note: 980 To use the new PetscSF, it may be necessary to know the indices of the leaves that are still participating. This can 981 be done by calling PetscSFGetGraph(). 982 983 .seealso: PetscSFSetGraph(), PetscSFGetGraph() 984 @*/ 985 PetscErrorCode PetscSFCreateEmbeddedSF(PetscSF sf,PetscInt nselected,const PetscInt *selected,PetscSF *newsf) 986 { 987 PetscInt i,n,*roots,*rootdata,*leafdata,nroots,nleaves,connected_leaves,*new_ilocal; 988 const PetscSFNode *iremote; 989 PetscSFNode *new_iremote; 990 PetscSF tmpsf; 991 MPI_Comm comm; 992 PetscErrorCode ierr; 993 994 PetscFunctionBegin; 995 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 996 PetscSFCheckGraphSet(sf,1); 997 if (nselected) PetscValidPointer(selected,3); 998 PetscValidPointer(newsf,4); 999 1000 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1001 1002 /* Uniq selected[] and put results in roots[] */ 1003 ierr = PetscObjectGetComm((PetscObject)sf,&comm);CHKERRQ(ierr); 1004 ierr = PetscMalloc1(nselected,&roots);CHKERRQ(ierr); 1005 ierr = PetscMemcpy(roots,selected,sizeof(PetscInt)*nselected);CHKERRQ(ierr); 1006 ierr = PetscSortedRemoveDupsInt(&nselected,roots);CHKERRQ(ierr); 1007 if (nselected && (roots[0] < 0 || roots[nselected-1] >= sf->nroots)) SETERRQ3(comm,PETSC_ERR_ARG_OUTOFRANGE,"Min/Max root indices %D/%D are not in [0,%D)",roots[0],roots[nselected-1],sf->nroots); 1008 1009 if (sf->ops->CreateEmbeddedSF) { 1010 ierr = (*sf->ops->CreateEmbeddedSF)(sf,nselected,roots,newsf);CHKERRQ(ierr); 1011 } else { 1012 /* A generic version of creating embedded sf. Note that we called PetscSFSetGraph() twice, which is certainly expensive */ 1013 /* Find out which leaves (not leaf data items) are still connected to roots in the embedded sf */ 1014 ierr = PetscSFGetGraph(sf,&nroots,&nleaves,NULL,&iremote);CHKERRQ(ierr); 1015 ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_RANKS,&tmpsf);CHKERRQ(ierr); 1016 ierr = PetscSFSetGraph(tmpsf,nroots,nleaves,NULL/*contiguous*/,PETSC_USE_POINTER,iremote,PETSC_USE_POINTER);CHKERRQ(ierr); 1017 ierr = PetscCalloc2(nroots,&rootdata,nleaves,&leafdata);CHKERRQ(ierr); 1018 for (i=0; i<nselected; ++i) rootdata[roots[i]] = 1; 1019 ierr = PetscSFBcastBegin(tmpsf,MPIU_INT,rootdata,leafdata);CHKERRQ(ierr); 1020 ierr = PetscSFBcastEnd(tmpsf,MPIU_INT,rootdata,leafdata);CHKERRQ(ierr); 1021 ierr = PetscSFDestroy(&tmpsf);CHKERRQ(ierr); 1022 1023 /* Build newsf with leaves that are still connected */ 1024 connected_leaves = 0; 1025 for (i=0; i<nleaves; ++i) connected_leaves += leafdata[i]; 1026 ierr = PetscMalloc1(connected_leaves,&new_ilocal);CHKERRQ(ierr); 1027 ierr = PetscMalloc1(connected_leaves,&new_iremote);CHKERRQ(ierr); 1028 for (i=0, n=0; i<nleaves; ++i) { 1029 if (leafdata[i]) { 1030 new_ilocal[n] = sf->mine ? sf->mine[i] : i; 1031 new_iremote[n].rank = sf->remote[i].rank; 1032 new_iremote[n].index = sf->remote[i].index; 1033 ++n; 1034 } 1035 } 1036 1037 if (n != connected_leaves) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"There is a size mismatch in the SF embedding, %d != %d",n,connected_leaves); 1038 ierr = PetscSFCreate(comm,newsf);CHKERRQ(ierr); 1039 ierr = PetscSFSetFromOptions(*newsf);CHKERRQ(ierr); 1040 ierr = PetscSFSetGraph(*newsf,nroots,connected_leaves,new_ilocal,PETSC_OWN_POINTER,new_iremote,PETSC_OWN_POINTER);CHKERRQ(ierr); 1041 ierr = PetscFree2(rootdata,leafdata);CHKERRQ(ierr); 1042 } 1043 ierr = PetscFree(roots);CHKERRQ(ierr); 1044 PetscFunctionReturn(0); 1045 } 1046 1047 /*@C 1048 PetscSFCreateEmbeddedLeafSF - removes edges from all but the selected leaves, does not remap indices 1049 1050 Collective 1051 1052 Input Arguments: 1053 + sf - original star forest 1054 . nselected - number of selected leaves on this process 1055 - selected - indices of the selected leaves on this process 1056 1057 Output Arguments: 1058 . newsf - new star forest 1059 1060 Level: advanced 1061 1062 .seealso: PetscSFCreateEmbeddedSF(), PetscSFSetGraph(), PetscSFGetGraph() 1063 @*/ 1064 PetscErrorCode PetscSFCreateEmbeddedLeafSF(PetscSF sf,PetscInt nselected,const PetscInt *selected,PetscSF *newsf) 1065 { 1066 const PetscSFNode *iremote; 1067 PetscSFNode *new_iremote; 1068 const PetscInt *ilocal; 1069 PetscInt i,nroots,*leaves,*new_ilocal; 1070 MPI_Comm comm; 1071 PetscErrorCode ierr; 1072 1073 PetscFunctionBegin; 1074 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1075 PetscSFCheckGraphSet(sf,1); 1076 if (nselected) PetscValidPointer(selected,3); 1077 PetscValidPointer(newsf,4); 1078 1079 /* Uniq selected[] and put results in leaves[] */ 1080 ierr = PetscObjectGetComm((PetscObject)sf,&comm);CHKERRQ(ierr); 1081 ierr = PetscMalloc1(nselected,&leaves);CHKERRQ(ierr); 1082 ierr = PetscMemcpy(leaves,selected,sizeof(PetscInt)*nselected);CHKERRQ(ierr); 1083 ierr = PetscSortedRemoveDupsInt(&nselected,leaves);CHKERRQ(ierr); 1084 if (nselected && (leaves[0] < 0 || leaves[nselected-1] >= sf->nleaves)) SETERRQ3(comm,PETSC_ERR_ARG_OUTOFRANGE,"Min/Max leaf indices %D/%D are not in [0,%D)",leaves[0],leaves[nselected-1],sf->nleaves); 1085 1086 /* Optimize the routine only when sf is setup and hence we can reuse sf's communication pattern */ 1087 if (sf->setupcalled && sf->ops->CreateEmbeddedLeafSF) { 1088 ierr = (*sf->ops->CreateEmbeddedLeafSF)(sf,nselected,leaves,newsf);CHKERRQ(ierr); 1089 } else { 1090 ierr = PetscSFGetGraph(sf,&nroots,NULL,&ilocal,&iremote);CHKERRQ(ierr); 1091 ierr = PetscMalloc1(nselected,&new_ilocal);CHKERRQ(ierr); 1092 ierr = PetscMalloc1(nselected,&new_iremote);CHKERRQ(ierr); 1093 for (i=0; i<nselected; ++i) { 1094 const PetscInt l = leaves[i]; 1095 new_ilocal[i] = ilocal ? ilocal[l] : l; 1096 new_iremote[i].rank = iremote[l].rank; 1097 new_iremote[i].index = iremote[l].index; 1098 } 1099 ierr = PetscSFCreate(comm,newsf);CHKERRQ(ierr); 1100 ierr = PetscSFSetFromOptions(*newsf);CHKERRQ(ierr); 1101 ierr = PetscSFSetGraph(*newsf,nroots,nselected,new_ilocal,PETSC_OWN_POINTER,new_iremote,PETSC_OWN_POINTER);CHKERRQ(ierr); 1102 } 1103 ierr = PetscFree(leaves);CHKERRQ(ierr); 1104 PetscFunctionReturn(0); 1105 } 1106 1107 /*@C 1108 PetscSFBcastAndOpBegin - begin pointwise broadcast with root value being reduced to leaf value, to be concluded with call to PetscSFBcastAndOpEnd() 1109 1110 Collective on PetscSF 1111 1112 Input Arguments: 1113 + sf - star forest on which to communicate 1114 . unit - data type associated with each node 1115 . rootdata - buffer to broadcast 1116 - op - operation to use for reduction 1117 1118 Output Arguments: 1119 . leafdata - buffer to be reduced with values from each leaf's respective root 1120 1121 Level: intermediate 1122 1123 .seealso: PetscSFBcastAndOpEnd(), PetscSFBcastBegin(), PetscSFBcastEnd() 1124 @*/ 1125 PetscErrorCode PetscSFBcastAndOpBegin(PetscSF sf,MPI_Datatype unit,const void *rootdata,void *leafdata,MPI_Op op) 1126 { 1127 PetscErrorCode ierr; 1128 1129 PetscFunctionBegin; 1130 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1131 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1132 ierr = PetscLogEventBegin(PETSCSF_BcastAndOpBegin,sf,0,0,0);CHKERRQ(ierr); 1133 ierr = (*sf->ops->BcastAndOpBegin)(sf,unit,rootdata,leafdata,op);CHKERRQ(ierr); 1134 ierr = PetscLogEventEnd(PETSCSF_BcastAndOpBegin,sf,0,0,0);CHKERRQ(ierr); 1135 PetscFunctionReturn(0); 1136 } 1137 1138 /*@C 1139 PetscSFBcastAndOpEnd - end a broadcast & reduce operation started with PetscSFBcastAndOpBegin() 1140 1141 Collective 1142 1143 Input Arguments: 1144 + sf - star forest 1145 . unit - data type 1146 . rootdata - buffer to broadcast 1147 - op - operation to use for reduction 1148 1149 Output Arguments: 1150 . leafdata - buffer to be reduced with values from each leaf's respective root 1151 1152 Level: intermediate 1153 1154 .seealso: PetscSFSetGraph(), PetscSFReduceEnd() 1155 @*/ 1156 PetscErrorCode PetscSFBcastAndOpEnd(PetscSF sf,MPI_Datatype unit,const void *rootdata,void *leafdata,MPI_Op op) 1157 { 1158 PetscErrorCode ierr; 1159 1160 PetscFunctionBegin; 1161 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1162 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1163 ierr = PetscLogEventBegin(PETSCSF_BcastAndOpEnd,sf,0,0,0);CHKERRQ(ierr); 1164 ierr = (*sf->ops->BcastAndOpEnd)(sf,unit,rootdata,leafdata,op);CHKERRQ(ierr); 1165 ierr = PetscLogEventEnd(PETSCSF_BcastAndOpEnd,sf,0,0,0);CHKERRQ(ierr); 1166 PetscFunctionReturn(0); 1167 } 1168 1169 /*@C 1170 PetscSFReduceBegin - begin reduction of leafdata into rootdata, to be completed with call to PetscSFReduceEnd() 1171 1172 Collective 1173 1174 Input Arguments: 1175 + sf - star forest 1176 . unit - data type 1177 . leafdata - values to reduce 1178 - op - reduction operation 1179 1180 Output Arguments: 1181 . rootdata - result of reduction of values from all leaves of each root 1182 1183 Level: intermediate 1184 1185 .seealso: PetscSFBcastBegin() 1186 @*/ 1187 PetscErrorCode PetscSFReduceBegin(PetscSF sf,MPI_Datatype unit,const void *leafdata,void *rootdata,MPI_Op op) 1188 { 1189 PetscErrorCode ierr; 1190 1191 PetscFunctionBegin; 1192 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1193 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1194 ierr = PetscLogEventBegin(PETSCSF_ReduceBegin,sf,0,0,0);CHKERRQ(ierr); 1195 ierr = (sf->ops->ReduceBegin)(sf,unit,leafdata,rootdata,op);CHKERRQ(ierr); 1196 ierr = PetscLogEventEnd(PETSCSF_ReduceBegin,sf,0,0,0);CHKERRQ(ierr); 1197 PetscFunctionReturn(0); 1198 } 1199 1200 /*@C 1201 PetscSFReduceEnd - end a reduction operation started with PetscSFReduceBegin() 1202 1203 Collective 1204 1205 Input Arguments: 1206 + sf - star forest 1207 . unit - data type 1208 . leafdata - values to reduce 1209 - op - reduction operation 1210 1211 Output Arguments: 1212 . rootdata - result of reduction of values from all leaves of each root 1213 1214 Level: intermediate 1215 1216 .seealso: PetscSFSetGraph(), PetscSFBcastEnd() 1217 @*/ 1218 PetscErrorCode PetscSFReduceEnd(PetscSF sf,MPI_Datatype unit,const void *leafdata,void *rootdata,MPI_Op op) 1219 { 1220 PetscErrorCode ierr; 1221 1222 PetscFunctionBegin; 1223 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1224 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1225 ierr = PetscLogEventBegin(PETSCSF_ReduceEnd,sf,0,0,0);CHKERRQ(ierr); 1226 ierr = (*sf->ops->ReduceEnd)(sf,unit,leafdata,rootdata,op);CHKERRQ(ierr); 1227 ierr = PetscLogEventEnd(PETSCSF_ReduceEnd,sf,0,0,0);CHKERRQ(ierr); 1228 PetscFunctionReturn(0); 1229 } 1230 1231 /*@C 1232 PetscSFComputeDegreeBegin - begin computation of degree for each root vertex, to be completed with PetscSFComputeDegreeEnd() 1233 1234 Collective 1235 1236 Input Arguments: 1237 . sf - star forest 1238 1239 Output Arguments: 1240 . degree - degree of each root vertex 1241 1242 Level: advanced 1243 1244 Notes: 1245 The returned array is owned by PetscSF and automatically freed by PetscSFDestroy(). Hence no need to call PetscFree() on it. 1246 1247 .seealso: PetscSFGatherBegin() 1248 @*/ 1249 PetscErrorCode PetscSFComputeDegreeBegin(PetscSF sf,const PetscInt **degree) 1250 { 1251 PetscErrorCode ierr; 1252 1253 PetscFunctionBegin; 1254 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1255 PetscSFCheckGraphSet(sf,1); 1256 PetscValidPointer(degree,2); 1257 if (!sf->degreeknown) { 1258 PetscInt i, nroots = sf->nroots, maxlocal = sf->maxleaf+1; /* TODO: We should use PetscSFGetLeafRange() */ 1259 if (sf->degree) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Calls to PetscSFComputeDegreeBegin() cannot be nested."); 1260 ierr = PetscMalloc1(nroots,&sf->degree);CHKERRQ(ierr); 1261 ierr = PetscMalloc1(PetscMax(maxlocal,1),&sf->degreetmp);CHKERRQ(ierr); /* allocate at least one entry, see check in PetscSFComputeDegreeEnd() */ 1262 for (i=0; i<nroots; i++) sf->degree[i] = 0; 1263 for (i=0; i<maxlocal; i++) sf->degreetmp[i] = 1; 1264 ierr = PetscSFReduceBegin(sf,MPIU_INT,sf->degreetmp,sf->degree,MPI_SUM);CHKERRQ(ierr); 1265 } 1266 *degree = NULL; 1267 PetscFunctionReturn(0); 1268 } 1269 1270 /*@C 1271 PetscSFComputeDegreeEnd - complete computation of degree for each root vertex, started with PetscSFComputeDegreeBegin() 1272 1273 Collective 1274 1275 Input Arguments: 1276 . sf - star forest 1277 1278 Output Arguments: 1279 . degree - degree of each root vertex 1280 1281 Level: developer 1282 1283 Notes: 1284 The returned array is owned by PetscSF and automatically freed by PetscSFDestroy(). Hence no need to call PetscFree() on it. 1285 1286 .seealso: 1287 @*/ 1288 PetscErrorCode PetscSFComputeDegreeEnd(PetscSF sf,const PetscInt **degree) 1289 { 1290 PetscErrorCode ierr; 1291 1292 PetscFunctionBegin; 1293 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1294 PetscSFCheckGraphSet(sf,1); 1295 PetscValidPointer(degree,2); 1296 if (!sf->degreeknown) { 1297 if (!sf->degreetmp) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PetscSFComputeDegreeBegin() before PetscSFComputeDegreeEnd()"); 1298 ierr = PetscSFReduceEnd(sf,MPIU_INT,sf->degreetmp,sf->degree,MPI_SUM);CHKERRQ(ierr); 1299 ierr = PetscFree(sf->degreetmp);CHKERRQ(ierr); 1300 sf->degreeknown = PETSC_TRUE; 1301 } 1302 *degree = sf->degree; 1303 PetscFunctionReturn(0); 1304 } 1305 1306 1307 /*@C 1308 PetscSFComputeMultiRootOriginalNumbering - Returns original numbering of multi-roots (roots of multi-SF returned by PetscSFGetMultiSF()). 1309 Each multi-root is assigned index of the corresponding original root. 1310 1311 Collective 1312 1313 Input Arguments: 1314 + sf - star forest 1315 - degree - degree of each root vertex, computed with PetscSFComputeDegreeBegin()/PetscSFComputeDegreeEnd() 1316 1317 Output Arguments: 1318 + nMultiRoots - (optional) number of multi-roots (roots of multi-SF) 1319 - multiRootsOrigNumbering - original indices of multi-roots; length of this array is nMultiRoots 1320 1321 Level: developer 1322 1323 Notes: 1324 The returned array multiRootsOrigNumbering is newly allocated and should be destroyed with PetscFree() when no longer needed. 1325 1326 .seealso: PetscSFComputeDegreeBegin(), PetscSFComputeDegreeEnd(), PetscSFGetMultiSF() 1327 @*/ 1328 PetscErrorCode PetscSFComputeMultiRootOriginalNumbering(PetscSF sf, const PetscInt degree[], PetscInt *nMultiRoots, PetscInt *multiRootsOrigNumbering[]) 1329 { 1330 PetscSF msf; 1331 PetscInt i, j, k, nroots, nmroots; 1332 PetscErrorCode ierr; 1333 1334 PetscFunctionBegin; 1335 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1336 ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr); 1337 if (nroots) PetscValidIntPointer(degree,2); 1338 if (nMultiRoots) PetscValidIntPointer(nMultiRoots,3); 1339 PetscValidPointer(multiRootsOrigNumbering,4); 1340 ierr = PetscSFGetMultiSF(sf,&msf);CHKERRQ(ierr); 1341 ierr = PetscSFGetGraph(msf, &nmroots, NULL, NULL, NULL);CHKERRQ(ierr); 1342 ierr = PetscMalloc1(nmroots, multiRootsOrigNumbering);CHKERRQ(ierr); 1343 for (i=0,j=0,k=0; i<nroots; i++) { 1344 if (!degree[i]) continue; 1345 for (j=0; j<degree[i]; j++,k++) { 1346 (*multiRootsOrigNumbering)[k] = i; 1347 } 1348 } 1349 #if defined(PETSC_USE_DEBUG) 1350 if (PetscUnlikely(k != nmroots)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"sanity check fail"); 1351 #endif 1352 if (nMultiRoots) *nMultiRoots = nmroots; 1353 PetscFunctionReturn(0); 1354 } 1355 1356 /*@C 1357 PetscSFFetchAndOpBegin - begin operation that fetches values from root and updates atomically by applying operation using my leaf value, to be completed with PetscSFFetchAndOpEnd() 1358 1359 Collective 1360 1361 Input Arguments: 1362 + sf - star forest 1363 . unit - data type 1364 . leafdata - leaf values to use in reduction 1365 - op - operation to use for reduction 1366 1367 Output Arguments: 1368 + rootdata - root values to be updated, input state is seen by first process to perform an update 1369 - leafupdate - state at each leaf's respective root immediately prior to my atomic update 1370 1371 Level: advanced 1372 1373 Note: 1374 The update is only atomic at the granularity provided by the hardware. Different roots referenced by the same process 1375 might be updated in a different order. Furthermore, if a composite type is used for the unit datatype, atomicity is 1376 not guaranteed across the whole vertex. Therefore, this function is mostly only used with primitive types such as 1377 integers. 1378 1379 .seealso: PetscSFComputeDegreeBegin(), PetscSFReduceBegin(), PetscSFSetGraph() 1380 @*/ 1381 PetscErrorCode PetscSFFetchAndOpBegin(PetscSF sf,MPI_Datatype unit,void *rootdata,const void *leafdata,void *leafupdate,MPI_Op op) 1382 { 1383 PetscErrorCode ierr; 1384 1385 PetscFunctionBegin; 1386 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1387 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1388 ierr = PetscLogEventBegin(PETSCSF_FetchAndOpBegin,sf,0,0,0);CHKERRQ(ierr); 1389 ierr = (*sf->ops->FetchAndOpBegin)(sf,unit,rootdata,leafdata,leafupdate,op);CHKERRQ(ierr); 1390 ierr = PetscLogEventEnd(PETSCSF_FetchAndOpBegin,sf,0,0,0);CHKERRQ(ierr); 1391 PetscFunctionReturn(0); 1392 } 1393 1394 /*@C 1395 PetscSFFetchAndOpEnd - end operation started in matching call to PetscSFFetchAndOpBegin() to fetch values from roots and update atomically by applying operation using my leaf value 1396 1397 Collective 1398 1399 Input Arguments: 1400 + sf - star forest 1401 . unit - data type 1402 . leafdata - leaf values to use in reduction 1403 - op - operation to use for reduction 1404 1405 Output Arguments: 1406 + rootdata - root values to be updated, input state is seen by first process to perform an update 1407 - leafupdate - state at each leaf's respective root immediately prior to my atomic update 1408 1409 Level: advanced 1410 1411 .seealso: PetscSFComputeDegreeEnd(), PetscSFReduceEnd(), PetscSFSetGraph() 1412 @*/ 1413 PetscErrorCode PetscSFFetchAndOpEnd(PetscSF sf,MPI_Datatype unit,void *rootdata,const void *leafdata,void *leafupdate,MPI_Op op) 1414 { 1415 PetscErrorCode ierr; 1416 1417 PetscFunctionBegin; 1418 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1419 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1420 ierr = PetscLogEventBegin(PETSCSF_FetchAndOpEnd,sf,0,0,0);CHKERRQ(ierr); 1421 ierr = (*sf->ops->FetchAndOpEnd)(sf,unit,rootdata,leafdata,leafupdate,op);CHKERRQ(ierr); 1422 ierr = PetscLogEventEnd(PETSCSF_FetchAndOpEnd,sf,0,0,0);CHKERRQ(ierr); 1423 PetscFunctionReturn(0); 1424 } 1425 1426 /*@C 1427 PetscSFGatherBegin - begin pointwise gather of all leaves into multi-roots, to be completed with PetscSFGatherEnd() 1428 1429 Collective 1430 1431 Input Arguments: 1432 + sf - star forest 1433 . unit - data type 1434 - leafdata - leaf data to gather to roots 1435 1436 Output Argument: 1437 . multirootdata - root buffer to gather into, amount of space per root is equal to its degree 1438 1439 Level: intermediate 1440 1441 .seealso: PetscSFComputeDegreeBegin(), PetscSFScatterBegin() 1442 @*/ 1443 PetscErrorCode PetscSFGatherBegin(PetscSF sf,MPI_Datatype unit,const void *leafdata,void *multirootdata) 1444 { 1445 PetscErrorCode ierr; 1446 PetscSF multi; 1447 1448 PetscFunctionBegin; 1449 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1450 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1451 ierr = PetscSFGetMultiSF(sf,&multi);CHKERRQ(ierr); 1452 ierr = PetscSFReduceBegin(multi,unit,leafdata,multirootdata,MPIU_REPLACE);CHKERRQ(ierr); 1453 PetscFunctionReturn(0); 1454 } 1455 1456 /*@C 1457 PetscSFGatherEnd - ends pointwise gather operation that was started with PetscSFGatherBegin() 1458 1459 Collective 1460 1461 Input Arguments: 1462 + sf - star forest 1463 . unit - data type 1464 - leafdata - leaf data to gather to roots 1465 1466 Output Argument: 1467 . multirootdata - root buffer to gather into, amount of space per root is equal to its degree 1468 1469 Level: intermediate 1470 1471 .seealso: PetscSFComputeDegreeEnd(), PetscSFScatterEnd() 1472 @*/ 1473 PetscErrorCode PetscSFGatherEnd(PetscSF sf,MPI_Datatype unit,const void *leafdata,void *multirootdata) 1474 { 1475 PetscErrorCode ierr; 1476 PetscSF multi; 1477 1478 PetscFunctionBegin; 1479 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1480 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1481 ierr = PetscSFGetMultiSF(sf,&multi);CHKERRQ(ierr); 1482 ierr = PetscSFReduceEnd(multi,unit,leafdata,multirootdata,MPIU_REPLACE);CHKERRQ(ierr); 1483 PetscFunctionReturn(0); 1484 } 1485 1486 /*@C 1487 PetscSFScatterBegin - begin pointwise scatter operation from multi-roots to leaves, to be completed with PetscSFScatterEnd() 1488 1489 Collective 1490 1491 Input Arguments: 1492 + sf - star forest 1493 . unit - data type 1494 - multirootdata - root buffer to send to each leaf, one unit of data per leaf 1495 1496 Output Argument: 1497 . leafdata - leaf data to be update with personal data from each respective root 1498 1499 Level: intermediate 1500 1501 .seealso: PetscSFComputeDegreeBegin(), PetscSFScatterBegin() 1502 @*/ 1503 PetscErrorCode PetscSFScatterBegin(PetscSF sf,MPI_Datatype unit,const void *multirootdata,void *leafdata) 1504 { 1505 PetscErrorCode ierr; 1506 PetscSF multi; 1507 1508 PetscFunctionBegin; 1509 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1510 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1511 ierr = PetscSFGetMultiSF(sf,&multi);CHKERRQ(ierr); 1512 ierr = PetscSFBcastBegin(multi,unit,multirootdata,leafdata);CHKERRQ(ierr); 1513 PetscFunctionReturn(0); 1514 } 1515 1516 /*@C 1517 PetscSFScatterEnd - ends pointwise scatter operation that was started with PetscSFScatterBegin() 1518 1519 Collective 1520 1521 Input Arguments: 1522 + sf - star forest 1523 . unit - data type 1524 - multirootdata - root buffer to send to each leaf, one unit of data per leaf 1525 1526 Output Argument: 1527 . leafdata - leaf data to be update with personal data from each respective root 1528 1529 Level: intermediate 1530 1531 .seealso: PetscSFComputeDegreeEnd(), PetscSFScatterEnd() 1532 @*/ 1533 PetscErrorCode PetscSFScatterEnd(PetscSF sf,MPI_Datatype unit,const void *multirootdata,void *leafdata) 1534 { 1535 PetscErrorCode ierr; 1536 PetscSF multi; 1537 1538 PetscFunctionBegin; 1539 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1540 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1541 ierr = PetscSFGetMultiSF(sf,&multi);CHKERRQ(ierr); 1542 ierr = PetscSFBcastEnd(multi,unit,multirootdata,leafdata);CHKERRQ(ierr); 1543 PetscFunctionReturn(0); 1544 } 1545 1546 /*@ 1547 PetscSFCompose - Compose a new PetscSF equivalent to action to PetscSFs 1548 1549 Input Parameters: 1550 + sfA - The first PetscSF 1551 - sfB - The second PetscSF 1552 1553 Output Parameters: 1554 . sfBA - equvalent PetscSF for applying A then B 1555 1556 Level: developer 1557 1558 .seealso: PetscSF, PetscSFGetGraph(), PetscSFSetGraph() 1559 @*/ 1560 PetscErrorCode PetscSFCompose(PetscSF sfA, PetscSF sfB, PetscSF *sfBA) 1561 { 1562 MPI_Comm comm; 1563 const PetscSFNode *remotePointsA, *remotePointsB; 1564 PetscSFNode *remotePointsBA; 1565 const PetscInt *localPointsA, *localPointsB; 1566 PetscInt numRootsA, numLeavesA, numRootsB, numLeavesB; 1567 PetscErrorCode ierr; 1568 1569 PetscFunctionBegin; 1570 PetscValidHeaderSpecific(sfA, PETSCSF_CLASSID, 1); 1571 PetscSFCheckGraphSet(sfA, 1); 1572 PetscValidHeaderSpecific(sfB, PETSCSF_CLASSID, 2); 1573 PetscSFCheckGraphSet(sfB, 2); 1574 PetscValidPointer(sfBA, 3); 1575 ierr = PetscObjectGetComm((PetscObject) sfA, &comm);CHKERRQ(ierr); 1576 ierr = PetscSFGetGraph(sfA, &numRootsA, &numLeavesA, &localPointsA, &remotePointsA);CHKERRQ(ierr); 1577 ierr = PetscSFGetGraph(sfB, &numRootsB, &numLeavesB, &localPointsB, &remotePointsB);CHKERRQ(ierr); 1578 ierr = PetscMalloc1(numLeavesB, &remotePointsBA);CHKERRQ(ierr); 1579 ierr = PetscSFBcastBegin(sfB, MPIU_2INT, remotePointsA, remotePointsBA);CHKERRQ(ierr); 1580 ierr = PetscSFBcastEnd(sfB, MPIU_2INT, remotePointsA, remotePointsBA);CHKERRQ(ierr); 1581 ierr = PetscSFCreate(comm, sfBA);CHKERRQ(ierr); 1582 ierr = PetscSFSetGraph(*sfBA, numRootsA, numLeavesB, localPointsB, PETSC_COPY_VALUES, remotePointsBA, PETSC_OWN_POINTER);CHKERRQ(ierr); 1583 PetscFunctionReturn(0); 1584 } 1585 1586 /* 1587 PetscSFCreateLocalSF_Private - Creates a local PetscSF that only has intra-process edges of the global PetscSF 1588 1589 Input Parameters: 1590 . sf - The global PetscSF 1591 1592 Output Parameters: 1593 . out - The local PetscSF 1594 */ 1595 PetscErrorCode PetscSFCreateLocalSF_Private(PetscSF sf,PetscSF *out) 1596 { 1597 MPI_Comm comm; 1598 PetscMPIInt myrank; 1599 const PetscInt *ilocal; 1600 const PetscSFNode *iremote; 1601 PetscInt i,j,nroots,nleaves,lnleaves,*lilocal; 1602 PetscSFNode *liremote; 1603 PetscSF lsf; 1604 PetscErrorCode ierr; 1605 1606 PetscFunctionBegin; 1607 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1608 if (sf->ops->CreateLocalSF) { 1609 ierr = (*sf->ops->CreateLocalSF)(sf,out);CHKERRQ(ierr); 1610 } else { 1611 /* Could use PetscSFCreateEmbeddedLeafSF, but since we know the comm is PETSC_COMM_SELF, we can make it fast */ 1612 ierr = PetscObjectGetComm((PetscObject)sf,&comm);CHKERRQ(ierr); 1613 ierr = MPI_Comm_rank(comm,&myrank);CHKERRQ(ierr); 1614 1615 /* Find out local edges and build a local SF */ 1616 ierr = PetscSFGetGraph(sf,&nroots,&nleaves,&ilocal,&iremote);CHKERRQ(ierr); 1617 for (i=lnleaves=0; i<nleaves; i++) {if (iremote[i].rank == (PetscInt)myrank) lnleaves++;} 1618 ierr = PetscMalloc1(lnleaves,&lilocal);CHKERRQ(ierr); 1619 ierr = PetscMalloc1(lnleaves,&liremote);CHKERRQ(ierr); 1620 1621 for (i=j=0; i<nleaves; i++) { 1622 if (iremote[i].rank == (PetscInt)myrank) { 1623 lilocal[j] = ilocal? ilocal[i] : i; /* ilocal=NULL for contiguous storage */ 1624 liremote[j].rank = 0; /* rank in PETSC_COMM_SELF */ 1625 liremote[j].index = iremote[i].index; 1626 j++; 1627 } 1628 } 1629 ierr = PetscSFCreate(PETSC_COMM_SELF,&lsf);CHKERRQ(ierr); 1630 ierr = PetscSFSetGraph(lsf,nroots,lnleaves,lilocal,PETSC_OWN_POINTER,liremote,PETSC_OWN_POINTER);CHKERRQ(ierr); 1631 ierr = PetscSFSetUp(lsf);CHKERRQ(ierr); 1632 *out = lsf; 1633 } 1634 PetscFunctionReturn(0); 1635 } 1636