Date: 2013-07-02T14:49:42+00:00

Actual source code: ex7.c
petsc-3.4.2 2013-07-02

      2: static char help[] = "Solves u`` + u^{2} = f with Newton-like methods. Using\n\
      3:  matrix-free techniques with user-provided explicit preconditioner matrix.\n\n";

      5: #include <petscsnes.h>

      7: extern PetscErrorCode   FormJacobian(SNES,Vec,Mat*,Mat*,MatStructure*,void*);
      8: extern PetscErrorCode   FormFunction(SNES,Vec,Vec,void*);
      9: extern PetscErrorCode   FormInitialGuess(SNES,Vec);
     10: extern PetscErrorCode   Monitor(SNES,PetscInt,PetscReal,void*);

     12: typedef struct {
     13:   PetscViewer viewer;
     14: } MonitorCtx;

     16: typedef struct {
     17:   Mat       precond;
     18:   PetscBool variant;
     19: } AppCtx;

     23: int main(int argc,char **argv)
     24: {
     25:   SNES           snes;                 /* SNES context */
     26:   SNESType       type = SNESNEWTONLS;        /* default nonlinear solution method */
     27:   Vec            x,r,F,U;              /* vectors */
     28:   Mat            J,B;                  /* Jacobian matrix-free, explicit preconditioner */
     29:   MonitorCtx     monP;                 /* monitoring context */
     30:   AppCtx         user;                 /* user-defined work context */
     31:   PetscScalar    h,xp = 0.0,v;
     32:   PetscInt       its,n = 5,i;

     35:   PetscInitialize(&argc,&argv,(char*)0,help);
     36:   PetscOptionsGetInt(NULL,"-n",&n,NULL);
     37:   PetscOptionsHasName(NULL,"-variant",&user.variant);
     38:   h    = 1.0/(n-1);

     40:   /* Set up data structures */
     41:   PetscViewerDrawOpen(PETSC_COMM_SELF,0,0,0,0,400,400,&monP.viewer);
     42:   VecCreateSeq(PETSC_COMM_SELF,n,&x);
     43:   PetscObjectSetName((PetscObject)x,"Approximate Solution");
     44:   VecDuplicate(x,&r);
     45:   VecDuplicate(x,&F);
     46:   VecDuplicate(x,&U);
     47:   PetscObjectSetName((PetscObject)U,"Exact Solution");

     49:   /* create explict matrix preconditioner */
     50:   MatCreateSeqAIJ(PETSC_COMM_SELF,n,n,3,NULL,&B);
     51:   user.precond = B;

     53:   /* Store right-hand-side of PDE and exact solution */
     54:   for (i=0; i<n; i++) {
     55:     v    = 6.0*xp + PetscPowScalar(xp+1.e-12,6.0); /* +1.e-12 is to prevent 0^6 */
     56:     VecSetValues(F,1,&i,&v,INSERT_VALUES);
     57:     v    = xp*xp*xp;
     58:     VecSetValues(U,1,&i,&v,INSERT_VALUES);
     59:     xp  += h;
     60:   }

     62:   /* Create nonlinear solver */
     63:   SNESCreate(PETSC_COMM_WORLD,&snes);
     64:   SNESSetType(snes,type);

     66:   /* Set various routines and options */
     67:   SNESSetFunction(snes,r,FormFunction,F);
     68:   if (user.variant) {
     69:     MatCreateMFFD(PETSC_COMM_WORLD,n,n,n,n,&J);
     70:     MatMFFDSetFunction(J,(PetscErrorCode (*)(void*, Vec, Vec))SNESComputeFunction,snes);
     71:   } else {
     72:     /* create matrix free matrix for Jacobian */
     73:     MatCreateSNESMF(snes,&J);
     74:   }

     76:   /* Set various routines and options */
     77:   SNESSetJacobian(snes,J,B,FormJacobian,&user);
     78:   SNESMonitorSet(snes,Monitor,&monP,0);
     79:   SNESSetFromOptions(snes);

     81:   /* Solve nonlinear system */
     82:   FormInitialGuess(snes,x);
     83:   SNESSolve(snes,NULL,x);
     84:   SNESGetIterationNumber(snes,&its);
     85:   PetscPrintf(PETSC_COMM_SELF,"number of SNES iterations = %D\n\n",its);

     87:   /* Free data structures */
     88:   VecDestroy(&x);  VecDestroy(&r);
     89:   VecDestroy(&U);  VecDestroy(&F);
     90:   MatDestroy(&J);  MatDestroy(&B);
     91:   SNESDestroy(&snes);
     92:   PetscViewerDestroy(&monP.viewer);
     93:   PetscFinalize();

     95:   return 0;
     96: }
     97: /* --------------------  Evaluate Function F(x) --------------------- */

     99: PetscErrorCode  FormFunction(SNES snes,Vec x,Vec f,void *dummy)
    100: {
    101:   PetscScalar    *xx,*ff,*FF,d;
    102:   PetscInt       i,n;

    105:   VecGetArray(x,&xx);
    106:   VecGetArray(f,&ff);
    107:   VecGetArray((Vec) dummy,&FF);
    108:   VecGetSize(x,&n);
    109:   d     = (PetscReal)(n - 1); d = d*d;
    110:   ff[0] = xx[0];
    111:   for (i=1; i<n-1; i++) ff[i] = d*(xx[i-1] - 2.0*xx[i] + xx[i+1]) + xx[i]*xx[i] - FF[i];
    112:   ff[n-1] = xx[n-1] - 1.0;
    113:   VecRestoreArray(x,&xx);
    114:   VecRestoreArray(f,&ff);
    115:   VecRestoreArray((Vec)dummy,&FF);
    116:   return 0;
    117: }
    118: /* --------------------  Form initial approximation ----------------- */

    122: PetscErrorCode  FormInitialGuess(SNES snes,Vec x)
    123: {
    125:   PetscScalar    pfive = .50;
    126:   VecSet(x,pfive);
    127:   return 0;
    128: }
    131: /* --------------------  Evaluate Jacobian F'(x) -------------------- */
    132: /*  Evaluates a matrix that is used to precondition the matrix-free
    133:     jacobian. In this case, the explict preconditioner matrix is
    134:     also EXACTLY the Jacobian. In general, it would be some lower
    135:     order, simplified apprioximation */

    137: PetscErrorCode  FormJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy)
    138: {
    139:   PetscScalar    *xx,A[3],d;
    140:   PetscInt       i,n,j[3],iter;
    142:   AppCtx         *user = (AppCtx*) dummy;

    144:   SNESGetIterationNumber(snes,&iter);

    146:   if (iter%2 ==0) { /* Compute new preconditioner matrix */
    147:     PetscPrintf(PETSC_COMM_SELF,"iter=%D, computing new preconditioning matrix\n",iter+1);
    148:     *B   = user->precond;
    149:     VecGetArray(x,&xx);
    150:     VecGetSize(x,&n);
    151:     d    = (PetscReal)(n - 1); d = d*d;

    153:     i    = 0; A[0] = 1.0;
    154:     MatSetValues(*B,1,&i,1,&i,&A[0],INSERT_VALUES);
    155:     for (i=1; i<n-1; i++) {
    156:       j[0] = i - 1; j[1] = i;                   j[2] = i + 1;
    157:       A[0] = d;     A[1] = -2.0*d + 2.0*xx[i];  A[2] = d;
    158:       MatSetValues(*B,1,&i,3,j,A,INSERT_VALUES);
    159:     }
    160:     i     = n-1; A[0] = 1.0;
    161:     MatSetValues(*B,1,&i,1,&i,&A[0],INSERT_VALUES);
    162:     MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);
    163:     MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);
    164:     VecRestoreArray(x,&xx);
    165:     *flag = SAME_NONZERO_PATTERN;
    166:   } else { /* reuse preconditioner from last iteration */
    167:     PetscPrintf(PETSC_COMM_SELF,"iter=%D, using old preconditioning matrix\n",iter+1);
    168:     *flag = SAME_PRECONDITIONER;
    169:   }
    170:   if (user->variant) {
    171:     MatMFFDSetBase(*jac,x,NULL);
    172:   }
    173:   MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);
    174:   MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);
    175:   return 0;
    176: }
    177: /* --------------------  User-defined monitor ----------------------- */

    181: PetscErrorCode  Monitor(SNES snes,PetscInt its,PetscReal fnorm,void *dummy)
    182: {
    184:   MonitorCtx     *monP = (MonitorCtx*) dummy;
    185:   Vec            x;
    186:   MPI_Comm       comm;

    188:   PetscObjectGetComm((PetscObject)snes,&comm);
    189:   PetscFPrintf(comm,stdout,"iter = %D, SNES Function norm %G \n",its,fnorm);
    190:   SNESGetSolution(snes,&x);
    191:   VecView(x,monP->viewer);
    192:   return 0;
    193: }