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 ierr = PetscLogEventBegin(PETSCSF_EmbedSF,sf,0,0,0);CHKERRQ(ierr); 992 leafsize = sf->maxleaf + 1; 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 ierr = PetscSFSetUp(*newsf);CHKERRQ(ierr); 1015 ierr = PetscLogEventEnd(PETSCSF_EmbedSF,sf,0,0,0);CHKERRQ(ierr); 1016 PetscFunctionReturn(0); 1017 } 1018 1019 /*@C 1020 PetscSFCreateEmbeddedLeafSF - removes edges from all but the selected leaves, does not remap indices 1021 1022 Collective 1023 1024 Input Arguments: 1025 + sf - original star forest 1026 . nleaves - number of leaves to select on this process 1027 - selected - selected leaves on this process 1028 1029 Output Arguments: 1030 . newsf - new star forest 1031 1032 Level: advanced 1033 1034 .seealso: PetscSFCreateEmbeddedSF(), PetscSFSetGraph(), PetscSFGetGraph() 1035 @*/ 1036 PetscErrorCode PetscSFCreateEmbeddedLeafSF(PetscSF sf, PetscInt nleaves, const PetscInt *selected, PetscSF *newsf) 1037 { 1038 PetscSFNode *iremote; 1039 PetscInt *ilocal; 1040 PetscInt i; 1041 PetscErrorCode ierr; 1042 1043 PetscFunctionBegin; 1044 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1); 1045 PetscSFCheckGraphSet(sf, 1); 1046 if (nleaves) PetscValidPointer(selected, 3); 1047 PetscValidPointer(newsf, 4); 1048 ierr = PetscMalloc1(nleaves, &ilocal);CHKERRQ(ierr); 1049 ierr = PetscMalloc1(nleaves, &iremote);CHKERRQ(ierr); 1050 for (i = 0; i < nleaves; ++i) { 1051 const PetscInt l = selected[i]; 1052 1053 ilocal[i] = sf->mine ? sf->mine[l] : l; 1054 iremote[i].rank = sf->remote[l].rank; 1055 iremote[i].index = sf->remote[l].index; 1056 } 1057 ierr = PetscSFDuplicate(sf, PETSCSF_DUPLICATE_RANKS, newsf);CHKERRQ(ierr); 1058 ierr = PetscSFSetGraph(*newsf, sf->nroots, nleaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER);CHKERRQ(ierr); 1059 PetscFunctionReturn(0); 1060 } 1061 1062 /*@C 1063 PetscSFBcastBegin - begin pointwise broadcast to be concluded with call to PetscSFBcastEnd() 1064 1065 Collective on PetscSF 1066 1067 Input Arguments: 1068 + sf - star forest on which to communicate 1069 . unit - data type associated with each node 1070 - rootdata - buffer to broadcast 1071 1072 Output Arguments: 1073 . leafdata - buffer to update with values from each leaf's respective root 1074 1075 Level: intermediate 1076 1077 .seealso: PetscSFCreate(), PetscSFSetGraph(), PetscSFView(), PetscSFBcastEnd(), PetscSFReduceBegin() 1078 @*/ 1079 PetscErrorCode PetscSFBcastBegin(PetscSF sf,MPI_Datatype unit,const void *rootdata,void *leafdata) 1080 { 1081 PetscErrorCode ierr; 1082 1083 PetscFunctionBegin; 1084 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1085 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1086 ierr = PetscLogEventBegin(PETSCSF_BcastBegin,sf,0,0,0);CHKERRQ(ierr); 1087 ierr = (*sf->ops->BcastBegin)(sf,unit,rootdata,leafdata);CHKERRQ(ierr); 1088 ierr = PetscLogEventEnd(PETSCSF_BcastBegin,sf,0,0,0);CHKERRQ(ierr); 1089 PetscFunctionReturn(0); 1090 } 1091 1092 /*@C 1093 PetscSFBcastEnd - end a broadcast operation started with PetscSFBcastBegin() 1094 1095 Collective 1096 1097 Input Arguments: 1098 + sf - star forest 1099 . unit - data type 1100 - rootdata - buffer to broadcast 1101 1102 Output Arguments: 1103 . leafdata - buffer to update with values from each leaf's respective root 1104 1105 Level: intermediate 1106 1107 .seealso: PetscSFSetGraph(), PetscSFReduceEnd() 1108 @*/ 1109 PetscErrorCode PetscSFBcastEnd(PetscSF sf,MPI_Datatype unit,const void *rootdata,void *leafdata) 1110 { 1111 PetscErrorCode ierr; 1112 1113 PetscFunctionBegin; 1114 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1115 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1116 ierr = PetscLogEventBegin(PETSCSF_BcastEnd,sf,0,0,0);CHKERRQ(ierr); 1117 ierr = (*sf->ops->BcastEnd)(sf,unit,rootdata,leafdata);CHKERRQ(ierr); 1118 ierr = PetscLogEventEnd(PETSCSF_BcastEnd,sf,0,0,0);CHKERRQ(ierr); 1119 PetscFunctionReturn(0); 1120 } 1121 1122 /*@C 1123 PetscSFBcastAndOpBegin - begin pointwise broadcast with root value being reduced to leaf value, to be concluded with call to PetscSFBcastAndOpEnd() 1124 1125 Collective on PetscSF 1126 1127 Input Arguments: 1128 + sf - star forest on which to communicate 1129 . unit - data type associated with each node 1130 . rootdata - buffer to broadcast 1131 - op - operation to use for reduction 1132 1133 Output Arguments: 1134 . leafdata - buffer to be reduced with values from each leaf's respective root 1135 1136 Level: intermediate 1137 1138 .seealso: PetscSFBcastAndOpEnd(), PetscSFBcastBegin(), PetscSFBcastEnd() 1139 @*/ 1140 PetscErrorCode PetscSFBcastAndOpBegin(PetscSF sf,MPI_Datatype unit,const void *rootdata,void *leafdata,MPI_Op op) 1141 { 1142 PetscErrorCode ierr; 1143 1144 PetscFunctionBegin; 1145 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1146 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1147 ierr = PetscLogEventBegin(PETSCSF_BcastAndOpBegin,sf,0,0,0);CHKERRQ(ierr); 1148 ierr = (*sf->ops->BcastAndOpBegin)(sf,unit,rootdata,leafdata,op);CHKERRQ(ierr); 1149 ierr = PetscLogEventEnd(PETSCSF_BcastAndOpBegin,sf,0,0,0);CHKERRQ(ierr); 1150 PetscFunctionReturn(0); 1151 } 1152 1153 /*@C 1154 PetscSFBcastAndOpEnd - end a broadcast & reduce operation started with PetscSFBcastAndOpBegin() 1155 1156 Collective 1157 1158 Input Arguments: 1159 + sf - star forest 1160 . unit - data type 1161 . rootdata - buffer to broadcast 1162 - op - operation to use for reduction 1163 1164 Output Arguments: 1165 . leafdata - buffer to be reduced with values from each leaf's respective root 1166 1167 Level: intermediate 1168 1169 .seealso: PetscSFSetGraph(), PetscSFReduceEnd() 1170 @*/ 1171 PetscErrorCode PetscSFBcastAndOpEnd(PetscSF sf,MPI_Datatype unit,const void *rootdata,void *leafdata,MPI_Op op) 1172 { 1173 PetscErrorCode ierr; 1174 1175 PetscFunctionBegin; 1176 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1177 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1178 ierr = PetscLogEventBegin(PETSCSF_BcastAndOpEnd,sf,0,0,0);CHKERRQ(ierr); 1179 ierr = (*sf->ops->BcastAndOpEnd)(sf,unit,rootdata,leafdata,op);CHKERRQ(ierr); 1180 ierr = PetscLogEventEnd(PETSCSF_BcastAndOpEnd,sf,0,0,0);CHKERRQ(ierr); 1181 PetscFunctionReturn(0); 1182 } 1183 1184 /*@C 1185 PetscSFReduceBegin - begin reduction of leafdata into rootdata, to be completed with call to PetscSFReduceEnd() 1186 1187 Collective 1188 1189 Input Arguments: 1190 + sf - star forest 1191 . unit - data type 1192 . leafdata - values to reduce 1193 - op - reduction operation 1194 1195 Output Arguments: 1196 . rootdata - result of reduction of values from all leaves of each root 1197 1198 Level: intermediate 1199 1200 .seealso: PetscSFBcastBegin() 1201 @*/ 1202 PetscErrorCode PetscSFReduceBegin(PetscSF sf,MPI_Datatype unit,const void *leafdata,void *rootdata,MPI_Op op) 1203 { 1204 PetscErrorCode ierr; 1205 1206 PetscFunctionBegin; 1207 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1208 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1209 ierr = PetscLogEventBegin(PETSCSF_ReduceBegin,sf,0,0,0);CHKERRQ(ierr); 1210 ierr = (sf->ops->ReduceBegin)(sf,unit,leafdata,rootdata,op);CHKERRQ(ierr); 1211 ierr = PetscLogEventEnd(PETSCSF_ReduceBegin,sf,0,0,0);CHKERRQ(ierr); 1212 PetscFunctionReturn(0); 1213 } 1214 1215 /*@C 1216 PetscSFReduceEnd - end a reduction operation started with PetscSFReduceBegin() 1217 1218 Collective 1219 1220 Input Arguments: 1221 + sf - star forest 1222 . unit - data type 1223 . leafdata - values to reduce 1224 - op - reduction operation 1225 1226 Output Arguments: 1227 . rootdata - result of reduction of values from all leaves of each root 1228 1229 Level: intermediate 1230 1231 .seealso: PetscSFSetGraph(), PetscSFBcastEnd() 1232 @*/ 1233 PetscErrorCode PetscSFReduceEnd(PetscSF sf,MPI_Datatype unit,const void *leafdata,void *rootdata,MPI_Op op) 1234 { 1235 PetscErrorCode ierr; 1236 1237 PetscFunctionBegin; 1238 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1239 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1240 ierr = PetscLogEventBegin(PETSCSF_ReduceEnd,sf,0,0,0);CHKERRQ(ierr); 1241 ierr = (*sf->ops->ReduceEnd)(sf,unit,leafdata,rootdata,op);CHKERRQ(ierr); 1242 ierr = PetscLogEventEnd(PETSCSF_ReduceEnd,sf,0,0,0);CHKERRQ(ierr); 1243 PetscFunctionReturn(0); 1244 } 1245 1246 /*@C 1247 PetscSFComputeDegreeBegin - begin computation of degree for each root vertex, to be completed with PetscSFComputeDegreeEnd() 1248 1249 Collective 1250 1251 Input Arguments: 1252 . sf - star forest 1253 1254 Output Arguments: 1255 . degree - degree of each root vertex 1256 1257 Level: advanced 1258 1259 Notes: 1260 The returned array is owned by PetscSF and automatically freed by PetscSFDestroy(). Hence no need to call PetscFree() on it. 1261 1262 .seealso: PetscSFGatherBegin() 1263 @*/ 1264 PetscErrorCode PetscSFComputeDegreeBegin(PetscSF sf,const PetscInt **degree) 1265 { 1266 PetscErrorCode ierr; 1267 1268 PetscFunctionBegin; 1269 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1270 PetscSFCheckGraphSet(sf,1); 1271 PetscValidPointer(degree,2); 1272 if (!sf->degreeknown) { 1273 PetscInt i, nroots = sf->nroots, maxlocal = sf->maxleaf+1; /* TODO: We should use PetscSFGetLeafRange() */ 1274 if (sf->degree) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Calls to PetscSFComputeDegreeBegin() cannot be nested."); 1275 ierr = PetscMalloc1(nroots,&sf->degree);CHKERRQ(ierr); 1276 ierr = PetscMalloc1(PetscMax(maxlocal,1),&sf->degreetmp);CHKERRQ(ierr); /* allocate at least one entry, see check in PetscSFComputeDegreeEnd() */ 1277 for (i=0; i<nroots; i++) sf->degree[i] = 0; 1278 for (i=0; i<maxlocal; i++) sf->degreetmp[i] = 1; 1279 ierr = PetscSFReduceBegin(sf,MPIU_INT,sf->degreetmp,sf->degree,MPI_SUM);CHKERRQ(ierr); 1280 } 1281 *degree = NULL; 1282 PetscFunctionReturn(0); 1283 } 1284 1285 /*@C 1286 PetscSFComputeDegreeEnd - complete computation of degree for each root vertex, started with PetscSFComputeDegreeBegin() 1287 1288 Collective 1289 1290 Input Arguments: 1291 . sf - star forest 1292 1293 Output Arguments: 1294 . degree - degree of each root vertex 1295 1296 Level: developer 1297 1298 Notes: 1299 The returned array is owned by PetscSF and automatically freed by PetscSFDestroy(). Hence no need to call PetscFree() on it. 1300 1301 .seealso: 1302 @*/ 1303 PetscErrorCode PetscSFComputeDegreeEnd(PetscSF sf,const PetscInt **degree) 1304 { 1305 PetscErrorCode ierr; 1306 1307 PetscFunctionBegin; 1308 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1309 PetscSFCheckGraphSet(sf,1); 1310 PetscValidPointer(degree,2); 1311 if (!sf->degreeknown) { 1312 if (!sf->degreetmp) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PetscSFComputeDegreeBegin() before PetscSFComputeDegreeEnd()"); 1313 ierr = PetscSFReduceEnd(sf,MPIU_INT,sf->degreetmp,sf->degree,MPI_SUM);CHKERRQ(ierr); 1314 ierr = PetscFree(sf->degreetmp);CHKERRQ(ierr); 1315 sf->degreeknown = PETSC_TRUE; 1316 } 1317 *degree = sf->degree; 1318 PetscFunctionReturn(0); 1319 } 1320 1321 1322 /*@C 1323 PetscSFComputeMultiRootOriginalNumbering - Returns original numbering of multi-roots (roots of multi-SF returned by PetscSFGetMultiSF()). 1324 Each multi-root is assigned index of the corresponding original root. 1325 1326 Collective 1327 1328 Input Arguments: 1329 + sf - star forest 1330 - degree - degree of each root vertex, computed with PetscSFComputeDegreeBegin()/PetscSFComputeDegreeEnd() 1331 1332 Output Arguments: 1333 + nMultiRoots - (optional) number of multi-roots (roots of multi-SF) 1334 - multiRootsOrigNumbering - original indices of multi-roots; length of this array is nMultiRoots 1335 1336 Level: developer 1337 1338 Notes: 1339 The returned array multiRootsOrigNumbering is newly allocated and should be destroyed with PetscFree() when no longer needed. 1340 1341 .seealso: PetscSFComputeDegreeBegin(), PetscSFComputeDegreeEnd(), PetscSFGetMultiSF() 1342 @*/ 1343 PetscErrorCode PetscSFComputeMultiRootOriginalNumbering(PetscSF sf, const PetscInt degree[], PetscInt *nMultiRoots, PetscInt *multiRootsOrigNumbering[]) 1344 { 1345 PetscSF msf; 1346 PetscInt i, j, k, nroots, nmroots; 1347 PetscErrorCode ierr; 1348 1349 PetscFunctionBegin; 1350 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1351 ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr); 1352 if (nroots) PetscValidIntPointer(degree,2); 1353 if (nMultiRoots) PetscValidIntPointer(nMultiRoots,3); 1354 PetscValidPointer(multiRootsOrigNumbering,4); 1355 ierr = PetscSFGetMultiSF(sf,&msf);CHKERRQ(ierr); 1356 ierr = PetscSFGetGraph(msf, &nmroots, NULL, NULL, NULL);CHKERRQ(ierr); 1357 ierr = PetscMalloc1(nmroots, multiRootsOrigNumbering);CHKERRQ(ierr); 1358 for (i=0,j=0,k=0; i<nroots; i++) { 1359 if (!degree[i]) continue; 1360 for (j=0; j<degree[i]; j++,k++) { 1361 (*multiRootsOrigNumbering)[k] = i; 1362 } 1363 } 1364 #if defined(PETSC_USE_DEBUG) 1365 if (PetscUnlikely(k != nmroots)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"sanity check fail"); 1366 #endif 1367 if (nMultiRoots) *nMultiRoots = nmroots; 1368 PetscFunctionReturn(0); 1369 } 1370 1371 /*@C 1372 PetscSFFetchAndOpBegin - begin operation that fetches values from root and updates atomically by applying operation using my leaf value, to be completed with PetscSFFetchAndOpEnd() 1373 1374 Collective 1375 1376 Input Arguments: 1377 + sf - star forest 1378 . unit - data type 1379 . leafdata - leaf values to use in reduction 1380 - op - operation to use for reduction 1381 1382 Output Arguments: 1383 + rootdata - root values to be updated, input state is seen by first process to perform an update 1384 - leafupdate - state at each leaf's respective root immediately prior to my atomic update 1385 1386 Level: advanced 1387 1388 Note: 1389 The update is only atomic at the granularity provided by the hardware. Different roots referenced by the same process 1390 might be updated in a different order. Furthermore, if a composite type is used for the unit datatype, atomicity is 1391 not guaranteed across the whole vertex. Therefore, this function is mostly only used with primitive types such as 1392 integers. 1393 1394 .seealso: PetscSFComputeDegreeBegin(), PetscSFReduceBegin(), PetscSFSetGraph() 1395 @*/ 1396 PetscErrorCode PetscSFFetchAndOpBegin(PetscSF sf,MPI_Datatype unit,void *rootdata,const void *leafdata,void *leafupdate,MPI_Op op) 1397 { 1398 PetscErrorCode ierr; 1399 1400 PetscFunctionBegin; 1401 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1402 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1403 ierr = PetscLogEventBegin(PETSCSF_FetchAndOpBegin,sf,0,0,0);CHKERRQ(ierr); 1404 ierr = (*sf->ops->FetchAndOpBegin)(sf,unit,rootdata,leafdata,leafupdate,op);CHKERRQ(ierr); 1405 ierr = PetscLogEventEnd(PETSCSF_FetchAndOpBegin,sf,0,0,0);CHKERRQ(ierr); 1406 PetscFunctionReturn(0); 1407 } 1408 1409 /*@C 1410 PetscSFFetchAndOpEnd - end operation started in matching call to PetscSFFetchAndOpBegin() to fetch values from roots and update atomically by applying operation using my leaf value 1411 1412 Collective 1413 1414 Input Arguments: 1415 + sf - star forest 1416 . unit - data type 1417 . leafdata - leaf values to use in reduction 1418 - op - operation to use for reduction 1419 1420 Output Arguments: 1421 + rootdata - root values to be updated, input state is seen by first process to perform an update 1422 - leafupdate - state at each leaf's respective root immediately prior to my atomic update 1423 1424 Level: advanced 1425 1426 .seealso: PetscSFComputeDegreeEnd(), PetscSFReduceEnd(), PetscSFSetGraph() 1427 @*/ 1428 PetscErrorCode PetscSFFetchAndOpEnd(PetscSF sf,MPI_Datatype unit,void *rootdata,const void *leafdata,void *leafupdate,MPI_Op op) 1429 { 1430 PetscErrorCode ierr; 1431 1432 PetscFunctionBegin; 1433 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1434 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1435 ierr = PetscLogEventBegin(PETSCSF_FetchAndOpEnd,sf,0,0,0);CHKERRQ(ierr); 1436 ierr = (*sf->ops->FetchAndOpEnd)(sf,unit,rootdata,leafdata,leafupdate,op);CHKERRQ(ierr); 1437 ierr = PetscLogEventEnd(PETSCSF_FetchAndOpEnd,sf,0,0,0);CHKERRQ(ierr); 1438 PetscFunctionReturn(0); 1439 } 1440 1441 /*@C 1442 PetscSFGatherBegin - begin pointwise gather of all leaves into multi-roots, to be completed with PetscSFGatherEnd() 1443 1444 Collective 1445 1446 Input Arguments: 1447 + sf - star forest 1448 . unit - data type 1449 - leafdata - leaf data to gather to roots 1450 1451 Output Argument: 1452 . multirootdata - root buffer to gather into, amount of space per root is equal to its degree 1453 1454 Level: intermediate 1455 1456 .seealso: PetscSFComputeDegreeBegin(), PetscSFScatterBegin() 1457 @*/ 1458 PetscErrorCode PetscSFGatherBegin(PetscSF sf,MPI_Datatype unit,const void *leafdata,void *multirootdata) 1459 { 1460 PetscErrorCode ierr; 1461 PetscSF multi; 1462 1463 PetscFunctionBegin; 1464 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1465 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1466 ierr = PetscSFGetMultiSF(sf,&multi);CHKERRQ(ierr); 1467 ierr = PetscSFReduceBegin(multi,unit,leafdata,multirootdata,MPIU_REPLACE);CHKERRQ(ierr); 1468 PetscFunctionReturn(0); 1469 } 1470 1471 /*@C 1472 PetscSFGatherEnd - ends pointwise gather operation that was started with PetscSFGatherBegin() 1473 1474 Collective 1475 1476 Input Arguments: 1477 + sf - star forest 1478 . unit - data type 1479 - leafdata - leaf data to gather to roots 1480 1481 Output Argument: 1482 . multirootdata - root buffer to gather into, amount of space per root is equal to its degree 1483 1484 Level: intermediate 1485 1486 .seealso: PetscSFComputeDegreeEnd(), PetscSFScatterEnd() 1487 @*/ 1488 PetscErrorCode PetscSFGatherEnd(PetscSF sf,MPI_Datatype unit,const void *leafdata,void *multirootdata) 1489 { 1490 PetscErrorCode ierr; 1491 PetscSF multi; 1492 1493 PetscFunctionBegin; 1494 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1495 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1496 ierr = PetscSFGetMultiSF(sf,&multi);CHKERRQ(ierr); 1497 ierr = PetscSFReduceEnd(multi,unit,leafdata,multirootdata,MPIU_REPLACE);CHKERRQ(ierr); 1498 PetscFunctionReturn(0); 1499 } 1500 1501 /*@C 1502 PetscSFScatterBegin - begin pointwise scatter operation from multi-roots to leaves, to be completed with PetscSFScatterEnd() 1503 1504 Collective 1505 1506 Input Arguments: 1507 + sf - star forest 1508 . unit - data type 1509 - multirootdata - root buffer to send to each leaf, one unit of data per leaf 1510 1511 Output Argument: 1512 . leafdata - leaf data to be update with personal data from each respective root 1513 1514 Level: intermediate 1515 1516 .seealso: PetscSFComputeDegreeBegin(), PetscSFScatterBegin() 1517 @*/ 1518 PetscErrorCode PetscSFScatterBegin(PetscSF sf,MPI_Datatype unit,const void *multirootdata,void *leafdata) 1519 { 1520 PetscErrorCode ierr; 1521 PetscSF multi; 1522 1523 PetscFunctionBegin; 1524 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1525 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1526 ierr = PetscSFGetMultiSF(sf,&multi);CHKERRQ(ierr); 1527 ierr = PetscSFBcastBegin(multi,unit,multirootdata,leafdata);CHKERRQ(ierr); 1528 PetscFunctionReturn(0); 1529 } 1530 1531 /*@C 1532 PetscSFScatterEnd - ends pointwise scatter operation that was started with PetscSFScatterBegin() 1533 1534 Collective 1535 1536 Input Arguments: 1537 + sf - star forest 1538 . unit - data type 1539 - multirootdata - root buffer to send to each leaf, one unit of data per leaf 1540 1541 Output Argument: 1542 . leafdata - leaf data to be update with personal data from each respective root 1543 1544 Level: intermediate 1545 1546 .seealso: PetscSFComputeDegreeEnd(), PetscSFScatterEnd() 1547 @*/ 1548 PetscErrorCode PetscSFScatterEnd(PetscSF sf,MPI_Datatype unit,const void *multirootdata,void *leafdata) 1549 { 1550 PetscErrorCode ierr; 1551 PetscSF multi; 1552 1553 PetscFunctionBegin; 1554 PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); 1555 ierr = PetscSFSetUp(sf);CHKERRQ(ierr); 1556 ierr = PetscSFGetMultiSF(sf,&multi);CHKERRQ(ierr); 1557 ierr = PetscSFBcastEnd(multi,unit,multirootdata,leafdata);CHKERRQ(ierr); 1558 PetscFunctionReturn(0); 1559 } 1560 1561 /*@ 1562 PetscSFCompose - Compose a new PetscSF equivalent to action to PetscSFs 1563 1564 Input Parameters: 1565 + sfA - The first PetscSF 1566 - sfB - The second PetscSF 1567 1568 Output Parameters: 1569 . sfBA - equvalent PetscSF for applying A then B 1570 1571 Level: developer 1572 1573 .seealso: PetscSF, PetscSFGetGraph(), PetscSFSetGraph() 1574 @*/ 1575 PetscErrorCode PetscSFCompose(PetscSF sfA, PetscSF sfB, PetscSF *sfBA) 1576 { 1577 MPI_Comm comm; 1578 const PetscSFNode *remotePointsA, *remotePointsB; 1579 PetscSFNode *remotePointsBA; 1580 const PetscInt *localPointsA, *localPointsB; 1581 PetscInt numRootsA, numLeavesA, numRootsB, numLeavesB; 1582 PetscErrorCode ierr; 1583 1584 PetscFunctionBegin; 1585 PetscValidHeaderSpecific(sfA, PETSCSF_CLASSID, 1); 1586 PetscSFCheckGraphSet(sfA, 1); 1587 PetscValidHeaderSpecific(sfB, PETSCSF_CLASSID, 2); 1588 PetscSFCheckGraphSet(sfB, 2); 1589 PetscValidPointer(sfBA, 3); 1590 ierr = PetscObjectGetComm((PetscObject) sfA, &comm);CHKERRQ(ierr); 1591 ierr = PetscSFGetGraph(sfA, &numRootsA, &numLeavesA, &localPointsA, &remotePointsA);CHKERRQ(ierr); 1592 ierr = PetscSFGetGraph(sfB, &numRootsB, &numLeavesB, &localPointsB, &remotePointsB);CHKERRQ(ierr); 1593 ierr = PetscMalloc1(numLeavesB, &remotePointsBA);CHKERRQ(ierr); 1594 ierr = PetscSFBcastBegin(sfB, MPIU_2INT, remotePointsA, remotePointsBA);CHKERRQ(ierr); 1595 ierr = PetscSFBcastEnd(sfB, MPIU_2INT, remotePointsA, remotePointsBA);CHKERRQ(ierr); 1596 ierr = PetscSFCreate(comm, sfBA);CHKERRQ(ierr); 1597 ierr = PetscSFSetGraph(*sfBA, numRootsA, numLeavesB, localPointsB, PETSC_COPY_VALUES, remotePointsBA, PETSC_OWN_POINTER);CHKERRQ(ierr); 1598 PetscFunctionReturn(0); 1599 } 1600