xref: /petsc/src/snes/interface/snesut.c (revision 193ac0bc5128976c4ec2c1a67f3f9cb026b77f22)
1 
2 #include <private/snesimpl.h>       /*I   "petscsnes.h"   I*/
3 
4 #undef __FUNCT__
5 #define __FUNCT__ "SNESMonitorSolution"
6 /*@C
7    SNESMonitorSolution - Monitors progress of the SNES solvers by calling
8    VecView() for the approximate solution at each iteration.
9 
10    Collective on SNES
11 
12    Input Parameters:
13 +  snes - the SNES context
14 .  its - iteration number
15 .  fgnorm - 2-norm of residual
16 -  dummy - either a viewer or PETSC_NULL
17 
18    Level: intermediate
19 
20 .keywords: SNES, nonlinear, vector, monitor, view
21 
22 .seealso: SNESMonitorSet(), SNESMonitorDefault(), VecView()
23 @*/
24 PetscErrorCode  SNESMonitorSolution(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
25 {
26   PetscErrorCode ierr;
27   Vec            x;
28   PetscViewer    viewer = (PetscViewer) dummy;
29 
30   PetscFunctionBegin;
31   ierr = SNESGetSolution(snes,&x);CHKERRQ(ierr);
32   if (!viewer) {
33     MPI_Comm comm;
34     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
35     viewer = PETSC_VIEWER_DRAW_(comm);
36   }
37   ierr = VecView(x,viewer);CHKERRQ(ierr);
38 
39   PetscFunctionReturn(0);
40 }
41 
42 #undef __FUNCT__
43 #define __FUNCT__ "SNESMonitorResidual"
44 /*@C
45    SNESMonitorResidual - Monitors progress of the SNES solvers by calling
46    VecView() for the residual at each iteration.
47 
48    Collective on SNES
49 
50    Input Parameters:
51 +  snes - the SNES context
52 .  its - iteration number
53 .  fgnorm - 2-norm of residual
54 -  dummy - either a viewer or PETSC_NULL
55 
56    Level: intermediate
57 
58 .keywords: SNES, nonlinear, vector, monitor, view
59 
60 .seealso: SNESMonitorSet(), SNESMonitorDefault(), VecView()
61 @*/
62 PetscErrorCode  SNESMonitorResidual(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
63 {
64   PetscErrorCode ierr;
65   Vec            x;
66   PetscViewer    viewer = (PetscViewer) dummy;
67 
68   PetscFunctionBegin;
69   ierr = SNESGetFunction(snes,&x,0,0);CHKERRQ(ierr);
70   if (!viewer) {
71     MPI_Comm comm;
72     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
73     viewer = PETSC_VIEWER_DRAW_(comm);
74   }
75   ierr = VecView(x,viewer);CHKERRQ(ierr);
76 
77   PetscFunctionReturn(0);
78 }
79 
80 #undef __FUNCT__
81 #define __FUNCT__ "SNESMonitorSolutionUpdate"
82 /*@C
83    SNESMonitorSolutionUpdate - Monitors progress of the SNES solvers by calling
84    VecView() for the UPDATE to the solution at each iteration.
85 
86    Collective on SNES
87 
88    Input Parameters:
89 +  snes - the SNES context
90 .  its - iteration number
91 .  fgnorm - 2-norm of residual
92 -  dummy - either a viewer or PETSC_NULL
93 
94    Level: intermediate
95 
96 .keywords: SNES, nonlinear, vector, monitor, view
97 
98 .seealso: SNESMonitorSet(), SNESMonitorDefault(), VecView()
99 @*/
100 PetscErrorCode  SNESMonitorSolutionUpdate(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
101 {
102   PetscErrorCode ierr;
103   Vec            x;
104   PetscViewer    viewer = (PetscViewer) dummy;
105 
106   PetscFunctionBegin;
107   ierr = SNESGetSolutionUpdate(snes,&x);CHKERRQ(ierr);
108   if (!viewer) {
109     MPI_Comm comm;
110     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
111     viewer = PETSC_VIEWER_DRAW_(comm);
112   }
113   ierr = VecView(x,viewer);CHKERRQ(ierr);
114 
115   PetscFunctionReturn(0);
116 }
117 
118 #undef __FUNCT__
119 #define __FUNCT__ "SNESMonitorDefault"
120 /*@C
121    SNESMonitorDefault - Monitors progress of the SNES solvers (default).
122 
123    Collective on SNES
124 
125    Input Parameters:
126 +  snes - the SNES context
127 .  its - iteration number
128 .  fgnorm - 2-norm of residual
129 -  dummy - unused context
130 
131    Notes:
132    This routine prints the residual norm at each iteration.
133 
134    Level: intermediate
135 
136 .keywords: SNES, nonlinear, default, monitor, norm
137 
138 .seealso: SNESMonitorSet(), SNESMonitorSolution()
139 @*/
140 PetscErrorCode  SNESMonitorDefault(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
141 {
142   PetscErrorCode ierr;
143   PetscViewer    viewer = dummy ? (PetscViewer) dummy : PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);
144 
145   PetscFunctionBegin;
146   ierr = PetscViewerASCIIAddTab(viewer,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
147   ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm %14.12e \n",its,(double)fgnorm);CHKERRQ(ierr);
148   ierr = PetscViewerASCIISubtractTab(viewer,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
149   PetscFunctionReturn(0);
150 }
151 
152 #undef __FUNCT__
153 #define __FUNCT__ "SNESMonitorRange_Private"
154 PetscErrorCode  SNESMonitorRange_Private(SNES snes,PetscInt it,PetscReal *per)
155 {
156   PetscErrorCode          ierr;
157   Vec                     resid;
158   PetscReal               rmax,pwork;
159   PetscInt                i,n,N;
160   PetscScalar             *r;
161 
162   PetscFunctionBegin;
163   ierr = SNESGetFunction(snes,&resid,0,0);CHKERRQ(ierr);
164   ierr = VecNorm(resid,NORM_INFINITY,&rmax);CHKERRQ(ierr);
165   ierr = VecGetLocalSize(resid,&n);CHKERRQ(ierr);
166   ierr = VecGetSize(resid,&N);CHKERRQ(ierr);
167   ierr = VecGetArray(resid,&r);CHKERRQ(ierr);
168   pwork = 0.0;
169   for (i=0; i<n; i++) {
170     pwork += (PetscAbsScalar(r[i]) > .20*rmax);
171   }
172   ierr = MPI_Allreduce(&pwork,per,1,MPIU_REAL,MPIU_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
173   ierr = VecRestoreArray(resid,&r);CHKERRQ(ierr);
174   *per  = *per/N;
175   PetscFunctionReturn(0);
176 }
177 
178 #undef __FUNCT__
179 #define __FUNCT__ "SNESMonitorRange"
180 /*@C
181    SNESMonitorRange - Prints the percentage of residual elements that are more then 10 percent of the maximum value.
182 
183    Collective on SNES
184 
185    Input Parameters:
186 +  snes   - iterative context
187 .  it    - iteration number
188 .  rnorm - 2-norm (preconditioned) residual value (may be estimated).
189 -  dummy - unused monitor context
190 
191    Options Database Key:
192 .  -snes_monitor_range - Activates SNESMonitorRange()
193 
194    Level: intermediate
195 
196 .keywords: SNES, default, monitor, residual
197 
198 .seealso: SNESMonitorSet(), SNESMonitorDefault(), SNESMonitorLGCreate()
199 @*/
200 PetscErrorCode  SNESMonitorRange(SNES snes,PetscInt it,PetscReal rnorm,void *dummy)
201 {
202   PetscErrorCode   ierr;
203   PetscReal        perc,rel;
204   PetscViewer      viewer = dummy ? (PetscViewer) dummy : PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);
205   /* should be in a MonitorRangeContext */
206   static PetscReal prev;
207 
208   PetscFunctionBegin;
209   if (!it) prev = rnorm;
210   ierr = SNESMonitorRange_Private(snes,it,&perc);CHKERRQ(ierr);
211 
212   rel  = (prev - rnorm)/prev;
213   prev = rnorm;
214   ierr = PetscViewerASCIIAddTab(viewer,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
215   ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES preconditioned resid norm %14.12e Percent values above 20 percent of maximum %5.2f relative decrease %5.2e ratio %5.2e \n",it,(double)rnorm,(double)100.0*perc,(double)rel,(double)rel/perc);CHKERRQ(ierr);
216   ierr = PetscViewerASCIISubtractTab(viewer,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
217   PetscFunctionReturn(0);
218 }
219 
220 typedef struct {
221   PetscViewer viewer;
222   PetscReal   *history;
223 } SNESMonitorRatioContext;
224 
225 #undef __FUNCT__
226 #define __FUNCT__ "SNESMonitorRatio"
227 /*@C
228    SNESMonitorRatio - Monitors progress of the SNES solvers by printing the ratio
229    of residual norm at each iteration to the previous.
230 
231    Collective on SNES
232 
233    Input Parameters:
234 +  snes - the SNES context
235 .  its - iteration number
236 .  fgnorm - 2-norm of residual (or gradient)
237 -  dummy -  context of monitor
238 
239    Level: intermediate
240 
241 .keywords: SNES, nonlinear, monitor, norm
242 
243 .seealso: SNESMonitorSet(), SNESMonitorSolution()
244 @*/
245 PetscErrorCode  SNESMonitorRatio(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
246 {
247   PetscErrorCode          ierr;
248   PetscInt                len;
249   PetscReal               *history;
250   SNESMonitorRatioContext *ctx = (SNESMonitorRatioContext*)dummy;
251 
252   PetscFunctionBegin;
253   ierr = SNESGetConvergenceHistory(snes,&history,PETSC_NULL,&len);CHKERRQ(ierr);
254   ierr = PetscViewerASCIIAddTab(ctx->viewer,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
255   if (!its || !history || its > len) {
256     ierr = PetscViewerASCIIPrintf(ctx->viewer,"%3D SNES Function norm %14.12e \n",its,(double)fgnorm);CHKERRQ(ierr);
257   } else {
258     PetscReal ratio = fgnorm/history[its-1];
259     ierr = PetscViewerASCIIPrintf(ctx->viewer,"%3D SNES Function norm %14.12e %G \n",its,(double)fgnorm,(double)ratio);CHKERRQ(ierr);
260   }
261   ierr = PetscViewerASCIISubtractTab(ctx->viewer,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
262   PetscFunctionReturn(0);
263 }
264 
265 /*
266    If the we set the history monitor space then we must destroy it
267 */
268 #undef __FUNCT__
269 #define __FUNCT__ "SNESMonitorRatioDestroy"
270 PetscErrorCode SNESMonitorRatioDestroy(void **ct)
271 {
272   PetscErrorCode          ierr;
273   SNESMonitorRatioContext *ctx = *(SNESMonitorRatioContext**)ct;
274 
275   PetscFunctionBegin;
276   ierr = PetscFree(ctx->history);CHKERRQ(ierr);
277   ierr = PetscViewerDestroy(&ctx->viewer);CHKERRQ(ierr);
278   ierr = PetscFree(ctx);CHKERRQ(ierr);
279   PetscFunctionReturn(0);
280 }
281 
282 #undef __FUNCT__
283 #define __FUNCT__ "SNESMonitorSetRatio"
284 /*@C
285    SNESMonitorSetRatio - Sets SNES to use a monitor that prints the
286    ratio of the function norm at each iteration.
287 
288    Collective on SNES
289 
290    Input Parameters:
291 +   snes - the SNES context
292 -   viewer - ASCII viewer to print output
293 
294    Level: intermediate
295 
296 .keywords: SNES, nonlinear, monitor, norm
297 
298 .seealso: SNESMonitorSet(), SNESMonitorSolution(), SNESMonitorDefault()
299 @*/
300 PetscErrorCode  SNESMonitorSetRatio(SNES snes,PetscViewer viewer)
301 {
302   PetscErrorCode          ierr;
303   SNESMonitorRatioContext *ctx;
304   PetscReal               *history;
305 
306   PetscFunctionBegin;
307   if (!viewer) {
308     ierr = PetscViewerASCIIOpen(((PetscObject)snes)->comm,"stdout",&viewer);CHKERRQ(ierr);
309     ierr = PetscObjectReference((PetscObject)viewer);CHKERRQ(ierr);
310   }
311   ierr = PetscNewLog(snes,SNESMonitorRatioContext,&ctx);
312   ierr = SNESGetConvergenceHistory(snes,&history,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
313   if (!history) {
314     ierr = PetscMalloc(100*sizeof(PetscReal),&ctx->history);CHKERRQ(ierr);
315     ierr = SNESSetConvergenceHistory(snes,ctx->history,0,100,PETSC_TRUE);CHKERRQ(ierr);
316   }
317   ctx->viewer = viewer;
318   ierr = SNESMonitorSet(snes,SNESMonitorRatio,ctx,SNESMonitorRatioDestroy);CHKERRQ(ierr);
319   PetscFunctionReturn(0);
320 }
321 
322 /* ---------------------------------------------------------------- */
323 #undef __FUNCT__
324 #define __FUNCT__ "SNESMonitorDefaultShort"
325 /*
326      Default (short) SNES Monitor, same as SNESMonitorDefault() except
327   it prints fewer digits of the residual as the residual gets smaller.
328   This is because the later digits are meaningless and are often
329   different on different machines; by using this routine different
330   machines will usually generate the same output.
331 */
332 PetscErrorCode  SNESMonitorDefaultShort(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
333 {
334   PetscErrorCode ierr;
335   PetscViewer    viewer = dummy ? (PetscViewer) dummy : PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);
336 
337   PetscFunctionBegin;
338   ierr = PetscViewerASCIIAddTab(viewer,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
339   if (fgnorm > 1.e-9) {
340     ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm %G \n",its,fgnorm);CHKERRQ(ierr);
341   } else if (fgnorm > 1.e-11){
342     ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm %5.3e \n",its,fgnorm);CHKERRQ(ierr);
343   } else {
344     ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm < 1.e-11\n",its);CHKERRQ(ierr);
345   }
346   ierr = PetscViewerASCIISubtractTab(viewer,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
347   PetscFunctionReturn(0);
348 }
349 /* ---------------------------------------------------------------- */
350 #undef __FUNCT__
351 #define __FUNCT__ "SNESDefaultConverged"
352 /*@C
353    SNESDefaultConverged - Convergence test of the solvers for
354    systems of nonlinear equations (default).
355 
356    Collective on SNES
357 
358    Input Parameters:
359 +  snes - the SNES context
360 .  it - the iteration (0 indicates before any Newton steps)
361 .  xnorm - 2-norm of current iterate
362 .  pnorm - 2-norm of current step
363 .  fnorm - 2-norm of function at current iterate
364 -  dummy - unused context
365 
366    Output Parameter:
367 .   reason  - one of
368 $  SNES_CONVERGED_FNORM_ABS       - (fnorm < abstol),
369 $  SNES_CONVERGED_PNORM_RELATIVE  - (pnorm < xtol*xnorm),
370 $  SNES_CONVERGED_FNORM_RELATIVE  - (fnorm < rtol*fnorm0),
371 $  SNES_DIVERGED_FUNCTION_COUNT   - (nfct > maxf),
372 $  SNES_DIVERGED_FNORM_NAN        - (fnorm == NaN),
373 $  SNES_CONVERGED_ITERATING       - (otherwise),
374 
375    where
376 +    maxf - maximum number of function evaluations,
377             set with SNESSetTolerances()
378 .    nfct - number of function evaluations,
379 .    abstol - absolute function norm tolerance,
380             set with SNESSetTolerances()
381 -    rtol - relative function norm tolerance, set with SNESSetTolerances()
382 
383    Level: intermediate
384 
385 .keywords: SNES, nonlinear, default, converged, convergence
386 
387 .seealso: SNESSetConvergenceTest()
388 @*/
389 PetscErrorCode  SNESDefaultConverged(SNES snes,PetscInt it,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
390 {
391   PetscErrorCode ierr;
392 
393   PetscFunctionBegin;
394   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
395   PetscValidPointer(reason,6);
396 
397   *reason = SNES_CONVERGED_ITERATING;
398 
399   if (!it) {
400     /* set parameter for default relative tolerance convergence test */
401     snes->ttol = fnorm*snes->rtol;
402   }
403   if (fnorm != fnorm) {
404     ierr = PetscInfo(snes,"Failed to converged, function norm is NaN\n");CHKERRQ(ierr);
405     *reason = SNES_DIVERGED_FNORM_NAN;
406   } else if (fnorm < snes->abstol) {
407     ierr = PetscInfo2(snes,"Converged due to function norm %G < %G\n",fnorm,snes->abstol);CHKERRQ(ierr);
408     *reason = SNES_CONVERGED_FNORM_ABS;
409   } else if (snes->nfuncs >= snes->max_funcs) {
410     ierr = PetscInfo2(snes,"Exceeded maximum number of function evaluations: %D > %D\n",snes->nfuncs,snes->max_funcs);CHKERRQ(ierr);
411     *reason = SNES_DIVERGED_FUNCTION_COUNT;
412   }
413 
414   if (it && !*reason) {
415     if (fnorm <= snes->ttol) {
416       ierr = PetscInfo2(snes,"Converged due to function norm %G < %G (relative tolerance)\n",fnorm,snes->ttol);CHKERRQ(ierr);
417       *reason = SNES_CONVERGED_FNORM_RELATIVE;
418     } else if (pnorm < snes->xtol*xnorm) {
419       ierr = PetscInfo3(snes,"Converged due to small update length: %G < %G * %G\n",pnorm,snes->xtol,xnorm);CHKERRQ(ierr);
420       *reason = SNES_CONVERGED_PNORM_RELATIVE;
421     }
422   }
423   PetscFunctionReturn(0);
424 }
425 
426 #undef __FUNCT__
427 #define __FUNCT__ "SNESSkipConverged"
428 /*@C
429    SNESSkipConverged - Convergence test for SNES that NEVER returns as
430    converged, UNLESS the maximum number of iteration have been reached.
431 
432    Logically Collective on SNES
433 
434    Input Parameters:
435 +  snes - the SNES context
436 .  it - the iteration (0 indicates before any Newton steps)
437 .  xnorm - 2-norm of current iterate
438 .  pnorm - 2-norm of current step
439 .  fnorm - 2-norm of function at current iterate
440 -  dummy - unused context
441 
442    Output Parameter:
443 .   reason  - SNES_CONVERGED_ITERATING, SNES_CONVERGED_ITS, or SNES_DIVERGED_FNORM_NAN
444 
445    Notes:
446    Convergence is then declared after a fixed number of iterations have been used.
447 
448    Level: advanced
449 
450 .keywords: SNES, nonlinear, skip, converged, convergence
451 
452 .seealso: SNESSetConvergenceTest()
453 @*/
454 PetscErrorCode  SNESSkipConverged(SNES snes,PetscInt it,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
455 {
456   PetscErrorCode ierr;
457 
458   PetscFunctionBegin;
459   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
460   PetscValidPointer(reason,6);
461 
462   *reason = SNES_CONVERGED_ITERATING;
463 
464   if (fnorm != fnorm) {
465     ierr = PetscInfo(snes,"Failed to converged, function norm is NaN\n");CHKERRQ(ierr);
466     *reason = SNES_DIVERGED_FNORM_NAN;
467   } else if(it == snes->max_its) {
468     *reason = SNES_CONVERGED_ITS;
469   }
470   PetscFunctionReturn(0);
471 }
472 
473 #undef __FUNCT__
474 #define __FUNCT__ "SNESDefaultGetWork"
475 /*
476   SNESDefaultGetWork - Gets a number of work vectors.
477 
478   Input Parameters:
479 . snes  - the SNES context
480 . nw - number of work vectors to allocate
481 
482    Level: developer
483 
484   Notes:
485   Call this only if no work vectors have been allocated
486  */
487 PetscErrorCode SNESDefaultGetWork(SNES snes,PetscInt nw)
488 {
489   PetscErrorCode ierr;
490 
491   PetscFunctionBegin;
492   if (snes->work) {ierr = VecDestroyVecs(snes->nwork,&snes->work);CHKERRQ(ierr);}
493   snes->nwork = nw;
494   ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr);
495   ierr = PetscLogObjectParents(snes,nw,snes->work);CHKERRQ(ierr);
496   PetscFunctionReturn(0);
497 }
498