Actual source code: vi.c

  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>

  9: /*@C
 10:    SNESVISetComputeVariableBounds - Sets a function  that is called to compute the variable bounds

 12:    Input parameter
 13: +  snes - the SNES context
 14: -  compute - computes the bounds

 16:    Level: advanced

 18: @*/
 19: PetscErrorCode SNESVISetComputeVariableBounds(SNES snes, PetscErrorCode (*compute)(SNES,Vec,Vec))
 20: {
 21:   PetscErrorCode   ierr;
 22:   SNES_VI          *vi;

 25:   SNESSetType(snes,SNESVI);
 26:   vi = (SNES_VI*)snes->data;
 27:   vi->computevariablebounds = compute;
 28:   return(0);
 29: }
 30: 

 34: /*
 35:    SNESVIComputeInactiveSetIS - Gets the global indices for the bogus inactive set variables

 37:    Input parameter
 38: .  snes - the SNES context
 39: .  X    - the snes solution vector

 41:    Output parameter
 42: .  ISact - active set index set

 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: 
 52:   VecGetLocalSize(X,&nlocal);
 53:   VecGetOwnershipRange(X,&ilow,&ihigh);
 54:   VecGetArrayRead(X,&x);
 55:   VecGetArrayRead(lower,&xl);
 56:   VecGetArrayRead(upper,&xu);
 57:   VecGetArrayRead(F,&f);
 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:   }

 63:   PetscMalloc(nloc_isact*sizeof(PetscInt),&idx_act);

 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:   }

 70:    /* Create inactive set IS */
 71:   ISCreateGeneral(((PetscObject)upper)->comm,nloc_isact,idx_act,PETSC_OWN_POINTER,inact);

 73:   VecRestoreArrayRead(X,&x);
 74:   VecRestoreArrayRead(lower,&xl);
 75:   VecRestoreArrayRead(upper,&xu);
 76:   VecRestoreArrayRead(F,&f);
 77:   return(0);
 78: }

 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. 

 84:     Simple calls the regular DM interpolation and restricts it to operation on the variables not associated with active constraints.

 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;

 98: /*
 99:      DMCreateGlobalVector_SNESVI - Creates global vector of the size of the reduced space

101: */
102: PetscErrorCode  DMCreateGlobalVector_SNESVI(DM dm,Vec *vec)
103: {
104:   PetscErrorCode          ierr;
105:   PetscContainer          isnes;
106:   DM_SNESVI               *dmsnesvi;

109:   PetscObjectQuery((PetscObject)dm,"VI",(PetscObject *)&isnes);
110:   if (!isnes) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_PLIB,"Composed SNES is missing");
111:   PetscContainerGetPointer(isnes,(void**)&dmsnesvi);
112:   VecCreateMPI(((PetscObject)dm)->comm,dmsnesvi->n,PETSC_DETERMINE,vec);
113:   return(0);
114: }

118: /*
119:      DMGetInterpolation_SNESVI - Modifieds the interpolation obtained from the DM by removing all rows and columns associated with active constraints.

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;

130:   PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject *)&isnes);
131:   if (!isnes) SETERRQ(((PetscObject)dm1)->comm,PETSC_ERR_PLIB,"Composed VI data structure is missing");
132:   PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);
133:   PetscObjectQuery((PetscObject)dm2,"VI",(PetscObject *)&isnes);
134:   if (!isnes) SETERRQ(((PetscObject)dm2)->comm,PETSC_ERR_PLIB,"Composed VI data structure is missing");
135:   PetscContainerGetPointer(isnes,(void**)&dmsnesvi2);
136: 
137:   (*dmsnesvi1->getinterpolation)(dm1,dm2,&interp,PETSC_NULL);
138:   MatGetSubMatrix(interp,dmsnesvi2->inactive,dmsnesvi1->inactive,MAT_INITIAL_MATRIX,mat);
139:   MatDestroy(&interp);
140:   *vec = 0;
141:   return(0);
142: }


148: /*
149:      DMCoarsen_SNESVI - Computes the regular coarsened DM then computes additional information about its inactive set

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;

165:   PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject *)&isnes);
166:   if (!isnes) SETERRQ(((PetscObject)dm1)->comm,PETSC_ERR_PLIB,"Composed VI data structure is missing");
167:   PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);
168: 
169:   /* get the original coarsen */
170:   (*dmsnesvi1->coarsen)(dm1,comm,dm2);

172:   /* not sure why this extra reference is needed, but without the dm2 disappears too early */
173:   PetscObjectReference((PetscObject)*dm2);

175:   /* need to set back global vectors in order to use the original injection */
176:   DMClearGlobalVectors(dm1);
177:   dm1->ops->createglobalvector = dmsnesvi1->createglobalvector;
178:   DMCreateGlobalVector(dm1,&finemarked);
179:   DMCreateGlobalVector(*dm2,&coarsemarked);

181:   /*
182:      fill finemarked with locations of inactive points
183:   */
184:   ISGetIndices(dmsnesvi1->inactive,&index);
185:   ISGetLocalSize(dmsnesvi1->inactive,&n);
186:   VecSet(finemarked,0.0);
187:   for (k=0;k<n;k++){
188:       VecSetValue(finemarked,index[k],1.0,INSERT_VALUES);
189:   }
190:   VecAssemblyBegin(finemarked);
191:   VecAssemblyEnd(finemarked);

193:   DMGetInjection(*dm2,dm1,&inject);
194:   VecScatterBegin(inject,finemarked,coarsemarked,INSERT_VALUES,SCATTER_FORWARD);
195:   VecScatterEnd(inject,finemarked,coarsemarked,INSERT_VALUES,SCATTER_FORWARD);
196:   VecScatterDestroy(&inject);

198:   /*
199:      create index set list of coarse inactive points from coarsemarked
200:   */
201:   VecGetLocalSize(coarsemarked,&n);
202:   VecGetOwnershipRange(coarsemarked,&rstart,PETSC_NULL);
203:   VecGetArray(coarsemarked,&marked);
204:   for (k=0; k<n; k++) {
205:     if (marked[k] != 0.0) cnt++;
206:   }
207:   PetscMalloc(cnt*sizeof(PetscInt),&coarseindex);
208:   cnt  = 0;
209:   for (k=0; k<n; k++) {
210:     if (marked[k] != 0.0) coarseindex[cnt++] = k + rstart;
211:   }
212:   VecRestoreArray(coarsemarked,&marked);
213:   ISCreateGeneral(PETSC_COMM_WORLD,cnt,coarseindex,PETSC_OWN_POINTER,&inactive);

215:   DMClearGlobalVectors(dm1);
216:   dm1->ops->createglobalvector = DMCreateGlobalVector_SNESVI;
217:   DMSetVI(*dm2,inactive);

219:   VecDestroy(&finemarked);
220:   VecDestroy(&coarsemarked);
221:   ISDestroy(&inactive);
222:   return(0);
223: }

227: PetscErrorCode DMDestroy_SNESVI(DM_SNESVI *dmsnesvi)
228: {
230: 
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:   DMClearGlobalVectors(dmsnesvi->dm);

240:   ISDestroy(&dmsnesvi->inactive);
241:   PetscFree(dmsnesvi);
242:   return(0);
243: }

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.

251: */
252: PetscErrorCode  DMSetVI(DM dm,IS inactive)
253: {
254:   PetscErrorCode          ierr;
255:   PetscContainer          isnes;
256:   DM_SNESVI               *dmsnesvi;

259:   if (!dm) return(0);

261:   PetscObjectReference((PetscObject)inactive);

263:   PetscObjectQuery((PetscObject)dm,"VI",(PetscObject *)&isnes);
264:   if (!isnes) {
265:     PetscContainerCreate(((PetscObject)dm)->comm,&isnes);
266:     PetscContainerSetUserDestroy(isnes,(PetscErrorCode (*)(void*))DMDestroy_SNESVI);
267:     PetscNew(DM_SNESVI,&dmsnesvi);
268:     PetscContainerSetPointer(isnes,(void*)dmsnesvi);
269:     PetscObjectCompose((PetscObject)dm,"VI",(PetscObject)isnes);
270:     PetscContainerDestroy(&isnes);
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:     PetscContainerGetPointer(isnes,(void**)&dmsnesvi);
279:     ISDestroy(&dmsnesvi->inactive);
280:   }
281:   DMClearGlobalVectors(dm);
282:   ISGetLocalSize(inactive,&dmsnesvi->n);
283:   dmsnesvi->inactive = inactive;
284:   dmsnesvi->dm       = dm;
285:   return(0);
286: }

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;

299:   if (!dm) return(0);
300:   PetscObjectCompose((PetscObject)dm,"VI",(PetscObject)PETSC_NULL);
301:   return(0);
302: }

304: /* --------------------------------------------------------------------------------------------------------*/

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;

321:   VecGetLocalSize(snes->vec_sol,&n);
322:   VecGetSize(snes->vec_sol,&N);
323:   VecGetArrayRead(vi->xl,&xl);
324:   VecGetArrayRead(vi->xu,&xu);
325:   VecGetArrayRead(snes->vec_sol,&x);
326:   VecGetArrayRead(snes->vec_func,&f);
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:   }

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:   VecRestoreArrayRead(snes->vec_func,&f);
342:   VecRestoreArrayRead(vi->xl,&xl);
343:   VecRestoreArrayRead(vi->xu,&xu);
344:   VecRestoreArrayRead(snes->vec_sol,&x);
345:   MPI_Allreduce(&rnorm,&fnorm,1,MPIU_REAL,MPIU_SUM,((PetscObject)snes)->comm);
346:   MPI_Allreduce(act,fact,2,MPIU_INT,MPIU_SUM,((PetscObject)snes)->comm);
347:   /* remove later */
348:   MPI_Allreduce(act_bound,fact_bound,2,MPIU_INT,MPIU_SUM,((PetscObject)snes)->comm);
349:   fnorm = PetscSqrtReal(fnorm);
350: 
351:   PetscViewerASCIIAddTab(viewer,((PetscObject)snes)->tablevel);
352:   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));
353:   PetscViewerASCIIPrintf(viewer,"                               lower constraints satisfied %D upper constraints satisfied %D\n",its,fact_bound[0],fact_bound[1]);
354: 
355:   PetscViewerASCIISubtractTab(viewer,((PetscObject)snes)->tablevel);
356:   return(0);
357: }

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: */
367: PetscErrorCode SNESVICheckLocalMin_Private(SNES snes,Mat A,Vec F,Vec W,PetscReal fnorm,PetscBool *ismin)
368: {
369:   PetscReal      a1;
371:   PetscBool     hastranspose;

374:   *ismin = PETSC_FALSE;
375:   MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);
376:   if (hastranspose) {
377:     /* Compute || J^T F|| */
378:     MatMultTranspose(A,F,W);
379:     VecNorm(W,NORM_2,&a1);
380:     PetscInfo1(snes,"|| J^T F|| %G near zero implies found a local minimum\n",a1/fnorm);
381:     if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE;
382:   } else {
383:     Vec         work;
384:     PetscScalar result;
385:     PetscReal   wnorm;

387:     VecSetRandom(W,PETSC_NULL);
388:     VecNorm(W,NORM_2,&wnorm);
389:     VecDuplicate(W,&work);
390:     MatMult(A,W,work);
391:     VecDot(F,work,&result);
392:     VecDestroy(&work);
393:     a1   = PetscAbsScalar(result)/(fnorm*wnorm);
394:     PetscInfo1(snes,"(F^T J random)/(|| F ||*||random|| %G near zero implies found a local minimum\n",a1);
395:     if (a1 < 1.e-4) *ismin = PETSC_TRUE;
396:   }
397:   return(0);
398: }

400: /*
401:      Checks if J^T(F - J*X) = 0 
402: */
405: PetscErrorCode SNESVICheckResidual_Private(SNES snes,Mat A,Vec F,Vec X,Vec W1,Vec W2)
406: {
407:   PetscReal      a1,a2;
409:   PetscBool     hastranspose;

412:   MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);
413:   if (hastranspose) {
414:     MatMult(A,X,W1);
415:     VecAXPY(W1,-1.0,F);

417:     /* Compute || J^T W|| */
418:     MatMultTranspose(A,W1,W2);
419:     VecNorm(W1,NORM_2,&a1);
420:     VecNorm(W2,NORM_2,&a2);
421:     if (a1 != 0.0) {
422:       PetscInfo1(snes,"||J^T(F-Ax)||/||F-AX|| %G near zero implies inconsistent rhs\n",a2/a1);
423:     }
424:   }
425:   return(0);
426: }

428: /*
429:   SNESDefaultConverged_VI - Checks the convergence of the semismooth newton algorithm.

431:   Notes:
432:   The convergence criterion currently implemented is
433:   merit < abstol
434:   merit < rtol*merit_initial
435: */
438: PetscErrorCode SNESDefaultConverged_VI(SNES snes,PetscInt it,PetscReal xnorm,PetscReal gradnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
439: {

445: 
446:   *reason = SNES_CONVERGED_ITERATING;

448:   if (!it) {
449:     /* set parameter for default relative tolerance convergence test */
450:     snes->ttol = fnorm*snes->rtol;
451:   }
452:   if (fnorm != fnorm) {
453:     PetscInfo(snes,"Failed to converged, function norm is NaN\n");
454:     *reason = SNES_DIVERGED_FNORM_NAN;
455:   } else if (fnorm < snes->abstol) {
456:     PetscInfo2(snes,"Converged due to function norm %G < %G\n",fnorm,snes->abstol);
457:     *reason = SNES_CONVERGED_FNORM_ABS;
458:   } else if (snes->nfuncs >= snes->max_funcs) {
459:     PetscInfo2(snes,"Exceeded maximum number of function evaluations: %D > %D\n",snes->nfuncs,snes->max_funcs);
460:     *reason = SNES_DIVERGED_FUNCTION_COUNT;
461:   }

463:   if (it && !*reason) {
464:     if (fnorm < snes->ttol) {
465:       PetscInfo2(snes,"Converged due to function norm %G < %G (relative tolerance)\n",fnorm,snes->ttol);
466:       *reason = SNES_CONVERGED_FNORM_RELATIVE;
467:     }
468:   }
469:   return(0);
470: }

472: /*
473:   SNESVIComputeMeritFunction - Evaluates the merit function for the mixed complementarity problem.

475:   Input Parameter:
476: . phi - the semismooth function

478:   Output Parameter:
479: . merit - the merit function
480: . phinorm - ||phi||

482:   Notes:
483:   The merit function for the mixed complementarity problem is defined as
484:      merit = 0.5*phi^T*phi
485: */
488: static PetscErrorCode SNESVIComputeMeritFunction(Vec phi, PetscReal* merit,PetscReal* phinorm)
489: {

493:   VecNormBegin(phi,NORM_2,phinorm);
494:   VecNormEnd(phi,NORM_2,phinorm);

496:   *merit = 0.5*(*phinorm)*(*phinorm);
497:   return(0);
498: }

500: PETSC_STATIC_INLINE PetscScalar Phi(PetscScalar a,PetscScalar b)
501: {
502:   return a + b - PetscSqrtScalar(a*a + b*b);
503: }

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: }

511: /* 
512:    SNESVIComputeFunction - Reformulates a system of nonlinear equations in mixed complementarity form to a system of nonlinear equations in semismooth form. 

514:    Input Parameters:  
515: .  snes - the SNES context
516: .  x - current iterate
517: .  functx - user defined function context

519:    Output Parameters:
520: .  phi - Semismooth function

522: */
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;

534:   (*vi->computeuserfunction)(snes,X,F,functx);
535:   VecGetLocalSize(X,&nlocal);
536:   VecGetArray(X,&x_arr);
537:   VecGetArray(F,&f_arr);
538:   VecGetArray(Xl,&l);
539:   VecGetArray(Xu,&u);
540:   VecGetArray(phi,&phi_arr);

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:   VecRestoreArray(X,&x_arr);
557:   VecRestoreArray(F,&f_arr);
558:   VecRestoreArray(Xl,&l);
559:   VecRestoreArray(Xu,&u);
560:   VecRestoreArray(phi,&phi_arr);
561:   return(0);
562: }

564: /* 
565:    SNESVIComputeBsubdifferentialVectors - Computes the diagonal shift (Da) and row scaling (Db) vectors needed for the
566:                                           the semismooth jacobian.
567: */
570: PetscErrorCode SNESVIComputeBsubdifferentialVectors(SNES snes,Vec X,Vec F,Mat jac,Vec Da,Vec Db)
571: {
573:   SNES_VI      *vi = (SNES_VI*)snes->data;
574:   PetscScalar    *l,*u,*x,*f,*da,*db,da1,da2,db1,db2;
575:   PetscInt       i,nlocal;


579:   VecGetArray(X,&x);
580:   VecGetArray(F,&f);
581:   VecGetArray(vi->xl,&l);
582:   VecGetArray(vi->xu,&u);
583:   VecGetArray(Da,&da);
584:   VecGetArray(Db,&db);
585:   VecGetLocalSize(X,&nlocal);
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:   }

610:   VecRestoreArray(X,&x);
611:   VecRestoreArray(F,&f);
612:   VecRestoreArray(vi->xl,&l);
613:   VecRestoreArray(vi->xu,&u);
614:   VecRestoreArray(Da,&da);
615:   VecRestoreArray(Db,&db);
616:   return(0);
617: }

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.

622:    Input Parameters:
623: .  Da       - Diagonal shift vector for the semismooth jacobian.
624: .  Db       - Row scaling vector for the semismooth jacobian. 

626:    Output Parameters:
627: .  jac      - semismooth jacobian
628: .  jac_pre  - optional preconditioning matrix

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: */
639: PetscErrorCode SNESVIComputeJacobian(Mat jac, Mat jac_pre,Vec Da, Vec Db)
640: {
642: 
643:   /* Do row scaling  and add diagonal perturbation */
644:   MatDiagonalScale(jac,Db,PETSC_NULL);
645:   MatDiagonalSet(jac,Da,ADD_VALUES);
646:   if (jac != jac_pre) { /* If jac and jac_pre are different */
647:     MatDiagonalScale(jac_pre,Db,PETSC_NULL);
648:     MatDiagonalSet(jac_pre,Da,ADD_VALUES);
649:   }
650:   return(0);
651: }

653: /*
654:    SNESVIComputeMeritFunctionGradient - Computes the gradient of the merit function psi.

656:    Input Parameters:
657:    phi - semismooth function.
658:    H   - semismooth jacobian
659:    
660:    Output Parameters:
661:    dpsi - merit function gradient

663:    Notes:
664:   The merit function gradient is computed as follows
665:         dpsi = H^T*phi
666: */
669: PetscErrorCode SNESVIComputeMeritFunctionGradient(Mat H, Vec phi, Vec dpsi)
670: {
672: 
674:   MatMultTranspose(H,phi,dpsi);
675:   return(0);
676: }

678: /* -------------------------------------------------------------------------- */
679: /*
680:    SNESVIProjectOntoBounds - Projects X onto the feasible region so that Xl[i] <= X[i] <= Xu[i] for i = 1...n.

682:    Input Parameters:
683: .  SNES - nonlinear solver context

685:    Output Parameters:
686: .  X - Bound projected X

688: */

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;

701:   VecGetLocalSize(X,&n);
702:   VecGetArray(X,&x);
703:   VecGetArrayRead(vi->xl,&xl);
704:   VecGetArrayRead(vi->xu,&xu);

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:   VecRestoreArray(X,&x);
711:   VecRestoreArrayRead(vi->xl,&xl);
712:   VecRestoreArrayRead(vi->xu,&xu);
713:   return(0);
714: }

716: /*  -------------------------------------------------------------------- 

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.

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.

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.

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().

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.  

752:     -------------------------------------------------------------------- */
753: /*
754:    SNESSolveVI_SS - Solves the complementarity problem with a semismooth Newton
755:    method using a line search.

757:    Input Parameters:
758: .  snes - the SNES context

760:    Output Parameter:
761: .  outits - number of iterations until termination

763:    Application Interface Routine: SNESSolve()

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: */
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;

784:   vi->computeuserfunction    = snes->ops->computefunction;
785:   snes->ops->computefunction = SNESVIComputeFunction;

787:   snes->numFailures            = 0;
788:   snes->numLinearSolveFailures = 0;
789:   snes->reason                 = SNES_CONVERGED_ITERATING;

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];

798:   PetscObjectTakeAccess(snes);
799:   snes->iter = 0;
800:   snes->norm = 0.0;
801:   PetscObjectGrantAccess(snes);

803:   SNESVIProjectOntoBounds(snes,X);
804:   SNESComputeFunction(snes,X,vi->phi);
805:   if (snes->domainerror) {
806:     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
807:     snes->ops->computefunction = vi->computeuserfunction;
808:     return(0);
809:   }
810:    /* Compute Merit function */
811:   SNESVIComputeMeritFunction(vi->phi,&vi->merit,&vi->phinorm);

813:   VecNormBegin(X,NORM_2,&xnorm);        /* xnorm <- ||x||  */
814:   VecNormEnd(X,NORM_2,&xnorm);
815:   if (PetscIsInfOrNanReal(vi->merit)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");

817:   PetscObjectTakeAccess(snes);
818:   snes->norm = vi->phinorm;
819:   PetscObjectGrantAccess(snes);
820:   SNESLogConvHistory(snes,vi->phinorm,0);
821:   SNESMonitor(snes,0,vi->phinorm);

823:   /* set parameter for default relative tolerance convergence test */
824:   snes->ttol = vi->phinorm*snes->rtol;
825:   /* test convergence */
826:   (*snes->ops->converged)(snes,0,0.0,0.0,vi->phinorm,&snes->reason,snes->cnvP);
827:   if (snes->reason) {
828:     snes->ops->computefunction = vi->computeuserfunction;
829:     return(0);
830:   }

832:   for (i=0; i<maxits; i++) {

834:     /* Call general purpose update function */
835:     if (snes->ops->update) {
836:       (*snes->ops->update)(snes, snes->iter);
837:     }
838: 
839:     /* Solve J Y = Phi, where J is the semismooth jacobian */
840:     /* Get the nonlinear function jacobian */
841:     SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);
842:     /* Get the diagonal shift and row scaling vectors */
843:     SNESVIComputeBsubdifferentialVectors(snes,X,F,snes->jacobian,vi->Da,vi->Db);
844:     /* Compute the semismooth jacobian */
845:     SNESVIComputeJacobian(snes->jacobian,snes->jacobian_pre,vi->Da,vi->Db);
846:     /* Compute the merit function gradient */
847:     SNESVIComputeMeritFunctionGradient(snes->jacobian,vi->phi,vi->dpsi);
848:     KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);
849:     SNES_KSPSolve(snes,snes->ksp,vi->phi,Y);
850:     KSPGetConvergedReason(snes->ksp,&kspreason);

852:     if (kspreason < 0) {
853:       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
854:         PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);
855:         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
856:         break;
857:       }
858:     }
859:     KSPGetIterationNumber(snes->ksp,&lits);
860:     snes->linear_its += lits;
861:     PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);
862:     /*
863:     if (vi->precheckstep) {
864:       PetscBool changed_y = PETSC_FALSE;
865:       (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);
866:     }

868:     if (PetscLogPrintInfo){
869:       SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);
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:     VecCopy(Y,snes->vec_sol_update);
877:     ynorm = 1; gnorm = vi->phinorm;
878:     (*vi->LineSearch)(snes,vi->lsP,X,vi->phi,G,Y,W,vi->phinorm,xnorm,&ynorm,&gnorm,&lssucceed);
879:     PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",vi->phinorm,gnorm,ynorm,(int)lssucceed);
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:       return(0);
885:     }
886:     if (!lssucceed) {
887:       if (++snes->numFailures >= snes->maxFailures) {
888:         PetscBool ismin;
889:         snes->reason = SNES_DIVERGED_LINE_SEARCH;
890:         SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);
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:     VecCopy(G,vi->phi);
899:     VecCopy(W,X);
900:     /* Monitor convergence */
901:     PetscObjectTakeAccess(snes);
902:     snes->iter = i+1;
903:     snes->norm = vi->phinorm;
904:     PetscObjectGrantAccess(snes);
905:     SNESLogConvHistory(snes,snes->norm,lits);
906:     SNESMonitor(snes,snes->iter,snes->norm);
907:     /* Test for convergence, xnorm = || X || */
908:     if (snes->ops->converged != SNESSkipConverged) { VecNorm(X,NORM_2,&xnorm); }
909:     (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,vi->phinorm,&snes->reason,snes->cnvP);
910:     if (snes->reason) break;
911:   }
912:   if (i == maxits) {
913:     PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);
914:     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
915:   }
916:   snes->ops->computefunction = vi->computeuserfunction;
917:   return(0);
918: }

922: /*
923:    SNESVIGetActiveSetIndices - Gets the global indices for the active set variables

925:    Input parameter
926: .  snes - the SNES context
927: .  X    - the snes solution vector
928: .  F    - the nonlinear function vector

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: 
942:   VecGetLocalSize(X,&nlocal);
943:   VecGetOwnershipRange(X,&ilow,&ihigh);
944:   VecGetArrayRead(X,&x);
945:   VecGetArrayRead(Xl,&xl);
946:   VecGetArrayRead(Xu,&xu);
947:   VecGetArrayRead(F,&f);
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:   }

957:   PetscMalloc(nloc_isact*sizeof(PetscInt),&idx_act);

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:   }

968:    /* Create active set IS */
969:   ISCreateGeneral(((PetscObject)snes)->comm,nloc_isact,idx_act,PETSC_OWN_POINTER,ISact);

971:   VecRestoreArrayRead(X,&x);
972:   VecRestoreArrayRead(Xl,&xl);
973:   VecRestoreArrayRead(Xu,&xu);
974:   VecRestoreArrayRead(F,&f);
975:   return(0);
976: }

980: PetscErrorCode SNESVICreateIndexSets_RS(SNES snes,Vec X,Vec F,IS* ISact,IS* ISinact)
981: {
982:   PetscErrorCode     ierr;

985:   SNESVIGetActiveSetIS(snes,X,F,ISact);
986:   ISComplement(*ISact,X->map->rstart,X->map->rend,ISinact);
987:   return(0);
988: }

990: /* Create active and inactive set vectors. The local size of this vector is set and petsc computes the global size */
993: PetscErrorCode SNESVICreateSubVectors(SNES snes,PetscInt n,Vec* newv)
994: {
996:   Vec            v;

999:   VecCreate(((PetscObject)snes)->comm,&v);
1000:   VecSetSizes(v,n,PETSC_DECIDE);
1001:   VecSetFromOptions(v);
1002:   *newv = v;

1004:   return(0);
1005: }

1007: /* Resets the snes PC and KSP when the active set sizes change */
1010: PetscErrorCode SNESVIResetPCandKSP(SNES snes,Mat Amat,Mat Pmat)
1011: {
1012:   PetscErrorCode         ierr;
1013:   KSP                    snesksp;

1016:   SNESGetKSP(snes,&snesksp);
1017:   KSPReset(snesksp);

1019:   /*
1020:   KSP                    kspnew;
1021:   PC                     pcnew;
1022:   const MatSolverPackage stype;


1025:   KSPCreate(((PetscObject)snes)->comm,&kspnew);
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:   KSPSetType(kspnew,((PetscObject)snesksp)->type_name);
1031:   KSPGetPC(kspnew,&pcnew);
1032:   PCSetType(kspnew->pc,((PetscObject)snesksp->pc)->type_name);
1033:   PCSetOperators(kspnew->pc,Amat,Pmat,DIFFERENT_NONZERO_PATTERN);
1034:   PCFactorGetMatSolverPackage(snesksp->pc,&stype);
1035:   PCFactorSetMatSolverPackage(kspnew->pc,stype);
1036:   KSPDestroy(&snesksp);
1037:   snes->ksp = kspnew;
1038:   PetscLogObjectParent(snes,kspnew);
1039:    KSPSetFromOptions(kspnew);*/
1040:   return(0);
1041: }


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;

1055:   VecGetLocalSize(X,&n);
1056:   VecGetArrayRead(vi->xl,&xl);
1057:   VecGetArrayRead(vi->xu,&xu);
1058:   VecGetArrayRead(X,&x);
1059:   VecGetArrayRead(F,&f);
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:   VecRestoreArrayRead(F,&f);
1071:   VecRestoreArrayRead(vi->xl,&xl);
1072:   VecRestoreArrayRead(vi->xu,&xu);
1073:   VecRestoreArrayRead(X,&x);
1074:   MPI_Allreduce(&rnorm,fnorm,1,MPIU_REAL,MPIU_SUM,((PetscObject)snes)->comm);
1075:   *fnorm = sqrt(*fnorm);
1076:   return(0);
1077: }

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). */
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;

1096:   snes->numFailures            = 0;
1097:   snes->numLinearSolveFailures = 0;
1098:   snes->reason                 = SNES_CONVERGED_ITERATING;

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];

1107:   PetscObjectTakeAccess(snes);
1108:   snes->iter = 0;
1109:   snes->norm = 0.0;
1110:   PetscObjectGrantAccess(snes);

1112:   SNESVIProjectOntoBounds(snes,X);
1113:   SNESComputeFunction(snes,X,F);
1114:   if (snes->domainerror) {
1115:     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
1116:     return(0);
1117:   }
1118:   SNESVIComputeInactiveSetFnorm(snes,F,X,&fnorm);
1119:   VecNormBegin(X,NORM_2,&xnorm);        /* xnorm <- ||x||  */
1120:   VecNormEnd(X,NORM_2,&xnorm);
1121:   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");

1123:   PetscObjectTakeAccess(snes);
1124:   snes->norm = fnorm;
1125:   PetscObjectGrantAccess(snes);
1126:   SNESLogConvHistory(snes,fnorm,0);
1127:   SNESMonitor(snes,0,fnorm);

1129:   /* set parameter for default relative tolerance convergence test */
1130:   snes->ttol = fnorm*snes->rtol;
1131:   /* test convergence */
1132:   (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
1133:   if (snes->reason) return(0);


1136:   for (i=0; i<maxits; i++) {

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;

1147:     /* Call general purpose update function */
1148:     if (snes->ops->update) {
1149:       (*snes->ops->update)(snes, snes->iter);
1150:     }
1151:     SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);


1154:         /* Create active and inactive index sets */
1155: 
1156:     /*original
1157:     SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&IS_inact);
1158:      */
1159:     SNESVIGetActiveSetIS(snes,X,F,&IS_act);
1160: 
1161:     if (vi->checkredundancy) {
1162:       (*vi->checkredundancy)(snes,IS_act,&IS_redact,vi->ctxP);
1163:       if (IS_redact){
1164:         ISSort(IS_redact);
1165:         ISComplement(IS_redact,X->map->rstart,X->map->rend,&IS_inact);
1166:         ISDestroy(&IS_redact);
1167:       }
1168:       else {
1169:         ISComplement(IS_act,X->map->rstart,X->map->rend,&IS_inact);
1170:       }
1171:     } else {
1172:       ISComplement(IS_act,X->map->rstart,X->map->rend,&IS_inact);
1173:     }
1174: 

1176:     /* Create inactive set submatrix */
1177:     MatGetSubMatrix(snes->jacobian,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);
1178: 
1179:     MatFindNonzeroRows(jac_inact_inact,&keptrows);
1180:     if (0 && keptrows) {
1181:     // if (keptrows) {
1182:       PetscInt       cnt,*nrows,k;
1183:       const PetscInt *krows,*inact;
1184:       PetscInt       rstart=jac_inact_inact->rmap->rstart;

1186:       MatDestroy(&jac_inact_inact);
1187:       ISDestroy(&IS_act);

1189:       ISGetLocalSize(keptrows,&cnt);
1190:       ISGetIndices(keptrows,&krows);
1191:       ISGetIndices(IS_inact,&inact);
1192:       PetscMalloc(cnt*sizeof(PetscInt),&nrows);
1193:       for (k=0; k<cnt; k++) {
1194:         nrows[k] = inact[krows[k]-rstart];
1195:       }
1196:       ISRestoreIndices(keptrows,&krows);
1197:       ISRestoreIndices(IS_inact,&inact);
1198:       ISDestroy(&keptrows);
1199:       ISDestroy(&IS_inact);
1200: 
1201:       ISCreateGeneral(PETSC_COMM_WORLD,cnt,nrows,PETSC_OWN_POINTER,&IS_inact);
1202:       ISComplement(IS_inact,F->map->rstart,F->map->rend,&IS_act);
1203:       MatGetSubMatrix(snes->jacobian,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);
1204:     }
1205:     DMSetVI(snes->dm,IS_inact);
1206:     /* remove later */

1208:     /*
1209:   VecView(vi->xu,PETSC_VIEWER_BINARY_(PETSC_COMM_WORLD));
1210:   VecView(vi->xl,PETSC_VIEWER_BINARY_(PETSC_COMM_WORLD));
1211:   VecView(X,PETSC_VIEWER_BINARY_(PETSC_COMM_WORLD));
1212:   VecView(F,PETSC_VIEWER_BINARY_(PETSC_COMM_WORLD));
1213:   ISView(IS_inact,PETSC_VIEWER_BINARY_(PETSC_COMM_WORLD));
1214:      */

1216:     /* Get sizes of active and inactive sets */
1217:     ISGetLocalSize(IS_act,&nis_act);
1218:     ISGetLocalSize(IS_inact,&nis_inact);

1220:     /* Create active and inactive set vectors */
1221:     SNESVICreateSubVectors(snes,nis_inact,&F_inact);
1222:     SNESVICreateSubVectors(snes,nis_act,&Y_act);
1223:     SNESVICreateSubVectors(snes,nis_inact,&Y_inact);

1225:     /* Create scatter contexts */
1226:     VecScatterCreate(Y,IS_act,Y_act,PETSC_NULL,&scat_act);
1227:     VecScatterCreate(Y,IS_inact,Y_inact,PETSC_NULL,&scat_inact);

1229:     /* Do a vec scatter to active and inactive set vectors */
1230:     VecScatterBegin(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);
1231:     VecScatterEnd(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);

1233:     VecScatterBegin(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);
1234:     VecScatterEnd(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);

1236:     VecScatterBegin(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);
1237:     VecScatterEnd(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);
1238: 
1239:     /* Active set direction = 0 */
1240:     VecSet(Y_act,0);
1241:     if (snes->jacobian != snes->jacobian_pre) {
1242:       MatGetSubMatrix(snes->jacobian_pre,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&prejac_inact_inact);
1243:     } else prejac_inact_inact = jac_inact_inact;

1245:     ISEqual(vi->IS_inact_prev,IS_inact,&isequal);
1246:     if (!isequal) {
1247:       SNESVIResetPCandKSP(snes,jac_inact_inact,prejac_inact_inact);
1248:       flg  = DIFFERENT_NONZERO_PATTERN;
1249:     }
1250: 
1251:     /*      ISView(IS_inact,0); */
1252:     /*      ISView(IS_act,0);*/
1253:     /*      MatView(snes->jacobian_pre,0); */

1255: 
1256: 
1257:     KSPSetOperators(snes->ksp,jac_inact_inact,prejac_inact_inact,flg);
1258:     KSPSetUp(snes->ksp);
1259:     {
1260:       PC        pc;
1261:       PetscBool flg;
1262:       KSPGetPC(snes->ksp,&pc);
1263:       PetscTypeCompare((PetscObject)pc,PCFIELDSPLIT,&flg);
1264:       if (flg) {
1265:         KSP      *subksps;
1266:         PCFieldSplitGetSubKSP(pc,PETSC_NULL,&subksps);
1267:         KSPGetPC(subksps[0],&pc);
1268:         PetscFree(subksps);
1269:         PetscTypeCompare((PetscObject)pc,PCBJACOBI,&flg);
1270:         if (flg) {
1271:           PetscInt       n,N = 101*101,j,cnts[3] = {0,0,0};
1272:           const PetscInt *ii;

1274:           ISGetSize(IS_inact,&n);
1275:           ISGetIndices(IS_inact,&ii);
1276:           for (j=0; j<n; j++) {
1277:             if (ii[j] < N) cnts[0]++;
1278:             else if (ii[j] < 2*N) cnts[1]++;
1279:             else if (ii[j] < 3*N) cnts[2]++;
1280:           }
1281:           ISRestoreIndices(IS_inact,&ii);

1283:           PCBJacobiSetTotalBlocks(pc,3,cnts);
1284:         }
1285:       }
1286:     }

1288:     SNES_KSPSolve(snes,snes->ksp,F_inact,Y_inact);
1289:     KSPGetConvergedReason(snes->ksp,&kspreason);
1290:     if (kspreason < 0) {
1291:       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
1292:         PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);
1293:         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
1294:         break;
1295:       }
1296:      }

1298:     VecScatterBegin(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);
1299:     VecScatterEnd(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);
1300:     VecScatterBegin(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);
1301:     VecScatterEnd(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);

1303:     VecDestroy(&F_inact);
1304:     VecDestroy(&Y_act);
1305:     VecDestroy(&Y_inact);
1306:     VecScatterDestroy(&scat_act);
1307:     VecScatterDestroy(&scat_inact);
1308:     ISDestroy(&IS_act);
1309:     if (!isequal) {
1310:       ISDestroy(&vi->IS_inact_prev);
1311:       ISDuplicate(IS_inact,&vi->IS_inact_prev);
1312:     }
1313:     ISDestroy(&IS_inact);
1314:     MatDestroy(&jac_inact_inact);
1315:     if (snes->jacobian != snes->jacobian_pre) {
1316:       MatDestroy(&prejac_inact_inact);
1317:     }
1318:     KSPGetIterationNumber(snes->ksp,&lits);
1319:     snes->linear_its += lits;
1320:     PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);
1321:     /*
1322:     if (vi->precheckstep) {
1323:       PetscBool changed_y = PETSC_FALSE;
1324:       (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);
1325:     }

1327:     if (PetscLogPrintInfo){
1328:       SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);
1329:     }
1330:     */
1331:     /* Compute a (scaled) negative update in the line search routine: 
1332:          Y <- X - lambda*Y 
1333:        and evaluate G = function(Y) (depends on the line search). 
1334:     */
1335:     VecCopy(Y,snes->vec_sol_update);
1336:     ynorm = 1; gnorm = fnorm;
1337:     (*vi->LineSearch)(snes,vi->lsP,X,F,G,Y,W,fnorm,xnorm,&ynorm,&gnorm,&lssucceed);
1338:     PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);
1339:     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
1340:     if (snes->domainerror) {
1341:       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
1342:       DMDestroyVI(snes->dm);
1343:       return(0);
1344:     }
1345:     if (!lssucceed) {
1346:       if (++snes->numFailures >= snes->maxFailures) {
1347:         PetscBool ismin;
1348:         snes->reason = SNES_DIVERGED_LINE_SEARCH;
1349:         SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);
1350:         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
1351:         break;
1352:       }
1353:     }
1354:     /* Update function and solution vectors */
1355:     fnorm = gnorm;
1356:     VecCopy(G,F);
1357:     VecCopy(W,X);
1358:     /* Monitor convergence */
1359:     PetscObjectTakeAccess(snes);
1360:     snes->iter = i+1;
1361:     snes->norm = fnorm;
1362:     PetscObjectGrantAccess(snes);
1363:     SNESLogConvHistory(snes,snes->norm,lits);
1364:     SNESMonitor(snes,snes->iter,snes->norm);
1365:     /* Test for convergence, xnorm = || X || */
1366:     if (snes->ops->converged != SNESSkipConverged) { VecNorm(X,NORM_2,&xnorm); }
1367:     (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);
1368:     if (snes->reason) break;
1369:   }
1370:   DMDestroyVI(snes->dm);
1371:   if (i == maxits) {
1372:     PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);
1373:     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
1374:   }
1375:   return(0);
1376: }

1380: PetscErrorCode SNESVISetRedundancyCheck(SNES snes,PetscErrorCode (*func)(SNES,IS,IS*,void*),void *ctx)
1381: {
1382:   SNES_VI         *vi = (SNES_VI*)snes->data;

1386:   vi->checkredundancy = func;
1387:   vi->ctxP            = ctx;
1388:   return(0);
1389: }

1391: #if defined(PETSC_HAVE_MATLAB_ENGINE)
1392: #include <engine.h>
1393: #include <mex.h>
1394: typedef struct {char *funcname; mxArray *ctx;} SNESMatlabContext;

1398: PetscErrorCode SNESVIRedundancyCheck_Matlab(SNES snes,IS is_act,IS* is_redact,void* ctx)
1399: {
1400:   PetscErrorCode      ierr;
1401:   SNESMatlabContext   *sctx = (SNESMatlabContext*)ctx;
1402:   int                 nlhs = 1, nrhs = 5;
1403:   mxArray             *plhs[1], *prhs[5];
1404:   long long int       l1 = 0, l2 = 0, ls = 0;
1405:   PetscInt            *indices=PETSC_NULL;


1413:   /* Create IS for reduced active set of size 0, its size and indices will
1414:    bet set by the Matlab function */
1415:   ISCreateGeneral(((PetscObject)snes)->comm,0,indices,PETSC_OWN_POINTER,is_redact);
1416:   /* call Matlab function in ctx */
1417:   PetscMemcpy(&ls,&snes,sizeof(snes));
1418:   PetscMemcpy(&l1,&is_act,sizeof(is_act));
1419:   PetscMemcpy(&l2,is_redact,sizeof(is_act));
1420:   prhs[0] = mxCreateDoubleScalar((double)ls);
1421:   prhs[1] = mxCreateDoubleScalar((double)l1);
1422:   prhs[2] = mxCreateDoubleScalar((double)l2);
1423:   prhs[3] = mxCreateString(sctx->funcname);
1424:   prhs[4] = sctx->ctx;
1425:   mexCallMATLAB(nlhs,plhs,nrhs,prhs,"PetscSNESVIRedundancyCheckInternal");
1426:   mxGetScalar(plhs[0]);
1427:   mxDestroyArray(prhs[0]);
1428:   mxDestroyArray(prhs[1]);
1429:   mxDestroyArray(prhs[2]);
1430:   mxDestroyArray(prhs[3]);
1431:   mxDestroyArray(plhs[0]);
1432:   return(0);
1433: }

1437: PetscErrorCode SNESVISetRedundancyCheckMatlab(SNES snes,const char* func,mxArray* ctx)
1438: {
1439:   PetscErrorCode      ierr;
1440:   SNESMatlabContext   *sctx;

1443:   /* currently sctx is memory bleed */
1444:   PetscMalloc(sizeof(SNESMatlabContext),&sctx);
1445:   PetscStrallocpy(func,&sctx->funcname);
1446:   sctx->ctx = mxDuplicateArray(ctx);
1447:   SNESVISetRedundancyCheck(snes,SNESVIRedundancyCheck_Matlab,sctx);
1448:   return(0);
1449: }
1450: 
1451: #endif


1454: /* Variational Inequality solver using augmented space method. It does the opposite of the
1455:    reduced space method i.e. it identifies the active set variables and instead of discarding
1456:    them it augments the original system by introducing additional equality 
1457:    constraint equations for active set variables. The user can optionally provide an IS for 
1458:    a subset of 'redundant' active set variables which will treated as free variables.
1459:    Specific implementation for Allen-Cahn problem 
1460: */
1463: PetscErrorCode SNESSolveVI_RSAUG(SNES snes)
1464: {
1465:   SNES_VI          *vi = (SNES_VI*)snes->data;
1466:   PetscErrorCode    ierr;
1467:   PetscInt          maxits,i,lits;
1468:   PetscBool         lssucceed;
1469:   MatStructure      flg = DIFFERENT_NONZERO_PATTERN;
1470:   PetscReal         fnorm,gnorm,xnorm=0,ynorm;
1471:   Vec                Y,X,F,G,W;
1472:   KSPConvergedReason kspreason;

1475:   snes->numFailures            = 0;
1476:   snes->numLinearSolveFailures = 0;
1477:   snes->reason                 = SNES_CONVERGED_ITERATING;

1479:   maxits        = snes->max_its;        /* maximum number of iterations */
1480:   X                = snes->vec_sol;        /* solution vector */
1481:   F                = snes->vec_func;        /* residual vector */
1482:   Y                = snes->work[0];        /* work vectors */
1483:   G                = snes->work[1];
1484:   W                = snes->work[2];

1486:   PetscObjectTakeAccess(snes);
1487:   snes->iter = 0;
1488:   snes->norm = 0.0;
1489:   PetscObjectGrantAccess(snes);

1491:   SNESVIProjectOntoBounds(snes,X);
1492:   SNESComputeFunction(snes,X,F);
1493:   if (snes->domainerror) {
1494:     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
1495:     return(0);
1496:   }
1497:   SNESVIComputeInactiveSetFnorm(snes,F,X,&fnorm);
1498:   VecNormBegin(X,NORM_2,&xnorm);        /* xnorm <- ||x||  */
1499:   VecNormEnd(X,NORM_2,&xnorm);
1500:   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");

1502:   PetscObjectTakeAccess(snes);
1503:   snes->norm = fnorm;
1504:   PetscObjectGrantAccess(snes);
1505:   SNESLogConvHistory(snes,fnorm,0);
1506:   SNESMonitor(snes,0,fnorm);

1508:   /* set parameter for default relative tolerance convergence test */
1509:   snes->ttol = fnorm*snes->rtol;
1510:   /* test convergence */
1511:   (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
1512:   if (snes->reason) return(0);

1514:   for (i=0; i<maxits; i++) {
1515:     IS             IS_act,IS_inact; /* _act -> active set _inact -> inactive set */
1516:     IS             IS_redact; /* redundant active set */
1517:     Mat            J_aug,Jpre_aug;
1518:     Vec            F_aug,Y_aug;
1519:     PetscInt       nis_redact,nis_act;
1520:     const PetscInt *idx_redact,*idx_act;
1521:     PetscInt       k;
1522:     PetscInt       *idx_actkept=PETSC_NULL,nkept=0; /* list of kept active set */
1523:     PetscScalar    *f,*f2;
1524:     PetscBool      isequal;
1525:     PetscInt       i1=0,j1=0;

1527:     /* Call general purpose update function */
1528:     if (snes->ops->update) {
1529:       (*snes->ops->update)(snes, snes->iter);
1530:     }
1531:     SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);

1533:     /* Create active and inactive index sets */
1534:     SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&IS_inact);

1536:     /* Get local active set size */
1537:     ISGetLocalSize(IS_act,&nis_act);
1538:     if (nis_act) {
1539:       ISGetIndices(IS_act,&idx_act);
1540:       IS_redact  = PETSC_NULL;
1541:       if(vi->checkredundancy) {
1542:         (*vi->checkredundancy)(snes,IS_act,&IS_redact,vi->ctxP);
1543:       }

1545:       if(!IS_redact) {
1546:         /* User called checkredundancy function but didn't create IS_redact because
1547:            there were no redundant active set variables */
1548:         /* Copy over all active set indices to the list */
1549:         PetscMalloc(nis_act*sizeof(PetscInt),&idx_actkept);
1550:         for(k=0;k < nis_act;k++) idx_actkept[k] = idx_act[k];
1551:         nkept = nis_act;
1552:       } else {
1553:         ISGetLocalSize(IS_redact,&nis_redact);
1554:         PetscMalloc((nis_act-nis_redact)*sizeof(PetscInt),&idx_actkept);

1556:         /* Create reduced active set list */
1557:         ISGetIndices(IS_act,&idx_act);
1558:         ISGetIndices(IS_redact,&idx_redact);
1559:         j1 = 0;nkept = 0;
1560:         for(k=0;k<nis_act;k++) {
1561:           if(j1 < nis_redact && idx_act[k] == idx_redact[j1]) j1++;
1562:           else idx_actkept[nkept++] = idx_act[k];
1563:         }
1564:         ISRestoreIndices(IS_act,&idx_act);
1565:         ISRestoreIndices(IS_redact,&idx_redact);

1567:         ISDestroy(&IS_redact);
1568:       }

1570:       /* Create augmented F and Y */
1571:       VecCreate(((PetscObject)snes)->comm,&F_aug);
1572:       VecSetSizes(F_aug,F->map->n+nkept,PETSC_DECIDE);
1573:       VecSetFromOptions(F_aug);
1574:       VecDuplicate(F_aug,&Y_aug);
1575: 
1576:       /* Copy over F to F_aug in the first n locations */
1577:       VecGetArray(F,&f);
1578:       VecGetArray(F_aug,&f2);
1579:       PetscMemcpy(f2,f,F->map->n*sizeof(PetscScalar));
1580:       VecRestoreArray(F,&f);
1581:       VecRestoreArray(F_aug,&f2);
1582: 
1583:       /* Create the augmented jacobian matrix */
1584:       MatCreate(((PetscObject)snes)->comm,&J_aug);
1585:       MatSetSizes(J_aug,X->map->n+nkept,X->map->n+nkept,PETSC_DECIDE,PETSC_DECIDE);
1586:       MatSetFromOptions(J_aug);
1587: 

1589:       { /* local vars */
1590:       /* Preallocate augmented matrix and set values in it...Doing only sequential case first*/
1591:       PetscInt          ncols;
1592:       const PetscInt    *cols;
1593:       const PetscScalar *vals;
1594:       PetscScalar        value[2];
1595:       PetscInt           row,col[2];
1596:       PetscInt           *d_nnz;
1597:       value[0] = 1.0; value[1] = 0.0;
1598:       PetscMalloc((X->map->n+nkept)*sizeof(PetscInt),&d_nnz);
1599:       PetscMemzero(d_nnz,(X->map->n+nkept)*sizeof(PetscInt));
1600:       for(row=0;row<snes->jacobian->rmap->n;row++) {
1601:         MatGetRow(snes->jacobian,row,&ncols,PETSC_NULL,PETSC_NULL);
1602:         d_nnz[row] += ncols;
1603:         MatRestoreRow(snes->jacobian,row,&ncols,PETSC_NULL,PETSC_NULL);
1604:       }

1606:       for(k=0;k<nkept;k++) {
1607:         d_nnz[idx_actkept[k]] += 1;
1608:         d_nnz[snes->jacobian->rmap->n+k] += 2;
1609:       }
1610:       MatSeqAIJSetPreallocation(J_aug,PETSC_NULL,d_nnz);
1611: 
1612:       PetscFree(d_nnz);

1614:       /* Set the original jacobian matrix in J_aug */
1615:       for(row=0;row<snes->jacobian->rmap->n;row++) {
1616:         MatGetRow(snes->jacobian,row,&ncols,&cols,&vals);
1617:         MatSetValues(J_aug,1,&row,ncols,cols,vals,INSERT_VALUES);
1618:         MatRestoreRow(snes->jacobian,row,&ncols,&cols,&vals);
1619:       }
1620:       /* Add the augmented part */
1621:       for(k=0;k<nkept;k++) {
1622:         row = snes->jacobian->rmap->n+k;
1623:         col[0] = idx_actkept[k]; col[1] = snes->jacobian->rmap->n+k;
1624:         MatSetValues(J_aug,1,&row,1,col,value,INSERT_VALUES);
1625:         MatSetValues(J_aug,1,&col[0],1,&row,&value[0],INSERT_VALUES);
1626:       }
1627:       MatAssemblyBegin(J_aug,MAT_FINAL_ASSEMBLY);
1628:       MatAssemblyEnd(J_aug,MAT_FINAL_ASSEMBLY);
1629:       /* Only considering prejac = jac for now */
1630:       Jpre_aug = J_aug;
1631:       } /* local vars*/
1632:       ISRestoreIndices(IS_act,&idx_act);
1633:       ISDestroy(&IS_act);
1634:     } else {
1635:       F_aug = F; J_aug = snes->jacobian; Y_aug = Y; Jpre_aug = snes->jacobian_pre;
1636:     }

1638:     ISEqual(vi->IS_inact_prev,IS_inact,&isequal);
1639:     if (!isequal) {
1640:       SNESVIResetPCandKSP(snes,J_aug,Jpre_aug);
1641:     }
1642:     KSPSetOperators(snes->ksp,J_aug,Jpre_aug,flg);
1643:     KSPSetUp(snes->ksp);
1644:     /*  {
1645:       PC        pc;
1646:       PetscBool flg;
1647:       KSPGetPC(snes->ksp,&pc);
1648:       PetscTypeCompare((PetscObject)pc,PCFIELDSPLIT,&flg);
1649:       if (flg) {
1650:         KSP      *subksps;
1651:         PCFieldSplitGetSubKSP(pc,PETSC_NULL,&subksps);
1652:         KSPGetPC(subksps[0],&pc);
1653:         PetscFree(subksps);
1654:         PetscTypeCompare((PetscObject)pc,PCBJACOBI,&flg);
1655:         if (flg) {
1656:           PetscInt       n,N = 101*101,j,cnts[3] = {0,0,0};
1657:           const PetscInt *ii;

1659:           ISGetSize(IS_inact,&n);
1660:           ISGetIndices(IS_inact,&ii);
1661:           for (j=0; j<n; j++) {
1662:             if (ii[j] < N) cnts[0]++;
1663:             else if (ii[j] < 2*N) cnts[1]++;
1664:             else if (ii[j] < 3*N) cnts[2]++;
1665:           }
1666:           ISRestoreIndices(IS_inact,&ii);

1668:           PCBJacobiSetTotalBlocks(pc,3,cnts);
1669:         }
1670:       }
1671:     }
1672:     */
1673:     SNES_KSPSolve(snes,snes->ksp,F_aug,Y_aug);
1674:     KSPGetConvergedReason(snes->ksp,&kspreason);
1675:     if (kspreason < 0) {
1676:       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
1677:         PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);
1678:         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
1679:         break;
1680:       }
1681:     }

1683:     if(nis_act) {
1684:       PetscScalar *y1,*y2;
1685:       VecGetArray(Y,&y1);
1686:       VecGetArray(Y_aug,&y2);
1687:       /* Copy over inactive Y_aug to Y */
1688:       j1 = 0;
1689:       for(i1=Y->map->rstart;i1 < Y->map->rend;i1++) {
1690:         if(j1 < nkept && idx_actkept[j1] == i1) j1++;
1691:         else y1[i1-Y->map->rstart] = y2[i1-Y->map->rstart];
1692:       }
1693:       VecRestoreArray(Y,&y1);
1694:       VecRestoreArray(Y_aug,&y2);

1696:       VecDestroy(&F_aug);
1697:       VecDestroy(&Y_aug);
1698:       MatDestroy(&J_aug);
1699:       PetscFree(idx_actkept);
1700:     }
1701: 
1702:     if (!isequal) {
1703:       ISDestroy(&vi->IS_inact_prev);
1704:       ISDuplicate(IS_inact,&vi->IS_inact_prev);
1705:     }
1706:     ISDestroy(&IS_inact);

1708:     KSPGetIterationNumber(snes->ksp,&lits);
1709:     snes->linear_its += lits;
1710:     PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);
1711:     /*
1712:     if (vi->precheckstep) {
1713:       PetscBool changed_y = PETSC_FALSE;
1714:       (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);
1715:     }

1717:     if (PetscLogPrintInfo){
1718:       SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);
1719:     }
1720:     */
1721:     /* Compute a (scaled) negative update in the line search routine: 
1722:          Y <- X - lambda*Y 
1723:        and evaluate G = function(Y) (depends on the line search). 
1724:     */
1725:     VecCopy(Y,snes->vec_sol_update);
1726:     ynorm = 1; gnorm = fnorm;
1727:     (*vi->LineSearch)(snes,vi->lsP,X,F,G,Y,W,fnorm,xnorm,&ynorm,&gnorm,&lssucceed);
1728:     PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);
1729:     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
1730:     if (snes->domainerror) {
1731:       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
1732:       return(0);
1733:     }
1734:     if (!lssucceed) {
1735:       if (++snes->numFailures >= snes->maxFailures) {
1736:         PetscBool ismin;
1737:         snes->reason = SNES_DIVERGED_LINE_SEARCH;
1738:         SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);
1739:         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
1740:         break;
1741:       }
1742:     }
1743:     /* Update function and solution vectors */
1744:     fnorm = gnorm;
1745:     VecCopy(G,F);
1746:     VecCopy(W,X);
1747:     /* Monitor convergence */
1748:     PetscObjectTakeAccess(snes);
1749:     snes->iter = i+1;
1750:     snes->norm = fnorm;
1751:     PetscObjectGrantAccess(snes);
1752:     SNESLogConvHistory(snes,snes->norm,lits);
1753:     SNESMonitor(snes,snes->iter,snes->norm);
1754:     /* Test for convergence, xnorm = || X || */
1755:     if (snes->ops->converged != SNESSkipConverged) { VecNorm(X,NORM_2,&xnorm); }
1756:     (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);
1757:     if (snes->reason) break;
1758:   }
1759:   if (i == maxits) {
1760:     PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);
1761:     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
1762:   }
1763:   return(0);
1764: }

1766: /* -------------------------------------------------------------------------- */
1767: /*
1768:    SNESSetUp_VI - Sets up the internal data structures for the later use
1769:    of the SNESVI nonlinear solver.

1771:    Input Parameter:
1772: .  snes - the SNES context
1773: .  x - the solution vector

1775:    Application Interface Routine: SNESSetUp()

1777:    Notes:
1778:    For basic use of the SNES solvers, the user need not explicitly call
1779:    SNESSetUp(), since these actions will automatically occur during
1780:    the call to SNESSolve().
1781:  */
1784: PetscErrorCode SNESSetUp_VI(SNES snes)
1785: {
1787:   SNES_VI        *vi = (SNES_VI*) snes->data;
1788:   PetscInt       i_start[3],i_end[3];


1792:   SNESDefaultGetWork(snes,3);

1794:   if (vi->computevariablebounds) {
1795:     if (!vi->xl) {VecDuplicate(snes->vec_sol,&vi->xl);}
1796:     if (!vi->xu) {VecDuplicate(snes->vec_sol,&vi->xu);}
1797:     (*vi->computevariablebounds)(snes,vi->xl,vi->xu);
1798:   } else if (!vi->xl && !vi->xu) {
1799:     /* If the lower and upper bound on variables are not set, set it to -Inf and Inf */
1800:     VecDuplicate(snes->vec_sol, &vi->xl);
1801:     VecSet(vi->xl,SNES_VI_NINF);
1802:     VecDuplicate(snes->vec_sol, &vi->xu);
1803:     VecSet(vi->xu,SNES_VI_INF);
1804:   } else {
1805:     /* Check if lower bound, upper bound and solution vector distribution across the processors is identical */
1806:     VecGetOwnershipRange(snes->vec_sol,i_start,i_end);
1807:     VecGetOwnershipRange(vi->xl,i_start+1,i_end+1);
1808:     VecGetOwnershipRange(vi->xu,i_start+2,i_end+2);
1809:     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]))
1810:       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.");
1811:   }
1812:   if (snes->ops->solve != SNESSolveVI_SS) {
1813:     /* Set up previous active index set for the first snes solve 
1814:        vi->IS_inact_prev = 0,1,2,....N */
1815:     PetscInt *indices;
1816:     PetscInt  i,n,rstart,rend;

1818:     VecGetOwnershipRange(snes->vec_sol,&rstart,&rend);
1819:     VecGetLocalSize(snes->vec_sol,&n);
1820:     PetscMalloc(n*sizeof(PetscInt),&indices);
1821:     for(i=0;i < n; i++) indices[i] = rstart + i;
1822:     ISCreateGeneral(((PetscObject)snes)->comm,n,indices,PETSC_OWN_POINTER,&vi->IS_inact_prev);
1823:   }

1825:   if (snes->ops->solve == SNESSolveVI_SS) {
1826:     VecDuplicate(snes->vec_sol, &vi->dpsi);
1827:     VecDuplicate(snes->vec_sol, &vi->phi);
1828:     VecDuplicate(snes->vec_sol, &vi->Da);
1829:     VecDuplicate(snes->vec_sol, &vi->Db);
1830:     VecDuplicate(snes->vec_sol, &vi->z);
1831:     VecDuplicate(snes->vec_sol, &vi->t);
1832:   }
1833:   return(0);
1834: }
1835: /* -------------------------------------------------------------------------- */
1838: PetscErrorCode SNESReset_VI(SNES snes)
1839: {
1840:   SNES_VI        *vi = (SNES_VI*) snes->data;

1844:   VecDestroy(&vi->xl);
1845:   VecDestroy(&vi->xu);
1846:   if (snes->ops->solve != SNESSolveVI_SS) {
1847:     ISDestroy(&vi->IS_inact_prev);
1848:   }
1849:   return(0);
1850: }

1852: /*
1853:    SNESDestroy_VI - Destroys the private SNES_VI context that was created
1854:    with SNESCreate_VI().

1856:    Input Parameter:
1857: .  snes - the SNES context

1859:    Application Interface Routine: SNESDestroy()
1860:  */
1863: PetscErrorCode SNESDestroy_VI(SNES snes)
1864: {
1865:   SNES_VI        *vi = (SNES_VI*) snes->data;


1870:   if (snes->ops->solve == SNESSolveVI_SS) {
1871:     /* clear vectors */
1872:     VecDestroy(&vi->dpsi);
1873:     VecDestroy(&vi->phi);
1874:     VecDestroy(&vi->Da);
1875:     VecDestroy(&vi->Db);
1876:     VecDestroy(&vi->z);
1877:     VecDestroy(&vi->t);
1878:   }
1879: 
1880:   PetscViewerDestroy(&vi->lsmonitor);
1881:   PetscFree(snes->data);

1883:   /* clear composed functions */
1884:   PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","",PETSC_NULL);
1885:   PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","",PETSC_NULL);
1886:   return(0);
1887: }

1889: /* -------------------------------------------------------------------------- */

1893: /*
1894:   This routine does not actually do a line search but it takes a full newton
1895:   step while ensuring that the new iterates remain within the constraints.
1896:   
1897: */
1898: PetscErrorCode SNESLineSearchNo_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscBool *flag)
1899: {
1901:   SNES_VI        *vi = (SNES_VI*)snes->data;
1902:   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;

1905:   *flag = PETSC_TRUE;
1906:   PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);
1907:   VecNorm(y,NORM_2,ynorm);         /* ynorm = || y || */
1908:   VecWAXPY(w,-1.0,y,x);            /* w <- x - y   */
1909:   SNESVIProjectOntoBounds(snes,w);
1910:   if (vi->postcheckstep) {
1911:    (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);
1912:   }
1913:   if (changed_y) {
1914:     VecWAXPY(w,-1.0,y,x);            /* w <- x - y   */
1915:     SNESVIProjectOntoBounds(snes,w);
1916:   }
1917:   SNESVIProjectOntoBounds(snes,w);
1918:   SNESComputeFunction(snes,w,g);
1919:   if (!snes->domainerror) {
1920:     if (snes->ops->solve != SNESSolveVI_SS) {
1921:        SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);
1922:     } else {
1923:       VecNorm(g,NORM_2,gnorm);  /* gnorm = || g || */
1924:     }
1925:     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1926:   }
1927:   if (vi->lsmonitor) {
1928:     PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
1929:     PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %g gnorm %g\n",(double)fnorm,(double)*gnorm);
1930:     PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
1931:   }
1932:   PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
1933:   return(0);
1934: }

1936: /* -------------------------------------------------------------------------- */

1940: /*
1941:   This routine is a copy of SNESLineSearchNoNorms in snes/impls/ls/ls.c
1942: */
1943: PetscErrorCode SNESLineSearchNoNorms_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscBool *flag)
1944: {
1946:   SNES_VI        *vi = (SNES_VI*)snes->data;
1947:   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;

1950:   *flag = PETSC_TRUE;
1951:   PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);
1952:   VecWAXPY(w,-1.0,y,x);            /* w <- x - y      */
1953:   SNESVIProjectOntoBounds(snes,w);
1954:   if (vi->postcheckstep) {
1955:    (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);
1956:   }
1957:   if (changed_y) {
1958:     VecWAXPY(w,-1.0,y,x);            /* w <- x - y   */
1959:     SNESVIProjectOntoBounds(snes,w);
1960:   }
1961: 
1962:   /* don't evaluate function the last time through */
1963:   if (snes->iter < snes->max_its-1) {
1964:     SNESComputeFunction(snes,w,g);
1965:   }
1966:   PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
1967:   return(0);
1968: }

1970: /* -------------------------------------------------------------------------- */
1973: /*
1974:   This routine implements a cubic line search while doing a projection on the variable bounds
1975: */
1976: PetscErrorCode SNESLineSearchCubic_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscBool *flag)
1977: {
1978:   PetscReal      initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
1979:   PetscReal      minlambda,lambda,lambdatemp;
1980: #if defined(PETSC_USE_COMPLEX)
1981:   PetscScalar    cinitslope;
1982: #endif
1984:   PetscInt       count;
1985:   SNES_VI        *vi = (SNES_VI*)snes->data;
1986:   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1987:   MPI_Comm       comm;

1990:   PetscObjectGetComm((PetscObject)snes,&comm);
1991:   PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);
1992:   *flag   = PETSC_TRUE;

1994:   VecNorm(y,NORM_2,ynorm);
1995:   if (*ynorm == 0.0) {
1996:     if (vi->lsmonitor) {
1997:       PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
1998:       PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Initial direction and size is 0\n");
1999:       PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2000:     }
2001:     *gnorm = fnorm;
2002:     VecCopy(x,w);
2003:     VecCopy(f,g);
2004:     *flag  = PETSC_FALSE;
2005:     goto theend1;
2006:   }
2007:   if (*ynorm > vi->maxstep) {        /* Step too big, so scale back */
2008:     if (vi->lsmonitor) {
2009:       PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2010:       PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Scaling step by %g old ynorm %g\n",(double)vi->maxstep/(*ynorm),(double)*ynorm);
2011:       PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2012:     }
2013:     VecScale(y,vi->maxstep/(*ynorm));
2014:     *ynorm = vi->maxstep;
2015:   }
2016:   VecMaxPointwiseDivide(y,x,&rellength);
2017:   minlambda = vi->minlambda/rellength;
2018:   MatMult(snes->jacobian,y,w);
2019: #if defined(PETSC_USE_COMPLEX)
2020:   VecDot(f,w,&cinitslope);
2021:   initslope = PetscRealPart(cinitslope);
2022: #else
2023:   VecDot(f,w,&initslope);
2024: #endif
2025:   if (initslope > 0.0)  initslope = -initslope;
2026:   if (initslope == 0.0) initslope = -1.0;

2028:   VecWAXPY(w,-1.0,y,x);
2029:   SNESVIProjectOntoBounds(snes,w);
2030:   if (snes->nfuncs >= snes->max_funcs) {
2031:     PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");
2032:     *flag = PETSC_FALSE;
2033:     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
2034:     goto theend1;
2035:   }
2036:   SNESComputeFunction(snes,w,g);
2037:   if (snes->ops->solve != SNESSolveVI_SS) {
2038:     SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);
2039:   } else {
2040:     VecNorm(g,NORM_2,gnorm);
2041:   }
2042:   if (snes->domainerror) {
2043:     PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
2044:     return(0);
2045:   }
2046:   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2047:   PetscInfo4(snes,"Initial fnorm %g gnorm %g alpha %g initslope %g\n",(double)fnorm,(double)*gnorm,(double)vi->alpha,(double)initslope);
2048:   if ((*gnorm)*(*gnorm) <= (1.0 - vi->alpha)*fnorm*fnorm ) { /* Sufficient reduction */
2049:     if (vi->lsmonitor) {
2050:       PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2051:       PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %g gnorm %g\n",(double)fnorm,(double)*gnorm);
2052:       PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2053:     }
2054:     goto theend1;
2055:   }

2057:   /* Fit points with quadratic */
2058:   lambda     = 1.0;
2059:   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
2060:   lambdaprev = lambda;
2061:   gnormprev  = *gnorm;
2062:   if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
2063:   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
2064:   else                         lambda = lambdatemp;

2066:   VecWAXPY(w,-lambda,y,x);
2067:   SNESVIProjectOntoBounds(snes,w);
2068:   if (snes->nfuncs >= snes->max_funcs) {
2069:     PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);
2070:     *flag = PETSC_FALSE;
2071:     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
2072:     goto theend1;
2073:   }
2074:   SNESComputeFunction(snes,w,g);
2075:   if (snes->ops->solve != SNESSolveVI_SS) {
2076:     SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);
2077:   } else {
2078:     VecNorm(g,NORM_2,gnorm);
2079:   }
2080:   if (snes->domainerror) {
2081:     PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
2082:     return(0);
2083:   }
2084:   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2085:   if (vi->lsmonitor) {
2086:     PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2087:     PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: gnorm after quadratic fit %g\n",(double)*gnorm);
2088:     PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2089:   }
2090:   if ((*gnorm)*(*gnorm) < (1.0 - vi->alpha)*fnorm*fnorm ) { /* sufficient reduction */
2091:     if (vi->lsmonitor) {
2092:       PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2093:       PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Quadratically determined step, lambda=%18.16e\n",lambda);
2094:       PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2095:     }
2096:     goto theend1;
2097:   }

2099:   /* Fit points with cubic */
2100:   count = 1;
2101:   while (PETSC_TRUE) {
2102:     if (lambda <= minlambda) {
2103:       if (vi->lsmonitor) {
2104:         PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2105:          PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: unable to find good step length! After %D tries \n",count);
2106:         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);
2107:         PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2108:       }
2109:       *flag = PETSC_FALSE;
2110:       break;
2111:     }
2112:     t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
2113:     t2 = .5*(gnormprev*gnormprev  - fnorm*fnorm) - lambdaprev*initslope;
2114:     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2115:     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2116:     d  = b*b - 3*a*initslope;
2117:     if (d < 0.0) d = 0.0;
2118:     if (a == 0.0) {
2119:       lambdatemp = -initslope/(2.0*b);
2120:     } else {
2121:       lambdatemp = (-b + sqrt(d))/(3.0*a);
2122:     }
2123:     lambdaprev = lambda;
2124:     gnormprev  = *gnorm;
2125:     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
2126:     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
2127:     else                         lambda     = lambdatemp;
2128:     VecWAXPY(w,-lambda,y,x);
2129:     SNESVIProjectOntoBounds(snes,w);
2130:     if (snes->nfuncs >= snes->max_funcs) {
2131:       PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);
2132:       PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);
2133:       *flag = PETSC_FALSE;
2134:       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
2135:       break;
2136:     }
2137:     SNESComputeFunction(snes,w,g);
2138:     if (snes->ops->solve != SNESSolveVI_SS) {
2139:       SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);
2140:     } else {
2141:       VecNorm(g,NORM_2,gnorm);
2142:     }
2143:     if (snes->domainerror) {
2144:       PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
2145:       return(0);
2146:     }
2147:     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2148:     if ((*gnorm)*(*gnorm) < (1.0 - vi->alpha)*fnorm*fnorm) { /* is reduction enough? */
2149:       if (vi->lsmonitor) {
2150:         PetscPrintf(comm,"    Line search: Cubically determined step, current gnorm %g lambda=%18.16e\n",(double)*gnorm,(double)lambda);
2151:       }
2152:       break;
2153:     } else {
2154:       if (vi->lsmonitor) {
2155:         PetscPrintf(comm,"    Line search: Cubic step no good, shrinking lambda, current gnorm %g lambda=%18.16e\n",(double)*gnorm,(double)lambda);
2156:       }
2157:     }
2158:     count++;
2159:   }
2160:   theend1:
2161:   /* Optional user-defined check for line search step validity */
2162:   if (vi->postcheckstep && *flag) {
2163:     (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);
2164:     if (changed_y) {
2165:       VecWAXPY(w,-1.0,y,x);
2166:       SNESVIProjectOntoBounds(snes,w);
2167:     }
2168:     if (changed_y || changed_w) { /* recompute the function if the step has changed */
2169:       SNESComputeFunction(snes,w,g);
2170:       if (snes->ops->solve != SNESSolveVI_SS) {
2171:         SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);
2172:       } else {
2173:         VecNorm(g,NORM_2,gnorm);
2174:       }
2175:       if (snes->domainerror) {
2176:         PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
2177:         return(0);
2178:       }
2179:       if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2180:       VecNormBegin(y,NORM_2,ynorm);
2181:       VecNormEnd(y,NORM_2,ynorm);
2182:     }
2183:   }
2184:   PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
2185:   return(0);
2186: }

2190: /*
2191:   This routine does a quadratic line search while keeping the iterates within the variable bounds
2192: */
2193: PetscErrorCode SNESLineSearchQuadratic_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscBool *flag)
2194: {
2195:   /* 
2196:      Note that for line search purposes we work with with the related
2197:      minimization problem:
2198:         min  z(x):  R^n -> R,
2199:      where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
2200:    */
2201:   PetscReal      initslope,minlambda,lambda,lambdatemp,rellength;
2202: #if defined(PETSC_USE_COMPLEX)
2203:   PetscScalar    cinitslope;
2204: #endif
2206:   PetscInt       count;
2207:   SNES_VI        *vi = (SNES_VI*)snes->data;
2208:   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;

2211:   PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);
2212:   *flag   = PETSC_TRUE;

2214:   VecNorm(y,NORM_2,ynorm);
2215:   if (*ynorm == 0.0) {
2216:     if (vi->lsmonitor) {
2217:       PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2218:       PetscViewerASCIIPrintf(vi->lsmonitor,"Line search: Direction and size is 0\n");
2219:       PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2220:     }
2221:     *gnorm = fnorm;
2222:     VecCopy(x,w);
2223:     VecCopy(f,g);
2224:     *flag  = PETSC_FALSE;
2225:     goto theend2;
2226:   }
2227:   if (*ynorm > vi->maxstep) {        /* Step too big, so scale back */
2228:     VecScale(y,vi->maxstep/(*ynorm));
2229:     *ynorm = vi->maxstep;
2230:   }
2231:   VecMaxPointwiseDivide(y,x,&rellength);
2232:   minlambda = vi->minlambda/rellength;
2233:   MatMult(snes->jacobian,y,w);
2234: #if defined(PETSC_USE_COMPLEX)
2235:   VecDot(f,w,&cinitslope);
2236:   initslope = PetscRealPart(cinitslope);
2237: #else
2238:   VecDot(f,w,&initslope);
2239: #endif
2240:   if (initslope > 0.0)  initslope = -initslope;
2241:   if (initslope == 0.0) initslope = -1.0;
2242:   PetscInfo1(snes,"Initslope %G \n",initslope);

2244:   VecWAXPY(w,-1.0,y,x);
2245:   SNESVIProjectOntoBounds(snes,w);
2246:   if (snes->nfuncs >= snes->max_funcs) {
2247:     PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");
2248:     *flag = PETSC_FALSE;
2249:     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
2250:     goto theend2;
2251:   }
2252:   SNESComputeFunction(snes,w,g);
2253:   if (snes->ops->solve != SNESSolveVI_SS) {
2254:     SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);
2255:   } else {
2256:     VecNorm(g,NORM_2,gnorm);
2257:   }
2258:   if (snes->domainerror) {
2259:     PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
2260:     return(0);
2261:   }
2262:   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2263:   if ((*gnorm)*(*gnorm) <= (1.0 - vi->alpha)*fnorm*fnorm) { /* Sufficient reduction */
2264:     if (vi->lsmonitor) {
2265:       PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2266:       PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);
2267:       PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2268:     }
2269:     goto theend2;
2270:   }

2272:   /* Fit points with quadratic */
2273:   lambda = 1.0;
2274:   count = 1;
2275:   while (PETSC_TRUE) {
2276:     if (lambda <= minlambda) { /* bad luck; use full step */
2277:       if (vi->lsmonitor) {
2278:         PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2279:         PetscViewerASCIIPrintf(vi->lsmonitor,"Line search: Unable to find good step length! %D \n",count);
2280:         PetscViewerASCIIPrintf(vi->lsmonitor,"Line search: fnorm=%G, gnorm=%G, ynorm=%G, lambda=%G, initial slope=%G\n",fnorm,*gnorm,*ynorm,lambda,initslope);
2281:         PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2282:       }
2283:       VecCopy(x,w);
2284:       *flag = PETSC_FALSE;
2285:       break;
2286:     }
2287:     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
2288:     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
2289:     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
2290:     else                         lambda     = lambdatemp;
2291: 
2292:     VecWAXPY(w,-lambda,y,x);
2293:     SNESVIProjectOntoBounds(snes,w);
2294:     if (snes->nfuncs >= snes->max_funcs) {
2295:       PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);
2296:       PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);
2297:       *flag = PETSC_FALSE;
2298:       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
2299:       break;
2300:     }
2301:     SNESComputeFunction(snes,w,g);
2302:     if (snes->domainerror) {
2303:       PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
2304:       return(0);
2305:     }
2306:     if (snes->ops->solve != SNESSolveVI_SS) {
2307:       SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);
2308:     } else {
2309:       VecNorm(g,NORM_2,gnorm);
2310:     }
2311:     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2312:     if ((*gnorm)*(*gnorm) < (1.0 - vi->alpha)*fnorm*fnorm) { /* sufficient reduction */
2313:       if (vi->lsmonitor) {
2314:         PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2315:         PetscViewerASCIIPrintf(vi->lsmonitor,"    Line Search: Quadratically determined step, lambda=%G\n",lambda);
2316:         PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);
2317:       }
2318:       break;
2319:     }
2320:     count++;
2321:   }
2322:   theend2:
2323:   /* Optional user-defined check for line search step validity */
2324:   if (vi->postcheckstep) {
2325:     (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);
2326:     if (changed_y) {
2327:       VecWAXPY(w,-1.0,y,x);
2328:       SNESVIProjectOntoBounds(snes,w);
2329:     }
2330:     if (changed_y || changed_w) { /* recompute the function if the step has changed */
2331:       SNESComputeFunction(snes,w,g);
2332:       if (snes->domainerror) {
2333:         PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
2334:         return(0);
2335:       }
2336:       if (snes->ops->solve != SNESSolveVI_SS) {
2337:         SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);
2338:       } else {
2339:         VecNorm(g,NORM_2,gnorm);
2340:       }

2342:       VecNormBegin(y,NORM_2,ynorm);
2343:       VecNormEnd(y,NORM_2,ynorm);
2344:       if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2345:     }
2346:   }
2347:   PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
2348:   return(0);
2349: }

2352: /* -------------------------------------------------------------------------- */
2356: PetscErrorCode  SNESLineSearchSet_VI(SNES snes,FCN2 func,void *lsctx)
2357: {
2359:   ((SNES_VI *)(snes->data))->LineSearch = func;
2360:   ((SNES_VI *)(snes->data))->lsP        = lsctx;
2361:   return(0);
2362: }

2365: /* -------------------------------------------------------------------------- */
2369: PetscErrorCode  SNESLineSearchSetMonitor_VI(SNES snes,PetscBool flg)
2370: {
2371:   SNES_VI        *vi = (SNES_VI*)snes->data;

2375:   if (flg && !vi->lsmonitor) {
2376:     PetscViewerASCIIOpen(((PetscObject)snes)->comm,"stdout",&vi->lsmonitor);
2377:   } else if (!flg && vi->lsmonitor) {
2378:     PetscViewerDestroy(&vi->lsmonitor);
2379:   }
2380:   return(0);
2381: }

2384: /*
2385:    SNESView_VI - Prints info from the SNESVI data structure.

2387:    Input Parameters:
2388: .  SNES - the SNES context
2389: .  viewer - visualization context

2391:    Application Interface Routine: SNESView()
2392: */
2395: static PetscErrorCode SNESView_VI(SNES snes,PetscViewer viewer)
2396: {
2397:   SNES_VI        *vi = (SNES_VI *)snes->data;
2398:   const char     *cstr,*tstr;
2400:   PetscBool     iascii;

2403:   PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
2404:   if (iascii) {
2405:     if (vi->LineSearch == SNESLineSearchNo_VI)             cstr = "SNESLineSearchNo";
2406:     else if (vi->LineSearch == SNESLineSearchQuadratic_VI) cstr = "SNESLineSearchQuadratic";
2407:     else if (vi->LineSearch == SNESLineSearchCubic_VI)     cstr = "SNESLineSearchCubic";
2408:     else                                                   cstr = "unknown";
2409:     if (snes->ops->solve == SNESSolveVI_SS)         tstr = "Semismooth";
2410:     else if (snes->ops->solve == SNESSolveVI_RS)    tstr = "Reduced Space";
2411:     else if (snes->ops->solve == SNESSolveVI_RSAUG) tstr = "Reduced space with augmented variables";
2412:     else                                         tstr = "unknown";
2413:     PetscViewerASCIIPrintf(viewer,"  VI algorithm: %s\n",tstr);
2414:     PetscViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);
2415:     PetscViewerASCIIPrintf(viewer,"  alpha=%G, maxstep=%G, minlambda=%G\n",vi->alpha,vi->maxstep,vi->minlambda);
2416:   }
2417:   return(0);
2418: }

2422: /*@
2423:    SNESVISetVariableBounds - Sets the lower and upper bounds for the solution vector. xl <= x <= xu.

2425:    Input Parameters:
2426: .  snes - the SNES context.
2427: .  xl   - lower bound.
2428: .  xu   - upper bound.

2430:    Notes:
2431:    If this routine is not called then the lower and upper bounds are set to 
2432:    SNES_VI_INF and SNES_VI_NINF respectively during SNESSetUp().

2434:    Level: advanced

2436: @*/
2437: PetscErrorCode SNESVISetVariableBounds(SNES snes, Vec xl, Vec xu)
2438: {
2439:   SNES_VI           *vi;
2440:   PetscErrorCode    ierr;
2441:   const PetscScalar *xxl,*xxu;
2442:   PetscInt          i,n, cnt = 0;

2448:   if (!snes->vec_func) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call SNESSetFunction() first");
2449:   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);
2450:   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);
2451:   SNESSetType(snes,SNESVI);
2452:   vi = (SNES_VI*)snes->data;
2453:   PetscObjectReference((PetscObject)xl);
2454:   PetscObjectReference((PetscObject)xu);
2455:   VecDestroy(&vi->xl);
2456:   VecDestroy(&vi->xu);
2457:   vi->xl = xl;
2458:   vi->xu = xu;
2459:   VecGetLocalSize(xl,&n);
2460:   VecGetArrayRead(xl,&xxl);
2461:   VecGetArrayRead(xu,&xxu);
2462:   for (i=0; i<n; i++) {
2463:     cnt += ((xxl[i] != SNES_VI_NINF) || (xxu[i] != SNES_VI_INF));
2464:   }
2465:   MPI_Allreduce(&cnt,&vi->ntruebounds,1,MPIU_INT,MPI_SUM,((PetscObject)snes)->comm);
2466:   VecRestoreArrayRead(xl,&xxl);
2467:   VecRestoreArrayRead(xu,&xxu);
2468:   return(0);
2469: }

2471: /* -------------------------------------------------------------------------- */
2472: /*
2473:    SNESSetFromOptions_VI - Sets various parameters for the SNESVI method.

2475:    Input Parameter:
2476: .  snes - the SNES context

2478:    Application Interface Routine: SNESSetFromOptions()
2479: */
2482: static PetscErrorCode SNESSetFromOptions_VI(SNES snes)
2483: {
2484:   SNES_VI        *vi = (SNES_VI *)snes->data;
2485:   const char     *lses[] = {"basic","basicnonorms","quadratic","cubic"};
2486:   const char     *vies[] = {"ss","rs","rsaug"};
2488:   PetscInt       indx;
2489:   PetscBool      flg,set,flg2;

2492:   PetscOptionsHead("SNES semismooth method options");
2493:   PetscOptionsBool("-snes_vi_monitor","Monitor all non-active variables","None",PETSC_FALSE,&flg,0);
2494:   if (flg) {
2495:     SNESMonitorSet(snes,SNESMonitorVI,0,0);
2496:   }
2497:   PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",vi->alpha,&vi->alpha,0);
2498:   PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",vi->maxstep,&vi->maxstep,0);
2499:   PetscOptionsReal("-snes_ls_minlambda","Minimum lambda allowed","None",vi->minlambda,&vi->minlambda,0);
2500:   PetscOptionsReal("-snes_vi_const_tol","constraint tolerance","None",vi->const_tol,&vi->const_tol,0);
2501:   PetscOptionsBool("-snes_ls_monitor","Print progress of line searches","SNESLineSearchSetMonitor",vi->lsmonitor ? PETSC_TRUE : PETSC_FALSE,&flg,&set);
2502:   if (set) {SNESLineSearchSetMonitor(snes,flg);}
2503:   PetscOptionsEList("-snes_vi_type","Semismooth algorithm used","",vies,3,"rs",&indx,&flg2);
2504:   if (flg2) {
2505:     switch (indx) {
2506:     case 0:
2507:       snes->ops->solve = SNESSolveVI_SS;
2508:       break;
2509:     case 1:
2510:       snes->ops->solve = SNESSolveVI_RS;
2511:       break;
2512:     case 2:
2513:       snes->ops->solve = SNESSolveVI_RSAUG;
2514:     }
2515:   }
2516:   PetscOptionsEList("-snes_ls","Line search used","SNESLineSearchSet",lses,4,"cubic",&indx,&flg);
2517:   if (flg) {
2518:     switch (indx) {
2519:     case 0:
2520:       SNESLineSearchSet(snes,SNESLineSearchNo_VI,PETSC_NULL);
2521:       break;
2522:     case 1:
2523:       SNESLineSearchSet(snes,SNESLineSearchNoNorms_VI,PETSC_NULL);
2524:       break;
2525:     case 2:
2526:       SNESLineSearchSet(snes,SNESLineSearchQuadratic_VI,PETSC_NULL);
2527:       break;
2528:     case 3:
2529:       SNESLineSearchSet(snes,SNESLineSearchCubic_VI,PETSC_NULL);
2530:       break;
2531:     }
2532:   }
2533:   PetscOptionsBool("-snes_vi_ignore_function_sign","Ignore the sign of function for active constraints","None",vi->ignorefunctionsign,&vi->ignorefunctionsign,PETSC_NULL);
2534:   PetscOptionsTail();
2535:   return(0);
2536: }
2537: /* -------------------------------------------------------------------------- */
2538: /*MC
2539:       SNESVI - Various solvers for variational inequalities based on Newton's method

2541:    Options Database:
2542: +   -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 
2543:                                 additional variables that enforce the constraints
2544: -   -snes_vi_monitor - prints the number of active constraints at each iteration.


2547:    Level: beginner

2549: .seealso:  SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(), 
2550:            SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(), 
2551:            SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams()

2553: M*/
2557: PetscErrorCode  SNESCreate_VI(SNES snes)
2558: {
2560:   SNES_VI        *vi;

2563:   snes->ops->reset           = SNESReset_VI;
2564:   snes->ops->setup           = SNESSetUp_VI;
2565:   snes->ops->solve           = SNESSolveVI_RS;
2566:   snes->ops->destroy         = SNESDestroy_VI;
2567:   snes->ops->setfromoptions  = SNESSetFromOptions_VI;
2568:   snes->ops->view            = SNESView_VI;
2569:   snes->ops->converged       = SNESDefaultConverged_VI;

2571:   PetscNewLog(snes,SNES_VI,&vi);
2572:   snes->data            = (void*)vi;
2573:   vi->alpha             = 1.e-4;
2574:   vi->maxstep           = 1.e8;
2575:   vi->minlambda         = 1.e-12;
2576:   vi->LineSearch        = SNESLineSearchCubic_VI;
2577:   vi->lsP               = PETSC_NULL;
2578:   vi->postcheckstep     = PETSC_NULL;
2579:   vi->postcheck         = PETSC_NULL;
2580:   vi->precheckstep      = PETSC_NULL;
2581:   vi->precheck          = PETSC_NULL;
2582:   vi->const_tol         =  2.2204460492503131e-16;
2583:   vi->checkredundancy   = PETSC_NULL;

2585:   PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","SNESLineSearchSetMonitor_VI",SNESLineSearchSetMonitor_VI);
2586:   PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","SNESLineSearchSet_VI",SNESLineSearchSet_VI);

2588:   return(0);
2589: }

2594: /*
2595:    SNESVIGetInactiveSet - Gets the global indices for the inactive set variables (these correspond to the degrees of freedom the linear
2596:      system is solved on)

2598:    Input parameter
2599: .  snes - the SNES context

2601:    Output parameter
2602: .  ISact - active set index set

2604:  */
2605: PetscErrorCode SNESVIGetInactiveSet(SNES snes,IS* inact)
2606: {
2607:   SNES_VI          *vi = (SNES_VI*)snes->data;
2609:   *inact = vi->IS_inact_prev;
2610:   return(0);
2611: }