xref: /petsc/src/snes/impls/vi/rs/virs.c (revision fbda97447efb739befdf7134ad897ba9ea04a9a4)
1c2fc9fa9SBarry Smith 
2c2fc9fa9SBarry Smith #include <../src/snes/impls/vi/rs/virsimpl.h> /*I "petscsnes.h" I*/
3af0996ceSBarry Smith #include <petsc/private/dmimpl.h>
4af0996ceSBarry Smith #include <petsc/private/vecimpl.h>
5c2fc9fa9SBarry Smith 
6f6dfbefdSBarry Smith /*@
7c2fc9fa9SBarry Smith    SNESVIGetInactiveSet - Gets the global indices for the inactive set variables (these correspond to the degrees of freedom the linear
8c2fc9fa9SBarry Smith      system is solved on)
9c2fc9fa9SBarry Smith 
107a7aea1fSJed Brown    Input parameter:
11f6dfbefdSBarry Smith .  snes - the `SNES` context
12c2fc9fa9SBarry Smith 
137a7aea1fSJed Brown    Output parameter:
14d5f1b7e6SEd Bueler .  inact - inactive set index set
15c2fc9fa9SBarry Smith 
16*fbda9744SBarry Smith    Level: advanced
17*fbda9744SBarry Smith 
18f6dfbefdSBarry Smith .seealso: `SNESVINEWTONRSLS`
19f6dfbefdSBarry Smith @*/
209371c9d4SSatish Balay PetscErrorCode SNESVIGetInactiveSet(SNES snes, IS *inact) {
21f450aa47SBarry Smith   SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data;
226e111a19SKarl Rupp 
23c2fc9fa9SBarry Smith   PetscFunctionBegin;
24f009fc93SPatrick Farrell   *inact = vi->IS_inact;
25c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
26c2fc9fa9SBarry Smith }
27c2fc9fa9SBarry Smith 
28c2fc9fa9SBarry Smith /*
29c2fc9fa9SBarry Smith     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
30c2fc9fa9SBarry Smith   defined by the reduced space method.
31c2fc9fa9SBarry Smith 
32c2fc9fa9SBarry Smith     Simple calls the regular DM interpolation and restricts it to operation on the variables not associated with active constraints.
33d49cd2b7SBarry Smith */
34c2fc9fa9SBarry Smith typedef struct {
35c2fc9fa9SBarry Smith   PetscInt n; /* size of vectors in the reduced DM space */
36c2fc9fa9SBarry Smith   IS       inactive;
37f5af7f23SKarl Rupp 
3825296bd5SBarry Smith   PetscErrorCode (*createinterpolation)(DM, DM, Mat *, Vec *); /* DM's original routines */
39c2fc9fa9SBarry Smith   PetscErrorCode (*coarsen)(DM, MPI_Comm, DM *);
40c2fc9fa9SBarry Smith   PetscErrorCode (*createglobalvector)(DM, Vec *);
415a84ad33SLisandro Dalcin   PetscErrorCode (*createinjection)(DM, DM, Mat *);
424a7a4c06SLawrence Mitchell   PetscErrorCode (*hascreateinjection)(DM, PetscBool *);
43f5af7f23SKarl Rupp 
44c2fc9fa9SBarry Smith   DM dm; /* when destroying this object we need to reset the above function into the base DM */
45c2fc9fa9SBarry Smith } DM_SNESVI;
46c2fc9fa9SBarry Smith 
47c2fc9fa9SBarry Smith /*
48c2fc9fa9SBarry Smith      DMCreateGlobalVector_SNESVI - Creates global vector of the size of the reduced space
49c2fc9fa9SBarry Smith */
509371c9d4SSatish Balay PetscErrorCode DMCreateGlobalVector_SNESVI(DM dm, Vec *vec) {
51c2fc9fa9SBarry Smith   PetscContainer isnes;
52c2fc9fa9SBarry Smith   DM_SNESVI     *dmsnesvi;
53c2fc9fa9SBarry Smith 
54c2fc9fa9SBarry Smith   PetscFunctionBegin;
559566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)dm, "VI", (PetscObject *)&isnes));
5628b400f6SJacob Faibussowitsch   PetscCheck(isnes, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Composed SNES is missing");
579566063dSJacob Faibussowitsch   PetscCall(PetscContainerGetPointer(isnes, (void **)&dmsnesvi));
589566063dSJacob Faibussowitsch   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)dm), dmsnesvi->n, PETSC_DETERMINE, vec));
599566063dSJacob Faibussowitsch   PetscCall(VecSetDM(*vec, dm));
60c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
61c2fc9fa9SBarry Smith }
62c2fc9fa9SBarry Smith 
63c2fc9fa9SBarry Smith /*
64e727c939SJed Brown      DMCreateInterpolation_SNESVI - Modifieds the interpolation obtained from the DM by removing all rows and columns associated with active constraints.
65c2fc9fa9SBarry Smith */
669371c9d4SSatish Balay PetscErrorCode DMCreateInterpolation_SNESVI(DM dm1, DM dm2, Mat *mat, Vec *vec) {
67c2fc9fa9SBarry Smith   PetscContainer isnes;
68c2fc9fa9SBarry Smith   DM_SNESVI     *dmsnesvi1, *dmsnesvi2;
69c2fc9fa9SBarry Smith   Mat            interp;
70c2fc9fa9SBarry Smith 
71c2fc9fa9SBarry Smith   PetscFunctionBegin;
729566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)dm1, "VI", (PetscObject *)&isnes));
7328b400f6SJacob Faibussowitsch   PetscCheck(isnes, PetscObjectComm((PetscObject)dm1), PETSC_ERR_PLIB, "Composed VI data structure is missing");
749566063dSJacob Faibussowitsch   PetscCall(PetscContainerGetPointer(isnes, (void **)&dmsnesvi1));
759566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)dm2, "VI", (PetscObject *)&isnes));
7628b400f6SJacob Faibussowitsch   PetscCheck(isnes, PetscObjectComm((PetscObject)dm2), PETSC_ERR_PLIB, "Composed VI data structure is missing");
779566063dSJacob Faibussowitsch   PetscCall(PetscContainerGetPointer(isnes, (void **)&dmsnesvi2));
78c2fc9fa9SBarry Smith 
799566063dSJacob Faibussowitsch   PetscCall((*dmsnesvi1->createinterpolation)(dm1, dm2, &interp, NULL));
809566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(interp, dmsnesvi2->inactive, dmsnesvi1->inactive, MAT_INITIAL_MATRIX, mat));
819566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interp));
829e5d0892SLisandro Dalcin   *vec = NULL;
83c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
84c2fc9fa9SBarry Smith }
85c2fc9fa9SBarry Smith 
86c2fc9fa9SBarry Smith /*
87c2fc9fa9SBarry Smith      DMCoarsen_SNESVI - Computes the regular coarsened DM then computes additional information about its inactive set
88c2fc9fa9SBarry Smith */
899371c9d4SSatish Balay PetscErrorCode DMCoarsen_SNESVI(DM dm1, MPI_Comm comm, DM *dm2) {
90c2fc9fa9SBarry Smith   PetscContainer  isnes;
91c2fc9fa9SBarry Smith   DM_SNESVI      *dmsnesvi1;
92c2fc9fa9SBarry Smith   Vec             finemarked, coarsemarked;
93c2fc9fa9SBarry Smith   IS              inactive;
946dbf9973SLawrence Mitchell   Mat             inject;
95c2fc9fa9SBarry Smith   const PetscInt *index;
96c2fc9fa9SBarry Smith   PetscInt        n, k, cnt = 0, rstart, *coarseindex;
97c2fc9fa9SBarry Smith   PetscScalar    *marked;
98c2fc9fa9SBarry Smith 
99c2fc9fa9SBarry Smith   PetscFunctionBegin;
1009566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)dm1, "VI", (PetscObject *)&isnes));
10128b400f6SJacob Faibussowitsch   PetscCheck(isnes, PetscObjectComm((PetscObject)dm1), PETSC_ERR_PLIB, "Composed VI data structure is missing");
1029566063dSJacob Faibussowitsch   PetscCall(PetscContainerGetPointer(isnes, (void **)&dmsnesvi1));
103c2fc9fa9SBarry Smith 
104c2fc9fa9SBarry Smith   /* get the original coarsen */
1059566063dSJacob Faibussowitsch   PetscCall((*dmsnesvi1->coarsen)(dm1, comm, dm2));
106c2fc9fa9SBarry Smith 
107c2fc9fa9SBarry Smith   /* not sure why this extra reference is needed, but without the dm2 disappears too early */
10894c98981SBarry Smith   /* Updating the KSPCreateVecs() to avoid using DMGetGlobalVector() when matrix is available removes the need for this reference? */
1099566063dSJacob Faibussowitsch   /*  PetscCall(PetscObjectReference((PetscObject)*dm2));*/
110c2fc9fa9SBarry Smith 
111c2fc9fa9SBarry Smith   /* need to set back global vectors in order to use the original injection */
1129566063dSJacob Faibussowitsch   PetscCall(DMClearGlobalVectors(dm1));
1131aa26658SKarl Rupp 
114c2fc9fa9SBarry Smith   dm1->ops->createglobalvector = dmsnesvi1->createglobalvector;
1151aa26658SKarl Rupp 
1169566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dm1, &finemarked));
1179566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(*dm2, &coarsemarked));
118c2fc9fa9SBarry Smith 
119c2fc9fa9SBarry Smith   /*
120c2fc9fa9SBarry Smith      fill finemarked with locations of inactive points
121c2fc9fa9SBarry Smith   */
1229566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(dmsnesvi1->inactive, &index));
1239566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(dmsnesvi1->inactive, &n));
1249566063dSJacob Faibussowitsch   PetscCall(VecSet(finemarked, 0.0));
12548a46eb9SPierre Jolivet   for (k = 0; k < n; k++) PetscCall(VecSetValue(finemarked, index[k], 1.0, INSERT_VALUES));
1269566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(finemarked));
1279566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(finemarked));
128c2fc9fa9SBarry Smith 
1299566063dSJacob Faibussowitsch   PetscCall(DMCreateInjection(*dm2, dm1, &inject));
1309566063dSJacob Faibussowitsch   PetscCall(MatRestrict(inject, finemarked, coarsemarked));
1319566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&inject));
132c2fc9fa9SBarry Smith 
133c2fc9fa9SBarry Smith   /*
134c2fc9fa9SBarry Smith      create index set list of coarse inactive points from coarsemarked
135c2fc9fa9SBarry Smith   */
1369566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(coarsemarked, &n));
1379566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(coarsemarked, &rstart, NULL));
1389566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coarsemarked, &marked));
139c2fc9fa9SBarry Smith   for (k = 0; k < n; k++) {
140c2fc9fa9SBarry Smith     if (marked[k] != 0.0) cnt++;
141c2fc9fa9SBarry Smith   }
1429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(cnt, &coarseindex));
143c2fc9fa9SBarry Smith   cnt = 0;
144c2fc9fa9SBarry Smith   for (k = 0; k < n; k++) {
145c2fc9fa9SBarry Smith     if (marked[k] != 0.0) coarseindex[cnt++] = k + rstart;
146c2fc9fa9SBarry Smith   }
1479566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coarsemarked, &marked));
1489566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)coarsemarked), cnt, coarseindex, PETSC_OWN_POINTER, &inactive));
149c2fc9fa9SBarry Smith 
1509566063dSJacob Faibussowitsch   PetscCall(DMClearGlobalVectors(dm1));
1511aa26658SKarl Rupp 
152c2fc9fa9SBarry Smith   dm1->ops->createglobalvector = DMCreateGlobalVector_SNESVI;
1531aa26658SKarl Rupp 
1549566063dSJacob Faibussowitsch   PetscCall(DMSetVI(*dm2, inactive));
155c2fc9fa9SBarry Smith 
1569566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&finemarked));
1579566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coarsemarked));
1589566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&inactive));
159c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
160c2fc9fa9SBarry Smith }
161c2fc9fa9SBarry Smith 
1629371c9d4SSatish Balay PetscErrorCode DMDestroy_SNESVI(DM_SNESVI *dmsnesvi) {
163c2fc9fa9SBarry Smith   PetscFunctionBegin;
164c2fc9fa9SBarry Smith   /* reset the base methods in the DM object that were changed when the DM_SNESVI was reset */
16525296bd5SBarry Smith   dmsnesvi->dm->ops->createinterpolation = dmsnesvi->createinterpolation;
166c2fc9fa9SBarry Smith   dmsnesvi->dm->ops->coarsen             = dmsnesvi->coarsen;
167c2fc9fa9SBarry Smith   dmsnesvi->dm->ops->createglobalvector  = dmsnesvi->createglobalvector;
1685a84ad33SLisandro Dalcin   dmsnesvi->dm->ops->createinjection     = dmsnesvi->createinjection;
1694a7a4c06SLawrence Mitchell   dmsnesvi->dm->ops->hascreateinjection  = dmsnesvi->hascreateinjection;
170c2fc9fa9SBarry Smith   /* need to clear out this vectors because some of them may not have a reference to the DM
171c2fc9fa9SBarry Smith     but they are counted as having references to the DM in DMDestroy() */
1729566063dSJacob Faibussowitsch   PetscCall(DMClearGlobalVectors(dmsnesvi->dm));
173c2fc9fa9SBarry Smith 
1749566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&dmsnesvi->inactive));
1759566063dSJacob Faibussowitsch   PetscCall(PetscFree(dmsnesvi));
176c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
177c2fc9fa9SBarry Smith }
178c2fc9fa9SBarry Smith 
179f6dfbefdSBarry Smith /*@
180c2fc9fa9SBarry Smith      DMSetVI - Marks a DM as associated with a VI problem. This causes the interpolation/restriction operators to
181c2fc9fa9SBarry Smith                be restricted to only those variables NOT associated with active constraints.
182c2fc9fa9SBarry Smith 
183f6dfbefdSBarry Smith     Logically Collective on dm
184f6dfbefdSBarry Smith 
185f6dfbefdSBarry Smith     Input Parameters:
186f6dfbefdSBarry Smith +   dm - the `DM` object
187f6dfbefdSBarry Smith -   inactive - an `IS` indicating which points are currently not active
188f6dfbefdSBarry Smith 
189*fbda9744SBarry Smith     Level: intermediate
190*fbda9744SBarry Smith 
191f6dfbefdSBarry Smith .seealso: `SNESVINEWTONRSLS`, `SNESVIGetInactiveSet()`
192f6dfbefdSBarry Smith @*/
193f6dfbefdSBarry Smith PetscErrorCode DMSetVI(DM dm, IS inactive) {
194c2fc9fa9SBarry Smith   PetscContainer isnes;
195c2fc9fa9SBarry Smith   DM_SNESVI     *dmsnesvi;
196c2fc9fa9SBarry Smith 
197c2fc9fa9SBarry Smith   PetscFunctionBegin;
198c2fc9fa9SBarry Smith   if (!dm) PetscFunctionReturn(0);
199c2fc9fa9SBarry Smith 
2009566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)inactive));
201c2fc9fa9SBarry Smith 
2029566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)dm, "VI", (PetscObject *)&isnes));
203c2fc9fa9SBarry Smith   if (!isnes) {
2049566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &isnes));
2059566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetUserDestroy(isnes, (PetscErrorCode(*)(void *))DMDestroy_SNESVI));
2069566063dSJacob Faibussowitsch     PetscCall(PetscNew(&dmsnesvi));
2079566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(isnes, (void *)dmsnesvi));
2089566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)dm, "VI", (PetscObject)isnes));
2099566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&isnes));
2101aa26658SKarl Rupp 
21125296bd5SBarry Smith     dmsnesvi->createinterpolation = dm->ops->createinterpolation;
21225296bd5SBarry Smith     dm->ops->createinterpolation  = DMCreateInterpolation_SNESVI;
213c2fc9fa9SBarry Smith     dmsnesvi->coarsen             = dm->ops->coarsen;
214c2fc9fa9SBarry Smith     dm->ops->coarsen              = DMCoarsen_SNESVI;
215c2fc9fa9SBarry Smith     dmsnesvi->createglobalvector  = dm->ops->createglobalvector;
216c2fc9fa9SBarry Smith     dm->ops->createglobalvector   = DMCreateGlobalVector_SNESVI;
2175a84ad33SLisandro Dalcin     dmsnesvi->createinjection     = dm->ops->createinjection;
2185a84ad33SLisandro Dalcin     dm->ops->createinjection      = NULL;
2194a7a4c06SLawrence Mitchell     dmsnesvi->hascreateinjection  = dm->ops->hascreateinjection;
2205a84ad33SLisandro Dalcin     dm->ops->hascreateinjection   = NULL;
221c2fc9fa9SBarry Smith   } else {
2229566063dSJacob Faibussowitsch     PetscCall(PetscContainerGetPointer(isnes, (void **)&dmsnesvi));
2239566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&dmsnesvi->inactive));
224c2fc9fa9SBarry Smith   }
2259566063dSJacob Faibussowitsch   PetscCall(DMClearGlobalVectors(dm));
2269566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(inactive, &dmsnesvi->n));
2271aa26658SKarl Rupp 
228c2fc9fa9SBarry Smith   dmsnesvi->inactive = inactive;
229c2fc9fa9SBarry Smith   dmsnesvi->dm       = dm;
230c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
231c2fc9fa9SBarry Smith }
232c2fc9fa9SBarry Smith 
233c2fc9fa9SBarry Smith /*
234c2fc9fa9SBarry Smith      DMDestroyVI - Frees the DM_SNESVI object contained in the DM
23525296bd5SBarry Smith          - also resets the function pointers in the DM for createinterpolation() etc to use the original DM
236c2fc9fa9SBarry Smith */
237f6dfbefdSBarry Smith PetscErrorCode DMDestroyVI(DM dm) {
238c2fc9fa9SBarry Smith   PetscFunctionBegin;
239c2fc9fa9SBarry Smith   if (!dm) PetscFunctionReturn(0);
2409566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)dm, "VI", (PetscObject)NULL));
241c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
242c2fc9fa9SBarry Smith }
243c2fc9fa9SBarry Smith 
2449371c9d4SSatish Balay PetscErrorCode SNESCreateIndexSets_VINEWTONRSLS(SNES snes, Vec X, Vec F, IS *ISact, IS *ISinact) {
245c2fc9fa9SBarry Smith   PetscFunctionBegin;
2469566063dSJacob Faibussowitsch   PetscCall(SNESVIGetActiveSetIS(snes, X, F, ISact));
2479566063dSJacob Faibussowitsch   PetscCall(ISComplement(*ISact, X->map->rstart, X->map->rend, ISinact));
248c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
249c2fc9fa9SBarry Smith }
250c2fc9fa9SBarry Smith 
251c2fc9fa9SBarry Smith /* Create active and inactive set vectors. The local size of this vector is set and petsc computes the global size */
2529371c9d4SSatish Balay PetscErrorCode SNESCreateSubVectors_VINEWTONRSLS(SNES snes, PetscInt n, Vec *newv) {
253c2fc9fa9SBarry Smith   Vec v;
254c2fc9fa9SBarry Smith 
255c2fc9fa9SBarry Smith   PetscFunctionBegin;
2569566063dSJacob Faibussowitsch   PetscCall(VecCreate(PetscObjectComm((PetscObject)snes), &v));
2579566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(v, n, PETSC_DECIDE));
2589566063dSJacob Faibussowitsch   PetscCall(VecSetType(v, VECSTANDARD));
259c2fc9fa9SBarry Smith   *newv = v;
260c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
261c2fc9fa9SBarry Smith }
262c2fc9fa9SBarry Smith 
263c2fc9fa9SBarry Smith /* Resets the snes PC and KSP when the active set sizes change */
2649371c9d4SSatish Balay PetscErrorCode SNESVIResetPCandKSP(SNES snes, Mat Amat, Mat Pmat) {
265c2fc9fa9SBarry Smith   KSP snesksp;
266c2fc9fa9SBarry Smith 
267c2fc9fa9SBarry Smith   PetscFunctionBegin;
2689566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(snes, &snesksp));
2699566063dSJacob Faibussowitsch   PetscCall(KSPReset(snesksp));
2709566063dSJacob Faibussowitsch   PetscCall(KSPResetFromOptions(snesksp));
271c2fc9fa9SBarry Smith 
272c2fc9fa9SBarry Smith   /*
273c2fc9fa9SBarry Smith   KSP                    kspnew;
274c2fc9fa9SBarry Smith   PC                     pcnew;
275ea799195SBarry Smith   MatSolverType          stype;
276c2fc9fa9SBarry Smith 
2779566063dSJacob Faibussowitsch   PetscCall(KSPCreate(PetscObjectComm((PetscObject)snes),&kspnew));
278c2fc9fa9SBarry Smith   kspnew->pc_side = snesksp->pc_side;
279c2fc9fa9SBarry Smith   kspnew->rtol    = snesksp->rtol;
280c2fc9fa9SBarry Smith   kspnew->abstol    = snesksp->abstol;
281c2fc9fa9SBarry Smith   kspnew->max_it  = snesksp->max_it;
2829566063dSJacob Faibussowitsch   PetscCall(KSPSetType(kspnew,((PetscObject)snesksp)->type_name));
2839566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(kspnew,&pcnew));
2849566063dSJacob Faibussowitsch   PetscCall(PCSetType(kspnew->pc,((PetscObject)snesksp->pc)->type_name));
2859566063dSJacob Faibussowitsch   PetscCall(PCSetOperators(kspnew->pc,Amat,Pmat));
2869566063dSJacob Faibussowitsch   PetscCall(PCFactorGetMatSolverType(snesksp->pc,&stype));
2879566063dSJacob Faibussowitsch   PetscCall(PCFactorSetMatSolverType(kspnew->pc,stype));
2889566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&snesksp));
289c2fc9fa9SBarry Smith   snes->ksp = kspnew;
2909566063dSJacob Faibussowitsch   PetscCall(PetscLogObjectParent((PetscObject)snes,(PetscObject)kspnew));
2919566063dSJacob Faibussowitsch    PetscCall(KSPSetFromOptions(kspnew));*/
292c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
293c2fc9fa9SBarry Smith }
294c2fc9fa9SBarry Smith 
295c2fc9fa9SBarry Smith /* Variational Inequality solver using reduce space method. No semismooth algorithm is
296c2fc9fa9SBarry Smith    implemented in this algorithm. It basically identifies the active constraints and does
297c2fc9fa9SBarry Smith    a linear solve on the other variables (those not associated with the active constraints). */
2989371c9d4SSatish Balay PetscErrorCode SNESSolve_VINEWTONRSLS(SNES snes) {
299f450aa47SBarry Smith   SNES_VINEWTONRSLS   *vi = (SNES_VINEWTONRSLS *)snes->data;
300c2fc9fa9SBarry Smith   PetscInt             maxits, i, lits;
301422a814eSBarry Smith   SNESLineSearchReason lssucceed;
302c2fc9fa9SBarry Smith   PetscReal            fnorm, gnorm, xnorm = 0, ynorm;
3039bd66eb0SPeter Brune   Vec                  Y, X, F;
304c2fc9fa9SBarry Smith   KSPConvergedReason   kspreason;
30592e89061SBarry Smith   KSP                  ksp;
30692e89061SBarry Smith   PC                   pc;
307c2fc9fa9SBarry Smith 
308c2fc9fa9SBarry Smith   PetscFunctionBegin;
30992e89061SBarry Smith   /* Multigrid must use Galerkin for coarse grids with active set/reduced space methods; cannot rediscretize on coarser grids*/
3109566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(snes, &ksp));
3119566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(ksp, &pc));
3129566063dSJacob Faibussowitsch   PetscCall(PCMGSetGalerkin(pc, PC_MG_GALERKIN_BOTH));
31392e89061SBarry Smith 
314c2fc9fa9SBarry Smith   snes->numFailures            = 0;
315c2fc9fa9SBarry Smith   snes->numLinearSolveFailures = 0;
316c2fc9fa9SBarry Smith   snes->reason                 = SNES_CONVERGED_ITERATING;
317c2fc9fa9SBarry Smith 
318c2fc9fa9SBarry Smith   maxits = snes->max_its;  /* maximum number of iterations */
319c2fc9fa9SBarry Smith   X      = snes->vec_sol;  /* solution vector */
320c2fc9fa9SBarry Smith   F      = snes->vec_func; /* residual vector */
321c2fc9fa9SBarry Smith   Y      = snes->work[0];  /* work vectors */
3229bd66eb0SPeter Brune 
3239566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchSetVIFunctions(snes->linesearch, SNESVIProjectOntoBounds, SNESVIComputeInactiveSetFnorm));
3249566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchSetVecs(snes->linesearch, X, NULL, NULL, NULL, NULL));
3259566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchSetUp(snes->linesearch));
326c2fc9fa9SBarry Smith 
3279566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
328c2fc9fa9SBarry Smith   snes->iter = 0;
329c2fc9fa9SBarry Smith   snes->norm = 0.0;
3309566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
331c2fc9fa9SBarry Smith 
3329566063dSJacob Faibussowitsch   PetscCall(SNESVIProjectOntoBounds(snes, X));
3339566063dSJacob Faibussowitsch   PetscCall(SNESComputeFunction(snes, X, F));
3349566063dSJacob Faibussowitsch   PetscCall(SNESVIComputeInactiveSetFnorm(snes, F, X, &fnorm));
3359566063dSJacob Faibussowitsch   PetscCall(VecNorm(X, NORM_2, &xnorm)); /* xnorm <- ||x||  */
336422a814eSBarry Smith   SNESCheckFunctionNorm(snes, fnorm);
3379566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
338c2fc9fa9SBarry Smith   snes->norm = fnorm;
3399566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
3409566063dSJacob Faibussowitsch   PetscCall(SNESLogConvergenceHistory(snes, fnorm, 0));
3419566063dSJacob Faibussowitsch   PetscCall(SNESMonitor(snes, 0, fnorm));
342c2fc9fa9SBarry Smith 
343c2fc9fa9SBarry Smith   /* test convergence */
344dbbe0bcdSBarry Smith   PetscUseTypeMethod(snes, converged, 0, 0.0, 0.0, fnorm, &snes->reason, snes->cnvP);
345c2fc9fa9SBarry Smith   if (snes->reason) PetscFunctionReturn(0);
346c2fc9fa9SBarry Smith 
347c2fc9fa9SBarry Smith   for (i = 0; i < maxits; i++) {
348f009fc93SPatrick Farrell     IS         IS_act;    /* _act -> active set _inact -> inactive set */
349c2fc9fa9SBarry Smith     IS         IS_redact; /* redundant active set */
350c2fc9fa9SBarry Smith     VecScatter scat_act, scat_inact;
351c2fc9fa9SBarry Smith     PetscInt   nis_act, nis_inact;
352c2fc9fa9SBarry Smith     Vec        Y_act, Y_inact, F_inact;
353c2fc9fa9SBarry Smith     Mat        jac_inact_inact, prejac_inact_inact;
354c2fc9fa9SBarry Smith     PetscBool  isequal;
355c2fc9fa9SBarry Smith 
356c2fc9fa9SBarry Smith     /* Call general purpose update function */
357dbbe0bcdSBarry Smith     PetscTryTypeMethod(snes, update, snes->iter);
3589566063dSJacob Faibussowitsch     PetscCall(SNESComputeJacobian(snes, X, snes->jacobian, snes->jacobian_pre));
35907b62357SFande Kong     SNESCheckJacobianDomainerror(snes);
360c2fc9fa9SBarry Smith 
361c2fc9fa9SBarry Smith     /* Create active and inactive index sets */
362c2fc9fa9SBarry Smith 
363c2fc9fa9SBarry Smith     /*original
3649566063dSJacob Faibussowitsch     PetscCall(SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&vi->IS_inact));
365c2fc9fa9SBarry Smith      */
3669566063dSJacob Faibussowitsch     PetscCall(SNESVIGetActiveSetIS(snes, X, F, &IS_act));
367c2fc9fa9SBarry Smith 
368c2fc9fa9SBarry Smith     if (vi->checkredundancy) {
3699566063dSJacob Faibussowitsch       PetscCall((*vi->checkredundancy)(snes, IS_act, &IS_redact, vi->ctxP));
370c2fc9fa9SBarry Smith       if (IS_redact) {
3719566063dSJacob Faibussowitsch         PetscCall(ISSort(IS_redact));
3729566063dSJacob Faibussowitsch         PetscCall(ISComplement(IS_redact, X->map->rstart, X->map->rend, &vi->IS_inact));
3739566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&IS_redact));
3741aa26658SKarl Rupp       } else {
3759566063dSJacob Faibussowitsch         PetscCall(ISComplement(IS_act, X->map->rstart, X->map->rend, &vi->IS_inact));
376c2fc9fa9SBarry Smith       }
377c2fc9fa9SBarry Smith     } else {
3789566063dSJacob Faibussowitsch       PetscCall(ISComplement(IS_act, X->map->rstart, X->map->rend, &vi->IS_inact));
379c2fc9fa9SBarry Smith     }
380c2fc9fa9SBarry Smith 
381c2fc9fa9SBarry Smith     /* Create inactive set submatrix */
3829566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(snes->jacobian, vi->IS_inact, vi->IS_inact, MAT_INITIAL_MATRIX, &jac_inact_inact));
383c2fc9fa9SBarry Smith 
38466bfb381SJed Brown     if (0) { /* Dead code (temporary developer hack) */
38566bfb381SJed Brown       IS keptrows;
3869566063dSJacob Faibussowitsch       PetscCall(MatFindNonzeroRows(jac_inact_inact, &keptrows));
38766bfb381SJed Brown       if (keptrows) {
388c2fc9fa9SBarry Smith         PetscInt        cnt, *nrows, k;
389c2fc9fa9SBarry Smith         const PetscInt *krows, *inact;
390367daffbSBarry Smith         PetscInt        rstart;
391c2fc9fa9SBarry Smith 
3929566063dSJacob Faibussowitsch         PetscCall(MatGetOwnershipRange(jac_inact_inact, &rstart, NULL));
3939566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&jac_inact_inact));
3949566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&IS_act));
395c2fc9fa9SBarry Smith 
3969566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(keptrows, &cnt));
3979566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(keptrows, &krows));
3989566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(vi->IS_inact, &inact));
3999566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(cnt, &nrows));
4001aa26658SKarl Rupp         for (k = 0; k < cnt; k++) nrows[k] = inact[krows[k] - rstart];
4019566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(keptrows, &krows));
4029566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(vi->IS_inact, &inact));
4039566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&keptrows));
4049566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&vi->IS_inact));
405c2fc9fa9SBarry Smith 
4069566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)snes), cnt, nrows, PETSC_OWN_POINTER, &vi->IS_inact));
4079566063dSJacob Faibussowitsch         PetscCall(ISComplement(vi->IS_inact, F->map->rstart, F->map->rend, &IS_act));
4089566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(snes->jacobian, vi->IS_inact, vi->IS_inact, MAT_INITIAL_MATRIX, &jac_inact_inact));
409c2fc9fa9SBarry Smith       }
41066bfb381SJed Brown     }
4119566063dSJacob Faibussowitsch     PetscCall(DMSetVI(snes->dm, vi->IS_inact));
412c2fc9fa9SBarry Smith     /* remove later */
413c2fc9fa9SBarry Smith 
414c2fc9fa9SBarry Smith     /*
4159566063dSJacob Faibussowitsch     PetscCall(VecView(vi->xu,PETSC_VIEWER_BINARY_(((PetscObject)(vi->xu))->comm)));
4169566063dSJacob Faibussowitsch     PetscCall(VecView(vi->xl,PETSC_VIEWER_BINARY_(((PetscObject)(vi->xl))->comm)));
4179566063dSJacob Faibussowitsch     PetscCall(VecView(X,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)X))));
4189566063dSJacob Faibussowitsch     PetscCall(VecView(F,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)F))));
4199566063dSJacob Faibussowitsch     PetscCall(ISView(vi->IS_inact,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)vi->IS_inact))));
420c2fc9fa9SBarry Smith      */
421c2fc9fa9SBarry Smith 
422c2fc9fa9SBarry Smith     /* Get sizes of active and inactive sets */
4239566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(IS_act, &nis_act));
4249566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(vi->IS_inact, &nis_inact));
425c2fc9fa9SBarry Smith 
426c2fc9fa9SBarry Smith     /* Create active and inactive set vectors */
4279566063dSJacob Faibussowitsch     PetscCall(SNESCreateSubVectors_VINEWTONRSLS(snes, nis_inact, &F_inact));
4289566063dSJacob Faibussowitsch     PetscCall(SNESCreateSubVectors_VINEWTONRSLS(snes, nis_act, &Y_act));
4299566063dSJacob Faibussowitsch     PetscCall(SNESCreateSubVectors_VINEWTONRSLS(snes, nis_inact, &Y_inact));
430c2fc9fa9SBarry Smith 
431c2fc9fa9SBarry Smith     /* Create scatter contexts */
4329566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(Y, IS_act, Y_act, NULL, &scat_act));
4339566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(Y, vi->IS_inact, Y_inact, NULL, &scat_inact));
434c2fc9fa9SBarry Smith 
435c2fc9fa9SBarry Smith     /* Do a vec scatter to active and inactive set vectors */
4369566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(scat_inact, F, F_inact, INSERT_VALUES, SCATTER_FORWARD));
4379566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(scat_inact, F, F_inact, INSERT_VALUES, SCATTER_FORWARD));
438c2fc9fa9SBarry Smith 
4399566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(scat_act, Y, Y_act, INSERT_VALUES, SCATTER_FORWARD));
4409566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(scat_act, Y, Y_act, INSERT_VALUES, SCATTER_FORWARD));
441c2fc9fa9SBarry Smith 
4429566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(scat_inact, Y, Y_inact, INSERT_VALUES, SCATTER_FORWARD));
4439566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(scat_inact, Y, Y_inact, INSERT_VALUES, SCATTER_FORWARD));
444c2fc9fa9SBarry Smith 
445c2fc9fa9SBarry Smith     /* Active set direction = 0 */
4469566063dSJacob Faibussowitsch     PetscCall(VecSet(Y_act, 0));
447c2fc9fa9SBarry Smith     if (snes->jacobian != snes->jacobian_pre) {
4489566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(snes->jacobian_pre, vi->IS_inact, vi->IS_inact, MAT_INITIAL_MATRIX, &prejac_inact_inact));
449c2fc9fa9SBarry Smith     } else prejac_inact_inact = jac_inact_inact;
450c2fc9fa9SBarry Smith 
4519566063dSJacob Faibussowitsch     PetscCall(ISEqual(vi->IS_inact_prev, vi->IS_inact, &isequal));
452c2fc9fa9SBarry Smith     if (!isequal) {
4539566063dSJacob Faibussowitsch       PetscCall(SNESVIResetPCandKSP(snes, jac_inact_inact, prejac_inact_inact));
4549566063dSJacob Faibussowitsch       PetscCall(PCFieldSplitRestrictIS(pc, vi->IS_inact));
455c2fc9fa9SBarry Smith     }
456c2fc9fa9SBarry Smith 
4579566063dSJacob Faibussowitsch     /*      PetscCall(ISView(vi->IS_inact,0)); */
4589566063dSJacob Faibussowitsch     /*      PetscCall(ISView(IS_act,0));*/
459c2fc9fa9SBarry Smith     /*      ierr = MatView(snes->jacobian_pre,0); */
460c2fc9fa9SBarry Smith 
4619566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(snes->ksp, jac_inact_inact, prejac_inact_inact));
4629566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(snes->ksp));
463c2fc9fa9SBarry Smith     {
464c2fc9fa9SBarry Smith       PC        pc;
465c2fc9fa9SBarry Smith       PetscBool flg;
4669566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(snes->ksp, &pc));
4679566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &flg));
468c2fc9fa9SBarry Smith       if (flg) {
469c2fc9fa9SBarry Smith         KSP *subksps;
4709566063dSJacob Faibussowitsch         PetscCall(PCFieldSplitGetSubKSP(pc, NULL, &subksps));
4719566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(subksps[0], &pc));
4729566063dSJacob Faibussowitsch         PetscCall(PetscFree(subksps));
4739566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCBJACOBI, &flg));
474c2fc9fa9SBarry Smith         if (flg) {
475c2fc9fa9SBarry Smith           PetscInt        n, N = 101 * 101, j, cnts[3] = {0, 0, 0};
476c2fc9fa9SBarry Smith           const PetscInt *ii;
477c2fc9fa9SBarry Smith 
4789566063dSJacob Faibussowitsch           PetscCall(ISGetSize(vi->IS_inact, &n));
4799566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(vi->IS_inact, &ii));
480c2fc9fa9SBarry Smith           for (j = 0; j < n; j++) {
481c2fc9fa9SBarry Smith             if (ii[j] < N) cnts[0]++;
482c2fc9fa9SBarry Smith             else if (ii[j] < 2 * N) cnts[1]++;
483c2fc9fa9SBarry Smith             else if (ii[j] < 3 * N) cnts[2]++;
484c2fc9fa9SBarry Smith           }
4859566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(vi->IS_inact, &ii));
486c2fc9fa9SBarry Smith 
4879566063dSJacob Faibussowitsch           PetscCall(PCBJacobiSetTotalBlocks(pc, 3, cnts));
488c2fc9fa9SBarry Smith         }
489c2fc9fa9SBarry Smith       }
490c2fc9fa9SBarry Smith     }
491c2fc9fa9SBarry Smith 
4929566063dSJacob Faibussowitsch     PetscCall(KSPSolve(snes->ksp, F_inact, Y_inact));
4939566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(scat_act, Y_act, Y, INSERT_VALUES, SCATTER_REVERSE));
4949566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(scat_act, Y_act, Y, INSERT_VALUES, SCATTER_REVERSE));
4959566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(scat_inact, Y_inact, Y, INSERT_VALUES, SCATTER_REVERSE));
4969566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(scat_inact, Y_inact, Y, INSERT_VALUES, SCATTER_REVERSE));
497c2fc9fa9SBarry Smith 
4989566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&F_inact));
4999566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&Y_act));
5009566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&Y_inact));
5019566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&scat_act));
5029566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&scat_inact));
5039566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&IS_act));
504c2fc9fa9SBarry Smith     if (!isequal) {
5059566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&vi->IS_inact_prev));
5069566063dSJacob Faibussowitsch       PetscCall(ISDuplicate(vi->IS_inact, &vi->IS_inact_prev));
507c2fc9fa9SBarry Smith     }
5089566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&vi->IS_inact));
5099566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&jac_inact_inact));
51048a46eb9SPierre Jolivet     if (snes->jacobian != snes->jacobian_pre) PetscCall(MatDestroy(&prejac_inact_inact));
511fa6eefd1SCian Wilson 
5129566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason(snes->ksp, &kspreason));
513fa6eefd1SCian Wilson     if (kspreason < 0) {
514fa6eefd1SCian Wilson       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
51563a3b9bcSJacob Faibussowitsch         PetscCall(PetscInfo(snes, "iter=%" PetscInt_FMT ", number linear solve failures %" PetscInt_FMT " greater than current SNES allowed, stopping solve\n", snes->iter, snes->numLinearSolveFailures));
516fa6eefd1SCian Wilson         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
517fa6eefd1SCian Wilson         break;
518fa6eefd1SCian Wilson       }
519fa6eefd1SCian Wilson     }
520fa6eefd1SCian Wilson 
5219566063dSJacob Faibussowitsch     PetscCall(KSPGetIterationNumber(snes->ksp, &lits));
522c2fc9fa9SBarry Smith     snes->linear_its += lits;
52363a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "iter=%" PetscInt_FMT ", linear solve iterations=%" PetscInt_FMT "\n", snes->iter, lits));
524c2fc9fa9SBarry Smith     /*
5256b2b7091SBarry Smith     if (snes->ops->precheck) {
526c2fc9fa9SBarry Smith       PetscBool changed_y = PETSC_FALSE;
527dbbe0bcdSBarry Smith       PetscUseTypeMethod(snes,precheck ,X,Y,snes->precheck,&changed_y);
528c2fc9fa9SBarry Smith     }
529c2fc9fa9SBarry Smith 
5301baa6e33SBarry Smith     if (PetscLogPrintInfo) PetscCall(SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W));
531c2fc9fa9SBarry Smith     */
532c2fc9fa9SBarry Smith     /* Compute a (scaled) negative update in the line search routine:
533c2fc9fa9SBarry Smith          Y <- X - lambda*Y
534c2fc9fa9SBarry Smith        and evaluate G = function(Y) (depends on the line search).
535c2fc9fa9SBarry Smith     */
5369566063dSJacob Faibussowitsch     PetscCall(VecCopy(Y, snes->vec_sol_update));
5379371c9d4SSatish Balay     ynorm = 1;
5389371c9d4SSatish Balay     gnorm = fnorm;
5399566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchApply(snes->linesearch, X, F, &gnorm, Y));
5409566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchGetReason(snes->linesearch, &lssucceed));
5419566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchGetNorms(snes->linesearch, &xnorm, &gnorm, &ynorm));
5429566063dSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n", (double)fnorm, (double)gnorm, (double)ynorm, (int)lssucceed));
543c2fc9fa9SBarry Smith     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
544c2fc9fa9SBarry Smith     if (snes->domainerror) {
545c2fc9fa9SBarry Smith       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
5469566063dSJacob Faibussowitsch       PetscCall(DMDestroyVI(snes->dm));
547c2fc9fa9SBarry Smith       PetscFunctionReturn(0);
548c2fc9fa9SBarry Smith     }
549422a814eSBarry Smith     if (lssucceed) {
550c2fc9fa9SBarry Smith       if (++snes->numFailures >= snes->maxFailures) {
551c2fc9fa9SBarry Smith         PetscBool ismin;
552c2fc9fa9SBarry Smith         snes->reason = SNES_DIVERGED_LINE_SEARCH;
5539566063dSJacob Faibussowitsch         PetscCall(SNESVICheckLocalMin_Private(snes, snes->jacobian, F, X, gnorm, &ismin));
554c2fc9fa9SBarry Smith         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
555c2fc9fa9SBarry Smith         break;
556c2fc9fa9SBarry Smith       }
557c2fc9fa9SBarry Smith     }
5589566063dSJacob Faibussowitsch     PetscCall(DMDestroyVI(snes->dm));
559c2fc9fa9SBarry Smith     /* Update function and solution vectors */
560c2fc9fa9SBarry Smith     fnorm = gnorm;
561c2fc9fa9SBarry Smith     /* Monitor convergence */
5629566063dSJacob Faibussowitsch     PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
563c2fc9fa9SBarry Smith     snes->iter  = i + 1;
564c2fc9fa9SBarry Smith     snes->norm  = fnorm;
565c1e67a49SFande Kong     snes->xnorm = xnorm;
566c1e67a49SFande Kong     snes->ynorm = ynorm;
5679566063dSJacob Faibussowitsch     PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
5689566063dSJacob Faibussowitsch     PetscCall(SNESLogConvergenceHistory(snes, snes->norm, lits));
5699566063dSJacob Faibussowitsch     PetscCall(SNESMonitor(snes, snes->iter, snes->norm));
570c2fc9fa9SBarry Smith     /* Test for convergence, xnorm = || X || */
5719566063dSJacob Faibussowitsch     if (snes->ops->converged != SNESConvergedSkip) PetscCall(VecNorm(X, NORM_2, &xnorm));
572dbbe0bcdSBarry Smith     PetscUseTypeMethod(snes, converged, snes->iter, xnorm, ynorm, fnorm, &snes->reason, snes->cnvP);
573c2fc9fa9SBarry Smith     if (snes->reason) break;
574c2fc9fa9SBarry Smith   }
57591a42fcfSBarry Smith   /* 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 */
5769566063dSJacob Faibussowitsch   PetscCall(DMDestroyVI(snes->dm));
577c2fc9fa9SBarry Smith   if (i == maxits) {
57863a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "Maximum number of iterations has been reached: %" PetscInt_FMT "\n", maxits));
579c2fc9fa9SBarry Smith     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
580c2fc9fa9SBarry Smith   }
581c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
582c2fc9fa9SBarry Smith }
583c2fc9fa9SBarry Smith 
584f6dfbefdSBarry Smith /*@C
585f6dfbefdSBarry Smith    SNESVISetRedundancyCheck - Provide a function to check for any redundancy in the VI active set
586f6dfbefdSBarry Smith 
587f6dfbefdSBarry Smith    Logically Collective on snes
588f6dfbefdSBarry Smith 
589f6dfbefdSBarry Smith    Input Parameters:
590f6dfbefdSBarry Smith +  snes - the `SNESVINEWTONRSLS` context
591f6dfbefdSBarry Smith .  func - the function to check of redundancies
592f6dfbefdSBarry Smith -  ctx - optional context used by the function
593f6dfbefdSBarry Smith 
594f6dfbefdSBarry Smith    Level: advanced
595f6dfbefdSBarry Smith 
596f6dfbefdSBarry Smith    Note:
597f6dfbefdSBarry Smith    Sometimes the inactive set will result in a non-singular sub-Jacobian problem that needs to be solved, this allows the user,
598f6dfbefdSBarry Smith    when they know more about their specific problem to provide a function that removes the redundancy that results in the singular linear system
599f6dfbefdSBarry Smith 
600f6dfbefdSBarry Smith .seealso: `SNESVINEWTONRSLS`, `SNESVIGetInactiveSet()`, `DMSetVI()`
601f6dfbefdSBarry Smith  @*/
6029371c9d4SSatish Balay PetscErrorCode SNESVISetRedundancyCheck(SNES snes, PetscErrorCode (*func)(SNES, IS, IS *, void *), void *ctx) {
603f450aa47SBarry Smith   SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data;
604c2fc9fa9SBarry Smith 
605c2fc9fa9SBarry Smith   PetscFunctionBegin;
606c2fc9fa9SBarry Smith   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
607c2fc9fa9SBarry Smith   vi->checkredundancy = func;
608c2fc9fa9SBarry Smith   vi->ctxP            = ctx;
609c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
610c2fc9fa9SBarry Smith }
611c2fc9fa9SBarry Smith 
612c2fc9fa9SBarry Smith #if defined(PETSC_HAVE_MATLAB_ENGINE)
613c2fc9fa9SBarry Smith #include <engine.h>
614c2fc9fa9SBarry Smith #include <mex.h>
6159371c9d4SSatish Balay typedef struct {
6169371c9d4SSatish Balay   char    *funcname;
6179371c9d4SSatish Balay   mxArray *ctx;
6189371c9d4SSatish Balay } SNESMatlabContext;
619c2fc9fa9SBarry Smith 
6209371c9d4SSatish Balay PetscErrorCode SNESVIRedundancyCheck_Matlab(SNES snes, IS is_act, IS *is_redact, void *ctx) {
621c2fc9fa9SBarry Smith   SNESMatlabContext *sctx = (SNESMatlabContext *)ctx;
622c2fc9fa9SBarry Smith   int                nlhs = 1, nrhs = 5;
623c2fc9fa9SBarry Smith   mxArray           *plhs[1], *prhs[5];
624c2fc9fa9SBarry Smith   long long int      l1 = 0, l2 = 0, ls = 0;
6250298fd71SBarry Smith   PetscInt          *indices = NULL;
626c2fc9fa9SBarry Smith 
627c2fc9fa9SBarry Smith   PetscFunctionBegin;
628c2fc9fa9SBarry Smith   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
629c2fc9fa9SBarry Smith   PetscValidHeaderSpecific(is_act, IS_CLASSID, 2);
630c2fc9fa9SBarry Smith   PetscValidPointer(is_redact, 3);
631c2fc9fa9SBarry Smith   PetscCheckSameComm(snes, 1, is_act, 2);
632c2fc9fa9SBarry Smith 
633c2fc9fa9SBarry Smith   /* Create IS for reduced active set of size 0, its size and indices will
634c2fc9fa9SBarry Smith    bet set by the Matlab function */
6359566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)snes), 0, indices, PETSC_OWN_POINTER, is_redact));
636c2fc9fa9SBarry Smith   /* call Matlab function in ctx */
6379566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(&ls, &snes, 1));
6389566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(&l1, &is_act, 1));
6399566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(&l2, is_redact, 1));
640c2fc9fa9SBarry Smith   prhs[0] = mxCreateDoubleScalar((double)ls);
641c2fc9fa9SBarry Smith   prhs[1] = mxCreateDoubleScalar((double)l1);
642c2fc9fa9SBarry Smith   prhs[2] = mxCreateDoubleScalar((double)l2);
643c2fc9fa9SBarry Smith   prhs[3] = mxCreateString(sctx->funcname);
644c2fc9fa9SBarry Smith   prhs[4] = sctx->ctx;
6459566063dSJacob Faibussowitsch   PetscCall(mexCallMATLAB(nlhs, plhs, nrhs, prhs, "PetscSNESVIRedundancyCheckInternal"));
6469566063dSJacob Faibussowitsch   PetscCall(mxGetScalar(plhs[0]));
647c2fc9fa9SBarry Smith   mxDestroyArray(prhs[0]);
648c2fc9fa9SBarry Smith   mxDestroyArray(prhs[1]);
649c2fc9fa9SBarry Smith   mxDestroyArray(prhs[2]);
650c2fc9fa9SBarry Smith   mxDestroyArray(prhs[3]);
651c2fc9fa9SBarry Smith   mxDestroyArray(plhs[0]);
652c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
653c2fc9fa9SBarry Smith }
654c2fc9fa9SBarry Smith 
6559371c9d4SSatish Balay PetscErrorCode SNESVISetRedundancyCheckMatlab(SNES snes, const char *func, mxArray *ctx) {
656c2fc9fa9SBarry Smith   SNESMatlabContext *sctx;
657c2fc9fa9SBarry Smith 
658c2fc9fa9SBarry Smith   PetscFunctionBegin;
659c2fc9fa9SBarry Smith   /* currently sctx is memory bleed */
6609566063dSJacob Faibussowitsch   PetscCall(PetscNew(&sctx));
6619566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(func, &sctx->funcname));
662c2fc9fa9SBarry Smith   sctx->ctx = mxDuplicateArray(ctx);
6639566063dSJacob Faibussowitsch   PetscCall(SNESVISetRedundancyCheck(snes, SNESVIRedundancyCheck_Matlab, sctx));
664c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
665c2fc9fa9SBarry Smith }
666c2fc9fa9SBarry Smith 
667c2fc9fa9SBarry Smith #endif
668c2fc9fa9SBarry Smith 
669c2fc9fa9SBarry Smith /*
670f450aa47SBarry Smith    SNESSetUp_VINEWTONRSLS - Sets up the internal data structures for the later use
671c2fc9fa9SBarry Smith    of the SNESVI nonlinear solver.
672c2fc9fa9SBarry Smith 
673c2fc9fa9SBarry Smith    Input Parameter:
674c2fc9fa9SBarry Smith .  snes - the SNES context
675c2fc9fa9SBarry Smith 
676c2fc9fa9SBarry Smith    Application Interface Routine: SNESSetUp()
677c2fc9fa9SBarry Smith 
678f6dfbefdSBarry Smith    Note:
679c2fc9fa9SBarry Smith    For basic use of the SNES solvers, the user need not explicitly call
680c2fc9fa9SBarry Smith    SNESSetUp(), since these actions will automatically occur during
681c2fc9fa9SBarry Smith    the call to SNESSolve().
682c2fc9fa9SBarry Smith  */
6839371c9d4SSatish Balay PetscErrorCode SNESSetUp_VINEWTONRSLS(SNES snes) {
684f450aa47SBarry Smith   SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data;
685c2fc9fa9SBarry Smith   PetscInt          *indices;
686c2fc9fa9SBarry Smith   PetscInt           i, n, rstart, rend;
687f1c6b773SPeter Brune   SNESLineSearch     linesearch;
688c2fc9fa9SBarry Smith 
689c2fc9fa9SBarry Smith   PetscFunctionBegin;
6909566063dSJacob Faibussowitsch   PetscCall(SNESSetUp_VI(snes));
691c2fc9fa9SBarry Smith 
692c2fc9fa9SBarry Smith   /* Set up previous active index set for the first snes solve
693c2fc9fa9SBarry Smith    vi->IS_inact_prev = 0,1,2,....N */
694c2fc9fa9SBarry Smith 
6959566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(snes->vec_sol, &rstart, &rend));
6969566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(snes->vec_sol, &n));
6979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &indices));
698c2fc9fa9SBarry Smith   for (i = 0; i < n; i++) indices[i] = rstart + i;
6999566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)snes), n, indices, PETSC_OWN_POINTER, &vi->IS_inact_prev));
7009bd66eb0SPeter Brune 
7019bd66eb0SPeter Brune   /* set the line search functions */
7029bd66eb0SPeter Brune   if (!snes->linesearch) {
7039566063dSJacob Faibussowitsch     PetscCall(SNESGetLineSearch(snes, &linesearch));
7049566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBT));
7059bd66eb0SPeter Brune   }
706c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
707c2fc9fa9SBarry Smith }
708f6dfbefdSBarry Smith 
7099371c9d4SSatish Balay PetscErrorCode SNESReset_VINEWTONRSLS(SNES snes) {
710f450aa47SBarry Smith   SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data;
711c2fc9fa9SBarry Smith 
712c2fc9fa9SBarry Smith   PetscFunctionBegin;
7139566063dSJacob Faibussowitsch   PetscCall(SNESReset_VI(snes));
7149566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&vi->IS_inact_prev));
715c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
716c2fc9fa9SBarry Smith }
717c2fc9fa9SBarry Smith 
718c2fc9fa9SBarry Smith /*MC
719f450aa47SBarry Smith       SNESVINEWTONRSLS - Reduced space active set solvers for variational inequalities based on Newton's method
720c2fc9fa9SBarry Smith 
721f6dfbefdSBarry Smith    Options Database Keys:
722b621fa8fSRichard Tran Mills +   -snes_type <vinewtonssls,vinewtonrsls> - a semi-smooth solver, a reduced space active set method
72361589011SJed Brown -   -snes_vi_monitor - prints the number of active constraints at each iteration.
724c2fc9fa9SBarry Smith 
725c2fc9fa9SBarry Smith    Level: beginner
726c2fc9fa9SBarry Smith 
727b80f3ac1SShri Abhyankar    References:
728606c0280SSatish Balay .  * - T. S. Munson, and S. Benson. Flexible Complementarity Solvers for Large Scale
729b80f3ac1SShri Abhyankar      Applications, Optimization Methods and Software, 21 (2006).
730b80f3ac1SShri Abhyankar 
731f6dfbefdSBarry Smith    Note:
732f6dfbefdSBarry Smith    At each set of this methods the algorithm produces an inactive set of variables that are constrained to their current values
733f6dfbefdSBarry Smith    (because changing these values would result in those variables no longer satisfying the inequality constraints)
734f6dfbefdSBarry Smith    and produces a step direction by solving the linear system arising from the Jacobian with the inactive variables removed. In other
735f6dfbefdSBarry Smith    words on a reduced space of the solution space. Based on the Newton update it then adjusts the inactive sep for the next iteration.
736c2fc9fa9SBarry Smith 
737f6dfbefdSBarry Smith .seealso: `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESVINEWTONSSLS`, `SNESNEWTONTRDC`, `SNESLineSearchSetType()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESVIGetInactiveSet()`, `DMSetVI()`, `SNESVISetRedundancyCheck()`
738c2fc9fa9SBarry Smith M*/
7399371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode SNESCreate_VINEWTONRSLS(SNES snes) {
740f450aa47SBarry Smith   SNES_VINEWTONRSLS *vi;
741d8d34be6SBarry Smith   SNESLineSearch     linesearch;
742c2fc9fa9SBarry Smith 
743c2fc9fa9SBarry Smith   PetscFunctionBegin;
744f450aa47SBarry Smith   snes->ops->reset          = SNESReset_VINEWTONRSLS;
745f450aa47SBarry Smith   snes->ops->setup          = SNESSetUp_VINEWTONRSLS;
746f450aa47SBarry Smith   snes->ops->solve          = SNESSolve_VINEWTONRSLS;
747c2fc9fa9SBarry Smith   snes->ops->destroy        = SNESDestroy_VI;
748c2fc9fa9SBarry Smith   snes->ops->setfromoptions = SNESSetFromOptions_VI;
7490298fd71SBarry Smith   snes->ops->view           = NULL;
7508d359177SBarry Smith   snes->ops->converged      = SNESConvergedDefault_VI;
751c2fc9fa9SBarry Smith 
752c2fc9fa9SBarry Smith   snes->usesksp = PETSC_TRUE;
753efd4aadfSBarry Smith   snes->usesnpc = PETSC_FALSE;
754c2fc9fa9SBarry Smith 
7559566063dSJacob Faibussowitsch   PetscCall(SNESGetLineSearch(snes, &linesearch));
75648a46eb9SPierre Jolivet   if (!((PetscObject)linesearch)->type_name) PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBT));
7579566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchBTSetAlpha(linesearch, 0.0));
758d8d34be6SBarry Smith 
7594fc747eaSLawrence Mitchell   snes->alwayscomputesfinalresidual = PETSC_TRUE;
7604fc747eaSLawrence Mitchell 
7619566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(snes, &vi));
762c2fc9fa9SBarry Smith   snes->data          = (void *)vi;
7630298fd71SBarry Smith   vi->checkredundancy = NULL;
764c2fc9fa9SBarry Smith 
7659566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESVISetVariableBounds_C", SNESVISetVariableBounds_VI));
7669566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESVISetComputeVariableBounds_C", SNESVISetComputeVariableBounds_VI));
767c2fc9fa9SBarry Smith   PetscFunctionReturn(0);
768c2fc9fa9SBarry Smith }
769