1c4762a1bSJed Brown static char help[] = "Test PetscSFFetchAndOp on patterned SF graphs. PetscSFFetchAndOp internally uses PetscSFBcastAndOp \n\
2c4762a1bSJed Brown and PetscSFReduce. So it is a good test to see if they all work for patterned graphs.\n\
3c4762a1bSJed Brown Run with ./prog -op [replace | sum]\n\n";
4c4762a1bSJed Brown
5c4762a1bSJed Brown #include <petscvec.h>
6c4762a1bSJed Brown #include <petscsf.h>
main(int argc,char ** argv)7d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
8d71ae5a4SJacob Faibussowitsch {
9c4762a1bSJed Brown PetscInt i, N = 10, low, high, nleaves;
10c4762a1bSJed Brown PetscMPIInt size, rank;
11c4762a1bSJed Brown Vec x, y, y2, gy2;
12c4762a1bSJed Brown PetscScalar *rootdata, *leafdata, *leafupdate;
13c4762a1bSJed Brown PetscLayout layout;
14c4762a1bSJed Brown PetscSF gathersf, allgathersf, alltoallsf;
15c4762a1bSJed Brown MPI_Op op = MPI_SUM;
16c4762a1bSJed Brown char opname[64];
17c4762a1bSJed Brown const char *mpiopname;
18c4762a1bSJed Brown PetscBool flag, isreplace, issum;
19c4762a1bSJed Brown
20327415f7SBarry Smith PetscFunctionBeginUser;
21*c8025a54SPierre Jolivet PetscCall(PetscInitialize(&argc, &argv, NULL, help));
229566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
239566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
24c4762a1bSJed Brown
259566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetString(NULL, NULL, "-op", opname, sizeof(opname), &flag));
269566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(opname, "replace", &isreplace));
279566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(opname, "sum", &issum));
28c4762a1bSJed Brown
299371c9d4SSatish Balay if (isreplace) {
309371c9d4SSatish Balay op = MPI_REPLACE;
319371c9d4SSatish Balay mpiopname = "MPI_REPLACE";
329371c9d4SSatish Balay } else if (issum) {
339371c9d4SSatish Balay op = MPIU_SUM;
349371c9d4SSatish Balay mpiopname = "MPI_SUM";
359371c9d4SSatish Balay } else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Unsupported argument (%s) to -op, which must be 'replace' or 'sum'", opname);
36c4762a1bSJed Brown
379566063dSJacob Faibussowitsch PetscCall(VecCreate(PETSC_COMM_WORLD, &x));
389566063dSJacob Faibussowitsch PetscCall(VecSetFromOptions(x));
399566063dSJacob Faibussowitsch PetscCall(VecSetSizes(x, PETSC_DECIDE, N));
40c4762a1bSJed Brown
41c4762a1bSJed Brown /*-------------------------------------*/
42c4762a1bSJed Brown /* PETSCSF_PATTERN_GATHER */
43c4762a1bSJed Brown /*-------------------------------------*/
44c4762a1bSJed Brown
45c4762a1bSJed Brown /* set MPI vec x to [1, 2, .., N] */
469566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(x, &low, &high));
479566063dSJacob Faibussowitsch for (i = low; i < high; i++) PetscCall(VecSetValue(x, i, (PetscScalar)i + 1.0, INSERT_VALUES));
489566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(x));
499566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(x));
50c4762a1bSJed Brown
51c4762a1bSJed Brown /* Create the gather SF */
529566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\nTesting PetscSFFetchAndOp on a PETSCSF_PATTERN_GATHER graph with op = %s\n", mpiopname));
539566063dSJacob Faibussowitsch PetscCall(VecGetLayout(x, &layout));
549566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(PETSC_COMM_WORLD, &gathersf));
559566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraphWithPattern(gathersf, layout, PETSCSF_PATTERN_GATHER));
56c4762a1bSJed Brown
57c4762a1bSJed Brown /* Create the leaf vector y (seq vector) and its duplicate y2 working as leafupdate */
589566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(gathersf, NULL, &nleaves, NULL, NULL));
599566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, nleaves, &y));
609566063dSJacob Faibussowitsch PetscCall(VecDuplicate(y, &y2));
61c4762a1bSJed Brown
629566063dSJacob Faibussowitsch PetscCall(VecGetArray(x, &rootdata));
639566063dSJacob Faibussowitsch PetscCall(VecGetArray(y, &leafdata));
649566063dSJacob Faibussowitsch PetscCall(VecGetArray(y2, &leafupdate));
65c4762a1bSJed Brown
66c4762a1bSJed Brown /* Bcast x to y,to initialize y = [1,N], then scale y to make leafupdate = y = [2,2*N] */
679566063dSJacob Faibussowitsch PetscCall(PetscSFBcastBegin(gathersf, MPIU_SCALAR, rootdata, leafdata, MPI_REPLACE));
689566063dSJacob Faibussowitsch PetscCall(PetscSFBcastEnd(gathersf, MPIU_SCALAR, rootdata, leafdata, MPI_REPLACE));
699566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(y, &leafdata));
709566063dSJacob Faibussowitsch PetscCall(VecScale(y, 2));
719566063dSJacob Faibussowitsch PetscCall(VecGetArray(y, &leafdata));
72c4762a1bSJed Brown
73c4762a1bSJed Brown /* FetchAndOp x to y */
749566063dSJacob Faibussowitsch PetscCall(PetscSFFetchAndOpBegin(gathersf, MPIU_SCALAR, rootdata, leafdata, leafupdate, op));
759566063dSJacob Faibussowitsch PetscCall(PetscSFFetchAndOpEnd(gathersf, MPIU_SCALAR, rootdata, leafdata, leafupdate, op));
76c4762a1bSJed Brown
77c4762a1bSJed Brown /* View roots (x) and leafupdate (y2). Since this is a gather graph, leafudpate = rootdata = [1,N], then rootdata += leafdata, i.e., [3,3*N] */
789566063dSJacob Faibussowitsch PetscCall(VecCreateMPIWithArray(PETSC_COMM_WORLD, 1, nleaves, PETSC_DECIDE, leafupdate, &gy2));
799566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)x, "rootdata"));
809566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)gy2, "leafupdate"));
81c4762a1bSJed Brown
829566063dSJacob Faibussowitsch PetscCall(VecView(x, PETSC_VIEWER_STDOUT_WORLD));
839566063dSJacob Faibussowitsch PetscCall(VecView(gy2, PETSC_VIEWER_STDOUT_WORLD));
849566063dSJacob Faibussowitsch PetscCall(VecDestroy(&gy2));
85c4762a1bSJed Brown
869566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(y2, &leafupdate));
879566063dSJacob Faibussowitsch PetscCall(VecDestroy(&y2));
88c4762a1bSJed Brown
899566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(y, &leafdata));
909566063dSJacob Faibussowitsch PetscCall(VecDestroy(&y));
91c4762a1bSJed Brown
929566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(x, &rootdata));
939566063dSJacob Faibussowitsch /* PetscCall(VecDestroy(&x)); */ /* We will reuse x in ALLGATHER, so do not destroy it */
94c4762a1bSJed Brown
959566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&gathersf));
96c4762a1bSJed Brown
97c4762a1bSJed Brown /*-------------------------------------*/
98c4762a1bSJed Brown /* PETSCSF_PATTERN_ALLGATHER */
99c4762a1bSJed Brown /*-------------------------------------*/
100c4762a1bSJed Brown
101c4762a1bSJed Brown /* set MPI vec x to [1, 2, .., N] */
1029566063dSJacob Faibussowitsch for (i = low; i < high; i++) PetscCall(VecSetValue(x, i, (PetscScalar)i + 1.0, INSERT_VALUES));
1039566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(x));
1049566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(x));
105c4762a1bSJed Brown
106c4762a1bSJed Brown /* Create the allgather SF */
1079566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\nTesting PetscSFFetchAndOp on a PETSCSF_PATTERN_ALLGATHER graph with op = %s\n", mpiopname));
1089566063dSJacob Faibussowitsch PetscCall(VecGetLayout(x, &layout));
1099566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(PETSC_COMM_WORLD, &allgathersf));
1109566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraphWithPattern(allgathersf, layout, PETSCSF_PATTERN_ALLGATHER));
111c4762a1bSJed Brown
112c4762a1bSJed Brown /* Create the leaf vector y (seq vector) and its duplicate y2 working as leafupdate */
1139566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(allgathersf, NULL, &nleaves, NULL, NULL));
1149566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, nleaves, &y));
1159566063dSJacob Faibussowitsch PetscCall(VecDuplicate(y, &y2));
116c4762a1bSJed Brown
1179566063dSJacob Faibussowitsch PetscCall(VecGetArray(x, &rootdata));
1189566063dSJacob Faibussowitsch PetscCall(VecGetArray(y, &leafdata));
1199566063dSJacob Faibussowitsch PetscCall(VecGetArray(y2, &leafupdate));
120c4762a1bSJed Brown
121c4762a1bSJed Brown /* Bcast x to y, to initialize y = [1,N], then scale y to make leafupdate = y = [2,2*N] */
1229566063dSJacob Faibussowitsch PetscCall(PetscSFBcastBegin(allgathersf, MPIU_SCALAR, rootdata, leafdata, MPI_REPLACE));
1239566063dSJacob Faibussowitsch PetscCall(PetscSFBcastEnd(allgathersf, MPIU_SCALAR, rootdata, leafdata, MPI_REPLACE));
1249566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(y, &leafdata));
1259566063dSJacob Faibussowitsch PetscCall(VecScale(y, 2));
1269566063dSJacob Faibussowitsch PetscCall(VecGetArray(y, &leafdata));
127c4762a1bSJed Brown
128c4762a1bSJed Brown /* FetchAndOp x to y */
1299566063dSJacob Faibussowitsch PetscCall(PetscSFFetchAndOpBegin(allgathersf, MPIU_SCALAR, rootdata, leafdata, leafupdate, op));
1309566063dSJacob Faibussowitsch PetscCall(PetscSFFetchAndOpEnd(allgathersf, MPIU_SCALAR, rootdata, leafdata, leafupdate, op));
131c4762a1bSJed Brown
132c4762a1bSJed Brown /* View roots (x) and leafupdate (y2). Since this is an allgather graph, we have (suppose ranks get updates in ascending order)
133c4762a1bSJed Brown rank 0: leafupdate = rootdata = [1,N], rootdata += leafdata = [3,3*N]
134c4762a1bSJed Brown rank 1: leafupdate = rootdata = [3,3*N], rootdata += leafdata = [5,5*N]
135c4762a1bSJed Brown rank 2: leafupdate = rootdata = [5,5*N], rootdata += leafdata = [7,7*N]
136c4762a1bSJed Brown ...
137c4762a1bSJed Brown */
1389566063dSJacob Faibussowitsch PetscCall(VecCreateMPIWithArray(PETSC_COMM_WORLD, 1, nleaves, PETSC_DECIDE, leafupdate, &gy2));
1399566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)x, "rootdata"));
1409566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)gy2, "leafupdate"));
141c4762a1bSJed Brown
1429566063dSJacob Faibussowitsch PetscCall(VecView(x, PETSC_VIEWER_STDOUT_WORLD));
1439566063dSJacob Faibussowitsch PetscCall(VecView(gy2, PETSC_VIEWER_STDOUT_WORLD));
1449566063dSJacob Faibussowitsch PetscCall(VecDestroy(&gy2));
145c4762a1bSJed Brown
1469566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(y2, &leafupdate));
1479566063dSJacob Faibussowitsch PetscCall(VecDestroy(&y2));
148c4762a1bSJed Brown
1499566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(y, &leafdata));
1509566063dSJacob Faibussowitsch PetscCall(VecDestroy(&y));
151c4762a1bSJed Brown
1529566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(x, &rootdata));
1539566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x)); /* We won't reuse x in ALLGATHER, so destroy it */
154c4762a1bSJed Brown
1559566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&allgathersf));
156c4762a1bSJed Brown
157c4762a1bSJed Brown /*-------------------------------------*/
158c4762a1bSJed Brown /* PETSCSF_PATTERN_ALLTOALL */
159c4762a1bSJed Brown /*-------------------------------------*/
160c4762a1bSJed Brown
1619566063dSJacob Faibussowitsch PetscCall(VecCreate(PETSC_COMM_WORLD, &x));
1629566063dSJacob Faibussowitsch PetscCall(VecSetFromOptions(x));
1639566063dSJacob Faibussowitsch PetscCall(VecSetSizes(x, size, PETSC_DECIDE));
164c4762a1bSJed Brown
165c4762a1bSJed Brown /* set MPI vec x to [1, 2, .., size^2] */
1669566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(x, &low, &high));
1679566063dSJacob Faibussowitsch for (i = low; i < high; i++) PetscCall(VecSetValue(x, i, (PetscScalar)i + 1.0, INSERT_VALUES));
1689566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(x));
1699566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(x));
170c4762a1bSJed Brown
171c4762a1bSJed Brown /* Create the alltoall SF */
1729566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\nTesting PetscSFFetchAndOp on a PETSCSF_PATTERN_ALLTOALL graph with op = %s\n", mpiopname));
1739566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(PETSC_COMM_WORLD, &alltoallsf));
1749566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraphWithPattern(alltoallsf, NULL /*insignificant*/, PETSCSF_PATTERN_ALLTOALL));
175c4762a1bSJed Brown
176c4762a1bSJed Brown /* Create the leaf vector y (seq vector) and its duplicate y2 working as leafupdate */
1779566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(alltoallsf, NULL, &nleaves, NULL, NULL));
1789566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, nleaves, &y));
1799566063dSJacob Faibussowitsch PetscCall(VecDuplicate(y, &y2));
180c4762a1bSJed Brown
1819566063dSJacob Faibussowitsch PetscCall(VecGetArray(x, &rootdata));
1829566063dSJacob Faibussowitsch PetscCall(VecGetArray(y, &leafdata));
1839566063dSJacob Faibussowitsch PetscCall(VecGetArray(y2, &leafupdate));
184c4762a1bSJed Brown
185c4762a1bSJed Brown /* Bcast x to y, to initialize y = 1+rank+size*i, with i=0..size-1 */
1869566063dSJacob Faibussowitsch PetscCall(PetscSFBcastBegin(alltoallsf, MPIU_SCALAR, rootdata, leafdata, MPI_REPLACE));
1879566063dSJacob Faibussowitsch PetscCall(PetscSFBcastEnd(alltoallsf, MPIU_SCALAR, rootdata, leafdata, MPI_REPLACE));
188c4762a1bSJed Brown
189c4762a1bSJed Brown /* FetchAndOp x to y */
1909566063dSJacob Faibussowitsch PetscCall(PetscSFFetchAndOpBegin(alltoallsf, MPIU_SCALAR, rootdata, leafdata, leafupdate, op));
1919566063dSJacob Faibussowitsch PetscCall(PetscSFFetchAndOpEnd(alltoallsf, MPIU_SCALAR, rootdata, leafdata, leafupdate, op));
192c4762a1bSJed Brown
193c4762a1bSJed Brown /* View roots (x) and leafupdate (y2). Since this is an alltoall graph, each root has only one leaf.
194c4762a1bSJed Brown So, leafupdate = rootdata = 1+rank+size*i, i=0..size-1; and rootdata += leafdata, i.e., rootdata = [2,2*N]
195c4762a1bSJed Brown */
1969566063dSJacob Faibussowitsch PetscCall(VecCreateMPIWithArray(PETSC_COMM_WORLD, 1, nleaves, PETSC_DECIDE, leafupdate, &gy2));
1979566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)x, "rootdata"));
1989566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)gy2, "leafupdate"));
199c4762a1bSJed Brown
2009566063dSJacob Faibussowitsch PetscCall(VecView(x, PETSC_VIEWER_STDOUT_WORLD));
2019566063dSJacob Faibussowitsch PetscCall(VecView(gy2, PETSC_VIEWER_STDOUT_WORLD));
2029566063dSJacob Faibussowitsch PetscCall(VecDestroy(&gy2));
203c4762a1bSJed Brown
2049566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(y2, &leafupdate));
2059566063dSJacob Faibussowitsch PetscCall(VecDestroy(&y2));
206c4762a1bSJed Brown
2079566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(y, &leafdata));
2089566063dSJacob Faibussowitsch PetscCall(VecDestroy(&y));
209c4762a1bSJed Brown
2109566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(x, &rootdata));
2119566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x));
212c4762a1bSJed Brown
2139566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&alltoallsf));
214c4762a1bSJed Brown
2159566063dSJacob Faibussowitsch PetscCall(PetscFinalize());
216b122ec5aSJacob Faibussowitsch return 0;
217c4762a1bSJed Brown }
218c4762a1bSJed Brown
219c4762a1bSJed Brown /*TEST
220c4762a1bSJed Brown
221c4762a1bSJed Brown test:
222c4762a1bSJed Brown # N=10 is divisible by nsize, to trigger Allgather/Gather in SF
223f424265bSStefano Zampini #MPI_Sendrecv_replace is broken with 20210400300
2240f85934cSJunchao Zhang requires: !defined(PETSC_HAVE_I_MPI)
225c4762a1bSJed Brown nsize: 2
226c4762a1bSJed Brown args: -op replace
227c4762a1bSJed Brown
228c4762a1bSJed Brown test:
229c4762a1bSJed Brown suffix: 2
230c4762a1bSJed Brown nsize: 2
231c4762a1bSJed Brown args: -op sum
232c4762a1bSJed Brown
233c4762a1bSJed Brown # N=10 is not divisible by nsize, to trigger Allgatherv/Gatherv in SF
234c4762a1bSJed Brown test:
235f424265bSStefano Zampini #MPI_Sendrecv_replace is broken with 20210400300
2360f85934cSJunchao Zhang requires: !defined(PETSC_HAVE_I_MPI)
237c4762a1bSJed Brown suffix: 3
238c4762a1bSJed Brown nsize: 3
239c4762a1bSJed Brown args: -op replace
240c4762a1bSJed Brown
241c4762a1bSJed Brown test:
242c4762a1bSJed Brown suffix: 4
243c4762a1bSJed Brown nsize: 3
244c4762a1bSJed Brown args: -op sum
245c4762a1bSJed Brown
246c4762a1bSJed Brown TEST*/
247