xref: /petsc/src/tao/unconstrained/impls/ntr/ntr.c (revision a7e14dcfba0d07adf6226a919460249440ec94c7)
1*a7e14dcfSSatish Balay #include "src/matrix/lmvmmat.h"
2*a7e14dcfSSatish Balay #include "ntr.h"
3*a7e14dcfSSatish Balay 
4*a7e14dcfSSatish Balay #include "petscksp.h"
5*a7e14dcfSSatish Balay #include "petscpc.h"
6*a7e14dcfSSatish Balay #include "petsc-private/kspimpl.h"
7*a7e14dcfSSatish Balay #include "petsc-private/pcimpl.h"
8*a7e14dcfSSatish Balay 
9*a7e14dcfSSatish Balay #define NTR_KSP_NASH    0
10*a7e14dcfSSatish Balay #define NTR_KSP_STCG    1
11*a7e14dcfSSatish Balay #define NTR_KSP_GLTR    2
12*a7e14dcfSSatish Balay #define NTR_KSP_TYPES   3
13*a7e14dcfSSatish Balay 
14*a7e14dcfSSatish Balay #define NTR_PC_NONE	0
15*a7e14dcfSSatish Balay #define NTR_PC_AHESS    1
16*a7e14dcfSSatish Balay #define NTR_PC_BFGS     2
17*a7e14dcfSSatish Balay #define NTR_PC_PETSC    3
18*a7e14dcfSSatish Balay #define NTR_PC_TYPES    4
19*a7e14dcfSSatish Balay 
20*a7e14dcfSSatish Balay #define BFGS_SCALE_AHESS   0
21*a7e14dcfSSatish Balay #define BFGS_SCALE_BFGS    1
22*a7e14dcfSSatish Balay #define BFGS_SCALE_TYPES   2
23*a7e14dcfSSatish Balay 
24*a7e14dcfSSatish Balay #define NTR_INIT_CONSTANT	  0
25*a7e14dcfSSatish Balay #define NTR_INIT_DIRECTION	  1
26*a7e14dcfSSatish Balay #define NTR_INIT_INTERPOLATION	  2
27*a7e14dcfSSatish Balay #define NTR_INIT_TYPES		  3
28*a7e14dcfSSatish Balay 
29*a7e14dcfSSatish Balay #define NTR_UPDATE_REDUCTION      0
30*a7e14dcfSSatish Balay #define NTR_UPDATE_INTERPOLATION  1
31*a7e14dcfSSatish Balay #define NTR_UPDATE_TYPES          2
32*a7e14dcfSSatish Balay 
33*a7e14dcfSSatish Balay static const char *NTR_KSP[64] = {
34*a7e14dcfSSatish Balay   "nash", "stcg", "gltr"
35*a7e14dcfSSatish Balay };
36*a7e14dcfSSatish Balay 
37*a7e14dcfSSatish Balay static const char *NTR_PC[64] = {
38*a7e14dcfSSatish Balay   "none", "ahess", "bfgs", "petsc"
39*a7e14dcfSSatish Balay };
40*a7e14dcfSSatish Balay 
41*a7e14dcfSSatish Balay static const char *BFGS_SCALE[64] = {
42*a7e14dcfSSatish Balay   "ahess", "bfgs"
43*a7e14dcfSSatish Balay };
44*a7e14dcfSSatish Balay 
45*a7e14dcfSSatish Balay static const char *NTR_INIT[64] = {
46*a7e14dcfSSatish Balay   "constant", "direction", "interpolation"
47*a7e14dcfSSatish Balay };
48*a7e14dcfSSatish Balay 
49*a7e14dcfSSatish Balay static const char *NTR_UPDATE[64] = {
50*a7e14dcfSSatish Balay   "reduction", "interpolation"
51*a7e14dcfSSatish Balay };
52*a7e14dcfSSatish Balay 
53*a7e14dcfSSatish Balay /*  Routine for BFGS preconditioner */
54*a7e14dcfSSatish Balay static PetscErrorCode MatLMVMSolveShell(PC pc, Vec xin, Vec xout);
55*a7e14dcfSSatish Balay 
56*a7e14dcfSSatish Balay /*
57*a7e14dcfSSatish Balay    TaoSolve_NTR - Implements Newton's Method with a trust region approach
58*a7e14dcfSSatish Balay    for solving unconstrained minimization problems.
59*a7e14dcfSSatish Balay 
60*a7e14dcfSSatish Balay    The basic algorithm is taken from MINPACK-2 (dstrn).
61*a7e14dcfSSatish Balay 
62*a7e14dcfSSatish Balay    TaoSolve_NTR computes a local minimizer of a twice differentiable function
63*a7e14dcfSSatish Balay    f by applying a trust region variant of Newton's method.  At each stage
64*a7e14dcfSSatish Balay    of the algorithm, we use the prconditioned conjugate gradient method to
65*a7e14dcfSSatish Balay    determine an approximate minimizer of the quadratic equation
66*a7e14dcfSSatish Balay 
67*a7e14dcfSSatish Balay         q(s) = <s, Hs + g>
68*a7e14dcfSSatish Balay 
69*a7e14dcfSSatish Balay    subject to the trust region constraint
70*a7e14dcfSSatish Balay 
71*a7e14dcfSSatish Balay         || s ||_M <= radius,
72*a7e14dcfSSatish Balay 
73*a7e14dcfSSatish Balay    where radius is the trust region radius and M is a symmetric positive
74*a7e14dcfSSatish Balay    definite matrix (the preconditioner).  Here g is the gradient and H
75*a7e14dcfSSatish Balay    is the Hessian matrix.
76*a7e14dcfSSatish Balay 
77*a7e14dcfSSatish Balay    Note:  TaoSolve_NTR MUST use the iterative solver KSPNASH, KSPSTCG,
78*a7e14dcfSSatish Balay           or KSPGLTR.  Thus, we set KSPNASH, KSPSTCG, or KSPGLTR in this
79*a7e14dcfSSatish Balay           routine regardless of what the user may have previously specified.
80*a7e14dcfSSatish Balay */
81*a7e14dcfSSatish Balay #undef __FUNCT__
82*a7e14dcfSSatish Balay #define __FUNCT__ "TaoSolve_NTR"
83*a7e14dcfSSatish Balay static PetscErrorCode TaoSolve_NTR(TaoSolver tao)
84*a7e14dcfSSatish Balay {
85*a7e14dcfSSatish Balay   TAO_NTR *tr = (TAO_NTR *)tao->data;
86*a7e14dcfSSatish Balay 
87*a7e14dcfSSatish Balay   PC pc;
88*a7e14dcfSSatish Balay 
89*a7e14dcfSSatish Balay   KSPConvergedReason ksp_reason;
90*a7e14dcfSSatish Balay   TaoSolverTerminationReason reason;
91*a7e14dcfSSatish Balay 
92*a7e14dcfSSatish Balay   MatStructure matflag;
93*a7e14dcfSSatish Balay 
94*a7e14dcfSSatish Balay   PetscReal fmin, ftrial, prered, actred, kappa, sigma, beta;
95*a7e14dcfSSatish Balay   PetscReal tau, tau_1, tau_2, tau_max, tau_min, max_radius;
96*a7e14dcfSSatish Balay   PetscReal f, gnorm;
97*a7e14dcfSSatish Balay 
98*a7e14dcfSSatish Balay   PetscReal delta;
99*a7e14dcfSSatish Balay   PetscReal norm_d;
100*a7e14dcfSSatish Balay   PetscErrorCode ierr;
101*a7e14dcfSSatish Balay 
102*a7e14dcfSSatish Balay   PetscInt iter = 0;
103*a7e14dcfSSatish Balay   PetscInt bfgsUpdates = 0;
104*a7e14dcfSSatish Balay   PetscInt needH;
105*a7e14dcfSSatish Balay 
106*a7e14dcfSSatish Balay   PetscInt i_max = 5;
107*a7e14dcfSSatish Balay   PetscInt j_max = 1;
108*a7e14dcfSSatish Balay   PetscInt i, j, N, n, its;
109*a7e14dcfSSatish Balay 
110*a7e14dcfSSatish Balay   PetscFunctionBegin;
111*a7e14dcfSSatish Balay 
112*a7e14dcfSSatish Balay   if (tao->XL || tao->XU || tao->ops->computebounds) {
113*a7e14dcfSSatish Balay     ierr = PetscPrintf(((PetscObject)tao)->comm,"WARNING: Variable bounds have been set but will be ignored by ntr algorithm\n"); CHKERRQ(ierr);
114*a7e14dcfSSatish Balay   }
115*a7e14dcfSSatish Balay 
116*a7e14dcfSSatish Balay   tao->trust = tao->trust0;
117*a7e14dcfSSatish Balay 
118*a7e14dcfSSatish Balay   /* Modify the radius if it is too large or small */
119*a7e14dcfSSatish Balay   tao->trust = PetscMax(tao->trust, tr->min_radius);
120*a7e14dcfSSatish Balay   tao->trust = PetscMin(tao->trust, tr->max_radius);
121*a7e14dcfSSatish Balay 
122*a7e14dcfSSatish Balay 
123*a7e14dcfSSatish Balay   if (NTR_PC_BFGS == tr->pc_type && !tr->M) {
124*a7e14dcfSSatish Balay     ierr = VecGetLocalSize(tao->solution,&n); CHKERRQ(ierr);
125*a7e14dcfSSatish Balay     ierr = VecGetSize(tao->solution,&N); CHKERRQ(ierr);
126*a7e14dcfSSatish Balay     ierr = MatCreateLMVM(((PetscObject)tao)->comm,n,N,&tr->M); CHKERRQ(ierr);
127*a7e14dcfSSatish Balay     ierr = MatLMVMAllocateVectors(tr->M,tao->solution); CHKERRQ(ierr);
128*a7e14dcfSSatish Balay   }
129*a7e14dcfSSatish Balay 
130*a7e14dcfSSatish Balay   /* Check convergence criteria */
131*a7e14dcfSSatish Balay   ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient); CHKERRQ(ierr);
132*a7e14dcfSSatish Balay   ierr = VecNorm(tao->gradient,NORM_2,&gnorm); CHKERRQ(ierr);
133*a7e14dcfSSatish Balay   if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) {
134*a7e14dcfSSatish Balay     SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
135*a7e14dcfSSatish Balay   }
136*a7e14dcfSSatish Balay   needH = 1;
137*a7e14dcfSSatish Balay 
138*a7e14dcfSSatish Balay   ierr = TaoMonitor(tao, iter, f, gnorm, 0.0, 1.0, &reason); CHKERRQ(ierr);
139*a7e14dcfSSatish Balay   if (reason != TAO_CONTINUE_ITERATING) {
140*a7e14dcfSSatish Balay     PetscFunctionReturn(0);
141*a7e14dcfSSatish Balay   }
142*a7e14dcfSSatish Balay 
143*a7e14dcfSSatish Balay   /* Create vectors for the limited memory preconditioner */
144*a7e14dcfSSatish Balay   if ((NTR_PC_BFGS == tr->pc_type) &&
145*a7e14dcfSSatish Balay       (BFGS_SCALE_BFGS != tr->bfgs_scale_type)) {
146*a7e14dcfSSatish Balay     if (!tr->Diag) {
147*a7e14dcfSSatish Balay 	ierr = VecDuplicate(tao->solution, &tr->Diag); CHKERRQ(ierr);
148*a7e14dcfSSatish Balay     }
149*a7e14dcfSSatish Balay   }
150*a7e14dcfSSatish Balay 
151*a7e14dcfSSatish Balay   switch(tr->ksp_type) {
152*a7e14dcfSSatish Balay   case NTR_KSP_NASH:
153*a7e14dcfSSatish Balay     ierr = KSPSetType(tao->ksp, KSPNASH); CHKERRQ(ierr);
154*a7e14dcfSSatish Balay     if (tao->ksp->ops->setfromoptions) {
155*a7e14dcfSSatish Balay       (*tao->ksp->ops->setfromoptions)(tao->ksp);
156*a7e14dcfSSatish Balay     }
157*a7e14dcfSSatish Balay     break;
158*a7e14dcfSSatish Balay 
159*a7e14dcfSSatish Balay   case NTR_KSP_STCG:
160*a7e14dcfSSatish Balay     ierr = KSPSetType(tao->ksp, KSPSTCG); CHKERRQ(ierr);
161*a7e14dcfSSatish Balay     if (tao->ksp->ops->setfromoptions) {
162*a7e14dcfSSatish Balay       (*tao->ksp->ops->setfromoptions)(tao->ksp);
163*a7e14dcfSSatish Balay     }
164*a7e14dcfSSatish Balay     break;
165*a7e14dcfSSatish Balay 
166*a7e14dcfSSatish Balay   default:
167*a7e14dcfSSatish Balay     ierr = KSPSetType(tao->ksp, KSPGLTR); CHKERRQ(ierr);
168*a7e14dcfSSatish Balay     if (tao->ksp->ops->setfromoptions) {
169*a7e14dcfSSatish Balay       (*tao->ksp->ops->setfromoptions)(tao->ksp);
170*a7e14dcfSSatish Balay     }
171*a7e14dcfSSatish Balay     break;
172*a7e14dcfSSatish Balay   }
173*a7e14dcfSSatish Balay 
174*a7e14dcfSSatish Balay   /*  Modify the preconditioner to use the bfgs approximation */
175*a7e14dcfSSatish Balay   ierr = KSPGetPC(tao->ksp, &pc); CHKERRQ(ierr);
176*a7e14dcfSSatish Balay   switch(tr->pc_type) {
177*a7e14dcfSSatish Balay   case NTR_PC_NONE:
178*a7e14dcfSSatish Balay     ierr = PCSetType(pc, PCNONE); CHKERRQ(ierr);
179*a7e14dcfSSatish Balay     if (pc->ops->setfromoptions) {
180*a7e14dcfSSatish Balay       (*pc->ops->setfromoptions)(pc);
181*a7e14dcfSSatish Balay     }
182*a7e14dcfSSatish Balay     break;
183*a7e14dcfSSatish Balay 
184*a7e14dcfSSatish Balay   case NTR_PC_AHESS:
185*a7e14dcfSSatish Balay     ierr = PCSetType(pc, PCJACOBI); CHKERRQ(ierr);
186*a7e14dcfSSatish Balay     if (pc->ops->setfromoptions) {
187*a7e14dcfSSatish Balay       (*pc->ops->setfromoptions)(pc);
188*a7e14dcfSSatish Balay     }
189*a7e14dcfSSatish Balay     ierr = PCJacobiSetUseAbs(pc); CHKERRQ(ierr);
190*a7e14dcfSSatish Balay     break;
191*a7e14dcfSSatish Balay 
192*a7e14dcfSSatish Balay   case NTR_PC_BFGS:
193*a7e14dcfSSatish Balay     ierr = PCSetType(pc, PCSHELL); CHKERRQ(ierr);
194*a7e14dcfSSatish Balay     if (pc->ops->setfromoptions) {
195*a7e14dcfSSatish Balay       (*pc->ops->setfromoptions)(pc);
196*a7e14dcfSSatish Balay     }
197*a7e14dcfSSatish Balay     ierr = PCShellSetName(pc, "bfgs"); CHKERRQ(ierr);
198*a7e14dcfSSatish Balay     ierr = PCShellSetContext(pc, tr->M); CHKERRQ(ierr);
199*a7e14dcfSSatish Balay     ierr = PCShellSetApply(pc, MatLMVMSolveShell); CHKERRQ(ierr);
200*a7e14dcfSSatish Balay     break;
201*a7e14dcfSSatish Balay 
202*a7e14dcfSSatish Balay   default:
203*a7e14dcfSSatish Balay     /*  Use the pc method set by pc_type */
204*a7e14dcfSSatish Balay     break;
205*a7e14dcfSSatish Balay   }
206*a7e14dcfSSatish Balay 
207*a7e14dcfSSatish Balay   /*  Initialize trust-region radius */
208*a7e14dcfSSatish Balay   switch(tr->init_type) {
209*a7e14dcfSSatish Balay   case NTR_INIT_CONSTANT:
210*a7e14dcfSSatish Balay     /*  Use the initial radius specified */
211*a7e14dcfSSatish Balay     break;
212*a7e14dcfSSatish Balay 
213*a7e14dcfSSatish Balay   case NTR_INIT_INTERPOLATION:
214*a7e14dcfSSatish Balay     /*  Use the initial radius specified */
215*a7e14dcfSSatish Balay     max_radius = 0.0;
216*a7e14dcfSSatish Balay 
217*a7e14dcfSSatish Balay     for (j = 0; j < j_max; ++j) {
218*a7e14dcfSSatish Balay       fmin = f;
219*a7e14dcfSSatish Balay       sigma = 0.0;
220*a7e14dcfSSatish Balay 
221*a7e14dcfSSatish Balay       if (needH) {
222*a7e14dcfSSatish Balay 	  ierr = TaoComputeHessian(tao, tao->solution, &tao->hessian, &tao->hessian_pre, &matflag); CHKERRQ(ierr);
223*a7e14dcfSSatish Balay         needH = 0;
224*a7e14dcfSSatish Balay       }
225*a7e14dcfSSatish Balay 
226*a7e14dcfSSatish Balay       for (i = 0; i < i_max; ++i) {
227*a7e14dcfSSatish Balay 
228*a7e14dcfSSatish Balay         ierr = VecCopy(tao->solution, tr->W); CHKERRQ(ierr);
229*a7e14dcfSSatish Balay 	ierr = VecAXPY(tr->W, -tao->trust/gnorm, tao->gradient); CHKERRQ(ierr);
230*a7e14dcfSSatish Balay 	ierr = TaoComputeObjective(tao, tr->W, &ftrial); CHKERRQ(ierr);
231*a7e14dcfSSatish Balay 
232*a7e14dcfSSatish Balay         if (PetscIsInfOrNanReal(ftrial)) {
233*a7e14dcfSSatish Balay 	  tau = tr->gamma1_i;
234*a7e14dcfSSatish Balay         }
235*a7e14dcfSSatish Balay         else {
236*a7e14dcfSSatish Balay 	  if (ftrial < fmin) {
237*a7e14dcfSSatish Balay             fmin = ftrial;
238*a7e14dcfSSatish Balay             sigma = -tao->trust / gnorm;
239*a7e14dcfSSatish Balay           }
240*a7e14dcfSSatish Balay 
241*a7e14dcfSSatish Balay 	  ierr = MatMult(tao->hessian, tao->gradient, tao->stepdirection); CHKERRQ(ierr);
242*a7e14dcfSSatish Balay 	  ierr = VecDot(tao->gradient, tao->stepdirection, &prered); CHKERRQ(ierr);
243*a7e14dcfSSatish Balay 
244*a7e14dcfSSatish Balay           prered = tao->trust * (gnorm - 0.5 * tao->trust * prered / (gnorm * gnorm));
245*a7e14dcfSSatish Balay           actred = f - ftrial;
246*a7e14dcfSSatish Balay 	  if ((PetscAbsScalar(actred) <= tr->epsilon) &&
247*a7e14dcfSSatish Balay               (PetscAbsScalar(prered) <= tr->epsilon)) {
248*a7e14dcfSSatish Balay 	    kappa = 1.0;
249*a7e14dcfSSatish Balay 	  }
250*a7e14dcfSSatish Balay 	  else {
251*a7e14dcfSSatish Balay 	    kappa = actred / prered;
252*a7e14dcfSSatish Balay 	  }
253*a7e14dcfSSatish Balay 
254*a7e14dcfSSatish Balay 	  tau_1 = tr->theta_i * gnorm * tao->trust / (tr->theta_i * gnorm * tao->trust + (1.0 - tr->theta_i) * prered - actred);
255*a7e14dcfSSatish Balay           tau_2 = tr->theta_i * gnorm * tao->trust / (tr->theta_i * gnorm * tao->trust - (1.0 + tr->theta_i) * prered + actred);
256*a7e14dcfSSatish Balay 	  tau_min = PetscMin(tau_1, tau_2);
257*a7e14dcfSSatish Balay 	  tau_max = PetscMax(tau_1, tau_2);
258*a7e14dcfSSatish Balay 
259*a7e14dcfSSatish Balay 	  if (PetscAbsScalar(kappa - 1.0) <= tr->mu1_i) {
260*a7e14dcfSSatish Balay 	    /*  Great agreement */
261*a7e14dcfSSatish Balay             max_radius = PetscMax(max_radius, tao->trust);
262*a7e14dcfSSatish Balay 
263*a7e14dcfSSatish Balay 	    if (tau_max < 1.0) {
264*a7e14dcfSSatish Balay               tau = tr->gamma3_i;
265*a7e14dcfSSatish Balay             }
266*a7e14dcfSSatish Balay             else if (tau_max > tr->gamma4_i) {
267*a7e14dcfSSatish Balay               tau = tr->gamma4_i;
268*a7e14dcfSSatish Balay             }
269*a7e14dcfSSatish Balay             else {
270*a7e14dcfSSatish Balay               tau = tau_max;
271*a7e14dcfSSatish Balay             }
272*a7e14dcfSSatish Balay           }
273*a7e14dcfSSatish Balay           else if (PetscAbsScalar(kappa - 1.0) <= tr->mu2_i) {
274*a7e14dcfSSatish Balay 	    /*  Good agreement */
275*a7e14dcfSSatish Balay             max_radius = PetscMax(max_radius, tao->trust);
276*a7e14dcfSSatish Balay 
277*a7e14dcfSSatish Balay 	    if (tau_max < tr->gamma2_i) {
278*a7e14dcfSSatish Balay               tau = tr->gamma2_i;
279*a7e14dcfSSatish Balay             }
280*a7e14dcfSSatish Balay             else if (tau_max > tr->gamma3_i) {
281*a7e14dcfSSatish Balay               tau = tr->gamma3_i;
282*a7e14dcfSSatish Balay             }
283*a7e14dcfSSatish Balay             else {
284*a7e14dcfSSatish Balay               tau = tau_max;
285*a7e14dcfSSatish Balay             }
286*a7e14dcfSSatish Balay           }
287*a7e14dcfSSatish Balay           else {
288*a7e14dcfSSatish Balay 	    /*  Not good agreement */
289*a7e14dcfSSatish Balay 	    if (tau_min > 1.0) {
290*a7e14dcfSSatish Balay 	      tau = tr->gamma2_i;
291*a7e14dcfSSatish Balay             }
292*a7e14dcfSSatish Balay             else if (tau_max < tr->gamma1_i) {
293*a7e14dcfSSatish Balay               tau = tr->gamma1_i;
294*a7e14dcfSSatish Balay             }
295*a7e14dcfSSatish Balay 	    else if ((tau_min < tr->gamma1_i) && (tau_max >= 1.0)) {
296*a7e14dcfSSatish Balay 	      tau = tr->gamma1_i;
297*a7e14dcfSSatish Balay             }
298*a7e14dcfSSatish Balay 	    else if ((tau_1 >= tr->gamma1_i) && (tau_1 < 1.0) &&
299*a7e14dcfSSatish Balay                      ((tau_2 < tr->gamma1_i) || (tau_2 >= 1.0))) {
300*a7e14dcfSSatish Balay               tau = tau_1;
301*a7e14dcfSSatish Balay             }
302*a7e14dcfSSatish Balay 	    else if ((tau_2 >= tr->gamma1_i) && (tau_2 < 1.0) &&
303*a7e14dcfSSatish Balay                      ((tau_1 < tr->gamma1_i) || (tau_2 >= 1.0))) {
304*a7e14dcfSSatish Balay               tau = tau_2;
305*a7e14dcfSSatish Balay             }
306*a7e14dcfSSatish Balay             else {
307*a7e14dcfSSatish Balay               tau = tau_max;
308*a7e14dcfSSatish Balay             }
309*a7e14dcfSSatish Balay           }
310*a7e14dcfSSatish Balay         }
311*a7e14dcfSSatish Balay         tao->trust = tau * tao->trust;
312*a7e14dcfSSatish Balay       }
313*a7e14dcfSSatish Balay 
314*a7e14dcfSSatish Balay       if (fmin < f) {
315*a7e14dcfSSatish Balay         f = fmin;
316*a7e14dcfSSatish Balay 	ierr = VecAXPY(tao->solution, sigma, tao->gradient); CHKERRQ(ierr);
317*a7e14dcfSSatish Balay 	ierr = TaoComputeGradient(tao,tao->solution, tao->gradient); CHKERRQ(ierr);
318*a7e14dcfSSatish Balay 
319*a7e14dcfSSatish Balay 	ierr = VecNorm(tao->gradient, NORM_2, &gnorm); CHKERRQ(ierr);
320*a7e14dcfSSatish Balay 
321*a7e14dcfSSatish Balay         if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) {
322*a7e14dcfSSatish Balay           SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
323*a7e14dcfSSatish Balay         }
324*a7e14dcfSSatish Balay         needH = 1;
325*a7e14dcfSSatish Balay 
326*a7e14dcfSSatish Balay         ierr = TaoMonitor(tao, iter, f, gnorm, 0.0, 1.0, &reason); CHKERRQ(ierr);
327*a7e14dcfSSatish Balay         if (reason != TAO_CONTINUE_ITERATING) {
328*a7e14dcfSSatish Balay           PetscFunctionReturn(0);
329*a7e14dcfSSatish Balay         }
330*a7e14dcfSSatish Balay       }
331*a7e14dcfSSatish Balay     }
332*a7e14dcfSSatish Balay     tao->trust = PetscMax(tao->trust, max_radius);
333*a7e14dcfSSatish Balay 
334*a7e14dcfSSatish Balay     /*  Modify the radius if it is too large or small */
335*a7e14dcfSSatish Balay     tao->trust = PetscMax(tao->trust, tr->min_radius);
336*a7e14dcfSSatish Balay     tao->trust = PetscMin(tao->trust, tr->max_radius);
337*a7e14dcfSSatish Balay     break;
338*a7e14dcfSSatish Balay 
339*a7e14dcfSSatish Balay   default:
340*a7e14dcfSSatish Balay     /*  Norm of the first direction will initialize radius */
341*a7e14dcfSSatish Balay     tao->trust = 0.0;
342*a7e14dcfSSatish Balay     break;
343*a7e14dcfSSatish Balay   }
344*a7e14dcfSSatish Balay 
345*a7e14dcfSSatish Balay   /* Set initial scaling for the BFGS preconditioner
346*a7e14dcfSSatish Balay      This step is done after computing the initial trust-region radius
347*a7e14dcfSSatish Balay      since the function value may have decreased */
348*a7e14dcfSSatish Balay   if (NTR_PC_BFGS == tr->pc_type) {
349*a7e14dcfSSatish Balay     if (f != 0.0) {
350*a7e14dcfSSatish Balay       delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm);
351*a7e14dcfSSatish Balay     }
352*a7e14dcfSSatish Balay     else {
353*a7e14dcfSSatish Balay       delta = 2.0 / (gnorm*gnorm);
354*a7e14dcfSSatish Balay     }
355*a7e14dcfSSatish Balay     ierr = MatLMVMSetDelta(tr->M,delta); CHKERRQ(ierr);
356*a7e14dcfSSatish Balay   }
357*a7e14dcfSSatish Balay 
358*a7e14dcfSSatish Balay   /* Have not converged; continue with Newton method */
359*a7e14dcfSSatish Balay   while (reason == TAO_CONTINUE_ITERATING) {
360*a7e14dcfSSatish Balay     ++iter;
361*a7e14dcfSSatish Balay 
362*a7e14dcfSSatish Balay     /* Compute the Hessian */
363*a7e14dcfSSatish Balay     if (needH) {
364*a7e14dcfSSatish Balay       ierr = TaoComputeHessian(tao, tao->solution, &tao->hessian, &tao->hessian_pre, &matflag); CHKERRQ(ierr);
365*a7e14dcfSSatish Balay       needH = 0;
366*a7e14dcfSSatish Balay     }
367*a7e14dcfSSatish Balay 
368*a7e14dcfSSatish Balay     if (NTR_PC_BFGS == tr->pc_type) {
369*a7e14dcfSSatish Balay       if (BFGS_SCALE_AHESS == tr->bfgs_scale_type) {
370*a7e14dcfSSatish Balay         /* Obtain diagonal for the bfgs preconditioner */
371*a7e14dcfSSatish Balay         ierr = MatGetDiagonal(tao->hessian, tr->Diag); CHKERRQ(ierr);
372*a7e14dcfSSatish Balay 	ierr = VecAbs(tr->Diag); CHKERRQ(ierr);
373*a7e14dcfSSatish Balay 	ierr = VecReciprocal(tr->Diag); CHKERRQ(ierr);
374*a7e14dcfSSatish Balay 	ierr = MatLMVMSetScale(tr->M,tr->Diag); CHKERRQ(ierr);
375*a7e14dcfSSatish Balay       }
376*a7e14dcfSSatish Balay 
377*a7e14dcfSSatish Balay       /* Update the limited memory preconditioner */
378*a7e14dcfSSatish Balay       ierr = MatLMVMUpdate(tr->M, tao->solution, tao->gradient); CHKERRQ(ierr);
379*a7e14dcfSSatish Balay       ++bfgsUpdates;
380*a7e14dcfSSatish Balay     }
381*a7e14dcfSSatish Balay 
382*a7e14dcfSSatish Balay     while (reason == TAO_CONTINUE_ITERATING) {
383*a7e14dcfSSatish Balay       ierr = KSPSetOperators(tao->ksp, tao->hessian, tao->hessian_pre, matflag); CHKERRQ(ierr);
384*a7e14dcfSSatish Balay 
385*a7e14dcfSSatish Balay       /* Solve the trust region subproblem */
386*a7e14dcfSSatish Balay       if (NTR_KSP_NASH == tr->ksp_type) {
387*a7e14dcfSSatish Balay 	ierr = KSPNASHSetRadius(tao->ksp,tao->trust); CHKERRQ(ierr);
388*a7e14dcfSSatish Balay 	ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection); CHKERRQ(ierr);
389*a7e14dcfSSatish Balay 	ierr = KSPGetIterationNumber(tao->ksp,&its); CHKERRQ(ierr);
390*a7e14dcfSSatish Balay 	tao->ksp_its+=its;
391*a7e14dcfSSatish Balay 	ierr = KSPNASHGetNormD(tao->ksp, &norm_d); CHKERRQ(ierr);
392*a7e14dcfSSatish Balay       } else if (NTR_KSP_STCG == tr->ksp_type) {
393*a7e14dcfSSatish Balay 	ierr = KSPSTCGSetRadius(tao->ksp,tao->trust); CHKERRQ(ierr);
394*a7e14dcfSSatish Balay 	ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection); CHKERRQ(ierr);
395*a7e14dcfSSatish Balay 	ierr = KSPGetIterationNumber(tao->ksp,&its); CHKERRQ(ierr);
396*a7e14dcfSSatish Balay 	tao->ksp_its+=its;
397*a7e14dcfSSatish Balay 	ierr = KSPSTCGGetNormD(tao->ksp, &norm_d); CHKERRQ(ierr);
398*a7e14dcfSSatish Balay       } else { /* NTR_KSP_GLTR */
399*a7e14dcfSSatish Balay 	ierr = KSPGLTRSetRadius(tao->ksp,tao->trust); CHKERRQ(ierr);
400*a7e14dcfSSatish Balay 	ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection); CHKERRQ(ierr);
401*a7e14dcfSSatish Balay 	ierr = KSPGetIterationNumber(tao->ksp,&its); CHKERRQ(ierr);
402*a7e14dcfSSatish Balay 	tao->ksp_its+=its;
403*a7e14dcfSSatish Balay 	ierr = KSPGLTRGetNormD(tao->ksp, &norm_d); CHKERRQ(ierr);
404*a7e14dcfSSatish Balay       }
405*a7e14dcfSSatish Balay 
406*a7e14dcfSSatish Balay       if (0.0 == tao->trust) {
407*a7e14dcfSSatish Balay         /* Radius was uninitialized; use the norm of the direction */
408*a7e14dcfSSatish Balay         if (norm_d > 0.0) {
409*a7e14dcfSSatish Balay           tao->trust = norm_d;
410*a7e14dcfSSatish Balay 
411*a7e14dcfSSatish Balay           /* Modify the radius if it is too large or small */
412*a7e14dcfSSatish Balay           tao->trust = PetscMax(tao->trust, tr->min_radius);
413*a7e14dcfSSatish Balay           tao->trust = PetscMin(tao->trust, tr->max_radius);
414*a7e14dcfSSatish Balay         }
415*a7e14dcfSSatish Balay         else {
416*a7e14dcfSSatish Balay           /* The direction was bad; set radius to default value and re-solve
417*a7e14dcfSSatish Balay 	     the trust-region subproblem to get a direction */
418*a7e14dcfSSatish Balay 	  tao->trust = tao->trust0;
419*a7e14dcfSSatish Balay 
420*a7e14dcfSSatish Balay           /* Modify the radius if it is too large or small */
421*a7e14dcfSSatish Balay           tao->trust = PetscMax(tao->trust, tr->min_radius);
422*a7e14dcfSSatish Balay           tao->trust = PetscMin(tao->trust, tr->max_radius);
423*a7e14dcfSSatish Balay 
424*a7e14dcfSSatish Balay 	  if (NTR_KSP_NASH == tr->ksp_type) {
425*a7e14dcfSSatish Balay 	    ierr = KSPNASHSetRadius(tao->ksp,tao->trust); CHKERRQ(ierr);
426*a7e14dcfSSatish Balay 	    ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection); CHKERRQ(ierr);
427*a7e14dcfSSatish Balay 	    ierr = KSPGetIterationNumber(tao->ksp,&its); CHKERRQ(ierr);
428*a7e14dcfSSatish Balay 	    tao->ksp_its+=its;
429*a7e14dcfSSatish Balay 	    ierr = KSPNASHGetNormD(tao->ksp, &norm_d); CHKERRQ(ierr);
430*a7e14dcfSSatish Balay 	  } else if (NTR_KSP_STCG == tr->ksp_type) {
431*a7e14dcfSSatish Balay 	    ierr = KSPSTCGSetRadius(tao->ksp,tao->trust); CHKERRQ(ierr);
432*a7e14dcfSSatish Balay 	    ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection); CHKERRQ(ierr);
433*a7e14dcfSSatish Balay 	    ierr = KSPGetIterationNumber(tao->ksp,&its); CHKERRQ(ierr);
434*a7e14dcfSSatish Balay 	    tao->ksp_its+=its;
435*a7e14dcfSSatish Balay 	    ierr = KSPSTCGGetNormD(tao->ksp, &norm_d); CHKERRQ(ierr);
436*a7e14dcfSSatish Balay 	  } else { /* NTR_KSP_GLTR */
437*a7e14dcfSSatish Balay 	    ierr = KSPGLTRSetRadius(tao->ksp,tao->trust); CHKERRQ(ierr);
438*a7e14dcfSSatish Balay 	    ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection); CHKERRQ(ierr);
439*a7e14dcfSSatish Balay 	    ierr = KSPGetIterationNumber(tao->ksp,&its); CHKERRQ(ierr);
440*a7e14dcfSSatish Balay 	    tao->ksp_its+=its;
441*a7e14dcfSSatish Balay 	    ierr = KSPGLTRGetNormD(tao->ksp, &norm_d); CHKERRQ(ierr);
442*a7e14dcfSSatish Balay 	  }
443*a7e14dcfSSatish Balay 
444*a7e14dcfSSatish Balay 	  if (norm_d == 0.0) {
445*a7e14dcfSSatish Balay             SETERRQ(PETSC_COMM_SELF,1, "Initial direction zero");
446*a7e14dcfSSatish Balay           }
447*a7e14dcfSSatish Balay         }
448*a7e14dcfSSatish Balay       }
449*a7e14dcfSSatish Balay       ierr = VecScale(tao->stepdirection, -1.0); CHKERRQ(ierr);
450*a7e14dcfSSatish Balay       ierr = KSPGetConvergedReason(tao->ksp, &ksp_reason); CHKERRQ(ierr);
451*a7e14dcfSSatish Balay       if ((KSP_DIVERGED_INDEFINITE_PC == ksp_reason) &&
452*a7e14dcfSSatish Balay           (NTR_PC_BFGS == tr->pc_type) && (bfgsUpdates > 1)) {
453*a7e14dcfSSatish Balay         /* Preconditioner is numerically indefinite; reset the
454*a7e14dcfSSatish Balay 	   approximate if using BFGS preconditioning. */
455*a7e14dcfSSatish Balay 
456*a7e14dcfSSatish Balay         if (f != 0.0) {
457*a7e14dcfSSatish Balay           delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm);
458*a7e14dcfSSatish Balay         }
459*a7e14dcfSSatish Balay         else {
460*a7e14dcfSSatish Balay           delta = 2.0 / (gnorm*gnorm);
461*a7e14dcfSSatish Balay         }
462*a7e14dcfSSatish Balay 	ierr = MatLMVMSetDelta(tr->M, delta); CHKERRQ(ierr);
463*a7e14dcfSSatish Balay 	ierr = MatLMVMReset(tr->M); CHKERRQ(ierr);
464*a7e14dcfSSatish Balay 	ierr = MatLMVMUpdate(tr->M, tao->solution, tao->gradient); CHKERRQ(ierr);
465*a7e14dcfSSatish Balay         bfgsUpdates = 1;
466*a7e14dcfSSatish Balay       }
467*a7e14dcfSSatish Balay 
468*a7e14dcfSSatish Balay       if (NTR_UPDATE_REDUCTION == tr->update_type) {
469*a7e14dcfSSatish Balay 	/* Get predicted reduction */
470*a7e14dcfSSatish Balay 	if (NTR_KSP_NASH == tr->ksp_type) {
471*a7e14dcfSSatish Balay 	  ierr = KSPNASHGetObjFcn(tao->ksp,&prered); CHKERRQ(ierr);
472*a7e14dcfSSatish Balay 	} else if (NTR_KSP_STCG == tr->ksp_type) {
473*a7e14dcfSSatish Balay 	  ierr = KSPSTCGGetObjFcn(tao->ksp,&prered); CHKERRQ(ierr);
474*a7e14dcfSSatish Balay 	} else { /* gltr */
475*a7e14dcfSSatish Balay 	  ierr = KSPGLTRGetObjFcn(tao->ksp,&prered); CHKERRQ(ierr);
476*a7e14dcfSSatish Balay 	}
477*a7e14dcfSSatish Balay 
478*a7e14dcfSSatish Balay 	if (prered >= 0.0) {
479*a7e14dcfSSatish Balay 	  /* The predicted reduction has the wrong sign.  This cannot
480*a7e14dcfSSatish Balay 	     happen in infinite precision arithmetic.  Step should
481*a7e14dcfSSatish Balay 	     be rejected! */
482*a7e14dcfSSatish Balay 	  tao->trust = tr->alpha1 * PetscMin(tao->trust, norm_d);
483*a7e14dcfSSatish Balay 	}
484*a7e14dcfSSatish Balay 	else {
485*a7e14dcfSSatish Balay 	  /* Compute trial step and function value */
486*a7e14dcfSSatish Balay 	  ierr = VecCopy(tao->solution,tr->W); CHKERRQ(ierr);
487*a7e14dcfSSatish Balay 	  ierr = VecAXPY(tr->W, 1.0, tao->stepdirection); CHKERRQ(ierr);
488*a7e14dcfSSatish Balay 	  ierr = TaoComputeObjective(tao, tr->W, &ftrial); CHKERRQ(ierr);
489*a7e14dcfSSatish Balay 
490*a7e14dcfSSatish Balay 	  if (PetscIsInfOrNanReal(ftrial)) {
491*a7e14dcfSSatish Balay 	    tao->trust = tr->alpha1 * PetscMin(tao->trust, norm_d);
492*a7e14dcfSSatish Balay 	  } else {
493*a7e14dcfSSatish Balay 	    /* Compute and actual reduction */
494*a7e14dcfSSatish Balay 	    actred = f - ftrial;
495*a7e14dcfSSatish Balay 	    prered = -prered;
496*a7e14dcfSSatish Balay 	    if ((PetscAbsScalar(actred) <= tr->epsilon) &&
497*a7e14dcfSSatish Balay                 (PetscAbsScalar(prered) <= tr->epsilon)) {
498*a7e14dcfSSatish Balay 	      kappa = 1.0;
499*a7e14dcfSSatish Balay 	    }
500*a7e14dcfSSatish Balay 	    else {
501*a7e14dcfSSatish Balay 	      kappa = actred / prered;
502*a7e14dcfSSatish Balay 	    }
503*a7e14dcfSSatish Balay 
504*a7e14dcfSSatish Balay 	    /* Accept or reject the step and update radius */
505*a7e14dcfSSatish Balay 	    if (kappa < tr->eta1) {
506*a7e14dcfSSatish Balay 	      /* Reject the step */
507*a7e14dcfSSatish Balay 	      tao->trust = tr->alpha1 * PetscMin(tao->trust, norm_d);
508*a7e14dcfSSatish Balay 	    }
509*a7e14dcfSSatish Balay 	    else {
510*a7e14dcfSSatish Balay 	      /* Accept the step */
511*a7e14dcfSSatish Balay 	      if (kappa < tr->eta2) {
512*a7e14dcfSSatish Balay 		/* Marginal bad step */
513*a7e14dcfSSatish Balay 		tao->trust = tr->alpha2 * PetscMin(tao->trust, norm_d);
514*a7e14dcfSSatish Balay 	      }
515*a7e14dcfSSatish Balay 	      else if (kappa < tr->eta3) {
516*a7e14dcfSSatish Balay 		/* Reasonable step */
517*a7e14dcfSSatish Balay 		tao->trust = tr->alpha3 * tao->trust;
518*a7e14dcfSSatish Balay 	      }
519*a7e14dcfSSatish Balay 	      else if (kappa < tr->eta4) {
520*a7e14dcfSSatish Balay 		/* Good step */
521*a7e14dcfSSatish Balay 		tao->trust = PetscMax(tr->alpha4 * norm_d, tao->trust);
522*a7e14dcfSSatish Balay 	      }
523*a7e14dcfSSatish Balay 	      else {
524*a7e14dcfSSatish Balay 		/* Very good step */
525*a7e14dcfSSatish Balay 		tao->trust = PetscMax(tr->alpha5 * norm_d, tao->trust);
526*a7e14dcfSSatish Balay 	      }
527*a7e14dcfSSatish Balay 	      break;
528*a7e14dcfSSatish Balay 	    }
529*a7e14dcfSSatish Balay 	  }
530*a7e14dcfSSatish Balay 	}
531*a7e14dcfSSatish Balay       }
532*a7e14dcfSSatish Balay       else {
533*a7e14dcfSSatish Balay 	/* Get predicted reduction */
534*a7e14dcfSSatish Balay 	if (NTR_KSP_NASH == tr->ksp_type) {
535*a7e14dcfSSatish Balay 	  ierr = KSPNASHGetObjFcn(tao->ksp,&prered); CHKERRQ(ierr);
536*a7e14dcfSSatish Balay 	} else if (NTR_KSP_STCG == tr->ksp_type) {
537*a7e14dcfSSatish Balay 	  ierr = KSPSTCGGetObjFcn(tao->ksp,&prered); CHKERRQ(ierr);
538*a7e14dcfSSatish Balay 	} else { /* gltr */
539*a7e14dcfSSatish Balay 	  ierr = KSPGLTRGetObjFcn(tao->ksp,&prered); CHKERRQ(ierr);
540*a7e14dcfSSatish Balay 	}
541*a7e14dcfSSatish Balay 
542*a7e14dcfSSatish Balay 	if (prered >= 0.0) {
543*a7e14dcfSSatish Balay 	  /* The predicted reduction has the wrong sign.  This cannot
544*a7e14dcfSSatish Balay 	     happen in infinite precision arithmetic.  Step should
545*a7e14dcfSSatish Balay 	     be rejected! */
546*a7e14dcfSSatish Balay 	  tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d);
547*a7e14dcfSSatish Balay 	}
548*a7e14dcfSSatish Balay 	else {
549*a7e14dcfSSatish Balay 	  ierr = VecCopy(tao->solution, tr->W); CHKERRQ(ierr);
550*a7e14dcfSSatish Balay 	  ierr = VecAXPY(tr->W, 1.0, tao->stepdirection); CHKERRQ(ierr);
551*a7e14dcfSSatish Balay 	  ierr = TaoComputeObjective(tao, tr->W, &ftrial); CHKERRQ(ierr);
552*a7e14dcfSSatish Balay 	  if (PetscIsInfOrNanReal(ftrial)) {
553*a7e14dcfSSatish Balay 	    tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d);
554*a7e14dcfSSatish Balay 	  }
555*a7e14dcfSSatish Balay 	  else {
556*a7e14dcfSSatish Balay 	    ierr = VecDot(tao->gradient, tao->stepdirection, &beta); CHKERRQ(ierr);
557*a7e14dcfSSatish Balay 	    actred = f - ftrial;
558*a7e14dcfSSatish Balay 	    prered = -prered;
559*a7e14dcfSSatish Balay 	    if ((PetscAbsScalar(actred) <= tr->epsilon) &&
560*a7e14dcfSSatish Balay                 (PetscAbsScalar(prered) <= tr->epsilon)) {
561*a7e14dcfSSatish Balay 	      kappa = 1.0;
562*a7e14dcfSSatish Balay 	    }
563*a7e14dcfSSatish Balay 	    else {
564*a7e14dcfSSatish Balay 	      kappa = actred / prered;
565*a7e14dcfSSatish Balay 	    }
566*a7e14dcfSSatish Balay 
567*a7e14dcfSSatish Balay 	    tau_1 = tr->theta * beta / (tr->theta * beta - (1.0 - tr->theta) * prered + actred);
568*a7e14dcfSSatish Balay 	    tau_2 = tr->theta * beta / (tr->theta * beta + (1.0 + tr->theta) * prered - actred);
569*a7e14dcfSSatish Balay 	    tau_min = PetscMin(tau_1, tau_2);
570*a7e14dcfSSatish Balay 	    tau_max = PetscMax(tau_1, tau_2);
571*a7e14dcfSSatish Balay 
572*a7e14dcfSSatish Balay 	    if (kappa >= 1.0 - tr->mu1) {
573*a7e14dcfSSatish Balay 	      /* Great agreement; accept step and update radius */
574*a7e14dcfSSatish Balay 	      if (tau_max < 1.0) {
575*a7e14dcfSSatish Balay 		tao->trust = PetscMax(tao->trust, tr->gamma3 * norm_d);
576*a7e14dcfSSatish Balay 	      }
577*a7e14dcfSSatish Balay 	      else if (tau_max > tr->gamma4) {
578*a7e14dcfSSatish Balay 		tao->trust = PetscMax(tao->trust, tr->gamma4 * norm_d);
579*a7e14dcfSSatish Balay 	      }
580*a7e14dcfSSatish Balay 	      else {
581*a7e14dcfSSatish Balay 		tao->trust = PetscMax(tao->trust, tau_max * norm_d);
582*a7e14dcfSSatish Balay 	      }
583*a7e14dcfSSatish Balay 	      break;
584*a7e14dcfSSatish Balay 	    }
585*a7e14dcfSSatish Balay 	    else if (kappa >= 1.0 - tr->mu2) {
586*a7e14dcfSSatish Balay 	      /* Good agreement */
587*a7e14dcfSSatish Balay 
588*a7e14dcfSSatish Balay 	      if (tau_max < tr->gamma2) {
589*a7e14dcfSSatish Balay 		tao->trust = tr->gamma2 * PetscMin(tao->trust, norm_d);
590*a7e14dcfSSatish Balay 	      }
591*a7e14dcfSSatish Balay 	      else if (tau_max > tr->gamma3) {
592*a7e14dcfSSatish Balay 		tao->trust = PetscMax(tao->trust, tr->gamma3 * norm_d);
593*a7e14dcfSSatish Balay 	      }
594*a7e14dcfSSatish Balay 	      else if (tau_max < 1.0) {
595*a7e14dcfSSatish Balay 		tao->trust = tau_max * PetscMin(tao->trust, norm_d);
596*a7e14dcfSSatish Balay 	      }
597*a7e14dcfSSatish Balay 	      else {
598*a7e14dcfSSatish Balay 		tao->trust = PetscMax(tao->trust, tau_max * norm_d);
599*a7e14dcfSSatish Balay 	      }
600*a7e14dcfSSatish Balay 	      break;
601*a7e14dcfSSatish Balay 	    }
602*a7e14dcfSSatish Balay 	    else {
603*a7e14dcfSSatish Balay 	      /* Not good agreement */
604*a7e14dcfSSatish Balay 	      if (tau_min > 1.0) {
605*a7e14dcfSSatish Balay 		tao->trust = tr->gamma2 * PetscMin(tao->trust, norm_d);
606*a7e14dcfSSatish Balay 	      }
607*a7e14dcfSSatish Balay 	      else if (tau_max < tr->gamma1) {
608*a7e14dcfSSatish Balay 		tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d);
609*a7e14dcfSSatish Balay 	      }
610*a7e14dcfSSatish Balay 	      else if ((tau_min < tr->gamma1) && (tau_max >= 1.0)) {
611*a7e14dcfSSatish Balay 		tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d);
612*a7e14dcfSSatish Balay 	      }
613*a7e14dcfSSatish Balay 	      else if ((tau_1 >= tr->gamma1) && (tau_1 < 1.0) &&
614*a7e14dcfSSatish Balay 		       ((tau_2 < tr->gamma1) || (tau_2 >= 1.0))) {
615*a7e14dcfSSatish Balay 		tao->trust = tau_1 * PetscMin(tao->trust, norm_d);
616*a7e14dcfSSatish Balay 	      }
617*a7e14dcfSSatish Balay 	      else if ((tau_2 >= tr->gamma1) && (tau_2 < 1.0) &&
618*a7e14dcfSSatish Balay 		       ((tau_1 < tr->gamma1) || (tau_2 >= 1.0))) {
619*a7e14dcfSSatish Balay 		tao->trust = tau_2 * PetscMin(tao->trust, norm_d);
620*a7e14dcfSSatish Balay 	      }
621*a7e14dcfSSatish Balay 	      else {
622*a7e14dcfSSatish Balay 		tao->trust = tau_max * PetscMin(tao->trust, norm_d);
623*a7e14dcfSSatish Balay 	      }
624*a7e14dcfSSatish Balay 	    }
625*a7e14dcfSSatish Balay 	  }
626*a7e14dcfSSatish Balay 	}
627*a7e14dcfSSatish Balay       }
628*a7e14dcfSSatish Balay 
629*a7e14dcfSSatish Balay       /* The step computed was not good and the radius was decreased.
630*a7e14dcfSSatish Balay 	 Monitor the radius to terminate. */
631*a7e14dcfSSatish Balay       ierr = TaoMonitor(tao, iter, f, gnorm, 0.0, tao->trust, &reason); CHKERRQ(ierr);
632*a7e14dcfSSatish Balay     }
633*a7e14dcfSSatish Balay 
634*a7e14dcfSSatish Balay     /* The radius may have been increased; modify if it is too large */
635*a7e14dcfSSatish Balay     tao->trust = PetscMin(tao->trust, tr->max_radius);
636*a7e14dcfSSatish Balay 
637*a7e14dcfSSatish Balay     if (reason == TAO_CONTINUE_ITERATING) {
638*a7e14dcfSSatish Balay       ierr = VecCopy(tr->W, tao->solution); CHKERRQ(ierr);
639*a7e14dcfSSatish Balay       f = ftrial;
640*a7e14dcfSSatish Balay       ierr = TaoComputeGradient(tao, tao->solution, tao->gradient);
641*a7e14dcfSSatish Balay       ierr = VecNorm(tao->gradient, NORM_2, &gnorm); CHKERRQ(ierr);
642*a7e14dcfSSatish Balay       if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) {
643*a7e14dcfSSatish Balay 	SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
644*a7e14dcfSSatish Balay       }
645*a7e14dcfSSatish Balay       needH = 1;
646*a7e14dcfSSatish Balay       ierr = TaoMonitor(tao, iter, f, gnorm, 0.0, tao->trust, &reason); CHKERRQ(ierr);
647*a7e14dcfSSatish Balay     }
648*a7e14dcfSSatish Balay   }
649*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
650*a7e14dcfSSatish Balay }
651*a7e14dcfSSatish Balay 
652*a7e14dcfSSatish Balay /*------------------------------------------------------------*/
653*a7e14dcfSSatish Balay #undef __FUNCT__
654*a7e14dcfSSatish Balay #define __FUNCT__ "TaoSetUp_NTR"
655*a7e14dcfSSatish Balay static PetscErrorCode TaoSetUp_NTR(TaoSolver tao)
656*a7e14dcfSSatish Balay {
657*a7e14dcfSSatish Balay   TAO_NTR *tr = (TAO_NTR *)tao->data;
658*a7e14dcfSSatish Balay   PetscErrorCode ierr;
659*a7e14dcfSSatish Balay 
660*a7e14dcfSSatish Balay   PetscFunctionBegin;
661*a7e14dcfSSatish Balay 
662*a7e14dcfSSatish Balay   if (!tao->gradient) {ierr = VecDuplicate(tao->solution, &tao->gradient); CHKERRQ(ierr);}
663*a7e14dcfSSatish Balay   if (!tao->stepdirection) {ierr = VecDuplicate(tao->solution, &tao->stepdirection); CHKERRQ(ierr);}
664*a7e14dcfSSatish Balay   if (!tr->W) {ierr = VecDuplicate(tao->solution, &tr->W); CHKERRQ(ierr);}
665*a7e14dcfSSatish Balay 
666*a7e14dcfSSatish Balay   tr->Diag = 0;
667*a7e14dcfSSatish Balay   tr->M = 0;
668*a7e14dcfSSatish Balay 
669*a7e14dcfSSatish Balay 
670*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
671*a7e14dcfSSatish Balay }
672*a7e14dcfSSatish Balay 
673*a7e14dcfSSatish Balay /*------------------------------------------------------------*/
674*a7e14dcfSSatish Balay #undef __FUNCT__
675*a7e14dcfSSatish Balay #define __FUNCT__ "TaoDestroy_NTR"
676*a7e14dcfSSatish Balay static PetscErrorCode TaoDestroy_NTR(TaoSolver tao)
677*a7e14dcfSSatish Balay {
678*a7e14dcfSSatish Balay   TAO_NTR *tr = (TAO_NTR *)tao->data;
679*a7e14dcfSSatish Balay   PetscErrorCode ierr;
680*a7e14dcfSSatish Balay 
681*a7e14dcfSSatish Balay   PetscFunctionBegin;
682*a7e14dcfSSatish Balay   if (tao->setupcalled) {
683*a7e14dcfSSatish Balay     ierr = VecDestroy(&tr->W); CHKERRQ(ierr);
684*a7e14dcfSSatish Balay   }
685*a7e14dcfSSatish Balay   if (tr->M) {
686*a7e14dcfSSatish Balay     ierr = MatDestroy(&tr->M); CHKERRQ(ierr);
687*a7e14dcfSSatish Balay     tr->M = PETSC_NULL;
688*a7e14dcfSSatish Balay   }
689*a7e14dcfSSatish Balay   if (tr->Diag) {
690*a7e14dcfSSatish Balay     ierr = VecDestroy(&tr->Diag); CHKERRQ(ierr);
691*a7e14dcfSSatish Balay     tr->Diag = PETSC_NULL;
692*a7e14dcfSSatish Balay   }
693*a7e14dcfSSatish Balay   ierr = PetscFree(tao->data); CHKERRQ(ierr);
694*a7e14dcfSSatish Balay   tao->data = PETSC_NULL;
695*a7e14dcfSSatish Balay 
696*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
697*a7e14dcfSSatish Balay }
698*a7e14dcfSSatish Balay 
699*a7e14dcfSSatish Balay /*------------------------------------------------------------*/
700*a7e14dcfSSatish Balay #undef __FUNCT__
701*a7e14dcfSSatish Balay #define __FUNCT__ "TaoSetFromOptions_NTR"
702*a7e14dcfSSatish Balay static PetscErrorCode TaoSetFromOptions_NTR(TaoSolver tao)
703*a7e14dcfSSatish Balay {
704*a7e14dcfSSatish Balay   TAO_NTR *tr = (TAO_NTR *)tao->data;
705*a7e14dcfSSatish Balay   PetscErrorCode ierr;
706*a7e14dcfSSatish Balay 
707*a7e14dcfSSatish Balay   PetscFunctionBegin;
708*a7e14dcfSSatish Balay   ierr = PetscOptionsHead("Newton trust region method for unconstrained optimization"); CHKERRQ(ierr);
709*a7e14dcfSSatish Balay   ierr = PetscOptionsEList("-tao_ntr_ksp_type", "ksp type", "", NTR_KSP, NTR_KSP_TYPES, NTR_KSP[tr->ksp_type], &tr->ksp_type, 0); CHKERRQ(ierr);
710*a7e14dcfSSatish Balay   ierr = PetscOptionsEList("-tao_ntr_pc_type", "pc type", "", NTR_PC, NTR_PC_TYPES, NTR_PC[tr->pc_type], &tr->pc_type, 0); CHKERRQ(ierr);
711*a7e14dcfSSatish Balay   ierr = PetscOptionsEList("-tao_ntr_bfgs_scale_type", "bfgs scale type", "", BFGS_SCALE, BFGS_SCALE_TYPES, BFGS_SCALE[tr->bfgs_scale_type], &tr->bfgs_scale_type, 0); CHKERRQ(ierr);
712*a7e14dcfSSatish Balay   ierr = PetscOptionsEList("-tao_ntr_init_type", "tao->trust initialization type", "", NTR_INIT, NTR_INIT_TYPES, NTR_INIT[tr->init_type], &tr->init_type, 0); CHKERRQ(ierr);
713*a7e14dcfSSatish Balay   ierr = PetscOptionsEList("-tao_ntr_update_type", "radius update type", "", NTR_UPDATE, NTR_UPDATE_TYPES, NTR_UPDATE[tr->update_type], &tr->update_type, 0); CHKERRQ(ierr);
714*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_eta1", "step is unsuccessful if actual reduction < eta1 * predicted reduction", "", tr->eta1, &tr->eta1, 0); CHKERRQ(ierr);
715*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_eta2", "", "", tr->eta2, &tr->eta2, 0); CHKERRQ(ierr);
716*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_eta3", "", "", tr->eta3, &tr->eta3, 0); CHKERRQ(ierr);
717*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_eta4", "", "", tr->eta4, &tr->eta4, 0); CHKERRQ(ierr);
718*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_alpha1", "", "", tr->alpha1, &tr->alpha1, 0); CHKERRQ(ierr);
719*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_alpha2", "", "", tr->alpha2, &tr->alpha2, 0); CHKERRQ(ierr);
720*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_alpha3", "", "", tr->alpha3, &tr->alpha3, 0); CHKERRQ(ierr);
721*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_alpha4", "", "", tr->alpha4, &tr->alpha4, 0); CHKERRQ(ierr);
722*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_alpha5", "", "", tr->alpha5, &tr->alpha5, 0); CHKERRQ(ierr);
723*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_mu1", "", "", tr->mu1, &tr->mu1, 0); CHKERRQ(ierr);
724*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_mu2", "", "", tr->mu2, &tr->mu2, 0); CHKERRQ(ierr);
725*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_gamma1", "", "", tr->gamma1, &tr->gamma1, 0); CHKERRQ(ierr);
726*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_gamma2", "", "", tr->gamma2, &tr->gamma2, 0); CHKERRQ(ierr);
727*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_gamma3", "", "", tr->gamma3, &tr->gamma3, 0); CHKERRQ(ierr);
728*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_gamma4", "", "", tr->gamma4, &tr->gamma4, 0); CHKERRQ(ierr);
729*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_theta", "", "", tr->theta, &tr->theta, 0); CHKERRQ(ierr);
730*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_mu1_i", "", "", tr->mu1_i, &tr->mu1_i, 0); CHKERRQ(ierr);
731*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_mu2_i", "", "", tr->mu2_i, &tr->mu2_i, 0); CHKERRQ(ierr);
732*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_gamma1_i", "", "", tr->gamma1_i, &tr->gamma1_i, 0); CHKERRQ(ierr);
733*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_gamma2_i", "", "", tr->gamma2_i, &tr->gamma2_i, 0); CHKERRQ(ierr);
734*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_gamma3_i", "", "", tr->gamma3_i, &tr->gamma3_i, 0); CHKERRQ(ierr);
735*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_gamma4_i", "", "", tr->gamma4_i, &tr->gamma4_i, 0); CHKERRQ(ierr);
736*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_theta_i", "", "", tr->theta_i, &tr->theta_i, 0); CHKERRQ(ierr);
737*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_min_radius", "lower bound on initial trust-region radius", "", tr->min_radius, &tr->min_radius, 0); CHKERRQ(ierr);
738*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_max_radius", "upper bound on trust-region radius", "", tr->max_radius, &tr->max_radius, 0); CHKERRQ(ierr);
739*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_ntr_epsilon", "tolerance used when computing actual and predicted reduction", "", tr->epsilon, &tr->epsilon, 0); CHKERRQ(ierr);
740*a7e14dcfSSatish Balay   ierr = PetscOptionsTail(); CHKERRQ(ierr);
741*a7e14dcfSSatish Balay   ierr = KSPSetFromOptions(tao->ksp); CHKERRQ(ierr);
742*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
743*a7e14dcfSSatish Balay }
744*a7e14dcfSSatish Balay 
745*a7e14dcfSSatish Balay /*------------------------------------------------------------*/
746*a7e14dcfSSatish Balay #undef __FUNCT__
747*a7e14dcfSSatish Balay #define __FUNCT__ "TaoView_NTR"
748*a7e14dcfSSatish Balay static PetscErrorCode TaoView_NTR(TaoSolver tao, PetscViewer viewer)
749*a7e14dcfSSatish Balay {
750*a7e14dcfSSatish Balay   TAO_NTR *tr = (TAO_NTR *)tao->data;
751*a7e14dcfSSatish Balay   PetscErrorCode ierr;
752*a7e14dcfSSatish Balay   PetscInt nrejects;
753*a7e14dcfSSatish Balay   PetscBool isascii;
754*a7e14dcfSSatish Balay   PetscFunctionBegin;
755*a7e14dcfSSatish Balay   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
756*a7e14dcfSSatish Balay   if (isascii) {
757*a7e14dcfSSatish Balay     ierr = PetscViewerASCIIPushTab(viewer); CHKERRQ(ierr);
758*a7e14dcfSSatish Balay     if (NTR_PC_BFGS == tr->pc_type && tr->M) {
759*a7e14dcfSSatish Balay       ierr = MatLMVMGetRejects(tr->M, &nrejects); CHKERRQ(ierr);
760*a7e14dcfSSatish Balay       ierr = PetscViewerASCIIPrintf(viewer, "Rejected matrix updates: %D\n", nrejects); CHKERRQ(ierr);
761*a7e14dcfSSatish Balay     }
762*a7e14dcfSSatish Balay     ierr = PetscViewerASCIIPopTab(viewer); CHKERRQ(ierr);
763*a7e14dcfSSatish Balay 
764*a7e14dcfSSatish Balay   } else {
765*a7e14dcfSSatish Balay     SETERRQ1(((PetscObject)tao)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for TAO NTR",((PetscObject)viewer)->type_name);
766*a7e14dcfSSatish Balay   }
767*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
768*a7e14dcfSSatish Balay }
769*a7e14dcfSSatish Balay 
770*a7e14dcfSSatish Balay /*------------------------------------------------------------*/
771*a7e14dcfSSatish Balay EXTERN_C_BEGIN
772*a7e14dcfSSatish Balay #undef __FUNCT__
773*a7e14dcfSSatish Balay #define __FUNCT__ "TaoCreate_NTR"
774*a7e14dcfSSatish Balay PetscErrorCode TaoCreate_NTR(TaoSolver tao)
775*a7e14dcfSSatish Balay {
776*a7e14dcfSSatish Balay   TAO_NTR *tr;
777*a7e14dcfSSatish Balay   PetscErrorCode ierr;
778*a7e14dcfSSatish Balay 
779*a7e14dcfSSatish Balay   PetscFunctionBegin;
780*a7e14dcfSSatish Balay 
781*a7e14dcfSSatish Balay   ierr = PetscNewLog(tao, TAO_NTR, &tr); CHKERRQ(ierr);
782*a7e14dcfSSatish Balay 
783*a7e14dcfSSatish Balay   tao->ops->setup = TaoSetUp_NTR;
784*a7e14dcfSSatish Balay   tao->ops->solve = TaoSolve_NTR;
785*a7e14dcfSSatish Balay   tao->ops->view = TaoView_NTR;
786*a7e14dcfSSatish Balay   tao->ops->setfromoptions = TaoSetFromOptions_NTR;
787*a7e14dcfSSatish Balay   tao->ops->destroy = TaoDestroy_NTR;
788*a7e14dcfSSatish Balay 
789*a7e14dcfSSatish Balay   tao->max_it = 50;
790*a7e14dcfSSatish Balay   tao->fatol = 1e-10;
791*a7e14dcfSSatish Balay   tao->frtol = 1e-10;
792*a7e14dcfSSatish Balay   tao->data = (void*)tr;
793*a7e14dcfSSatish Balay 
794*a7e14dcfSSatish Balay   tao->trust0 = 100.0;
795*a7e14dcfSSatish Balay 
796*a7e14dcfSSatish Balay   /*  Standard trust region update parameters */
797*a7e14dcfSSatish Balay   tr->eta1 = 1.0e-4;
798*a7e14dcfSSatish Balay   tr->eta2 = 0.25;
799*a7e14dcfSSatish Balay   tr->eta3 = 0.50;
800*a7e14dcfSSatish Balay   tr->eta4 = 0.90;
801*a7e14dcfSSatish Balay 
802*a7e14dcfSSatish Balay   tr->alpha1 = 0.25;
803*a7e14dcfSSatish Balay   tr->alpha2 = 0.50;
804*a7e14dcfSSatish Balay   tr->alpha3 = 1.00;
805*a7e14dcfSSatish Balay   tr->alpha4 = 2.00;
806*a7e14dcfSSatish Balay   tr->alpha5 = 4.00;
807*a7e14dcfSSatish Balay 
808*a7e14dcfSSatish Balay   /*  Interpolation parameters */
809*a7e14dcfSSatish Balay   tr->mu1_i = 0.35;
810*a7e14dcfSSatish Balay   tr->mu2_i = 0.50;
811*a7e14dcfSSatish Balay 
812*a7e14dcfSSatish Balay   tr->gamma1_i = 0.0625;
813*a7e14dcfSSatish Balay   tr->gamma2_i = 0.50;
814*a7e14dcfSSatish Balay   tr->gamma3_i = 2.00;
815*a7e14dcfSSatish Balay   tr->gamma4_i = 5.00;
816*a7e14dcfSSatish Balay 
817*a7e14dcfSSatish Balay   tr->theta_i = 0.25;
818*a7e14dcfSSatish Balay 
819*a7e14dcfSSatish Balay   /*  Interpolation trust region update parameters */
820*a7e14dcfSSatish Balay   tr->mu1 = 0.10;
821*a7e14dcfSSatish Balay   tr->mu2 = 0.50;
822*a7e14dcfSSatish Balay 
823*a7e14dcfSSatish Balay   tr->gamma1 = 0.25;
824*a7e14dcfSSatish Balay   tr->gamma2 = 0.50;
825*a7e14dcfSSatish Balay   tr->gamma3 = 2.00;
826*a7e14dcfSSatish Balay   tr->gamma4 = 4.00;
827*a7e14dcfSSatish Balay 
828*a7e14dcfSSatish Balay   tr->theta = 0.05;
829*a7e14dcfSSatish Balay 
830*a7e14dcfSSatish Balay   tr->min_radius = 1.0e-10;
831*a7e14dcfSSatish Balay   tr->max_radius = 1.0e10;
832*a7e14dcfSSatish Balay   tr->epsilon = 1.0e-6;
833*a7e14dcfSSatish Balay 
834*a7e14dcfSSatish Balay   tr->ksp_type        = NTR_KSP_STCG;
835*a7e14dcfSSatish Balay   tr->pc_type         = NTR_PC_BFGS;
836*a7e14dcfSSatish Balay   tr->bfgs_scale_type = BFGS_SCALE_AHESS;
837*a7e14dcfSSatish Balay   tr->init_type	      = NTR_INIT_INTERPOLATION;
838*a7e14dcfSSatish Balay   tr->update_type     = NTR_UPDATE_REDUCTION;
839*a7e14dcfSSatish Balay 
840*a7e14dcfSSatish Balay 
841*a7e14dcfSSatish Balay   /* Set linear solver to default for trust region */
842*a7e14dcfSSatish Balay   ierr = KSPCreate(((PetscObject)tao)->comm, &tao->ksp); CHKERRQ(ierr);
843*a7e14dcfSSatish Balay 
844*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
845*a7e14dcfSSatish Balay 
846*a7e14dcfSSatish Balay 
847*a7e14dcfSSatish Balay }
848*a7e14dcfSSatish Balay EXTERN_C_END
849*a7e14dcfSSatish Balay 
850*a7e14dcfSSatish Balay 
851*a7e14dcfSSatish Balay #undef __FUNCT__
852*a7e14dcfSSatish Balay #define __FUNCT__ "MatLMVMSolveShell"
853*a7e14dcfSSatish Balay static PetscErrorCode MatLMVMSolveShell(PC pc, Vec b, Vec x)
854*a7e14dcfSSatish Balay {
855*a7e14dcfSSatish Balay     PetscErrorCode ierr;
856*a7e14dcfSSatish Balay     Mat M;
857*a7e14dcfSSatish Balay     PetscFunctionBegin;
858*a7e14dcfSSatish Balay     PetscValidHeaderSpecific(pc,PC_CLASSID,1);
859*a7e14dcfSSatish Balay     PetscValidHeaderSpecific(b,VEC_CLASSID,2);
860*a7e14dcfSSatish Balay     PetscValidHeaderSpecific(x,VEC_CLASSID,3);
861*a7e14dcfSSatish Balay     ierr = PCShellGetContext(pc,(void**)&M); CHKERRQ(ierr);
862*a7e14dcfSSatish Balay     ierr = MatLMVMSolve(M, b, x); CHKERRQ(ierr);
863*a7e14dcfSSatish Balay     PetscFunctionReturn(0);
864*a7e14dcfSSatish Balay }
865