xref: /petsc/src/snes/tutorials/ex2.c (revision dbbe0bcd3f3a8fbab5a45420dc06f8387e5764c6)
1 
2 static char help[] = "Newton method to solve u'' + u^{2} = f, sequentially.\n\
3 This example employs a user-defined monitoring routine.\n\n";
4 
5 /*
6    Include "petscdraw.h" so that we can use PETSc drawing routines.
7    Include "petscsnes.h" so that we can use SNES solvers.  Note that this
8    file automatically includes:
9      petscsys.h       - base PETSc routines   petscvec.h - vectors
10      petscmat.h - matrices
11      petscis.h     - index sets            petscksp.h - Krylov subspace methods
12      petscviewer.h - viewers               petscpc.h  - preconditioners
13      petscksp.h   - linear solvers
14 */
15 
16 #include <petscsnes.h>
17 
18 /*
19    User-defined routines
20 */
21 extern PetscErrorCode FormJacobian(SNES,Vec,Mat,Mat,void*);
22 extern PetscErrorCode FormFunction(SNES,Vec,Vec,void*);
23 extern PetscErrorCode FormInitialGuess(Vec);
24 extern PetscErrorCode Monitor(SNES,PetscInt,PetscReal,void*);
25 
26 /*
27    User-defined context for monitoring
28 */
29 typedef struct {
30   PetscViewer viewer;
31 } MonitorCtx;
32 
33 int main(int argc,char **argv)
34 {
35   SNES           snes;                   /* SNES context */
36   Vec            x,r,F,U;             /* vectors */
37   Mat            J;                      /* Jacobian matrix */
38   MonitorCtx     monP;                   /* monitoring context */
39   PetscInt       its,n = 5,i,maxit,maxf;
40   PetscMPIInt    size;
41   PetscScalar    h,xp,v,none = -1.0;
42   PetscReal      abstol,rtol,stol,norm;
43 
44   PetscFunctionBeginUser;
45   PetscCall(PetscInitialize(&argc,&argv,(char*)0,help));
46   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size));
47   PetscCheck(size == 1,PETSC_COMM_SELF,PETSC_ERR_WRONG_MPI_SIZE,"This is a uniprocessor example only!");
48   PetscCall(PetscOptionsGetInt(NULL,NULL,"-n",&n,NULL));
49   h    = 1.0/(n-1);
50 
51   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
52      Create nonlinear solver context
53      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
54 
55   PetscCall(SNESCreate(PETSC_COMM_WORLD,&snes));
56 
57   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
58      Create vector data structures; set function evaluation routine
59      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
60   /*
61      Note that we form 1 vector from scratch and then duplicate as needed.
62   */
63   PetscCall(VecCreate(PETSC_COMM_WORLD,&x));
64   PetscCall(VecSetSizes(x,PETSC_DECIDE,n));
65   PetscCall(VecSetFromOptions(x));
66   PetscCall(VecDuplicate(x,&r));
67   PetscCall(VecDuplicate(x,&F));
68   PetscCall(VecDuplicate(x,&U));
69 
70   /*
71      Set function evaluation routine and vector
72   */
73   PetscCall(SNESSetFunction(snes,r,FormFunction,(void*)F));
74 
75   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
76      Create matrix data structure; set Jacobian evaluation routine
77      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
78 
79   PetscCall(MatCreate(PETSC_COMM_WORLD,&J));
80   PetscCall(MatSetSizes(J,PETSC_DECIDE,PETSC_DECIDE,n,n));
81   PetscCall(MatSetFromOptions(J));
82   PetscCall(MatSeqAIJSetPreallocation(J,3,NULL));
83 
84   /*
85      Set Jacobian matrix data structure and default Jacobian evaluation
86      routine. User can override with:
87      -snes_fd : default finite differencing approximation of Jacobian
88      -snes_mf : matrix-free Newton-Krylov method with no preconditioning
89                 (unless user explicitly sets preconditioner)
90      -snes_mf_operator : form preconditioning matrix as set by the user,
91                          but use matrix-free approx for Jacobian-vector
92                          products within Newton-Krylov method
93   */
94 
95   PetscCall(SNESSetJacobian(snes,J,J,FormJacobian,NULL));
96 
97   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
98      Customize nonlinear solver; set runtime options
99    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
100 
101   /*
102      Set an optional user-defined monitoring routine
103   */
104   PetscCall(PetscViewerDrawOpen(PETSC_COMM_WORLD,0,0,0,0,400,400,&monP.viewer));
105   PetscCall(SNESMonitorSet(snes,Monitor,&monP,0));
106 
107   /*
108      Set names for some vectors to facilitate monitoring (optional)
109   */
110   PetscCall(PetscObjectSetName((PetscObject)x,"Approximate Solution"));
111   PetscCall(PetscObjectSetName((PetscObject)U,"Exact Solution"));
112 
113   /*
114      Set SNES/KSP/KSP/PC runtime options, e.g.,
115          -snes_view -snes_monitor -ksp_type <ksp> -pc_type <pc>
116   */
117   PetscCall(SNESSetFromOptions(snes));
118 
119   /*
120      Print parameters used for convergence testing (optional) ... just
121      to demonstrate this routine; this information is also printed with
122      the option -snes_view
123   */
124   PetscCall(SNESGetTolerances(snes,&abstol,&rtol,&stol,&maxit,&maxf));
125   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"atol=%g, rtol=%g, stol=%g, maxit=%" PetscInt_FMT ", maxf=%" PetscInt_FMT "\n",(double)abstol,(double)rtol,(double)stol,maxit,maxf));
126 
127   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
128      Initialize application:
129      Store right-hand-side of PDE and exact solution
130    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
131 
132   xp = 0.0;
133   for (i=0; i<n; i++) {
134     v    = 6.0*xp + PetscPowScalar(xp+1.e-12,6.0); /* +1.e-12 is to prevent 0^6 */
135     PetscCall(VecSetValues(F,1,&i,&v,INSERT_VALUES));
136     v    = xp*xp*xp;
137     PetscCall(VecSetValues(U,1,&i,&v,INSERT_VALUES));
138     xp  += h;
139   }
140 
141   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
142      Evaluate initial guess; then solve nonlinear system
143    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
144   /*
145      Note: The user should initialize the vector, x, with the initial guess
146      for the nonlinear solver prior to calling SNESSolve().  In particular,
147      to employ an initial guess of zero, the user should explicitly set
148      this vector to zero by calling VecSet().
149   */
150   PetscCall(FormInitialGuess(x));
151   PetscCall(SNESSolve(snes,NULL,x));
152   PetscCall(SNESGetIterationNumber(snes,&its));
153   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"number of SNES iterations = %" PetscInt_FMT "\n\n",its));
154 
155   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
156      Check solution and clean up
157    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
158 
159   /*
160      Check the error
161   */
162   PetscCall(VecAXPY(x,none,U));
163   PetscCall(VecNorm(x,NORM_2,&norm));
164   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Norm of error %g, Iterations %" PetscInt_FMT "\n",(double)norm,its));
165 
166   /*
167      Free work space.  All PETSc objects should be destroyed when they
168      are no longer needed.
169   */
170   PetscCall(VecDestroy(&x));  PetscCall(VecDestroy(&r));
171   PetscCall(VecDestroy(&U));  PetscCall(VecDestroy(&F));
172   PetscCall(MatDestroy(&J));  PetscCall(SNESDestroy(&snes));
173   PetscCall(PetscViewerDestroy(&monP.viewer));
174   PetscCall(PetscFinalize());
175   return 0;
176 }
177 /* ------------------------------------------------------------------- */
178 /*
179    FormInitialGuess - Computes initial guess.
180 
181    Input/Output Parameter:
182 .  x - the solution vector
183 */
184 PetscErrorCode FormInitialGuess(Vec x)
185 {
186   PetscScalar    pfive = .50;
187   PetscCall(VecSet(x,pfive));
188   return 0;
189 }
190 /* ------------------------------------------------------------------- */
191 /*
192    FormFunction - Evaluates nonlinear function, F(x).
193 
194    Input Parameters:
195 .  snes - the SNES context
196 .  x - input vector
197 .  ctx - optional user-defined context, as set by SNESSetFunction()
198 
199    Output Parameter:
200 .  f - function vector
201 
202    Note:
203    The user-defined context can contain any application-specific data
204    needed for the function evaluation (such as various parameters, work
205    vectors, and grid information).  In this program the context is just
206    a vector containing the right-hand-side of the discretized PDE.
207  */
208 
209 PetscErrorCode FormFunction(SNES snes,Vec x,Vec f,void *ctx)
210 {
211   Vec               g = (Vec)ctx;
212   const PetscScalar *xx,*gg;
213   PetscScalar       *ff,d;
214   PetscInt          i,n;
215 
216   /*
217      Get pointers to vector data.
218        - For default PETSc vectors, VecGetArray() returns a pointer to
219          the data array.  Otherwise, the routine is implementation dependent.
220        - You MUST call VecRestoreArray() when you no longer need access to
221          the array.
222   */
223   PetscCall(VecGetArrayRead(x,&xx));
224   PetscCall(VecGetArray(f,&ff));
225   PetscCall(VecGetArrayRead(g,&gg));
226 
227   /*
228      Compute function
229   */
230   PetscCall(VecGetSize(x,&n));
231   d     = (PetscReal)(n - 1); d = d*d;
232   ff[0] = xx[0];
233   for (i=1; i<n-1; i++) ff[i] = d*(xx[i-1] - 2.0*xx[i] + xx[i+1]) + xx[i]*xx[i] - gg[i];
234   ff[n-1] = xx[n-1] - 1.0;
235 
236   /*
237      Restore vectors
238   */
239   PetscCall(VecRestoreArrayRead(x,&xx));
240   PetscCall(VecRestoreArray(f,&ff));
241   PetscCall(VecRestoreArrayRead(g,&gg));
242   return 0;
243 }
244 /* ------------------------------------------------------------------- */
245 /*
246    FormJacobian - Evaluates Jacobian matrix.
247 
248    Input Parameters:
249 .  snes - the SNES context
250 .  x - input vector
251 .  dummy - optional user-defined context (not used here)
252 
253    Output Parameters:
254 .  jac - Jacobian matrix
255 .  B - optionally different preconditioning matrix
256 
257 */
258 
259 PetscErrorCode FormJacobian(SNES snes,Vec x,Mat jac,Mat B,void *dummy)
260 {
261   const PetscScalar *xx;
262   PetscScalar       A[3],d;
263   PetscInt          i,n,j[3];
264 
265   /*
266      Get pointer to vector data
267   */
268   PetscCall(VecGetArrayRead(x,&xx));
269 
270   /*
271      Compute Jacobian entries and insert into matrix.
272       - Note that in this case we set all elements for a particular
273         row at once.
274   */
275   PetscCall(VecGetSize(x,&n));
276   d    = (PetscReal)(n - 1); d = d*d;
277 
278   /*
279      Interior grid points
280   */
281   for (i=1; i<n-1; i++) {
282     j[0] = i - 1; j[1] = i; j[2] = i + 1;
283     A[0] = A[2] = d; A[1] = -2.0*d + 2.0*xx[i];
284     PetscCall(MatSetValues(B,1,&i,3,j,A,INSERT_VALUES));
285   }
286 
287   /*
288      Boundary points
289   */
290   i = 0;   A[0] = 1.0;
291 
292   PetscCall(MatSetValues(B,1,&i,1,&i,A,INSERT_VALUES));
293 
294   i = n-1; A[0] = 1.0;
295 
296   PetscCall(MatSetValues(B,1,&i,1,&i,A,INSERT_VALUES));
297 
298   /*
299      Restore vector
300   */
301   PetscCall(VecRestoreArrayRead(x,&xx));
302 
303   /*
304      Assemble matrix
305   */
306   PetscCall(MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY));
307   PetscCall(MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY));
308   if (jac != B) {
309     PetscCall(MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY));
310     PetscCall(MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY));
311   }
312   return 0;
313 }
314 /* ------------------------------------------------------------------- */
315 /*
316    Monitor - User-defined monitoring routine that views the
317    current iterate with an x-window plot.
318 
319    Input Parameters:
320    snes - the SNES context
321    its - iteration number
322    norm - 2-norm function value (may be estimated)
323    ctx - optional user-defined context for private data for the
324          monitor routine, as set by SNESMonitorSet()
325 
326    Note:
327    See the manpage for PetscViewerDrawOpen() for useful runtime options,
328    such as -nox to deactivate all x-window output.
329  */
330 PetscErrorCode Monitor(SNES snes,PetscInt its,PetscReal fnorm,void *ctx)
331 {
332   MonitorCtx     *monP = (MonitorCtx*) ctx;
333   Vec            x;
334 
335   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"iter = %" PetscInt_FMT ", SNES Function norm %g\n",its,(double)fnorm));
336   PetscCall(SNESGetSolution(snes,&x));
337   PetscCall(VecView(x,monP->viewer));
338   return 0;
339 }
340 
341 /*TEST
342 
343    test:
344       args: -nox -snes_monitor_cancel -snes_monitor_short -snes_view -pc_type jacobi -ksp_gmres_cgs_refinement_type refine_always
345 
346    test:
347       suffix: 2
348       args: -nox -snes_monitor_cancel -snes_monitor_short -snes_type newtontr -snes_view
349       requires: !single
350 
351    test:
352       suffix: 3
353       args: -nox -malloc no -options_left no -snes_monitor_cancel -snes_monitor_short -snes_view -pc_type jacobi -ksp_gmres_cgs_refinement_type refine_always
354 
355    test:
356       suffix: 4
357       args: -nox -snes_monitor_cancel -snes_monitor_short -snes_type newtontrdc -snes_view
358       requires: !single
359 
360 TEST*/
361