xref: /petsc/src/snes/impls/vi/vi.c (revision 18d3aa3f5b7b6cf3b58215079fab4e2a5c7adae3)
1 #define PETSCSNES_DLL
2 
3 #include "../src/snes/impls/vi/viimpl.h" /*I "petscsnes.h" I*/
4 #include "../include/private/kspimpl.h"
5 #include "../include/private/matimpl.h"
6 
7 #undef __FUNCT__
8 #define __FUNCT__ "SNESMonitorVI"
9 PetscErrorCode  SNESMonitorVI(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
10 {
11   PetscErrorCode          ierr;
12   SNES_VI                 *vi = (SNES_VI*)snes->data;
13   PetscViewerASCIIMonitor viewer = (PetscViewerASCIIMonitor) dummy;
14   const PetscScalar       *x,*xl,*xu,*f;
15   PetscInt                i,n,act = 0;
16   PetscReal               rnorm,fnorm;
17 
18   PetscFunctionBegin;
19   if (!dummy) {
20     ierr = PetscViewerASCIIMonitorCreate(((PetscObject)snes)->comm,"stdout",0,&viewer);CHKERRQ(ierr);
21   }
22   ierr = VecGetLocalSize(snes->vec_sol,&n);CHKERRQ(ierr);
23   ierr = VecGetArrayRead(vi->xl,&xl);CHKERRQ(ierr);
24   ierr = VecGetArrayRead(vi->xu,&xu);CHKERRQ(ierr);
25   ierr = VecGetArrayRead(snes->vec_sol,&x);CHKERRQ(ierr);
26   ierr = VecGetArrayRead(snes->vec_func,&f);CHKERRQ(ierr);
27 
28   rnorm = 0.0;
29   for (i=0; i<n; i++) {
30     if (((x[i] > xl[i] + 1.e-8 || (f[i] < 0.0)) && ((x[i] < xu[i] - 1.e-8) || f[i] > 0.0))) rnorm += f[i]*f[i];
31     else act++;
32   }
33   ierr = VecRestoreArrayRead(snes->vec_func,&f);CHKERRQ(ierr);
34   ierr = VecRestoreArrayRead(vi->xl,&xl);CHKERRQ(ierr);
35   ierr = VecRestoreArrayRead(vi->xu,&xu);CHKERRQ(ierr);
36   ierr = VecRestoreArrayRead(snes->vec_sol,&x);CHKERRQ(ierr);
37   ierr = MPI_Allreduce(&rnorm,&fnorm,1,MPIU_REAL,MPI_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
38   fnorm = sqrt(fnorm);
39   ierr = PetscViewerASCIIMonitorPrintf(viewer,"%3D SNES VI Function norm %14.12e Active constraints %D\n",its,fnorm,act);CHKERRQ(ierr);
40   if (!dummy) {
41     ierr = PetscViewerASCIIMonitorDestroy(viewer);CHKERRQ(ierr);
42   }
43   PetscFunctionReturn(0);
44 }
45 
46 /*
47      Checks if J^T F = 0 which implies we've found a local minimum of the norm of the function,
48     || 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
49     0 = (J^T F)^T W = F^T J W iff W not in the null space of J. Thanks for Jorge More
50     for this trick. One assumes that the probability that W is in the null space of J is very, very small.
51 */
52 #undef __FUNCT__
53 #define __FUNCT__ "SNESVICheckLocalMin_Private"
54 PetscErrorCode SNESVICheckLocalMin_Private(SNES snes,Mat A,Vec F,Vec W,PetscReal fnorm,PetscBool *ismin)
55 {
56   PetscReal      a1;
57   PetscErrorCode ierr;
58   PetscBool     hastranspose;
59 
60   PetscFunctionBegin;
61   *ismin = PETSC_FALSE;
62   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
63   if (hastranspose) {
64     /* Compute || J^T F|| */
65     ierr = MatMultTranspose(A,F,W);CHKERRQ(ierr);
66     ierr = VecNorm(W,NORM_2,&a1);CHKERRQ(ierr);
67     ierr = PetscInfo1(snes,"|| J^T F|| %G near zero implies found a local minimum\n",a1/fnorm);CHKERRQ(ierr);
68     if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE;
69   } else {
70     Vec         work;
71     PetscScalar result;
72     PetscReal   wnorm;
73 
74     ierr = VecSetRandom(W,PETSC_NULL);CHKERRQ(ierr);
75     ierr = VecNorm(W,NORM_2,&wnorm);CHKERRQ(ierr);
76     ierr = VecDuplicate(W,&work);CHKERRQ(ierr);
77     ierr = MatMult(A,W,work);CHKERRQ(ierr);
78     ierr = VecDot(F,work,&result);CHKERRQ(ierr);
79     ierr = VecDestroy(work);CHKERRQ(ierr);
80     a1   = PetscAbsScalar(result)/(fnorm*wnorm);
81     ierr = PetscInfo1(snes,"(F^T J random)/(|| F ||*||random|| %G near zero implies found a local minimum\n",a1);CHKERRQ(ierr);
82     if (a1 < 1.e-4) *ismin = PETSC_TRUE;
83   }
84   PetscFunctionReturn(0);
85 }
86 
87 /*
88      Checks if J^T(F - J*X) = 0
89 */
90 #undef __FUNCT__
91 #define __FUNCT__ "SNESVICheckResidual_Private"
92 PetscErrorCode SNESVICheckResidual_Private(SNES snes,Mat A,Vec F,Vec X,Vec W1,Vec W2)
93 {
94   PetscReal      a1,a2;
95   PetscErrorCode ierr;
96   PetscBool     hastranspose;
97 
98   PetscFunctionBegin;
99   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
100   if (hastranspose) {
101     ierr = MatMult(A,X,W1);CHKERRQ(ierr);
102     ierr = VecAXPY(W1,-1.0,F);CHKERRQ(ierr);
103 
104     /* Compute || J^T W|| */
105     ierr = MatMultTranspose(A,W1,W2);CHKERRQ(ierr);
106     ierr = VecNorm(W1,NORM_2,&a1);CHKERRQ(ierr);
107     ierr = VecNorm(W2,NORM_2,&a2);CHKERRQ(ierr);
108     if (a1 != 0.0) {
109       ierr = PetscInfo1(snes,"||J^T(F-Ax)||/||F-AX|| %G near zero implies inconsistent rhs\n",a2/a1);CHKERRQ(ierr);
110     }
111   }
112   PetscFunctionReturn(0);
113 }
114 
115 /*
116   SNESDefaultConverged_VI - Checks the convergence of the semismooth newton algorithm.
117 
118   Notes:
119   The convergence criterion currently implemented is
120   merit < abstol
121   merit < rtol*merit_initial
122 */
123 #undef __FUNCT__
124 #define __FUNCT__ "SNESDefaultConverged_VI"
125 PetscErrorCode SNESDefaultConverged_VI(SNES snes,PetscInt it,PetscReal xnorm,PetscReal gradnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
126 {
127   PetscErrorCode ierr;
128 
129   PetscFunctionBegin;
130   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
131   PetscValidPointer(reason,6);
132 
133   *reason = SNES_CONVERGED_ITERATING;
134 
135   if (!it) {
136     /* set parameter for default relative tolerance convergence test */
137     snes->ttol = fnorm*snes->rtol;
138   }
139   if (fnorm != fnorm) {
140     ierr = PetscInfo(snes,"Failed to converged, function norm is NaN\n");CHKERRQ(ierr);
141     *reason = SNES_DIVERGED_FNORM_NAN;
142   } else if (fnorm < snes->abstol) {
143     ierr = PetscInfo2(snes,"Converged due to function norm %G < %G\n",fnorm,snes->abstol);CHKERRQ(ierr);
144     *reason = SNES_CONVERGED_FNORM_ABS;
145   } else if (snes->nfuncs >= snes->max_funcs) {
146     ierr = PetscInfo2(snes,"Exceeded maximum number of function evaluations: %D > %D\n",snes->nfuncs,snes->max_funcs);CHKERRQ(ierr);
147     *reason = SNES_DIVERGED_FUNCTION_COUNT;
148   }
149 
150   if (it && !*reason) {
151     if (fnorm < snes->ttol) {
152       ierr = PetscInfo2(snes,"Converged due to function norm %G < %G (relative tolerance)\n",fnorm,snes->ttol);CHKERRQ(ierr);
153       *reason = SNES_CONVERGED_FNORM_RELATIVE;
154     }
155   }
156   PetscFunctionReturn(0);
157 }
158 
159 /*
160   SNESVIComputeMeritFunction - Evaluates the merit function for the mixed complementarity problem.
161 
162   Input Parameter:
163 . phi - the semismooth function
164 
165   Output Parameter:
166 . merit - the merit function
167 . phinorm - ||phi||
168 
169   Notes:
170   The merit function for the mixed complementarity problem is defined as
171      merit = 0.5*phi^T*phi
172 */
173 #undef __FUNCT__
174 #define __FUNCT__ "SNESVIComputeMeritFunction"
175 static PetscErrorCode SNESVIComputeMeritFunction(Vec phi, PetscReal* merit,PetscReal* phinorm)
176 {
177   PetscErrorCode ierr;
178 
179   PetscFunctionBegin;
180   ierr = VecNormBegin(phi,NORM_2,phinorm);
181   ierr = VecNormEnd(phi,NORM_2,phinorm);
182 
183   *merit = 0.5*(*phinorm)*(*phinorm);
184   PetscFunctionReturn(0);
185 }
186 
187 PETSC_STATIC_INLINE PetscScalar Phi(PetscScalar a,PetscScalar b)
188 {
189   return a + b - sqrt(a*a + b*b);
190 }
191 
192 PETSC_STATIC_INLINE PetscScalar DPhi(PetscScalar a,PetscScalar b)
193 {
194   if ((PetscAbsScalar(a) >= 1.e-6) || (PetscAbsScalar(b) >= 1.e-6)) return  1.0 - a/ sqrt(a*a + b*b);
195   else return .5;
196 }
197 
198 /*
199    SNESVIComputeFunction - Reformulates a system of nonlinear equations in mixed complementarity form to a system of nonlinear equations in semismooth form.
200 
201    Input Parameters:
202 .  snes - the SNES context
203 .  x - current iterate
204 .  functx - user defined function context
205 
206    Output Parameters:
207 .  phi - Semismooth function
208 
209 */
210 #undef __FUNCT__
211 #define __FUNCT__ "SNESVIComputeFunction"
212 static PetscErrorCode SNESVIComputeFunction(SNES snes,Vec X,Vec phi,void* functx)
213 {
214   PetscErrorCode  ierr;
215   SNES_VI         *vi = (SNES_VI*)snes->data;
216   Vec             Xl = vi->xl,Xu = vi->xu,F = snes->vec_func;
217   PetscScalar     *phi_arr,*x_arr,*f_arr,*l,*u;
218   PetscInt        i,nlocal;
219 
220   PetscFunctionBegin;
221   ierr = (*vi->computeuserfunction)(snes,X,F,functx);CHKERRQ(ierr);
222   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
223   ierr = VecGetArray(X,&x_arr);CHKERRQ(ierr);
224   ierr = VecGetArray(F,&f_arr);CHKERRQ(ierr);
225   ierr = VecGetArray(Xl,&l);CHKERRQ(ierr);
226   ierr = VecGetArray(Xu,&u);CHKERRQ(ierr);
227   ierr = VecGetArray(phi,&phi_arr);CHKERRQ(ierr);
228 
229   for (i=0;i < nlocal;i++) {
230     if ((l[i] <= PETSC_VI_NINF) && (u[i] >= PETSC_VI_INF)) { /* no constraints on variable */
231       phi_arr[i] = f_arr[i];
232     } else if (l[i] <= PETSC_VI_NINF) {                      /* upper bound on variable only */
233       phi_arr[i] = -Phi(u[i] - x_arr[i],-f_arr[i]);
234     } else if (u[i] >= PETSC_VI_INF) {                       /* lower bound on variable only */
235       phi_arr[i] = Phi(x_arr[i] - l[i],f_arr[i]);
236     } else if (l[i] == u[i]) {
237       phi_arr[i] = l[i] - x_arr[i];
238     } else {                                                /* both bounds on variable */
239       phi_arr[i] = Phi(x_arr[i] - l[i],-Phi(u[i] - x_arr[i],-f_arr[i]));
240     }
241   }
242 
243   ierr = VecRestoreArray(X,&x_arr);CHKERRQ(ierr);
244   ierr = VecRestoreArray(F,&f_arr);CHKERRQ(ierr);
245   ierr = VecRestoreArray(Xl,&l);CHKERRQ(ierr);
246   ierr = VecRestoreArray(Xu,&u);CHKERRQ(ierr);
247   ierr = VecRestoreArray(phi,&phi_arr);CHKERRQ(ierr);
248   PetscFunctionReturn(0);
249 }
250 
251 /*
252    SNESVIComputeBsubdifferentialVectors - Computes the diagonal shift (Da) and row scaling (Db) vectors needed for the
253                                           the semismooth jacobian.
254 */
255 #undef __FUNCT__
256 #define __FUNCT__ "SNESVIComputeBsubdifferentialVectors"
257 PetscErrorCode SNESVIComputeBsubdifferentialVectors(SNES snes,Vec X,Vec F,Mat jac,Vec Da,Vec Db)
258 {
259   PetscErrorCode ierr;
260   SNES_VI      *vi = (SNES_VI*)snes->data;
261   PetscScalar    *l,*u,*x,*f,*da,*db,da1,da2,db1,db2;
262   PetscInt       i,nlocal;
263 
264   PetscFunctionBegin;
265 
266   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
267   ierr = VecGetArray(F,&f);CHKERRQ(ierr);
268   ierr = VecGetArray(vi->xl,&l);CHKERRQ(ierr);
269   ierr = VecGetArray(vi->xu,&u);CHKERRQ(ierr);
270   ierr = VecGetArray(Da,&da);CHKERRQ(ierr);
271   ierr = VecGetArray(Db,&db);CHKERRQ(ierr);
272   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
273 
274   for (i=0;i< nlocal;i++) {
275     if ((l[i] <= PETSC_VI_NINF) && (u[i] >= PETSC_VI_INF)) {/* no constraints on variable */
276       da[i] = 0;
277       db[i] = 1;
278     } else if (l[i] <= PETSC_VI_NINF) {                     /* upper bound on variable only */
279       da[i] = DPhi(u[i] - x[i], -f[i]);
280       db[i] = DPhi(-f[i],u[i] - x[i]);
281     } else if (u[i] >= PETSC_VI_INF) {                      /* lower bound on variable only */
282       da[i] = DPhi(x[i] - l[i], f[i]);
283       db[i] = DPhi(f[i],x[i] - l[i]);
284     } else if (l[i] == u[i]) {                              /* fixed variable */
285       da[i] = 1;
286       db[i] = 0;
287     } else {                                                /* upper and lower bounds on variable */
288       da1 = DPhi(x[i] - l[i], -Phi(u[i] - x[i], -f[i]));
289       db1 = DPhi(-Phi(u[i] - x[i], -f[i]),x[i] - l[i]);
290       da2 = DPhi(u[i] - x[i], -f[i]);
291       db2 = DPhi(-f[i],u[i] - x[i]);
292       da[i] = da1 + db1*da2;
293       db[i] = db1*db2;
294     }
295   }
296 
297   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
298   ierr = VecRestoreArray(F,&f);CHKERRQ(ierr);
299   ierr = VecRestoreArray(vi->xl,&l);CHKERRQ(ierr);
300   ierr = VecRestoreArray(vi->xu,&u);CHKERRQ(ierr);
301   ierr = VecRestoreArray(Da,&da);CHKERRQ(ierr);
302   ierr = VecRestoreArray(Db,&db);CHKERRQ(ierr);
303   PetscFunctionReturn(0);
304 }
305 
306 /*
307    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.
308 
309    Input Parameters:
310 .  Da       - Diagonal shift vector for the semismooth jacobian.
311 .  Db       - Row scaling vector for the semismooth jacobian.
312 
313    Output Parameters:
314 .  jac      - semismooth jacobian
315 .  jac_pre  - optional preconditioning matrix
316 
317    Notes:
318    The semismooth jacobian matrix is given by
319    jac = Da + Db*jacfun
320    where Db is the row scaling matrix stored as a vector,
321          Da is the diagonal perturbation matrix stored as a vector
322    and   jacfun is the jacobian of the original nonlinear function.
323 */
324 #undef __FUNCT__
325 #define __FUNCT__ "SNESVIComputeJacobian"
326 PetscErrorCode SNESVIComputeJacobian(Mat jac, Mat jac_pre,Vec Da, Vec Db)
327 {
328   PetscErrorCode ierr;
329 
330   /* Do row scaling  and add diagonal perturbation */
331   ierr = MatDiagonalScale(jac,Db,PETSC_NULL);CHKERRQ(ierr);
332   ierr = MatDiagonalSet(jac,Da,ADD_VALUES);CHKERRQ(ierr);
333   if (jac != jac_pre) { /* If jac and jac_pre are different */
334     ierr = MatDiagonalScale(jac_pre,Db,PETSC_NULL);
335     ierr = MatDiagonalSet(jac_pre,Da,ADD_VALUES);CHKERRQ(ierr);
336   }
337   PetscFunctionReturn(0);
338 }
339 
340 /*
341    SNESVIComputeMeritFunctionGradient - Computes the gradient of the merit function psi.
342 
343    Input Parameters:
344    phi - semismooth function.
345    H   - semismooth jacobian
346 
347    Output Parameters:
348    dpsi - merit function gradient
349 
350    Notes:
351   The merit function gradient is computed as follows
352         dpsi = H^T*phi
353 */
354 #undef __FUNCT__
355 #define __FUNCT__ "SNESVIComputeMeritFunctionGradient"
356 PetscErrorCode SNESVIComputeMeritFunctionGradient(Mat H, Vec phi, Vec dpsi)
357 {
358   PetscErrorCode ierr;
359 
360   PetscFunctionBegin;
361   ierr = MatMultTranspose(H,phi,dpsi);
362   PetscFunctionReturn(0);
363 }
364 
365 /* -------------------------------------------------------------------------- */
366 /*
367    SNESVIProjectOntoBounds - Projects X onto the feasible region so that Xl[i] <= X[i] <= Xu[i] for i = 1...n.
368 
369    Input Parameters:
370 .  SNES - nonlinear solver context
371 
372    Output Parameters:
373 .  X - Bound projected X
374 
375 */
376 
377 #undef __FUNCT__
378 #define __FUNCT__ "SNESVIProjectOntoBounds"
379 PetscErrorCode SNESVIProjectOntoBounds(SNES snes,Vec X)
380 {
381   PetscErrorCode    ierr;
382   SNES_VI           *vi = (SNES_VI*)snes->data;
383   const PetscScalar *xl,*xu;
384   PetscScalar       *x;
385   PetscInt          i,n;
386 
387   PetscFunctionBegin;
388   ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr);
389   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
390   ierr = VecGetArrayRead(vi->xl,&xl);CHKERRQ(ierr);
391   ierr = VecGetArrayRead(vi->xu,&xu);CHKERRQ(ierr);
392 
393   for(i = 0;i<n;i++) {
394     if (x[i] < xl[i]) x[i] = xl[i];
395     else if (x[i] > xu[i]) x[i] = xu[i];
396   }
397   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
398   ierr = VecRestoreArrayRead(vi->xl,&xl);CHKERRQ(ierr);
399   ierr = VecRestoreArrayRead(vi->xu,&xu);CHKERRQ(ierr);
400   PetscFunctionReturn(0);
401 }
402 
403 /*  --------------------------------------------------------------------
404 
405      This file implements a semismooth truncated Newton method with a line search,
406      for solving a system of nonlinear equations in complementarity form, using the KSP, Vec,
407      and Mat interfaces for linear solvers, vectors, and matrices,
408      respectively.
409 
410      The following basic routines are required for each nonlinear solver:
411           SNESCreate_XXX()          - Creates a nonlinear solver context
412           SNESSetFromOptions_XXX()  - Sets runtime options
413           SNESSolve_XXX()           - Solves the nonlinear system
414           SNESDestroy_XXX()         - Destroys the nonlinear solver context
415      The suffix "_XXX" denotes a particular implementation, in this case
416      we use _VI (e.g., SNESCreate_VI, SNESSolve_VI) for solving
417      systems of nonlinear equations with a line search (LS) method.
418      These routines are actually called via the common user interface
419      routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and
420      SNESDestroy(), so the application code interface remains identical
421      for all nonlinear solvers.
422 
423      Another key routine is:
424           SNESSetUp_XXX()           - Prepares for the use of a nonlinear solver
425      by setting data structures and options.   The interface routine SNESSetUp()
426      is not usually called directly by the user, but instead is called by
427      SNESSolve() if necessary.
428 
429      Additional basic routines are:
430           SNESView_XXX()            - Prints details of runtime options that
431                                       have actually been used.
432      These are called by application codes via the interface routines
433      SNESView().
434 
435      The various types of solvers (preconditioners, Krylov subspace methods,
436      nonlinear solvers, timesteppers) are all organized similarly, so the
437      above description applies to these categories also.
438 
439     -------------------------------------------------------------------- */
440 /*
441    SNESSolveVI_SS - Solves the complementarity problem with a semismooth Newton
442    method using a line search.
443 
444    Input Parameters:
445 .  snes - the SNES context
446 
447    Output Parameter:
448 .  outits - number of iterations until termination
449 
450    Application Interface Routine: SNESSolve()
451 
452    Notes:
453    This implements essentially a semismooth Newton method with a
454    line search. The default line search does not do any line seach
455    but rather takes a full newton step.
456 */
457 #undef __FUNCT__
458 #define __FUNCT__ "SNESSolveVI_SS"
459 PetscErrorCode SNESSolveVI_SS(SNES snes)
460 {
461   SNES_VI            *vi = (SNES_VI*)snes->data;
462   PetscErrorCode     ierr;
463   PetscInt           maxits,i,lits;
464   PetscBool          lssucceed;
465   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
466   PetscReal          gnorm,xnorm=0,ynorm;
467   Vec                Y,X,F,G,W;
468   KSPConvergedReason kspreason;
469 
470   PetscFunctionBegin;
471   vi->computeuserfunction    = snes->ops->computefunction;
472   snes->ops->computefunction = SNESVIComputeFunction;
473 
474   snes->numFailures            = 0;
475   snes->numLinearSolveFailures = 0;
476   snes->reason                 = SNES_CONVERGED_ITERATING;
477 
478   maxits	= snes->max_its;	/* maximum number of iterations */
479   X		= snes->vec_sol;	/* solution vector */
480   F		= snes->vec_func;	/* residual vector */
481   Y		= snes->work[0];	/* work vectors */
482   G		= snes->work[1];
483   W		= snes->work[2];
484 
485   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
486   snes->iter = 0;
487   snes->norm = 0.0;
488   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
489 
490   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
491   ierr = SNESComputeFunction(snes,X,vi->phi);CHKERRQ(ierr);
492   if (snes->domainerror) {
493     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
494     snes->ops->computefunction = vi->computeuserfunction;
495     PetscFunctionReturn(0);
496   }
497    /* Compute Merit function */
498   ierr = SNESVIComputeMeritFunction(vi->phi,&vi->merit,&vi->phinorm);CHKERRQ(ierr);
499 
500   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
501   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
502   if PetscIsInfOrNanReal(vi->merit) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
503 
504   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
505   snes->norm = vi->phinorm;
506   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
507   SNESLogConvHistory(snes,vi->phinorm,0);
508   SNESMonitor(snes,0,vi->phinorm);
509 
510   /* set parameter for default relative tolerance convergence test */
511   snes->ttol = vi->phinorm*snes->rtol;
512   /* test convergence */
513   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
514   if (snes->reason) {
515     snes->ops->computefunction = vi->computeuserfunction;
516     PetscFunctionReturn(0);
517   }
518 
519   for (i=0; i<maxits; i++) {
520 
521     /* Call general purpose update function */
522     if (snes->ops->update) {
523       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
524     }
525 
526     /* Solve J Y = Phi, where J is the semismooth jacobian */
527     /* Get the nonlinear function jacobian */
528     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
529     /* Get the diagonal shift and row scaling vectors */
530     ierr = SNESVIComputeBsubdifferentialVectors(snes,X,F,snes->jacobian,vi->Da,vi->Db);CHKERRQ(ierr);
531     /* Compute the semismooth jacobian */
532     ierr = SNESVIComputeJacobian(snes->jacobian,snes->jacobian_pre,vi->Da,vi->Db);CHKERRQ(ierr);
533     /* Compute the merit function gradient */
534     ierr = SNESVIComputeMeritFunctionGradient(snes->jacobian,vi->phi,vi->dpsi);CHKERRQ(ierr);
535     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
536     ierr = SNES_KSPSolve(snes,snes->ksp,vi->phi,Y);CHKERRQ(ierr);
537     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
538 
539     if (kspreason < 0) {
540       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
541         ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
542         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
543         break;
544       }
545     }
546     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
547     snes->linear_its += lits;
548     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
549     /*
550     if (vi->precheckstep) {
551       PetscBool changed_y = PETSC_FALSE;
552       ierr = (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);CHKERRQ(ierr);
553     }
554 
555     if (PetscLogPrintInfo){
556       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
557     }
558     */
559     /* Compute a (scaled) negative update in the line search routine:
560          Y <- X - lambda*Y
561        and evaluate G = function(Y) (depends on the line search).
562     */
563     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
564     ynorm = 1; gnorm = vi->phinorm;
565     ierr = (*vi->LineSearch)(snes,vi->lsP,X,vi->phi,G,Y,W,vi->phinorm,xnorm,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
566     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",vi->phinorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr);
567     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
568     if (snes->domainerror) {
569       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
570       snes->ops->computefunction = vi->computeuserfunction;
571       PetscFunctionReturn(0);
572     }
573     if (!lssucceed) {
574       if (++snes->numFailures >= snes->maxFailures) {
575 	PetscBool ismin;
576         snes->reason = SNES_DIVERGED_LINE_SEARCH;
577         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
578         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
579         break;
580       }
581     }
582     /* Update function and solution vectors */
583     vi->phinorm = gnorm;
584     vi->merit = 0.5*vi->phinorm*vi->phinorm;
585     ierr = VecCopy(G,vi->phi);CHKERRQ(ierr);
586     ierr = VecCopy(W,X);CHKERRQ(ierr);
587     /* Monitor convergence */
588     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
589     snes->iter = i+1;
590     snes->norm = vi->phinorm;
591     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
592     SNESLogConvHistory(snes,snes->norm,lits);
593     SNESMonitor(snes,snes->iter,snes->norm);
594     /* Test for convergence, xnorm = || X || */
595     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
596     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
597     if (snes->reason) break;
598   }
599   if (i == maxits) {
600     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
601     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
602   }
603   snes->ops->computefunction = vi->computeuserfunction;
604   PetscFunctionReturn(0);
605 }
606 
607 #undef __FUNCT__
608 #define __FUNCT__ "SNESVIGetActiveSetIS"
609 /*
610    SNESVIGetActiveSetIndices - Gets the global indices for the active set variables
611 
612    Input parameter
613 .  snes - the SNES context
614 .  X    - the snes solution vector
615 .  F    - the nonlinear function vector
616 
617    Output parameter
618 .  ISact - active set index set
619  */
620 PetscErrorCode SNESVIGetActiveSetIS(SNES snes,Vec X,Vec F,IS* ISact)
621 {
622   PetscErrorCode   ierr;
623   SNES_VI          *vi = (SNES_VI*)snes->data;
624   Vec               Xl=vi->xl,Xu=vi->xu;
625   const PetscScalar *x,*f,*xl,*xu;
626   PetscInt          *idx_act,i,nlocal,nloc_isact=0,ilow,ihigh,i1=0;
627 
628   PetscFunctionBegin;
629   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
630   ierr = VecGetOwnershipRange(X,&ilow,&ihigh);CHKERRQ(ierr);
631   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
632   ierr = VecGetArrayRead(Xl,&xl);CHKERRQ(ierr);
633   ierr = VecGetArrayRead(Xu,&xu);CHKERRQ(ierr);
634   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
635   /* Compute active set size */
636   for (i=0; i < nlocal;i++) {
637     if (!((x[i] > xl[i] + 1.e-8 || (f[i] < 0.0)) && ((x[i] < xu[i] - 1.e-8) || f[i] > 0.0))) nloc_isact++;
638   }
639 
640   ierr = PetscMalloc(nloc_isact*sizeof(PetscInt),&idx_act);CHKERRQ(ierr);
641 
642   /* Set active set indices */
643   for(i=0; i < nlocal; i++) {
644     if (!((x[i] > xl[i] + 1.e-8 || (f[i] < 0.0)) && ((x[i] < xu[i] - 1.e-8) || f[i] > 0.0))) idx_act[i1++] = ilow+i;
645   }
646 
647    /* Create active set IS */
648   ierr = ISCreateGeneral(((PetscObject)snes)->comm,nloc_isact,idx_act,PETSC_OWN_POINTER,ISact);CHKERRQ(ierr);
649 
650   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
651   ierr = VecRestoreArrayRead(Xl,&xl);CHKERRQ(ierr);
652   ierr = VecRestoreArrayRead(Xu,&xu);CHKERRQ(ierr);
653   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
654   PetscFunctionReturn(0);
655 }
656 
657 #undef __FUNCT__
658 #define __FUNCT__ "SNESVICreateIndexSets_RS"
659 PetscErrorCode SNESVICreateIndexSets_RS(SNES snes,Vec X,Vec F,IS* ISact,IS* ISinact)
660 {
661   PetscErrorCode     ierr;
662 
663   PetscFunctionBegin;
664   ierr = SNESVIGetActiveSetIS(snes,X,F,ISact);CHKERRQ(ierr);
665   ierr = ISComplement(*ISact,X->map->rstart,X->map->rend,ISinact);CHKERRQ(ierr);
666   PetscFunctionReturn(0);
667 }
668 
669 /* Create active and inactive set vectors. The local size of this vector is set and petsc computes the global size */
670 #undef __FUNCT__
671 #define __FUNCT__ "SNESVICreateSubVectors"
672 PetscErrorCode SNESVICreateSubVectors(SNES snes,PetscInt n,Vec* newv)
673 {
674   PetscErrorCode ierr;
675   Vec            v;
676 
677   PetscFunctionBegin;
678   ierr = VecCreate(((PetscObject)snes)->comm,&v);CHKERRQ(ierr);
679   ierr = VecSetSizes(v,n,PETSC_DECIDE);CHKERRQ(ierr);
680   ierr = VecSetFromOptions(v);CHKERRQ(ierr);
681   *newv = v;
682 
683   PetscFunctionReturn(0);
684 }
685 
686 /* Resets the snes PC and KSP when the active set sizes change */
687 #undef __FUNCT__
688 #define __FUNCT__ "SNESVIResetPCandKSP"
689 PetscErrorCode SNESVIResetPCandKSP(SNES snes,Mat Amat,Mat Pmat)
690 {
691   PetscErrorCode         ierr;
692   KSP                    kspnew,snesksp;
693   PC                     pcnew;
694   const MatSolverPackage stype;
695 
696   PetscFunctionBegin;
697   /* The active and inactive set sizes have changed so need to create a new snes->ksp object */
698   ierr = SNESGetKSP(snes,&snesksp);CHKERRQ(ierr);
699   ierr = KSPCreate(((PetscObject)snes)->comm,&kspnew);CHKERRQ(ierr);
700   /* Copy over snes->ksp info */
701   kspnew->pc_side = snesksp->pc_side;
702   kspnew->rtol    = snesksp->rtol;
703   kspnew->abstol    = snesksp->abstol;
704   kspnew->max_it  = snesksp->max_it;
705   ierr = KSPSetType(kspnew,((PetscObject)snesksp)->type_name);CHKERRQ(ierr);
706   ierr = KSPGetPC(kspnew,&pcnew);CHKERRQ(ierr);
707   ierr = PCSetType(kspnew->pc,((PetscObject)snesksp->pc)->type_name);CHKERRQ(ierr);
708   ierr = PCSetOperators(kspnew->pc,Amat,Pmat,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
709   ierr = PCFactorGetMatSolverPackage(snesksp->pc,&stype);CHKERRQ(ierr);
710   ierr = PCFactorSetMatSolverPackage(kspnew->pc,stype);CHKERRQ(ierr);
711   ierr = KSPDestroy(snesksp);CHKERRQ(ierr);
712   snes->ksp = kspnew;
713   ierr = PetscLogObjectParent(snes,kspnew);CHKERRQ(ierr);
714   ierr = KSPSetFromOptions(kspnew);CHKERRQ(ierr);
715   PetscFunctionReturn(0);
716 }
717 
718 
719 #undef __FUNCT__
720 #define __FUNCT__ "SNESVIComputeInactiveSetFnorm"
721 PetscErrorCode SNESVIComputeInactiveSetFnorm(SNES snes,Vec F,Vec X,PetscScalar *fnorm)
722 {
723   PetscErrorCode    ierr;
724   SNES_VI           *vi = (SNES_VI*)snes->data;
725   const PetscScalar *x,*xl,*xu,*f;
726   PetscInt          i,n;
727   PetscReal         rnorm;
728 
729   PetscFunctionBegin;
730   ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr);
731   ierr = VecGetArrayRead(vi->xl,&xl);CHKERRQ(ierr);
732   ierr = VecGetArrayRead(vi->xu,&xu);CHKERRQ(ierr);
733   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
734   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
735   rnorm = 0.0;
736   for (i=0; i<n; i++) {
737     if (((x[i] > xl[i] + 1.e-8 || (f[i] < 0.0)) && ((x[i] < xu[i] - 1.e-8) || f[i] > 0.0))) rnorm += f[i]*f[i];
738   }
739   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
740   ierr = VecRestoreArrayRead(vi->xl,&xl);CHKERRQ(ierr);
741   ierr = VecRestoreArrayRead(vi->xu,&xu);CHKERRQ(ierr);
742   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
743   ierr = MPI_Allreduce(&rnorm,fnorm,1,MPIU_REAL,MPI_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
744   *fnorm = sqrt(*fnorm);
745   PetscFunctionReturn(0);
746 }
747 
748 /* Variational Inequality solver using reduce space method. No semismooth algorithm is
749    implemented in this algorithm. It basically identifies the active variables and does
750    a linear solve on the inactive variables. */
751 #undef __FUNCT__
752 #define __FUNCT__ "SNESSolveVI_RS"
753 PetscErrorCode SNESSolveVI_RS(SNES snes)
754 {
755   SNES_VI          *vi = (SNES_VI*)snes->data;
756   PetscErrorCode    ierr;
757   PetscInt          maxits,i,lits;
758   PetscBool         lssucceed;
759   MatStructure      flg = DIFFERENT_NONZERO_PATTERN;
760   PetscReal         fnorm,gnorm,xnorm=0,ynorm;
761   Vec                Y,X,F,G,W;
762   KSPConvergedReason kspreason;
763 
764   PetscFunctionBegin;
765   snes->numFailures            = 0;
766   snes->numLinearSolveFailures = 0;
767   snes->reason                 = SNES_CONVERGED_ITERATING;
768 
769   maxits	= snes->max_its;	/* maximum number of iterations */
770   X		= snes->vec_sol;	/* solution vector */
771   F		= snes->vec_func;	/* residual vector */
772   Y		= snes->work[0];	/* work vectors */
773   G		= snes->work[1];
774   W		= snes->work[2];
775 
776   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
777   snes->iter = 0;
778   snes->norm = 0.0;
779   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
780 
781   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
782   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
783   if (snes->domainerror) {
784     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
785     PetscFunctionReturn(0);
786   }
787   ierr = SNESVIComputeInactiveSetFnorm(snes,F,X,&fnorm);CHKERRQ(ierr);
788   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
789   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
790   if PetscIsInfOrNanReal(fnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
791 
792   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
793   snes->norm = fnorm;
794   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
795   SNESLogConvHistory(snes,fnorm,0);
796   SNESMonitor(snes,0,fnorm);
797 
798   /* set parameter for default relative tolerance convergence test */
799   snes->ttol = fnorm*snes->rtol;
800   /* test convergence */
801   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
802   if (snes->reason) PetscFunctionReturn(0);
803 
804   for (i=0; i<maxits; i++) {
805 
806     IS         IS_act,IS_inact; /* _act -> active set _inact -> inactive set */
807     VecScatter scat_act,scat_inact;
808     PetscInt   nis_act,nis_inact;
809     Vec        Y_act,Y_inact,F_inact;
810     Mat        jac_inact_inact,prejac_inact_inact;
811     IS         keptrows;
812     PetscBool  isequal;
813 
814     /* Call general purpose update function */
815     if (snes->ops->update) {
816       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
817     }
818     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
819 
820     /* Create active and inactive index sets */
821     ierr = SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&IS_inact);CHKERRQ(ierr);
822 
823     /* Create inactive set submatrix */
824     ierr = MatGetSubMatrix(snes->jacobian,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr);
825     ierr = MatFindNonzeroRows(jac_inact_inact,&keptrows);CHKERRQ(ierr);
826     if (keptrows) {
827       PetscInt       cnt,*nrows,k;
828       const PetscInt *krows,*inact;
829       PetscInt       rstart=jac_inact_inact->rmap->rstart;
830 
831       ierr = MatDestroy(jac_inact_inact);CHKERRQ(ierr);
832       ierr = ISDestroy(IS_act);CHKERRQ(ierr);
833 
834       ierr = ISGetLocalSize(keptrows,&cnt);CHKERRQ(ierr);
835       ierr = ISGetIndices(keptrows,&krows);CHKERRQ(ierr);
836       ierr = ISGetIndices(IS_inact,&inact);CHKERRQ(ierr);
837       ierr = PetscMalloc(cnt*sizeof(PetscInt),&nrows);CHKERRQ(ierr);
838       for (k=0; k<cnt; k++) {
839         nrows[k] = inact[krows[k]-rstart];
840       }
841       ierr = ISRestoreIndices(keptrows,&krows);CHKERRQ(ierr);
842       ierr = ISRestoreIndices(IS_inact,&inact);CHKERRQ(ierr);
843       ierr = ISDestroy(keptrows);CHKERRQ(ierr);
844       ierr = ISDestroy(IS_inact);CHKERRQ(ierr);
845 
846       ierr = ISCreateGeneral(PETSC_COMM_WORLD,cnt,nrows,PETSC_OWN_POINTER,&IS_inact);CHKERRQ(ierr);
847       ierr = ISComplement(IS_inact,F->map->rstart,F->map->rend,&IS_act);CHKERRQ(ierr);
848       ierr = MatGetSubMatrix(snes->jacobian,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr);
849     }
850 
851     /* Get sizes of active and inactive sets */
852     ierr = ISGetLocalSize(IS_act,&nis_act);CHKERRQ(ierr);
853     ierr = ISGetLocalSize(IS_inact,&nis_inact);CHKERRQ(ierr);
854 
855     /* Create active and inactive set vectors */
856     ierr = SNESVICreateSubVectors(snes,nis_inact,&F_inact);CHKERRQ(ierr);
857     ierr = SNESVICreateSubVectors(snes,nis_act,&Y_act);CHKERRQ(ierr);
858     ierr = SNESVICreateSubVectors(snes,nis_inact,&Y_inact);CHKERRQ(ierr);
859 
860     /* Create scatter contexts */
861     ierr = VecScatterCreate(Y,IS_act,Y_act,PETSC_NULL,&scat_act);CHKERRQ(ierr);
862     ierr = VecScatterCreate(Y,IS_inact,Y_inact,PETSC_NULL,&scat_inact);CHKERRQ(ierr);
863 
864     /* Do a vec scatter to active and inactive set vectors */
865     ierr = VecScatterBegin(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
866     ierr = VecScatterEnd(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
867 
868     ierr = VecScatterBegin(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
869     ierr = VecScatterEnd(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
870 
871     ierr = VecScatterBegin(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
872     ierr = VecScatterEnd(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
873 
874     /* Active set direction = 0 */
875     ierr = VecSet(Y_act,0);CHKERRQ(ierr);
876     if (snes->jacobian != snes->jacobian_pre) {
877       ierr = MatGetSubMatrix(snes->jacobian_pre,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&prejac_inact_inact);CHKERRQ(ierr);
878     } else prejac_inact_inact = jac_inact_inact;
879 
880     ierr = ISEqual(vi->IS_inact_prev,IS_inact,&isequal);CHKERRQ(ierr);
881     if (!isequal) {
882       ierr = SNESVIResetPCandKSP(snes,jac_inact_inact,prejac_inact_inact);CHKERRQ(ierr);
883     }
884 
885     /*      ierr = ISView(IS_inact,0);CHKERRQ(ierr); */
886     /*      ierr = ISView(IS_act,0);CHKERRQ(ierr);*/
887     /*      ierr = MatView(snes->jacobian_pre,0); */
888 
889     ierr = KSPSetOperators(snes->ksp,jac_inact_inact,prejac_inact_inact,flg);CHKERRQ(ierr);
890     ierr = KSPSetUp(snes->ksp);CHKERRQ(ierr);
891     {
892       PC        pc;
893       PetscBool flg;
894       ierr = KSPGetPC(snes->ksp,&pc);CHKERRQ(ierr);
895       ierr = PetscTypeCompare((PetscObject)pc,PCFIELDSPLIT,&flg);CHKERRQ(ierr);
896       if (flg) {
897         KSP      *subksps;
898         ierr = PCFieldSplitGetSubKSP(pc,PETSC_NULL,&subksps);CHKERRQ(ierr);
899         ierr = KSPGetPC(subksps[0],&pc);CHKERRQ(ierr);
900         ierr = PetscFree(subksps);CHKERRQ(ierr);
901         ierr = PetscTypeCompare((PetscObject)pc,PCBJACOBI,&flg);CHKERRQ(ierr);
902         if (flg) {
903           PetscInt       n,N = 101*101,j,cnts[3] = {0,0,0};
904           const PetscInt *ii;
905 
906           ierr = ISGetSize(IS_inact,&n);CHKERRQ(ierr);
907           ierr = ISGetIndices(IS_inact,&ii);CHKERRQ(ierr);
908           for (j=0; j<n; j++) {
909             if (ii[j] < N) cnts[0]++;
910             else if (ii[j] < 2*N) cnts[1]++;
911             else if (ii[j] < 3*N) cnts[2]++;
912           }
913           ierr = ISRestoreIndices(IS_inact,&ii);CHKERRQ(ierr);
914 
915           ierr = PCBJacobiSetTotalBlocks(pc,3,cnts);CHKERRQ(ierr);
916         }
917       }
918     }
919 
920     ierr = SNES_KSPSolve(snes,snes->ksp,F_inact,Y_inact);CHKERRQ(ierr);
921     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
922     if (kspreason < 0) {
923       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
924         ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
925         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
926         break;
927       }
928      }
929 
930     ierr = VecScatterBegin(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
931     ierr = VecScatterEnd(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
932     ierr = VecScatterBegin(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
933     ierr = VecScatterEnd(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
934 
935     ierr = VecDestroy(F_inact);CHKERRQ(ierr);
936     ierr = VecDestroy(Y_act);CHKERRQ(ierr);
937     ierr = VecDestroy(Y_inact);CHKERRQ(ierr);
938     ierr = VecScatterDestroy(scat_act);CHKERRQ(ierr);
939     ierr = VecScatterDestroy(scat_inact);CHKERRQ(ierr);
940     ierr = ISDestroy(IS_act);CHKERRQ(ierr);
941     if (!isequal) {
942       ierr = ISDestroy(vi->IS_inact_prev);CHKERRQ(ierr);
943       ierr = ISDuplicate(IS_inact,&vi->IS_inact_prev);CHKERRQ(ierr);
944     }
945     ierr = ISDestroy(IS_inact);CHKERRQ(ierr);
946     ierr = MatDestroy(jac_inact_inact);CHKERRQ(ierr);
947     if (snes->jacobian != snes->jacobian_pre) {
948       ierr = MatDestroy(prejac_inact_inact);CHKERRQ(ierr);
949     }
950     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
951     snes->linear_its += lits;
952     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
953     /*
954     if (vi->precheckstep) {
955       PetscBool changed_y = PETSC_FALSE;
956       ierr = (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);CHKERRQ(ierr);
957     }
958 
959     if (PetscLogPrintInfo){
960       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
961     }
962     */
963     /* Compute a (scaled) negative update in the line search routine:
964          Y <- X - lambda*Y
965        and evaluate G = function(Y) (depends on the line search).
966     */
967     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
968     ynorm = 1; gnorm = fnorm;
969     ierr = (*vi->LineSearch)(snes,vi->lsP,X,F,G,Y,W,fnorm,xnorm,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
970     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr);
971     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
972     if (snes->domainerror) {
973       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
974       PetscFunctionReturn(0);
975     }
976     if (!lssucceed) {
977       if (++snes->numFailures >= snes->maxFailures) {
978 	PetscBool ismin;
979         snes->reason = SNES_DIVERGED_LINE_SEARCH;
980         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
981         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
982         break;
983       }
984     }
985     /* Update function and solution vectors */
986     fnorm = gnorm;
987     ierr = VecCopy(G,F);CHKERRQ(ierr);
988     ierr = VecCopy(W,X);CHKERRQ(ierr);
989     /* Monitor convergence */
990     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
991     snes->iter = i+1;
992     snes->norm = fnorm;
993     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
994     SNESLogConvHistory(snes,snes->norm,lits);
995     SNESMonitor(snes,snes->iter,snes->norm);
996     /* Test for convergence, xnorm = || X || */
997     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
998     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
999     if (snes->reason) break;
1000   }
1001   if (i == maxits) {
1002     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
1003     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
1004   }
1005   PetscFunctionReturn(0);
1006 }
1007 
1008 /* -------------------------------------------------------------------------- */
1009 /*
1010    SNESSetUp_VI - Sets up the internal data structures for the later use
1011    of the SNESVI nonlinear solver.
1012 
1013    Input Parameter:
1014 .  snes - the SNES context
1015 .  x - the solution vector
1016 
1017    Application Interface Routine: SNESSetUp()
1018 
1019    Notes:
1020    For basic use of the SNES solvers, the user need not explicitly call
1021    SNESSetUp(), since these actions will automatically occur during
1022    the call to SNESSolve().
1023  */
1024 #undef __FUNCT__
1025 #define __FUNCT__ "SNESSetUp_VI"
1026 PetscErrorCode SNESSetUp_VI(SNES snes)
1027 {
1028   PetscErrorCode ierr;
1029   SNES_VI        *vi = (SNES_VI*) snes->data;
1030   PetscInt       i_start[3],i_end[3];
1031 
1032   PetscFunctionBegin;
1033   if (!snes->vec_sol_update) {
1034     ierr = VecDuplicate(snes->vec_sol,&snes->vec_sol_update);CHKERRQ(ierr);
1035     ierr = PetscLogObjectParent(snes,snes->vec_sol_update);CHKERRQ(ierr);
1036   }
1037   if (!snes->work) {
1038     snes->nwork = 3;
1039     ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr);
1040     ierr = PetscLogObjectParents(snes,snes->nwork,snes->work);CHKERRQ(ierr);
1041   }
1042 
1043   /* If the lower and upper bound on variables are not set, set it to
1044      -Inf and Inf */
1045   if (!vi->xl && !vi->xu) {
1046     vi->usersetxbounds = PETSC_FALSE;
1047     ierr = VecDuplicate(snes->vec_sol, &vi->xl); CHKERRQ(ierr);
1048     ierr = VecSet(vi->xl,PETSC_VI_NINF);CHKERRQ(ierr);
1049     ierr = VecDuplicate(snes->vec_sol, &vi->xu); CHKERRQ(ierr);
1050     ierr = VecSet(vi->xu,PETSC_VI_INF);CHKERRQ(ierr);
1051   } else {
1052     /* Check if lower bound, upper bound and solution vector distribution across the processors is identical */
1053     ierr = VecGetOwnershipRange(snes->vec_sol,i_start,i_end);CHKERRQ(ierr);
1054     ierr = VecGetOwnershipRange(vi->xl,i_start+1,i_end+1);CHKERRQ(ierr);
1055     ierr = VecGetOwnershipRange(vi->xu,i_start+2,i_end+2);CHKERRQ(ierr);
1056     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]))
1057       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.");
1058   }
1059   if (snes->ops->solve == SNESSolveVI_RS) {
1060     /* Set up previous active index set for the first snes solve
1061        vi->IS_inact_prev = 0,1,2,....N */
1062     PetscInt *indices;
1063     PetscInt  i,n,rstart,rend;
1064 
1065     ierr = VecGetOwnershipRange(snes->vec_sol,&rstart,&rend);CHKERRQ(ierr);
1066     ierr = VecGetLocalSize(snes->vec_sol,&n);CHKERRQ(ierr);
1067     ierr = PetscMalloc(n*sizeof(PetscInt),&indices);CHKERRQ(ierr);
1068     for(i=0;i < n; i++) indices[i] = rstart + i;
1069     ierr = ISCreateGeneral(((PetscObject)snes)->comm,n,indices,PETSC_OWN_POINTER,&vi->IS_inact_prev);
1070   }
1071 
1072   if (snes->ops->solve != SNESSolveVI_RS) {
1073     ierr = VecDuplicate(snes->vec_sol, &vi->dpsi);CHKERRQ(ierr);
1074     ierr = VecDuplicate(snes->vec_sol, &vi->phi); CHKERRQ(ierr);
1075     ierr = VecDuplicate(snes->vec_sol, &vi->Da); CHKERRQ(ierr);
1076     ierr = VecDuplicate(snes->vec_sol, &vi->Db); CHKERRQ(ierr);
1077     ierr = VecDuplicate(snes->vec_sol, &vi->z);CHKERRQ(ierr);
1078     ierr = VecDuplicate(snes->vec_sol, &vi->t); CHKERRQ(ierr);
1079   }
1080   PetscFunctionReturn(0);
1081 }
1082 /* -------------------------------------------------------------------------- */
1083 /*
1084    SNESDestroy_VI - Destroys the private SNES_VI context that was created
1085    with SNESCreate_VI().
1086 
1087    Input Parameter:
1088 .  snes - the SNES context
1089 
1090    Application Interface Routine: SNESDestroy()
1091  */
1092 #undef __FUNCT__
1093 #define __FUNCT__ "SNESDestroy_VI"
1094 PetscErrorCode SNESDestroy_VI(SNES snes)
1095 {
1096   SNES_VI        *vi = (SNES_VI*) snes->data;
1097   PetscErrorCode ierr;
1098 
1099   PetscFunctionBegin;
1100   if (snes->vec_sol_update) {
1101     ierr = VecDestroy(snes->vec_sol_update);CHKERRQ(ierr);
1102     snes->vec_sol_update = PETSC_NULL;
1103   }
1104   if (snes->work) {
1105     ierr = VecDestroyVecs(snes->nwork,&snes->work);CHKERRQ(ierr);
1106   }
1107   if (snes->ops->solve == SNESSolveVI_RS) {
1108     ierr = ISDestroy(vi->IS_inact_prev);
1109   }
1110 
1111   if (snes->ops->solve != SNESSolveVI_RS) {
1112     /* clear vectors */
1113     ierr = VecDestroy(vi->dpsi);CHKERRQ(ierr);
1114     ierr = VecDestroy(vi->phi); CHKERRQ(ierr);
1115     ierr = VecDestroy(vi->Da); CHKERRQ(ierr);
1116     ierr = VecDestroy(vi->Db); CHKERRQ(ierr);
1117     ierr = VecDestroy(vi->z); CHKERRQ(ierr);
1118     ierr = VecDestroy(vi->t); CHKERRQ(ierr);
1119   }
1120 
1121   if (!vi->usersetxbounds) {
1122     ierr = VecDestroy(vi->xl); CHKERRQ(ierr);
1123     ierr = VecDestroy(vi->xu); CHKERRQ(ierr);
1124   }
1125 
1126   if (vi->lsmonitor) {
1127     ierr = PetscViewerASCIIMonitorDestroy(vi->lsmonitor);CHKERRQ(ierr);
1128   }
1129   ierr = PetscFree(snes->data);CHKERRQ(ierr);
1130 
1131   /* clear composed functions */
1132   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","",PETSC_NULL);CHKERRQ(ierr);
1133   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","",PETSC_NULL);CHKERRQ(ierr);
1134   PetscFunctionReturn(0);
1135 }
1136 
1137 /* -------------------------------------------------------------------------- */
1138 #undef __FUNCT__
1139 #define __FUNCT__ "SNESLineSearchNo_VI"
1140 
1141 /*
1142   This routine does not actually do a line search but it takes a full newton
1143   step while ensuring that the new iterates remain within the constraints.
1144 
1145 */
1146 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,PetscBool *flag)
1147 {
1148   PetscErrorCode ierr;
1149   SNES_VI        *vi = (SNES_VI*)snes->data;
1150   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1151 
1152   PetscFunctionBegin;
1153   *flag = PETSC_TRUE;
1154   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1155   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);         /* ynorm = || y || */
1156   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
1157   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1158   if (vi->postcheckstep) {
1159    ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1160   }
1161   if (changed_y) {
1162     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
1163     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1164   }
1165   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1166   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1167   if (!snes->domainerror) {
1168     if (snes->ops->solve == SNESSolveVI_RS) {
1169        ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1170     } else {
1171       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);  /* gnorm = || g || */
1172     }
1173     if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1174   }
1175   if (vi->lsmonitor) {
1176     ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1177   }
1178   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1179   PetscFunctionReturn(0);
1180 }
1181 
1182 /* -------------------------------------------------------------------------- */
1183 #undef __FUNCT__
1184 #define __FUNCT__ "SNESLineSearchNoNorms_VI"
1185 
1186 /*
1187   This routine is a copy of SNESLineSearchNoNorms in snes/impls/ls/ls.c
1188 */
1189 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,PetscBool *flag)
1190 {
1191   PetscErrorCode ierr;
1192   SNES_VI        *vi = (SNES_VI*)snes->data;
1193   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1194 
1195   PetscFunctionBegin;
1196   *flag = PETSC_TRUE;
1197   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1198   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y      */
1199   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1200   if (vi->postcheckstep) {
1201    ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1202   }
1203   if (changed_y) {
1204     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
1205     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1206   }
1207 
1208   /* don't evaluate function the last time through */
1209   if (snes->iter < snes->max_its-1) {
1210     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1211   }
1212   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1213   PetscFunctionReturn(0);
1214 }
1215 
1216 /* -------------------------------------------------------------------------- */
1217 #undef __FUNCT__
1218 #define __FUNCT__ "SNESLineSearchCubic_VI"
1219 /*
1220   This routine implements a cubic line search while doing a projection on the variable bounds
1221 */
1222 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,PetscBool *flag)
1223 {
1224   PetscReal      initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
1225   PetscReal      minlambda,lambda,lambdatemp;
1226 #if defined(PETSC_USE_COMPLEX)
1227   PetscScalar    cinitslope;
1228 #endif
1229   PetscErrorCode ierr;
1230   PetscInt       count;
1231   SNES_VI        *vi = (SNES_VI*)snes->data;
1232   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1233   MPI_Comm       comm;
1234 
1235   PetscFunctionBegin;
1236   ierr = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
1237   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1238   *flag   = PETSC_TRUE;
1239 
1240   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
1241   if (*ynorm == 0.0) {
1242     if (vi->lsmonitor) {
1243       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Initial direction and size is 0\n");CHKERRQ(ierr);
1244     }
1245     *gnorm = fnorm;
1246     ierr   = VecCopy(x,w);CHKERRQ(ierr);
1247     ierr   = VecCopy(f,g);CHKERRQ(ierr);
1248     *flag  = PETSC_FALSE;
1249     goto theend1;
1250   }
1251   if (*ynorm > vi->maxstep) {	/* Step too big, so scale back */
1252     if (vi->lsmonitor) {
1253       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Scaling step by %G old ynorm %G\n",vi->maxstep/(*ynorm),*ynorm);CHKERRQ(ierr);
1254     }
1255     ierr = VecScale(y,vi->maxstep/(*ynorm));CHKERRQ(ierr);
1256     *ynorm = vi->maxstep;
1257   }
1258   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
1259   minlambda = vi->minlambda/rellength;
1260   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
1261 #if defined(PETSC_USE_COMPLEX)
1262   ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
1263   initslope = PetscRealPart(cinitslope);
1264 #else
1265   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
1266 #endif
1267   if (initslope > 0.0)  initslope = -initslope;
1268   if (initslope == 0.0) initslope = -1.0;
1269 
1270   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1271   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1272   if (snes->nfuncs >= snes->max_funcs) {
1273     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
1274     *flag = PETSC_FALSE;
1275     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1276     goto theend1;
1277   }
1278   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1279   if (snes->ops->solve == SNESSolveVI_RS) {
1280     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1281   } else {
1282     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1283   }
1284   if (snes->domainerror) {
1285     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1286     PetscFunctionReturn(0);
1287   }
1288   if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1289   ierr = PetscInfo2(snes,"Initial fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1290   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + vi->alpha*initslope) { /* Sufficient reduction */
1291     if (vi->lsmonitor) {
1292       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1293     }
1294     goto theend1;
1295   }
1296 
1297   /* Fit points with quadratic */
1298   lambda     = 1.0;
1299   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
1300   lambdaprev = lambda;
1301   gnormprev  = *gnorm;
1302   if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
1303   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
1304   else                         lambda = lambdatemp;
1305 
1306   ierr  = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
1307   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1308   if (snes->nfuncs >= snes->max_funcs) {
1309     ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);CHKERRQ(ierr);
1310     *flag = PETSC_FALSE;
1311     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1312     goto theend1;
1313   }
1314   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1315   if (snes->ops->solve == SNESSolveVI_RS) {
1316     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1317   } else {
1318     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1319   }
1320   if (snes->domainerror) {
1321     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1322     PetscFunctionReturn(0);
1323   }
1324   if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1325   if (vi->lsmonitor) {
1326     ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: gnorm after quadratic fit %G\n",*gnorm);CHKERRQ(ierr);
1327   }
1328   if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* sufficient reduction */
1329     if (vi->lsmonitor) {
1330       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Quadratically determined step, lambda=%18.16e\n",lambda);CHKERRQ(ierr);
1331     }
1332     goto theend1;
1333   }
1334 
1335   /* Fit points with cubic */
1336   count = 1;
1337   while (PETSC_TRUE) {
1338     if (lambda <= minlambda) {
1339       if (vi->lsmonitor) {
1340 	ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: unable to find good step length! After %D tries \n",count);CHKERRQ(ierr);
1341 	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);
1342       }
1343       *flag = PETSC_FALSE;
1344       break;
1345     }
1346     t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
1347     t2 = .5*(gnormprev*gnormprev  - fnorm*fnorm) - lambdaprev*initslope;
1348     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
1349     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
1350     d  = b*b - 3*a*initslope;
1351     if (d < 0.0) d = 0.0;
1352     if (a == 0.0) {
1353       lambdatemp = -initslope/(2.0*b);
1354     } else {
1355       lambdatemp = (-b + sqrt(d))/(3.0*a);
1356     }
1357     lambdaprev = lambda;
1358     gnormprev  = *gnorm;
1359     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
1360     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
1361     else                         lambda     = lambdatemp;
1362     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
1363     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1364     if (snes->nfuncs >= snes->max_funcs) {
1365       ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
1366       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);
1367       *flag = PETSC_FALSE;
1368       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1369       break;
1370     }
1371     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1372     if (snes->ops->solve == SNESSolveVI_RS) {
1373       ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1374     } else {
1375       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1376     }
1377     if (snes->domainerror) {
1378       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1379       PetscFunctionReturn(0);
1380     }
1381     if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1382     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* is reduction enough? */
1383       if (vi->lsmonitor) {
1384 	ierr = PetscPrintf(comm,"    Line search: Cubically determined step, current gnorm %G lambda=%18.16e\n",*gnorm,lambda);CHKERRQ(ierr);
1385       }
1386       break;
1387     } else {
1388       if (vi->lsmonitor) {
1389         ierr = PetscPrintf(comm,"    Line search: Cubic step no good, shrinking lambda, current gnorm %G lambda=%18.16e\n",*gnorm,lambda);CHKERRQ(ierr);
1390       }
1391     }
1392     count++;
1393   }
1394   theend1:
1395   /* Optional user-defined check for line search step validity */
1396   if (vi->postcheckstep && *flag) {
1397     ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1398     if (changed_y) {
1399       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1400       ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1401     }
1402     if (changed_y || changed_w) { /* recompute the function if the step has changed */
1403       ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1404       if (snes->ops->solve == SNESSolveVI_RS) {
1405         ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1406       } else {
1407         ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1408       }
1409       if (snes->domainerror) {
1410         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1411         PetscFunctionReturn(0);
1412       }
1413       if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1414       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
1415       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
1416     }
1417   }
1418   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1419   PetscFunctionReturn(0);
1420 }
1421 
1422 #undef __FUNCT__
1423 #define __FUNCT__ "SNESLineSearchQuadratic_VI"
1424 /*
1425   This routine does a quadratic line search while keeping the iterates within the variable bounds
1426 */
1427 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,PetscBool *flag)
1428 {
1429   /*
1430      Note that for line search purposes we work with with the related
1431      minimization problem:
1432         min  z(x):  R^n -> R,
1433      where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
1434    */
1435   PetscReal      initslope,minlambda,lambda,lambdatemp,rellength;
1436 #if defined(PETSC_USE_COMPLEX)
1437   PetscScalar    cinitslope;
1438 #endif
1439   PetscErrorCode ierr;
1440   PetscInt       count;
1441   SNES_VI        *vi = (SNES_VI*)snes->data;
1442   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1443 
1444   PetscFunctionBegin;
1445   ierr    = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1446   *flag   = PETSC_TRUE;
1447 
1448   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
1449   if (*ynorm == 0.0) {
1450     if (vi->lsmonitor) {
1451       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"Line search: Direction and size is 0\n");CHKERRQ(ierr);
1452     }
1453     *gnorm = fnorm;
1454     ierr   = VecCopy(x,w);CHKERRQ(ierr);
1455     ierr   = VecCopy(f,g);CHKERRQ(ierr);
1456     *flag  = PETSC_FALSE;
1457     goto theend2;
1458   }
1459   if (*ynorm > vi->maxstep) {	/* Step too big, so scale back */
1460     ierr   = VecScale(y,vi->maxstep/(*ynorm));CHKERRQ(ierr);
1461     *ynorm = vi->maxstep;
1462   }
1463   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
1464   minlambda = vi->minlambda/rellength;
1465   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
1466 #if defined(PETSC_USE_COMPLEX)
1467   ierr      = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
1468   initslope = PetscRealPart(cinitslope);
1469 #else
1470   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
1471 #endif
1472   if (initslope > 0.0)  initslope = -initslope;
1473   if (initslope == 0.0) initslope = -1.0;
1474   ierr = PetscInfo1(snes,"Initslope %G \n",initslope);CHKERRQ(ierr);
1475 
1476   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1477   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1478   if (snes->nfuncs >= snes->max_funcs) {
1479     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
1480     *flag = PETSC_FALSE;
1481     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1482     goto theend2;
1483   }
1484   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1485   if (snes->ops->solve == SNESSolveVI_RS) {
1486     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1487   } else {
1488     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1489   }
1490   if (snes->domainerror) {
1491     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1492     PetscFunctionReturn(0);
1493   }
1494   if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1495   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + vi->alpha*initslope) { /* Sufficient reduction */
1496     if (vi->lsmonitor) {
1497       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1498     }
1499     goto theend2;
1500   }
1501 
1502   /* Fit points with quadratic */
1503   lambda = 1.0;
1504   count = 1;
1505   while (PETSC_TRUE) {
1506     if (lambda <= minlambda) { /* bad luck; use full step */
1507       if (vi->lsmonitor) {
1508         ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"Line search: Unable to find good step length! %D \n",count);CHKERRQ(ierr);
1509         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);
1510       }
1511       ierr = VecCopy(x,w);CHKERRQ(ierr);
1512       *flag = PETSC_FALSE;
1513       break;
1514     }
1515     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
1516     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
1517     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
1518     else                         lambda     = lambdatemp;
1519 
1520     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
1521     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1522     if (snes->nfuncs >= snes->max_funcs) {
1523       ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
1524       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);
1525       *flag = PETSC_FALSE;
1526       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1527       break;
1528     }
1529     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1530     if (snes->domainerror) {
1531       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1532       PetscFunctionReturn(0);
1533     }
1534     if (snes->ops->solve == SNESSolveVI_RS) {
1535       ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1536     } else {
1537       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1538     }
1539     if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1540     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* sufficient reduction */
1541       if (vi->lsmonitor) {
1542         ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line Search: Quadratically determined step, lambda=%G\n",lambda);CHKERRQ(ierr);
1543       }
1544       break;
1545     }
1546     count++;
1547   }
1548   theend2:
1549   /* Optional user-defined check for line search step validity */
1550   if (vi->postcheckstep) {
1551     ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1552     if (changed_y) {
1553       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1554       ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1555     }
1556     if (changed_y || changed_w) { /* recompute the function if the step has changed */
1557       ierr = SNESComputeFunction(snes,w,g);
1558       if (snes->domainerror) {
1559         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1560         PetscFunctionReturn(0);
1561       }
1562       if (snes->ops->solve == SNESSolveVI_RS) {
1563         ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1564       } else {
1565         ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1566       }
1567 
1568       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
1569       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
1570       if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1571     }
1572   }
1573   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1574   PetscFunctionReturn(0);
1575 }
1576 
1577 typedef PetscErrorCode (*FCN2)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal,PetscReal*,PetscReal*,PetscBool*); /* force argument to next function to not be extern C*/
1578 /* -------------------------------------------------------------------------- */
1579 EXTERN_C_BEGIN
1580 #undef __FUNCT__
1581 #define __FUNCT__ "SNESLineSearchSet_VI"
1582 PetscErrorCode  SNESLineSearchSet_VI(SNES snes,FCN2 func,void *lsctx)
1583 {
1584   PetscFunctionBegin;
1585   ((SNES_VI *)(snes->data))->LineSearch = func;
1586   ((SNES_VI *)(snes->data))->lsP        = lsctx;
1587   PetscFunctionReturn(0);
1588 }
1589 EXTERN_C_END
1590 
1591 /* -------------------------------------------------------------------------- */
1592 EXTERN_C_BEGIN
1593 #undef __FUNCT__
1594 #define __FUNCT__ "SNESLineSearchSetMonitor_VI"
1595 PetscErrorCode  SNESLineSearchSetMonitor_VI(SNES snes,PetscBool flg)
1596 {
1597   SNES_VI        *vi = (SNES_VI*)snes->data;
1598   PetscErrorCode ierr;
1599 
1600   PetscFunctionBegin;
1601   if (flg && !vi->lsmonitor) {
1602     ierr = PetscViewerASCIIMonitorCreate(((PetscObject)snes)->comm,"stdout",((PetscObject)snes)->tablevel,&vi->lsmonitor);CHKERRQ(ierr);
1603   } else if (!flg && vi->lsmonitor) {
1604     ierr = PetscViewerASCIIMonitorDestroy(vi->lsmonitor);CHKERRQ(ierr);
1605   }
1606   PetscFunctionReturn(0);
1607 }
1608 EXTERN_C_END
1609 
1610 /*
1611    SNESView_VI - Prints info from the SNESVI data structure.
1612 
1613    Input Parameters:
1614 .  SNES - the SNES context
1615 .  viewer - visualization context
1616 
1617    Application Interface Routine: SNESView()
1618 */
1619 #undef __FUNCT__
1620 #define __FUNCT__ "SNESView_VI"
1621 static PetscErrorCode SNESView_VI(SNES snes,PetscViewer viewer)
1622 {
1623   SNES_VI        *vi = (SNES_VI *)snes->data;
1624   const char     *cstr,*tstr;
1625   PetscErrorCode ierr;
1626   PetscBool     iascii;
1627 
1628   PetscFunctionBegin;
1629   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
1630   if (iascii) {
1631     if (vi->LineSearch == SNESLineSearchNo_VI)             cstr = "SNESLineSearchNo";
1632     else if (vi->LineSearch == SNESLineSearchQuadratic_VI) cstr = "SNESLineSearchQuadratic";
1633     else if (vi->LineSearch == SNESLineSearchCubic_VI)     cstr = "SNESLineSearchCubic";
1634     else                                                             cstr = "unknown";
1635     if (snes->ops->solve == SNESSolveVI_SS)      tstr = "Semismooth";
1636     else if (snes->ops->solve == SNESSolveVI_RS) tstr = "Reduced Space";
1637     else                                         tstr = "unknown";
1638     ierr = PetscViewerASCIIPrintf(viewer,"  VI algorithm: %s\n",tstr);CHKERRQ(ierr);
1639     ierr = PetscViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);CHKERRQ(ierr);
1640     ierr = PetscViewerASCIIPrintf(viewer,"  alpha=%G, maxstep=%G, minlambda=%G\n",vi->alpha,vi->maxstep,vi->minlambda);CHKERRQ(ierr);
1641   } else {
1642     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Viewer type %s not supported for SNES EQ VI",((PetscObject)viewer)->type_name);
1643   }
1644   PetscFunctionReturn(0);
1645 }
1646 
1647 #undef __FUNCT__
1648 #define __FUNCT__ "SNESVISetVariableBounds"
1649 /*@
1650    SNESVISetVariableBounds - Sets the lower and upper bounds for the solution vector. xl <= x <= xu.
1651 
1652    Input Parameters:
1653 .  snes - the SNES context.
1654 .  xl   - lower bound.
1655 .  xu   - upper bound.
1656 
1657    Notes:
1658    If this routine is not called then the lower and upper bounds are set to
1659    PETSC_VI_INF and PETSC_VI_NINF respectively during SNESSetUp().
1660 
1661 @*/
1662 PetscErrorCode SNESVISetVariableBounds(SNES snes, Vec xl, Vec xu)
1663 {
1664   SNES_VI  *vi = (SNES_VI*)snes->data;
1665 
1666   PetscFunctionBegin;
1667   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
1668   PetscValidHeaderSpecific(xl,VEC_CLASSID,2);
1669   PetscValidHeaderSpecific(xu,VEC_CLASSID,3);
1670   if (!snes->vec_func) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call SNESSetFunction() first");
1671   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);
1672   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);
1673 
1674   vi->usersetxbounds = PETSC_TRUE;
1675   vi->xl = xl;
1676   vi->xu = xu;
1677   PetscFunctionReturn(0);
1678 }
1679 
1680 /* -------------------------------------------------------------------------- */
1681 /*
1682    SNESSetFromOptions_VI - Sets various parameters for the SNESVI method.
1683 
1684    Input Parameter:
1685 .  snes - the SNES context
1686 
1687    Application Interface Routine: SNESSetFromOptions()
1688 */
1689 #undef __FUNCT__
1690 #define __FUNCT__ "SNESSetFromOptions_VI"
1691 static PetscErrorCode SNESSetFromOptions_VI(SNES snes)
1692 {
1693   SNES_VI        *vi = (SNES_VI *)snes->data;
1694   const char     *lses[] = {"basic","basicnonorms","quadratic","cubic"};
1695   const char     *vies[] = {"ss","rs"};
1696   PetscErrorCode ierr;
1697   PetscInt       indx;
1698   PetscBool      flg,set,flg2;
1699 
1700   PetscFunctionBegin;
1701   ierr = PetscOptionsHead("SNES semismooth method options");CHKERRQ(ierr);
1702   ierr = PetscOptionsBool("-snes_vi_monitor","Monitor all non-active variables","None",PETSC_FALSE,&flg,0);CHKERRQ(ierr);
1703   if (flg) {
1704     ierr = SNESMonitorSet(snes,SNESMonitorVI,0,0);CHKERRQ(ierr);
1705   }
1706   ierr = PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",vi->alpha,&vi->alpha,0);CHKERRQ(ierr);
1707   ierr = PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",vi->maxstep,&vi->maxstep,0);CHKERRQ(ierr);
1708   ierr = PetscOptionsReal("-snes_ls_minlambda","Minimum lambda allowed","None",vi->minlambda,&vi->minlambda,0);CHKERRQ(ierr);
1709   ierr = PetscOptionsReal("-snes_vi_const_tol","constraint tolerance","None",vi->const_tol,&vi->const_tol,0);CHKERRQ(ierr);
1710   ierr = PetscOptionsBool("-snes_ls_monitor","Print progress of line searches","SNESLineSearchSetMonitor",vi->lsmonitor ? PETSC_TRUE : PETSC_FALSE,&flg,&set);CHKERRQ(ierr);
1711   if (set) {ierr = SNESLineSearchSetMonitor(snes,flg);CHKERRQ(ierr);}
1712   ierr = PetscOptionsEList("-snes_vi_type","Semismooth algorithm used","",vies,2,"ss",&indx,&flg2);CHKERRQ(ierr);
1713   if (flg2) {
1714     switch (indx) {
1715     case 0:
1716       snes->ops->solve = SNESSolveVI_SS;
1717       break;
1718     case 1:
1719       snes->ops->solve = SNESSolveVI_RS;
1720       break;
1721     }
1722   }
1723   ierr = PetscOptionsEList("-snes_ls","Line search used","SNESLineSearchSet",lses,4,"basic",&indx,&flg);CHKERRQ(ierr);
1724   if (flg) {
1725     switch (indx) {
1726     case 0:
1727       ierr = SNESLineSearchSet(snes,SNESLineSearchNo_VI,PETSC_NULL);CHKERRQ(ierr);
1728       break;
1729     case 1:
1730       ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms_VI,PETSC_NULL);CHKERRQ(ierr);
1731       break;
1732     case 2:
1733       ierr = SNESLineSearchSet(snes,SNESLineSearchQuadratic_VI,PETSC_NULL);CHKERRQ(ierr);
1734       break;
1735     case 3:
1736       ierr = SNESLineSearchSet(snes,SNESLineSearchCubic_VI,PETSC_NULL);CHKERRQ(ierr);
1737       break;
1738     }
1739   }
1740   ierr = PetscOptionsTail();CHKERRQ(ierr);
1741   PetscFunctionReturn(0);
1742 }
1743 /* -------------------------------------------------------------------------- */
1744 /*MC
1745       SNESVI - Semismooth newton method based nonlinear solver that uses a line search
1746 
1747    Options Database:
1748 +   -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
1749 .   -snes_ls_alpha <alpha> - Sets alpha
1750 .   -snes_ls_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)
1751 .   -snes_ls_minlambda <minlambda>  - Sets the minimum lambda the line search will use  minlambda / max_i ( y[i]/x[i] )
1752 -   -snes_ls_monitor - print information about progress of line searches
1753 
1754 
1755    Level: beginner
1756 
1757 .seealso:  SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(),
1758            SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(),
1759            SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams()
1760 
1761 M*/
1762 EXTERN_C_BEGIN
1763 #undef __FUNCT__
1764 #define __FUNCT__ "SNESCreate_VI"
1765 PetscErrorCode  SNESCreate_VI(SNES snes)
1766 {
1767   PetscErrorCode ierr;
1768   SNES_VI      *vi;
1769 
1770   PetscFunctionBegin;
1771   snes->ops->setup	     = SNESSetUp_VI;
1772   snes->ops->solve	     = SNESSolveVI_SS;
1773   snes->ops->destroy	     = SNESDestroy_VI;
1774   snes->ops->setfromoptions  = SNESSetFromOptions_VI;
1775   snes->ops->view            = SNESView_VI;
1776   snes->ops->converged       = SNESDefaultConverged_VI;
1777 
1778   ierr                   = PetscNewLog(snes,SNES_VI,&vi);CHKERRQ(ierr);
1779   snes->data    	 = (void*)vi;
1780   vi->alpha		 = 1.e-4;
1781   vi->maxstep		 = 1.e8;
1782   vi->minlambda         = 1.e-12;
1783   vi->LineSearch        = SNESLineSearchNo_VI;
1784   vi->lsP               = PETSC_NULL;
1785   vi->postcheckstep     = PETSC_NULL;
1786   vi->postcheck         = PETSC_NULL;
1787   vi->precheckstep      = PETSC_NULL;
1788   vi->precheck          = PETSC_NULL;
1789   vi->const_tol         =  2.2204460492503131e-16;
1790 
1791   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","SNESLineSearchSetMonitor_VI",SNESLineSearchSetMonitor_VI);CHKERRQ(ierr);
1792   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","SNESLineSearchSet_VI",SNESLineSearchSet_VI);CHKERRQ(ierr);
1793 
1794   PetscFunctionReturn(0);
1795 }
1796 EXTERN_C_END
1797