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