xref: /petsc/src/vec/is/sf/tests/ex9.c (revision 97929ea760a70c780fc4b78d3065eb9e422113fe)
1*97929ea7SJunchao Zhang static char help[]= "This example shows 1) how to transfer vectors from a parent communicator to vectors on a child communicator and vice versa;\n\
2*97929ea7SJunchao Zhang   2) how to transfer vectors from a subcommunicator to vectors on another subcommunicator. The two subcommunicators are not\n\
3*97929ea7SJunchao Zhang   required to cover all processes in PETSC_COMM_WORLD; 3) how to copy a vector from a parent communicator to vectors on its child communicators.\n\n";
4*97929ea7SJunchao Zhang 
5*97929ea7SJunchao Zhang #include <petscvec.h>
6*97929ea7SJunchao Zhang int main(int argc,char **argv)
7*97929ea7SJunchao Zhang {
8*97929ea7SJunchao Zhang   PetscErrorCode ierr;
9*97929ea7SJunchao Zhang   PetscMPIInt    nproc,grank,mycolor;
10*97929ea7SJunchao Zhang   PetscInt       i,n,N = 20,low,high;
11*97929ea7SJunchao Zhang   MPI_Comm       subcomm;
12*97929ea7SJunchao Zhang   Vec            x,yg; /* global vectors on PETSC_COMM_WORLD */
13*97929ea7SJunchao Zhang   VecScatter     vscat;
14*97929ea7SJunchao Zhang   IS             ix,iy;
15*97929ea7SJunchao Zhang   PetscBool      world2sub  = PETSC_FALSE;  /* Copy a vector from WORLD to a subcomm? */
16*97929ea7SJunchao Zhang   PetscBool      sub2sub    = PETSC_FALSE;  /* Copy a vector from a subcomm to another subcomm? */
17*97929ea7SJunchao Zhang   PetscBool      world2subs = PETSC_FALSE;  /* Copy a vector from WORLD to multiple subcomms? */
18*97929ea7SJunchao Zhang 
19*97929ea7SJunchao Zhang   ierr = PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr;
20*97929ea7SJunchao Zhang   ierr = MPI_Comm_size(PETSC_COMM_WORLD,&nproc);CHKERRQ(ierr);
21*97929ea7SJunchao Zhang   ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&grank);CHKERRQ(ierr);
22*97929ea7SJunchao Zhang 
23*97929ea7SJunchao Zhang   if (nproc < 2) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_SIZ,"This test must have at least two processes to run");
24*97929ea7SJunchao Zhang 
25*97929ea7SJunchao Zhang   ierr = PetscOptionsGetBool(NULL,0,"-world2sub",&world2sub,NULL);CHKERRQ(ierr);
26*97929ea7SJunchao Zhang   ierr = PetscOptionsGetBool(NULL,0,"-sub2sub",&sub2sub,NULL);CHKERRQ(ierr);
27*97929ea7SJunchao Zhang   ierr = PetscOptionsGetBool(NULL,0,"-world2subs",&world2subs,NULL);CHKERRQ(ierr);
28*97929ea7SJunchao Zhang 
29*97929ea7SJunchao Zhang   /* Split PETSC_COMM_WORLD into three subcomms. Each process can only see the subcomm it belongs to */
30*97929ea7SJunchao Zhang   mycolor = grank % 3;
31*97929ea7SJunchao Zhang   ierr    = MPI_Comm_split(PETSC_COMM_WORLD,mycolor,grank,&subcomm);CHKERRQ(ierr);
32*97929ea7SJunchao Zhang 
33*97929ea7SJunchao Zhang   /*===========================================================================
34*97929ea7SJunchao Zhang    *  Transfer a vector x defined on PETSC_COMM_WORLD to a vector y defined on
35*97929ea7SJunchao Zhang    *  a subcommunicator of PETSC_COMM_WORLD and vice versa.
36*97929ea7SJunchao Zhang    *===========================================================================*/
37*97929ea7SJunchao Zhang   if (world2sub) {
38*97929ea7SJunchao Zhang     ierr = VecCreateMPI(PETSC_COMM_WORLD,PETSC_DECIDE,N,&x);CHKERRQ(ierr);
39*97929ea7SJunchao Zhang     ierr = PetscObjectSetName((PetscObject)x,"x_commworld");CHKERRQ(ierr); /* Give a name to view x clearly */
40*97929ea7SJunchao Zhang 
41*97929ea7SJunchao Zhang     /* Initialize x to [-0.0, -1.0, -2.0, ..., -19.0] */
42*97929ea7SJunchao Zhang     ierr = VecGetOwnershipRange(x,&low,&high);CHKERRQ(ierr);
43*97929ea7SJunchao Zhang     for (i=low; i<high; i++) {
44*97929ea7SJunchao Zhang       PetscScalar val = -i;
45*97929ea7SJunchao Zhang       ierr = VecSetValue(x,i,val,INSERT_VALUES);CHKERRQ(ierr);
46*97929ea7SJunchao Zhang     }
47*97929ea7SJunchao Zhang     ierr = VecAssemblyBegin(x);CHKERRQ(ierr);
48*97929ea7SJunchao Zhang     ierr = VecAssemblyEnd(x);CHKERRQ(ierr);
49*97929ea7SJunchao Zhang 
50*97929ea7SJunchao Zhang     /* Transfer x to a vector y only defined on subcomm0 and vice versa */
51*97929ea7SJunchao Zhang     if (mycolor == 0) { /* subcomm0 contains ranks 0, 3, 6, ... in PETSC_COMM_WORLD */
52*97929ea7SJunchao Zhang       Vec         y;
53*97929ea7SJunchao Zhang       PetscScalar *yvalue;
54*97929ea7SJunchao Zhang 
55*97929ea7SJunchao Zhang       ierr = VecCreateMPI(subcomm,PETSC_DECIDE,N,&y);CHKERRQ(ierr);
56*97929ea7SJunchao Zhang       ierr = PetscObjectSetName((PetscObject)y,"y_subcomm_0");CHKERRQ(ierr); /* Give a name to view y clearly */
57*97929ea7SJunchao Zhang       ierr = VecGetLocalSize(y,&n);CHKERRQ(ierr);
58*97929ea7SJunchao Zhang       ierr = VecGetArray(y,&yvalue);CHKERRQ(ierr);
59*97929ea7SJunchao Zhang       /* Create yg on PETSC_COMM_WORLD and alias yg with y. They share the memory pointed by yvalue.
60*97929ea7SJunchao Zhang         Note this is a collective call. All processes have to call it and supply consistent N.
61*97929ea7SJunchao Zhang       */
62*97929ea7SJunchao Zhang       ierr = VecCreateMPIWithArray(PETSC_COMM_WORLD,1,n,N,yvalue,&yg);CHKERRQ(ierr);
63*97929ea7SJunchao Zhang 
64*97929ea7SJunchao Zhang       /* Create an identity map that makes yg[i] = x[i], i=0..N-1 */
65*97929ea7SJunchao Zhang       ierr = VecGetOwnershipRange(yg,&low,&high);CHKERRQ(ierr); /* low, high are global indices */
66*97929ea7SJunchao Zhang       ierr = ISCreateStride(PETSC_COMM_SELF,high-low,low,1,&ix);CHKERRQ(ierr);
67*97929ea7SJunchao Zhang       ierr = ISDuplicate(ix,&iy);CHKERRQ(ierr);
68*97929ea7SJunchao Zhang 
69*97929ea7SJunchao Zhang       /* Union of ix's on subcomm0 covers the full range of [0,N) */
70*97929ea7SJunchao Zhang       ierr = VecScatterCreate(x,ix,yg,iy,&vscat);CHKERRQ(ierr);
71*97929ea7SJunchao Zhang       ierr = VecScatterBegin(vscat,x,yg,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
72*97929ea7SJunchao Zhang       ierr = VecScatterEnd(vscat,x,yg,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
73*97929ea7SJunchao Zhang 
74*97929ea7SJunchao Zhang       /* Once yg got the data from x, we return yvalue to y so that we can use y in other operations.
75*97929ea7SJunchao Zhang         VecGetArray must be paired with VecRestoreArray.
76*97929ea7SJunchao Zhang       */
77*97929ea7SJunchao Zhang       ierr = VecRestoreArray(y,&yvalue);CHKERRQ(ierr);
78*97929ea7SJunchao Zhang 
79*97929ea7SJunchao Zhang       /* Libraries on subcomm0 can safely use y now, for example, view and scale it */
80*97929ea7SJunchao Zhang       ierr = VecView(y,PETSC_VIEWER_STDOUT_(subcomm));CHKERRQ(ierr);
81*97929ea7SJunchao Zhang       ierr = VecScale(y,2.0);CHKERRQ(ierr);
82*97929ea7SJunchao Zhang 
83*97929ea7SJunchao Zhang       /* Send the new y back to x */
84*97929ea7SJunchao Zhang       ierr = VecGetArray(y,&yvalue);CHKERRQ(ierr); /* If VecScale is done on GPU, Petsc will prepare a valid yvalue for access */
85*97929ea7SJunchao Zhang       /* Supply new yvalue to yg without memory copying */
86*97929ea7SJunchao Zhang       ierr = VecPlaceArray(yg,yvalue);CHKERRQ(ierr);
87*97929ea7SJunchao Zhang       ierr = VecScatterBegin(vscat,yg,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
88*97929ea7SJunchao Zhang       ierr = VecScatterEnd(vscat,yg,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
89*97929ea7SJunchao Zhang       ierr = VecResetArray(yg);CHKERRQ(ierr);
90*97929ea7SJunchao Zhang       ierr = VecRestoreArray(y,&yvalue);CHKERRQ(ierr);
91*97929ea7SJunchao Zhang 
92*97929ea7SJunchao Zhang       ierr = VecDestroy(&y);CHKERRQ(ierr);
93*97929ea7SJunchao Zhang     } else {
94*97929ea7SJunchao Zhang       /* Ranks outside of subcomm0 do not supply values to yg */
95*97929ea7SJunchao Zhang       ierr = VecCreateMPIWithArray(PETSC_COMM_WORLD,1,0/*n*/,N,NULL,&yg);CHKERRQ(ierr);
96*97929ea7SJunchao Zhang 
97*97929ea7SJunchao Zhang       /* Ranks in subcomm0 already specified the full range of the identity map. The remaining
98*97929ea7SJunchao Zhang         ranks just need to create empty ISes to cheat VecScatterCreate.
99*97929ea7SJunchao Zhang       */
100*97929ea7SJunchao Zhang       ierr = ISCreateStride(PETSC_COMM_SELF,0,0,1,&ix);CHKERRQ(ierr);
101*97929ea7SJunchao Zhang       ierr = ISDuplicate(ix,&iy);CHKERRQ(ierr);
102*97929ea7SJunchao Zhang 
103*97929ea7SJunchao Zhang       ierr = VecScatterCreate(x,ix,yg,iy,&vscat);CHKERRQ(ierr);
104*97929ea7SJunchao Zhang       ierr = VecScatterBegin(vscat,x,yg,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
105*97929ea7SJunchao Zhang       ierr = VecScatterEnd(vscat,x,yg,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
106*97929ea7SJunchao Zhang 
107*97929ea7SJunchao Zhang       /* Send the new y back to x. Ranks outside of subcomm0 actually have nothing to send.
108*97929ea7SJunchao Zhang         But they have to call VecScatterBegin/End since these routines are collective.
109*97929ea7SJunchao Zhang       */
110*97929ea7SJunchao Zhang       ierr = VecScatterBegin(vscat,yg,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
111*97929ea7SJunchao Zhang       ierr = VecScatterEnd(vscat,yg,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
112*97929ea7SJunchao Zhang     }
113*97929ea7SJunchao Zhang 
114*97929ea7SJunchao Zhang     ierr = VecView(x,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
115*97929ea7SJunchao Zhang     ierr = ISDestroy(&ix);CHKERRQ(ierr);
116*97929ea7SJunchao Zhang     ierr = ISDestroy(&iy);CHKERRQ(ierr);
117*97929ea7SJunchao Zhang     ierr = VecDestroy(&x);CHKERRQ(ierr);
118*97929ea7SJunchao Zhang     ierr = VecDestroy(&yg);CHKERRQ(ierr);
119*97929ea7SJunchao Zhang     ierr = VecScatterDestroy(&vscat);CHKERRQ(ierr);
120*97929ea7SJunchao Zhang   } /* world2sub */
121*97929ea7SJunchao Zhang 
122*97929ea7SJunchao Zhang   /*===========================================================================
123*97929ea7SJunchao Zhang    *  Transfer a vector x defined on subcomm0 to a vector y defined on
124*97929ea7SJunchao Zhang    *  subcomm1. The two subcomms are not overlapping and their union is
125*97929ea7SJunchao Zhang    *  not necessarily equal to PETSC_COMM_WORLD.
126*97929ea7SJunchao Zhang    *===========================================================================*/
127*97929ea7SJunchao Zhang   if (sub2sub) {
128*97929ea7SJunchao Zhang     if (mycolor == 0) {
129*97929ea7SJunchao Zhang       /* Intentionally declare N as a local variable so that processes in subcomm1 do not know its value */
130*97929ea7SJunchao Zhang       PetscInt          n,N = 22;
131*97929ea7SJunchao Zhang       Vec               x,xg,yg;
132*97929ea7SJunchao Zhang       IS                ix,iy;
133*97929ea7SJunchao Zhang       VecScatter        vscat;
134*97929ea7SJunchao Zhang       const PetscScalar *xvalue;
135*97929ea7SJunchao Zhang       MPI_Comm          intercomm,parentcomm;
136*97929ea7SJunchao Zhang       PetscMPIInt       lrank;
137*97929ea7SJunchao Zhang 
138*97929ea7SJunchao Zhang       ierr = MPI_Comm_rank(subcomm,&lrank);CHKERRQ(ierr);
139*97929ea7SJunchao Zhang       ierr = VecCreateMPI(subcomm,PETSC_DECIDE,N,&x);CHKERRQ(ierr); /* x is on subcomm */
140*97929ea7SJunchao Zhang       ierr = VecGetOwnershipRange(x,&low,&high);CHKERRQ(ierr);
141*97929ea7SJunchao Zhang 
142*97929ea7SJunchao Zhang       /* initialize x = [0.0, 1.0, 2.0, ..., 21.0] */
143*97929ea7SJunchao Zhang       for (i=low; i<high; i++) {
144*97929ea7SJunchao Zhang         PetscScalar val = i;
145*97929ea7SJunchao Zhang         ierr = VecSetValue(x,i,val,INSERT_VALUES);CHKERRQ(ierr);
146*97929ea7SJunchao Zhang       }
147*97929ea7SJunchao Zhang       ierr = VecAssemblyBegin(x);CHKERRQ(ierr);
148*97929ea7SJunchao Zhang       ierr = VecAssemblyEnd(x);CHKERRQ(ierr);
149*97929ea7SJunchao Zhang 
150*97929ea7SJunchao Zhang       ierr = MPI_Intercomm_create(subcomm,0,PETSC_COMM_WORLD/*peer_comm*/,1,100/*tag*/,&intercomm);CHKERRQ(ierr);
151*97929ea7SJunchao Zhang 
152*97929ea7SJunchao Zhang       /* Tell rank 0 of subcomm1 the global size of x */
153*97929ea7SJunchao Zhang       if (!lrank) {ierr = MPI_Send(&N,1,MPIU_INT,0/*receiver's rank in remote comm, i.e., subcomm1*/,200/*tag*/,intercomm);CHKERRQ(ierr);}
154*97929ea7SJunchao Zhang 
155*97929ea7SJunchao Zhang       /* Create an intracomm Petsc can work on. Ranks in subcomm0 are ordered before ranks in subcomm1 in parentcomm.
156*97929ea7SJunchao Zhang         But this order actually does not matter, since what we care is vector y, which is defined on subcomm1.
157*97929ea7SJunchao Zhang       */
158*97929ea7SJunchao Zhang       ierr = MPI_Intercomm_merge(intercomm,0/*low*/,&parentcomm);CHKERRQ(ierr);
159*97929ea7SJunchao Zhang 
160*97929ea7SJunchao Zhang       /* Create a vector xg on parentcomm, which shares memory with x */
161*97929ea7SJunchao Zhang       ierr = VecGetArrayRead(x,&xvalue);CHKERRQ(ierr);
162*97929ea7SJunchao Zhang       ierr = VecGetLocalSize(x,&n);CHKERRQ(ierr);
163*97929ea7SJunchao Zhang       ierr = VecCreateMPIWithArray(parentcomm,1,n,N,xvalue,&xg);CHKERRQ(ierr);
164*97929ea7SJunchao Zhang 
165*97929ea7SJunchao Zhang       /* Ranks in subcomm 0 have nothing on yg, so they simply have n=0, array=NULL */
166*97929ea7SJunchao Zhang       ierr = VecCreateMPIWithArray(parentcomm,1,0/*n*/,N,NULL/*array*/,&yg);CHKERRQ(ierr);
167*97929ea7SJunchao Zhang 
168*97929ea7SJunchao Zhang       /* Create the vecscatter, which does identity map by setting yg[i] = xg[i], i=0..N-1. */
169*97929ea7SJunchao Zhang       ierr = VecGetOwnershipRange(xg,&low,&high);CHKERRQ(ierr); /* low, high are global indices of xg */
170*97929ea7SJunchao Zhang       ierr = ISCreateStride(PETSC_COMM_SELF,high-low,low,1,&ix);CHKERRQ(ierr);
171*97929ea7SJunchao Zhang       ierr = ISDuplicate(ix,&iy);CHKERRQ(ierr);
172*97929ea7SJunchao Zhang       ierr = VecScatterCreate(xg,ix,yg,iy,&vscat);CHKERRQ(ierr);
173*97929ea7SJunchao Zhang 
174*97929ea7SJunchao Zhang       /* Scatter values from xg to yg */
175*97929ea7SJunchao Zhang       ierr = VecScatterBegin(vscat,xg,yg,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
176*97929ea7SJunchao Zhang       ierr = VecScatterEnd(vscat,xg,yg,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
177*97929ea7SJunchao Zhang 
178*97929ea7SJunchao Zhang       /* After the VecScatter is done, xg is idle so we can safely return xvalue to x */
179*97929ea7SJunchao Zhang       ierr = VecRestoreArrayRead(x,&xvalue);CHKERRQ(ierr);
180*97929ea7SJunchao Zhang       ierr = VecDestroy(&x);CHKERRQ(ierr);
181*97929ea7SJunchao Zhang       ierr = ISDestroy(&ix);CHKERRQ(ierr);
182*97929ea7SJunchao Zhang       ierr = ISDestroy(&iy);CHKERRQ(ierr);
183*97929ea7SJunchao Zhang       ierr = VecDestroy(&xg);CHKERRQ(ierr);
184*97929ea7SJunchao Zhang       ierr = VecDestroy(&yg);CHKERRQ(ierr);
185*97929ea7SJunchao Zhang       ierr = VecScatterDestroy(&vscat);CHKERRQ(ierr);
186*97929ea7SJunchao Zhang       ierr = MPI_Comm_free(&intercomm);CHKERRQ(ierr);
187*97929ea7SJunchao Zhang       ierr = MPI_Comm_free(&parentcomm);CHKERRQ(ierr);
188*97929ea7SJunchao Zhang     } else if (mycolor == 1) { /* subcomm 1, containing ranks 1, 4, 7, ... in PETSC_COMM_WORLD */
189*97929ea7SJunchao Zhang       PetscInt    n,N;
190*97929ea7SJunchao Zhang       Vec         y,xg,yg;
191*97929ea7SJunchao Zhang       IS          ix,iy;
192*97929ea7SJunchao Zhang       VecScatter  vscat;
193*97929ea7SJunchao Zhang       PetscScalar *yvalue;
194*97929ea7SJunchao Zhang       MPI_Comm    intercomm,parentcomm;
195*97929ea7SJunchao Zhang       PetscMPIInt lrank;
196*97929ea7SJunchao Zhang 
197*97929ea7SJunchao Zhang       ierr = MPI_Comm_rank(subcomm,&lrank);CHKERRQ(ierr);
198*97929ea7SJunchao Zhang       ierr = MPI_Intercomm_create(subcomm,0,PETSC_COMM_WORLD/*peer_comm*/,0/*remote_leader*/,100/*tag*/,&intercomm);CHKERRQ(ierr);
199*97929ea7SJunchao Zhang 
200*97929ea7SJunchao Zhang       /* Two rank-0 are talking */
201*97929ea7SJunchao Zhang       if (!lrank) {ierr = MPI_Recv(&N,1,MPIU_INT,0/*sender's rank in remote comm, i.e. subcomm0*/,200/*tag*/,intercomm,MPI_STATUS_IGNORE);CHKERRQ(ierr);}
202*97929ea7SJunchao Zhang       /* Rank 0 of subcomm1 bcasts N to its members */
203*97929ea7SJunchao Zhang       ierr = MPI_Bcast(&N,1,MPIU_INT,0/*local root*/,subcomm);CHKERRQ(ierr);
204*97929ea7SJunchao Zhang 
205*97929ea7SJunchao Zhang       /* Create a intracomm Petsc can work on */
206*97929ea7SJunchao Zhang       ierr = MPI_Intercomm_merge(intercomm,1/*high*/,&parentcomm);CHKERRQ(ierr);
207*97929ea7SJunchao Zhang 
208*97929ea7SJunchao Zhang       /* Ranks in subcomm1 have nothing on xg, so they simply have n=0, array=NULL.*/
209*97929ea7SJunchao Zhang       ierr = VecCreateMPIWithArray(parentcomm,1/*bs*/,0/*n*/,N,NULL/*array*/,&xg);CHKERRQ(ierr);
210*97929ea7SJunchao Zhang 
211*97929ea7SJunchao Zhang       ierr = VecCreateMPI(subcomm,PETSC_DECIDE,N,&y);CHKERRQ(ierr);
212*97929ea7SJunchao Zhang       ierr = PetscObjectSetName((PetscObject)y,"y_subcomm_1");CHKERRQ(ierr); /* Give a name to view y clearly */
213*97929ea7SJunchao Zhang       ierr = VecGetLocalSize(y,&n);CHKERRQ(ierr);
214*97929ea7SJunchao Zhang       ierr = VecGetArray(y,&yvalue);CHKERRQ(ierr);
215*97929ea7SJunchao Zhang       /* Create a vector yg on parentcomm, which shares memory with y. xg and yg must be
216*97929ea7SJunchao Zhang         created in the same order in subcomm0/1. For example, we can not reverse the order of
217*97929ea7SJunchao Zhang         creating xg and yg in subcomm1.
218*97929ea7SJunchao Zhang       */
219*97929ea7SJunchao Zhang       ierr = VecCreateMPIWithArray(parentcomm,1/*bs*/,n,N,yvalue,&yg);CHKERRQ(ierr);
220*97929ea7SJunchao Zhang 
221*97929ea7SJunchao Zhang       /* Ranks in subcomm0 already specified the full range of the identity map.
222*97929ea7SJunchao Zhang         ranks in subcomm1 just need to create empty ISes to cheat VecScatterCreate.
223*97929ea7SJunchao Zhang       */
224*97929ea7SJunchao Zhang       ierr = ISCreateStride(PETSC_COMM_SELF,0,0,1,&ix);CHKERRQ(ierr);
225*97929ea7SJunchao Zhang       ierr = ISDuplicate(ix,&iy);CHKERRQ(ierr);
226*97929ea7SJunchao Zhang       ierr = VecScatterCreate(xg,ix,yg,iy,&vscat);CHKERRQ(ierr);
227*97929ea7SJunchao Zhang 
228*97929ea7SJunchao Zhang       /* Scatter values from xg to yg */
229*97929ea7SJunchao Zhang       ierr = VecScatterBegin(vscat,xg,yg,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
230*97929ea7SJunchao Zhang       ierr = VecScatterEnd(vscat,xg,yg,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
231*97929ea7SJunchao Zhang 
232*97929ea7SJunchao Zhang       /* After the VecScatter is done, values in yg are available. y is our interest, so we return yvalue to y */
233*97929ea7SJunchao Zhang       ierr = VecRestoreArray(y,&yvalue);CHKERRQ(ierr);
234*97929ea7SJunchao Zhang 
235*97929ea7SJunchao Zhang       /* Libraries on subcomm1 can safely use y now, for example, view it */
236*97929ea7SJunchao Zhang       ierr = VecView(y,PETSC_VIEWER_STDOUT_(subcomm));CHKERRQ(ierr);
237*97929ea7SJunchao Zhang 
238*97929ea7SJunchao Zhang       ierr = VecDestroy(&y);CHKERRQ(ierr);
239*97929ea7SJunchao Zhang       ierr = ISDestroy(&ix);CHKERRQ(ierr);
240*97929ea7SJunchao Zhang       ierr = ISDestroy(&iy);CHKERRQ(ierr);
241*97929ea7SJunchao Zhang       ierr = VecDestroy(&xg);CHKERRQ(ierr);
242*97929ea7SJunchao Zhang       ierr = VecDestroy(&yg);CHKERRQ(ierr);
243*97929ea7SJunchao Zhang       ierr = VecScatterDestroy(&vscat);CHKERRQ(ierr);
244*97929ea7SJunchao Zhang       ierr = MPI_Comm_free(&intercomm);CHKERRQ(ierr);
245*97929ea7SJunchao Zhang       ierr = MPI_Comm_free(&parentcomm);CHKERRQ(ierr);
246*97929ea7SJunchao Zhang     } else if (mycolor == 2) { /* subcomm2 */
247*97929ea7SJunchao Zhang       /* Processes in subcomm2 do not participate in the VecScatter. They can freely do unrelated things on subcomm2 */
248*97929ea7SJunchao Zhang     }
249*97929ea7SJunchao Zhang   } /* sub2sub */
250*97929ea7SJunchao Zhang 
251*97929ea7SJunchao Zhang   /*===========================================================================
252*97929ea7SJunchao Zhang    *  Copy a vector x defined on PETSC_COMM_WORLD to vectors y defined on
253*97929ea7SJunchao Zhang    *  every subcommunicator of PETSC_COMM_WORLD. We could use multiple transfers
254*97929ea7SJunchao Zhang    *  as we did in case 1, but that is not efficient. Instead, we use one vecscatter
255*97929ea7SJunchao Zhang    *  to achieve that.
256*97929ea7SJunchao Zhang    *===========================================================================*/
257*97929ea7SJunchao Zhang   if (world2subs) {
258*97929ea7SJunchao Zhang     Vec         y,yg;
259*97929ea7SJunchao Zhang     PetscInt    n,N=15,xstart,ystart,low,high;
260*97929ea7SJunchao Zhang     PetscScalar *yvalue;
261*97929ea7SJunchao Zhang 
262*97929ea7SJunchao Zhang     /* Initialize x to [0, 1, 2, 3, ..., N-1] */
263*97929ea7SJunchao Zhang     ierr = VecCreateMPI(PETSC_COMM_WORLD,PETSC_DECIDE,N,&x);CHKERRQ(ierr);
264*97929ea7SJunchao Zhang     ierr = VecGetOwnershipRange(x,&low,&high);CHKERRQ(ierr);
265*97929ea7SJunchao Zhang     for (i=low; i<high; i++) {ierr = VecSetValue(x,i,(PetscScalar)i,INSERT_VALUES);CHKERRQ(ierr);}
266*97929ea7SJunchao Zhang     ierr = VecAssemblyBegin(x);CHKERRQ(ierr);
267*97929ea7SJunchao Zhang     ierr = VecAssemblyEnd(x);CHKERRQ(ierr);
268*97929ea7SJunchao Zhang 
269*97929ea7SJunchao Zhang     /* Every subcomm has a y as long as x */
270*97929ea7SJunchao Zhang     ierr = VecCreateMPI(subcomm,PETSC_DECIDE,N,&y);CHKERRQ(ierr);
271*97929ea7SJunchao Zhang     ierr = VecGetLocalSize(y,&n);CHKERRQ(ierr);
272*97929ea7SJunchao Zhang 
273*97929ea7SJunchao Zhang     /* Create a global vector yg on PETSC_COMM_WORLD using y's memory. yg's global size = N*(number of subcommunicators).
274*97929ea7SJunchao Zhang        Eeach rank in subcomms contributes a piece to construct the global yg. Keep in mind that pieces from a subcomm are not
275*97929ea7SJunchao Zhang        necessarily consecutive in yg. That depends on how PETSC_COMM_WORLD is split. In our case, subcomm0 is made of rank
276*97929ea7SJunchao Zhang        0, 3, 6 etc from PETSC_COMM_WORLD. So subcomm0's pieces are interleaved with pieces from other subcomms in yg.
277*97929ea7SJunchao Zhang     */
278*97929ea7SJunchao Zhang     ierr = VecGetArray(y,&yvalue);CHKERRQ(ierr);
279*97929ea7SJunchao Zhang     ierr = VecCreateMPIWithArray(PETSC_COMM_WORLD,1,n,PETSC_DECIDE,yvalue,&yg);CHKERRQ(ierr);
280*97929ea7SJunchao Zhang     ierr = PetscObjectSetName((PetscObject)yg,"yg_on_subcomms");CHKERRQ(ierr); /* Give a name to view yg clearly */
281*97929ea7SJunchao Zhang 
282*97929ea7SJunchao Zhang     /* The following two lines are key. From xstart, we know where to pull entries from x. Note that we get xstart from y,
283*97929ea7SJunchao Zhang        since first entry of y on this rank is from x[xstart]. From ystart, we know where ot put entries to yg.
284*97929ea7SJunchao Zhang      */
285*97929ea7SJunchao Zhang     ierr = VecGetOwnershipRange(y,&xstart,NULL);CHKERRQ(ierr);
286*97929ea7SJunchao Zhang     ierr = VecGetOwnershipRange(yg,&ystart,NULL);CHKERRQ(ierr);
287*97929ea7SJunchao Zhang 
288*97929ea7SJunchao Zhang     ierr = ISCreateStride(PETSC_COMM_SELF,n,xstart,1,&ix);CHKERRQ(ierr);
289*97929ea7SJunchao Zhang     ierr = ISCreateStride(PETSC_COMM_SELF,n,ystart,1,&iy);CHKERRQ(ierr);
290*97929ea7SJunchao Zhang     ierr = VecScatterCreate(x,ix,yg,iy,&vscat);CHKERRQ(ierr);
291*97929ea7SJunchao Zhang     ierr = VecScatterBegin(vscat,x,yg,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
292*97929ea7SJunchao Zhang     ierr = VecScatterEnd(vscat,x,yg,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
293*97929ea7SJunchao Zhang 
294*97929ea7SJunchao Zhang     /* View yg on PETSC_COMM_WORLD before destroying it. We shall see the interleaving effect in output. */
295*97929ea7SJunchao Zhang     ierr = VecView(yg,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
296*97929ea7SJunchao Zhang     ierr = VecDestroy(&yg);CHKERRQ(ierr);
297*97929ea7SJunchao Zhang 
298*97929ea7SJunchao Zhang     /* Restory yvalue so that processes in subcomm can use y from now on. */
299*97929ea7SJunchao Zhang     ierr = VecRestoreArray(y,&yvalue);CHKERRQ(ierr);
300*97929ea7SJunchao Zhang     ierr = VecScale(y,3.0);CHKERRQ(ierr);
301*97929ea7SJunchao Zhang 
302*97929ea7SJunchao Zhang     ierr = ISDestroy(&ix);CHKERRQ(ierr); /* One can also destroy ix, iy immediately after VecScatterCreate() */
303*97929ea7SJunchao Zhang     ierr = ISDestroy(&iy);CHKERRQ(ierr);
304*97929ea7SJunchao Zhang     ierr = VecDestroy(&x);CHKERRQ(ierr);
305*97929ea7SJunchao Zhang     ierr = VecDestroy(&y);CHKERRQ(ierr);
306*97929ea7SJunchao Zhang     ierr = VecScatterDestroy(&vscat);CHKERRQ(ierr);
307*97929ea7SJunchao Zhang   } /* world2subs */
308*97929ea7SJunchao Zhang 
309*97929ea7SJunchao Zhang   ierr = MPI_Comm_free(&subcomm);CHKERRQ(ierr);
310*97929ea7SJunchao Zhang   ierr = PetscFinalize();
311*97929ea7SJunchao Zhang   return ierr;
312*97929ea7SJunchao Zhang }
313*97929ea7SJunchao Zhang 
314*97929ea7SJunchao Zhang /*TEST
315*97929ea7SJunchao Zhang 
316*97929ea7SJunchao Zhang    build:
317*97929ea7SJunchao Zhang      requires: !define(PETSC_HAVE_MPIUNI)
318*97929ea7SJunchao Zhang    testset:
319*97929ea7SJunchao Zhang      nsize: 7
320*97929ea7SJunchao Zhang 
321*97929ea7SJunchao Zhang      test:
322*97929ea7SJunchao Zhang        suffix: 1
323*97929ea7SJunchao Zhang        args: -world2sub
324*97929ea7SJunchao Zhang 
325*97929ea7SJunchao Zhang      test:
326*97929ea7SJunchao Zhang        suffix: 2
327*97929ea7SJunchao Zhang        args: -sub2sub
328*97929ea7SJunchao Zhang 
329*97929ea7SJunchao Zhang      test:
330*97929ea7SJunchao Zhang        suffix: 3
331*97929ea7SJunchao Zhang        args: -world2subs
332*97929ea7SJunchao Zhang 
333*97929ea7SJunchao Zhang      test:
334*97929ea7SJunchao Zhang        suffix: 4
335*97929ea7SJunchao Zhang        args: -world2sub -sf_type neighbor
336*97929ea7SJunchao Zhang        output_file: output/ex9_1.out
337*97929ea7SJunchao Zhang        # OpenMPI has a bug wrt MPI_Neighbor_alltoallv etc (https://github.com/open-mpi/ompi/pull/6782). Once the patch is in, we can remove !define(PETSC_HAVE_OMPI_MAJOR_VERSION)
338*97929ea7SJunchao Zhang        requires: define(PETSC_HAVE_MPI_NEIGHBORHOOD_COLLECTIVES) !define(PETSC_HAVE_OMPI_MAJOR_VERSION)
339*97929ea7SJunchao Zhang TEST*/
340*97929ea7SJunchao Zhang 
341