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 16fbda9744SBarry Smith Level: advanced 17fbda9744SBarry 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 189fbda9744SBarry Smith Level: intermediate 190fbda9744SBarry 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(KSPSetFromOptions(kspnew));*/ 291c2fc9fa9SBarry Smith PetscFunctionReturn(0); 292c2fc9fa9SBarry Smith } 293c2fc9fa9SBarry Smith 294c2fc9fa9SBarry Smith /* Variational Inequality solver using reduce space method. No semismooth algorithm is 295c2fc9fa9SBarry Smith implemented in this algorithm. It basically identifies the active constraints and does 296c2fc9fa9SBarry Smith a linear solve on the other variables (those not associated with the active constraints). */ 2979371c9d4SSatish Balay PetscErrorCode SNESSolve_VINEWTONRSLS(SNES snes) { 298f450aa47SBarry Smith SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data; 299c2fc9fa9SBarry Smith PetscInt maxits, i, lits; 300422a814eSBarry Smith SNESLineSearchReason lssucceed; 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 3229566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetVIFunctions(snes->linesearch, SNESVIProjectOntoBounds, SNESVIComputeInactiveSetFnorm)); 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|| */ 335422a814eSBarry Smith SNESCheckFunctionNorm(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)); 3409566063dSJacob Faibussowitsch PetscCall(SNESMonitor(snes, 0, fnorm)); 341c2fc9fa9SBarry Smith 342c2fc9fa9SBarry Smith /* test convergence */ 343dbbe0bcdSBarry Smith PetscUseTypeMethod(snes, converged, 0, 0.0, 0.0, fnorm, &snes->reason, snes->cnvP); 344c2fc9fa9SBarry Smith if (snes->reason) PetscFunctionReturn(0); 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)); 35807b62357SFande Kong 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 /* 4149566063dSJacob Faibussowitsch PetscCall(VecView(vi->xu,PETSC_VIEWER_BINARY_(((PetscObject)(vi->xu))->comm))); 4159566063dSJacob Faibussowitsch 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)); 446c2fc9fa9SBarry Smith if (snes->jacobian != snes->jacobian_pre) { 4479566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(snes->jacobian_pre, vi->IS_inact, vi->IS_inact, MAT_INITIAL_MATRIX, &prejac_inact_inact)); 448c2fc9fa9SBarry Smith } else prejac_inact_inact = jac_inact_inact; 449c2fc9fa9SBarry Smith 4509566063dSJacob Faibussowitsch PetscCall(ISEqual(vi->IS_inact_prev, vi->IS_inact, &isequal)); 451c2fc9fa9SBarry Smith if (!isequal) { 4529566063dSJacob Faibussowitsch PetscCall(SNESVIResetPCandKSP(snes, jac_inact_inact, prejac_inact_inact)); 4539566063dSJacob Faibussowitsch PetscCall(PCFieldSplitRestrictIS(pc, vi->IS_inact)); 454c2fc9fa9SBarry Smith } 455c2fc9fa9SBarry Smith 4569566063dSJacob Faibussowitsch /* PetscCall(ISView(vi->IS_inact,0)); */ 4579566063dSJacob Faibussowitsch /* PetscCall(ISView(IS_act,0));*/ 458c2fc9fa9SBarry Smith /* ierr = MatView(snes->jacobian_pre,0); */ 459c2fc9fa9SBarry Smith 4609566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(snes->ksp, jac_inact_inact, prejac_inact_inact)); 4619566063dSJacob Faibussowitsch PetscCall(KSPSetUp(snes->ksp)); 462c2fc9fa9SBarry Smith { 463c2fc9fa9SBarry Smith PC pc; 464c2fc9fa9SBarry Smith PetscBool flg; 4659566063dSJacob Faibussowitsch PetscCall(KSPGetPC(snes->ksp, &pc)); 4669566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &flg)); 467c2fc9fa9SBarry Smith if (flg) { 468c2fc9fa9SBarry Smith KSP *subksps; 4699566063dSJacob Faibussowitsch PetscCall(PCFieldSplitGetSubKSP(pc, NULL, &subksps)); 4709566063dSJacob Faibussowitsch PetscCall(KSPGetPC(subksps[0], &pc)); 4719566063dSJacob Faibussowitsch PetscCall(PetscFree(subksps)); 4729566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCBJACOBI, &flg)); 473c2fc9fa9SBarry Smith if (flg) { 474c2fc9fa9SBarry Smith PetscInt n, N = 101 * 101, j, cnts[3] = {0, 0, 0}; 475c2fc9fa9SBarry Smith const PetscInt *ii; 476c2fc9fa9SBarry Smith 4779566063dSJacob Faibussowitsch PetscCall(ISGetSize(vi->IS_inact, &n)); 4789566063dSJacob Faibussowitsch PetscCall(ISGetIndices(vi->IS_inact, &ii)); 479c2fc9fa9SBarry Smith for (j = 0; j < n; j++) { 480c2fc9fa9SBarry Smith if (ii[j] < N) cnts[0]++; 481c2fc9fa9SBarry Smith else if (ii[j] < 2 * N) cnts[1]++; 482c2fc9fa9SBarry Smith else if (ii[j] < 3 * N) cnts[2]++; 483c2fc9fa9SBarry Smith } 4849566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(vi->IS_inact, &ii)); 485c2fc9fa9SBarry Smith 4869566063dSJacob Faibussowitsch PetscCall(PCBJacobiSetTotalBlocks(pc, 3, cnts)); 487c2fc9fa9SBarry Smith } 488c2fc9fa9SBarry Smith } 489c2fc9fa9SBarry Smith } 490c2fc9fa9SBarry Smith 4919566063dSJacob Faibussowitsch PetscCall(KSPSolve(snes->ksp, F_inact, Y_inact)); 4929566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(scat_act, Y_act, Y, INSERT_VALUES, SCATTER_REVERSE)); 4939566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(scat_act, Y_act, Y, INSERT_VALUES, SCATTER_REVERSE)); 4949566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(scat_inact, Y_inact, Y, INSERT_VALUES, SCATTER_REVERSE)); 4959566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(scat_inact, Y_inact, Y, INSERT_VALUES, SCATTER_REVERSE)); 496c2fc9fa9SBarry Smith 4979566063dSJacob Faibussowitsch PetscCall(VecDestroy(&F_inact)); 4989566063dSJacob Faibussowitsch PetscCall(VecDestroy(&Y_act)); 4999566063dSJacob Faibussowitsch PetscCall(VecDestroy(&Y_inact)); 5009566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&scat_act)); 5019566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&scat_inact)); 5029566063dSJacob Faibussowitsch PetscCall(ISDestroy(&IS_act)); 503c2fc9fa9SBarry Smith if (!isequal) { 5049566063dSJacob Faibussowitsch PetscCall(ISDestroy(&vi->IS_inact_prev)); 5059566063dSJacob Faibussowitsch PetscCall(ISDuplicate(vi->IS_inact, &vi->IS_inact_prev)); 506c2fc9fa9SBarry Smith } 5079566063dSJacob Faibussowitsch PetscCall(ISDestroy(&vi->IS_inact)); 5089566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac_inact_inact)); 50948a46eb9SPierre Jolivet if (snes->jacobian != snes->jacobian_pre) PetscCall(MatDestroy(&prejac_inact_inact)); 510fa6eefd1SCian Wilson 5119566063dSJacob Faibussowitsch PetscCall(KSPGetConvergedReason(snes->ksp, &kspreason)); 512fa6eefd1SCian Wilson if (kspreason < 0) { 513fa6eefd1SCian Wilson if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { 51463a3b9bcSJacob 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)); 515fa6eefd1SCian Wilson snes->reason = SNES_DIVERGED_LINEAR_SOLVE; 516fa6eefd1SCian Wilson break; 517fa6eefd1SCian Wilson } 518fa6eefd1SCian Wilson } 519fa6eefd1SCian Wilson 5209566063dSJacob Faibussowitsch PetscCall(KSPGetIterationNumber(snes->ksp, &lits)); 521c2fc9fa9SBarry Smith snes->linear_its += lits; 52263a3b9bcSJacob Faibussowitsch PetscCall(PetscInfo(snes, "iter=%" PetscInt_FMT ", linear solve iterations=%" PetscInt_FMT "\n", snes->iter, lits)); 523c2fc9fa9SBarry Smith /* 5246b2b7091SBarry Smith if (snes->ops->precheck) { 525c2fc9fa9SBarry Smith PetscBool changed_y = PETSC_FALSE; 526dbbe0bcdSBarry Smith PetscUseTypeMethod(snes,precheck ,X,Y,snes->precheck,&changed_y); 527c2fc9fa9SBarry Smith } 528c2fc9fa9SBarry Smith 5291baa6e33SBarry Smith if (PetscLogPrintInfo) PetscCall(SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W)); 530c2fc9fa9SBarry Smith */ 531c2fc9fa9SBarry Smith /* Compute a (scaled) negative update in the line search routine: 532c2fc9fa9SBarry Smith Y <- X - lambda*Y 533c2fc9fa9SBarry Smith and evaluate G = function(Y) (depends on the line search). 534c2fc9fa9SBarry Smith */ 5359566063dSJacob Faibussowitsch PetscCall(VecCopy(Y, snes->vec_sol_update)); 5369371c9d4SSatish Balay ynorm = 1; 5379371c9d4SSatish Balay gnorm = fnorm; 5389566063dSJacob Faibussowitsch PetscCall(SNESLineSearchApply(snes->linesearch, X, F, &gnorm, Y)); 5399566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetReason(snes->linesearch, &lssucceed)); 5409566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetNorms(snes->linesearch, &xnorm, &gnorm, &ynorm)); 5419566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes, "fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n", (double)fnorm, (double)gnorm, (double)ynorm, (int)lssucceed)); 542c2fc9fa9SBarry Smith if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; 543c2fc9fa9SBarry Smith if (snes->domainerror) { 544c2fc9fa9SBarry Smith snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 5459566063dSJacob Faibussowitsch PetscCall(DMDestroyVI(snes->dm)); 546c2fc9fa9SBarry Smith PetscFunctionReturn(0); 547c2fc9fa9SBarry Smith } 548422a814eSBarry Smith if (lssucceed) { 549c2fc9fa9SBarry Smith if (++snes->numFailures >= snes->maxFailures) { 550c2fc9fa9SBarry Smith PetscBool ismin; 551c2fc9fa9SBarry Smith snes->reason = SNES_DIVERGED_LINE_SEARCH; 5529566063dSJacob Faibussowitsch PetscCall(SNESVICheckLocalMin_Private(snes, snes->jacobian, F, X, gnorm, &ismin)); 553c2fc9fa9SBarry Smith if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; 554c2fc9fa9SBarry Smith break; 555c2fc9fa9SBarry Smith } 556c2fc9fa9SBarry Smith } 5579566063dSJacob Faibussowitsch PetscCall(DMDestroyVI(snes->dm)); 558c2fc9fa9SBarry Smith /* Update function and solution vectors */ 559c2fc9fa9SBarry Smith fnorm = gnorm; 560c2fc9fa9SBarry Smith /* Monitor convergence */ 5619566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 562c2fc9fa9SBarry Smith snes->iter = i + 1; 563c2fc9fa9SBarry Smith snes->norm = fnorm; 564c1e67a49SFande Kong snes->xnorm = xnorm; 565c1e67a49SFande Kong snes->ynorm = ynorm; 5669566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 5679566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes, snes->norm, lits)); 5689566063dSJacob Faibussowitsch PetscCall(SNESMonitor(snes, snes->iter, snes->norm)); 569c2fc9fa9SBarry Smith /* Test for convergence, xnorm = || X || */ 5709566063dSJacob Faibussowitsch if (snes->ops->converged != SNESConvergedSkip) PetscCall(VecNorm(X, NORM_2, &xnorm)); 571dbbe0bcdSBarry Smith PetscUseTypeMethod(snes, converged, snes->iter, xnorm, ynorm, fnorm, &snes->reason, snes->cnvP); 572c2fc9fa9SBarry Smith if (snes->reason) break; 573c2fc9fa9SBarry Smith } 57491a42fcfSBarry 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 */ 5759566063dSJacob Faibussowitsch PetscCall(DMDestroyVI(snes->dm)); 576c2fc9fa9SBarry Smith if (i == maxits) { 57763a3b9bcSJacob Faibussowitsch PetscCall(PetscInfo(snes, "Maximum number of iterations has been reached: %" PetscInt_FMT "\n", maxits)); 578c2fc9fa9SBarry Smith if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 579c2fc9fa9SBarry Smith } 580c2fc9fa9SBarry Smith PetscFunctionReturn(0); 581c2fc9fa9SBarry Smith } 582c2fc9fa9SBarry Smith 583f6dfbefdSBarry Smith /*@C 584f6dfbefdSBarry Smith SNESVISetRedundancyCheck - Provide a function to check for any redundancy in the VI active set 585f6dfbefdSBarry Smith 586f6dfbefdSBarry Smith Logically Collective on snes 587f6dfbefdSBarry Smith 588f6dfbefdSBarry Smith Input Parameters: 589f6dfbefdSBarry Smith + snes - the `SNESVINEWTONRSLS` context 590f6dfbefdSBarry Smith . func - the function to check of redundancies 591f6dfbefdSBarry Smith - ctx - optional context used by the function 592f6dfbefdSBarry Smith 593f6dfbefdSBarry Smith Level: advanced 594f6dfbefdSBarry Smith 595f6dfbefdSBarry Smith Note: 596f6dfbefdSBarry Smith Sometimes the inactive set will result in a non-singular sub-Jacobian problem that needs to be solved, this allows the user, 597f6dfbefdSBarry Smith when they know more about their specific problem to provide a function that removes the redundancy that results in the singular linear system 598f6dfbefdSBarry Smith 599f6dfbefdSBarry Smith .seealso: `SNESVINEWTONRSLS`, `SNESVIGetInactiveSet()`, `DMSetVI()` 600f6dfbefdSBarry Smith @*/ 6019371c9d4SSatish Balay PetscErrorCode SNESVISetRedundancyCheck(SNES snes, PetscErrorCode (*func)(SNES, IS, IS *, void *), void *ctx) { 602f450aa47SBarry Smith SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data; 603c2fc9fa9SBarry Smith 604c2fc9fa9SBarry Smith PetscFunctionBegin; 605c2fc9fa9SBarry Smith PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 606c2fc9fa9SBarry Smith vi->checkredundancy = func; 607c2fc9fa9SBarry Smith vi->ctxP = ctx; 608c2fc9fa9SBarry Smith PetscFunctionReturn(0); 609c2fc9fa9SBarry Smith } 610c2fc9fa9SBarry Smith 611c2fc9fa9SBarry Smith #if defined(PETSC_HAVE_MATLAB_ENGINE) 612c2fc9fa9SBarry Smith #include <engine.h> 613c2fc9fa9SBarry Smith #include <mex.h> 6149371c9d4SSatish Balay typedef struct { 6159371c9d4SSatish Balay char *funcname; 6169371c9d4SSatish Balay mxArray *ctx; 6179371c9d4SSatish Balay } SNESMatlabContext; 618c2fc9fa9SBarry Smith 6199371c9d4SSatish Balay PetscErrorCode SNESVIRedundancyCheck_Matlab(SNES snes, IS is_act, IS *is_redact, void *ctx) { 620c2fc9fa9SBarry Smith SNESMatlabContext *sctx = (SNESMatlabContext *)ctx; 621c2fc9fa9SBarry Smith int nlhs = 1, nrhs = 5; 622c2fc9fa9SBarry Smith mxArray *plhs[1], *prhs[5]; 623c2fc9fa9SBarry Smith long long int l1 = 0, l2 = 0, ls = 0; 6240298fd71SBarry Smith PetscInt *indices = NULL; 625c2fc9fa9SBarry Smith 626c2fc9fa9SBarry Smith PetscFunctionBegin; 627c2fc9fa9SBarry Smith PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 628c2fc9fa9SBarry Smith PetscValidHeaderSpecific(is_act, IS_CLASSID, 2); 629c2fc9fa9SBarry Smith PetscValidPointer(is_redact, 3); 630c2fc9fa9SBarry Smith PetscCheckSameComm(snes, 1, is_act, 2); 631c2fc9fa9SBarry Smith 632c2fc9fa9SBarry Smith /* Create IS for reduced active set of size 0, its size and indices will 633c2fc9fa9SBarry Smith bet set by the Matlab function */ 6349566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)snes), 0, indices, PETSC_OWN_POINTER, is_redact)); 635c2fc9fa9SBarry Smith /* call Matlab function in ctx */ 6369566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(&ls, &snes, 1)); 6379566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(&l1, &is_act, 1)); 6389566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(&l2, is_redact, 1)); 639c2fc9fa9SBarry Smith prhs[0] = mxCreateDoubleScalar((double)ls); 640c2fc9fa9SBarry Smith prhs[1] = mxCreateDoubleScalar((double)l1); 641c2fc9fa9SBarry Smith prhs[2] = mxCreateDoubleScalar((double)l2); 642c2fc9fa9SBarry Smith prhs[3] = mxCreateString(sctx->funcname); 643c2fc9fa9SBarry Smith prhs[4] = sctx->ctx; 6449566063dSJacob Faibussowitsch PetscCall(mexCallMATLAB(nlhs, plhs, nrhs, prhs, "PetscSNESVIRedundancyCheckInternal")); 6459566063dSJacob Faibussowitsch PetscCall(mxGetScalar(plhs[0])); 646c2fc9fa9SBarry Smith mxDestroyArray(prhs[0]); 647c2fc9fa9SBarry Smith mxDestroyArray(prhs[1]); 648c2fc9fa9SBarry Smith mxDestroyArray(prhs[2]); 649c2fc9fa9SBarry Smith mxDestroyArray(prhs[3]); 650c2fc9fa9SBarry Smith mxDestroyArray(plhs[0]); 651c2fc9fa9SBarry Smith PetscFunctionReturn(0); 652c2fc9fa9SBarry Smith } 653c2fc9fa9SBarry Smith 6549371c9d4SSatish Balay PetscErrorCode SNESVISetRedundancyCheckMatlab(SNES snes, const char *func, mxArray *ctx) { 655c2fc9fa9SBarry Smith SNESMatlabContext *sctx; 656c2fc9fa9SBarry Smith 657c2fc9fa9SBarry Smith PetscFunctionBegin; 658c2fc9fa9SBarry Smith /* currently sctx is memory bleed */ 6599566063dSJacob Faibussowitsch PetscCall(PetscNew(&sctx)); 6609566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(func, &sctx->funcname)); 661c2fc9fa9SBarry Smith sctx->ctx = mxDuplicateArray(ctx); 6629566063dSJacob Faibussowitsch PetscCall(SNESVISetRedundancyCheck(snes, SNESVIRedundancyCheck_Matlab, sctx)); 663c2fc9fa9SBarry Smith PetscFunctionReturn(0); 664c2fc9fa9SBarry Smith } 665c2fc9fa9SBarry Smith 666c2fc9fa9SBarry Smith #endif 667c2fc9fa9SBarry Smith 668c2fc9fa9SBarry Smith /* 669f450aa47SBarry Smith SNESSetUp_VINEWTONRSLS - Sets up the internal data structures for the later use 670c2fc9fa9SBarry Smith of the SNESVI nonlinear solver. 671c2fc9fa9SBarry Smith 672c2fc9fa9SBarry Smith Input Parameter: 673c2fc9fa9SBarry Smith . snes - the SNES context 674c2fc9fa9SBarry Smith 675c2fc9fa9SBarry Smith Application Interface Routine: SNESSetUp() 676c2fc9fa9SBarry Smith 677f6dfbefdSBarry Smith Note: 678c2fc9fa9SBarry Smith For basic use of the SNES solvers, the user need not explicitly call 679c2fc9fa9SBarry Smith SNESSetUp(), since these actions will automatically occur during 680c2fc9fa9SBarry Smith the call to SNESSolve(). 681c2fc9fa9SBarry Smith */ 6829371c9d4SSatish Balay PetscErrorCode SNESSetUp_VINEWTONRSLS(SNES snes) { 683f450aa47SBarry Smith SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data; 684c2fc9fa9SBarry Smith PetscInt *indices; 685c2fc9fa9SBarry Smith PetscInt i, n, rstart, rend; 686f1c6b773SPeter Brune SNESLineSearch linesearch; 687c2fc9fa9SBarry Smith 688c2fc9fa9SBarry Smith PetscFunctionBegin; 6899566063dSJacob Faibussowitsch PetscCall(SNESSetUp_VI(snes)); 690c2fc9fa9SBarry Smith 691c2fc9fa9SBarry Smith /* Set up previous active index set for the first snes solve 692c2fc9fa9SBarry Smith vi->IS_inact_prev = 0,1,2,....N */ 693c2fc9fa9SBarry Smith 6949566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(snes->vec_sol, &rstart, &rend)); 6959566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(snes->vec_sol, &n)); 6969566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &indices)); 697c2fc9fa9SBarry Smith for (i = 0; i < n; i++) indices[i] = rstart + i; 6989566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)snes), n, indices, PETSC_OWN_POINTER, &vi->IS_inact_prev)); 6999bd66eb0SPeter Brune 7009bd66eb0SPeter Brune /* set the line search functions */ 7019bd66eb0SPeter Brune if (!snes->linesearch) { 7029566063dSJacob Faibussowitsch PetscCall(SNESGetLineSearch(snes, &linesearch)); 7039566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBT)); 7049bd66eb0SPeter Brune } 705c2fc9fa9SBarry Smith PetscFunctionReturn(0); 706c2fc9fa9SBarry Smith } 707f6dfbefdSBarry Smith 7089371c9d4SSatish Balay PetscErrorCode SNESReset_VINEWTONRSLS(SNES snes) { 709f450aa47SBarry Smith SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data; 710c2fc9fa9SBarry Smith 711c2fc9fa9SBarry Smith PetscFunctionBegin; 7129566063dSJacob Faibussowitsch PetscCall(SNESReset_VI(snes)); 7139566063dSJacob Faibussowitsch PetscCall(ISDestroy(&vi->IS_inact_prev)); 714c2fc9fa9SBarry Smith PetscFunctionReturn(0); 715c2fc9fa9SBarry Smith } 716c2fc9fa9SBarry Smith 717c2fc9fa9SBarry Smith /*MC 718f450aa47SBarry Smith SNESVINEWTONRSLS - Reduced space active set solvers for variational inequalities based on Newton's method 719c2fc9fa9SBarry Smith 720f6dfbefdSBarry Smith Options Database Keys: 721b621fa8fSRichard Tran Mills + -snes_type <vinewtonssls,vinewtonrsls> - a semi-smooth solver, a reduced space active set method 72261589011SJed Brown - -snes_vi_monitor - prints the number of active constraints at each iteration. 723c2fc9fa9SBarry Smith 724c2fc9fa9SBarry Smith Level: beginner 725c2fc9fa9SBarry Smith 726b80f3ac1SShri Abhyankar References: 727606c0280SSatish Balay . * - T. S. Munson, and S. Benson. Flexible Complementarity Solvers for Large Scale 728b80f3ac1SShri Abhyankar Applications, Optimization Methods and Software, 21 (2006). 729b80f3ac1SShri Abhyankar 730f6dfbefdSBarry Smith Note: 731f6dfbefdSBarry Smith At each set of this methods the algorithm produces an inactive set of variables that are constrained to their current values 732f6dfbefdSBarry Smith (because changing these values would result in those variables no longer satisfying the inequality constraints) 733f6dfbefdSBarry Smith and produces a step direction by solving the linear system arising from the Jacobian with the inactive variables removed. In other 734f6dfbefdSBarry 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. 735c2fc9fa9SBarry Smith 736f6dfbefdSBarry Smith .seealso: `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESVINEWTONSSLS`, `SNESNEWTONTRDC`, `SNESLineSearchSetType()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESVIGetInactiveSet()`, `DMSetVI()`, `SNESVISetRedundancyCheck()` 737c2fc9fa9SBarry Smith M*/ 7389371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode SNESCreate_VINEWTONRSLS(SNES snes) { 739f450aa47SBarry Smith SNES_VINEWTONRSLS *vi; 740d8d34be6SBarry Smith SNESLineSearch linesearch; 741c2fc9fa9SBarry Smith 742c2fc9fa9SBarry Smith PetscFunctionBegin; 743f450aa47SBarry Smith snes->ops->reset = SNESReset_VINEWTONRSLS; 744f450aa47SBarry Smith snes->ops->setup = SNESSetUp_VINEWTONRSLS; 745f450aa47SBarry Smith snes->ops->solve = SNESSolve_VINEWTONRSLS; 746c2fc9fa9SBarry Smith snes->ops->destroy = SNESDestroy_VI; 747c2fc9fa9SBarry Smith snes->ops->setfromoptions = SNESSetFromOptions_VI; 7480298fd71SBarry Smith snes->ops->view = NULL; 7498d359177SBarry Smith snes->ops->converged = SNESConvergedDefault_VI; 750c2fc9fa9SBarry Smith 751c2fc9fa9SBarry Smith snes->usesksp = PETSC_TRUE; 752efd4aadfSBarry Smith snes->usesnpc = PETSC_FALSE; 753c2fc9fa9SBarry Smith 7549566063dSJacob Faibussowitsch PetscCall(SNESGetLineSearch(snes, &linesearch)); 75548a46eb9SPierre Jolivet if (!((PetscObject)linesearch)->type_name) PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBT)); 7569566063dSJacob Faibussowitsch PetscCall(SNESLineSearchBTSetAlpha(linesearch, 0.0)); 757d8d34be6SBarry Smith 7584fc747eaSLawrence Mitchell snes->alwayscomputesfinalresidual = PETSC_TRUE; 7594fc747eaSLawrence Mitchell 760*4dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&vi)); 761c2fc9fa9SBarry Smith snes->data = (void *)vi; 7620298fd71SBarry Smith vi->checkredundancy = NULL; 763c2fc9fa9SBarry Smith 7649566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESVISetVariableBounds_C", SNESVISetVariableBounds_VI)); 7659566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESVISetComputeVariableBounds_C", SNESVISetComputeVariableBounds_VI)); 766c2fc9fa9SBarry Smith PetscFunctionReturn(0); 767c2fc9fa9SBarry Smith } 768