xref: /petsc/src/snes/impls/richardson/snesrichardson.c (revision 028b6e763ad4b43dad2546398a0b7c4c9de6b45e)
1*028b6e76SBarry Smith 
2*028b6e76SBarry Smith #include <../src/snes/impls/picard/picard.h>
3*028b6e76SBarry Smith 
4*028b6e76SBarry Smith #undef __FUNCT__
5*028b6e76SBarry Smith #define __FUNCT__ "SNESReset_Picard"
6*028b6e76SBarry Smith PetscErrorCode SNESReset_Picard(SNES snes)
7*028b6e76SBarry Smith {
8*028b6e76SBarry Smith   PetscErrorCode ierr;
9*028b6e76SBarry Smith 
10*028b6e76SBarry Smith   PetscFunctionBegin;
11*028b6e76SBarry Smith   if (snes->work) {ierr = VecDestroyVecs(snes->nwork,&snes->work);CHKERRQ(ierr);}
12*028b6e76SBarry Smith   PetscFunctionReturn(0);
13*028b6e76SBarry Smith }
14*028b6e76SBarry Smith 
15*028b6e76SBarry Smith /*
16*028b6e76SBarry Smith   SNESDestroy_Picard - Destroys the private SNES_Picard context that was created with SNESCreate_Picard().
17*028b6e76SBarry Smith 
18*028b6e76SBarry Smith   Input Parameter:
19*028b6e76SBarry Smith . snes - the SNES context
20*028b6e76SBarry Smith 
21*028b6e76SBarry Smith   Application Interface Routine: SNESDestroy()
22*028b6e76SBarry Smith */
23*028b6e76SBarry Smith #undef __FUNCT__
24*028b6e76SBarry Smith #define __FUNCT__ "SNESDestroy_Picard"
25*028b6e76SBarry Smith PetscErrorCode SNESDestroy_Picard(SNES snes)
26*028b6e76SBarry Smith {
27*028b6e76SBarry Smith   PetscErrorCode ierr;
28*028b6e76SBarry Smith   SNES_Picard    *neP = (SNES_Picard*)snes->data;
29*028b6e76SBarry Smith 
30*028b6e76SBarry Smith   PetscFunctionBegin;
31*028b6e76SBarry Smith   ierr = SNESReset_Picard(snes);CHKERRQ(ierr);
32*028b6e76SBarry Smith   ierr = PetscViewerDestroy(&neP->monitor);CHKERRQ(ierr);
33*028b6e76SBarry Smith   ierr = PetscFree(snes->data);CHKERRQ(ierr);
34*028b6e76SBarry Smith   PetscFunctionReturn(0);
35*028b6e76SBarry Smith }
36*028b6e76SBarry Smith 
37*028b6e76SBarry Smith /*
38*028b6e76SBarry Smith    SNESSetUp_Picard - Sets up the internal data structures for the later use
39*028b6e76SBarry Smith    of the SNESPICARD nonlinear solver.
40*028b6e76SBarry Smith 
41*028b6e76SBarry Smith    Input Parameters:
42*028b6e76SBarry Smith +  snes - the SNES context
43*028b6e76SBarry Smith -  x - the solution vector
44*028b6e76SBarry Smith 
45*028b6e76SBarry Smith    Application Interface Routine: SNESSetUp()
46*028b6e76SBarry Smith  */
47*028b6e76SBarry Smith #undef __FUNCT__
48*028b6e76SBarry Smith #define __FUNCT__ "SNESSetUp_Picard"
49*028b6e76SBarry Smith PetscErrorCode SNESSetUp_Picard(SNES snes)
50*028b6e76SBarry Smith {
51*028b6e76SBarry Smith   PetscErrorCode ierr;
52*028b6e76SBarry Smith 
53*028b6e76SBarry Smith   PetscFunctionBegin;
54*028b6e76SBarry Smith   ierr = SNESDefaultGetWork(snes,1);CHKERRQ(ierr);
55*028b6e76SBarry Smith   PetscFunctionReturn(0);
56*028b6e76SBarry Smith }
57*028b6e76SBarry Smith 
58*028b6e76SBarry Smith EXTERN_C_BEGIN
59*028b6e76SBarry Smith #undef __FUNCT__
60*028b6e76SBarry Smith #define __FUNCT__ "SNESLineSearchSetMonitor_Picard"
61*028b6e76SBarry Smith PetscErrorCode  SNESLineSearchSetMonitor_Picard(SNES snes,PetscBool  flg)
62*028b6e76SBarry Smith {
63*028b6e76SBarry Smith   SNES_Picard    *neP = (SNES_Picard*)snes->data;
64*028b6e76SBarry Smith   PetscErrorCode ierr;
65*028b6e76SBarry Smith 
66*028b6e76SBarry Smith   PetscFunctionBegin;
67*028b6e76SBarry Smith   if (flg && !neP->monitor) {
68*028b6e76SBarry Smith     ierr = PetscViewerASCIIOpen(((PetscObject)snes)->comm,"stdout",&neP->monitor);CHKERRQ(ierr);
69*028b6e76SBarry Smith   } else if (!flg && neP->monitor) {
70*028b6e76SBarry Smith     ierr = PetscViewerDestroy(&neP->monitor);CHKERRQ(ierr);
71*028b6e76SBarry Smith   }
72*028b6e76SBarry Smith   PetscFunctionReturn(0);
73*028b6e76SBarry Smith }
74*028b6e76SBarry Smith EXTERN_C_END
75*028b6e76SBarry Smith 
76*028b6e76SBarry Smith PetscErrorCode SNESLineSearchNoNorms_Picard(SNES,void*,Vec,Vec,Vec,PetscReal,PetscReal,Vec,Vec,PetscReal*,PetscReal*,PetscBool*);
77*028b6e76SBarry Smith PetscErrorCode SNESLineSearchNo_Picard(SNES,void*,Vec,Vec,Vec,PetscReal,PetscReal,Vec,Vec,PetscReal*,PetscReal*,PetscBool*);
78*028b6e76SBarry Smith PetscErrorCode SNESLineSearchQuadratic_Picard(SNES,void*,Vec,Vec,Vec,PetscReal,PetscReal,Vec,Vec,PetscReal*,PetscReal*,PetscBool*);
79*028b6e76SBarry Smith /*
80*028b6e76SBarry Smith   SNESSetFromOptions_Picard - Sets various parameters for the SNESLS method.
81*028b6e76SBarry Smith 
82*028b6e76SBarry Smith   Input Parameter:
83*028b6e76SBarry Smith . snes - the SNES context
84*028b6e76SBarry Smith 
85*028b6e76SBarry Smith   Application Interface Routine: SNESSetFromOptions()
86*028b6e76SBarry Smith */
87*028b6e76SBarry Smith #undef __FUNCT__
88*028b6e76SBarry Smith #define __FUNCT__ "SNESSetFromOptions_Picard"
89*028b6e76SBarry Smith static PetscErrorCode SNESSetFromOptions_Picard(SNES snes)
90*028b6e76SBarry Smith {
91*028b6e76SBarry Smith   SNES_Picard        *ls = (SNES_Picard *)snes->data;
92*028b6e76SBarry Smith   SNESLineSearchType indx;
93*028b6e76SBarry Smith   PetscBool          flg,set;
94*028b6e76SBarry Smith   PetscErrorCode     ierr;
95*028b6e76SBarry Smith 
96*028b6e76SBarry Smith   PetscFunctionBegin;
97*028b6e76SBarry Smith   ierr = PetscOptionsHead("SNES Picard options");CHKERRQ(ierr);
98*028b6e76SBarry Smith     ierr = PetscOptionsEnum("-snes_ls","Picard line search type","SNESLineSearchSet",SNESLineSearchTypes,(PetscEnum)ls->type,(PetscEnum*)&indx,&flg);CHKERRQ(ierr);
99*028b6e76SBarry Smith     if (flg) {
100*028b6e76SBarry Smith       ls->type = indx;
101*028b6e76SBarry Smith       switch (indx) {
102*028b6e76SBarry Smith       case SNES_LS_BASIC:
103*028b6e76SBarry Smith         ierr = SNESLineSearchSet(snes,SNESLineSearchNo_Picard,PETSC_NULL);CHKERRQ(ierr);
104*028b6e76SBarry Smith         break;
105*028b6e76SBarry Smith       case SNES_LS_BASIC_NONORMS:
106*028b6e76SBarry Smith         ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms_Picard,PETSC_NULL);CHKERRQ(ierr);
107*028b6e76SBarry Smith         break;
108*028b6e76SBarry Smith       case SNES_LS_QUADRATIC:
109*028b6e76SBarry Smith         ierr = SNESLineSearchSet(snes,SNESLineSearchQuadratic_Picard,PETSC_NULL);CHKERRQ(ierr);
110*028b6e76SBarry Smith         break;
111*028b6e76SBarry Smith       case SNES_LS_CUBIC:
112*028b6e76SBarry Smith         SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_SUP,"No support for cubic search");
113*028b6e76SBarry Smith         break;
114*028b6e76SBarry Smith       }
115*028b6e76SBarry Smith     }
116*028b6e76SBarry Smith     ierr = PetscOptionsReal("-snes_ls_damping","Damping parameter","SNES",ls->damping,&ls->damping,&flg);CHKERRQ(ierr);
117*028b6e76SBarry Smith     ierr = PetscOptionsBool("-snes_ls_monitor","Print progress of line searches","SNESLineSearchSetMonitor",ls->monitor ? PETSC_TRUE : PETSC_FALSE,&flg,&set);CHKERRQ(ierr);
118*028b6e76SBarry Smith     if (set) {ierr = SNESLineSearchSetMonitor(snes,flg);CHKERRQ(ierr);}
119*028b6e76SBarry Smith   ierr = PetscOptionsTail();CHKERRQ(ierr);
120*028b6e76SBarry Smith   PetscFunctionReturn(0);
121*028b6e76SBarry Smith }
122*028b6e76SBarry Smith 
123*028b6e76SBarry Smith /*
124*028b6e76SBarry Smith   SNESView_Picard - Prints info from the SNESPicard data structure.
125*028b6e76SBarry Smith 
126*028b6e76SBarry Smith   Input Parameters:
127*028b6e76SBarry Smith + SNES - the SNES context
128*028b6e76SBarry Smith - viewer - visualization context
129*028b6e76SBarry Smith 
130*028b6e76SBarry Smith   Application Interface Routine: SNESView()
131*028b6e76SBarry Smith */
132*028b6e76SBarry Smith #undef __FUNCT__
133*028b6e76SBarry Smith #define __FUNCT__ "SNESView_Picard"
134*028b6e76SBarry Smith static PetscErrorCode SNESView_Picard(SNES snes, PetscViewer viewer)
135*028b6e76SBarry Smith {
136*028b6e76SBarry Smith   SNES_Picard   *ls = (SNES_Picard *)snes->data;
137*028b6e76SBarry Smith   PetscBool      iascii;
138*028b6e76SBarry Smith   PetscErrorCode ierr;
139*028b6e76SBarry Smith 
140*028b6e76SBarry Smith   PetscFunctionBegin;
141*028b6e76SBarry Smith   ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
142*028b6e76SBarry Smith   if (iascii) {
143*028b6e76SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  picard variant: %s\n", SNESLineSearchTypeName(ls->type));CHKERRQ(ierr);
144*028b6e76SBarry Smith   }
145*028b6e76SBarry Smith   PetscFunctionReturn(0);
146*028b6e76SBarry Smith }
147*028b6e76SBarry Smith 
148*028b6e76SBarry Smith #undef __FUNCT__
149*028b6e76SBarry Smith #define __FUNCT__ "SNESLineSearchNo_Picard"
150*028b6e76SBarry Smith PetscErrorCode SNESLineSearchNo_Picard(SNES snes,void *lsctx,Vec X,Vec F,Vec Y,PetscReal fnorm,PetscReal dummyXnorm,Vec dummyG,Vec W,PetscReal *dummyYnorm,PetscReal *gnorm,PetscBool *flag)
151*028b6e76SBarry Smith {
152*028b6e76SBarry Smith   PetscErrorCode ierr;
153*028b6e76SBarry Smith   SNES_Picard    *neP = (SNES_Picard *) snes->data;
154*028b6e76SBarry Smith 
155*028b6e76SBarry Smith   PetscFunctionBegin;
156*028b6e76SBarry Smith   ierr = VecAXPY(X, neP->damping, Y);CHKERRQ(ierr);
157*028b6e76SBarry Smith   ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
158*028b6e76SBarry Smith   ierr = VecNorm(F, NORM_2, gnorm);CHKERRQ(ierr);
159*028b6e76SBarry Smith   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated norm");
160*028b6e76SBarry Smith   PetscFunctionReturn(0);
161*028b6e76SBarry Smith }
162*028b6e76SBarry Smith 
163*028b6e76SBarry Smith #undef __FUNCT__
164*028b6e76SBarry Smith #define __FUNCT__ "SNESLineSearchNoNorms_Picard"
165*028b6e76SBarry Smith PetscErrorCode SNESLineSearchNoNorms_Picard(SNES snes,void *lsctx,Vec X,Vec F,Vec Y,PetscReal fnorm,PetscReal dummyXnorm,Vec dummyG,Vec W,PetscReal *dummyYnorm,PetscReal *gnorm,PetscBool *flag)
166*028b6e76SBarry Smith {
167*028b6e76SBarry Smith   PetscErrorCode ierr;
168*028b6e76SBarry Smith   SNES_Picard    *neP = (SNES_Picard *) snes->data;
169*028b6e76SBarry Smith 
170*028b6e76SBarry Smith   PetscFunctionBegin;
171*028b6e76SBarry Smith   ierr = VecAXPY(X, neP->damping, Y);CHKERRQ(ierr);
172*028b6e76SBarry Smith   ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
173*028b6e76SBarry Smith   PetscFunctionReturn(0);
174*028b6e76SBarry Smith }
175*028b6e76SBarry Smith 
176*028b6e76SBarry Smith #undef __FUNCT__
177*028b6e76SBarry Smith #define __FUNCT__ "SNESLineSearchQuadratic_Picard"
178*028b6e76SBarry Smith PetscErrorCode SNESLineSearchQuadratic_Picard(SNES snes,void *lsctx,Vec X,Vec F,Vec Y,PetscReal fnorm,PetscReal dummyXnorm,Vec G,Vec W,PetscReal *dummyYnorm,PetscReal *gnorm,PetscBool *flag)
179*028b6e76SBarry Smith {
180*028b6e76SBarry Smith   PetscInt       i;
181*028b6e76SBarry Smith   PetscReal      alphas[3] = {0.0, 0.5, 1.0};
182*028b6e76SBarry Smith   PetscReal      norms[3];
183*028b6e76SBarry Smith   PetscReal      alpha,a,b;
184*028b6e76SBarry Smith   PetscErrorCode ierr;
185*028b6e76SBarry Smith   SNES_Picard    *neP = (SNES_Picard *) snes->data;
186*028b6e76SBarry Smith 
187*028b6e76SBarry Smith   PetscFunctionBegin;
188*028b6e76SBarry Smith   norms[0]  = fnorm;
189*028b6e76SBarry Smith   for(i=1; i < 3; ++i) {
190*028b6e76SBarry Smith     ierr = VecWAXPY(W, alphas[i], Y, X);CHKERRQ(ierr);     /* W =  X^n - \alpha Y */
191*028b6e76SBarry Smith     ierr = SNESComputeFunction(snes, W, F);CHKERRQ(ierr);
192*028b6e76SBarry Smith     ierr = VecNorm(F, NORM_2, &norms[i]);CHKERRQ(ierr);
193*028b6e76SBarry Smith   }
194*028b6e76SBarry Smith   for(i = 0; i < 3; ++i) {
195*028b6e76SBarry Smith     norms[i] = PetscSqr(norms[i]);
196*028b6e76SBarry Smith   }
197*028b6e76SBarry Smith   /* Fit a quadratic:
198*028b6e76SBarry Smith        If we have x_{0,1,2} = 0, x_1, x_2 which generate norms y_{0,1,2}
199*028b6e76SBarry Smith        a = (x_1 y_2 - x_2 y_1 + (x_2 - x_1) y_0)/(x^2_2 x_1 - x_2 x^2_1)
200*028b6e76SBarry Smith        b = (x^2_1 y_2 - x^2_2 y_1 + (x^2_2 - x^2_1) y_0)/(x_2 x^2_1 - x^2_2 x_1)
201*028b6e76SBarry Smith        c = y_0
202*028b6e76SBarry Smith        x_min = -b/2a
203*028b6e76SBarry Smith 
204*028b6e76SBarry Smith        If we let x_{0,1,2} = 0, 0.5, 1.0
205*028b6e76SBarry Smith        a = 2 y_2 - 4 y_1 + 2 y_0
206*028b6e76SBarry Smith        b =  -y_2 + 4 y_1 - 3 y_0
207*028b6e76SBarry Smith        c =   y_0
208*028b6e76SBarry Smith   */
209*028b6e76SBarry Smith   a = (alphas[1]*norms[2] - alphas[2]*norms[1] + (alphas[2] - alphas[1])*norms[0])/(PetscSqr(alphas[2])*alphas[1] - alphas[2]*PetscSqr(alphas[1]));
210*028b6e76SBarry Smith   b = (PetscSqr(alphas[1])*norms[2] - PetscSqr(alphas[2])*norms[1] + (PetscSqr(alphas[2]) - PetscSqr(alphas[1]))*norms[0])/(alphas[2]*PetscSqr(alphas[1]) - PetscSqr(alphas[2])*alphas[1]);
211*028b6e76SBarry Smith   /* Check for positive a (concave up) */
212*028b6e76SBarry Smith   if (a >= 0.0) {
213*028b6e76SBarry Smith     alpha = -b/(2.0*a);
214*028b6e76SBarry Smith     alpha = PetscMin(alpha, alphas[2]);
215*028b6e76SBarry Smith     alpha = PetscMax(alpha, alphas[0]);
216*028b6e76SBarry Smith   } else {
217*028b6e76SBarry Smith     alpha = 1.0;
218*028b6e76SBarry Smith   }
219*028b6e76SBarry Smith   if (neP->monitor) {
220*028b6e76SBarry Smith     ierr = PetscViewerASCIIAddTab(neP->monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
221*028b6e76SBarry Smith     ierr = PetscViewerASCIIPrintf(neP->monitor,"    Line search: norms[0] = %g, norms[1] = %g, norms[2] = %g alpha %g\n", sqrt(norms[0]),sqrt(norms[1]),sqrt(norms[2]),alpha);CHKERRQ(ierr);
222*028b6e76SBarry Smith     ierr = PetscViewerASCIISubtractTab(neP->monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
223*028b6e76SBarry Smith   }
224*028b6e76SBarry Smith   ierr = VecAXPY(X, alpha, Y);CHKERRQ(ierr);
225*028b6e76SBarry Smith   if (alpha != 1.0) {
226*028b6e76SBarry Smith     ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
227*028b6e76SBarry Smith     ierr = VecNorm(F, NORM_2, gnorm);CHKERRQ(ierr);
228*028b6e76SBarry Smith   } else {
229*028b6e76SBarry Smith     *gnorm = PetscSqrtReal(norms[2]);
230*028b6e76SBarry Smith   }
231*028b6e76SBarry Smith   if (alpha == 0.0) *flag = PETSC_FALSE;
232*028b6e76SBarry Smith   else              *flag = PETSC_TRUE;
233*028b6e76SBarry Smith   PetscFunctionReturn(0);
234*028b6e76SBarry Smith }
235*028b6e76SBarry Smith 
236*028b6e76SBarry Smith /*
237*028b6e76SBarry Smith   SNESSolve_Picard - Solves a nonlinear system with the Picard method.
238*028b6e76SBarry Smith 
239*028b6e76SBarry Smith   Input Parameters:
240*028b6e76SBarry Smith . snes - the SNES context
241*028b6e76SBarry Smith 
242*028b6e76SBarry Smith   Output Parameter:
243*028b6e76SBarry Smith . outits - number of iterations until termination
244*028b6e76SBarry Smith 
245*028b6e76SBarry Smith   Application Interface Routine: SNESSolve()
246*028b6e76SBarry Smith */
247*028b6e76SBarry Smith #undef __FUNCT__
248*028b6e76SBarry Smith #define __FUNCT__ "SNESSolve_Picard"
249*028b6e76SBarry Smith PetscErrorCode SNESSolve_Picard(SNES snes)
250*028b6e76SBarry Smith {
251*028b6e76SBarry Smith   SNES_Picard         *neP = (SNES_Picard *) snes->data;
252*028b6e76SBarry Smith   Vec                 X, Y, F, W;
253*028b6e76SBarry Smith   PetscReal           fnorm;
254*028b6e76SBarry Smith   PetscInt            maxits, i;
255*028b6e76SBarry Smith   PetscErrorCode      ierr;
256*028b6e76SBarry Smith   SNESConvergedReason reason;
257*028b6e76SBarry Smith 
258*028b6e76SBarry Smith   PetscFunctionBegin;
259*028b6e76SBarry Smith   snes->reason = SNES_CONVERGED_ITERATING;
260*028b6e76SBarry Smith 
261*028b6e76SBarry Smith   maxits = snes->max_its;	     /* maximum number of iterations */
262*028b6e76SBarry Smith   X      = snes->vec_sol;	     /* X^n */
263*028b6e76SBarry Smith   Y      = snes->vec_sol_update; /* \tilde X */
264*028b6e76SBarry Smith   F      = snes->vec_func;       /* residual vector */
265*028b6e76SBarry Smith   W      = snes->work[0];        /* work vector */
266*028b6e76SBarry Smith 
267*028b6e76SBarry Smith   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
268*028b6e76SBarry Smith   snes->iter = 0;
269*028b6e76SBarry Smith   snes->norm = 0.;
270*028b6e76SBarry Smith   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
271*028b6e76SBarry Smith   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
272*028b6e76SBarry Smith   if (snes->domainerror) {
273*028b6e76SBarry Smith     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
274*028b6e76SBarry Smith     PetscFunctionReturn(0);
275*028b6e76SBarry Smith   }
276*028b6e76SBarry Smith   ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
277*028b6e76SBarry Smith   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm");
278*028b6e76SBarry Smith   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
279*028b6e76SBarry Smith   snes->norm = fnorm;
280*028b6e76SBarry Smith   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
281*028b6e76SBarry Smith   SNESLogConvHistory(snes,fnorm,0);
282*028b6e76SBarry Smith   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
283*028b6e76SBarry Smith 
284*028b6e76SBarry Smith   /* set parameter for default relative tolerance convergence test */
285*028b6e76SBarry Smith   snes->ttol = fnorm*snes->rtol;
286*028b6e76SBarry Smith   /* test convergence */
287*028b6e76SBarry Smith   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
288*028b6e76SBarry Smith   if (snes->reason) PetscFunctionReturn(0);
289*028b6e76SBarry Smith 
290*028b6e76SBarry Smith   for(i = 0; i < maxits; i++) {
291*028b6e76SBarry Smith     PetscBool  lsSuccess = PETSC_TRUE;
292*028b6e76SBarry Smith     PetscReal  dummyNorm;
293*028b6e76SBarry Smith 
294*028b6e76SBarry Smith     /* Call general purpose update function */
295*028b6e76SBarry Smith     if (snes->ops->update) {
296*028b6e76SBarry Smith       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
297*028b6e76SBarry Smith     }
298*028b6e76SBarry Smith     if (!snes->pc) {
299*028b6e76SBarry Smith       ierr = VecCopy(F,Y);CHKERRQ(ierr);
300*028b6e76SBarry Smith       ierr = VecScale(Y,-1.0);CHKERRQ(ierr);
301*028b6e76SBarry Smith     } else {
302*028b6e76SBarry Smith       ierr = VecCopy(X,Y);CHKERRQ(ierr);
303*028b6e76SBarry Smith       ierr = SNESSolve(snes->pc, 0, Y);CHKERRQ(ierr);
304*028b6e76SBarry Smith       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
305*028b6e76SBarry Smith       if (reason < 0) {
306*028b6e76SBarry Smith         snes->reason = SNES_DIVERGED_INNER;
307*028b6e76SBarry Smith         PetscFunctionReturn(0);
308*028b6e76SBarry Smith       }
309*028b6e76SBarry Smith       ierr = VecAXPY(Y,-1.0,X);CHKERRQ(ierr);
310*028b6e76SBarry Smith     }
311*028b6e76SBarry Smith 
312*028b6e76SBarry Smith       ierr = (*neP->LineSearch)(snes, neP->lsP, X, F, Y, fnorm, 0.0, 0, W, &dummyNorm, &fnorm, &lsSuccess);CHKERRQ(ierr);
313*028b6e76SBarry Smith     if (!lsSuccess) {
314*028b6e76SBarry Smith       if (++snes->numFailures >= snes->maxFailures) {
315*028b6e76SBarry Smith         snes->reason = SNES_DIVERGED_LINE_SEARCH;
316*028b6e76SBarry Smith         break;
317*028b6e76SBarry Smith       }
318*028b6e76SBarry Smith     }
319*028b6e76SBarry Smith     if (snes->nfuncs >= snes->max_funcs) {
320*028b6e76SBarry Smith       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
321*028b6e76SBarry Smith       break;
322*028b6e76SBarry Smith     }
323*028b6e76SBarry Smith     if (snes->domainerror) {
324*028b6e76SBarry Smith       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
325*028b6e76SBarry Smith       PetscFunctionReturn(0);
326*028b6e76SBarry Smith     }
327*028b6e76SBarry Smith     /* Monitor convergence */
328*028b6e76SBarry Smith     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
329*028b6e76SBarry Smith     snes->iter = i+1;
330*028b6e76SBarry Smith     snes->norm = fnorm;
331*028b6e76SBarry Smith     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
332*028b6e76SBarry Smith     SNESLogConvHistory(snes,snes->norm,0);
333*028b6e76SBarry Smith     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
334*028b6e76SBarry Smith     /* Test for convergence */
335*028b6e76SBarry Smith     ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
336*028b6e76SBarry Smith     if (snes->reason) break;
337*028b6e76SBarry Smith   }
338*028b6e76SBarry Smith   if (i == maxits) {
339*028b6e76SBarry Smith     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr);
340*028b6e76SBarry Smith     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
341*028b6e76SBarry Smith   }
342*028b6e76SBarry Smith   PetscFunctionReturn(0);
343*028b6e76SBarry Smith }
344*028b6e76SBarry Smith 
345*028b6e76SBarry Smith typedef PetscErrorCode (*FCN1)(SNES,Vec,Vec,void*,PetscBool *);                 /* force argument to next function to not be extern C*/
346*028b6e76SBarry Smith EXTERN_C_BEGIN
347*028b6e76SBarry Smith #undef __FUNCT__
348*028b6e76SBarry Smith #define __FUNCT__ "SNESLineSearchSetPreCheck_Picard"
349*028b6e76SBarry Smith PetscErrorCode  SNESLineSearchSetPreCheck_Picard(SNES snes, FCN1 func, void *checkctx)
350*028b6e76SBarry Smith {
351*028b6e76SBarry Smith   PetscFunctionBegin;
352*028b6e76SBarry Smith   ((SNES_Picard *)(snes->data))->precheckstep = func;
353*028b6e76SBarry Smith   ((SNES_Picard *)(snes->data))->precheck     = checkctx;
354*028b6e76SBarry Smith   PetscFunctionReturn(0);
355*028b6e76SBarry Smith }
356*028b6e76SBarry Smith EXTERN_C_END
357*028b6e76SBarry Smith 
358*028b6e76SBarry Smith typedef PetscErrorCode (*FCN2)(SNES,void*,Vec,Vec,Vec,PetscReal,PetscReal,Vec,Vec,PetscReal*,PetscReal*,PetscBool *); /* force argument to next function to not be extern C*/
359*028b6e76SBarry Smith EXTERN_C_BEGIN
360*028b6e76SBarry Smith #undef __FUNCT__
361*028b6e76SBarry Smith #define __FUNCT__ "SNESLineSearchSet_Picard"
362*028b6e76SBarry Smith PetscErrorCode  SNESLineSearchSet_Picard(SNES snes, FCN2 func, void *lsctx)
363*028b6e76SBarry Smith {
364*028b6e76SBarry Smith   PetscFunctionBegin;
365*028b6e76SBarry Smith   ((SNES_Picard *)(snes->data))->LineSearch = func;
366*028b6e76SBarry Smith   ((SNES_Picard *)(snes->data))->lsP        = lsctx;
367*028b6e76SBarry Smith   PetscFunctionReturn(0);
368*028b6e76SBarry Smith }
369*028b6e76SBarry Smith EXTERN_C_END
370*028b6e76SBarry Smith 
371*028b6e76SBarry Smith typedef PetscErrorCode (*FCN3)(SNES,Vec,Vec,Vec,void*,PetscBool *,PetscBool *); /* force argument to next function to not be extern C*/
372*028b6e76SBarry Smith EXTERN_C_BEGIN
373*028b6e76SBarry Smith #undef __FUNCT__
374*028b6e76SBarry Smith #define __FUNCT__ "SNESLineSearchSetPostCheck_Picard"
375*028b6e76SBarry Smith PetscErrorCode  SNESLineSearchSetPostCheck_Picard(SNES snes, FCN3 func, void *checkctx)
376*028b6e76SBarry Smith {
377*028b6e76SBarry Smith   PetscFunctionBegin;
378*028b6e76SBarry Smith   ((SNES_Picard *)(snes->data))->postcheckstep = func;
379*028b6e76SBarry Smith   ((SNES_Picard *)(snes->data))->postcheck     = checkctx;
380*028b6e76SBarry Smith   PetscFunctionReturn(0);
381*028b6e76SBarry Smith }
382*028b6e76SBarry Smith EXTERN_C_END
383*028b6e76SBarry Smith 
384*028b6e76SBarry Smith /*MC
385*028b6e76SBarry Smith   SNESPICARD - Picard nonlinear solver that uses successive substitutions
386*028b6e76SBarry Smith 
387*028b6e76SBarry Smith   Level: beginner
388*028b6e76SBarry Smith 
389*028b6e76SBarry Smith   Options Database:
390*028b6e76SBarry Smith +   -snes_ls_damping - damping factor to apply to F(x) (used only if -snes_ls is basic or basicnonorms)
391*028b6e76SBarry Smith -   -snes_ls <basic,basicnormnorms,quadratic>
392*028b6e76SBarry Smith 
393*028b6e76SBarry Smith   Notes: Solves F(x) - b = 0 using x^{n+1} = x^{n} - lambda (F(x^n) - b) where lambda is obtained either SNESLineSearchSetDamping(), -snes_damping or
394*028b6e76SBarry Smith      a line search.
395*028b6e76SBarry Smith 
396*028b6e76SBarry Smith      This uses no derivative information thus will be much slower then Newton's method obtained with -snes_type ls
397*028b6e76SBarry Smith 
398*028b6e76SBarry Smith .seealso:  SNESCreate(), SNES, SNESSetType(), SNESLS, SNESTR
399*028b6e76SBarry Smith M*/
400*028b6e76SBarry Smith EXTERN_C_BEGIN
401*028b6e76SBarry Smith #undef __FUNCT__
402*028b6e76SBarry Smith #define __FUNCT__ "SNESCreate_Picard"
403*028b6e76SBarry Smith PetscErrorCode  SNESCreate_Picard(SNES snes)
404*028b6e76SBarry Smith {
405*028b6e76SBarry Smith   SNES_Picard   *neP;
406*028b6e76SBarry Smith   PetscErrorCode ierr;
407*028b6e76SBarry Smith 
408*028b6e76SBarry Smith   PetscFunctionBegin;
409*028b6e76SBarry Smith   snes->ops->destroy	     = SNESDestroy_Picard;
410*028b6e76SBarry Smith   snes->ops->setup	     = SNESSetUp_Picard;
411*028b6e76SBarry Smith   snes->ops->setfromoptions  = SNESSetFromOptions_Picard;
412*028b6e76SBarry Smith   snes->ops->view            = SNESView_Picard;
413*028b6e76SBarry Smith   snes->ops->solve	     = SNESSolve_Picard;
414*028b6e76SBarry Smith   snes->ops->reset           = SNESReset_Picard;
415*028b6e76SBarry Smith 
416*028b6e76SBarry Smith   snes->usesksp              = PETSC_FALSE;
417*028b6e76SBarry Smith 
418*028b6e76SBarry Smith   ierr = PetscNewLog(snes, SNES_Picard, &neP);CHKERRQ(ierr);
419*028b6e76SBarry Smith   snes->data = (void*) neP;
420*028b6e76SBarry Smith   neP->maxstep	     = 1.e8;
421*028b6e76SBarry Smith   neP->steptol       = 1.e-12;
422*028b6e76SBarry Smith   neP->type          = SNES_LS_QUADRATIC;
423*028b6e76SBarry Smith   neP->damping	     = 1.0;
424*028b6e76SBarry Smith   neP->LineSearch    = SNESLineSearchQuadratic_Picard;
425*028b6e76SBarry Smith   neP->lsP           = PETSC_NULL;
426*028b6e76SBarry Smith   neP->postcheckstep = PETSC_NULL;
427*028b6e76SBarry Smith   neP->postcheck     = PETSC_NULL;
428*028b6e76SBarry Smith   neP->precheckstep  = PETSC_NULL;
429*028b6e76SBarry Smith   neP->precheck      = PETSC_NULL;
430*028b6e76SBarry Smith 
431*028b6e76SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","SNESLineSearchSetMonitor_Picard",SNESLineSearchSetMonitor_Picard);CHKERRQ(ierr);
432*028b6e76SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","SNESLineSearchSet_Picard",SNESLineSearchSet_Picard);CHKERRQ(ierr);
433*028b6e76SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPostCheck_C","SNESLineSearchSetPostCheck_Picard",SNESLineSearchSetPostCheck_Picard);CHKERRQ(ierr);
434*028b6e76SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPreCheck_C","SNESLineSearchSetPreCheck_Picard",SNESLineSearchSetPreCheck_Picard);CHKERRQ(ierr);
435*028b6e76SBarry Smith   PetscFunctionReturn(0);
436*028b6e76SBarry Smith }
437*028b6e76SBarry Smith EXTERN_C_END
438