xref: /petsc/src/snes/impls/vi/ss/viss.c (revision c2e3fba1fe1cda7e6350bbca19c4ed35ce95940a)
1c2fc9fa9SBarry Smith 
2c2fc9fa9SBarry Smith #include <../src/snes/impls/vi/ss/vissimpl.h> /*I "petscsnes.h" I*/
3c2fc9fa9SBarry Smith 
4c2fc9fa9SBarry Smith /*
5c2fc9fa9SBarry Smith   SNESVIComputeMeritFunction - Evaluates the merit function for the mixed complementarity problem.
6c2fc9fa9SBarry Smith 
7c2fc9fa9SBarry Smith   Input Parameter:
8c2fc9fa9SBarry Smith . phi - the semismooth function
9c2fc9fa9SBarry Smith 
10c2fc9fa9SBarry Smith   Output Parameter:
11c2fc9fa9SBarry Smith . merit - the merit function
12c2fc9fa9SBarry Smith . phinorm - ||phi||
13c2fc9fa9SBarry Smith 
14c2fc9fa9SBarry Smith   Notes:
15c2fc9fa9SBarry Smith   The merit function for the mixed complementarity problem is defined as
16c2fc9fa9SBarry Smith      merit = 0.5*phi^T*phi
17c2fc9fa9SBarry Smith */
18c2fc9fa9SBarry Smith static PetscErrorCode SNESVIComputeMeritFunction(Vec phi, PetscReal *merit,PetscReal *phinorm)
19c2fc9fa9SBarry Smith {
20c2fc9fa9SBarry Smith   PetscFunctionBegin;
219566063dSJacob Faibussowitsch   PetscCall(VecNormBegin(phi,NORM_2,phinorm));
229566063dSJacob Faibussowitsch   PetscCall(VecNormEnd(phi,NORM_2,phinorm));
23c2fc9fa9SBarry Smith 
24c2fc9fa9SBarry Smith   *merit = 0.5*(*phinorm)*(*phinorm);
25c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
26c2fc9fa9SBarry Smith }
27c2fc9fa9SBarry Smith 
289fbee547SJacob Faibussowitsch static inline PetscScalar Phi(PetscScalar a,PetscScalar b)
29c2fc9fa9SBarry Smith {
30c2fc9fa9SBarry Smith   return a + b - PetscSqrtScalar(a*a + b*b);
31c2fc9fa9SBarry Smith }
32c2fc9fa9SBarry Smith 
339fbee547SJacob Faibussowitsch static inline PetscScalar DPhi(PetscScalar a,PetscScalar b)
34c2fc9fa9SBarry Smith {
35c2fc9fa9SBarry Smith   if ((PetscAbsScalar(a) >= 1.e-6) || (PetscAbsScalar(b) >= 1.e-6)) return 1.0 - a/ PetscSqrtScalar(a*a + b*b);
36c2fc9fa9SBarry Smith   else return .5;
37c2fc9fa9SBarry Smith }
38c2fc9fa9SBarry Smith 
39c2fc9fa9SBarry Smith /*
40c2fc9fa9SBarry Smith    SNESVIComputeFunction - Reformulates a system of nonlinear equations in mixed complementarity form to a system of nonlinear equations in semismooth form.
41c2fc9fa9SBarry Smith 
42c2fc9fa9SBarry Smith    Input Parameters:
43c2fc9fa9SBarry Smith .  snes - the SNES context
44d5f1b7e6SEd Bueler .  X - current iterate
45c2fc9fa9SBarry Smith .  functx - user defined function context
46c2fc9fa9SBarry Smith 
47c2fc9fa9SBarry Smith    Output Parameters:
48c2fc9fa9SBarry Smith .  phi - Semismooth function
49c2fc9fa9SBarry Smith 
50c2fc9fa9SBarry Smith */
51c2fc9fa9SBarry Smith static PetscErrorCode SNESVIComputeFunction(SNES snes,Vec X,Vec phi,void *functx)
52c2fc9fa9SBarry Smith {
53f450aa47SBarry Smith   SNES_VINEWTONSSLS *vi = (SNES_VINEWTONSSLS*)snes->data;
54c2fc9fa9SBarry Smith   Vec               Xl  = snes->xl,Xu = snes->xu,F = snes->vec_func;
555edff71fSBarry Smith   PetscScalar       *phi_arr,*f_arr,*l,*u;
565edff71fSBarry Smith   const PetscScalar *x_arr;
57c2fc9fa9SBarry Smith   PetscInt          i,nlocal;
58c2fc9fa9SBarry Smith 
59c2fc9fa9SBarry Smith   PetscFunctionBegin;
609566063dSJacob Faibussowitsch   PetscCall((*vi->computeuserfunction)(snes,X,F,functx));
619566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(X,&nlocal));
629566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(X,&x_arr));
639566063dSJacob Faibussowitsch   PetscCall(VecGetArray(F,&f_arr));
649566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Xl,&l));
659566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Xu,&u));
669566063dSJacob Faibussowitsch   PetscCall(VecGetArray(phi,&phi_arr));
67c2fc9fa9SBarry Smith 
68c2fc9fa9SBarry Smith   for (i=0; i < nlocal; i++) {
69e270355aSBarry Smith     if ((PetscRealPart(l[i]) <= PETSC_NINFINITY) && (PetscRealPart(u[i]) >= PETSC_INFINITY)) { /* no constraints on variable */
70c2fc9fa9SBarry Smith       phi_arr[i] = f_arr[i];
71e270355aSBarry Smith     } else if (PetscRealPart(l[i]) <= PETSC_NINFINITY) {                      /* upper bound on variable only */
72c2fc9fa9SBarry Smith       phi_arr[i] = -Phi(u[i] - x_arr[i],-f_arr[i]);
73e270355aSBarry Smith     } else if (PetscRealPart(u[i]) >= PETSC_INFINITY) {                       /* lower bound on variable only */
74c2fc9fa9SBarry Smith       phi_arr[i] = Phi(x_arr[i] - l[i],f_arr[i]);
75c2fc9fa9SBarry Smith     } else if (l[i] == u[i]) {
76c2fc9fa9SBarry Smith       phi_arr[i] = l[i] - x_arr[i];
77c2fc9fa9SBarry Smith     } else {                                                /* both bounds on variable */
78c2fc9fa9SBarry Smith       phi_arr[i] = Phi(x_arr[i] - l[i],-Phi(u[i] - x_arr[i],-f_arr[i]));
79c2fc9fa9SBarry Smith     }
80c2fc9fa9SBarry Smith   }
81c2fc9fa9SBarry Smith 
829566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(X,&x_arr));
839566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(F,&f_arr));
849566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Xl,&l));
859566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Xu,&u));
869566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(phi,&phi_arr));
87c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
88c2fc9fa9SBarry Smith }
89c2fc9fa9SBarry Smith 
90c2fc9fa9SBarry Smith /*
91c2fc9fa9SBarry Smith    SNESVIComputeBsubdifferentialVectors - Computes the diagonal shift (Da) and row scaling (Db) vectors needed for the
92c2fc9fa9SBarry Smith                                           the semismooth jacobian.
93c2fc9fa9SBarry Smith */
94c2fc9fa9SBarry Smith PetscErrorCode SNESVIComputeBsubdifferentialVectors(SNES snes,Vec X,Vec F,Mat jac,Vec Da,Vec Db)
95c2fc9fa9SBarry Smith {
96c2fc9fa9SBarry Smith   PetscScalar    *l,*u,*x,*f,*da,*db,da1,da2,db1,db2;
97c2fc9fa9SBarry Smith   PetscInt       i,nlocal;
98c2fc9fa9SBarry Smith 
99c2fc9fa9SBarry Smith   PetscFunctionBegin;
1009566063dSJacob Faibussowitsch   PetscCall(VecGetArray(X,&x));
1019566063dSJacob Faibussowitsch   PetscCall(VecGetArray(F,&f));
1029566063dSJacob Faibussowitsch   PetscCall(VecGetArray(snes->xl,&l));
1039566063dSJacob Faibussowitsch   PetscCall(VecGetArray(snes->xu,&u));
1049566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Da,&da));
1059566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Db,&db));
1069566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(X,&nlocal));
107c2fc9fa9SBarry Smith 
108c2fc9fa9SBarry Smith   for (i=0; i< nlocal; i++) {
109e270355aSBarry Smith     if ((PetscRealPart(l[i]) <= PETSC_NINFINITY) && (PetscRealPart(u[i]) >= PETSC_INFINITY)) { /* no constraints on variable */
110c2fc9fa9SBarry Smith       da[i] = 0;
111c2fc9fa9SBarry Smith       db[i] = 1;
112e270355aSBarry Smith     } else if (PetscRealPart(l[i]) <= PETSC_NINFINITY) {                     /* upper bound on variable only */
113c2fc9fa9SBarry Smith       da[i] = DPhi(u[i] - x[i], -f[i]);
114c2fc9fa9SBarry Smith       db[i] = DPhi(-f[i],u[i] - x[i]);
115e270355aSBarry Smith     } else if (PetscRealPart(u[i]) >= PETSC_INFINITY) {                      /* lower bound on variable only */
116c2fc9fa9SBarry Smith       da[i] = DPhi(x[i] - l[i], f[i]);
117c2fc9fa9SBarry Smith       db[i] = DPhi(f[i],x[i] - l[i]);
118c2fc9fa9SBarry Smith     } else if (l[i] == u[i]) {                              /* fixed variable */
119c2fc9fa9SBarry Smith       da[i] = 1;
120c2fc9fa9SBarry Smith       db[i] = 0;
121c2fc9fa9SBarry Smith     } else {                                                /* upper and lower bounds on variable */
122c2fc9fa9SBarry Smith       da1   = DPhi(x[i] - l[i], -Phi(u[i] - x[i], -f[i]));
123c2fc9fa9SBarry Smith       db1   = DPhi(-Phi(u[i] - x[i], -f[i]),x[i] - l[i]);
124c2fc9fa9SBarry Smith       da2   = DPhi(u[i] - x[i], -f[i]);
125c2fc9fa9SBarry Smith       db2   = DPhi(-f[i],u[i] - x[i]);
126c2fc9fa9SBarry Smith       da[i] = da1 + db1*da2;
127c2fc9fa9SBarry Smith       db[i] = db1*db2;
128c2fc9fa9SBarry Smith     }
129c2fc9fa9SBarry Smith   }
130c2fc9fa9SBarry Smith 
1319566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(X,&x));
1329566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(F,&f));
1339566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(snes->xl,&l));
1349566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(snes->xu,&u));
1359566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Da,&da));
1369566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Db,&db));
137c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
138c2fc9fa9SBarry Smith }
139c2fc9fa9SBarry Smith 
140c2fc9fa9SBarry Smith /*
141c2fc9fa9SBarry 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.
142c2fc9fa9SBarry Smith 
143c2fc9fa9SBarry Smith    Input Parameters:
144c2fc9fa9SBarry Smith .  Da       - Diagonal shift vector for the semismooth jacobian.
145c2fc9fa9SBarry Smith .  Db       - Row scaling vector for the semismooth jacobian.
146c2fc9fa9SBarry Smith 
147c2fc9fa9SBarry Smith    Output Parameters:
148c2fc9fa9SBarry Smith .  jac      - semismooth jacobian
149c2fc9fa9SBarry Smith .  jac_pre  - optional preconditioning matrix
150c2fc9fa9SBarry Smith 
151c2fc9fa9SBarry Smith    Notes:
152c2fc9fa9SBarry Smith    The semismooth jacobian matrix is given by
153c2fc9fa9SBarry Smith    jac = Da + Db*jacfun
154c2fc9fa9SBarry Smith    where Db is the row scaling matrix stored as a vector,
155c2fc9fa9SBarry Smith          Da is the diagonal perturbation matrix stored as a vector
156c2fc9fa9SBarry Smith    and   jacfun is the jacobian of the original nonlinear function.
157c2fc9fa9SBarry Smith */
158c2fc9fa9SBarry Smith PetscErrorCode SNESVIComputeJacobian(Mat jac, Mat jac_pre,Vec Da, Vec Db)
159c2fc9fa9SBarry Smith {
160c2fc9fa9SBarry Smith 
161c2fc9fa9SBarry Smith   /* Do row scaling  and add diagonal perturbation */
162362febeeSStefano Zampini   PetscFunctionBegin;
1639566063dSJacob Faibussowitsch   PetscCall(MatDiagonalScale(jac,Db,NULL));
1649566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet(jac,Da,ADD_VALUES));
165c2fc9fa9SBarry Smith   if (jac != jac_pre) { /* If jac and jac_pre are different */
1669566063dSJacob Faibussowitsch     PetscCall(MatDiagonalScale(jac_pre,Db,NULL));
1679566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet(jac_pre,Da,ADD_VALUES));
168c2fc9fa9SBarry Smith   }
169c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
170c2fc9fa9SBarry Smith }
171c2fc9fa9SBarry Smith 
172c2fc9fa9SBarry Smith /*
173c2fc9fa9SBarry Smith    SNESVIComputeMeritFunctionGradient - Computes the gradient of the merit function psi.
174c2fc9fa9SBarry Smith 
175c2fc9fa9SBarry Smith    Input Parameters:
176c2fc9fa9SBarry Smith    phi - semismooth function.
177c2fc9fa9SBarry Smith    H   - semismooth jacobian
178c2fc9fa9SBarry Smith 
179c2fc9fa9SBarry Smith    Output Parameters:
180c2fc9fa9SBarry Smith    dpsi - merit function gradient
181c2fc9fa9SBarry Smith 
182c2fc9fa9SBarry Smith    Notes:
183c2fc9fa9SBarry Smith   The merit function gradient is computed as follows
184c2fc9fa9SBarry Smith         dpsi = H^T*phi
185c2fc9fa9SBarry Smith */
186c2fc9fa9SBarry Smith PetscErrorCode SNESVIComputeMeritFunctionGradient(Mat H, Vec phi, Vec dpsi)
187c2fc9fa9SBarry Smith {
188c2fc9fa9SBarry Smith   PetscFunctionBegin;
1899566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(H,phi,dpsi));
190c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
191c2fc9fa9SBarry Smith }
192c2fc9fa9SBarry Smith 
193c2fc9fa9SBarry Smith /*
194f450aa47SBarry Smith    SNESSolve_VINEWTONSSLS - Solves the complementarity problem with a semismooth Newton
195c2fc9fa9SBarry Smith    method using a line search.
196c2fc9fa9SBarry Smith 
197c2fc9fa9SBarry Smith    Input Parameters:
198c2fc9fa9SBarry Smith .  snes - the SNES context
199c2fc9fa9SBarry Smith 
200c2fc9fa9SBarry Smith    Application Interface Routine: SNESSolve()
201c2fc9fa9SBarry Smith 
202c2fc9fa9SBarry Smith    Notes:
203c2fc9fa9SBarry Smith    This implements essentially a semismooth Newton method with a
204d5f1b7e6SEd Bueler    line search. The default line search does not do any line search
205d5f1b7e6SEd Bueler    but rather takes a full Newton step.
206016d19f9SBarry Smith 
20704d7464bSBarry 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
208016d19f9SBarry Smith 
209c2fc9fa9SBarry Smith */
210f450aa47SBarry Smith PetscErrorCode SNESSolve_VINEWTONSSLS(SNES snes)
211c2fc9fa9SBarry Smith {
212f450aa47SBarry Smith   SNES_VINEWTONSSLS    *vi = (SNES_VINEWTONSSLS*)snes->data;
213c2fc9fa9SBarry Smith   PetscInt             maxits,i,lits;
214422a814eSBarry Smith   SNESLineSearchReason lssucceed;
215c2fc9fa9SBarry Smith   PetscReal            gnorm,xnorm=0,ynorm;
2169bd66eb0SPeter Brune   Vec                  Y,X,F;
217c2fc9fa9SBarry Smith   KSPConvergedReason   kspreason;
2186cab3a1bSJed Brown   DM                   dm;
219942e3340SBarry Smith   DMSNES               sdm;
220c2fc9fa9SBarry Smith 
221c2fc9fa9SBarry Smith   PetscFunctionBegin;
2229566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes,&dm));
2239566063dSJacob Faibussowitsch   PetscCall(DMGetDMSNES(dm,&sdm));
2241aa26658SKarl Rupp 
22522c6f798SBarry Smith   vi->computeuserfunction   = sdm->ops->computefunction;
22622c6f798SBarry Smith   sdm->ops->computefunction = SNESVIComputeFunction;
227c2fc9fa9SBarry Smith 
228c2fc9fa9SBarry Smith   snes->numFailures            = 0;
229c2fc9fa9SBarry Smith   snes->numLinearSolveFailures = 0;
230c2fc9fa9SBarry Smith   snes->reason                 = SNES_CONVERGED_ITERATING;
231c2fc9fa9SBarry Smith 
232c2fc9fa9SBarry Smith   maxits = snes->max_its;               /* maximum number of iterations */
233c2fc9fa9SBarry Smith   X      = snes->vec_sol;               /* solution vector */
234c2fc9fa9SBarry Smith   F      = snes->vec_func;              /* residual vector */
235c2fc9fa9SBarry Smith   Y      = snes->work[0];               /* work vectors */
236c2fc9fa9SBarry Smith 
2379566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
238c2fc9fa9SBarry Smith   snes->iter = 0;
239c2fc9fa9SBarry Smith   snes->norm = 0.0;
2409566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
241c2fc9fa9SBarry Smith 
2429566063dSJacob Faibussowitsch   PetscCall(SNESVIProjectOntoBounds(snes,X));
2439566063dSJacob Faibussowitsch   PetscCall(SNESComputeFunction(snes,X,vi->phi));
244c2fc9fa9SBarry Smith   if (snes->domainerror) {
245c2fc9fa9SBarry Smith     snes->reason              = SNES_DIVERGED_FUNCTION_DOMAIN;
24622c6f798SBarry Smith     sdm->ops->computefunction = vi->computeuserfunction;
247c2fc9fa9SBarry Smith     PetscFunctionReturn(0);
248c2fc9fa9SBarry Smith   }
249c2fc9fa9SBarry Smith   /* Compute Merit function */
2509566063dSJacob Faibussowitsch   PetscCall(SNESVIComputeMeritFunction(vi->phi,&vi->merit,&vi->phinorm));
251c2fc9fa9SBarry Smith 
2529566063dSJacob Faibussowitsch   PetscCall(VecNormBegin(X,NORM_2,&xnorm));        /* xnorm <- ||x||  */
2539566063dSJacob Faibussowitsch   PetscCall(VecNormEnd(X,NORM_2,&xnorm));
254422a814eSBarry Smith   SNESCheckFunctionNorm(snes,vi->merit);
255c2fc9fa9SBarry Smith 
2569566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
257c2fc9fa9SBarry Smith   snes->norm = vi->phinorm;
2589566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
2599566063dSJacob Faibussowitsch   PetscCall(SNESLogConvergenceHistory(snes,vi->phinorm,0));
2609566063dSJacob Faibussowitsch   PetscCall(SNESMonitor(snes,0,vi->phinorm));
261c2fc9fa9SBarry Smith 
262c2fc9fa9SBarry Smith   /* test convergence */
2639566063dSJacob Faibussowitsch   PetscCall((*snes->ops->converged)(snes,0,0.0,0.0,vi->phinorm,&snes->reason,snes->cnvP));
264c2fc9fa9SBarry Smith   if (snes->reason) {
26522c6f798SBarry Smith     sdm->ops->computefunction = vi->computeuserfunction;
266c2fc9fa9SBarry Smith     PetscFunctionReturn(0);
267c2fc9fa9SBarry Smith   }
268c2fc9fa9SBarry Smith 
269c2fc9fa9SBarry Smith   for (i=0; i<maxits; i++) {
270c2fc9fa9SBarry Smith 
271c2fc9fa9SBarry Smith     /* Call general purpose update function */
272c2fc9fa9SBarry Smith     if (snes->ops->update) {
2739566063dSJacob Faibussowitsch       PetscCall((*snes->ops->update)(snes, snes->iter));
274c2fc9fa9SBarry Smith     }
275c2fc9fa9SBarry Smith 
276c2fc9fa9SBarry Smith     /* Solve J Y = Phi, where J is the semismooth jacobian */
277b9600128SPeter Brune 
278b9600128SPeter Brune     /* Get the jacobian -- note that the function must be the original function for snes_fd and snes_fd_color to work for this*/
27922c6f798SBarry Smith     sdm->ops->computefunction = vi->computeuserfunction;
2809566063dSJacob Faibussowitsch     PetscCall(SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre));
28107b62357SFande Kong     SNESCheckJacobianDomainerror(snes);
28222c6f798SBarry Smith     sdm->ops->computefunction = SNESVIComputeFunction;
283b9600128SPeter Brune 
284c2fc9fa9SBarry Smith     /* Get the diagonal shift and row scaling vectors */
2859566063dSJacob Faibussowitsch     PetscCall(SNESVIComputeBsubdifferentialVectors(snes,X,F,snes->jacobian,vi->Da,vi->Db));
286c2fc9fa9SBarry Smith     /* Compute the semismooth jacobian */
2879566063dSJacob Faibussowitsch     PetscCall(SNESVIComputeJacobian(snes->jacobian,snes->jacobian_pre,vi->Da,vi->Db));
288c2fc9fa9SBarry Smith     /* Compute the merit function gradient */
2899566063dSJacob Faibussowitsch     PetscCall(SNESVIComputeMeritFunctionGradient(snes->jacobian,vi->phi,vi->dpsi));
2909566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre));
2919566063dSJacob Faibussowitsch     PetscCall(KSPSolve(snes->ksp,vi->phi,Y));
2929566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason(snes->ksp,&kspreason));
293c2fc9fa9SBarry Smith 
294c2fc9fa9SBarry Smith     if (kspreason < 0) {
295c2fc9fa9SBarry Smith       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
29663a3b9bcSJacob Faibussowitsch         PetscCall(PetscInfo(snes,"iter=%" PetscInt_FMT ", number linear solve failures %" PetscInt_FMT " greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures));
297c2fc9fa9SBarry Smith         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
298c2fc9fa9SBarry Smith         break;
299c2fc9fa9SBarry Smith       }
300c2fc9fa9SBarry Smith     }
3019566063dSJacob Faibussowitsch     PetscCall(KSPGetIterationNumber(snes->ksp,&lits));
302c2fc9fa9SBarry Smith     snes->linear_its += lits;
30363a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(snes,"iter=%" PetscInt_FMT ", linear solve iterations=%" PetscInt_FMT "\n",snes->iter,lits));
304c2fc9fa9SBarry Smith     /*
3056b2b7091SBarry Smith     if (snes->ops->precheck) {
306c2fc9fa9SBarry Smith       PetscBool changed_y = PETSC_FALSE;
3079566063dSJacob Faibussowitsch       PetscCall((*snes->ops->precheck)(snes,X,Y,snes->precheck,&changed_y));
308c2fc9fa9SBarry Smith     }
309c2fc9fa9SBarry Smith 
310c2fc9fa9SBarry Smith     if (PetscLogPrintInfo) {
3119566063dSJacob Faibussowitsch       PetscCall(SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W));
312c2fc9fa9SBarry Smith     }
313c2fc9fa9SBarry Smith     */
314c2fc9fa9SBarry Smith     /* Compute a (scaled) negative update in the line search routine:
315c2fc9fa9SBarry Smith          Y <- X - lambda*Y
316c2fc9fa9SBarry Smith        and evaluate G = function(Y) (depends on the line search).
317c2fc9fa9SBarry Smith     */
3189566063dSJacob Faibussowitsch     PetscCall(VecCopy(Y,snes->vec_sol_update));
319c2fc9fa9SBarry Smith     ynorm = 1; gnorm = vi->phinorm;
3209566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchApply(snes->linesearch, X, vi->phi, &gnorm, Y));
3219566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchGetReason(snes->linesearch, &lssucceed));
3229566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchGetNorms(snes->linesearch, &xnorm, &gnorm, &ynorm));
3239566063dSJacob Faibussowitsch     PetscCall(PetscInfo(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)vi->phinorm,(double)gnorm,(double)ynorm,(int)lssucceed));
324c2fc9fa9SBarry Smith     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
325c2fc9fa9SBarry Smith     if (snes->domainerror) {
326c2fc9fa9SBarry Smith       snes->reason              = SNES_DIVERGED_FUNCTION_DOMAIN;
32722c6f798SBarry Smith       sdm->ops->computefunction = vi->computeuserfunction;
328c2fc9fa9SBarry Smith       PetscFunctionReturn(0);
329c2fc9fa9SBarry Smith     }
330422a814eSBarry Smith     if (lssucceed) {
331c2fc9fa9SBarry Smith       if (++snes->numFailures >= snes->maxFailures) {
332c2fc9fa9SBarry Smith         PetscBool ismin;
333c2fc9fa9SBarry Smith         snes->reason = SNES_DIVERGED_LINE_SEARCH;
3349566063dSJacob Faibussowitsch         PetscCall(SNESVICheckLocalMin_Private(snes,snes->jacobian,vi->phi,X,gnorm,&ismin));
335c2fc9fa9SBarry Smith         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
336c2fc9fa9SBarry Smith         break;
337c2fc9fa9SBarry Smith       }
338c2fc9fa9SBarry Smith     }
339c2fc9fa9SBarry Smith     /* Update function and solution vectors */
340c2fc9fa9SBarry Smith     vi->phinorm = gnorm;
341c2fc9fa9SBarry Smith     vi->merit   = 0.5*vi->phinorm*vi->phinorm;
342c2fc9fa9SBarry Smith     /* Monitor convergence */
3439566063dSJacob Faibussowitsch     PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
344c2fc9fa9SBarry Smith     snes->iter = i+1;
345c2fc9fa9SBarry Smith     snes->norm = vi->phinorm;
346c1e67a49SFande Kong     snes->xnorm = xnorm;
347c1e67a49SFande Kong     snes->ynorm = ynorm;
3489566063dSJacob Faibussowitsch     PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
3499566063dSJacob Faibussowitsch     PetscCall(SNESLogConvergenceHistory(snes,snes->norm,lits));
3509566063dSJacob Faibussowitsch     PetscCall(SNESMonitor(snes,snes->iter,snes->norm));
351c2fc9fa9SBarry Smith     /* Test for convergence, xnorm = || X || */
3529566063dSJacob Faibussowitsch     if (snes->ops->converged != SNESConvergedSkip) PetscCall(VecNorm(X,NORM_2,&xnorm));
3539566063dSJacob Faibussowitsch     PetscCall((*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,vi->phinorm,&snes->reason,snes->cnvP));
354c2fc9fa9SBarry Smith     if (snes->reason) break;
355c2fc9fa9SBarry Smith   }
356c2fc9fa9SBarry Smith   if (i == maxits) {
35763a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(snes,"Maximum number of iterations has been reached: %" PetscInt_FMT "\n",maxits));
358c2fc9fa9SBarry Smith     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
359c2fc9fa9SBarry Smith   }
36022c6f798SBarry Smith   sdm->ops->computefunction = vi->computeuserfunction;
361c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
362c2fc9fa9SBarry Smith }
363c2fc9fa9SBarry Smith 
364c2fc9fa9SBarry Smith /* -------------------------------------------------------------------------- */
365c2fc9fa9SBarry Smith /*
366f450aa47SBarry Smith    SNESSetUp_VINEWTONSSLS - Sets up the internal data structures for the later use
367c2fc9fa9SBarry Smith    of the SNES nonlinear solver.
368c2fc9fa9SBarry Smith 
369c2fc9fa9SBarry Smith    Input Parameter:
370c2fc9fa9SBarry Smith .  snes - the SNES context
371c2fc9fa9SBarry Smith 
372c2fc9fa9SBarry Smith    Application Interface Routine: SNESSetUp()
373c2fc9fa9SBarry Smith 
374c2fc9fa9SBarry Smith    Notes:
375c2fc9fa9SBarry Smith    For basic use of the SNES solvers, the user need not explicitly call
376c2fc9fa9SBarry Smith    SNESSetUp(), since these actions will automatically occur during
377c2fc9fa9SBarry Smith    the call to SNESSolve().
378c2fc9fa9SBarry Smith  */
379f450aa47SBarry Smith PetscErrorCode SNESSetUp_VINEWTONSSLS(SNES snes)
380c2fc9fa9SBarry Smith {
381f450aa47SBarry Smith   SNES_VINEWTONSSLS *vi = (SNES_VINEWTONSSLS*) snes->data;
382c2fc9fa9SBarry Smith 
383c2fc9fa9SBarry Smith   PetscFunctionBegin;
3849566063dSJacob Faibussowitsch   PetscCall(SNESSetUp_VI(snes));
3859566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(snes->vec_sol, &vi->dpsi));
3869566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(snes->vec_sol, &vi->phi));
3879566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(snes->vec_sol, &vi->Da));
3889566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(snes->vec_sol, &vi->Db));
3899566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(snes->vec_sol, &vi->z));
3909566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(snes->vec_sol, &vi->t));
391c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
392c2fc9fa9SBarry Smith }
393c2fc9fa9SBarry Smith /* -------------------------------------------------------------------------- */
394f450aa47SBarry Smith PetscErrorCode SNESReset_VINEWTONSSLS(SNES snes)
395c2fc9fa9SBarry Smith {
396f450aa47SBarry Smith   SNES_VINEWTONSSLS *vi = (SNES_VINEWTONSSLS*) snes->data;
397c2fc9fa9SBarry Smith 
398c2fc9fa9SBarry Smith   PetscFunctionBegin;
3999566063dSJacob Faibussowitsch   PetscCall(SNESReset_VI(snes));
4009566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vi->dpsi));
4019566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vi->phi));
4029566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vi->Da));
4039566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vi->Db));
4049566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vi->z));
4059566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vi->t));
406c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
407c2fc9fa9SBarry Smith }
408c2fc9fa9SBarry Smith 
409c2fc9fa9SBarry Smith /* -------------------------------------------------------------------------- */
410c2fc9fa9SBarry Smith /*
411f450aa47SBarry Smith    SNESSetFromOptions_VINEWTONSSLS - Sets various parameters for the SNESVI method.
412c2fc9fa9SBarry Smith 
413c2fc9fa9SBarry Smith    Input Parameter:
414c2fc9fa9SBarry Smith .  snes - the SNES context
415c2fc9fa9SBarry Smith 
416c2fc9fa9SBarry Smith    Application Interface Routine: SNESSetFromOptions()
417c2fc9fa9SBarry Smith */
4184416b707SBarry Smith static PetscErrorCode SNESSetFromOptions_VINEWTONSSLS(PetscOptionItems *PetscOptionsObject,SNES snes)
419c2fc9fa9SBarry Smith {
420c2fc9fa9SBarry Smith   PetscFunctionBegin;
4219566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions_VI(PetscOptionsObject,snes));
422d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject,"SNES semismooth method options");
423d0609cedSBarry Smith   PetscOptionsHeadEnd();
424c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
425c2fc9fa9SBarry Smith }
426c2fc9fa9SBarry Smith 
427c2fc9fa9SBarry Smith /* -------------------------------------------------------------------------- */
428c2fc9fa9SBarry Smith /*MC
429f450aa47SBarry Smith       SNESVINEWTONSSLS - Semi-smooth solver for variational inequalities based on Newton's method
430c2fc9fa9SBarry Smith 
43161589011SJed Brown    Options Database:
432d5f1b7e6SEd Bueler +   -snes_type <vinewtonssls,vinewtonrsls> a semi-smooth solver, a reduced space active set method
43361589011SJed Brown -   -snes_vi_monitor - prints the number of active constraints at each iteration.
43461589011SJed Brown 
435c2fc9fa9SBarry Smith    Level: beginner
436c2fc9fa9SBarry Smith 
437b80f3ac1SShri Abhyankar    References:
438606c0280SSatish Balay +  * -  T. S. Munson, F. Facchinei, M. C. Ferris, A. Fischer, and C. Kanzow. The semismooth
439b80f3ac1SShri Abhyankar      algorithm for large scale complementarity problems. INFORMS Journal on Computing, 13 (2001).
440606c0280SSatish Balay -  * -  T. S. Munson, and S. Benson. Flexible Complementarity Solvers for Large Scale
441d5f1b7e6SEd Bueler      Applications, Optimization Methods and Software, 21 (2006).
442b80f3ac1SShri Abhyankar 
443*c2e3fba1SPatrick Sanan .seealso: `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESVINEWTONRSLS`, `SNESNEWTONTR`, `SNESLineSearchSetType()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchSetPreCheck()`
444c2fc9fa9SBarry Smith 
445c2fc9fa9SBarry Smith M*/
4468cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_VINEWTONSSLS(SNES snes)
447c2fc9fa9SBarry Smith {
448f450aa47SBarry Smith   SNES_VINEWTONSSLS *vi;
449d8d34be6SBarry Smith   SNESLineSearch    linesearch;
450c2fc9fa9SBarry Smith 
451c2fc9fa9SBarry Smith   PetscFunctionBegin;
452f450aa47SBarry Smith   snes->ops->reset          = SNESReset_VINEWTONSSLS;
453f450aa47SBarry Smith   snes->ops->setup          = SNESSetUp_VINEWTONSSLS;
454f450aa47SBarry Smith   snes->ops->solve          = SNESSolve_VINEWTONSSLS;
455c2fc9fa9SBarry Smith   snes->ops->destroy        = SNESDestroy_VI;
456f450aa47SBarry Smith   snes->ops->setfromoptions = SNESSetFromOptions_VINEWTONSSLS;
4570298fd71SBarry Smith   snes->ops->view           = NULL;
458c2fc9fa9SBarry Smith 
459c2fc9fa9SBarry Smith   snes->usesksp = PETSC_TRUE;
460efd4aadfSBarry Smith   snes->usesnpc = PETSC_FALSE;
461c2fc9fa9SBarry Smith 
4629566063dSJacob Faibussowitsch   PetscCall(SNESGetLineSearch(snes, &linesearch));
463ec786807SJed Brown   if (!((PetscObject)linesearch)->type_name) {
4649566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBT));
4659566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchBTSetAlpha(linesearch, 0.0));
466ec786807SJed Brown   }
467d8d34be6SBarry Smith 
4684fc747eaSLawrence Mitchell   snes->alwayscomputesfinalresidual = PETSC_FALSE;
4694fc747eaSLawrence Mitchell 
4709566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(snes,&vi));
471c2fc9fa9SBarry Smith   snes->data = (void*)vi;
472c2fc9fa9SBarry Smith 
4739566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESVISetVariableBounds_C",SNESVISetVariableBounds_VI));
4749566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESVISetComputeVariableBounds_C",SNESVISetComputeVariableBounds_VI));
475c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
476c2fc9fa9SBarry Smith }
477