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