xref: /petsc/src/snes/impls/ntrdc/ntrdc.c (revision 41ba4c6c04ec6b90096e1e0d2d3de306864f2fe5)
1*41ba4c6cSHeeho Park 
2*41ba4c6cSHeeho Park #include <../src/snes/impls/ntrdc/ntrdcimpl.h>                /*I   "petscsnes.h"   I*/
3*41ba4c6cSHeeho Park 
4*41ba4c6cSHeeho Park typedef struct {
5*41ba4c6cSHeeho Park   SNES           snes;
6*41ba4c6cSHeeho Park   /*  Information on the regular SNES convergence test; which may have been user provided
7*41ba4c6cSHeeho Park       Copied from tr.c (maybe able to disposed, but this is a private function) - Heeho
8*41ba4c6cSHeeho Park       Same with SNESTR_KSPConverged_Private, SNESTR_KSPConverged_Destroy, and SNESTR_Converged_Private
9*41ba4c6cSHeeho Park  */
10*41ba4c6cSHeeho Park 
11*41ba4c6cSHeeho Park   PetscErrorCode (*convtest)(KSP,PetscInt,PetscReal,KSPConvergedReason*,void*);
12*41ba4c6cSHeeho Park   PetscErrorCode (*convdestroy)(void*);
13*41ba4c6cSHeeho Park   void           *convctx;
14*41ba4c6cSHeeho Park } SNES_TRDC_KSPConverged_Ctx;
15*41ba4c6cSHeeho Park 
16*41ba4c6cSHeeho Park static PetscErrorCode SNESTRDC_KSPConverged_Private(KSP ksp,PetscInt n,PetscReal rnorm,KSPConvergedReason *reason,void *cctx)
17*41ba4c6cSHeeho Park {
18*41ba4c6cSHeeho Park   SNES_TRDC_KSPConverged_Ctx  *ctx = (SNES_TRDC_KSPConverged_Ctx*)cctx;
19*41ba4c6cSHeeho Park   SNES                        snes = ctx->snes;
20*41ba4c6cSHeeho Park   SNES_NEWTONTRDC             *neP = (SNES_NEWTONTRDC*)snes->data;
21*41ba4c6cSHeeho Park   Vec                         x;
22*41ba4c6cSHeeho Park   PetscReal                   nrm;
23*41ba4c6cSHeeho Park   PetscErrorCode              ierr;
24*41ba4c6cSHeeho Park 
25*41ba4c6cSHeeho Park   PetscFunctionBegin;
26*41ba4c6cSHeeho Park   ierr = (*ctx->convtest)(ksp,n,rnorm,reason,ctx->convctx);CHKERRQ(ierr);
27*41ba4c6cSHeeho Park   if (*reason) {
28*41ba4c6cSHeeho Park     ierr = PetscInfo2(snes,"Default or user provided convergence test KSP iterations=%" PetscInt_FMT ", rnorm=%g\n",n,(double)rnorm);CHKERRQ(ierr);
29*41ba4c6cSHeeho Park   }
30*41ba4c6cSHeeho Park   /* Determine norm of solution */
31*41ba4c6cSHeeho Park   ierr = KSPBuildSolution(ksp,NULL,&x);CHKERRQ(ierr);
32*41ba4c6cSHeeho Park   ierr = VecNorm(x,NORM_2,&nrm);CHKERRQ(ierr);
33*41ba4c6cSHeeho Park   if (nrm >= neP->delta) {
34*41ba4c6cSHeeho Park     ierr    = PetscInfo2(snes,"Ending linear iteration early, delta=%g, length=%g\n",(double)neP->delta,(double)nrm);CHKERRQ(ierr);
35*41ba4c6cSHeeho Park     *reason = KSP_CONVERGED_STEP_LENGTH;
36*41ba4c6cSHeeho Park   }
37*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
38*41ba4c6cSHeeho Park }
39*41ba4c6cSHeeho Park 
40*41ba4c6cSHeeho Park static PetscErrorCode SNESTRDC_KSPConverged_Destroy(void *cctx)
41*41ba4c6cSHeeho Park {
42*41ba4c6cSHeeho Park   SNES_TRDC_KSPConverged_Ctx *ctx = (SNES_TRDC_KSPConverged_Ctx*)cctx;
43*41ba4c6cSHeeho Park   PetscErrorCode             ierr;
44*41ba4c6cSHeeho Park 
45*41ba4c6cSHeeho Park   PetscFunctionBegin;
46*41ba4c6cSHeeho Park   ierr = (*ctx->convdestroy)(ctx->convctx);CHKERRQ(ierr);
47*41ba4c6cSHeeho Park   ierr = PetscFree(ctx);CHKERRQ(ierr);
48*41ba4c6cSHeeho Park 
49*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
50*41ba4c6cSHeeho Park }
51*41ba4c6cSHeeho Park 
52*41ba4c6cSHeeho Park /* ---------------------------------------------------------------- */
53*41ba4c6cSHeeho Park /*
54*41ba4c6cSHeeho Park    SNESTRDC_Converged_Private -test convergence JUST for
55*41ba4c6cSHeeho Park    the trust region tolerance.
56*41ba4c6cSHeeho Park 
57*41ba4c6cSHeeho Park */
58*41ba4c6cSHeeho Park static PetscErrorCode SNESTRDC_Converged_Private(SNES snes,PetscInt it,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
59*41ba4c6cSHeeho Park {
60*41ba4c6cSHeeho Park   SNES_NEWTONTRDC  *neP = (SNES_NEWTONTRDC*)snes->data;
61*41ba4c6cSHeeho Park   PetscErrorCode   ierr;
62*41ba4c6cSHeeho Park 
63*41ba4c6cSHeeho Park   PetscFunctionBegin;
64*41ba4c6cSHeeho Park   *reason = SNES_CONVERGED_ITERATING;
65*41ba4c6cSHeeho Park   if (neP->delta < xnorm * snes->deltatol) {
66*41ba4c6cSHeeho Park     ierr    = PetscInfo3(snes,"Diverged due to too small a trust region %g<%g*%g\n",(double)neP->delta,(double)xnorm,(double)snes->deltatol);CHKERRQ(ierr);
67*41ba4c6cSHeeho Park     *reason = SNES_DIVERGED_TR_DELTA;
68*41ba4c6cSHeeho Park   } else if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) {
69*41ba4c6cSHeeho Park     ierr    = PetscInfo1(snes,"Exceeded maximum number of function evaluations: %" PetscInt_FMT "\n",snes->max_funcs);CHKERRQ(ierr);
70*41ba4c6cSHeeho Park     *reason = SNES_DIVERGED_FUNCTION_COUNT;
71*41ba4c6cSHeeho Park   }
72*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
73*41ba4c6cSHeeho Park }
74*41ba4c6cSHeeho Park 
75*41ba4c6cSHeeho Park /*@
76*41ba4c6cSHeeho Park   SNESNewtonTRDCGetRhoFlag - Get whether the solution update is within the trust-region.
77*41ba4c6cSHeeho Park 
78*41ba4c6cSHeeho Park   Input Parameters:
79*41ba4c6cSHeeho Park . snes - the nonlinear solver object
80*41ba4c6cSHeeho Park 
81*41ba4c6cSHeeho Park   Output Parameters:
82*41ba4c6cSHeeho Park . rho_flag: PETSC_TRUE if the solution update is in the trust-region; otherwise, PETSC_FALSE
83*41ba4c6cSHeeho Park 
84*41ba4c6cSHeeho Park   Level: developer
85*41ba4c6cSHeeho Park 
86*41ba4c6cSHeeho Park @*/
87*41ba4c6cSHeeho Park PetscErrorCode  SNESNewtonTRDCGetRhoFlag(SNES snes,PetscBool *rho_flag)
88*41ba4c6cSHeeho Park {
89*41ba4c6cSHeeho Park   SNES_NEWTONTRDC  *tr = (SNES_NEWTONTRDC*)snes->data;
90*41ba4c6cSHeeho Park 
91*41ba4c6cSHeeho Park   PetscFunctionBegin;
92*41ba4c6cSHeeho Park   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
93*41ba4c6cSHeeho Park   PetscValidBoolPointer(rho_flag,2);
94*41ba4c6cSHeeho Park   *rho_flag = tr->rho_satisfied;
95*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
96*41ba4c6cSHeeho Park }
97*41ba4c6cSHeeho Park 
98*41ba4c6cSHeeho Park /*@C
99*41ba4c6cSHeeho Park    SNESNewtonTRDCSetPreCheck - Sets a user function that is called before the search step has been determined.
100*41ba4c6cSHeeho Park        Allows the user a chance to change or override the trust region decision.
101*41ba4c6cSHeeho Park 
102*41ba4c6cSHeeho Park    Logically Collective on snes
103*41ba4c6cSHeeho Park 
104*41ba4c6cSHeeho Park    Input Parameters:
105*41ba4c6cSHeeho Park +  snes - the nonlinear solver object
106*41ba4c6cSHeeho Park .  func - [optional] function evaluation routine, see SNESNewtonTRDCPreCheck()  for the calling sequence
107*41ba4c6cSHeeho Park -  ctx  - [optional] user-defined context for private data for the function evaluation routine (may be NULL)
108*41ba4c6cSHeeho Park 
109*41ba4c6cSHeeho Park    Level: intermediate
110*41ba4c6cSHeeho Park 
111*41ba4c6cSHeeho Park    Note: This function is called BEFORE the function evaluation within the SNESNEWTONTRDC solver.
112*41ba4c6cSHeeho Park 
113*41ba4c6cSHeeho Park .seealso: SNESNewtonTRDCPreCheck(), SNESNewtonTRDCGetPreCheck(), SNESNewtonTRDCSetPostCheck(), SNESNewtonTRDCGetPostCheck()
114*41ba4c6cSHeeho Park @*/
115*41ba4c6cSHeeho Park PetscErrorCode  SNESNewtonTRDCSetPreCheck(SNES snes, PetscErrorCode (*func)(SNES,Vec,Vec,PetscBool*,void*),void *ctx)
116*41ba4c6cSHeeho Park {
117*41ba4c6cSHeeho Park   SNES_NEWTONTRDC  *tr = (SNES_NEWTONTRDC*)snes->data;
118*41ba4c6cSHeeho Park 
119*41ba4c6cSHeeho Park   PetscFunctionBegin;
120*41ba4c6cSHeeho Park   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
121*41ba4c6cSHeeho Park   if (func) tr->precheck    = func;
122*41ba4c6cSHeeho Park   if (ctx)  tr->precheckctx = ctx;
123*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
124*41ba4c6cSHeeho Park }
125*41ba4c6cSHeeho Park 
126*41ba4c6cSHeeho Park /*@C
127*41ba4c6cSHeeho Park    SNESNewtonTRDCGetPreCheck - Gets the pre-check function
128*41ba4c6cSHeeho Park 
129*41ba4c6cSHeeho Park    Not collective
130*41ba4c6cSHeeho Park 
131*41ba4c6cSHeeho Park    Input Parameter:
132*41ba4c6cSHeeho Park .  snes - the nonlinear solver context
133*41ba4c6cSHeeho Park 
134*41ba4c6cSHeeho Park    Output Parameters:
135*41ba4c6cSHeeho Park +  func - [optional] function evaluation routine, see for the calling sequence SNESNewtonTRDCPreCheck()
136*41ba4c6cSHeeho Park -  ctx  - [optional] user-defined context for private data for the function evaluation routine (may be NULL)
137*41ba4c6cSHeeho Park 
138*41ba4c6cSHeeho Park    Level: intermediate
139*41ba4c6cSHeeho Park 
140*41ba4c6cSHeeho Park .seealso: SNESNewtonTRDCSetPreCheck(), SNESNewtonTRDCPreCheck()
141*41ba4c6cSHeeho Park @*/
142*41ba4c6cSHeeho Park PetscErrorCode  SNESNewtonTRDCGetPreCheck(SNES snes, PetscErrorCode (**func)(SNES,Vec,Vec,PetscBool*,void*),void **ctx)
143*41ba4c6cSHeeho Park {
144*41ba4c6cSHeeho Park   SNES_NEWTONTRDC  *tr = (SNES_NEWTONTRDC*)snes->data;
145*41ba4c6cSHeeho Park 
146*41ba4c6cSHeeho Park   PetscFunctionBegin;
147*41ba4c6cSHeeho Park   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
148*41ba4c6cSHeeho Park   if (func) *func = tr->precheck;
149*41ba4c6cSHeeho Park   if (ctx)  *ctx  = tr->precheckctx;
150*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
151*41ba4c6cSHeeho Park }
152*41ba4c6cSHeeho Park 
153*41ba4c6cSHeeho Park /*@C
154*41ba4c6cSHeeho Park    SNESNewtonTRDCSetPostCheck - Sets a user function that is called after the search step has been determined but before the next
155*41ba4c6cSHeeho Park        function evaluation. Allows the user a chance to change or override the decision of the line search routine
156*41ba4c6cSHeeho Park 
157*41ba4c6cSHeeho Park    Logically Collective on snes
158*41ba4c6cSHeeho Park 
159*41ba4c6cSHeeho Park    Input Parameters:
160*41ba4c6cSHeeho Park +  snes - the nonlinear solver object
161*41ba4c6cSHeeho Park .  func - [optional] function evaluation routine, see SNESNewtonTRDCPostCheck()  for the calling sequence
162*41ba4c6cSHeeho Park -  ctx  - [optional] user-defined context for private data for the function evaluation routine (may be NULL)
163*41ba4c6cSHeeho Park 
164*41ba4c6cSHeeho Park    Level: intermediate
165*41ba4c6cSHeeho Park 
166*41ba4c6cSHeeho Park    Note: This function is called BEFORE the function evaluation within the SNESNEWTONTRDC solver while the function set in
167*41ba4c6cSHeeho Park    SNESLineSearchSetPostCheck() is called AFTER the function evaluation.
168*41ba4c6cSHeeho Park 
169*41ba4c6cSHeeho Park .seealso: SNESNewtonTRDCPostCheck(), SNESNewtonTRDCGetPostCheck()
170*41ba4c6cSHeeho Park @*/
171*41ba4c6cSHeeho Park PetscErrorCode  SNESNewtonTRDCSetPostCheck(SNES snes,PetscErrorCode (*func)(SNES,Vec,Vec,Vec,PetscBool*,PetscBool*,void*),void *ctx)
172*41ba4c6cSHeeho Park {
173*41ba4c6cSHeeho Park   SNES_NEWTONTRDC  *tr = (SNES_NEWTONTRDC*)snes->data;
174*41ba4c6cSHeeho Park 
175*41ba4c6cSHeeho Park   PetscFunctionBegin;
176*41ba4c6cSHeeho Park   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
177*41ba4c6cSHeeho Park   if (func) tr->postcheck    = func;
178*41ba4c6cSHeeho Park   if (ctx)  tr->postcheckctx = ctx;
179*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
180*41ba4c6cSHeeho Park }
181*41ba4c6cSHeeho Park 
182*41ba4c6cSHeeho Park /*@C
183*41ba4c6cSHeeho Park    SNESNewtonTRDCGetPostCheck - Gets the post-check function
184*41ba4c6cSHeeho Park 
185*41ba4c6cSHeeho Park    Not collective
186*41ba4c6cSHeeho Park 
187*41ba4c6cSHeeho Park    Input Parameter:
188*41ba4c6cSHeeho Park .  snes - the nonlinear solver context
189*41ba4c6cSHeeho Park 
190*41ba4c6cSHeeho Park    Output Parameters:
191*41ba4c6cSHeeho Park +  func - [optional] function evaluation routine, see for the calling sequence SNESNewtonTRDCPostCheck()
192*41ba4c6cSHeeho Park -  ctx  - [optional] user-defined context for private data for the function evaluation routine (may be NULL)
193*41ba4c6cSHeeho Park 
194*41ba4c6cSHeeho Park    Level: intermediate
195*41ba4c6cSHeeho Park 
196*41ba4c6cSHeeho Park .seealso: SNESNewtonTRDCSetPostCheck(), SNESNewtonTRDCPostCheck()
197*41ba4c6cSHeeho Park @*/
198*41ba4c6cSHeeho Park PetscErrorCode  SNESNewtonTRDCGetPostCheck(SNES snes,PetscErrorCode (**func)(SNES,Vec,Vec,Vec,PetscBool*,PetscBool*,void*),void **ctx)
199*41ba4c6cSHeeho Park {
200*41ba4c6cSHeeho Park   SNES_NEWTONTRDC  *tr = (SNES_NEWTONTRDC*)snes->data;
201*41ba4c6cSHeeho Park 
202*41ba4c6cSHeeho Park   PetscFunctionBegin;
203*41ba4c6cSHeeho Park   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
204*41ba4c6cSHeeho Park   if (func) *func = tr->postcheck;
205*41ba4c6cSHeeho Park   if (ctx)  *ctx  = tr->postcheckctx;
206*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
207*41ba4c6cSHeeho Park }
208*41ba4c6cSHeeho Park 
209*41ba4c6cSHeeho Park /*@C
210*41ba4c6cSHeeho Park    SNESNewtonTRDCPreCheck - Called before the step has been determined in SNESNEWTONTRDC
211*41ba4c6cSHeeho Park 
212*41ba4c6cSHeeho Park    Logically Collective on snes
213*41ba4c6cSHeeho Park 
214*41ba4c6cSHeeho Park    Input Parameters:
215*41ba4c6cSHeeho Park +  snes - the solver
216*41ba4c6cSHeeho Park .  X - The last solution
217*41ba4c6cSHeeho Park -  Y - The step direction
218*41ba4c6cSHeeho Park 
219*41ba4c6cSHeeho Park    Output Parameters:
220*41ba4c6cSHeeho Park .  changed_Y - Indicator that the step direction Y has been changed.
221*41ba4c6cSHeeho Park 
222*41ba4c6cSHeeho Park    Level: developer
223*41ba4c6cSHeeho Park 
224*41ba4c6cSHeeho Park .seealso: SNESNewtonTRDCSetPreCheck(), SNESNewtonTRDCGetPreCheck()
225*41ba4c6cSHeeho Park @*/
226*41ba4c6cSHeeho Park static PetscErrorCode SNESNewtonTRDCPreCheck(SNES snes,Vec X,Vec Y,PetscBool *changed_Y)
227*41ba4c6cSHeeho Park {
228*41ba4c6cSHeeho Park   SNES_NEWTONTRDC  *tr = (SNES_NEWTONTRDC*)snes->data;
229*41ba4c6cSHeeho Park   PetscErrorCode   ierr;
230*41ba4c6cSHeeho Park 
231*41ba4c6cSHeeho Park   PetscFunctionBegin;
232*41ba4c6cSHeeho Park   *changed_Y = PETSC_FALSE;
233*41ba4c6cSHeeho Park   if (tr->precheck) {
234*41ba4c6cSHeeho Park     ierr = (*tr->precheck)(snes,X,Y,changed_Y,tr->precheckctx);CHKERRQ(ierr);
235*41ba4c6cSHeeho Park     PetscValidLogicalCollectiveBool(snes,*changed_Y,4);
236*41ba4c6cSHeeho Park   }
237*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
238*41ba4c6cSHeeho Park }
239*41ba4c6cSHeeho Park 
240*41ba4c6cSHeeho Park /*@C
241*41ba4c6cSHeeho Park    SNESNewtonTRDCPostCheck - Called after the step has been determined in SNESNEWTONTRDC but before the function evaluation
242*41ba4c6cSHeeho Park 
243*41ba4c6cSHeeho Park    Logically Collective on snes
244*41ba4c6cSHeeho Park 
245*41ba4c6cSHeeho Park    Input Parameters:
246*41ba4c6cSHeeho Park +  snes - the solver.  X - The last solution
247*41ba4c6cSHeeho Park .  Y - The full step direction
248*41ba4c6cSHeeho Park -  W - The updated solution, W = X - Y
249*41ba4c6cSHeeho Park 
250*41ba4c6cSHeeho Park    Output Parameters:
251*41ba4c6cSHeeho Park +  changed_Y - indicator if step has been changed
252*41ba4c6cSHeeho Park -  changed_W - Indicator if the new candidate solution W has been changed.
253*41ba4c6cSHeeho Park 
254*41ba4c6cSHeeho Park    Notes:
255*41ba4c6cSHeeho Park      If Y is changed then W is recomputed as X - Y
256*41ba4c6cSHeeho Park 
257*41ba4c6cSHeeho Park    Level: developer
258*41ba4c6cSHeeho Park 
259*41ba4c6cSHeeho Park .seealso: SNESNewtonTRDCSetPostCheck(), SNESNewtonTRDCGetPostCheck()
260*41ba4c6cSHeeho Park @*/
261*41ba4c6cSHeeho Park static PetscErrorCode SNESNewtonTRDCPostCheck(SNES snes,Vec X,Vec Y,Vec W,PetscBool *changed_Y,PetscBool *changed_W)
262*41ba4c6cSHeeho Park {
263*41ba4c6cSHeeho Park   SNES_NEWTONTRDC  *tr = (SNES_NEWTONTRDC*)snes->data;
264*41ba4c6cSHeeho Park   PetscErrorCode   ierr;
265*41ba4c6cSHeeho Park 
266*41ba4c6cSHeeho Park   PetscFunctionBegin;
267*41ba4c6cSHeeho Park   *changed_Y = PETSC_FALSE;
268*41ba4c6cSHeeho Park   *changed_W = PETSC_FALSE;
269*41ba4c6cSHeeho Park   if (tr->postcheck) {
270*41ba4c6cSHeeho Park     ierr = (*tr->postcheck)(snes,X,Y,W,changed_Y,changed_W,tr->postcheckctx);CHKERRQ(ierr);
271*41ba4c6cSHeeho Park     PetscValidLogicalCollectiveBool(snes,*changed_Y,5);
272*41ba4c6cSHeeho Park     PetscValidLogicalCollectiveBool(snes,*changed_W,6);
273*41ba4c6cSHeeho Park   }
274*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
275*41ba4c6cSHeeho Park }
276*41ba4c6cSHeeho Park 
277*41ba4c6cSHeeho Park /*
278*41ba4c6cSHeeho Park    SNESSolve_NEWTONTRDC - Implements Newton's Method with trust-region subproblem and adds dogleg Cauchy
279*41ba4c6cSHeeho Park    (Steepest Descent direction) step and direction if the trust region is not satisfied for solving system of
280*41ba4c6cSHeeho Park    nonlinear equations
281*41ba4c6cSHeeho Park 
282*41ba4c6cSHeeho Park */
283*41ba4c6cSHeeho Park static PetscErrorCode SNESSolve_NEWTONTRDC(SNES snes)
284*41ba4c6cSHeeho Park {
285*41ba4c6cSHeeho Park   SNES_NEWTONTRDC            *neP = (SNES_NEWTONTRDC*)snes->data;
286*41ba4c6cSHeeho Park   Vec                        X,F,Y,G,W,GradF,YNtmp;
287*41ba4c6cSHeeho Park   Vec                        YCtmp;
288*41ba4c6cSHeeho Park   Mat                        jac;
289*41ba4c6cSHeeho Park   PetscErrorCode             ierr;
290*41ba4c6cSHeeho Park   PetscInt                   maxits,i,j,lits,inner_count,bs;
291*41ba4c6cSHeeho Park   PetscReal                  rho,fnorm,gnorm,xnorm=0,delta,ynorm,temp_xnorm,temp_ynorm;  /* TRDC inner iteration */
292*41ba4c6cSHeeho Park   PetscReal                  inorms[99]; /* need to make it dynamic eventually, fixed max block size of 99 for now */
293*41ba4c6cSHeeho Park   PetscReal                  deltaM,ynnorm,f0,mp,gTy,g,yTHy;  /* rho calculation */
294*41ba4c6cSHeeho Park   PetscReal                  auk,gfnorm,ycnorm,c0,c1,c2,tau,tau_pos,tau_neg,gTBg;  /* Cauchy Point */
295*41ba4c6cSHeeho Park   KSP                        ksp;
296*41ba4c6cSHeeho Park   SNESConvergedReason        reason = SNES_CONVERGED_ITERATING;
297*41ba4c6cSHeeho Park   PetscBool                  breakout = PETSC_FALSE;
298*41ba4c6cSHeeho Park   SNES_TRDC_KSPConverged_Ctx *ctx;
299*41ba4c6cSHeeho Park   PetscErrorCode             (*convtest)(KSP,PetscInt,PetscReal,KSPConvergedReason*,void*),(*convdestroy)(void*);
300*41ba4c6cSHeeho Park   void                       *convctx;
301*41ba4c6cSHeeho Park 
302*41ba4c6cSHeeho Park   PetscFunctionBegin;
303*41ba4c6cSHeeho Park   maxits = snes->max_its;               /* maximum number of iterations */
304*41ba4c6cSHeeho Park   X      = snes->vec_sol;               /* solution vector */
305*41ba4c6cSHeeho Park   F      = snes->vec_func;              /* residual vector */
306*41ba4c6cSHeeho Park   Y      = snes->work[0];               /* update vector */
307*41ba4c6cSHeeho Park   G      = snes->work[1];               /* updated residual */
308*41ba4c6cSHeeho Park   W      = snes->work[2];               /* temporary vector */
309*41ba4c6cSHeeho Park   GradF  = snes->work[3];               /* grad f = J^T F */
310*41ba4c6cSHeeho Park   YNtmp  = snes->work[4];               /* Newton solution */
311*41ba4c6cSHeeho Park   YCtmp  = snes->work[5];               /* Cauchy solution */
312*41ba4c6cSHeeho Park 
313*41ba4c6cSHeeho Park   if (snes->xl || snes->xu || snes->ops->computevariablebounds) SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
314*41ba4c6cSHeeho Park 
315*41ba4c6cSHeeho Park   ierr = VecGetBlockSize(YNtmp,&bs);CHKERRQ(ierr);
316*41ba4c6cSHeeho Park 
317*41ba4c6cSHeeho Park   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
318*41ba4c6cSHeeho Park   snes->iter = 0;
319*41ba4c6cSHeeho Park   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
320*41ba4c6cSHeeho Park 
321*41ba4c6cSHeeho Park   /* Set the linear stopping criteria to use the More' trick. From tr.c */
322*41ba4c6cSHeeho Park   ierr = SNESGetKSP(snes,&ksp);CHKERRQ(ierr);
323*41ba4c6cSHeeho Park   ierr = KSPGetConvergenceTest(ksp,&convtest,&convctx,&convdestroy);CHKERRQ(ierr);
324*41ba4c6cSHeeho Park   if (convtest != SNESTRDC_KSPConverged_Private) {
325*41ba4c6cSHeeho Park     ierr                  = PetscNew(&ctx);CHKERRQ(ierr);
326*41ba4c6cSHeeho Park     ctx->snes             = snes;
327*41ba4c6cSHeeho Park     ierr                  = KSPGetAndClearConvergenceTest(ksp,&ctx->convtest,&ctx->convctx,&ctx->convdestroy);CHKERRQ(ierr);
328*41ba4c6cSHeeho Park     ierr                  = KSPSetConvergenceTest(ksp,SNESTRDC_KSPConverged_Private,ctx,SNESTRDC_KSPConverged_Destroy);CHKERRQ(ierr);
329*41ba4c6cSHeeho Park     ierr                  = PetscInfo(snes,"Using Krylov convergence test SNESTRDC_KSPConverged_Private\n");CHKERRQ(ierr);
330*41ba4c6cSHeeho Park   }
331*41ba4c6cSHeeho Park 
332*41ba4c6cSHeeho Park   if (!snes->vec_func_init_set) {
333*41ba4c6cSHeeho Park     ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);          /* F(X) */
334*41ba4c6cSHeeho Park   } else snes->vec_func_init_set = PETSC_FALSE;
335*41ba4c6cSHeeho Park 
336*41ba4c6cSHeeho Park   ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);             /* fnorm <- || F || */
337*41ba4c6cSHeeho Park   SNESCheckFunctionNorm(snes,fnorm);
338*41ba4c6cSHeeho Park   ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr);             /* xnorm <- || X || */
339*41ba4c6cSHeeho Park 
340*41ba4c6cSHeeho Park   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
341*41ba4c6cSHeeho Park   snes->norm = fnorm;
342*41ba4c6cSHeeho Park   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
343*41ba4c6cSHeeho Park   delta      = xnorm ? neP->delta0*xnorm : neP->delta0;  /* initial trust region size scaled by xnorm */
344*41ba4c6cSHeeho Park   deltaM     = xnorm ? neP->deltaM*xnorm : neP->deltaM;  /* maximum trust region size scaled by xnorm */
345*41ba4c6cSHeeho Park   neP->delta = delta;
346*41ba4c6cSHeeho Park   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
347*41ba4c6cSHeeho Park   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
348*41ba4c6cSHeeho Park 
349*41ba4c6cSHeeho Park   neP->rho_satisfied = PETSC_FALSE;
350*41ba4c6cSHeeho Park 
351*41ba4c6cSHeeho Park   /* test convergence */
352*41ba4c6cSHeeho Park   ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
353*41ba4c6cSHeeho Park   if (snes->reason) PetscFunctionReturn(0);
354*41ba4c6cSHeeho Park 
355*41ba4c6cSHeeho Park   for (i=0; i<maxits; i++) {
356*41ba4c6cSHeeho Park     PetscBool changed_y;
357*41ba4c6cSHeeho Park     PetscBool changed_w;
358*41ba4c6cSHeeho Park 
359*41ba4c6cSHeeho Park     /* dogleg method */
360*41ba4c6cSHeeho Park     ierr = SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr);
361*41ba4c6cSHeeho Park     SNESCheckJacobianDomainerror(snes);
362*41ba4c6cSHeeho Park     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian);CHKERRQ(ierr);
363*41ba4c6cSHeeho Park     ierr = KSPSolve(snes->ksp,F,YNtmp);CHKERRQ(ierr);   /* Quasi Newton Solution */
364*41ba4c6cSHeeho Park     SNESCheckKSPSolve(snes);  /* this is necessary but old tr.c did not have it*/
365*41ba4c6cSHeeho Park     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
366*41ba4c6cSHeeho Park     ierr = SNESGetJacobian(snes,&jac,NULL,NULL,NULL);CHKERRQ(ierr);
367*41ba4c6cSHeeho Park 
368*41ba4c6cSHeeho Park     /* rescale Jacobian, Newton solution update, and re-calculate delta for multiphase (multivariable)
369*41ba4c6cSHeeho Park        for inner iteration and Cauchy direction calculation
370*41ba4c6cSHeeho Park     */
371*41ba4c6cSHeeho Park     if (bs > 1 && neP->auto_scale_multiphase) {
372*41ba4c6cSHeeho Park       ierr = VecStrideNormAll(YNtmp,NORM_INFINITY,inorms);CHKERRQ(ierr);
373*41ba4c6cSHeeho Park       for (j=0; j<bs; j++) {
374*41ba4c6cSHeeho Park         if (neP->auto_scale_max > 1.0) {
375*41ba4c6cSHeeho Park           if (inorms[j] < 1.0/neP->auto_scale_max) {
376*41ba4c6cSHeeho Park             inorms[j] = 1.0/neP->auto_scale_max;
377*41ba4c6cSHeeho Park           }
378*41ba4c6cSHeeho Park         }
379*41ba4c6cSHeeho Park         ierr = VecStrideSet(W,j,inorms[j]);CHKERRQ(ierr);
380*41ba4c6cSHeeho Park         ierr = VecStrideScale(YNtmp,j,1.0/inorms[j]);
381*41ba4c6cSHeeho Park         ierr = VecStrideScale(X,j,1.0/inorms[j]);
382*41ba4c6cSHeeho Park       }
383*41ba4c6cSHeeho Park       ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr);
384*41ba4c6cSHeeho Park       if (i == 0) {
385*41ba4c6cSHeeho Park         delta = neP->delta0*xnorm;
386*41ba4c6cSHeeho Park       } else {
387*41ba4c6cSHeeho Park         delta = neP->delta*xnorm;
388*41ba4c6cSHeeho Park       }
389*41ba4c6cSHeeho Park       deltaM = neP->deltaM*xnorm;
390*41ba4c6cSHeeho Park       ierr = MatDiagonalScale(jac,PETSC_NULL,W);CHKERRQ(ierr);
391*41ba4c6cSHeeho Park     }
392*41ba4c6cSHeeho Park 
393*41ba4c6cSHeeho Park     /* calculating GradF of minimization function */
394*41ba4c6cSHeeho Park     ierr = MatMultTranspose(jac,F,GradF);CHKERRQ(ierr);  /* grad f = J^T F */
395*41ba4c6cSHeeho Park     ierr = VecNorm(YNtmp,NORM_2,&ynnorm);CHKERRQ(ierr);  /* ynnorm <- || Y_newton || */
396*41ba4c6cSHeeho Park 
397*41ba4c6cSHeeho Park     inner_count = 0;
398*41ba4c6cSHeeho Park     neP->rho_satisfied = PETSC_FALSE;
399*41ba4c6cSHeeho Park     while (1) {
400*41ba4c6cSHeeho Park       if (ynnorm <= delta) {  /* see if the Newton solution is within the trust region */
401*41ba4c6cSHeeho Park         ierr = VecCopy(YNtmp,Y);CHKERRQ(ierr);
402*41ba4c6cSHeeho Park       } else if (neP->use_cauchy) { /* use Cauchy direction if enabled */
403*41ba4c6cSHeeho Park         ierr = MatMult(jac,GradF,W);CHKERRQ(ierr);
404*41ba4c6cSHeeho Park         ierr = VecDotRealPart(W,W,&gTBg);CHKERRQ(ierr);  /* completes GradF^T J^T J GradF */
405*41ba4c6cSHeeho Park         ierr = VecNorm(GradF,NORM_2,&gfnorm);CHKERRQ(ierr);  /* grad f norm <- || grad f || */
406*41ba4c6cSHeeho Park         if (gTBg <= 0.0) {
407*41ba4c6cSHeeho Park           auk = PETSC_MAX_REAL;
408*41ba4c6cSHeeho Park         } else {
409*41ba4c6cSHeeho Park           auk = PetscSqr(gfnorm)/gTBg;
410*41ba4c6cSHeeho Park         }
411*41ba4c6cSHeeho Park         auk  = PetscMin(delta/gfnorm,auk);
412*41ba4c6cSHeeho Park         ierr = VecCopy(GradF,YCtmp);CHKERRQ(ierr);  /* this could be improved */
413*41ba4c6cSHeeho Park         ierr = VecScale(YCtmp,auk);CHKERRQ(ierr);  /* YCtmp, Cauchy solution*/
414*41ba4c6cSHeeho Park         ierr = VecNorm(YCtmp,NORM_2,&ycnorm);CHKERRQ(ierr);  /* ycnorm <- || Y_cauchy || */
415*41ba4c6cSHeeho Park         if (ycnorm >= delta) {  /* see if the Cauchy solution meets the criteria */
416*41ba4c6cSHeeho Park             ierr = VecCopy(YCtmp,Y);CHKERRQ(ierr);
417*41ba4c6cSHeeho Park             ierr = PetscInfo3(snes,"DL evaluated. delta: %8.4e, ynnorm: %8.4e, ycnorm: %8.4e\n",(double)delta,(double)ynnorm,(double)ycnorm);CHKERRQ(ierr);
418*41ba4c6cSHeeho Park         } else {  /* take ratio, tau, of Cauchy and Newton direction and step */
419*41ba4c6cSHeeho Park           ierr    = VecAXPY(YNtmp,-1.0,YCtmp);CHKERRQ(ierr);  /* YCtmp = A, YNtmp = B */
420*41ba4c6cSHeeho Park           ierr    = VecNorm(YNtmp,NORM_2,&c0);CHKERRQ(ierr);  /* this could be improved */
421*41ba4c6cSHeeho Park           c0      = PetscSqr(c0);
422*41ba4c6cSHeeho Park           ierr    = VecDotRealPart(YCtmp,YNtmp,&c1);CHKERRQ(ierr);
423*41ba4c6cSHeeho Park           c1      = 2.0*c1;
424*41ba4c6cSHeeho Park           ierr    = VecNorm(YCtmp,NORM_2,&c2);CHKERRQ(ierr);  /* this could be improved */
425*41ba4c6cSHeeho Park           c2      = PetscSqr(c2) - PetscSqr(delta);
426*41ba4c6cSHeeho Park           tau_pos = (c1 + PetscSqrtReal(PetscSqr(c1) - 4.*c0*c2))/(2.*c0); /* quadratic formula */
427*41ba4c6cSHeeho Park           tau_neg = (c1 - PetscSqrtReal(PetscSqr(c1) - 4.*c0*c2))/(2.*c0);
428*41ba4c6cSHeeho Park           tau     = PetscMax(tau_pos, tau_neg);  /* can tau_neg > tau_pos? I don't think so, but just in case. */
429*41ba4c6cSHeeho Park           ierr    = PetscInfo3(snes,"DL evaluated. tau: %8.4e, ynnorm: %8.4e, ycnorm: %8.4e\n",(double)tau,(double)ynnorm,(double)ycnorm);CHKERRQ(ierr);
430*41ba4c6cSHeeho Park           ierr    = VecWAXPY(W,tau,YNtmp,YCtmp);CHKERRQ(ierr);
431*41ba4c6cSHeeho Park           ierr    = VecAXPY(W,-tau,YCtmp);CHKERRQ(ierr);
432*41ba4c6cSHeeho Park           ierr    = VecCopy(W, Y);CHKERRQ(ierr); /* this could be improved */
433*41ba4c6cSHeeho Park         }
434*41ba4c6cSHeeho Park       } else {
435*41ba4c6cSHeeho Park         /* if Cauchy is disabled, only use Newton direction */
436*41ba4c6cSHeeho Park         auk = delta/ynnorm;
437*41ba4c6cSHeeho Park         ierr = VecScale(YNtmp,auk);CHKERRQ(ierr);
438*41ba4c6cSHeeho Park         ierr = VecCopy(YNtmp,Y);CHKERRQ(ierr); /* this could be improved (many VecCopy, VecNorm)*/
439*41ba4c6cSHeeho Park       }
440*41ba4c6cSHeeho Park 
441*41ba4c6cSHeeho Park       ierr = VecNorm(Y,NORM_2,&ynorm);CHKERRQ(ierr);  /* compute the final ynorm  */
442*41ba4c6cSHeeho Park       f0 = 0.5*PetscSqr(fnorm);  /* minimizing function f(X) */
443*41ba4c6cSHeeho Park       ierr = MatMult(jac,Y,W);CHKERRQ(ierr);
444*41ba4c6cSHeeho Park       ierr = VecDotRealPart(W,W,&yTHy);CHKERRQ(ierr);  /* completes GradY^T J^T J GradY */
445*41ba4c6cSHeeho Park       ierr = VecDotRealPart(GradF,Y,&gTy);CHKERRQ(ierr);
446*41ba4c6cSHeeho Park       mp = f0 - gTy + 0.5*yTHy;  /* quadratic model to satisfy, -gTy because our update is X-Y*/
447*41ba4c6cSHeeho Park 
448*41ba4c6cSHeeho Park       /* scale back solution update */
449*41ba4c6cSHeeho Park       if (bs > 1 && neP->auto_scale_multiphase) {
450*41ba4c6cSHeeho Park         for (j=0; j<bs; j++) {
451*41ba4c6cSHeeho Park           ierr = VecStrideScale(Y,j,inorms[j]);
452*41ba4c6cSHeeho Park           if (inner_count == 0) {
453*41ba4c6cSHeeho Park             /* TRDC inner algorithm does not need scaled X after calculating delta in the outer iteration */
454*41ba4c6cSHeeho Park             /* need to scale back X to match Y and provide proper update to the external code */
455*41ba4c6cSHeeho Park             ierr = VecStrideScale(X,j,inorms[j]);
456*41ba4c6cSHeeho Park           }
457*41ba4c6cSHeeho Park         }
458*41ba4c6cSHeeho Park         if (inner_count == 0) {ierr = VecNorm(X,NORM_2,&temp_xnorm);CHKERRQ(ierr);}  /* only in the first iteration */
459*41ba4c6cSHeeho Park         ierr = VecNorm(Y,NORM_2,&temp_ynorm);CHKERRQ(ierr);
460*41ba4c6cSHeeho Park       } else {
461*41ba4c6cSHeeho Park         temp_xnorm = xnorm;
462*41ba4c6cSHeeho Park         temp_ynorm = ynorm;
463*41ba4c6cSHeeho Park       }
464*41ba4c6cSHeeho Park       inner_count++;
465*41ba4c6cSHeeho Park 
466*41ba4c6cSHeeho Park       /* Evaluate the solution to meet the improvement ratio criteria */
467*41ba4c6cSHeeho Park       ierr = SNESNewtonTRDCPreCheck(snes,X,Y,&changed_y);CHKERRQ(ierr);
468*41ba4c6cSHeeho Park       ierr = VecWAXPY(W,-1.0,Y,X);CHKERRQ(ierr);
469*41ba4c6cSHeeho Park       ierr = SNESNewtonTRDCPostCheck(snes,X,Y,W,&changed_y,&changed_w);CHKERRQ(ierr);
470*41ba4c6cSHeeho Park       if (changed_y) {ierr = VecWAXPY(W,-1.0,Y,X);CHKERRQ(ierr);}
471*41ba4c6cSHeeho Park       ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
472*41ba4c6cSHeeho Park       ierr = SNESComputeFunction(snes,W,G);CHKERRQ(ierr); /*  F(X-Y) = G */
473*41ba4c6cSHeeho Park       ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr);      /* gnorm <- || g || */
474*41ba4c6cSHeeho Park       SNESCheckFunctionNorm(snes,gnorm);
475*41ba4c6cSHeeho Park       g = 0.5*PetscSqr(gnorm); /* minimizing function g(W) */
476*41ba4c6cSHeeho Park       if (f0 == mp) rho = 0.0;
477*41ba4c6cSHeeho Park       else rho = (f0 - g)/(f0 - mp);  /* actual improvement over predicted improvement */
478*41ba4c6cSHeeho Park 
479*41ba4c6cSHeeho Park       if (rho < neP->eta2) {
480*41ba4c6cSHeeho Park         delta *= neP->t1;  /* shrink the region */
481*41ba4c6cSHeeho Park       } else if (rho > neP->eta3) {
482*41ba4c6cSHeeho Park         delta = PetscMin(neP->t2*delta,deltaM); /* expand the region, but not greater than deltaM */
483*41ba4c6cSHeeho Park       }
484*41ba4c6cSHeeho Park 
485*41ba4c6cSHeeho Park       neP->delta = delta;
486*41ba4c6cSHeeho Park       if (rho >= neP->eta1) {
487*41ba4c6cSHeeho Park         /* unscale delta and xnorm before going to the next outer iteration */
488*41ba4c6cSHeeho Park         if (bs > 1 && neP->auto_scale_multiphase) {
489*41ba4c6cSHeeho Park           neP->delta = delta/xnorm;
490*41ba4c6cSHeeho Park           xnorm      = temp_xnorm;
491*41ba4c6cSHeeho Park           ynorm      = temp_ynorm;
492*41ba4c6cSHeeho Park         }
493*41ba4c6cSHeeho Park         neP->rho_satisfied = PETSC_TRUE;
494*41ba4c6cSHeeho Park         break;  /* the improvement ratio is satisfactory */
495*41ba4c6cSHeeho Park       }
496*41ba4c6cSHeeho Park       ierr = PetscInfo(snes,"Trying again in smaller region\n");CHKERRQ(ierr);
497*41ba4c6cSHeeho Park 
498*41ba4c6cSHeeho Park       /* check to see if progress is hopeless */
499*41ba4c6cSHeeho Park       neP->itflag = PETSC_FALSE;
500*41ba4c6cSHeeho Park       /* both delta, ynorm, and xnorm are either scaled or unscaled */
501*41ba4c6cSHeeho Park       ierr        = SNESTRDC_Converged_Private(snes,snes->iter,xnorm,ynorm,fnorm,&reason,snes->cnvP);CHKERRQ(ierr);
502*41ba4c6cSHeeho Park       if (!reason) {
503*41ba4c6cSHeeho Park          /* temp_xnorm, temp_ynorm is always unscaled */
504*41ba4c6cSHeeho Park          /* also the inner iteration already calculated the Jacobian and solved the matrix */
505*41ba4c6cSHeeho Park          /* therefore, it should be passing iteration number of iter+1 instead of iter+0 in the first iteration and after */
506*41ba4c6cSHeeho Park          ierr = (*snes->ops->converged)(snes,snes->iter+1,temp_xnorm,temp_ynorm,fnorm,&reason,snes->cnvP);CHKERRQ(ierr);
507*41ba4c6cSHeeho Park       }
508*41ba4c6cSHeeho Park       /* if multiphase state changes, break out inner iteration */
509*41ba4c6cSHeeho Park       if (reason == SNES_BREAKOUT_INNER_ITER) {
510*41ba4c6cSHeeho Park         if (bs > 1 && neP->auto_scale_multiphase) {
511*41ba4c6cSHeeho Park           /* unscale delta and xnorm before going to the next outer iteration */
512*41ba4c6cSHeeho Park           neP->delta = delta/xnorm;
513*41ba4c6cSHeeho Park           xnorm      = temp_xnorm;
514*41ba4c6cSHeeho Park           ynorm      = temp_ynorm;
515*41ba4c6cSHeeho Park         }
516*41ba4c6cSHeeho Park         reason = SNES_CONVERGED_ITERATING;
517*41ba4c6cSHeeho Park         break;
518*41ba4c6cSHeeho Park       }
519*41ba4c6cSHeeho Park       if (reason == SNES_CONVERGED_SNORM_RELATIVE) reason = SNES_DIVERGED_INNER;
520*41ba4c6cSHeeho Park       if (reason) {
521*41ba4c6cSHeeho Park         if (reason < 0) {
522*41ba4c6cSHeeho Park             /* We're not progressing, so return with the current iterate */
523*41ba4c6cSHeeho Park             ierr     = SNESMonitor(snes,i+1,fnorm);CHKERRQ(ierr);
524*41ba4c6cSHeeho Park             breakout = PETSC_TRUE;
525*41ba4c6cSHeeho Park             break;
526*41ba4c6cSHeeho Park         } else if (reason > 0) {
527*41ba4c6cSHeeho Park             /* We're converged, so return with the current iterate and update solution */
528*41ba4c6cSHeeho Park             ierr     = SNESMonitor(snes,i+1,fnorm);CHKERRQ(ierr);
529*41ba4c6cSHeeho Park             breakout = PETSC_FALSE;
530*41ba4c6cSHeeho Park             break;
531*41ba4c6cSHeeho Park         }
532*41ba4c6cSHeeho Park       }
533*41ba4c6cSHeeho Park       snes->numFailures++;
534*41ba4c6cSHeeho Park     }
535*41ba4c6cSHeeho Park     if (!breakout) {
536*41ba4c6cSHeeho Park       /* Update function and solution vectors */
537*41ba4c6cSHeeho Park       fnorm       = gnorm;
538*41ba4c6cSHeeho Park       ierr        = VecCopy(G,F);CHKERRQ(ierr);
539*41ba4c6cSHeeho Park       ierr        = VecCopy(W,X);CHKERRQ(ierr);
540*41ba4c6cSHeeho Park       /* Monitor convergence */
541*41ba4c6cSHeeho Park       ierr        = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
542*41ba4c6cSHeeho Park       snes->iter  = i+1;
543*41ba4c6cSHeeho Park       snes->norm  = fnorm;
544*41ba4c6cSHeeho Park       snes->xnorm = xnorm;
545*41ba4c6cSHeeho Park       snes->ynorm = ynorm;
546*41ba4c6cSHeeho Park       ierr        = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
547*41ba4c6cSHeeho Park       ierr        = SNESLogConvergenceHistory(snes,snes->norm,lits);CHKERRQ(ierr);
548*41ba4c6cSHeeho Park       ierr        = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
549*41ba4c6cSHeeho Park       /* Test for convergence, xnorm = || X || */
550*41ba4c6cSHeeho Park       neP->itflag = PETSC_TRUE;
551*41ba4c6cSHeeho Park       if (snes->ops->converged != SNESConvergedSkip) {ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr);}
552*41ba4c6cSHeeho Park       ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&reason,snes->cnvP);CHKERRQ(ierr);
553*41ba4c6cSHeeho Park       if (reason) break;
554*41ba4c6cSHeeho Park     } else break;
555*41ba4c6cSHeeho Park   }
556*41ba4c6cSHeeho Park 
557*41ba4c6cSHeeho Park   /* ierr         = PetscFree(inorms);CHKERRQ(ierr); */
558*41ba4c6cSHeeho Park   if (i == maxits) {
559*41ba4c6cSHeeho Park     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %" PetscInt_FMT "\n",maxits);CHKERRQ(ierr);
560*41ba4c6cSHeeho Park     if (!reason) reason = SNES_DIVERGED_MAX_IT;
561*41ba4c6cSHeeho Park   }
562*41ba4c6cSHeeho Park   ierr         = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
563*41ba4c6cSHeeho Park   snes->reason = reason;
564*41ba4c6cSHeeho Park   ierr         = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
565*41ba4c6cSHeeho Park   if (convtest != SNESTRDC_KSPConverged_Private) {
566*41ba4c6cSHeeho Park     ierr       = KSPGetAndClearConvergenceTest(ksp,&ctx->convtest,&ctx->convctx,&ctx->convdestroy);CHKERRQ(ierr);
567*41ba4c6cSHeeho Park     ierr       = PetscFree(ctx);CHKERRQ(ierr);
568*41ba4c6cSHeeho Park     ierr       = KSPSetConvergenceTest(ksp,convtest,convctx,convdestroy);CHKERRQ(ierr);
569*41ba4c6cSHeeho Park   }
570*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
571*41ba4c6cSHeeho Park }
572*41ba4c6cSHeeho Park 
573*41ba4c6cSHeeho Park /*------------------------------------------------------------*/
574*41ba4c6cSHeeho Park static PetscErrorCode SNESSetUp_NEWTONTRDC(SNES snes)
575*41ba4c6cSHeeho Park {
576*41ba4c6cSHeeho Park   PetscErrorCode ierr;
577*41ba4c6cSHeeho Park 
578*41ba4c6cSHeeho Park   PetscFunctionBegin;
579*41ba4c6cSHeeho Park   ierr = SNESSetWorkVecs(snes,6);CHKERRQ(ierr);
580*41ba4c6cSHeeho Park   ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
581*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
582*41ba4c6cSHeeho Park }
583*41ba4c6cSHeeho Park 
584*41ba4c6cSHeeho Park PetscErrorCode SNESReset_NEWTONTRDC(SNES snes)
585*41ba4c6cSHeeho Park {
586*41ba4c6cSHeeho Park 
587*41ba4c6cSHeeho Park   PetscFunctionBegin;
588*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
589*41ba4c6cSHeeho Park }
590*41ba4c6cSHeeho Park 
591*41ba4c6cSHeeho Park static PetscErrorCode SNESDestroy_NEWTONTRDC(SNES snes)
592*41ba4c6cSHeeho Park {
593*41ba4c6cSHeeho Park   PetscErrorCode ierr;
594*41ba4c6cSHeeho Park 
595*41ba4c6cSHeeho Park   PetscFunctionBegin;
596*41ba4c6cSHeeho Park   ierr = SNESReset_NEWTONTRDC(snes);CHKERRQ(ierr);
597*41ba4c6cSHeeho Park   ierr = PetscFree(snes->data);CHKERRQ(ierr);
598*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
599*41ba4c6cSHeeho Park }
600*41ba4c6cSHeeho Park /*------------------------------------------------------------*/
601*41ba4c6cSHeeho Park 
602*41ba4c6cSHeeho Park static PetscErrorCode SNESSetFromOptions_NEWTONTRDC(PetscOptionItems *PetscOptionsObject,SNES snes)
603*41ba4c6cSHeeho Park {
604*41ba4c6cSHeeho Park   SNES_NEWTONTRDC  *ctx = (SNES_NEWTONTRDC*)snes->data;
605*41ba4c6cSHeeho Park   PetscErrorCode   ierr;
606*41ba4c6cSHeeho Park 
607*41ba4c6cSHeeho Park   PetscFunctionBegin;
608*41ba4c6cSHeeho Park   ierr = PetscOptionsHead(PetscOptionsObject,"SNES trust region options for nonlinear equations");CHKERRQ(ierr);
609*41ba4c6cSHeeho Park   ierr = PetscOptionsReal("-snes_trdc_tol","Trust region tolerance","SNESSetTrustRegionTolerance",snes->deltatol,&snes->deltatol,NULL);CHKERRQ(ierr);
610*41ba4c6cSHeeho Park   ierr = PetscOptionsReal("-snes_trdc_eta1","eta1","None",ctx->eta1,&ctx->eta1,NULL);CHKERRQ(ierr);
611*41ba4c6cSHeeho Park   ierr = PetscOptionsReal("-snes_trdc_eta2","eta2","None",ctx->eta2,&ctx->eta2,NULL);CHKERRQ(ierr);
612*41ba4c6cSHeeho Park   ierr = PetscOptionsReal("-snes_trdc_eta3","eta3","None",ctx->eta3,&ctx->eta3,NULL);CHKERRQ(ierr);
613*41ba4c6cSHeeho Park   ierr = PetscOptionsReal("-snes_trdc_t1","t1","None",ctx->t1,&ctx->t1,NULL);CHKERRQ(ierr);
614*41ba4c6cSHeeho Park   ierr = PetscOptionsReal("-snes_trdc_t2","t2","None",ctx->t2,&ctx->t2,NULL);CHKERRQ(ierr);
615*41ba4c6cSHeeho Park   ierr = PetscOptionsReal("-snes_trdc_deltaM","deltaM","None",ctx->deltaM,&ctx->deltaM,NULL);CHKERRQ(ierr);
616*41ba4c6cSHeeho Park   ierr = PetscOptionsReal("-snes_trdc_delta0","delta0","None",ctx->delta0,&ctx->delta0,NULL);CHKERRQ(ierr);
617*41ba4c6cSHeeho Park   ierr = PetscOptionsReal("-snes_trdc_auto_scale_max","auto_scale_max","None",ctx->auto_scale_max,&ctx->auto_scale_max,NULL);CHKERRQ(ierr);
618*41ba4c6cSHeeho Park   ierr = PetscOptionsBool("-snes_trdc_use_cauchy","use_cauchy","use Cauchy step and direction",ctx->use_cauchy,&ctx->use_cauchy,NULL);CHKERRQ(ierr);
619*41ba4c6cSHeeho Park   ierr = PetscOptionsBool("-snes_trdc_auto_scale_multiphase","auto_scale_multiphase","Auto scaling for proper cauchy direction",ctx->auto_scale_multiphase,&ctx->auto_scale_multiphase,NULL);CHKERRQ(ierr);
620*41ba4c6cSHeeho Park   ierr = PetscOptionsTail();CHKERRQ(ierr);
621*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
622*41ba4c6cSHeeho Park }
623*41ba4c6cSHeeho Park 
624*41ba4c6cSHeeho Park static PetscErrorCode SNESView_NEWTONTRDC(SNES snes,PetscViewer viewer)
625*41ba4c6cSHeeho Park {
626*41ba4c6cSHeeho Park   SNES_NEWTONTRDC  *tr = (SNES_NEWTONTRDC*)snes->data;
627*41ba4c6cSHeeho Park   PetscErrorCode   ierr;
628*41ba4c6cSHeeho Park   PetscBool        iascii;
629*41ba4c6cSHeeho Park 
630*41ba4c6cSHeeho Park   PetscFunctionBegin;
631*41ba4c6cSHeeho Park   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
632*41ba4c6cSHeeho Park   if (iascii) {
633*41ba4c6cSHeeho Park     ierr = PetscViewerASCIIPrintf(viewer,"  Trust region tolerance (-snes_trtol)\n",(double)snes->deltatol);CHKERRQ(ierr);
634*41ba4c6cSHeeho Park     ierr = PetscViewerASCIIPrintf(viewer,"  eta1=%g, eta2=%g, eta3=%g\n",(double)tr->eta1,(double)tr->eta2,(double)tr->eta3);CHKERRQ(ierr);
635*41ba4c6cSHeeho Park     ierr = PetscViewerASCIIPrintf(viewer,"  delta0=%g, t1=%g, t2=%g, deltaM=%g\n",(double)tr->delta0,(double)tr->t1,(double)tr->t2,(double)tr->deltaM);CHKERRQ(ierr);
636*41ba4c6cSHeeho Park   }
637*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
638*41ba4c6cSHeeho Park }
639*41ba4c6cSHeeho Park /* ------------------------------------------------------------ */
640*41ba4c6cSHeeho Park /*MC
641*41ba4c6cSHeeho Park       SNESNEWTONTRDC - Newton based nonlinear solver that uses trust-region dogleg method with Cauchy direction
642*41ba4c6cSHeeho Park 
643*41ba4c6cSHeeho Park    Options Database:
644*41ba4c6cSHeeho Park +   -snes_trdc_tol <tol> - trust region tolerance
645*41ba4c6cSHeeho Park .   -snes_trdc_eta1 <eta1> - trust region parameter 0.0 <= eta1 <= eta2, rho >= eta1 breaks out of the inner iteration (default: eta1=0.001)
646*41ba4c6cSHeeho Park .   -snes_trdc_eta2 <eta2> - trust region parameter 0.0 <= eta1 <= eta2, rho <= eta2 shrinks the trust region (default: eta2=0.25)
647*41ba4c6cSHeeho Park .   -snes_trdc_eta3 <eta3> - trust region parameter eta3 > eta2, rho >= eta3 expands the trust region (default: eta3=0.75)
648*41ba4c6cSHeeho Park .   -snes_trdc_t1 <t1> - trust region parameter, shrinking factor of trust region (default: 0.25)
649*41ba4c6cSHeeho Park .   -snes_trdc_t2 <t2> - trust region parameter, expanding factor of trust region (default: 2.0)
650*41ba4c6cSHeeho Park .   -snes_trdc_deltaM <deltaM> - trust region parameter, max size of trust region, deltaM*norm2(x) (default: 0.5)
651*41ba4c6cSHeeho Park .   -snes_trdc_delta0 <delta0> - trust region parameter, initial size of trust region, delta0*norm2(x) (default: 0.1)
652*41ba4c6cSHeeho Park .   -snes_trdc_auto_scale_max <auto_scale_max> - used with auto_scale_multiphase, caps the maximum auto-scaling factor
653*41ba4c6cSHeeho Park .   -snes_trdc_use_cauchy <use_cauchy> - True uses dogleg Cauchy (Steepest Descent direction) step & direction in the trust region algorithm
654*41ba4c6cSHeeho Park -   -snes_trdc_auto_scale_multiphase <auto_scale_multiphase> - True turns on auto-scaling for multivariable block matrix for Cauchy and trust region
655*41ba4c6cSHeeho Park 
656*41ba4c6cSHeeho Park     Notes:
657*41ba4c6cSHeeho Park     The algorithm is taken from "Linear and Nonlinear Solvers for Simulating Multiphase Flow
658*41ba4c6cSHeeho Park     within Large-Scale Engineered Subsurface Systems" by Heeho D. Park, Glenn E. Hammond,
659*41ba4c6cSHeeho Park     Albert J. Valocchi, Tara LaForce.
660*41ba4c6cSHeeho Park 
661*41ba4c6cSHeeho Park    Level: intermediate
662*41ba4c6cSHeeho Park 
663*41ba4c6cSHeeho Park .seealso:  SNESCreate(), SNES, SNESSetType(), SNESNEWTONLS, SNESSetTrustRegionTolerance(), SNESNEWTONTRDC
664*41ba4c6cSHeeho Park 
665*41ba4c6cSHeeho Park M*/
666*41ba4c6cSHeeho Park PETSC_EXTERN PetscErrorCode SNESCreate_NEWTONTRDC(SNES snes)
667*41ba4c6cSHeeho Park {
668*41ba4c6cSHeeho Park   SNES_NEWTONTRDC  *neP;
669*41ba4c6cSHeeho Park   PetscErrorCode   ierr;
670*41ba4c6cSHeeho Park 
671*41ba4c6cSHeeho Park   PetscFunctionBegin;
672*41ba4c6cSHeeho Park   snes->ops->setup          = SNESSetUp_NEWTONTRDC;
673*41ba4c6cSHeeho Park   snes->ops->solve          = SNESSolve_NEWTONTRDC;
674*41ba4c6cSHeeho Park   snes->ops->destroy        = SNESDestroy_NEWTONTRDC;
675*41ba4c6cSHeeho Park   snes->ops->setfromoptions = SNESSetFromOptions_NEWTONTRDC;
676*41ba4c6cSHeeho Park   snes->ops->view           = SNESView_NEWTONTRDC;
677*41ba4c6cSHeeho Park   snes->ops->reset          = SNESReset_NEWTONTRDC;
678*41ba4c6cSHeeho Park 
679*41ba4c6cSHeeho Park   snes->usesksp = PETSC_TRUE;
680*41ba4c6cSHeeho Park   snes->usesnpc = PETSC_FALSE;
681*41ba4c6cSHeeho Park 
682*41ba4c6cSHeeho Park   snes->alwayscomputesfinalresidual = PETSC_TRUE;
683*41ba4c6cSHeeho Park 
684*41ba4c6cSHeeho Park   ierr        = PetscNewLog(snes,&neP);CHKERRQ(ierr);
685*41ba4c6cSHeeho Park   snes->data  = (void*)neP;
686*41ba4c6cSHeeho Park   neP->delta  = 0.0;
687*41ba4c6cSHeeho Park   neP->delta0 = 0.1;
688*41ba4c6cSHeeho Park   neP->eta1   = 0.001;
689*41ba4c6cSHeeho Park   neP->eta2   = 0.25;
690*41ba4c6cSHeeho Park   neP->eta3   = 0.75;
691*41ba4c6cSHeeho Park   neP->t1     = 0.25;
692*41ba4c6cSHeeho Park   neP->t2     = 2.0;
693*41ba4c6cSHeeho Park   neP->deltaM = 0.5;
694*41ba4c6cSHeeho Park   neP->sigma  = 0.0001;
695*41ba4c6cSHeeho Park   neP->itflag = PETSC_FALSE;
696*41ba4c6cSHeeho Park   neP->rnorm0 = 0.0;
697*41ba4c6cSHeeho Park   neP->ttol   = 0.0;
698*41ba4c6cSHeeho Park   neP->use_cauchy            = PETSC_TRUE;
699*41ba4c6cSHeeho Park   neP->auto_scale_multiphase = PETSC_FALSE;
700*41ba4c6cSHeeho Park   neP->auto_scale_max        = -1.0;
701*41ba4c6cSHeeho Park   neP->rho_satisfied         = PETSC_FALSE;
702*41ba4c6cSHeeho Park   snes->deltatol             = 1.e-12;
703*41ba4c6cSHeeho Park 
704*41ba4c6cSHeeho Park   /* for multiphase (multivariable) scaling */
705*41ba4c6cSHeeho Park   /* may be used for dynamic allocation of inorms, but it fails snes_tutorials-ex3_13
706*41ba4c6cSHeeho Park      on test forced DIVERGED_JACOBIAN_DOMAIN test. I will use static array for now.
707*41ba4c6cSHeeho Park   ierr = VecGetBlockSize(snes->work[0],&neP->bs);CHKERRQ(ierr);
708*41ba4c6cSHeeho Park   ierr = PetscCalloc1(neP->bs,&neP->inorms);CHKERRQ(ierr);
709*41ba4c6cSHeeho Park   */
710*41ba4c6cSHeeho Park 
711*41ba4c6cSHeeho Park   PetscFunctionReturn(0);
712*41ba4c6cSHeeho Park }
713