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