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