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 @*/ 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 */ 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"); 589566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(isnes, (void **)&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 */ 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"); 769566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(isnes, (void **)&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"); 799566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(isnes, (void **)&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 */ 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"); 1059566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(isnes, (void **)&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 16549abdd8aSBarry Smith static PetscErrorCode DMDestroy_SNESVI(void **ctx) 166d71ae5a4SJacob Faibussowitsch { 16749abdd8aSBarry 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 @*/ 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 { 2259566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(isnes, (void **)&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 */ 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 */ 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 */ 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). */ 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; 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 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|| */ 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)); 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)); 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 /* 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(SNESLineSearchGetReason(snes->linesearch, &lssucceed)); 5399566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetNorms(snes->linesearch, &xnorm, &gnorm, &ynorm)); 5409566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes, "fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n", (double)fnorm, (double)gnorm, (double)ynorm, (int)lssucceed)); 541c2fc9fa9SBarry Smith if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; 542c2fc9fa9SBarry Smith if (snes->domainerror) { 543c2fc9fa9SBarry Smith snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 5449566063dSJacob Faibussowitsch PetscCall(DMDestroyVI(snes->dm)); 5453ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 546c2fc9fa9SBarry Smith } 547422a814eSBarry Smith if (lssucceed) { 548c2fc9fa9SBarry Smith if (++snes->numFailures >= snes->maxFailures) { 549c2fc9fa9SBarry Smith PetscBool ismin; 550c2fc9fa9SBarry Smith snes->reason = SNES_DIVERGED_LINE_SEARCH; 5519566063dSJacob Faibussowitsch PetscCall(SNESVICheckLocalMin_Private(snes, snes->jacobian, F, X, gnorm, &ismin)); 552c2fc9fa9SBarry Smith if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; 553c2fc9fa9SBarry Smith break; 554c2fc9fa9SBarry Smith } 555c2fc9fa9SBarry Smith } 5569566063dSJacob Faibussowitsch PetscCall(DMDestroyVI(snes->dm)); 557c2fc9fa9SBarry Smith /* Update function and solution vectors */ 558c2fc9fa9SBarry Smith fnorm = gnorm; 559c2fc9fa9SBarry Smith /* Monitor convergence */ 5609566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 561c2fc9fa9SBarry Smith snes->iter = i + 1; 562c2fc9fa9SBarry Smith snes->norm = fnorm; 563c1e67a49SFande Kong snes->xnorm = xnorm; 564c1e67a49SFande Kong snes->ynorm = ynorm; 5659566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 5669566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes, snes->norm, lits)); 567c2fc9fa9SBarry Smith /* Test for convergence, xnorm = || X || */ 5689566063dSJacob Faibussowitsch if (snes->ops->converged != SNESConvergedSkip) PetscCall(VecNorm(X, NORM_2, &xnorm)); 5692d157150SStefano Zampini PetscCall(SNESConverged(snes, snes->iter, xnorm, ynorm, fnorm)); 5702d157150SStefano Zampini PetscCall(SNESMonitor(snes, snes->iter, snes->norm)); 571c2fc9fa9SBarry Smith if (snes->reason) break; 572c2fc9fa9SBarry Smith } 57391a42fcfSBarry 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 */ 5749566063dSJacob Faibussowitsch PetscCall(DMDestroyVI(snes->dm)); 5753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 576c2fc9fa9SBarry Smith } 577c2fc9fa9SBarry Smith 578f6dfbefdSBarry Smith /*@C 579f6dfbefdSBarry Smith SNESVISetRedundancyCheck - Provide a function to check for any redundancy in the VI active set 580f6dfbefdSBarry Smith 581c3339decSBarry Smith Logically Collective 582f6dfbefdSBarry Smith 583f6dfbefdSBarry Smith Input Parameters: 584f6dfbefdSBarry Smith + snes - the `SNESVINEWTONRSLS` context 585f6dfbefdSBarry Smith . func - the function to check of redundancies 586f6dfbefdSBarry Smith - ctx - optional context used by the function 587f6dfbefdSBarry Smith 588f6dfbefdSBarry Smith Level: advanced 589f6dfbefdSBarry Smith 590f6dfbefdSBarry Smith Note: 591420bcc1bSBarry Smith Sometimes the inactive set will result in a singular sub-Jacobian problem that needs to be solved, this allows the user, 592f6dfbefdSBarry Smith when they know more about their specific problem to provide a function that removes the redundancy that results in the singular linear system 593f6dfbefdSBarry Smith 594420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESVINEWTONRSLS`, `SNESVIGetInactiveSet()`, `DMSetVI()` 595f6dfbefdSBarry Smith @*/ 596d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESVISetRedundancyCheck(SNES snes, PetscErrorCode (*func)(SNES, IS, IS *, void *), void *ctx) 597d71ae5a4SJacob Faibussowitsch { 598f450aa47SBarry Smith SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data; 599c2fc9fa9SBarry Smith 600c2fc9fa9SBarry Smith PetscFunctionBegin; 601c2fc9fa9SBarry Smith PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 602c2fc9fa9SBarry Smith vi->checkredundancy = func; 603c2fc9fa9SBarry Smith vi->ctxP = ctx; 6043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 605c2fc9fa9SBarry Smith } 606c2fc9fa9SBarry Smith 607d1e78c4fSBarry Smith #if defined(PETSC_HAVE_MATLAB) 608c2fc9fa9SBarry Smith #include <engine.h> 609c2fc9fa9SBarry Smith #include <mex.h> 6109371c9d4SSatish Balay typedef struct { 6119371c9d4SSatish Balay char *funcname; 6129371c9d4SSatish Balay mxArray *ctx; 6139371c9d4SSatish Balay } SNESMatlabContext; 614c2fc9fa9SBarry Smith 615d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESVIRedundancyCheck_Matlab(SNES snes, IS is_act, IS *is_redact, void *ctx) 616d71ae5a4SJacob Faibussowitsch { 617c2fc9fa9SBarry Smith SNESMatlabContext *sctx = (SNESMatlabContext *)ctx; 618c2fc9fa9SBarry Smith int nlhs = 1, nrhs = 5; 619c2fc9fa9SBarry Smith mxArray *plhs[1], *prhs[5]; 620c2fc9fa9SBarry Smith long long int l1 = 0, l2 = 0, ls = 0; 6210298fd71SBarry Smith PetscInt *indices = NULL; 622c2fc9fa9SBarry Smith 623c2fc9fa9SBarry Smith PetscFunctionBegin; 624c2fc9fa9SBarry Smith PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 625c2fc9fa9SBarry Smith PetscValidHeaderSpecific(is_act, IS_CLASSID, 2); 6264f572ea9SToby Isaac PetscAssertPointer(is_redact, 3); 627c2fc9fa9SBarry Smith PetscCheckSameComm(snes, 1, is_act, 2); 628c2fc9fa9SBarry Smith 629c2fc9fa9SBarry Smith /* Create IS for reduced active set of size 0, its size and indices will 63021afe8ebSBarry Smith bet set by the MATLAB function */ 6319566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)snes), 0, indices, PETSC_OWN_POINTER, is_redact)); 63221afe8ebSBarry Smith /* call MATLAB function in ctx */ 6339566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(&ls, &snes, 1)); 6349566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(&l1, &is_act, 1)); 6359566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(&l2, is_redact, 1)); 636c2fc9fa9SBarry Smith prhs[0] = mxCreateDoubleScalar((double)ls); 637c2fc9fa9SBarry Smith prhs[1] = mxCreateDoubleScalar((double)l1); 638c2fc9fa9SBarry Smith prhs[2] = mxCreateDoubleScalar((double)l2); 639c2fc9fa9SBarry Smith prhs[3] = mxCreateString(sctx->funcname); 640c2fc9fa9SBarry Smith prhs[4] = sctx->ctx; 6419566063dSJacob Faibussowitsch PetscCall(mexCallMATLAB(nlhs, plhs, nrhs, prhs, "PetscSNESVIRedundancyCheckInternal")); 6429566063dSJacob Faibussowitsch PetscCall(mxGetScalar(plhs[0])); 643c2fc9fa9SBarry Smith mxDestroyArray(prhs[0]); 644c2fc9fa9SBarry Smith mxDestroyArray(prhs[1]); 645c2fc9fa9SBarry Smith mxDestroyArray(prhs[2]); 646c2fc9fa9SBarry Smith mxDestroyArray(prhs[3]); 647c2fc9fa9SBarry Smith mxDestroyArray(plhs[0]); 6483ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 649c2fc9fa9SBarry Smith } 650c2fc9fa9SBarry Smith 651d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESVISetRedundancyCheckMatlab(SNES snes, const char *func, mxArray *ctx) 652d71ae5a4SJacob Faibussowitsch { 653c2fc9fa9SBarry Smith SNESMatlabContext *sctx; 654c2fc9fa9SBarry Smith 655c2fc9fa9SBarry Smith PetscFunctionBegin; 656c2fc9fa9SBarry Smith /* currently sctx is memory bleed */ 6579566063dSJacob Faibussowitsch PetscCall(PetscNew(&sctx)); 6589566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(func, &sctx->funcname)); 659c2fc9fa9SBarry Smith sctx->ctx = mxDuplicateArray(ctx); 6609566063dSJacob Faibussowitsch PetscCall(SNESVISetRedundancyCheck(snes, SNESVIRedundancyCheck_Matlab, sctx)); 6613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 662c2fc9fa9SBarry Smith } 663c2fc9fa9SBarry Smith 664c2fc9fa9SBarry Smith #endif 665c2fc9fa9SBarry Smith 666ba38deedSJacob Faibussowitsch static PetscErrorCode SNESSetUp_VINEWTONRSLS(SNES snes) 667d71ae5a4SJacob Faibussowitsch { 668f450aa47SBarry Smith SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data; 669c2fc9fa9SBarry Smith PetscInt *indices; 670c2fc9fa9SBarry Smith PetscInt i, n, rstart, rend; 671f1c6b773SPeter Brune SNESLineSearch linesearch; 672c2fc9fa9SBarry Smith 673c2fc9fa9SBarry Smith PetscFunctionBegin; 6749566063dSJacob Faibussowitsch PetscCall(SNESSetUp_VI(snes)); 675c2fc9fa9SBarry Smith 676c2fc9fa9SBarry Smith /* Set up previous active index set for the first snes solve 677c2fc9fa9SBarry Smith vi->IS_inact_prev = 0,1,2,....N */ 678c2fc9fa9SBarry Smith 679*b2ccae6bSStefano Zampini PetscCall(VecGetOwnershipRange(snes->work[0], &rstart, &rend)); 680*b2ccae6bSStefano Zampini PetscCall(VecGetLocalSize(snes->work[0], &n)); 6819566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &indices)); 682c2fc9fa9SBarry Smith for (i = 0; i < n; i++) indices[i] = rstart + i; 6839566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)snes), n, indices, PETSC_OWN_POINTER, &vi->IS_inact_prev)); 6849bd66eb0SPeter Brune 6859bd66eb0SPeter Brune /* set the line search functions */ 6869bd66eb0SPeter Brune if (!snes->linesearch) { 6879566063dSJacob Faibussowitsch PetscCall(SNESGetLineSearch(snes, &linesearch)); 6889566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBT)); 6899bd66eb0SPeter Brune } 6903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 691c2fc9fa9SBarry Smith } 692f6dfbefdSBarry Smith 693ba38deedSJacob Faibussowitsch static PetscErrorCode SNESReset_VINEWTONRSLS(SNES snes) 694d71ae5a4SJacob Faibussowitsch { 695f450aa47SBarry Smith SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data; 696c2fc9fa9SBarry Smith 697c2fc9fa9SBarry Smith PetscFunctionBegin; 6989566063dSJacob Faibussowitsch PetscCall(SNESReset_VI(snes)); 6999566063dSJacob Faibussowitsch PetscCall(ISDestroy(&vi->IS_inact_prev)); 7003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 701c2fc9fa9SBarry Smith } 702c2fc9fa9SBarry Smith 703c2fc9fa9SBarry Smith /*MC 704f450aa47SBarry Smith SNESVINEWTONRSLS - Reduced space active set solvers for variational inequalities based on Newton's method 705c2fc9fa9SBarry Smith 706f6dfbefdSBarry Smith Options Database Keys: 7071d27aa22SBarry Smith + -snes_type <vinewtonssls,vinewtonrsls> - a semi-smooth solver or a reduced space active set method 70861589011SJed Brown - -snes_vi_monitor - prints the number of active constraints at each iteration. 709c2fc9fa9SBarry Smith 710c2fc9fa9SBarry Smith Level: beginner 711c2fc9fa9SBarry Smith 712f6dfbefdSBarry Smith Note: 713f6dfbefdSBarry Smith At each set of this methods the algorithm produces an inactive set of variables that are constrained to their current values 714f6dfbefdSBarry Smith (because changing these values would result in those variables no longer satisfying the inequality constraints) 715f6dfbefdSBarry Smith and produces a step direction by solving the linear system arising from the Jacobian with the inactive variables removed. In other 716420bcc1bSBarry 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. 717c2fc9fa9SBarry Smith 7181d27aa22SBarry Smith See {cite}`benson2006flexible` 719420bcc1bSBarry Smith 720420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESVINEWTONSSLS`, `SNESNEWTONTR`, `SNESLineSearchSetType()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESVIGetInactiveSet()`, `DMSetVI()`, `SNESVISetRedundancyCheck()` 721c2fc9fa9SBarry Smith M*/ 722d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode SNESCreate_VINEWTONRSLS(SNES snes) 723d71ae5a4SJacob Faibussowitsch { 724f450aa47SBarry Smith SNES_VINEWTONRSLS *vi; 725d8d34be6SBarry Smith SNESLineSearch linesearch; 726c2fc9fa9SBarry Smith 727c2fc9fa9SBarry Smith PetscFunctionBegin; 728f450aa47SBarry Smith snes->ops->reset = SNESReset_VINEWTONRSLS; 729f450aa47SBarry Smith snes->ops->setup = SNESSetUp_VINEWTONRSLS; 730f450aa47SBarry Smith snes->ops->solve = SNESSolve_VINEWTONRSLS; 731c2fc9fa9SBarry Smith snes->ops->destroy = SNESDestroy_VI; 732c2fc9fa9SBarry Smith snes->ops->setfromoptions = SNESSetFromOptions_VI; 7330298fd71SBarry Smith snes->ops->view = NULL; 7348d359177SBarry Smith snes->ops->converged = SNESConvergedDefault_VI; 735c2fc9fa9SBarry Smith 736c2fc9fa9SBarry Smith snes->usesksp = PETSC_TRUE; 737efd4aadfSBarry Smith snes->usesnpc = PETSC_FALSE; 738c2fc9fa9SBarry Smith 7399566063dSJacob Faibussowitsch PetscCall(SNESGetLineSearch(snes, &linesearch)); 74048a46eb9SPierre Jolivet if (!((PetscObject)linesearch)->type_name) PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBT)); 7419566063dSJacob Faibussowitsch PetscCall(SNESLineSearchBTSetAlpha(linesearch, 0.0)); 742d8d34be6SBarry Smith 7434fc747eaSLawrence Mitchell snes->alwayscomputesfinalresidual = PETSC_TRUE; 7444fc747eaSLawrence Mitchell 74577e5a1f9SBarry Smith PetscCall(SNESParametersInitialize(snes)); 74677e5a1f9SBarry Smith 7474dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&vi)); 748c2fc9fa9SBarry Smith snes->data = (void *)vi; 7490298fd71SBarry Smith vi->checkredundancy = NULL; 750c2fc9fa9SBarry Smith 7519566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESVISetVariableBounds_C", SNESVISetVariableBounds_VI)); 7529566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESVISetComputeVariableBounds_C", SNESVISetComputeVariableBounds_VI)); 7533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 754c2fc9fa9SBarry Smith } 755