xref: /petsc/src/snes/impls/vi/vi.c (revision 9fb22e1a5a92dd4c1f6b11e8d40bcaba12a7ec6d)
1 #define PETSCSNES_DLL
2 
3 #include "../src/snes/impls/vi/viimpl.h"
4 
5 /*
6      Checks if J^T F = 0 which implies we've found a local minimum of the norm of the function,
7     || F(u) ||_2 but not a zero, F(u) = 0. In the case when one cannot compute J^T F we use the fact that
8     0 = (J^T F)^T W = F^T J W iff W not in the null space of J. Thanks for Jorge More
9     for this trick. One assumes that the probability that W is in the null space of J is very, very small.
10 */
11 #undef __FUNCT__
12 #define __FUNCT__ "SNESVICheckLocalMin_Private"
13 PetscErrorCode SNESVICheckLocalMin_Private(SNES snes,Mat A,Vec F,Vec W,PetscReal fnorm,PetscTruth *ismin)
14 {
15   PetscReal      a1;
16   PetscErrorCode ierr;
17   PetscTruth     hastranspose;
18 
19   PetscFunctionBegin;
20   *ismin = PETSC_FALSE;
21   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
22   if (hastranspose) {
23     /* Compute || J^T F|| */
24     ierr = MatMultTranspose(A,F,W);CHKERRQ(ierr);
25     ierr = VecNorm(W,NORM_2,&a1);CHKERRQ(ierr);
26     ierr = PetscInfo1(snes,"|| J^T F|| %G near zero implies found a local minimum\n",a1/fnorm);CHKERRQ(ierr);
27     if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE;
28   } else {
29     Vec         work;
30     PetscScalar result;
31     PetscReal   wnorm;
32 
33     ierr = VecSetRandom(W,PETSC_NULL);CHKERRQ(ierr);
34     ierr = VecNorm(W,NORM_2,&wnorm);CHKERRQ(ierr);
35     ierr = VecDuplicate(W,&work);CHKERRQ(ierr);
36     ierr = MatMult(A,W,work);CHKERRQ(ierr);
37     ierr = VecDot(F,work,&result);CHKERRQ(ierr);
38     ierr = VecDestroy(work);CHKERRQ(ierr);
39     a1   = PetscAbsScalar(result)/(fnorm*wnorm);
40     ierr = PetscInfo1(snes,"(F^T J random)/(|| F ||*||random|| %G near zero implies found a local minimum\n",a1);CHKERRQ(ierr);
41     if (a1 < 1.e-4) *ismin = PETSC_TRUE;
42   }
43   PetscFunctionReturn(0);
44 }
45 
46 /*
47      Checks if J^T(F - J*X) = 0
48 */
49 #undef __FUNCT__
50 #define __FUNCT__ "SNESVICheckResidual_Private"
51 PetscErrorCode SNESVICheckResidual_Private(SNES snes,Mat A,Vec F,Vec X,Vec W1,Vec W2)
52 {
53   PetscReal      a1,a2;
54   PetscErrorCode ierr;
55   PetscTruth     hastranspose;
56 
57   PetscFunctionBegin;
58   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
59   if (hastranspose) {
60     ierr = MatMult(A,X,W1);CHKERRQ(ierr);
61     ierr = VecAXPY(W1,-1.0,F);CHKERRQ(ierr);
62 
63     /* Compute || J^T W|| */
64     ierr = MatMultTranspose(A,W1,W2);CHKERRQ(ierr);
65     ierr = VecNorm(W1,NORM_2,&a1);CHKERRQ(ierr);
66     ierr = VecNorm(W2,NORM_2,&a2);CHKERRQ(ierr);
67     if (a1 != 0.0) {
68       ierr = PetscInfo1(snes,"||J^T(F-Ax)||/||F-AX|| %G near zero implies inconsistent rhs\n",a2/a1);CHKERRQ(ierr);
69     }
70   }
71   PetscFunctionReturn(0);
72 }
73 
74 /*
75   SNESDefaultConverged_VI - Checks the convergence of the semismooth newton algorithm.
76 
77   Notes:
78   The convergence criterion currently implemented is
79   merit < abstol
80   merit < rtol*merit_initial
81 */
82 #undef __FUNCT__
83 #define __FUNCT__ "SNESDefaultConverged_VI"
84 PetscErrorCode SNESDefaultConverged_VI(SNES snes,PetscInt it,PetscReal xnorm,PetscReal gradnorm,PetscReal merit,SNESConvergedReason *reason,void *dummy)
85 {
86   PetscErrorCode ierr;
87 
88   PetscFunctionBegin;
89   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
90   PetscValidPointer(reason,6);
91 
92   *reason = SNES_CONVERGED_ITERATING;
93 
94   if (!it) {
95     /* set parameter for default relative tolerance convergence test */
96     snes->ttol = merit*snes->rtol;
97   }
98   if (merit != merit) {
99     ierr = PetscInfo(snes,"Failed to converged, function norm is NaN\n");CHKERRQ(ierr);
100     *reason = SNES_DIVERGED_FNORM_NAN;
101   } else if (merit < snes->abstol) {
102     ierr = PetscInfo2(snes,"Converged due to merit function %G < %G\n",merit,snes->abstol);CHKERRQ(ierr);
103     *reason = SNES_CONVERGED_FNORM_ABS;
104   } else if (snes->nfuncs >= snes->max_funcs) {
105     ierr = PetscInfo2(snes,"Exceeded maximum number of function evaluations: %D > %D\n",snes->nfuncs,snes->max_funcs);CHKERRQ(ierr);
106     *reason = SNES_DIVERGED_FUNCTION_COUNT;
107   }
108 
109   if (it && !*reason) {
110     if (merit < snes->ttol) {
111       ierr = PetscInfo2(snes,"Converged due to merit function %G < %G (relative tolerance)\n",merit,snes->ttol);CHKERRQ(ierr);
112       *reason = SNES_CONVERGED_FNORM_RELATIVE;
113     }
114   }
115   PetscFunctionReturn(0);
116 }
117 
118 /*
119   SNESVIComputeMeritFunction - Evaluates the merit function for the mixed complementarity problem.
120 
121   Input Parameter:
122 . phi - the semismooth function
123 
124   Output Parameter:
125 . merit - the merit function
126 . phinorm - ||phi||
127 
128   Notes:
129   The merit function for the mixed complementarity problem is defined as
130      merit = 0.5*phi^T*phi
131 */
132 #undef __FUNCT__
133 #define __FUNCT__ "SNESVIComputeMeritFunction"
134 static PetscErrorCode SNESVIComputeMeritFunction(Vec phi, PetscReal* merit,PetscReal* phinorm)
135 {
136   PetscErrorCode ierr;
137 
138   PetscFunctionBegin;
139   ierr = VecNormBegin(phi,NORM_2,phinorm);
140   ierr = VecNormEnd(phi,NORM_2,phinorm);
141 
142   *merit = 0.5*(*phinorm)*(*phinorm);
143   PetscFunctionReturn(0);
144 }
145 
146 /*
147   ComputeFischerFunction - Computes the semismooth fischer burmeister function for a mixed complementarity equation.
148 
149   Notes:
150   The Fischer-Burmeister function is defined as
151        ff(a,b) := sqrt(a*a + b*b) - a - b
152   and is used reformulate a complementarity equation  as a semismooth equation.
153 */
154 
155 #undef __FUNCT__
156 #define __FUNCT__ "ComputeFischerFunction"
157 static PetscErrorCode ComputeFischerFunction(PetscScalar a, PetscScalar b, PetscScalar* ff)
158 {
159   PetscFunctionBegin;
160   *ff = sqrt(a*a + b*b) - a - b;
161   PetscFunctionReturn(0);
162 }
163 
164 /*
165    SNESVIComputeFunction - Reformulates a system of nonlinear equations in mixed complementarity form to a system of nonlinear equations in semismooth form.
166 
167    Input Parameters:
168 .  snes - the SNES context
169 .  x - current iterate
170 .  functx - user defined function context
171 
172    Output Parameters:
173 .  phi - Semismooth function
174 
175    Notes:
176    The result of this function is done by cases:
177 +  l[i] == -infinity, u[i] == infinity  -- phi[i] = -f[i]
178 .  l[i] == -infinity, u[i] finite       -- phi[i] = ss(u[i]-x[i], -f[i])
179 .  l[i] finite,       u[i] == infinity  -- phi[i] = ss(x[i]-l[i],  f[i])
180 .  l[i] finite < u[i] finite -- phi[i] = phi(x[i]-l[i], ss(u[i]-x[i], -f[u]))
181 -  otherwise l[i] == u[i] -- phi[i] = l[i] - x[i]
182    ss is the semismoothing function used to reformulate the nonlinear equation in complementarity
183    form to semismooth form
184 
185 */
186 #undef __FUNCT__
187 #define __FUNCT__ "SNESVIComputeFunction"
188 static PetscErrorCode SNESVIComputeFunction(SNES snes,Vec X,Vec phi,void* functx)
189 {
190   PetscErrorCode  ierr;
191   SNES_VI       *vi = (SNES_VI*)snes->data;
192   Vec             Xl = vi->xl,Xu = vi->xu,F = snes->vec_func;
193   PetscScalar     *phi_arr,*x_arr,*f_arr,*l,*u,t;
194   PetscInt        i,nlocal;
195 
196   PetscFunctionBegin;
197   ierr = (*vi->computeuserfunction)(snes,X,F,functx);CHKERRQ(ierr);
198   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
199 
200   ierr = VecGetArray(X,&x_arr);CHKERRQ(ierr);
201   ierr = VecGetArray(F,&f_arr);CHKERRQ(ierr);
202   ierr = VecGetArray(Xl,&l);CHKERRQ(ierr);
203   ierr = VecGetArray(Xu,&u);CHKERRQ(ierr);
204   ierr = VecGetArray(phi,&phi_arr);CHKERRQ(ierr);
205 
206   for (i=0;i < nlocal;i++) {
207     if ((l[i] <= PETSC_VI_NINF) && (u[i] >= PETSC_VI_INF)) {
208       phi_arr[i] = -f_arr[i];
209     }
210     else if (l[i] <= PETSC_VI_NINF) {
211       t = u[i] - x_arr[i];
212       ierr = ComputeFischerFunction(t,-f_arr[i],&phi_arr[i]);CHKERRQ(ierr);
213       phi_arr[i] = -phi_arr[i];
214     }
215     else if (u[i] >= PETSC_VI_INF) {
216       t = x_arr[i] - l[i];
217       ierr = ComputeFischerFunction(t,f_arr[i],&phi_arr[i]);CHKERRQ(ierr);
218     }
219     else if (l[i] == u[i]) {
220       phi_arr[i] = l[i] - x_arr[i];
221     }
222     else {
223       t = u[i] - x_arr[i];
224       ierr = ComputeFischerFunction(t,-f_arr[i],&phi_arr[i]);
225       t = x_arr[i] - l[i];
226       ierr = ComputeFischerFunction(t,phi_arr[i],&phi_arr[i]);
227     }
228   }
229 
230   ierr = VecRestoreArray(X,&x_arr);CHKERRQ(ierr);
231   ierr = VecRestoreArray(F,&f_arr);CHKERRQ(ierr);
232   ierr = VecRestoreArray(Xl,&l);CHKERRQ(ierr);
233   ierr = VecRestoreArray(Xu,&u);CHKERRQ(ierr);
234   ierr = VecRestoreArray(phi,&phi_arr);CHKERRQ(ierr);
235 
236   PetscFunctionReturn(0);
237 }
238 
239 /*
240    SNESVIComputeJacobian - Computes the jacobian of the semismooth function.The Jacobian for the semismooth function is an element of the B-subdifferential of the Fischer-Burmeister function for complementarity problems.
241 
242    Input Parameters:
243 .  snes     - the SNES context
244 .  X        - the current iterate
245 .  vec_func - nonlinear function evaluated at x
246 
247    Output Parameters:
248 .  jac      - semismooth jacobian
249 .  jac_pre  - optional preconditioning matrix
250 .  flag     - flag passed on by SNESComputeJacobian.
251 .  jacctx   - user provided jacobian context
252 
253    Notes:
254    The semismooth jacobian matrix is given by
255    jac = Da + Db*jacfun
256    where Db is the row scaling matrix stored as a vector,
257          Da is the diagonal perturbation matrix stored as a vector
258    and   jacfun is the jacobian of the original nonlinear function.
259 */
260 #undef __FUNCT__
261 #define __FUNCT__ "SNESVIComputeJacobian"
262 PetscErrorCode SNESVIComputeJacobian(SNES snes,Vec X,Mat *jac, Mat *jac_pre, MatStructure *flg,void* jacctx)
263 {
264   PetscErrorCode ierr;
265   SNES_VI      *vi = (SNES_VI*)snes->data;
266   PetscScalar    *l,*u,*x,*f,*da,*db,*z,*t,t1,t2,ci,di,ei;
267   PetscInt       i,nlocal;
268   Vec            F = snes->vec_func;
269 
270   PetscFunctionBegin;
271 
272   ierr = (*vi->computeuserjacobian)(snes,X,jac,jac_pre,flg,jacctx);CHKERRQ(ierr);
273 
274   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
275   ierr = VecGetArray(F,&f);CHKERRQ(ierr);
276   ierr = VecGetArray(vi->xl,&l);CHKERRQ(ierr);
277   ierr = VecGetArray(vi->xu,&u);CHKERRQ(ierr);
278   ierr = VecGetArray(vi->Da,&da);CHKERRQ(ierr);
279   ierr = VecGetArray(vi->Db,&db);CHKERRQ(ierr);
280   ierr = VecGetArray(vi->z,&z);CHKERRQ(ierr);
281 
282   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
283   /* Set the elements of the vector z:
284      z[i] = 1 if (x[i] - l[i],f[i]) = (0,0) or (u[i] - x[i],f[i]) = (0,0)
285      else z[i] = 0
286   */
287   for(i=0;i < nlocal;i++) {
288     da[i] = db[i] = z[i] = 0;
289     if(PetscAbsScalar(f[i]) <= vi->const_tol) {
290       if ((l[i] > PETSC_VI_NINF) && (PetscAbsScalar(x[i]-l[i]) <= vi->const_tol)) {
291 	da[i] = 1;
292 	z[i]  = 1;
293       }
294       if ((u[i] < PETSC_VI_INF) && (PetscAbsScalar(u[i]-x[i]) <= vi->const_tol)) {
295 	db[i] = 1;
296 	z[i]  = 1;
297       }
298     }
299   }
300   ierr = VecRestoreArray(vi->z,&z);CHKERRQ(ierr);
301   ierr = MatMult(*jac,vi->z,vi->t);CHKERRQ(ierr);
302   ierr = VecGetArray(vi->t,&t);CHKERRQ(ierr);
303   /* Compute the elements of the diagonal perturbation vector Da and row scaling vector Db */
304   for(i=0;i< nlocal;i++) {
305     /* Free variables */
306     if ((l[i] <= PETSC_VI_NINF) && (u[i] >= PETSC_VI_INF)) {
307       da[i] = 0; db[i] = -1;
308     }
309     /* lower bounded variables */
310     else if (u[i] >= PETSC_VI_INF) {
311       if (da[i] >= 1) {
312 	t2 = PetscScalarNorm(1,t[i]);
313 	da[i] = 1/t2 - 1;
314 	db[i] = t[i]/t2 - 1;
315       } else {
316 	t1 = x[i] - l[i];
317 	t2 = PetscScalarNorm(t1,f[i]);
318 	da[i] = t1/t2 - 1;
319 	db[i] = f[i]/t2 - 1;
320       }
321     }
322     /* upper bounded variables */
323     else if (l[i] <= PETSC_VI_NINF) {
324       if (db[i] >= 1) {
325 	t2 = PetscScalarNorm(1,t[i]);
326 	da[i] = -1/t2 -1;
327 	db[i] = -t[i]/t2 - 1;
328       }
329       else {
330 	t1 = u[i] - x[i];
331 	t2 = PetscScalarNorm(t1,f[i]);
332 	da[i] = t1/t2 - 1;
333 	db[i] = -f[i]/t2 - 1;
334       }
335     }
336     /* Fixed variables */
337     else if (l[i] == u[i]) {
338       da[i] = -1;
339       db[i] = 0;
340     }
341     /* Box constrained variables */
342     else {
343       if (db[i] >= 1) {
344 	t2 = PetscScalarNorm(1,t[i]);
345 	ci = 1/t2 + 1;
346 	di = t[i]/t2 + 1;
347       }
348       else {
349 	t1 = x[i] - u[i];
350 	t2 = PetscScalarNorm(t1,f[i]);
351 	ci = t1/t2 + 1;
352 	di = f[i]/t2 + 1;
353       }
354 
355       if (da[i] >= 1) {
356 	t1 = ci + di*t[i];
357 	t2 = PetscScalarNorm(1,t1);
358 	t1 = t1/t2 - 1;
359 	t2 = 1/t2  - 1;
360       }
361       else {
362 	ierr = ComputeFischerFunction(u[i]-x[i],-f[i],&ei);CHKERRQ(ierr);
363 	t2 = PetscScalarNorm(x[i]-l[i],ei);
364 	t1 = ei/t2 - 1;
365 	t2 = (x[i] - l[i])/t2 - 1;
366       }
367 
368       da[i] = t2 + t1*ci;
369       db[i] = t1*di;
370     }
371   }
372   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
373   ierr = VecRestoreArray(F,&f);CHKERRQ(ierr);
374   ierr = VecRestoreArray(vi->xl,&l);CHKERRQ(ierr);
375   ierr = VecRestoreArray(vi->xu,&u);CHKERRQ(ierr);
376   ierr = VecRestoreArray(vi->Da,&da);CHKERRQ(ierr);
377   ierr = VecRestoreArray(vi->Db,&db);CHKERRQ(ierr);
378   ierr = VecRestoreArray(vi->t,&t);CHKERRQ(ierr);
379 
380   /* Do row scaling  and add diagonal perturbation */
381   ierr = MatDiagonalScale(*jac,vi->Db,PETSC_NULL);CHKERRQ(ierr);
382   ierr = MatDiagonalSet(*jac,vi->Da,ADD_VALUES);CHKERRQ(ierr);
383   if (*jac != *jac_pre) { /* If jac and jac_pre are different */
384     ierr = MatDiagonalScale(*jac_pre,vi->Db,PETSC_NULL);
385     ierr = MatDiagonalSet(*jac_pre,vi->Da,ADD_VALUES);CHKERRQ(ierr);
386   }
387 
388   PetscFunctionReturn(0);
389 }
390 
391 /*
392    SNESVIComputeMeritFunctionGradient - Computes the gradient of the merit function psi.
393 
394    Input Parameters:
395 .  phi - semismooth function.
396 .  H   - semismooth jacobian
397 
398    Output Parameters:
399 .  dpsi - merit function gradient
400 
401    Notes:
402    The merit function gradient is computed as follows
403    dpsi = H^T*phi
404 */
405 #undef __FUNCT__
406 #define __FUNCT__ "SNESVIComputeMeritFunctionGradient"
407 PetscErrorCode SNESVIComputeMeritFunctionGradient(Mat H, Vec phi, Vec dpsi)
408 {
409   PetscErrorCode ierr;
410 
411   PetscFunctionBegin;
412   ierr = MatMultTranspose(H,phi,dpsi);
413 
414   PetscFunctionReturn(0);
415 }
416 
417 /*
418    SNESVISetDescentDirection - Sets the descent direction for the semismooth algorithm
419 
420    Input Parameters:
421 .  snes - the SNES context.
422 .  dpsi - gradient of the merit function.
423 
424    Output Parameters:
425 .  flg  - PETSC_TRUE if the sufficient descent condition is not satisfied.
426 
427    Notes:
428    The condition for the sufficient descent direction is
429         dpsi^T*Y > delta*||Y||^rho
430    where rho, delta are as defined in the SNES_VI structure.
431    If this condition is satisfied then the existing descent direction i.e.
432    the direction given by the linear solve should be used otherwise it should be set to the negative of the merit function gradient i.e -dpsi.
433 */
434 #undef __FUNCT__
435 #define __FUNCT__ "SNESVICheckDescentDirection"
436 PetscErrorCode SNESVICheckDescentDirection(SNES snes,Vec dpsi, Vec Y,PetscTruth* flg)
437 {
438   PetscErrorCode  ierr;
439   SNES_VI       *vi = (SNES_VI*)snes->data;
440   PetscScalar     dpsidotY;
441   PetscReal       norm_Y,rhs;
442   const PetscReal rho = vi->rho,delta=vi->delta;
443 
444   PetscFunctionBegin;
445 
446   *flg = PETSC_FALSE;
447   ierr = VecDot(dpsi,Y,&dpsidotY);CHKERRQ(ierr);
448   ierr = VecNormBegin(Y,NORM_2,&norm_Y);CHKERRQ(ierr);
449   ierr = VecNormEnd(Y,NORM_2,&norm_Y);CHKERRQ(ierr);
450 
451   rhs = delta*PetscPowScalar(norm_Y,rho);
452 
453   if (dpsidotY <= rhs) *flg = PETSC_TRUE;
454 
455   PetscFunctionReturn(0);
456 }
457 
458 /*
459    SNESVIAdjustInitialGuess - Readjusts the initial guess to the SNES solver supplied by the user so that the initial guess lies inside the feasible region .
460 
461    Input Parameters:
462 .  lb - lower bound.
463 .  ub - upper bound.
464 
465    Output Parameters:
466 .  X - the readjusted initial guess.
467 
468    Notes:
469    The readjusted initial guess X[i] = max(max(min(l[i],X[i]),min(X[i],u[i])),min(l[i],u[i]))
470 */
471 #undef __FUNCT__
472 #define __FUNCT__ "SNESVIAdjustInitialGuess"
473 PetscErrorCode SNESVIAdjustInitialGuess(Vec X, Vec lb, Vec ub)
474 {
475   PetscErrorCode ierr;
476   PetscInt       i,nlocal;
477   PetscScalar    *x,*l,*u;
478 
479   PetscFunctionBegin;
480 
481   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
482   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
483   ierr = VecGetArray(lb,&l);CHKERRQ(ierr);
484   ierr = VecGetArray(ub,&u);CHKERRQ(ierr);
485 
486   for(i = 0; i < nlocal; i++) {
487     x[i] = PetscMax(PetscMax(PetscMin(x[i],l[i]),PetscMin(x[i],u[i])),PetscMin(l[i],u[i]));
488   }
489 
490   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
491   ierr = VecRestoreArray(lb,&l);CHKERRQ(ierr);
492   ierr = VecRestoreArray(ub,&u);CHKERRQ(ierr);
493 
494   PetscFunctionReturn(0);
495 }
496 
497 /*  --------------------------------------------------------------------
498 
499      This file implements a semismooth truncated Newton method with a line search,
500      for solving a system of nonlinear equations in complementarity form, using the KSP, Vec,
501      and Mat interfaces for linear solvers, vectors, and matrices,
502      respectively.
503 
504      The following basic routines are required for each nonlinear solver:
505           SNESCreate_XXX()          - Creates a nonlinear solver context
506           SNESSetFromOptions_XXX()  - Sets runtime options
507           SNESSolve_XXX()           - Solves the nonlinear system
508           SNESDestroy_XXX()         - Destroys the nonlinear solver context
509      The suffix "_XXX" denotes a particular implementation, in this case
510      we use _VI (e.g., SNESCreate_VI, SNESSolve_VI) for solving
511      systems of nonlinear equations with a line search (LS) method.
512      These routines are actually called via the common user interface
513      routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and
514      SNESDestroy(), so the application code interface remains identical
515      for all nonlinear solvers.
516 
517      Another key routine is:
518           SNESSetUp_XXX()           - Prepares for the use of a nonlinear solver
519      by setting data structures and options.   The interface routine SNESSetUp()
520      is not usually called directly by the user, but instead is called by
521      SNESSolve() if necessary.
522 
523      Additional basic routines are:
524           SNESView_XXX()            - Prints details of runtime options that
525                                       have actually been used.
526      These are called by application codes via the interface routines
527      SNESView().
528 
529      The various types of solvers (preconditioners, Krylov subspace methods,
530      nonlinear solvers, timesteppers) are all organized similarly, so the
531      above description applies to these categories also.
532 
533     -------------------------------------------------------------------- */
534 /*
535    SNESSolve_VI - Solves the complementarity problem with a semismooth Newton
536    method using a line search.
537 
538    Input Parameters:
539 .  snes - the SNES context
540 
541    Output Parameter:
542 .  outits - number of iterations until termination
543 
544    Application Interface Routine: SNESSolve()
545 
546    Notes:
547    This implements essentially a semismooth Newton method with a
548    line search.  By default a cubic backtracking line search
549    is employed, as described in the text "Numerical Methods for
550    Unconstrained Optimization and Nonlinear Equations" by Dennis
551    and Schnabel.
552 */
553 #undef __FUNCT__
554 #define __FUNCT__ "SNESSolve_VI"
555 PetscErrorCode SNESSolve_VI(SNES snes)
556 {
557   SNES_VI          *vi = (SNES_VI*)snes->data;
558   PetscErrorCode     ierr;
559   PetscInt           maxits,i,lits;
560   PetscTruth         lssucceed,changedir;
561   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
562   PetscReal          gnorm,xnorm=0,ynorm;
563   Vec                Y,X,F,G,W;
564   KSPConvergedReason kspreason;
565 
566   PetscFunctionBegin;
567   snes->numFailures            = 0;
568   snes->numLinearSolveFailures = 0;
569   snes->reason                 = SNES_CONVERGED_ITERATING;
570 
571   maxits	= snes->max_its;	/* maximum number of iterations */
572   X		= snes->vec_sol;	/* solution vector */
573   F		= snes->vec_func;	/* residual vector */
574   Y		= snes->work[0];	/* work vectors */
575   G		= snes->work[1];
576   W		= snes->work[2];
577 
578   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
579   snes->iter = 0;
580   snes->norm = 0.0;
581   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
582 
583   ierr = SNESVIAdjustInitialGuess(X,vi->xl,vi->xu);CHKERRQ(ierr);
584   ierr = SNESComputeFunction(snes,X,vi->phi);CHKERRQ(ierr);
585   if (snes->domainerror) {
586     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
587     PetscFunctionReturn(0);
588   }
589    /* Compute Merit function */
590   ierr = SNESVIComputeMeritFunction(vi->phi,&vi->merit,&vi->phinorm);CHKERRQ(ierr);
591 
592   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
593   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
594   if PetscIsInfOrNanReal(vi->merit) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
595 
596   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
597   snes->norm = vi->phinorm;
598   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
599   SNESLogConvHistory(snes,vi->phinorm,0);
600   SNESMonitor(snes,0,vi->phinorm);
601 
602   /* set parameter for default relative tolerance convergence test */
603   snes->ttol = vi->phinorm*snes->rtol;
604   /* test convergence */
605   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
606   if (snes->reason) PetscFunctionReturn(0);
607 
608   for (i=0; i<maxits; i++) {
609 
610     /* Call general purpose update function */
611     if (snes->ops->update) {
612       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
613     }
614 
615     /* Solve J Y = Phi, where J is the semismooth jacobian */
616     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
617 
618     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
619     ierr = SNES_KSPSolve(snes,snes->ksp,vi->phi,Y);CHKERRQ(ierr);
620     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
621     ierr = SNESVIComputeMeritFunctionGradient(snes->jacobian,vi->phi,vi->dpsi);CHKERRQ(ierr);
622     ierr = SNESVICheckDescentDirection(snes,vi->dpsi,Y,&changedir);CHKERRQ(ierr);
623     if (kspreason < 0 || changedir) {
624       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
625         ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
626         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
627         break;
628       }
629       ierr = VecCopy(vi->dpsi,Y);CHKERRQ(ierr);
630     }
631     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
632     snes->linear_its += lits;
633     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
634     /*
635     if (vi->precheckstep) {
636       PetscTruth changed_y = PETSC_FALSE;
637       ierr = (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);CHKERRQ(ierr);
638     }
639 
640     if (PetscLogPrintInfo){
641       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
642     }
643     */
644     /* Compute a (scaled) negative update in the line search routine:
645          Y <- X - lambda*Y
646        and evaluate G = function(Y) (depends on the line search).
647     */
648     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
649     ynorm = 1; gnorm = vi->phinorm;
650     ierr = (*vi->LineSearch)(snes,vi->lsP,X,vi->phi,G,Y,W,vi->phinorm,xnorm,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
651     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",vi->phinorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr);
652     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
653     if (snes->domainerror) {
654       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
655       PetscFunctionReturn(0);
656     }
657     if (!lssucceed) {
658       if (++snes->numFailures >= snes->maxFailures) {
659 	PetscTruth ismin;
660         snes->reason = SNES_DIVERGED_LINE_SEARCH;
661         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
662         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
663         break;
664       }
665     }
666     /* Update function and solution vectors */
667     vi->phinorm = gnorm;
668     vi->merit = 0.5*vi->phinorm*vi->phinorm;
669     ierr = VecCopy(G,vi->phi);CHKERRQ(ierr);
670     ierr = VecCopy(W,X);CHKERRQ(ierr);
671     /* Monitor convergence */
672     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
673     snes->iter = i+1;
674     snes->norm = vi->phinorm;
675     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
676     SNESLogConvHistory(snes,snes->norm,lits);
677     SNESMonitor(snes,snes->iter,snes->norm);
678     /* Test for convergence, xnorm = || X || */
679     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
680     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
681     if (snes->reason) break;
682   }
683   if (i == maxits) {
684     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
685     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
686   }
687   PetscFunctionReturn(0);
688 }
689 /* -------------------------------------------------------------------------- */
690 /*
691    SNESSetUp_VI - Sets up the internal data structures for the later use
692    of the SNESVI nonlinear solver.
693 
694    Input Parameter:
695 .  snes - the SNES context
696 .  x - the solution vector
697 
698    Application Interface Routine: SNESSetUp()
699 
700    Notes:
701    For basic use of the SNES solvers, the user need not explicitly call
702    SNESSetUp(), since these actions will automatically occur during
703    the call to SNESSolve().
704  */
705 #undef __FUNCT__
706 #define __FUNCT__ "SNESSetUp_VI"
707 PetscErrorCode SNESSetUp_VI(SNES snes)
708 {
709   PetscErrorCode ierr;
710   SNES_VI      *vi = (SNES_VI*) snes->data;
711   PetscInt       i_start[3],i_end[3];
712 
713   PetscFunctionBegin;
714   if (!snes->vec_sol_update) {
715     ierr = VecDuplicate(snes->vec_sol,&snes->vec_sol_update);CHKERRQ(ierr);
716     ierr = PetscLogObjectParent(snes,snes->vec_sol_update);CHKERRQ(ierr);
717   }
718   if (!snes->work) {
719     snes->nwork = 3;
720     ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr);
721     ierr = PetscLogObjectParents(snes,snes->nwork,snes->work);CHKERRQ(ierr);
722   }
723 
724   ierr = VecDuplicate(snes->vec_sol, &vi->phi); CHKERRQ(ierr);
725   ierr = VecDuplicate(snes->vec_sol, &vi->dpsi); CHKERRQ(ierr);
726   ierr = VecDuplicate(snes->vec_sol, &vi->Da); CHKERRQ(ierr);
727   ierr = VecDuplicate(snes->vec_sol, &vi->Db); CHKERRQ(ierr);
728   ierr = VecDuplicate(snes->vec_sol, &vi->z);CHKERRQ(ierr);
729   ierr = VecDuplicate(snes->vec_sol, &vi->t); CHKERRQ(ierr);
730 
731   /* If the lower and upper bound on variables are not set, set it to
732      -Inf and Inf */
733   if (!vi->xl && !vi->xu) {
734     vi->usersetxbounds = PETSC_FALSE;
735     ierr = VecDuplicate(snes->vec_sol, &vi->xl); CHKERRQ(ierr);
736     ierr = VecSet(vi->xl,PETSC_VI_NINF);CHKERRQ(ierr);
737     ierr = VecDuplicate(snes->vec_sol, &vi->xu); CHKERRQ(ierr);
738     ierr = VecSet(vi->xu,PETSC_VI_INF);CHKERRQ(ierr);
739   } else {
740     /* Check if lower bound, upper bound and solution vector distribution across the processors is identical */
741     ierr = VecGetOwnershipRange(snes->vec_sol,i_start,i_end);CHKERRQ(ierr);
742     ierr = VecGetOwnershipRange(vi->xl,i_start+1,i_end+1);CHKERRQ(ierr);
743     ierr = VecGetOwnershipRange(vi->xu,i_start+2,i_end+2);CHKERRQ(ierr);
744     if ((i_start[0] != i_start[1]) || (i_start[0] != i_start[2]) || (i_end[0] != i_end[1]) || (i_end[0] != i_end[2]))
745       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Distribution of lower bound, upper bound and the solution vector should be identical across all the processors.");
746   }
747 
748   vi->computeuserfunction = snes->ops->computefunction;
749   vi->computeuserjacobian = snes->ops->computejacobian;
750 
751   snes->ops->computefunction = SNESVIComputeFunction;
752   snes->ops->computejacobian = SNESVIComputeJacobian;
753   PetscFunctionReturn(0);
754 }
755 /* -------------------------------------------------------------------------- */
756 /*
757    SNESDestroy_VI - Destroys the private SNES_VI context that was created
758    with SNESCreate_VI().
759 
760    Input Parameter:
761 .  snes - the SNES context
762 
763    Application Interface Routine: SNESDestroy()
764  */
765 #undef __FUNCT__
766 #define __FUNCT__ "SNESDestroy_VI"
767 PetscErrorCode SNESDestroy_VI(SNES snes)
768 {
769   SNES_VI        *vi = (SNES_VI*) snes->data;
770   PetscErrorCode ierr;
771 
772   PetscFunctionBegin;
773   if (snes->vec_sol_update) {
774     ierr = VecDestroy(snes->vec_sol_update);CHKERRQ(ierr);
775     snes->vec_sol_update = PETSC_NULL;
776   }
777   if (snes->nwork) {
778     ierr = VecDestroyVecs(snes->work,snes->nwork);CHKERRQ(ierr);
779     snes->nwork = 0;
780     snes->work  = PETSC_NULL;
781   }
782 
783   /* clear vectors */
784   ierr = VecDestroy(vi->phi); CHKERRQ(ierr);
785   ierr = VecDestroy(vi->dpsi); CHKERRQ(ierr);
786   ierr = VecDestroy(vi->Da); CHKERRQ(ierr);
787   ierr = VecDestroy(vi->Db); CHKERRQ(ierr);
788   ierr = VecDestroy(vi->z); CHKERRQ(ierr);
789   ierr = VecDestroy(vi->t); CHKERRQ(ierr);
790   if (!vi->usersetxbounds) {
791     ierr = VecDestroy(vi->xl); CHKERRQ(ierr);
792     ierr = VecDestroy(vi->xu); CHKERRQ(ierr);
793   }
794   if (vi->lsmonitor) {
795     ierr = PetscViewerASCIIMonitorDestroy(vi->lsmonitor);CHKERRQ(ierr);
796   }
797   ierr = PetscFree(snes->data);CHKERRQ(ierr);
798 
799   /* clear composed functions */
800   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","",PETSC_NULL);CHKERRQ(ierr);
801   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","",PETSC_NULL);CHKERRQ(ierr);
802   PetscFunctionReturn(0);
803 }
804 /* -------------------------------------------------------------------------- */
805 #undef __FUNCT__
806 #define __FUNCT__ "SNESLineSearchNo_VI"
807 
808 /*
809   This routine is a copy of SNESLineSearchNo routine in snes/impls/ls/ls.c
810 
811 */
812 PetscErrorCode SNESLineSearchNo_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
813 {
814   PetscErrorCode ierr;
815   SNES_VI        *vi = (SNES_VI*)snes->data;
816   PetscTruth     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
817 
818   PetscFunctionBegin;
819   *flag = PETSC_TRUE;
820   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
821   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);         /* ynorm = || y || */
822   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
823   if (vi->postcheckstep) {
824    ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
825   }
826   if (changed_y) {
827     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
828   }
829   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
830   if (!snes->domainerror) {
831     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);  /* gnorm = || g || */
832     if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
833   }
834   if (vi->lsmonitor) {
835     ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
836   }
837   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
838   PetscFunctionReturn(0);
839 }
840 
841 /* -------------------------------------------------------------------------- */
842 #undef __FUNCT__
843 #define __FUNCT__ "SNESLineSearchNoNorms_VI"
844 
845 /*
846   This routine is a copy of SNESLineSearchNoNorms in snes/impls/ls/ls.c
847 */
848 PetscErrorCode SNESLineSearchNoNorms_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
849 {
850   PetscErrorCode ierr;
851   SNES_VI        *vi = (SNES_VI*)snes->data;
852   PetscTruth     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
853 
854   PetscFunctionBegin;
855   *flag = PETSC_TRUE;
856   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
857   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y      */
858   if (vi->postcheckstep) {
859    ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
860   }
861   if (changed_y) {
862     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
863   }
864 
865   /* don't evaluate function the last time through */
866   if (snes->iter < snes->max_its-1) {
867     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
868   }
869   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
870   PetscFunctionReturn(0);
871 }
872 /* -------------------------------------------------------------------------- */
873 #undef __FUNCT__
874 #define __FUNCT__ "SNESLineSearchCubic_VI"
875 /*
876   This routine is a copy of SNESLineSearchCubic in snes/impls/ls/ls.c
877 */
878 PetscErrorCode SNESLineSearchCubic_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
879 {
880   /*
881      Note that for line search purposes we work with with the related
882      minimization problem:
883         min  z(x):  R^n -> R,
884      where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2.
885      This function z(x) is same as the merit function for the complementarity problem.
886    */
887 
888   PetscReal      initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
889   PetscReal      minlambda,lambda,lambdatemp;
890 #if defined(PETSC_USE_COMPLEX)
891   PetscScalar    cinitslope;
892 #endif
893   PetscErrorCode ierr;
894   PetscInt       count;
895   SNES_VI      *vi = (SNES_VI*)snes->data;
896   PetscTruth     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
897   MPI_Comm       comm;
898 
899   PetscFunctionBegin;
900   ierr = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
901   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
902   *flag   = PETSC_TRUE;
903 
904   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
905   if (*ynorm == 0.0) {
906     if (vi->lsmonitor) {
907       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Initial direction and size is 0\n");CHKERRQ(ierr);
908     }
909     *gnorm = fnorm;
910     ierr   = VecCopy(x,w);CHKERRQ(ierr);
911     ierr   = VecCopy(f,g);CHKERRQ(ierr);
912     *flag  = PETSC_FALSE;
913     goto theend1;
914   }
915   if (*ynorm > vi->maxstep) {	/* Step too big, so scale back */
916     if (vi->lsmonitor) {
917       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Scaling step by %G old ynorm %G\n",vi->maxstep/(*ynorm),*ynorm);CHKERRQ(ierr);
918     }
919     ierr = VecScale(y,vi->maxstep/(*ynorm));CHKERRQ(ierr);
920     *ynorm = vi->maxstep;
921   }
922   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
923   minlambda = vi->minlambda/rellength;
924   /*  ierr      = MatMult(snes->jacobian,y,w);CHKERRQ(ierr); */
925 #if defined(PETSC_USE_COMPLEX)
926   ierr      = VecDot(vi->dpsi,y,&cinitslope);CHKERRQ(ierr);
927   initslope = PetscRealPart(cinitslope);
928 #else
929   ierr      = VecDot(vi->dpsi,y,&initslope);CHKERRQ(ierr);
930 #endif
931   if (initslope > 0.0)  initslope = -initslope;
932   if (initslope == 0.0) initslope = -1.0;
933 
934   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
935   if (snes->nfuncs >= snes->max_funcs) {
936     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
937     *flag = PETSC_FALSE;
938     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
939     goto theend1;
940   }
941   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
942   if (snes->domainerror) {
943     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
944     PetscFunctionReturn(0);
945   }
946   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
947   if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
948   ierr = PetscInfo2(snes,"Initial fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
949   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + vi->alpha*initslope) { /* Sufficient reduction */
950     if (vi->lsmonitor) {
951       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
952     }
953     goto theend1;
954   }
955 
956   /* Fit points with quadratic */
957   lambda     = 1.0;
958   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
959   lambdaprev = lambda;
960   gnormprev  = *gnorm;
961   if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
962   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
963   else                         lambda = lambdatemp;
964 
965   ierr  = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
966   if (snes->nfuncs >= snes->max_funcs) {
967     ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);CHKERRQ(ierr);
968     *flag = PETSC_FALSE;
969     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
970     goto theend1;
971   }
972   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
973   if (snes->domainerror) {
974     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
975     PetscFunctionReturn(0);
976   }
977   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
978   if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
979   if (vi->lsmonitor) {
980     ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: gnorm after quadratic fit %G\n",*gnorm);CHKERRQ(ierr);
981   }
982   if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* sufficient reduction */
983     if (vi->lsmonitor) {
984       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Quadratically determined step, lambda=%18.16e\n",lambda);CHKERRQ(ierr);
985     }
986     goto theend1;
987   }
988 
989   /* Fit points with cubic */
990   count = 1;
991   while (PETSC_TRUE) {
992     if (lambda <= minlambda) {
993       if (vi->lsmonitor) {
994 	ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: unable to find good step length! After %D tries \n",count);CHKERRQ(ierr);
995 	ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,minlambda,lambda,initslope);CHKERRQ(ierr);
996       }
997       *flag = PETSC_FALSE;
998       break;
999     }
1000     t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
1001     t2 = .5*(gnormprev*gnormprev  - fnorm*fnorm) - lambdaprev*initslope;
1002     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
1003     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
1004     d  = b*b - 3*a*initslope;
1005     if (d < 0.0) d = 0.0;
1006     if (a == 0.0) {
1007       lambdatemp = -initslope/(2.0*b);
1008     } else {
1009       lambdatemp = (-b + sqrt(d))/(3.0*a);
1010     }
1011     lambdaprev = lambda;
1012     gnormprev  = *gnorm;
1013     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
1014     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
1015     else                         lambda     = lambdatemp;
1016     ierr  = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
1017     if (snes->nfuncs >= snes->max_funcs) {
1018       ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
1019       ierr = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);CHKERRQ(ierr);
1020       *flag = PETSC_FALSE;
1021       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1022       break;
1023     }
1024     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1025     if (snes->domainerror) {
1026       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1027       PetscFunctionReturn(0);
1028     }
1029     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1030     if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1031     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* is reduction enough? */
1032       if (vi->lsmonitor) {
1033 	ierr = PetscPrintf(comm,"    Line search: Cubically determined step, current gnorm %G lambda=%18.16e\n",*gnorm,lambda);CHKERRQ(ierr);
1034       }
1035       break;
1036     } else {
1037       if (vi->lsmonitor) {
1038         ierr = PetscPrintf(comm,"    Line search: Cubic step no good, shrinking lambda, current gnorm %G lambda=%18.16e\n",*gnorm,lambda);CHKERRQ(ierr);
1039       }
1040     }
1041     count++;
1042   }
1043   theend1:
1044   /* Optional user-defined check for line search step validity */
1045   if (vi->postcheckstep && *flag) {
1046     ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1047     if (changed_y) {
1048       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1049     }
1050     if (changed_y || changed_w) { /* recompute the function if the step has changed */
1051       ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1052       if (snes->domainerror) {
1053         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1054         PetscFunctionReturn(0);
1055       }
1056       ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr);
1057       if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1058       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
1059       ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr);
1060       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
1061     }
1062   }
1063   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1064   PetscFunctionReturn(0);
1065 }
1066 /* -------------------------------------------------------------------------- */
1067 #undef __FUNCT__
1068 #define __FUNCT__ "SNESLineSearchQuadratic_VI"
1069 /*
1070   This routine is a copy of SNESLineSearchQuadratic in snes/impls/ls/ls.c
1071 */
1072 PetscErrorCode SNESLineSearchQuadratic_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
1073 {
1074   /*
1075      Note that for line search purposes we work with with the related
1076      minimization problem:
1077         min  z(x):  R^n -> R,
1078      where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
1079      z(x) is the same as the merit function for the complementarity problem
1080    */
1081   PetscReal      initslope,minlambda,lambda,lambdatemp,rellength;
1082 #if defined(PETSC_USE_COMPLEX)
1083   PetscScalar    cinitslope;
1084 #endif
1085   PetscErrorCode ierr;
1086   PetscInt       count;
1087   SNES_VI        *vi = (SNES_VI*)snes->data;
1088   PetscTruth     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1089 
1090   PetscFunctionBegin;
1091   ierr    = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1092   *flag   = PETSC_TRUE;
1093 
1094   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
1095   if (*ynorm == 0.0) {
1096     if (vi->lsmonitor) {
1097       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"Line search: Direction and size is 0\n");CHKERRQ(ierr);
1098     }
1099     *gnorm = fnorm;
1100     ierr   = VecCopy(x,w);CHKERRQ(ierr);
1101     ierr   = VecCopy(f,g);CHKERRQ(ierr);
1102     *flag  = PETSC_FALSE;
1103     goto theend2;
1104   }
1105   if (*ynorm > vi->maxstep) {	/* Step too big, so scale back */
1106     ierr   = VecScale(y,vi->maxstep/(*ynorm));CHKERRQ(ierr);
1107     *ynorm = vi->maxstep;
1108   }
1109   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
1110   minlambda = vi->minlambda/rellength;
1111   /*  ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr); */
1112 #if defined(PETSC_USE_COMPLEX)
1113   ierr      = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
1114   initslope = PetscRealPart(cinitslope);
1115 #else
1116   ierr = VecDot(vi->dpsi,y,&initslope);CHKERRQ(ierr);
1117 #endif
1118   if (initslope > 0.0)  initslope = -initslope;
1119   if (initslope == 0.0) initslope = -1.0;
1120   ierr = PetscInfo1(snes,"Initslope %G \n",initslope);CHKERRQ(ierr);
1121 
1122   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1123   if (snes->nfuncs >= snes->max_funcs) {
1124     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
1125     *flag = PETSC_FALSE;
1126     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1127     goto theend2;
1128   }
1129   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1130   if (snes->domainerror) {
1131     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1132     PetscFunctionReturn(0);
1133   }
1134   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1135   if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1136   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + vi->alpha*initslope) { /* Sufficient reduction */
1137     if (vi->lsmonitor) {
1138       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1139     }
1140     goto theend2;
1141   }
1142 
1143   /* Fit points with quadratic */
1144   lambda = 1.0;
1145   count = 1;
1146   while (PETSC_TRUE) {
1147     if (lambda <= minlambda) { /* bad luck; use full step */
1148       if (vi->lsmonitor) {
1149         ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"Line search: Unable to find good step length! %D \n",count);CHKERRQ(ierr);
1150         ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"Line search: fnorm=%G, gnorm=%G, ynorm=%G, lambda=%G, initial slope=%G\n",fnorm,*gnorm,*ynorm,lambda,initslope);CHKERRQ(ierr);
1151       }
1152       ierr = VecCopy(x,w);CHKERRQ(ierr);
1153       *flag = PETSC_FALSE;
1154       break;
1155     }
1156     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
1157     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
1158     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
1159     else                         lambda     = lambdatemp;
1160 
1161     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
1162     if (snes->nfuncs >= snes->max_funcs) {
1163       ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
1164       ierr  = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);CHKERRQ(ierr);
1165       *flag = PETSC_FALSE;
1166       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1167       break;
1168     }
1169     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1170     if (snes->domainerror) {
1171       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1172       PetscFunctionReturn(0);
1173     }
1174     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1175     if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1176     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* sufficient reduction */
1177       if (vi->lsmonitor) {
1178         ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line Search: Quadratically determined step, lambda=%G\n",lambda);CHKERRQ(ierr);
1179       }
1180       break;
1181     }
1182     count++;
1183   }
1184   theend2:
1185   /* Optional user-defined check for line search step validity */
1186   if (vi->postcheckstep) {
1187     ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1188     if (changed_y) {
1189       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1190     }
1191     if (changed_y || changed_w) { /* recompute the function if the step has changed */
1192       ierr = SNESComputeFunction(snes,w,g);
1193       if (snes->domainerror) {
1194         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1195         PetscFunctionReturn(0);
1196       }
1197       ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr);
1198       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
1199       ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr);
1200       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
1201       if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1202     }
1203   }
1204   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1205   PetscFunctionReturn(0);
1206 }
1207 
1208 typedef PetscErrorCode (*FCN2)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal,PetscReal*,PetscReal*,PetscTruth*); /* force argument to next function to not be extern C*/
1209 /* -------------------------------------------------------------------------- */
1210 EXTERN_C_BEGIN
1211 #undef __FUNCT__
1212 #define __FUNCT__ "SNESLineSearchSet_VI"
1213 PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchSet_VI(SNES snes,FCN2 func,void *lsctx)
1214 {
1215   PetscFunctionBegin;
1216   ((SNES_VI *)(snes->data))->LineSearch = func;
1217   ((SNES_VI *)(snes->data))->lsP        = lsctx;
1218   PetscFunctionReturn(0);
1219 }
1220 EXTERN_C_END
1221 
1222 /* -------------------------------------------------------------------------- */
1223 EXTERN_C_BEGIN
1224 #undef __FUNCT__
1225 #define __FUNCT__ "SNESLineSearchSetMonitor_VI"
1226 PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchSetMonitor_VI(SNES snes,PetscTruth flg)
1227 {
1228   SNES_VI        *vi = (SNES_VI*)snes->data;
1229   PetscErrorCode ierr;
1230 
1231   PetscFunctionBegin;
1232   if (flg && !vi->lsmonitor) {
1233     ierr = PetscViewerASCIIMonitorCreate(((PetscObject)snes)->comm,"stdout",((PetscObject)snes)->tablevel,&vi->lsmonitor);CHKERRQ(ierr);
1234   } else if (!flg && vi->lsmonitor) {
1235     ierr = PetscViewerASCIIMonitorDestroy(vi->lsmonitor);CHKERRQ(ierr);
1236   }
1237   PetscFunctionReturn(0);
1238 }
1239 EXTERN_C_END
1240 
1241 /*
1242    SNESView_VI - Prints info from the SNESVI data structure.
1243 
1244    Input Parameters:
1245 .  SNES - the SNES context
1246 .  viewer - visualization context
1247 
1248    Application Interface Routine: SNESView()
1249 */
1250 #undef __FUNCT__
1251 #define __FUNCT__ "SNESView_VI"
1252 static PetscErrorCode SNESView_VI(SNES snes,PetscViewer viewer)
1253 {
1254   SNES_VI        *vi = (SNES_VI *)snes->data;
1255   const char     *cstr;
1256   PetscErrorCode ierr;
1257   PetscTruth     iascii;
1258 
1259   PetscFunctionBegin;
1260   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
1261   if (iascii) {
1262     if (vi->LineSearch == SNESLineSearchNo_VI)             cstr = "SNESLineSearchNo";
1263     else if (vi->LineSearch == SNESLineSearchQuadratic_VI) cstr = "SNESLineSearchQuadratic";
1264     else if (vi->LineSearch == SNESLineSearchCubic_VI)     cstr = "SNESLineSearchCubic";
1265     else                                                cstr = "unknown";
1266     ierr = PetscViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);CHKERRQ(ierr);
1267     ierr = PetscViewerASCIIPrintf(viewer,"  alpha=%G, maxstep=%G, minlambda=%G\n",vi->alpha,vi->maxstep,vi->minlambda);CHKERRQ(ierr);
1268   } else {
1269     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Viewer type %s not supported for SNES EQ VI",((PetscObject)viewer)->type_name);
1270   }
1271   PetscFunctionReturn(0);
1272 }
1273 
1274 /*
1275    SNESVISetVariableBounds - Sets the lower and upper bounds for the solution vector. xl <= x <= xu.
1276 
1277    Input Parameters:
1278 .  snes - the SNES context.
1279 .  xl   - lower bound.
1280 .  xu   - upper bound.
1281 
1282    Notes:
1283    If this routine is not called then the lower and upper bounds are set to
1284    -Infinity and Infinity respectively during SNESSetUp.
1285 */
1286 
1287 #undef __FUNCT__
1288 #define __FUNCT__ "SNESVISetVariableBounds"
1289 PetscErrorCode SNESVISetVariableBounds(SNES snes, Vec xl, Vec xu)
1290 {
1291   SNES_VI        *vi = (SNES_VI*)snes->data;
1292 
1293   PetscFunctionBegin;
1294   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
1295   PetscValidHeaderSpecific(xl,VEC_CLASSID,2);
1296   PetscValidHeaderSpecific(xu,VEC_CLASSID,3);
1297 
1298   /* Check if SNESSetFunction is called */
1299   if(!snes->vec_func) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call SNESSetFunction() first");
1300 
1301   /* Check if the vector sizes are compatible for lower and upper bounds */
1302   if (xl->map->N != snes->vec_func->map->N) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Incompatible vector lengths lower bound = %D solution vector = %D",xl->map->N,snes->vec_func->map->N);
1303   if (xu->map->N != snes->vec_func->map->N) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Incompatible vector lengths: upper bound = %D solution vector = %D",xu->map->N,snes->vec_func->map->N);
1304   vi->usersetxbounds = PETSC_TRUE;
1305   vi->xl = xl;
1306   vi->xu = xu;
1307 
1308   PetscFunctionReturn(0);
1309 }
1310 /* -------------------------------------------------------------------------- */
1311 /*
1312    SNESSetFromOptions_VI - Sets various parameters for the SNESVI method.
1313 
1314    Input Parameter:
1315 .  snes - the SNES context
1316 
1317    Application Interface Routine: SNESSetFromOptions()
1318 */
1319 #undef __FUNCT__
1320 #define __FUNCT__ "SNESSetFromOptions_VI"
1321 static PetscErrorCode SNESSetFromOptions_VI(SNES snes)
1322 {
1323   SNES_VI        *vi = (SNES_VI *)snes->data;
1324   const char     *lses[] = {"basic","basicnonorms","quadratic","cubic"};
1325   PetscErrorCode ierr;
1326   PetscInt       indx;
1327   PetscTruth     flg,set;
1328 
1329   PetscFunctionBegin;
1330     ierr = PetscOptionsHead("SNES semismooth method options");CHKERRQ(ierr);
1331     ierr = PetscOptionsReal("-snes_vi_alpha","Function norm must decrease by","None",vi->alpha,&vi->alpha,0);CHKERRQ(ierr);
1332     ierr = PetscOptionsReal("-snes_vi_maxstep","Step must be less than","None",vi->maxstep,&vi->maxstep,0);CHKERRQ(ierr);
1333     ierr = PetscOptionsReal("-snes_vi_minlambda","Minimum lambda allowed","None",vi->minlambda,&vi->minlambda,0);CHKERRQ(ierr);
1334     ierr = PetscOptionsReal("-snes_vi_delta","descent test fraction","None",vi->delta,&vi->delta,0);CHKERRQ(ierr);
1335     ierr = PetscOptionsReal("-snes_vi_rho","descent test power","None",vi->rho,&vi->rho,0);CHKERRQ(ierr);
1336     ierr = PetscOptionsReal("-snes_vi_const_tol","constraint tolerance","None",vi->const_tol,&vi->const_tol,0);CHKERRQ(ierr);
1337     ierr = PetscOptionsTruth("-snes_vi_lsmonitor","Print progress of line searches","SNESLineSearchSetMonitor",vi->lsmonitor ? PETSC_TRUE : PETSC_FALSE,&flg,&set);CHKERRQ(ierr);
1338     if (set) {ierr = SNESLineSearchSetMonitor(snes,flg);CHKERRQ(ierr);}
1339 
1340     ierr = PetscOptionsEList("-snes_vi_ls","Line search used","SNESLineSearchSet",lses,4,"cubic",&indx,&flg);CHKERRQ(ierr);
1341     if (flg) {
1342       switch (indx) {
1343       case 0:
1344         ierr = SNESLineSearchSet(snes,SNESLineSearchNo_VI,PETSC_NULL);CHKERRQ(ierr);
1345         break;
1346       case 1:
1347         ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms_VI,PETSC_NULL);CHKERRQ(ierr);
1348         break;
1349       case 2:
1350         ierr = SNESLineSearchSet(snes,SNESLineSearchQuadratic_VI,PETSC_NULL);CHKERRQ(ierr);
1351         break;
1352       case 3:
1353         ierr = SNESLineSearchSet(snes,SNESLineSearchCubic_VI,PETSC_NULL);CHKERRQ(ierr);
1354         break;
1355       }
1356     }
1357   ierr = PetscOptionsTail();CHKERRQ(ierr);
1358   PetscFunctionReturn(0);
1359 }
1360 /* -------------------------------------------------------------------------- */
1361 /*MC
1362       SNESVI - Semismooth newton method based nonlinear solver that uses a line search
1363 
1364    Options Database:
1365 +   -snes_vi [cubic,quadratic,basic,basicnonorms] - Selects line search
1366 .   -snes_vi_alpha <alpha> - Sets alpha
1367 .   -snes_vi_maxstep <maxstep> - Sets the maximum stepsize the line search will use (if the 2-norm(y) > maxstep then scale y to be y = (maxstep/2-norm(y)) *y)
1368 .   -snes_vi_minlambda <minlambda>  - Sets the minimum lambda the line search will use  minlambda / max_i ( y[i]/x[i] )
1369     -snes_vi_delta <delta> - Sets the fraction used in the descent test.
1370     -snes_vi_rho <rho> - Sets the power used in the descent test.
1371      For a descent direction to be accepted it has to satisfy the condition dpsi^T*d <= -delta*||d||^rho
1372 -   -snes_vi_monitor - print information about progress of line searches
1373 
1374 
1375    Level: beginner
1376 
1377 .seealso:  SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(),
1378            SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(),
1379            SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams()
1380 
1381 M*/
1382 EXTERN_C_BEGIN
1383 #undef __FUNCT__
1384 #define __FUNCT__ "SNESCreate_VI"
1385 PetscErrorCode PETSCSNES_DLLEXPORT SNESCreate_VI(SNES snes)
1386 {
1387   PetscErrorCode ierr;
1388   SNES_VI      *vi;
1389 
1390   PetscFunctionBegin;
1391   snes->ops->setup	     = SNESSetUp_VI;
1392   snes->ops->solve	     = SNESSolve_VI;
1393   snes->ops->destroy	     = SNESDestroy_VI;
1394   snes->ops->setfromoptions  = SNESSetFromOptions_VI;
1395   snes->ops->view            = SNESView_VI;
1396   snes->ops->converged       = SNESDefaultConverged_VI;
1397 
1398   ierr                   = PetscNewLog(snes,SNES_VI,&vi);CHKERRQ(ierr);
1399   snes->data    	 = (void*)vi;
1400   vi->alpha		 = 1.e-4;
1401   vi->maxstep		 = 1.e8;
1402   vi->minlambda         = 1.e-12;
1403   vi->LineSearch        = SNESLineSearchCubic_VI;
1404   vi->lsP               = PETSC_NULL;
1405   vi->postcheckstep     = PETSC_NULL;
1406   vi->postcheck         = PETSC_NULL;
1407   vi->precheckstep      = PETSC_NULL;
1408   vi->precheck          = PETSC_NULL;
1409   vi->rho               = 2.1;
1410   vi->delta             = 1e-10;
1411   vi->const_tol         =  2.2204460492503131e-16;
1412   vi->computessfunction = ComputeFischerFunction;
1413 
1414   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","SNESLineSearchSetMonitor_VI",SNESLineSearchSetMonitor_VI);CHKERRQ(ierr);
1415   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","SNESLineSearchSet_VI",SNESLineSearchSet_VI);CHKERRQ(ierr);
1416 
1417   PetscFunctionReturn(0);
1418 }
1419 EXTERN_C_END
1420