Date: 2022-08-02T03:14:55+00:00

Actual source code: ex1.c

      2: static char help[] = "Newton's method for a two-variable system, sequential.\n\n";

      4: /*
      5:    Include "petscsnes.h" so that we can use SNES solvers.  Note that this
      6:    file automatically includes:
      7:      petscsys.h       - base PETSc routines   petscvec.h - vectors
      8:      petscmat.h - matrices
      9:      petscis.h     - index sets            petscksp.h - Krylov subspace methods
     10:      petscviewer.h - viewers               petscpc.h  - preconditioners
     11:      petscksp.h   - linear solvers
     12: */

This examples solves either
\begin{equation}
F\genfrac{(}{)}{0pt}{}{x_0}{x_1} = \genfrac{(}{)}{0pt}{}{x^2_0 + x_0 x_1 - 3}{x_0 x_1 + x^2_1 - 6}
\end{equation}
or if the {\tt -hard} options is given
\begin{equation}
F\genfrac{(}{)}{0pt}{}{x_0}{x_1} = \genfrac{(}{)}{0pt}{}{\sin(3 x_0) + x_0}{x_1}
\end{equation}

     23: #include <petscsnes.h>

     25: /*
     26:    User-defined routines
     27: */
     28: extern PetscErrorCode FormJacobian1(SNES,Vec,Mat,Mat,void*);
     29: extern PetscErrorCode FormFunction1(SNES,Vec,Vec,void*);
     30: extern PetscErrorCode FormJacobian2(SNES,Vec,Mat,Mat,void*);
     31: extern PetscErrorCode FormFunction2(SNES,Vec,Vec,void*);

     33: int main(int argc,char **argv)
     34: {
     35:   SNES           snes;         /* nonlinear solver context */
     36:   KSP            ksp;          /* linear solver context */
     37:   PC             pc;           /* preconditioner context */
     38:   Vec            x,r;          /* solution, residual vectors */
     39:   Mat            J;            /* Jacobian matrix */
     40:   PetscMPIInt    size;
     41:   PetscScalar    pfive = .5,*xx;
     42:   PetscBool      flg;

     44:   PetscInitialize(&argc,&argv,(char*)0,help);
     45:   MPI_Comm_size(PETSC_COMM_WORLD,&size);

     48:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     49:      Create nonlinear solver context
     50:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     51:   SNESCreate(PETSC_COMM_WORLD,&snes);

     53:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     54:      Create matrix and vector data structures; set corresponding routines
     55:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     56:   /*
     57:      Create vectors for solution and nonlinear function
     58:   */
     59:   VecCreate(PETSC_COMM_WORLD,&x);
     60:   VecSetSizes(x,PETSC_DECIDE,2);
     61:   VecSetFromOptions(x);
     62:   VecDuplicate(x,&r);

     64:   /*
     65:      Create Jacobian matrix data structure
     66:   */
     67:   MatCreate(PETSC_COMM_WORLD,&J);
     68:   MatSetSizes(J,PETSC_DECIDE,PETSC_DECIDE,2,2);
     69:   MatSetFromOptions(J);
     70:   MatSetUp(J);

     72:   PetscOptionsHasName(NULL,NULL,"-hard",&flg);
     73:   if (!flg) {
     74:     /*
     75:      Set function evaluation routine and vector.
     76:     */
     77:     SNESSetFunction(snes,r,FormFunction1,NULL);

     79:     /*
     80:      Set Jacobian matrix data structure and Jacobian evaluation routine
     81:     */
     82:     SNESSetJacobian(snes,J,J,FormJacobian1,NULL);
     83:   } else {
     84:     SNESSetFunction(snes,r,FormFunction2,NULL);
     85:     SNESSetJacobian(snes,J,J,FormJacobian2,NULL);
     86:   }

     88:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     89:      Customize nonlinear solver; set runtime options
     90:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     91:   /*
     92:      Set linear solver defaults for this problem. By extracting the
     93:      KSP and PC contexts from the SNES context, we can then
     94:      directly call any KSP and PC routines to set various options.
     95:   */
     96:   SNESGetKSP(snes,&ksp);
     97:   KSPGetPC(ksp,&pc);
     98:   PCSetType(pc,PCNONE);
     99:   KSPSetTolerances(ksp,1.e-4,PETSC_DEFAULT,PETSC_DEFAULT,20);

    101:   /*
    102:      Set SNES/KSP/KSP/PC runtime options, e.g.,
    103:          -snes_view -snes_monitor -ksp_type <ksp> -pc_type <pc>
    104:      These options will override those specified above as long as
    105:      SNESSetFromOptions() is called _after_ any other customization
    106:      routines.
    107:   */
    108:   SNESSetFromOptions(snes);

    110:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    111:      Evaluate initial guess; then solve nonlinear system
    112:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    113:   if (!flg) {
    114:     VecSet(x,pfive);
    115:   } else {
    116:     VecGetArray(x,&xx);
    117:     xx[0] = 2.0; xx[1] = 3.0;
    118:     VecRestoreArray(x,&xx);
    119:   }
    120:   /*
    121:      Note: The user should initialize the vector, x, with the initial guess
    122:      for the nonlinear solver prior to calling SNESSolve().  In particular,
    123:      to employ an initial guess of zero, the user should explicitly set
    124:      this vector to zero by calling VecSet().
    125:   */

    127:   SNESSolve(snes,NULL,x);
    128:   if (flg) {
    129:     Vec f;
    130:     VecView(x,PETSC_VIEWER_STDOUT_WORLD);
    131:     SNESGetFunction(snes,&f,0,0);
    132:     VecView(r,PETSC_VIEWER_STDOUT_WORLD);
    133:   }

    135:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    136:      Free work space.  All PETSc objects should be destroyed when they
    137:      are no longer needed.
    138:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    140:   VecDestroy(&x)); PetscCall(VecDestroy(&r);
    141:   MatDestroy(&J)); PetscCall(SNESDestroy(&snes);
    142:   PetscFinalize();
    143:   return 0;
    144: }
    145: /* ------------------------------------------------------------------- */
    146: /*
    147:    FormFunction1 - Evaluates nonlinear function, F(x).

    149:    Input Parameters:
    150: .  snes - the SNES context
    151: .  x    - input vector
    152: .  ctx  - optional user-defined context

    154:    Output Parameter:
    155: .  f - function vector
    156:  */
    157: PetscErrorCode FormFunction1(SNES snes,Vec x,Vec f,void *ctx)
    158: {
    159:   const PetscScalar *xx;
    160:   PetscScalar       *ff;

    162:   /*
    163:    Get pointers to vector data.
    164:       - For default PETSc vectors, VecGetArray() returns a pointer to
    165:         the data array.  Otherwise, the routine is implementation dependent.
    166:       - You MUST call VecRestoreArray() when you no longer need access to
    167:         the array.
    168:    */
    169:   VecGetArrayRead(x,&xx);
    170:   VecGetArray(f,&ff);

    172:   /* Compute function */
    173:   ff[0] = xx[0]*xx[0] + xx[0]*xx[1] - 3.0;
    174:   ff[1] = xx[0]*xx[1] + xx[1]*xx[1] - 6.0;

    176:   /* Restore vectors */
    177:   VecRestoreArrayRead(x,&xx);
    178:   VecRestoreArray(f,&ff);
    179:   return 0;
    180: }
    181: /* ------------------------------------------------------------------- */
    182: /*
    183:    FormJacobian1 - Evaluates Jacobian matrix.

    185:    Input Parameters:
    186: .  snes - the SNES context
    187: .  x - input vector
    188: .  dummy - optional user-defined context (not used here)

    190:    Output Parameters:
    191: .  jac - Jacobian matrix
    192: .  B - optionally different preconditioning matrix
    193: .  flag - flag indicating matrix structure
    194: */
    195: PetscErrorCode FormJacobian1(SNES snes,Vec x,Mat jac,Mat B,void *dummy)
    196: {
    197:   const PetscScalar *xx;
    198:   PetscScalar       A[4];
    199:   PetscInt          idx[2] = {0,1};

    201:   /*
    202:      Get pointer to vector data
    203:   */
    204:   VecGetArrayRead(x,&xx);

    206:   /*
    207:      Compute Jacobian entries and insert into matrix.
    208:       - Since this is such a small problem, we set all entries for
    209:         the matrix at once.
    210:   */
    211:   A[0]  = 2.0*xx[0] + xx[1]; A[1] = xx[0];
    212:   A[2]  = xx[1]; A[3] = xx[0] + 2.0*xx[1];
    213:   MatSetValues(B,2,idx,2,idx,A,INSERT_VALUES);

    215:   /*
    216:      Restore vector
    217:   */
    218:   VecRestoreArrayRead(x,&xx);

    220:   /*
    221:      Assemble matrix
    222:   */
    223:   MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
    224:   MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
    225:   if (jac != B) {
    226:     MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
    227:     MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
    228:   }
    229:   return 0;
    230: }

    232: /* ------------------------------------------------------------------- */
    233: PetscErrorCode FormFunction2(SNES snes,Vec x,Vec f,void *dummy)
    234: {
    235:   const PetscScalar *xx;
    236:   PetscScalar       *ff;

    238:   /*
    239:      Get pointers to vector data.
    240:        - For default PETSc vectors, VecGetArray() returns a pointer to
    241:          the data array.  Otherwise, the routine is implementation dependent.
    242:        - You MUST call VecRestoreArray() when you no longer need access to
    243:          the array.
    244:   */
    245:   VecGetArrayRead(x,&xx);
    246:   VecGetArray(f,&ff);

    248:   /*
    249:      Compute function
    250:   */
    251:   ff[0] = PetscSinScalar(3.0*xx[0]) + xx[0];
    252:   ff[1] = xx[1];

    254:   /*
    255:      Restore vectors
    256:   */
    257:   VecRestoreArrayRead(x,&xx);
    258:   VecRestoreArray(f,&ff);
    259:   return 0;
    260: }
    261: /* ------------------------------------------------------------------- */
    262: PetscErrorCode FormJacobian2(SNES snes,Vec x,Mat jac,Mat B,void *dummy)
    263: {
    264:   const PetscScalar *xx;
    265:   PetscScalar       A[4];
    266:   PetscInt          idx[2] = {0,1};

    268:   /*
    269:      Get pointer to vector data
    270:   */
    271:   VecGetArrayRead(x,&xx);

    273:   /*
    274:      Compute Jacobian entries and insert into matrix.
    275:       - Since this is such a small problem, we set all entries for
    276:         the matrix at once.
    277:   */
    278:   A[0]  = 3.0*PetscCosScalar(3.0*xx[0]) + 1.0; A[1] = 0.0;
    279:   A[2]  = 0.0;                     A[3] = 1.0;
    280:   MatSetValues(B,2,idx,2,idx,A,INSERT_VALUES);

    282:   /*
    283:      Restore vector
    284:   */
    285:   VecRestoreArrayRead(x,&xx);

    287:   /*
    288:      Assemble matrix
    289:   */
    290:   MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
    291:   MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
    292:   if (jac != B) {
    293:     MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
    294:     MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
    295:   }
    296:   return 0;
    297: }

    299: /*TEST

    301:    test:
    302:       args: -ksp_gmres_cgs_refinement_type refine_always -snes_monitor_short
    303:       requires: !single

    305:    test:
    306:       suffix: 2
    307:       requires: !single
    308:       args:  -snes_monitor_short
    309:       output_file: output/ex1_1.out

    311:    test:
    312:       suffix: 3
    313:       args: -ksp_view_solution ascii:ex1_2_sol.tmp:ascii_matlab  -snes_monitor_short
    314:       requires: !single
    315:       output_file: output/ex1_1.out

    317:    test:
    318:       suffix: 4
    319:       args: -ksp_view_solution ascii:ex1_2_sol.tmp::append  -snes_monitor_short
    320:       requires: !single
    321:       output_file: output/ex1_1.out

    323:    test:
    324:       suffix: 5
    325:       args: -ksp_view_solution ascii:ex1_2_sol.tmp:ascii_matlab:append  -snes_monitor_short
    326:       requires: !single
    327:       output_file: output/ex1_1.out

    329:    test:
    330:       suffix: 6
    331:       args: -ksp_view_solution ascii:ex1_2_sol.tmp:default:append  -snes_monitor_short
    332:       requires: !single
    333:       output_file: output/ex1_1.out

    335:    test:
    336:       suffix: X
    337:       args: -ksp_monitor_short -ksp_type gmres -ksp_gmres_krylov_monitor -snes_monitor_short -snes_rtol 1.e-4
    338:       requires: !single x

    340: TEST*/