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