xref: /petsc/src/snes/impls/vi/vi.c (revision 08da532b2310464c3bf489aef60f0ccd6d61141d)
1 
2 #include <../include/private/snesimpl.h> /*I "petscsnes.h" I*/
3 #include <../include/private/kspimpl.h>
4 #include <../include/private/matimpl.h>
5 #include <../include/private/dmimpl.h>
6 
7 #undef __FUNCT__
8 #define __FUNCT__ "SNESVISetComputeVariableBounds"
9 /*@C
10    SNESVISetComputeVariableBounds - Sets a function  that is called to compute the variable bounds
11 
12    Input parameter
13 +  snes - the SNES context
14 -  compute - computes the bounds
15 
16    Level: advanced
17 
18 @*/
19 PetscErrorCode SNESVISetComputeVariableBounds(SNES snes, PetscErrorCode (*compute)(SNES,Vec,Vec))
20 {
21   PetscErrorCode   ierr,(*f)(SNES,PetscErrorCode(*)(SNES,Vec,Vec));
22 
23   PetscFunctionBegin;
24   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
25   ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESVISetComputeVariableBounds_C",(PetscVoidStarFunction)&f);CHKERRQ(ierr);
26   if (!f) {ierr = SNESSetType(snes,SNESVIRS);CHKERRQ(ierr);}
27   ierr = PetscUseMethod(snes,"SNESVISetComputeVariableBounds_C",(SNES,PetscErrorCode(*)(SNES,Vec,Vec)),(snes,compute));CHKERRQ(ierr);
28   PetscFunctionReturn(0);
29 }
30 
31 EXTERN_C_BEGIN
32 #undef __FUNCT__
33 #define __FUNCT__ "SNESVISetComputeVariableBounds_VI"
34 PetscErrorCode SNESVISetComputeVariableBounds_VI(SNES snes,SNESVIComputeVariableBoundsFunction compute)
35 {
36   PetscFunctionBegin;
37   snes->ops->computevariablebounds = compute;
38   PetscFunctionReturn(0);
39 }
40 EXTERN_C_END
41 
42 #undef __FUNCT__
43 #define __FUNCT__ "SNESVIComputeInactiveSetIS"
44 /*
45    SNESVIComputeInactiveSetIS - Gets the global indices for the bogus inactive set variables
46 
47    Input parameter
48 .  snes - the SNES context
49 .  X    - the snes solution vector
50 
51    Output parameter
52 .  ISact - active set index set
53 
54  */
55 PetscErrorCode SNESVIComputeInactiveSetIS(Vec upper,Vec lower,Vec X,Vec F,IS* inact)
56 {
57   PetscErrorCode    ierr;
58   const PetscScalar *x,*xl,*xu,*f;
59   PetscInt          *idx_act,i,nlocal,nloc_isact=0,ilow,ihigh,i1=0;
60 
61   PetscFunctionBegin;
62   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
63   ierr = VecGetOwnershipRange(X,&ilow,&ihigh);CHKERRQ(ierr);
64   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
65   ierr = VecGetArrayRead(lower,&xl);CHKERRQ(ierr);
66   ierr = VecGetArrayRead(upper,&xu);CHKERRQ(ierr);
67   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
68   /* Compute inactive set size */
69   for (i=0; i < nlocal;i++) {
70     if (((PetscRealPart(x[i]) > PetscRealPart(xl[i]) + 1.e-8 || (PetscRealPart(f[i]) < 0.0)) && ((PetscRealPart(x[i]) < PetscRealPart(xu[i]) - 1.e-8) || PetscRealPart(f[i]) > 0.0))) nloc_isact++;
71   }
72 
73   ierr = PetscMalloc(nloc_isact*sizeof(PetscInt),&idx_act);CHKERRQ(ierr);
74 
75   /* Set inactive set indices */
76   for(i=0; i < nlocal; i++) {
77     if (((PetscRealPart(x[i]) > PetscRealPart(xl[i]) + 1.e-8 || (PetscRealPart(f[i]) < 0.0)) && ((PetscRealPart(x[i]) < PetscRealPart(xu[i]) - 1.e-8) || PetscRealPart(f[i]) > 0.0))) idx_act[i1++] = ilow+i;
78   }
79 
80    /* Create inactive set IS */
81   ierr = ISCreateGeneral(((PetscObject)upper)->comm,nloc_isact,idx_act,PETSC_OWN_POINTER,inact);CHKERRQ(ierr);
82 
83   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
84   ierr = VecRestoreArrayRead(lower,&xl);CHKERRQ(ierr);
85   ierr = VecRestoreArrayRead(upper,&xu);CHKERRQ(ierr);
86   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
87   PetscFunctionReturn(0);
88 }
89 
90 /* --------------------------------------------------------------------------------------------------------*/
91 
92 #undef __FUNCT__
93 #define __FUNCT__ "SNESMonitorVI"
94 PetscErrorCode  SNESMonitorVI(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
95 {
96   PetscErrorCode    ierr;
97   PetscViewer        viewer = dummy ? (PetscViewer) dummy : PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);
98   const PetscScalar  *x,*xl,*xu,*f;
99   PetscInt           i,n,act[2] = {0,0},fact[2],N;
100   /* Number of components that actually hit the bounds (c.f. active variables) */
101   PetscInt           act_bound[2] = {0,0},fact_bound[2];
102   PetscReal          rnorm,fnorm;
103 
104   PetscFunctionBegin;
105   ierr = VecGetLocalSize(snes->vec_sol,&n);CHKERRQ(ierr);
106   ierr = VecGetSize(snes->vec_sol,&N);CHKERRQ(ierr);
107   ierr = VecGetArrayRead(snes->xl,&xl);CHKERRQ(ierr);
108   ierr = VecGetArrayRead(snes->xu,&xu);CHKERRQ(ierr);
109   ierr = VecGetArrayRead(snes->vec_sol,&x);CHKERRQ(ierr);
110   ierr = VecGetArrayRead(snes->vec_func,&f);CHKERRQ(ierr);
111 
112   rnorm = 0.0;
113   for (i=0; i<n; i++) {
114     if (((PetscRealPart(x[i]) > PetscRealPart(xl[i]) + 1.e-8 || (PetscRealPart(f[i]) < 0.0)) && ((PetscRealPart(x[i]) < PetscRealPart(xu[i]) - 1.e-8) || PetscRealPart(f[i]) > 0.0))) rnorm += PetscRealPart(PetscConj(f[i])*f[i]);
115     else if (PetscRealPart(x[i]) <= PetscRealPart(xl[i]) + 1.e-8 && PetscRealPart(f[i]) >= 0.0) act[0]++;
116     else if (PetscRealPart(x[i]) >= PetscRealPart(xu[i]) - 1.e-8 && PetscRealPart(f[i]) <= 0.0) act[1]++;
117     else SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_PLIB,"Can never get here");
118   }
119 
120   for (i=0; i<n; i++) {
121     if (PetscRealPart(x[i]) <= PetscRealPart(xl[i]) + 1.e-8) act_bound[0]++;
122     else if (PetscRealPart(x[i]) >= PetscRealPart(xu[i]) - 1.e-8) act_bound[1]++;
123   }
124   ierr = VecRestoreArrayRead(snes->vec_func,&f);CHKERRQ(ierr);
125   ierr = VecRestoreArrayRead(snes->xl,&xl);CHKERRQ(ierr);
126   ierr = VecRestoreArrayRead(snes->xu,&xu);CHKERRQ(ierr);
127   ierr = VecRestoreArrayRead(snes->vec_sol,&x);CHKERRQ(ierr);
128   ierr = MPI_Allreduce(&rnorm,&fnorm,1,MPIU_REAL,MPIU_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
129   ierr = MPI_Allreduce(act,fact,2,MPIU_INT,MPIU_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
130   ierr = MPI_Allreduce(act_bound,fact_bound,2,MPIU_INT,MPIU_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
131   fnorm = PetscSqrtReal(fnorm);
132 
133   ierr = PetscViewerASCIIAddTab(viewer,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
134   ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES VI Function norm %14.12e Active lower constraints %D/%D upper constraints %D/%D Percent of total %g Percent of bounded %g\n",its,(double)fnorm,fact[0],fact_bound[0],fact[1],fact_bound[1],((double)(fact[0]+fact[1]))/((double)N),((double)(fact[0]+fact[1]))/((double)snes->ntruebounds));CHKERRQ(ierr);
135 
136   ierr = PetscViewerASCIISubtractTab(viewer,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
137   PetscFunctionReturn(0);
138 }
139 
140 /*
141      Checks if J^T F = 0 which implies we've found a local minimum of the norm of the function,
142     || 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
143     0 = (J^T F)^T W = F^T J W iff W not in the null space of J. Thanks for Jorge More
144     for this trick. One assumes that the probability that W is in the null space of J is very, very small.
145 */
146 #undef __FUNCT__
147 #define __FUNCT__ "SNESVICheckLocalMin_Private"
148 PetscErrorCode SNESVICheckLocalMin_Private(SNES snes,Mat A,Vec F,Vec W,PetscReal fnorm,PetscBool *ismin)
149 {
150   PetscReal      a1;
151   PetscErrorCode ierr;
152   PetscBool     hastranspose;
153 
154   PetscFunctionBegin;
155   *ismin = PETSC_FALSE;
156   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
157   if (hastranspose) {
158     /* Compute || J^T F|| */
159     ierr = MatMultTranspose(A,F,W);CHKERRQ(ierr);
160     ierr = VecNorm(W,NORM_2,&a1);CHKERRQ(ierr);
161     ierr = PetscInfo1(snes,"|| J^T F|| %g near zero implies found a local minimum\n",(double)(a1/fnorm));CHKERRQ(ierr);
162     if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE;
163   } else {
164     Vec         work;
165     PetscScalar result;
166     PetscReal   wnorm;
167 
168     ierr = VecSetRandom(W,PETSC_NULL);CHKERRQ(ierr);
169     ierr = VecNorm(W,NORM_2,&wnorm);CHKERRQ(ierr);
170     ierr = VecDuplicate(W,&work);CHKERRQ(ierr);
171     ierr = MatMult(A,W,work);CHKERRQ(ierr);
172     ierr = VecDot(F,work,&result);CHKERRQ(ierr);
173     ierr = VecDestroy(&work);CHKERRQ(ierr);
174     a1   = PetscAbsScalar(result)/(fnorm*wnorm);
175     ierr = PetscInfo1(snes,"(F^T J random)/(|| F ||*||random|| %g near zero implies found a local minimum\n",(double)a1);CHKERRQ(ierr);
176     if (a1 < 1.e-4) *ismin = PETSC_TRUE;
177   }
178   PetscFunctionReturn(0);
179 }
180 
181 /*
182      Checks if J^T(F - J*X) = 0
183 */
184 #undef __FUNCT__
185 #define __FUNCT__ "SNESVICheckResidual_Private"
186 PetscErrorCode SNESVICheckResidual_Private(SNES snes,Mat A,Vec F,Vec X,Vec W1,Vec W2)
187 {
188   PetscReal      a1,a2;
189   PetscErrorCode ierr;
190   PetscBool     hastranspose;
191 
192   PetscFunctionBegin;
193   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
194   if (hastranspose) {
195     ierr = MatMult(A,X,W1);CHKERRQ(ierr);
196     ierr = VecAXPY(W1,-1.0,F);CHKERRQ(ierr);
197 
198     /* Compute || J^T W|| */
199     ierr = MatMultTranspose(A,W1,W2);CHKERRQ(ierr);
200     ierr = VecNorm(W1,NORM_2,&a1);CHKERRQ(ierr);
201     ierr = VecNorm(W2,NORM_2,&a2);CHKERRQ(ierr);
202     if (a1 != 0.0) {
203       ierr = PetscInfo1(snes,"||J^T(F-Ax)||/||F-AX|| %g near zero implies inconsistent rhs\n",(double)(a2/a1));CHKERRQ(ierr);
204     }
205   }
206   PetscFunctionReturn(0);
207 }
208 
209 /*
210   SNESDefaultConverged_VI - Checks the convergence of the semismooth newton algorithm.
211 
212   Notes:
213   The convergence criterion currently implemented is
214   merit < abstol
215   merit < rtol*merit_initial
216 */
217 #undef __FUNCT__
218 #define __FUNCT__ "SNESDefaultConverged_VI"
219 PetscErrorCode SNESDefaultConverged_VI(SNES snes,PetscInt it,PetscReal xnorm,PetscReal gradnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
220 {
221   PetscErrorCode ierr;
222 
223   PetscFunctionBegin;
224   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
225   PetscValidPointer(reason,6);
226 
227   *reason = SNES_CONVERGED_ITERATING;
228 
229   if (!it) {
230     /* set parameter for default relative tolerance convergence test */
231     snes->ttol = fnorm*snes->rtol;
232   }
233   if (fnorm != fnorm) {
234     ierr = PetscInfo(snes,"Failed to converged, function norm is NaN\n");CHKERRQ(ierr);
235     *reason = SNES_DIVERGED_FNORM_NAN;
236   } else if (fnorm < snes->abstol) {
237     ierr = PetscInfo2(snes,"Converged due to function norm %g < %g\n",(double)fnorm,(double)snes->abstol);CHKERRQ(ierr);
238     *reason = SNES_CONVERGED_FNORM_ABS;
239   } else if (snes->nfuncs >= snes->max_funcs) {
240     ierr = PetscInfo2(snes,"Exceeded maximum number of function evaluations: %D > %D\n",snes->nfuncs,snes->max_funcs);CHKERRQ(ierr);
241     *reason = SNES_DIVERGED_FUNCTION_COUNT;
242   }
243 
244   if (it && !*reason) {
245     if (fnorm < snes->ttol) {
246       ierr = PetscInfo2(snes,"Converged due to function norm %g < %g (relative tolerance)\n",(double)fnorm,(double)snes->ttol);CHKERRQ(ierr);
247       *reason = SNES_CONVERGED_FNORM_RELATIVE;
248     }
249   }
250   PetscFunctionReturn(0);
251 }
252 
253 
254 /* -------------------------------------------------------------------------- */
255 /*
256    SNESVIProjectOntoBounds - Projects X onto the feasible region so that Xl[i] <= X[i] <= Xu[i] for i = 1...n.
257 
258    Input Parameters:
259 .  SNES - nonlinear solver context
260 
261    Output Parameters:
262 .  X - Bound projected X
263 
264 */
265 
266 #undef __FUNCT__
267 #define __FUNCT__ "SNESVIProjectOntoBounds"
268 PetscErrorCode SNESVIProjectOntoBounds(SNES snes,Vec X)
269 {
270   PetscErrorCode    ierr;
271   const PetscScalar *xl,*xu;
272   PetscScalar       *x;
273   PetscInt          i,n;
274 
275   PetscFunctionBegin;
276   ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr);
277   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
278   ierr = VecGetArrayRead(snes->xl,&xl);CHKERRQ(ierr);
279   ierr = VecGetArrayRead(snes->xu,&xu);CHKERRQ(ierr);
280 
281   for(i = 0;i<n;i++) {
282     if (PetscRealPart(x[i]) < PetscRealPart(xl[i])) x[i] = xl[i];
283     else if (PetscRealPart(x[i]) > PetscRealPart(xu[i])) x[i] = xu[i];
284   }
285   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
286   ierr = VecRestoreArrayRead(snes->xl,&xl);CHKERRQ(ierr);
287   ierr = VecRestoreArrayRead(snes->xu,&xu);CHKERRQ(ierr);
288   PetscFunctionReturn(0);
289 }
290 
291 
292 #undef __FUNCT__
293 #define __FUNCT__ "SNESVIGetActiveSetIS"
294 /*
295    SNESVIGetActiveSetIndices - Gets the global indices for the active set variables
296 
297    Input parameter
298 .  snes - the SNES context
299 .  X    - the snes solution vector
300 .  F    - the nonlinear function vector
301 
302    Output parameter
303 .  ISact - active set index set
304  */
305 PetscErrorCode SNESVIGetActiveSetIS(SNES snes,Vec X,Vec F,IS* ISact)
306 {
307   PetscErrorCode   ierr;
308   Vec               Xl=snes->xl,Xu=snes->xu;
309   const PetscScalar *x,*f,*xl,*xu;
310   PetscInt          *idx_act,i,nlocal,nloc_isact=0,ilow,ihigh,i1=0;
311 
312   PetscFunctionBegin;
313   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
314   ierr = VecGetOwnershipRange(X,&ilow,&ihigh);CHKERRQ(ierr);
315   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
316   ierr = VecGetArrayRead(Xl,&xl);CHKERRQ(ierr);
317   ierr = VecGetArrayRead(Xu,&xu);CHKERRQ(ierr);
318   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
319   /* Compute active set size */
320   for (i=0; i < nlocal;i++) {
321     if (!((PetscRealPart(x[i]) > PetscRealPart(xl[i]) + 1.e-8 || (PetscRealPart(f[i]) < 0.0)) && ((PetscRealPart(x[i]) < PetscRealPart(xu[i]) - 1.e-8) || PetscRealPart(f[i]) > 0.0))) nloc_isact++;
322   }
323 
324   ierr = PetscMalloc(nloc_isact*sizeof(PetscInt),&idx_act);CHKERRQ(ierr);
325 
326   /* Set active set indices */
327   for(i=0; i < nlocal; i++) {
328     if (!((PetscRealPart(x[i]) > PetscRealPart(xl[i]) + 1.e-8 || (PetscRealPart(f[i]) < 0.0)) && ((PetscRealPart(x[i]) < PetscRealPart(xu[i]) - 1.e-8) || PetscRealPart(f[i]) > 0.0))) idx_act[i1++] = ilow+i;
329   }
330 
331    /* Create active set IS */
332   ierr = ISCreateGeneral(((PetscObject)snes)->comm,nloc_isact,idx_act,PETSC_OWN_POINTER,ISact);CHKERRQ(ierr);
333 
334   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
335   ierr = VecRestoreArrayRead(Xl,&xl);CHKERRQ(ierr);
336   ierr = VecRestoreArrayRead(Xu,&xu);CHKERRQ(ierr);
337   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
338   PetscFunctionReturn(0);
339 }
340 
341 #undef __FUNCT__
342 #define __FUNCT__ "SNESVICreateIndexSets_RS"
343 PetscErrorCode SNESVICreateIndexSets_RS(SNES snes,Vec X,Vec F,IS* ISact,IS* ISinact)
344 {
345   PetscErrorCode     ierr;
346 
347   PetscFunctionBegin;
348   ierr = SNESVIGetActiveSetIS(snes,X,F,ISact);CHKERRQ(ierr);
349   ierr = ISComplement(*ISact,X->map->rstart,X->map->rend,ISinact);CHKERRQ(ierr);
350   PetscFunctionReturn(0);
351 }
352 
353 #undef __FUNCT__
354 #define __FUNCT__ "SNESVIComputeInactiveSetFnorm"
355 PetscErrorCode SNESVIComputeInactiveSetFnorm(SNES snes,Vec F,Vec X,PetscReal *fnorm)
356 {
357   PetscErrorCode    ierr;
358   const PetscScalar *x,*xl,*xu,*f;
359   PetscInt          i,n;
360   PetscReal         rnorm;
361 
362   PetscFunctionBegin;
363   ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr);
364   ierr = VecGetArrayRead(snes->xl,&xl);CHKERRQ(ierr);
365   ierr = VecGetArrayRead(snes->xu,&xu);CHKERRQ(ierr);
366   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
367   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
368   rnorm = 0.0;
369   for (i=0; i<n; i++) {
370     if (((PetscRealPart(x[i]) > PetscRealPart(xl[i]) + 1.e-8 || (PetscRealPart(f[i]) < 0.0)) && ((PetscRealPart(x[i]) < PetscRealPart(xu[i]) - 1.e-8) || PetscRealPart(f[i]) > 0.0))) rnorm += PetscRealPart(PetscConj(f[i])*f[i]);
371   }
372   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
373   ierr = VecRestoreArrayRead(snes->xl,&xl);CHKERRQ(ierr);
374   ierr = VecRestoreArrayRead(snes->xu,&xu);CHKERRQ(ierr);
375   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
376   ierr = MPI_Allreduce(&rnorm,fnorm,1,MPIU_REAL,MPIU_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
377   *fnorm = PetscSqrtReal(*fnorm);
378   PetscFunctionReturn(0);
379 }
380 
381 #undef __FUNCT__
382 #define __FUNCT__ "SNESVIDMComputeVariableBounds"
383 PetscErrorCode SNESVIDMComputeVariableBounds(SNES snes,Vec xl, Vec xu)
384 {
385   PetscErrorCode     ierr;
386   PetscFunctionBegin;
387   ierr = DMComputeVariableBounds(snes->dm, xl, xu); CHKERRQ(ierr);
388   PetscFunctionReturn(0);
389 }
390 
391 
392 /* -------------------------------------------------------------------------- */
393 /*
394    SNESSetUp_VI - Does setup common to all VI solvers -- basically makes sure bounds have been properly set up
395    of the SNESVI nonlinear solver.
396 
397    Input Parameter:
398 .  snes - the SNES context
399 .  x - the solution vector
400 
401    Application Interface Routine: SNESSetUp()
402 
403    Notes:
404    For basic use of the SNES solvers, the user need not explicitly call
405    SNESSetUp(), since these actions will automatically occur during
406    the call to SNESSolve().
407  */
408 #undef __FUNCT__
409 #define __FUNCT__ "SNESSetUp_VI"
410 PetscErrorCode SNESSetUp_VI(SNES snes)
411 {
412   PetscErrorCode ierr;
413   PetscInt       i_start[3],i_end[3];
414 
415   PetscFunctionBegin;
416 
417   ierr = SNESDefaultGetWork(snes,3);CHKERRQ(ierr);
418 
419   if(!snes->ops->computevariablebounds && snes->dm) {
420     snes->ops->computevariablebounds = SNESVIDMComputeVariableBounds;
421   }
422   if (snes->ops->computevariablebounds) {
423     if (!snes->xl) {ierr = VecDuplicate(snes->vec_sol,&snes->xl);CHKERRQ(ierr);}
424     if (!snes->xu) {ierr = VecDuplicate(snes->vec_sol,&snes->xu);CHKERRQ(ierr);}
425     ierr = (*snes->ops->computevariablebounds)(snes,snes->xl,snes->xu);CHKERRQ(ierr);
426   } else if (!snes->xl && !snes->xu) {
427     /* If the lower and upper bound on variables are not set, set it to -Inf and Inf */
428     ierr = VecDuplicate(snes->vec_sol, &snes->xl);CHKERRQ(ierr);
429     ierr = VecSet(snes->xl,SNES_VI_NINF);CHKERRQ(ierr);
430     ierr = VecDuplicate(snes->vec_sol, &snes->xu);CHKERRQ(ierr);
431     ierr = VecSet(snes->xu,SNES_VI_INF);CHKERRQ(ierr);
432   } else {
433     /* Check if lower bound, upper bound and solution vector distribution across the processors is identical */
434     ierr = VecGetOwnershipRange(snes->vec_sol,i_start,i_end);CHKERRQ(ierr);
435     ierr = VecGetOwnershipRange(snes->xl,i_start+1,i_end+1);CHKERRQ(ierr);
436     ierr = VecGetOwnershipRange(snes->xu,i_start+2,i_end+2);CHKERRQ(ierr);
437     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]))
438       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.");
439   }
440 
441   PetscFunctionReturn(0);
442 }
443 /* -------------------------------------------------------------------------- */
444 #undef __FUNCT__
445 #define __FUNCT__ "SNESReset_VI"
446 PetscErrorCode SNESReset_VI(SNES snes)
447 {
448   PetscErrorCode ierr;
449 
450   PetscFunctionBegin;
451   ierr = VecDestroy(&snes->xl);CHKERRQ(ierr);
452   ierr = VecDestroy(&snes->xu);CHKERRQ(ierr);
453   PetscFunctionReturn(0);
454 }
455 
456 /*
457    SNESDestroy_VI - Destroys the private SNES_VI context that was created
458    with SNESCreate_VI().
459 
460    Input Parameter:
461 .  snes - the SNES context
462 
463    Application Interface Routine: SNESDestroy()
464  */
465 #undef __FUNCT__
466 #define __FUNCT__ "SNESDestroy_VI"
467 PetscErrorCode SNESDestroy_VI(SNES snes)
468 {
469   PetscErrorCode ierr;
470 
471   PetscFunctionBegin;
472   ierr = PetscFree(snes->data);CHKERRQ(ierr);
473 
474   /* clear composed functions */
475   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","",PETSC_NULL);CHKERRQ(ierr);
476   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","",PETSC_NULL);CHKERRQ(ierr);
477   PetscFunctionReturn(0);
478 }
479 
480 /* -------------------------------------------------------------------------- */
481 
482 /*
483 
484       These line searches are common for all the VI solvers
485 */
486 extern PetscErrorCode SNESSolve_VISS(SNES);
487 
488 #undef __FUNCT__
489 #define __FUNCT__ "SNESLineSearchNo_VI"
490 
491 /*
492   This routine does not actually do a line search but it takes a full newton
493   step while ensuring that the new iterates remain within the constraints.
494 
495 */
496 PetscErrorCode SNESLineSearchNo_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec y,PetscReal fnorm,PetscReal xnorm,Vec g,Vec w,PetscReal *ynorm,PetscReal *gnorm,PetscBool *flag)
497 {
498   PetscErrorCode ierr;
499   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
500 
501   PetscFunctionBegin;
502   *flag = PETSC_TRUE;
503   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
504   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);         /* ynorm = || y || */
505   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
506   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
507   if (snes->ops->postcheckstep) {
508    ierr = (*snes->ops->postcheckstep)(snes,x,y,w,snes->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
509   }
510   if (changed_y) {
511     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
512     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
513   }
514   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
515   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
516   if (!snes->domainerror) {
517     if (snes->ops->solve != SNESSolve_VISS) {
518        ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
519     } else {
520       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);  /* gnorm = || g || */
521     }
522     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
523   }
524   if (snes->ls_monitor) {
525     ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
526     ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: Using full step: fnorm %g gnorm %g\n",(double)fnorm,(double)*gnorm);CHKERRQ(ierr);
527     ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
528   }
529   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
530   PetscFunctionReturn(0);
531 }
532 
533 /* -------------------------------------------------------------------------- */
534 #undef __FUNCT__
535 #define __FUNCT__ "SNESLineSearchNoNorms_VI"
536 
537 /*
538   This routine is a copy of SNESLineSearchNoNorms in snes/impls/ls/ls.c
539 */
540 PetscErrorCode SNESLineSearchNoNorms_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec y,PetscReal fnorm,PetscReal xnorm,Vec g,Vec w,PetscReal *ynorm,PetscReal *gnorm,PetscBool *flag)
541 {
542   PetscErrorCode ierr;
543   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
544 
545   PetscFunctionBegin;
546   *flag = PETSC_TRUE;
547   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
548   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y      */
549   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
550   if (snes->ops->postcheckstep) {
551    ierr = (*snes->ops->postcheckstep)(snes,x,y,w,snes->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
552   }
553   if (changed_y) {
554     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
555     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
556   }
557 
558   /* don't evaluate function the last time through */
559   if (snes->iter < snes->max_its-1) {
560     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
561   }
562   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
563   PetscFunctionReturn(0);
564 }
565 
566 /* -------------------------------------------------------------------------- */
567 
568 #undef __FUNCT__
569 #define __FUNCT__ "SNESLineSearchCubic_VI"
570 /*
571   This routine implements a cubic line search while doing a projection on the variable bounds
572 */
573 PetscErrorCode SNESLineSearchCubic_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec y,PetscReal fnorm,PetscReal xnorm,Vec g,Vec w,PetscReal *ynorm,PetscReal *gnorm,PetscBool *flag)
574 {
575   PetscReal      initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
576   PetscReal      minlambda,lambda,lambdatemp;
577 #if defined(PETSC_USE_COMPLEX)
578   PetscScalar    cinitslope;
579 #endif
580   PetscErrorCode ierr;
581   PetscInt       count;
582   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
583   MPI_Comm       comm;
584 
585   PetscFunctionBegin;
586   ierr = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
587   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
588   *flag   = PETSC_TRUE;
589 
590   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
591   if (*ynorm == 0.0) {
592     if (snes->ls_monitor) {
593       ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
594       ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: Initial direction and size is 0\n");CHKERRQ(ierr);
595       ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
596     }
597     *gnorm = fnorm;
598     ierr   = VecCopy(x,w);CHKERRQ(ierr);
599     ierr   = VecCopy(f,g);CHKERRQ(ierr);
600     *flag  = PETSC_FALSE;
601     goto theend1;
602   }
603   if (*ynorm > snes->maxstep) {	/* Step too big, so scale back */
604     if (snes->ls_monitor) {
605       ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
606       ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: Scaling step by %g old ynorm %g\n",(double)(snes->maxstep/(*ynorm)),(double)(*ynorm));CHKERRQ(ierr);
607       ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
608     }
609     ierr = VecScale(y,snes->maxstep/(*ynorm));CHKERRQ(ierr);
610     *ynorm = snes->maxstep;
611   }
612   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
613   minlambda = snes->steptol/rellength;
614   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
615 #if defined(PETSC_USE_COMPLEX)
616   ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
617   initslope = PetscRealPart(cinitslope);
618 #else
619   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
620 #endif
621   if (initslope > 0.0)  initslope = -initslope;
622   if (initslope == 0.0) initslope = -1.0;
623 
624   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
625   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
626   if (snes->nfuncs >= snes->max_funcs) {
627     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
628     *flag = PETSC_FALSE;
629     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
630     goto theend1;
631   }
632   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
633   if (snes->ops->solve != SNESSolve_VISS) {
634     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
635   } else {
636     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
637   }
638   if (snes->domainerror) {
639     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
640     PetscFunctionReturn(0);
641   }
642   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
643   ierr = PetscInfo4(snes,"Initial fnorm %g gnorm %g alpha %g initslope %g\n",(double)fnorm,(double)*gnorm,(double)snes->ls_alpha,(double)initslope);CHKERRQ(ierr);
644   if ((*gnorm)*(*gnorm) <= (1.0 - snes->ls_alpha)*fnorm*fnorm ) { /* Sufficient reduction */
645     if (snes->ls_monitor) {
646       ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
647       ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: Using full step: fnorm %g gnorm %g\n",(double)fnorm,(double)(*gnorm));CHKERRQ(ierr);
648       ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
649     }
650     goto theend1;
651   }
652 
653   /* Fit points with quadratic */
654   lambda     = 1.0;
655   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
656   lambdaprev = lambda;
657   gnormprev  = *gnorm;
658   if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
659   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
660   else                         lambda = lambdatemp;
661 
662   ierr  = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
663   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
664   if (snes->nfuncs >= snes->max_funcs) {
665     ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);CHKERRQ(ierr);
666     *flag = PETSC_FALSE;
667     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
668     goto theend1;
669   }
670   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
671   if (snes->ops->solve != SNESSolve_VISS) {
672     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
673   } else {
674     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
675   }
676   if (snes->domainerror) {
677     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
678     PetscFunctionReturn(0);
679   }
680   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
681   if (snes->ls_monitor) {
682     ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
683     ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: gnorm after quadratic fit %g\n",(double)(*gnorm));CHKERRQ(ierr);
684     ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
685   }
686   if ((*gnorm)*(*gnorm) < (1.0 - snes->ls_alpha)*fnorm*fnorm ) { /* sufficient reduction */
687     if (snes->ls_monitor) {
688       ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
689       ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: Quadratically determined step, lambda=%18.16e\n",(double)lambda);CHKERRQ(ierr);
690       ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
691     }
692     goto theend1;
693   }
694 
695   /* Fit points with cubic */
696   count = 1;
697   while (PETSC_TRUE) {
698     if (lambda <= minlambda) {
699       if (snes->ls_monitor) {
700         ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
701  	ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: unable to find good step length! After %D tries \n",count);CHKERRQ(ierr);
702 	ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",(double)fnorm,(double)(*gnorm),(double)(*ynorm),(double)minlambda,(double)lambda,(double)initslope);CHKERRQ(ierr);
703         ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
704       }
705       *flag = PETSC_FALSE;
706       break;
707     }
708     t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
709     t2 = .5*(gnormprev*gnormprev  - fnorm*fnorm) - lambdaprev*initslope;
710     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
711     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
712     d  = b*b - 3*a*initslope;
713     if (d < 0.0) d = 0.0;
714     if (a == 0.0) {
715       lambdatemp = -initslope/(2.0*b);
716     } else {
717       lambdatemp = (-b + PetscSqrtReal(d))/(3.0*a);
718     }
719     lambdaprev = lambda;
720     gnormprev  = *gnorm;
721     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
722     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
723     else                         lambda     = lambdatemp;
724     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
725     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
726     if (snes->nfuncs >= snes->max_funcs) {
727       ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
728       ierr = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",(double)fnorm,(double)(*gnorm),(double)(*ynorm),(double)lambda,(double)initslope);CHKERRQ(ierr);
729       *flag = PETSC_FALSE;
730       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
731       break;
732     }
733     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
734     if (snes->ops->solve != SNESSolve_VISS) {
735       ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
736     } else {
737       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
738     }
739     if (snes->domainerror) {
740       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
741       PetscFunctionReturn(0);
742     }
743     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
744     if ((*gnorm)*(*gnorm) < (1.0 - snes->ls_alpha)*fnorm*fnorm) { /* is reduction enough? */
745       if (snes->ls_monitor) {
746 	ierr = PetscPrintf(comm,"    Line search: Cubically determined step, current gnorm %g lambda=%18.16e\n",(double)(*gnorm),(double)lambda);CHKERRQ(ierr);
747       }
748       break;
749     } else {
750       if (snes->ls_monitor) {
751         ierr = PetscPrintf(comm,"    Line search: Cubic step no good, shrinking lambda, current gnorm %g lambda=%18.16e\n",(double)(*gnorm),(double)lambda);CHKERRQ(ierr);
752       }
753     }
754     count++;
755   }
756   theend1:
757   /* Optional user-defined check for line search step validity */
758   if (snes->ops->postcheckstep && *flag) {
759     ierr = (*snes->ops->postcheckstep)(snes,x,y,w,snes->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
760     if (changed_y) {
761       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
762       ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
763     }
764     if (changed_y || changed_w) { /* recompute the function if the step has changed */
765       ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
766       if (snes->ops->solve != SNESSolve_VISS) {
767         ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
768       } else {
769         ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
770       }
771       if (snes->domainerror) {
772         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
773         PetscFunctionReturn(0);
774       }
775       if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
776       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
777       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
778     }
779   }
780   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
781   PetscFunctionReturn(0);
782 }
783 
784 #undef __FUNCT__
785 #define __FUNCT__ "SNESLineSearchQuadratic_VI"
786 /*
787   This routine does a quadratic line search while keeping the iterates within the variable bounds
788 */
789 PetscErrorCode SNESLineSearchQuadratic_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec y,PetscReal fnorm,PetscReal xnorm,Vec g,Vec w,PetscReal *ynorm,PetscReal *gnorm,PetscBool *flag)
790 {
791   /*
792      Note that for line search purposes we work with with the related
793      minimization problem:
794         min  z(x):  R^n -> R,
795      where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
796    */
797   PetscReal      initslope,minlambda,lambda,lambdatemp,rellength;
798 #if defined(PETSC_USE_COMPLEX)
799   PetscScalar    cinitslope;
800 #endif
801   PetscErrorCode ierr;
802   PetscInt       count;
803   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
804 
805   PetscFunctionBegin;
806   ierr    = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
807   *flag   = PETSC_TRUE;
808 
809   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
810   if (*ynorm == 0.0) {
811     if (snes->ls_monitor) {
812       ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
813       ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"Line search: Direction and size is 0\n");CHKERRQ(ierr);
814       ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
815     }
816     *gnorm = fnorm;
817     ierr   = VecCopy(x,w);CHKERRQ(ierr);
818     ierr   = VecCopy(f,g);CHKERRQ(ierr);
819     *flag  = PETSC_FALSE;
820     goto theend2;
821   }
822   if (*ynorm > snes->maxstep) {	/* Step too big, so scale back */
823     ierr   = VecScale(y,snes->maxstep/(*ynorm));CHKERRQ(ierr);
824     *ynorm = snes->maxstep;
825   }
826   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
827   minlambda = snes->steptol/rellength;
828   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
829 #if defined(PETSC_USE_COMPLEX)
830   ierr      = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
831   initslope = PetscRealPart(cinitslope);
832 #else
833   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
834 #endif
835   if (initslope > 0.0)  initslope = -initslope;
836   if (initslope == 0.0) initslope = -1.0;
837   ierr = PetscInfo1(snes,"Initslope %g \n",(double)initslope);CHKERRQ(ierr);
838 
839   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
840   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
841   if (snes->nfuncs >= snes->max_funcs) {
842     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
843     *flag = PETSC_FALSE;
844     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
845     goto theend2;
846   }
847   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
848   if (snes->ops->solve != SNESSolve_VISS) {
849     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
850   } else {
851     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
852   }
853   if (snes->domainerror) {
854     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
855     PetscFunctionReturn(0);
856   }
857   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
858   if ((*gnorm)*(*gnorm) <= (1.0 - snes->ls_alpha)*fnorm*fnorm) { /* Sufficient reduction */
859     if (snes->ls_monitor) {
860       ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
861       ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: Using full step: fnorm %g gnorm %g\n",(double)fnorm,(double)(*gnorm));CHKERRQ(ierr);
862       ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
863     }
864     goto theend2;
865   }
866 
867   /* Fit points with quadratic */
868   lambda = 1.0;
869   count = 1;
870   while (PETSC_TRUE) {
871     if (lambda <= minlambda) { /* bad luck; use full step */
872       if (snes->ls_monitor) {
873         ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
874         ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"Line search: Unable to find good step length! %D \n",count);CHKERRQ(ierr);
875         ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"Line search: fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",(double)fnorm,(double)(*gnorm),(double)(*ynorm),(double)lambda,(double)initslope);CHKERRQ(ierr);
876         ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
877       }
878       ierr = VecCopy(x,w);CHKERRQ(ierr);
879       *flag = PETSC_FALSE;
880       break;
881     }
882     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
883     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
884     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
885     else                         lambda     = lambdatemp;
886 
887     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
888     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
889     if (snes->nfuncs >= snes->max_funcs) {
890       ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
891       ierr  = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",(double)fnorm,(double)(*gnorm),(double)(*ynorm),(double)lambda,(double)initslope);CHKERRQ(ierr);
892       *flag = PETSC_FALSE;
893       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
894       break;
895     }
896     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
897     if (snes->domainerror) {
898       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
899       PetscFunctionReturn(0);
900     }
901     if (snes->ops->solve != SNESSolve_VISS) {
902       ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
903     } else {
904       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
905     }
906     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
907     if ((*gnorm)*(*gnorm) < (1.0 - snes->ls_alpha)*fnorm*fnorm) { /* sufficient reduction */
908       if (snes->ls_monitor) {
909         ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
910         ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line Search: Quadratically determined step, lambda=%g\n",(double)lambda);CHKERRQ(ierr);
911         ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
912       }
913       break;
914     }
915     count++;
916   }
917   theend2:
918   /* Optional user-defined check for line search step validity */
919   if (snes->ops->postcheckstep) {
920     ierr = (*snes->ops->postcheckstep)(snes,x,y,w,snes->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
921     if (changed_y) {
922       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
923       ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
924     }
925     if (changed_y || changed_w) { /* recompute the function if the step has changed */
926       ierr = SNESComputeFunction(snes,w,g);
927       if (snes->domainerror) {
928         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
929         PetscFunctionReturn(0);
930       }
931       if (snes->ops->solve != SNESSolve_VISS) {
932         ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
933       } else {
934         ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
935       }
936 
937       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
938       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
939       if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
940     }
941   }
942   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
943   PetscFunctionReturn(0);
944 }
945 
946 
947 #undef __FUNCT__
948 #define __FUNCT__ "SNESVISetVariableBounds"
949 /*@
950    SNESVISetVariableBounds - Sets the lower and upper bounds for the solution vector. xl <= x <= xu.
951 
952    Input Parameters:
953 .  snes - the SNES context.
954 .  xl   - lower bound.
955 .  xu   - upper bound.
956 
957    Notes:
958    If this routine is not called then the lower and upper bounds are set to
959    SNES_VI_INF and SNES_VI_NINF respectively during SNESSetUp().
960 
961    Level: advanced
962 
963 @*/
964 PetscErrorCode SNESVISetVariableBounds(SNES snes, Vec xl, Vec xu)
965 {
966   PetscErrorCode   ierr,(*f)(SNES,Vec,Vec);
967 
968   PetscFunctionBegin;
969   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
970   PetscValidHeaderSpecific(xl,VEC_CLASSID,2);
971   PetscValidHeaderSpecific(xu,VEC_CLASSID,3);
972   ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESVISetVariableBounds_C",(PetscVoidStarFunction)&f);CHKERRQ(ierr);
973   if (!f) {ierr = SNESSetType(snes,SNESVIRS);CHKERRQ(ierr);}
974   ierr = PetscUseMethod(snes,"SNESVISetVariableBounds_C",(SNES,Vec,Vec),(snes,xl,xu));CHKERRQ(ierr);
975   PetscFunctionReturn(0);
976 }
977 
978 EXTERN_C_BEGIN
979 #undef __FUNCT__
980 #define __FUNCT__ "SNESVISetVariableBounds_VI"
981 PetscErrorCode SNESVISetVariableBounds_VI(SNES snes,Vec xl,Vec xu)
982 {
983   PetscErrorCode    ierr;
984   const PetscScalar *xxl,*xxu;
985   PetscInt          i,n, cnt = 0;
986 
987   PetscFunctionBegin;
988   ierr = SNESGetFunction(snes,&snes->vec_func,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
989   if (!snes->vec_func) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call SNESSetFunction() or SNESSetDM() first");
990   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);
991   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);
992   ierr = SNESSetType(snes,SNESVIRS);CHKERRQ(ierr);
993   ierr = PetscObjectReference((PetscObject)xl);CHKERRQ(ierr);
994   ierr = PetscObjectReference((PetscObject)xu);CHKERRQ(ierr);
995   ierr = VecDestroy(&snes->xl);CHKERRQ(ierr);
996   ierr = VecDestroy(&snes->xu);CHKERRQ(ierr);
997   snes->xl = xl;
998   snes->xu = xu;
999   ierr = VecGetLocalSize(xl,&n);CHKERRQ(ierr);
1000   ierr = VecGetArrayRead(xl,&xxl);CHKERRQ(ierr);
1001   ierr = VecGetArrayRead(xu,&xxu);CHKERRQ(ierr);
1002   for (i=0; i<n; i++) {
1003     cnt += ((xxl[i] != SNES_VI_NINF) || (xxu[i] != SNES_VI_INF));
1004   }
1005   ierr = MPI_Allreduce(&cnt,&snes->ntruebounds,1,MPIU_INT,MPI_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
1006   ierr = VecRestoreArrayRead(xl,&xxl);CHKERRQ(ierr);
1007   ierr = VecRestoreArrayRead(xu,&xxu);CHKERRQ(ierr);
1008   PetscFunctionReturn(0);
1009 }
1010 EXTERN_C_END
1011 
1012 EXTERN_C_BEGIN
1013 #undef __FUNCT__
1014 #define __FUNCT__ "SNESLineSearchSetType_VI"
1015 PetscErrorCode  SNESLineSearchSetType_VI(SNES snes, SNESLineSearchType type)
1016 {
1017   PetscErrorCode ierr;
1018   PetscFunctionBegin;
1019 
1020   switch (type) {
1021   case SNES_LS_BASIC:
1022     ierr = SNESLineSearchSet(snes,SNESLineSearchNo_VI,PETSC_NULL);CHKERRQ(ierr);
1023     break;
1024   case SNES_LS_BASIC_NONORMS:
1025     ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms_VI,PETSC_NULL);CHKERRQ(ierr);
1026     break;
1027   case SNES_LS_QUADRATIC:
1028     ierr = SNESLineSearchSet(snes,SNESLineSearchQuadratic_VI,PETSC_NULL);CHKERRQ(ierr);
1029     break;
1030   case SNES_LS_CUBIC:
1031     ierr = SNESLineSearchSet(snes,SNESLineSearchCubic_VI,PETSC_NULL);CHKERRQ(ierr);
1032     break;
1033   default:
1034     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP,"Unknown line search type");
1035     break;
1036   }
1037   snes->ls_type = type;
1038   PetscFunctionReturn(0);
1039 }
1040 EXTERN_C_END
1041 
1042 #undef __FUNCT__
1043 #define __FUNCT__ "SNESSetFromOptions_VI"
1044 PetscErrorCode SNESSetFromOptions_VI(SNES snes)
1045 {
1046   PetscErrorCode  ierr;
1047   PetscBool       flg;
1048 
1049   PetscFunctionBegin;
1050   ierr = PetscOptionsHead("SNES VI options");CHKERRQ(ierr);
1051   ierr = PetscOptionsBool("-snes_vi_monitor","Monitor all non-active variables","None",PETSC_FALSE,&flg,0);CHKERRQ(ierr);
1052   if (flg) {
1053     ierr = SNESMonitorSet(snes,SNESMonitorVI,0,0);CHKERRQ(ierr);
1054   }
1055   ierr = PetscOptionsTail();CHKERRQ(ierr);
1056   PetscFunctionReturn(0);
1057 }
1058