xref: /petsc/src/snes/impls/vi/vi.c (revision 84df9cb40eca90ea9b18a456fab7a4ecc7f6c1a4)
1 
2 #include <../src/snes/impls/vi/viimpl.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;
22   SNES_VI          *vi;
23 
24   PetscFunctionBegin;
25   ierr = SNESSetType(snes,SNESVI);CHKERRQ(ierr);
26   vi = (SNES_VI*)snes->data;
27   vi->computevariablebounds = compute;
28   PetscFunctionReturn(0);
29 }
30 
31 
32 #undef __FUNCT__
33 #define __FUNCT__ "SNESVIComputeInactiveSetIS"
34 /*
35    SNESVIComputeInactiveSetIS - Gets the global indices for the bogus inactive set variables
36 
37    Input parameter
38 .  snes - the SNES context
39 .  X    - the snes solution vector
40 
41    Output parameter
42 .  ISact - active set index set
43 
44  */
45 PetscErrorCode SNESVIComputeInactiveSetIS(Vec upper,Vec lower,Vec X,Vec F,IS* inact)
46 {
47   PetscErrorCode   ierr;
48   const PetscScalar *x,*xl,*xu,*f;
49   PetscInt          *idx_act,i,nlocal,nloc_isact=0,ilow,ihigh,i1=0;
50 
51   PetscFunctionBegin;
52   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
53   ierr = VecGetOwnershipRange(X,&ilow,&ihigh);CHKERRQ(ierr);
54   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
55   ierr = VecGetArrayRead(lower,&xl);CHKERRQ(ierr);
56   ierr = VecGetArrayRead(upper,&xu);CHKERRQ(ierr);
57   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
58   /* Compute inactive set size */
59   for (i=0; i < nlocal;i++) {
60     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++;
61   }
62 
63   ierr = PetscMalloc(nloc_isact*sizeof(PetscInt),&idx_act);CHKERRQ(ierr);
64 
65   /* Set inactive set indices */
66   for(i=0; i < nlocal; i++) {
67     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;
68   }
69 
70    /* Create inactive set IS */
71   ierr = ISCreateGeneral(((PetscObject)upper)->comm,nloc_isact,idx_act,PETSC_OWN_POINTER,inact);CHKERRQ(ierr);
72 
73   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
74   ierr = VecRestoreArrayRead(lower,&xl);CHKERRQ(ierr);
75   ierr = VecRestoreArrayRead(upper,&xu);CHKERRQ(ierr);
76   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
77   PetscFunctionReturn(0);
78 }
79 
80 /*
81     Provides a wrapper to a DM to allow it to be used to generated the interpolation/restriction from the DM for the smaller matrices and vectors
82   defined by the reduced space method.
83 
84     Simple calls the regular DM interpolation and restricts it to operation on the variables not associated with active constraints.
85 
86 <*/
87 typedef struct {
88   PetscInt       n;                                        /* size of vectors in the reduced DM space */
89   IS             inactive;
90   PetscErrorCode (*getinterpolation)(DM,DM,Mat*,Vec*);    /* DM's original routines */
91   PetscErrorCode (*coarsen)(DM, MPI_Comm, DM*);
92   PetscErrorCode (*createglobalvector)(DM,Vec*);
93   DM             dm;                                      /* when destroying this object we need to reset the above function into the base DM */
94 } DM_SNESVI;
95 
96 #undef __FUNCT__
97 #define __FUNCT__ "DMCreateGlobalVector_SNESVI"
98 /*
99      DMCreateGlobalVector_SNESVI - Creates global vector of the size of the reduced space
100 
101 */
102 PetscErrorCode  DMCreateGlobalVector_SNESVI(DM dm,Vec *vec)
103 {
104   PetscErrorCode          ierr;
105   PetscContainer          isnes;
106   DM_SNESVI               *dmsnesvi;
107 
108   PetscFunctionBegin;
109   ierr = PetscObjectQuery((PetscObject)dm,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
110   if (!isnes) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_PLIB,"Composed SNES is missing");
111   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi);CHKERRQ(ierr);
112   ierr = VecCreateMPI(((PetscObject)dm)->comm,dmsnesvi->n,PETSC_DETERMINE,vec);CHKERRQ(ierr);
113   PetscFunctionReturn(0);
114 }
115 
116 #undef __FUNCT__
117 #define __FUNCT__ "DMGetInterpolation_SNESVI"
118 /*
119      DMGetInterpolation_SNESVI - Modifieds the interpolation obtained from the DM by removing all rows and columns associated with active constraints.
120 
121 */
122 PetscErrorCode  DMGetInterpolation_SNESVI(DM dm1,DM dm2,Mat *mat,Vec *vec)
123 {
124   PetscErrorCode          ierr;
125   PetscContainer          isnes;
126   DM_SNESVI               *dmsnesvi1,*dmsnesvi2;
127   Mat                     interp;
128 
129   PetscFunctionBegin;
130   ierr = PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
131   if (!isnes) SETERRQ(((PetscObject)dm1)->comm,PETSC_ERR_PLIB,"Composed VI data structure is missing");
132   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);CHKERRQ(ierr);
133   ierr = PetscObjectQuery((PetscObject)dm2,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
134   if (!isnes) SETERRQ(((PetscObject)dm2)->comm,PETSC_ERR_PLIB,"Composed VI data structure is missing");
135   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi2);CHKERRQ(ierr);
136 
137   ierr = (*dmsnesvi1->getinterpolation)(dm1,dm2,&interp,PETSC_NULL);CHKERRQ(ierr);
138   ierr = MatGetSubMatrix(interp,dmsnesvi2->inactive,dmsnesvi1->inactive,MAT_INITIAL_MATRIX,mat);CHKERRQ(ierr);
139   ierr = MatDestroy(&interp);CHKERRQ(ierr);
140   *vec = 0;
141   PetscFunctionReturn(0);
142 }
143 
144 extern PetscErrorCode  DMSetVI(DM,IS);
145 
146 #undef __FUNCT__
147 #define __FUNCT__ "DMCoarsen_SNESVI"
148 /*
149      DMCoarsen_SNESVI - Computes the regular coarsened DM then computes additional information about its inactive set
150 
151 */
152 PetscErrorCode  DMCoarsen_SNESVI(DM dm1,MPI_Comm comm,DM *dm2)
153 {
154   PetscErrorCode          ierr;
155   PetscContainer          isnes;
156   DM_SNESVI               *dmsnesvi1;
157   Vec                     finemarked,coarsemarked;
158   IS                      inactive;
159   VecScatter              inject;
160   const PetscInt          *index;
161   PetscInt                n,k,cnt = 0,rstart,*coarseindex;
162   PetscScalar             *marked;
163 
164   PetscFunctionBegin;
165   ierr = PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
166   if (!isnes) SETERRQ(((PetscObject)dm1)->comm,PETSC_ERR_PLIB,"Composed VI data structure is missing");
167   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);CHKERRQ(ierr);
168 
169   /* get the original coarsen */
170   ierr = (*dmsnesvi1->coarsen)(dm1,comm,dm2);CHKERRQ(ierr);
171 
172   /* not sure why this extra reference is needed, but without the dm2 disappears too early */
173   ierr = PetscObjectReference((PetscObject)*dm2);CHKERRQ(ierr);
174 
175   /* need to set back global vectors in order to use the original injection */
176   ierr = DMClearGlobalVectors(dm1);CHKERRQ(ierr);
177   dm1->ops->createglobalvector = dmsnesvi1->createglobalvector;
178   ierr = DMCreateGlobalVector(dm1,&finemarked);CHKERRQ(ierr);
179   ierr = DMCreateGlobalVector(*dm2,&coarsemarked);CHKERRQ(ierr);
180 
181   /*
182      fill finemarked with locations of inactive points
183   */
184   ierr = ISGetIndices(dmsnesvi1->inactive,&index);CHKERRQ(ierr);
185   ierr = ISGetLocalSize(dmsnesvi1->inactive,&n);CHKERRQ(ierr);
186   ierr = VecSet(finemarked,0.0);CHKERRQ(ierr);
187   for (k=0;k<n;k++){
188       ierr = VecSetValue(finemarked,index[k],1.0,INSERT_VALUES);CHKERRQ(ierr);
189   }
190   ierr = VecAssemblyBegin(finemarked);CHKERRQ(ierr);
191   ierr = VecAssemblyEnd(finemarked);CHKERRQ(ierr);
192 
193   ierr = DMGetInjection(*dm2,dm1,&inject);CHKERRQ(ierr);
194   ierr = VecScatterBegin(inject,finemarked,coarsemarked,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
195   ierr = VecScatterEnd(inject,finemarked,coarsemarked,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
196   ierr = VecScatterDestroy(&inject);CHKERRQ(ierr);
197 
198   /*
199      create index set list of coarse inactive points from coarsemarked
200   */
201   ierr = VecGetLocalSize(coarsemarked,&n);CHKERRQ(ierr);
202   ierr = VecGetOwnershipRange(coarsemarked,&rstart,PETSC_NULL);CHKERRQ(ierr);
203   ierr = VecGetArray(coarsemarked,&marked);CHKERRQ(ierr);
204   for (k=0; k<n; k++) {
205     if (marked[k] != 0.0) cnt++;
206   }
207   ierr = PetscMalloc(cnt*sizeof(PetscInt),&coarseindex);CHKERRQ(ierr);
208   cnt  = 0;
209   for (k=0; k<n; k++) {
210     if (marked[k] != 0.0) coarseindex[cnt++] = k + rstart;
211   }
212   ierr = VecRestoreArray(coarsemarked,&marked);CHKERRQ(ierr);
213   ierr = ISCreateGeneral(PETSC_COMM_WORLD,cnt,coarseindex,PETSC_OWN_POINTER,&inactive);CHKERRQ(ierr);
214 
215   ierr = DMClearGlobalVectors(dm1);CHKERRQ(ierr);
216   dm1->ops->createglobalvector = DMCreateGlobalVector_SNESVI;
217   ierr = DMSetVI(*dm2,inactive);CHKERRQ(ierr);
218 
219   ierr = VecDestroy(&finemarked);CHKERRQ(ierr);
220   ierr = VecDestroy(&coarsemarked);CHKERRQ(ierr);
221   ierr = ISDestroy(&inactive);CHKERRQ(ierr);
222   PetscFunctionReturn(0);
223 }
224 
225 #undef __FUNCT__
226 #define __FUNCT__ "DMDestroy_SNESVI"
227 PetscErrorCode DMDestroy_SNESVI(DM_SNESVI *dmsnesvi)
228 {
229   PetscErrorCode ierr;
230 
231   PetscFunctionBegin;
232   /* reset the base methods in the DM object that were changed when the DM_SNESVI was reset */
233   dmsnesvi->dm->ops->getinterpolation   = dmsnesvi->getinterpolation;
234   dmsnesvi->dm->ops->coarsen            = dmsnesvi->coarsen;
235   dmsnesvi->dm->ops->createglobalvector = dmsnesvi->createglobalvector;
236   /* need to clear out this vectors because some of them may not have a reference to the DM
237     but they are counted as having references to the DM in DMDestroy() */
238   ierr = DMClearGlobalVectors(dmsnesvi->dm);CHKERRQ(ierr);
239 
240   ierr = ISDestroy(&dmsnesvi->inactive);CHKERRQ(ierr);
241   ierr = PetscFree(dmsnesvi);CHKERRQ(ierr);
242   PetscFunctionReturn(0);
243 }
244 
245 #undef __FUNCT__
246 #define __FUNCT__ "DMSetVI"
247 /*
248      DMSetVI - Marks a DM as associated with a VI problem. This causes the interpolation/restriction operators to
249                be restricted to only those variables NOT associated with active constraints.
250 
251 */
252 PetscErrorCode  DMSetVI(DM dm,IS inactive)
253 {
254   PetscErrorCode          ierr;
255   PetscContainer          isnes;
256   DM_SNESVI               *dmsnesvi;
257 
258   PetscFunctionBegin;
259   if (!dm) PetscFunctionReturn(0);
260 
261   ierr = PetscObjectReference((PetscObject)inactive);CHKERRQ(ierr);
262 
263   ierr = PetscObjectQuery((PetscObject)dm,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
264   if (!isnes) {
265     ierr = PetscContainerCreate(((PetscObject)dm)->comm,&isnes);CHKERRQ(ierr);
266     ierr = PetscContainerSetUserDestroy(isnes,(PetscErrorCode (*)(void*))DMDestroy_SNESVI);CHKERRQ(ierr);
267     ierr = PetscNew(DM_SNESVI,&dmsnesvi);CHKERRQ(ierr);
268     ierr = PetscContainerSetPointer(isnes,(void*)dmsnesvi);CHKERRQ(ierr);
269     ierr = PetscObjectCompose((PetscObject)dm,"VI",(PetscObject)isnes);CHKERRQ(ierr);
270     ierr = PetscContainerDestroy(&isnes);CHKERRQ(ierr);
271     dmsnesvi->getinterpolation   = dm->ops->getinterpolation;
272     dm->ops->getinterpolation    = DMGetInterpolation_SNESVI;
273     dmsnesvi->coarsen            = dm->ops->coarsen;
274     dm->ops->coarsen             = DMCoarsen_SNESVI;
275     dmsnesvi->createglobalvector = dm->ops->createglobalvector;
276     dm->ops->createglobalvector  = DMCreateGlobalVector_SNESVI;
277   } else {
278     ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi);CHKERRQ(ierr);
279     ierr = ISDestroy(&dmsnesvi->inactive);CHKERRQ(ierr);
280   }
281   ierr = DMClearGlobalVectors(dm);CHKERRQ(ierr);
282   ierr = ISGetLocalSize(inactive,&dmsnesvi->n);CHKERRQ(ierr);
283   dmsnesvi->inactive = inactive;
284   dmsnesvi->dm       = dm;
285   PetscFunctionReturn(0);
286 }
287 
288 #undef __FUNCT__
289 #define __FUNCT__ "DMDestroyVI"
290 /*
291      DMDestroyVI - Frees the DM_SNESVI object contained in the DM
292          - also resets the function pointers in the DM for getinterpolation() etc to use the original DM
293 */
294 PetscErrorCode  DMDestroyVI(DM dm)
295 {
296   PetscErrorCode          ierr;
297 
298   PetscFunctionBegin;
299   if (!dm) PetscFunctionReturn(0);
300   ierr = PetscObjectCompose((PetscObject)dm,"VI",(PetscObject)PETSC_NULL);CHKERRQ(ierr);
301   PetscFunctionReturn(0);
302 }
303 
304 /* --------------------------------------------------------------------------------------------------------*/
305 
306 #undef __FUNCT__
307 #define __FUNCT__ "SNESMonitorVI"
308 PetscErrorCode  SNESMonitorVI(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
309 {
310   PetscErrorCode    ierr;
311   SNES_VI            *vi = (SNES_VI*)snes->data;
312   PetscViewer        viewer = dummy ? (PetscViewer) dummy : PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);
313   const PetscScalar  *x,*xl,*xu,*f;
314   PetscInt           i,n,act[2] = {0,0},fact[2],N;
315   /* remove later */
316   /* Number of components that actually hit the bounds (c.f. active variables) */
317   PetscInt           act_bound[2] = {0,0},fact_bound[2];
318   PetscReal          rnorm,fnorm;
319 
320   PetscFunctionBegin;
321   ierr = VecGetLocalSize(snes->vec_sol,&n);CHKERRQ(ierr);
322   ierr = VecGetSize(snes->vec_sol,&N);CHKERRQ(ierr);
323   ierr = VecGetArrayRead(vi->xl,&xl);CHKERRQ(ierr);
324   ierr = VecGetArrayRead(vi->xu,&xu);CHKERRQ(ierr);
325   ierr = VecGetArrayRead(snes->vec_sol,&x);CHKERRQ(ierr);
326   ierr = VecGetArrayRead(snes->vec_func,&f);CHKERRQ(ierr);
327 
328   rnorm = 0.0;
329   for (i=0; i<n; i++) {
330     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]);
331     else if (PetscRealPart(x[i]) <= PetscRealPart(xl[i]) + 1.e-8 && PetscRealPart(f[i]) >= 0.0) act[0]++;
332     else if (PetscRealPart(x[i]) >= PetscRealPart(xu[i]) - 1.e-8 && PetscRealPart(f[i]) <= 0.0) act[1]++;
333     else SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_PLIB,"Can never get here");
334   }
335 
336   /* Remove later, number of components that actually hit the bounds */
337   for (i=0; i<n; i++) {
338     if (PetscRealPart(x[i]) <= PetscRealPart(xl[i]) + 1.e-8) act_bound[0]++;
339     else if (PetscRealPart(x[i]) >= PetscRealPart(xu[i]) - 1.e-8) act_bound[1]++;
340   }
341   ierr = VecRestoreArrayRead(snes->vec_func,&f);CHKERRQ(ierr);
342   ierr = VecRestoreArrayRead(vi->xl,&xl);CHKERRQ(ierr);
343   ierr = VecRestoreArrayRead(vi->xu,&xu);CHKERRQ(ierr);
344   ierr = VecRestoreArrayRead(snes->vec_sol,&x);CHKERRQ(ierr);
345   ierr = MPI_Allreduce(&rnorm,&fnorm,1,MPIU_REAL,MPIU_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
346   ierr = MPI_Allreduce(act,fact,2,MPIU_INT,MPIU_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
347   /* remove later */
348   ierr = MPI_Allreduce(act_bound,fact_bound,2,MPIU_INT,MPIU_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
349   fnorm = PetscSqrtReal(fnorm);
350 
351   ierr = PetscViewerASCIIAddTab(viewer,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
352   ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES VI Function norm %14.12e Active lower constraints %D upper constraints %D Percent of total %g Percent of bounded %g\n",its,(double)fnorm,fact[0],fact[1],((double)(fact[0]+fact[1]))/((double)N),((double)(fact[0]+fact[1]))/((double)vi->ntruebounds));CHKERRQ(ierr);
353   ierr = PetscViewerASCIIPrintf(viewer,"                               lower constraints satisfied %D upper constraints satisfied %D\n",its,fact_bound[0],fact_bound[1]);CHKERRQ(ierr);
354 
355   ierr = PetscViewerASCIISubtractTab(viewer,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
356   PetscFunctionReturn(0);
357 }
358 
359 /*
360      Checks if J^T F = 0 which implies we've found a local minimum of the norm of the function,
361     || 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
362     0 = (J^T F)^T W = F^T J W iff W not in the null space of J. Thanks for Jorge More
363     for this trick. One assumes that the probability that W is in the null space of J is very, very small.
364 */
365 #undef __FUNCT__
366 #define __FUNCT__ "SNESVICheckLocalMin_Private"
367 PetscErrorCode SNESVICheckLocalMin_Private(SNES snes,Mat A,Vec F,Vec W,PetscReal fnorm,PetscBool *ismin)
368 {
369   PetscReal      a1;
370   PetscErrorCode ierr;
371   PetscBool     hastranspose;
372 
373   PetscFunctionBegin;
374   *ismin = PETSC_FALSE;
375   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
376   if (hastranspose) {
377     /* Compute || J^T F|| */
378     ierr = MatMultTranspose(A,F,W);CHKERRQ(ierr);
379     ierr = VecNorm(W,NORM_2,&a1);CHKERRQ(ierr);
380     ierr = PetscInfo1(snes,"|| J^T F|| %G near zero implies found a local minimum\n",a1/fnorm);CHKERRQ(ierr);
381     if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE;
382   } else {
383     Vec         work;
384     PetscScalar result;
385     PetscReal   wnorm;
386 
387     ierr = VecSetRandom(W,PETSC_NULL);CHKERRQ(ierr);
388     ierr = VecNorm(W,NORM_2,&wnorm);CHKERRQ(ierr);
389     ierr = VecDuplicate(W,&work);CHKERRQ(ierr);
390     ierr = MatMult(A,W,work);CHKERRQ(ierr);
391     ierr = VecDot(F,work,&result);CHKERRQ(ierr);
392     ierr = VecDestroy(&work);CHKERRQ(ierr);
393     a1   = PetscAbsScalar(result)/(fnorm*wnorm);
394     ierr = PetscInfo1(snes,"(F^T J random)/(|| F ||*||random|| %G near zero implies found a local minimum\n",a1);CHKERRQ(ierr);
395     if (a1 < 1.e-4) *ismin = PETSC_TRUE;
396   }
397   PetscFunctionReturn(0);
398 }
399 
400 /*
401      Checks if J^T(F - J*X) = 0
402 */
403 #undef __FUNCT__
404 #define __FUNCT__ "SNESVICheckResidual_Private"
405 PetscErrorCode SNESVICheckResidual_Private(SNES snes,Mat A,Vec F,Vec X,Vec W1,Vec W2)
406 {
407   PetscReal      a1,a2;
408   PetscErrorCode ierr;
409   PetscBool     hastranspose;
410 
411   PetscFunctionBegin;
412   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
413   if (hastranspose) {
414     ierr = MatMult(A,X,W1);CHKERRQ(ierr);
415     ierr = VecAXPY(W1,-1.0,F);CHKERRQ(ierr);
416 
417     /* Compute || J^T W|| */
418     ierr = MatMultTranspose(A,W1,W2);CHKERRQ(ierr);
419     ierr = VecNorm(W1,NORM_2,&a1);CHKERRQ(ierr);
420     ierr = VecNorm(W2,NORM_2,&a2);CHKERRQ(ierr);
421     if (a1 != 0.0) {
422       ierr = PetscInfo1(snes,"||J^T(F-Ax)||/||F-AX|| %G near zero implies inconsistent rhs\n",a2/a1);CHKERRQ(ierr);
423     }
424   }
425   PetscFunctionReturn(0);
426 }
427 
428 /*
429   SNESDefaultConverged_VI - Checks the convergence of the semismooth newton algorithm.
430 
431   Notes:
432   The convergence criterion currently implemented is
433   merit < abstol
434   merit < rtol*merit_initial
435 */
436 #undef __FUNCT__
437 #define __FUNCT__ "SNESDefaultConverged_VI"
438 PetscErrorCode SNESDefaultConverged_VI(SNES snes,PetscInt it,PetscReal xnorm,PetscReal gradnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
439 {
440   PetscErrorCode ierr;
441 
442   PetscFunctionBegin;
443   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
444   PetscValidPointer(reason,6);
445 
446   *reason = SNES_CONVERGED_ITERATING;
447 
448   if (!it) {
449     /* set parameter for default relative tolerance convergence test */
450     snes->ttol = fnorm*snes->rtol;
451   }
452   if (fnorm != fnorm) {
453     ierr = PetscInfo(snes,"Failed to converged, function norm is NaN\n");CHKERRQ(ierr);
454     *reason = SNES_DIVERGED_FNORM_NAN;
455   } else if (fnorm < snes->abstol) {
456     ierr = PetscInfo2(snes,"Converged due to function norm %G < %G\n",fnorm,snes->abstol);CHKERRQ(ierr);
457     *reason = SNES_CONVERGED_FNORM_ABS;
458   } else if (snes->nfuncs >= snes->max_funcs) {
459     ierr = PetscInfo2(snes,"Exceeded maximum number of function evaluations: %D > %D\n",snes->nfuncs,snes->max_funcs);CHKERRQ(ierr);
460     *reason = SNES_DIVERGED_FUNCTION_COUNT;
461   }
462 
463   if (it && !*reason) {
464     if (fnorm < snes->ttol) {
465       ierr = PetscInfo2(snes,"Converged due to function norm %G < %G (relative tolerance)\n",fnorm,snes->ttol);CHKERRQ(ierr);
466       *reason = SNES_CONVERGED_FNORM_RELATIVE;
467     }
468   }
469   PetscFunctionReturn(0);
470 }
471 
472 /*
473   SNESVIComputeMeritFunction - Evaluates the merit function for the mixed complementarity problem.
474 
475   Input Parameter:
476 . phi - the semismooth function
477 
478   Output Parameter:
479 . merit - the merit function
480 . phinorm - ||phi||
481 
482   Notes:
483   The merit function for the mixed complementarity problem is defined as
484      merit = 0.5*phi^T*phi
485 */
486 #undef __FUNCT__
487 #define __FUNCT__ "SNESVIComputeMeritFunction"
488 static PetscErrorCode SNESVIComputeMeritFunction(Vec phi, PetscReal* merit,PetscReal* phinorm)
489 {
490   PetscErrorCode ierr;
491 
492   PetscFunctionBegin;
493   ierr = VecNormBegin(phi,NORM_2,phinorm);CHKERRQ(ierr);
494   ierr = VecNormEnd(phi,NORM_2,phinorm);CHKERRQ(ierr);
495 
496   *merit = 0.5*(*phinorm)*(*phinorm);
497   PetscFunctionReturn(0);
498 }
499 
500 PETSC_STATIC_INLINE PetscScalar Phi(PetscScalar a,PetscScalar b)
501 {
502   return a + b - PetscSqrtScalar(a*a + b*b);
503 }
504 
505 PETSC_STATIC_INLINE PetscScalar DPhi(PetscScalar a,PetscScalar b)
506 {
507   if ((PetscAbsScalar(a) >= 1.e-6) || (PetscAbsScalar(b) >= 1.e-6)) return  1.0 - a/ PetscSqrtScalar(a*a + b*b);
508   else return .5;
509 }
510 
511 /*
512    SNESVIComputeFunction - Reformulates a system of nonlinear equations in mixed complementarity form to a system of nonlinear equations in semismooth form.
513 
514    Input Parameters:
515 .  snes - the SNES context
516 .  x - current iterate
517 .  functx - user defined function context
518 
519    Output Parameters:
520 .  phi - Semismooth function
521 
522 */
523 #undef __FUNCT__
524 #define __FUNCT__ "SNESVIComputeFunction"
525 static PetscErrorCode SNESVIComputeFunction(SNES snes,Vec X,Vec phi,void* functx)
526 {
527   PetscErrorCode  ierr;
528   SNES_VI         *vi = (SNES_VI*)snes->data;
529   Vec             Xl = vi->xl,Xu = vi->xu,F = snes->vec_func;
530   PetscScalar     *phi_arr,*x_arr,*f_arr,*l,*u;
531   PetscInt        i,nlocal;
532 
533   PetscFunctionBegin;
534   ierr = (*vi->computeuserfunction)(snes,X,F,functx);CHKERRQ(ierr);
535   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
536   ierr = VecGetArray(X,&x_arr);CHKERRQ(ierr);
537   ierr = VecGetArray(F,&f_arr);CHKERRQ(ierr);
538   ierr = VecGetArray(Xl,&l);CHKERRQ(ierr);
539   ierr = VecGetArray(Xu,&u);CHKERRQ(ierr);
540   ierr = VecGetArray(phi,&phi_arr);CHKERRQ(ierr);
541 
542   for (i=0;i < nlocal;i++) {
543     if ((PetscRealPart(l[i]) <= SNES_VI_NINF) && (PetscRealPart(u[i]) >= SNES_VI_INF)) { /* no constraints on variable */
544       phi_arr[i] = f_arr[i];
545     } else if (PetscRealPart(l[i]) <= SNES_VI_NINF) {                      /* upper bound on variable only */
546       phi_arr[i] = -Phi(u[i] - x_arr[i],-f_arr[i]);
547     } else if (PetscRealPart(u[i]) >= SNES_VI_INF) {                       /* lower bound on variable only */
548       phi_arr[i] = Phi(x_arr[i] - l[i],f_arr[i]);
549     } else if (l[i] == u[i]) {
550       phi_arr[i] = l[i] - x_arr[i];
551     } else {                                                /* both bounds on variable */
552       phi_arr[i] = Phi(x_arr[i] - l[i],-Phi(u[i] - x_arr[i],-f_arr[i]));
553     }
554   }
555 
556   ierr = VecRestoreArray(X,&x_arr);CHKERRQ(ierr);
557   ierr = VecRestoreArray(F,&f_arr);CHKERRQ(ierr);
558   ierr = VecRestoreArray(Xl,&l);CHKERRQ(ierr);
559   ierr = VecRestoreArray(Xu,&u);CHKERRQ(ierr);
560   ierr = VecRestoreArray(phi,&phi_arr);CHKERRQ(ierr);
561   PetscFunctionReturn(0);
562 }
563 
564 /*
565    SNESVIComputeBsubdifferentialVectors - Computes the diagonal shift (Da) and row scaling (Db) vectors needed for the
566                                           the semismooth jacobian.
567 */
568 #undef __FUNCT__
569 #define __FUNCT__ "SNESVIComputeBsubdifferentialVectors"
570 PetscErrorCode SNESVIComputeBsubdifferentialVectors(SNES snes,Vec X,Vec F,Mat jac,Vec Da,Vec Db)
571 {
572   PetscErrorCode ierr;
573   SNES_VI      *vi = (SNES_VI*)snes->data;
574   PetscScalar    *l,*u,*x,*f,*da,*db,da1,da2,db1,db2;
575   PetscInt       i,nlocal;
576 
577   PetscFunctionBegin;
578 
579   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
580   ierr = VecGetArray(F,&f);CHKERRQ(ierr);
581   ierr = VecGetArray(vi->xl,&l);CHKERRQ(ierr);
582   ierr = VecGetArray(vi->xu,&u);CHKERRQ(ierr);
583   ierr = VecGetArray(Da,&da);CHKERRQ(ierr);
584   ierr = VecGetArray(Db,&db);CHKERRQ(ierr);
585   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
586 
587   for (i=0;i< nlocal;i++) {
588     if ((PetscRealPart(l[i]) <= SNES_VI_NINF) && (PetscRealPart(u[i]) >= SNES_VI_INF)) {/* no constraints on variable */
589       da[i] = 0;
590       db[i] = 1;
591     } else if (PetscRealPart(l[i]) <= SNES_VI_NINF) {                     /* upper bound on variable only */
592       da[i] = DPhi(u[i] - x[i], -f[i]);
593       db[i] = DPhi(-f[i],u[i] - x[i]);
594     } else if (PetscRealPart(u[i]) >= SNES_VI_INF) {                      /* lower bound on variable only */
595       da[i] = DPhi(x[i] - l[i], f[i]);
596       db[i] = DPhi(f[i],x[i] - l[i]);
597     } else if (l[i] == u[i]) {                              /* fixed variable */
598       da[i] = 1;
599       db[i] = 0;
600     } else {                                                /* upper and lower bounds on variable */
601       da1 = DPhi(x[i] - l[i], -Phi(u[i] - x[i], -f[i]));
602       db1 = DPhi(-Phi(u[i] - x[i], -f[i]),x[i] - l[i]);
603       da2 = DPhi(u[i] - x[i], -f[i]);
604       db2 = DPhi(-f[i],u[i] - x[i]);
605       da[i] = da1 + db1*da2;
606       db[i] = db1*db2;
607     }
608   }
609 
610   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
611   ierr = VecRestoreArray(F,&f);CHKERRQ(ierr);
612   ierr = VecRestoreArray(vi->xl,&l);CHKERRQ(ierr);
613   ierr = VecRestoreArray(vi->xu,&u);CHKERRQ(ierr);
614   ierr = VecRestoreArray(Da,&da);CHKERRQ(ierr);
615   ierr = VecRestoreArray(Db,&db);CHKERRQ(ierr);
616   PetscFunctionReturn(0);
617 }
618 
619 /*
620    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.
621 
622    Input Parameters:
623 .  Da       - Diagonal shift vector for the semismooth jacobian.
624 .  Db       - Row scaling vector for the semismooth jacobian.
625 
626    Output Parameters:
627 .  jac      - semismooth jacobian
628 .  jac_pre  - optional preconditioning matrix
629 
630    Notes:
631    The semismooth jacobian matrix is given by
632    jac = Da + Db*jacfun
633    where Db is the row scaling matrix stored as a vector,
634          Da is the diagonal perturbation matrix stored as a vector
635    and   jacfun is the jacobian of the original nonlinear function.
636 */
637 #undef __FUNCT__
638 #define __FUNCT__ "SNESVIComputeJacobian"
639 PetscErrorCode SNESVIComputeJacobian(Mat jac, Mat jac_pre,Vec Da, Vec Db)
640 {
641   PetscErrorCode ierr;
642 
643   /* Do row scaling  and add diagonal perturbation */
644   ierr = MatDiagonalScale(jac,Db,PETSC_NULL);CHKERRQ(ierr);
645   ierr = MatDiagonalSet(jac,Da,ADD_VALUES);CHKERRQ(ierr);
646   if (jac != jac_pre) { /* If jac and jac_pre are different */
647     ierr = MatDiagonalScale(jac_pre,Db,PETSC_NULL);
648     ierr = MatDiagonalSet(jac_pre,Da,ADD_VALUES);CHKERRQ(ierr);
649   }
650   PetscFunctionReturn(0);
651 }
652 
653 /*
654    SNESVIComputeMeritFunctionGradient - Computes the gradient of the merit function psi.
655 
656    Input Parameters:
657    phi - semismooth function.
658    H   - semismooth jacobian
659 
660    Output Parameters:
661    dpsi - merit function gradient
662 
663    Notes:
664   The merit function gradient is computed as follows
665         dpsi = H^T*phi
666 */
667 #undef __FUNCT__
668 #define __FUNCT__ "SNESVIComputeMeritFunctionGradient"
669 PetscErrorCode SNESVIComputeMeritFunctionGradient(Mat H, Vec phi, Vec dpsi)
670 {
671   PetscErrorCode ierr;
672 
673   PetscFunctionBegin;
674   ierr = MatMultTranspose(H,phi,dpsi);CHKERRQ(ierr);
675   PetscFunctionReturn(0);
676 }
677 
678 /* -------------------------------------------------------------------------- */
679 /*
680    SNESVIProjectOntoBounds - Projects X onto the feasible region so that Xl[i] <= X[i] <= Xu[i] for i = 1...n.
681 
682    Input Parameters:
683 .  SNES - nonlinear solver context
684 
685    Output Parameters:
686 .  X - Bound projected X
687 
688 */
689 
690 #undef __FUNCT__
691 #define __FUNCT__ "SNESVIProjectOntoBounds"
692 PetscErrorCode SNESVIProjectOntoBounds(SNES snes,Vec X)
693 {
694   PetscErrorCode    ierr;
695   SNES_VI           *vi = (SNES_VI*)snes->data;
696   const PetscScalar *xl,*xu;
697   PetscScalar       *x;
698   PetscInt          i,n;
699 
700   PetscFunctionBegin;
701   ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr);
702   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
703   ierr = VecGetArrayRead(vi->xl,&xl);CHKERRQ(ierr);
704   ierr = VecGetArrayRead(vi->xu,&xu);CHKERRQ(ierr);
705 
706   for(i = 0;i<n;i++) {
707     if (PetscRealPart(x[i]) < PetscRealPart(xl[i])) x[i] = xl[i];
708     else if (PetscRealPart(x[i]) > PetscRealPart(xu[i])) x[i] = xu[i];
709   }
710   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
711   ierr = VecRestoreArrayRead(vi->xl,&xl);CHKERRQ(ierr);
712   ierr = VecRestoreArrayRead(vi->xu,&xu);CHKERRQ(ierr);
713   PetscFunctionReturn(0);
714 }
715 
716 /*  --------------------------------------------------------------------
717 
718      This file implements a semismooth truncated Newton method with a line search,
719      for solving a system of nonlinear equations in complementarity form, using the KSP, Vec,
720      and Mat interfaces for linear solvers, vectors, and matrices,
721      respectively.
722 
723      The following basic routines are required for each nonlinear solver:
724           SNESCreate_XXX()          - Creates a nonlinear solver context
725           SNESSetFromOptions_XXX()  - Sets runtime options
726           SNESSolve_XXX()           - Solves the nonlinear system
727           SNESDestroy_XXX()         - Destroys the nonlinear solver context
728      The suffix "_XXX" denotes a particular implementation, in this case
729      we use _VI (e.g., SNESCreate_VI, SNESSolve_VI) for solving
730      systems of nonlinear equations with a line search (LS) method.
731      These routines are actually called via the common user interface
732      routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and
733      SNESDestroy(), so the application code interface remains identical
734      for all nonlinear solvers.
735 
736      Another key routine is:
737           SNESSetUp_XXX()           - Prepares for the use of a nonlinear solver
738      by setting data structures and options.   The interface routine SNESSetUp()
739      is not usually called directly by the user, but instead is called by
740      SNESSolve() if necessary.
741 
742      Additional basic routines are:
743           SNESView_XXX()            - Prints details of runtime options that
744                                       have actually been used.
745      These are called by application codes via the interface routines
746      SNESView().
747 
748      The various types of solvers (preconditioners, Krylov subspace methods,
749      nonlinear solvers, timesteppers) are all organized similarly, so the
750      above description applies to these categories also.
751 
752     -------------------------------------------------------------------- */
753 /*
754    SNESSolveVI_SS - Solves the complementarity problem with a semismooth Newton
755    method using a line search.
756 
757    Input Parameters:
758 .  snes - the SNES context
759 
760    Output Parameter:
761 .  outits - number of iterations until termination
762 
763    Application Interface Routine: SNESSolve()
764 
765    Notes:
766    This implements essentially a semismooth Newton method with a
767    line search. The default line search does not do any line seach
768    but rather takes a full newton step.
769 */
770 #undef __FUNCT__
771 #define __FUNCT__ "SNESSolveVI_SS"
772 PetscErrorCode SNESSolveVI_SS(SNES snes)
773 {
774   SNES_VI            *vi = (SNES_VI*)snes->data;
775   PetscErrorCode     ierr;
776   PetscInt           maxits,i,lits;
777   PetscBool          lssucceed;
778   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
779   PetscReal          gnorm,xnorm=0,ynorm;
780   Vec                Y,X,F,G,W;
781   KSPConvergedReason kspreason;
782 
783   PetscFunctionBegin;
784   vi->computeuserfunction    = snes->ops->computefunction;
785   snes->ops->computefunction = SNESVIComputeFunction;
786 
787   snes->numFailures            = 0;
788   snes->numLinearSolveFailures = 0;
789   snes->reason                 = SNES_CONVERGED_ITERATING;
790 
791   maxits	= snes->max_its;	/* maximum number of iterations */
792   X		= snes->vec_sol;	/* solution vector */
793   F		= snes->vec_func;	/* residual vector */
794   Y		= snes->work[0];	/* work vectors */
795   G		= snes->work[1];
796   W		= snes->work[2];
797 
798   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
799   snes->iter = 0;
800   snes->norm = 0.0;
801   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
802 
803   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
804   ierr = SNESComputeFunction(snes,X,vi->phi);CHKERRQ(ierr);
805   if (snes->domainerror) {
806     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
807     snes->ops->computefunction = vi->computeuserfunction;
808     PetscFunctionReturn(0);
809   }
810    /* Compute Merit function */
811   ierr = SNESVIComputeMeritFunction(vi->phi,&vi->merit,&vi->phinorm);CHKERRQ(ierr);
812 
813   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
814   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
815   if (PetscIsInfOrNanReal(vi->merit)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
816 
817   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
818   snes->norm = vi->phinorm;
819   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
820   SNESLogConvHistory(snes,vi->phinorm,0);
821   ierr = SNESMonitor(snes,0,vi->phinorm);CHKERRQ(ierr);
822 
823   /* set parameter for default relative tolerance convergence test */
824   snes->ttol = vi->phinorm*snes->rtol;
825   /* test convergence */
826   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
827   if (snes->reason) {
828     snes->ops->computefunction = vi->computeuserfunction;
829     PetscFunctionReturn(0);
830   }
831 
832   for (i=0; i<maxits; i++) {
833 
834     /* Call general purpose update function */
835     if (snes->ops->update) {
836       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
837     }
838 
839     /* Solve J Y = Phi, where J is the semismooth jacobian */
840     /* Get the nonlinear function jacobian */
841     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
842     /* Get the diagonal shift and row scaling vectors */
843     ierr = SNESVIComputeBsubdifferentialVectors(snes,X,F,snes->jacobian,vi->Da,vi->Db);CHKERRQ(ierr);
844     /* Compute the semismooth jacobian */
845     ierr = SNESVIComputeJacobian(snes->jacobian,snes->jacobian_pre,vi->Da,vi->Db);CHKERRQ(ierr);
846     /* Compute the merit function gradient */
847     ierr = SNESVIComputeMeritFunctionGradient(snes->jacobian,vi->phi,vi->dpsi);CHKERRQ(ierr);
848     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
849     ierr = SNES_KSPSolve(snes,snes->ksp,vi->phi,Y);CHKERRQ(ierr);
850     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
851 
852     if (kspreason < 0) {
853       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
854         ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
855         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
856         break;
857       }
858     }
859     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
860     snes->linear_its += lits;
861     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
862     /*
863     if (vi->precheckstep) {
864       PetscBool changed_y = PETSC_FALSE;
865       ierr = (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);CHKERRQ(ierr);
866     }
867 
868     if (PetscLogPrintInfo){
869       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
870     }
871     */
872     /* Compute a (scaled) negative update in the line search routine:
873          Y <- X - lambda*Y
874        and evaluate G = function(Y) (depends on the line search).
875     */
876     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
877     ynorm = 1; gnorm = vi->phinorm;
878     ierr = (*vi->LineSearch)(snes,vi->lsP,X,vi->phi,Y,vi->phinorm,xnorm,G,W,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
879     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",vi->phinorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr);
880     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
881     if (snes->domainerror) {
882       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
883       snes->ops->computefunction = vi->computeuserfunction;
884       PetscFunctionReturn(0);
885     }
886     if (!lssucceed) {
887       if (++snes->numFailures >= snes->maxFailures) {
888 	PetscBool ismin;
889         snes->reason = SNES_DIVERGED_LINE_SEARCH;
890         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
891         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
892         break;
893       }
894     }
895     /* Update function and solution vectors */
896     vi->phinorm = gnorm;
897     vi->merit = 0.5*vi->phinorm*vi->phinorm;
898     ierr = VecCopy(G,vi->phi);CHKERRQ(ierr);
899     ierr = VecCopy(W,X);CHKERRQ(ierr);
900     /* Monitor convergence */
901     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
902     snes->iter = i+1;
903     snes->norm = vi->phinorm;
904     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
905     SNESLogConvHistory(snes,snes->norm,lits);
906     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
907     /* Test for convergence, xnorm = || X || */
908     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
909     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
910     if (snes->reason) break;
911   }
912   if (i == maxits) {
913     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
914     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
915   }
916   snes->ops->computefunction = vi->computeuserfunction;
917   PetscFunctionReturn(0);
918 }
919 
920 #undef __FUNCT__
921 #define __FUNCT__ "SNESVIGetActiveSetIS"
922 /*
923    SNESVIGetActiveSetIndices - Gets the global indices for the active set variables
924 
925    Input parameter
926 .  snes - the SNES context
927 .  X    - the snes solution vector
928 .  F    - the nonlinear function vector
929 
930    Output parameter
931 .  ISact - active set index set
932  */
933 PetscErrorCode SNESVIGetActiveSetIS(SNES snes,Vec X,Vec F,IS* ISact)
934 {
935   PetscErrorCode   ierr;
936   SNES_VI          *vi = (SNES_VI*)snes->data;
937   Vec               Xl=vi->xl,Xu=vi->xu;
938   const PetscScalar *x,*f,*xl,*xu;
939   PetscInt          *idx_act,i,nlocal,nloc_isact=0,ilow,ihigh,i1=0;
940 
941   PetscFunctionBegin;
942   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
943   ierr = VecGetOwnershipRange(X,&ilow,&ihigh);CHKERRQ(ierr);
944   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
945   ierr = VecGetArrayRead(Xl,&xl);CHKERRQ(ierr);
946   ierr = VecGetArrayRead(Xu,&xu);CHKERRQ(ierr);
947   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
948   /* Compute active set size */
949   for (i=0; i < nlocal;i++) {
950     if (!vi->ignorefunctionsign) {
951       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++;
952     } else {
953       if (!(PetscRealPart(x[i]) > PetscRealPart(xl[i]) + 1.e-8  && PetscRealPart(x[i]) < PetscRealPart(xu[i]) - 1.e-8)) nloc_isact++;
954     }
955   }
956 
957   ierr = PetscMalloc(nloc_isact*sizeof(PetscInt),&idx_act);CHKERRQ(ierr);
958 
959   /* Set active set indices */
960   for(i=0; i < nlocal; i++) {
961     if (!vi->ignorefunctionsign) {
962       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;
963     } else {
964       if (!(PetscRealPart(x[i]) > PetscRealPart(xl[i]) + 1.e-8  && PetscRealPart(x[i]) < PetscRealPart(xu[i]) - 1.e-8)) idx_act[i1++] = ilow+i;
965     }
966   }
967 
968    /* Create active set IS */
969   ierr = ISCreateGeneral(((PetscObject)snes)->comm,nloc_isact,idx_act,PETSC_OWN_POINTER,ISact);CHKERRQ(ierr);
970 
971   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
972   ierr = VecRestoreArrayRead(Xl,&xl);CHKERRQ(ierr);
973   ierr = VecRestoreArrayRead(Xu,&xu);CHKERRQ(ierr);
974   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
975   PetscFunctionReturn(0);
976 }
977 
978 #undef __FUNCT__
979 #define __FUNCT__ "SNESVICreateIndexSets_RS"
980 PetscErrorCode SNESVICreateIndexSets_RS(SNES snes,Vec X,Vec F,IS* ISact,IS* ISinact)
981 {
982   PetscErrorCode     ierr;
983 
984   PetscFunctionBegin;
985   ierr = SNESVIGetActiveSetIS(snes,X,F,ISact);CHKERRQ(ierr);
986   ierr = ISComplement(*ISact,X->map->rstart,X->map->rend,ISinact);CHKERRQ(ierr);
987   PetscFunctionReturn(0);
988 }
989 
990 /* Create active and inactive set vectors. The local size of this vector is set and petsc computes the global size */
991 #undef __FUNCT__
992 #define __FUNCT__ "SNESVICreateSubVectors"
993 PetscErrorCode SNESVICreateSubVectors(SNES snes,PetscInt n,Vec* newv)
994 {
995   PetscErrorCode ierr;
996   Vec            v;
997 
998   PetscFunctionBegin;
999   ierr = VecCreate(((PetscObject)snes)->comm,&v);CHKERRQ(ierr);
1000   ierr = VecSetSizes(v,n,PETSC_DECIDE);CHKERRQ(ierr);
1001   ierr = VecSetFromOptions(v);CHKERRQ(ierr);
1002   *newv = v;
1003 
1004   PetscFunctionReturn(0);
1005 }
1006 
1007 /* Resets the snes PC and KSP when the active set sizes change */
1008 #undef __FUNCT__
1009 #define __FUNCT__ "SNESVIResetPCandKSP"
1010 PetscErrorCode SNESVIResetPCandKSP(SNES snes,Mat Amat,Mat Pmat)
1011 {
1012   PetscErrorCode         ierr;
1013   KSP                    snesksp;
1014 
1015   PetscFunctionBegin;
1016   ierr = SNESGetKSP(snes,&snesksp);CHKERRQ(ierr);
1017   ierr = KSPReset(snesksp);CHKERRQ(ierr);
1018 
1019   /*
1020   KSP                    kspnew;
1021   PC                     pcnew;
1022   const MatSolverPackage stype;
1023 
1024 
1025   ierr = KSPCreate(((PetscObject)snes)->comm,&kspnew);CHKERRQ(ierr);
1026   kspnew->pc_side = snesksp->pc_side;
1027   kspnew->rtol    = snesksp->rtol;
1028   kspnew->abstol    = snesksp->abstol;
1029   kspnew->max_it  = snesksp->max_it;
1030   ierr = KSPSetType(kspnew,((PetscObject)snesksp)->type_name);CHKERRQ(ierr);
1031   ierr = KSPGetPC(kspnew,&pcnew);CHKERRQ(ierr);
1032   ierr = PCSetType(kspnew->pc,((PetscObject)snesksp->pc)->type_name);CHKERRQ(ierr);
1033   ierr = PCSetOperators(kspnew->pc,Amat,Pmat,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
1034   ierr = PCFactorGetMatSolverPackage(snesksp->pc,&stype);CHKERRQ(ierr);
1035   ierr = PCFactorSetMatSolverPackage(kspnew->pc,stype);CHKERRQ(ierr);
1036   ierr = KSPDestroy(&snesksp);CHKERRQ(ierr);
1037   snes->ksp = kspnew;
1038   ierr = PetscLogObjectParent(snes,kspnew);CHKERRQ(ierr);
1039    ierr = KSPSetFromOptions(kspnew);CHKERRQ(ierr);*/
1040   PetscFunctionReturn(0);
1041 }
1042 
1043 
1044 #undef __FUNCT__
1045 #define __FUNCT__ "SNESVIComputeInactiveSetFnorm"
1046 PetscErrorCode SNESVIComputeInactiveSetFnorm(SNES snes,Vec F,Vec X,PetscReal *fnorm)
1047 {
1048   PetscErrorCode    ierr;
1049   SNES_VI           *vi = (SNES_VI*)snes->data;
1050   const PetscScalar *x,*xl,*xu,*f;
1051   PetscInt          i,n;
1052   PetscReal         rnorm;
1053 
1054   PetscFunctionBegin;
1055   ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr);
1056   ierr = VecGetArrayRead(vi->xl,&xl);CHKERRQ(ierr);
1057   ierr = VecGetArrayRead(vi->xu,&xu);CHKERRQ(ierr);
1058   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
1059   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
1060   rnorm = 0.0;
1061   if (!vi->ignorefunctionsign) {
1062     for (i=0; i<n; i++) {
1063       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]);
1064     }
1065   } else {
1066     for (i=0; i<n; i++) {
1067       if ((PetscRealPart(x[i]) > PetscRealPart(xl[i]) + 1.e-8) && (PetscRealPart(x[i]) < PetscRealPart(xu[i]) - 1.e-8)) rnorm += PetscRealPart(PetscConj(f[i])*f[i]);
1068     }
1069   }
1070   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
1071   ierr = VecRestoreArrayRead(vi->xl,&xl);CHKERRQ(ierr);
1072   ierr = VecRestoreArrayRead(vi->xu,&xu);CHKERRQ(ierr);
1073   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
1074   ierr = MPI_Allreduce(&rnorm,fnorm,1,MPIU_REAL,MPIU_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
1075   *fnorm = sqrt(*fnorm);
1076   PetscFunctionReturn(0);
1077 }
1078 
1079 /* Variational Inequality solver using reduce space method. No semismooth algorithm is
1080    implemented in this algorithm. It basically identifies the active constraints and does
1081    a linear solve on the other variables (those not associated with the active constraints). */
1082 #undef __FUNCT__
1083 #define __FUNCT__ "SNESSolveVI_RS"
1084 PetscErrorCode SNESSolveVI_RS(SNES snes)
1085 {
1086   SNES_VI          *vi = (SNES_VI*)snes->data;
1087   PetscErrorCode    ierr;
1088   PetscInt          maxits,i,lits;
1089   PetscBool         lssucceed;
1090   MatStructure      flg = DIFFERENT_NONZERO_PATTERN;
1091   PetscReal         fnorm,gnorm,xnorm=0,ynorm;
1092   Vec                Y,X,F,G,W;
1093   KSPConvergedReason kspreason;
1094 
1095   PetscFunctionBegin;
1096   snes->numFailures            = 0;
1097   snes->numLinearSolveFailures = 0;
1098   snes->reason                 = SNES_CONVERGED_ITERATING;
1099 
1100   maxits	= snes->max_its;	/* maximum number of iterations */
1101   X		= snes->vec_sol;	/* solution vector */
1102   F		= snes->vec_func;	/* residual vector */
1103   Y		= snes->work[0];	/* work vectors */
1104   G		= snes->work[1];
1105   W		= snes->work[2];
1106 
1107   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
1108   snes->iter = 0;
1109   snes->norm = 0.0;
1110   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
1111 
1112   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
1113   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
1114   if (snes->domainerror) {
1115     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
1116     PetscFunctionReturn(0);
1117   }
1118   ierr = SNESVIComputeInactiveSetFnorm(snes,F,X,&fnorm);CHKERRQ(ierr);
1119   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
1120   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
1121   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1122 
1123   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
1124   snes->norm = fnorm;
1125   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
1126   SNESLogConvHistory(snes,fnorm,0);
1127   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
1128 
1129   /* set parameter for default relative tolerance convergence test */
1130   snes->ttol = fnorm*snes->rtol;
1131   /* test convergence */
1132   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
1133   if (snes->reason) PetscFunctionReturn(0);
1134 
1135 
1136   for (i=0; i<maxits; i++) {
1137 
1138     IS         IS_act,IS_inact; /* _act -> active set _inact -> inactive set */
1139     IS         IS_redact; /* redundant active set */
1140     VecScatter scat_act,scat_inact;
1141     PetscInt   nis_act,nis_inact;
1142     Vec        Y_act,Y_inact,F_inact;
1143     Mat        jac_inact_inact,prejac_inact_inact;
1144     IS         keptrows;
1145     PetscBool  isequal;
1146 
1147     /* Call general purpose update function */
1148     if (snes->ops->update) {
1149       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
1150     }
1151     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
1152 
1153 
1154         /* Create active and inactive index sets */
1155 
1156     /*original
1157     ierr = SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&IS_inact);CHKERRQ(ierr);
1158      */
1159     ierr = SNESVIGetActiveSetIS(snes,X,F,&IS_act);CHKERRQ(ierr);
1160 
1161     if (vi->checkredundancy) {
1162       (*vi->checkredundancy)(snes,IS_act,&IS_redact,vi->ctxP);CHKERRQ(ierr);
1163       if (IS_redact){
1164         ierr = ISSort(IS_redact);CHKERRQ(ierr);
1165         ierr = ISComplement(IS_redact,X->map->rstart,X->map->rend,&IS_inact);CHKERRQ(ierr);
1166         ierr = ISDestroy(&IS_redact);CHKERRQ(ierr);
1167       }
1168       else {
1169         ierr = ISComplement(IS_act,X->map->rstart,X->map->rend,&IS_inact);CHKERRQ(ierr);
1170       }
1171     } else {
1172       ierr = ISComplement(IS_act,X->map->rstart,X->map->rend,&IS_inact);CHKERRQ(ierr);
1173     }
1174 
1175 
1176     /* Create inactive set submatrix */
1177     ierr = MatGetSubMatrix(snes->jacobian,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr);
1178 
1179     ierr = MatFindNonzeroRows(jac_inact_inact,&keptrows);CHKERRQ(ierr);
1180     if (0 && keptrows) {
1181       PetscInt       cnt,*nrows,k;
1182       const PetscInt *krows,*inact;
1183       PetscInt       rstart=jac_inact_inact->rmap->rstart;
1184 
1185       ierr = MatDestroy(&jac_inact_inact);CHKERRQ(ierr);
1186       ierr = ISDestroy(&IS_act);CHKERRQ(ierr);
1187 
1188       ierr = ISGetLocalSize(keptrows,&cnt);CHKERRQ(ierr);
1189       ierr = ISGetIndices(keptrows,&krows);CHKERRQ(ierr);
1190       ierr = ISGetIndices(IS_inact,&inact);CHKERRQ(ierr);
1191       ierr = PetscMalloc(cnt*sizeof(PetscInt),&nrows);CHKERRQ(ierr);
1192       for (k=0; k<cnt; k++) {
1193         nrows[k] = inact[krows[k]-rstart];
1194       }
1195       ierr = ISRestoreIndices(keptrows,&krows);CHKERRQ(ierr);
1196       ierr = ISRestoreIndices(IS_inact,&inact);CHKERRQ(ierr);
1197       ierr = ISDestroy(&keptrows);CHKERRQ(ierr);
1198       ierr = ISDestroy(&IS_inact);CHKERRQ(ierr);
1199 
1200       ierr = ISCreateGeneral(PETSC_COMM_WORLD,cnt,nrows,PETSC_OWN_POINTER,&IS_inact);CHKERRQ(ierr);
1201       ierr = ISComplement(IS_inact,F->map->rstart,F->map->rend,&IS_act);CHKERRQ(ierr);
1202       ierr = MatGetSubMatrix(snes->jacobian,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr);
1203     }
1204     ierr = DMSetVI(snes->dm,IS_inact);CHKERRQ(ierr);
1205     /* remove later */
1206 
1207     /*
1208   ierr = VecView(vi->xu,PETSC_VIEWER_BINARY_(PETSC_COMM_WORLD));CHKERRQ(ierr);
1209   ierr = VecView(vi->xl,PETSC_VIEWER_BINARY_(PETSC_COMM_WORLD));CHKERRQ(ierr);
1210   ierr = VecView(X,PETSC_VIEWER_BINARY_(PETSC_COMM_WORLD));CHKERRQ(ierr);
1211   ierr = VecView(F,PETSC_VIEWER_BINARY_(PETSC_COMM_WORLD));CHKERRQ(ierr);
1212   ierr = ISView(IS_inact,PETSC_VIEWER_BINARY_(PETSC_COMM_WORLD));CHKERRQ(ierr);
1213      */
1214 
1215     /* Get sizes of active and inactive sets */
1216     ierr = ISGetLocalSize(IS_act,&nis_act);CHKERRQ(ierr);
1217     ierr = ISGetLocalSize(IS_inact,&nis_inact);CHKERRQ(ierr);
1218 
1219     /* Create active and inactive set vectors */
1220     ierr = SNESVICreateSubVectors(snes,nis_inact,&F_inact);CHKERRQ(ierr);
1221     ierr = SNESVICreateSubVectors(snes,nis_act,&Y_act);CHKERRQ(ierr);
1222     ierr = SNESVICreateSubVectors(snes,nis_inact,&Y_inact);CHKERRQ(ierr);
1223 
1224     /* Create scatter contexts */
1225     ierr = VecScatterCreate(Y,IS_act,Y_act,PETSC_NULL,&scat_act);CHKERRQ(ierr);
1226     ierr = VecScatterCreate(Y,IS_inact,Y_inact,PETSC_NULL,&scat_inact);CHKERRQ(ierr);
1227 
1228     /* Do a vec scatter to active and inactive set vectors */
1229     ierr = VecScatterBegin(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1230     ierr = VecScatterEnd(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1231 
1232     ierr = VecScatterBegin(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1233     ierr = VecScatterEnd(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1234 
1235     ierr = VecScatterBegin(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1236     ierr = VecScatterEnd(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1237 
1238     /* Active set direction = 0 */
1239     ierr = VecSet(Y_act,0);CHKERRQ(ierr);
1240     if (snes->jacobian != snes->jacobian_pre) {
1241       ierr = MatGetSubMatrix(snes->jacobian_pre,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&prejac_inact_inact);CHKERRQ(ierr);
1242     } else prejac_inact_inact = jac_inact_inact;
1243 
1244     ierr = ISEqual(vi->IS_inact_prev,IS_inact,&isequal);CHKERRQ(ierr);
1245     if (!isequal) {
1246       ierr = SNESVIResetPCandKSP(snes,jac_inact_inact,prejac_inact_inact);CHKERRQ(ierr);
1247       flg  = DIFFERENT_NONZERO_PATTERN;
1248     }
1249 
1250     /*      ierr = ISView(IS_inact,0);CHKERRQ(ierr); */
1251     /*      ierr = ISView(IS_act,0);CHKERRQ(ierr);*/
1252     /*      ierr = MatView(snes->jacobian_pre,0); */
1253 
1254 
1255 
1256     ierr = KSPSetOperators(snes->ksp,jac_inact_inact,prejac_inact_inact,flg);CHKERRQ(ierr);
1257     ierr = KSPSetUp(snes->ksp);CHKERRQ(ierr);
1258     {
1259       PC        pc;
1260       PetscBool flg;
1261       ierr = KSPGetPC(snes->ksp,&pc);CHKERRQ(ierr);
1262       ierr = PetscTypeCompare((PetscObject)pc,PCFIELDSPLIT,&flg);CHKERRQ(ierr);
1263       if (flg) {
1264         KSP      *subksps;
1265         ierr = PCFieldSplitGetSubKSP(pc,PETSC_NULL,&subksps);CHKERRQ(ierr);
1266         ierr = KSPGetPC(subksps[0],&pc);CHKERRQ(ierr);
1267         ierr = PetscFree(subksps);CHKERRQ(ierr);
1268         ierr = PetscTypeCompare((PetscObject)pc,PCBJACOBI,&flg);CHKERRQ(ierr);
1269         if (flg) {
1270           PetscInt       n,N = 101*101,j,cnts[3] = {0,0,0};
1271           const PetscInt *ii;
1272 
1273           ierr = ISGetSize(IS_inact,&n);CHKERRQ(ierr);
1274           ierr = ISGetIndices(IS_inact,&ii);CHKERRQ(ierr);
1275           for (j=0; j<n; j++) {
1276             if (ii[j] < N) cnts[0]++;
1277             else if (ii[j] < 2*N) cnts[1]++;
1278             else if (ii[j] < 3*N) cnts[2]++;
1279           }
1280           ierr = ISRestoreIndices(IS_inact,&ii);CHKERRQ(ierr);
1281 
1282           ierr = PCBJacobiSetTotalBlocks(pc,3,cnts);CHKERRQ(ierr);
1283         }
1284       }
1285     }
1286 
1287     ierr = SNES_KSPSolve(snes,snes->ksp,F_inact,Y_inact);CHKERRQ(ierr);
1288     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
1289     if (kspreason < 0) {
1290       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
1291         ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
1292         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
1293         break;
1294       }
1295      }
1296 
1297     ierr = VecScatterBegin(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1298     ierr = VecScatterEnd(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1299     ierr = VecScatterBegin(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1300     ierr = VecScatterEnd(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1301 
1302     ierr = VecDestroy(&F_inact);CHKERRQ(ierr);
1303     ierr = VecDestroy(&Y_act);CHKERRQ(ierr);
1304     ierr = VecDestroy(&Y_inact);CHKERRQ(ierr);
1305     ierr = VecScatterDestroy(&scat_act);CHKERRQ(ierr);
1306     ierr = VecScatterDestroy(&scat_inact);CHKERRQ(ierr);
1307     ierr = ISDestroy(&IS_act);CHKERRQ(ierr);
1308     if (!isequal) {
1309       ierr = ISDestroy(&vi->IS_inact_prev);CHKERRQ(ierr);
1310       ierr = ISDuplicate(IS_inact,&vi->IS_inact_prev);CHKERRQ(ierr);
1311     }
1312     ierr = ISDestroy(&IS_inact);CHKERRQ(ierr);
1313     ierr = MatDestroy(&jac_inact_inact);CHKERRQ(ierr);
1314     if (snes->jacobian != snes->jacobian_pre) {
1315       ierr = MatDestroy(&prejac_inact_inact);CHKERRQ(ierr);
1316     }
1317     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
1318     snes->linear_its += lits;
1319     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
1320     /*
1321     if (vi->precheckstep) {
1322       PetscBool changed_y = PETSC_FALSE;
1323       ierr = (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);CHKERRQ(ierr);
1324     }
1325 
1326     if (PetscLogPrintInfo){
1327       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
1328     }
1329     */
1330     /* Compute a (scaled) negative update in the line search routine:
1331          Y <- X - lambda*Y
1332        and evaluate G = function(Y) (depends on the line search).
1333     */
1334     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
1335     ynorm = 1; gnorm = fnorm;
1336     ierr = (*vi->LineSearch)(snes,vi->lsP,X,F,Y,fnorm,xnorm,G,W,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
1337     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr);
1338     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
1339     if (snes->domainerror) {
1340       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
1341       ierr = DMDestroyVI(snes->dm);CHKERRQ(ierr);
1342       PetscFunctionReturn(0);
1343     }
1344     if (!lssucceed) {
1345       if (++snes->numFailures >= snes->maxFailures) {
1346 	PetscBool ismin;
1347         snes->reason = SNES_DIVERGED_LINE_SEARCH;
1348         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
1349         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
1350         break;
1351       }
1352     }
1353     /* Update function and solution vectors */
1354     fnorm = gnorm;
1355     ierr = VecCopy(G,F);CHKERRQ(ierr);
1356     ierr = VecCopy(W,X);CHKERRQ(ierr);
1357     /* Monitor convergence */
1358     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
1359     snes->iter = i+1;
1360     snes->norm = fnorm;
1361     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
1362     SNESLogConvHistory(snes,snes->norm,lits);
1363     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
1364     /* Test for convergence, xnorm = || X || */
1365     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
1366     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
1367     if (snes->reason) break;
1368   }
1369   ierr = DMDestroyVI(snes->dm);CHKERRQ(ierr);
1370   if (i == maxits) {
1371     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
1372     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
1373   }
1374   PetscFunctionReturn(0);
1375 }
1376 
1377 #undef __FUNCT__
1378 #define __FUNCT__ "SNESVISetRedundancyCheck"
1379 PetscErrorCode SNESVISetRedundancyCheck(SNES snes,PetscErrorCode (*func)(SNES,IS,IS*,void*),void *ctx)
1380 {
1381   SNES_VI         *vi = (SNES_VI*)snes->data;
1382 
1383   PetscFunctionBegin;
1384   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
1385   vi->checkredundancy = func;
1386   vi->ctxP            = ctx;
1387   PetscFunctionReturn(0);
1388 }
1389 
1390 #if defined(PETSC_HAVE_MATLAB_ENGINE)
1391 #include <engine.h>
1392 #include <mex.h>
1393 typedef struct {char *funcname; mxArray *ctx;} SNESMatlabContext;
1394 
1395 #undef __FUNCT__
1396 #define __FUNCT__ "SNESVIRedundancyCheck_Matlab"
1397 PetscErrorCode SNESVIRedundancyCheck_Matlab(SNES snes,IS is_act,IS* is_redact,void* ctx)
1398 {
1399   PetscErrorCode      ierr;
1400   SNESMatlabContext   *sctx = (SNESMatlabContext*)ctx;
1401   int                 nlhs = 1, nrhs = 5;
1402   mxArray             *plhs[1], *prhs[5];
1403   long long int       l1 = 0, l2 = 0, ls = 0;
1404   PetscInt            *indices=PETSC_NULL;
1405 
1406   PetscFunctionBegin;
1407   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
1408   PetscValidHeaderSpecific(is_act,IS_CLASSID,2);
1409   PetscValidPointer(is_redact,3);
1410   PetscCheckSameComm(snes,1,is_act,2);
1411 
1412   /* Create IS for reduced active set of size 0, its size and indices will
1413    bet set by the Matlab function */
1414   ierr = ISCreateGeneral(((PetscObject)snes)->comm,0,indices,PETSC_OWN_POINTER,is_redact);CHKERRQ(ierr);
1415   /* call Matlab function in ctx */
1416   ierr = PetscMemcpy(&ls,&snes,sizeof(snes));CHKERRQ(ierr);
1417   ierr = PetscMemcpy(&l1,&is_act,sizeof(is_act));CHKERRQ(ierr);
1418   ierr = PetscMemcpy(&l2,is_redact,sizeof(is_act));CHKERRQ(ierr);
1419   prhs[0] = mxCreateDoubleScalar((double)ls);
1420   prhs[1] = mxCreateDoubleScalar((double)l1);
1421   prhs[2] = mxCreateDoubleScalar((double)l2);
1422   prhs[3] = mxCreateString(sctx->funcname);
1423   prhs[4] = sctx->ctx;
1424   ierr    = mexCallMATLAB(nlhs,plhs,nrhs,prhs,"PetscSNESVIRedundancyCheckInternal");CHKERRQ(ierr);
1425   ierr    = mxGetScalar(plhs[0]);CHKERRQ(ierr);
1426   mxDestroyArray(prhs[0]);
1427   mxDestroyArray(prhs[1]);
1428   mxDestroyArray(prhs[2]);
1429   mxDestroyArray(prhs[3]);
1430   mxDestroyArray(plhs[0]);
1431   PetscFunctionReturn(0);
1432 }
1433 
1434 #undef __FUNCT__
1435 #define __FUNCT__ "SNESVISetRedundancyCheckMatlab"
1436 PetscErrorCode SNESVISetRedundancyCheckMatlab(SNES snes,const char* func,mxArray* ctx)
1437 {
1438   PetscErrorCode      ierr;
1439   SNESMatlabContext   *sctx;
1440 
1441   PetscFunctionBegin;
1442   /* currently sctx is memory bleed */
1443   ierr = PetscMalloc(sizeof(SNESMatlabContext),&sctx);CHKERRQ(ierr);
1444   ierr = PetscStrallocpy(func,&sctx->funcname);CHKERRQ(ierr);
1445   sctx->ctx = mxDuplicateArray(ctx);
1446   ierr = SNESVISetRedundancyCheck(snes,SNESVIRedundancyCheck_Matlab,sctx);CHKERRQ(ierr);
1447   PetscFunctionReturn(0);
1448 }
1449 
1450 #endif
1451 
1452 
1453 /* Variational Inequality solver using augmented space method. It does the opposite of the
1454    reduced space method i.e. it identifies the active set variables and instead of discarding
1455    them it augments the original system by introducing additional equality
1456    constraint equations for active set variables. The user can optionally provide an IS for
1457    a subset of 'redundant' active set variables which will treated as free variables.
1458    Specific implementation for Allen-Cahn problem
1459 */
1460 #undef __FUNCT__
1461 #define __FUNCT__ "SNESSolveVI_RSAUG"
1462 PetscErrorCode SNESSolveVI_RSAUG(SNES snes)
1463 {
1464   SNES_VI          *vi = (SNES_VI*)snes->data;
1465   PetscErrorCode    ierr;
1466   PetscInt          maxits,i,lits;
1467   PetscBool         lssucceed;
1468   MatStructure      flg = DIFFERENT_NONZERO_PATTERN;
1469   PetscReal         fnorm,gnorm,xnorm=0,ynorm;
1470   Vec                Y,X,F,G,W;
1471   KSPConvergedReason kspreason;
1472 
1473   PetscFunctionBegin;
1474   snes->numFailures            = 0;
1475   snes->numLinearSolveFailures = 0;
1476   snes->reason                 = SNES_CONVERGED_ITERATING;
1477 
1478   maxits	= snes->max_its;	/* maximum number of iterations */
1479   X		= snes->vec_sol;	/* solution vector */
1480   F		= snes->vec_func;	/* residual vector */
1481   Y		= snes->work[0];	/* work vectors */
1482   G		= snes->work[1];
1483   W		= snes->work[2];
1484 
1485   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
1486   snes->iter = 0;
1487   snes->norm = 0.0;
1488   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
1489 
1490   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
1491   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
1492   if (snes->domainerror) {
1493     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
1494     PetscFunctionReturn(0);
1495   }
1496   ierr = SNESVIComputeInactiveSetFnorm(snes,F,X,&fnorm);CHKERRQ(ierr);
1497   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
1498   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
1499   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1500 
1501   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
1502   snes->norm = fnorm;
1503   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
1504   SNESLogConvHistory(snes,fnorm,0);
1505   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
1506 
1507   /* set parameter for default relative tolerance convergence test */
1508   snes->ttol = fnorm*snes->rtol;
1509   /* test convergence */
1510   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
1511   if (snes->reason) PetscFunctionReturn(0);
1512 
1513   for (i=0; i<maxits; i++) {
1514     IS             IS_act,IS_inact; /* _act -> active set _inact -> inactive set */
1515     IS             IS_redact; /* redundant active set */
1516     Mat            J_aug,Jpre_aug;
1517     Vec            F_aug,Y_aug;
1518     PetscInt       nis_redact,nis_act;
1519     const PetscInt *idx_redact,*idx_act;
1520     PetscInt       k;
1521     PetscInt       *idx_actkept=PETSC_NULL,nkept=0; /* list of kept active set */
1522     PetscScalar    *f,*f2;
1523     PetscBool      isequal;
1524     PetscInt       i1=0,j1=0;
1525 
1526     /* Call general purpose update function */
1527     if (snes->ops->update) {
1528       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
1529     }
1530     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
1531 
1532     /* Create active and inactive index sets */
1533     ierr = SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&IS_inact);CHKERRQ(ierr);
1534 
1535     /* Get local active set size */
1536     ierr = ISGetLocalSize(IS_act,&nis_act);CHKERRQ(ierr);
1537     if (nis_act) {
1538       ierr = ISGetIndices(IS_act,&idx_act);CHKERRQ(ierr);
1539       IS_redact  = PETSC_NULL;
1540       if(vi->checkredundancy) {
1541 	(*vi->checkredundancy)(snes,IS_act,&IS_redact,vi->ctxP);
1542       }
1543 
1544       if(!IS_redact) {
1545 	/* User called checkredundancy function but didn't create IS_redact because
1546            there were no redundant active set variables */
1547 	/* Copy over all active set indices to the list */
1548 	ierr = PetscMalloc(nis_act*sizeof(PetscInt),&idx_actkept);CHKERRQ(ierr);
1549 	for(k=0;k < nis_act;k++) idx_actkept[k] = idx_act[k];
1550 	nkept = nis_act;
1551       } else {
1552 	ierr = ISGetLocalSize(IS_redact,&nis_redact);CHKERRQ(ierr);
1553 	ierr = PetscMalloc((nis_act-nis_redact)*sizeof(PetscInt),&idx_actkept);CHKERRQ(ierr);
1554 
1555 	/* Create reduced active set list */
1556 	ierr = ISGetIndices(IS_act,&idx_act);CHKERRQ(ierr);
1557 	ierr = ISGetIndices(IS_redact,&idx_redact);CHKERRQ(ierr);
1558 	j1 = 0;nkept = 0;
1559 	for(k=0;k<nis_act;k++) {
1560 	  if(j1 < nis_redact && idx_act[k] == idx_redact[j1]) j1++;
1561 	  else idx_actkept[nkept++] = idx_act[k];
1562 	}
1563 	ierr = ISRestoreIndices(IS_act,&idx_act);CHKERRQ(ierr);
1564 	ierr = ISRestoreIndices(IS_redact,&idx_redact);CHKERRQ(ierr);
1565 
1566         ierr = ISDestroy(&IS_redact);CHKERRQ(ierr);
1567       }
1568 
1569       /* Create augmented F and Y */
1570       ierr = VecCreate(((PetscObject)snes)->comm,&F_aug);CHKERRQ(ierr);
1571       ierr = VecSetSizes(F_aug,F->map->n+nkept,PETSC_DECIDE);CHKERRQ(ierr);
1572       ierr = VecSetFromOptions(F_aug);CHKERRQ(ierr);
1573       ierr = VecDuplicate(F_aug,&Y_aug);CHKERRQ(ierr);
1574 
1575       /* Copy over F to F_aug in the first n locations */
1576       ierr = VecGetArray(F,&f);CHKERRQ(ierr);
1577       ierr = VecGetArray(F_aug,&f2);CHKERRQ(ierr);
1578       ierr = PetscMemcpy(f2,f,F->map->n*sizeof(PetscScalar));CHKERRQ(ierr);
1579       ierr = VecRestoreArray(F,&f);CHKERRQ(ierr);
1580       ierr = VecRestoreArray(F_aug,&f2);CHKERRQ(ierr);
1581 
1582       /* Create the augmented jacobian matrix */
1583       ierr = MatCreate(((PetscObject)snes)->comm,&J_aug);CHKERRQ(ierr);
1584       ierr = MatSetSizes(J_aug,X->map->n+nkept,X->map->n+nkept,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
1585       ierr = MatSetFromOptions(J_aug);CHKERRQ(ierr);
1586 
1587 
1588       { /* local vars */
1589       /* Preallocate augmented matrix and set values in it...Doing only sequential case first*/
1590       PetscInt          ncols;
1591       const PetscInt    *cols;
1592       const PetscScalar *vals;
1593       PetscScalar        value[2];
1594       PetscInt           row,col[2];
1595       PetscInt           *d_nnz;
1596       value[0] = 1.0; value[1] = 0.0;
1597       ierr = PetscMalloc((X->map->n+nkept)*sizeof(PetscInt),&d_nnz);CHKERRQ(ierr);
1598       ierr = PetscMemzero(d_nnz,(X->map->n+nkept)*sizeof(PetscInt));CHKERRQ(ierr);
1599       for(row=0;row<snes->jacobian->rmap->n;row++) {
1600         ierr = MatGetRow(snes->jacobian,row,&ncols,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
1601         d_nnz[row] += ncols;
1602         ierr = MatRestoreRow(snes->jacobian,row,&ncols,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
1603       }
1604 
1605       for(k=0;k<nkept;k++) {
1606         d_nnz[idx_actkept[k]] += 1;
1607         d_nnz[snes->jacobian->rmap->n+k] += 2;
1608       }
1609       ierr = MatSeqAIJSetPreallocation(J_aug,PETSC_NULL,d_nnz);CHKERRQ(ierr);
1610 
1611       ierr = PetscFree(d_nnz);CHKERRQ(ierr);
1612 
1613       /* Set the original jacobian matrix in J_aug */
1614       for(row=0;row<snes->jacobian->rmap->n;row++) {
1615 	ierr = MatGetRow(snes->jacobian,row,&ncols,&cols,&vals);CHKERRQ(ierr);
1616 	ierr = MatSetValues(J_aug,1,&row,ncols,cols,vals,INSERT_VALUES);CHKERRQ(ierr);
1617 	ierr = MatRestoreRow(snes->jacobian,row,&ncols,&cols,&vals);CHKERRQ(ierr);
1618       }
1619       /* Add the augmented part */
1620       for(k=0;k<nkept;k++) {
1621 	row = snes->jacobian->rmap->n+k;
1622 	col[0] = idx_actkept[k]; col[1] = snes->jacobian->rmap->n+k;
1623 	ierr = MatSetValues(J_aug,1,&row,1,col,value,INSERT_VALUES);CHKERRQ(ierr);
1624 	ierr = MatSetValues(J_aug,1,&col[0],1,&row,&value[0],INSERT_VALUES);CHKERRQ(ierr);
1625       }
1626       ierr = MatAssemblyBegin(J_aug,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1627       ierr = MatAssemblyEnd(J_aug,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1628       /* Only considering prejac = jac for now */
1629       Jpre_aug = J_aug;
1630       } /* local vars*/
1631       ierr = ISRestoreIndices(IS_act,&idx_act);CHKERRQ(ierr);
1632       ierr = ISDestroy(&IS_act);CHKERRQ(ierr);
1633     } else {
1634       F_aug = F; J_aug = snes->jacobian; Y_aug = Y; Jpre_aug = snes->jacobian_pre;
1635     }
1636 
1637     ierr = ISEqual(vi->IS_inact_prev,IS_inact,&isequal);CHKERRQ(ierr);
1638     if (!isequal) {
1639       ierr = SNESVIResetPCandKSP(snes,J_aug,Jpre_aug);CHKERRQ(ierr);
1640     }
1641     ierr = KSPSetOperators(snes->ksp,J_aug,Jpre_aug,flg);CHKERRQ(ierr);
1642     ierr = KSPSetUp(snes->ksp);CHKERRQ(ierr);
1643     /*  {
1644       PC        pc;
1645       PetscBool flg;
1646       ierr = KSPGetPC(snes->ksp,&pc);CHKERRQ(ierr);
1647       ierr = PetscTypeCompare((PetscObject)pc,PCFIELDSPLIT,&flg);CHKERRQ(ierr);
1648       if (flg) {
1649         KSP      *subksps;
1650         ierr = PCFieldSplitGetSubKSP(pc,PETSC_NULL,&subksps);CHKERRQ(ierr);
1651         ierr = KSPGetPC(subksps[0],&pc);CHKERRQ(ierr);
1652         ierr = PetscFree(subksps);CHKERRQ(ierr);
1653         ierr = PetscTypeCompare((PetscObject)pc,PCBJACOBI,&flg);CHKERRQ(ierr);
1654         if (flg) {
1655           PetscInt       n,N = 101*101,j,cnts[3] = {0,0,0};
1656           const PetscInt *ii;
1657 
1658           ierr = ISGetSize(IS_inact,&n);CHKERRQ(ierr);
1659           ierr = ISGetIndices(IS_inact,&ii);CHKERRQ(ierr);
1660           for (j=0; j<n; j++) {
1661             if (ii[j] < N) cnts[0]++;
1662             else if (ii[j] < 2*N) cnts[1]++;
1663             else if (ii[j] < 3*N) cnts[2]++;
1664           }
1665           ierr = ISRestoreIndices(IS_inact,&ii);CHKERRQ(ierr);
1666 
1667           ierr = PCBJacobiSetTotalBlocks(pc,3,cnts);CHKERRQ(ierr);
1668         }
1669       }
1670     }
1671     */
1672     ierr = SNES_KSPSolve(snes,snes->ksp,F_aug,Y_aug);CHKERRQ(ierr);
1673     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
1674     if (kspreason < 0) {
1675       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
1676         ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
1677         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
1678         break;
1679       }
1680     }
1681 
1682     if(nis_act) {
1683       PetscScalar *y1,*y2;
1684       ierr = VecGetArray(Y,&y1);CHKERRQ(ierr);
1685       ierr = VecGetArray(Y_aug,&y2);CHKERRQ(ierr);
1686       /* Copy over inactive Y_aug to Y */
1687       j1 = 0;
1688       for(i1=Y->map->rstart;i1 < Y->map->rend;i1++) {
1689 	if(j1 < nkept && idx_actkept[j1] == i1) j1++;
1690 	else y1[i1-Y->map->rstart] = y2[i1-Y->map->rstart];
1691       }
1692       ierr = VecRestoreArray(Y,&y1);CHKERRQ(ierr);
1693       ierr = VecRestoreArray(Y_aug,&y2);CHKERRQ(ierr);
1694 
1695       ierr = VecDestroy(&F_aug);CHKERRQ(ierr);
1696       ierr = VecDestroy(&Y_aug);CHKERRQ(ierr);
1697       ierr = MatDestroy(&J_aug);CHKERRQ(ierr);
1698       ierr = PetscFree(idx_actkept);CHKERRQ(ierr);
1699     }
1700 
1701     if (!isequal) {
1702       ierr = ISDestroy(&vi->IS_inact_prev);CHKERRQ(ierr);
1703       ierr = ISDuplicate(IS_inact,&vi->IS_inact_prev);CHKERRQ(ierr);
1704     }
1705     ierr = ISDestroy(&IS_inact);CHKERRQ(ierr);
1706 
1707     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
1708     snes->linear_its += lits;
1709     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
1710     /*
1711     if (vi->precheckstep) {
1712       PetscBool changed_y = PETSC_FALSE;
1713       ierr = (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);CHKERRQ(ierr);
1714     }
1715 
1716     if (PetscLogPrintInfo){
1717       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
1718     }
1719     */
1720     /* Compute a (scaled) negative update in the line search routine:
1721          Y <- X - lambda*Y
1722        and evaluate G = function(Y) (depends on the line search).
1723     */
1724     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
1725     ynorm = 1; gnorm = fnorm;
1726     ierr = (*vi->LineSearch)(snes,vi->lsP,X,F,Y,fnorm,xnorm,G,W,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
1727     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr);
1728     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
1729     if (snes->domainerror) {
1730       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
1731       PetscFunctionReturn(0);
1732     }
1733     if (!lssucceed) {
1734       if (++snes->numFailures >= snes->maxFailures) {
1735 	PetscBool ismin;
1736         snes->reason = SNES_DIVERGED_LINE_SEARCH;
1737         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
1738         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
1739         break;
1740       }
1741     }
1742     /* Update function and solution vectors */
1743     fnorm = gnorm;
1744     ierr = VecCopy(G,F);CHKERRQ(ierr);
1745     ierr = VecCopy(W,X);CHKERRQ(ierr);
1746     /* Monitor convergence */
1747     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
1748     snes->iter = i+1;
1749     snes->norm = fnorm;
1750     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
1751     SNESLogConvHistory(snes,snes->norm,lits);
1752     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
1753     /* Test for convergence, xnorm = || X || */
1754     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
1755     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
1756     if (snes->reason) break;
1757   }
1758   if (i == maxits) {
1759     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
1760     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
1761   }
1762   PetscFunctionReturn(0);
1763 }
1764 
1765 /* -------------------------------------------------------------------------- */
1766 /*
1767    SNESSetUp_VI - Sets up the internal data structures for the later use
1768    of the SNESVI nonlinear solver.
1769 
1770    Input Parameter:
1771 .  snes - the SNES context
1772 .  x - the solution vector
1773 
1774    Application Interface Routine: SNESSetUp()
1775 
1776    Notes:
1777    For basic use of the SNES solvers, the user need not explicitly call
1778    SNESSetUp(), since these actions will automatically occur during
1779    the call to SNESSolve().
1780  */
1781 #undef __FUNCT__
1782 #define __FUNCT__ "SNESSetUp_VI"
1783 PetscErrorCode SNESSetUp_VI(SNES snes)
1784 {
1785   PetscErrorCode ierr;
1786   SNES_VI        *vi = (SNES_VI*) snes->data;
1787   PetscInt       i_start[3],i_end[3];
1788 
1789   PetscFunctionBegin;
1790 
1791   ierr = SNESDefaultGetWork(snes,3);CHKERRQ(ierr);
1792 
1793   if (vi->computevariablebounds) {
1794     if (!vi->xl) {ierr = VecDuplicate(snes->vec_sol,&vi->xl);CHKERRQ(ierr);}
1795     if (!vi->xu) {ierr = VecDuplicate(snes->vec_sol,&vi->xu);CHKERRQ(ierr);}
1796     ierr = (*vi->computevariablebounds)(snes,vi->xl,vi->xu);CHKERRQ(ierr);
1797   } else if (!vi->xl && !vi->xu) {
1798     /* If the lower and upper bound on variables are not set, set it to -Inf and Inf */
1799     ierr = VecDuplicate(snes->vec_sol, &vi->xl);CHKERRQ(ierr);
1800     ierr = VecSet(vi->xl,SNES_VI_NINF);CHKERRQ(ierr);
1801     ierr = VecDuplicate(snes->vec_sol, &vi->xu);CHKERRQ(ierr);
1802     ierr = VecSet(vi->xu,SNES_VI_INF);CHKERRQ(ierr);
1803   } else {
1804     /* Check if lower bound, upper bound and solution vector distribution across the processors is identical */
1805     ierr = VecGetOwnershipRange(snes->vec_sol,i_start,i_end);CHKERRQ(ierr);
1806     ierr = VecGetOwnershipRange(vi->xl,i_start+1,i_end+1);CHKERRQ(ierr);
1807     ierr = VecGetOwnershipRange(vi->xu,i_start+2,i_end+2);CHKERRQ(ierr);
1808     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]))
1809       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.");
1810   }
1811   if (snes->ops->solve != SNESSolveVI_SS) {
1812     /* Set up previous active index set for the first snes solve
1813        vi->IS_inact_prev = 0,1,2,....N */
1814     PetscInt *indices;
1815     PetscInt  i,n,rstart,rend;
1816 
1817     ierr = VecGetOwnershipRange(snes->vec_sol,&rstart,&rend);CHKERRQ(ierr);
1818     ierr = VecGetLocalSize(snes->vec_sol,&n);CHKERRQ(ierr);
1819     ierr = PetscMalloc(n*sizeof(PetscInt),&indices);CHKERRQ(ierr);
1820     for(i=0;i < n; i++) indices[i] = rstart + i;
1821     ierr = ISCreateGeneral(((PetscObject)snes)->comm,n,indices,PETSC_OWN_POINTER,&vi->IS_inact_prev);
1822   }
1823 
1824   if (snes->ops->solve == SNESSolveVI_SS) {
1825     ierr = VecDuplicate(snes->vec_sol, &vi->dpsi);CHKERRQ(ierr);
1826     ierr = VecDuplicate(snes->vec_sol, &vi->phi);CHKERRQ(ierr);
1827     ierr = VecDuplicate(snes->vec_sol, &vi->Da);CHKERRQ(ierr);
1828     ierr = VecDuplicate(snes->vec_sol, &vi->Db);CHKERRQ(ierr);
1829     ierr = VecDuplicate(snes->vec_sol, &vi->z);CHKERRQ(ierr);
1830     ierr = VecDuplicate(snes->vec_sol, &vi->t);CHKERRQ(ierr);
1831   }
1832   PetscFunctionReturn(0);
1833 }
1834 /* -------------------------------------------------------------------------- */
1835 #undef __FUNCT__
1836 #define __FUNCT__ "SNESReset_VI"
1837 PetscErrorCode SNESReset_VI(SNES snes)
1838 {
1839   SNES_VI        *vi = (SNES_VI*) snes->data;
1840   PetscErrorCode ierr;
1841 
1842   PetscFunctionBegin;
1843   ierr = VecDestroy(&vi->xl);CHKERRQ(ierr);
1844   ierr = VecDestroy(&vi->xu);CHKERRQ(ierr);
1845   if (snes->ops->solve != SNESSolveVI_SS) {
1846     ierr = ISDestroy(&vi->IS_inact_prev);CHKERRQ(ierr);
1847   }
1848   PetscFunctionReturn(0);
1849 }
1850 
1851 /*
1852    SNESDestroy_VI - Destroys the private SNES_VI context that was created
1853    with SNESCreate_VI().
1854 
1855    Input Parameter:
1856 .  snes - the SNES context
1857 
1858    Application Interface Routine: SNESDestroy()
1859  */
1860 #undef __FUNCT__
1861 #define __FUNCT__ "SNESDestroy_VI"
1862 PetscErrorCode SNESDestroy_VI(SNES snes)
1863 {
1864   SNES_VI        *vi = (SNES_VI*) snes->data;
1865   PetscErrorCode ierr;
1866 
1867   PetscFunctionBegin;
1868 
1869   if (snes->ops->solve == SNESSolveVI_SS) {
1870     /* clear vectors */
1871     ierr = VecDestroy(&vi->dpsi);CHKERRQ(ierr);
1872     ierr = VecDestroy(&vi->phi);CHKERRQ(ierr);
1873     ierr = VecDestroy(&vi->Da);CHKERRQ(ierr);
1874     ierr = VecDestroy(&vi->Db);CHKERRQ(ierr);
1875     ierr = VecDestroy(&vi->z);CHKERRQ(ierr);
1876     ierr = VecDestroy(&vi->t);CHKERRQ(ierr);
1877   }
1878 
1879   ierr = PetscViewerDestroy(&vi->lsmonitor);CHKERRQ(ierr);
1880   ierr = PetscFree(snes->data);CHKERRQ(ierr);
1881 
1882   /* clear composed functions */
1883   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","",PETSC_NULL);CHKERRQ(ierr);
1884   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","",PETSC_NULL);CHKERRQ(ierr);
1885   PetscFunctionReturn(0);
1886 }
1887 
1888 /* -------------------------------------------------------------------------- */
1889 #undef __FUNCT__
1890 #define __FUNCT__ "SNESLineSearchNo_VI"
1891 
1892 /*
1893   This routine does not actually do a line search but it takes a full newton
1894   step while ensuring that the new iterates remain within the constraints.
1895 
1896 */
1897 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)
1898 {
1899   PetscErrorCode ierr;
1900   SNES_VI        *vi = (SNES_VI*)snes->data;
1901   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1902 
1903   PetscFunctionBegin;
1904   *flag = PETSC_TRUE;
1905   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1906   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);         /* ynorm = || y || */
1907   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
1908   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1909   if (vi->postcheckstep) {
1910    ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1911   }
1912   if (changed_y) {
1913     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
1914     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1915   }
1916   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1917   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1918   if (!snes->domainerror) {
1919     if (snes->ops->solve != SNESSolveVI_SS) {
1920        ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
1921     } else {
1922       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);  /* gnorm = || g || */
1923     }
1924     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1925   }
1926   if (vi->lsmonitor) {
1927     ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
1928     ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %g gnorm %g\n",(double)fnorm,(double)*gnorm);CHKERRQ(ierr);
1929     ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
1930   }
1931   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1932   PetscFunctionReturn(0);
1933 }
1934 
1935 /* -------------------------------------------------------------------------- */
1936 #undef __FUNCT__
1937 #define __FUNCT__ "SNESLineSearchNoNorms_VI"
1938 
1939 /*
1940   This routine is a copy of SNESLineSearchNoNorms in snes/impls/ls/ls.c
1941 */
1942 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)
1943 {
1944   PetscErrorCode ierr;
1945   SNES_VI        *vi = (SNES_VI*)snes->data;
1946   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1947 
1948   PetscFunctionBegin;
1949   *flag = PETSC_TRUE;
1950   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1951   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y      */
1952   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1953   if (vi->postcheckstep) {
1954    ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1955   }
1956   if (changed_y) {
1957     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
1958     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1959   }
1960 
1961   /* don't evaluate function the last time through */
1962   if (snes->iter < snes->max_its-1) {
1963     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1964   }
1965   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1966   PetscFunctionReturn(0);
1967 }
1968 
1969 /* -------------------------------------------------------------------------- */
1970 #undef __FUNCT__
1971 #define __FUNCT__ "SNESLineSearchCubic_VI"
1972 /*
1973   This routine implements a cubic line search while doing a projection on the variable bounds
1974 */
1975 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)
1976 {
1977   PetscReal      initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
1978   PetscReal      minlambda,lambda,lambdatemp;
1979 #if defined(PETSC_USE_COMPLEX)
1980   PetscScalar    cinitslope;
1981 #endif
1982   PetscErrorCode ierr;
1983   PetscInt       count;
1984   SNES_VI        *vi = (SNES_VI*)snes->data;
1985   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1986   MPI_Comm       comm;
1987 
1988   PetscFunctionBegin;
1989   ierr = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
1990   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1991   *flag   = PETSC_TRUE;
1992 
1993   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
1994   if (*ynorm == 0.0) {
1995     if (vi->lsmonitor) {
1996       ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
1997       ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Initial direction and size is 0\n");CHKERRQ(ierr);
1998       ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
1999     }
2000     *gnorm = fnorm;
2001     ierr   = VecCopy(x,w);CHKERRQ(ierr);
2002     ierr   = VecCopy(f,g);CHKERRQ(ierr);
2003     *flag  = PETSC_FALSE;
2004     goto theend1;
2005   }
2006   if (*ynorm > vi->maxstep) {	/* Step too big, so scale back */
2007     if (vi->lsmonitor) {
2008       ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2009       ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Scaling step by %g old ynorm %g\n",(double)vi->maxstep/(*ynorm),(double)*ynorm);CHKERRQ(ierr);
2010       ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2011     }
2012     ierr = VecScale(y,vi->maxstep/(*ynorm));CHKERRQ(ierr);
2013     *ynorm = vi->maxstep;
2014   }
2015   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
2016   minlambda = vi->minlambda/rellength;
2017   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
2018 #if defined(PETSC_USE_COMPLEX)
2019   ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
2020   initslope = PetscRealPart(cinitslope);
2021 #else
2022   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
2023 #endif
2024   if (initslope > 0.0)  initslope = -initslope;
2025   if (initslope == 0.0) initslope = -1.0;
2026 
2027   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
2028   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
2029   if (snes->nfuncs >= snes->max_funcs) {
2030     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
2031     *flag = PETSC_FALSE;
2032     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
2033     goto theend1;
2034   }
2035   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
2036   if (snes->ops->solve != SNESSolveVI_SS) {
2037     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
2038   } else {
2039     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
2040   }
2041   if (snes->domainerror) {
2042     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2043     PetscFunctionReturn(0);
2044   }
2045   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2046   ierr = PetscInfo4(snes,"Initial fnorm %g gnorm %g alpha %g initslope %g\n",(double)fnorm,(double)*gnorm,(double)vi->alpha,(double)initslope);CHKERRQ(ierr);
2047   if ((*gnorm)*(*gnorm) <= (1.0 - vi->alpha)*fnorm*fnorm ) { /* Sufficient reduction */
2048     if (vi->lsmonitor) {
2049       ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2050       ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %g gnorm %g\n",(double)fnorm,(double)*gnorm);CHKERRQ(ierr);
2051       ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2052     }
2053     goto theend1;
2054   }
2055 
2056   /* Fit points with quadratic */
2057   lambda     = 1.0;
2058   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
2059   lambdaprev = lambda;
2060   gnormprev  = *gnorm;
2061   if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
2062   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
2063   else                         lambda = lambdatemp;
2064 
2065   ierr  = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
2066   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
2067   if (snes->nfuncs >= snes->max_funcs) {
2068     ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);CHKERRQ(ierr);
2069     *flag = PETSC_FALSE;
2070     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
2071     goto theend1;
2072   }
2073   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
2074   if (snes->ops->solve != SNESSolveVI_SS) {
2075     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
2076   } else {
2077     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
2078   }
2079   if (snes->domainerror) {
2080     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2081     PetscFunctionReturn(0);
2082   }
2083   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2084   if (vi->lsmonitor) {
2085     ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2086     ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: gnorm after quadratic fit %g\n",(double)*gnorm);CHKERRQ(ierr);
2087     ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2088   }
2089   if ((*gnorm)*(*gnorm) < (1.0 - vi->alpha)*fnorm*fnorm ) { /* sufficient reduction */
2090     if (vi->lsmonitor) {
2091       ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2092       ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Quadratically determined step, lambda=%18.16e\n",lambda);CHKERRQ(ierr);
2093       ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2094     }
2095     goto theend1;
2096   }
2097 
2098   /* Fit points with cubic */
2099   count = 1;
2100   while (PETSC_TRUE) {
2101     if (lambda <= minlambda) {
2102       if (vi->lsmonitor) {
2103         ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2104  	ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: unable to find good step length! After %D tries \n",count);CHKERRQ(ierr);
2105 	ierr = PetscViewerASCIIPrintf(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);
2106         ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2107       }
2108       *flag = PETSC_FALSE;
2109       break;
2110     }
2111     t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
2112     t2 = .5*(gnormprev*gnormprev  - fnorm*fnorm) - lambdaprev*initslope;
2113     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2114     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2115     d  = b*b - 3*a*initslope;
2116     if (d < 0.0) d = 0.0;
2117     if (a == 0.0) {
2118       lambdatemp = -initslope/(2.0*b);
2119     } else {
2120       lambdatemp = (-b + sqrt(d))/(3.0*a);
2121     }
2122     lambdaprev = lambda;
2123     gnormprev  = *gnorm;
2124     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
2125     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
2126     else                         lambda     = lambdatemp;
2127     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
2128     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
2129     if (snes->nfuncs >= snes->max_funcs) {
2130       ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
2131       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);
2132       *flag = PETSC_FALSE;
2133       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
2134       break;
2135     }
2136     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
2137     if (snes->ops->solve != SNESSolveVI_SS) {
2138       ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
2139     } else {
2140       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
2141     }
2142     if (snes->domainerror) {
2143       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2144       PetscFunctionReturn(0);
2145     }
2146     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2147     if ((*gnorm)*(*gnorm) < (1.0 - vi->alpha)*fnorm*fnorm) { /* is reduction enough? */
2148       if (vi->lsmonitor) {
2149 	ierr = PetscPrintf(comm,"    Line search: Cubically determined step, current gnorm %g lambda=%18.16e\n",(double)*gnorm,(double)lambda);CHKERRQ(ierr);
2150       }
2151       break;
2152     } else {
2153       if (vi->lsmonitor) {
2154         ierr = PetscPrintf(comm,"    Line search: Cubic step no good, shrinking lambda, current gnorm %g lambda=%18.16e\n",(double)*gnorm,(double)lambda);CHKERRQ(ierr);
2155       }
2156     }
2157     count++;
2158   }
2159   theend1:
2160   /* Optional user-defined check for line search step validity */
2161   if (vi->postcheckstep && *flag) {
2162     ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
2163     if (changed_y) {
2164       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
2165       ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
2166     }
2167     if (changed_y || changed_w) { /* recompute the function if the step has changed */
2168       ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
2169       if (snes->ops->solve != SNESSolveVI_SS) {
2170         ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
2171       } else {
2172         ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
2173       }
2174       if (snes->domainerror) {
2175         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2176         PetscFunctionReturn(0);
2177       }
2178       if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2179       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
2180       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
2181     }
2182   }
2183   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2184   PetscFunctionReturn(0);
2185 }
2186 
2187 #undef __FUNCT__
2188 #define __FUNCT__ "SNESLineSearchQuadratic_VI"
2189 /*
2190   This routine does a quadratic line search while keeping the iterates within the variable bounds
2191 */
2192 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)
2193 {
2194   /*
2195      Note that for line search purposes we work with with the related
2196      minimization problem:
2197         min  z(x):  R^n -> R,
2198      where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
2199    */
2200   PetscReal      initslope,minlambda,lambda,lambdatemp,rellength;
2201 #if defined(PETSC_USE_COMPLEX)
2202   PetscScalar    cinitslope;
2203 #endif
2204   PetscErrorCode ierr;
2205   PetscInt       count;
2206   SNES_VI        *vi = (SNES_VI*)snes->data;
2207   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
2208 
2209   PetscFunctionBegin;
2210   ierr    = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2211   *flag   = PETSC_TRUE;
2212 
2213   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
2214   if (*ynorm == 0.0) {
2215     if (vi->lsmonitor) {
2216       ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2217       ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"Line search: Direction and size is 0\n");CHKERRQ(ierr);
2218       ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2219     }
2220     *gnorm = fnorm;
2221     ierr   = VecCopy(x,w);CHKERRQ(ierr);
2222     ierr   = VecCopy(f,g);CHKERRQ(ierr);
2223     *flag  = PETSC_FALSE;
2224     goto theend2;
2225   }
2226   if (*ynorm > vi->maxstep) {	/* Step too big, so scale back */
2227     ierr   = VecScale(y,vi->maxstep/(*ynorm));CHKERRQ(ierr);
2228     *ynorm = vi->maxstep;
2229   }
2230   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
2231   minlambda = vi->minlambda/rellength;
2232   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
2233 #if defined(PETSC_USE_COMPLEX)
2234   ierr      = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
2235   initslope = PetscRealPart(cinitslope);
2236 #else
2237   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
2238 #endif
2239   if (initslope > 0.0)  initslope = -initslope;
2240   if (initslope == 0.0) initslope = -1.0;
2241   ierr = PetscInfo1(snes,"Initslope %G \n",initslope);CHKERRQ(ierr);
2242 
2243   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
2244   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
2245   if (snes->nfuncs >= snes->max_funcs) {
2246     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
2247     *flag = PETSC_FALSE;
2248     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
2249     goto theend2;
2250   }
2251   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
2252   if (snes->ops->solve != SNESSolveVI_SS) {
2253     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
2254   } else {
2255     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
2256   }
2257   if (snes->domainerror) {
2258     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2259     PetscFunctionReturn(0);
2260   }
2261   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2262   if ((*gnorm)*(*gnorm) <= (1.0 - vi->alpha)*fnorm*fnorm) { /* Sufficient reduction */
2263     if (vi->lsmonitor) {
2264       ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2265       ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
2266       ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2267     }
2268     goto theend2;
2269   }
2270 
2271   /* Fit points with quadratic */
2272   lambda = 1.0;
2273   count = 1;
2274   while (PETSC_TRUE) {
2275     if (lambda <= minlambda) { /* bad luck; use full step */
2276       if (vi->lsmonitor) {
2277         ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2278         ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"Line search: Unable to find good step length! %D \n",count);CHKERRQ(ierr);
2279         ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"Line search: fnorm=%G, gnorm=%G, ynorm=%G, lambda=%G, initial slope=%G\n",fnorm,*gnorm,*ynorm,lambda,initslope);CHKERRQ(ierr);
2280         ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2281       }
2282       ierr = VecCopy(x,w);CHKERRQ(ierr);
2283       *flag = PETSC_FALSE;
2284       break;
2285     }
2286     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
2287     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
2288     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
2289     else                         lambda     = lambdatemp;
2290 
2291     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
2292     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
2293     if (snes->nfuncs >= snes->max_funcs) {
2294       ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
2295       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);
2296       *flag = PETSC_FALSE;
2297       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
2298       break;
2299     }
2300     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
2301     if (snes->domainerror) {
2302       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2303       PetscFunctionReturn(0);
2304     }
2305     if (snes->ops->solve != SNESSolveVI_SS) {
2306       ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
2307     } else {
2308       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
2309     }
2310     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2311     if ((*gnorm)*(*gnorm) < (1.0 - vi->alpha)*fnorm*fnorm) { /* sufficient reduction */
2312       if (vi->lsmonitor) {
2313         ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2314         ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line Search: Quadratically determined step, lambda=%G\n",lambda);CHKERRQ(ierr);
2315         ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2316       }
2317       break;
2318     }
2319     count++;
2320   }
2321   theend2:
2322   /* Optional user-defined check for line search step validity */
2323   if (vi->postcheckstep) {
2324     ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
2325     if (changed_y) {
2326       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
2327       ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
2328     }
2329     if (changed_y || changed_w) { /* recompute the function if the step has changed */
2330       ierr = SNESComputeFunction(snes,w,g);
2331       if (snes->domainerror) {
2332         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2333         PetscFunctionReturn(0);
2334       }
2335       if (snes->ops->solve != SNESSolveVI_SS) {
2336         ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
2337       } else {
2338         ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
2339       }
2340 
2341       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
2342       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
2343       if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2344     }
2345   }
2346   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2347   PetscFunctionReturn(0);
2348 }
2349 
2350 typedef PetscErrorCode (*FCN2)(SNES,void*,Vec,Vec,Vec,PetscReal,PetscReal,Vec,Vec,PetscReal*,PetscReal*,PetscBool*); /* force argument to next function to not be extern C*/
2351 /* -------------------------------------------------------------------------- */
2352 EXTERN_C_BEGIN
2353 #undef __FUNCT__
2354 #define __FUNCT__ "SNESLineSearchSet_VI"
2355 PetscErrorCode  SNESLineSearchSet_VI(SNES snes,FCN2 func,void *lsctx)
2356 {
2357   PetscFunctionBegin;
2358   ((SNES_VI *)(snes->data))->LineSearch = func;
2359   ((SNES_VI *)(snes->data))->lsP        = lsctx;
2360   PetscFunctionReturn(0);
2361 }
2362 EXTERN_C_END
2363 
2364 /* -------------------------------------------------------------------------- */
2365 EXTERN_C_BEGIN
2366 #undef __FUNCT__
2367 #define __FUNCT__ "SNESLineSearchSetMonitor_VI"
2368 PetscErrorCode  SNESLineSearchSetMonitor_VI(SNES snes,PetscBool flg)
2369 {
2370   SNES_VI        *vi = (SNES_VI*)snes->data;
2371   PetscErrorCode ierr;
2372 
2373   PetscFunctionBegin;
2374   if (flg && !vi->lsmonitor) {
2375     ierr = PetscViewerASCIIOpen(((PetscObject)snes)->comm,"stdout",&vi->lsmonitor);CHKERRQ(ierr);
2376   } else if (!flg && vi->lsmonitor) {
2377     ierr = PetscViewerDestroy(&vi->lsmonitor);CHKERRQ(ierr);
2378   }
2379   PetscFunctionReturn(0);
2380 }
2381 EXTERN_C_END
2382 
2383 /*
2384    SNESView_VI - Prints info from the SNESVI data structure.
2385 
2386    Input Parameters:
2387 .  SNES - the SNES context
2388 .  viewer - visualization context
2389 
2390    Application Interface Routine: SNESView()
2391 */
2392 #undef __FUNCT__
2393 #define __FUNCT__ "SNESView_VI"
2394 static PetscErrorCode SNESView_VI(SNES snes,PetscViewer viewer)
2395 {
2396   SNES_VI        *vi = (SNES_VI *)snes->data;
2397   const char     *cstr,*tstr;
2398   PetscErrorCode ierr;
2399   PetscBool     iascii;
2400 
2401   PetscFunctionBegin;
2402   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
2403   if (iascii) {
2404     if (vi->LineSearch == SNESLineSearchNo_VI)             cstr = "SNESLineSearchNo";
2405     else if (vi->LineSearch == SNESLineSearchQuadratic_VI) cstr = "SNESLineSearchQuadratic";
2406     else if (vi->LineSearch == SNESLineSearchCubic_VI)     cstr = "SNESLineSearchCubic";
2407     else                                                   cstr = "unknown";
2408     if (snes->ops->solve == SNESSolveVI_SS)         tstr = "Semismooth";
2409     else if (snes->ops->solve == SNESSolveVI_RS)    tstr = "Reduced Space";
2410     else if (snes->ops->solve == SNESSolveVI_RSAUG) tstr = "Reduced space with augmented variables";
2411     else                                         tstr = "unknown";
2412     ierr = PetscViewerASCIIPrintf(viewer,"  VI algorithm: %s\n",tstr);CHKERRQ(ierr);
2413     ierr = PetscViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);CHKERRQ(ierr);
2414     ierr = PetscViewerASCIIPrintf(viewer,"  alpha=%G, maxstep=%G, minlambda=%G\n",vi->alpha,vi->maxstep,vi->minlambda);CHKERRQ(ierr);
2415   }
2416   PetscFunctionReturn(0);
2417 }
2418 
2419 #undef __FUNCT__
2420 #define __FUNCT__ "SNESVISetVariableBounds"
2421 /*@
2422    SNESVISetVariableBounds - Sets the lower and upper bounds for the solution vector. xl <= x <= xu.
2423 
2424    Input Parameters:
2425 .  snes - the SNES context.
2426 .  xl   - lower bound.
2427 .  xu   - upper bound.
2428 
2429    Notes:
2430    If this routine is not called then the lower and upper bounds are set to
2431    SNES_VI_INF and SNES_VI_NINF respectively during SNESSetUp().
2432 
2433    Level: advanced
2434 
2435 @*/
2436 PetscErrorCode SNESVISetVariableBounds(SNES snes, Vec xl, Vec xu)
2437 {
2438   SNES_VI           *vi;
2439   PetscErrorCode    ierr;
2440   const PetscScalar *xxl,*xxu;
2441   PetscInt          i,n, cnt = 0;
2442 
2443   PetscFunctionBegin;
2444   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
2445   PetscValidHeaderSpecific(xl,VEC_CLASSID,2);
2446   PetscValidHeaderSpecific(xu,VEC_CLASSID,3);
2447   if (!snes->vec_func) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call SNESSetFunction() first");
2448   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);
2449   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);
2450   ierr = SNESSetType(snes,SNESVI);CHKERRQ(ierr);
2451   vi = (SNES_VI*)snes->data;
2452   ierr = PetscObjectReference((PetscObject)xl);CHKERRQ(ierr);
2453   ierr = PetscObjectReference((PetscObject)xu);CHKERRQ(ierr);
2454   ierr = VecDestroy(&vi->xl);CHKERRQ(ierr);
2455   ierr = VecDestroy(&vi->xu);CHKERRQ(ierr);
2456   vi->xl = xl;
2457   vi->xu = xu;
2458   ierr = VecGetLocalSize(xl,&n);CHKERRQ(ierr);
2459   ierr = VecGetArrayRead(xl,&xxl);CHKERRQ(ierr);
2460   ierr = VecGetArrayRead(xu,&xxu);CHKERRQ(ierr);
2461   for (i=0; i<n; i++) {
2462     cnt += ((xxl[i] != SNES_VI_NINF) || (xxu[i] != SNES_VI_INF));
2463   }
2464   ierr = MPI_Allreduce(&cnt,&vi->ntruebounds,1,MPIU_INT,MPI_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
2465   ierr = VecRestoreArrayRead(xl,&xxl);CHKERRQ(ierr);
2466   ierr = VecRestoreArrayRead(xu,&xxu);CHKERRQ(ierr);
2467   PetscFunctionReturn(0);
2468 }
2469 
2470 /* -------------------------------------------------------------------------- */
2471 /*
2472    SNESSetFromOptions_VI - Sets various parameters for the SNESVI method.
2473 
2474    Input Parameter:
2475 .  snes - the SNES context
2476 
2477    Application Interface Routine: SNESSetFromOptions()
2478 */
2479 #undef __FUNCT__
2480 #define __FUNCT__ "SNESSetFromOptions_VI"
2481 static PetscErrorCode SNESSetFromOptions_VI(SNES snes)
2482 {
2483   SNES_VI            *vi = (SNES_VI *)snes->data;
2484   const char         *vies[] = {"ss","rs","rsaug"};
2485   PetscErrorCode     ierr;
2486   PetscInt           indx;
2487   SNESLineSearchType inds;
2488   PetscBool          flg,set,flg2;
2489 
2490   PetscFunctionBegin;
2491   ierr = PetscOptionsHead("SNES semismooth method options");CHKERRQ(ierr);
2492   ierr = PetscOptionsBool("-snes_vi_monitor","Monitor all non-active variables","None",PETSC_FALSE,&flg,0);CHKERRQ(ierr);
2493   if (flg) {
2494     ierr = SNESMonitorSet(snes,SNESMonitorVI,0,0);CHKERRQ(ierr);
2495   }
2496   ierr = PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",vi->alpha,&vi->alpha,0);CHKERRQ(ierr);
2497   ierr = PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",vi->maxstep,&vi->maxstep,0);CHKERRQ(ierr);
2498   ierr = PetscOptionsReal("-snes_ls_minlambda","Minimum lambda allowed","None",vi->minlambda,&vi->minlambda,0);CHKERRQ(ierr);
2499   ierr = PetscOptionsReal("-snes_vi_const_tol","constraint tolerance","None",vi->const_tol,&vi->const_tol,0);CHKERRQ(ierr);
2500   ierr = PetscOptionsBool("-snes_ls_monitor","Print progress of line searches","SNESLineSearchSetMonitor",vi->lsmonitor ? PETSC_TRUE : PETSC_FALSE,&flg,&set);CHKERRQ(ierr);
2501   if (set) {ierr = SNESLineSearchSetMonitor(snes,flg);CHKERRQ(ierr);}
2502   ierr = PetscOptionsEList("-snes_vi_type","Semismooth algorithm used","",vies,3,"rs",&indx,&flg2);CHKERRQ(ierr);
2503   if (flg2) {
2504     switch (indx) {
2505     case 0:
2506       snes->ops->solve = SNESSolveVI_SS;
2507       break;
2508     case 1:
2509       snes->ops->solve = SNESSolveVI_RS;
2510       break;
2511     case 2:
2512       snes->ops->solve = SNESSolveVI_RSAUG;
2513     }
2514   }
2515   ierr = PetscOptionsEnum("-snes_ls","Line search used","SNESLineSearchSet",SNESLineSearchTypes,(PetscEnum)SNES_LS_CUBIC,(PetscEnum*)&inds,&flg);CHKERRQ(ierr);
2516   if (flg) {
2517     switch (inds) {
2518     case SNES_LS_BASIC:
2519       ierr = SNESLineSearchSet(snes,SNESLineSearchNo_VI,PETSC_NULL);CHKERRQ(ierr);
2520       break;
2521     case SNES_LS_BASIC_NONORMS:
2522       ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms_VI,PETSC_NULL);CHKERRQ(ierr);
2523       break;
2524     case SNES_LS_QUADRATIC:
2525       ierr = SNESLineSearchSet(snes,SNESLineSearchQuadratic_VI,PETSC_NULL);CHKERRQ(ierr);
2526       break;
2527     case SNES_LS_CUBIC:
2528       ierr = SNESLineSearchSet(snes,SNESLineSearchCubic_VI,PETSC_NULL);CHKERRQ(ierr);
2529       break;
2530     }
2531   }
2532   ierr = PetscOptionsBool("-snes_vi_ignore_function_sign","Ignore the sign of function for active constraints","None",vi->ignorefunctionsign,&vi->ignorefunctionsign,PETSC_NULL);CHKERRQ(ierr);
2533   ierr = PetscOptionsTail();CHKERRQ(ierr);
2534   PetscFunctionReturn(0);
2535 }
2536 /* -------------------------------------------------------------------------- */
2537 /*MC
2538       SNESVI - Various solvers for variational inequalities based on Newton's method
2539 
2540    Options Database:
2541 +   -snes_vi_type <ss,rs,rsaug> a semi-smooth solver, a reduced space active set method and a reduced space active set method that does not eliminate the active constraints from the Jacobian instead augments the Jacobian with
2542                                 additional variables that enforce the constraints
2543 -   -snes_vi_monitor - prints the number of active constraints at each iteration.
2544 
2545 
2546    Level: beginner
2547 
2548 .seealso:  SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(),
2549            SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(),
2550            SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams()
2551 
2552 M*/
2553 EXTERN_C_BEGIN
2554 #undef __FUNCT__
2555 #define __FUNCT__ "SNESCreate_VI"
2556 PetscErrorCode  SNESCreate_VI(SNES snes)
2557 {
2558   PetscErrorCode ierr;
2559   SNES_VI        *vi;
2560 
2561   PetscFunctionBegin;
2562   snes->ops->reset           = SNESReset_VI;
2563   snes->ops->setup           = SNESSetUp_VI;
2564   snes->ops->solve           = SNESSolveVI_RS;
2565   snes->ops->destroy         = SNESDestroy_VI;
2566   snes->ops->setfromoptions  = SNESSetFromOptions_VI;
2567   snes->ops->view            = SNESView_VI;
2568   snes->ops->converged       = SNESDefaultConverged_VI;
2569 
2570   snes->usesksp             = PETSC_TRUE;
2571   snes->usespc              = PETSC_FALSE;
2572 
2573   ierr                  = PetscNewLog(snes,SNES_VI,&vi);CHKERRQ(ierr);
2574   snes->data            = (void*)vi;
2575   vi->alpha             = 1.e-4;
2576   vi->maxstep           = 1.e8;
2577   vi->minlambda         = 1.e-12;
2578   vi->LineSearch        = SNESLineSearchCubic_VI;
2579   vi->lsP               = PETSC_NULL;
2580   vi->postcheckstep     = PETSC_NULL;
2581   vi->postcheck         = PETSC_NULL;
2582   vi->precheckstep      = PETSC_NULL;
2583   vi->precheck          = PETSC_NULL;
2584   vi->const_tol         =  2.2204460492503131e-16;
2585   vi->checkredundancy   = PETSC_NULL;
2586 
2587   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","SNESLineSearchSetMonitor_VI",SNESLineSearchSetMonitor_VI);CHKERRQ(ierr);
2588   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","SNESLineSearchSet_VI",SNESLineSearchSet_VI);CHKERRQ(ierr);
2589 
2590   PetscFunctionReturn(0);
2591 }
2592 EXTERN_C_END
2593 
2594 #undef __FUNCT__
2595 #define __FUNCT__ "SNESVIGetInactiveSet"
2596 /*
2597    SNESVIGetInactiveSet - Gets the global indices for the inactive set variables (these correspond to the degrees of freedom the linear
2598      system is solved on)
2599 
2600    Input parameter
2601 .  snes - the SNES context
2602 
2603    Output parameter
2604 .  ISact - active set index set
2605 
2606  */
2607 PetscErrorCode SNESVIGetInactiveSet(SNES snes,IS* inact)
2608 {
2609   SNES_VI          *vi = (SNES_VI*)snes->data;
2610   PetscFunctionBegin;
2611   *inact = vi->IS_inact_prev;
2612   PetscFunctionReturn(0);
2613 }
2614