Date: 2026-03-31T05:46:27+00:00

Actual source code: ex1.c

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

      3: /*
      4:    Include "petscsnes.h" so that we can use SNES solvers.  Note that this
      5:    file automatically includes:
      6:      petscsys.h       - base PETSc routines   petscvec.h - vectors
      7:      petscmat.h - matrices
      8:      petscis.h     - index sets            petscksp.h - Krylov subspace methods
      9:      petscviewer.h - viewers               petscpc.h  - preconditioners
     10:      petscksp.h   - linear solvers
     11: */
     12: /*F
     13: This examples solves either
     14: \begin{equation}
     15:   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}
     16: \end{equation}
     17: or if the {\tt -hard} options is given
     18: \begin{equation}
     19:   F\genfrac{(}{)}{0pt}{}{x_0}{x_1} = \genfrac{(}{)}{0pt}{}{\sin(3 x_0) + x_0}{x_1}
     20: \end{equation}
     21: F*/
     22: #include <petscsnes.h>

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

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

     43:   PetscFunctionBeginUser;
     44:   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
     45:   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
     46:   PetscCheck(size == 1, PETSC_COMM_WORLD, PETSC_ERR_WRONG_MPI_SIZE, "Example is only for sequential runs");

     48:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     49:      Create nonlinear solver context
     50:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     51:   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
     52:   PetscCall(SNESSetType(snes, SNESNEWTONLS));
     53:   PetscCall(SNESSetOptionsPrefix(snes, "mysolver_"));

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

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

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

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

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

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

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

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

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

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

    153:    Input Parameters:
    154: .  snes - the SNES context
    155: .  x    - input vector
    156: .  ctx  - optional user-defined context

    158:    Output Parameter:
    159: .  f - function vector
    160:  */
    161: PetscErrorCode FormFunction1(SNES snes, Vec x, Vec f, PetscCtx ctx)
    162: {
    163:   const PetscScalar *xx;
    164:   PetscScalar       *ff;

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

    177:   /* Compute function */
    178:   ff[0] = xx[0] * xx[0] + xx[0] * xx[1] - 3.0;
    179:   ff[1] = xx[0] * xx[1] + xx[1] * xx[1] - 6.0;

    181:   /* Restore vectors */
    182:   PetscCall(VecRestoreArrayRead(x, &xx));
    183:   PetscCall(VecRestoreArray(f, &ff));
    184:   PetscFunctionReturn(PETSC_SUCCESS);
    185: }
    186: /* ------------------------------------------------------------------- */
    187: /*
    188:    FormJacobian1 - Evaluates Jacobian matrix.

    190:    Input Parameters:
    191: .  snes - the SNES context
    192: .  x - input vector
    193: .  dummy - optional user-defined context (not used here)

    195:    Output Parameters:
    196: .  jac - Jacobian matrix
    197: .  B - optionally different matrix used to construct the preconditioner

    199: */
    200: PetscErrorCode FormJacobian1(SNES snes, Vec x, Mat jac, Mat B, void *dummy)
    201: {
    202:   const PetscScalar *xx;
    203:   PetscScalar        A[4];
    204:   PetscInt           idx[2] = {0, 1};

    206:   PetscFunctionBeginUser;
    207:   /*
    208:      Get pointer to vector data
    209:   */
    210:   PetscCall(VecGetArrayRead(x, &xx));

    212:   /*
    213:      Compute Jacobian entries and insert into matrix.
    214:       - Since this is such a small problem, we set all entries for
    215:         the matrix at once.
    216:   */
    217:   A[0] = 2.0 * xx[0] + xx[1];
    218:   A[1] = xx[0];
    219:   A[2] = xx[1];
    220:   A[3] = xx[0] + 2.0 * xx[1];
    221:   PetscCall(MatSetValues(B, 2, idx, 2, idx, A, INSERT_VALUES));

    223:   /*
    224:      Restore vector
    225:   */
    226:   PetscCall(VecRestoreArrayRead(x, &xx));

    228:   /*
    229:      Assemble matrix
    230:   */
    231:   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
    232:   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
    233:   if (jac != B) {
    234:     PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY));
    235:     PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY));
    236:   }
    237:   PetscFunctionReturn(PETSC_SUCCESS);
    238: }

    240: /* ------------------------------------------------------------------- */
    241: PetscErrorCode FormFunction2(SNES snes, Vec x, Vec f, void *dummy)
    242: {
    243:   const PetscScalar *xx;
    244:   PetscScalar       *ff;

    246:   PetscFunctionBeginUser;
    247:   /*
    248:      Get pointers to vector data.
    249:        - For default PETSc vectors, VecGetArray() returns a pointer to
    250:          the data array.  Otherwise, the routine is implementation dependent.
    251:        - You MUST call VecRestoreArray() when you no longer need access to
    252:          the array.
    253:   */
    254:   PetscCall(VecGetArrayRead(x, &xx));
    255:   PetscCall(VecGetArray(f, &ff));

    257:   /*
    258:      Compute function
    259:   */
    260:   ff[0] = PetscSinScalar(3.0 * xx[0]) + xx[0];
    261:   ff[1] = xx[1];

    263:   /*
    264:      Restore vectors
    265:   */
    266:   PetscCall(VecRestoreArrayRead(x, &xx));
    267:   PetscCall(VecRestoreArray(f, &ff));
    268:   PetscFunctionReturn(PETSC_SUCCESS);
    269: }
    270: /* ------------------------------------------------------------------- */
    271: PetscErrorCode FormJacobian2(SNES snes, Vec x, Mat jac, Mat B, void *dummy)
    272: {
    273:   const PetscScalar *xx;
    274:   PetscScalar        A[4];
    275:   PetscInt           idx[2] = {0, 1};

    277:   PetscFunctionBeginUser;
    278:   /*
    279:      Get pointer to vector data
    280:   */
    281:   PetscCall(VecGetArrayRead(x, &xx));

    283:   /*
    284:      Compute Jacobian entries and insert into matrix.
    285:       - Since this is such a small problem, we set all entries for
    286:         the matrix at once.
    287:   */
    288:   A[0] = 3.0 * PetscCosScalar(3.0 * xx[0]) + 1.0;
    289:   A[1] = 0.0;
    290:   A[2] = 0.0;
    291:   A[3] = 1.0;
    292:   PetscCall(MatSetValues(B, 2, idx, 2, idx, A, INSERT_VALUES));

    294:   /*
    295:      Restore vector
    296:   */
    297:   PetscCall(VecRestoreArrayRead(x, &xx));

    299:   /*
    300:      Assemble matrix
    301:   */
    302:   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
    303:   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
    304:   if (jac != B) {
    305:     PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY));
    306:     PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY));
    307:   }
    308:   PetscFunctionReturn(PETSC_SUCCESS);
    309: }

    311: /*TEST

    313:    test:
    314:       args: -prefix_push mysolver_ -ksp_gmres_cgs_refinement_type refine_always -snes_monitor_short -prefix_pop
    315:       requires: !single

    317:    # test harness puts {{ }} options always at the end, need to specify the prefix explicitly
    318:    test:
    319:       suffix: 2
    320:       requires: !single
    321:       args: -prefix_push mysolver_ -snes_monitor_short -prefix_pop -mysolver_snes_ksp_ew {{0 1}}
    322:       output_file: output/ex1_1.out

    324:    test:
    325:       suffix: 3
    326:       args: -prefix_push mysolver_ -ksp_view_solution ascii:ex1_2_sol.tmp:ascii_matlab -snes_monitor_short -prefix_pop
    327:       requires: !single
    328:       output_file: output/ex1_1.out

    330:    test:
    331:       suffix: 4
    332:       args: -prefix_push mysolver_ -ksp_view_solution ascii:ex1_2_sol.tmp::append -snes_monitor_short -prefix_pop
    333:       requires: !single
    334:       output_file: output/ex1_1.out

    336:    test:
    337:       suffix: 5
    338:       args: -prefix_push mysolver_ -ksp_view_solution ascii:ex1_2_sol.tmp:ascii_matlab:append -snes_monitor_short -prefix_pop
    339:       requires: !single
    340:       output_file: output/ex1_1.out

    342:    test:
    343:       suffix: 6
    344:       args: -prefix_push mysolver_ -ksp_view_solution ascii:ex1_2_sol.tmp:default:append -snes_monitor_short -prefix_pop
    345:       requires: !single
    346:       output_file: output/ex1_1.out

    348:    test:
    349:       suffix: X
    350:       args: -prefix_push mysolver_ -ksp_monitor_short -ksp_type gmres -ksp_gmres_krylov_monitor -snes_monitor_short -snes_rtol 1.e-4 -prefix_pop
    351:       requires: !single x

    353: TEST*/