xref: /petsc/src/snes/impls/vi/rs/virs.c (revision 7d5fd1e4d9337468ad3f05b65b7facdcd2dfd2a4)
1 
2 #include <../src/snes/impls/vi/rs/virsimpl.h> /*I "petscsnes.h" I*/
3 #include <petsc/private/dmimpl.h>
4 #include <petsc/private/vecimpl.h>
5 
6 /*
7    SNESVIGetInactiveSet - Gets the global indices for the inactive set variables (these correspond to the degrees of freedom the linear
8      system is solved on)
9 
10    Input parameter:
11 .  snes - the SNES context
12 
13    Output parameter:
14 .  inact - inactive set index set
15 
16  */
17 PetscErrorCode SNESVIGetInactiveSet(SNES snes,IS *inact)
18 {
19   SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS*)snes->data;
20 
21   PetscFunctionBegin;
22   *inact = vi->IS_inact;
23   PetscFunctionReturn(0);
24 }
25 
26 /*
27     Provides a wrapper to a DM to allow it to be used to generated the interpolation/restriction from the DM for the smaller matrices and vectors
28   defined by the reduced space method.
29 
30     Simple calls the regular DM interpolation and restricts it to operation on the variables not associated with active constraints.
31 
32 */
33 typedef struct {
34   PetscInt n;                                              /* size of vectors in the reduced DM space */
35   IS       inactive;
36 
37   PetscErrorCode (*createinterpolation)(DM,DM,Mat*,Vec*);  /* DM's original routines */
38   PetscErrorCode (*coarsen)(DM, MPI_Comm, DM*);
39   PetscErrorCode (*createglobalvector)(DM,Vec*);
40   PetscErrorCode (*createinjection)(DM,DM,Mat*);
41   PetscErrorCode (*hascreateinjection)(DM,PetscBool*);
42 
43   DM dm;                                                  /* when destroying this object we need to reset the above function into the base DM */
44 } DM_SNESVI;
45 
46 /*
47      DMCreateGlobalVector_SNESVI - Creates global vector of the size of the reduced space
48 
49 */
50 PetscErrorCode  DMCreateGlobalVector_SNESVI(DM dm,Vec *vec)
51 {
52   PetscErrorCode ierr;
53   PetscContainer isnes;
54   DM_SNESVI      *dmsnesvi;
55 
56   PetscFunctionBegin;
57   ierr = PetscObjectQuery((PetscObject)dm,"VI",(PetscObject*)&isnes);CHKERRQ(ierr);
58   if (!isnes) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Composed SNES is missing");
59   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi);CHKERRQ(ierr);
60   ierr = VecCreateMPI(PetscObjectComm((PetscObject)dm),dmsnesvi->n,PETSC_DETERMINE,vec);CHKERRQ(ierr);
61   ierr = VecSetDM(*vec, dm);CHKERRQ(ierr);
62   PetscFunctionReturn(0);
63 }
64 
65 /*
66      DMCreateInterpolation_SNESVI - Modifieds the interpolation obtained from the DM by removing all rows and columns associated with active constraints.
67 
68 */
69 PetscErrorCode  DMCreateInterpolation_SNESVI(DM dm1,DM dm2,Mat *mat,Vec *vec)
70 {
71   PetscErrorCode ierr;
72   PetscContainer isnes;
73   DM_SNESVI      *dmsnesvi1,*dmsnesvi2;
74   Mat            interp;
75 
76   PetscFunctionBegin;
77   ierr = PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject*)&isnes);CHKERRQ(ierr);
78   if (!isnes) SETERRQ(PetscObjectComm((PetscObject)dm1),PETSC_ERR_PLIB,"Composed VI data structure is missing");
79   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);CHKERRQ(ierr);
80   ierr = PetscObjectQuery((PetscObject)dm2,"VI",(PetscObject*)&isnes);CHKERRQ(ierr);
81   if (!isnes) SETERRQ(PetscObjectComm((PetscObject)dm2),PETSC_ERR_PLIB,"Composed VI data structure is missing");
82   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi2);CHKERRQ(ierr);
83 
84   ierr = (*dmsnesvi1->createinterpolation)(dm1,dm2,&interp,NULL);CHKERRQ(ierr);
85   ierr = MatCreateSubMatrix(interp,dmsnesvi2->inactive,dmsnesvi1->inactive,MAT_INITIAL_MATRIX,mat);CHKERRQ(ierr);
86   ierr = MatDestroy(&interp);CHKERRQ(ierr);
87   *vec = NULL;
88   PetscFunctionReturn(0);
89 }
90 
91 static PetscErrorCode DMSetVI(DM,IS);
92 static PetscErrorCode DMDestroyVI(DM);
93 
94 /*
95      DMCoarsen_SNESVI - Computes the regular coarsened DM then computes additional information about its inactive set
96 
97 */
98 PetscErrorCode  DMCoarsen_SNESVI(DM dm1,MPI_Comm comm,DM *dm2)
99 {
100   PetscErrorCode ierr;
101   PetscContainer isnes;
102   DM_SNESVI      *dmsnesvi1;
103   Vec            finemarked,coarsemarked;
104   IS             inactive;
105   Mat            inject;
106   const PetscInt *index;
107   PetscInt       n,k,cnt = 0,rstart,*coarseindex;
108   PetscScalar    *marked;
109 
110   PetscFunctionBegin;
111   ierr = PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject*)&isnes);CHKERRQ(ierr);
112   if (!isnes) SETERRQ(PetscObjectComm((PetscObject)dm1),PETSC_ERR_PLIB,"Composed VI data structure is missing");
113   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);CHKERRQ(ierr);
114 
115   /* get the original coarsen */
116   ierr = (*dmsnesvi1->coarsen)(dm1,comm,dm2);CHKERRQ(ierr);
117 
118   /* not sure why this extra reference is needed, but without the dm2 disappears too early */
119   /* Updating the KSPCreateVecs() to avoid using DMGetGlobalVector() when matrix is available removes the need for this reference? */
120   /*  ierr = PetscObjectReference((PetscObject)*dm2);CHKERRQ(ierr);*/
121 
122   /* need to set back global vectors in order to use the original injection */
123   ierr = DMClearGlobalVectors(dm1);CHKERRQ(ierr);
124 
125   dm1->ops->createglobalvector = dmsnesvi1->createglobalvector;
126 
127   ierr = DMCreateGlobalVector(dm1,&finemarked);CHKERRQ(ierr);
128   ierr = DMCreateGlobalVector(*dm2,&coarsemarked);CHKERRQ(ierr);
129 
130   /*
131      fill finemarked with locations of inactive points
132   */
133   ierr = ISGetIndices(dmsnesvi1->inactive,&index);CHKERRQ(ierr);
134   ierr = ISGetLocalSize(dmsnesvi1->inactive,&n);CHKERRQ(ierr);
135   ierr = VecSet(finemarked,0.0);CHKERRQ(ierr);
136   for (k=0; k<n; k++) {
137     ierr = VecSetValue(finemarked,index[k],1.0,INSERT_VALUES);CHKERRQ(ierr);
138   }
139   ierr = VecAssemblyBegin(finemarked);CHKERRQ(ierr);
140   ierr = VecAssemblyEnd(finemarked);CHKERRQ(ierr);
141 
142   ierr = DMCreateInjection(*dm2,dm1,&inject);CHKERRQ(ierr);
143   ierr = MatRestrict(inject,finemarked,coarsemarked);CHKERRQ(ierr);
144   ierr = MatDestroy(&inject);CHKERRQ(ierr);
145 
146   /*
147      create index set list of coarse inactive points from coarsemarked
148   */
149   ierr = VecGetLocalSize(coarsemarked,&n);CHKERRQ(ierr);
150   ierr = VecGetOwnershipRange(coarsemarked,&rstart,NULL);CHKERRQ(ierr);
151   ierr = VecGetArray(coarsemarked,&marked);CHKERRQ(ierr);
152   for (k=0; k<n; k++) {
153     if (marked[k] != 0.0) cnt++;
154   }
155   ierr = PetscMalloc1(cnt,&coarseindex);CHKERRQ(ierr);
156   cnt  = 0;
157   for (k=0; k<n; k++) {
158     if (marked[k] != 0.0) coarseindex[cnt++] = k + rstart;
159   }
160   ierr = VecRestoreArray(coarsemarked,&marked);CHKERRQ(ierr);
161   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)coarsemarked),cnt,coarseindex,PETSC_OWN_POINTER,&inactive);CHKERRQ(ierr);
162 
163   ierr = DMClearGlobalVectors(dm1);CHKERRQ(ierr);
164 
165   dm1->ops->createglobalvector = DMCreateGlobalVector_SNESVI;
166 
167   ierr = DMSetVI(*dm2,inactive);CHKERRQ(ierr);
168 
169   ierr = VecDestroy(&finemarked);CHKERRQ(ierr);
170   ierr = VecDestroy(&coarsemarked);CHKERRQ(ierr);
171   ierr = ISDestroy(&inactive);CHKERRQ(ierr);
172   PetscFunctionReturn(0);
173 }
174 
175 PetscErrorCode DMDestroy_SNESVI(DM_SNESVI *dmsnesvi)
176 {
177   PetscErrorCode ierr;
178 
179   PetscFunctionBegin;
180   /* reset the base methods in the DM object that were changed when the DM_SNESVI was reset */
181   dmsnesvi->dm->ops->createinterpolation = dmsnesvi->createinterpolation;
182   dmsnesvi->dm->ops->coarsen             = dmsnesvi->coarsen;
183   dmsnesvi->dm->ops->createglobalvector  = dmsnesvi->createglobalvector;
184   dmsnesvi->dm->ops->createinjection     = dmsnesvi->createinjection;
185   dmsnesvi->dm->ops->hascreateinjection  = dmsnesvi->hascreateinjection;
186   /* need to clear out this vectors because some of them may not have a reference to the DM
187     but they are counted as having references to the DM in DMDestroy() */
188   ierr = DMClearGlobalVectors(dmsnesvi->dm);CHKERRQ(ierr);
189 
190   ierr = ISDestroy(&dmsnesvi->inactive);CHKERRQ(ierr);
191   ierr = PetscFree(dmsnesvi);CHKERRQ(ierr);
192   PetscFunctionReturn(0);
193 }
194 
195 /*
196      DMSetVI - Marks a DM as associated with a VI problem. This causes the interpolation/restriction operators to
197                be restricted to only those variables NOT associated with active constraints.
198 
199 */
200 static PetscErrorCode DMSetVI(DM dm,IS inactive)
201 {
202   PetscErrorCode ierr;
203   PetscContainer isnes;
204   DM_SNESVI      *dmsnesvi;
205 
206   PetscFunctionBegin;
207   if (!dm) PetscFunctionReturn(0);
208 
209   ierr = PetscObjectReference((PetscObject)inactive);CHKERRQ(ierr);
210 
211   ierr = PetscObjectQuery((PetscObject)dm,"VI",(PetscObject*)&isnes);CHKERRQ(ierr);
212   if (!isnes) {
213     ierr = PetscContainerCreate(PetscObjectComm((PetscObject)dm),&isnes);CHKERRQ(ierr);
214     ierr = PetscContainerSetUserDestroy(isnes,(PetscErrorCode (*)(void*))DMDestroy_SNESVI);CHKERRQ(ierr);
215     ierr = PetscNew(&dmsnesvi);CHKERRQ(ierr);
216     ierr = PetscContainerSetPointer(isnes,(void*)dmsnesvi);CHKERRQ(ierr);
217     ierr = PetscObjectCompose((PetscObject)dm,"VI",(PetscObject)isnes);CHKERRQ(ierr);
218     ierr = PetscContainerDestroy(&isnes);CHKERRQ(ierr);
219 
220     dmsnesvi->createinterpolation = dm->ops->createinterpolation;
221     dm->ops->createinterpolation  = DMCreateInterpolation_SNESVI;
222     dmsnesvi->coarsen             = dm->ops->coarsen;
223     dm->ops->coarsen              = DMCoarsen_SNESVI;
224     dmsnesvi->createglobalvector  = dm->ops->createglobalvector;
225     dm->ops->createglobalvector   = DMCreateGlobalVector_SNESVI;
226     dmsnesvi->createinjection     = dm->ops->createinjection;
227     dm->ops->createinjection      = NULL;
228     dmsnesvi->hascreateinjection  = dm->ops->hascreateinjection;
229     dm->ops->hascreateinjection   = NULL;
230   } else {
231     ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi);CHKERRQ(ierr);
232     ierr = ISDestroy(&dmsnesvi->inactive);CHKERRQ(ierr);
233   }
234   ierr = DMClearGlobalVectors(dm);CHKERRQ(ierr);
235   ierr = ISGetLocalSize(inactive,&dmsnesvi->n);CHKERRQ(ierr);
236 
237   dmsnesvi->inactive = inactive;
238   dmsnesvi->dm       = dm;
239   PetscFunctionReturn(0);
240 }
241 
242 /*
243      DMDestroyVI - Frees the DM_SNESVI object contained in the DM
244          - also resets the function pointers in the DM for createinterpolation() etc to use the original DM
245 */
246 static PetscErrorCode DMDestroyVI(DM dm)
247 {
248   PetscErrorCode ierr;
249 
250   PetscFunctionBegin;
251   if (!dm) PetscFunctionReturn(0);
252   ierr = PetscObjectCompose((PetscObject)dm,"VI",(PetscObject)NULL);CHKERRQ(ierr);
253   PetscFunctionReturn(0);
254 }
255 
256 /* --------------------------------------------------------------------------------------------------------*/
257 
258 PetscErrorCode SNESCreateIndexSets_VINEWTONRSLS(SNES snes,Vec X,Vec F,IS *ISact,IS *ISinact)
259 {
260   PetscErrorCode ierr;
261 
262   PetscFunctionBegin;
263   ierr = SNESVIGetActiveSetIS(snes,X,F,ISact);CHKERRQ(ierr);
264   ierr = ISComplement(*ISact,X->map->rstart,X->map->rend,ISinact);CHKERRQ(ierr);
265   PetscFunctionReturn(0);
266 }
267 
268 /* Create active and inactive set vectors. The local size of this vector is set and petsc computes the global size */
269 PetscErrorCode SNESCreateSubVectors_VINEWTONRSLS(SNES snes,PetscInt n,Vec *newv)
270 {
271   PetscErrorCode ierr;
272   Vec            v;
273 
274   PetscFunctionBegin;
275   ierr  = VecCreate(PetscObjectComm((PetscObject)snes),&v);CHKERRQ(ierr);
276   ierr  = VecSetSizes(v,n,PETSC_DECIDE);CHKERRQ(ierr);
277   ierr  = VecSetType(v,VECSTANDARD);CHKERRQ(ierr);
278   *newv = v;
279   PetscFunctionReturn(0);
280 }
281 
282 /* Resets the snes PC and KSP when the active set sizes change */
283 PetscErrorCode SNESVIResetPCandKSP(SNES snes,Mat Amat,Mat Pmat)
284 {
285   PetscErrorCode ierr;
286   KSP            snesksp;
287 
288   PetscFunctionBegin;
289   ierr = SNESGetKSP(snes,&snesksp);CHKERRQ(ierr);
290   ierr = KSPReset(snesksp);CHKERRQ(ierr);
291   ierr = KSPResetFromOptions(snesksp);CHKERRQ(ierr);
292 
293   /*
294   KSP                    kspnew;
295   PC                     pcnew;
296   MatSolverType          stype;
297 
298   ierr = KSPCreate(PetscObjectComm((PetscObject)snes),&kspnew);CHKERRQ(ierr);
299   kspnew->pc_side = snesksp->pc_side;
300   kspnew->rtol    = snesksp->rtol;
301   kspnew->abstol    = snesksp->abstol;
302   kspnew->max_it  = snesksp->max_it;
303   ierr = KSPSetType(kspnew,((PetscObject)snesksp)->type_name);CHKERRQ(ierr);
304   ierr = KSPGetPC(kspnew,&pcnew);CHKERRQ(ierr);
305   ierr = PCSetType(kspnew->pc,((PetscObject)snesksp->pc)->type_name);CHKERRQ(ierr);
306   ierr = PCSetOperators(kspnew->pc,Amat,Pmat);CHKERRQ(ierr);
307   ierr = PCFactorGetMatSolverType(snesksp->pc,&stype);CHKERRQ(ierr);
308   ierr = PCFactorSetMatSolverType(kspnew->pc,stype);CHKERRQ(ierr);
309   ierr = KSPDestroy(&snesksp);CHKERRQ(ierr);
310   snes->ksp = kspnew;
311   ierr = PetscLogObjectParent((PetscObject)snes,(PetscObject)kspnew);CHKERRQ(ierr);
312    ierr = KSPSetFromOptions(kspnew);CHKERRQ(ierr);*/
313   PetscFunctionReturn(0);
314 }
315 
316 /* Variational Inequality solver using reduce space method. No semismooth algorithm is
317    implemented in this algorithm. It basically identifies the active constraints and does
318    a linear solve on the other variables (those not associated with the active constraints). */
319 PetscErrorCode SNESSolve_VINEWTONRSLS(SNES snes)
320 {
321   SNES_VINEWTONRSLS    *vi = (SNES_VINEWTONRSLS*)snes->data;
322   PetscErrorCode       ierr;
323   PetscInt             maxits,i,lits;
324   SNESLineSearchReason lssucceed;
325   PetscReal            fnorm,gnorm,xnorm=0,ynorm;
326   Vec                  Y,X,F;
327   KSPConvergedReason   kspreason;
328   KSP                  ksp;
329   PC                   pc;
330 
331   PetscFunctionBegin;
332   /* Multigrid must use Galerkin for coarse grids with active set/reduced space methods; cannot rediscretize on coarser grids*/
333   ierr = SNESGetKSP(snes,&ksp);CHKERRQ(ierr);
334   ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr);
335   ierr = PCMGSetGalerkin(pc,PC_MG_GALERKIN_BOTH);CHKERRQ(ierr);
336 
337   snes->numFailures            = 0;
338   snes->numLinearSolveFailures = 0;
339   snes->reason                 = SNES_CONVERGED_ITERATING;
340 
341   maxits = snes->max_its;               /* maximum number of iterations */
342   X      = snes->vec_sol;               /* solution vector */
343   F      = snes->vec_func;              /* residual vector */
344   Y      = snes->work[0];               /* work vectors */
345 
346   ierr = SNESLineSearchSetVIFunctions(snes->linesearch, SNESVIProjectOntoBounds, SNESVIComputeInactiveSetFnorm);CHKERRQ(ierr);
347   ierr = SNESLineSearchSetVecs(snes->linesearch, X, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
348   ierr = SNESLineSearchSetUp(snes->linesearch);CHKERRQ(ierr);
349 
350   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
351   snes->iter = 0;
352   snes->norm = 0.0;
353   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
354 
355   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
356   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
357   ierr = SNESVIComputeInactiveSetFnorm(snes,F,X,&fnorm);CHKERRQ(ierr);
358   ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr);        /* xnorm <- ||x||  */
359   SNESCheckFunctionNorm(snes,fnorm);
360   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
361   snes->norm = fnorm;
362   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
363   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
364   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
365 
366   /* test convergence */
367   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
368   if (snes->reason) PetscFunctionReturn(0);
369 
370   for (i=0; i<maxits; i++) {
371 
372     IS         IS_act; /* _act -> active set _inact -> inactive set */
373     IS         IS_redact; /* redundant active set */
374     VecScatter scat_act,scat_inact;
375     PetscInt   nis_act,nis_inact;
376     Vec        Y_act,Y_inact,F_inact;
377     Mat        jac_inact_inact,prejac_inact_inact;
378     PetscBool  isequal;
379 
380     /* Call general purpose update function */
381     if (snes->ops->update) {
382       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
383     }
384     ierr = SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr);
385     SNESCheckJacobianDomainerror(snes);
386 
387     /* Create active and inactive index sets */
388 
389     /*original
390     ierr = SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&vi->IS_inact);CHKERRQ(ierr);
391      */
392     ierr = SNESVIGetActiveSetIS(snes,X,F,&IS_act);CHKERRQ(ierr);
393 
394     if (vi->checkredundancy) {
395       (*vi->checkredundancy)(snes,IS_act,&IS_redact,vi->ctxP);CHKERRQ(ierr);
396       if (IS_redact) {
397         ierr = ISSort(IS_redact);CHKERRQ(ierr);
398         ierr = ISComplement(IS_redact,X->map->rstart,X->map->rend,&vi->IS_inact);CHKERRQ(ierr);
399         ierr = ISDestroy(&IS_redact);CHKERRQ(ierr);
400       } else {
401         ierr = ISComplement(IS_act,X->map->rstart,X->map->rend,&vi->IS_inact);CHKERRQ(ierr);
402       }
403     } else {
404       ierr = ISComplement(IS_act,X->map->rstart,X->map->rend,&vi->IS_inact);CHKERRQ(ierr);
405     }
406 
407     /* Create inactive set submatrix */
408     ierr = MatCreateSubMatrix(snes->jacobian,vi->IS_inact,vi->IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr);
409 
410     if (0) {                    /* Dead code (temporary developer hack) */
411       IS keptrows;
412       ierr = MatFindNonzeroRows(jac_inact_inact,&keptrows);CHKERRQ(ierr);
413       if (keptrows) {
414         PetscInt       cnt,*nrows,k;
415         const PetscInt *krows,*inact;
416         PetscInt       rstart;
417 
418         ierr = MatGetOwnershipRange(jac_inact_inact,&rstart,NULL);CHKERRQ(ierr);
419         ierr = MatDestroy(&jac_inact_inact);CHKERRQ(ierr);
420         ierr = ISDestroy(&IS_act);CHKERRQ(ierr);
421 
422         ierr = ISGetLocalSize(keptrows,&cnt);CHKERRQ(ierr);
423         ierr = ISGetIndices(keptrows,&krows);CHKERRQ(ierr);
424         ierr = ISGetIndices(vi->IS_inact,&inact);CHKERRQ(ierr);
425         ierr = PetscMalloc1(cnt,&nrows);CHKERRQ(ierr);
426         for (k=0; k<cnt; k++) nrows[k] = inact[krows[k]-rstart];
427         ierr = ISRestoreIndices(keptrows,&krows);CHKERRQ(ierr);
428         ierr = ISRestoreIndices(vi->IS_inact,&inact);CHKERRQ(ierr);
429         ierr = ISDestroy(&keptrows);CHKERRQ(ierr);
430         ierr = ISDestroy(&vi->IS_inact);CHKERRQ(ierr);
431 
432         ierr = ISCreateGeneral(PetscObjectComm((PetscObject)snes),cnt,nrows,PETSC_OWN_POINTER,&vi->IS_inact);CHKERRQ(ierr);
433         ierr = ISComplement(vi->IS_inact,F->map->rstart,F->map->rend,&IS_act);CHKERRQ(ierr);
434         ierr = MatCreateSubMatrix(snes->jacobian,vi->IS_inact,vi->IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr);
435       }
436     }
437     ierr = DMSetVI(snes->dm,vi->IS_inact);CHKERRQ(ierr);
438     /* remove later */
439 
440     /*
441     ierr = VecView(vi->xu,PETSC_VIEWER_BINARY_(((PetscObject)(vi->xu))->comm));CHKERRQ(ierr);
442     ierr = VecView(vi->xl,PETSC_VIEWER_BINARY_(((PetscObject)(vi->xl))->comm));CHKERRQ(ierr);
443     ierr = VecView(X,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)X)));CHKERRQ(ierr);
444     ierr = VecView(F,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)F)));CHKERRQ(ierr);
445     ierr = ISView(vi->IS_inact,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)vi->IS_inact)));CHKERRQ(ierr);
446      */
447 
448     /* Get sizes of active and inactive sets */
449     ierr = ISGetLocalSize(IS_act,&nis_act);CHKERRQ(ierr);
450     ierr = ISGetLocalSize(vi->IS_inact,&nis_inact);CHKERRQ(ierr);
451 
452     /* Create active and inactive set vectors */
453     ierr = SNESCreateSubVectors_VINEWTONRSLS(snes,nis_inact,&F_inact);CHKERRQ(ierr);
454     ierr = SNESCreateSubVectors_VINEWTONRSLS(snes,nis_act,&Y_act);CHKERRQ(ierr);
455     ierr = SNESCreateSubVectors_VINEWTONRSLS(snes,nis_inact,&Y_inact);CHKERRQ(ierr);
456 
457     /* Create scatter contexts */
458     ierr = VecScatterCreate(Y,IS_act,Y_act,NULL,&scat_act);CHKERRQ(ierr);
459     ierr = VecScatterCreate(Y,vi->IS_inact,Y_inact,NULL,&scat_inact);CHKERRQ(ierr);
460 
461     /* Do a vec scatter to active and inactive set vectors */
462     ierr = VecScatterBegin(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
463     ierr = VecScatterEnd(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
464 
465     ierr = VecScatterBegin(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
466     ierr = VecScatterEnd(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
467 
468     ierr = VecScatterBegin(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
469     ierr = VecScatterEnd(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
470 
471     /* Active set direction = 0 */
472     ierr = VecSet(Y_act,0);CHKERRQ(ierr);
473     if (snes->jacobian != snes->jacobian_pre) {
474       ierr = MatCreateSubMatrix(snes->jacobian_pre,vi->IS_inact,vi->IS_inact,MAT_INITIAL_MATRIX,&prejac_inact_inact);CHKERRQ(ierr);
475     } else prejac_inact_inact = jac_inact_inact;
476 
477     ierr = ISEqual(vi->IS_inact_prev,vi->IS_inact,&isequal);CHKERRQ(ierr);
478     if (!isequal) {
479       ierr = SNESVIResetPCandKSP(snes,jac_inact_inact,prejac_inact_inact);CHKERRQ(ierr);
480       ierr = PCFieldSplitRestrictIS(pc,vi->IS_inact);CHKERRQ(ierr);
481     }
482 
483     /*      ierr = ISView(vi->IS_inact,0);CHKERRQ(ierr); */
484     /*      ierr = ISView(IS_act,0);CHKERRQ(ierr);*/
485     /*      ierr = MatView(snes->jacobian_pre,0); */
486 
487     ierr = KSPSetOperators(snes->ksp,jac_inact_inact,prejac_inact_inact);CHKERRQ(ierr);
488     ierr = KSPSetUp(snes->ksp);CHKERRQ(ierr);
489     {
490       PC        pc;
491       PetscBool flg;
492       ierr = KSPGetPC(snes->ksp,&pc);CHKERRQ(ierr);
493       ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&flg);CHKERRQ(ierr);
494       if (flg) {
495         KSP *subksps;
496         ierr = PCFieldSplitGetSubKSP(pc,NULL,&subksps);CHKERRQ(ierr);
497         ierr = KSPGetPC(subksps[0],&pc);CHKERRQ(ierr);
498         ierr = PetscFree(subksps);CHKERRQ(ierr);
499         ierr = PetscObjectTypeCompare((PetscObject)pc,PCBJACOBI,&flg);CHKERRQ(ierr);
500         if (flg) {
501           PetscInt       n,N = 101*101,j,cnts[3] = {0,0,0};
502           const PetscInt *ii;
503 
504           ierr = ISGetSize(vi->IS_inact,&n);CHKERRQ(ierr);
505           ierr = ISGetIndices(vi->IS_inact,&ii);CHKERRQ(ierr);
506           for (j=0; j<n; j++) {
507             if (ii[j] < N) cnts[0]++;
508             else if (ii[j] < 2*N) cnts[1]++;
509             else if (ii[j] < 3*N) cnts[2]++;
510           }
511           ierr = ISRestoreIndices(vi->IS_inact,&ii);CHKERRQ(ierr);
512 
513           ierr = PCBJacobiSetTotalBlocks(pc,3,cnts);CHKERRQ(ierr);
514         }
515       }
516     }
517 
518     ierr = KSPSolve(snes->ksp,F_inact,Y_inact);CHKERRQ(ierr);
519     ierr = VecScatterBegin(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
520     ierr = VecScatterEnd(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
521     ierr = VecScatterBegin(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
522     ierr = VecScatterEnd(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
523 
524     ierr = VecDestroy(&F_inact);CHKERRQ(ierr);
525     ierr = VecDestroy(&Y_act);CHKERRQ(ierr);
526     ierr = VecDestroy(&Y_inact);CHKERRQ(ierr);
527     ierr = VecScatterDestroy(&scat_act);CHKERRQ(ierr);
528     ierr = VecScatterDestroy(&scat_inact);CHKERRQ(ierr);
529     ierr = ISDestroy(&IS_act);CHKERRQ(ierr);
530     if (!isequal) {
531       ierr = ISDestroy(&vi->IS_inact_prev);CHKERRQ(ierr);
532       ierr = ISDuplicate(vi->IS_inact,&vi->IS_inact_prev);CHKERRQ(ierr);
533     }
534     ierr = ISDestroy(&vi->IS_inact);CHKERRQ(ierr);
535     ierr = MatDestroy(&jac_inact_inact);CHKERRQ(ierr);
536     if (snes->jacobian != snes->jacobian_pre) {
537       ierr = MatDestroy(&prejac_inact_inact);CHKERRQ(ierr);
538     }
539 
540     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
541     if (kspreason < 0) {
542       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
543         ierr         = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
544         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
545         break;
546       }
547     }
548 
549     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
550     snes->linear_its += lits;
551     ierr              = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
552     /*
553     if (snes->ops->precheck) {
554       PetscBool changed_y = PETSC_FALSE;
555       ierr = (*snes->ops->precheck)(snes,X,Y,snes->precheck,&changed_y);CHKERRQ(ierr);
556     }
557 
558     if (PetscLogPrintInfo) {
559       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
560     }
561     */
562     /* Compute a (scaled) negative update in the line search routine:
563          Y <- X - lambda*Y
564        and evaluate G = function(Y) (depends on the line search).
565     */
566     ierr  = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
567     ynorm = 1; gnorm = fnorm;
568     ierr  = SNESLineSearchApply(snes->linesearch, X, F, &gnorm, Y);CHKERRQ(ierr);
569     ierr  = SNESLineSearchGetReason(snes->linesearch, &lssucceed);CHKERRQ(ierr);
570     ierr  = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &gnorm, &ynorm);CHKERRQ(ierr);
571     ierr  = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)fnorm,(double)gnorm,(double)ynorm,(int)lssucceed);CHKERRQ(ierr);
572     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
573     if (snes->domainerror) {
574       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
575       ierr         = DMDestroyVI(snes->dm);CHKERRQ(ierr);
576       PetscFunctionReturn(0);
577     }
578     if (lssucceed) {
579       if (++snes->numFailures >= snes->maxFailures) {
580         PetscBool ismin;
581         snes->reason = SNES_DIVERGED_LINE_SEARCH;
582         ierr         = SNESVICheckLocalMin_Private(snes,snes->jacobian,F,X,gnorm,&ismin);CHKERRQ(ierr);
583         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
584         break;
585       }
586    }
587    ierr = DMDestroyVI(snes->dm);CHKERRQ(ierr);
588     /* Update function and solution vectors */
589     fnorm = gnorm;
590     /* Monitor convergence */
591     ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
592     snes->iter = i+1;
593     snes->norm = fnorm;
594     snes->xnorm = xnorm;
595     snes->ynorm = ynorm;
596     ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
597     ierr       = SNESLogConvergenceHistory(snes,snes->norm,lits);CHKERRQ(ierr);
598     ierr       = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
599     /* Test for convergence, xnorm = || X || */
600     if (snes->ops->converged != SNESConvergedSkip) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
601     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
602     if (snes->reason) break;
603   }
604   /* make sure that the VI information attached to the DM is removed if the for loop above was broken early due to some exceptional conditional */
605   ierr = DMDestroyVI(snes->dm);CHKERRQ(ierr);
606   if (i == maxits) {
607     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
608     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
609   }
610   PetscFunctionReturn(0);
611 }
612 
613 PetscErrorCode SNESVISetRedundancyCheck(SNES snes,PetscErrorCode (*func)(SNES,IS,IS*,void*),void *ctx)
614 {
615   SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS*)snes->data;
616 
617   PetscFunctionBegin;
618   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
619   vi->checkredundancy = func;
620   vi->ctxP            = ctx;
621   PetscFunctionReturn(0);
622 }
623 
624 #if defined(PETSC_HAVE_MATLAB_ENGINE)
625 #include <engine.h>
626 #include <mex.h>
627 typedef struct {char *funcname; mxArray *ctx;} SNESMatlabContext;
628 
629 PetscErrorCode SNESVIRedundancyCheck_Matlab(SNES snes,IS is_act,IS *is_redact,void *ctx)
630 {
631   PetscErrorCode    ierr;
632   SNESMatlabContext *sctx = (SNESMatlabContext*)ctx;
633   int               nlhs  = 1, nrhs = 5;
634   mxArray           *plhs[1], *prhs[5];
635   long long int     l1      = 0, l2 = 0, ls = 0;
636   PetscInt          *indices=NULL;
637 
638   PetscFunctionBegin;
639   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
640   PetscValidHeaderSpecific(is_act,IS_CLASSID,2);
641   PetscValidPointer(is_redact,3);
642   PetscCheckSameComm(snes,1,is_act,2);
643 
644   /* Create IS for reduced active set of size 0, its size and indices will
645    bet set by the Matlab function */
646   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)snes),0,indices,PETSC_OWN_POINTER,is_redact);CHKERRQ(ierr);
647   /* call Matlab function in ctx */
648   ierr    = PetscArraycpy(&ls,&snes,1);CHKERRQ(ierr);
649   ierr    = PetscArraycpy(&l1,&is_act,1);CHKERRQ(ierr);
650   ierr    = PetscArraycpy(&l2,is_redact,1);CHKERRQ(ierr);
651   prhs[0] = mxCreateDoubleScalar((double)ls);
652   prhs[1] = mxCreateDoubleScalar((double)l1);
653   prhs[2] = mxCreateDoubleScalar((double)l2);
654   prhs[3] = mxCreateString(sctx->funcname);
655   prhs[4] = sctx->ctx;
656   ierr    = mexCallMATLAB(nlhs,plhs,nrhs,prhs,"PetscSNESVIRedundancyCheckInternal");CHKERRQ(ierr);
657   ierr    = mxGetScalar(plhs[0]);CHKERRQ(ierr);
658   mxDestroyArray(prhs[0]);
659   mxDestroyArray(prhs[1]);
660   mxDestroyArray(prhs[2]);
661   mxDestroyArray(prhs[3]);
662   mxDestroyArray(plhs[0]);
663   PetscFunctionReturn(0);
664 }
665 
666 PetscErrorCode SNESVISetRedundancyCheckMatlab(SNES snes,const char *func,mxArray *ctx)
667 {
668   PetscErrorCode    ierr;
669   SNESMatlabContext *sctx;
670 
671   PetscFunctionBegin;
672   /* currently sctx is memory bleed */
673   ierr      = PetscNew(&sctx);CHKERRQ(ierr);
674   ierr      = PetscStrallocpy(func,&sctx->funcname);CHKERRQ(ierr);
675   sctx->ctx = mxDuplicateArray(ctx);
676   ierr      = SNESVISetRedundancyCheck(snes,SNESVIRedundancyCheck_Matlab,sctx);CHKERRQ(ierr);
677   PetscFunctionReturn(0);
678 }
679 
680 #endif
681 
682 /* -------------------------------------------------------------------------- */
683 /*
684    SNESSetUp_VINEWTONRSLS - Sets up the internal data structures for the later use
685    of the SNESVI nonlinear solver.
686 
687    Input Parameter:
688 .  snes - the SNES context
689 
690    Application Interface Routine: SNESSetUp()
691 
692    Notes:
693    For basic use of the SNES solvers, the user need not explicitly call
694    SNESSetUp(), since these actions will automatically occur during
695    the call to SNESSolve().
696  */
697 PetscErrorCode SNESSetUp_VINEWTONRSLS(SNES snes)
698 {
699   PetscErrorCode    ierr;
700   SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS*) snes->data;
701   PetscInt          *indices;
702   PetscInt          i,n,rstart,rend;
703   SNESLineSearch    linesearch;
704 
705   PetscFunctionBegin;
706   ierr = SNESSetUp_VI(snes);CHKERRQ(ierr);
707 
708   /* Set up previous active index set for the first snes solve
709    vi->IS_inact_prev = 0,1,2,....N */
710 
711   ierr = VecGetOwnershipRange(snes->vec_sol,&rstart,&rend);CHKERRQ(ierr);
712   ierr = VecGetLocalSize(snes->vec_sol,&n);CHKERRQ(ierr);
713   ierr = PetscMalloc1(n,&indices);CHKERRQ(ierr);
714   for (i=0; i < n; i++) indices[i] = rstart + i;
715   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)snes),n,indices,PETSC_OWN_POINTER,&vi->IS_inact_prev);CHKERRQ(ierr);
716 
717   /* set the line search functions */
718   if (!snes->linesearch) {
719     ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
720     ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHBT);CHKERRQ(ierr);
721   }
722   PetscFunctionReturn(0);
723 }
724 /* -------------------------------------------------------------------------- */
725 PetscErrorCode SNESReset_VINEWTONRSLS(SNES snes)
726 {
727   SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS*) snes->data;
728   PetscErrorCode    ierr;
729 
730   PetscFunctionBegin;
731   ierr = SNESReset_VI(snes);CHKERRQ(ierr);
732   ierr = ISDestroy(&vi->IS_inact_prev);CHKERRQ(ierr);
733   PetscFunctionReturn(0);
734 }
735 
736 /* -------------------------------------------------------------------------- */
737 /*MC
738       SNESVINEWTONRSLS - Reduced space active set solvers for variational inequalities based on Newton's method
739 
740    Options Database:
741 +   -snes_type <vinewtonssls,vinewtonrsls> - a semi-smooth solver, a reduced space active set method
742 -   -snes_vi_monitor - prints the number of active constraints at each iteration.
743 
744    Level: beginner
745 
746    References:
747 .  1. - T. S. Munson, and S. Benson. Flexible Complementarity Solvers for Large Scale
748      Applications, Optimization Methods and Software, 21 (2006).
749 
750 .seealso:  SNESVISetVariableBounds(), SNESVISetComputeVariableBounds(), SNESCreate(), SNES, SNESSetType(), SNESVINEWTONSSLS, SNESNEWTONTR, SNESLineSearchSetType(),SNESLineSearchSetPostCheck(), SNESLineSearchSetPreCheck()
751 
752 M*/
753 PETSC_EXTERN PetscErrorCode SNESCreate_VINEWTONRSLS(SNES snes)
754 {
755   PetscErrorCode    ierr;
756   SNES_VINEWTONRSLS *vi;
757   SNESLineSearch    linesearch;
758 
759   PetscFunctionBegin;
760   snes->ops->reset          = SNESReset_VINEWTONRSLS;
761   snes->ops->setup          = SNESSetUp_VINEWTONRSLS;
762   snes->ops->solve          = SNESSolve_VINEWTONRSLS;
763   snes->ops->destroy        = SNESDestroy_VI;
764   snes->ops->setfromoptions = SNESSetFromOptions_VI;
765   snes->ops->view           = NULL;
766   snes->ops->converged      = SNESConvergedDefault_VI;
767 
768   snes->usesksp = PETSC_TRUE;
769   snes->usesnpc = PETSC_FALSE;
770 
771   ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
772   if (!((PetscObject)linesearch)->type_name) {
773     ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHBT);CHKERRQ(ierr);
774   }
775   ierr = SNESLineSearchBTSetAlpha(linesearch, 0.0);CHKERRQ(ierr);
776 
777   snes->alwayscomputesfinalresidual = PETSC_TRUE;
778 
779   ierr                = PetscNewLog(snes,&vi);CHKERRQ(ierr);
780   snes->data          = (void*)vi;
781   vi->checkredundancy = NULL;
782 
783   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESVISetVariableBounds_C",SNESVISetVariableBounds_VI);CHKERRQ(ierr);
784   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESVISetComputeVariableBounds_C",SNESVISetComputeVariableBounds_VI);CHKERRQ(ierr);
785   PetscFunctionReturn(0);
786 }
787