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