Date: 2025-03-28T21:10:54+00:00

Actual source code: ex53.c

      1: static char help[] = "Solves a tridiagonal linear system with KSP. \n\
      2:                       Modified from ex1.c to illustrate reuse of preconditioner \n\
      3:                       Written as requested by [petsc-maint #63875] \n\n";

      5: #include <petscksp.h>

      7: int main(int argc, char **args)
      8: {
      9:   Vec         x, x2, b, u;                              /* approx solution, RHS, exact solution */
     10:   Mat         A;                                        /* linear system matrix */
     11:   KSP         ksp;                                      /* linear solver context */
     12:   PC          pc;                                       /* preconditioner context */
     13:   PetscReal   norm, tol = 100. * PETSC_MACHINE_EPSILON; /* norm of solution error */
     14:   PetscInt    i, n      = 10, col[3], its;
     15:   PetscMPIInt rank, size;
     16:   PetscScalar one = 1.0, value[3];

     18:   PetscFunctionBeginUser;
     19:   PetscCall(PetscInitialize(&argc, &args, NULL, help));
     20:   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
     21:   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
     22:   PetscCall(PetscOptionsGetInt(NULL, NULL, "-n", &n, NULL));

     24:   /* Create vectors.*/
     25:   PetscCall(VecCreate(PETSC_COMM_WORLD, &x));
     26:   PetscCall(PetscObjectSetName((PetscObject)x, "Solution"));
     27:   PetscCall(VecSetSizes(x, PETSC_DECIDE, n));
     28:   PetscCall(VecSetFromOptions(x));
     29:   PetscCall(VecDuplicate(x, &b));
     30:   PetscCall(VecDuplicate(x, &u));
     31:   PetscCall(VecDuplicate(x, &x2));

     33:   /* Create matrix. Only proc[0] sets values - not efficient for parallel processing!
     34:      See ex23.c for efficient parallel assembly matrix */
     35:   PetscCall(MatCreate(PETSC_COMM_WORLD, &A));
     36:   PetscCall(MatSetSizes(A, PETSC_DECIDE, PETSC_DECIDE, n, n));
     37:   PetscCall(MatSetFromOptions(A));
     38:   PetscCall(MatSetUp(A));

     40:   if (rank == 0) {
     41:     value[0] = -1.0;
     42:     value[1] = 2.0;
     43:     value[2] = -1.0;
     44:     for (i = 1; i < n - 1; i++) {
     45:       col[0] = i - 1;
     46:       col[1] = i;
     47:       col[2] = i + 1;
     48:       PetscCall(MatSetValues(A, 1, &i, 3, col, value, INSERT_VALUES));
     49:     }
     50:     i      = n - 1;
     51:     col[0] = n - 2;
     52:     col[1] = n - 1;
     53:     PetscCall(MatSetValues(A, 1, &i, 2, col, value, INSERT_VALUES));
     54:     i        = 0;
     55:     col[0]   = 0;
     56:     col[1]   = 1;
     57:     value[0] = 2.0;
     58:     value[1] = -1.0;
     59:     PetscCall(MatSetValues(A, 1, &i, 2, col, value, INSERT_VALUES));

     61:     i        = 0;
     62:     col[0]   = n - 1;
     63:     value[0] = 0.5; /* make A non-symmetric */
     64:     PetscCall(MatSetValues(A, 1, &i, 1, col, value, INSERT_VALUES));
     65:   }
     66:   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
     67:   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));

     69:   /* Set exact solution */
     70:   PetscCall(VecSet(u, one));

     72:   /* Create linear solver context */
     73:   PetscCall(KSPCreate(PETSC_COMM_WORLD, &ksp));
     74:   PetscCall(KSPSetOperators(ksp, A, A));
     75:   PetscCall(KSPGetPC(ksp, &pc));
     76:   PetscCall(PCSetType(pc, PCLU));
     77: #if defined(PETSC_HAVE_MUMPS)
     78:   if (size > 1) PetscCall(PCFactorSetMatSolverType(pc, MATSOLVERMUMPS));
     79: #endif
     80:   PetscCall(KSPSetFromOptions(ksp));

     82:   /* 1. Solve linear system A x = b */
     83:   PetscCall(MatMult(A, u, b));
     84:   PetscCall(KSPSolve(ksp, b, x));

     86:   /* Check the error */
     87:   PetscCall(VecAXPY(x, -1.0, u));
     88:   PetscCall(VecNorm(x, NORM_2, &norm));
     89:   PetscCall(KSPGetIterationNumber(ksp, &its));
     90:   if (norm > tol) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "1. Norm of error for Ax=b: %g, Iterations %" PetscInt_FMT "\n", (double)norm, its));

     92:   /* 2. Solve linear system A^T x = b*/
     93:   PetscCall(MatMultTranspose(A, u, b));
     94:   PetscCall(KSPSolveTranspose(ksp, b, x2));

     96:   /* Check the error */
     97:   PetscCall(VecAXPY(x2, -1.0, u));
     98:   PetscCall(VecNorm(x2, NORM_2, &norm));
     99:   PetscCall(KSPGetIterationNumber(ksp, &its));
    100:   if (norm > tol) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "2. Norm of error for A^T x=b: %g, Iterations %" PetscInt_FMT "\n", (double)norm, its));

    102:   /* 3. Change A and solve A x = b with an iterative solver using A=LU as a preconditioner*/
    103:   if (rank == 0) {
    104:     i        = 0;
    105:     col[0]   = n - 1;
    106:     value[0] = 1.e-2;
    107:     PetscCall(MatSetValues(A, 1, &i, 1, col, value, ADD_VALUES));
    108:   }
    109:   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
    110:   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));

    112:   PetscCall(MatMult(A, u, b));
    113:   PetscCall(KSPSolve(ksp, b, x));

    115:   /* Check the error */
    116:   PetscCall(VecAXPY(x, -1.0, u));
    117:   PetscCall(VecNorm(x, NORM_2, &norm));
    118:   PetscCall(KSPGetIterationNumber(ksp, &its));
    119:   if (norm > tol) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "3. Norm of error for (A+Delta) x=b: %g, Iterations %" PetscInt_FMT "\n", (double)norm, its));

    121:   /* Free work space. */
    122:   PetscCall(VecDestroy(&x));
    123:   PetscCall(VecDestroy(&u));
    124:   PetscCall(VecDestroy(&x2));
    125:   PetscCall(VecDestroy(&b));
    126:   PetscCall(MatDestroy(&A));
    127:   PetscCall(KSPDestroy(&ksp));

    129:   PetscCall(PetscFinalize());
    130:   return 0;
    131: }

    133: /*TEST

    135:    test:
    136:       requires: mumps

    138:    test:
    139:       suffix: 2
    140:       nsize: 2
    141:       requires: mumps
    142:       output_file: output/ex53.out

    144: TEST*/