Actual source code: ex115.c

  1: static char help[] = "Tests MatHYPRE\n";

  3: #include <petscmathypre.h>
  4: #include <petscpkg_version.h>

  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;

 18:   PetscFunctionBeginUser;
 19:   PetscCall(PetscInitialize(&argc, &args, NULL, help));
 20:   PetscCall(PetscOptionsGetString(NULL, NULL, "-f", file, sizeof(file), &flg));
 21:   if (PetscDefined(USE_COMPLEX)) {
 22:     testptap       = PETSC_FALSE;
 23:     testmatmatmult = PETSC_FALSE;
 24:     PetscCall(PetscOptionsInsertString(NULL, "-options_left 0"));
 25:   }
 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

 37:   if (!flg) { /* Create a matrix and test MatSetValues */
 38:     PetscMPIInt size;

 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;

 84:       PetscCall(PetscOptionsGetBool(NULL, NULL, "-test_offproc", &test_offproc, NULL));
 85:       if (test_offproc) {
 86:         const PetscInt *ranges;
 87:         PetscMPIInt     rank;

 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};

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

113: #if PetscDefined(USE_COMPLEX)
114:     /* make the matrix imaginary */
115:     PetscCall(MatScale(A, PETSC_i));
116:     PetscCall(MatScale(B, PETSC_i));
117: #endif

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;

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:   }

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));

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));

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");

192:   /* check PtAP */
193:   if (testptap && M == N) {
194:     Mat pP, hP;

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_DETERMINE, &pP));
199:     PetscCall(MatPtAP(A, A, MAT_REUSE_MATRIX, PETSC_DETERMINE, &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");

204:     /* MatPtAP_HYPRE_HYPRE -> output is a MatHYPRE */
205:     PetscCall(MatPtAP(C, B, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &hP));
206:     PetscCall(MatPtAP(C, B, MAT_REUSE_MATRIX, PETSC_DETERMINE, &hP));
207:     PetscCall(MatPtAPMultEqual(C, B, hP, 10, &flg));
208:     PetscCheck(flg, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Error in MatPtAP_HYPRE_HYPRE");

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));

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_DETERMINE, &hP));
226:     PetscCall(MatPtAP(A, B, MAT_REUSE_MATRIX, PETSC_DETERMINE, &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));

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));

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_DETERMINE, &pAB));
244:     PetscCall(MatMatMult(A, B, MAT_REUSE_MATRIX, PETSC_DETERMINE, &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");

249:     /* MatMatMult_HYPRE_HYPRE -> output is a MatHYPRE */
250:     PetscCall(MatMatMult(C, D, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &CD));
251:     PetscCall(MatMatMult(C, D, MAT_REUSE_MATRIX, PETSC_DETERMINE, &CD));
252:     PetscCall(MatMatMultEqual(C, D, CD, 10, &flg));
253:     PetscCheck(flg, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Error in MatMatMult_HYPRE_HYPRE");

255:     /* Test MatAXPY_Basic() */
256: #if !PetscDefined(HAVE_HYPRE_DEVICE)
257:     PetscCall(MatAXPY(CD, -1., pAB, DIFFERENT_NONZERO_PATTERN));

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

267:     PetscCall(MatDestroy(&C));
268:     PetscCall(MatDestroy(&D));
269:     PetscCall(MatDestroy(&pAB));
270:     PetscCall(MatDestroy(&CD));

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_DETERMINE, &CAB));
277:     PetscCall(MatDestroy(&C));
278:     PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &C));
279:     PetscCall(MatMatMult(C, A, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &D));
280:     PetscCall(MatDestroy(&C));
281:     PetscCall(MatMatMult(D, B, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &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:   }

293:   /* Check MatView */
294:   PetscCall(MatConvert(A, MATHYPRE, MAT_INITIAL_MATRIX, &B));
295:   PetscCall(MatViewFromOptions(B, NULL, "-view_B"));

297:   /* Check MatDuplicate/MatCopy */
298:   for (j = 0; j < 3; j++) {
299:     MatDuplicateOption dop;

301:     dop = MAT_COPY_VALUES;
302:     if (j == 1) dop = MAT_DO_NOT_COPY_VALUES;
303:     if (j == 2) dop = MAT_SHARE_NONZERO_PATTERN;

305:     for (i = 0; i < 3; i++) {
306:       MatStructure str;

308:       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Dup/Copy tests: %" PetscInt_FMT " %" PetscInt_FMT "\n", j, i));

310:       str = DIFFERENT_NONZERO_PATTERN;
311:       if (i == 1) str = SAME_NONZERO_PATTERN;
312:       if (i == 2) str = SUBSET_NONZERO_PATTERN;

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));

367: #if PETSC_PKG_HYPRE_VERSION_GE(2, 19, 0)
368:   {
369:     Vec y, y2;

371:     PetscCall(MatConvert(A, MATHYPRE, MAT_INITIAL_MATRIX, &B));
372:     PetscCall(MatCreateVecs(A, NULL, &y));
373:     PetscCall(MatCreateVecs(B, NULL, &y2));
374:     PetscCall(MatGetRowSumAbs(A, y));
375:     PetscCall(MatGetRowSumAbs(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_rowsumabs_diff"));
380:       PetscCall(VecViewFromOptions(y2, NULL, "-view_rowsumabs_diff"));
381:       SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error MatGetRowSumAbs %g", (double)err);
382:     }
383:     PetscCall(MatDestroy(&B));
384:     PetscCall(VecDestroy(&y));
385:     PetscCall(VecDestroy(&y2));
386:   }
387: #endif

389:   PetscCall(MatHasCongruentLayouts(A, &flg));
390:   if (flg) {
391:     Vec y, y2;

393:     PetscCall(MatConvert(A, MATHYPRE, MAT_INITIAL_MATRIX, &B));
394:     PetscCall(MatCreateVecs(A, NULL, &y));
395:     PetscCall(MatCreateVecs(B, NULL, &y2));
396:     PetscCall(MatGetDiagonal(A, y));
397:     PetscCall(MatGetDiagonal(B, y2));
398:     PetscCall(VecAXPY(y2, -1.0, y));
399:     PetscCall(VecNorm(y2, NORM_INFINITY, &err));
400:     if (err > PETSC_SMALL) {
401:       PetscCall(VecViewFromOptions(y, NULL, "-view_diagonal_diff"));
402:       PetscCall(VecViewFromOptions(y2, NULL, "-view_diagonal_diff"));
403:       SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Error MatGetDiagonal %g", err);
404:     }
405:     PetscCall(MatDestroy(&B));
406:     PetscCall(VecDestroy(&y));
407:     PetscCall(VecDestroy(&y2));
408:   }

410:   PetscCall(MatDestroy(&A));

412:   PetscCall(PetscFinalize());
413:   return 0;
414: }

416: /*TEST

418:    build:
419:       requires: hypre

421:    test:
422:       suffix: 1
423:       args: -N 11 -M 11
424:       output_file: output/ex115_1.out

426:    test:
427:       suffix: 2
428:       nsize: 3
429:       args: -N 13 -M 13 -matmatmult_via hypre -options_left 0
430:       output_file: output/ex115_1.out

432:    test:
433:       suffix: 3
434:       nsize: 4
435:       args: -M 13 -N 7 -matmatmult_via hypre -options_left 0
436:       output_file: output/ex115_1.out

438:    test:
439:       suffix: 4
440:       nsize: 2
441:       args: -M 12 -N 19
442:       output_file: output/ex115_1.out

444:    test:
445:       suffix: 5
446:       nsize: 3
447:       args: -M 13 -N 13 -options_left 0 -matptap_via hypre -matptap_hypre_outtype hypre
448:       output_file: output/ex115_1.out

450:    test:
451:       requires: !defined(PETSC_HAVE_HYPRE_DEVICE)
452:       suffix: 6
453:       nsize: 3
454:       args: -M 12 -N 19 -test_offproc
455:       output_file: output/ex115_1.out

457:    test:
458:       requires: !defined(PETSC_HAVE_HYPRE_DEVICE)
459:       suffix: 7
460:       nsize: 3
461:       args: -M 19 -N 12 -test_offproc -view_B ::ascii_info_detail
462:       output_file: output/ex115_7.out

464:    test:
465:       requires: !defined(PETSC_HAVE_HYPRE_DEVICE)
466:       suffix: 8
467:       nsize: 3
468:       args: -M 1 -N 12 -test_offproc
469:       output_file: output/ex115_1.out

471:    test:
472:       requires: !defined(PETSC_HAVE_HYPRE_DEVICE)
473:       suffix: 9
474:       nsize: 3
475:       args: -M 1 -N 2 -test_offproc
476:       output_file: output/ex115_1.out

478: TEST*/