xref: /petsc/src/snes/impls/vi/rs/virs.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
1c2fc9fa9SBarry Smith #include <../src/snes/impls/vi/rs/virsimpl.h> /*I "petscsnes.h" I*/
2af0996ceSBarry Smith #include <petsc/private/dmimpl.h>
3af0996ceSBarry Smith #include <petsc/private/vecimpl.h>
4c2fc9fa9SBarry Smith 
5f6dfbefdSBarry Smith /*@
6c2fc9fa9SBarry Smith   SNESVIGetInactiveSet - Gets the global indices for the inactive set variables (these correspond to the degrees of freedom the linear
7c2fc9fa9SBarry Smith   system is solved on)
8c2fc9fa9SBarry Smith 
9e4094ef1SJacob Faibussowitsch   Input Parameter:
10f6dfbefdSBarry Smith . snes - the `SNES` context
11c2fc9fa9SBarry Smith 
12e4094ef1SJacob Faibussowitsch   Output Parameter:
13d5f1b7e6SEd Bueler . inact - inactive set index set
14c2fc9fa9SBarry Smith 
15fbda9744SBarry Smith   Level: advanced
16fbda9744SBarry Smith 
17420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESVINEWTONRSLS`
18f6dfbefdSBarry Smith @*/
SNESVIGetInactiveSet(SNES snes,IS * inact)19d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESVIGetInactiveSet(SNES snes, IS *inact)
20d71ae5a4SJacob Faibussowitsch {
21f450aa47SBarry Smith   SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data;
226e111a19SKarl Rupp 
23c2fc9fa9SBarry Smith   PetscFunctionBegin;
24f009fc93SPatrick Farrell   *inact = vi->IS_inact;
253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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 */
DMCreateGlobalVector_SNESVI(DM dm,Vec * vec)50ba38deedSJacob Faibussowitsch static PetscErrorCode DMCreateGlobalVector_SNESVI(DM dm, Vec *vec)
51d71ae5a4SJacob Faibussowitsch {
52c2fc9fa9SBarry Smith   PetscContainer isnes;
53c2fc9fa9SBarry Smith   DM_SNESVI     *dmsnesvi;
54c2fc9fa9SBarry Smith 
55c2fc9fa9SBarry Smith   PetscFunctionBegin;
569566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)dm, "VI", (PetscObject *)&isnes));
5728b400f6SJacob Faibussowitsch   PetscCheck(isnes, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Composed SNES is missing");
58*2a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(isnes, &dmsnesvi));
599566063dSJacob Faibussowitsch   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)dm), dmsnesvi->n, PETSC_DETERMINE, vec));
609566063dSJacob Faibussowitsch   PetscCall(VecSetDM(*vec, dm));
613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
62c2fc9fa9SBarry Smith }
63c2fc9fa9SBarry Smith 
64c2fc9fa9SBarry Smith /*
65e727c939SJed Brown      DMCreateInterpolation_SNESVI - Modifieds the interpolation obtained from the DM by removing all rows and columns associated with active constraints.
66c2fc9fa9SBarry Smith */
DMCreateInterpolation_SNESVI(DM dm1,DM dm2,Mat * mat,Vec * vec)67ba38deedSJacob Faibussowitsch static PetscErrorCode DMCreateInterpolation_SNESVI(DM dm1, DM dm2, Mat *mat, Vec *vec)
68d71ae5a4SJacob Faibussowitsch {
69c2fc9fa9SBarry Smith   PetscContainer isnes;
70c2fc9fa9SBarry Smith   DM_SNESVI     *dmsnesvi1, *dmsnesvi2;
71c2fc9fa9SBarry Smith   Mat            interp;
72c2fc9fa9SBarry Smith 
73c2fc9fa9SBarry Smith   PetscFunctionBegin;
749566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)dm1, "VI", (PetscObject *)&isnes));
7528b400f6SJacob Faibussowitsch   PetscCheck(isnes, PetscObjectComm((PetscObject)dm1), PETSC_ERR_PLIB, "Composed VI data structure is missing");
76*2a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(isnes, &dmsnesvi1));
779566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)dm2, "VI", (PetscObject *)&isnes));
7828b400f6SJacob Faibussowitsch   PetscCheck(isnes, PetscObjectComm((PetscObject)dm2), PETSC_ERR_PLIB, "Composed VI data structure is missing");
79*2a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(isnes, &dmsnesvi2));
80c2fc9fa9SBarry Smith 
819566063dSJacob Faibussowitsch   PetscCall((*dmsnesvi1->createinterpolation)(dm1, dm2, &interp, NULL));
829566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(interp, dmsnesvi2->inactive, dmsnesvi1->inactive, MAT_INITIAL_MATRIX, mat));
839566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interp));
849e5d0892SLisandro Dalcin   *vec = NULL;
853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
86c2fc9fa9SBarry Smith }
87c2fc9fa9SBarry Smith 
88c2fc9fa9SBarry Smith /*
89c2fc9fa9SBarry Smith      DMCoarsen_SNESVI - Computes the regular coarsened DM then computes additional information about its inactive set
90c2fc9fa9SBarry Smith */
DMCoarsen_SNESVI(DM dm1,MPI_Comm comm,DM * dm2)91ba38deedSJacob Faibussowitsch static PetscErrorCode DMCoarsen_SNESVI(DM dm1, MPI_Comm comm, DM *dm2)
92d71ae5a4SJacob Faibussowitsch {
93c2fc9fa9SBarry Smith   PetscContainer  isnes;
94c2fc9fa9SBarry Smith   DM_SNESVI      *dmsnesvi1;
95c2fc9fa9SBarry Smith   Vec             finemarked, coarsemarked;
96c2fc9fa9SBarry Smith   IS              inactive;
976dbf9973SLawrence Mitchell   Mat             inject;
98c2fc9fa9SBarry Smith   const PetscInt *index;
99c2fc9fa9SBarry Smith   PetscInt        n, k, cnt = 0, rstart, *coarseindex;
100c2fc9fa9SBarry Smith   PetscScalar    *marked;
101c2fc9fa9SBarry Smith 
102c2fc9fa9SBarry Smith   PetscFunctionBegin;
1039566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)dm1, "VI", (PetscObject *)&isnes));
10428b400f6SJacob Faibussowitsch   PetscCheck(isnes, PetscObjectComm((PetscObject)dm1), PETSC_ERR_PLIB, "Composed VI data structure is missing");
105*2a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(isnes, &dmsnesvi1));
106c2fc9fa9SBarry Smith 
107c2fc9fa9SBarry Smith   /* get the original coarsen */
1089566063dSJacob Faibussowitsch   PetscCall((*dmsnesvi1->coarsen)(dm1, comm, dm2));
109c2fc9fa9SBarry Smith 
110c2fc9fa9SBarry Smith   /* not sure why this extra reference is needed, but without the dm2 disappears too early */
11194c98981SBarry Smith   /* Updating the KSPCreateVecs() to avoid using DMGetGlobalVector() when matrix is available removes the need for this reference? */
1129566063dSJacob Faibussowitsch   /*  PetscCall(PetscObjectReference((PetscObject)*dm2));*/
113c2fc9fa9SBarry Smith 
114c2fc9fa9SBarry Smith   /* need to set back global vectors in order to use the original injection */
1159566063dSJacob Faibussowitsch   PetscCall(DMClearGlobalVectors(dm1));
1161aa26658SKarl Rupp 
117c2fc9fa9SBarry Smith   dm1->ops->createglobalvector = dmsnesvi1->createglobalvector;
1181aa26658SKarl Rupp 
1199566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dm1, &finemarked));
1209566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(*dm2, &coarsemarked));
121c2fc9fa9SBarry Smith 
122c2fc9fa9SBarry Smith   /*
123c2fc9fa9SBarry Smith      fill finemarked with locations of inactive points
124c2fc9fa9SBarry Smith   */
1259566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(dmsnesvi1->inactive, &index));
1269566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(dmsnesvi1->inactive, &n));
1279566063dSJacob Faibussowitsch   PetscCall(VecSet(finemarked, 0.0));
12848a46eb9SPierre Jolivet   for (k = 0; k < n; k++) PetscCall(VecSetValue(finemarked, index[k], 1.0, INSERT_VALUES));
1299566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(finemarked));
1309566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(finemarked));
131c2fc9fa9SBarry Smith 
1329566063dSJacob Faibussowitsch   PetscCall(DMCreateInjection(*dm2, dm1, &inject));
1339566063dSJacob Faibussowitsch   PetscCall(MatRestrict(inject, finemarked, coarsemarked));
1349566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&inject));
135c2fc9fa9SBarry Smith 
136c2fc9fa9SBarry Smith   /*
137c2fc9fa9SBarry Smith      create index set list of coarse inactive points from coarsemarked
138c2fc9fa9SBarry Smith   */
1399566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(coarsemarked, &n));
1409566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(coarsemarked, &rstart, NULL));
1419566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coarsemarked, &marked));
142c2fc9fa9SBarry Smith   for (k = 0; k < n; k++) {
143c2fc9fa9SBarry Smith     if (marked[k] != 0.0) cnt++;
144c2fc9fa9SBarry Smith   }
1459566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(cnt, &coarseindex));
146c2fc9fa9SBarry Smith   cnt = 0;
147c2fc9fa9SBarry Smith   for (k = 0; k < n; k++) {
148c2fc9fa9SBarry Smith     if (marked[k] != 0.0) coarseindex[cnt++] = k + rstart;
149c2fc9fa9SBarry Smith   }
1509566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coarsemarked, &marked));
1519566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)coarsemarked), cnt, coarseindex, PETSC_OWN_POINTER, &inactive));
152c2fc9fa9SBarry Smith 
1539566063dSJacob Faibussowitsch   PetscCall(DMClearGlobalVectors(dm1));
1541aa26658SKarl Rupp 
155c2fc9fa9SBarry Smith   dm1->ops->createglobalvector = DMCreateGlobalVector_SNESVI;
1561aa26658SKarl Rupp 
1579566063dSJacob Faibussowitsch   PetscCall(DMSetVI(*dm2, inactive));
158c2fc9fa9SBarry Smith 
1599566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&finemarked));
1609566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coarsemarked));
1619566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&inactive));
1623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
163c2fc9fa9SBarry Smith }
164c2fc9fa9SBarry Smith 
DMDestroy_SNESVI(PetscCtxRt ctx)165*2a8381b2SBarry Smith static PetscErrorCode DMDestroy_SNESVI(PetscCtxRt ctx)
166d71ae5a4SJacob Faibussowitsch {
167*2a8381b2SBarry Smith   DM_SNESVI *dmsnesvi = *(DM_SNESVI **)ctx;
168f1e99121SPierre Jolivet 
169c2fc9fa9SBarry Smith   PetscFunctionBegin;
170c2fc9fa9SBarry Smith   /* reset the base methods in the DM object that were changed when the DM_SNESVI was reset */
17125296bd5SBarry Smith   dmsnesvi->dm->ops->createinterpolation = dmsnesvi->createinterpolation;
172c2fc9fa9SBarry Smith   dmsnesvi->dm->ops->coarsen             = dmsnesvi->coarsen;
173c2fc9fa9SBarry Smith   dmsnesvi->dm->ops->createglobalvector  = dmsnesvi->createglobalvector;
1745a84ad33SLisandro Dalcin   dmsnesvi->dm->ops->createinjection     = dmsnesvi->createinjection;
1754a7a4c06SLawrence Mitchell   dmsnesvi->dm->ops->hascreateinjection  = dmsnesvi->hascreateinjection;
176c2fc9fa9SBarry Smith   /* need to clear out this vectors because some of them may not have a reference to the DM
177c2fc9fa9SBarry Smith     but they are counted as having references to the DM in DMDestroy() */
1789566063dSJacob Faibussowitsch   PetscCall(DMClearGlobalVectors(dmsnesvi->dm));
179c2fc9fa9SBarry Smith 
1809566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&dmsnesvi->inactive));
1819566063dSJacob Faibussowitsch   PetscCall(PetscFree(dmsnesvi));
1823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
183c2fc9fa9SBarry Smith }
184c2fc9fa9SBarry Smith 
185f6dfbefdSBarry Smith /*@
186420bcc1bSBarry Smith   DMSetVI - Marks a `DM` as associated with a VI problem. This causes the interpolation/restriction operators to
187c2fc9fa9SBarry Smith   be restricted to only those variables NOT associated with active constraints.
188c2fc9fa9SBarry Smith 
189c3339decSBarry Smith   Logically Collective
190f6dfbefdSBarry Smith 
191f6dfbefdSBarry Smith   Input Parameters:
192f6dfbefdSBarry Smith + dm       - the `DM` object
193f6dfbefdSBarry Smith - inactive - an `IS` indicating which points are currently not active
194f6dfbefdSBarry Smith 
195fbda9744SBarry Smith   Level: intermediate
196fbda9744SBarry Smith 
197420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESVINEWTONRSLS`, `SNESVIGetInactiveSet()`
198f6dfbefdSBarry Smith @*/
DMSetVI(DM dm,IS inactive)199d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSetVI(DM dm, IS inactive)
200d71ae5a4SJacob Faibussowitsch {
201c2fc9fa9SBarry Smith   PetscContainer isnes;
202c2fc9fa9SBarry Smith   DM_SNESVI     *dmsnesvi;
203c2fc9fa9SBarry Smith 
204c2fc9fa9SBarry Smith   PetscFunctionBegin;
2053ba16761SJacob Faibussowitsch   if (!dm) PetscFunctionReturn(PETSC_SUCCESS);
206c2fc9fa9SBarry Smith 
2079566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)inactive));
208c2fc9fa9SBarry Smith 
2099566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)dm, "VI", (PetscObject *)&isnes));
210c2fc9fa9SBarry Smith   if (!isnes) {
2119566063dSJacob Faibussowitsch     PetscCall(PetscNew(&dmsnesvi));
21203e76207SPierre Jolivet     PetscCall(PetscObjectContainerCompose((PetscObject)dm, "VI", dmsnesvi, DMDestroy_SNESVI));
2131aa26658SKarl Rupp 
21425296bd5SBarry Smith     dmsnesvi->createinterpolation = dm->ops->createinterpolation;
21525296bd5SBarry Smith     dm->ops->createinterpolation  = DMCreateInterpolation_SNESVI;
216c2fc9fa9SBarry Smith     dmsnesvi->coarsen             = dm->ops->coarsen;
217c2fc9fa9SBarry Smith     dm->ops->coarsen              = DMCoarsen_SNESVI;
218c2fc9fa9SBarry Smith     dmsnesvi->createglobalvector  = dm->ops->createglobalvector;
219c2fc9fa9SBarry Smith     dm->ops->createglobalvector   = DMCreateGlobalVector_SNESVI;
2205a84ad33SLisandro Dalcin     dmsnesvi->createinjection     = dm->ops->createinjection;
2215a84ad33SLisandro Dalcin     dm->ops->createinjection      = NULL;
2224a7a4c06SLawrence Mitchell     dmsnesvi->hascreateinjection  = dm->ops->hascreateinjection;
2235a84ad33SLisandro Dalcin     dm->ops->hascreateinjection   = NULL;
224c2fc9fa9SBarry Smith   } else {
225*2a8381b2SBarry Smith     PetscCall(PetscContainerGetPointer(isnes, &dmsnesvi));
2269566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&dmsnesvi->inactive));
227c2fc9fa9SBarry Smith   }
2289566063dSJacob Faibussowitsch   PetscCall(DMClearGlobalVectors(dm));
2299566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(inactive, &dmsnesvi->n));
2301aa26658SKarl Rupp 
231c2fc9fa9SBarry Smith   dmsnesvi->inactive = inactive;
232c2fc9fa9SBarry Smith   dmsnesvi->dm       = dm;
2333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
234c2fc9fa9SBarry Smith }
235c2fc9fa9SBarry Smith 
236c2fc9fa9SBarry Smith /*
237c2fc9fa9SBarry Smith      DMDestroyVI - Frees the DM_SNESVI object contained in the DM
23825296bd5SBarry Smith          - also resets the function pointers in the DM for createinterpolation() etc to use the original DM
239c2fc9fa9SBarry Smith */
DMDestroyVI(DM dm)240d71ae5a4SJacob Faibussowitsch PetscErrorCode DMDestroyVI(DM dm)
241d71ae5a4SJacob Faibussowitsch {
242c2fc9fa9SBarry Smith   PetscFunctionBegin;
2433ba16761SJacob Faibussowitsch   if (!dm) PetscFunctionReturn(PETSC_SUCCESS);
2449566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)dm, "VI", (PetscObject)NULL));
2453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
246c2fc9fa9SBarry Smith }
247c2fc9fa9SBarry Smith 
248f0b74427SPierre Jolivet /* Create active and inactive set vectors. The local size of this vector is set and PETSc computes the global size */
SNESCreateSubVectors_VINEWTONRSLS(SNES snes,PetscInt n,Vec * newv)249ba38deedSJacob Faibussowitsch static PetscErrorCode SNESCreateSubVectors_VINEWTONRSLS(SNES snes, PetscInt n, Vec *newv)
250d71ae5a4SJacob Faibussowitsch {
251c2fc9fa9SBarry Smith   Vec v;
252c2fc9fa9SBarry Smith 
253c2fc9fa9SBarry Smith   PetscFunctionBegin;
2549566063dSJacob Faibussowitsch   PetscCall(VecCreate(PetscObjectComm((PetscObject)snes), &v));
2559566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(v, n, PETSC_DECIDE));
2569566063dSJacob Faibussowitsch   PetscCall(VecSetType(v, VECSTANDARD));
257c2fc9fa9SBarry Smith   *newv = v;
2583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
259c2fc9fa9SBarry Smith }
260c2fc9fa9SBarry Smith 
261c2fc9fa9SBarry Smith /* Resets the snes PC and KSP when the active set sizes change */
SNESVIResetPCandKSP(SNES snes,Mat Amat,Mat Pmat)262ba38deedSJacob Faibussowitsch static PetscErrorCode SNESVIResetPCandKSP(SNES snes, Mat Amat, Mat Pmat)
263d71ae5a4SJacob Faibussowitsch {
264c2fc9fa9SBarry Smith   KSP snesksp;
265c2fc9fa9SBarry Smith 
266c2fc9fa9SBarry Smith   PetscFunctionBegin;
2679566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(snes, &snesksp));
2689566063dSJacob Faibussowitsch   PetscCall(KSPReset(snesksp));
2699566063dSJacob Faibussowitsch   PetscCall(KSPResetFromOptions(snesksp));
270c2fc9fa9SBarry Smith 
271c2fc9fa9SBarry Smith   /*
272c2fc9fa9SBarry Smith   KSP                    kspnew;
273c2fc9fa9SBarry Smith   PC                     pcnew;
274ea799195SBarry Smith   MatSolverType          stype;
275c2fc9fa9SBarry Smith 
2769566063dSJacob Faibussowitsch   PetscCall(KSPCreate(PetscObjectComm((PetscObject)snes),&kspnew));
277c2fc9fa9SBarry Smith   kspnew->pc_side = snesksp->pc_side;
278c2fc9fa9SBarry Smith   kspnew->rtol    = snesksp->rtol;
279c2fc9fa9SBarry Smith   kspnew->abstol    = snesksp->abstol;
280c2fc9fa9SBarry Smith   kspnew->max_it  = snesksp->max_it;
2819566063dSJacob Faibussowitsch   PetscCall(KSPSetType(kspnew,((PetscObject)snesksp)->type_name));
2829566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(kspnew,&pcnew));
2839566063dSJacob Faibussowitsch   PetscCall(PCSetType(kspnew->pc,((PetscObject)snesksp->pc)->type_name));
2849566063dSJacob Faibussowitsch   PetscCall(PCSetOperators(kspnew->pc,Amat,Pmat));
2859566063dSJacob Faibussowitsch   PetscCall(PCFactorGetMatSolverType(snesksp->pc,&stype));
2869566063dSJacob Faibussowitsch   PetscCall(PCFactorSetMatSolverType(kspnew->pc,stype));
2879566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&snesksp));
288c2fc9fa9SBarry Smith   snes->ksp = kspnew;
2899566063dSJacob Faibussowitsch    PetscCall(KSPSetFromOptions(kspnew));*/
2903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
291c2fc9fa9SBarry Smith }
292c2fc9fa9SBarry Smith 
293c2fc9fa9SBarry Smith /* Variational Inequality solver using reduce space method. No semismooth algorithm is
294c2fc9fa9SBarry Smith    implemented in this algorithm. It basically identifies the active constraints and does
295c2fc9fa9SBarry Smith    a linear solve on the other variables (those not associated with the active constraints). */
SNESSolve_VINEWTONRSLS(SNES snes)296ba38deedSJacob Faibussowitsch static PetscErrorCode SNESSolve_VINEWTONRSLS(SNES snes)
297d71ae5a4SJacob Faibussowitsch {
298f450aa47SBarry Smith   SNES_VINEWTONRSLS   *vi = (SNES_VINEWTONRSLS *)snes->data;
299c2fc9fa9SBarry Smith   PetscInt             maxits, i, lits;
30076c63389SBarry Smith   SNESLineSearchReason lsreason;
301c2fc9fa9SBarry Smith   PetscReal            fnorm, gnorm, xnorm = 0, ynorm;
3029bd66eb0SPeter Brune   Vec                  Y, X, F;
303c2fc9fa9SBarry Smith   KSPConvergedReason   kspreason;
30492e89061SBarry Smith   KSP                  ksp;
30592e89061SBarry Smith   PC                   pc;
306c2fc9fa9SBarry Smith 
307c2fc9fa9SBarry Smith   PetscFunctionBegin;
30892e89061SBarry Smith   /* Multigrid must use Galerkin for coarse grids with active set/reduced space methods; cannot rediscretize on coarser grids*/
3099566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(snes, &ksp));
3109566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(ksp, &pc));
3119566063dSJacob Faibussowitsch   PetscCall(PCMGSetGalerkin(pc, PC_MG_GALERKIN_BOTH));
31292e89061SBarry Smith 
313c2fc9fa9SBarry Smith   snes->numFailures            = 0;
314c2fc9fa9SBarry Smith   snes->numLinearSolveFailures = 0;
315c2fc9fa9SBarry Smith   snes->reason                 = SNES_CONVERGED_ITERATING;
316c2fc9fa9SBarry Smith 
317c2fc9fa9SBarry Smith   maxits = snes->max_its;  /* maximum number of iterations */
318c2fc9fa9SBarry Smith   X      = snes->vec_sol;  /* solution vector */
319c2fc9fa9SBarry Smith   F      = snes->vec_func; /* residual vector */
320c2fc9fa9SBarry Smith   Y      = snes->work[0];  /* work vectors */
3219bd66eb0SPeter Brune 
322d5def619SJonas Heinzmann   PetscCall(SNESLineSearchSetVIFunctions(snes->linesearch, SNESVIProjectOntoBounds, SNESVIComputeInactiveSetFnorm, SNESVIComputeInactiveSetFtY));
3239566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchSetVecs(snes->linesearch, X, NULL, NULL, NULL, NULL));
3249566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchSetUp(snes->linesearch));
325c2fc9fa9SBarry Smith 
3269566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
327c2fc9fa9SBarry Smith   snes->iter = 0;
328c2fc9fa9SBarry Smith   snes->norm = 0.0;
3299566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
330c2fc9fa9SBarry Smith 
3319566063dSJacob Faibussowitsch   PetscCall(SNESVIProjectOntoBounds(snes, X));
3329566063dSJacob Faibussowitsch   PetscCall(SNESComputeFunction(snes, X, F));
3339566063dSJacob Faibussowitsch   PetscCall(SNESVIComputeInactiveSetFnorm(snes, F, X, &fnorm));
3349566063dSJacob Faibussowitsch   PetscCall(VecNorm(X, NORM_2, &xnorm)); /* xnorm <- ||x||  */
33576c63389SBarry Smith   SNESCheckFunctionDomainError(snes, fnorm);
3369566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
337c2fc9fa9SBarry Smith   snes->norm = fnorm;
3389566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
3399566063dSJacob Faibussowitsch   PetscCall(SNESLogConvergenceHistory(snes, fnorm, 0));
340c2fc9fa9SBarry Smith 
341c2fc9fa9SBarry Smith   /* test convergence */
3422d157150SStefano Zampini   PetscCall(SNESConverged(snes, 0, 0.0, 0.0, fnorm));
3432d157150SStefano Zampini   PetscCall(SNESMonitor(snes, 0, fnorm));
3443ba16761SJacob Faibussowitsch   if (snes->reason) PetscFunctionReturn(PETSC_SUCCESS);
345c2fc9fa9SBarry Smith 
346c2fc9fa9SBarry Smith   for (i = 0; i < maxits; i++) {
347f009fc93SPatrick Farrell     IS         IS_act;    /* _act -> active set _inact -> inactive set */
348c2fc9fa9SBarry Smith     IS         IS_redact; /* redundant active set */
349c2fc9fa9SBarry Smith     VecScatter scat_act, scat_inact;
350c2fc9fa9SBarry Smith     PetscInt   nis_act, nis_inact;
351c2fc9fa9SBarry Smith     Vec        Y_act, Y_inact, F_inact;
352c2fc9fa9SBarry Smith     Mat        jac_inact_inact, prejac_inact_inact;
353c2fc9fa9SBarry Smith     PetscBool  isequal;
354c2fc9fa9SBarry Smith 
355c2fc9fa9SBarry Smith     /* Call general purpose update function */
356dbbe0bcdSBarry Smith     PetscTryTypeMethod(snes, update, snes->iter);
3579566063dSJacob Faibussowitsch     PetscCall(SNESComputeJacobian(snes, X, snes->jacobian, snes->jacobian_pre));
35876c63389SBarry Smith     SNESCheckJacobianDomainError(snes);
359c2fc9fa9SBarry Smith 
360c2fc9fa9SBarry Smith     /* Create active and inactive index sets */
361c2fc9fa9SBarry Smith 
362c2fc9fa9SBarry Smith     /*original
3639566063dSJacob Faibussowitsch     PetscCall(SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&vi->IS_inact));
364c2fc9fa9SBarry Smith      */
3659566063dSJacob Faibussowitsch     PetscCall(SNESVIGetActiveSetIS(snes, X, F, &IS_act));
366c2fc9fa9SBarry Smith 
367c2fc9fa9SBarry Smith     if (vi->checkredundancy) {
3689566063dSJacob Faibussowitsch       PetscCall((*vi->checkredundancy)(snes, IS_act, &IS_redact, vi->ctxP));
369c2fc9fa9SBarry Smith       if (IS_redact) {
3709566063dSJacob Faibussowitsch         PetscCall(ISSort(IS_redact));
3719566063dSJacob Faibussowitsch         PetscCall(ISComplement(IS_redact, X->map->rstart, X->map->rend, &vi->IS_inact));
3729566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&IS_redact));
3731aa26658SKarl Rupp       } else {
3749566063dSJacob Faibussowitsch         PetscCall(ISComplement(IS_act, X->map->rstart, X->map->rend, &vi->IS_inact));
375c2fc9fa9SBarry Smith       }
376c2fc9fa9SBarry Smith     } else {
3779566063dSJacob Faibussowitsch       PetscCall(ISComplement(IS_act, X->map->rstart, X->map->rend, &vi->IS_inact));
378c2fc9fa9SBarry Smith     }
379c2fc9fa9SBarry Smith 
380c2fc9fa9SBarry Smith     /* Create inactive set submatrix */
3819566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(snes->jacobian, vi->IS_inact, vi->IS_inact, MAT_INITIAL_MATRIX, &jac_inact_inact));
382c2fc9fa9SBarry Smith 
38366bfb381SJed Brown     if (0) { /* Dead code (temporary developer hack) */
38466bfb381SJed Brown       IS keptrows;
3859566063dSJacob Faibussowitsch       PetscCall(MatFindNonzeroRows(jac_inact_inact, &keptrows));
38666bfb381SJed Brown       if (keptrows) {
387c2fc9fa9SBarry Smith         PetscInt        cnt, *nrows, k;
388c2fc9fa9SBarry Smith         const PetscInt *krows, *inact;
389367daffbSBarry Smith         PetscInt        rstart;
390c2fc9fa9SBarry Smith 
3919566063dSJacob Faibussowitsch         PetscCall(MatGetOwnershipRange(jac_inact_inact, &rstart, NULL));
3929566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&jac_inact_inact));
3939566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&IS_act));
394c2fc9fa9SBarry Smith 
3959566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(keptrows, &cnt));
3969566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(keptrows, &krows));
3979566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(vi->IS_inact, &inact));
3989566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(cnt, &nrows));
3991aa26658SKarl Rupp         for (k = 0; k < cnt; k++) nrows[k] = inact[krows[k] - rstart];
4009566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(keptrows, &krows));
4019566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(vi->IS_inact, &inact));
4029566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&keptrows));
4039566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&vi->IS_inact));
404c2fc9fa9SBarry Smith 
4059566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)snes), cnt, nrows, PETSC_OWN_POINTER, &vi->IS_inact));
4069566063dSJacob Faibussowitsch         PetscCall(ISComplement(vi->IS_inact, F->map->rstart, F->map->rend, &IS_act));
4079566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(snes->jacobian, vi->IS_inact, vi->IS_inact, MAT_INITIAL_MATRIX, &jac_inact_inact));
408c2fc9fa9SBarry Smith       }
40966bfb381SJed Brown     }
4109566063dSJacob Faibussowitsch     PetscCall(DMSetVI(snes->dm, vi->IS_inact));
411c2fc9fa9SBarry Smith     /* remove later */
412c2fc9fa9SBarry Smith 
413c2fc9fa9SBarry Smith     /*
414f4f49eeaSPierre Jolivet     PetscCall(VecView(vi->xu,PETSC_VIEWER_BINARY_(((PetscObject)vi->xu)->comm)));
415f4f49eeaSPierre Jolivet     PetscCall(VecView(vi->xl,PETSC_VIEWER_BINARY_(((PetscObject)vi->xl)->comm)));
4169566063dSJacob Faibussowitsch     PetscCall(VecView(X,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)X))));
4179566063dSJacob Faibussowitsch     PetscCall(VecView(F,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)F))));
4189566063dSJacob Faibussowitsch     PetscCall(ISView(vi->IS_inact,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)vi->IS_inact))));
419c2fc9fa9SBarry Smith      */
420c2fc9fa9SBarry Smith 
421c2fc9fa9SBarry Smith     /* Get sizes of active and inactive sets */
4229566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(IS_act, &nis_act));
4239566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(vi->IS_inact, &nis_inact));
424c2fc9fa9SBarry Smith 
425c2fc9fa9SBarry Smith     /* Create active and inactive set vectors */
4269566063dSJacob Faibussowitsch     PetscCall(SNESCreateSubVectors_VINEWTONRSLS(snes, nis_inact, &F_inact));
4279566063dSJacob Faibussowitsch     PetscCall(SNESCreateSubVectors_VINEWTONRSLS(snes, nis_act, &Y_act));
4289566063dSJacob Faibussowitsch     PetscCall(SNESCreateSubVectors_VINEWTONRSLS(snes, nis_inact, &Y_inact));
429c2fc9fa9SBarry Smith 
430c2fc9fa9SBarry Smith     /* Create scatter contexts */
4319566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(Y, IS_act, Y_act, NULL, &scat_act));
4329566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(Y, vi->IS_inact, Y_inact, NULL, &scat_inact));
433c2fc9fa9SBarry Smith 
434c2fc9fa9SBarry Smith     /* Do a vec scatter to active and inactive set vectors */
4359566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(scat_inact, F, F_inact, INSERT_VALUES, SCATTER_FORWARD));
4369566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(scat_inact, F, F_inact, INSERT_VALUES, SCATTER_FORWARD));
437c2fc9fa9SBarry Smith 
4389566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(scat_act, Y, Y_act, INSERT_VALUES, SCATTER_FORWARD));
4399566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(scat_act, Y, Y_act, INSERT_VALUES, SCATTER_FORWARD));
440c2fc9fa9SBarry Smith 
4419566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(scat_inact, Y, Y_inact, INSERT_VALUES, SCATTER_FORWARD));
4429566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(scat_inact, Y, Y_inact, INSERT_VALUES, SCATTER_FORWARD));
443c2fc9fa9SBarry Smith 
444c2fc9fa9SBarry Smith     /* Active set direction = 0 */
4459566063dSJacob Faibussowitsch     PetscCall(VecSet(Y_act, 0));
446ac530a7eSPierre Jolivet     if (snes->jacobian != snes->jacobian_pre) PetscCall(MatCreateSubMatrix(snes->jacobian_pre, vi->IS_inact, vi->IS_inact, MAT_INITIAL_MATRIX, &prejac_inact_inact));
447ac530a7eSPierre Jolivet     else prejac_inact_inact = jac_inact_inact;
448c2fc9fa9SBarry Smith 
4499566063dSJacob Faibussowitsch     PetscCall(ISEqual(vi->IS_inact_prev, vi->IS_inact, &isequal));
450c2fc9fa9SBarry Smith     if (!isequal) {
4519566063dSJacob Faibussowitsch       PetscCall(SNESVIResetPCandKSP(snes, jac_inact_inact, prejac_inact_inact));
4529566063dSJacob Faibussowitsch       PetscCall(PCFieldSplitRestrictIS(pc, vi->IS_inact));
453c2fc9fa9SBarry Smith     }
454c2fc9fa9SBarry Smith 
4559566063dSJacob Faibussowitsch     /*      PetscCall(ISView(vi->IS_inact,0)); */
4569566063dSJacob Faibussowitsch     /*      PetscCall(ISView(IS_act,0));*/
457c2fc9fa9SBarry Smith     /*      ierr = MatView(snes->jacobian_pre,0); */
458c2fc9fa9SBarry Smith 
4599566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(snes->ksp, jac_inact_inact, prejac_inact_inact));
4609566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(snes->ksp));
461c2fc9fa9SBarry Smith     {
462c2fc9fa9SBarry Smith       PC        pc;
463c2fc9fa9SBarry Smith       PetscBool flg;
4649566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(snes->ksp, &pc));
4659566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &flg));
466c2fc9fa9SBarry Smith       if (flg) {
467c2fc9fa9SBarry Smith         KSP *subksps;
4689566063dSJacob Faibussowitsch         PetscCall(PCFieldSplitGetSubKSP(pc, NULL, &subksps));
4699566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(subksps[0], &pc));
4709566063dSJacob Faibussowitsch         PetscCall(PetscFree(subksps));
4719566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCBJACOBI, &flg));
472c2fc9fa9SBarry Smith         if (flg) {
473c2fc9fa9SBarry Smith           PetscInt        n, N = 101 * 101, j, cnts[3] = {0, 0, 0};
474c2fc9fa9SBarry Smith           const PetscInt *ii;
475c2fc9fa9SBarry Smith 
4769566063dSJacob Faibussowitsch           PetscCall(ISGetSize(vi->IS_inact, &n));
4779566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(vi->IS_inact, &ii));
478c2fc9fa9SBarry Smith           for (j = 0; j < n; j++) {
479c2fc9fa9SBarry Smith             if (ii[j] < N) cnts[0]++;
480c2fc9fa9SBarry Smith             else if (ii[j] < 2 * N) cnts[1]++;
481c2fc9fa9SBarry Smith             else if (ii[j] < 3 * N) cnts[2]++;
482c2fc9fa9SBarry Smith           }
4839566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(vi->IS_inact, &ii));
484c2fc9fa9SBarry Smith 
4859566063dSJacob Faibussowitsch           PetscCall(PCBJacobiSetTotalBlocks(pc, 3, cnts));
486c2fc9fa9SBarry Smith         }
487c2fc9fa9SBarry Smith       }
488c2fc9fa9SBarry Smith     }
489c2fc9fa9SBarry Smith 
4909566063dSJacob Faibussowitsch     PetscCall(KSPSolve(snes->ksp, F_inact, Y_inact));
4919566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(scat_act, Y_act, Y, INSERT_VALUES, SCATTER_REVERSE));
4929566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(scat_act, Y_act, Y, INSERT_VALUES, SCATTER_REVERSE));
4939566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(scat_inact, Y_inact, Y, INSERT_VALUES, SCATTER_REVERSE));
4949566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(scat_inact, Y_inact, Y, INSERT_VALUES, SCATTER_REVERSE));
495c2fc9fa9SBarry Smith 
4969566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&F_inact));
4979566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&Y_act));
4989566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&Y_inact));
4999566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&scat_act));
5009566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&scat_inact));
5019566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&IS_act));
502c2fc9fa9SBarry Smith     if (!isequal) {
5039566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&vi->IS_inact_prev));
5049566063dSJacob Faibussowitsch       PetscCall(ISDuplicate(vi->IS_inact, &vi->IS_inact_prev));
505c2fc9fa9SBarry Smith     }
5069566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&vi->IS_inact));
5079566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&jac_inact_inact));
50848a46eb9SPierre Jolivet     if (snes->jacobian != snes->jacobian_pre) PetscCall(MatDestroy(&prejac_inact_inact));
509fa6eefd1SCian Wilson 
5109566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason(snes->ksp, &kspreason));
511fa6eefd1SCian Wilson     if (kspreason < 0) {
512fa6eefd1SCian Wilson       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
51363a3b9bcSJacob 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));
514fa6eefd1SCian Wilson         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
515fa6eefd1SCian Wilson         break;
516fa6eefd1SCian Wilson       }
517fa6eefd1SCian Wilson     }
518fa6eefd1SCian Wilson 
5199566063dSJacob Faibussowitsch     PetscCall(KSPGetIterationNumber(snes->ksp, &lits));
520c2fc9fa9SBarry Smith     snes->linear_its += lits;
52163a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "iter=%" PetscInt_FMT ", linear solve iterations=%" PetscInt_FMT "\n", snes->iter, lits));
522c2fc9fa9SBarry Smith     /*
5236b2b7091SBarry Smith     if (snes->ops->precheck) {
524c2fc9fa9SBarry Smith       PetscBool changed_y = PETSC_FALSE;
525dbbe0bcdSBarry Smith       PetscUseTypeMethod(snes,precheck ,X,Y,snes->precheck,&changed_y);
526c2fc9fa9SBarry Smith     }
527c2fc9fa9SBarry Smith 
5281baa6e33SBarry Smith     if (PetscLogPrintInfo) PetscCall(SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W));
529c2fc9fa9SBarry Smith     */
530c2fc9fa9SBarry Smith     /* Compute a (scaled) negative update in the line search routine:
531c2fc9fa9SBarry Smith          Y <- X - lambda*Y
532c2fc9fa9SBarry Smith        and evaluate G = function(Y) (depends on the line search).
533c2fc9fa9SBarry Smith     */
5349566063dSJacob Faibussowitsch     PetscCall(VecCopy(Y, snes->vec_sol_update));
5359371c9d4SSatish Balay     ynorm = 1;
5369371c9d4SSatish Balay     gnorm = fnorm;
5379566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchApply(snes->linesearch, X, F, &gnorm, Y));
5389566063dSJacob Faibussowitsch     PetscCall(DMDestroyVI(snes->dm));
53976c63389SBarry Smith     if (snes->reason) break;
54076c63389SBarry Smith     PetscCall(SNESLineSearchGetReason(snes->linesearch, &lsreason));
54176c63389SBarry Smith     if (lsreason) {
54276c63389SBarry Smith       if (snes->stol * xnorm > ynorm) {
54376c63389SBarry Smith         snes->reason = SNES_CONVERGED_SNORM_RELATIVE;
54476c63389SBarry Smith         break;
54576c63389SBarry Smith       } else if (lsreason == SNES_LINESEARCH_FAILED_FUNCTION_DOMAIN) {
54676c63389SBarry Smith         snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
54776c63389SBarry Smith         break;
54876c63389SBarry Smith       } else if (lsreason == SNES_LINESEARCH_FAILED_NANORINF) {
54976c63389SBarry Smith         snes->reason = SNES_DIVERGED_FUNCTION_NANORINF;
55076c63389SBarry Smith         break;
55176c63389SBarry Smith       } else if (lsreason == SNES_LINESEARCH_FAILED_OBJECTIVE_DOMAIN) {
55276c63389SBarry Smith         snes->reason = SNES_DIVERGED_OBJECTIVE_DOMAIN;
55376c63389SBarry Smith         break;
55476c63389SBarry Smith       } else if (lsreason == SNES_LINESEARCH_FAILED_JACOBIAN_DOMAIN) {
55576c63389SBarry Smith         snes->reason = SNES_DIVERGED_JACOBIAN_DOMAIN;
55676c63389SBarry Smith         break;
55776c63389SBarry Smith       } else if (++snes->numFailures >= snes->maxFailures) {
558c2fc9fa9SBarry Smith         PetscBool ismin;
55976c63389SBarry Smith 
560c2fc9fa9SBarry Smith         snes->reason = SNES_DIVERGED_LINE_SEARCH;
5619566063dSJacob Faibussowitsch         PetscCall(SNESVICheckLocalMin_Private(snes, snes->jacobian, F, X, gnorm, &ismin));
562c2fc9fa9SBarry Smith         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
563c2fc9fa9SBarry Smith         break;
564c2fc9fa9SBarry Smith       }
565c2fc9fa9SBarry Smith     }
56676c63389SBarry Smith     PetscCall(SNESLineSearchGetNorms(snes->linesearch, &xnorm, &gnorm, &ynorm));
56776c63389SBarry Smith     PetscCall(PetscInfo(snes, "fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n", (double)fnorm, (double)gnorm, (double)ynorm, (int)lsreason));
568c2fc9fa9SBarry Smith     /* Update function and solution vectors */
569c2fc9fa9SBarry Smith     fnorm = gnorm;
570c2fc9fa9SBarry Smith     /* Monitor convergence */
5719566063dSJacob Faibussowitsch     PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
572c2fc9fa9SBarry Smith     snes->iter  = i + 1;
573c2fc9fa9SBarry Smith     snes->norm  = fnorm;
574c1e67a49SFande Kong     snes->xnorm = xnorm;
575c1e67a49SFande Kong     snes->ynorm = ynorm;
5769566063dSJacob Faibussowitsch     PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
5779566063dSJacob Faibussowitsch     PetscCall(SNESLogConvergenceHistory(snes, snes->norm, lits));
578c2fc9fa9SBarry Smith     /* Test for convergence, xnorm = || X || */
5799566063dSJacob Faibussowitsch     if (snes->ops->converged != SNESConvergedSkip) PetscCall(VecNorm(X, NORM_2, &xnorm));
5802d157150SStefano Zampini     PetscCall(SNESConverged(snes, snes->iter, xnorm, ynorm, fnorm));
5812d157150SStefano Zampini     PetscCall(SNESMonitor(snes, snes->iter, snes->norm));
582c2fc9fa9SBarry Smith     if (snes->reason) break;
583c2fc9fa9SBarry Smith   }
58491a42fcfSBarry 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 */
5859566063dSJacob Faibussowitsch   PetscCall(DMDestroyVI(snes->dm));
5863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
587c2fc9fa9SBarry Smith }
588c2fc9fa9SBarry Smith 
589f6dfbefdSBarry Smith /*@C
590f6dfbefdSBarry Smith   SNESVISetRedundancyCheck - Provide a function to check for any redundancy in the VI active set
591f6dfbefdSBarry Smith 
592c3339decSBarry Smith   Logically Collective
593f6dfbefdSBarry Smith 
594f6dfbefdSBarry Smith   Input Parameters:
595f6dfbefdSBarry Smith + snes - the `SNESVINEWTONRSLS` context
596f6dfbefdSBarry Smith . func - the function to check of redundancies
597f6dfbefdSBarry Smith - ctx  - optional context used by the function
598f6dfbefdSBarry Smith 
599f6dfbefdSBarry Smith   Level: advanced
600f6dfbefdSBarry Smith 
601f6dfbefdSBarry Smith   Note:
602420bcc1bSBarry Smith   Sometimes the inactive set will result in a singular sub-Jacobian problem that needs to be solved, this allows the user,
603f6dfbefdSBarry Smith   when they know more about their specific problem to provide a function that removes the redundancy that results in the singular linear system
604f6dfbefdSBarry Smith 
605420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESVINEWTONRSLS`, `SNESVIGetInactiveSet()`, `DMSetVI()`
606f6dfbefdSBarry Smith  @*/
SNESVISetRedundancyCheck(SNES snes,PetscErrorCode (* func)(SNES,IS,IS *,void *),PetscCtx ctx)607*2a8381b2SBarry Smith PetscErrorCode SNESVISetRedundancyCheck(SNES snes, PetscErrorCode (*func)(SNES, IS, IS *, void *), PetscCtx ctx)
608d71ae5a4SJacob Faibussowitsch {
609f450aa47SBarry Smith   SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data;
610c2fc9fa9SBarry Smith 
611c2fc9fa9SBarry Smith   PetscFunctionBegin;
612c2fc9fa9SBarry Smith   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
613c2fc9fa9SBarry Smith   vi->checkredundancy = func;
614c2fc9fa9SBarry Smith   vi->ctxP            = ctx;
6153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
616c2fc9fa9SBarry Smith }
617c2fc9fa9SBarry Smith 
618d1e78c4fSBarry Smith #if defined(PETSC_HAVE_MATLAB)
619c2fc9fa9SBarry Smith   #include <engine.h>
620c2fc9fa9SBarry Smith   #include <mex.h>
6219371c9d4SSatish Balay typedef struct {
6229371c9d4SSatish Balay   char    *funcname;
6239371c9d4SSatish Balay   mxArray *ctx;
6249371c9d4SSatish Balay } SNESMatlabContext;
625c2fc9fa9SBarry Smith 
SNESVIRedundancyCheck_Matlab(SNES snes,IS is_act,IS * is_redact,PetscCtx ctx)626*2a8381b2SBarry Smith PetscErrorCode SNESVIRedundancyCheck_Matlab(SNES snes, IS is_act, IS *is_redact, PetscCtx ctx)
627d71ae5a4SJacob Faibussowitsch {
628c2fc9fa9SBarry Smith   SNESMatlabContext *sctx = (SNESMatlabContext *)ctx;
629c2fc9fa9SBarry Smith   int                nlhs = 1, nrhs = 5;
630c2fc9fa9SBarry Smith   mxArray           *plhs[1], *prhs[5];
631c2fc9fa9SBarry Smith   long long int      l1 = 0, l2 = 0, ls = 0;
6320298fd71SBarry Smith   PetscInt          *indices = NULL;
633c2fc9fa9SBarry Smith 
634c2fc9fa9SBarry Smith   PetscFunctionBegin;
635c2fc9fa9SBarry Smith   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
636c2fc9fa9SBarry Smith   PetscValidHeaderSpecific(is_act, IS_CLASSID, 2);
6374f572ea9SToby Isaac   PetscAssertPointer(is_redact, 3);
638c2fc9fa9SBarry Smith   PetscCheckSameComm(snes, 1, is_act, 2);
639c2fc9fa9SBarry Smith 
640c2fc9fa9SBarry Smith   /* Create IS for reduced active set of size 0, its size and indices will
64121afe8ebSBarry Smith    bet set by the MATLAB function */
6429566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)snes), 0, indices, PETSC_OWN_POINTER, is_redact));
64321afe8ebSBarry Smith   /* call MATLAB function in ctx */
6449566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(&ls, &snes, 1));
6459566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(&l1, &is_act, 1));
6469566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(&l2, is_redact, 1));
647c2fc9fa9SBarry Smith   prhs[0] = mxCreateDoubleScalar((double)ls);
648c2fc9fa9SBarry Smith   prhs[1] = mxCreateDoubleScalar((double)l1);
649c2fc9fa9SBarry Smith   prhs[2] = mxCreateDoubleScalar((double)l2);
650c2fc9fa9SBarry Smith   prhs[3] = mxCreateString(sctx->funcname);
651c2fc9fa9SBarry Smith   prhs[4] = sctx->ctx;
6529566063dSJacob Faibussowitsch   PetscCall(mexCallMATLAB(nlhs, plhs, nrhs, prhs, "PetscSNESVIRedundancyCheckInternal"));
6539566063dSJacob Faibussowitsch   PetscCall(mxGetScalar(plhs[0]));
654c2fc9fa9SBarry Smith   mxDestroyArray(prhs[0]);
655c2fc9fa9SBarry Smith   mxDestroyArray(prhs[1]);
656c2fc9fa9SBarry Smith   mxDestroyArray(prhs[2]);
657c2fc9fa9SBarry Smith   mxDestroyArray(prhs[3]);
658c2fc9fa9SBarry Smith   mxDestroyArray(plhs[0]);
6593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
660c2fc9fa9SBarry Smith }
661c2fc9fa9SBarry Smith 
SNESVISetRedundancyCheckMatlab(SNES snes,const char * func,mxArray * ctx)662d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESVISetRedundancyCheckMatlab(SNES snes, const char *func, mxArray *ctx)
663d71ae5a4SJacob Faibussowitsch {
664c2fc9fa9SBarry Smith   SNESMatlabContext *sctx;
665c2fc9fa9SBarry Smith 
666c2fc9fa9SBarry Smith   PetscFunctionBegin;
667c2fc9fa9SBarry Smith   /* currently sctx is memory bleed */
6689566063dSJacob Faibussowitsch   PetscCall(PetscNew(&sctx));
6699566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(func, &sctx->funcname));
670c2fc9fa9SBarry Smith   sctx->ctx = mxDuplicateArray(ctx);
6719566063dSJacob Faibussowitsch   PetscCall(SNESVISetRedundancyCheck(snes, SNESVIRedundancyCheck_Matlab, sctx));
6723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
673c2fc9fa9SBarry Smith }
674c2fc9fa9SBarry Smith 
675c2fc9fa9SBarry Smith #endif
676c2fc9fa9SBarry Smith 
SNESSetUp_VINEWTONRSLS(SNES snes)677ba38deedSJacob Faibussowitsch static PetscErrorCode SNESSetUp_VINEWTONRSLS(SNES snes)
678d71ae5a4SJacob Faibussowitsch {
679f450aa47SBarry Smith   SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data;
680c2fc9fa9SBarry Smith   PetscInt          *indices;
681c2fc9fa9SBarry Smith   PetscInt           i, n, rstart, rend;
682f1c6b773SPeter Brune   SNESLineSearch     linesearch;
683c2fc9fa9SBarry Smith 
684c2fc9fa9SBarry Smith   PetscFunctionBegin;
6859566063dSJacob Faibussowitsch   PetscCall(SNESSetUp_VI(snes));
686c2fc9fa9SBarry Smith 
687c2fc9fa9SBarry Smith   /* Set up previous active index set for the first snes solve
688c2fc9fa9SBarry Smith    vi->IS_inact_prev = 0,1,2,....N */
689c2fc9fa9SBarry Smith 
690b2ccae6bSStefano Zampini   PetscCall(VecGetOwnershipRange(snes->work[0], &rstart, &rend));
691b2ccae6bSStefano Zampini   PetscCall(VecGetLocalSize(snes->work[0], &n));
6929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &indices));
693c2fc9fa9SBarry Smith   for (i = 0; i < n; i++) indices[i] = rstart + i;
6949566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)snes), n, indices, PETSC_OWN_POINTER, &vi->IS_inact_prev));
6959bd66eb0SPeter Brune 
6969bd66eb0SPeter Brune   /* set the line search functions */
6979bd66eb0SPeter Brune   if (!snes->linesearch) {
6989566063dSJacob Faibussowitsch     PetscCall(SNESGetLineSearch(snes, &linesearch));
6999566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBT));
7009bd66eb0SPeter Brune   }
7013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
702c2fc9fa9SBarry Smith }
703f6dfbefdSBarry Smith 
SNESReset_VINEWTONRSLS(SNES snes)704ba38deedSJacob Faibussowitsch static PetscErrorCode SNESReset_VINEWTONRSLS(SNES snes)
705d71ae5a4SJacob Faibussowitsch {
706f450aa47SBarry Smith   SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data;
707c2fc9fa9SBarry Smith 
708c2fc9fa9SBarry Smith   PetscFunctionBegin;
7099566063dSJacob Faibussowitsch   PetscCall(SNESReset_VI(snes));
7109566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&vi->IS_inact_prev));
7113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
712c2fc9fa9SBarry Smith }
713c2fc9fa9SBarry Smith 
714c2fc9fa9SBarry Smith /*MC
715f450aa47SBarry Smith       SNESVINEWTONRSLS - Reduced space active set solvers for variational inequalities based on Newton's method
716c2fc9fa9SBarry Smith 
717f6dfbefdSBarry Smith    Options Database Keys:
7181d27aa22SBarry Smith +   -snes_type <vinewtonssls,vinewtonrsls> - a semi-smooth solver or a reduced space active set method
71961589011SJed Brown -   -snes_vi_monitor                       - prints the number of active constraints at each iteration.
720c2fc9fa9SBarry Smith 
721c2fc9fa9SBarry Smith    Level: beginner
722c2fc9fa9SBarry Smith 
723f6dfbefdSBarry Smith    Note:
724f6dfbefdSBarry Smith    At each set of this methods the algorithm produces an inactive set of variables that are constrained to their current values
725f6dfbefdSBarry Smith    (because changing these values would result in those variables no longer satisfying the inequality constraints)
726f6dfbefdSBarry Smith    and produces a step direction by solving the linear system arising from the Jacobian with the inactive variables removed. In other
727420bcc1bSBarry Smith    words on a reduced space of the solution space. Based on the Newton update it then adjusts the inactive set for the next iteration.
728c2fc9fa9SBarry Smith 
7291d27aa22SBarry Smith    See {cite}`benson2006flexible`
730420bcc1bSBarry Smith 
731420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESVINEWTONSSLS`, `SNESNEWTONTR`, `SNESLineSearchSetType()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESVIGetInactiveSet()`, `DMSetVI()`, `SNESVISetRedundancyCheck()`
732c2fc9fa9SBarry Smith M*/
SNESCreate_VINEWTONRSLS(SNES snes)733d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode SNESCreate_VINEWTONRSLS(SNES snes)
734d71ae5a4SJacob Faibussowitsch {
735f450aa47SBarry Smith   SNES_VINEWTONRSLS *vi;
736d8d34be6SBarry Smith   SNESLineSearch     linesearch;
737c2fc9fa9SBarry Smith 
738c2fc9fa9SBarry Smith   PetscFunctionBegin;
739f450aa47SBarry Smith   snes->ops->reset          = SNESReset_VINEWTONRSLS;
740f450aa47SBarry Smith   snes->ops->setup          = SNESSetUp_VINEWTONRSLS;
741f450aa47SBarry Smith   snes->ops->solve          = SNESSolve_VINEWTONRSLS;
742c2fc9fa9SBarry Smith   snes->ops->destroy        = SNESDestroy_VI;
743c2fc9fa9SBarry Smith   snes->ops->setfromoptions = SNESSetFromOptions_VI;
7440298fd71SBarry Smith   snes->ops->view           = NULL;
7458d359177SBarry Smith   snes->ops->converged      = SNESConvergedDefault_VI;
746c2fc9fa9SBarry Smith 
747c2fc9fa9SBarry Smith   snes->usesksp = PETSC_TRUE;
748efd4aadfSBarry Smith   snes->usesnpc = PETSC_FALSE;
749c2fc9fa9SBarry Smith 
7509566063dSJacob Faibussowitsch   PetscCall(SNESGetLineSearch(snes, &linesearch));
75148a46eb9SPierre Jolivet   if (!((PetscObject)linesearch)->type_name) PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBT));
7529566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchBTSetAlpha(linesearch, 0.0));
753d8d34be6SBarry Smith 
7544fc747eaSLawrence Mitchell   snes->alwayscomputesfinalresidual = PETSC_TRUE;
7554fc747eaSLawrence Mitchell 
75677e5a1f9SBarry Smith   PetscCall(SNESParametersInitialize(snes));
75777e5a1f9SBarry Smith 
7584dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&vi));
759c2fc9fa9SBarry Smith   snes->data          = (void *)vi;
7600298fd71SBarry Smith   vi->checkredundancy = NULL;
761c2fc9fa9SBarry Smith 
7629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESVISetVariableBounds_C", SNESVISetVariableBounds_VI));
7639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESVISetComputeVariableBounds_C", SNESVISetComputeVariableBounds_VI));
7643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
765c2fc9fa9SBarry Smith }
766