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