xref: /petsc/src/mat/tests/ex18.c (revision ffa8c5705e8ab2cf85ee1d14dbe507a6e2eb5283)
1 static char help[] = "Tests the use of MatZeroRowsColumns() for parallel matrices.\n\
2 Contributed-by: Stephan Kramer <s.kramer@imperial.ac.uk>\n\n";
3 
4 #include <petscmat.h>
5 
6 int main(int argc,char **args)
7 {
8   Mat            A;
9   Vec            x, rhs, y;
10   PetscInt       i,j,k,b,m = 3,n,nlocal=2,bs=1,Ii,J;
11   PetscInt       *boundary_nodes, nboundary_nodes, *boundary_indices;
12   PetscMPIInt    rank,size;
13   PetscScalar    v,v0,v1,v2,a0=0.1,a,rhsval, *boundary_values,diag = 1.0;
14   PetscReal      norm;
15   char           convname[64];
16   PetscBool      upwind = PETSC_FALSE, nonlocalBC = PETSC_FALSE, zerorhs = PETSC_TRUE, convert = PETSC_FALSE;
17 
18   PetscCall(PetscInitialize(&argc,&args,(char*)0,help));
19   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD,&rank));
20   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size));
21   n = nlocal*size;
22 
23   PetscCall(PetscOptionsGetInt(NULL,NULL, "-bs", &bs, NULL));
24   PetscCall(PetscOptionsGetBool(NULL,NULL, "-nonlocal_bc", &nonlocalBC, NULL));
25   PetscCall(PetscOptionsGetScalar(NULL,NULL, "-diag", &diag, NULL));
26   PetscCall(PetscOptionsGetString(NULL,NULL,"-convname",convname,sizeof(convname),&convert));
27   PetscCall(PetscOptionsGetBool(NULL,NULL, "-zerorhs", &zerorhs, NULL));
28 
29   PetscCall(MatCreate(PETSC_COMM_WORLD,&A));
30   PetscCall(MatSetSizes(A,PETSC_DECIDE,PETSC_DECIDE,m*n*bs,m*n*bs));
31   PetscCall(MatSetFromOptions(A));
32   PetscCall(MatSetUp(A));
33 
34   PetscCall(MatCreateVecs(A, NULL, &rhs));
35   PetscCall(VecSetFromOptions(rhs));
36   PetscCall(VecSetUp(rhs));
37 
38   rhsval = 0.0;
39   for (i=0; i<m; i++) {
40     for (j=nlocal*rank; j<nlocal*(rank+1); j++) {
41       a = a0;
42       for (b=0; b<bs; b++) {
43         /* let's start with a 5-point stencil diffusion term */
44         v = -1.0;  Ii = (j + n*i)*bs + b;
45         if (i>0)   {J = Ii - n*bs; PetscCall(MatSetValues(A,1,&Ii,1,&J,&v,ADD_VALUES));}
46         if (i<m-1) {J = Ii + n*bs; PetscCall(MatSetValues(A,1,&Ii,1,&J,&v,ADD_VALUES));}
47         if (j>0)   {J = Ii - 1*bs; PetscCall(MatSetValues(A,1,&Ii,1,&J,&v,ADD_VALUES));}
48         if (j<n-1) {J = Ii + 1*bs; PetscCall(MatSetValues(A,1,&Ii,1,&J,&v,ADD_VALUES));}
49         v = 4.0; PetscCall(MatSetValues(A,1,&Ii,1,&Ii,&v,ADD_VALUES));
50         if (upwind) {
51           /* now add a 2nd order upwind advection term to add a little asymmetry */
52           if (j>2) {
53             J = Ii-2*bs; v2 = 0.5*a; v1 = -2.0*a; v0 = 1.5*a;
54             PetscCall(MatSetValues(A,1,&Ii,1,&J,&v2,ADD_VALUES));
55           } else {
56             /* fall back to 1st order upwind */
57             v1 = -1.0*a; v0 = 1.0*a;
58           };
59           if (j>1) {J = Ii-1*bs; PetscCall(MatSetValues(A,1,&Ii,1,&J,&v1,ADD_VALUES));}
60           PetscCall(MatSetValues(A,1,&Ii,1,&Ii,&v0,ADD_VALUES));
61           a /= 10.; /* use a different velocity for the next component */
62           /* add a coupling to the previous and next components */
63           v = 0.5;
64           if (b>0) {J = Ii - 1; PetscCall(MatSetValues(A,1,&Ii,1,&J,&v,ADD_VALUES));}
65           if (b<bs-1) {J = Ii + 1; PetscCall(MatSetValues(A,1,&Ii,1,&J,&v,ADD_VALUES));}
66         }
67         /* make up some rhs */
68         PetscCall(VecSetValue(rhs, Ii, rhsval, INSERT_VALUES));
69         rhsval += 1.0;
70       }
71     }
72   }
73   PetscCall(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY));
74   PetscCall(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY));
75 
76   if (convert) { /* Test different Mat implementations */
77     Mat B;
78 
79     PetscCall(MatConvert(A,convname,MAT_INITIAL_MATRIX,&B));
80     PetscCall(MatDestroy(&A));
81     A    = B;
82   }
83 
84   PetscCall(VecAssemblyBegin(rhs));
85   PetscCall(VecAssemblyEnd(rhs));
86   /* set rhs to zero to simplify */
87   if (zerorhs) {
88     PetscCall(VecZeroEntries(rhs));
89   }
90 
91   if (nonlocalBC) {
92     /*version where boundary conditions are set by processes that don't necessarily own the nodes */
93     if (rank == 0) {
94       nboundary_nodes = size>m ? nlocal : m-size+nlocal;
95       PetscCall(PetscMalloc1(nboundary_nodes,&boundary_nodes));
96       k = 0;
97       for (i=size; i<m; i++,k++) {boundary_nodes[k] = n*i;};
98     } else if (rank < m) {
99       nboundary_nodes = nlocal+1;
100       PetscCall(PetscMalloc1(nboundary_nodes,&boundary_nodes));
101       boundary_nodes[0] = rank*n;
102       k = 1;
103     } else {
104       nboundary_nodes = nlocal;
105       PetscCall(PetscMalloc1(nboundary_nodes,&boundary_nodes));
106       k = 0;
107     }
108     for (j=nlocal*rank; j<nlocal*(rank+1); j++,k++) {boundary_nodes[k] = j;};
109   } else {
110     /*version where boundary conditions are set by the node owners only */
111     PetscCall(PetscMalloc1(m*n,&boundary_nodes));
112     k=0;
113     for (j=0; j<n; j++) {
114       Ii = j;
115       if (Ii>=rank*m*nlocal && Ii<(rank+1)*m*nlocal) boundary_nodes[k++] = Ii;
116     }
117     for (i=1; i<m; i++) {
118       Ii = n*i;
119       if (Ii>=rank*m*nlocal && Ii<(rank+1)*m*nlocal) boundary_nodes[k++] = Ii;
120     }
121     nboundary_nodes = k;
122   }
123 
124   PetscCall(VecDuplicate(rhs, &x));
125   PetscCall(VecZeroEntries(x));
126   PetscCall(PetscMalloc2(nboundary_nodes*bs,&boundary_indices,nboundary_nodes*bs,&boundary_values));
127   for (k=0; k<nboundary_nodes; k++) {
128     Ii = boundary_nodes[k]*bs;
129     v = 1.0*boundary_nodes[k];
130     for (b=0; b<bs; b++, Ii++) {
131       boundary_indices[k*bs+b] = Ii;
132       boundary_values[k*bs+b] = v;
133       PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "%d %" PetscInt_FMT " %f\n", rank, Ii, (double)PetscRealPart(v)));
134       v += 0.1;
135     }
136   }
137   PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, NULL));
138   PetscCall(VecSetValues(x, nboundary_nodes*bs, boundary_indices, boundary_values, INSERT_VALUES));
139   PetscCall(VecAssemblyBegin(x));
140   PetscCall(VecAssemblyEnd(x));
141 
142   /* We can check the rhs returned by MatZeroColumns by computing y=rhs-A*x  and overwriting the boundary entries with boundary values */
143   PetscCall(VecDuplicate(x, &y));
144   PetscCall(MatMult(A, x, y));
145   PetscCall(VecAYPX(y, -1.0, rhs));
146   for (k=0; k<nboundary_nodes*bs; k++) boundary_values[k] *= diag;
147   PetscCall(VecSetValues(y, nboundary_nodes*bs, boundary_indices, boundary_values, INSERT_VALUES));
148   PetscCall(VecAssemblyBegin(y));
149   PetscCall(VecAssemblyEnd(y));
150 
151   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "*** Matrix A and vector x:\n"));
152   PetscCall(MatView(A, PETSC_VIEWER_STDOUT_WORLD));
153   PetscCall(VecView(x,PETSC_VIEWER_STDOUT_WORLD));
154 
155   PetscCall(MatZeroRowsColumns(A, nboundary_nodes*bs, boundary_indices, diag, x, rhs));
156   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "*** Vector rhs returned by MatZeroRowsColumns\n"));
157   PetscCall(VecView(rhs,PETSC_VIEWER_STDOUT_WORLD));
158   PetscCall(VecAXPY(y, -1.0, rhs));
159   PetscCall(VecNorm(y, NORM_INFINITY, &norm));
160   if (norm > 1.0e-10) {
161     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "*** Difference between rhs and y, inf-norm: %f\n", (double)norm));
162     PetscCall(VecView(y,PETSC_VIEWER_STDOUT_WORLD));
163     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Bug in MatZeroRowsColumns");
164   }
165 
166   PetscCall(PetscFree(boundary_nodes));
167   PetscCall(PetscFree2(boundary_indices,boundary_values));
168   PetscCall(VecDestroy(&x));
169   PetscCall(VecDestroy(&y));
170   PetscCall(VecDestroy(&rhs));
171   PetscCall(MatDestroy(&A));
172 
173   PetscCall(PetscFinalize());
174   return 0;
175 }
176 
177 /*TEST
178 
179    test:
180       diff_args: -j
181       suffix: 0
182 
183    test:
184       diff_args: -j
185       suffix: 1
186       nsize: 2
187 
188    test:
189       diff_args: -j
190       suffix: 10
191       nsize: 2
192       args: -bs 2 -nonlocal_bc
193 
194    test:
195       diff_args: -j
196       suffix: 11
197       nsize: 7
198       args: -bs 2 -nonlocal_bc
199 
200    test:
201       diff_args: -j
202       suffix: 12
203       args: -bs 2 -nonlocal_bc -mat_type baij
204 
205    test:
206       diff_args: -j
207       suffix: 13
208       nsize: 2
209       args: -bs 2 -nonlocal_bc -mat_type baij
210 
211    test:
212       diff_args: -j
213       suffix: 14
214       nsize: 7
215       args: -bs 2 -nonlocal_bc -mat_type baij
216 
217    test:
218       diff_args: -j
219       suffix: 2
220       nsize: 7
221 
222    test:
223       diff_args: -j
224       suffix: 3
225       args: -mat_type baij
226 
227    test:
228       diff_args: -j
229       suffix: 4
230       nsize: 2
231       args: -mat_type baij
232 
233    test:
234       diff_args: -j
235       suffix: 5
236       nsize: 7
237       args: -mat_type baij
238 
239    test:
240       diff_args: -j
241       suffix: 6
242       args: -bs 2 -mat_type baij
243 
244    test:
245       diff_args: -j
246       suffix: 7
247       nsize: 2
248       args: -bs 2 -mat_type baij
249 
250    test:
251       diff_args: -j
252       suffix: 8
253       nsize: 7
254       args: -bs 2 -mat_type baij
255 
256    test:
257       diff_args: -j
258       suffix: 9
259       args: -bs 2 -nonlocal_bc
260 
261    test:
262       diff_args: -j
263       suffix: 15
264       args: -bs 2 -nonlocal_bc -convname shell
265 
266    test:
267       diff_args: -j
268       suffix: 16
269       nsize: 2
270       args: -bs 2 -nonlocal_bc -convname shell
271 
272    test:
273       diff_args: -j
274       suffix: 17
275       args: -bs 2 -nonlocal_bc -convname dense
276 
277    testset:
278       diff_args: -j
279       suffix: full
280       nsize: {{1 3}separate output}
281       args: -diag {{0.12 -0.13}separate output} -convname {{aij shell baij}separate output} -zerorhs 0
282 
283    test:
284       diff_args: -j
285       requires: cuda
286       suffix: cusparse_1
287       nsize: 1
288       args: -diag {{0.12 -0.13}separate output} -convname {{seqaijcusparse mpiaijcusparse}separate output} -zerorhs 0 -mat_type {{seqaijcusparse mpiaijcusparse}separate output}
289 
290    test:
291       diff_args: -j
292       requires: cuda
293       suffix: cusparse_3
294       nsize: 3
295       args: -diag {{0.12 -0.13}separate output} -convname mpiaijcusparse -zerorhs 0 -mat_type mpiaijcusparse
296 
297 TEST*/
298