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