xref: /petsc/src/vec/is/sf/impls/basic/sfbasic.c (revision b7c0d12a26d4b426015009c8f0a095fd1bca8609)
18cd53115SBarry Smith 
240e23c03SJunchao Zhang #include <../src/vec/is/sf/impls/basic/sfbasic.h>
395fce210SBarry Smith 
440e23c03SJunchao Zhang /*===================================================================================*/
5eb02082bSJunchao Zhang /*              Internal routines for PetscSFPack                              */
640e23c03SJunchao Zhang /*===================================================================================*/
795fce210SBarry Smith 
840e23c03SJunchao Zhang /* Return root and leaf MPI requests for communication in the given direction. If the requests have not been
940e23c03SJunchao Zhang    initialized (since we use persistent requests), then initialize them.
1095fce210SBarry Smith */
11eb02082bSJunchao Zhang static PetscErrorCode PetscSFPackGetReqs_Basic(PetscSF sf,PetscSFPack link,PetscSFDirection direction,MPI_Request **rootreqs,MPI_Request **leafreqs)
1240e23c03SJunchao Zhang {
13b23bfdefSJunchao Zhang   PetscErrorCode ierr;
1440e23c03SJunchao Zhang   PetscSF_Basic  *bas = (PetscSF_Basic*)sf->data;
15b23bfdefSJunchao Zhang   PetscInt       i,j,nrootranks,ndrootranks,nleafranks,ndleafranks,disp;
1640e23c03SJunchao Zhang   const PetscInt *rootoffset,*leafoffset;
1740e23c03SJunchao Zhang   PetscMPIInt    n;
1840e23c03SJunchao Zhang   MPI_Comm       comm = PetscObjectComm((PetscObject)sf);
19eb02082bSJunchao Zhang   MPI_Datatype   unit = link->unit;
20120a1823SJunchao Zhang   PetscMemType   rootmtype,leafmtype;
2195fce210SBarry Smith 
2240e23c03SJunchao Zhang   PetscFunctionBegin;
23120a1823SJunchao Zhang   if (use_gpu_aware_mpi) {
24120a1823SJunchao Zhang     rootmtype = link->rootmtype;
25120a1823SJunchao Zhang     leafmtype = link->leafmtype;
26120a1823SJunchao Zhang   } else {
27120a1823SJunchao Zhang     rootmtype = PETSC_MEMTYPE_HOST;
28120a1823SJunchao Zhang     leafmtype = PETSC_MEMTYPE_HOST;
29120a1823SJunchao Zhang   }
30120a1823SJunchao Zhang 
31eb02082bSJunchao Zhang   if (rootreqs && !link->rootreqsinited[direction][rootmtype]) {
3240e23c03SJunchao Zhang     ierr = PetscSFGetRootInfo_Basic(sf,&nrootranks,&ndrootranks,NULL,&rootoffset,NULL);CHKERRQ(ierr);
3340e23c03SJunchao Zhang     if (direction == PETSCSF_LEAF2ROOT_REDUCE) {
34eb02082bSJunchao Zhang       for (i=ndrootranks,j=0; i<nrootranks; i++,j++) {
35b23bfdefSJunchao Zhang         disp = (rootoffset[i] - rootoffset[ndrootranks])*link->unitbytes;
3640e23c03SJunchao Zhang         ierr = PetscMPIIntCast(rootoffset[i+1]-rootoffset[i],&n);CHKERRQ(ierr);
37eb02082bSJunchao Zhang         ierr = MPI_Recv_init(link->rootbuf[rootmtype]+disp,n,unit,bas->iranks[i],link->tag,comm,&link->rootreqs[direction][rootmtype][j]);CHKERRQ(ierr);
3840e23c03SJunchao Zhang       }
3940e23c03SJunchao Zhang     } else if (direction == PETSCSF_ROOT2LEAF_BCAST) {
40eb02082bSJunchao Zhang       for (i=ndrootranks,j=0; i<nrootranks; i++,j++) {
41b23bfdefSJunchao Zhang         disp = (rootoffset[i] - rootoffset[ndrootranks])*link->unitbytes;
4240e23c03SJunchao Zhang         ierr = PetscMPIIntCast(rootoffset[i+1]-rootoffset[i],&n);CHKERRQ(ierr);
43eb02082bSJunchao Zhang         ierr = MPI_Send_init(link->rootbuf[rootmtype]+disp,n,unit,bas->iranks[i],link->tag,comm,&link->rootreqs[direction][rootmtype][j]);CHKERRQ(ierr);
4440e23c03SJunchao Zhang       }
45eb02082bSJunchao Zhang     } else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Out-of-range PetscSFDirection = %d\n",(int)direction);
46eb02082bSJunchao Zhang     link->rootreqsinited[direction][rootmtype] = PETSC_TRUE;
47eb02082bSJunchao Zhang   }
48eb02082bSJunchao Zhang 
49eb02082bSJunchao Zhang   if (leafreqs && !link->leafreqsinited[direction][leafmtype]) {
50eb02082bSJunchao Zhang     ierr = PetscSFGetLeafInfo_Basic(sf,&nleafranks,&ndleafranks,NULL,&leafoffset,NULL,NULL);CHKERRQ(ierr);
51eb02082bSJunchao Zhang     if (direction == PETSCSF_LEAF2ROOT_REDUCE) {
52eb02082bSJunchao Zhang       for (i=ndleafranks,j=0; i<nleafranks; i++,j++) {
53b23bfdefSJunchao Zhang         disp = (leafoffset[i] - leafoffset[ndleafranks])*link->unitbytes;
5440e23c03SJunchao Zhang         ierr = PetscMPIIntCast(leafoffset[i+1]-leafoffset[i],&n);CHKERRQ(ierr);
55eb02082bSJunchao Zhang         ierr = MPI_Send_init(link->leafbuf[leafmtype]+disp,n,unit,sf->ranks[i],link->tag,comm,&link->leafreqs[direction][leafmtype][j]);CHKERRQ(ierr);
5640e23c03SJunchao Zhang       }
57eb02082bSJunchao Zhang     } else if (direction == PETSCSF_ROOT2LEAF_BCAST) {
58eb02082bSJunchao Zhang       for (i=ndleafranks,j=0; i<nleafranks; i++,j++) {
59eb02082bSJunchao Zhang         disp = (leafoffset[i] - leafoffset[ndleafranks])*link->unitbytes;
60eb02082bSJunchao Zhang         ierr = PetscMPIIntCast(leafoffset[i+1]-leafoffset[i],&n);CHKERRQ(ierr);
61eb02082bSJunchao Zhang         ierr = MPI_Recv_init(link->leafbuf[leafmtype]+disp,n,unit,sf->ranks[i],link->tag,comm,&link->leafreqs[direction][leafmtype][j]);CHKERRQ(ierr);
62eb02082bSJunchao Zhang       }
63eb02082bSJunchao Zhang     } else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Out-of-range PetscSFDirection = %d\n",(int)direction);
64eb02082bSJunchao Zhang     link->leafreqsinited[direction][leafmtype] = PETSC_TRUE;
6595fce210SBarry Smith   }
6695fce210SBarry Smith 
67eb02082bSJunchao Zhang   if (rootreqs) *rootreqs = link->rootreqs[direction][rootmtype];
68eb02082bSJunchao Zhang   if (leafreqs) *leafreqs = link->leafreqs[direction][leafmtype];
6940e23c03SJunchao Zhang   PetscFunctionReturn(0);
7095fce210SBarry Smith }
7195fce210SBarry Smith 
72b23bfdefSJunchao Zhang /* Common part shared by SFBasic and SFNeighbor based on the fact they all deal with sparse graphs. */
73eb02082bSJunchao Zhang PETSC_INTERN PetscErrorCode PetscSFPackGet_Basic_Common(PetscSF sf,MPI_Datatype unit,PetscMemType rootmtype,const void *rootdata,PetscMemType leafmtype,const void *leafdata,PetscInt nrootreqs,PetscInt nleafreqs,PetscSFPack *mylink)
7440e23c03SJunchao Zhang {
7540e23c03SJunchao Zhang   PetscErrorCode    ierr;
76b23bfdefSJunchao Zhang   PetscSF_Basic     *bas = (PetscSF_Basic*)sf->data;
77eb02082bSJunchao Zhang   PetscInt          i,j,nreqs,nrootranks,ndrootranks,nleafranks,ndleafranks;
7840e23c03SJunchao Zhang   const PetscInt    *rootoffset,*leafoffset;
79eb02082bSJunchao Zhang   PetscSFPack       *p,link;
80b23bfdefSJunchao Zhang   PetscBool         match;
8140e23c03SJunchao Zhang 
8240e23c03SJunchao Zhang   PetscFunctionBegin;
83b23bfdefSJunchao Zhang   ierr = PetscSFPackSetErrorOnUnsupportedOverlap(sf,unit,rootdata,leafdata);CHKERRQ(ierr);
849d1c8addSJunchao Zhang 
8540e23c03SJunchao Zhang   /* Look for types in cache */
86eb02082bSJunchao Zhang   for (p=&bas->avail; (link=*p); p=&link->next) {
8740e23c03SJunchao Zhang     ierr = MPIPetsc_Type_compare(unit,link->unit,&match);CHKERRQ(ierr);
8840e23c03SJunchao Zhang     if (match) {
8940e23c03SJunchao Zhang       *p = link->next; /* Remove from available list */
9040e23c03SJunchao Zhang       goto found;
9140e23c03SJunchao Zhang     }
9253deab39SPeter Brune   }
9353deab39SPeter Brune 
9440e23c03SJunchao Zhang   ierr = PetscSFGetRootInfo_Basic(sf,&nrootranks,&ndrootranks,NULL,&rootoffset,NULL);CHKERRQ(ierr);
9540e23c03SJunchao Zhang   ierr = PetscSFGetLeafInfo_Basic(sf,&nleafranks,&ndleafranks,NULL,&leafoffset,NULL,NULL);CHKERRQ(ierr);
9640e23c03SJunchao Zhang   ierr = PetscNew(&link);CHKERRQ(ierr);
97eb02082bSJunchao Zhang   ierr = PetscSFPackSetUp_Host(sf,link,unit);CHKERRQ(ierr);
98b23bfdefSJunchao Zhang   ierr = PetscCommGetNewTag(PetscObjectComm((PetscObject)sf),&link->tag);CHKERRQ(ierr); /* One tag per link */
9953deab39SPeter Brune 
100eb02082bSJunchao Zhang   /* Allocate root, leaf, self buffers, and MPI requests */
101eb02082bSJunchao Zhang   link->rootbuflen = rootoffset[nrootranks]-rootoffset[ndrootranks];
102eb02082bSJunchao Zhang   link->leafbuflen = leafoffset[nleafranks]-leafoffset[ndleafranks];
103eb02082bSJunchao Zhang   link->selfbuflen = rootoffset[ndrootranks]*link->unitbytes;
104eb02082bSJunchao Zhang   link->nrootreqs  = nrootreqs;
105eb02082bSJunchao Zhang   link->nleafreqs  = nleafreqs;
106eb02082bSJunchao Zhang   nreqs            = (nrootreqs+nleafreqs)*4; /* Quadruple the requests since there are two communication directions and two memory types */
107eb02082bSJunchao Zhang   ierr             = PetscMalloc1(nreqs,&link->reqs);CHKERRQ(ierr);
108eb02082bSJunchao Zhang   for (i=0; i<nreqs; i++) link->reqs[i] = MPI_REQUEST_NULL; /* Initialized to NULL so that we know which need to be freed in Destroy */
109eb02082bSJunchao Zhang 
110eb02082bSJunchao Zhang   for (i=0; i<2; i++) { /* Two communication directions */
111eb02082bSJunchao Zhang     for (j=0; j<2; j++) { /* Two memory types */
112eb02082bSJunchao Zhang       link->rootreqs[i][j] = link->reqs + nrootreqs*(2*i+j);
113eb02082bSJunchao Zhang       link->leafreqs[i][j] = link->reqs + nrootreqs*4 + nleafreqs*(2*i+j);
114eb02082bSJunchao Zhang     }
115eb02082bSJunchao Zhang   }
11653deab39SPeter Brune 
11740e23c03SJunchao Zhang found:
118eb02082bSJunchao Zhang   link->rootmtype = rootmtype;
119eb02082bSJunchao Zhang   link->leafmtype = leafmtype;
120eb02082bSJunchao Zhang #if defined(PETSC_HAVE_CUDA)
121120a1823SJunchao Zhang   ierr = PetscSFPackSetUp_Device(sf,link,unit);CHKERRQ(ierr);
122120a1823SJunchao Zhang   if (!use_gpu_aware_mpi) {
123120a1823SJunchao Zhang     /* If not using GPU aware MPI, we always need buffers on host. In case root/leafdata is on device, we copy root/leafdata to/from
124120a1823SJunchao Zhang        these buffers for MPI. We only need buffers for remote neighbors since self-to-self communication is not done via MPI.
125120a1823SJunchao Zhang      */
126120a1823SJunchao Zhang     if (!link->rootbuf[PETSC_MEMTYPE_HOST]) {ierr = PetscMallocWithMemType(PETSC_MEMTYPE_HOST,link->rootbuflen*link->unitbytes,(void**)&link->rootbuf[PETSC_MEMTYPE_HOST]);CHKERRQ(ierr);}
127120a1823SJunchao Zhang     if (!link->leafbuf[PETSC_MEMTYPE_HOST]) {ierr = PetscMallocWithMemType(PETSC_MEMTYPE_HOST,link->leafbuflen*link->unitbytes,(void**)&link->leafbuf[PETSC_MEMTYPE_HOST]);CHKERRQ(ierr);}
128120a1823SJunchao Zhang   }
129eb02082bSJunchao Zhang #endif
130eb02082bSJunchao Zhang   if (!link->rootbuf[rootmtype]) {ierr = PetscMallocWithMemType(rootmtype,link->rootbuflen*link->unitbytes,(void**)&link->rootbuf[rootmtype]);CHKERRQ(ierr);}
131eb02082bSJunchao Zhang   if (!link->leafbuf[leafmtype]) {ierr = PetscMallocWithMemType(leafmtype,link->leafbuflen*link->unitbytes,(void**)&link->leafbuf[leafmtype]);CHKERRQ(ierr);}
132eb02082bSJunchao Zhang   if (!link->selfbuf[rootmtype]) {ierr = PetscMallocWithMemType(rootmtype,link->selfbuflen*link->unitbytes,(void**)&link->selfbuf[rootmtype]);CHKERRQ(ierr);}
133eb02082bSJunchao Zhang   if (rootmtype != leafmtype && !link->selfbuf[leafmtype]) {ierr = PetscMallocWithMemType(leafmtype,link->selfbuflen*link->unitbytes,(void**)&link->selfbuf[leafmtype]);CHKERRQ(ierr);}
134b23bfdefSJunchao Zhang   link->rkey = rootdata;
135b23bfdefSJunchao Zhang   link->lkey = leafdata;
13640e23c03SJunchao Zhang   link->next = bas->inuse;
137eb02082bSJunchao Zhang   bas->inuse = link;
13840e23c03SJunchao Zhang 
13940e23c03SJunchao Zhang   *mylink    = link;
14040e23c03SJunchao Zhang   PetscFunctionReturn(0);
14195fce210SBarry Smith }
14295fce210SBarry Smith 
143eb02082bSJunchao Zhang static PetscErrorCode PetscSFPackGet_Basic(PetscSF sf,MPI_Datatype unit,PetscMemType rootmtype,const void *rootdata,PetscMemType leafmtype,const void *leafdata,PetscSFDirection direction,PetscSFPack *mylink)
144b23bfdefSJunchao Zhang {
145b23bfdefSJunchao Zhang   PetscErrorCode    ierr;
146eb02082bSJunchao Zhang   PetscInt          nrootranks,ndrootranks,nleafranks,ndleafranks;
147b23bfdefSJunchao Zhang 
148b23bfdefSJunchao Zhang   PetscFunctionBegin;
149b23bfdefSJunchao Zhang   ierr = PetscSFGetRootInfo_Basic(sf,&nrootranks,&ndrootranks,NULL,NULL,NULL);CHKERRQ(ierr);
150b23bfdefSJunchao Zhang   ierr = PetscSFGetLeafInfo_Basic(sf,&nleafranks,&ndleafranks,NULL,NULL,NULL,NULL);CHKERRQ(ierr);
151eb02082bSJunchao Zhang   ierr = PetscSFPackGet_Basic_Common(sf,unit,rootmtype,rootdata,leafmtype,leafdata,nrootranks-ndrootranks,nleafranks-ndleafranks,mylink);CHKERRQ(ierr);
152b23bfdefSJunchao Zhang   PetscFunctionReturn(0);
153b23bfdefSJunchao Zhang }
154b23bfdefSJunchao Zhang 
15540e23c03SJunchao Zhang /*===================================================================================*/
15640e23c03SJunchao Zhang /*              SF public interface implementations                                  */
15740e23c03SJunchao Zhang /*===================================================================================*/
15840e23c03SJunchao Zhang PETSC_INTERN PetscErrorCode PetscSFSetUp_Basic(PetscSF sf)
15995fce210SBarry Smith {
16095fce210SBarry Smith   PetscErrorCode ierr;
161b23bfdefSJunchao Zhang   PetscSF_Basic  *bas = (PetscSF_Basic*)sf->data;
16295fce210SBarry Smith   PetscInt       *rlengths,*ilengths,i;
16340e23c03SJunchao Zhang   PetscMPIInt    rank,niranks,*iranks,tag;
16495fce210SBarry Smith   MPI_Comm       comm;
165b5a8e515SJed Brown   MPI_Group      group;
16640e23c03SJunchao Zhang   MPI_Request    *rootreqs,*leafreqs;
16795fce210SBarry Smith 
16895fce210SBarry Smith   PetscFunctionBegin;
169b5a8e515SJed Brown   ierr = MPI_Comm_group(PETSC_COMM_SELF,&group);CHKERRQ(ierr);
170b5a8e515SJed Brown   ierr = PetscSFSetUpRanks(sf,group);CHKERRQ(ierr);
171b5a8e515SJed Brown   ierr = MPI_Group_free(&group);CHKERRQ(ierr);
17295fce210SBarry Smith   ierr = PetscObjectGetComm((PetscObject)sf,&comm);CHKERRQ(ierr);
17340e23c03SJunchao Zhang   ierr = PetscObjectGetNewTag((PetscObject)sf,&tag);CHKERRQ(ierr);
174c943f53fSJed Brown   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
17595fce210SBarry Smith   /*
17695fce210SBarry Smith    * Inform roots about how many leaves and from which ranks
17795fce210SBarry Smith    */
178785e854fSJed Brown   ierr = PetscMalloc1(sf->nranks,&rlengths);CHKERRQ(ierr);
17995fce210SBarry Smith   /* Determine number, sending ranks, and length of incoming */
18095fce210SBarry Smith   for (i=0; i<sf->nranks; i++) {
18195fce210SBarry Smith     rlengths[i] = sf->roffset[i+1] - sf->roffset[i]; /* Number of roots referenced by my leaves; for rank sf->ranks[i] */
18295fce210SBarry Smith   }
18340e23c03SJunchao Zhang   ierr = PetscCommBuildTwoSided(comm,1,MPIU_INT,sf->nranks-sf->ndranks,sf->ranks+sf->ndranks,rlengths+sf->ndranks,&niranks,&iranks,(void**)&ilengths);CHKERRQ(ierr);
184c943f53fSJed Brown 
1850b899082SJunchao Zhang   /* Sort iranks. See use of VecScatterGetRemoteOrdered_Private() in MatGetBrowsOfAoCols_MPIAIJ() on why.
1860b899082SJunchao Zhang      We could sort ranks there at the price of allocating extra working arrays. Presumably, niranks is
1870b899082SJunchao Zhang      small and the sorting is cheap.
1880b899082SJunchao Zhang    */
1890b899082SJunchao Zhang   ierr = PetscSortMPIIntWithIntArray(niranks,iranks,ilengths);CHKERRQ(ierr);
1900b899082SJunchao Zhang 
191c943f53fSJed Brown   /* Partition into distinguished and non-distinguished incoming ranks */
192c943f53fSJed Brown   bas->ndiranks = sf->ndranks;
193c943f53fSJed Brown   bas->niranks = bas->ndiranks + niranks;
194c943f53fSJed Brown   ierr = PetscMalloc2(bas->niranks,&bas->iranks,bas->niranks+1,&bas->ioffset);CHKERRQ(ierr);
195c943f53fSJed Brown   bas->ioffset[0] = 0;
196c943f53fSJed Brown   for (i=0; i<bas->ndiranks; i++) {
197c943f53fSJed Brown     bas->iranks[i] = sf->ranks[i];
198c943f53fSJed Brown     bas->ioffset[i+1] = bas->ioffset[i] + rlengths[i];
199c943f53fSJed Brown   }
20040e23c03SJunchao Zhang   if (bas->ndiranks > 1 || (bas->ndiranks == 1 && bas->iranks[0] != rank)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Broken setup for shared ranks");
20140e23c03SJunchao Zhang   for ( ; i<bas->niranks; i++) {
202c943f53fSJed Brown     bas->iranks[i] = iranks[i-bas->ndiranks];
203c943f53fSJed Brown     bas->ioffset[i+1] = bas->ioffset[i] + ilengths[i-bas->ndiranks];
204c943f53fSJed Brown   }
205c943f53fSJed Brown   bas->itotal = bas->ioffset[i];
20695fce210SBarry Smith   ierr = PetscFree(rlengths);CHKERRQ(ierr);
207c943f53fSJed Brown   ierr = PetscFree(iranks);CHKERRQ(ierr);
208c943f53fSJed Brown   ierr = PetscFree(ilengths);CHKERRQ(ierr);
20995fce210SBarry Smith 
21095fce210SBarry Smith   /* Send leaf identities to roots */
211c943f53fSJed Brown   ierr = PetscMalloc1(bas->itotal,&bas->irootloc);CHKERRQ(ierr);
21240e23c03SJunchao Zhang   ierr = PetscMalloc2(bas->niranks-bas->ndiranks,&rootreqs,sf->nranks-sf->ndranks,&leafreqs);CHKERRQ(ierr);
21340e23c03SJunchao Zhang   for (i=bas->ndiranks; i<bas->niranks; i++) {
21440e23c03SJunchao Zhang     ierr = MPI_Irecv(bas->irootloc+bas->ioffset[i],bas->ioffset[i+1]-bas->ioffset[i],MPIU_INT,bas->iranks[i],tag,comm,&rootreqs[i-bas->ndiranks]);CHKERRQ(ierr);
21540e23c03SJunchao Zhang   }
21640e23c03SJunchao Zhang   for (i=0; i<sf->nranks; i++) {
21795fce210SBarry Smith     PetscMPIInt npoints;
21895fce210SBarry Smith     ierr = PetscMPIIntCast(sf->roffset[i+1] - sf->roffset[i],&npoints);CHKERRQ(ierr);
21940e23c03SJunchao Zhang     if (i < sf->ndranks) {
22040e23c03SJunchao Zhang       if (sf->ranks[i] != rank) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cannot interpret distinguished leaf rank");
22140e23c03SJunchao Zhang       if (bas->iranks[0] != rank) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cannot interpret distinguished root rank");
22240e23c03SJunchao Zhang       if (npoints != bas->ioffset[1]-bas->ioffset[0]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Distinguished rank exchange has mismatched lengths");
22340e23c03SJunchao Zhang       ierr = PetscArraycpy(bas->irootloc+bas->ioffset[0],sf->rremote+sf->roffset[i],npoints);CHKERRQ(ierr);
224c943f53fSJed Brown       continue;
225c943f53fSJed Brown     }
22640e23c03SJunchao Zhang     ierr = MPI_Isend(sf->rremote+sf->roffset[i],npoints,MPIU_INT,sf->ranks[i],tag,comm,&leafreqs[i-sf->ndranks]);CHKERRQ(ierr);
227bf39f1bfSJed Brown   }
22840e23c03SJunchao Zhang   ierr = MPI_Waitall(bas->niranks-bas->ndiranks,rootreqs,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
22940e23c03SJunchao Zhang   ierr = MPI_Waitall(sf->nranks-sf->ndranks,leafreqs,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
23040e23c03SJunchao Zhang   ierr = PetscFree2(rootreqs,leafreqs);CHKERRQ(ierr);
23195fce210SBarry Smith 
232eb02082bSJunchao Zhang   sf->selfleafdups    = PETSC_TRUE; /* The conservative assumption is there are data race */
233eb02082bSJunchao Zhang   sf->remoteleafdups  = PETSC_TRUE;
234eb02082bSJunchao Zhang   bas->selfrootdups   = PETSC_TRUE;
235eb02082bSJunchao Zhang   bas->remoterootdups = PETSC_TRUE;
236eb02082bSJunchao Zhang 
237b23bfdefSJunchao Zhang   /* Setup packing optimization for roots and leaves */
238eb02082bSJunchao Zhang   ierr = PetscSFPackSetupOptimizations_Basic(sf);CHKERRQ(ierr);
23995fce210SBarry Smith   PetscFunctionReturn(0);
24095fce210SBarry Smith }
24195fce210SBarry Smith 
2424416b707SBarry Smith static PetscErrorCode PetscSFSetFromOptions_Basic(PetscOptionItems *PetscOptionsObject,PetscSF sf)
24395fce210SBarry Smith {
24495fce210SBarry Smith   PetscErrorCode ierr;
24595fce210SBarry Smith 
24695fce210SBarry Smith   PetscFunctionBegin;
247e55864a3SBarry Smith   ierr = PetscOptionsHead(PetscOptionsObject,"PetscSF Basic options");CHKERRQ(ierr);
24895fce210SBarry Smith   ierr = PetscOptionsTail();CHKERRQ(ierr);
24995fce210SBarry Smith   PetscFunctionReturn(0);
25095fce210SBarry Smith }
25195fce210SBarry Smith 
25240e23c03SJunchao Zhang PETSC_INTERN PetscErrorCode PetscSFReset_Basic(PetscSF sf)
25395fce210SBarry Smith {
25495fce210SBarry Smith   PetscSF_Basic     *bas = (PetscSF_Basic*)sf->data;
25595fce210SBarry Smith   PetscErrorCode    ierr;
25695fce210SBarry Smith 
25795fce210SBarry Smith   PetscFunctionBegin;
25829046d53SLisandro Dalcin   if (bas->inuse) SETERRQ(PetscObjectComm((PetscObject)sf),PETSC_ERR_ARG_WRONGSTATE,"Outstanding operation has not been completed");
259c943f53fSJed Brown   ierr = PetscFree2(bas->iranks,bas->ioffset);CHKERRQ(ierr);
260c943f53fSJed Brown   ierr = PetscFree(bas->irootloc);CHKERRQ(ierr);
261eb02082bSJunchao Zhang #if defined(PETSC_HAVE_CUDA)
262eb02082bSJunchao Zhang   if (bas->irootloc_d) {cudaError_t err = cudaFree(bas->irootloc_d);CHKERRCUDA(err);bas->irootloc_d=NULL;}
263eb02082bSJunchao Zhang #endif
26464f49babSJed Brown   ierr = PetscSFPackDestroyAvailable(&bas->avail);CHKERRQ(ierr);
265eb02082bSJunchao Zhang   ierr = PetscSFPackDestroyOptimizations_Basic(sf);CHKERRQ(ierr);
26695fce210SBarry Smith   PetscFunctionReturn(0);
26795fce210SBarry Smith }
26895fce210SBarry Smith 
26940e23c03SJunchao Zhang PETSC_INTERN PetscErrorCode PetscSFDestroy_Basic(PetscSF sf)
27095fce210SBarry Smith {
27195fce210SBarry Smith   PetscErrorCode ierr;
27295fce210SBarry Smith 
27395fce210SBarry Smith   PetscFunctionBegin;
27440e23c03SJunchao Zhang   ierr = PetscSFReset(sf);CHKERRQ(ierr);
27595fce210SBarry Smith   ierr = PetscFree(sf->data);CHKERRQ(ierr);
27695fce210SBarry Smith   PetscFunctionReturn(0);
27795fce210SBarry Smith }
27895fce210SBarry Smith 
27940e23c03SJunchao Zhang PETSC_INTERN PetscErrorCode PetscSFView_Basic(PetscSF sf,PetscViewer viewer)
28095fce210SBarry Smith {
28195fce210SBarry Smith   PetscErrorCode ierr;
28295fce210SBarry Smith   PetscBool      iascii;
28395fce210SBarry Smith 
28495fce210SBarry Smith   PetscFunctionBegin;
28595fce210SBarry Smith   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
286b23bfdefSJunchao Zhang   if (iascii) {ierr = PetscViewerASCIIPrintf(viewer,"  sort=%s\n",sf->rankorder ? "rank-order" : "unordered");CHKERRQ(ierr);}
28795fce210SBarry Smith   PetscFunctionReturn(0);
28895fce210SBarry Smith }
28995fce210SBarry Smith 
290eb02082bSJunchao Zhang static PetscErrorCode PetscSFBcastAndOpBegin_Basic(PetscSF sf,MPI_Datatype unit,PetscMemType rootmtype,const void *rootdata,PetscMemType leafmtype,void *leafdata,MPI_Op op)
29195fce210SBarry Smith {
29295fce210SBarry Smith   PetscErrorCode    ierr;
293eb02082bSJunchao Zhang   PetscSFPack       link;
294eb02082bSJunchao Zhang   const PetscInt    *rootloc = NULL;
29595fce210SBarry Smith   MPI_Request       *rootreqs,*leafreqs;
29695fce210SBarry Smith 
29795fce210SBarry Smith   PetscFunctionBegin;
298eb02082bSJunchao Zhang   ierr = PetscSFPackGet_Basic(sf,unit,rootmtype,rootdata,leafmtype,leafdata,PETSCSF_ROOT2LEAF_BCAST,&link);CHKERRQ(ierr);
299eb02082bSJunchao Zhang   ierr = PetscSFGetRootIndicesWithMemType_Basic(sf,rootmtype,&rootloc);CHKERRQ(ierr);
30095fce210SBarry Smith 
301b23bfdefSJunchao Zhang   ierr = PetscSFPackGetReqs_Basic(sf,link,PETSCSF_ROOT2LEAF_BCAST,&rootreqs,&leafreqs);CHKERRQ(ierr);
302b23bfdefSJunchao Zhang   /* Post Irecv. Note distinguished ranks receive data via shared memory (i.e., not via MPI) */
303eb02082bSJunchao Zhang   ierr = MPI_Startall_irecv(link->leafbuflen,unit,link->nleafreqs,leafreqs);CHKERRQ(ierr);
30430e38525SJunchao Zhang 
305b23bfdefSJunchao Zhang   /* Do Isend */
306eb02082bSJunchao Zhang   ierr = PetscSFPackRootData(sf,link,rootloc,rootdata,PETSC_TRUE);CHKERRQ(ierr);
307eb02082bSJunchao Zhang   ierr = MPI_Startall_isend(link->rootbuflen,unit,link->nrootreqs,rootreqs);CHKERRQ(ierr);
308eb02082bSJunchao Zhang 
309eb02082bSJunchao Zhang   /* Do self to self communication via memcpy only when rootdata and leafdata are in different memory */
310eb02082bSJunchao Zhang   if (rootmtype != leafmtype) {ierr = PetscMemcpyWithMemType(leafmtype,rootmtype,link->selfbuf[leafmtype],link->selfbuf[rootmtype],link->selfbuflen*link->unitbytes);CHKERRQ(ierr);}
31195fce210SBarry Smith   PetscFunctionReturn(0);
31295fce210SBarry Smith }
31395fce210SBarry Smith 
314eb02082bSJunchao Zhang PETSC_INTERN PetscErrorCode PetscSFBcastAndOpEnd_Basic(PetscSF sf,MPI_Datatype unit,PetscMemType rootmtype,const void *rootdata,PetscMemType leafmtype,void *leafdata,MPI_Op op)
31595fce210SBarry Smith {
31695fce210SBarry Smith   PetscErrorCode    ierr;
317eb02082bSJunchao Zhang   PetscSFPack       link;
318eb02082bSJunchao Zhang   const PetscInt    *leafloc = NULL;
31995fce210SBarry Smith 
32095fce210SBarry Smith   PetscFunctionBegin;
321eb02082bSJunchao Zhang   ierr = PetscSFPackGetInUse(sf,unit,rootdata,leafdata,PETSC_OWN_POINTER,&link);CHKERRQ(ierr);
322*b7c0d12aSJunchao Zhang   ierr = PetscSFPackWaitall(link,PETSCSF_ROOT2LEAF_BCAST);CHKERRQ(ierr);
323eb02082bSJunchao Zhang   ierr = PetscSFGetLeafIndicesWithMemType_Basic(sf,leafmtype,&leafloc);CHKERRQ(ierr);
324eb02082bSJunchao Zhang   ierr = PetscSFUnpackAndOpLeafData(sf,link,leafloc,leafdata,op,PETSC_TRUE);CHKERRQ(ierr);
325eb02082bSJunchao Zhang   ierr = PetscSFPackReclaim(sf,&link);CHKERRQ(ierr);
32695fce210SBarry Smith   PetscFunctionReturn(0);
32795fce210SBarry Smith }
32895fce210SBarry Smith 
32995fce210SBarry Smith /* leaf -> root with reduction */
330eb02082bSJunchao Zhang static PetscErrorCode PetscSFReduceBegin_Basic(PetscSF sf,MPI_Datatype unit,PetscMemType leafmtype,const void *leafdata,PetscMemType rootmtype,void *rootdata,MPI_Op op)
33195fce210SBarry Smith {
33295fce210SBarry Smith   PetscErrorCode    ierr;
333eb02082bSJunchao Zhang   PetscSFPack       link;
334eb02082bSJunchao Zhang   const PetscInt    *leafloc = NULL;
335277f51e8SBarry Smith   MPI_Request       *rootreqs = NULL,*leafreqs = NULL; /* dummy values for compiler warnings about uninitialized value */
33695fce210SBarry Smith 
33795fce210SBarry Smith   PetscFunctionBegin;
338eb02082bSJunchao Zhang   ierr = PetscSFGetLeafIndicesWithMemType_Basic(sf,leafmtype,&leafloc);
33995fce210SBarry Smith 
340eb02082bSJunchao Zhang   ierr = PetscSFPackGet_Basic(sf,unit,rootmtype,rootdata,leafmtype,leafdata,PETSCSF_LEAF2ROOT_REDUCE,&link);CHKERRQ(ierr);
341b23bfdefSJunchao Zhang   ierr = PetscSFPackGetReqs_Basic(sf,link,PETSCSF_LEAF2ROOT_REDUCE,&rootreqs,&leafreqs);CHKERRQ(ierr);
342c943f53fSJed Brown   /* Eagerly post root receives for non-distinguished ranks */
343eb02082bSJunchao Zhang   ierr = MPI_Startall_irecv(link->rootbuflen,unit,link->nrootreqs,rootreqs);CHKERRQ(ierr);
34430e38525SJunchao Zhang 
34595fce210SBarry Smith   /* Pack and send leaf data */
346eb02082bSJunchao Zhang   ierr = PetscSFPackLeafData(sf,link,leafloc,leafdata,PETSC_TRUE);CHKERRQ(ierr);
347eb02082bSJunchao Zhang   ierr = MPI_Startall_isend(link->leafbuflen,unit,link->nleafreqs,leafreqs);CHKERRQ(ierr);
348eb02082bSJunchao Zhang 
349eb02082bSJunchao Zhang   if (rootmtype != leafmtype) {ierr = PetscMemcpyWithMemType(rootmtype,leafmtype,link->selfbuf[rootmtype],link->selfbuf[leafmtype],link->selfbuflen*link->unitbytes);CHKERRQ(ierr);}
35095fce210SBarry Smith   PetscFunctionReturn(0);
35195fce210SBarry Smith }
35295fce210SBarry Smith 
353eb02082bSJunchao Zhang PETSC_INTERN PetscErrorCode PetscSFReduceEnd_Basic(PetscSF sf,MPI_Datatype unit,PetscMemType leafmtype,const void *leafdata,PetscMemType rootmtype,void *rootdata,MPI_Op op)
35495fce210SBarry Smith {
35595fce210SBarry Smith   PetscErrorCode    ierr;
356eb02082bSJunchao Zhang   PetscSFPack       link;
357eb02082bSJunchao Zhang   const PetscInt    *rootloc = NULL;
35895fce210SBarry Smith 
35995fce210SBarry Smith   PetscFunctionBegin;
360eb02082bSJunchao Zhang   ierr = PetscSFGetRootIndicesWithMemType_Basic(sf,rootmtype,&rootloc);CHKERRQ(ierr);
361eb02082bSJunchao Zhang   ierr = PetscSFPackGetInUse(sf,unit,rootdata,leafdata,PETSC_OWN_POINTER,&link);CHKERRQ(ierr);
362*b7c0d12aSJunchao Zhang   ierr = PetscSFPackWaitall(link,PETSCSF_LEAF2ROOT_REDUCE);CHKERRQ(ierr);
363eb02082bSJunchao Zhang   ierr = PetscSFUnpackAndOpRootData(sf,link,rootloc,rootdata,op,PETSC_TRUE);CHKERRQ(ierr);
364eb02082bSJunchao Zhang   ierr = PetscSFPackReclaim(sf,&link);CHKERRQ(ierr);
36595fce210SBarry Smith   PetscFunctionReturn(0);
36695fce210SBarry Smith }
36795fce210SBarry Smith 
368eb02082bSJunchao Zhang PETSC_INTERN PetscErrorCode PetscSFFetchAndOpBegin_Basic(PetscSF sf,MPI_Datatype unit,PetscMemType rootmtype,void *rootdata,PetscMemType leafmtype,const void *leafdata,void *leafupdate,MPI_Op op)
36995fce210SBarry Smith {
37095fce210SBarry Smith   PetscErrorCode ierr;
37195fce210SBarry Smith 
37295fce210SBarry Smith   PetscFunctionBegin;
37340e23c03SJunchao Zhang   ierr = PetscSFReduceBegin(sf,unit,leafdata,rootdata,op);CHKERRQ(ierr);
37495fce210SBarry Smith   PetscFunctionReturn(0);
37595fce210SBarry Smith }
37695fce210SBarry Smith 
377eb02082bSJunchao Zhang static PetscErrorCode PetscSFFetchAndOpEnd_Basic(PetscSF sf,MPI_Datatype unit,PetscMemType rootmtype,void *rootdata,PetscMemType leafmtype,const void *leafdata,void *leafupdate,MPI_Op op)
37895fce210SBarry Smith {
37995fce210SBarry Smith   PetscErrorCode    ierr;
380eb02082bSJunchao Zhang   PetscSFPack       link;
381eb02082bSJunchao Zhang   const PetscInt    *rootloc = NULL,*leafloc = NULL;
38295fce210SBarry Smith   MPI_Request       *rootreqs,*leafreqs;
38395fce210SBarry Smith 
38495fce210SBarry Smith   PetscFunctionBegin;
385eb02082bSJunchao Zhang   ierr = PetscSFGetRootIndicesWithMemType_Basic(sf,rootmtype,&rootloc);CHKERRQ(ierr);
386eb02082bSJunchao Zhang   ierr = PetscSFGetLeafIndicesWithMemType_Basic(sf,leafmtype,&leafloc);CHKERRQ(ierr);
387eb02082bSJunchao Zhang   ierr = PetscSFPackGetInUse(sf,unit,rootdata,leafdata,PETSC_OWN_POINTER,&link);CHKERRQ(ierr);
38895fce210SBarry Smith   /* This implementation could be changed to unpack as receives arrive, at the cost of non-determinism */
389*b7c0d12aSJunchao Zhang   ierr = PetscSFPackWaitall(link,PETSCSF_LEAF2ROOT_REDUCE);CHKERRQ(ierr);
390b23bfdefSJunchao Zhang   ierr = PetscSFPackGetReqs_Basic(sf,link,PETSCSF_ROOT2LEAF_BCAST,&rootreqs,&leafreqs);CHKERRQ(ierr);
39140e23c03SJunchao Zhang 
39295fce210SBarry Smith   /* Post leaf receives */
393eb02082bSJunchao Zhang   ierr = MPI_Startall_irecv(link->leafbuflen,unit,link->nleafreqs,leafreqs);CHKERRQ(ierr);
39430e38525SJunchao Zhang 
39595fce210SBarry Smith   /* Process local fetch-and-op, post root sends */
396eb02082bSJunchao Zhang   ierr = PetscSFFetchAndOpRootData(sf,link,rootloc,rootdata,op,PETSC_TRUE);CHKERRQ(ierr);
397eb02082bSJunchao Zhang   ierr = MPI_Startall_isend(link->rootbuflen,unit,link->nrootreqs,rootreqs);CHKERRQ(ierr);
398eb02082bSJunchao Zhang   if (rootmtype != leafmtype) {ierr = PetscMemcpyWithMemType(leafmtype,rootmtype,link->selfbuf[leafmtype],link->selfbuf[rootmtype],link->selfbuflen*link->unitbytes);CHKERRQ(ierr);}
399b23bfdefSJunchao Zhang 
400b23bfdefSJunchao Zhang   /* Unpack and insert fetched data into leaves */
401*b7c0d12aSJunchao Zhang   ierr = PetscSFPackWaitall(link,PETSCSF_ROOT2LEAF_BCAST);CHKERRQ(ierr);
402eb02082bSJunchao Zhang   ierr = PetscSFUnpackAndOpLeafData(sf,link,leafloc,leafupdate,MPIU_REPLACE,PETSC_TRUE);CHKERRQ(ierr);
403eb02082bSJunchao Zhang   ierr = PetscSFPackReclaim(sf,&link);CHKERRQ(ierr);
40495fce210SBarry Smith   PetscFunctionReturn(0);
40595fce210SBarry Smith }
40695fce210SBarry Smith 
40740e23c03SJunchao Zhang PETSC_INTERN PetscErrorCode PetscSFGetLeafRanks_Basic(PetscSF sf,PetscInt *niranks,const PetscMPIInt **iranks,const PetscInt **ioffset,const PetscInt **irootloc)
4088750ddebSJunchao Zhang {
4098750ddebSJunchao Zhang   PetscSF_Basic *bas = (PetscSF_Basic*)sf->data;
4108750ddebSJunchao Zhang 
4118750ddebSJunchao Zhang   PetscFunctionBegin;
4128750ddebSJunchao Zhang   if (niranks)  *niranks  = bas->niranks;
4138750ddebSJunchao Zhang   if (iranks)   *iranks   = bas->iranks;
4148750ddebSJunchao Zhang   if (ioffset)  *ioffset  = bas->ioffset;
4158750ddebSJunchao Zhang   if (irootloc) *irootloc = bas->irootloc;
4168750ddebSJunchao Zhang   PetscFunctionReturn(0);
4178750ddebSJunchao Zhang }
4188750ddebSJunchao Zhang 
419f659e5c7SJunchao Zhang /* An optimized PetscSFCreateEmbeddedSF. We aggresively make use of the established communication on sf.
420f659e5c7SJunchao Zhang    We need one bcast on sf, and no communication anymore to build the embedded sf. Note that selected[]
421f659e5c7SJunchao Zhang    was sorted before calling the routine.
422f659e5c7SJunchao Zhang  */
423f659e5c7SJunchao Zhang PETSC_INTERN PetscErrorCode PetscSFCreateEmbeddedSF_Basic(PetscSF sf,PetscInt nselected,const PetscInt *selected,PetscSF *newsf)
424f659e5c7SJunchao Zhang {
425f659e5c7SJunchao Zhang   PetscSF           esf;
426b23bfdefSJunchao Zhang   PetscInt          esf_nranks,esf_ndranks,*esf_roffset,*esf_rmine,*esf_rremote,count;
427b23bfdefSJunchao Zhang   PetscInt          i,j,k,p,q,nroots,*rootdata,*leafdata,connected_leaves,*new_ilocal,nranks,ndranks,niranks,ndiranks,minleaf,maxleaf,maxlocal;
428f659e5c7SJunchao Zhang   PetscMPIInt       *esf_ranks;
429f659e5c7SJunchao Zhang   const PetscMPIInt *ranks,*iranks;
430b23bfdefSJunchao Zhang   const PetscInt    *roffset,*rmine,*rremote,*ioffset,*irootloc,*buffer;
431f659e5c7SJunchao Zhang   PetscBool         connected;
432eb02082bSJunchao Zhang   PetscSFPack       link;
433f659e5c7SJunchao Zhang   PetscSFNode       *new_iremote;
434f659e5c7SJunchao Zhang   PetscSF_Basic     *bas;
435f659e5c7SJunchao Zhang   PetscErrorCode    ierr;
436f659e5c7SJunchao Zhang 
437f659e5c7SJunchao Zhang   PetscFunctionBegin;
438f659e5c7SJunchao Zhang   ierr = PetscSFCreate(PetscObjectComm((PetscObject)sf),&esf);CHKERRQ(ierr);
439f659e5c7SJunchao Zhang   ierr = PetscSFSetType(esf,PETSCSFBASIC);CHKERRQ(ierr); /* This optimized routine can only create a basic sf */
440f659e5c7SJunchao Zhang 
441f659e5c7SJunchao Zhang   /* Find out which leaves are still connected to roots in the embedded sf */
442f659e5c7SJunchao Zhang   ierr = PetscSFGetGraph(sf,&nroots,NULL,NULL,NULL);CHKERRQ(ierr);
443f659e5c7SJunchao Zhang   ierr = PetscSFGetLeafRange(sf,&minleaf,&maxleaf);CHKERRQ(ierr);
444f659e5c7SJunchao Zhang   /* We abused the term leafdata here, whose size is usually the number of leaf data items. Here its size is # of leaves (always >= # of leaf data items) */
445f659e5c7SJunchao Zhang   maxlocal = (minleaf > maxleaf)? 0 : maxleaf-minleaf+1; /* maxleaf=-1 and minleaf=0 when nleaves=0 */
446f659e5c7SJunchao Zhang   ierr = PetscCalloc2(nroots,&rootdata,maxlocal,&leafdata);CHKERRQ(ierr);
447f659e5c7SJunchao Zhang   /* Tag selected roots */
448f659e5c7SJunchao Zhang   for (i=0; i<nselected; ++i) rootdata[selected[i]] = 1;
449f659e5c7SJunchao Zhang 
450f659e5c7SJunchao Zhang   /* Bcast from roots to leaves to tag connected leaves. We reuse the established bcast communication in
451f659e5c7SJunchao Zhang      sf but do not do unpacking (from leaf buffer to leafdata). The raw data in leaf buffer is what we are
452f659e5c7SJunchao Zhang      interested in since it tells which leaves are connected to which ranks.
453f659e5c7SJunchao Zhang    */
454eb02082bSJunchao Zhang   ierr = PetscSFBcastAndOpBegin_Basic(sf,MPIU_INT,PETSC_MEMTYPE_HOST,rootdata,PETSC_MEMTYPE_HOST,leafdata-minleaf,MPIU_REPLACE);CHKERRQ(ierr); /* Need to give leafdata but we won't use it */
455eb02082bSJunchao Zhang   ierr = PetscSFPackGetInUse(sf,MPIU_INT,rootdata,leafdata-minleaf,PETSC_OWN_POINTER,&link);CHKERRQ(ierr);
456*b7c0d12aSJunchao Zhang   ierr = PetscSFPackWaitall(link,PETSCSF_ROOT2LEAF_BCAST);CHKERRQ(ierr);
457f659e5c7SJunchao Zhang   ierr = PetscSFGetLeafInfo_Basic(sf,&nranks,&ndranks,&ranks,&roffset,&rmine,&rremote);CHKERRQ(ierr); /* Get send info */
458f659e5c7SJunchao Zhang   esf_nranks = esf_ndranks = connected_leaves = 0;
459b23bfdefSJunchao Zhang   for (i=0; i<nranks; i++) {
460f659e5c7SJunchao Zhang     connected = PETSC_FALSE; /* Is the current process still connected to this remote root rank? */
461eb02082bSJunchao Zhang     buffer    = i < ndranks? (PetscInt*)link->selfbuf[PETSC_MEMTYPE_HOST] : (PetscInt*)link->leafbuf[PETSC_MEMTYPE_HOST] + (roffset[i] - roffset[ndranks]);
462b23bfdefSJunchao Zhang     count     = roffset[i+1] - roffset[i];
463b23bfdefSJunchao Zhang     for (j=0; j<count; j++) {if (buffer[j]) {connected_leaves++; connected = PETSC_TRUE;}}
464f659e5c7SJunchao Zhang     if (connected) {esf_nranks++; if (i < ndranks) esf_ndranks++;}
465f659e5c7SJunchao Zhang   }
466f659e5c7SJunchao Zhang 
467f659e5c7SJunchao Zhang   /* Set graph of esf and also set up its outgoing communication (i.e., send info), which is usually done by PetscSFSetUpRanks */
468f659e5c7SJunchao Zhang   ierr = PetscMalloc1(connected_leaves,&new_ilocal);CHKERRQ(ierr);
469f659e5c7SJunchao Zhang   ierr = PetscMalloc1(connected_leaves,&new_iremote);CHKERRQ(ierr);
470f659e5c7SJunchao Zhang   ierr = PetscMalloc4(esf_nranks,&esf_ranks,esf_nranks+1,&esf_roffset,connected_leaves,&esf_rmine,connected_leaves,&esf_rremote);CHKERRQ(ierr);
471f659e5c7SJunchao Zhang   p    = 0; /* Counter for connected root ranks */
472f659e5c7SJunchao Zhang   q    = 0; /* Counter for connected leaves */
473f659e5c7SJunchao Zhang   esf_roffset[0] = 0;
474f659e5c7SJunchao Zhang   for (i=0; i<nranks; i++) { /* Scan leaf data again to fill esf arrays */
475eb02082bSJunchao Zhang     buffer    = i < ndranks? (PetscInt*)link->selfbuf[PETSC_MEMTYPE_HOST] : (PetscInt*)link->leafbuf[PETSC_MEMTYPE_HOST] + (roffset[i] - roffset[ndranks]);
476f659e5c7SJunchao Zhang     connected = PETSC_FALSE;
477f659e5c7SJunchao Zhang     for (j=roffset[i],k=0; j<roffset[i+1]; j++,k++) {
478b23bfdefSJunchao Zhang         if (buffer[k]) {
479f659e5c7SJunchao Zhang         esf_rmine[q]         = new_ilocal[q] = rmine[j];
480f659e5c7SJunchao Zhang         esf_rremote[q]       = rremote[j];
481f659e5c7SJunchao Zhang         new_iremote[q].index = rremote[j];
482f659e5c7SJunchao Zhang         new_iremote[q].rank  = ranks[i];
483f659e5c7SJunchao Zhang         connected            = PETSC_TRUE;
484f659e5c7SJunchao Zhang         q++;
485f659e5c7SJunchao Zhang       }
486f659e5c7SJunchao Zhang     }
487f659e5c7SJunchao Zhang     if (connected) {
488f659e5c7SJunchao Zhang       esf_ranks[p]     = ranks[i];
489f659e5c7SJunchao Zhang       esf_roffset[p+1] = q;
490f659e5c7SJunchao Zhang       p++;
491f659e5c7SJunchao Zhang     }
492f659e5c7SJunchao Zhang   }
493f659e5c7SJunchao Zhang 
494eb02082bSJunchao Zhang   ierr = PetscSFPackReclaim(sf,&link);CHKERRQ(ierr);
495f659e5c7SJunchao Zhang 
496f659e5c7SJunchao Zhang   /* SetGraph internally resets the SF, so we only set its fields after the call */
497f659e5c7SJunchao Zhang   ierr         = PetscSFSetGraph(esf,nroots,connected_leaves,new_ilocal,PETSC_OWN_POINTER,new_iremote,PETSC_OWN_POINTER);CHKERRQ(ierr);
498f659e5c7SJunchao Zhang   esf->nranks  = esf_nranks;
499f659e5c7SJunchao Zhang   esf->ndranks = esf_ndranks;
500f659e5c7SJunchao Zhang   esf->ranks   = esf_ranks;
501f659e5c7SJunchao Zhang   esf->roffset = esf_roffset;
502f659e5c7SJunchao Zhang   esf->rmine   = esf_rmine;
503f659e5c7SJunchao Zhang   esf->rremote = esf_rremote;
504f659e5c7SJunchao Zhang 
505f659e5c7SJunchao Zhang   /* Set up the incoming communication (i.e., recv info) stored in esf->data, which is usually done by PetscSFSetUp_Basic */
506f659e5c7SJunchao Zhang   bas  = (PetscSF_Basic*)esf->data;
507f659e5c7SJunchao Zhang   ierr = PetscSFGetRootInfo_Basic(sf,&niranks,&ndiranks,&iranks,&ioffset,&irootloc);CHKERRQ(ierr); /* Get recv info */
508f659e5c7SJunchao Zhang   /* Embedded sf always has simpler communication than the original one. We might allocate longer arrays than needed here. But we
509f659e5c7SJunchao Zhang      expect these arrays are usually short, so we do not care. The benefit is we can fill these arrays by just parsing irootloc once.
510f659e5c7SJunchao Zhang    */
511f659e5c7SJunchao Zhang   ierr = PetscMalloc2(niranks,&bas->iranks,niranks+1,&bas->ioffset);CHKERRQ(ierr);
512f659e5c7SJunchao Zhang   ierr = PetscMalloc1(ioffset[niranks],&bas->irootloc);CHKERRQ(ierr);
513f659e5c7SJunchao Zhang   bas->niranks = bas->ndiranks = bas->ioffset[0] = 0;
514f659e5c7SJunchao Zhang   p = 0; /* Counter for connected leaf ranks */
515f659e5c7SJunchao Zhang   q = 0; /* Counter for connected roots */
516f659e5c7SJunchao Zhang   for (i=0; i<niranks; i++) {
517f659e5c7SJunchao Zhang     connected = PETSC_FALSE; /* Is the current process still connected to this remote leaf rank? */
518f659e5c7SJunchao Zhang     for (j=ioffset[i]; j<ioffset[i+1]; j++) {
519f659e5c7SJunchao Zhang       PetscInt loc;
520f659e5c7SJunchao Zhang       ierr = PetscFindInt(irootloc[j],nselected,selected,&loc);CHKERRQ(ierr);
521f659e5c7SJunchao Zhang       if (loc >= 0) { /* Found in selected this root is connected */
522f659e5c7SJunchao Zhang         bas->irootloc[q++] = irootloc[j];
523f659e5c7SJunchao Zhang         connected = PETSC_TRUE;
524f659e5c7SJunchao Zhang       }
525f659e5c7SJunchao Zhang     }
526f659e5c7SJunchao Zhang     if (connected) {
527f659e5c7SJunchao Zhang       bas->niranks++;
528f659e5c7SJunchao Zhang       if (i<ndiranks) bas->ndiranks++; /* Note that order of ranks (including distinguished ranks) is kept */
529f659e5c7SJunchao Zhang       bas->iranks[p]    = iranks[i];
530f659e5c7SJunchao Zhang       bas->ioffset[p+1] = q;
531f659e5c7SJunchao Zhang       p++;
532f659e5c7SJunchao Zhang     }
533f659e5c7SJunchao Zhang   }
534f659e5c7SJunchao Zhang   bas->itotal = q;
535f659e5c7SJunchao Zhang 
536f659e5c7SJunchao Zhang   /* Setup packing optimizations */
537eb02082bSJunchao Zhang   ierr = PetscSFPackSetupOptimizations_Basic(esf);CHKERRQ(ierr);
538f659e5c7SJunchao Zhang   esf->setupcalled = PETSC_TRUE; /* We have done setup ourselves! */
539f659e5c7SJunchao Zhang 
540f659e5c7SJunchao Zhang   ierr = PetscFree2(rootdata,leafdata);CHKERRQ(ierr);
541f659e5c7SJunchao Zhang   *newsf = esf;
542f659e5c7SJunchao Zhang   PetscFunctionReturn(0);
543f659e5c7SJunchao Zhang }
544f659e5c7SJunchao Zhang 
545f659e5c7SJunchao Zhang PETSC_INTERN PetscErrorCode PetscSFCreateEmbeddedLeafSF_Basic(PetscSF sf,PetscInt nselected,const PetscInt *selected,PetscSF *newsf)
546f659e5c7SJunchao Zhang {
547f659e5c7SJunchao Zhang   PetscSF           esf;
548f659e5c7SJunchao Zhang   PetscInt          i,j,k,p,q,nroots,*rootdata,*leafdata,*new_ilocal,niranks,ndiranks,minleaf,maxleaf,maxlocal;
549b23bfdefSJunchao Zhang   const PetscInt    *ilocal,*ioffset,*irootloc,*buffer;
550f659e5c7SJunchao Zhang   const PetscMPIInt *iranks;
551eb02082bSJunchao Zhang   PetscSFPack       link;
552f659e5c7SJunchao Zhang   PetscSFNode       *new_iremote;
553f659e5c7SJunchao Zhang   const PetscSFNode *iremote;
554f659e5c7SJunchao Zhang   PetscSF_Basic     *bas;
555f659e5c7SJunchao Zhang   MPI_Group         group;
556f659e5c7SJunchao Zhang   PetscErrorCode    ierr;
557f659e5c7SJunchao Zhang 
558f659e5c7SJunchao Zhang   PetscFunctionBegin;
559f659e5c7SJunchao Zhang   ierr = PetscSFCreate(PetscObjectComm((PetscObject)sf),&esf);CHKERRQ(ierr);
560f659e5c7SJunchao Zhang   ierr = PetscSFSetType(esf,PETSCSFBASIC);CHKERRQ(ierr); /* This optimized routine can only create a basic sf */
561f659e5c7SJunchao Zhang 
562f659e5c7SJunchao Zhang   /* Set the graph of esf, which is easy for CreateEmbeddedLeafSF */
563f659e5c7SJunchao Zhang   ierr = PetscSFGetGraph(sf,&nroots,NULL,&ilocal,&iremote);CHKERRQ(ierr);
564f659e5c7SJunchao Zhang   ierr = PetscSFGetLeafRange(sf,&minleaf,&maxleaf);CHKERRQ(ierr);
565f659e5c7SJunchao Zhang   ierr = PetscMalloc1(nselected,&new_ilocal);CHKERRQ(ierr);
566f659e5c7SJunchao Zhang   ierr = PetscMalloc1(nselected,&new_iremote);CHKERRQ(ierr);
567f659e5c7SJunchao Zhang   for (i=0; i<nselected; i++) {
568f659e5c7SJunchao Zhang     const PetscInt l     = selected[i];
569f659e5c7SJunchao Zhang     new_ilocal[i]        = ilocal ? ilocal[l] : l;
570f659e5c7SJunchao Zhang     new_iremote[i].rank  = iremote[l].rank;
571f659e5c7SJunchao Zhang     new_iremote[i].index = iremote[l].index;
572f659e5c7SJunchao Zhang   }
573f659e5c7SJunchao Zhang 
574f659e5c7SJunchao Zhang   /* Tag selected leaves before PetscSFSetGraph since new_ilocal might turn into NULL since we use PETSC_OWN_POINTER below */
575f659e5c7SJunchao Zhang   maxlocal = (minleaf > maxleaf)? 0 : maxleaf-minleaf+1; /* maxleaf=-1 and minleaf=0 when nleaves=0 */
576f659e5c7SJunchao Zhang   ierr = PetscCalloc2(nroots,&rootdata,maxlocal,&leafdata);CHKERRQ(ierr);
577f659e5c7SJunchao Zhang   for (i=0; i<nselected; i++) leafdata[new_ilocal[i]-minleaf] = 1; /* -minleaf to adjust indices according to minleaf */
578f659e5c7SJunchao Zhang 
579f659e5c7SJunchao Zhang   ierr = PetscSFSetGraph(esf,nroots,nselected,new_ilocal,PETSC_OWN_POINTER,new_iremote,PETSC_OWN_POINTER);CHKERRQ(ierr);
580f659e5c7SJunchao Zhang 
581f659e5c7SJunchao Zhang   /* Set up the outgoing communication (i.e., send info). We can not reuse rmine etc in sf since there is no way to
582f659e5c7SJunchao Zhang      map rmine[i] (ilocal of leaves) back to selected[j]  (leaf indices).
583f659e5c7SJunchao Zhang    */
584f659e5c7SJunchao Zhang   ierr = MPI_Comm_group(PETSC_COMM_SELF,&group);CHKERRQ(ierr);
585f659e5c7SJunchao Zhang   ierr = PetscSFSetUpRanks(esf,group);CHKERRQ(ierr);
586f659e5c7SJunchao Zhang   ierr = MPI_Group_free(&group);CHKERRQ(ierr);
587f659e5c7SJunchao Zhang 
588f659e5c7SJunchao Zhang   /* Set up the incoming communication (i.e., recv info) */
589f659e5c7SJunchao Zhang   ierr = PetscSFGetRootInfo_Basic(sf,&niranks,&ndiranks,&iranks,&ioffset,&irootloc);CHKERRQ(ierr);
590f659e5c7SJunchao Zhang   bas  = (PetscSF_Basic*)esf->data;
591f659e5c7SJunchao Zhang   ierr = PetscMalloc2(niranks,&bas->iranks,niranks+1,&bas->ioffset);CHKERRQ(ierr);
592f659e5c7SJunchao Zhang   ierr = PetscMalloc1(ioffset[niranks],&bas->irootloc);CHKERRQ(ierr);
593f659e5c7SJunchao Zhang 
594f659e5c7SJunchao Zhang   /* Pass info about selected leaves to root buffer */
595eb02082bSJunchao Zhang   ierr = PetscSFReduceBegin_Basic(sf,MPIU_INT,PETSC_MEMTYPE_HOST,leafdata-minleaf,PETSC_MEMTYPE_HOST,rootdata,MPIU_REPLACE);CHKERRQ(ierr); /* -minleaf to re-adjust start address of leafdata */
596eb02082bSJunchao Zhang   ierr = PetscSFPackGetInUse(sf,MPIU_INT,rootdata,leafdata-minleaf,PETSC_OWN_POINTER,&link);CHKERRQ(ierr);
597*b7c0d12aSJunchao Zhang   ierr = PetscSFPackWaitall(link,PETSCSF_LEAF2ROOT_REDUCE);CHKERRQ(ierr);
598f659e5c7SJunchao Zhang 
599f659e5c7SJunchao Zhang   bas->niranks = bas->ndiranks = bas->ioffset[0] = 0;
600f659e5c7SJunchao Zhang   p = 0; /* Counter for connected leaf ranks */
601f659e5c7SJunchao Zhang   q = 0; /* Counter for connected roots */
602f659e5c7SJunchao Zhang   for (i=0; i<niranks; i++) {
603f659e5c7SJunchao Zhang     PetscBool connected = PETSC_FALSE; /* Is the current process still connected to this remote leaf rank? */
604eb02082bSJunchao Zhang     buffer = i < ndiranks? (PetscInt*)link->selfbuf[PETSC_MEMTYPE_HOST] : (PetscInt*)link->rootbuf[PETSC_MEMTYPE_HOST] + (ioffset[i] - ioffset[ndiranks]);
605f659e5c7SJunchao Zhang     for (j=ioffset[i],k=0; j<ioffset[i+1]; j++,k++) {
606b23bfdefSJunchao Zhang       if (buffer[k]) {bas->irootloc[q++] = irootloc[j]; connected = PETSC_TRUE;}
607f659e5c7SJunchao Zhang     }
608f659e5c7SJunchao Zhang     if (connected) {
609f659e5c7SJunchao Zhang       bas->niranks++;
610f659e5c7SJunchao Zhang       if (i<ndiranks) bas->ndiranks++;
611f659e5c7SJunchao Zhang       bas->iranks[p]    = iranks[i];
612f659e5c7SJunchao Zhang       bas->ioffset[p+1] = q;
613f659e5c7SJunchao Zhang       p++;
614f659e5c7SJunchao Zhang     }
615f659e5c7SJunchao Zhang   }
616f659e5c7SJunchao Zhang   bas->itotal = q;
617eb02082bSJunchao Zhang   ierr = PetscSFPackReclaim(sf,&link);CHKERRQ(ierr);
618f659e5c7SJunchao Zhang 
619f659e5c7SJunchao Zhang   /* Setup packing optimizations */
620eb02082bSJunchao Zhang   ierr = PetscSFPackSetupOptimizations_Basic(esf);CHKERRQ(ierr);
621f659e5c7SJunchao Zhang   esf->setupcalled = PETSC_TRUE; /* We have done setup ourselves! */
622f659e5c7SJunchao Zhang 
623f659e5c7SJunchao Zhang   ierr = PetscFree2(rootdata,leafdata);CHKERRQ(ierr);
624f659e5c7SJunchao Zhang   *newsf = esf;
625f659e5c7SJunchao Zhang   PetscFunctionReturn(0);
626f659e5c7SJunchao Zhang }
627f659e5c7SJunchao Zhang 
6288cc058d9SJed Brown PETSC_EXTERN PetscErrorCode PetscSFCreate_Basic(PetscSF sf)
62995fce210SBarry Smith {
63040e23c03SJunchao Zhang   PetscSF_Basic  *dat;
63195fce210SBarry Smith   PetscErrorCode ierr;
63295fce210SBarry Smith 
63395fce210SBarry Smith   PetscFunctionBegin;
63495fce210SBarry Smith   sf->ops->SetUp                = PetscSFSetUp_Basic;
63595fce210SBarry Smith   sf->ops->SetFromOptions       = PetscSFSetFromOptions_Basic;
63695fce210SBarry Smith   sf->ops->Reset                = PetscSFReset_Basic;
63795fce210SBarry Smith   sf->ops->Destroy              = PetscSFDestroy_Basic;
63895fce210SBarry Smith   sf->ops->View                 = PetscSFView_Basic;
6393482bfa8SJunchao Zhang   sf->ops->BcastAndOpBegin      = PetscSFBcastAndOpBegin_Basic;
6403482bfa8SJunchao Zhang   sf->ops->BcastAndOpEnd        = PetscSFBcastAndOpEnd_Basic;
64195fce210SBarry Smith   sf->ops->ReduceBegin          = PetscSFReduceBegin_Basic;
64295fce210SBarry Smith   sf->ops->ReduceEnd            = PetscSFReduceEnd_Basic;
64395fce210SBarry Smith   sf->ops->FetchAndOpBegin      = PetscSFFetchAndOpBegin_Basic;
64495fce210SBarry Smith   sf->ops->FetchAndOpEnd        = PetscSFFetchAndOpEnd_Basic;
6458750ddebSJunchao Zhang   sf->ops->GetLeafRanks         = PetscSFGetLeafRanks_Basic;
646f659e5c7SJunchao Zhang   sf->ops->CreateEmbeddedSF     = PetscSFCreateEmbeddedSF_Basic;
647f659e5c7SJunchao Zhang   sf->ops->CreateEmbeddedLeafSF = PetscSFCreateEmbeddedLeafSF_Basic;
64895fce210SBarry Smith 
64940e23c03SJunchao Zhang   ierr = PetscNewLog(sf,&dat);CHKERRQ(ierr);
65040e23c03SJunchao Zhang   sf->data = (void*)dat;
65195fce210SBarry Smith   PetscFunctionReturn(0);
65295fce210SBarry Smith }
653