xref: /petsc/src/vec/is/sf/interface/sf.c (revision d41018fbca6d4154d714cb88048ef0415f9bedc1)
1af0996ceSBarry Smith #include <petsc/private/sfimpl.h> /*I "petscsf.h" I*/
295fce210SBarry Smith #include <petscctable.h>
395fce210SBarry Smith 
495fce210SBarry Smith #if defined(PETSC_USE_DEBUG)
595fce210SBarry Smith #  define PetscSFCheckGraphSet(sf,arg) do {                          \
695fce210SBarry Smith     if (PetscUnlikely(!(sf)->graphset))                              \
7dd5b3ca6SJunchao Zhang       SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call PetscSFSetGraph() or PetscSFSetGraphWithPattern() on argument %D \"%s\" before %s()",(arg),#sf,PETSC_FUNCTION_NAME); \
895fce210SBarry Smith   } while (0)
995fce210SBarry Smith #else
1095fce210SBarry Smith #  define PetscSFCheckGraphSet(sf,arg) do {} while (0)
1195fce210SBarry Smith #endif
1295fce210SBarry Smith 
1395fce210SBarry Smith const char *const PetscSFDuplicateOptions[] = {"CONFONLY","RANKS","GRAPH","PetscSFDuplicateOption","PETSCSF_DUPLICATE_",0};
1495fce210SBarry Smith 
158af6ec1cSBarry Smith /*@
1695fce210SBarry Smith    PetscSFCreate - create a star forest communication context
1795fce210SBarry Smith 
18d083f849SBarry Smith    Collective
1995fce210SBarry Smith 
2095fce210SBarry Smith    Input Arguments:
2195fce210SBarry Smith .  comm - communicator on which the star forest will operate
2295fce210SBarry Smith 
2395fce210SBarry Smith    Output Arguments:
2495fce210SBarry Smith .  sf - new star forest context
2595fce210SBarry Smith 
26dd5b3ca6SJunchao Zhang    Options Database Keys:
27dd5b3ca6SJunchao Zhang +  -sf_type basic     -Use MPI persistent Isend/Irecv for communication (Default)
28dd5b3ca6SJunchao Zhang .  -sf_type window    -Use MPI-3 one-sided window for communication
29dd5b3ca6SJunchao Zhang -  -sf_type neighbor  -Use MPI-3 neighborhood collectives for communication
30dd5b3ca6SJunchao Zhang 
3195fce210SBarry Smith    Level: intermediate
3295fce210SBarry Smith 
33dd5b3ca6SJunchao Zhang    Notes:
34dd5b3ca6SJunchao Zhang    When one knows the communication graph is one of the predefined graph, such as MPI_Alltoall, MPI_Allgatherv,
35dd5b3ca6SJunchao Zhang    MPI_Gatherv, one can create a PetscSF and then set its graph with PetscSFSetGraphWithPattern(). These special
36dd5b3ca6SJunchao Zhang    SFs are optimized and they have better performance than general SFs.
37dd5b3ca6SJunchao Zhang 
38dd5b3ca6SJunchao Zhang .seealso: PetscSFSetGraph(), PetscSFSetGraphWithPattern(), PetscSFDestroy()
3995fce210SBarry Smith @*/
4095fce210SBarry Smith PetscErrorCode PetscSFCreate(MPI_Comm comm,PetscSF *sf)
4195fce210SBarry Smith {
4295fce210SBarry Smith   PetscErrorCode ierr;
4395fce210SBarry Smith   PetscSF        b;
4495fce210SBarry Smith 
4595fce210SBarry Smith   PetscFunctionBegin;
4695fce210SBarry Smith   PetscValidPointer(sf,2);
47607a6623SBarry Smith   ierr = PetscSFInitializePackage();CHKERRQ(ierr);
4895fce210SBarry Smith 
4973107ff1SLisandro Dalcin   ierr = PetscHeaderCreate(b,PETSCSF_CLASSID,"PetscSF","Star Forest","PetscSF",comm,PetscSFDestroy,PetscSFView);CHKERRQ(ierr);
5095fce210SBarry Smith 
5195fce210SBarry Smith   b->nroots    = -1;
5295fce210SBarry Smith   b->nleaves   = -1;
5329046d53SLisandro Dalcin   b->minleaf   = PETSC_MAX_INT;
5429046d53SLisandro Dalcin   b->maxleaf   = PETSC_MIN_INT;
5595fce210SBarry Smith   b->nranks    = -1;
5695fce210SBarry Smith   b->rankorder = PETSC_TRUE;
5795fce210SBarry Smith   b->ingroup   = MPI_GROUP_NULL;
5895fce210SBarry Smith   b->outgroup  = MPI_GROUP_NULL;
5995fce210SBarry Smith   b->graphset  = PETSC_FALSE;
6095fce210SBarry Smith 
6195fce210SBarry Smith   *sf = b;
6295fce210SBarry Smith   PetscFunctionReturn(0);
6395fce210SBarry Smith }
6495fce210SBarry Smith 
6529046d53SLisandro Dalcin /*@
6695fce210SBarry Smith    PetscSFReset - Reset a star forest so that different sizes or neighbors can be used
6795fce210SBarry Smith 
6895fce210SBarry Smith    Collective
6995fce210SBarry Smith 
7095fce210SBarry Smith    Input Arguments:
7195fce210SBarry Smith .  sf - star forest
7295fce210SBarry Smith 
7395fce210SBarry Smith    Level: advanced
7495fce210SBarry Smith 
7595fce210SBarry Smith .seealso: PetscSFCreate(), PetscSFSetGraph(), PetscSFDestroy()
7695fce210SBarry Smith @*/
7795fce210SBarry Smith PetscErrorCode PetscSFReset(PetscSF sf)
7895fce210SBarry Smith {
7995fce210SBarry Smith   PetscErrorCode ierr;
8095fce210SBarry Smith 
8195fce210SBarry Smith   PetscFunctionBegin;
8295fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
8379715d56SJed Brown   if (sf->ops->Reset) {ierr = (*sf->ops->Reset)(sf);CHKERRQ(ierr);}
8429046d53SLisandro Dalcin   sf->nroots   = -1;
8529046d53SLisandro Dalcin   sf->nleaves  = -1;
8629046d53SLisandro Dalcin   sf->minleaf  = PETSC_MAX_INT;
8729046d53SLisandro Dalcin   sf->maxleaf  = PETSC_MIN_INT;
8895fce210SBarry Smith   sf->mine     = NULL;
8995fce210SBarry Smith   sf->remote   = NULL;
9029046d53SLisandro Dalcin   sf->graphset = PETSC_FALSE;
9129046d53SLisandro Dalcin   ierr = PetscFree(sf->mine_alloc);CHKERRQ(ierr);
9295fce210SBarry Smith   ierr = PetscFree(sf->remote_alloc);CHKERRQ(ierr);
9321c688dcSJed Brown   sf->nranks = -1;
9429046d53SLisandro Dalcin   ierr = PetscFree4(sf->ranks,sf->roffset,sf->rmine,sf->rremote);CHKERRQ(ierr);
9529046d53SLisandro Dalcin   sf->degreeknown = PETSC_FALSE;
9695fce210SBarry Smith   ierr = PetscFree(sf->degree);CHKERRQ(ierr);
9795fce210SBarry Smith   if (sf->ingroup  != MPI_GROUP_NULL) {ierr = MPI_Group_free(&sf->ingroup);CHKERRQ(ierr);}
9895fce210SBarry Smith   if (sf->outgroup != MPI_GROUP_NULL) {ierr = MPI_Group_free(&sf->outgroup);CHKERRQ(ierr);}
9995fce210SBarry Smith   ierr = PetscSFDestroy(&sf->multi);CHKERRQ(ierr);
100dd5b3ca6SJunchao Zhang   ierr = PetscLayoutDestroy(&sf->map);CHKERRQ(ierr);
10195fce210SBarry Smith   sf->setupcalled = PETSC_FALSE;
10295fce210SBarry Smith   PetscFunctionReturn(0);
10395fce210SBarry Smith }
10495fce210SBarry Smith 
10595fce210SBarry Smith /*@C
10629046d53SLisandro Dalcin    PetscSFSetType - Set the PetscSF communication implementation
10795fce210SBarry Smith 
10895fce210SBarry Smith    Collective on PetscSF
10995fce210SBarry Smith 
11095fce210SBarry Smith    Input Parameters:
11195fce210SBarry Smith +  sf - the PetscSF context
11295fce210SBarry Smith -  type - a known method
11395fce210SBarry Smith 
11495fce210SBarry Smith    Options Database Key:
11595fce210SBarry Smith .  -sf_type <type> - Sets the method; use -help for a list
11695fce210SBarry Smith    of available methods (for instance, window, pt2pt, neighbor)
11795fce210SBarry Smith 
11895fce210SBarry Smith    Notes:
11995fce210SBarry Smith    See "include/petscsf.h" for available methods (for instance)
12095fce210SBarry Smith +    PETSCSFWINDOW - MPI-2/3 one-sided
12195fce210SBarry Smith -    PETSCSFBASIC - basic implementation using MPI-1 two-sided
12295fce210SBarry Smith 
12395fce210SBarry Smith   Level: intermediate
12495fce210SBarry Smith 
12595fce210SBarry Smith .seealso: PetscSFType, PetscSFCreate()
12695fce210SBarry Smith @*/
12795fce210SBarry Smith PetscErrorCode PetscSFSetType(PetscSF sf,PetscSFType type)
12895fce210SBarry Smith {
12995fce210SBarry Smith   PetscErrorCode ierr,(*r)(PetscSF);
13095fce210SBarry Smith   PetscBool      match;
13195fce210SBarry Smith 
13295fce210SBarry Smith   PetscFunctionBegin;
13395fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
13495fce210SBarry Smith   PetscValidCharPointer(type,2);
13595fce210SBarry Smith 
13695fce210SBarry Smith   ierr = PetscObjectTypeCompare((PetscObject)sf,type,&match);CHKERRQ(ierr);
13795fce210SBarry Smith   if (match) PetscFunctionReturn(0);
13895fce210SBarry Smith 
139adc40e5bSBarry Smith   ierr = PetscFunctionListFind(PetscSFList,type,&r);CHKERRQ(ierr);
14095fce210SBarry Smith   if (!r) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unable to find requested PetscSF type %s",type);
14129046d53SLisandro Dalcin   /* Destroy the previous PetscSF implementation context */
14229046d53SLisandro Dalcin   if (sf->ops->Destroy) {ierr = (*(sf)->ops->Destroy)(sf);CHKERRQ(ierr);}
14395fce210SBarry Smith   ierr = PetscMemzero(sf->ops,sizeof(*sf->ops));CHKERRQ(ierr);
14495fce210SBarry Smith   ierr = PetscObjectChangeTypeName((PetscObject)sf,type);CHKERRQ(ierr);
14595fce210SBarry Smith   ierr = (*r)(sf);CHKERRQ(ierr);
14695fce210SBarry Smith   PetscFunctionReturn(0);
14795fce210SBarry Smith }
14895fce210SBarry Smith 
14929046d53SLisandro Dalcin /*@C
15029046d53SLisandro Dalcin   PetscSFGetType - Get the PetscSF communication implementation
15129046d53SLisandro Dalcin 
15229046d53SLisandro Dalcin   Not Collective
15329046d53SLisandro Dalcin 
15429046d53SLisandro Dalcin   Input Parameter:
15529046d53SLisandro Dalcin . sf  - the PetscSF context
15629046d53SLisandro Dalcin 
15729046d53SLisandro Dalcin   Output Parameter:
15829046d53SLisandro Dalcin . type - the PetscSF type name
15929046d53SLisandro Dalcin 
16029046d53SLisandro Dalcin   Level: intermediate
16129046d53SLisandro Dalcin 
16229046d53SLisandro Dalcin .seealso: PetscSFSetType(), PetscSFCreate()
16329046d53SLisandro Dalcin @*/
16429046d53SLisandro Dalcin PetscErrorCode PetscSFGetType(PetscSF sf, PetscSFType *type)
16529046d53SLisandro Dalcin {
16629046d53SLisandro Dalcin   PetscFunctionBegin;
16729046d53SLisandro Dalcin   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID,1);
16829046d53SLisandro Dalcin   PetscValidPointer(type,2);
16929046d53SLisandro Dalcin   *type = ((PetscObject)sf)->type_name;
17029046d53SLisandro Dalcin   PetscFunctionReturn(0);
17129046d53SLisandro Dalcin }
17229046d53SLisandro Dalcin 
173d36d33e4SMatthew G. Knepley /*@
17495fce210SBarry Smith    PetscSFDestroy - destroy star forest
17595fce210SBarry Smith 
17695fce210SBarry Smith    Collective
17795fce210SBarry Smith 
17895fce210SBarry Smith    Input Arguments:
17995fce210SBarry Smith .  sf - address of star forest
18095fce210SBarry Smith 
18195fce210SBarry Smith    Level: intermediate
18295fce210SBarry Smith 
18395fce210SBarry Smith .seealso: PetscSFCreate(), PetscSFReset()
18495fce210SBarry Smith @*/
18595fce210SBarry Smith PetscErrorCode PetscSFDestroy(PetscSF *sf)
18695fce210SBarry Smith {
18795fce210SBarry Smith   PetscErrorCode ierr;
18895fce210SBarry Smith 
18995fce210SBarry Smith   PetscFunctionBegin;
19095fce210SBarry Smith   if (!*sf) PetscFunctionReturn(0);
19195fce210SBarry Smith   PetscValidHeaderSpecific((*sf),PETSCSF_CLASSID,1);
19229046d53SLisandro Dalcin   if (--((PetscObject)(*sf))->refct > 0) {*sf = NULL; PetscFunctionReturn(0);}
19395fce210SBarry Smith   ierr = PetscSFReset(*sf);CHKERRQ(ierr);
19495fce210SBarry Smith   if ((*sf)->ops->Destroy) {ierr = (*(*sf)->ops->Destroy)(*sf);CHKERRQ(ierr);}
19595fce210SBarry Smith   ierr = PetscHeaderDestroy(sf);CHKERRQ(ierr);
19695fce210SBarry Smith   PetscFunctionReturn(0);
19795fce210SBarry Smith }
19895fce210SBarry Smith 
19995fce210SBarry Smith /*@
20095fce210SBarry Smith    PetscSFSetUp - set up communication structures
20195fce210SBarry Smith 
20295fce210SBarry Smith    Collective
20395fce210SBarry Smith 
20495fce210SBarry Smith    Input Arguments:
20595fce210SBarry Smith .  sf - star forest communication object
20695fce210SBarry Smith 
20795fce210SBarry Smith    Level: beginner
20895fce210SBarry Smith 
20995fce210SBarry Smith .seealso: PetscSFSetFromOptions(), PetscSFSetType()
21095fce210SBarry Smith @*/
21195fce210SBarry Smith PetscErrorCode PetscSFSetUp(PetscSF sf)
21295fce210SBarry Smith {
21395fce210SBarry Smith   PetscErrorCode ierr;
21495fce210SBarry Smith 
21595fce210SBarry Smith   PetscFunctionBegin;
21629046d53SLisandro Dalcin   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
21729046d53SLisandro Dalcin   PetscSFCheckGraphSet(sf,1);
21895fce210SBarry Smith   if (sf->setupcalled) PetscFunctionReturn(0);
21995fce210SBarry Smith   if (!((PetscObject)sf)->type_name) {ierr = PetscSFSetType(sf,PETSCSFBASIC);CHKERRQ(ierr);}
22029046d53SLisandro Dalcin   ierr = PetscLogEventBegin(PETSCSF_SetUp,sf,0,0,0);CHKERRQ(ierr);
22195fce210SBarry Smith   if (sf->ops->SetUp) {ierr = (*sf->ops->SetUp)(sf);CHKERRQ(ierr);}
22229046d53SLisandro Dalcin   ierr = PetscLogEventEnd(PETSCSF_SetUp,sf,0,0,0);CHKERRQ(ierr);
22395fce210SBarry Smith   sf->setupcalled = PETSC_TRUE;
22495fce210SBarry Smith   PetscFunctionReturn(0);
22595fce210SBarry Smith }
22695fce210SBarry Smith 
2278af6ec1cSBarry Smith /*@
22895fce210SBarry Smith    PetscSFSetFromOptions - set PetscSF options using the options database
22995fce210SBarry Smith 
23095fce210SBarry Smith    Logically Collective
23195fce210SBarry Smith 
23295fce210SBarry Smith    Input Arguments:
23395fce210SBarry Smith .  sf - star forest
23495fce210SBarry Smith 
23595fce210SBarry Smith    Options Database Keys:
23660263706SJed Brown +  -sf_type - implementation type, see PetscSFSetType()
23760263706SJed Brown -  -sf_rank_order - sort composite points for gathers and scatters in rank order, gathers are non-deterministic otherwise
23895fce210SBarry Smith 
23995fce210SBarry Smith    Level: intermediate
24095fce210SBarry Smith 
24195fce210SBarry Smith .seealso: PetscSFWindowSetSyncType()
24295fce210SBarry Smith @*/
24395fce210SBarry Smith PetscErrorCode PetscSFSetFromOptions(PetscSF sf)
24495fce210SBarry Smith {
24595fce210SBarry Smith   PetscSFType    deft;
24695fce210SBarry Smith   char           type[256];
24795fce210SBarry Smith   PetscErrorCode ierr;
24895fce210SBarry Smith   PetscBool      flg;
24995fce210SBarry Smith 
25095fce210SBarry Smith   PetscFunctionBegin;
25195fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
25295fce210SBarry Smith   ierr = PetscObjectOptionsBegin((PetscObject)sf);CHKERRQ(ierr);
25395fce210SBarry Smith   deft = ((PetscObject)sf)->type_name ? ((PetscObject)sf)->type_name : PETSCSFBASIC;
25429046d53SLisandro Dalcin   ierr = PetscOptionsFList("-sf_type","PetscSF implementation type","PetscSFSetType",PetscSFList,deft,type,sizeof(type),&flg);CHKERRQ(ierr);
25595fce210SBarry Smith   ierr = PetscSFSetType(sf,flg ? type : deft);CHKERRQ(ierr);
25695fce210SBarry Smith   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);
257e55864a3SBarry Smith   if (sf->ops->SetFromOptions) {ierr = (*sf->ops->SetFromOptions)(PetscOptionsObject,sf);CHKERRQ(ierr);}
25895fce210SBarry Smith   ierr = PetscOptionsEnd();CHKERRQ(ierr);
25995fce210SBarry Smith   PetscFunctionReturn(0);
26095fce210SBarry Smith }
26195fce210SBarry Smith 
26229046d53SLisandro Dalcin /*@
26395fce210SBarry Smith    PetscSFSetRankOrder - sort multi-points for gathers and scatters by rank order
26495fce210SBarry Smith 
26595fce210SBarry Smith    Logically Collective
26695fce210SBarry Smith 
26795fce210SBarry Smith    Input Arguments:
26895fce210SBarry Smith +  sf - star forest
26995fce210SBarry Smith -  flg - PETSC_TRUE to sort, PETSC_FALSE to skip sorting (lower setup cost, but non-deterministic)
27095fce210SBarry Smith 
27195fce210SBarry Smith    Level: advanced
27295fce210SBarry Smith 
27395fce210SBarry Smith .seealso: PetscSFGatherBegin(), PetscSFScatterBegin()
27495fce210SBarry Smith @*/
27595fce210SBarry Smith PetscErrorCode PetscSFSetRankOrder(PetscSF sf,PetscBool flg)
27695fce210SBarry Smith {
27795fce210SBarry Smith 
27895fce210SBarry Smith   PetscFunctionBegin;
27995fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
28095fce210SBarry Smith   PetscValidLogicalCollectiveBool(sf,flg,2);
28195fce210SBarry Smith   if (sf->multi) SETERRQ(PetscObjectComm((PetscObject)sf),PETSC_ERR_ARG_WRONGSTATE,"Rank ordering must be set before first call to PetscSFGatherBegin() or PetscSFScatterBegin()");
28295fce210SBarry Smith   sf->rankorder = flg;
28395fce210SBarry Smith   PetscFunctionReturn(0);
28495fce210SBarry Smith }
28595fce210SBarry Smith 
2868af6ec1cSBarry Smith /*@
28795fce210SBarry Smith    PetscSFSetGraph - Set a parallel star forest
28895fce210SBarry Smith 
28995fce210SBarry Smith    Collective
29095fce210SBarry Smith 
29195fce210SBarry Smith    Input Arguments:
29295fce210SBarry Smith +  sf - star forest
29395fce210SBarry Smith .  nroots - number of root vertices on the current process (these are possible targets for other process to attach leaves)
29495fce210SBarry Smith .  nleaves - number of leaf vertices on the current process, each of these references a root on any process
29595fce210SBarry Smith .  ilocal - locations of leaves in leafdata buffers, pass NULL for contiguous storage
29695fce210SBarry Smith .  localmode - copy mode for ilocal
29795fce210SBarry Smith .  iremote - remote locations of root vertices for each leaf on the current process
29895fce210SBarry Smith -  remotemode - copy mode for iremote
29995fce210SBarry Smith 
30095fce210SBarry Smith    Level: intermediate
30195fce210SBarry Smith 
30295452b02SPatrick Sanan    Notes:
30395452b02SPatrick Sanan     In Fortran you must use PETSC_COPY_VALUES for localmode and remotemode
30438ab3f8aSBarry Smith 
3052ad1e87fSLisandro Dalcin    Developers Note: Local indices which are the identity permutation in the range [0,nleaves) are discarded as they
3062ad1e87fSLisandro Dalcin    encode contiguous storage. In such case, if localmode is PETSC_OWN_POINTER, the memory is deallocated as it is not
3072ad1e87fSLisandro Dalcin    needed
3082ad1e87fSLisandro Dalcin 
30995fce210SBarry Smith .seealso: PetscSFCreate(), PetscSFView(), PetscSFGetGraph()
31095fce210SBarry Smith @*/
31195fce210SBarry Smith PetscErrorCode PetscSFSetGraph(PetscSF sf,PetscInt nroots,PetscInt nleaves,const PetscInt *ilocal,PetscCopyMode localmode,const PetscSFNode *iremote,PetscCopyMode remotemode)
31295fce210SBarry Smith {
31395fce210SBarry Smith   PetscErrorCode ierr;
31495fce210SBarry Smith 
31595fce210SBarry Smith   PetscFunctionBegin;
31695fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
31729046d53SLisandro Dalcin   if (nleaves > 0 && ilocal) PetscValidIntPointer(ilocal,4);
31829046d53SLisandro Dalcin   if (nleaves > 0) PetscValidPointer(iremote,6);
31929046d53SLisandro Dalcin   if (nroots  < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"nroots %D, cannot be negative",nroots);
32095fce210SBarry Smith   if (nleaves < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"nleaves %D, cannot be negative",nleaves);
32129046d53SLisandro Dalcin 
32295fce210SBarry Smith   ierr = PetscSFReset(sf);CHKERRQ(ierr);
32329046d53SLisandro Dalcin   ierr = PetscLogEventBegin(PETSCSF_SetGraph,sf,0,0,0);CHKERRQ(ierr);
32429046d53SLisandro Dalcin 
32595fce210SBarry Smith   sf->nroots  = nroots;
32695fce210SBarry Smith   sf->nleaves = nleaves;
32729046d53SLisandro Dalcin 
32829046d53SLisandro Dalcin   if (nleaves && ilocal) {
32921c688dcSJed Brown     PetscInt i;
33029046d53SLisandro Dalcin     PetscInt minleaf = PETSC_MAX_INT;
33129046d53SLisandro Dalcin     PetscInt maxleaf = PETSC_MIN_INT;
3322ad1e87fSLisandro Dalcin     int      contiguous = 1;
33329046d53SLisandro Dalcin     for (i=0; i<nleaves; i++) {
33429046d53SLisandro Dalcin       minleaf = PetscMin(minleaf,ilocal[i]);
33529046d53SLisandro Dalcin       maxleaf = PetscMax(maxleaf,ilocal[i]);
3362ad1e87fSLisandro Dalcin       contiguous &= (ilocal[i] == i);
33729046d53SLisandro Dalcin     }
33829046d53SLisandro Dalcin     sf->minleaf = minleaf;
33929046d53SLisandro Dalcin     sf->maxleaf = maxleaf;
3402ad1e87fSLisandro Dalcin     if (contiguous) {
3412ad1e87fSLisandro Dalcin       if (localmode == PETSC_OWN_POINTER) {
3422ad1e87fSLisandro Dalcin         ierr = PetscFree(ilocal);CHKERRQ(ierr);
3432ad1e87fSLisandro Dalcin       }
3442ad1e87fSLisandro Dalcin       ilocal = NULL;
3452ad1e87fSLisandro Dalcin     }
34629046d53SLisandro Dalcin   } else {
34729046d53SLisandro Dalcin     sf->minleaf = 0;
34829046d53SLisandro Dalcin     sf->maxleaf = nleaves - 1;
34929046d53SLisandro Dalcin   }
35029046d53SLisandro Dalcin 
35129046d53SLisandro Dalcin   if (ilocal) {
35295fce210SBarry Smith     switch (localmode) {
35395fce210SBarry Smith     case PETSC_COPY_VALUES:
354785e854fSJed Brown       ierr = PetscMalloc1(nleaves,&sf->mine_alloc);CHKERRQ(ierr);
355580bdb30SBarry Smith       ierr = PetscArraycpy(sf->mine_alloc,ilocal,nleaves);CHKERRQ(ierr);
35695fce210SBarry Smith       sf->mine = sf->mine_alloc;
35795fce210SBarry Smith       break;
35895fce210SBarry Smith     case PETSC_OWN_POINTER:
35995fce210SBarry Smith       sf->mine_alloc = (PetscInt*)ilocal;
36095fce210SBarry Smith       sf->mine       = sf->mine_alloc;
36195fce210SBarry Smith       break;
36295fce210SBarry Smith     case PETSC_USE_POINTER:
36329046d53SLisandro Dalcin       sf->mine_alloc = NULL;
36495fce210SBarry Smith       sf->mine       = (PetscInt*)ilocal;
36595fce210SBarry Smith       break;
36695fce210SBarry Smith     default: SETERRQ(PetscObjectComm((PetscObject)sf),PETSC_ERR_ARG_OUTOFRANGE,"Unknown localmode");
36795fce210SBarry Smith     }
36895fce210SBarry Smith   }
36929046d53SLisandro Dalcin 
37095fce210SBarry Smith   switch (remotemode) {
37195fce210SBarry Smith   case PETSC_COPY_VALUES:
372785e854fSJed Brown     ierr = PetscMalloc1(nleaves,&sf->remote_alloc);CHKERRQ(ierr);
373580bdb30SBarry Smith     ierr = PetscArraycpy(sf->remote_alloc,iremote,nleaves);CHKERRQ(ierr);
37495fce210SBarry Smith     sf->remote = sf->remote_alloc;
37595fce210SBarry Smith     break;
37695fce210SBarry Smith   case PETSC_OWN_POINTER:
37795fce210SBarry Smith     sf->remote_alloc = (PetscSFNode*)iremote;
37895fce210SBarry Smith     sf->remote       = sf->remote_alloc;
37995fce210SBarry Smith     break;
38095fce210SBarry Smith   case PETSC_USE_POINTER:
38129046d53SLisandro Dalcin     sf->remote_alloc = NULL;
38295fce210SBarry Smith     sf->remote       = (PetscSFNode*)iremote;
38395fce210SBarry Smith     break;
38495fce210SBarry Smith   default: SETERRQ(PetscObjectComm((PetscObject)sf),PETSC_ERR_ARG_OUTOFRANGE,"Unknown remotemode");
38595fce210SBarry Smith   }
38695fce210SBarry Smith 
387563ffbabSMatthew G. Knepley   ierr = PetscLogEventEnd(PETSCSF_SetGraph,sf,0,0,0);CHKERRQ(ierr);
38829046d53SLisandro Dalcin   sf->graphset = PETSC_TRUE;
38995fce210SBarry Smith   PetscFunctionReturn(0);
39095fce210SBarry Smith }
39195fce210SBarry Smith 
39229046d53SLisandro Dalcin /*@
393dd5b3ca6SJunchao Zhang   PetscSFSetGraphWithPattern - Sets the graph of an SF with a specific pattern
394dd5b3ca6SJunchao Zhang 
395dd5b3ca6SJunchao Zhang   Collective
396dd5b3ca6SJunchao Zhang 
397dd5b3ca6SJunchao Zhang   Input Parameters:
398dd5b3ca6SJunchao Zhang + sf      - The PetscSF
399dd5b3ca6SJunchao Zhang . map     - Layout of roots over all processes (insignificant when pattern is PETSCSF_PATTERN_ALLTOALL)
400dd5b3ca6SJunchao Zhang - pattern - One of PETSCSF_PATTERN_ALLGATHER, PETSCSF_PATTERN_GATHER, PETSCSF_PATTERN_ALLTOALL
401dd5b3ca6SJunchao Zhang 
402dd5b3ca6SJunchao Zhang   Notes:
403dd5b3ca6SJunchao Zhang   It is easier to explain PetscSFPattern using vectors. Suppose we have an MPI vector x and its layout is map.
404dd5b3ca6SJunchao Zhang   n and N are local and global sizes of x respectively.
405dd5b3ca6SJunchao Zhang 
406dd5b3ca6SJunchao Zhang   With PETSCSF_PATTERN_ALLGATHER, the routine creates a graph that if one does Bcast on it, it will copy x to
407dd5b3ca6SJunchao Zhang   sequential vectors y on all ranks.
408dd5b3ca6SJunchao Zhang 
409dd5b3ca6SJunchao Zhang   With PETSCSF_PATTERN_GATHER, the routine creates a graph that if one does Bcast on it, it will copy x to a
410dd5b3ca6SJunchao Zhang   sequential vector y on rank 0.
411dd5b3ca6SJunchao Zhang 
412dd5b3ca6SJunchao Zhang   In above cases, entries of x are roots and entries of y are leaves.
413dd5b3ca6SJunchao Zhang 
414dd5b3ca6SJunchao Zhang   With PETSCSF_PATTERN_ALLTOALL, map is insignificant. Suppose NP is size of sf's communicator. The routine
415dd5b3ca6SJunchao Zhang   creates a graph that every rank has NP leaves and NP roots. On rank i, its leaf j is connected to root i
416dd5b3ca6SJunchao Zhang   of rank j. Here 0 <=i,j<NP. It is a kind of MPI_Alltoall with sendcount/recvcount being 1. Note that it does
417dd5b3ca6SJunchao Zhang   not mean one can not send multiple items. One just needs to create a new MPI datatype for the mulptiple data
418dd5b3ca6SJunchao Zhang   items with MPI_Type_contiguous() and use that as the <unit> argument in SF routines.
419dd5b3ca6SJunchao Zhang 
420dd5b3ca6SJunchao Zhang   In this case, roots and leaves are symmetric.
421dd5b3ca6SJunchao Zhang 
422dd5b3ca6SJunchao Zhang   Level: intermediate
423dd5b3ca6SJunchao Zhang  @*/
424dd5b3ca6SJunchao Zhang PetscErrorCode PetscSFSetGraphWithPattern(PetscSF sf,PetscLayout map,PetscSFPattern pattern)
425dd5b3ca6SJunchao Zhang {
426dd5b3ca6SJunchao Zhang   MPI_Comm       comm;
427dd5b3ca6SJunchao Zhang   PetscInt       n,N,res[2];
428dd5b3ca6SJunchao Zhang   PetscMPIInt    rank,size;
429dd5b3ca6SJunchao Zhang   PetscSFType    type;
430dd5b3ca6SJunchao Zhang   PetscErrorCode ierr;
431dd5b3ca6SJunchao Zhang 
432dd5b3ca6SJunchao Zhang   PetscFunctionBegin;
433dd5b3ca6SJunchao Zhang   ierr = PetscObjectGetComm((PetscObject)sf, &comm);CHKERRQ(ierr);
434dd5b3ca6SJunchao Zhang   if (pattern < PETSCSF_PATTERN_ALLGATHER || pattern > PETSCSF_PATTERN_ALLTOALL) SETERRQ1(comm,PETSC_ERR_ARG_OUTOFRANGE,"Unsupported PetscSFPattern %D\n",pattern);
435dd5b3ca6SJunchao Zhang   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
436dd5b3ca6SJunchao Zhang   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
437dd5b3ca6SJunchao Zhang 
438dd5b3ca6SJunchao Zhang   if (pattern == PETSCSF_PATTERN_ALLTOALL) {
439dd5b3ca6SJunchao Zhang     type = PETSCSFALLTOALL;
440dd5b3ca6SJunchao Zhang     ierr = PetscLayoutCreate(comm,&sf->map);CHKERRQ(ierr);
441dd5b3ca6SJunchao Zhang     ierr = PetscLayoutSetLocalSize(sf->map,size);CHKERRQ(ierr);
442dd5b3ca6SJunchao Zhang     ierr = PetscLayoutSetSize(sf->map,((PetscInt)size)*size);CHKERRQ(ierr);
443dd5b3ca6SJunchao Zhang     ierr = PetscLayoutSetUp(sf->map);CHKERRQ(ierr);
444dd5b3ca6SJunchao Zhang   } else {
445dd5b3ca6SJunchao Zhang     ierr   = PetscLayoutGetLocalSize(map,&n);CHKERRQ(ierr);
446dd5b3ca6SJunchao Zhang     ierr   = PetscLayoutGetSize(map,&N);CHKERRQ(ierr);
447dd5b3ca6SJunchao Zhang     res[0] = n;
448dd5b3ca6SJunchao Zhang     res[1] = -n;
449dd5b3ca6SJunchao Zhang     /* Check if n are same over all ranks so that we can optimize it */
450dd5b3ca6SJunchao Zhang     ierr   = MPIU_Allreduce(MPI_IN_PLACE,res,2,MPIU_INT,MPI_MAX,comm);CHKERRQ(ierr);
451dd5b3ca6SJunchao Zhang     if (res[0] == -res[1]) { /* same n */
452dd5b3ca6SJunchao Zhang       type = (pattern == PETSCSF_PATTERN_ALLGATHER) ? PETSCSFALLGATHER  : PETSCSFGATHER;
453dd5b3ca6SJunchao Zhang     } else {
454dd5b3ca6SJunchao Zhang       type = (pattern == PETSCSF_PATTERN_ALLGATHER) ? PETSCSFALLGATHERV : PETSCSFGATHERV;
455dd5b3ca6SJunchao Zhang     }
456dd5b3ca6SJunchao Zhang     ierr = PetscLayoutReference(map,&sf->map);CHKERRQ(ierr);
457dd5b3ca6SJunchao Zhang   }
458dd5b3ca6SJunchao Zhang   ierr = PetscSFSetType(sf,type);CHKERRQ(ierr);
459dd5b3ca6SJunchao Zhang 
460dd5b3ca6SJunchao Zhang   sf->pattern = pattern;
461dd5b3ca6SJunchao Zhang   sf->mine    = NULL; /* Contiguous */
462dd5b3ca6SJunchao Zhang 
463dd5b3ca6SJunchao Zhang   /* Set nleaves, nroots here in case user calls PetscSFGetGraph, which is legal to call even before PetscSFSetUp is called.
464dd5b3ca6SJunchao Zhang      Also set other easy stuff.
465dd5b3ca6SJunchao Zhang    */
466dd5b3ca6SJunchao Zhang   if (pattern == PETSCSF_PATTERN_ALLGATHER) {
467dd5b3ca6SJunchao Zhang     sf->nleaves      = N;
468dd5b3ca6SJunchao Zhang     sf->nroots       = n;
469dd5b3ca6SJunchao Zhang     sf->nranks       = size;
470dd5b3ca6SJunchao Zhang     sf->minleaf      = 0;
471dd5b3ca6SJunchao Zhang     sf->maxleaf      = N - 1;
472dd5b3ca6SJunchao Zhang   } else if (pattern == PETSCSF_PATTERN_GATHER) {
473dd5b3ca6SJunchao Zhang     sf->nleaves      = rank ? 0 : N;
474dd5b3ca6SJunchao Zhang     sf->nroots       = n;
475dd5b3ca6SJunchao Zhang     sf->nranks       = rank ? 0 : size;
476dd5b3ca6SJunchao Zhang     sf->minleaf      = 0;
477dd5b3ca6SJunchao Zhang     sf->maxleaf      = rank ? -1 : N - 1;
478dd5b3ca6SJunchao Zhang   } else if (pattern == PETSCSF_PATTERN_ALLTOALL) {
479dd5b3ca6SJunchao Zhang     sf->nleaves      = size;
480dd5b3ca6SJunchao Zhang     sf->nroots       = size;
481dd5b3ca6SJunchao Zhang     sf->nranks       = size;
482dd5b3ca6SJunchao Zhang     sf->minleaf      = 0;
483dd5b3ca6SJunchao Zhang     sf->maxleaf      = size - 1;
484dd5b3ca6SJunchao Zhang   }
485dd5b3ca6SJunchao Zhang   sf->ndranks  = 0; /* We do not need to separate out distinguished ranks for patterned graphs to improve communication performance */
486dd5b3ca6SJunchao Zhang   sf->graphset = PETSC_TRUE;
487dd5b3ca6SJunchao Zhang   PetscFunctionReturn(0);
488dd5b3ca6SJunchao Zhang }
489dd5b3ca6SJunchao Zhang 
490dd5b3ca6SJunchao Zhang /*@
49195fce210SBarry Smith    PetscSFCreateInverseSF - given a PetscSF in which all vertices have degree 1, creates the inverse map
49295fce210SBarry Smith 
49395fce210SBarry Smith    Collective
49495fce210SBarry Smith 
49595fce210SBarry Smith    Input Arguments:
496dd5b3ca6SJunchao Zhang 
49795fce210SBarry Smith .  sf - star forest to invert
49895fce210SBarry Smith 
49995fce210SBarry Smith    Output Arguments:
50095fce210SBarry Smith .  isf - inverse of sf
50195fce210SBarry Smith    Level: advanced
50295fce210SBarry Smith 
50395fce210SBarry Smith    Notes:
50495fce210SBarry Smith    All roots must have degree 1.
50595fce210SBarry Smith 
50695fce210SBarry Smith    The local space may be a permutation, but cannot be sparse.
50795fce210SBarry Smith 
50895fce210SBarry Smith .seealso: PetscSFSetGraph()
50995fce210SBarry Smith @*/
51095fce210SBarry Smith PetscErrorCode PetscSFCreateInverseSF(PetscSF sf,PetscSF *isf)
51195fce210SBarry Smith {
51295fce210SBarry Smith   PetscErrorCode ierr;
51395fce210SBarry Smith   PetscMPIInt    rank;
51495fce210SBarry Smith   PetscInt       i,nroots,nleaves,maxlocal,count,*newilocal;
51595fce210SBarry Smith   const PetscInt *ilocal;
51695fce210SBarry Smith   PetscSFNode    *roots,*leaves;
51795fce210SBarry Smith 
51895fce210SBarry Smith   PetscFunctionBegin;
51929046d53SLisandro Dalcin   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
52029046d53SLisandro Dalcin   PetscSFCheckGraphSet(sf,1);
52129046d53SLisandro Dalcin   PetscValidPointer(isf,2);
52229046d53SLisandro Dalcin 
52395fce210SBarry Smith   ierr = PetscSFGetGraph(sf,&nroots,&nleaves,&ilocal,NULL);CHKERRQ(ierr);
52429046d53SLisandro Dalcin   maxlocal = sf->maxleaf+1; /* TODO: We should use PetscSFGetLeafRange() */
52529046d53SLisandro Dalcin 
52629046d53SLisandro Dalcin   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)sf),&rank);CHKERRQ(ierr);
527ae9aee6dSMatthew G. Knepley   ierr = PetscMalloc2(nroots,&roots,maxlocal,&leaves);CHKERRQ(ierr);
528ae9aee6dSMatthew G. Knepley   for (i=0; i<maxlocal; i++) {
52995fce210SBarry Smith     leaves[i].rank  = rank;
53095fce210SBarry Smith     leaves[i].index = i;
53195fce210SBarry Smith   }
53295fce210SBarry Smith   for (i=0; i <nroots; i++) {
53395fce210SBarry Smith     roots[i].rank  = -1;
53495fce210SBarry Smith     roots[i].index = -1;
53595fce210SBarry Smith   }
5368bfbc91cSJed Brown   ierr = PetscSFReduceBegin(sf,MPIU_2INT,leaves,roots,MPIU_REPLACE);CHKERRQ(ierr);
5378bfbc91cSJed Brown   ierr = PetscSFReduceEnd(sf,MPIU_2INT,leaves,roots,MPIU_REPLACE);CHKERRQ(ierr);
53895fce210SBarry Smith 
53995fce210SBarry Smith   /* Check whether our leaves are sparse */
54095fce210SBarry Smith   for (i=0,count=0; i<nroots; i++) if (roots[i].rank >= 0) count++;
54195fce210SBarry Smith   if (count == nroots) newilocal = NULL;
54295fce210SBarry Smith   else {                        /* Index for sparse leaves and compact "roots" array (which is to become our leaves). */
543785e854fSJed Brown     ierr = PetscMalloc1(count,&newilocal);CHKERRQ(ierr);
54495fce210SBarry Smith     for (i=0,count=0; i<nroots; i++) {
54595fce210SBarry Smith       if (roots[i].rank >= 0) {
54695fce210SBarry Smith         newilocal[count]   = i;
54795fce210SBarry Smith         roots[count].rank  = roots[i].rank;
54895fce210SBarry Smith         roots[count].index = roots[i].index;
54995fce210SBarry Smith         count++;
55095fce210SBarry Smith       }
55195fce210SBarry Smith     }
55295fce210SBarry Smith   }
55395fce210SBarry Smith 
55495fce210SBarry Smith   ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_CONFONLY,isf);CHKERRQ(ierr);
55595fce210SBarry Smith   ierr = PetscSFSetGraph(*isf,maxlocal,count,newilocal,PETSC_OWN_POINTER,roots,PETSC_COPY_VALUES);CHKERRQ(ierr);
55695fce210SBarry Smith   ierr = PetscFree2(roots,leaves);CHKERRQ(ierr);
55795fce210SBarry Smith   PetscFunctionReturn(0);
55895fce210SBarry Smith }
55995fce210SBarry Smith 
56095fce210SBarry Smith /*@
56195fce210SBarry Smith    PetscSFDuplicate - duplicate a PetscSF, optionally preserving rank connectivity and graph
56295fce210SBarry Smith 
56395fce210SBarry Smith    Collective
56495fce210SBarry Smith 
56595fce210SBarry Smith    Input Arguments:
56695fce210SBarry Smith +  sf - communication object to duplicate
56795fce210SBarry Smith -  opt - PETSCSF_DUPLICATE_CONFONLY, PETSCSF_DUPLICATE_RANKS, or PETSCSF_DUPLICATE_GRAPH (see PetscSFDuplicateOption)
56895fce210SBarry Smith 
56995fce210SBarry Smith    Output Arguments:
57095fce210SBarry Smith .  newsf - new communication object
57195fce210SBarry Smith 
57295fce210SBarry Smith    Level: beginner
57395fce210SBarry Smith 
57495fce210SBarry Smith .seealso: PetscSFCreate(), PetscSFSetType(), PetscSFSetGraph()
57595fce210SBarry Smith @*/
57695fce210SBarry Smith PetscErrorCode PetscSFDuplicate(PetscSF sf,PetscSFDuplicateOption opt,PetscSF *newsf)
57795fce210SBarry Smith {
57829046d53SLisandro Dalcin   PetscSFType    type;
57995fce210SBarry Smith   PetscErrorCode ierr;
58095fce210SBarry Smith 
58195fce210SBarry Smith   PetscFunctionBegin;
58229046d53SLisandro Dalcin   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
58329046d53SLisandro Dalcin   PetscValidLogicalCollectiveEnum(sf,opt,2);
58429046d53SLisandro Dalcin   PetscValidPointer(newsf,3);
58595fce210SBarry Smith   ierr = PetscSFCreate(PetscObjectComm((PetscObject)sf),newsf);CHKERRQ(ierr);
58629046d53SLisandro Dalcin   ierr = PetscSFGetType(sf,&type);CHKERRQ(ierr);
58729046d53SLisandro Dalcin   if (type) {ierr = PetscSFSetType(*newsf,type);CHKERRQ(ierr);}
58895fce210SBarry Smith   if (opt == PETSCSF_DUPLICATE_GRAPH) {
589dd5b3ca6SJunchao Zhang     PetscSFCheckGraphSet(sf,1);
590dd5b3ca6SJunchao Zhang     if (sf->pattern == PETSCSF_PATTERN_GENERAL) {
59195fce210SBarry Smith       PetscInt          nroots,nleaves;
59295fce210SBarry Smith       const PetscInt    *ilocal;
59395fce210SBarry Smith       const PetscSFNode *iremote;
59495fce210SBarry Smith       ierr = PetscSFGetGraph(sf,&nroots,&nleaves,&ilocal,&iremote);CHKERRQ(ierr);
59595fce210SBarry Smith       ierr = PetscSFSetGraph(*newsf,nroots,nleaves,ilocal,PETSC_COPY_VALUES,iremote,PETSC_COPY_VALUES);CHKERRQ(ierr);
596dd5b3ca6SJunchao Zhang     } else {
597dd5b3ca6SJunchao Zhang       ierr = PetscSFSetGraphWithPattern(*newsf,sf->map,sf->pattern);CHKERRQ(ierr);
598dd5b3ca6SJunchao Zhang     }
59995fce210SBarry Smith   }
60029046d53SLisandro Dalcin   if (sf->ops->Duplicate) {ierr = (*sf->ops->Duplicate)(sf,opt,*newsf);CHKERRQ(ierr);}
60195fce210SBarry Smith   PetscFunctionReturn(0);
60295fce210SBarry Smith }
60395fce210SBarry Smith 
60495fce210SBarry Smith /*@C
60595fce210SBarry Smith    PetscSFGetGraph - Get the graph specifying a parallel star forest
60695fce210SBarry Smith 
60795fce210SBarry Smith    Not Collective
60895fce210SBarry Smith 
60995fce210SBarry Smith    Input Arguments:
61095fce210SBarry Smith .  sf - star forest
61195fce210SBarry Smith 
61295fce210SBarry Smith    Output Arguments:
61395fce210SBarry Smith +  nroots - number of root vertices on the current process (these are possible targets for other process to attach leaves)
61495fce210SBarry Smith .  nleaves - number of leaf vertices on the current process, each of these references a root on any process
61595fce210SBarry Smith .  ilocal - locations of leaves in leafdata buffers
61695fce210SBarry Smith -  iremote - remote locations of root vertices for each leaf on the current process
61795fce210SBarry Smith 
618373e0d91SLisandro Dalcin    Notes:
619373e0d91SLisandro Dalcin    We are not currently requiring that the graph is set, thus returning nroots=-1 if it has not been set yet
620373e0d91SLisandro Dalcin 
62195fce210SBarry Smith    Level: intermediate
62295fce210SBarry Smith 
62395fce210SBarry Smith .seealso: PetscSFCreate(), PetscSFView(), PetscSFSetGraph()
62495fce210SBarry Smith @*/
62595fce210SBarry Smith PetscErrorCode PetscSFGetGraph(PetscSF sf,PetscInt *nroots,PetscInt *nleaves,const PetscInt **ilocal,const PetscSFNode **iremote)
62695fce210SBarry Smith {
627b8dee149SJunchao Zhang   PetscErrorCode ierr;
62895fce210SBarry Smith 
62995fce210SBarry Smith   PetscFunctionBegin;
63095fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
631b8dee149SJunchao Zhang   if (sf->ops->GetGraph) {
632b8dee149SJunchao Zhang     ierr = (sf->ops->GetGraph)(sf,nroots,nleaves,ilocal,iremote);CHKERRQ(ierr);
633b8dee149SJunchao Zhang   } else {
63495fce210SBarry Smith     if (nroots) *nroots = sf->nroots;
63595fce210SBarry Smith     if (nleaves) *nleaves = sf->nleaves;
63695fce210SBarry Smith     if (ilocal) *ilocal = sf->mine;
63795fce210SBarry Smith     if (iremote) *iremote = sf->remote;
638b8dee149SJunchao Zhang   }
63995fce210SBarry Smith   PetscFunctionReturn(0);
64095fce210SBarry Smith }
64195fce210SBarry Smith 
64229046d53SLisandro Dalcin /*@
64395fce210SBarry Smith    PetscSFGetLeafRange - Get the active leaf ranges
64495fce210SBarry Smith 
64595fce210SBarry Smith    Not Collective
64695fce210SBarry Smith 
64795fce210SBarry Smith    Input Arguments:
64895fce210SBarry Smith .  sf - star forest
64995fce210SBarry Smith 
65095fce210SBarry Smith    Output Arguments:
651dd5b3ca6SJunchao Zhang +  minleaf - minimum active leaf on this process. Return 0 if there are no leaves.
652dd5b3ca6SJunchao Zhang -  maxleaf - maximum active leaf on this process. Return -1 if there are no leaves.
65395fce210SBarry Smith 
65495fce210SBarry Smith    Level: developer
65595fce210SBarry Smith 
65695fce210SBarry Smith .seealso: PetscSFCreate(), PetscSFView(), PetscSFSetGraph(), PetscSFGetGraph()
65795fce210SBarry Smith @*/
65895fce210SBarry Smith PetscErrorCode PetscSFGetLeafRange(PetscSF sf,PetscInt *minleaf,PetscInt *maxleaf)
65995fce210SBarry Smith {
66095fce210SBarry Smith 
66195fce210SBarry Smith   PetscFunctionBegin;
66295fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
66329046d53SLisandro Dalcin   PetscSFCheckGraphSet(sf,1);
66495fce210SBarry Smith   if (minleaf) *minleaf = sf->minleaf;
66595fce210SBarry Smith   if (maxleaf) *maxleaf = sf->maxleaf;
66695fce210SBarry Smith   PetscFunctionReturn(0);
66795fce210SBarry Smith }
66895fce210SBarry Smith 
66995fce210SBarry Smith /*@C
67095fce210SBarry Smith    PetscSFView - view a star forest
67195fce210SBarry Smith 
67295fce210SBarry Smith    Collective
67395fce210SBarry Smith 
67495fce210SBarry Smith    Input Arguments:
67595fce210SBarry Smith +  sf - star forest
67695fce210SBarry Smith -  viewer - viewer to display graph, for example PETSC_VIEWER_STDOUT_WORLD
67795fce210SBarry Smith 
67895fce210SBarry Smith    Level: beginner
67995fce210SBarry Smith 
68095fce210SBarry Smith .seealso: PetscSFCreate(), PetscSFSetGraph()
68195fce210SBarry Smith @*/
68295fce210SBarry Smith PetscErrorCode PetscSFView(PetscSF sf,PetscViewer viewer)
68395fce210SBarry Smith {
68495fce210SBarry Smith   PetscErrorCode    ierr;
68595fce210SBarry Smith   PetscBool         iascii;
68695fce210SBarry Smith   PetscViewerFormat format;
68795fce210SBarry Smith 
68895fce210SBarry Smith   PetscFunctionBegin;
68995fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
69095fce210SBarry Smith   if (!viewer) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sf),&viewer);CHKERRQ(ierr);}
69195fce210SBarry Smith   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
69295fce210SBarry Smith   PetscCheckSameComm(sf,1,viewer,2);
69380153354SVaclav Hapla   if (sf->graphset) {ierr = PetscSFSetUp(sf);CHKERRQ(ierr);}
69495fce210SBarry Smith   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
69595fce210SBarry Smith   if (iascii) {
69695fce210SBarry Smith     PetscMPIInt rank;
69781bfa7aaSJed Brown     PetscInt    ii,i,j;
69895fce210SBarry Smith 
699dae58748SBarry Smith     ierr = PetscObjectPrintClassNamePrefixType((PetscObject)sf,viewer);CHKERRQ(ierr);
70095fce210SBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
70195fce210SBarry Smith     if (sf->ops->View) {ierr = (*sf->ops->View)(sf,viewer);CHKERRQ(ierr);}
702dd5b3ca6SJunchao Zhang     if (sf->pattern == PETSCSF_PATTERN_GENERAL) {
70380153354SVaclav Hapla       if (!sf->graphset) {
70480153354SVaclav Hapla         ierr = PetscViewerASCIIPrintf(viewer,"PetscSFSetGraph() has not been called yet\n");CHKERRQ(ierr);
70580153354SVaclav Hapla         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
70680153354SVaclav Hapla         PetscFunctionReturn(0);
70780153354SVaclav Hapla       }
70895fce210SBarry Smith       ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)sf),&rank);CHKERRQ(ierr);
7091575c14dSBarry Smith       ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
71095fce210SBarry Smith       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Number of roots=%D, leaves=%D, remote ranks=%D\n",rank,sf->nroots,sf->nleaves,sf->nranks);CHKERRQ(ierr);
71195fce210SBarry Smith       for (i=0; i<sf->nleaves; i++) {
71295fce210SBarry Smith         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);
71395fce210SBarry Smith       }
71495fce210SBarry Smith       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
71595fce210SBarry Smith       ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
71695fce210SBarry Smith       if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
71781bfa7aaSJed Brown         PetscMPIInt *tmpranks,*perm;
71881bfa7aaSJed Brown         ierr = PetscMalloc2(sf->nranks,&tmpranks,sf->nranks,&perm);CHKERRQ(ierr);
719580bdb30SBarry Smith         ierr = PetscArraycpy(tmpranks,sf->ranks,sf->nranks);CHKERRQ(ierr);
72081bfa7aaSJed Brown         for (i=0; i<sf->nranks; i++) perm[i] = i;
72181bfa7aaSJed Brown         ierr = PetscSortMPIIntWithArray(sf->nranks,tmpranks,perm);CHKERRQ(ierr);
72295fce210SBarry Smith         ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Roots referenced by my leaves, by rank\n",rank);CHKERRQ(ierr);
72381bfa7aaSJed Brown         for (ii=0; ii<sf->nranks; ii++) {
72481bfa7aaSJed Brown           i = perm[ii];
7257904a332SBarry Smith           ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] %d: %D edges\n",rank,sf->ranks[i],sf->roffset[i+1]-sf->roffset[i]);CHKERRQ(ierr);
72695fce210SBarry Smith           for (j=sf->roffset[i]; j<sf->roffset[i+1]; j++) {
72795fce210SBarry Smith             ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d]    %D <- %D\n",rank,sf->rmine[j],sf->rremote[j]);CHKERRQ(ierr);
72895fce210SBarry Smith           }
72995fce210SBarry Smith         }
73081bfa7aaSJed Brown         ierr = PetscFree2(tmpranks,perm);CHKERRQ(ierr);
73195fce210SBarry Smith       }
73295fce210SBarry Smith       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
7331575c14dSBarry Smith       ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
734dd5b3ca6SJunchao Zhang     }
73595fce210SBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
73695fce210SBarry Smith   }
73795fce210SBarry Smith   PetscFunctionReturn(0);
73895fce210SBarry Smith }
73995fce210SBarry Smith 
74095fce210SBarry Smith /*@C
741dec1416fSJunchao Zhang    PetscSFGetRootRanks - Get root ranks and number of vertices referenced by leaves on this process
74295fce210SBarry Smith 
74395fce210SBarry Smith    Not Collective
74495fce210SBarry Smith 
74595fce210SBarry Smith    Input Arguments:
74695fce210SBarry Smith .  sf - star forest
74795fce210SBarry Smith 
74895fce210SBarry Smith    Output Arguments:
74995fce210SBarry Smith +  nranks - number of ranks referenced by local part
75095fce210SBarry Smith .  ranks - array of ranks
75195fce210SBarry Smith .  roffset - offset in rmine/rremote for each rank (length nranks+1)
75295fce210SBarry Smith .  rmine - concatenated array holding local indices referencing each remote rank
75395fce210SBarry Smith -  rremote - concatenated array holding remote indices referenced for each remote rank
75495fce210SBarry Smith 
75595fce210SBarry Smith    Level: developer
75695fce210SBarry Smith 
757dec1416fSJunchao Zhang .seealso: PetscSFGetLeafRanks()
75895fce210SBarry Smith @*/
759dec1416fSJunchao Zhang PetscErrorCode PetscSFGetRootRanks(PetscSF sf,PetscInt *nranks,const PetscMPIInt **ranks,const PetscInt **roffset,const PetscInt **rmine,const PetscInt **rremote)
76095fce210SBarry Smith {
761dec1416fSJunchao Zhang   PetscErrorCode ierr;
76295fce210SBarry Smith 
76395fce210SBarry Smith   PetscFunctionBegin;
76495fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
76529046d53SLisandro Dalcin   if (!sf->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call PetscSFSetUp() before obtaining ranks");
766dec1416fSJunchao Zhang   if (sf->ops->GetRootRanks) {
767dec1416fSJunchao Zhang     ierr = (sf->ops->GetRootRanks)(sf,nranks,ranks,roffset,rmine,rremote);CHKERRQ(ierr);
768dec1416fSJunchao Zhang   } else {
769dec1416fSJunchao Zhang     /* The generic implementation */
77095fce210SBarry Smith     if (nranks)  *nranks  = sf->nranks;
77195fce210SBarry Smith     if (ranks)   *ranks   = sf->ranks;
77295fce210SBarry Smith     if (roffset) *roffset = sf->roffset;
77395fce210SBarry Smith     if (rmine)   *rmine   = sf->rmine;
77495fce210SBarry Smith     if (rremote) *rremote = sf->rremote;
775dec1416fSJunchao Zhang   }
77695fce210SBarry Smith   PetscFunctionReturn(0);
77795fce210SBarry Smith }
77895fce210SBarry Smith 
7798750ddebSJunchao Zhang /*@C
7808750ddebSJunchao Zhang    PetscSFGetLeafRanks - Get leaf ranks referencing roots on this process
7818750ddebSJunchao Zhang 
7828750ddebSJunchao Zhang    Not Collective
7838750ddebSJunchao Zhang 
7848750ddebSJunchao Zhang    Input Arguments:
7858750ddebSJunchao Zhang .  sf - star forest
7868750ddebSJunchao Zhang 
7878750ddebSJunchao Zhang    Output Arguments:
7888750ddebSJunchao Zhang +  niranks - number of leaf ranks referencing roots on this process
7898750ddebSJunchao Zhang .  iranks - array of ranks
7908750ddebSJunchao Zhang .  ioffset - offset in irootloc for each rank (length niranks+1)
7918750ddebSJunchao Zhang -  irootloc - concatenated array holding local indices of roots referenced by each leaf rank
7928750ddebSJunchao Zhang 
7938750ddebSJunchao Zhang    Level: developer
7948750ddebSJunchao Zhang 
795dec1416fSJunchao Zhang .seealso: PetscSFGetRootRanks()
7968750ddebSJunchao Zhang @*/
7978750ddebSJunchao Zhang PetscErrorCode PetscSFGetLeafRanks(PetscSF sf,PetscInt *niranks,const PetscMPIInt **iranks,const PetscInt **ioffset,const PetscInt **irootloc)
7988750ddebSJunchao Zhang {
7998750ddebSJunchao Zhang   PetscErrorCode ierr;
8008750ddebSJunchao Zhang 
8018750ddebSJunchao Zhang   PetscFunctionBegin;
8028750ddebSJunchao Zhang   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
8038750ddebSJunchao Zhang   if (!sf->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call PetscSFSetUp() before obtaining ranks");
8048750ddebSJunchao Zhang   if (sf->ops->GetLeafRanks) {
8058750ddebSJunchao Zhang     ierr = (sf->ops->GetLeafRanks)(sf,niranks,iranks,ioffset,irootloc);CHKERRQ(ierr);
8068750ddebSJunchao Zhang   } else {
8078750ddebSJunchao Zhang     PetscSFType type;
8088750ddebSJunchao Zhang     ierr = PetscSFGetType(sf,&type);CHKERRQ(ierr);
8098750ddebSJunchao Zhang     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"PetscSFGetLeafRanks() is not supported on this StarForest type: %s", type);
8108750ddebSJunchao Zhang   }
8118750ddebSJunchao Zhang   PetscFunctionReturn(0);
8128750ddebSJunchao Zhang }
8138750ddebSJunchao Zhang 
814b5a8e515SJed Brown static PetscBool InList(PetscMPIInt needle,PetscMPIInt n,const PetscMPIInt *list) {
815b5a8e515SJed Brown   PetscInt i;
816b5a8e515SJed Brown   for (i=0; i<n; i++) {
817b5a8e515SJed Brown     if (needle == list[i]) return PETSC_TRUE;
818b5a8e515SJed Brown   }
819b5a8e515SJed Brown   return PETSC_FALSE;
820b5a8e515SJed Brown }
821b5a8e515SJed Brown 
82295fce210SBarry Smith /*@C
82321c688dcSJed Brown    PetscSFSetUpRanks - Set up data structures associated with ranks; this is for internal use by PetscSF implementations.
82421c688dcSJed Brown 
82521c688dcSJed Brown    Collective
82621c688dcSJed Brown 
82721c688dcSJed Brown    Input Arguments:
828b5a8e515SJed Brown +  sf - PetscSF to set up; PetscSFSetGraph() must have been called
829b5a8e515SJed Brown -  dgroup - MPI_Group of ranks to be distinguished (e.g., for self or shared memory exchange)
83021c688dcSJed Brown 
83121c688dcSJed Brown    Level: developer
83221c688dcSJed Brown 
833dec1416fSJunchao Zhang .seealso: PetscSFGetRootRanks()
83421c688dcSJed Brown @*/
835b5a8e515SJed Brown PetscErrorCode PetscSFSetUpRanks(PetscSF sf,MPI_Group dgroup)
83621c688dcSJed Brown {
83721c688dcSJed Brown   PetscErrorCode     ierr;
83821c688dcSJed Brown   PetscTable         table;
83921c688dcSJed Brown   PetscTablePosition pos;
840b5a8e515SJed Brown   PetscMPIInt        size,groupsize,*groupranks;
841247e8311SStefano Zampini   PetscInt           *rcount,*ranks;
842247e8311SStefano Zampini   PetscInt           i, irank = -1,orank = -1;
84321c688dcSJed Brown 
84421c688dcSJed Brown   PetscFunctionBegin;
84521c688dcSJed Brown   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
84629046d53SLisandro Dalcin   PetscSFCheckGraphSet(sf,1);
84721c688dcSJed Brown   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)sf),&size);CHKERRQ(ierr);
84821c688dcSJed Brown   ierr = PetscTableCreate(10,size,&table);CHKERRQ(ierr);
84921c688dcSJed Brown   for (i=0; i<sf->nleaves; i++) {
85021c688dcSJed Brown     /* Log 1-based rank */
85121c688dcSJed Brown     ierr = PetscTableAdd(table,sf->remote[i].rank+1,1,ADD_VALUES);CHKERRQ(ierr);
85221c688dcSJed Brown   }
85321c688dcSJed Brown   ierr = PetscTableGetCount(table,&sf->nranks);CHKERRQ(ierr);
85421c688dcSJed Brown   ierr = PetscMalloc4(sf->nranks,&sf->ranks,sf->nranks+1,&sf->roffset,sf->nleaves,&sf->rmine,sf->nleaves,&sf->rremote);CHKERRQ(ierr);
85521c688dcSJed Brown   ierr = PetscMalloc2(sf->nranks,&rcount,sf->nranks,&ranks);CHKERRQ(ierr);
85621c688dcSJed Brown   ierr = PetscTableGetHeadPosition(table,&pos);CHKERRQ(ierr);
85721c688dcSJed Brown   for (i=0; i<sf->nranks; i++) {
85821c688dcSJed Brown     ierr = PetscTableGetNext(table,&pos,&ranks[i],&rcount[i]);CHKERRQ(ierr);
85921c688dcSJed Brown     ranks[i]--;             /* Convert back to 0-based */
86021c688dcSJed Brown   }
86121c688dcSJed Brown   ierr = PetscTableDestroy(&table);CHKERRQ(ierr);
862b5a8e515SJed Brown 
863b5a8e515SJed Brown   /* We expect that dgroup is reliably "small" while nranks could be large */
864b5a8e515SJed Brown   {
8657fb8a5e4SKarl Rupp     MPI_Group group = MPI_GROUP_NULL;
866b5a8e515SJed Brown     PetscMPIInt *dgroupranks;
867b5a8e515SJed Brown     ierr = MPI_Comm_group(PetscObjectComm((PetscObject)sf),&group);CHKERRQ(ierr);
868b5a8e515SJed Brown     ierr = MPI_Group_size(dgroup,&groupsize);CHKERRQ(ierr);
869b5a8e515SJed Brown     ierr = PetscMalloc1(groupsize,&dgroupranks);CHKERRQ(ierr);
870b5a8e515SJed Brown     ierr = PetscMalloc1(groupsize,&groupranks);CHKERRQ(ierr);
871b5a8e515SJed Brown     for (i=0; i<groupsize; i++) dgroupranks[i] = i;
872f3fc9a17SJed Brown     if (groupsize) {ierr = MPI_Group_translate_ranks(dgroup,groupsize,dgroupranks,group,groupranks);CHKERRQ(ierr);}
873b5a8e515SJed Brown     ierr = MPI_Group_free(&group);CHKERRQ(ierr);
874b5a8e515SJed Brown     ierr = PetscFree(dgroupranks);CHKERRQ(ierr);
875b5a8e515SJed Brown   }
876b5a8e515SJed Brown 
877b5a8e515SJed Brown   /* Partition ranks[] into distinguished (first sf->ndranks) followed by non-distinguished */
878b5a8e515SJed Brown   for (sf->ndranks=0,i=sf->nranks; sf->ndranks<i; ) {
879b5a8e515SJed Brown     for (i--; sf->ndranks<i; i--) { /* Scan i backward looking for distinguished rank */
880b5a8e515SJed Brown       if (InList(ranks[i],groupsize,groupranks)) break;
881b5a8e515SJed Brown     }
882b5a8e515SJed Brown     for ( ; sf->ndranks<=i; sf->ndranks++) { /* Scan sf->ndranks forward looking for non-distinguished rank */
883b5a8e515SJed Brown       if (!InList(ranks[sf->ndranks],groupsize,groupranks)) break;
884b5a8e515SJed Brown     }
885b5a8e515SJed Brown     if (sf->ndranks < i) {                         /* Swap ranks[sf->ndranks] with ranks[i] */
886b5a8e515SJed Brown       PetscInt    tmprank,tmpcount;
887247e8311SStefano Zampini 
888b5a8e515SJed Brown       tmprank             = ranks[i];
889b5a8e515SJed Brown       tmpcount            = rcount[i];
890b5a8e515SJed Brown       ranks[i]            = ranks[sf->ndranks];
891b5a8e515SJed Brown       rcount[i]           = rcount[sf->ndranks];
892b5a8e515SJed Brown       ranks[sf->ndranks]  = tmprank;
893b5a8e515SJed Brown       rcount[sf->ndranks] = tmpcount;
894b5a8e515SJed Brown       sf->ndranks++;
895b5a8e515SJed Brown     }
896b5a8e515SJed Brown   }
897b5a8e515SJed Brown   ierr = PetscFree(groupranks);CHKERRQ(ierr);
898b5a8e515SJed Brown   ierr = PetscSortIntWithArray(sf->ndranks,ranks,rcount);CHKERRQ(ierr);
899b5a8e515SJed Brown   ierr = PetscSortIntWithArray(sf->nranks-sf->ndranks,ranks+sf->ndranks,rcount+sf->ndranks);CHKERRQ(ierr);
90021c688dcSJed Brown   sf->roffset[0] = 0;
90121c688dcSJed Brown   for (i=0; i<sf->nranks; i++) {
90221c688dcSJed Brown     ierr = PetscMPIIntCast(ranks[i],sf->ranks+i);CHKERRQ(ierr);
90321c688dcSJed Brown     sf->roffset[i+1] = sf->roffset[i] + rcount[i];
90421c688dcSJed Brown     rcount[i]        = 0;
90521c688dcSJed Brown   }
906247e8311SStefano Zampini   for (i=0, irank = -1, orank = -1; i<sf->nleaves; i++) {
907247e8311SStefano Zampini     /* short circuit */
908247e8311SStefano Zampini     if (orank != sf->remote[i].rank) {
90921c688dcSJed Brown       /* Search for index of iremote[i].rank in sf->ranks */
910b5a8e515SJed Brown       ierr = PetscFindMPIInt(sf->remote[i].rank,sf->ndranks,sf->ranks,&irank);CHKERRQ(ierr);
911b5a8e515SJed Brown       if (irank < 0) {
912b5a8e515SJed Brown         ierr = PetscFindMPIInt(sf->remote[i].rank,sf->nranks-sf->ndranks,sf->ranks+sf->ndranks,&irank);CHKERRQ(ierr);
913b5a8e515SJed Brown         if (irank >= 0) irank += sf->ndranks;
91421c688dcSJed Brown       }
915247e8311SStefano Zampini       orank = sf->remote[i].rank;
916247e8311SStefano Zampini     }
917b5a8e515SJed Brown     if (irank < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not find rank %D in array",sf->remote[i].rank);
91821c688dcSJed Brown     sf->rmine[sf->roffset[irank] + rcount[irank]]   = sf->mine ? sf->mine[i] : i;
91921c688dcSJed Brown     sf->rremote[sf->roffset[irank] + rcount[irank]] = sf->remote[i].index;
92021c688dcSJed Brown     rcount[irank]++;
92121c688dcSJed Brown   }
92221c688dcSJed Brown   ierr = PetscFree2(rcount,ranks);CHKERRQ(ierr);
92321c688dcSJed Brown   PetscFunctionReturn(0);
92421c688dcSJed Brown }
92521c688dcSJed Brown 
92621c688dcSJed Brown /*@C
92795fce210SBarry Smith    PetscSFGetGroups - gets incoming and outgoing process groups
92895fce210SBarry Smith 
92995fce210SBarry Smith    Collective
93095fce210SBarry Smith 
93195fce210SBarry Smith    Input Argument:
93295fce210SBarry Smith .  sf - star forest
93395fce210SBarry Smith 
93495fce210SBarry Smith    Output Arguments:
93595fce210SBarry Smith +  incoming - group of origin processes for incoming edges (leaves that reference my roots)
93695fce210SBarry Smith -  outgoing - group of destination processes for outgoing edges (roots that I reference)
93795fce210SBarry Smith 
93895fce210SBarry Smith    Level: developer
93995fce210SBarry Smith 
94095fce210SBarry Smith .seealso: PetscSFGetWindow(), PetscSFRestoreWindow()
94195fce210SBarry Smith @*/
94295fce210SBarry Smith PetscErrorCode PetscSFGetGroups(PetscSF sf,MPI_Group *incoming,MPI_Group *outgoing)
94395fce210SBarry Smith {
94495fce210SBarry Smith   PetscErrorCode ierr;
9457fb8a5e4SKarl Rupp   MPI_Group      group = MPI_GROUP_NULL;
94695fce210SBarry Smith 
94795fce210SBarry Smith   PetscFunctionBegin;
94829046d53SLisandro Dalcin   if (!sf->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call PetscSFSetUp() before obtaining groups");
94995fce210SBarry Smith   if (sf->ingroup == MPI_GROUP_NULL) {
95095fce210SBarry Smith     PetscInt       i;
95195fce210SBarry Smith     const PetscInt *indegree;
95295fce210SBarry Smith     PetscMPIInt    rank,*outranks,*inranks;
95395fce210SBarry Smith     PetscSFNode    *remote;
95495fce210SBarry Smith     PetscSF        bgcount;
95595fce210SBarry Smith 
95695fce210SBarry Smith     /* Compute the number of incoming ranks */
957785e854fSJed Brown     ierr = PetscMalloc1(sf->nranks,&remote);CHKERRQ(ierr);
95895fce210SBarry Smith     for (i=0; i<sf->nranks; i++) {
95995fce210SBarry Smith       remote[i].rank  = sf->ranks[i];
96095fce210SBarry Smith       remote[i].index = 0;
96195fce210SBarry Smith     }
96295fce210SBarry Smith     ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_CONFONLY,&bgcount);CHKERRQ(ierr);
96395fce210SBarry Smith     ierr = PetscSFSetGraph(bgcount,1,sf->nranks,NULL,PETSC_COPY_VALUES,remote,PETSC_OWN_POINTER);CHKERRQ(ierr);
96495fce210SBarry Smith     ierr = PetscSFComputeDegreeBegin(bgcount,&indegree);CHKERRQ(ierr);
96595fce210SBarry Smith     ierr = PetscSFComputeDegreeEnd(bgcount,&indegree);CHKERRQ(ierr);
96695fce210SBarry Smith 
96795fce210SBarry Smith     /* Enumerate the incoming ranks */
968dcca6d9dSJed Brown     ierr = PetscMalloc2(indegree[0],&inranks,sf->nranks,&outranks);CHKERRQ(ierr);
96995fce210SBarry Smith     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)sf),&rank);CHKERRQ(ierr);
97095fce210SBarry Smith     for (i=0; i<sf->nranks; i++) outranks[i] = rank;
97195fce210SBarry Smith     ierr = PetscSFGatherBegin(bgcount,MPI_INT,outranks,inranks);CHKERRQ(ierr);
97295fce210SBarry Smith     ierr = PetscSFGatherEnd(bgcount,MPI_INT,outranks,inranks);CHKERRQ(ierr);
97395fce210SBarry Smith     ierr = MPI_Comm_group(PetscObjectComm((PetscObject)sf),&group);CHKERRQ(ierr);
97495fce210SBarry Smith     ierr = MPI_Group_incl(group,indegree[0],inranks,&sf->ingroup);CHKERRQ(ierr);
97595fce210SBarry Smith     ierr = MPI_Group_free(&group);CHKERRQ(ierr);
97695fce210SBarry Smith     ierr = PetscFree2(inranks,outranks);CHKERRQ(ierr);
97795fce210SBarry Smith     ierr = PetscSFDestroy(&bgcount);CHKERRQ(ierr);
97895fce210SBarry Smith   }
97995fce210SBarry Smith   *incoming = sf->ingroup;
98095fce210SBarry Smith 
98195fce210SBarry Smith   if (sf->outgroup == MPI_GROUP_NULL) {
98295fce210SBarry Smith     ierr = MPI_Comm_group(PetscObjectComm((PetscObject)sf),&group);CHKERRQ(ierr);
98395fce210SBarry Smith     ierr = MPI_Group_incl(group,sf->nranks,sf->ranks,&sf->outgroup);CHKERRQ(ierr);
98495fce210SBarry Smith     ierr = MPI_Group_free(&group);CHKERRQ(ierr);
98595fce210SBarry Smith   }
98695fce210SBarry Smith   *outgoing = sf->outgroup;
98795fce210SBarry Smith   PetscFunctionReturn(0);
98895fce210SBarry Smith }
98995fce210SBarry Smith 
99029046d53SLisandro Dalcin /*@
99195fce210SBarry Smith    PetscSFGetMultiSF - gets the inner SF implemeting gathers and scatters
99295fce210SBarry Smith 
99395fce210SBarry Smith    Collective
99495fce210SBarry Smith 
99595fce210SBarry Smith    Input Argument:
99695fce210SBarry Smith .  sf - star forest that may contain roots with 0 or with more than 1 vertex
99795fce210SBarry Smith 
99895fce210SBarry Smith    Output Arguments:
99995fce210SBarry Smith .  multi - star forest with split roots, such that each root has degree exactly 1
100095fce210SBarry Smith 
100195fce210SBarry Smith    Level: developer
100295fce210SBarry Smith 
100395fce210SBarry Smith    Notes:
100495fce210SBarry Smith 
100595fce210SBarry Smith    In most cases, users should use PetscSFGatherBegin() and PetscSFScatterBegin() instead of manipulating multi
100695fce210SBarry Smith    directly. Since multi satisfies the stronger condition that each entry in the global space has exactly one incoming
100795fce210SBarry Smith    edge, it is a candidate for future optimization that might involve its removal.
100895fce210SBarry Smith 
1009673100f5SVaclav Hapla .seealso: PetscSFSetGraph(), PetscSFGatherBegin(), PetscSFScatterBegin(), PetscSFComputeMultiRootOriginalNumbering()
101095fce210SBarry Smith @*/
101195fce210SBarry Smith PetscErrorCode PetscSFGetMultiSF(PetscSF sf,PetscSF *multi)
101295fce210SBarry Smith {
101395fce210SBarry Smith   PetscErrorCode ierr;
101495fce210SBarry Smith 
101595fce210SBarry Smith   PetscFunctionBegin;
101695fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
101795fce210SBarry Smith   PetscValidPointer(multi,2);
101895fce210SBarry Smith   if (sf->nroots < 0) {         /* Graph has not been set yet; why do we need this? */
101995fce210SBarry Smith     ierr   = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_RANKS,&sf->multi);CHKERRQ(ierr);
102095fce210SBarry Smith     *multi = sf->multi;
102195fce210SBarry Smith     PetscFunctionReturn(0);
102295fce210SBarry Smith   }
102395fce210SBarry Smith   if (!sf->multi) {
102495fce210SBarry Smith     const PetscInt *indegree;
10259837ea96SMatthew G. Knepley     PetscInt       i,*inoffset,*outones,*outoffset,maxlocal;
102695fce210SBarry Smith     PetscSFNode    *remote;
102729046d53SLisandro Dalcin     maxlocal = sf->maxleaf+1; /* TODO: We should use PetscSFGetLeafRange() */
102895fce210SBarry Smith     ierr = PetscSFComputeDegreeBegin(sf,&indegree);CHKERRQ(ierr);
102995fce210SBarry Smith     ierr = PetscSFComputeDegreeEnd(sf,&indegree);CHKERRQ(ierr);
10309837ea96SMatthew G. Knepley     ierr = PetscMalloc3(sf->nroots+1,&inoffset,maxlocal,&outones,maxlocal,&outoffset);CHKERRQ(ierr);
103195fce210SBarry Smith     inoffset[0] = 0;
103295fce210SBarry Smith     for (i=0; i<sf->nroots; i++) inoffset[i+1] = inoffset[i] + indegree[i];
10339837ea96SMatthew G. Knepley     for (i=0; i<maxlocal; i++) outones[i] = 1;
1034dbd2ff41SBarry Smith     ierr = PetscSFFetchAndOpBegin(sf,MPIU_INT,inoffset,outones,outoffset,MPI_SUM);CHKERRQ(ierr);
1035dbd2ff41SBarry Smith     ierr = PetscSFFetchAndOpEnd(sf,MPIU_INT,inoffset,outones,outoffset,MPI_SUM);CHKERRQ(ierr);
103695fce210SBarry Smith     for (i=0; i<sf->nroots; i++) inoffset[i] -= indegree[i]; /* Undo the increment */
103795fce210SBarry Smith #if 0
103895fce210SBarry Smith #if defined(PETSC_USE_DEBUG)                                 /* Check that the expected number of increments occurred */
103995fce210SBarry Smith     for (i=0; i<sf->nroots; i++) {
104095fce210SBarry Smith       if (inoffset[i] + indegree[i] != inoffset[i+1]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Incorrect result after PetscSFFetchAndOp");
104195fce210SBarry Smith     }
104295fce210SBarry Smith #endif
104395fce210SBarry Smith #endif
1044785e854fSJed Brown     ierr = PetscMalloc1(sf->nleaves,&remote);CHKERRQ(ierr);
104595fce210SBarry Smith     for (i=0; i<sf->nleaves; i++) {
104695fce210SBarry Smith       remote[i].rank  = sf->remote[i].rank;
104738e7336fSToby Isaac       remote[i].index = outoffset[sf->mine ? sf->mine[i] : i];
104895fce210SBarry Smith     }
104995fce210SBarry Smith     ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_RANKS,&sf->multi);CHKERRQ(ierr);
105001365b40SToby Isaac     ierr = PetscSFSetGraph(sf->multi,inoffset[sf->nroots],sf->nleaves,sf->mine,PETSC_COPY_VALUES,remote,PETSC_OWN_POINTER);CHKERRQ(ierr);
105195fce210SBarry Smith     if (sf->rankorder) {        /* Sort the ranks */
105295fce210SBarry Smith       PetscMPIInt rank;
105395fce210SBarry Smith       PetscInt    *inranks,*newoffset,*outranks,*newoutoffset,*tmpoffset,maxdegree;
105495fce210SBarry Smith       PetscSFNode *newremote;
105595fce210SBarry Smith       ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)sf),&rank);CHKERRQ(ierr);
105695fce210SBarry Smith       for (i=0,maxdegree=0; i<sf->nroots; i++) maxdegree = PetscMax(maxdegree,indegree[i]);
10579837ea96SMatthew G. Knepley       ierr = PetscMalloc5(sf->multi->nroots,&inranks,sf->multi->nroots,&newoffset,maxlocal,&outranks,maxlocal,&newoutoffset,maxdegree,&tmpoffset);CHKERRQ(ierr);
10589837ea96SMatthew G. Knepley       for (i=0; i<maxlocal; i++) outranks[i] = rank;
10598bfbc91cSJed Brown       ierr = PetscSFReduceBegin(sf->multi,MPIU_INT,outranks,inranks,MPIU_REPLACE);CHKERRQ(ierr);
10608bfbc91cSJed Brown       ierr = PetscSFReduceEnd(sf->multi,MPIU_INT,outranks,inranks,MPIU_REPLACE);CHKERRQ(ierr);
106195fce210SBarry Smith       /* Sort the incoming ranks at each vertex, build the inverse map */
106295fce210SBarry Smith       for (i=0; i<sf->nroots; i++) {
106395fce210SBarry Smith         PetscInt j;
106495fce210SBarry Smith         for (j=0; j<indegree[i]; j++) tmpoffset[j] = j;
106595fce210SBarry Smith         ierr = PetscSortIntWithArray(indegree[i],inranks+inoffset[i],tmpoffset);CHKERRQ(ierr);
106695fce210SBarry Smith         for (j=0; j<indegree[i]; j++) newoffset[inoffset[i] + tmpoffset[j]] = inoffset[i] + j;
106795fce210SBarry Smith       }
106895fce210SBarry Smith       ierr = PetscSFBcastBegin(sf->multi,MPIU_INT,newoffset,newoutoffset);CHKERRQ(ierr);
106995fce210SBarry Smith       ierr = PetscSFBcastEnd(sf->multi,MPIU_INT,newoffset,newoutoffset);CHKERRQ(ierr);
1070785e854fSJed Brown       ierr = PetscMalloc1(sf->nleaves,&newremote);CHKERRQ(ierr);
107195fce210SBarry Smith       for (i=0; i<sf->nleaves; i++) {
107295fce210SBarry Smith         newremote[i].rank  = sf->remote[i].rank;
107301365b40SToby Isaac         newremote[i].index = newoutoffset[sf->mine ? sf->mine[i] : i];
107495fce210SBarry Smith       }
107501365b40SToby Isaac       ierr = PetscSFSetGraph(sf->multi,inoffset[sf->nroots],sf->nleaves,sf->mine,PETSC_COPY_VALUES,newremote,PETSC_OWN_POINTER);CHKERRQ(ierr);
107695fce210SBarry Smith       ierr = PetscFree5(inranks,newoffset,outranks,newoutoffset,tmpoffset);CHKERRQ(ierr);
107795fce210SBarry Smith     }
107895fce210SBarry Smith     ierr = PetscFree3(inoffset,outones,outoffset);CHKERRQ(ierr);
107995fce210SBarry Smith   }
108095fce210SBarry Smith   *multi = sf->multi;
108195fce210SBarry Smith   PetscFunctionReturn(0);
108295fce210SBarry Smith }
108395fce210SBarry Smith 
108495fce210SBarry Smith /*@C
108595fce210SBarry Smith    PetscSFCreateEmbeddedSF - removes edges from all but the selected roots, does not remap indices
108695fce210SBarry Smith 
108795fce210SBarry Smith    Collective
108895fce210SBarry Smith 
108995fce210SBarry Smith    Input Arguments:
109095fce210SBarry Smith +  sf - original star forest
1091ba2a7774SJunchao Zhang .  nselected  - number of selected roots on this process
1092ba2a7774SJunchao Zhang -  selected   - indices of the selected roots on this process
109395fce210SBarry Smith 
109495fce210SBarry Smith    Output Arguments:
109595fce210SBarry Smith .  newsf - new star forest
109695fce210SBarry Smith 
109795fce210SBarry Smith    Level: advanced
109895fce210SBarry Smith 
109995fce210SBarry Smith    Note:
110095fce210SBarry Smith    To use the new PetscSF, it may be necessary to know the indices of the leaves that are still participating. This can
110195fce210SBarry Smith    be done by calling PetscSFGetGraph().
110295fce210SBarry Smith 
110395fce210SBarry Smith .seealso: PetscSFSetGraph(), PetscSFGetGraph()
110495fce210SBarry Smith @*/
1105ba2a7774SJunchao Zhang PetscErrorCode PetscSFCreateEmbeddedSF(PetscSF sf,PetscInt nselected,const PetscInt *selected,PetscSF *newsf)
110695fce210SBarry Smith {
1107f659e5c7SJunchao Zhang   PetscInt          i,n,*roots,*rootdata,*leafdata,nroots,nleaves,connected_leaves,*new_ilocal;
1108ba2a7774SJunchao Zhang   const PetscSFNode *iremote;
1109f659e5c7SJunchao Zhang   PetscSFNode       *new_iremote;
1110ba2a7774SJunchao Zhang   PetscSF           tmpsf;
1111f659e5c7SJunchao Zhang   MPI_Comm          comm;
11120511a646SMatthew G. Knepley   PetscErrorCode    ierr;
111395fce210SBarry Smith 
111495fce210SBarry Smith   PetscFunctionBegin;
111595fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
111629046d53SLisandro Dalcin   PetscSFCheckGraphSet(sf,1);
1117ba2a7774SJunchao Zhang   if (nselected) PetscValidPointer(selected,3);
111895fce210SBarry Smith   PetscValidPointer(newsf,4);
11190511a646SMatthew G. Knepley 
1120f659e5c7SJunchao Zhang   ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
1121f659e5c7SJunchao Zhang 
1122f659e5c7SJunchao Zhang   /* Uniq selected[] and put results in roots[] */
1123f659e5c7SJunchao Zhang   ierr = PetscObjectGetComm((PetscObject)sf,&comm);CHKERRQ(ierr);
1124f659e5c7SJunchao Zhang   ierr = PetscMalloc1(nselected,&roots);CHKERRQ(ierr);
1125dd5b3ca6SJunchao Zhang   ierr = PetscArraycpy(roots,selected,nselected);CHKERRQ(ierr);
1126f659e5c7SJunchao Zhang   ierr = PetscSortedRemoveDupsInt(&nselected,roots);CHKERRQ(ierr);
1127f659e5c7SJunchao Zhang   if (nselected && (roots[0] < 0 || roots[nselected-1] >= sf->nroots)) SETERRQ3(comm,PETSC_ERR_ARG_OUTOFRANGE,"Min/Max root indices %D/%D are not in [0,%D)",roots[0],roots[nselected-1],sf->nroots);
1128f659e5c7SJunchao Zhang 
1129f659e5c7SJunchao Zhang   if (sf->ops->CreateEmbeddedSF) {
1130f659e5c7SJunchao Zhang     ierr = (*sf->ops->CreateEmbeddedSF)(sf,nselected,roots,newsf);CHKERRQ(ierr);
1131f659e5c7SJunchao Zhang   } else {
1132f659e5c7SJunchao Zhang     /* A generic version of creating embedded sf. Note that we called PetscSFSetGraph() twice, which is certainly expensive */
1133ba2a7774SJunchao Zhang     /* Find out which leaves (not leaf data items) are still connected to roots in the embedded sf */
1134f659e5c7SJunchao Zhang     ierr = PetscSFGetGraph(sf,&nroots,&nleaves,NULL,&iremote);CHKERRQ(ierr);
1135ba2a7774SJunchao Zhang     ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_RANKS,&tmpsf);CHKERRQ(ierr);
1136ba2a7774SJunchao Zhang     ierr = PetscSFSetGraph(tmpsf,nroots,nleaves,NULL/*contiguous*/,PETSC_USE_POINTER,iremote,PETSC_USE_POINTER);CHKERRQ(ierr);
1137ba2a7774SJunchao Zhang     ierr = PetscCalloc2(nroots,&rootdata,nleaves,&leafdata);CHKERRQ(ierr);
1138f659e5c7SJunchao Zhang     for (i=0; i<nselected; ++i) rootdata[roots[i]] = 1;
1139ba2a7774SJunchao Zhang     ierr = PetscSFBcastBegin(tmpsf,MPIU_INT,rootdata,leafdata);CHKERRQ(ierr);
1140ba2a7774SJunchao Zhang     ierr = PetscSFBcastEnd(tmpsf,MPIU_INT,rootdata,leafdata);CHKERRQ(ierr);
1141ba2a7774SJunchao Zhang     ierr = PetscSFDestroy(&tmpsf);CHKERRQ(ierr);
1142ba2a7774SJunchao Zhang 
1143ba2a7774SJunchao Zhang     /* Build newsf with leaves that are still connected */
1144f659e5c7SJunchao Zhang     connected_leaves = 0;
1145f659e5c7SJunchao Zhang     for (i=0; i<nleaves; ++i) connected_leaves += leafdata[i];
1146f659e5c7SJunchao Zhang     ierr = PetscMalloc1(connected_leaves,&new_ilocal);CHKERRQ(ierr);
1147f659e5c7SJunchao Zhang     ierr = PetscMalloc1(connected_leaves,&new_iremote);CHKERRQ(ierr);
1148ba2a7774SJunchao Zhang     for (i=0, n=0; i<nleaves; ++i) {
1149ba2a7774SJunchao Zhang       if (leafdata[i]) {
1150ba2a7774SJunchao Zhang         new_ilocal[n]        = sf->mine ? sf->mine[i] : i;
1151ba2a7774SJunchao Zhang         new_iremote[n].rank  = sf->remote[i].rank;
1152ba2a7774SJunchao Zhang         new_iremote[n].index = sf->remote[i].index;
1153fc1ede2bSMatthew G. Knepley         ++n;
115495fce210SBarry Smith       }
115595fce210SBarry Smith     }
1156f659e5c7SJunchao Zhang 
1157f659e5c7SJunchao Zhang     if (n != connected_leaves) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"There is a size mismatch in the SF embedding, %d != %d",n,connected_leaves);
1158f659e5c7SJunchao Zhang     ierr = PetscSFCreate(comm,newsf);CHKERRQ(ierr);
1159f659e5c7SJunchao Zhang     ierr = PetscSFSetFromOptions(*newsf);CHKERRQ(ierr);
1160f659e5c7SJunchao Zhang     ierr = PetscSFSetGraph(*newsf,nroots,connected_leaves,new_ilocal,PETSC_OWN_POINTER,new_iremote,PETSC_OWN_POINTER);CHKERRQ(ierr);
116195fce210SBarry Smith     ierr = PetscFree2(rootdata,leafdata);CHKERRQ(ierr);
1162f659e5c7SJunchao Zhang   }
1163f659e5c7SJunchao Zhang   ierr = PetscFree(roots);CHKERRQ(ierr);
116495fce210SBarry Smith   PetscFunctionReturn(0);
116595fce210SBarry Smith }
116695fce210SBarry Smith 
11672f5fb4c2SMatthew G. Knepley /*@C
11682f5fb4c2SMatthew G. Knepley   PetscSFCreateEmbeddedLeafSF - removes edges from all but the selected leaves, does not remap indices
11692f5fb4c2SMatthew G. Knepley 
11702f5fb4c2SMatthew G. Knepley   Collective
11712f5fb4c2SMatthew G. Knepley 
11722f5fb4c2SMatthew G. Knepley   Input Arguments:
11732f5fb4c2SMatthew G. Knepley + sf - original star forest
1174f659e5c7SJunchao Zhang . nselected  - number of selected leaves on this process
1175f659e5c7SJunchao Zhang - selected   - indices of the selected leaves on this process
11762f5fb4c2SMatthew G. Knepley 
11772f5fb4c2SMatthew G. Knepley   Output Arguments:
11782f5fb4c2SMatthew G. Knepley .  newsf - new star forest
11792f5fb4c2SMatthew G. Knepley 
11802f5fb4c2SMatthew G. Knepley   Level: advanced
11812f5fb4c2SMatthew G. Knepley 
11822f5fb4c2SMatthew G. Knepley .seealso: PetscSFCreateEmbeddedSF(), PetscSFSetGraph(), PetscSFGetGraph()
11832f5fb4c2SMatthew G. Knepley @*/
1184f659e5c7SJunchao Zhang PetscErrorCode PetscSFCreateEmbeddedLeafSF(PetscSF sf,PetscInt nselected,const PetscInt *selected,PetscSF *newsf)
11852f5fb4c2SMatthew G. Knepley {
1186f659e5c7SJunchao Zhang   const PetscSFNode *iremote;
1187f659e5c7SJunchao Zhang   PetscSFNode       *new_iremote;
1188f659e5c7SJunchao Zhang   const PetscInt    *ilocal;
1189f659e5c7SJunchao Zhang   PetscInt          i,nroots,*leaves,*new_ilocal;
1190f659e5c7SJunchao Zhang   MPI_Comm          comm;
11912f5fb4c2SMatthew G. Knepley   PetscErrorCode    ierr;
11922f5fb4c2SMatthew G. Knepley 
11932f5fb4c2SMatthew G. Knepley   PetscFunctionBegin;
11942f5fb4c2SMatthew G. Knepley   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
119529046d53SLisandro Dalcin   PetscSFCheckGraphSet(sf,1);
1196f659e5c7SJunchao Zhang   if (nselected) PetscValidPointer(selected,3);
11972f5fb4c2SMatthew G. Knepley   PetscValidPointer(newsf,4);
11982f5fb4c2SMatthew G. Knepley 
1199f659e5c7SJunchao Zhang   /* Uniq selected[] and put results in leaves[] */
1200f659e5c7SJunchao Zhang   ierr = PetscObjectGetComm((PetscObject)sf,&comm);CHKERRQ(ierr);
1201f659e5c7SJunchao Zhang   ierr = PetscMalloc1(nselected,&leaves);CHKERRQ(ierr);
1202dd5b3ca6SJunchao Zhang   ierr = PetscArraycpy(leaves,selected,nselected);CHKERRQ(ierr);
1203f659e5c7SJunchao Zhang   ierr = PetscSortedRemoveDupsInt(&nselected,leaves);CHKERRQ(ierr);
1204f659e5c7SJunchao Zhang   if (nselected && (leaves[0] < 0 || leaves[nselected-1] >= sf->nleaves)) SETERRQ3(comm,PETSC_ERR_ARG_OUTOFRANGE,"Min/Max leaf indices %D/%D are not in [0,%D)",leaves[0],leaves[nselected-1],sf->nleaves);
1205f659e5c7SJunchao Zhang 
1206f659e5c7SJunchao Zhang   /* Optimize the routine only when sf is setup and hence we can reuse sf's communication pattern */
1207f659e5c7SJunchao Zhang   if (sf->setupcalled && sf->ops->CreateEmbeddedLeafSF) {
1208f659e5c7SJunchao Zhang     ierr = (*sf->ops->CreateEmbeddedLeafSF)(sf,nselected,leaves,newsf);CHKERRQ(ierr);
1209f659e5c7SJunchao Zhang   } else {
1210f659e5c7SJunchao Zhang     ierr = PetscSFGetGraph(sf,&nroots,NULL,&ilocal,&iremote);CHKERRQ(ierr);
1211f659e5c7SJunchao Zhang     ierr = PetscMalloc1(nselected,&new_ilocal);CHKERRQ(ierr);
1212f659e5c7SJunchao Zhang     ierr = PetscMalloc1(nselected,&new_iremote);CHKERRQ(ierr);
1213f659e5c7SJunchao Zhang     for (i=0; i<nselected; ++i) {
1214f659e5c7SJunchao Zhang       const PetscInt l     = leaves[i];
1215f659e5c7SJunchao Zhang       new_ilocal[i]        = ilocal ? ilocal[l] : l;
1216f659e5c7SJunchao Zhang       new_iremote[i].rank  = iremote[l].rank;
1217f659e5c7SJunchao Zhang       new_iremote[i].index = iremote[l].index;
12182f5fb4c2SMatthew G. Knepley     }
1219f659e5c7SJunchao Zhang     ierr = PetscSFCreate(comm,newsf);CHKERRQ(ierr);
1220f659e5c7SJunchao Zhang     ierr = PetscSFSetFromOptions(*newsf);CHKERRQ(ierr);
1221f659e5c7SJunchao Zhang     ierr = PetscSFSetGraph(*newsf,nroots,nselected,new_ilocal,PETSC_OWN_POINTER,new_iremote,PETSC_OWN_POINTER);CHKERRQ(ierr);
1222f659e5c7SJunchao Zhang   }
1223f659e5c7SJunchao Zhang   ierr = PetscFree(leaves);CHKERRQ(ierr);
12242f5fb4c2SMatthew G. Knepley   PetscFunctionReturn(0);
12252f5fb4c2SMatthew G. Knepley }
12262f5fb4c2SMatthew G. Knepley 
122795fce210SBarry Smith /*@C
12283482bfa8SJunchao Zhang    PetscSFBcastAndOpBegin - begin pointwise broadcast with root value being reduced to leaf value, to be concluded with call to PetscSFBcastAndOpEnd()
12293482bfa8SJunchao Zhang 
12303482bfa8SJunchao Zhang    Collective on PetscSF
12313482bfa8SJunchao Zhang 
12323482bfa8SJunchao Zhang    Input Arguments:
12333482bfa8SJunchao Zhang +  sf - star forest on which to communicate
12343482bfa8SJunchao Zhang .  unit - data type associated with each node
12353482bfa8SJunchao Zhang .  rootdata - buffer to broadcast
12363482bfa8SJunchao Zhang -  op - operation to use for reduction
12373482bfa8SJunchao Zhang 
12383482bfa8SJunchao Zhang    Output Arguments:
12393482bfa8SJunchao Zhang .  leafdata - buffer to be reduced with values from each leaf's respective root
12403482bfa8SJunchao Zhang 
12413482bfa8SJunchao Zhang    Level: intermediate
12423482bfa8SJunchao Zhang 
12433482bfa8SJunchao Zhang .seealso: PetscSFBcastAndOpEnd(), PetscSFBcastBegin(), PetscSFBcastEnd()
12443482bfa8SJunchao Zhang @*/
12453482bfa8SJunchao Zhang PetscErrorCode PetscSFBcastAndOpBegin(PetscSF sf,MPI_Datatype unit,const void *rootdata,void *leafdata,MPI_Op op)
12463482bfa8SJunchao Zhang {
12473482bfa8SJunchao Zhang   PetscErrorCode ierr;
12483482bfa8SJunchao Zhang 
12493482bfa8SJunchao Zhang   PetscFunctionBegin;
12503482bfa8SJunchao Zhang   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
12513482bfa8SJunchao Zhang   ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
12523482bfa8SJunchao Zhang   ierr = PetscLogEventBegin(PETSCSF_BcastAndOpBegin,sf,0,0,0);CHKERRQ(ierr);
12533482bfa8SJunchao Zhang   ierr = (*sf->ops->BcastAndOpBegin)(sf,unit,rootdata,leafdata,op);CHKERRQ(ierr);
12543482bfa8SJunchao Zhang   ierr = PetscLogEventEnd(PETSCSF_BcastAndOpBegin,sf,0,0,0);CHKERRQ(ierr);
12553482bfa8SJunchao Zhang   PetscFunctionReturn(0);
12563482bfa8SJunchao Zhang }
12573482bfa8SJunchao Zhang 
12583482bfa8SJunchao Zhang /*@C
12593482bfa8SJunchao Zhang    PetscSFBcastAndOpEnd - end a broadcast & reduce operation started with PetscSFBcastAndOpBegin()
12603482bfa8SJunchao Zhang 
12613482bfa8SJunchao Zhang    Collective
12623482bfa8SJunchao Zhang 
12633482bfa8SJunchao Zhang    Input Arguments:
12643482bfa8SJunchao Zhang +  sf - star forest
12653482bfa8SJunchao Zhang .  unit - data type
12663482bfa8SJunchao Zhang .  rootdata - buffer to broadcast
12673482bfa8SJunchao Zhang -  op - operation to use for reduction
12683482bfa8SJunchao Zhang 
12693482bfa8SJunchao Zhang    Output Arguments:
12703482bfa8SJunchao Zhang .  leafdata - buffer to be reduced with values from each leaf's respective root
12713482bfa8SJunchao Zhang 
12723482bfa8SJunchao Zhang    Level: intermediate
12733482bfa8SJunchao Zhang 
12743482bfa8SJunchao Zhang .seealso: PetscSFSetGraph(), PetscSFReduceEnd()
12753482bfa8SJunchao Zhang @*/
12763482bfa8SJunchao Zhang PetscErrorCode PetscSFBcastAndOpEnd(PetscSF sf,MPI_Datatype unit,const void *rootdata,void *leafdata,MPI_Op op)
12773482bfa8SJunchao Zhang {
12783482bfa8SJunchao Zhang   PetscErrorCode ierr;
12793482bfa8SJunchao Zhang 
12803482bfa8SJunchao Zhang   PetscFunctionBegin;
12813482bfa8SJunchao Zhang   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
12823482bfa8SJunchao Zhang   ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
12833482bfa8SJunchao Zhang   ierr = PetscLogEventBegin(PETSCSF_BcastAndOpEnd,sf,0,0,0);CHKERRQ(ierr);
12843482bfa8SJunchao Zhang   ierr = (*sf->ops->BcastAndOpEnd)(sf,unit,rootdata,leafdata,op);CHKERRQ(ierr);
12853482bfa8SJunchao Zhang   ierr = PetscLogEventEnd(PETSCSF_BcastAndOpEnd,sf,0,0,0);CHKERRQ(ierr);
12863482bfa8SJunchao Zhang   PetscFunctionReturn(0);
12873482bfa8SJunchao Zhang }
12883482bfa8SJunchao Zhang 
12893482bfa8SJunchao Zhang /*@C
129095fce210SBarry Smith    PetscSFReduceBegin - begin reduction of leafdata into rootdata, to be completed with call to PetscSFReduceEnd()
129195fce210SBarry Smith 
129295fce210SBarry Smith    Collective
129395fce210SBarry Smith 
129495fce210SBarry Smith    Input Arguments:
129595fce210SBarry Smith +  sf - star forest
129695fce210SBarry Smith .  unit - data type
129795fce210SBarry Smith .  leafdata - values to reduce
129895fce210SBarry Smith -  op - reduction operation
129995fce210SBarry Smith 
130095fce210SBarry Smith    Output Arguments:
130195fce210SBarry Smith .  rootdata - result of reduction of values from all leaves of each root
130295fce210SBarry Smith 
130395fce210SBarry Smith    Level: intermediate
130495fce210SBarry Smith 
130595fce210SBarry Smith .seealso: PetscSFBcastBegin()
130695fce210SBarry Smith @*/
130795fce210SBarry Smith PetscErrorCode PetscSFReduceBegin(PetscSF sf,MPI_Datatype unit,const void *leafdata,void *rootdata,MPI_Op op)
130895fce210SBarry Smith {
130995fce210SBarry Smith   PetscErrorCode ierr;
131095fce210SBarry Smith 
131195fce210SBarry Smith   PetscFunctionBegin;
131295fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
131395fce210SBarry Smith   ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
131429046d53SLisandro Dalcin   ierr = PetscLogEventBegin(PETSCSF_ReduceBegin,sf,0,0,0);CHKERRQ(ierr);
131595fce210SBarry Smith   ierr = (sf->ops->ReduceBegin)(sf,unit,leafdata,rootdata,op);CHKERRQ(ierr);
1316563ffbabSMatthew G. Knepley   ierr = PetscLogEventEnd(PETSCSF_ReduceBegin,sf,0,0,0);CHKERRQ(ierr);
131795fce210SBarry Smith   PetscFunctionReturn(0);
131895fce210SBarry Smith }
131995fce210SBarry Smith 
132095fce210SBarry Smith /*@C
132195fce210SBarry Smith    PetscSFReduceEnd - end a reduction operation started with PetscSFReduceBegin()
132295fce210SBarry Smith 
132395fce210SBarry Smith    Collective
132495fce210SBarry Smith 
132595fce210SBarry Smith    Input Arguments:
132695fce210SBarry Smith +  sf - star forest
132795fce210SBarry Smith .  unit - data type
132895fce210SBarry Smith .  leafdata - values to reduce
132995fce210SBarry Smith -  op - reduction operation
133095fce210SBarry Smith 
133195fce210SBarry Smith    Output Arguments:
133295fce210SBarry Smith .  rootdata - result of reduction of values from all leaves of each root
133395fce210SBarry Smith 
133495fce210SBarry Smith    Level: intermediate
133595fce210SBarry Smith 
133695fce210SBarry Smith .seealso: PetscSFSetGraph(), PetscSFBcastEnd()
133795fce210SBarry Smith @*/
133895fce210SBarry Smith PetscErrorCode PetscSFReduceEnd(PetscSF sf,MPI_Datatype unit,const void *leafdata,void *rootdata,MPI_Op op)
133995fce210SBarry Smith {
134095fce210SBarry Smith   PetscErrorCode ierr;
134195fce210SBarry Smith 
134295fce210SBarry Smith   PetscFunctionBegin;
134395fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
134495fce210SBarry Smith   ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
134529046d53SLisandro Dalcin   ierr = PetscLogEventBegin(PETSCSF_ReduceEnd,sf,0,0,0);CHKERRQ(ierr);
134695fce210SBarry Smith   ierr = (*sf->ops->ReduceEnd)(sf,unit,leafdata,rootdata,op);CHKERRQ(ierr);
1347563ffbabSMatthew G. Knepley   ierr = PetscLogEventEnd(PETSCSF_ReduceEnd,sf,0,0,0);CHKERRQ(ierr);
134895fce210SBarry Smith   PetscFunctionReturn(0);
134995fce210SBarry Smith }
135095fce210SBarry Smith 
135195fce210SBarry Smith /*@C
135295fce210SBarry Smith    PetscSFComputeDegreeBegin - begin computation of degree for each root vertex, to be completed with PetscSFComputeDegreeEnd()
135395fce210SBarry Smith 
135495fce210SBarry Smith    Collective
135595fce210SBarry Smith 
135695fce210SBarry Smith    Input Arguments:
135795fce210SBarry Smith .  sf - star forest
135895fce210SBarry Smith 
135995fce210SBarry Smith    Output Arguments:
136095fce210SBarry Smith .  degree - degree of each root vertex
136195fce210SBarry Smith 
136295fce210SBarry Smith    Level: advanced
136395fce210SBarry Smith 
1364ffe67aa5SVáclav Hapla    Notes:
1365ffe67aa5SVáclav Hapla    The returned array is owned by PetscSF and automatically freed by PetscSFDestroy(). Hence no need to call PetscFree() on it.
1366ffe67aa5SVáclav Hapla 
136795fce210SBarry Smith .seealso: PetscSFGatherBegin()
136895fce210SBarry Smith @*/
136995fce210SBarry Smith PetscErrorCode PetscSFComputeDegreeBegin(PetscSF sf,const PetscInt **degree)
137095fce210SBarry Smith {
137195fce210SBarry Smith   PetscErrorCode ierr;
137295fce210SBarry Smith 
137395fce210SBarry Smith   PetscFunctionBegin;
137495fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
137595fce210SBarry Smith   PetscSFCheckGraphSet(sf,1);
137695fce210SBarry Smith   PetscValidPointer(degree,2);
1377803bd9e8SMatthew G. Knepley   if (!sf->degreeknown) {
137829046d53SLisandro Dalcin     PetscInt i, nroots = sf->nroots, maxlocal = sf->maxleaf+1;  /* TODO: We should use PetscSFGetLeafRange() */
1379803bd9e8SMatthew G. Knepley     if (sf->degree) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Calls to PetscSFComputeDegreeBegin() cannot be nested.");
138029046d53SLisandro Dalcin     ierr = PetscMalloc1(nroots,&sf->degree);CHKERRQ(ierr);
138129046d53SLisandro Dalcin     ierr = PetscMalloc1(PetscMax(maxlocal,1),&sf->degreetmp);CHKERRQ(ierr); /* allocate at least one entry, see check in PetscSFComputeDegreeEnd() */
138229046d53SLisandro Dalcin     for (i=0; i<nroots; i++) sf->degree[i] = 0;
13839837ea96SMatthew G. Knepley     for (i=0; i<maxlocal; i++) sf->degreetmp[i] = 1;
1384dbd2ff41SBarry Smith     ierr = PetscSFReduceBegin(sf,MPIU_INT,sf->degreetmp,sf->degree,MPI_SUM);CHKERRQ(ierr);
138595fce210SBarry Smith   }
138695fce210SBarry Smith   *degree = NULL;
138795fce210SBarry Smith   PetscFunctionReturn(0);
138895fce210SBarry Smith }
138995fce210SBarry Smith 
139095fce210SBarry Smith /*@C
139195fce210SBarry Smith    PetscSFComputeDegreeEnd - complete computation of degree for each root vertex, started with PetscSFComputeDegreeBegin()
139295fce210SBarry Smith 
139395fce210SBarry Smith    Collective
139495fce210SBarry Smith 
139595fce210SBarry Smith    Input Arguments:
139695fce210SBarry Smith .  sf - star forest
139795fce210SBarry Smith 
139895fce210SBarry Smith    Output Arguments:
139995fce210SBarry Smith .  degree - degree of each root vertex
140095fce210SBarry Smith 
140195fce210SBarry Smith    Level: developer
140295fce210SBarry Smith 
1403ffe67aa5SVáclav Hapla    Notes:
1404ffe67aa5SVáclav Hapla    The returned array is owned by PetscSF and automatically freed by PetscSFDestroy(). Hence no need to call PetscFree() on it.
1405ffe67aa5SVáclav Hapla 
140695fce210SBarry Smith .seealso:
140795fce210SBarry Smith @*/
140895fce210SBarry Smith PetscErrorCode PetscSFComputeDegreeEnd(PetscSF sf,const PetscInt **degree)
140995fce210SBarry Smith {
141095fce210SBarry Smith   PetscErrorCode ierr;
141195fce210SBarry Smith 
141295fce210SBarry Smith   PetscFunctionBegin;
141395fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
141495fce210SBarry Smith   PetscSFCheckGraphSet(sf,1);
141529046d53SLisandro Dalcin   PetscValidPointer(degree,2);
141695fce210SBarry Smith   if (!sf->degreeknown) {
141729046d53SLisandro Dalcin     if (!sf->degreetmp) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PetscSFComputeDegreeBegin() before PetscSFComputeDegreeEnd()");
1418dbd2ff41SBarry Smith     ierr = PetscSFReduceEnd(sf,MPIU_INT,sf->degreetmp,sf->degree,MPI_SUM);CHKERRQ(ierr);
141995fce210SBarry Smith     ierr = PetscFree(sf->degreetmp);CHKERRQ(ierr);
142095fce210SBarry Smith     sf->degreeknown = PETSC_TRUE;
142195fce210SBarry Smith   }
142295fce210SBarry Smith   *degree = sf->degree;
142395fce210SBarry Smith   PetscFunctionReturn(0);
142495fce210SBarry Smith }
142595fce210SBarry Smith 
1426673100f5SVaclav Hapla 
1427673100f5SVaclav Hapla /*@C
142866dfcd1aSVaclav Hapla    PetscSFComputeMultiRootOriginalNumbering - Returns original numbering of multi-roots (roots of multi-SF returned by PetscSFGetMultiSF()).
142966dfcd1aSVaclav Hapla    Each multi-root is assigned index of the corresponding original root.
1430673100f5SVaclav Hapla 
1431673100f5SVaclav Hapla    Collective
1432673100f5SVaclav Hapla 
1433673100f5SVaclav Hapla    Input Arguments:
1434673100f5SVaclav Hapla +  sf - star forest
1435673100f5SVaclav Hapla -  degree - degree of each root vertex, computed with PetscSFComputeDegreeBegin()/PetscSFComputeDegreeEnd()
1436673100f5SVaclav Hapla 
1437673100f5SVaclav Hapla    Output Arguments:
143866dfcd1aSVaclav Hapla +  nMultiRoots - (optional) number of multi-roots (roots of multi-SF)
143966dfcd1aSVaclav Hapla -  multiRootsOrigNumbering - original indices of multi-roots; length of this array is nMultiRoots
1440673100f5SVaclav Hapla 
1441673100f5SVaclav Hapla    Level: developer
1442673100f5SVaclav Hapla 
1443ffe67aa5SVáclav Hapla    Notes:
1444ffe67aa5SVáclav Hapla    The returned array multiRootsOrigNumbering is newly allocated and should be destroyed with PetscFree() when no longer needed.
1445ffe67aa5SVáclav Hapla 
1446673100f5SVaclav Hapla .seealso: PetscSFComputeDegreeBegin(), PetscSFComputeDegreeEnd(), PetscSFGetMultiSF()
1447673100f5SVaclav Hapla @*/
144866dfcd1aSVaclav Hapla PetscErrorCode PetscSFComputeMultiRootOriginalNumbering(PetscSF sf, const PetscInt degree[], PetscInt *nMultiRoots, PetscInt *multiRootsOrigNumbering[])
1449673100f5SVaclav Hapla {
1450673100f5SVaclav Hapla   PetscSF             msf;
1451673100f5SVaclav Hapla   PetscInt            i, j, k, nroots, nmroots;
1452673100f5SVaclav Hapla   PetscErrorCode      ierr;
1453673100f5SVaclav Hapla 
1454673100f5SVaclav Hapla   PetscFunctionBegin;
1455673100f5SVaclav Hapla   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
1456673100f5SVaclav Hapla   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
145729328920SVaclav Hapla   if (nroots) PetscValidIntPointer(degree,2);
145866dfcd1aSVaclav Hapla   if (nMultiRoots) PetscValidIntPointer(nMultiRoots,3);
145966dfcd1aSVaclav Hapla   PetscValidPointer(multiRootsOrigNumbering,4);
1460673100f5SVaclav Hapla   ierr = PetscSFGetMultiSF(sf,&msf);CHKERRQ(ierr);
1461673100f5SVaclav Hapla   ierr = PetscSFGetGraph(msf, &nmroots, NULL, NULL, NULL);CHKERRQ(ierr);
146266dfcd1aSVaclav Hapla   ierr = PetscMalloc1(nmroots, multiRootsOrigNumbering);CHKERRQ(ierr);
1463673100f5SVaclav Hapla   for (i=0,j=0,k=0; i<nroots; i++) {
1464673100f5SVaclav Hapla     if (!degree[i]) continue;
1465673100f5SVaclav Hapla     for (j=0; j<degree[i]; j++,k++) {
146666dfcd1aSVaclav Hapla       (*multiRootsOrigNumbering)[k] = i;
1467673100f5SVaclav Hapla     }
1468673100f5SVaclav Hapla   }
1469673100f5SVaclav Hapla #if defined(PETSC_USE_DEBUG)
1470673100f5SVaclav Hapla   if (PetscUnlikely(k != nmroots)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"sanity check fail");
1471673100f5SVaclav Hapla #endif
147266dfcd1aSVaclav Hapla   if (nMultiRoots) *nMultiRoots = nmroots;
1473673100f5SVaclav Hapla   PetscFunctionReturn(0);
1474673100f5SVaclav Hapla }
1475673100f5SVaclav Hapla 
147695fce210SBarry Smith /*@C
147795fce210SBarry Smith    PetscSFFetchAndOpBegin - begin operation that fetches values from root and updates atomically by applying operation using my leaf value, to be completed with PetscSFFetchAndOpEnd()
147895fce210SBarry Smith 
147995fce210SBarry Smith    Collective
148095fce210SBarry Smith 
148195fce210SBarry Smith    Input Arguments:
148295fce210SBarry Smith +  sf - star forest
148395fce210SBarry Smith .  unit - data type
148495fce210SBarry Smith .  leafdata - leaf values to use in reduction
148595fce210SBarry Smith -  op - operation to use for reduction
148695fce210SBarry Smith 
148795fce210SBarry Smith    Output Arguments:
148895fce210SBarry Smith +  rootdata - root values to be updated, input state is seen by first process to perform an update
148995fce210SBarry Smith -  leafupdate - state at each leaf's respective root immediately prior to my atomic update
149095fce210SBarry Smith 
149195fce210SBarry Smith    Level: advanced
149295fce210SBarry Smith 
149395fce210SBarry Smith    Note:
149495fce210SBarry Smith    The update is only atomic at the granularity provided by the hardware. Different roots referenced by the same process
149595fce210SBarry Smith    might be updated in a different order. Furthermore, if a composite type is used for the unit datatype, atomicity is
149695fce210SBarry Smith    not guaranteed across the whole vertex. Therefore, this function is mostly only used with primitive types such as
149795fce210SBarry Smith    integers.
149895fce210SBarry Smith 
149995fce210SBarry Smith .seealso: PetscSFComputeDegreeBegin(), PetscSFReduceBegin(), PetscSFSetGraph()
150095fce210SBarry Smith @*/
150195fce210SBarry Smith PetscErrorCode PetscSFFetchAndOpBegin(PetscSF sf,MPI_Datatype unit,void *rootdata,const void *leafdata,void *leafupdate,MPI_Op op)
150295fce210SBarry Smith {
150395fce210SBarry Smith   PetscErrorCode ierr;
150495fce210SBarry Smith 
150595fce210SBarry Smith   PetscFunctionBegin;
150695fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
150795fce210SBarry Smith   ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
150829046d53SLisandro Dalcin   ierr = PetscLogEventBegin(PETSCSF_FetchAndOpBegin,sf,0,0,0);CHKERRQ(ierr);
150995fce210SBarry Smith   ierr = (*sf->ops->FetchAndOpBegin)(sf,unit,rootdata,leafdata,leafupdate,op);CHKERRQ(ierr);
1510563ffbabSMatthew G. Knepley   ierr = PetscLogEventEnd(PETSCSF_FetchAndOpBegin,sf,0,0,0);CHKERRQ(ierr);
151195fce210SBarry Smith   PetscFunctionReturn(0);
151295fce210SBarry Smith }
151395fce210SBarry Smith 
151495fce210SBarry Smith /*@C
151595fce210SBarry Smith    PetscSFFetchAndOpEnd - end operation started in matching call to PetscSFFetchAndOpBegin() to fetch values from roots and update atomically by applying operation using my leaf value
151695fce210SBarry Smith 
151795fce210SBarry Smith    Collective
151895fce210SBarry Smith 
151995fce210SBarry Smith    Input Arguments:
152095fce210SBarry Smith +  sf - star forest
152195fce210SBarry Smith .  unit - data type
152295fce210SBarry Smith .  leafdata - leaf values to use in reduction
152395fce210SBarry Smith -  op - operation to use for reduction
152495fce210SBarry Smith 
152595fce210SBarry Smith    Output Arguments:
152695fce210SBarry Smith +  rootdata - root values to be updated, input state is seen by first process to perform an update
152795fce210SBarry Smith -  leafupdate - state at each leaf's respective root immediately prior to my atomic update
152895fce210SBarry Smith 
152995fce210SBarry Smith    Level: advanced
153095fce210SBarry Smith 
153195fce210SBarry Smith .seealso: PetscSFComputeDegreeEnd(), PetscSFReduceEnd(), PetscSFSetGraph()
153295fce210SBarry Smith @*/
153395fce210SBarry Smith PetscErrorCode PetscSFFetchAndOpEnd(PetscSF sf,MPI_Datatype unit,void *rootdata,const void *leafdata,void *leafupdate,MPI_Op op)
153495fce210SBarry Smith {
153595fce210SBarry Smith   PetscErrorCode ierr;
153695fce210SBarry Smith 
153795fce210SBarry Smith   PetscFunctionBegin;
153895fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
153995fce210SBarry Smith   ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
154029046d53SLisandro Dalcin   ierr = PetscLogEventBegin(PETSCSF_FetchAndOpEnd,sf,0,0,0);CHKERRQ(ierr);
154195fce210SBarry Smith   ierr = (*sf->ops->FetchAndOpEnd)(sf,unit,rootdata,leafdata,leafupdate,op);CHKERRQ(ierr);
1542563ffbabSMatthew G. Knepley   ierr = PetscLogEventEnd(PETSCSF_FetchAndOpEnd,sf,0,0,0);CHKERRQ(ierr);
154395fce210SBarry Smith   PetscFunctionReturn(0);
154495fce210SBarry Smith }
154595fce210SBarry Smith 
154695fce210SBarry Smith /*@C
154795fce210SBarry Smith    PetscSFGatherBegin - begin pointwise gather of all leaves into multi-roots, to be completed with PetscSFGatherEnd()
154895fce210SBarry Smith 
154995fce210SBarry Smith    Collective
155095fce210SBarry Smith 
155195fce210SBarry Smith    Input Arguments:
155295fce210SBarry Smith +  sf - star forest
155395fce210SBarry Smith .  unit - data type
155495fce210SBarry Smith -  leafdata - leaf data to gather to roots
155595fce210SBarry Smith 
155695fce210SBarry Smith    Output Argument:
155795fce210SBarry Smith .  multirootdata - root buffer to gather into, amount of space per root is equal to its degree
155895fce210SBarry Smith 
155995fce210SBarry Smith    Level: intermediate
156095fce210SBarry Smith 
156195fce210SBarry Smith .seealso: PetscSFComputeDegreeBegin(), PetscSFScatterBegin()
156295fce210SBarry Smith @*/
156395fce210SBarry Smith PetscErrorCode PetscSFGatherBegin(PetscSF sf,MPI_Datatype unit,const void *leafdata,void *multirootdata)
156495fce210SBarry Smith {
156595fce210SBarry Smith   PetscErrorCode ierr;
156695fce210SBarry Smith   PetscSF        multi;
156795fce210SBarry Smith 
156895fce210SBarry Smith   PetscFunctionBegin;
156995fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
157029046d53SLisandro Dalcin   ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
157195fce210SBarry Smith   ierr = PetscSFGetMultiSF(sf,&multi);CHKERRQ(ierr);
15728bfbc91cSJed Brown   ierr = PetscSFReduceBegin(multi,unit,leafdata,multirootdata,MPIU_REPLACE);CHKERRQ(ierr);
157395fce210SBarry Smith   PetscFunctionReturn(0);
157495fce210SBarry Smith }
157595fce210SBarry Smith 
157695fce210SBarry Smith /*@C
157795fce210SBarry Smith    PetscSFGatherEnd - ends pointwise gather operation that was started with PetscSFGatherBegin()
157895fce210SBarry Smith 
157995fce210SBarry Smith    Collective
158095fce210SBarry Smith 
158195fce210SBarry Smith    Input Arguments:
158295fce210SBarry Smith +  sf - star forest
158395fce210SBarry Smith .  unit - data type
158495fce210SBarry Smith -  leafdata - leaf data to gather to roots
158595fce210SBarry Smith 
158695fce210SBarry Smith    Output Argument:
158795fce210SBarry Smith .  multirootdata - root buffer to gather into, amount of space per root is equal to its degree
158895fce210SBarry Smith 
158995fce210SBarry Smith    Level: intermediate
159095fce210SBarry Smith 
159195fce210SBarry Smith .seealso: PetscSFComputeDegreeEnd(), PetscSFScatterEnd()
159295fce210SBarry Smith @*/
159395fce210SBarry Smith PetscErrorCode PetscSFGatherEnd(PetscSF sf,MPI_Datatype unit,const void *leafdata,void *multirootdata)
159495fce210SBarry Smith {
159595fce210SBarry Smith   PetscErrorCode ierr;
159695fce210SBarry Smith   PetscSF        multi;
159795fce210SBarry Smith 
159895fce210SBarry Smith   PetscFunctionBegin;
159995fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
160095fce210SBarry Smith   ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
160195fce210SBarry Smith   ierr = PetscSFGetMultiSF(sf,&multi);CHKERRQ(ierr);
16028bfbc91cSJed Brown   ierr = PetscSFReduceEnd(multi,unit,leafdata,multirootdata,MPIU_REPLACE);CHKERRQ(ierr);
160395fce210SBarry Smith   PetscFunctionReturn(0);
160495fce210SBarry Smith }
160595fce210SBarry Smith 
160695fce210SBarry Smith /*@C
160795fce210SBarry Smith    PetscSFScatterBegin - begin pointwise scatter operation from multi-roots to leaves, to be completed with PetscSFScatterEnd()
160895fce210SBarry Smith 
160995fce210SBarry Smith    Collective
161095fce210SBarry Smith 
161195fce210SBarry Smith    Input Arguments:
161295fce210SBarry Smith +  sf - star forest
161395fce210SBarry Smith .  unit - data type
161495fce210SBarry Smith -  multirootdata - root buffer to send to each leaf, one unit of data per leaf
161595fce210SBarry Smith 
161695fce210SBarry Smith    Output Argument:
161795fce210SBarry Smith .  leafdata - leaf data to be update with personal data from each respective root
161895fce210SBarry Smith 
161995fce210SBarry Smith    Level: intermediate
162095fce210SBarry Smith 
162195fce210SBarry Smith .seealso: PetscSFComputeDegreeBegin(), PetscSFScatterBegin()
162295fce210SBarry Smith @*/
162395fce210SBarry Smith PetscErrorCode PetscSFScatterBegin(PetscSF sf,MPI_Datatype unit,const void *multirootdata,void *leafdata)
162495fce210SBarry Smith {
162595fce210SBarry Smith   PetscErrorCode ierr;
162695fce210SBarry Smith   PetscSF        multi;
162795fce210SBarry Smith 
162895fce210SBarry Smith   PetscFunctionBegin;
162995fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
163095fce210SBarry Smith   ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
163195fce210SBarry Smith   ierr = PetscSFGetMultiSF(sf,&multi);CHKERRQ(ierr);
163295fce210SBarry Smith   ierr = PetscSFBcastBegin(multi,unit,multirootdata,leafdata);CHKERRQ(ierr);
163395fce210SBarry Smith   PetscFunctionReturn(0);
163495fce210SBarry Smith }
163595fce210SBarry Smith 
163695fce210SBarry Smith /*@C
163795fce210SBarry Smith    PetscSFScatterEnd - ends pointwise scatter operation that was started with PetscSFScatterBegin()
163895fce210SBarry Smith 
163995fce210SBarry Smith    Collective
164095fce210SBarry Smith 
164195fce210SBarry Smith    Input Arguments:
164295fce210SBarry Smith +  sf - star forest
164395fce210SBarry Smith .  unit - data type
164495fce210SBarry Smith -  multirootdata - root buffer to send to each leaf, one unit of data per leaf
164595fce210SBarry Smith 
164695fce210SBarry Smith    Output Argument:
164795fce210SBarry Smith .  leafdata - leaf data to be update with personal data from each respective root
164895fce210SBarry Smith 
164995fce210SBarry Smith    Level: intermediate
165095fce210SBarry Smith 
165195fce210SBarry Smith .seealso: PetscSFComputeDegreeEnd(), PetscSFScatterEnd()
165295fce210SBarry Smith @*/
165395fce210SBarry Smith PetscErrorCode PetscSFScatterEnd(PetscSF sf,MPI_Datatype unit,const void *multirootdata,void *leafdata)
165495fce210SBarry Smith {
165595fce210SBarry Smith   PetscErrorCode ierr;
165695fce210SBarry Smith   PetscSF        multi;
165795fce210SBarry Smith 
165895fce210SBarry Smith   PetscFunctionBegin;
165995fce210SBarry Smith   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
166095fce210SBarry Smith   ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
166195fce210SBarry Smith   ierr = PetscSFGetMultiSF(sf,&multi);CHKERRQ(ierr);
166295fce210SBarry Smith   ierr = PetscSFBcastEnd(multi,unit,multirootdata,leafdata);CHKERRQ(ierr);
166395fce210SBarry Smith   PetscFunctionReturn(0);
166495fce210SBarry Smith }
1665a7b3aa13SAta Mesgarnejad 
1666a7b3aa13SAta Mesgarnejad /*@
166704c0ada0SJunchao Zhang   PetscSFCompose - Compose a new PetscSF by putting the second SF under the first one in a top (roots) down (leaves) view
1668a7b3aa13SAta Mesgarnejad 
1669a7b3aa13SAta Mesgarnejad   Input Parameters:
167004c0ada0SJunchao Zhang + sfA - The first PetscSF, whose local space may be a permutation, but can not be sparse.
167104c0ada0SJunchao Zhang - sfB - The second PetscSF, whose number of roots must be equal to number of leaves of sfA on each processor
1672a7b3aa13SAta Mesgarnejad 
1673a7b3aa13SAta Mesgarnejad   Output Parameters:
167404c0ada0SJunchao Zhang . sfBA - The composite SF. Doing a Bcast on the new SF is equvalent to doing Bcast on sfA, then Bcast on sfB
1675a7b3aa13SAta Mesgarnejad 
1676a7b3aa13SAta Mesgarnejad   Level: developer
1677a7b3aa13SAta Mesgarnejad 
167804c0ada0SJunchao Zhang .seealso: PetscSF, PetscSFComposeInverse(), PetscSFGetGraph(), PetscSFSetGraph()
1679a7b3aa13SAta Mesgarnejad @*/
1680a7b3aa13SAta Mesgarnejad PetscErrorCode PetscSFCompose(PetscSF sfA,PetscSF sfB,PetscSF *sfBA)
1681a7b3aa13SAta Mesgarnejad {
168204c0ada0SJunchao Zhang   PetscErrorCode    ierr;
1683a7b3aa13SAta Mesgarnejad   MPI_Comm          comm;
1684a7b3aa13SAta Mesgarnejad   const PetscSFNode *remotePointsA,*remotePointsB;
1685*d41018fbSJunchao Zhang   PetscSFNode       *remotePointsBA=NULL,*reorderedRemotePointsA = NULL,*leafdataB;
1686*d41018fbSJunchao Zhang   const PetscInt    *localPointsA,*localPointsB,*localPointsBA;
1687*d41018fbSJunchao Zhang   PetscInt          i,numRootsA,numLeavesA,numRootsB,numLeavesB,minleaf,maxleaf;
1688a7b3aa13SAta Mesgarnejad 
1689a7b3aa13SAta Mesgarnejad   PetscFunctionBegin;
1690a7b3aa13SAta Mesgarnejad   PetscValidHeaderSpecific(sfA,PETSCSF_CLASSID,1);
169129046d53SLisandro Dalcin   PetscSFCheckGraphSet(sfA,1);
169229046d53SLisandro Dalcin   PetscValidHeaderSpecific(sfB,PETSCSF_CLASSID,2);
169329046d53SLisandro Dalcin   PetscSFCheckGraphSet(sfB,2);
169429046d53SLisandro Dalcin   PetscValidPointer(sfBA,3);
1695a7b3aa13SAta Mesgarnejad   ierr = PetscObjectGetComm((PetscObject)sfA,&comm);CHKERRQ(ierr);
1696a7b3aa13SAta Mesgarnejad   ierr = PetscSFGetGraph(sfA,&numRootsA,&numLeavesA,&localPointsA,&remotePointsA);CHKERRQ(ierr);
1697a7b3aa13SAta Mesgarnejad   ierr = PetscSFGetGraph(sfB,&numRootsB,&numLeavesB,&localPointsB,&remotePointsB);CHKERRQ(ierr);
169804c0ada0SJunchao Zhang   ierr = PetscSFGetLeafRange(sfA,&minleaf,&maxleaf);CHKERRQ(ierr);
1699*d41018fbSJunchao Zhang   if (maxleaf+1 != numLeavesA || minleaf) SETERRQ(comm,PETSC_ERR_ARG_INCOMP,"The first SF can not have sparse local space");
170004c0ada0SJunchao Zhang   if (numRootsB != numLeavesA) SETERRQ(comm,PETSC_ERR_ARG_INCOMP,"The second SF's number of roots must be equal to the first SF's number of leaves");
1701*d41018fbSJunchao Zhang   if (localPointsA) {
1702*d41018fbSJunchao Zhang     /* Local space is dense permutation of identity. Need to rewire order of the remote points */
1703*d41018fbSJunchao Zhang     ierr = PetscMalloc1(numLeavesA,&reorderedRemotePointsA);CHKERRQ(ierr);
1704*d41018fbSJunchao Zhang     for (i=0; i<numLeavesA; i++) reorderedRemotePointsA[localPointsA[i]-minleaf] = remotePointsA[i];
1705*d41018fbSJunchao Zhang     remotePointsA = reorderedRemotePointsA;
1706*d41018fbSJunchao Zhang   }
1707*d41018fbSJunchao Zhang   ierr = PetscSFGetLeafRange(sfB,&minleaf,&maxleaf);CHKERRQ(ierr);
1708*d41018fbSJunchao Zhang   ierr = PetscMalloc1(maxleaf-minleaf+1,&leafdataB);CHKERRQ(ierr);
1709*d41018fbSJunchao Zhang   ierr = PetscSFBcastBegin(sfB,MPIU_2INT,remotePointsA,leafdataB-minleaf);CHKERRQ(ierr);
1710*d41018fbSJunchao Zhang   ierr = PetscSFBcastEnd(sfB,MPIU_2INT,remotePointsA,leafdataB-minleaf);CHKERRQ(ierr);
1711*d41018fbSJunchao Zhang   ierr = PetscFree(reorderedRemotePointsA);CHKERRQ(ierr);
1712*d41018fbSJunchao Zhang 
1713*d41018fbSJunchao Zhang   if (minleaf == 0 && maxleaf + 1 == numLeavesB) { /* Local space of sfB is an identity or permutation */
1714*d41018fbSJunchao Zhang     localPointsBA  = NULL;
1715*d41018fbSJunchao Zhang     remotePointsBA = leafdataB;
1716*d41018fbSJunchao Zhang   } else {
1717*d41018fbSJunchao Zhang     localPointsBA  = localPointsB;
1718a7b3aa13SAta Mesgarnejad     ierr = PetscMalloc1(numLeavesB,&remotePointsBA);CHKERRQ(ierr);
1719*d41018fbSJunchao Zhang     for (i=0; i<numLeavesB; i++) remotePointsBA[i] = leafdataB[localPointsB[i]-minleaf];
1720*d41018fbSJunchao Zhang     ierr = PetscFree(leafdataB);CHKERRQ(ierr);
1721*d41018fbSJunchao Zhang   }
1722a7b3aa13SAta Mesgarnejad   ierr = PetscSFCreate(comm, sfBA);CHKERRQ(ierr);
1723*d41018fbSJunchao Zhang   ierr = PetscSFSetGraph(*sfBA,numRootsA,numLeavesB,localPointsBA,PETSC_COPY_VALUES,remotePointsBA,PETSC_OWN_POINTER);CHKERRQ(ierr);
1724a7b3aa13SAta Mesgarnejad   PetscFunctionReturn(0);
1725a7b3aa13SAta Mesgarnejad }
17261c6ba672SJunchao Zhang 
172704c0ada0SJunchao Zhang /*@
172804c0ada0SJunchao Zhang   PetscSFComposeInverse - Compose a new PetscSF by putting inverse of the second SF under the first one
172904c0ada0SJunchao Zhang 
173004c0ada0SJunchao Zhang   Input Parameters:
173104c0ada0SJunchao Zhang + sfA - The first PetscSF, whose local space may be a permutation, but can not be sparse.
173204c0ada0SJunchao Zhang - sfB - The second PetscSF, whose number of leaves must be equal to number of leaves of sfA on each processor. All roots must have degree 1.
173304c0ada0SJunchao Zhang 
173404c0ada0SJunchao Zhang   Output Parameters:
173504c0ada0SJunchao Zhang . sfBA - The composite SF. Doing a Bcast on the new SF is equvalent to doing Bcast on sfA, then Bcast on inverse of sfB
173604c0ada0SJunchao Zhang 
173704c0ada0SJunchao Zhang   Level: developer
173804c0ada0SJunchao Zhang 
173904c0ada0SJunchao Zhang .seealso: PetscSF, PetscSFCompose(), PetscSFGetGraph(), PetscSFSetGraph()
174004c0ada0SJunchao Zhang @*/
174104c0ada0SJunchao Zhang PetscErrorCode PetscSFComposeInverse(PetscSF sfA,PetscSF sfB,PetscSF *sfBA)
174204c0ada0SJunchao Zhang {
174304c0ada0SJunchao Zhang   PetscErrorCode    ierr;
174404c0ada0SJunchao Zhang   MPI_Comm          comm;
174504c0ada0SJunchao Zhang   const PetscSFNode *remotePointsA,*remotePointsB;
174604c0ada0SJunchao Zhang   PetscSFNode       *remotePointsBA;
174704c0ada0SJunchao Zhang   const PetscInt    *localPointsA,*localPointsB;
174804c0ada0SJunchao Zhang   PetscInt          numRootsA,numLeavesA,numRootsB,numLeavesB,minleaf,maxleaf;
174904c0ada0SJunchao Zhang 
175004c0ada0SJunchao Zhang   PetscFunctionBegin;
175104c0ada0SJunchao Zhang   PetscValidHeaderSpecific(sfA,PETSCSF_CLASSID,1);
175204c0ada0SJunchao Zhang   PetscSFCheckGraphSet(sfA,1);
175304c0ada0SJunchao Zhang   PetscValidHeaderSpecific(sfB,PETSCSF_CLASSID,2);
175404c0ada0SJunchao Zhang   PetscSFCheckGraphSet(sfB,2);
175504c0ada0SJunchao Zhang   PetscValidPointer(sfBA,3);
175604c0ada0SJunchao Zhang   ierr = PetscObjectGetComm((PetscObject) sfA, &comm);CHKERRQ(ierr);
175704c0ada0SJunchao Zhang   ierr = PetscSFGetGraph(sfA, &numRootsA, &numLeavesA, &localPointsA, &remotePointsA);CHKERRQ(ierr);
175804c0ada0SJunchao Zhang   ierr = PetscSFGetGraph(sfB, &numRootsB, &numLeavesB, &localPointsB, &remotePointsB);CHKERRQ(ierr);
175904c0ada0SJunchao Zhang   ierr = PetscSFGetLeafRange(sfA,&minleaf,&maxleaf);CHKERRQ(ierr);
176004c0ada0SJunchao Zhang   if (maxleaf+1-minleaf != numLeavesA) SETERRQ(comm,PETSC_ERR_ARG_INCOMP,"The first SF can not have sparse local space");
176104c0ada0SJunchao Zhang   if (numLeavesA != numLeavesB) SETERRQ(comm,PETSC_ERR_ARG_INCOMP,"The second SF's number of leaves must be equal to the first SF's number of leaves");
176204c0ada0SJunchao Zhang   ierr = PetscMalloc1(numRootsB,&remotePointsBA);CHKERRQ(ierr);
176304c0ada0SJunchao Zhang   ierr = PetscSFReduceBegin(sfB,MPIU_2INT,remotePointsA,remotePointsBA,MPIU_REPLACE);CHKERRQ(ierr);
176404c0ada0SJunchao Zhang   ierr = PetscSFReduceEnd(sfB,MPIU_2INT,remotePointsA,remotePointsBA,MPIU_REPLACE);CHKERRQ(ierr);
176504c0ada0SJunchao Zhang   ierr = PetscSFCreate(comm,sfBA);CHKERRQ(ierr);
176604c0ada0SJunchao Zhang   ierr = PetscSFSetGraph(*sfBA,numRootsA,numRootsB,NULL,PETSC_COPY_VALUES,remotePointsBA,PETSC_OWN_POINTER);CHKERRQ(ierr);
176704c0ada0SJunchao Zhang   PetscFunctionReturn(0);
176804c0ada0SJunchao Zhang }
176904c0ada0SJunchao Zhang 
17701c6ba672SJunchao Zhang /*
17711c6ba672SJunchao Zhang   PetscSFCreateLocalSF_Private - Creates a local PetscSF that only has intra-process edges of the global PetscSF
17721c6ba672SJunchao Zhang 
17731c6ba672SJunchao Zhang   Input Parameters:
17741c6ba672SJunchao Zhang . sf - The global PetscSF
17751c6ba672SJunchao Zhang 
17761c6ba672SJunchao Zhang   Output Parameters:
17771c6ba672SJunchao Zhang . out - The local PetscSF
17781c6ba672SJunchao Zhang  */
17791c6ba672SJunchao Zhang PetscErrorCode PetscSFCreateLocalSF_Private(PetscSF sf,PetscSF *out)
17801c6ba672SJunchao Zhang {
17811c6ba672SJunchao Zhang   MPI_Comm           comm;
17821c6ba672SJunchao Zhang   PetscMPIInt        myrank;
17831c6ba672SJunchao Zhang   const PetscInt     *ilocal;
17841c6ba672SJunchao Zhang   const PetscSFNode  *iremote;
17851c6ba672SJunchao Zhang   PetscInt           i,j,nroots,nleaves,lnleaves,*lilocal;
17861c6ba672SJunchao Zhang   PetscSFNode        *liremote;
17871c6ba672SJunchao Zhang   PetscSF            lsf;
17881c6ba672SJunchao Zhang   PetscErrorCode     ierr;
17891c6ba672SJunchao Zhang 
17901c6ba672SJunchao Zhang   PetscFunctionBegin;
17911c6ba672SJunchao Zhang   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
17921c6ba672SJunchao Zhang   if (sf->ops->CreateLocalSF) {
17931c6ba672SJunchao Zhang     ierr = (*sf->ops->CreateLocalSF)(sf,out);CHKERRQ(ierr);
17941c6ba672SJunchao Zhang   } else {
17951c6ba672SJunchao Zhang     /* Could use PetscSFCreateEmbeddedLeafSF, but since we know the comm is PETSC_COMM_SELF, we can make it fast */
17961c6ba672SJunchao Zhang     ierr = PetscObjectGetComm((PetscObject)sf,&comm);CHKERRQ(ierr);
17971c6ba672SJunchao Zhang     ierr = MPI_Comm_rank(comm,&myrank);CHKERRQ(ierr);
17981c6ba672SJunchao Zhang 
17991c6ba672SJunchao Zhang     /* Find out local edges and build a local SF */
18001c6ba672SJunchao Zhang     ierr = PetscSFGetGraph(sf,&nroots,&nleaves,&ilocal,&iremote);CHKERRQ(ierr);
18011c6ba672SJunchao Zhang     for (i=lnleaves=0; i<nleaves; i++) {if (iremote[i].rank == (PetscInt)myrank) lnleaves++;}
18021c6ba672SJunchao Zhang     ierr = PetscMalloc1(lnleaves,&lilocal);CHKERRQ(ierr);
18031c6ba672SJunchao Zhang     ierr = PetscMalloc1(lnleaves,&liremote);CHKERRQ(ierr);
18041c6ba672SJunchao Zhang 
18051c6ba672SJunchao Zhang     for (i=j=0; i<nleaves; i++) {
18061c6ba672SJunchao Zhang       if (iremote[i].rank == (PetscInt)myrank) {
18071c6ba672SJunchao Zhang         lilocal[j]        = ilocal? ilocal[i] : i; /* ilocal=NULL for contiguous storage */
18081c6ba672SJunchao Zhang         liremote[j].rank  = 0; /* rank in PETSC_COMM_SELF */
18091c6ba672SJunchao Zhang         liremote[j].index = iremote[i].index;
18101c6ba672SJunchao Zhang         j++;
18111c6ba672SJunchao Zhang       }
18121c6ba672SJunchao Zhang     }
18131c6ba672SJunchao Zhang     ierr = PetscSFCreate(PETSC_COMM_SELF,&lsf);CHKERRQ(ierr);
18141c6ba672SJunchao Zhang     ierr = PetscSFSetGraph(lsf,nroots,lnleaves,lilocal,PETSC_OWN_POINTER,liremote,PETSC_OWN_POINTER);CHKERRQ(ierr);
18151c6ba672SJunchao Zhang     ierr = PetscSFSetUp(lsf);CHKERRQ(ierr);
18161c6ba672SJunchao Zhang     *out = lsf;
18171c6ba672SJunchao Zhang   }
18181c6ba672SJunchao Zhang   PetscFunctionReturn(0);
18191c6ba672SJunchao Zhang }
1820dd5b3ca6SJunchao Zhang 
1821dd5b3ca6SJunchao Zhang /* Similar to PetscSFBcast, but only Bcast to leaves on rank 0 */
1822dd5b3ca6SJunchao Zhang PetscErrorCode PetscSFBcastToZero_Private(PetscSF sf,MPI_Datatype unit,const void *rootdata,void *leafdata)
1823dd5b3ca6SJunchao Zhang {
1824dd5b3ca6SJunchao Zhang   PetscErrorCode     ierr;
1825dd5b3ca6SJunchao Zhang 
1826dd5b3ca6SJunchao Zhang   PetscFunctionBegin;
1827dd5b3ca6SJunchao Zhang   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
1828dd5b3ca6SJunchao Zhang   ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
1829dd5b3ca6SJunchao Zhang   ierr = PetscLogEventBegin(PETSCSF_BcastAndOpBegin,sf,0,0,0);CHKERRQ(ierr);
1830dd5b3ca6SJunchao Zhang   if (sf->ops->BcastToZero) {
1831dd5b3ca6SJunchao Zhang     ierr = (*sf->ops->BcastToZero)(sf,unit,rootdata,leafdata);CHKERRQ(ierr);
1832dd5b3ca6SJunchao Zhang   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"PetscSFBcastToZero_Private is not supported on this SF type");
1833dd5b3ca6SJunchao Zhang   ierr = PetscLogEventEnd(PETSCSF_BcastAndOpBegin,sf,0,0,0);CHKERRQ(ierr);
1834dd5b3ca6SJunchao Zhang   PetscFunctionReturn(0);
1835dd5b3ca6SJunchao Zhang }
1836dd5b3ca6SJunchao Zhang 
1837