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:       PetscInt       cnt,*nrows,k;
1182:       const PetscInt *krows,*inact;
1183:       PetscInt       rstart=jac_inact_inact->rmap->rstart;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

1566:         ISDestroy(&IS_redact);
1567:       }

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

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

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

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

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

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

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

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

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

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

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

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

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

1774:    Application Interface Routine: SNESSetUp()

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


1791:   SNESDefaultGetWork(snes,3);

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

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

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

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

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

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

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


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

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

1888: /* -------------------------------------------------------------------------- */

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

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

1935: /* -------------------------------------------------------------------------- */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2433:    Level: advanced

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

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

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

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

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

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

2540:    Options Database:
2541: +   -snes_vi_type <ss,rs,rsaug> a semi-smooth solver, a reduced space active set method and a reduced space active set method that does not eliminate the active constraints from the Jacobian instead augments the Jacobian with 
2542:                                 additional variables that enforce the constraints
2543: -   -snes_vi_monitor - prints the number of active constraints at each iteration.


2546:    Level: beginner

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

2552: M*/
2556: PetscErrorCode  SNESCreate_VI(SNES snes)
2557: {
2559:   SNES_VI        *vi;

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

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

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

2587:   return(0);
2588: }

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

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

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

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