xref: /petsc/src/snes/impls/vi/vi.c (revision 13e0d08325be81619ffebf1117f9a3b4ad59ea83)
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->nwork) {
1105     ierr = VecDestroyVecs(&snes->work,snes->nwork);CHKERRQ(ierr);
1106     snes->nwork = 0;
1107   }
1108   if (snes->ops->solve == SNESSolveVI_RS) {
1109     ierr = ISDestroy(vi->IS_inact_prev);
1110   }
1111 
1112   if (snes->ops->solve != SNESSolveVI_RS) {
1113     /* clear vectors */
1114     ierr = VecDestroy(vi->dpsi);CHKERRQ(ierr);
1115     ierr = VecDestroy(vi->phi); CHKERRQ(ierr);
1116     ierr = VecDestroy(vi->Da); CHKERRQ(ierr);
1117     ierr = VecDestroy(vi->Db); CHKERRQ(ierr);
1118     ierr = VecDestroy(vi->z); CHKERRQ(ierr);
1119     ierr = VecDestroy(vi->t); CHKERRQ(ierr);
1120   }
1121 
1122   if (!vi->usersetxbounds) {
1123     ierr = VecDestroy(vi->xl); CHKERRQ(ierr);
1124     ierr = VecDestroy(vi->xu); CHKERRQ(ierr);
1125   }
1126 
1127   if (vi->lsmonitor) {
1128     ierr = PetscViewerASCIIMonitorDestroy(vi->lsmonitor);CHKERRQ(ierr);
1129   }
1130   ierr = PetscFree(snes->data);CHKERRQ(ierr);
1131 
1132   /* clear composed functions */
1133   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","",PETSC_NULL);CHKERRQ(ierr);
1134   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","",PETSC_NULL);CHKERRQ(ierr);
1135   PetscFunctionReturn(0);
1136 }
1137 
1138 /* -------------------------------------------------------------------------- */
1139 #undef __FUNCT__
1140 #define __FUNCT__ "SNESLineSearchNo_VI"
1141 
1142 /*
1143   This routine does not actually do a line search but it takes a full newton
1144   step while ensuring that the new iterates remain within the constraints.
1145 
1146 */
1147 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)
1148 {
1149   PetscErrorCode ierr;
1150   SNES_VI        *vi = (SNES_VI*)snes->data;
1151   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1152 
1153   PetscFunctionBegin;
1154   *flag = PETSC_TRUE;
1155   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1156   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);         /* ynorm = || y || */
1157   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
1158   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1159   if (vi->postcheckstep) {
1160    ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1161   }
1162   if (changed_y) {
1163     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
1164     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1165   }
1166   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1167   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1168   if (!snes->domainerror) {
1169     if (snes->ops->solve == SNESSolveVI_RS) {
1170        ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1171     } else {
1172       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);  /* gnorm = || g || */
1173     }
1174     if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1175   }
1176   if (vi->lsmonitor) {
1177     ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1178   }
1179   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1180   PetscFunctionReturn(0);
1181 }
1182 
1183 /* -------------------------------------------------------------------------- */
1184 #undef __FUNCT__
1185 #define __FUNCT__ "SNESLineSearchNoNorms_VI"
1186 
1187 /*
1188   This routine is a copy of SNESLineSearchNoNorms in snes/impls/ls/ls.c
1189 */
1190 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)
1191 {
1192   PetscErrorCode ierr;
1193   SNES_VI        *vi = (SNES_VI*)snes->data;
1194   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1195 
1196   PetscFunctionBegin;
1197   *flag = PETSC_TRUE;
1198   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1199   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y      */
1200   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1201   if (vi->postcheckstep) {
1202    ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1203   }
1204   if (changed_y) {
1205     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
1206     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1207   }
1208 
1209   /* don't evaluate function the last time through */
1210   if (snes->iter < snes->max_its-1) {
1211     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1212   }
1213   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1214   PetscFunctionReturn(0);
1215 }
1216 
1217 /* -------------------------------------------------------------------------- */
1218 #undef __FUNCT__
1219 #define __FUNCT__ "SNESLineSearchCubic_VI"
1220 /*
1221   This routine implements a cubic line search while doing a projection on the variable bounds
1222 */
1223 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)
1224 {
1225   PetscReal      initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
1226   PetscReal      minlambda,lambda,lambdatemp;
1227 #if defined(PETSC_USE_COMPLEX)
1228   PetscScalar    cinitslope;
1229 #endif
1230   PetscErrorCode ierr;
1231   PetscInt       count;
1232   SNES_VI        *vi = (SNES_VI*)snes->data;
1233   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1234   MPI_Comm       comm;
1235 
1236   PetscFunctionBegin;
1237   ierr = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
1238   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1239   *flag   = PETSC_TRUE;
1240 
1241   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
1242   if (*ynorm == 0.0) {
1243     if (vi->lsmonitor) {
1244       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Initial direction and size is 0\n");CHKERRQ(ierr);
1245     }
1246     *gnorm = fnorm;
1247     ierr   = VecCopy(x,w);CHKERRQ(ierr);
1248     ierr   = VecCopy(f,g);CHKERRQ(ierr);
1249     *flag  = PETSC_FALSE;
1250     goto theend1;
1251   }
1252   if (*ynorm > vi->maxstep) {	/* Step too big, so scale back */
1253     if (vi->lsmonitor) {
1254       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Scaling step by %G old ynorm %G\n",vi->maxstep/(*ynorm),*ynorm);CHKERRQ(ierr);
1255     }
1256     ierr = VecScale(y,vi->maxstep/(*ynorm));CHKERRQ(ierr);
1257     *ynorm = vi->maxstep;
1258   }
1259   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
1260   minlambda = vi->minlambda/rellength;
1261   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
1262 #if defined(PETSC_USE_COMPLEX)
1263   ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
1264   initslope = PetscRealPart(cinitslope);
1265 #else
1266   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
1267 #endif
1268   if (initslope > 0.0)  initslope = -initslope;
1269   if (initslope == 0.0) initslope = -1.0;
1270 
1271   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1272   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1273   if (snes->nfuncs >= snes->max_funcs) {
1274     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
1275     *flag = PETSC_FALSE;
1276     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1277     goto theend1;
1278   }
1279   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1280   if (snes->ops->solve == SNESSolveVI_RS) {
1281     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1282   } else {
1283     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1284   }
1285   if (snes->domainerror) {
1286     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1287     PetscFunctionReturn(0);
1288   }
1289   if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1290   ierr = PetscInfo2(snes,"Initial fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1291   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + vi->alpha*initslope) { /* Sufficient reduction */
1292     if (vi->lsmonitor) {
1293       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1294     }
1295     goto theend1;
1296   }
1297 
1298   /* Fit points with quadratic */
1299   lambda     = 1.0;
1300   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
1301   lambdaprev = lambda;
1302   gnormprev  = *gnorm;
1303   if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
1304   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
1305   else                         lambda = lambdatemp;
1306 
1307   ierr  = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
1308   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1309   if (snes->nfuncs >= snes->max_funcs) {
1310     ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);CHKERRQ(ierr);
1311     *flag = PETSC_FALSE;
1312     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1313     goto theend1;
1314   }
1315   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1316   if (snes->ops->solve == SNESSolveVI_RS) {
1317     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1318   } else {
1319     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1320   }
1321   if (snes->domainerror) {
1322     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1323     PetscFunctionReturn(0);
1324   }
1325   if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1326   if (vi->lsmonitor) {
1327     ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: gnorm after quadratic fit %G\n",*gnorm);CHKERRQ(ierr);
1328   }
1329   if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* sufficient reduction */
1330     if (vi->lsmonitor) {
1331       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Quadratically determined step, lambda=%18.16e\n",lambda);CHKERRQ(ierr);
1332     }
1333     goto theend1;
1334   }
1335 
1336   /* Fit points with cubic */
1337   count = 1;
1338   while (PETSC_TRUE) {
1339     if (lambda <= minlambda) {
1340       if (vi->lsmonitor) {
1341 	ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: unable to find good step length! After %D tries \n",count);CHKERRQ(ierr);
1342 	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);
1343       }
1344       *flag = PETSC_FALSE;
1345       break;
1346     }
1347     t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
1348     t2 = .5*(gnormprev*gnormprev  - fnorm*fnorm) - lambdaprev*initslope;
1349     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
1350     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
1351     d  = b*b - 3*a*initslope;
1352     if (d < 0.0) d = 0.0;
1353     if (a == 0.0) {
1354       lambdatemp = -initslope/(2.0*b);
1355     } else {
1356       lambdatemp = (-b + sqrt(d))/(3.0*a);
1357     }
1358     lambdaprev = lambda;
1359     gnormprev  = *gnorm;
1360     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
1361     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
1362     else                         lambda     = lambdatemp;
1363     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
1364     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1365     if (snes->nfuncs >= snes->max_funcs) {
1366       ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
1367       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);
1368       *flag = PETSC_FALSE;
1369       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1370       break;
1371     }
1372     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1373     if (snes->ops->solve == SNESSolveVI_RS) {
1374       ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1375     } else {
1376       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1377     }
1378     if (snes->domainerror) {
1379       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1380       PetscFunctionReturn(0);
1381     }
1382     if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1383     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* is reduction enough? */
1384       if (vi->lsmonitor) {
1385 	ierr = PetscPrintf(comm,"    Line search: Cubically determined step, current gnorm %G lambda=%18.16e\n",*gnorm,lambda);CHKERRQ(ierr);
1386       }
1387       break;
1388     } else {
1389       if (vi->lsmonitor) {
1390         ierr = PetscPrintf(comm,"    Line search: Cubic step no good, shrinking lambda, current gnorm %G lambda=%18.16e\n",*gnorm,lambda);CHKERRQ(ierr);
1391       }
1392     }
1393     count++;
1394   }
1395   theend1:
1396   /* Optional user-defined check for line search step validity */
1397   if (vi->postcheckstep && *flag) {
1398     ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1399     if (changed_y) {
1400       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1401       ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1402     }
1403     if (changed_y || changed_w) { /* recompute the function if the step has changed */
1404       ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1405       if (snes->ops->solve == SNESSolveVI_RS) {
1406         ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1407       } else {
1408         ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1409       }
1410       if (snes->domainerror) {
1411         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1412         PetscFunctionReturn(0);
1413       }
1414       if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1415       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
1416       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
1417     }
1418   }
1419   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1420   PetscFunctionReturn(0);
1421 }
1422 
1423 #undef __FUNCT__
1424 #define __FUNCT__ "SNESLineSearchQuadratic_VI"
1425 /*
1426   This routine does a quadratic line search while keeping the iterates within the variable bounds
1427 */
1428 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)
1429 {
1430   /*
1431      Note that for line search purposes we work with with the related
1432      minimization problem:
1433         min  z(x):  R^n -> R,
1434      where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
1435    */
1436   PetscReal      initslope,minlambda,lambda,lambdatemp,rellength;
1437 #if defined(PETSC_USE_COMPLEX)
1438   PetscScalar    cinitslope;
1439 #endif
1440   PetscErrorCode ierr;
1441   PetscInt       count;
1442   SNES_VI        *vi = (SNES_VI*)snes->data;
1443   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1444 
1445   PetscFunctionBegin;
1446   ierr    = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1447   *flag   = PETSC_TRUE;
1448 
1449   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
1450   if (*ynorm == 0.0) {
1451     if (vi->lsmonitor) {
1452       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"Line search: Direction and size is 0\n");CHKERRQ(ierr);
1453     }
1454     *gnorm = fnorm;
1455     ierr   = VecCopy(x,w);CHKERRQ(ierr);
1456     ierr   = VecCopy(f,g);CHKERRQ(ierr);
1457     *flag  = PETSC_FALSE;
1458     goto theend2;
1459   }
1460   if (*ynorm > vi->maxstep) {	/* Step too big, so scale back */
1461     ierr   = VecScale(y,vi->maxstep/(*ynorm));CHKERRQ(ierr);
1462     *ynorm = vi->maxstep;
1463   }
1464   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
1465   minlambda = vi->minlambda/rellength;
1466   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
1467 #if defined(PETSC_USE_COMPLEX)
1468   ierr      = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
1469   initslope = PetscRealPart(cinitslope);
1470 #else
1471   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
1472 #endif
1473   if (initslope > 0.0)  initslope = -initslope;
1474   if (initslope == 0.0) initslope = -1.0;
1475   ierr = PetscInfo1(snes,"Initslope %G \n",initslope);CHKERRQ(ierr);
1476 
1477   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1478   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1479   if (snes->nfuncs >= snes->max_funcs) {
1480     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
1481     *flag = PETSC_FALSE;
1482     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1483     goto theend2;
1484   }
1485   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1486   if (snes->ops->solve == SNESSolveVI_RS) {
1487     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1488   } else {
1489     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1490   }
1491   if (snes->domainerror) {
1492     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1493     PetscFunctionReturn(0);
1494   }
1495   if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1496   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + vi->alpha*initslope) { /* Sufficient reduction */
1497     if (vi->lsmonitor) {
1498       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1499     }
1500     goto theend2;
1501   }
1502 
1503   /* Fit points with quadratic */
1504   lambda = 1.0;
1505   count = 1;
1506   while (PETSC_TRUE) {
1507     if (lambda <= minlambda) { /* bad luck; use full step */
1508       if (vi->lsmonitor) {
1509         ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"Line search: Unable to find good step length! %D \n",count);CHKERRQ(ierr);
1510         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);
1511       }
1512       ierr = VecCopy(x,w);CHKERRQ(ierr);
1513       *flag = PETSC_FALSE;
1514       break;
1515     }
1516     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
1517     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
1518     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
1519     else                         lambda     = lambdatemp;
1520 
1521     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
1522     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1523     if (snes->nfuncs >= snes->max_funcs) {
1524       ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
1525       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);
1526       *flag = PETSC_FALSE;
1527       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1528       break;
1529     }
1530     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1531     if (snes->domainerror) {
1532       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1533       PetscFunctionReturn(0);
1534     }
1535     if (snes->ops->solve == SNESSolveVI_RS) {
1536       ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1537     } else {
1538       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1539     }
1540     if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1541     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* sufficient reduction */
1542       if (vi->lsmonitor) {
1543         ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line Search: Quadratically determined step, lambda=%G\n",lambda);CHKERRQ(ierr);
1544       }
1545       break;
1546     }
1547     count++;
1548   }
1549   theend2:
1550   /* Optional user-defined check for line search step validity */
1551   if (vi->postcheckstep) {
1552     ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1553     if (changed_y) {
1554       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1555       ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1556     }
1557     if (changed_y || changed_w) { /* recompute the function if the step has changed */
1558       ierr = SNESComputeFunction(snes,w,g);
1559       if (snes->domainerror) {
1560         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1561         PetscFunctionReturn(0);
1562       }
1563       if (snes->ops->solve == SNESSolveVI_RS) {
1564         ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1565       } else {
1566         ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
1567       }
1568 
1569       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
1570       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
1571       if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1572     }
1573   }
1574   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1575   PetscFunctionReturn(0);
1576 }
1577 
1578 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*/
1579 /* -------------------------------------------------------------------------- */
1580 EXTERN_C_BEGIN
1581 #undef __FUNCT__
1582 #define __FUNCT__ "SNESLineSearchSet_VI"
1583 PetscErrorCode  SNESLineSearchSet_VI(SNES snes,FCN2 func,void *lsctx)
1584 {
1585   PetscFunctionBegin;
1586   ((SNES_VI *)(snes->data))->LineSearch = func;
1587   ((SNES_VI *)(snes->data))->lsP        = lsctx;
1588   PetscFunctionReturn(0);
1589 }
1590 EXTERN_C_END
1591 
1592 /* -------------------------------------------------------------------------- */
1593 EXTERN_C_BEGIN
1594 #undef __FUNCT__
1595 #define __FUNCT__ "SNESLineSearchSetMonitor_VI"
1596 PetscErrorCode  SNESLineSearchSetMonitor_VI(SNES snes,PetscBool flg)
1597 {
1598   SNES_VI        *vi = (SNES_VI*)snes->data;
1599   PetscErrorCode ierr;
1600 
1601   PetscFunctionBegin;
1602   if (flg && !vi->lsmonitor) {
1603     ierr = PetscViewerASCIIMonitorCreate(((PetscObject)snes)->comm,"stdout",((PetscObject)snes)->tablevel,&vi->lsmonitor);CHKERRQ(ierr);
1604   } else if (!flg && vi->lsmonitor) {
1605     ierr = PetscViewerASCIIMonitorDestroy(vi->lsmonitor);CHKERRQ(ierr);
1606   }
1607   PetscFunctionReturn(0);
1608 }
1609 EXTERN_C_END
1610 
1611 /*
1612    SNESView_VI - Prints info from the SNESVI data structure.
1613 
1614    Input Parameters:
1615 .  SNES - the SNES context
1616 .  viewer - visualization context
1617 
1618    Application Interface Routine: SNESView()
1619 */
1620 #undef __FUNCT__
1621 #define __FUNCT__ "SNESView_VI"
1622 static PetscErrorCode SNESView_VI(SNES snes,PetscViewer viewer)
1623 {
1624   SNES_VI        *vi = (SNES_VI *)snes->data;
1625   const char     *cstr,*tstr;
1626   PetscErrorCode ierr;
1627   PetscBool     iascii;
1628 
1629   PetscFunctionBegin;
1630   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
1631   if (iascii) {
1632     if (vi->LineSearch == SNESLineSearchNo_VI)             cstr = "SNESLineSearchNo";
1633     else if (vi->LineSearch == SNESLineSearchQuadratic_VI) cstr = "SNESLineSearchQuadratic";
1634     else if (vi->LineSearch == SNESLineSearchCubic_VI)     cstr = "SNESLineSearchCubic";
1635     else                                                             cstr = "unknown";
1636     if (snes->ops->solve == SNESSolveVI_SS)      tstr = "Semismooth";
1637     else if (snes->ops->solve == SNESSolveVI_RS) tstr = "Reduced Space";
1638     else                                         tstr = "unknown";
1639     ierr = PetscViewerASCIIPrintf(viewer,"  VI algorithm: %s\n",tstr);CHKERRQ(ierr);
1640     ierr = PetscViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);CHKERRQ(ierr);
1641     ierr = PetscViewerASCIIPrintf(viewer,"  alpha=%G, maxstep=%G, minlambda=%G\n",vi->alpha,vi->maxstep,vi->minlambda);CHKERRQ(ierr);
1642   } else {
1643     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Viewer type %s not supported for SNES EQ VI",((PetscObject)viewer)->type_name);
1644   }
1645   PetscFunctionReturn(0);
1646 }
1647 
1648 #undef __FUNCT__
1649 #define __FUNCT__ "SNESVISetVariableBounds"
1650 /*@
1651    SNESVISetVariableBounds - Sets the lower and upper bounds for the solution vector. xl <= x <= xu.
1652 
1653    Input Parameters:
1654 .  snes - the SNES context.
1655 .  xl   - lower bound.
1656 .  xu   - upper bound.
1657 
1658    Notes:
1659    If this routine is not called then the lower and upper bounds are set to
1660    PETSC_VI_INF and PETSC_VI_NINF respectively during SNESSetUp().
1661 
1662 @*/
1663 PetscErrorCode SNESVISetVariableBounds(SNES snes, Vec xl, Vec xu)
1664 {
1665   SNES_VI  *vi = (SNES_VI*)snes->data;
1666 
1667   PetscFunctionBegin;
1668   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
1669   PetscValidHeaderSpecific(xl,VEC_CLASSID,2);
1670   PetscValidHeaderSpecific(xu,VEC_CLASSID,3);
1671   if (!snes->vec_func) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call SNESSetFunction() first");
1672   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);
1673   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);
1674 
1675   vi->usersetxbounds = PETSC_TRUE;
1676   vi->xl = xl;
1677   vi->xu = xu;
1678   PetscFunctionReturn(0);
1679 }
1680 
1681 /* -------------------------------------------------------------------------- */
1682 /*
1683    SNESSetFromOptions_VI - Sets various parameters for the SNESVI method.
1684 
1685    Input Parameter:
1686 .  snes - the SNES context
1687 
1688    Application Interface Routine: SNESSetFromOptions()
1689 */
1690 #undef __FUNCT__
1691 #define __FUNCT__ "SNESSetFromOptions_VI"
1692 static PetscErrorCode SNESSetFromOptions_VI(SNES snes)
1693 {
1694   SNES_VI        *vi = (SNES_VI *)snes->data;
1695   const char     *lses[] = {"basic","basicnonorms","quadratic","cubic"};
1696   const char     *vies[] = {"ss","rs"};
1697   PetscErrorCode ierr;
1698   PetscInt       indx;
1699   PetscBool      flg,set,flg2;
1700 
1701   PetscFunctionBegin;
1702   ierr = PetscOptionsHead("SNES semismooth method options");CHKERRQ(ierr);
1703   ierr = PetscOptionsBool("-snes_vi_monitor","Monitor all non-active variables","None",PETSC_FALSE,&flg,0);CHKERRQ(ierr);
1704   if (flg) {
1705     ierr = SNESMonitorSet(snes,SNESMonitorVI,0,0);CHKERRQ(ierr);
1706   }
1707   ierr = PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",vi->alpha,&vi->alpha,0);CHKERRQ(ierr);
1708   ierr = PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",vi->maxstep,&vi->maxstep,0);CHKERRQ(ierr);
1709   ierr = PetscOptionsReal("-snes_ls_minlambda","Minimum lambda allowed","None",vi->minlambda,&vi->minlambda,0);CHKERRQ(ierr);
1710   ierr = PetscOptionsReal("-snes_vi_const_tol","constraint tolerance","None",vi->const_tol,&vi->const_tol,0);CHKERRQ(ierr);
1711   ierr = PetscOptionsBool("-snes_ls_monitor","Print progress of line searches","SNESLineSearchSetMonitor",vi->lsmonitor ? PETSC_TRUE : PETSC_FALSE,&flg,&set);CHKERRQ(ierr);
1712   if (set) {ierr = SNESLineSearchSetMonitor(snes,flg);CHKERRQ(ierr);}
1713   ierr = PetscOptionsEList("-snes_vi_type","Semismooth algorithm used","",vies,2,"ss",&indx,&flg2);CHKERRQ(ierr);
1714   if (flg2) {
1715     switch (indx) {
1716     case 0:
1717       snes->ops->solve = SNESSolveVI_SS;
1718       break;
1719     case 1:
1720       snes->ops->solve = SNESSolveVI_RS;
1721       break;
1722     }
1723   }
1724   ierr = PetscOptionsEList("-snes_ls","Line search used","SNESLineSearchSet",lses,4,"basic",&indx,&flg);CHKERRQ(ierr);
1725   if (flg) {
1726     switch (indx) {
1727     case 0:
1728       ierr = SNESLineSearchSet(snes,SNESLineSearchNo_VI,PETSC_NULL);CHKERRQ(ierr);
1729       break;
1730     case 1:
1731       ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms_VI,PETSC_NULL);CHKERRQ(ierr);
1732       break;
1733     case 2:
1734       ierr = SNESLineSearchSet(snes,SNESLineSearchQuadratic_VI,PETSC_NULL);CHKERRQ(ierr);
1735       break;
1736     case 3:
1737       ierr = SNESLineSearchSet(snes,SNESLineSearchCubic_VI,PETSC_NULL);CHKERRQ(ierr);
1738       break;
1739     }
1740   }
1741   ierr = PetscOptionsTail();CHKERRQ(ierr);
1742   PetscFunctionReturn(0);
1743 }
1744 /* -------------------------------------------------------------------------- */
1745 /*MC
1746       SNESVI - Semismooth newton method based nonlinear solver that uses a line search
1747 
1748    Options Database:
1749 +   -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
1750 .   -snes_ls_alpha <alpha> - Sets alpha
1751 .   -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)
1752 .   -snes_ls_minlambda <minlambda>  - Sets the minimum lambda the line search will use  minlambda / max_i ( y[i]/x[i] )
1753 -   -snes_ls_monitor - print information about progress of line searches
1754 
1755 
1756    Level: beginner
1757 
1758 .seealso:  SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(),
1759            SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(),
1760            SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams()
1761 
1762 M*/
1763 EXTERN_C_BEGIN
1764 #undef __FUNCT__
1765 #define __FUNCT__ "SNESCreate_VI"
1766 PetscErrorCode  SNESCreate_VI(SNES snes)
1767 {
1768   PetscErrorCode ierr;
1769   SNES_VI      *vi;
1770 
1771   PetscFunctionBegin;
1772   snes->ops->setup	     = SNESSetUp_VI;
1773   snes->ops->solve	     = SNESSolveVI_SS;
1774   snes->ops->destroy	     = SNESDestroy_VI;
1775   snes->ops->setfromoptions  = SNESSetFromOptions_VI;
1776   snes->ops->view            = SNESView_VI;
1777   snes->ops->converged       = SNESDefaultConverged_VI;
1778 
1779   ierr                   = PetscNewLog(snes,SNES_VI,&vi);CHKERRQ(ierr);
1780   snes->data    	 = (void*)vi;
1781   vi->alpha		 = 1.e-4;
1782   vi->maxstep		 = 1.e8;
1783   vi->minlambda         = 1.e-12;
1784   vi->LineSearch        = SNESLineSearchNo_VI;
1785   vi->lsP               = PETSC_NULL;
1786   vi->postcheckstep     = PETSC_NULL;
1787   vi->postcheck         = PETSC_NULL;
1788   vi->precheckstep      = PETSC_NULL;
1789   vi->precheck          = PETSC_NULL;
1790   vi->const_tol         =  2.2204460492503131e-16;
1791 
1792   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","SNESLineSearchSetMonitor_VI",SNESLineSearchSetMonitor_VI);CHKERRQ(ierr);
1793   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","SNESLineSearchSet_VI",SNESLineSearchSet_VI);CHKERRQ(ierr);
1794 
1795   PetscFunctionReturn(0);
1796 }
1797 EXTERN_C_END
1798