xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision ddd40ce523a7cea6c5531ba94c3449af29fb68c1)
1 #include <../src/snes/impls/ngmres/snesngmres.h> /*I "petscsnes.h" I*/
2 #include <petscblaslapack.h>
3 
4 const char *const SNESNGMRESRestartTypes[] = {"NONE","PERIODIC","DIFFERENCE","SNESNGMRESRestartType","SNES_NGMRES_RESTART_",0};
5 const char *const SNESNGMRESSelectTypes[] = {"NONE","DIFFERENCE","LINESEARCH","SNESNGMRESSelectType","SNES_NGMRES_SELECT_",0};
6 
7 #undef __FUNCT__
8 #define __FUNCT__ "SNESReset_NGMRES"
9 PetscErrorCode SNESReset_NGMRES(SNES snes)
10 {
11   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
12   PetscErrorCode ierr;
13 
14   PetscFunctionBegin;
15   ierr = VecDestroyVecs(ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);
16   ierr = VecDestroyVecs(ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);
17   ierr = SNESLineSearchDestroy(&ngmres->additive_linesearch);CHKERRQ(ierr);
18   PetscFunctionReturn(0);
19 }
20 
21 #undef __FUNCT__
22 #define __FUNCT__ "SNESDestroy_NGMRES"
23 PetscErrorCode SNESDestroy_NGMRES(SNES snes)
24 {
25   PetscErrorCode ierr;
26   SNES_NGMRES    *ngmres = (SNES_NGMRES*)snes->data;
27 
28   PetscFunctionBegin;
29   ierr = SNESReset_NGMRES(snes);CHKERRQ(ierr);
30   ierr = PetscFree5(ngmres->h,ngmres->beta,ngmres->xi,ngmres->fnorms,ngmres->q);CHKERRQ(ierr);
31   ierr = PetscFree(ngmres->s);CHKERRQ(ierr);
32   ierr = PetscFree(ngmres->xnorms);CHKERRQ(ierr);
33 #if PETSC_USE_COMPLEX
34   ierr = PetscFree(ngmres->rwork);CHKERRQ(ierr);
35 #endif
36   ierr = PetscFree(ngmres->work);CHKERRQ(ierr);
37   ierr = PetscFree(snes->data);CHKERRQ(ierr);
38   PetscFunctionReturn(0);
39 }
40 
41 #undef __FUNCT__
42 #define __FUNCT__ "SNESSetUp_NGMRES"
43 PetscErrorCode SNESSetUp_NGMRES(SNES snes)
44 {
45   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
46   const char     *optionsprefix;
47   PetscInt       msize,hsize;
48   PetscErrorCode ierr;
49 
50   PetscFunctionBegin;
51   if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
52     SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"SNESNGMRES does not support left preconditioning with unpreconditioned function");
53   }
54   ierr = SNESSetWorkVecs(snes,5);CHKERRQ(ierr);
55   if (!ngmres->Xdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);}
56   if (!ngmres->Fdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);}
57   if (!ngmres->setup_called) {
58     msize = ngmres->msize;          /* restart size */
59     hsize = msize * msize;
60 
61     /* explicit least squares minimization solve */
62     ierr = PetscMalloc5(hsize,PetscScalar,&ngmres->h,
63                         msize,PetscScalar,&ngmres->beta,
64                         msize,PetscScalar,&ngmres->xi,
65                         msize,PetscReal, &ngmres->fnorms,
66                         hsize,PetscScalar,&ngmres->q);CHKERRQ(ierr);
67     if (ngmres->singlereduction) {
68       ierr = PetscMalloc(msize*sizeof(PetscReal),&ngmres->xnorms);CHKERRQ(ierr);
69     }
70     ngmres->nrhs  = 1;
71     ngmres->lda   = msize;
72     ngmres->ldb   = msize;
73     ierr          = PetscMalloc(msize*sizeof(PetscScalar),&ngmres->s);CHKERRQ(ierr);
74     ierr          = PetscMemzero(ngmres->h,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
75     ierr          = PetscMemzero(ngmres->q,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
76     ierr          = PetscMemzero(ngmres->xi,  msize*sizeof(PetscScalar));CHKERRQ(ierr);
77     ierr          = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr);
78     ngmres->lwork = 12*msize;
79 #if PETSC_USE_COMPLEX
80     ierr = PetscMalloc(sizeof(PetscReal)*ngmres->lwork,&ngmres->rwork);CHKERRQ(ierr);
81 #endif
82     ierr = PetscMalloc(sizeof(PetscScalar)*ngmres->lwork,&ngmres->work);CHKERRQ(ierr);
83   }
84 
85   /* linesearch setup */
86   ierr = SNESGetOptionsPrefix(snes,&optionsprefix);CHKERRQ(ierr);
87 
88   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
89     ierr = SNESLineSearchCreate(PetscObjectComm((PetscObject)snes),&ngmres->additive_linesearch);CHKERRQ(ierr);
90     ierr = SNESLineSearchSetSNES(ngmres->additive_linesearch,snes);CHKERRQ(ierr);
91     ierr = SNESLineSearchSetType(ngmres->additive_linesearch,SNESLINESEARCHL2);CHKERRQ(ierr);
92     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,"additive_");CHKERRQ(ierr);
93     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,optionsprefix);CHKERRQ(ierr);
94     ierr = SNESLineSearchSetFromOptions(ngmres->additive_linesearch);CHKERRQ(ierr);
95   }
96 
97   ngmres->setup_called = PETSC_TRUE;
98   PetscFunctionReturn(0);
99 }
100 
101 #undef __FUNCT__
102 #define __FUNCT__ "SNESSetFromOptions_NGMRES"
103 PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes)
104 {
105   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
106   PetscErrorCode ierr;
107   PetscBool      debug;
108   SNESLineSearch linesearch;
109 
110   PetscFunctionBegin;
111   ierr = PetscOptionsHead("SNES NGMRES options");CHKERRQ(ierr);
112   ierr = PetscOptionsEnum("-snes_ngmres_select_type","Select type","SNESNGMRESSetSelectType",SNESNGMRESSelectTypes,
113                           (PetscEnum)ngmres->select_type,(PetscEnum*)&ngmres->select_type,NULL);CHKERRQ(ierr);
114   ierr = PetscOptionsEnum("-snes_ngmres_restart_type","Restart type","SNESNGMRESSetRestartType",SNESNGMRESRestartTypes,
115                           (PetscEnum)ngmres->restart_type,(PetscEnum*)&ngmres->restart_type,NULL);CHKERRQ(ierr);
116   ierr = PetscOptionsBool("-snes_ngmres_candidate", "Use candidate storage",              "SNES",ngmres->candidate,&ngmres->candidate,NULL);CHKERRQ(ierr);
117   ierr = PetscOptionsBool("-snes_ngmres_approxfunc","Linearly approximate the function", "SNES",ngmres->approxfunc,&ngmres->approxfunc,NULL);CHKERRQ(ierr);
118   ierr = PetscOptionsInt("-snes_ngmres_m",          "Number of directions",               "SNES",ngmres->msize,&ngmres->msize,NULL);CHKERRQ(ierr);
119   ierr = PetscOptionsInt("-snes_ngmres_restart",    "Iterations before forced restart",   "SNES",ngmres->restart_periodic,&ngmres->restart_periodic,NULL);CHKERRQ(ierr);
120   ierr = PetscOptionsInt("-snes_ngmres_restart_it", "Tolerance iterations before restart","SNES",ngmres->restart_it,&ngmres->restart_it,NULL);CHKERRQ(ierr);
121   ierr = PetscOptionsBool("-snes_ngmres_monitor",   "Monitor actions of NGMRES",          "SNES",ngmres->monitor ? PETSC_TRUE : PETSC_FALSE,&debug,NULL);CHKERRQ(ierr);
122   if (debug) {
123     ngmres->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr);
124   }
125   ierr = PetscOptionsReal("-snes_ngmres_gammaA",    "Residual selection constant",   "SNES",ngmres->gammaA,&ngmres->gammaA,NULL);CHKERRQ(ierr);
126   ierr = PetscOptionsReal("-snes_ngmres_gammaC",    "Residual restart constant",     "SNES",ngmres->gammaC,&ngmres->gammaC,NULL);CHKERRQ(ierr);
127   ierr = PetscOptionsReal("-snes_ngmres_epsilonB",  "Difference selection constant", "SNES",ngmres->epsilonB,&ngmres->epsilonB,NULL);CHKERRQ(ierr);
128   ierr = PetscOptionsReal("-snes_ngmres_deltaB",    "Difference residual selection constant", "SNES",ngmres->deltaB,&ngmres->deltaB,NULL);CHKERRQ(ierr);
129   ierr = PetscOptionsBool("-snes_ngmres_single_reduction", "Aggregate reductions",  "SNES",ngmres->singlereduction,&ngmres->singlereduction,NULL);CHKERRQ(ierr);
130   ierr = PetscOptionsTail();CHKERRQ(ierr);
131   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
132 
133   /* set the default type of the line search if the user hasn't already. */
134   if (!snes->linesearch) {
135     ierr = SNESGetLineSearch(snes,&linesearch);CHKERRQ(ierr);
136     ierr = SNESLineSearchSetType(linesearch,SNESLINESEARCHBASIC);CHKERRQ(ierr);
137   }
138   PetscFunctionReturn(0);
139 }
140 
141 #undef __FUNCT__
142 #define __FUNCT__ "SNESView_NGMRES"
143 PetscErrorCode SNESView_NGMRES(SNES snes,PetscViewer viewer)
144 {
145   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
146   PetscBool      iascii;
147   PetscErrorCode ierr;
148 
149   PetscFunctionBegin;
150   ierr = PetscObjectTypeCompare((PetscObject) viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
151   if (iascii) {
152     ierr = PetscViewerASCIIPrintf(viewer,"  Number of stored past updates: %d\n", ngmres->msize);CHKERRQ(ierr);
153     ierr = PetscViewerASCIIPrintf(viewer,"  Residual selection: gammaA=%1.0e, gammaC=%1.0e\n",ngmres->gammaA,ngmres->gammaC);CHKERRQ(ierr);
154     ierr = PetscViewerASCIIPrintf(viewer,"  Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n",ngmres->epsilonB,ngmres->deltaB);CHKERRQ(ierr);
155   }
156   PetscFunctionReturn(0);
157 }
158 
159 #undef __FUNCT__
160 #define __FUNCT__ "SNESSolve_NGMRES"
161 PetscErrorCode SNESSolve_NGMRES(SNES snes)
162 {
163 
164   SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data;
165   /* present solution, residual, and preconditioned residual */
166   Vec X,F,B,D,Y;
167 
168   /* candidate linear combination answers */
169   Vec XA,FA,XM,FM;
170 
171   /* coefficients and RHS to the minimization problem */
172   PetscReal fnorm,fMnorm,fAnorm;
173   PetscInt  k,k_restart,l,ivec,restart_count = 0;
174 
175   /* solution selection data */
176   PetscBool selectRestart;
177   PetscReal dnorm,dminnorm = 0.0;
178   PetscReal fminnorm,xnorm,ynorm;
179 
180   SNESConvergedReason reason;
181   PetscBool           lssucceed;
182   PetscErrorCode      ierr;
183 
184   PetscFunctionBegin;
185   /* variable initialization */
186   snes->reason = SNES_CONVERGED_ITERATING;
187   X            = snes->vec_sol;
188   F            = snes->vec_func;
189   B            = snes->vec_rhs;
190   XA           = snes->vec_sol_update;
191   FA           = snes->work[0];
192   D            = snes->work[1];
193 
194   /* work for the line search */
195   Y  = snes->work[2];
196   XM = snes->work[3];
197   FM = snes->work[4];
198 
199   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
200   snes->iter = 0;
201   snes->norm = 0.;
202   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
203 
204   /* initialization */
205 
206   if (snes->pc && snes->pcside == PC_LEFT) {
207     ierr = SNESApplyPC(snes,X,NULL,NULL,F);CHKERRQ(ierr);
208     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
209     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
210       snes->reason = SNES_DIVERGED_INNER;
211       PetscFunctionReturn(0);
212     }
213     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
214   } else {
215     if (!snes->vec_func_init_set) {
216       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
217       if (snes->domainerror) {
218         snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
219         PetscFunctionReturn(0);
220       }
221     } else snes->vec_func_init_set = PETSC_FALSE;
222     if (!snes->norm_init_set) {
223       /* convergence test */
224       ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
225       if (PetscIsInfOrNanReal(fnorm)) {
226         snes->reason = SNES_DIVERGED_FNORM_NAN;
227         PetscFunctionReturn(0);
228       }
229     } else {
230       fnorm               = snes->norm_init;
231       snes->norm_init_set = PETSC_FALSE;
232     }
233   }
234   fminnorm = fnorm;
235 
236   /* q_{00} = nu  */
237   SNESNGMRESUpdateSubspace_Private(snes,0,0,F,fnorm,X);
238 
239   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
240   snes->norm = fnorm;
241   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
242   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
243   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
244   ierr       = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
245   if (snes->reason) PetscFunctionReturn(0);
246 
247   k_restart = 1;
248   l         = 1;
249   for (k=1; k < snes->max_its+1; k++) {
250     /* select which vector of the stored subspace will be updated */
251     ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */
252 
253     /* Computation of x^M */
254     if (snes->pc && snes->pcside == PC_RIGHT) {
255       ierr = VecCopy(X,XM);CHKERRQ(ierr);
256       ierr = SNESSetInitialFunction(snes->pc,F);CHKERRQ(ierr);
257       ierr = SNESSetInitialFunctionNorm(snes->pc,fnorm);CHKERRQ(ierr);
258 
259       ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
260       ierr = SNESSolve(snes->pc,B,XM);CHKERRQ(ierr);
261       ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
262 
263       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
264       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
265         snes->reason = SNES_DIVERGED_INNER;
266         PetscFunctionReturn(0);
267       }
268       ierr = SNESGetPCFunction(snes,FM,&fMnorm);CHKERRQ(ierr);
269     } else {
270       /* no preconditioner -- just take gradient descent with line search */
271       ierr = VecCopy(F,Y);CHKERRQ(ierr);
272       ierr = VecCopy(F,FM);CHKERRQ(ierr);
273       ierr = VecCopy(X,XM);CHKERRQ(ierr);
274 
275       fMnorm = fnorm;
276 
277       ierr = SNESLineSearchApply(snes->linesearch,XM,FM,&fMnorm,Y);CHKERRQ(ierr);
278       ierr = SNESLineSearchGetSuccess(snes->linesearch,&lssucceed);CHKERRQ(ierr);
279       if (!lssucceed) {
280         if (++snes->numFailures >= snes->maxFailures) {
281           snes->reason = SNES_DIVERGED_LINE_SEARCH;
282           PetscFunctionReturn(0);
283         }
284       }
285     }
286     ierr = SNESNGMRESFormCombinedSolution_Private(snes,l,XM,FM,fMnorm,X,XA,FA);CHKERRQ(ierr);
287     /* r = F(x) */
288     if (fminnorm > fMnorm) fminnorm = fMnorm;  /* the minimum norm is now of F^M */
289 
290     /* differences for selection and restart */
291     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
292       ierr = SNESNGMRESCalculateDifferences_Private(snes,l,X,F,XM,FM,XA,FA,D,&dnorm,&dminnorm,&fAnorm);CHKERRQ(ierr);
293     } else {
294       ierr = VecNorm(FA,NORM_2,&fAnorm);CHKERRQ(ierr);
295     }
296     if (PetscIsInfOrNanReal(fAnorm)) {
297       snes->reason = SNES_DIVERGED_FNORM_NAN;
298       PetscFunctionReturn(0);
299     }
300 
301     /* combination (additive) or selection (multiplicative) of the N-GMRES solution */
302     ierr          = SNESNGMRESSelect_Private(snes,k_restart,XM,FM,fMnorm,XA,FA,fAnorm,dnorm,fminnorm,dminnorm,X,F,Y,&fnorm);CHKERRQ(ierr);
303     selectRestart = PETSC_FALSE;
304     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) {
305       ierr = SNESNGMRESSelectRestart_Private(snes,l,fAnorm,dnorm,fminnorm,dminnorm,&selectRestart);CHKERRQ(ierr);
306       /* if the restart conditions persist for more than restart_it iterations, restart. */
307       if (selectRestart) restart_count++;
308       else restart_count = 0;
309     } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) {
310       if (k_restart > ngmres->restart_periodic) {
311         if (ngmres->monitor) ierr = PetscViewerASCIIPrintf(ngmres->monitor,"periodic restart after %D iterations\n",k_restart);CHKERRQ(ierr);
312         restart_count = ngmres->restart_it;
313       }
314     }
315     /* restart after restart conditions have persisted for a fixed number of iterations */
316     if (restart_count >= ngmres->restart_it) {
317       if (ngmres->monitor) {
318         ierr = PetscViewerASCIIPrintf(ngmres->monitor,"Restarted at iteration %d\n",k_restart);CHKERRQ(ierr);
319       }
320       restart_count = 0;
321       k_restart     = 1;
322       l             = 1;
323       /* q_{00} = nu */
324       if (ngmres->candidate) {
325         ierr = SNESNGMRESUpdateSubspace_Private(snes,0,0,FM,fMnorm,XM);CHKERRQ(ierr);
326       } else {
327         ierr = SNESNGMRESUpdateSubspace_Private(snes,0,0,F,fMnorm,X);CHKERRQ(ierr);
328       }
329     } else {
330       /* select the current size of the subspace */
331       if (l < ngmres->msize) l++;
332       k_restart++;
333       /* place the current entry in the list of previous entries */
334       if (ngmres->candidate) {
335         if (fminnorm > fMnorm) fminnorm = fMnorm;
336         ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,FM,fMnorm,XM);CHKERRQ(ierr);
337       } else {
338         if (fminnorm > fnorm) fminnorm = fnorm;
339         ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,F,fnorm,X);CHKERRQ(ierr);
340       }
341     }
342 
343     ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
344     snes->iter = k;
345     snes->norm = fnorm;
346     ierr = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
347     ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr);
348     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
349     ierr = VecNormBegin(Y,NORM_2,&ynorm);CHKERRQ(ierr);
350     ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);
351     ierr = VecNormEnd(Y,NORM_2,&ynorm);CHKERRQ(ierr);
352     ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
353     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
354     if (snes->reason) PetscFunctionReturn(0);
355   }
356   snes->reason = SNES_DIVERGED_MAX_IT;
357   PetscFunctionReturn(0);
358 }
359 
360 #undef __FUNCT__
361 #define __FUNCT__ "SNESNGMRESSetRestartType"
362 /*@
363     SNESNGMRESSetRestartType - Sets the restart type for SNESNGMRES.
364 
365     Logically Collective on SNES
366 
367     Input Parameters:
368 +   snes - the iterative context
369 -   rtype - restart type
370 
371     Options Database:
372 +   -snes_ngmres_restart_type<difference,periodic,none> - set the restart type
373 -   -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic
374 
375     Level: intermediate
376 
377     SNESNGMRESRestartTypes:
378 +   SNES_NGMRES_RESTART_NONE - never restart
379 .   SNES_NGMRES_RESTART_DIFFERENCE - restart based upon difference criteria
380 -   SNES_NGMRES_RESTART_PERIODIC - restart after a fixed number of iterations
381 
382     Notes:
383     The default line search used is the L2 line search and it requires two additional function evaluations.
384 
385 .keywords: SNES, SNESNGMRES, restart, type, set SNESLineSearch
386 @*/
387 PetscErrorCode SNESNGMRESSetRestartType(SNES snes,SNESNGMRESRestartType rtype)
388 {
389   PetscErrorCode ierr;
390 
391   PetscFunctionBegin;
392   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
393   ierr = PetscTryMethod(snes,"SNESNGMRESSetRestartType_C",(SNES,SNESNGMRESRestartType),(snes,rtype));CHKERRQ(ierr);
394   PetscFunctionReturn(0);
395 }
396 
397 #undef __FUNCT__
398 #define __FUNCT__ "SNESNGMRESSetSelectType"
399 /*@
400     SNESNGMRESSetSelectType - Sets the selection type for SNESNGMRES.  This determines how the candidate solution and
401     combined solution are used to create the next iterate.
402 
403     Logically Collective on SNES
404 
405     Input Parameters:
406 +   snes - the iterative context
407 -   stype - selection type
408 
409     Options Database:
410 .   -snes_ngmres_select_type<difference,none,linesearch>
411 
412     Level: intermediate
413 
414     SNESNGMRESSelectTypes:
415 +   SNES_NGMRES_SELECT_NONE - choose the combined solution all the time
416 .   SNES_NGMRES_SELECT_DIFFERENCE - choose based upon the selection criteria
417 -   SNES_NGMRES_SELECT_LINESEARCH - choose based upon line search combination
418 
419     Notes:
420     The default line search used is the L2 line search and it requires two additional function evaluations.
421 
422 .keywords: SNES, SNESNGMRES, selection, type, set SNESLineSearch
423 @*/
424 PetscErrorCode SNESNGMRESSetSelectType(SNES snes,SNESNGMRESSelectType stype)
425 {
426   PetscErrorCode ierr;
427 
428   PetscFunctionBegin;
429   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
430   ierr = PetscTryMethod(snes,"SNESNGMRESSetSelectType_C",(SNES,SNESNGMRESSelectType),(snes,stype));CHKERRQ(ierr);
431   PetscFunctionReturn(0);
432 }
433 
434 #undef __FUNCT__
435 #define __FUNCT__ "SNESNGMRESSetSelectType_NGMRES"
436 PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes,SNESNGMRESSelectType stype)
437 {
438   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
439 
440   PetscFunctionBegin;
441   ngmres->select_type = stype;
442   PetscFunctionReturn(0);
443 }
444 
445 #undef __FUNCT__
446 #define __FUNCT__ "SNESNGMRESSetRestartType_NGMRES"
447 PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes,SNESNGMRESRestartType rtype)
448 {
449   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
450 
451   PetscFunctionBegin;
452   ngmres->restart_type = rtype;
453   PetscFunctionReturn(0);
454 }
455 
456 /*MC
457   SNESNGMRES - The Nonlinear Generalized Minimum Residual method.
458 
459    Level: beginner
460 
461    Options Database:
462 +  -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution
463 .  -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions
464 .  -snes_ngmres_candidate        - Use NGMRES variant which combines candidate solutions instead of actual solutions
465 .  -snes_ngmres_m                - Number of stored previous solutions and residuals
466 .  -snes_ngmres_restart_it       - Number of iterations the restart conditions hold before restart
467 .  -snes_ngmres_gammaA           - Residual tolerance for solution select between the candidate and combination
468 .  -snes_ngmres_gammaC           - Residual tolerance for restart
469 .  -snes_ngmres_epsilonB         - Difference tolerance between subsequent solutions triggering restart
470 .  -snes_ngmres_deltaB           - Difference tolerance between residuals triggering restart
471 .  -snes_ngmres_monitor          - Prints relevant information about the ngmres iteration
472 .  -snes_linesearch_type <basic,l2,cp> - Line search type used for the default smoother
473 -  -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type
474 
475    Notes:
476 
477    The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized
478    optimization problem at each iteration.
479 
480    References:
481 
482    "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio,
483    SIAM Journal on Scientific Computing, 21(5), 2000.
484 
485 .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
486 M*/
487 
488 #undef __FUNCT__
489 #define __FUNCT__ "SNESCreate_NGMRES"
490 PETSC_EXTERN PetscErrorCode SNESCreate_NGMRES(SNES snes)
491 {
492   SNES_NGMRES    *ngmres;
493   PetscErrorCode ierr;
494 
495   PetscFunctionBegin;
496   snes->ops->destroy        = SNESDestroy_NGMRES;
497   snes->ops->setup          = SNESSetUp_NGMRES;
498   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
499   snes->ops->view           = SNESView_NGMRES;
500   snes->ops->solve          = SNESSolve_NGMRES;
501   snes->ops->reset          = SNESReset_NGMRES;
502 
503   snes->usespc   = PETSC_TRUE;
504   snes->usesksp  = PETSC_FALSE;
505   snes->pcside   = PC_RIGHT;
506   snes->functype = SNES_FUNCTION_PRECONDITIONED;
507 
508   ierr          = PetscNewLog(snes,SNES_NGMRES,&ngmres);CHKERRQ(ierr);
509   snes->data    = (void*) ngmres;
510   ngmres->msize = 30;
511 
512   if (!snes->tolerancesset) {
513     snes->max_funcs = 30000;
514     snes->max_its   = 10000;
515   }
516 
517   ngmres->candidate = PETSC_FALSE;
518 
519   ngmres->additive_linesearch = NULL;
520   ngmres->approxfunc       = PETSC_FALSE;
521   ngmres->restart_it       = 2;
522   ngmres->restart_periodic = 30;
523   ngmres->gammaA           = 2.0;
524   ngmres->gammaC           = 2.0;
525   ngmres->deltaB           = 0.9;
526   ngmres->epsilonB         = 0.1;
527 
528   ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE;
529   ngmres->select_type  = SNES_NGMRES_SELECT_DIFFERENCE;
530 
531   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetSelectType_C",SNESNGMRESSetSelectType_NGMRES);CHKERRQ(ierr);
532   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetRestartType_C",SNESNGMRESSetRestartType_NGMRES);CHKERRQ(ierr);
533   PetscFunctionReturn(0);
534 }
535 
536