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 on MPI_Comm 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 .keywords: PetscSF, set, type 115 116 .seealso: PetscSFType, PetscSFCreate() 117 @*/ 118 PetscErrorCode PetscSFSetType(PetscSF sf,PetscSFType type) 119 { 120 PetscErrorCode ierr,(*r)(PetscSF); 121 PetscBool match; 122 123 PetscFunctionBegin; 124 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 125 PetscValidCharPointer(type,2); 126 127 ierr = PetscObjectTypeCompare((PetscObject)sf,type,&match);CHKERRQ(ierr); 128 if (match) PetscFunctionReturn(0); 129 130 ierr = PetscFunctionListFind(PetscSFList,type,&r);CHKERRQ(ierr); 131 if (!r) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unable to find requested PetscSF type %s",type); 132 /* Destroy the previous PetscSF implementation context */ 133 if (sf->ops->Destroy) {ierr = (*(sf)->ops->Destroy)(sf);CHKERRQ(ierr);} 134 ierr = PetscMemzero(sf->ops,sizeof(*sf->ops));CHKERRQ(ierr); 135 ierr = PetscObjectChangeTypeName((PetscObject)sf,type);CHKERRQ(ierr); 136 ierr = (*r)(sf);CHKERRQ(ierr); 137 PetscFunctionReturn(0); 138 } 139 140 /*@C 141 PetscSFGetType - Get the PetscSF communication implementation 142 143 Not Collective 144 145 Input Parameter: 146 . sf - the PetscSF context 147 148 Output Parameter: 149 . type - the PetscSF type name 150 151 Level: intermediate 152 153 .keywords: PetscSF, get, type 154 .seealso: PetscSFSetType(), PetscSFCreate() 155 @*/ 156 PetscErrorCode PetscSFGetType(PetscSF sf, PetscSFType *type) 157 { 158 PetscFunctionBegin; 159 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID,1); 160 PetscValidPointer(type,2); 161 *type = ((PetscObject)sf)->type_name; 162 PetscFunctionReturn(0); 163 } 164 165 /*@ 166 PetscSFDestroy - destroy star forest 167 168 Collective 169 170 Input Arguments: 171 . sf - address of star forest 172 173 Level: intermediate 174 175 .seealso: PetscSFCreate(), PetscSFReset() 176 @*/ 177 PetscErrorCode PetscSFDestroy(PetscSF *sf) 178 { 179 PetscErrorCode ierr; 180 181 PetscFunctionBegin; 182 if (!*sf) PetscFunctionReturn(0); 183 PetscValidHeaderSpecific((*sf),PETSCSF_CLASSID,1); 184 if (--((PetscObject)(*sf))->refct > 0) {*sf = NULL; PetscFunctionReturn(0);} 185 ierr = PetscSFReset(*sf);CHKERRQ(ierr); 186 if ((*sf)->ops->Destroy) {ierr = (*(*sf)->ops->Destroy)(*sf);CHKERRQ(ierr);} 187 ierr = PetscHeaderDestroy(sf);CHKERRQ(ierr); 188 PetscFunctionReturn(0); 189 } 190 191 /*@ 192 PetscSFSetUp - set up communication structures 193 194 Collective 195 196 Input Arguments: 197 . sf - star forest communication object 198 199 Level: beginner 200 201 .seealso: PetscSFSetFromOptions(), PetscSFSetType() 202 @*/ 203 PetscErrorCode PetscSFSetUp(PetscSF sf) 204 { 205 PetscErrorCode ierr; 206 207 PetscFunctionBegin; 208 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 209 PetscSFCheckGraphSet(sf,1); 210 if (sf->setupcalled) PetscFunctionReturn(0); 211 if (!((PetscObject)sf)->type_name) {ierr = PetscSFSetType(sf,PETSCSFBASIC);CHKERRQ(ierr);} 212 ierr = PetscLogEventBegin(PETSCSF_SetUp,sf,0,0,0);CHKERRQ(ierr); 213 if (sf->ops->SetUp) {ierr = (*sf->ops->SetUp)(sf);CHKERRQ(ierr);} 214 ierr = PetscLogEventEnd(PETSCSF_SetUp,sf,0,0,0);CHKERRQ(ierr); 215 sf->setupcalled = PETSC_TRUE; 216 PetscFunctionReturn(0); 217 } 218 219 /*@ 220 PetscSFSetFromOptions - set PetscSF options using the options database 221 222 Logically Collective 223 224 Input Arguments: 225 . sf - star forest 226 227 Options Database Keys: 228 + -sf_type - implementation type, see PetscSFSetType() 229 - -sf_rank_order - sort composite points for gathers and scatters in rank order, gathers are non-deterministic otherwise 230 231 Level: intermediate 232 233 .keywords: KSP, set, from, options, database 234 235 .seealso: PetscSFWindowSetSyncType() 236 @*/ 237 PetscErrorCode PetscSFSetFromOptions(PetscSF sf) 238 { 239 PetscSFType deft; 240 char type[256]; 241 PetscErrorCode ierr; 242 PetscBool flg; 243 244 PetscFunctionBegin; 245 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 246 ierr = PetscObjectOptionsBegin((PetscObject)sf);CHKERRQ(ierr); 247 deft = ((PetscObject)sf)->type_name ? ((PetscObject)sf)->type_name : PETSCSFBASIC; 248 ierr = PetscOptionsFList("-sf_type","PetscSF implementation type","PetscSFSetType",PetscSFList,deft,type,sizeof(type),&flg);CHKERRQ(ierr); 249 ierr = PetscSFSetType(sf,flg ? type : deft);CHKERRQ(ierr); 250 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); 251 if (sf->ops->SetFromOptions) {ierr = (*sf->ops->SetFromOptions)(PetscOptionsObject,sf);CHKERRQ(ierr);} 252 ierr = PetscOptionsEnd();CHKERRQ(ierr); 253 PetscFunctionReturn(0); 254 } 255 256 /*@ 257 PetscSFSetRankOrder - sort multi-points for gathers and scatters by rank order 258 259 Logically Collective 260 261 Input Arguments: 262 + sf - star forest 263 - flg - PETSC_TRUE to sort, PETSC_FALSE to skip sorting (lower setup cost, but non-deterministic) 264 265 Level: advanced 266 267 .seealso: PetscSFGatherBegin(), PetscSFScatterBegin() 268 @*/ 269 PetscErrorCode PetscSFSetRankOrder(PetscSF sf,PetscBool flg) 270 { 271 272 PetscFunctionBegin; 273 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 274 PetscValidLogicalCollectiveBool(sf,flg,2); 275 if (sf->multi) SETERRQ(PetscObjectComm((PetscObject)sf),PETSC_ERR_ARG_WRONGSTATE,"Rank ordering must be set before first call to PetscSFGatherBegin() or PetscSFScatterBegin()"); 276 sf->rankorder = flg; 277 PetscFunctionReturn(0); 278 } 279 280 /*@ 281 PetscSFSetGraph - Set a parallel star forest 282 283 Collective 284 285 Input Arguments: 286 + sf - star forest 287 . nroots - number of root vertices on the current process (these are possible targets for other process to attach leaves) 288 . nleaves - number of leaf vertices on the current process, each of these references a root on any process 289 . ilocal - locations of leaves in leafdata buffers, pass NULL for contiguous storage 290 . localmode - copy mode for ilocal 291 . iremote - remote locations of root vertices for each leaf on the current process 292 - remotemode - copy mode for iremote 293 294 Level: intermediate 295 296 Notes: 297 In Fortran you must use PETSC_COPY_VALUES for localmode and remotemode 298 299 Developers Note: Local indices which are the identity permutation in the range [0,nleaves) are discarded as they 300 encode contiguous storage. In such case, if localmode is PETSC_OWN_POINTER, the memory is deallocated as it is not 301 needed 302 303 .seealso: PetscSFCreate(), PetscSFView(), PetscSFGetGraph() 304 @*/ 305 PetscErrorCode PetscSFSetGraph(PetscSF sf,PetscInt nroots,PetscInt nleaves,const PetscInt *ilocal,PetscCopyMode localmode,const PetscSFNode *iremote,PetscCopyMode remotemode) 306 { 307 PetscErrorCode ierr; 308 309 PetscFunctionBegin; 310 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 311 if (nleaves > 0 && ilocal) PetscValidIntPointer(ilocal,4); 312 if (nleaves > 0) PetscValidPointer(iremote,6); 313 if (nroots < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"nroots %D, cannot be negative",nroots); 314 if (nleaves < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"nleaves %D, cannot be negative",nleaves); 315 316 ierr = PetscSFReset(sf);CHKERRQ(ierr); 317 ierr = PetscLogEventBegin(PETSCSF_SetGraph,sf,0,0,0);CHKERRQ(ierr); 318 319 sf->nroots = nroots; 320 sf->nleaves = nleaves; 321 322 if (nleaves && ilocal) { 323 PetscInt i; 324 PetscInt minleaf = PETSC_MAX_INT; 325 PetscInt maxleaf = PETSC_MIN_INT; 326 int contiguous = 1; 327 for (i=0; i<nleaves; i++) { 328 minleaf = PetscMin(minleaf,ilocal[i]); 329 maxleaf = PetscMax(maxleaf,ilocal[i]); 330 contiguous &= (ilocal[i] == i); 331 } 332 sf->minleaf = minleaf; 333 sf->maxleaf = maxleaf; 334 if (contiguous) { 335 if (localmode == PETSC_OWN_POINTER) { 336 ierr = PetscFree(ilocal);CHKERRQ(ierr); 337 } 338 ilocal = NULL; 339 } 340 } else { 341 sf->minleaf = 0; 342 sf->maxleaf = nleaves - 1; 343 } 344 345 if (ilocal) { 346 switch (localmode) { 347 case PETSC_COPY_VALUES: 348 ierr = PetscMalloc1(nleaves,&sf->mine_alloc);CHKERRQ(ierr); 349 ierr = PetscMemcpy(sf->mine_alloc,ilocal,nleaves*sizeof(*ilocal));CHKERRQ(ierr); 350 sf->mine = sf->mine_alloc; 351 break; 352 case PETSC_OWN_POINTER: 353 sf->mine_alloc = (PetscInt*)ilocal; 354 sf->mine = sf->mine_alloc; 355 break; 356 case PETSC_USE_POINTER: 357 sf->mine_alloc = NULL; 358 sf->mine = (PetscInt*)ilocal; 359 break; 360 default: SETERRQ(PetscObjectComm((PetscObject)sf),PETSC_ERR_ARG_OUTOFRANGE,"Unknown localmode"); 361 } 362 } 363 364 switch (remotemode) { 365 case PETSC_COPY_VALUES: 366 ierr = PetscMalloc1(nleaves,&sf->remote_alloc);CHKERRQ(ierr); 367 ierr = PetscMemcpy(sf->remote_alloc,iremote,nleaves*sizeof(*iremote));CHKERRQ(ierr); 368 sf->remote = sf->remote_alloc; 369 break; 370 case PETSC_OWN_POINTER: 371 sf->remote_alloc = (PetscSFNode*)iremote; 372 sf->remote = sf->remote_alloc; 373 break; 374 case PETSC_USE_POINTER: 375 sf->remote_alloc = NULL; 376 sf->remote = (PetscSFNode*)iremote; 377 break; 378 default: SETERRQ(PetscObjectComm((PetscObject)sf),PETSC_ERR_ARG_OUTOFRANGE,"Unknown remotemode"); 379 } 380 381 ierr = PetscLogEventEnd(PETSCSF_SetGraph,sf,0,0,0);CHKERRQ(ierr); 382 sf->graphset = PETSC_TRUE; 383 PetscFunctionReturn(0); 384 } 385 386 /*@ 387 PetscSFCreateInverseSF - given a PetscSF in which all vertices have degree 1, creates the inverse map 388 389 Collective 390 391 Input Arguments: 392 . sf - star forest to invert 393 394 Output Arguments: 395 . isf - inverse of sf 396 397 Level: advanced 398 399 Notes: 400 All roots must have degree 1. 401 402 The local space may be a permutation, but cannot be sparse. 403 404 .seealso: PetscSFSetGraph() 405 @*/ 406 PetscErrorCode PetscSFCreateInverseSF(PetscSF sf,PetscSF *isf) 407 { 408 PetscErrorCode ierr; 409 PetscMPIInt rank; 410 PetscInt i,nroots,nleaves,maxlocal,count,*newilocal; 411 const PetscInt *ilocal; 412 PetscSFNode *roots,*leaves; 413 414 PetscFunctionBegin; 415 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 416 PetscSFCheckGraphSet(sf,1); 417 PetscValidPointer(isf,2); 418 419 ierr = PetscSFGetGraph(sf,&nroots,&nleaves,&ilocal,NULL);CHKERRQ(ierr); 420 maxlocal = sf->maxleaf+1; /* TODO: We should use PetscSFGetLeafRange() */ 421 422 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)sf),&rank);CHKERRQ(ierr); 423 ierr = PetscMalloc2(nroots,&roots,maxlocal,&leaves);CHKERRQ(ierr); 424 for (i=0; i<maxlocal; i++) { 425 leaves[i].rank = rank; 426 leaves[i].index = i; 427 } 428 for (i=0; i <nroots; i++) { 429 roots[i].rank = -1; 430 roots[i].index = -1; 431 } 432 ierr = PetscSFReduceBegin(sf,MPIU_2INT,leaves,roots,MPIU_REPLACE);CHKERRQ(ierr); 433 ierr = PetscSFReduceEnd(sf,MPIU_2INT,leaves,roots,MPIU_REPLACE);CHKERRQ(ierr); 434 435 /* Check whether our leaves are sparse */ 436 for (i=0,count=0; i<nroots; i++) if (roots[i].rank >= 0) count++; 437 if (count == nroots) newilocal = NULL; 438 else { /* Index for sparse leaves and compact "roots" array (which is to become our leaves). */ 439 ierr = PetscMalloc1(count,&newilocal);CHKERRQ(ierr); 440 for (i=0,count=0; i<nroots; i++) { 441 if (roots[i].rank >= 0) { 442 newilocal[count] = i; 443 roots[count].rank = roots[i].rank; 444 roots[count].index = roots[i].index; 445 count++; 446 } 447 } 448 } 449 450 ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_CONFONLY,isf);CHKERRQ(ierr); 451 ierr = PetscSFSetGraph(*isf,maxlocal,count,newilocal,PETSC_OWN_POINTER,roots,PETSC_COPY_VALUES);CHKERRQ(ierr); 452 ierr = PetscFree2(roots,leaves);CHKERRQ(ierr); 453 PetscFunctionReturn(0); 454 } 455 456 /*@ 457 PetscSFDuplicate - duplicate a PetscSF, optionally preserving rank connectivity and graph 458 459 Collective 460 461 Input Arguments: 462 + sf - communication object to duplicate 463 - opt - PETSCSF_DUPLICATE_CONFONLY, PETSCSF_DUPLICATE_RANKS, or PETSCSF_DUPLICATE_GRAPH (see PetscSFDuplicateOption) 464 465 Output Arguments: 466 . newsf - new communication object 467 468 Level: beginner 469 470 .seealso: PetscSFCreate(), PetscSFSetType(), PetscSFSetGraph() 471 @*/ 472 PetscErrorCode PetscSFDuplicate(PetscSF sf,PetscSFDuplicateOption opt,PetscSF *newsf) 473 { 474 PetscSFType type; 475 PetscErrorCode ierr; 476 477 PetscFunctionBegin; 478 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 479 PetscValidLogicalCollectiveEnum(sf,opt,2); 480 PetscValidPointer(newsf,3); 481 ierr = PetscSFCreate(PetscObjectComm((PetscObject)sf),newsf);CHKERRQ(ierr); 482 ierr = PetscSFGetType(sf,&type);CHKERRQ(ierr); 483 if (type) {ierr = PetscSFSetType(*newsf,type);CHKERRQ(ierr);} 484 if (opt == PETSCSF_DUPLICATE_GRAPH) { 485 PetscInt nroots,nleaves; 486 const PetscInt *ilocal; 487 const PetscSFNode *iremote; 488 PetscSFCheckGraphSet(sf,1); 489 ierr = PetscSFGetGraph(sf,&nroots,&nleaves,&ilocal,&iremote);CHKERRQ(ierr); 490 ierr = PetscSFSetGraph(*newsf,nroots,nleaves,ilocal,PETSC_COPY_VALUES,iremote,PETSC_COPY_VALUES);CHKERRQ(ierr); 491 } 492 if (sf->ops->Duplicate) {ierr = (*sf->ops->Duplicate)(sf,opt,*newsf);CHKERRQ(ierr);} 493 PetscFunctionReturn(0); 494 } 495 496 /*@C 497 PetscSFGetGraph - Get the graph specifying a parallel star forest 498 499 Not Collective 500 501 Input Arguments: 502 . sf - star forest 503 504 Output Arguments: 505 + nroots - number of root vertices on the current process (these are possible targets for other process to attach leaves) 506 . nleaves - number of leaf vertices on the current process, each of these references a root on any process 507 . ilocal - locations of leaves in leafdata buffers 508 - iremote - remote locations of root vertices for each leaf on the current process 509 510 Notes: 511 We are not currently requiring that the graph is set, thus returning nroots=-1 if it has not been set yet 512 513 Level: intermediate 514 515 .seealso: PetscSFCreate(), PetscSFView(), PetscSFSetGraph() 516 @*/ 517 PetscErrorCode PetscSFGetGraph(PetscSF sf,PetscInt *nroots,PetscInt *nleaves,const PetscInt **ilocal,const PetscSFNode **iremote) 518 { 519 520 PetscFunctionBegin; 521 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 522 if (nroots) *nroots = sf->nroots; 523 if (nleaves) *nleaves = sf->nleaves; 524 if (ilocal) *ilocal = sf->mine; 525 if (iremote) *iremote = sf->remote; 526 PetscFunctionReturn(0); 527 } 528 529 /*@ 530 PetscSFGetLeafRange - Get the active leaf ranges 531 532 Not Collective 533 534 Input Arguments: 535 . sf - star forest 536 537 Output Arguments: 538 + minleaf - minimum active leaf on this process 539 - maxleaf - maximum active leaf on this process 540 541 Level: developer 542 543 .seealso: PetscSFCreate(), PetscSFView(), PetscSFSetGraph(), PetscSFGetGraph() 544 @*/ 545 PetscErrorCode PetscSFGetLeafRange(PetscSF sf,PetscInt *minleaf,PetscInt *maxleaf) 546 { 547 548 PetscFunctionBegin; 549 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 550 PetscSFCheckGraphSet(sf,1); 551 if (minleaf) *minleaf = sf->minleaf; 552 if (maxleaf) *maxleaf = sf->maxleaf; 553 PetscFunctionReturn(0); 554 } 555 556 /*@C 557 PetscSFView - view a star forest 558 559 Collective 560 561 Input Arguments: 562 + sf - star forest 563 - viewer - viewer to display graph, for example PETSC_VIEWER_STDOUT_WORLD 564 565 Level: beginner 566 567 .seealso: PetscSFCreate(), PetscSFSetGraph() 568 @*/ 569 PetscErrorCode PetscSFView(PetscSF sf,PetscViewer viewer) 570 { 571 PetscErrorCode ierr; 572 PetscBool iascii; 573 PetscViewerFormat format; 574 575 PetscFunctionBegin; 576 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 577 if (!viewer) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sf),&viewer);CHKERRQ(ierr);} 578 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 579 PetscCheckSameComm(sf,1,viewer,2); 580 if (sf->graphset) {ierr = PetscSFSetUp(sf);CHKERRQ(ierr);} 581 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 582 if (iascii) { 583 PetscMPIInt rank; 584 PetscInt ii,i,j; 585 586 ierr = PetscObjectPrintClassNamePrefixType((PetscObject)sf,viewer);CHKERRQ(ierr); 587 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 588 if (sf->ops->View) {ierr = (*sf->ops->View)(sf,viewer);CHKERRQ(ierr);} 589 if (!sf->graphset) { 590 ierr = PetscViewerASCIIPrintf(viewer,"PetscSFSetGraph() has not been called yet\n");CHKERRQ(ierr); 591 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 592 PetscFunctionReturn(0); 593 } 594 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)sf),&rank);CHKERRQ(ierr); 595 ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr); 596 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Number of roots=%D, leaves=%D, remote ranks=%D\n",rank,sf->nroots,sf->nleaves,sf->nranks);CHKERRQ(ierr); 597 for (i=0; i<sf->nleaves; i++) { 598 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); 599 } 600 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 601 ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr); 602 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 603 PetscMPIInt *tmpranks,*perm; 604 ierr = PetscMalloc2(sf->nranks,&tmpranks,sf->nranks,&perm);CHKERRQ(ierr); 605 ierr = PetscMemcpy(tmpranks,sf->ranks,sf->nranks*sizeof(tmpranks[0]));CHKERRQ(ierr); 606 for (i=0; i<sf->nranks; i++) perm[i] = i; 607 ierr = PetscSortMPIIntWithArray(sf->nranks,tmpranks,perm);CHKERRQ(ierr); 608 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Roots referenced by my leaves, by rank\n",rank);CHKERRQ(ierr); 609 for (ii=0; ii<sf->nranks; ii++) { 610 i = perm[ii]; 611 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] %d: %D edges\n",rank,sf->ranks[i],sf->roffset[i+1]-sf->roffset[i]);CHKERRQ(ierr); 612 for (j=sf->roffset[i]; j<sf->roffset[i+1]; j++) { 613 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] %D <- %D\n",rank,sf->rmine[j],sf->rremote[j]);CHKERRQ(ierr); 614 } 615 } 616 ierr = PetscFree2(tmpranks,perm);CHKERRQ(ierr); 617 } 618 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 619 ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr); 620 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 621 } 622 PetscFunctionReturn(0); 623 } 624 625 /*@C 626 PetscSFGetRanks - Get ranks and number of vertices referenced by leaves on this process 627 628 Not Collective 629 630 Input Arguments: 631 . sf - star forest 632 633 Output Arguments: 634 + nranks - number of ranks referenced by local part 635 . ranks - array of ranks 636 . roffset - offset in rmine/rremote for each rank (length nranks+1) 637 . rmine - concatenated array holding local indices referencing each remote rank 638 - rremote - concatenated array holding remote indices referenced for each remote rank 639 640 Level: developer 641 642 .seealso: PetscSFSetGraph() 643 @*/ 644 PetscErrorCode PetscSFGetRanks(PetscSF sf,PetscInt *nranks,const PetscMPIInt **ranks,const PetscInt **roffset,const PetscInt **rmine,const PetscInt **rremote) 645 { 646 647 PetscFunctionBegin; 648 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 649 if (!sf->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call PetscSFSetUp() before obtaining ranks"); 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 PetscFunctionReturn(0); 656 } 657 658 /*@C 659 PetscSFGetLeafRanks - Get leaf ranks referencing roots on this process 660 661 Not Collective 662 663 Input Arguments: 664 . sf - star forest 665 666 Output Arguments: 667 + niranks - number of leaf ranks referencing roots on this process 668 . iranks - array of ranks 669 . ioffset - offset in irootloc for each rank (length niranks+1) 670 - irootloc - concatenated array holding local indices of roots referenced by each leaf rank 671 672 Level: developer 673 674 .seealso: PetscSFGetRanks() 675 @*/ 676 PetscErrorCode PetscSFGetLeafRanks(PetscSF sf,PetscInt *niranks,const PetscMPIInt **iranks,const PetscInt **ioffset,const PetscInt **irootloc) 677 { 678 PetscErrorCode ierr; 679 680 PetscFunctionBegin; 681 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 682 if (!sf->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call PetscSFSetUp() before obtaining ranks"); 683 if (sf->ops->GetLeafRanks) { 684 ierr = (sf->ops->GetLeafRanks)(sf,niranks,iranks,ioffset,irootloc);CHKERRQ(ierr); 685 } else { 686 PetscSFType type; 687 ierr = PetscSFGetType(sf,&type);CHKERRQ(ierr); 688 SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"PetscSFGetLeafRanks() is not supported on this StarForest type: %s", type); 689 } 690 PetscFunctionReturn(0); 691 } 692 693 static PetscBool InList(PetscMPIInt needle,PetscMPIInt n,const PetscMPIInt *list) { 694 PetscInt i; 695 for (i=0; i<n; i++) { 696 if (needle == list[i]) return PETSC_TRUE; 697 } 698 return PETSC_FALSE; 699 } 700 701 /*@C 702 PetscSFSetUpRanks - Set up data structures associated with ranks; this is for internal use by PetscSF implementations. 703 704 Collective 705 706 Input Arguments: 707 + sf - PetscSF to set up; PetscSFSetGraph() must have been called 708 - dgroup - MPI_Group of ranks to be distinguished (e.g., for self or shared memory exchange) 709 710 Level: developer 711 712 .seealso: PetscSFGetRanks() 713 @*/ 714 PetscErrorCode PetscSFSetUpRanks(PetscSF sf,MPI_Group dgroup) 715 { 716 PetscErrorCode ierr; 717 PetscTable table; 718 PetscTablePosition pos; 719 PetscMPIInt size,groupsize,*groupranks; 720 PetscInt i,*rcount,*ranks; 721 722 PetscFunctionBegin; 723 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 724 PetscSFCheckGraphSet(sf,1); 725 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)sf),&size);CHKERRQ(ierr); 726 ierr = PetscTableCreate(10,size,&table);CHKERRQ(ierr); 727 for (i=0; i<sf->nleaves; i++) { 728 /* Log 1-based rank */ 729 ierr = PetscTableAdd(table,sf->remote[i].rank+1,1,ADD_VALUES);CHKERRQ(ierr); 730 } 731 ierr = PetscTableGetCount(table,&sf->nranks);CHKERRQ(ierr); 732 ierr = PetscMalloc4(sf->nranks,&sf->ranks,sf->nranks+1,&sf->roffset,sf->nleaves,&sf->rmine,sf->nleaves,&sf->rremote);CHKERRQ(ierr); 733 ierr = PetscMalloc2(sf->nranks,&rcount,sf->nranks,&ranks);CHKERRQ(ierr); 734 ierr = PetscTableGetHeadPosition(table,&pos);CHKERRQ(ierr); 735 for (i=0; i<sf->nranks; i++) { 736 ierr = PetscTableGetNext(table,&pos,&ranks[i],&rcount[i]);CHKERRQ(ierr); 737 ranks[i]--; /* Convert back to 0-based */ 738 } 739 ierr = PetscTableDestroy(&table);CHKERRQ(ierr); 740 741 /* We expect that dgroup is reliably "small" while nranks could be large */ 742 { 743 MPI_Group group = MPI_GROUP_NULL; 744 PetscMPIInt *dgroupranks; 745 ierr = MPI_Comm_group(PetscObjectComm((PetscObject)sf),&group);CHKERRQ(ierr); 746 ierr = MPI_Group_size(dgroup,&groupsize);CHKERRQ(ierr); 747 ierr = PetscMalloc1(groupsize,&dgroupranks);CHKERRQ(ierr); 748 ierr = PetscMalloc1(groupsize,&groupranks);CHKERRQ(ierr); 749 for (i=0; i<groupsize; i++) dgroupranks[i] = i; 750 if (groupsize) {ierr = MPI_Group_translate_ranks(dgroup,groupsize,dgroupranks,group,groupranks);CHKERRQ(ierr);} 751 ierr = MPI_Group_free(&group);CHKERRQ(ierr); 752 ierr = PetscFree(dgroupranks);CHKERRQ(ierr); 753 } 754 755 /* Partition ranks[] into distinguished (first sf->ndranks) followed by non-distinguished */ 756 for (sf->ndranks=0,i=sf->nranks; sf->ndranks<i; ) { 757 for (i--; sf->ndranks<i; i--) { /* Scan i backward looking for distinguished rank */ 758 if (InList(ranks[i],groupsize,groupranks)) break; 759 } 760 for ( ; sf->ndranks<=i; sf->ndranks++) { /* Scan sf->ndranks forward looking for non-distinguished rank */ 761 if (!InList(ranks[sf->ndranks],groupsize,groupranks)) break; 762 } 763 if (sf->ndranks < i) { /* Swap ranks[sf->ndranks] with ranks[i] */ 764 PetscInt tmprank,tmpcount; 765 tmprank = ranks[i]; 766 tmpcount = rcount[i]; 767 ranks[i] = ranks[sf->ndranks]; 768 rcount[i] = rcount[sf->ndranks]; 769 ranks[sf->ndranks] = tmprank; 770 rcount[sf->ndranks] = tmpcount; 771 sf->ndranks++; 772 } 773 } 774 ierr = PetscFree(groupranks);CHKERRQ(ierr); 775 ierr = PetscSortIntWithArray(sf->ndranks,ranks,rcount);CHKERRQ(ierr); 776 ierr = PetscSortIntWithArray(sf->nranks-sf->ndranks,ranks+sf->ndranks,rcount+sf->ndranks);CHKERRQ(ierr); 777 sf->roffset[0] = 0; 778 for (i=0; i<sf->nranks; i++) { 779 ierr = PetscMPIIntCast(ranks[i],sf->ranks+i);CHKERRQ(ierr); 780 sf->roffset[i+1] = sf->roffset[i] + rcount[i]; 781 rcount[i] = 0; 782 } 783 for (i=0; i<sf->nleaves; i++) { 784 PetscInt irank; 785 /* Search for index of iremote[i].rank in sf->ranks */ 786 ierr = PetscFindMPIInt(sf->remote[i].rank,sf->ndranks,sf->ranks,&irank);CHKERRQ(ierr); 787 if (irank < 0) { 788 ierr = PetscFindMPIInt(sf->remote[i].rank,sf->nranks-sf->ndranks,sf->ranks+sf->ndranks,&irank);CHKERRQ(ierr); 789 if (irank >= 0) irank += sf->ndranks; 790 } 791 if (irank < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not find rank %D in array",sf->remote[i].rank); 792 sf->rmine[sf->roffset[irank] + rcount[irank]] = sf->mine ? sf->mine[i] : i; 793 sf->rremote[sf->roffset[irank] + rcount[irank]] = sf->remote[i].index; 794 rcount[irank]++; 795 } 796 ierr = PetscFree2(rcount,ranks);CHKERRQ(ierr); 797 PetscFunctionReturn(0); 798 } 799 800 /*@C 801 PetscSFGetGroups - gets incoming and outgoing process groups 802 803 Collective 804 805 Input Argument: 806 . sf - star forest 807 808 Output Arguments: 809 + incoming - group of origin processes for incoming edges (leaves that reference my roots) 810 - outgoing - group of destination processes for outgoing edges (roots that I reference) 811 812 Level: developer 813 814 .seealso: PetscSFGetWindow(), PetscSFRestoreWindow() 815 @*/ 816 PetscErrorCode PetscSFGetGroups(PetscSF sf,MPI_Group *incoming,MPI_Group *outgoing) 817 { 818 PetscErrorCode ierr; 819 MPI_Group group = MPI_GROUP_NULL; 820 821 PetscFunctionBegin; 822 if (!sf->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call PetscSFSetUp() before obtaining groups"); 823 if (sf->ingroup == MPI_GROUP_NULL) { 824 PetscInt i; 825 const PetscInt *indegree; 826 PetscMPIInt rank,*outranks,*inranks; 827 PetscSFNode *remote; 828 PetscSF bgcount; 829 830 /* Compute the number of incoming ranks */ 831 ierr = PetscMalloc1(sf->nranks,&remote);CHKERRQ(ierr); 832 for (i=0; i<sf->nranks; i++) { 833 remote[i].rank = sf->ranks[i]; 834 remote[i].index = 0; 835 } 836 ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_CONFONLY,&bgcount);CHKERRQ(ierr); 837 ierr = PetscSFSetGraph(bgcount,1,sf->nranks,NULL,PETSC_COPY_VALUES,remote,PETSC_OWN_POINTER);CHKERRQ(ierr); 838 ierr = PetscSFComputeDegreeBegin(bgcount,&indegree);CHKERRQ(ierr); 839 ierr = PetscSFComputeDegreeEnd(bgcount,&indegree);CHKERRQ(ierr); 840 841 /* Enumerate the incoming ranks */ 842 ierr = PetscMalloc2(indegree[0],&inranks,sf->nranks,&outranks);CHKERRQ(ierr); 843 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)sf),&rank);CHKERRQ(ierr); 844 for (i=0; i<sf->nranks; i++) outranks[i] = rank; 845 ierr = PetscSFGatherBegin(bgcount,MPI_INT,outranks,inranks);CHKERRQ(ierr); 846 ierr = PetscSFGatherEnd(bgcount,MPI_INT,outranks,inranks);CHKERRQ(ierr); 847 ierr = MPI_Comm_group(PetscObjectComm((PetscObject)sf),&group);CHKERRQ(ierr); 848 ierr = MPI_Group_incl(group,indegree[0],inranks,&sf->ingroup);CHKERRQ(ierr); 849 ierr = MPI_Group_free(&group);CHKERRQ(ierr); 850 ierr = PetscFree2(inranks,outranks);CHKERRQ(ierr); 851 ierr = PetscSFDestroy(&bgcount);CHKERRQ(ierr); 852 } 853 *incoming = sf->ingroup; 854 855 if (sf->outgroup == MPI_GROUP_NULL) { 856 ierr = MPI_Comm_group(PetscObjectComm((PetscObject)sf),&group);CHKERRQ(ierr); 857 ierr = MPI_Group_incl(group,sf->nranks,sf->ranks,&sf->outgroup);CHKERRQ(ierr); 858 ierr = MPI_Group_free(&group);CHKERRQ(ierr); 859 } 860 *outgoing = sf->outgroup; 861 PetscFunctionReturn(0); 862 } 863 864 /*@ 865 PetscSFGetMultiSF - gets the inner SF implemeting gathers and scatters 866 867 Collective 868 869 Input Argument: 870 . sf - star forest that may contain roots with 0 or with more than 1 vertex 871 872 Output Arguments: 873 . multi - star forest with split roots, such that each root has degree exactly 1 874 875 Level: developer 876 877 Notes: 878 879 In most cases, users should use PetscSFGatherBegin() and PetscSFScatterBegin() instead of manipulating multi 880 directly. Since multi satisfies the stronger condition that each entry in the global space has exactly one incoming 881 edge, it is a candidate for future optimization that might involve its removal. 882 883 .seealso: PetscSFSetGraph(), PetscSFGatherBegin(), PetscSFScatterBegin(), PetscSFComputeMultiRootOriginalNumbering() 884 @*/ 885 PetscErrorCode PetscSFGetMultiSF(PetscSF sf,PetscSF *multi) 886 { 887 PetscErrorCode ierr; 888 889 PetscFunctionBegin; 890 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 891 PetscValidPointer(multi,2); 892 if (sf->nroots < 0) { /* Graph has not been set yet; why do we need this? */ 893 ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_RANKS,&sf->multi);CHKERRQ(ierr); 894 *multi = sf->multi; 895 PetscFunctionReturn(0); 896 } 897 if (!sf->multi) { 898 const PetscInt *indegree; 899 PetscInt i,*inoffset,*outones,*outoffset,maxlocal; 900 PetscSFNode *remote; 901 maxlocal = sf->maxleaf+1; /* TODO: We should use PetscSFGetLeafRange() */ 902 ierr = PetscSFComputeDegreeBegin(sf,&indegree);CHKERRQ(ierr); 903 ierr = PetscSFComputeDegreeEnd(sf,&indegree);CHKERRQ(ierr); 904 ierr = PetscMalloc3(sf->nroots+1,&inoffset,maxlocal,&outones,maxlocal,&outoffset);CHKERRQ(ierr); 905 inoffset[0] = 0; 906 for (i=0; i<sf->nroots; i++) inoffset[i+1] = inoffset[i] + indegree[i]; 907 for (i=0; i<maxlocal; i++) outones[i] = 1; 908 ierr = PetscSFFetchAndOpBegin(sf,MPIU_INT,inoffset,outones,outoffset,MPI_SUM);CHKERRQ(ierr); 909 ierr = PetscSFFetchAndOpEnd(sf,MPIU_INT,inoffset,outones,outoffset,MPI_SUM);CHKERRQ(ierr); 910 for (i=0; i<sf->nroots; i++) inoffset[i] -= indegree[i]; /* Undo the increment */ 911 #if 0 912 #if defined(PETSC_USE_DEBUG) /* Check that the expected number of increments occurred */ 913 for (i=0; i<sf->nroots; i++) { 914 if (inoffset[i] + indegree[i] != inoffset[i+1]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Incorrect result after PetscSFFetchAndOp"); 915 } 916 #endif 917 #endif 918 ierr = PetscMalloc1(sf->nleaves,&remote);CHKERRQ(ierr); 919 for (i=0; i<sf->nleaves; i++) { 920 remote[i].rank = sf->remote[i].rank; 921 remote[i].index = outoffset[sf->mine ? sf->mine[i] : i]; 922 } 923 ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_RANKS,&sf->multi);CHKERRQ(ierr); 924 ierr = PetscSFSetGraph(sf->multi,inoffset[sf->nroots],sf->nleaves,sf->mine,PETSC_COPY_VALUES,remote,PETSC_OWN_POINTER);CHKERRQ(ierr); 925 if (sf->rankorder) { /* Sort the ranks */ 926 PetscMPIInt rank; 927 PetscInt *inranks,*newoffset,*outranks,*newoutoffset,*tmpoffset,maxdegree; 928 PetscSFNode *newremote; 929 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)sf),&rank);CHKERRQ(ierr); 930 for (i=0,maxdegree=0; i<sf->nroots; i++) maxdegree = PetscMax(maxdegree,indegree[i]); 931 ierr = PetscMalloc5(sf->multi->nroots,&inranks,sf->multi->nroots,&newoffset,maxlocal,&outranks,maxlocal,&newoutoffset,maxdegree,&tmpoffset);CHKERRQ(ierr); 932 for (i=0; i<maxlocal; i++) outranks[i] = rank; 933 ierr = PetscSFReduceBegin(sf->multi,MPIU_INT,outranks,inranks,MPIU_REPLACE);CHKERRQ(ierr); 934 ierr = PetscSFReduceEnd(sf->multi,MPIU_INT,outranks,inranks,MPIU_REPLACE);CHKERRQ(ierr); 935 /* Sort the incoming ranks at each vertex, build the inverse map */ 936 for (i=0; i<sf->nroots; i++) { 937 PetscInt j; 938 for (j=0; j<indegree[i]; j++) tmpoffset[j] = j; 939 ierr = PetscSortIntWithArray(indegree[i],inranks+inoffset[i],tmpoffset);CHKERRQ(ierr); 940 for (j=0; j<indegree[i]; j++) newoffset[inoffset[i] + tmpoffset[j]] = inoffset[i] + j; 941 } 942 ierr = PetscSFBcastBegin(sf->multi,MPIU_INT,newoffset,newoutoffset);CHKERRQ(ierr); 943 ierr = PetscSFBcastEnd(sf->multi,MPIU_INT,newoffset,newoutoffset);CHKERRQ(ierr); 944 ierr = PetscMalloc1(sf->nleaves,&newremote);CHKERRQ(ierr); 945 for (i=0; i<sf->nleaves; i++) { 946 newremote[i].rank = sf->remote[i].rank; 947 newremote[i].index = newoutoffset[sf->mine ? sf->mine[i] : i]; 948 } 949 ierr = PetscSFSetGraph(sf->multi,inoffset[sf->nroots],sf->nleaves,sf->mine,PETSC_COPY_VALUES,newremote,PETSC_OWN_POINTER);CHKERRQ(ierr); 950 ierr = PetscFree5(inranks,newoffset,outranks,newoutoffset,tmpoffset);CHKERRQ(ierr); 951 } 952 ierr = PetscFree3(inoffset,outones,outoffset);CHKERRQ(ierr); 953 } 954 *multi = sf->multi; 955 PetscFunctionReturn(0); 956 } 957 958 /*@C 959 PetscSFCreateEmbeddedSF - removes edges from all but the selected roots, does not remap indices 960 961 Collective 962 963 Input Arguments: 964 + sf - original star forest 965 . nroots - number of roots to select on this process 966 - selected - selected roots on this process 967 968 Output Arguments: 969 . newsf - new star forest 970 971 Level: advanced 972 973 Note: 974 To use the new PetscSF, it may be necessary to know the indices of the leaves that are still participating. This can 975 be done by calling PetscSFGetGraph(). 976 977 .seealso: PetscSFSetGraph(), PetscSFGetGraph() 978 @*/ 979 PetscErrorCode PetscSFCreateEmbeddedSF(PetscSF sf,PetscInt nroots,const PetscInt *selected,PetscSF *newsf) 980 { 981 PetscInt *rootdata, *leafdata, *ilocal; 982 PetscSFNode *iremote; 983 PetscInt leafsize = 0, nleaves = 0, n, i; 984 PetscErrorCode ierr; 985 986 PetscFunctionBegin; 987 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 988 PetscSFCheckGraphSet(sf,1); 989 if (nroots) PetscValidPointer(selected,3); 990 PetscValidPointer(newsf,4); 991 if (sf->mine) for (i = 0; i < sf->nleaves; ++i) {leafsize = PetscMax(leafsize, sf->mine[i]+1);} 992 else leafsize = sf->nleaves; 993 ierr = PetscCalloc2(sf->nroots,&rootdata,leafsize,&leafdata);CHKERRQ(ierr); 994 for (i=0; i<nroots; ++i) rootdata[selected[i]] = 1; 995 ierr = PetscSFBcastBegin(sf,MPIU_INT,rootdata,leafdata);CHKERRQ(ierr); 996 ierr = PetscSFBcastEnd(sf,MPIU_INT,rootdata,leafdata);CHKERRQ(ierr); 997 for (i = 0; i < leafsize; ++i) nleaves += leafdata[i]; 998 ierr = PetscMalloc1(nleaves,&ilocal);CHKERRQ(ierr); 999 ierr = PetscMalloc1(nleaves,&iremote);CHKERRQ(ierr); 1000 for (i = 0, n = 0; i < sf->nleaves; ++i) { 1001 const PetscInt lidx = sf->mine ? sf->mine[i] : i; 1002 1003 if (leafdata[lidx]) { 1004 ilocal[n] = lidx; 1005 iremote[n].rank = sf->remote[i].rank; 1006 iremote[n].index = sf->remote[i].index; 1007 ++n; 1008 } 1009 } 1010 if (n != nleaves) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "There is a size mismatch in the SF embedding, %d != %d", n, nleaves); 1011 ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_RANKS,newsf);CHKERRQ(ierr); 1012 ierr = PetscSFSetGraph(*newsf,sf->nroots,nleaves,ilocal,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER);CHKERRQ(ierr); 1013 ierr = PetscFree2(rootdata,leafdata);CHKERRQ(ierr); 1014 PetscFunctionReturn(0); 1015 } 1016 1017 /*@C 1018 PetscSFCreateEmbeddedLeafSF - removes edges from all but the selected leaves, does not remap indices 1019 1020 Collective 1021 1022 Input Arguments: 1023 + sf - original star forest 1024 . nleaves - number of leaves to select on this process 1025 - selected - selected leaves on this process 1026 1027 Output Arguments: 1028 . newsf - new star forest 1029 1030 Level: advanced 1031 1032 .seealso: PetscSFCreateEmbeddedSF(), PetscSFSetGraph(), PetscSFGetGraph() 1033 @*/ 1034 PetscErrorCode PetscSFCreateEmbeddedLeafSF(PetscSF sf, PetscInt nleaves, const PetscInt *selected, PetscSF *newsf) 1035 { 1036 PetscSFNode *iremote; 1037 PetscInt *ilocal; 1038 PetscInt i; 1039 PetscErrorCode ierr; 1040 1041 PetscFunctionBegin; 1042 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1); 1043 PetscSFCheckGraphSet(sf, 1); 1044 if (nleaves) PetscValidPointer(selected, 3); 1045 PetscValidPointer(newsf, 4); 1046 ierr = PetscMalloc1(nleaves, &ilocal);CHKERRQ(ierr); 1047 ierr = PetscMalloc1(nleaves, &iremote);CHKERRQ(ierr); 1048 for (i = 0; i < nleaves; ++i) { 1049 const PetscInt l = selected[i]; 1050 1051 ilocal[i] = sf->mine ? sf->mine[l] : l; 1052 iremote[i].rank = sf->remote[l].rank; 1053 iremote[i].index = sf->remote[l].index; 1054 } 1055 ierr = PetscSFDuplicate(sf, PETSCSF_DUPLICATE_RANKS, newsf);CHKERRQ(ierr); 1056 ierr = PetscSFSetGraph(*newsf, sf->nroots, nleaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER);CHKERRQ(ierr); 1057 PetscFunctionReturn(0); 1058 } 1059 1060 /*@C 1061 PetscSFBcastBegin - begin pointwise broadcast to be concluded with call to PetscSFBcastEnd() 1062 1063 Collective on PetscSF 1064 1065 Input Arguments: 1066 + sf - star forest on which to communicate 1067 . unit - data type associated with each node 1068 - rootdata - buffer to broadcast 1069 1070 Output Arguments: 1071 . leafdata - buffer to update with values from each leaf's respective root 1072 1073 Level: intermediate 1074 1075 .seealso: PetscSFCreate(), PetscSFSetGraph(), PetscSFView(), PetscSFBcastEnd(), PetscSFReduceBegin() 1076 @*/ 1077 PetscErrorCode PetscSFBcastBegin(PetscSF sf,MPI_Datatype unit,const void *rootdata,void *leafdata) 1078 { 1079 PetscErrorCode ierr; 1080 1081 PetscFunctionBegin; 1082 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1083 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1084 ierr = PetscLogEventBegin(PETSCSF_BcastBegin,sf,0,0,0);CHKERRQ(ierr); 1085 ierr = (*sf->ops->BcastBegin)(sf,unit,rootdata,leafdata);CHKERRQ(ierr); 1086 ierr = PetscLogEventEnd(PETSCSF_BcastBegin,sf,0,0,0);CHKERRQ(ierr); 1087 PetscFunctionReturn(0); 1088 } 1089 1090 /*@C 1091 PetscSFBcastEnd - end a broadcast operation started with PetscSFBcastBegin() 1092 1093 Collective 1094 1095 Input Arguments: 1096 + sf - star forest 1097 . unit - data type 1098 - rootdata - buffer to broadcast 1099 1100 Output Arguments: 1101 . leafdata - buffer to update with values from each leaf's respective root 1102 1103 Level: intermediate 1104 1105 .seealso: PetscSFSetGraph(), PetscSFReduceEnd() 1106 @*/ 1107 PetscErrorCode PetscSFBcastEnd(PetscSF sf,MPI_Datatype unit,const void *rootdata,void *leafdata) 1108 { 1109 PetscErrorCode ierr; 1110 1111 PetscFunctionBegin; 1112 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1113 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1114 ierr = PetscLogEventBegin(PETSCSF_BcastEnd,sf,0,0,0);CHKERRQ(ierr); 1115 ierr = (*sf->ops->BcastEnd)(sf,unit,rootdata,leafdata);CHKERRQ(ierr); 1116 ierr = PetscLogEventEnd(PETSCSF_BcastEnd,sf,0,0,0);CHKERRQ(ierr); 1117 PetscFunctionReturn(0); 1118 } 1119 1120 /*@C 1121 PetscSFBcastAndOpBegin - begin pointwise broadcast with root value being reduced to leaf value, to be concluded with call to PetscSFBcastAndOpEnd() 1122 1123 Collective on PetscSF 1124 1125 Input Arguments: 1126 + sf - star forest on which to communicate 1127 . unit - data type associated with each node 1128 . rootdata - buffer to broadcast 1129 - op - operation to use for reduction 1130 1131 Output Arguments: 1132 . leafdata - buffer to be reduced with values from each leaf's respective root 1133 1134 Level: intermediate 1135 1136 .seealso: PetscSFBcastAndOpEnd(), PetscSFBcastBegin(), PetscSFBcastEnd() 1137 @*/ 1138 PetscErrorCode PetscSFBcastAndOpBegin(PetscSF sf,MPI_Datatype unit,const void *rootdata,void *leafdata,MPI_Op op) 1139 { 1140 PetscErrorCode ierr; 1141 1142 PetscFunctionBegin; 1143 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1144 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1145 ierr = PetscLogEventBegin(PETSCSF_BcastAndOpBegin,sf,0,0,0);CHKERRQ(ierr); 1146 ierr = (*sf->ops->BcastAndOpBegin)(sf,unit,rootdata,leafdata,op);CHKERRQ(ierr); 1147 ierr = PetscLogEventEnd(PETSCSF_BcastAndOpBegin,sf,0,0,0);CHKERRQ(ierr); 1148 PetscFunctionReturn(0); 1149 } 1150 1151 /*@C 1152 PetscSFBcastAndOpEnd - end a broadcast & reduce operation started with PetscSFBcastAndOpBegin() 1153 1154 Collective 1155 1156 Input Arguments: 1157 + sf - star forest 1158 . unit - data type 1159 . rootdata - buffer to broadcast 1160 - op - operation to use for reduction 1161 1162 Output Arguments: 1163 . leafdata - buffer to be reduced with values from each leaf's respective root 1164 1165 Level: intermediate 1166 1167 .seealso: PetscSFSetGraph(), PetscSFReduceEnd() 1168 @*/ 1169 PetscErrorCode PetscSFBcastAndOpEnd(PetscSF sf,MPI_Datatype unit,const void *rootdata,void *leafdata,MPI_Op op) 1170 { 1171 PetscErrorCode ierr; 1172 1173 PetscFunctionBegin; 1174 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1175 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1176 ierr = PetscLogEventBegin(PETSCSF_BcastAndOpEnd,sf,0,0,0);CHKERRQ(ierr); 1177 ierr = (*sf->ops->BcastAndOpEnd)(sf,unit,rootdata,leafdata,op);CHKERRQ(ierr); 1178 ierr = PetscLogEventEnd(PETSCSF_BcastAndOpEnd,sf,0,0,0);CHKERRQ(ierr); 1179 PetscFunctionReturn(0); 1180 } 1181 1182 /*@C 1183 PetscSFReduceBegin - begin reduction of leafdata into rootdata, to be completed with call to PetscSFReduceEnd() 1184 1185 Collective 1186 1187 Input Arguments: 1188 + sf - star forest 1189 . unit - data type 1190 . leafdata - values to reduce 1191 - op - reduction operation 1192 1193 Output Arguments: 1194 . rootdata - result of reduction of values from all leaves of each root 1195 1196 Level: intermediate 1197 1198 .seealso: PetscSFBcastBegin() 1199 @*/ 1200 PetscErrorCode PetscSFReduceBegin(PetscSF sf,MPI_Datatype unit,const void *leafdata,void *rootdata,MPI_Op op) 1201 { 1202 PetscErrorCode ierr; 1203 1204 PetscFunctionBegin; 1205 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1206 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1207 ierr = PetscLogEventBegin(PETSCSF_ReduceBegin,sf,0,0,0);CHKERRQ(ierr); 1208 ierr = (sf->ops->ReduceBegin)(sf,unit,leafdata,rootdata,op);CHKERRQ(ierr); 1209 ierr = PetscLogEventEnd(PETSCSF_ReduceBegin,sf,0,0,0);CHKERRQ(ierr); 1210 PetscFunctionReturn(0); 1211 } 1212 1213 /*@C 1214 PetscSFReduceEnd - end a reduction operation started with PetscSFReduceBegin() 1215 1216 Collective 1217 1218 Input Arguments: 1219 + sf - star forest 1220 . unit - data type 1221 . leafdata - values to reduce 1222 - op - reduction operation 1223 1224 Output Arguments: 1225 . rootdata - result of reduction of values from all leaves of each root 1226 1227 Level: intermediate 1228 1229 .seealso: PetscSFSetGraph(), PetscSFBcastEnd() 1230 @*/ 1231 PetscErrorCode PetscSFReduceEnd(PetscSF sf,MPI_Datatype unit,const void *leafdata,void *rootdata,MPI_Op op) 1232 { 1233 PetscErrorCode ierr; 1234 1235 PetscFunctionBegin; 1236 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1237 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1238 ierr = PetscLogEventBegin(PETSCSF_ReduceEnd,sf,0,0,0);CHKERRQ(ierr); 1239 ierr = (*sf->ops->ReduceEnd)(sf,unit,leafdata,rootdata,op);CHKERRQ(ierr); 1240 ierr = PetscLogEventEnd(PETSCSF_ReduceEnd,sf,0,0,0);CHKERRQ(ierr); 1241 PetscFunctionReturn(0); 1242 } 1243 1244 /*@C 1245 PetscSFComputeDegreeBegin - begin computation of degree for each root vertex, to be completed with PetscSFComputeDegreeEnd() 1246 1247 Collective 1248 1249 Input Arguments: 1250 . sf - star forest 1251 1252 Output Arguments: 1253 . degree - degree of each root vertex 1254 1255 Level: advanced 1256 1257 .seealso: PetscSFGatherBegin() 1258 @*/ 1259 PetscErrorCode PetscSFComputeDegreeBegin(PetscSF sf,const PetscInt **degree) 1260 { 1261 PetscErrorCode ierr; 1262 1263 PetscFunctionBegin; 1264 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1265 PetscSFCheckGraphSet(sf,1); 1266 PetscValidPointer(degree,2); 1267 if (!sf->degreeknown) { 1268 PetscInt i, nroots = sf->nroots, maxlocal = sf->maxleaf+1; /* TODO: We should use PetscSFGetLeafRange() */ 1269 if (sf->degree) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Calls to PetscSFComputeDegreeBegin() cannot be nested."); 1270 ierr = PetscMalloc1(nroots,&sf->degree);CHKERRQ(ierr); 1271 ierr = PetscMalloc1(PetscMax(maxlocal,1),&sf->degreetmp);CHKERRQ(ierr); /* allocate at least one entry, see check in PetscSFComputeDegreeEnd() */ 1272 for (i=0; i<nroots; i++) sf->degree[i] = 0; 1273 for (i=0; i<maxlocal; i++) sf->degreetmp[i] = 1; 1274 ierr = PetscSFReduceBegin(sf,MPIU_INT,sf->degreetmp,sf->degree,MPI_SUM);CHKERRQ(ierr); 1275 } 1276 *degree = NULL; 1277 PetscFunctionReturn(0); 1278 } 1279 1280 /*@C 1281 PetscSFComputeDegreeEnd - complete computation of degree for each root vertex, started with PetscSFComputeDegreeBegin() 1282 1283 Collective 1284 1285 Input Arguments: 1286 . sf - star forest 1287 1288 Output Arguments: 1289 . degree - degree of each root vertex 1290 1291 Level: developer 1292 1293 .seealso: 1294 @*/ 1295 PetscErrorCode PetscSFComputeDegreeEnd(PetscSF sf,const PetscInt **degree) 1296 { 1297 PetscErrorCode ierr; 1298 1299 PetscFunctionBegin; 1300 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1301 PetscSFCheckGraphSet(sf,1); 1302 PetscValidPointer(degree,2); 1303 if (!sf->degreeknown) { 1304 if (!sf->degreetmp) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PetscSFComputeDegreeBegin() before PetscSFComputeDegreeEnd()"); 1305 ierr = PetscSFReduceEnd(sf,MPIU_INT,sf->degreetmp,sf->degree,MPI_SUM);CHKERRQ(ierr); 1306 ierr = PetscFree(sf->degreetmp);CHKERRQ(ierr); 1307 sf->degreeknown = PETSC_TRUE; 1308 } 1309 *degree = sf->degree; 1310 PetscFunctionReturn(0); 1311 } 1312 1313 1314 /*@C 1315 PetscSFComputeMultiRootOriginalNumbering - Returns original numbering of multi-roots (roots of multi-SF returned by PetscSFGetMultiSF()). Each multi-root is assigned index of its original root. 1316 1317 Collective 1318 1319 Input Arguments: 1320 + sf - star forest 1321 - degree - degree of each root vertex, computed with PetscSFComputeDegreeBegin()/PetscSFComputeDegreeEnd() 1322 1323 Output Arguments: 1324 . mRootsOrigNumbering - original indices of multi-roots; length of the array is equal to the number of multi-roots (roots of multi-SF) 1325 1326 Level: developer 1327 1328 .seealso: PetscSFComputeDegreeBegin(), PetscSFComputeDegreeEnd(), PetscSFGetMultiSF() 1329 @*/ 1330 PetscErrorCode PetscSFComputeMultiRootOriginalNumbering(PetscSF sf, const PetscInt degree[], PetscInt *mRootsOrigNumbering[]) 1331 { 1332 PetscSF msf; 1333 PetscInt i, j, k, nroots, nmroots; 1334 PetscErrorCode ierr; 1335 1336 PetscFunctionBegin; 1337 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1338 ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr); 1339 if (nroots) PetscValidIntPointer(degree,2); 1340 PetscValidPointer(mRootsOrigNumbering,3); 1341 ierr = PetscSFGetMultiSF(sf,&msf);CHKERRQ(ierr); 1342 ierr = PetscSFGetGraph(msf, &nmroots, NULL, NULL, NULL);CHKERRQ(ierr); 1343 ierr = PetscMalloc1(nmroots, mRootsOrigNumbering);CHKERRQ(ierr); 1344 for (i=0,j=0,k=0; i<nroots; i++) { 1345 if (!degree[i]) continue; 1346 for (j=0; j<degree[i]; j++,k++) { 1347 (*mRootsOrigNumbering)[k] = i; 1348 } 1349 } 1350 #if defined(PETSC_USE_DEBUG) 1351 if (PetscUnlikely(k != nmroots)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"sanity check fail"); 1352 #endif 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