Date: 2022-03-04T17:39:12+00:00

Actual source code: ex15.c

      2: static char help[] = "Solves a linear system in parallel with KSP.  Also\n\
      3: illustrates setting a user-defined shell preconditioner and using the\n\
      4: Input parameters include:\n\
      5:   -user_defined_pc : Activate a user-defined preconditioner\n\n";

      7: /*T
      8:    Concepts: KSP^basic parallel example
      9:    Concepts: PC^setting a user-defined shell preconditioner
     10:    Processors: n
     11: T*/

     13: /*
     14:   Include "petscksp.h" so that we can use KSP solvers.  Note that this file
     15:   automatically includes:
     16:      petscsys.h       - base PETSc routines   petscvec.h - vectors
     17:      petscmat.h - matrices
     18:      petscis.h     - index sets            petscksp.h - Krylov subspace methods
     19:      petscviewer.h - viewers               petscpc.h  - preconditioners
     20: */
     21: #include <petscksp.h>

     23: /* Define context for user-provided preconditioner */
     24: typedef struct {
     25:   Vec diag;
     26: } SampleShellPC;

     28: /* Declare routines for user-provided preconditioner */
     29: extern PetscErrorCode SampleShellPCCreate(SampleShellPC**);
     30: extern PetscErrorCode SampleShellPCSetUp(PC,Mat,Vec);
     31: extern PetscErrorCode SampleShellPCApply(PC,Vec x,Vec y);
     32: extern PetscErrorCode SampleShellPCDestroy(PC);

     34: /*
     35:    User-defined routines.  Note that immediately before each routine below,
     36:    If defined, this macro is used in the PETSc error handlers to provide a
     37:    complete traceback of routine names.  All PETSc library routines use this
     38:    macro, and users can optionally employ it as well in their application
     39:    codes.  Note that users can get a traceback of PETSc errors regardless of
     40:    provides the added traceback detail of the application routine names.
     41: */

     43: int main(int argc,char **args)
     44: {
     45:   Vec            x,b,u;   /* approx solution, RHS, exact solution */
     46:   Mat            A;         /* linear system matrix */
     47:   KSP            ksp;      /* linear solver context */
     48:   PC             pc;        /* preconditioner context */
     49:   PetscReal      norm;      /* norm of solution error */
     50:   SampleShellPC  *shell;    /* user-defined preconditioner context */
     51:   PetscScalar    v,one = 1.0,none = -1.0;
     52:   PetscInt       i,j,Ii,J,Istart,Iend,m = 8,n = 7,its;
     54:   PetscBool      user_defined_pc = PETSC_FALSE;

     56:   PetscInitialize(&argc,&args,(char*)0,help);if (ierr) return ierr;
     57:   PetscOptionsGetInt(NULL,NULL,"-m",&m,NULL);
     58:   PetscOptionsGetInt(NULL,NULL,"-n",&n,NULL);

     60:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     61:          Compute the matrix and right-hand-side vector that define
     62:          the linear system, Ax = b.
     63:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     64:   /*
     65:      Create parallel matrix, specifying only its global dimensions.
     66:      When using MatCreate(), the matrix format can be specified at
     67:      runtime. Also, the parallel partioning of the matrix is
     68:      determined by PETSc at runtime.
     69:   */
     70:   MatCreate(PETSC_COMM_WORLD,&A);
     71:   MatSetSizes(A,PETSC_DECIDE,PETSC_DECIDE,m*n,m*n);
     72:   MatSetFromOptions(A);
     73:   MatSetUp(A);

     75:   /*
     76:      Currently, all PETSc parallel matrix formats are partitioned by
     77:      contiguous chunks of rows across the processors.  Determine which
     78:      rows of the matrix are locally owned.
     79:   */
     80:   MatGetOwnershipRange(A,&Istart,&Iend);

     82:   /*
     83:      Set matrix elements for the 2-D, five-point stencil in parallel.
     84:       - Each processor needs to insert only elements that it owns
     85:         locally (but any non-local elements will be sent to the
     86:         appropriate processor during matrix assembly).
     87:       - Always specify global rows and columns of matrix entries.
     88:    */
     89:   for (Ii=Istart; Ii<Iend; Ii++) {
     90:     v = -1.0; i = Ii/n; j = Ii - i*n;
     91:     if (i>0)   {J = Ii - n; MatSetValues(A,1,&Ii,1,&J,&v,INSERT_VALUES);}
     92:     if (i<m-1) {J = Ii + n; MatSetValues(A,1,&Ii,1,&J,&v,INSERT_VALUES);}
     93:     if (j>0)   {J = Ii - 1; MatSetValues(A,1,&Ii,1,&J,&v,INSERT_VALUES);}
     94:     if (j<n-1) {J = Ii + 1; MatSetValues(A,1,&Ii,1,&J,&v,INSERT_VALUES);}
     95:     v = 4.0; MatSetValues(A,1,&Ii,1,&Ii,&v,INSERT_VALUES);
     96:   }

     98:   /*
     99:      Assemble matrix, using the 2-step process:
    100:        MatAssemblyBegin(), MatAssemblyEnd()
    101:      Computations can be done while messages are in transition
    102:      by placing code between these two statements.
    103:   */
    104:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
    105:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);

    107:   /*
    108:      Create parallel vectors.
    109:       - When using VecCreate() VecSetSizes() and VecSetFromOptions(),
    110:         we specify only the vector's global
    111:         dimension; the parallel partitioning is determined at runtime.
    112:       - Note: We form 1 vector from scratch and then duplicate as needed.
    113:   */
    114:   VecCreate(PETSC_COMM_WORLD,&u);
    115:   VecSetSizes(u,PETSC_DECIDE,m*n);
    116:   VecSetFromOptions(u);
    117:   VecDuplicate(u,&b);
    118:   VecDuplicate(b,&x);

    120:   /*
    121:      Set exact solution; then compute right-hand-side vector.
    122:   */
    123:   VecSet(u,one);
    124:   MatMult(A,u,b);

    126:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    127:                 Create the linear solver and set various options
    128:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    130:   /*
    131:      Create linear solver context
    132:   */
    133:   KSPCreate(PETSC_COMM_WORLD,&ksp);

    135:   /*
    136:      Set operators. Here the matrix that defines the linear system
    137:      also serves as the preconditioning matrix.
    138:   */
    139:   KSPSetOperators(ksp,A,A);

    141:   /*
    142:      Set linear solver defaults for this problem (optional).
    143:      - By extracting the KSP and PC contexts from the KSP context,
    144:        we can then directly call any KSP and PC routines
    145:        to set various options.
    146:   */
    147:   KSPGetPC(ksp,&pc);
    148:   KSPSetTolerances(ksp,1.e-7,PETSC_DEFAULT,PETSC_DEFAULT,
    149:                           PETSC_DEFAULT);

    151:   /*
    152:      Set a user-defined "shell" preconditioner if desired
    153:   */
    154:   PetscOptionsGetBool(NULL,NULL,"-user_defined_pc",&user_defined_pc,NULL);
    155:   if (user_defined_pc) {
    156:     /* (Required) Indicate to PETSc that we're using a "shell" preconditioner */
    157:     PCSetType(pc,PCSHELL);

    159:     /* (Optional) Create a context for the user-defined preconditioner; this
    160:        context can be used to contain any application-specific data. */
    161:     SampleShellPCCreate(&shell);

    163:     /* (Required) Set the user-defined routine for applying the preconditioner */
    164:     PCShellSetApply(pc,SampleShellPCApply);
    165:     PCShellSetContext(pc,shell);

    167:     /* (Optional) Set user-defined function to free objects used by custom preconditioner */
    168:     PCShellSetDestroy(pc,SampleShellPCDestroy);

    170:     /* (Optional) Set a name for the preconditioner, used for PCView() */
    171:     PCShellSetName(pc,"MyPreconditioner");

    173:     /* (Optional) Do any setup required for the preconditioner */
    174:     /* Note: This function could be set with PCShellSetSetUp and it would be called when necessary */
    175:     SampleShellPCSetUp(pc,A,x);

    177:   } else {
    178:     PCSetType(pc,PCJACOBI);
    179:   }

    181:   /*
    182:     Set runtime options, e.g.,
    183:         -ksp_type <type> -pc_type <type> -ksp_monitor -ksp_rtol <rtol>
    184:     These options will override those specified above as long as
    185:     KSPSetFromOptions() is called _after_ any other customization
    186:     routines.
    187:   */
    188:   KSPSetFromOptions(ksp);

    190:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    191:                       Solve the linear system
    192:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    194:   KSPSolve(ksp,b,x);

    196:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    197:                       Check solution and clean up
    198:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    200:   /*
    201:      Check the error
    202:   */
    203:   VecAXPY(x,none,u);
    204:   VecNorm(x,NORM_2,&norm);
    205:   KSPGetIterationNumber(ksp,&its);
    206:   PetscPrintf(PETSC_COMM_WORLD,"Norm of error %g iterations %D\n",(double)norm,its);

    208:   /*
    209:      Free work space.  All PETSc objects should be destroyed when they
    210:      are no longer needed.
    211:   */
    212:   KSPDestroy(&ksp);
    213:   VecDestroy(&u);  VecDestroy(&x);
    214:   VecDestroy(&b);  MatDestroy(&A);

    216:   PetscFinalize();
    217:   return ierr;

    219: }

    221: /***********************************************************************/
    222: /*          Routines for a user-defined shell preconditioner           */
    223: /***********************************************************************/

    225: /*
    226:    SampleShellPCCreate - This routine creates a user-defined
    227:    preconditioner context.

    229:    Output Parameter:
    230: .  shell - user-defined preconditioner context
    231: */
    232: PetscErrorCode SampleShellPCCreate(SampleShellPC **shell)
    233: {
    234:   SampleShellPC  *newctx;

    237:   PetscNew(&newctx);
    238:   newctx->diag = 0;
    239:   *shell       = newctx;
    240:   return 0;
    241: }
    242: /* ------------------------------------------------------------------- */
    243: /*
    244:    SampleShellPCSetUp - This routine sets up a user-defined
    245:    preconditioner context.

    247:    Input Parameters:
    248: .  pc    - preconditioner object
    249: .  pmat  - preconditioner matrix
    250: .  x     - vector

    252:    Output Parameter:
    253: .  shell - fully set up user-defined preconditioner context

    255:    Notes:
    256:    In this example, we define the shell preconditioner to be Jacobi's
    257:    method.  Thus, here we create a work vector for storing the reciprocal
    258:    of the diagonal of the preconditioner matrix; this vector is then
    259:    used within the routine SampleShellPCApply().
    260: */
    261: PetscErrorCode SampleShellPCSetUp(PC pc,Mat pmat,Vec x)
    262: {
    263:   SampleShellPC  *shell;
    264:   Vec            diag;

    267:   PCShellGetContext(pc,&shell);
    268:   VecDuplicate(x,&diag);
    269:   MatGetDiagonal(pmat,diag);
    270:   VecReciprocal(diag);

    272:   shell->diag = diag;
    273:   return 0;
    274: }
    275: /* ------------------------------------------------------------------- */
    276: /*
    277:    SampleShellPCApply - This routine demonstrates the use of a
    278:    user-provided preconditioner.

    280:    Input Parameters:
    281: +  pc - preconditioner object
    282: -  x - input vector

    284:    Output Parameter:
    285: .  y - preconditioned vector

    287:    Notes:
    288:    This code implements the Jacobi preconditioner, merely as an
    289:    example of working with a PCSHELL.  Note that the Jacobi method
    290:    is already provided within PETSc.
    291: */
    292: PetscErrorCode SampleShellPCApply(PC pc,Vec x,Vec y)
    293: {
    294:   SampleShellPC  *shell;

    297:   PCShellGetContext(pc,&shell);
    298:   VecPointwiseMult(y,x,shell->diag);

    300:   return 0;
    301: }
    302: /* ------------------------------------------------------------------- */
    303: /*
    304:    SampleShellPCDestroy - This routine destroys a user-defined
    305:    preconditioner context.

    307:    Input Parameter:
    308: .  shell - user-defined preconditioner context
    309: */
    310: PetscErrorCode SampleShellPCDestroy(PC pc)
    311: {
    312:   SampleShellPC  *shell;

    315:   PCShellGetContext(pc,&shell);
    316:   VecDestroy(&shell->diag);
    317:   PetscFree(shell);

    319:   return 0;
    320: }

    322: /*TEST

    324:    build:
    325:       requires: !complex !single

    327:    test:
    328:       nsize: 2
    329:       args: -ksp_view -user_defined_pc -ksp_gmres_cgs_refinement_type refine_always

    331:    test:
    332:       suffix: tsirm
    333:       args: -m 60 -n 60 -ksp_type tsirm -pc_type ksp -ksp_monitor_short -ksp_ksp_type fgmres -ksp_ksp_rtol 1e-10 -ksp_pc_type mg -ksp_ksp_max_it 30
    334:       timeoutfactor: 4

    336: TEST*/