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