xref: /petsc/src/mat/tests/ex115.c (revision fbf9dbe564678ed6eff1806adbc4c4f01b9743f4)
1 
2 static char help[] = "Tests MatHYPRE\n";
3 
4 #include <petscmathypre.h>
5 
6 int main(int argc, char **args)
7 {
8   Mat                 A, B, C, D;
9   Mat                 pAB, CD, CAB;
10   hypre_ParCSRMatrix *parcsr;
11   PetscReal           err;
12   PetscInt            i, j, N = 6, M = 6;
13   PetscBool           flg, testptap = PETSC_TRUE, testmatmatmult = PETSC_TRUE;
14   PetscReal           norm;
15   char                file[256];
16 
17   PetscFunctionBeginUser;
18   PetscCall(PetscInitialize(&argc, &args, (char *)0, help));
19   PetscCall(PetscOptionsGetString(NULL, NULL, "-f", file, sizeof(file), &flg));
20 #if defined(PETSC_USE_COMPLEX)
21   testptap       = PETSC_FALSE;
22   testmatmatmult = PETSC_FALSE;
23   PetscCall(PetscOptionsInsertString(NULL, "-options_left 0"));
24 #endif
25   PetscCall(PetscOptionsGetBool(NULL, NULL, "-ptap", &testptap, NULL));
26   PetscCall(PetscOptionsGetBool(NULL, NULL, "-matmatmult", &testmatmatmult, NULL));
27   PetscCall(MatCreate(PETSC_COMM_WORLD, &A));
28   if (!flg) { /* Create a matrix and test MatSetValues */
29     PetscMPIInt size;
30 
31     PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
32     PetscCall(PetscOptionsGetInt(NULL, NULL, "-M", &M, NULL));
33     PetscCall(PetscOptionsGetInt(NULL, NULL, "-N", &N, NULL));
34     PetscCall(MatSetSizes(A, PETSC_DECIDE, PETSC_DECIDE, M, N));
35     PetscCall(MatSetType(A, MATAIJ));
36     PetscCall(MatSeqAIJSetPreallocation(A, 9, NULL));
37     PetscCall(MatMPIAIJSetPreallocation(A, 9, NULL, 9, NULL));
38     PetscCall(MatCreate(PETSC_COMM_WORLD, &B));
39     PetscCall(MatSetSizes(B, PETSC_DECIDE, PETSC_DECIDE, M, N));
40     PetscCall(MatSetType(B, MATHYPRE));
41     if (M == N) {
42       PetscCall(MatHYPRESetPreallocation(B, 9, NULL, 9, NULL));
43     } else {
44       PetscCall(MatHYPRESetPreallocation(B, 6, NULL, 6, NULL));
45     }
46     if (M == N) {
47       for (i = 0; i < M; i++) {
48         PetscInt    cols[] = {0, 1, 2, 3, 4, 5};
49         PetscScalar vals[] = {0, 1. / size, 2. / size, 3. / size, 4. / size, 5. / size};
50         for (j = i - 2; j < i + 1; j++) {
51           if (j >= N) {
52             PetscCall(MatSetValue(A, i, N - 1, (1. * j * N + i) / (3. * N * size), ADD_VALUES));
53             PetscCall(MatSetValue(B, i, N - 1, (1. * j * N + i) / (3. * N * size), ADD_VALUES));
54           } else if (i > j) {
55             PetscCall(MatSetValue(A, i, PetscMin(j, N - 1), (1. * j * N + i) / (2. * N * size), ADD_VALUES));
56             PetscCall(MatSetValue(B, i, PetscMin(j, N - 1), (1. * j * N + i) / (2. * N * size), ADD_VALUES));
57           } else {
58             PetscCall(MatSetValue(A, i, PetscMin(j, N - 1), -1. - (1. * j * N + i) / (4. * N * size), ADD_VALUES));
59             PetscCall(MatSetValue(B, i, PetscMin(j, N - 1), -1. - (1. * j * N + i) / (4. * N * size), ADD_VALUES));
60           }
61         }
62         PetscCall(MatSetValues(A, 1, &i, PetscMin(6, N), cols, vals, ADD_VALUES));
63         PetscCall(MatSetValues(B, 1, &i, PetscMin(6, N), cols, vals, ADD_VALUES));
64       }
65     } else {
66       PetscInt  rows[2];
67       PetscBool test_offproc = PETSC_FALSE;
68 
69       PetscCall(PetscOptionsGetBool(NULL, NULL, "-test_offproc", &test_offproc, NULL));
70       if (test_offproc) {
71         const PetscInt *ranges;
72         PetscMPIInt     rank;
73 
74         PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
75         PetscCall(MatGetOwnershipRanges(A, &ranges));
76         rows[0] = ranges[(rank + 1) % size];
77         rows[1] = ranges[(rank + 1) % size + 1];
78       } else {
79         PetscCall(MatGetOwnershipRange(A, &rows[0], &rows[1]));
80       }
81       for (i = rows[0]; i < rows[1]; i++) {
82         PetscInt    cols[] = {0, 1, 2, 3, 4, 5};
83         PetscScalar vals[] = {-1, 1, -2, 2, -3, 3};
84 
85         PetscCall(MatSetValues(A, 1, &i, PetscMin(6, N), cols, vals, INSERT_VALUES));
86         PetscCall(MatSetValues(B, 1, &i, PetscMin(6, N), cols, vals, INSERT_VALUES));
87       }
88     }
89     /* MAT_FLUSH_ASSEMBLY currently not supported */
90     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
91     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
92     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
93     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
94 
95 #if defined(PETSC_USE_COMPLEX)
96     /* make the matrix imaginary */
97     PetscCall(MatScale(A, PETSC_i));
98     PetscCall(MatScale(B, PETSC_i));
99 #endif
100 
101     /* MatAXPY further exercises MatSetValues_HYPRE */
102     PetscCall(MatAXPY(B, -1., A, DIFFERENT_NONZERO_PATTERN));
103     PetscCall(MatConvert(B, MATMPIAIJ, MAT_INITIAL_MATRIX, &C));
104     PetscCall(MatNorm(C, NORM_INFINITY, &err));
105     PetscCheck(err <= PETSC_SMALL, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error MatSetValues %g", err);
106     PetscCall(MatDestroy(&B));
107     PetscCall(MatDestroy(&C));
108   } else {
109     PetscViewer viewer;
110 
111     PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD, file, FILE_MODE_READ, &viewer));
112     PetscCall(MatSetFromOptions(A));
113     PetscCall(MatLoad(A, viewer));
114     PetscCall(PetscViewerDestroy(&viewer));
115     PetscCall(MatGetSize(A, &M, &N));
116   }
117 
118   /* check conversion routines */
119   PetscCall(MatViewFromOptions(A, NULL, "-view_A"));
120   PetscCall(MatConvert(A, MATHYPRE, MAT_INITIAL_MATRIX, &B));
121   PetscCall(MatViewFromOptions(B, NULL, "-view_convert"));
122   PetscCall(MatMultEqual(B, A, 4, &flg));
123   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error Mat HYPRE init");
124   PetscCall(MatConvert(A, MATHYPRE, MAT_REUSE_MATRIX, &B));
125   PetscCall(MatViewFromOptions(B, NULL, "-view_convert"));
126   PetscCall(MatMultEqual(B, A, 4, &flg));
127   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error Mat HYPRE reuse");
128   PetscCall(MatConvert(B, MATIS, MAT_INITIAL_MATRIX, &D));
129   PetscCall(MatConvert(B, MATIS, MAT_REUSE_MATRIX, &D));
130   PetscCall(MatMultEqual(D, A, 4, &flg));
131   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error Mat IS");
132   PetscCall(MatConvert(B, MATAIJ, MAT_INITIAL_MATRIX, &C));
133   PetscCall(MatConvert(B, MATAIJ, MAT_REUSE_MATRIX, &C));
134   PetscCall(MatMultEqual(C, A, 4, &flg));
135   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error Mat AIJ");
136   PetscCall(MatAXPY(C, -1., A, SAME_NONZERO_PATTERN));
137   PetscCall(MatNorm(C, NORM_INFINITY, &err));
138   PetscCheck(err <= PETSC_SMALL, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error Mat AIJ %g", err);
139   PetscCall(MatDestroy(&C));
140   PetscCall(MatConvert(D, MATAIJ, MAT_INITIAL_MATRIX, &C));
141   PetscCall(MatAXPY(C, -1., A, SAME_NONZERO_PATTERN));
142   PetscCall(MatNorm(C, NORM_INFINITY, &err));
143   PetscCheck(err <= PETSC_SMALL, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error Mat IS %g", err);
144   PetscCall(MatDestroy(&C));
145   PetscCall(MatDestroy(&D));
146 
147   /* check MatCreateFromParCSR */
148   PetscCall(MatHYPREGetParCSR(B, &parcsr));
149   PetscCall(MatCreateFromParCSR(parcsr, MATAIJ, PETSC_COPY_VALUES, &D));
150   PetscCall(MatDestroy(&D));
151   PetscCall(MatCreateFromParCSR(parcsr, MATHYPRE, PETSC_USE_POINTER, &C));
152 
153   /* check MatMult operations */
154   PetscCall(MatMultEqual(A, B, 4, &flg));
155   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error MatMult B");
156   PetscCall(MatMultEqual(A, C, 4, &flg));
157   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error MatMult C");
158   PetscCall(MatMultAddEqual(A, B, 4, &flg));
159   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error MatMultAdd B");
160   PetscCall(MatMultAddEqual(A, C, 4, &flg));
161   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error MatMultAdd C");
162   PetscCall(MatMultTransposeEqual(A, B, 4, &flg));
163   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error MatMultTranspose B");
164   PetscCall(MatMultTransposeEqual(A, C, 4, &flg));
165   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error MatMultTranspose C");
166   PetscCall(MatMultTransposeAddEqual(A, B, 4, &flg));
167   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error MatMultTransposeAdd B");
168   PetscCall(MatMultTransposeAddEqual(A, C, 4, &flg));
169   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error MatMultTransposeAdd C");
170 
171   /* check PtAP */
172   if (testptap && M == N) {
173     Mat pP, hP;
174 
175     /* PETSc MatPtAP -> output is a MatAIJ
176        It uses HYPRE functions when -matptap_via hypre is specified at command line */
177     PetscCall(MatPtAP(A, A, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &pP));
178     PetscCall(MatPtAP(A, A, MAT_REUSE_MATRIX, PETSC_DEFAULT, &pP));
179     PetscCall(MatNorm(pP, NORM_INFINITY, &norm));
180     PetscCall(MatPtAPMultEqual(A, A, pP, 10, &flg));
181     PetscCheck(flg, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Error in MatPtAP_MatAIJ");
182 
183     /* MatPtAP_HYPRE_HYPRE -> output is a MatHYPRE */
184     PetscCall(MatPtAP(C, B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &hP));
185     PetscCall(MatPtAP(C, B, MAT_REUSE_MATRIX, PETSC_DEFAULT, &hP));
186     PetscCall(MatPtAPMultEqual(C, B, hP, 10, &flg));
187     PetscCheck(flg, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Error in MatPtAP_HYPRE_HYPRE");
188 
189     /* Test MatAXPY_Basic() */
190     PetscCall(MatAXPY(hP, -1., pP, DIFFERENT_NONZERO_PATTERN));
191     PetscCall(MatHasOperation(hP, MATOP_NORM, &flg));
192     if (!flg) { /* TODO add MatNorm_HYPRE */
193       PetscCall(MatConvert(hP, MATAIJ, MAT_INPLACE_MATRIX, &hP));
194     }
195     PetscCall(MatNorm(hP, NORM_INFINITY, &err));
196     PetscCheck(err / norm <= PETSC_SMALL, PetscObjectComm((PetscObject)hP), PETSC_ERR_PLIB, "Error MatPtAP %g %g", err, norm);
197     PetscCall(MatDestroy(&pP));
198     PetscCall(MatDestroy(&hP));
199 
200     /* MatPtAP_AIJ_HYPRE -> output can be decided at runtime with -matptap_hypre_outtype */
201     PetscCall(MatPtAP(A, B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &hP));
202     PetscCall(MatPtAP(A, B, MAT_REUSE_MATRIX, PETSC_DEFAULT, &hP));
203     PetscCall(MatPtAPMultEqual(A, B, hP, 10, &flg));
204     PetscCheck(flg, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Error in MatPtAP_AIJ_HYPRE");
205     PetscCall(MatDestroy(&hP));
206   }
207   PetscCall(MatDestroy(&C));
208   PetscCall(MatDestroy(&B));
209 
210   /* check MatMatMult */
211   if (testmatmatmult) {
212     PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &B));
213     PetscCall(MatConvert(A, MATHYPRE, MAT_INITIAL_MATRIX, &C));
214     PetscCall(MatConvert(B, MATHYPRE, MAT_INITIAL_MATRIX, &D));
215 
216     /* PETSc MatMatMult -> output is a MatAIJ
217        It uses HYPRE functions when -matmatmult_via hypre is specified at command line */
218     PetscCall(MatMatMult(A, B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &pAB));
219     PetscCall(MatMatMult(A, B, MAT_REUSE_MATRIX, PETSC_DEFAULT, &pAB));
220     PetscCall(MatNorm(pAB, NORM_INFINITY, &norm));
221     PetscCall(MatMatMultEqual(A, B, pAB, 10, &flg));
222     PetscCheck(flg, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Error in MatMatMult_AIJ_AIJ");
223 
224     /* MatMatMult_HYPRE_HYPRE -> output is a MatHYPRE */
225     PetscCall(MatMatMult(C, D, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &CD));
226     PetscCall(MatMatMult(C, D, MAT_REUSE_MATRIX, PETSC_DEFAULT, &CD));
227     PetscCall(MatMatMultEqual(C, D, CD, 10, &flg));
228     PetscCheck(flg, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Error in MatMatMult_HYPRE_HYPRE");
229 
230     /* Test MatAXPY_Basic() */
231     PetscCall(MatAXPY(CD, -1., pAB, DIFFERENT_NONZERO_PATTERN));
232 
233     PetscCall(MatHasOperation(CD, MATOP_NORM, &flg));
234     if (!flg) { /* TODO add MatNorm_HYPRE */
235       PetscCall(MatConvert(CD, MATAIJ, MAT_INPLACE_MATRIX, &CD));
236     }
237     PetscCall(MatNorm(CD, NORM_INFINITY, &err));
238     PetscCheck((err / norm) <= PETSC_SMALL, PetscObjectComm((PetscObject)CD), PETSC_ERR_PLIB, "Error MatMatMult %g %g", err, norm);
239 
240     PetscCall(MatDestroy(&C));
241     PetscCall(MatDestroy(&D));
242     PetscCall(MatDestroy(&pAB));
243     PetscCall(MatDestroy(&CD));
244 
245     /* When configured with HYPRE, MatMatMatMult is available for the triplet transpose(aij)-aij-aij */
246     PetscCall(MatCreateTranspose(A, &C));
247     PetscCall(MatMatMatMult(C, A, B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &CAB));
248     PetscCall(MatDestroy(&C));
249     PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &C));
250     PetscCall(MatMatMult(C, A, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &D));
251     PetscCall(MatDestroy(&C));
252     PetscCall(MatMatMult(D, B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &C));
253     PetscCall(MatNorm(C, NORM_INFINITY, &norm));
254     PetscCall(MatAXPY(C, -1., CAB, DIFFERENT_NONZERO_PATTERN));
255     PetscCall(MatNorm(C, NORM_INFINITY, &err));
256     PetscCheck((err / norm) <= PETSC_SMALL, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error MatMatMatMult %g %g", err, norm);
257     PetscCall(MatDestroy(&C));
258     PetscCall(MatDestroy(&D));
259     PetscCall(MatDestroy(&CAB));
260     PetscCall(MatDestroy(&B));
261   }
262 
263   /* Check MatView */
264   PetscCall(MatConvert(A, MATHYPRE, MAT_INITIAL_MATRIX, &B));
265   PetscCall(MatViewFromOptions(B, NULL, "-view_B"));
266 
267   /* Check MatDuplicate/MatCopy */
268   for (j = 0; j < 3; j++) {
269     MatDuplicateOption dop;
270 
271     dop = MAT_COPY_VALUES;
272     if (j == 1) dop = MAT_DO_NOT_COPY_VALUES;
273     if (j == 2) dop = MAT_SHARE_NONZERO_PATTERN;
274 
275     for (i = 0; i < 3; i++) {
276       MatStructure str;
277 
278       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Dup/Copy tests: %" PetscInt_FMT " %" PetscInt_FMT "\n", j, i));
279 
280       str = DIFFERENT_NONZERO_PATTERN;
281       if (i == 1) str = SAME_NONZERO_PATTERN;
282       if (i == 2) str = SUBSET_NONZERO_PATTERN;
283 
284       PetscCall(MatDuplicate(A, dop, &C));
285       PetscCall(MatDuplicate(B, dop, &D));
286       if (dop != MAT_COPY_VALUES) {
287         PetscCall(MatCopy(A, C, str));
288         PetscCall(MatCopy(B, D, str));
289       }
290       /* AXPY with AIJ and HYPRE */
291       PetscCall(MatAXPY(C, -1.0, D, str));
292       PetscCall(MatNorm(C, NORM_INFINITY, &err));
293       if (err > PETSC_SMALL) {
294         PetscCall(MatViewFromOptions(A, NULL, "-view_duplicate_diff"));
295         PetscCall(MatViewFromOptions(B, NULL, "-view_duplicate_diff"));
296         PetscCall(MatViewFromOptions(C, NULL, "-view_duplicate_diff"));
297         PetscCall(MatViewFromOptions(D, NULL, "-view_duplicate_diff"));
298         SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error test 1 MatDuplicate/MatCopy %g (%" PetscInt_FMT ",%" PetscInt_FMT ")", err, j, i);
299       }
300       /* AXPY with HYPRE and HYPRE */
301       PetscCall(MatAXPY(D, -1.0, B, str));
302       if (err > PETSC_SMALL) {
303         PetscCall(MatViewFromOptions(A, NULL, "-view_duplicate_diff"));
304         PetscCall(MatViewFromOptions(B, NULL, "-view_duplicate_diff"));
305         PetscCall(MatViewFromOptions(D, NULL, "-view_duplicate_diff"));
306         SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error test 2 MatDuplicate/MatCopy %g (%" PetscInt_FMT ",%" PetscInt_FMT ")", err, j, i);
307       }
308       /* Copy from HYPRE to AIJ */
309       PetscCall(MatCopy(B, C, str));
310       /* Copy from AIJ to HYPRE */
311       PetscCall(MatCopy(A, D, str));
312       /* AXPY with HYPRE and AIJ */
313       PetscCall(MatAXPY(D, -1.0, C, str));
314       PetscCall(MatHasOperation(D, MATOP_NORM, &flg));
315       if (!flg) { /* TODO add MatNorm_HYPRE */
316         PetscCall(MatConvert(D, MATAIJ, MAT_INPLACE_MATRIX, &D));
317       }
318       PetscCall(MatNorm(D, NORM_INFINITY, &err));
319       if (err > PETSC_SMALL) {
320         PetscCall(MatViewFromOptions(A, NULL, "-view_duplicate_diff"));
321         PetscCall(MatViewFromOptions(C, NULL, "-view_duplicate_diff"));
322         PetscCall(MatViewFromOptions(D, NULL, "-view_duplicate_diff"));
323         SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error test 3 MatDuplicate/MatCopy %g (%" PetscInt_FMT ",%" PetscInt_FMT ")", err, j, i);
324       }
325       PetscCall(MatDestroy(&C));
326       PetscCall(MatDestroy(&D));
327     }
328   }
329   PetscCall(MatDestroy(&B));
330 
331   PetscCall(MatHasCongruentLayouts(A, &flg));
332   if (flg) {
333     Vec y, y2;
334 
335     PetscCall(MatConvert(A, MATHYPRE, MAT_INITIAL_MATRIX, &B));
336     PetscCall(MatCreateVecs(A, NULL, &y));
337     PetscCall(MatCreateVecs(B, NULL, &y2));
338     PetscCall(MatGetDiagonal(A, y));
339     PetscCall(MatGetDiagonal(B, y2));
340     PetscCall(VecAXPY(y2, -1.0, y));
341     PetscCall(VecNorm(y2, NORM_INFINITY, &err));
342     if (err > PETSC_SMALL) {
343       PetscCall(VecViewFromOptions(y, NULL, "-view_diagonal_diff"));
344       PetscCall(VecViewFromOptions(y2, NULL, "-view_diagonal_diff"));
345       SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error MatGetDiagonal %g", err);
346     }
347     PetscCall(MatDestroy(&B));
348     PetscCall(VecDestroy(&y));
349     PetscCall(VecDestroy(&y2));
350   }
351 
352   PetscCall(MatDestroy(&A));
353 
354   PetscCall(PetscFinalize());
355   return 0;
356 }
357 
358 /*TEST
359 
360    build:
361       requires: hypre
362 
363    test:
364       requires: !defined(PETSC_HAVE_HYPRE_DEVICE)
365       suffix: 1
366       args: -N 11 -M 11
367       output_file: output/ex115_1.out
368 
369    test:
370       requires: !defined(PETSC_HAVE_HYPRE_DEVICE)
371       suffix: 2
372       nsize: 3
373       args: -N 13 -M 13 -matmatmult_via hypre
374       output_file: output/ex115_1.out
375 
376    test:
377       requires: !defined(PETSC_HAVE_HYPRE_DEVICE)
378       suffix: 3
379       nsize: 4
380       args: -M 13 -N 7 -matmatmult_via hypre
381       output_file: output/ex115_1.out
382 
383    test:
384       requires: !defined(PETSC_HAVE_HYPRE_DEVICE)
385       suffix: 4
386       nsize: 2
387       args: -M 12 -N 19
388       output_file: output/ex115_1.out
389 
390    test:
391       requires: !defined(PETSC_HAVE_HYPRE_DEVICE)
392       suffix: 5
393       nsize: 3
394       args: -M 13 -N 13 -matptap_via hypre -matptap_hypre_outtype hypre
395       output_file: output/ex115_1.out
396 
397    test:
398       requires: !defined(PETSC_HAVE_HYPRE_DEVICE)
399       suffix: 6
400       nsize: 3
401       args: -M 12 -N 19 -test_offproc
402       output_file: output/ex115_1.out
403 
404    test:
405       requires: !defined(PETSC_HAVE_HYPRE_DEVICE)
406       suffix: 7
407       nsize: 3
408       args: -M 19 -N 12 -test_offproc -view_B ::ascii_info_detail
409       output_file: output/ex115_7.out
410 
411    test:
412       requires: !defined(PETSC_HAVE_HYPRE_DEVICE)
413       suffix: 8
414       nsize: 3
415       args: -M 1 -N 12 -test_offproc
416       output_file: output/ex115_1.out
417 
418    test:
419       requires: !defined(PETSC_HAVE_HYPRE_DEVICE)
420       suffix: 9
421       nsize: 3
422       args: -M 1 -N 2 -test_offproc
423       output_file: output/ex115_1.out
424 
425 TEST*/
426