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