xref: /petsc/src/snes/impls/vi/ss/viss.c (revision eabe889f41eab0385d57eba42f0f78f2ecc7ced4)
1 
2 #include <../src/snes/impls/vi/ss/vissimpl.h> /*I "petscsnes.h" I*/
3 #include <../include/petsc-private/kspimpl.h>
4 #include <../include/petsc-private/matimpl.h>
5 #include <../include/petsc-private/dmimpl.h>
6 
7 
8 /*
9   SNESVIComputeMeritFunction - Evaluates the merit function for the mixed complementarity problem.
10 
11   Input Parameter:
12 . phi - the semismooth function
13 
14   Output Parameter:
15 . merit - the merit function
16 . phinorm - ||phi||
17 
18   Notes:
19   The merit function for the mixed complementarity problem is defined as
20      merit = 0.5*phi^T*phi
21 */
22 #undef __FUNCT__
23 #define __FUNCT__ "SNESVIComputeMeritFunction"
24 static PetscErrorCode SNESVIComputeMeritFunction(Vec phi, PetscReal* merit,PetscReal* phinorm)
25 {
26   PetscErrorCode ierr;
27 
28   PetscFunctionBegin;
29   ierr = VecNormBegin(phi,NORM_2,phinorm);CHKERRQ(ierr);
30   ierr = VecNormEnd(phi,NORM_2,phinorm);CHKERRQ(ierr);
31 
32   *merit = 0.5*(*phinorm)*(*phinorm);
33   PetscFunctionReturn(0);
34 }
35 
36 PETSC_STATIC_INLINE PetscScalar Phi(PetscScalar a,PetscScalar b)
37 {
38   return a + b - PetscSqrtScalar(a*a + b*b);
39 }
40 
41 PETSC_STATIC_INLINE PetscScalar DPhi(PetscScalar a,PetscScalar b)
42 {
43   if ((PetscAbsScalar(a) >= 1.e-6) || (PetscAbsScalar(b) >= 1.e-6)) return  1.0 - a/ PetscSqrtScalar(a*a + b*b);
44   else return .5;
45 }
46 
47 /*
48    SNESVIComputeFunction - Reformulates a system of nonlinear equations in mixed complementarity form to a system of nonlinear equations in semismooth form.
49 
50    Input Parameters:
51 .  snes - the SNES context
52 .  x - current iterate
53 .  functx - user defined function context
54 
55    Output Parameters:
56 .  phi - Semismooth function
57 
58 */
59 #undef __FUNCT__
60 #define __FUNCT__ "SNESVIComputeFunction"
61 static PetscErrorCode SNESVIComputeFunction(SNES snes,Vec X,Vec phi,void* functx)
62 {
63   PetscErrorCode  ierr;
64   SNES_VISS       *vi = (SNES_VISS*)snes->data;
65   Vec             Xl = snes->xl,Xu = snes->xu,F = snes->vec_func;
66   PetscScalar     *phi_arr,*x_arr,*f_arr,*l,*u;
67   PetscInt        i,nlocal;
68 
69   PetscFunctionBegin;
70   ierr = (*vi->computeuserfunction)(snes,X,F,functx);CHKERRQ(ierr);
71   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
72   ierr = VecGetArray(X,&x_arr);CHKERRQ(ierr);
73   ierr = VecGetArray(F,&f_arr);CHKERRQ(ierr);
74   ierr = VecGetArray(Xl,&l);CHKERRQ(ierr);
75   ierr = VecGetArray(Xu,&u);CHKERRQ(ierr);
76   ierr = VecGetArray(phi,&phi_arr);CHKERRQ(ierr);
77 
78   for (i=0;i < nlocal;i++) {
79     if ((PetscRealPart(l[i]) <= SNES_VI_NINF) && (PetscRealPart(u[i]) >= SNES_VI_INF)) { /* no constraints on variable */
80       phi_arr[i] = f_arr[i];
81     } else if (PetscRealPart(l[i]) <= SNES_VI_NINF) {                      /* upper bound on variable only */
82       phi_arr[i] = -Phi(u[i] - x_arr[i],-f_arr[i]);
83     } else if (PetscRealPart(u[i]) >= SNES_VI_INF) {                       /* lower bound on variable only */
84       phi_arr[i] = Phi(x_arr[i] - l[i],f_arr[i]);
85     } else if (l[i] == u[i]) {
86       phi_arr[i] = l[i] - x_arr[i];
87     } else {                                                /* both bounds on variable */
88       phi_arr[i] = Phi(x_arr[i] - l[i],-Phi(u[i] - x_arr[i],-f_arr[i]));
89     }
90   }
91 
92   ierr = VecRestoreArray(X,&x_arr);CHKERRQ(ierr);
93   ierr = VecRestoreArray(F,&f_arr);CHKERRQ(ierr);
94   ierr = VecRestoreArray(Xl,&l);CHKERRQ(ierr);
95   ierr = VecRestoreArray(Xu,&u);CHKERRQ(ierr);
96   ierr = VecRestoreArray(phi,&phi_arr);CHKERRQ(ierr);
97   PetscFunctionReturn(0);
98 }
99 
100 /*
101    SNESVIComputeBsubdifferentialVectors - Computes the diagonal shift (Da) and row scaling (Db) vectors needed for the
102                                           the semismooth jacobian.
103 */
104 #undef __FUNCT__
105 #define __FUNCT__ "SNESVIComputeBsubdifferentialVectors"
106 PetscErrorCode SNESVIComputeBsubdifferentialVectors(SNES snes,Vec X,Vec F,Mat jac,Vec Da,Vec Db)
107 {
108   PetscErrorCode ierr;
109   PetscScalar    *l,*u,*x,*f,*da,*db,da1,da2,db1,db2;
110   PetscInt       i,nlocal;
111 
112   PetscFunctionBegin;
113 
114   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
115   ierr = VecGetArray(F,&f);CHKERRQ(ierr);
116   ierr = VecGetArray(snes->xl,&l);CHKERRQ(ierr);
117   ierr = VecGetArray(snes->xu,&u);CHKERRQ(ierr);
118   ierr = VecGetArray(Da,&da);CHKERRQ(ierr);
119   ierr = VecGetArray(Db,&db);CHKERRQ(ierr);
120   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
121 
122   for (i=0;i< nlocal;i++) {
123     if ((PetscRealPart(l[i]) <= SNES_VI_NINF) && (PetscRealPart(u[i]) >= SNES_VI_INF)) {/* no constraints on variable */
124       da[i] = 0;
125       db[i] = 1;
126     } else if (PetscRealPart(l[i]) <= SNES_VI_NINF) {                     /* upper bound on variable only */
127       da[i] = DPhi(u[i] - x[i], -f[i]);
128       db[i] = DPhi(-f[i],u[i] - x[i]);
129     } else if (PetscRealPart(u[i]) >= SNES_VI_INF) {                      /* lower bound on variable only */
130       da[i] = DPhi(x[i] - l[i], f[i]);
131       db[i] = DPhi(f[i],x[i] - l[i]);
132     } else if (l[i] == u[i]) {                              /* fixed variable */
133       da[i] = 1;
134       db[i] = 0;
135     } else {                                                /* upper and lower bounds on variable */
136       da1 = DPhi(x[i] - l[i], -Phi(u[i] - x[i], -f[i]));
137       db1 = DPhi(-Phi(u[i] - x[i], -f[i]),x[i] - l[i]);
138       da2 = DPhi(u[i] - x[i], -f[i]);
139       db2 = DPhi(-f[i],u[i] - x[i]);
140       da[i] = da1 + db1*da2;
141       db[i] = db1*db2;
142     }
143   }
144 
145   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
146   ierr = VecRestoreArray(F,&f);CHKERRQ(ierr);
147   ierr = VecRestoreArray(snes->xl,&l);CHKERRQ(ierr);
148   ierr = VecRestoreArray(snes->xu,&u);CHKERRQ(ierr);
149   ierr = VecRestoreArray(Da,&da);CHKERRQ(ierr);
150   ierr = VecRestoreArray(Db,&db);CHKERRQ(ierr);
151   PetscFunctionReturn(0);
152 }
153 
154 /*
155    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.
156 
157    Input Parameters:
158 .  Da       - Diagonal shift vector for the semismooth jacobian.
159 .  Db       - Row scaling vector for the semismooth jacobian.
160 
161    Output Parameters:
162 .  jac      - semismooth jacobian
163 .  jac_pre  - optional preconditioning matrix
164 
165    Notes:
166    The semismooth jacobian matrix is given by
167    jac = Da + Db*jacfun
168    where Db is the row scaling matrix stored as a vector,
169          Da is the diagonal perturbation matrix stored as a vector
170    and   jacfun is the jacobian of the original nonlinear function.
171 */
172 #undef __FUNCT__
173 #define __FUNCT__ "SNESVIComputeJacobian"
174 PetscErrorCode SNESVIComputeJacobian(Mat jac, Mat jac_pre,Vec Da, Vec Db)
175 {
176   PetscErrorCode ierr;
177 
178   /* Do row scaling  and add diagonal perturbation */
179   ierr = MatDiagonalScale(jac,Db,PETSC_NULL);CHKERRQ(ierr);
180   ierr = MatDiagonalSet(jac,Da,ADD_VALUES);CHKERRQ(ierr);
181   if (jac != jac_pre) { /* If jac and jac_pre are different */
182     ierr = MatDiagonalScale(jac_pre,Db,PETSC_NULL);
183     ierr = MatDiagonalSet(jac_pre,Da,ADD_VALUES);CHKERRQ(ierr);
184   }
185   PetscFunctionReturn(0);
186 }
187 
188 /*
189    SNESVIComputeMeritFunctionGradient - Computes the gradient of the merit function psi.
190 
191    Input Parameters:
192    phi - semismooth function.
193    H   - semismooth jacobian
194 
195    Output Parameters:
196    dpsi - merit function gradient
197 
198    Notes:
199   The merit function gradient is computed as follows
200         dpsi = H^T*phi
201 */
202 #undef __FUNCT__
203 #define __FUNCT__ "SNESVIComputeMeritFunctionGradient"
204 PetscErrorCode SNESVIComputeMeritFunctionGradient(Mat H, Vec phi, Vec dpsi)
205 {
206   PetscErrorCode ierr;
207 
208   PetscFunctionBegin;
209   ierr = MatMultTranspose(H,phi,dpsi);CHKERRQ(ierr);
210   PetscFunctionReturn(0);
211 }
212 
213 
214 
215 /*
216    SNESSolve_VISS - Solves the complementarity problem with a semismooth Newton
217    method using a line search.
218 
219    Input Parameters:
220 .  snes - the SNES context
221 
222    Output Parameter:
223 .  outits - number of iterations until termination
224 
225    Application Interface Routine: SNESSolve()
226 
227    Notes:
228    This implements essentially a semismooth Newton method with a
229    line search. The default line search does not do any line seach
230    but rather takes a full newton step.
231 */
232 #undef __FUNCT__
233 #define __FUNCT__ "SNESSolve_VISS"
234 PetscErrorCode SNESSolve_VISS(SNES snes)
235 {
236   SNES_VISS          *vi = (SNES_VISS*)snes->data;
237   PetscErrorCode     ierr;
238   PetscInt           maxits,i,lits;
239   PetscBool          lssucceed;
240   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
241   PetscReal          gnorm,xnorm=0,ynorm;
242   Vec                Y,X,F;
243   KSPConvergedReason kspreason;
244   DM                 dm;
245   SNESDM             sdm;
246 
247   PetscFunctionBegin;
248   ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
249   ierr = DMSNESGetContext(dm,&sdm);CHKERRQ(ierr);
250   vi->computeuserfunction    = sdm->computefunction;
251   sdm->computefunction = SNESVIComputeFunction;
252 
253   snes->numFailures            = 0;
254   snes->numLinearSolveFailures = 0;
255   snes->reason                 = SNES_CONVERGED_ITERATING;
256 
257   maxits	= snes->max_its;	/* maximum number of iterations */
258   X		= snes->vec_sol;	/* solution vector */
259   F		= snes->vec_func;	/* residual vector */
260   Y		= snes->work[0];	/* work vectors */
261 
262   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
263   snes->iter = 0;
264   snes->norm = 0.0;
265   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
266 
267   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
268   ierr = SNESComputeFunction(snes,X,vi->phi);CHKERRQ(ierr);
269   if (snes->domainerror) {
270     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
271     sdm->computefunction = vi->computeuserfunction;
272     PetscFunctionReturn(0);
273   }
274    /* Compute Merit function */
275   ierr = SNESVIComputeMeritFunction(vi->phi,&vi->merit,&vi->phinorm);CHKERRQ(ierr);
276 
277   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
278   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
279   if (PetscIsInfOrNanReal(vi->merit)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
280 
281   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
282   snes->norm = vi->phinorm;
283   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
284   SNESLogConvHistory(snes,vi->phinorm,0);
285   ierr = SNESMonitor(snes,0,vi->phinorm);CHKERRQ(ierr);
286 
287   /* set parameter for default relative tolerance convergence test */
288   snes->ttol = vi->phinorm*snes->rtol;
289   /* test convergence */
290   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
291   if (snes->reason) {
292     sdm->computefunction = vi->computeuserfunction;
293     PetscFunctionReturn(0);
294   }
295 
296   for (i=0; i<maxits; i++) {
297 
298     /* Call general purpose update function */
299     if (snes->ops->update) {
300       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
301     }
302 
303     /* Solve J Y = Phi, where J is the semismooth jacobian */
304     /* Get the nonlinear function jacobian */
305     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
306     /* Get the diagonal shift and row scaling vectors */
307     ierr = SNESVIComputeBsubdifferentialVectors(snes,X,F,snes->jacobian,vi->Da,vi->Db);CHKERRQ(ierr);
308     /* Compute the semismooth jacobian */
309     ierr = SNESVIComputeJacobian(snes->jacobian,snes->jacobian_pre,vi->Da,vi->Db);CHKERRQ(ierr);
310     /* Compute the merit function gradient */
311     ierr = SNESVIComputeMeritFunctionGradient(snes->jacobian,vi->phi,vi->dpsi);CHKERRQ(ierr);
312     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
313     ierr = SNES_KSPSolve(snes,snes->ksp,vi->phi,Y);CHKERRQ(ierr);
314     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
315 
316     if (kspreason < 0) {
317       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
318         ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
319         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
320         break;
321       }
322     }
323     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
324     snes->linear_its += lits;
325     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
326     /*
327     if (snes->ops->precheckstep) {
328       PetscBool changed_y = PETSC_FALSE;
329       ierr = (*snes->ops->precheckstep)(snes,X,Y,snes->precheck,&changed_y);CHKERRQ(ierr);
330     }
331 
332     if (PetscLogPrintInfo){
333       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
334     }
335     */
336     /* Compute a (scaled) negative update in the line search routine:
337          Y <- X - lambda*Y
338        and evaluate G = function(Y) (depends on the line search).
339     */
340     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
341     ynorm = 1; gnorm = vi->phinorm;
342     /* ierr = (*snes->ops->linesearch)(snes,snes->lsP,X,vi->phi,Y,vi->phinorm,xnorm,G,W,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr); */
343     ierr = SNESLineSearchApply(snes->linesearch, X, vi->phi, &gnorm, Y);CHKERRQ(ierr);
344     ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &gnorm, &ynorm);CHKERRQ(ierr);
345     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)vi->phinorm,(double)gnorm,(double)ynorm,(int)lssucceed);CHKERRQ(ierr);
346     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
347     if (snes->domainerror) {
348       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
349       sdm->computefunction = vi->computeuserfunction;
350       PetscFunctionReturn(0);
351     }
352     ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr);
353     if (!lssucceed) {
354       if (++snes->numFailures >= snes->maxFailures) {
355 	PetscBool ismin;
356         snes->reason = SNES_DIVERGED_LINE_SEARCH;
357         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,vi->phi,X,gnorm,&ismin);CHKERRQ(ierr);
358         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
359         break;
360       }
361     }
362     /* Update function and solution vectors */
363     vi->phinorm = gnorm;
364     vi->merit = 0.5*vi->phinorm*vi->phinorm;
365     /* Monitor convergence */
366     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
367     snes->iter = i+1;
368     snes->norm = vi->phinorm;
369     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
370     SNESLogConvHistory(snes,snes->norm,lits);
371     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
372     /* Test for convergence, xnorm = || X || */
373     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
374     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
375     if (snes->reason) break;
376   }
377   if (i == maxits) {
378     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
379     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
380   }
381   sdm->computefunction = vi->computeuserfunction;
382   PetscFunctionReturn(0);
383 }
384 
385 /* -------------------------------------------------------------------------- */
386 /*
387    SNESSetUp_VISS - Sets up the internal data structures for the later use
388    of the SNES nonlinear solver.
389 
390    Input Parameter:
391 .  snes - the SNES context
392 .  x - the solution vector
393 
394    Application Interface Routine: SNESSetUp()
395 
396    Notes:
397    For basic use of the SNES solvers, the user need not explicitly call
398    SNESSetUp(), since these actions will automatically occur during
399    the call to SNESSolve().
400  */
401 #undef __FUNCT__
402 #define __FUNCT__ "SNESSetUp_VISS"
403 PetscErrorCode SNESSetUp_VISS(SNES snes)
404 {
405   PetscErrorCode ierr;
406   SNES_VISS      *vi = (SNES_VISS*) snes->data;
407 
408   PetscFunctionBegin;
409   ierr = SNESSetUp_VI(snes);CHKERRQ(ierr);
410   ierr = VecDuplicate(snes->vec_sol, &vi->dpsi);CHKERRQ(ierr);
411   ierr = VecDuplicate(snes->vec_sol, &vi->phi);CHKERRQ(ierr);
412   ierr = VecDuplicate(snes->vec_sol, &vi->Da);CHKERRQ(ierr);
413   ierr = VecDuplicate(snes->vec_sol, &vi->Db);CHKERRQ(ierr);
414   ierr = VecDuplicate(snes->vec_sol, &vi->z);CHKERRQ(ierr);
415   ierr = VecDuplicate(snes->vec_sol, &vi->t);CHKERRQ(ierr);
416   PetscFunctionReturn(0);
417 }
418 /* -------------------------------------------------------------------------- */
419 #undef __FUNCT__
420 #define __FUNCT__ "SNESReset_VISS"
421 PetscErrorCode SNESReset_VISS(SNES snes)
422 {
423   SNES_VISS      *vi = (SNES_VISS*) snes->data;
424   PetscErrorCode ierr;
425 
426   PetscFunctionBegin;
427   ierr = SNESReset_VI(snes);CHKERRQ(ierr);
428   ierr = VecDestroy(&vi->dpsi);CHKERRQ(ierr);
429   ierr = VecDestroy(&vi->phi);CHKERRQ(ierr);
430   ierr = VecDestroy(&vi->Da);CHKERRQ(ierr);
431   ierr = VecDestroy(&vi->Db);CHKERRQ(ierr);
432   ierr = VecDestroy(&vi->z);CHKERRQ(ierr);
433   ierr = VecDestroy(&vi->t);CHKERRQ(ierr);
434   PetscFunctionReturn(0);
435 }
436 
437 /* -------------------------------------------------------------------------- */
438 /*
439    SNESSetFromOptions_VISS - Sets various parameters for the SNESVI method.
440 
441    Input Parameter:
442 .  snes - the SNES context
443 
444    Application Interface Routine: SNESSetFromOptions()
445 */
446 #undef __FUNCT__
447 #define __FUNCT__ "SNESSetFromOptions_VISS"
448 static PetscErrorCode SNESSetFromOptions_VISS(SNES snes)
449 {
450   PetscErrorCode     ierr;
451   SNESLineSearch    linesearch;
452 
453   PetscFunctionBegin;
454   ierr = SNESSetFromOptions_VI(snes);CHKERRQ(ierr);
455   ierr = PetscOptionsHead("SNES semismooth method options");CHKERRQ(ierr);
456   ierr = PetscOptionsTail();CHKERRQ(ierr);
457   /* set up the default line search */
458   if (!snes->linesearch) {
459     ierr = SNESGetSNESLineSearch(snes, &linesearch);CHKERRQ(ierr);
460     ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHBT);CHKERRQ(ierr);
461   }
462 
463   PetscFunctionReturn(0);
464 }
465 
466 
467 /* -------------------------------------------------------------------------- */
468 /*MC
469       SNESVISS - Semi-smooth solver for variational inequalities based on Newton's method
470 
471    Options Database:
472 +   -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 additional variables that enforce the constraints
473 -   -snes_vi_monitor - prints the number of active constraints at each iteration.
474 
475    Level: beginner
476 
477    References:
478    - T. S. Munson, F. Facchinei, M. C. Ferris, A. Fischer, and C. Kanzow. The semismooth
479      algorithm for large scale complementarity problems. INFORMS Journal on Computing, 13 (2001).
480 
481 .seealso:  SNESVISetVariableBounds(), SNESVISetComputeVariableBounds(), SNESCreate(), SNES, SNESSetType(), SNESVIRS, SNESVISS, SNESTR, SNESLineSearchSet(),
482            SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(),
483            SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams()
484 
485 M*/
486 EXTERN_C_BEGIN
487 #undef __FUNCT__
488 #define __FUNCT__ "SNESCreate_VISS"
489 PetscErrorCode  SNESCreate_VISS(SNES snes)
490 {
491   PetscErrorCode ierr;
492   SNES_VISS      *vi;
493 
494   PetscFunctionBegin;
495   snes->ops->reset           = SNESReset_VISS;
496   snes->ops->setup           = SNESSetUp_VISS;
497   snes->ops->solve           = SNESSolve_VISS;
498   snes->ops->destroy         = SNESDestroy_VI;
499   snes->ops->setfromoptions  = SNESSetFromOptions_VISS;
500   snes->ops->view            = PETSC_NULL;
501 
502   snes->usesksp             = PETSC_TRUE;
503   snes->usespc              = PETSC_FALSE;
504 
505   ierr                       = PetscNewLog(snes,SNES_VISS,&vi);CHKERRQ(ierr);
506   snes->data                 = (void*)vi;
507 
508   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESVISetVariableBounds_C","SNESVISetVariableBounds_VI",SNESVISetVariableBounds_VI);CHKERRQ(ierr);
509   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESVISetComputeVariableBounds_C","SNESVISetComputeVariableBounds_VI",SNESVISetComputeVariableBounds_VI);CHKERRQ(ierr);
510   PetscFunctionReturn(0);
511 }
512 EXTERN_C_END
513 
514