Actual source code: ex52.c


  2: static char help[] = "Solves a linear system in parallel with KSP. Modified from ex2.c \n\
  3:                       Illustrate how to use external packages MUMPS, SUPERLU and STRUMPACK \n\
  4: Input parameters include:\n\
  5:   -random_exact_sol : use a random exact solution vector\n\
  6:   -view_exact_sol   : write exact solution vector to stdout\n\
  7:   -m <mesh_x>       : number of mesh points in x-direction\n\
  8:   -n <mesh_y>       : number of mesh points in y-direction\n\n";

 10: #include <petscksp.h>

 12: #if defined(PETSC_HAVE_MUMPS)
 13: /* Subroutine contributed by Varun Hiremath */
 14: PetscErrorCode printMumpsMemoryInfo(Mat F)
 15: {
 16:   PetscInt maxMem, sumMem;

 18:   PetscFunctionBeginUser;
 19:   PetscCall(MatMumpsGetInfog(F, 16, &maxMem));
 20:   PetscCall(MatMumpsGetInfog(F, 17, &sumMem));
 21:   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\n MUMPS INFOG(16) :: Max memory in MB = %" PetscInt_FMT, maxMem));
 22:   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\n MUMPS INFOG(17) :: Sum memory in MB = %" PetscInt_FMT "\n", sumMem));
 23:   PetscFunctionReturn(PETSC_SUCCESS);
 24: }
 25: #endif

 27: int main(int argc, char **args)
 28: {
 29:   Vec         x, b, u; /* approx solution, RHS, exact solution */
 30:   Mat         A, F;
 31:   KSP         ksp; /* linear solver context */
 32:   PC          pc;
 33:   PetscRandom rctx; /* random number generator context */
 34:   PetscReal   norm; /* norm of solution error */
 35:   PetscInt    i, j, Ii, J, Istart, Iend, m = 8, n = 7, its;
 36:   PetscBool   flg = PETSC_FALSE, flg_ilu = PETSC_FALSE, flg_ch = PETSC_FALSE;
 37: #if defined(PETSC_HAVE_MUMPS)
 38:   PetscBool flg_mumps = PETSC_FALSE, flg_mumps_ch = PETSC_FALSE;
 39: #endif
 40: #if defined(PETSC_HAVE_SUPERLU) || defined(PETSC_HAVE_SUPERLU_DIST)
 41:   PetscBool flg_superlu = PETSC_FALSE;
 42: #endif
 43: #if defined(PETSC_HAVE_STRUMPACK)
 44:   PetscBool flg_strumpack = PETSC_FALSE;
 45: #endif
 46:   PetscScalar v;
 47:   PetscMPIInt rank, size;
 48: #if defined(PETSC_USE_LOG)
 49:   PetscLogStage stage;
 50: #endif

 52:   PetscFunctionBeginUser;
 53:   PetscCall(PetscInitialize(&argc, &args, (char *)0, help));
 54:   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
 55:   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
 56:   PetscCall(PetscOptionsGetInt(NULL, NULL, "-m", &m, NULL));
 57:   PetscCall(PetscOptionsGetInt(NULL, NULL, "-n", &n, NULL));
 58:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 59:          Compute the matrix and right-hand-side vector that define
 60:          the linear system, Ax = b.
 61:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 62:   PetscCall(MatCreate(PETSC_COMM_WORLD, &A));
 63:   PetscCall(MatSetSizes(A, PETSC_DECIDE, PETSC_DECIDE, m * n, m * n));
 64:   PetscCall(MatSetFromOptions(A));
 65:   PetscCall(MatMPIAIJSetPreallocation(A, 5, NULL, 5, NULL));
 66:   PetscCall(MatSeqAIJSetPreallocation(A, 5, NULL));
 67:   PetscCall(MatSetUp(A));

 69:   /*
 70:      Currently, all PETSc parallel matrix formats are partitioned by
 71:      contiguous chunks of rows across the processors.  Determine which
 72:      rows of the matrix are locally owned.
 73:   */
 74:   PetscCall(MatGetOwnershipRange(A, &Istart, &Iend));

 76:   /*
 77:      Set matrix elements for the 2-D, five-point stencil in parallel.
 78:       - Each processor needs to insert only elements that it owns
 79:         locally (but any non-local elements will be sent to the
 80:         appropriate processor during matrix assembly).
 81:       - Always specify global rows and columns of matrix entries.

 83:      Note: this uses the less common natural ordering that orders first
 84:      all the unknowns for x = h then for x = 2h etc; Hence you see J = Ii +- n
 85:      instead of J = I +- m as you might expect. The more standard ordering
 86:      would first do all variables for y = h, then y = 2h etc.

 88:    */
 89:   PetscCall(PetscLogStageRegister("Assembly", &stage));
 90:   PetscCall(PetscLogStagePush(stage));
 91:   for (Ii = Istart; Ii < Iend; Ii++) {
 92:     v = -1.0;
 93:     i = Ii / n;
 94:     j = Ii - i * n;
 95:     if (i > 0) {
 96:       J = Ii - n;
 97:       PetscCall(MatSetValues(A, 1, &Ii, 1, &J, &v, INSERT_VALUES));
 98:     }
 99:     if (i < m - 1) {
100:       J = Ii + n;
101:       PetscCall(MatSetValues(A, 1, &Ii, 1, &J, &v, INSERT_VALUES));
102:     }
103:     if (j > 0) {
104:       J = Ii - 1;
105:       PetscCall(MatSetValues(A, 1, &Ii, 1, &J, &v, INSERT_VALUES));
106:     }
107:     if (j < n - 1) {
108:       J = Ii + 1;
109:       PetscCall(MatSetValues(A, 1, &Ii, 1, &J, &v, INSERT_VALUES));
110:     }
111:     v = 4.0;
112:     PetscCall(MatSetValues(A, 1, &Ii, 1, &Ii, &v, INSERT_VALUES));
113:   }

115:   /*
116:      Assemble matrix, using the 2-step process:
117:        MatAssemblyBegin(), MatAssemblyEnd()
118:      Computations can be done while messages are in transition
119:      by placing code between these two statements.
120:   */
121:   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
122:   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
123:   PetscCall(PetscLogStagePop());

125:   /* A is symmetric. Set symmetric flag to enable ICC/Cholesky preconditioner */
126:   PetscCall(MatSetOption(A, MAT_SYMMETRIC, PETSC_TRUE));

128:   /* Create parallel vectors */
129:   PetscCall(MatCreateVecs(A, &u, &b));
130:   PetscCall(VecDuplicate(u, &x));

132:   /*
133:      Set exact solution; then compute right-hand-side vector.
134:      By default we use an exact solution of a vector with all
135:      elements of 1.0;  Alternatively, using the runtime option
136:      -random_sol forms a solution vector with random components.
137:   */
138:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-random_exact_sol", &flg, NULL));
139:   if (flg) {
140:     PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rctx));
141:     PetscCall(PetscRandomSetFromOptions(rctx));
142:     PetscCall(VecSetRandom(u, rctx));
143:     PetscCall(PetscRandomDestroy(&rctx));
144:   } else {
145:     PetscCall(VecSet(u, 1.0));
146:   }
147:   PetscCall(MatMult(A, u, b));

149:   /*
150:      View the exact solution vector if desired
151:   */
152:   flg = PETSC_FALSE;
153:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-view_exact_sol", &flg, NULL));
154:   if (flg) PetscCall(VecView(u, PETSC_VIEWER_STDOUT_WORLD));

156:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
157:                 Create the linear solver and set various options
158:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

160:   /*
161:      Create linear solver context
162:   */
163:   PetscCall(KSPCreate(PETSC_COMM_WORLD, &ksp));
164:   PetscCall(KSPSetOperators(ksp, A, A));

166:   /*
167:     Example of how to use external package MUMPS
168:     Note: runtime options
169:           '-ksp_type preonly -pc_type lu -pc_factor_mat_solver_type mumps -mat_mumps_icntl_7 3 -mat_mumps_icntl_1 0.0'
170:           are equivalent to these procedural calls
171:   */
172: #if defined(PETSC_HAVE_MUMPS)
173:   flg_mumps    = PETSC_FALSE;
174:   flg_mumps_ch = PETSC_FALSE;
175:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-use_mumps_lu", &flg_mumps, NULL));
176:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-use_mumps_ch", &flg_mumps_ch, NULL));
177:   if (flg_mumps || flg_mumps_ch) {
178:     PetscCall(KSPSetType(ksp, KSPPREONLY));
179:     PetscInt  ival, icntl;
180:     PetscReal val;
181:     PetscCall(KSPGetPC(ksp, &pc));
182:     if (flg_mumps) {
183:       PetscCall(PCSetType(pc, PCLU));
184:     } else if (flg_mumps_ch) {
185:       PetscCall(MatSetOption(A, MAT_SPD, PETSC_TRUE)); /* set MUMPS id%SYM=1 */
186:       PetscCall(PCSetType(pc, PCCHOLESKY));
187:     }
188:     PetscCall(PCFactorSetMatSolverType(pc, MATSOLVERMUMPS));
189:     PetscCall(PCFactorSetUpMatSolverType(pc)); /* call MatGetFactor() to create F */
190:     PetscCall(PCFactorGetMatrix(pc, &F));
191:     PetscCall(MatMumpsSetIcntl(F, 24, 1));
192:     PetscCall(MatMumpsGetIcntl(F, 24, &ival));
193:     PetscCheck(ival == 1, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "ICNTL(24) = %" PetscInt_FMT " (!= 1)", ival);
194:     PetscCall(MatMumpsSetCntl(F, 3, 1e-6));
195:     PetscCall(MatMumpsGetCntl(F, 3, &val));
196:     PetscCheck(PetscEqualReal(val, 1e-6), PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "CNTL(3) = %g (!= %g)", (double)val, 1e-6);
197:     if (flg_mumps) {
198:       /* Zero the first and last rows in the rank, they should then show up in corresponding null pivot rows output via
199:          MatMumpsGetNullPivots */
200:       flg = PETSC_FALSE;
201:       PetscCall(PetscOptionsGetBool(NULL, NULL, "-zero_first_and_last_rows", &flg, NULL));
202:       if (flg) {
203:         PetscInt rows[2];
204:         rows[0] = Istart;   /* first row of the rank */
205:         rows[1] = Iend - 1; /* last row of the rank */
206:         PetscCall(MatZeroRows(A, 2, rows, 0.0, NULL, NULL));
207:       }
208:       /* Get memory estimates from MUMPS' MatLUFactorSymbolic(), e.g. INFOG(16), INFOG(17).
209:          KSPSetUp() below will do nothing inside MatLUFactorSymbolic() */
210:       MatFactorInfo info;
211:       PetscCall(MatLUFactorSymbolic(F, A, NULL, NULL, &info));
212:       flg = PETSC_FALSE;
213:       PetscCall(PetscOptionsGetBool(NULL, NULL, "-print_mumps_memory", &flg, NULL));
214:       if (flg) PetscCall(printMumpsMemoryInfo(F));
215:     }

217:     /* sequential ordering */
218:     icntl = 7;
219:     ival  = 2;
220:     PetscCall(MatMumpsSetIcntl(F, icntl, ival));

222:     /* threshold for row pivot detection */
223:     PetscCall(MatMumpsGetIcntl(F, 24, &ival));
224:     PetscCheck(ival == 1, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "ICNTL(24) = %" PetscInt_FMT " (!= 1)", ival);
225:     icntl = 3;
226:     PetscCall(MatMumpsGetCntl(F, icntl, &val));
227:     PetscCheck(PetscEqualReal(val, 1e-6), PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "CNTL(3) = %g (!= %g)", (double)val, 1e-6);

229:     /* compute determinant of A */
230:     PetscCall(MatMumpsSetIcntl(F, 33, 1));
231:   }
232: #endif

234:   /*
235:     Example of how to use external package SuperLU
236:     Note: runtime options
237:           '-ksp_type preonly -pc_type ilu -pc_factor_mat_solver_type superlu -mat_superlu_ilu_droptol 1.e-8'
238:           are equivalent to these procedual calls
239:   */
240: #if defined(PETSC_HAVE_SUPERLU) || defined(PETSC_HAVE_SUPERLU_DIST)
241:   flg_ilu     = PETSC_FALSE;
242:   flg_superlu = PETSC_FALSE;
243:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-use_superlu_lu", &flg_superlu, NULL));
244:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-use_superlu_ilu", &flg_ilu, NULL));
245:   if (flg_superlu || flg_ilu) {
246:     PetscCall(KSPSetType(ksp, KSPPREONLY));
247:     PetscCall(KSPGetPC(ksp, &pc));
248:     if (flg_superlu) PetscCall(PCSetType(pc, PCLU));
249:     else if (flg_ilu) PetscCall(PCSetType(pc, PCILU));
250:     if (size == 1) {
251:   #if !defined(PETSC_HAVE_SUPERLU)
252:       SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "This test requires SUPERLU");
253:   #else
254:       PetscCall(PCFactorSetMatSolverType(pc, MATSOLVERSUPERLU));
255:   #endif
256:     } else {
257:   #if !defined(PETSC_HAVE_SUPERLU_DIST)
258:       SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "This test requires SUPERLU_DIST");
259:   #else
260:       PetscCall(PCFactorSetMatSolverType(pc, MATSOLVERSUPERLU_DIST));
261:   #endif
262:     }
263:     PetscCall(PCFactorSetUpMatSolverType(pc)); /* call MatGetFactor() to create F */
264:     PetscCall(PCFactorGetMatrix(pc, &F));
265:   #if defined(PETSC_HAVE_SUPERLU)
266:     if (size == 1) PetscCall(MatSuperluSetILUDropTol(F, 1.e-8));
267:   #endif
268:   }
269: #endif

271:   /*
272:     Example of how to use external package STRUMPACK
273:     Note: runtime options
274:           '-pc_type lu/ilu \
275:            -pc_factor_mat_solver_type strumpack \
276:            -mat_strumpack_reordering METIS \
277:            -mat_strumpack_colperm 0 \
278:            -mat_strumpack_hss_rel_tol 1.e-3 \
279:            -mat_strumpack_hss_min_sep_size 50 \
280:            -mat_strumpack_max_rank 100 \
281:            -mat_strumpack_leaf_size 4'
282:        are equivalent to these procedural calls

284:     We refer to the STRUMPACK-sparse manual, section 5, for more info on
285:     how to tune the preconditioner.
286:   */
287: #if defined(PETSC_HAVE_STRUMPACK)
288:   flg_ilu       = PETSC_FALSE;
289:   flg_strumpack = PETSC_FALSE;
290:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-use_strumpack_lu", &flg_strumpack, NULL));
291:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-use_strumpack_ilu", &flg_ilu, NULL));
292:   if (flg_strumpack || flg_ilu) {
293:     PetscCall(KSPSetType(ksp, KSPPREONLY));
294:     PetscCall(KSPGetPC(ksp, &pc));
295:     if (flg_strumpack) PetscCall(PCSetType(pc, PCLU));
296:     else if (flg_ilu) PetscCall(PCSetType(pc, PCILU));
297:   #if !defined(PETSC_HAVE_STRUMPACK)
298:     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "This test requires STRUMPACK");
299:   #endif
300:     PetscCall(PCFactorSetMatSolverType(pc, MATSOLVERSTRUMPACK));
301:     PetscCall(PCFactorSetUpMatSolverType(pc)); /* call MatGetFactor() to create F */
302:     PetscCall(PCFactorGetMatrix(pc, &F));
303:   #if defined(PETSC_HAVE_STRUMPACK)
304:     /* Set the fill-reducing reordering.                              */
305:     PetscCall(MatSTRUMPACKSetReordering(F, MAT_STRUMPACK_METIS));
306:     /* Since this is a simple discretization, the diagonal is always  */
307:     /* nonzero, and there is no need for the extra MC64 permutation.  */
308:     PetscCall(MatSTRUMPACKSetColPerm(F, PETSC_FALSE));
309:     /* The compression tolerance used when doing low-rank compression */
310:     /* in the preconditioner. This is problem specific!               */
311:     PetscCall(MatSTRUMPACKSetHSSRelTol(F, 1.e-3));
312:     /* Set minimum matrix size for HSS compression to 15 in order to  */
313:     /* demonstrate preconditioner on small problems. For performance  */
314:     /* a value of say 500 is better.                                  */
315:     PetscCall(MatSTRUMPACKSetHSSMinSepSize(F, 15));
316:     /* You can further limit the fill in the preconditioner by        */
317:     /* setting a maximum rank                                         */
318:     PetscCall(MatSTRUMPACKSetHSSMaxRank(F, 100));
319:     /* Set the size of the diagonal blocks (the leafs) in the HSS     */
320:     /* approximation. The default value should be better for real     */
321:     /* problems. This is mostly for illustration on a small problem.  */
322:     PetscCall(MatSTRUMPACKSetHSSLeafSize(F, 4));
323:   #endif
324:   }
325: #endif

327:   /*
328:     Example of how to use procedural calls that are equivalent to
329:           '-ksp_type preonly -pc_type lu/ilu -pc_factor_mat_solver_type petsc'
330:   */
331:   flg     = PETSC_FALSE;
332:   flg_ilu = PETSC_FALSE;
333:   flg_ch  = PETSC_FALSE;
334:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-use_petsc_lu", &flg, NULL));
335:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-use_petsc_ilu", &flg_ilu, NULL));
336:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-use_petsc_ch", &flg_ch, NULL));
337:   if (flg || flg_ilu || flg_ch) {
338:     Vec diag;

340:     PetscCall(KSPSetType(ksp, KSPPREONLY));
341:     PetscCall(KSPGetPC(ksp, &pc));
342:     if (flg) PetscCall(PCSetType(pc, PCLU));
343:     else if (flg_ilu) PetscCall(PCSetType(pc, PCILU));
344:     else if (flg_ch) PetscCall(PCSetType(pc, PCCHOLESKY));
345:     PetscCall(PCFactorSetMatSolverType(pc, MATSOLVERPETSC));
346:     PetscCall(PCFactorSetUpMatSolverType(pc)); /* call MatGetFactor() to create F */
347:     PetscCall(PCFactorGetMatrix(pc, &F));

349:     /* Test MatGetDiagonal() */
350:     PetscCall(KSPSetUp(ksp));
351:     PetscCall(VecDuplicate(x, &diag));
352:     PetscCall(MatGetDiagonal(F, diag));
353:     /* PetscCall(VecView(diag,PETSC_VIEWER_STDOUT_WORLD)); */
354:     PetscCall(VecDestroy(&diag));
355:   }

357:   PetscCall(KSPSetFromOptions(ksp));

359:   /* Get info from matrix factors */
360:   PetscCall(KSPSetUp(ksp));

362: #if defined(PETSC_HAVE_MUMPS)
363:   if (flg_mumps || flg_mumps_ch) {
364:     PetscInt  icntl, infog34, num_null_pivots, *null_pivots;
365:     PetscReal cntl, rinfo12, rinfo13;
366:     icntl = 3;
367:     PetscCall(MatMumpsGetCntl(F, icntl, &cntl));

369:     /* compute determinant and check for any null pivots*/
370:     if (rank == 0) {
371:       PetscCall(MatMumpsGetInfog(F, 34, &infog34));
372:       PetscCall(MatMumpsGetRinfog(F, 12, &rinfo12));
373:       PetscCall(MatMumpsGetRinfog(F, 13, &rinfo13));
374:       PetscCall(MatMumpsGetNullPivots(F, &num_null_pivots, &null_pivots));
375:       PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Mumps row pivot threshold = %g\n", cntl));
376:       PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Mumps determinant = (%g, %g) * 2^%" PetscInt_FMT " \n", (double)rinfo12, (double)rinfo13, infog34));
377:       if (num_null_pivots > 0) {
378:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Mumps num of null pivots detected = %" PetscInt_FMT "\n", num_null_pivots));
379:         PetscCall(PetscSortInt(num_null_pivots, null_pivots)); /* just make the printf deterministic */
380:         for (j = 0; j < num_null_pivots; j++) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Mumps row with null pivots is = %" PetscInt_FMT "\n", null_pivots[j]));
381:       }
382:       PetscCall(PetscFree(null_pivots));
383:     }
384:   }
385: #endif

387:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
388:                       Solve the linear system
389:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
390:   PetscCall(KSPSolve(ksp, b, x));

392:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
393:                       Check solution and clean up
394:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
395:   PetscCall(VecAXPY(x, -1.0, u));
396:   PetscCall(VecNorm(x, NORM_2, &norm));
397:   PetscCall(KSPGetIterationNumber(ksp, &its));

399:   /*
400:      Print convergence information.  PetscPrintf() produces a single
401:      print statement from all processes that share a communicator.
402:      An alternative is PetscFPrintf(), which prints to a file.
403:   */
404:   if (norm < 1.e-12) {
405:     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Norm of error < 1.e-12 iterations %" PetscInt_FMT "\n", its));
406:   } else {
407:     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Norm of error %g iterations %" PetscInt_FMT "\n", (double)norm, its));
408:   }

410:   /*
411:      Free work space.  All PETSc objects should be destroyed when they
412:      are no longer needed.
413:   */
414:   PetscCall(KSPDestroy(&ksp));
415:   PetscCall(VecDestroy(&u));
416:   PetscCall(VecDestroy(&x));
417:   PetscCall(VecDestroy(&b));
418:   PetscCall(MatDestroy(&A));

420:   /*
421:      Always call PetscFinalize() before exiting a program.  This routine
422:        - finalizes the PETSc libraries as well as MPI
423:        - provides summary and diagnostic information if certain runtime
424:          options are chosen (e.g., -log_view).
425:   */
426:   PetscCall(PetscFinalize());
427:   return 0;
428: }

430: /*TEST

432:    test:
433:       args: -use_petsc_lu
434:       output_file: output/ex52_2.out

436:    test:
437:       suffix: mumps
438:       nsize: 3
439:       requires: mumps
440:       args: -use_mumps_lu
441:       output_file: output/ex52_1.out

443:    test:
444:       suffix: mumps_2
445:       nsize: 3
446:       requires: mumps
447:       args: -use_mumps_ch
448:       output_file: output/ex52_1.out

450:    test:
451:       suffix: mumps_3
452:       nsize: 3
453:       requires: mumps
454:       args: -use_mumps_ch -mat_type sbaij
455:       output_file: output/ex52_1.out

457:    test:
458:       suffix: mumps_4
459:       nsize: 3
460:       requires: mumps !complex !single
461:       args: -use_mumps_lu -m 50 -n 50 -print_mumps_memory
462:       output_file: output/ex52_4.out

464:    test:
465:       suffix: mumps_5
466:       nsize: 3
467:       requires: mumps !complex !single
468:       args: -use_mumps_lu -m 50 -n 50 -zero_first_and_last_rows
469:       output_file: output/ex52_5.out

471:    test:
472:       suffix: mumps_omp_2
473:       nsize: 4
474:       requires: mumps hwloc openmp pthread defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
475:       args: -use_mumps_lu -mat_mumps_use_omp_threads 2
476:       output_file: output/ex52_1.out

478:    test:
479:       suffix: mumps_omp_3
480:       nsize: 4
481:       requires: mumps hwloc openmp pthread defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
482:       args: -use_mumps_ch -mat_mumps_use_omp_threads 3
483:       # Ignore the warning since we are intentionally testing the imbalanced case
484:       filter: grep -v "Warning: number of OpenMP threads"
485:       output_file: output/ex52_1.out

487:    test:
488:       suffix: mumps_omp_4
489:       nsize: 4
490:       requires: mumps hwloc openmp pthread defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
491:       # let petsc guess a proper number for threads
492:       args: -use_mumps_ch -mat_type sbaij -mat_mumps_use_omp_threads
493:       output_file: output/ex52_1.out

495:    testset:
496:       suffix: strumpack_2
497:       nsize: {{1 2}}
498:       requires: strumpack
499:       args: -use_strumpack_lu
500:       output_file: output/ex52_3.out

502:       test:
503:         suffix: aij
504:         args: -mat_type aij

506:       test:
507:         requires: kokkos_kernels
508:         suffix: kok
509:         args: -mat_type aijkokkos

511:       test:
512:         requires: cuda
513:         suffix: cuda
514:         args: -mat_type aijcusparse

516:       test:
517:         requires: hip
518:         suffix: hip
519:         args: -mat_type aijhipsparse

521:    test:
522:       suffix: strumpack_ilu
523:       nsize: {{1 2}}
524:       requires: strumpack
525:       args: -use_strumpack_ilu
526:       output_file: output/ex52_3.out

528:    testset:
529:       suffix: superlu_dist
530:       nsize: {{1 2}}
531:       requires: superlu superlu_dist
532:       args: -use_superlu_lu
533:       output_file: output/ex52_2.out

535:       test:
536:         suffix: aij
537:         args: -mat_type aij

539:       test:
540:         requires: kokkos_kernels
541:         suffix: kok
542:         args: -mat_type aijkokkos

544:       test:
545:         requires: cuda
546:         suffix: cuda
547:         args: -mat_type aijcusparse

549:       test:
550:         requires: hip
551:         suffix: hip
552:         args: -mat_type aijhipsparse

554:    test:
555:       suffix: superlu_ilu
556:       requires: superlu superlu_dist
557:       args: -use_superlu_ilu
558:       output_file: output/ex52_2.out

560: TEST*/