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