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 10e4094ef1SJacob Faibussowitsch Input Parameter: 11f6dfbefdSBarry Smith . snes - the `SNES` context 12c2fc9fa9SBarry Smith 13e4094ef1SJacob Faibussowitsch Output Parameter: 14d5f1b7e6SEd Bueler . inact - inactive set index set 15c2fc9fa9SBarry Smith 16fbda9744SBarry Smith Level: advanced 17fbda9744SBarry Smith 18f6dfbefdSBarry Smith .seealso: `SNESVINEWTONRSLS` 19f6dfbefdSBarry Smith @*/ 20d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESVIGetInactiveSet(SNES snes, IS *inact) 21d71ae5a4SJacob Faibussowitsch { 22f450aa47SBarry Smith SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data; 236e111a19SKarl Rupp 24c2fc9fa9SBarry Smith PetscFunctionBegin; 25f009fc93SPatrick Farrell *inact = vi->IS_inact; 263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 27c2fc9fa9SBarry Smith } 28c2fc9fa9SBarry Smith 29c2fc9fa9SBarry Smith /* 30c2fc9fa9SBarry 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 31c2fc9fa9SBarry Smith defined by the reduced space method. 32c2fc9fa9SBarry Smith 33c2fc9fa9SBarry Smith Simple calls the regular DM interpolation and restricts it to operation on the variables not associated with active constraints. 34d49cd2b7SBarry Smith */ 35c2fc9fa9SBarry Smith typedef struct { 36c2fc9fa9SBarry Smith PetscInt n; /* size of vectors in the reduced DM space */ 37c2fc9fa9SBarry Smith IS inactive; 38f5af7f23SKarl Rupp 3925296bd5SBarry Smith PetscErrorCode (*createinterpolation)(DM, DM, Mat *, Vec *); /* DM's original routines */ 40c2fc9fa9SBarry Smith PetscErrorCode (*coarsen)(DM, MPI_Comm, DM *); 41c2fc9fa9SBarry Smith PetscErrorCode (*createglobalvector)(DM, Vec *); 425a84ad33SLisandro Dalcin PetscErrorCode (*createinjection)(DM, DM, Mat *); 434a7a4c06SLawrence Mitchell PetscErrorCode (*hascreateinjection)(DM, PetscBool *); 44f5af7f23SKarl Rupp 45c2fc9fa9SBarry Smith DM dm; /* when destroying this object we need to reset the above function into the base DM */ 46c2fc9fa9SBarry Smith } DM_SNESVI; 47c2fc9fa9SBarry Smith 48c2fc9fa9SBarry Smith /* 49c2fc9fa9SBarry Smith DMCreateGlobalVector_SNESVI - Creates global vector of the size of the reduced space 50c2fc9fa9SBarry Smith */ 51*ba38deedSJacob Faibussowitsch static PetscErrorCode DMCreateGlobalVector_SNESVI(DM dm, Vec *vec) 52d71ae5a4SJacob Faibussowitsch { 53c2fc9fa9SBarry Smith PetscContainer isnes; 54c2fc9fa9SBarry Smith DM_SNESVI *dmsnesvi; 55c2fc9fa9SBarry Smith 56c2fc9fa9SBarry Smith PetscFunctionBegin; 579566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm, "VI", (PetscObject *)&isnes)); 5828b400f6SJacob Faibussowitsch PetscCheck(isnes, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Composed SNES is missing"); 599566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(isnes, (void **)&dmsnesvi)); 609566063dSJacob Faibussowitsch PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)dm), dmsnesvi->n, PETSC_DETERMINE, vec)); 619566063dSJacob Faibussowitsch PetscCall(VecSetDM(*vec, dm)); 623ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 63c2fc9fa9SBarry Smith } 64c2fc9fa9SBarry Smith 65c2fc9fa9SBarry Smith /* 66e727c939SJed Brown DMCreateInterpolation_SNESVI - Modifieds the interpolation obtained from the DM by removing all rows and columns associated with active constraints. 67c2fc9fa9SBarry Smith */ 68*ba38deedSJacob Faibussowitsch static PetscErrorCode DMCreateInterpolation_SNESVI(DM dm1, DM dm2, Mat *mat, Vec *vec) 69d71ae5a4SJacob Faibussowitsch { 70c2fc9fa9SBarry Smith PetscContainer isnes; 71c2fc9fa9SBarry Smith DM_SNESVI *dmsnesvi1, *dmsnesvi2; 72c2fc9fa9SBarry Smith Mat interp; 73c2fc9fa9SBarry Smith 74c2fc9fa9SBarry Smith PetscFunctionBegin; 759566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm1, "VI", (PetscObject *)&isnes)); 7628b400f6SJacob Faibussowitsch PetscCheck(isnes, PetscObjectComm((PetscObject)dm1), PETSC_ERR_PLIB, "Composed VI data structure is missing"); 779566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(isnes, (void **)&dmsnesvi1)); 789566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm2, "VI", (PetscObject *)&isnes)); 7928b400f6SJacob Faibussowitsch PetscCheck(isnes, PetscObjectComm((PetscObject)dm2), PETSC_ERR_PLIB, "Composed VI data structure is missing"); 809566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(isnes, (void **)&dmsnesvi2)); 81c2fc9fa9SBarry Smith 829566063dSJacob Faibussowitsch PetscCall((*dmsnesvi1->createinterpolation)(dm1, dm2, &interp, NULL)); 839566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(interp, dmsnesvi2->inactive, dmsnesvi1->inactive, MAT_INITIAL_MATRIX, mat)); 849566063dSJacob Faibussowitsch PetscCall(MatDestroy(&interp)); 859e5d0892SLisandro Dalcin *vec = NULL; 863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 87c2fc9fa9SBarry Smith } 88c2fc9fa9SBarry Smith 89c2fc9fa9SBarry Smith /* 90c2fc9fa9SBarry Smith DMCoarsen_SNESVI - Computes the regular coarsened DM then computes additional information about its inactive set 91c2fc9fa9SBarry Smith */ 92*ba38deedSJacob Faibussowitsch static PetscErrorCode DMCoarsen_SNESVI(DM dm1, MPI_Comm comm, DM *dm2) 93d71ae5a4SJacob Faibussowitsch { 94c2fc9fa9SBarry Smith PetscContainer isnes; 95c2fc9fa9SBarry Smith DM_SNESVI *dmsnesvi1; 96c2fc9fa9SBarry Smith Vec finemarked, coarsemarked; 97c2fc9fa9SBarry Smith IS inactive; 986dbf9973SLawrence Mitchell Mat inject; 99c2fc9fa9SBarry Smith const PetscInt *index; 100c2fc9fa9SBarry Smith PetscInt n, k, cnt = 0, rstart, *coarseindex; 101c2fc9fa9SBarry Smith PetscScalar *marked; 102c2fc9fa9SBarry Smith 103c2fc9fa9SBarry Smith PetscFunctionBegin; 1049566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm1, "VI", (PetscObject *)&isnes)); 10528b400f6SJacob Faibussowitsch PetscCheck(isnes, PetscObjectComm((PetscObject)dm1), PETSC_ERR_PLIB, "Composed VI data structure is missing"); 1069566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(isnes, (void **)&dmsnesvi1)); 107c2fc9fa9SBarry Smith 108c2fc9fa9SBarry Smith /* get the original coarsen */ 1099566063dSJacob Faibussowitsch PetscCall((*dmsnesvi1->coarsen)(dm1, comm, dm2)); 110c2fc9fa9SBarry Smith 111c2fc9fa9SBarry Smith /* not sure why this extra reference is needed, but without the dm2 disappears too early */ 11294c98981SBarry Smith /* Updating the KSPCreateVecs() to avoid using DMGetGlobalVector() when matrix is available removes the need for this reference? */ 1139566063dSJacob Faibussowitsch /* PetscCall(PetscObjectReference((PetscObject)*dm2));*/ 114c2fc9fa9SBarry Smith 115c2fc9fa9SBarry Smith /* need to set back global vectors in order to use the original injection */ 1169566063dSJacob Faibussowitsch PetscCall(DMClearGlobalVectors(dm1)); 1171aa26658SKarl Rupp 118c2fc9fa9SBarry Smith dm1->ops->createglobalvector = dmsnesvi1->createglobalvector; 1191aa26658SKarl Rupp 1209566063dSJacob Faibussowitsch PetscCall(DMCreateGlobalVector(dm1, &finemarked)); 1219566063dSJacob Faibussowitsch PetscCall(DMCreateGlobalVector(*dm2, &coarsemarked)); 122c2fc9fa9SBarry Smith 123c2fc9fa9SBarry Smith /* 124c2fc9fa9SBarry Smith fill finemarked with locations of inactive points 125c2fc9fa9SBarry Smith */ 1269566063dSJacob Faibussowitsch PetscCall(ISGetIndices(dmsnesvi1->inactive, &index)); 1279566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(dmsnesvi1->inactive, &n)); 1289566063dSJacob Faibussowitsch PetscCall(VecSet(finemarked, 0.0)); 12948a46eb9SPierre Jolivet for (k = 0; k < n; k++) PetscCall(VecSetValue(finemarked, index[k], 1.0, INSERT_VALUES)); 1309566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(finemarked)); 1319566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(finemarked)); 132c2fc9fa9SBarry Smith 1339566063dSJacob Faibussowitsch PetscCall(DMCreateInjection(*dm2, dm1, &inject)); 1349566063dSJacob Faibussowitsch PetscCall(MatRestrict(inject, finemarked, coarsemarked)); 1359566063dSJacob Faibussowitsch PetscCall(MatDestroy(&inject)); 136c2fc9fa9SBarry Smith 137c2fc9fa9SBarry Smith /* 138c2fc9fa9SBarry Smith create index set list of coarse inactive points from coarsemarked 139c2fc9fa9SBarry Smith */ 1409566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(coarsemarked, &n)); 1419566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(coarsemarked, &rstart, NULL)); 1429566063dSJacob Faibussowitsch PetscCall(VecGetArray(coarsemarked, &marked)); 143c2fc9fa9SBarry Smith for (k = 0; k < n; k++) { 144c2fc9fa9SBarry Smith if (marked[k] != 0.0) cnt++; 145c2fc9fa9SBarry Smith } 1469566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(cnt, &coarseindex)); 147c2fc9fa9SBarry Smith cnt = 0; 148c2fc9fa9SBarry Smith for (k = 0; k < n; k++) { 149c2fc9fa9SBarry Smith if (marked[k] != 0.0) coarseindex[cnt++] = k + rstart; 150c2fc9fa9SBarry Smith } 1519566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(coarsemarked, &marked)); 1529566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)coarsemarked), cnt, coarseindex, PETSC_OWN_POINTER, &inactive)); 153c2fc9fa9SBarry Smith 1549566063dSJacob Faibussowitsch PetscCall(DMClearGlobalVectors(dm1)); 1551aa26658SKarl Rupp 156c2fc9fa9SBarry Smith dm1->ops->createglobalvector = DMCreateGlobalVector_SNESVI; 1571aa26658SKarl Rupp 1589566063dSJacob Faibussowitsch PetscCall(DMSetVI(*dm2, inactive)); 159c2fc9fa9SBarry Smith 1609566063dSJacob Faibussowitsch PetscCall(VecDestroy(&finemarked)); 1619566063dSJacob Faibussowitsch PetscCall(VecDestroy(&coarsemarked)); 1629566063dSJacob Faibussowitsch PetscCall(ISDestroy(&inactive)); 1633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 164c2fc9fa9SBarry Smith } 165c2fc9fa9SBarry Smith 166*ba38deedSJacob Faibussowitsch static PetscErrorCode DMDestroy_SNESVI(DM_SNESVI *dmsnesvi) 167d71ae5a4SJacob Faibussowitsch { 168c2fc9fa9SBarry Smith PetscFunctionBegin; 169c2fc9fa9SBarry Smith /* reset the base methods in the DM object that were changed when the DM_SNESVI was reset */ 17025296bd5SBarry Smith dmsnesvi->dm->ops->createinterpolation = dmsnesvi->createinterpolation; 171c2fc9fa9SBarry Smith dmsnesvi->dm->ops->coarsen = dmsnesvi->coarsen; 172c2fc9fa9SBarry Smith dmsnesvi->dm->ops->createglobalvector = dmsnesvi->createglobalvector; 1735a84ad33SLisandro Dalcin dmsnesvi->dm->ops->createinjection = dmsnesvi->createinjection; 1744a7a4c06SLawrence Mitchell dmsnesvi->dm->ops->hascreateinjection = dmsnesvi->hascreateinjection; 175c2fc9fa9SBarry Smith /* need to clear out this vectors because some of them may not have a reference to the DM 176c2fc9fa9SBarry Smith but they are counted as having references to the DM in DMDestroy() */ 1779566063dSJacob Faibussowitsch PetscCall(DMClearGlobalVectors(dmsnesvi->dm)); 178c2fc9fa9SBarry Smith 1799566063dSJacob Faibussowitsch PetscCall(ISDestroy(&dmsnesvi->inactive)); 1809566063dSJacob Faibussowitsch PetscCall(PetscFree(dmsnesvi)); 1813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 182c2fc9fa9SBarry Smith } 183c2fc9fa9SBarry Smith 184f6dfbefdSBarry Smith /*@ 185c2fc9fa9SBarry Smith DMSetVI - Marks a DM as associated with a VI problem. This causes the interpolation/restriction operators to 186c2fc9fa9SBarry Smith be restricted to only those variables NOT associated with active constraints. 187c2fc9fa9SBarry Smith 188c3339decSBarry Smith Logically Collective 189f6dfbefdSBarry Smith 190f6dfbefdSBarry Smith Input Parameters: 191f6dfbefdSBarry Smith + dm - the `DM` object 192f6dfbefdSBarry Smith - inactive - an `IS` indicating which points are currently not active 193f6dfbefdSBarry Smith 194fbda9744SBarry Smith Level: intermediate 195fbda9744SBarry Smith 196f6dfbefdSBarry Smith .seealso: `SNESVINEWTONRSLS`, `SNESVIGetInactiveSet()` 197f6dfbefdSBarry Smith @*/ 198d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSetVI(DM dm, IS inactive) 199d71ae5a4SJacob Faibussowitsch { 200c2fc9fa9SBarry Smith PetscContainer isnes; 201c2fc9fa9SBarry Smith DM_SNESVI *dmsnesvi; 202c2fc9fa9SBarry Smith 203c2fc9fa9SBarry Smith PetscFunctionBegin; 2043ba16761SJacob Faibussowitsch if (!dm) PetscFunctionReturn(PETSC_SUCCESS); 205c2fc9fa9SBarry Smith 2069566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)inactive)); 207c2fc9fa9SBarry Smith 2089566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm, "VI", (PetscObject *)&isnes)); 209c2fc9fa9SBarry Smith if (!isnes) { 2109566063dSJacob Faibussowitsch PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &isnes)); 2119566063dSJacob Faibussowitsch PetscCall(PetscContainerSetUserDestroy(isnes, (PetscErrorCode(*)(void *))DMDestroy_SNESVI)); 2129566063dSJacob Faibussowitsch PetscCall(PetscNew(&dmsnesvi)); 2139566063dSJacob Faibussowitsch PetscCall(PetscContainerSetPointer(isnes, (void *)dmsnesvi)); 2149566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)dm, "VI", (PetscObject)isnes)); 2159566063dSJacob Faibussowitsch PetscCall(PetscContainerDestroy(&isnes)); 2161aa26658SKarl Rupp 21725296bd5SBarry Smith dmsnesvi->createinterpolation = dm->ops->createinterpolation; 21825296bd5SBarry Smith dm->ops->createinterpolation = DMCreateInterpolation_SNESVI; 219c2fc9fa9SBarry Smith dmsnesvi->coarsen = dm->ops->coarsen; 220c2fc9fa9SBarry Smith dm->ops->coarsen = DMCoarsen_SNESVI; 221c2fc9fa9SBarry Smith dmsnesvi->createglobalvector = dm->ops->createglobalvector; 222c2fc9fa9SBarry Smith dm->ops->createglobalvector = DMCreateGlobalVector_SNESVI; 2235a84ad33SLisandro Dalcin dmsnesvi->createinjection = dm->ops->createinjection; 2245a84ad33SLisandro Dalcin dm->ops->createinjection = NULL; 2254a7a4c06SLawrence Mitchell dmsnesvi->hascreateinjection = dm->ops->hascreateinjection; 2265a84ad33SLisandro Dalcin dm->ops->hascreateinjection = NULL; 227c2fc9fa9SBarry Smith } else { 2289566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(isnes, (void **)&dmsnesvi)); 2299566063dSJacob Faibussowitsch PetscCall(ISDestroy(&dmsnesvi->inactive)); 230c2fc9fa9SBarry Smith } 2319566063dSJacob Faibussowitsch PetscCall(DMClearGlobalVectors(dm)); 2329566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(inactive, &dmsnesvi->n)); 2331aa26658SKarl Rupp 234c2fc9fa9SBarry Smith dmsnesvi->inactive = inactive; 235c2fc9fa9SBarry Smith dmsnesvi->dm = dm; 2363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 237c2fc9fa9SBarry Smith } 238c2fc9fa9SBarry Smith 239c2fc9fa9SBarry Smith /* 240c2fc9fa9SBarry Smith DMDestroyVI - Frees the DM_SNESVI object contained in the DM 24125296bd5SBarry Smith - also resets the function pointers in the DM for createinterpolation() etc to use the original DM 242c2fc9fa9SBarry Smith */ 243d71ae5a4SJacob Faibussowitsch PetscErrorCode DMDestroyVI(DM dm) 244d71ae5a4SJacob Faibussowitsch { 245c2fc9fa9SBarry Smith PetscFunctionBegin; 2463ba16761SJacob Faibussowitsch if (!dm) PetscFunctionReturn(PETSC_SUCCESS); 2479566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)dm, "VI", (PetscObject)NULL)); 2483ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 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 */ 252*ba38deedSJacob Faibussowitsch static PetscErrorCode SNESCreateSubVectors_VINEWTONRSLS(SNES snes, PetscInt n, Vec *newv) 253d71ae5a4SJacob Faibussowitsch { 254c2fc9fa9SBarry Smith Vec v; 255c2fc9fa9SBarry Smith 256c2fc9fa9SBarry Smith PetscFunctionBegin; 2579566063dSJacob Faibussowitsch PetscCall(VecCreate(PetscObjectComm((PetscObject)snes), &v)); 2589566063dSJacob Faibussowitsch PetscCall(VecSetSizes(v, n, PETSC_DECIDE)); 2599566063dSJacob Faibussowitsch PetscCall(VecSetType(v, VECSTANDARD)); 260c2fc9fa9SBarry Smith *newv = v; 2613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 262c2fc9fa9SBarry Smith } 263c2fc9fa9SBarry Smith 264c2fc9fa9SBarry Smith /* Resets the snes PC and KSP when the active set sizes change */ 265*ba38deedSJacob Faibussowitsch static PetscErrorCode SNESVIResetPCandKSP(SNES snes, Mat Amat, Mat Pmat) 266d71ae5a4SJacob Faibussowitsch { 267c2fc9fa9SBarry Smith KSP snesksp; 268c2fc9fa9SBarry Smith 269c2fc9fa9SBarry Smith PetscFunctionBegin; 2709566063dSJacob Faibussowitsch PetscCall(SNESGetKSP(snes, &snesksp)); 2719566063dSJacob Faibussowitsch PetscCall(KSPReset(snesksp)); 2729566063dSJacob Faibussowitsch PetscCall(KSPResetFromOptions(snesksp)); 273c2fc9fa9SBarry Smith 274c2fc9fa9SBarry Smith /* 275c2fc9fa9SBarry Smith KSP kspnew; 276c2fc9fa9SBarry Smith PC pcnew; 277ea799195SBarry Smith MatSolverType stype; 278c2fc9fa9SBarry Smith 2799566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)snes),&kspnew)); 280c2fc9fa9SBarry Smith kspnew->pc_side = snesksp->pc_side; 281c2fc9fa9SBarry Smith kspnew->rtol = snesksp->rtol; 282c2fc9fa9SBarry Smith kspnew->abstol = snesksp->abstol; 283c2fc9fa9SBarry Smith kspnew->max_it = snesksp->max_it; 2849566063dSJacob Faibussowitsch PetscCall(KSPSetType(kspnew,((PetscObject)snesksp)->type_name)); 2859566063dSJacob Faibussowitsch PetscCall(KSPGetPC(kspnew,&pcnew)); 2869566063dSJacob Faibussowitsch PetscCall(PCSetType(kspnew->pc,((PetscObject)snesksp->pc)->type_name)); 2879566063dSJacob Faibussowitsch PetscCall(PCSetOperators(kspnew->pc,Amat,Pmat)); 2889566063dSJacob Faibussowitsch PetscCall(PCFactorGetMatSolverType(snesksp->pc,&stype)); 2899566063dSJacob Faibussowitsch PetscCall(PCFactorSetMatSolverType(kspnew->pc,stype)); 2909566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&snesksp)); 291c2fc9fa9SBarry Smith snes->ksp = kspnew; 2929566063dSJacob Faibussowitsch PetscCall(KSPSetFromOptions(kspnew));*/ 2933ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 294c2fc9fa9SBarry Smith } 295c2fc9fa9SBarry Smith 296c2fc9fa9SBarry Smith /* Variational Inequality solver using reduce space method. No semismooth algorithm is 297c2fc9fa9SBarry Smith implemented in this algorithm. It basically identifies the active constraints and does 298c2fc9fa9SBarry Smith a linear solve on the other variables (those not associated with the active constraints). */ 299*ba38deedSJacob Faibussowitsch static PetscErrorCode SNESSolve_VINEWTONRSLS(SNES snes) 300d71ae5a4SJacob Faibussowitsch { 301f450aa47SBarry Smith SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data; 302c2fc9fa9SBarry Smith PetscInt maxits, i, lits; 303422a814eSBarry Smith SNESLineSearchReason lssucceed; 304c2fc9fa9SBarry Smith PetscReal fnorm, gnorm, xnorm = 0, ynorm; 3059bd66eb0SPeter Brune Vec Y, X, F; 306c2fc9fa9SBarry Smith KSPConvergedReason kspreason; 30792e89061SBarry Smith KSP ksp; 30892e89061SBarry Smith PC pc; 309c2fc9fa9SBarry Smith 310c2fc9fa9SBarry Smith PetscFunctionBegin; 31192e89061SBarry Smith /* Multigrid must use Galerkin for coarse grids with active set/reduced space methods; cannot rediscretize on coarser grids*/ 3129566063dSJacob Faibussowitsch PetscCall(SNESGetKSP(snes, &ksp)); 3139566063dSJacob Faibussowitsch PetscCall(KSPGetPC(ksp, &pc)); 3149566063dSJacob Faibussowitsch PetscCall(PCMGSetGalerkin(pc, PC_MG_GALERKIN_BOTH)); 31592e89061SBarry Smith 316c2fc9fa9SBarry Smith snes->numFailures = 0; 317c2fc9fa9SBarry Smith snes->numLinearSolveFailures = 0; 318c2fc9fa9SBarry Smith snes->reason = SNES_CONVERGED_ITERATING; 319c2fc9fa9SBarry Smith 320c2fc9fa9SBarry Smith maxits = snes->max_its; /* maximum number of iterations */ 321c2fc9fa9SBarry Smith X = snes->vec_sol; /* solution vector */ 322c2fc9fa9SBarry Smith F = snes->vec_func; /* residual vector */ 323c2fc9fa9SBarry Smith Y = snes->work[0]; /* work vectors */ 3249bd66eb0SPeter Brune 3259566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetVIFunctions(snes->linesearch, SNESVIProjectOntoBounds, SNESVIComputeInactiveSetFnorm)); 3269566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetVecs(snes->linesearch, X, NULL, NULL, NULL, NULL)); 3279566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetUp(snes->linesearch)); 328c2fc9fa9SBarry Smith 3299566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 330c2fc9fa9SBarry Smith snes->iter = 0; 331c2fc9fa9SBarry Smith snes->norm = 0.0; 3329566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 333c2fc9fa9SBarry Smith 3349566063dSJacob Faibussowitsch PetscCall(SNESVIProjectOntoBounds(snes, X)); 3359566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, X, F)); 3369566063dSJacob Faibussowitsch PetscCall(SNESVIComputeInactiveSetFnorm(snes, F, X, &fnorm)); 3379566063dSJacob Faibussowitsch PetscCall(VecNorm(X, NORM_2, &xnorm)); /* xnorm <- ||x|| */ 338422a814eSBarry Smith SNESCheckFunctionNorm(snes, fnorm); 3399566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 340c2fc9fa9SBarry Smith snes->norm = fnorm; 3419566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 3429566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes, fnorm, 0)); 343c2fc9fa9SBarry Smith 344c2fc9fa9SBarry Smith /* test convergence */ 3452d157150SStefano Zampini PetscCall(SNESConverged(snes, 0, 0.0, 0.0, fnorm)); 3462d157150SStefano Zampini PetscCall(SNESMonitor(snes, 0, fnorm)); 3473ba16761SJacob Faibussowitsch if (snes->reason) PetscFunctionReturn(PETSC_SUCCESS); 348c2fc9fa9SBarry Smith 349c2fc9fa9SBarry Smith for (i = 0; i < maxits; i++) { 350f009fc93SPatrick Farrell IS IS_act; /* _act -> active set _inact -> inactive set */ 351c2fc9fa9SBarry Smith IS IS_redact; /* redundant active set */ 352c2fc9fa9SBarry Smith VecScatter scat_act, scat_inact; 353c2fc9fa9SBarry Smith PetscInt nis_act, nis_inact; 354c2fc9fa9SBarry Smith Vec Y_act, Y_inact, F_inact; 355c2fc9fa9SBarry Smith Mat jac_inact_inact, prejac_inact_inact; 356c2fc9fa9SBarry Smith PetscBool isequal; 357c2fc9fa9SBarry Smith 358c2fc9fa9SBarry Smith /* Call general purpose update function */ 359dbbe0bcdSBarry Smith PetscTryTypeMethod(snes, update, snes->iter); 3609566063dSJacob Faibussowitsch PetscCall(SNESComputeJacobian(snes, X, snes->jacobian, snes->jacobian_pre)); 36107b62357SFande Kong SNESCheckJacobianDomainerror(snes); 362c2fc9fa9SBarry Smith 363c2fc9fa9SBarry Smith /* Create active and inactive index sets */ 364c2fc9fa9SBarry Smith 365c2fc9fa9SBarry Smith /*original 3669566063dSJacob Faibussowitsch PetscCall(SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&vi->IS_inact)); 367c2fc9fa9SBarry Smith */ 3689566063dSJacob Faibussowitsch PetscCall(SNESVIGetActiveSetIS(snes, X, F, &IS_act)); 369c2fc9fa9SBarry Smith 370c2fc9fa9SBarry Smith if (vi->checkredundancy) { 3719566063dSJacob Faibussowitsch PetscCall((*vi->checkredundancy)(snes, IS_act, &IS_redact, vi->ctxP)); 372c2fc9fa9SBarry Smith if (IS_redact) { 3739566063dSJacob Faibussowitsch PetscCall(ISSort(IS_redact)); 3749566063dSJacob Faibussowitsch PetscCall(ISComplement(IS_redact, X->map->rstart, X->map->rend, &vi->IS_inact)); 3759566063dSJacob Faibussowitsch PetscCall(ISDestroy(&IS_redact)); 3761aa26658SKarl Rupp } else { 3779566063dSJacob Faibussowitsch PetscCall(ISComplement(IS_act, X->map->rstart, X->map->rend, &vi->IS_inact)); 378c2fc9fa9SBarry Smith } 379c2fc9fa9SBarry Smith } else { 3809566063dSJacob Faibussowitsch PetscCall(ISComplement(IS_act, X->map->rstart, X->map->rend, &vi->IS_inact)); 381c2fc9fa9SBarry Smith } 382c2fc9fa9SBarry Smith 383c2fc9fa9SBarry Smith /* Create inactive set submatrix */ 3849566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(snes->jacobian, vi->IS_inact, vi->IS_inact, MAT_INITIAL_MATRIX, &jac_inact_inact)); 385c2fc9fa9SBarry Smith 38666bfb381SJed Brown if (0) { /* Dead code (temporary developer hack) */ 38766bfb381SJed Brown IS keptrows; 3889566063dSJacob Faibussowitsch PetscCall(MatFindNonzeroRows(jac_inact_inact, &keptrows)); 38966bfb381SJed Brown if (keptrows) { 390c2fc9fa9SBarry Smith PetscInt cnt, *nrows, k; 391c2fc9fa9SBarry Smith const PetscInt *krows, *inact; 392367daffbSBarry Smith PetscInt rstart; 393c2fc9fa9SBarry Smith 3949566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(jac_inact_inact, &rstart, NULL)); 3959566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac_inact_inact)); 3969566063dSJacob Faibussowitsch PetscCall(ISDestroy(&IS_act)); 397c2fc9fa9SBarry Smith 3989566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(keptrows, &cnt)); 3999566063dSJacob Faibussowitsch PetscCall(ISGetIndices(keptrows, &krows)); 4009566063dSJacob Faibussowitsch PetscCall(ISGetIndices(vi->IS_inact, &inact)); 4019566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(cnt, &nrows)); 4021aa26658SKarl Rupp for (k = 0; k < cnt; k++) nrows[k] = inact[krows[k] - rstart]; 4039566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(keptrows, &krows)); 4049566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(vi->IS_inact, &inact)); 4059566063dSJacob Faibussowitsch PetscCall(ISDestroy(&keptrows)); 4069566063dSJacob Faibussowitsch PetscCall(ISDestroy(&vi->IS_inact)); 407c2fc9fa9SBarry Smith 4089566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)snes), cnt, nrows, PETSC_OWN_POINTER, &vi->IS_inact)); 4099566063dSJacob Faibussowitsch PetscCall(ISComplement(vi->IS_inact, F->map->rstart, F->map->rend, &IS_act)); 4109566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(snes->jacobian, vi->IS_inact, vi->IS_inact, MAT_INITIAL_MATRIX, &jac_inact_inact)); 411c2fc9fa9SBarry Smith } 41266bfb381SJed Brown } 4139566063dSJacob Faibussowitsch PetscCall(DMSetVI(snes->dm, vi->IS_inact)); 414c2fc9fa9SBarry Smith /* remove later */ 415c2fc9fa9SBarry Smith 416c2fc9fa9SBarry Smith /* 4179566063dSJacob Faibussowitsch PetscCall(VecView(vi->xu,PETSC_VIEWER_BINARY_(((PetscObject)(vi->xu))->comm))); 4189566063dSJacob Faibussowitsch PetscCall(VecView(vi->xl,PETSC_VIEWER_BINARY_(((PetscObject)(vi->xl))->comm))); 4199566063dSJacob Faibussowitsch PetscCall(VecView(X,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)X)))); 4209566063dSJacob Faibussowitsch PetscCall(VecView(F,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)F)))); 4219566063dSJacob Faibussowitsch PetscCall(ISView(vi->IS_inact,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)vi->IS_inact)))); 422c2fc9fa9SBarry Smith */ 423c2fc9fa9SBarry Smith 424c2fc9fa9SBarry Smith /* Get sizes of active and inactive sets */ 4259566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(IS_act, &nis_act)); 4269566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vi->IS_inact, &nis_inact)); 427c2fc9fa9SBarry Smith 428c2fc9fa9SBarry Smith /* Create active and inactive set vectors */ 4299566063dSJacob Faibussowitsch PetscCall(SNESCreateSubVectors_VINEWTONRSLS(snes, nis_inact, &F_inact)); 4309566063dSJacob Faibussowitsch PetscCall(SNESCreateSubVectors_VINEWTONRSLS(snes, nis_act, &Y_act)); 4319566063dSJacob Faibussowitsch PetscCall(SNESCreateSubVectors_VINEWTONRSLS(snes, nis_inact, &Y_inact)); 432c2fc9fa9SBarry Smith 433c2fc9fa9SBarry Smith /* Create scatter contexts */ 4349566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(Y, IS_act, Y_act, NULL, &scat_act)); 4359566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(Y, vi->IS_inact, Y_inact, NULL, &scat_inact)); 436c2fc9fa9SBarry Smith 437c2fc9fa9SBarry Smith /* Do a vec scatter to active and inactive set vectors */ 4389566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(scat_inact, F, F_inact, INSERT_VALUES, SCATTER_FORWARD)); 4399566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(scat_inact, F, F_inact, INSERT_VALUES, SCATTER_FORWARD)); 440c2fc9fa9SBarry Smith 4419566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(scat_act, Y, Y_act, INSERT_VALUES, SCATTER_FORWARD)); 4429566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(scat_act, Y, Y_act, INSERT_VALUES, SCATTER_FORWARD)); 443c2fc9fa9SBarry Smith 4449566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(scat_inact, Y, Y_inact, INSERT_VALUES, SCATTER_FORWARD)); 4459566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(scat_inact, Y, Y_inact, INSERT_VALUES, SCATTER_FORWARD)); 446c2fc9fa9SBarry Smith 447c2fc9fa9SBarry Smith /* Active set direction = 0 */ 4489566063dSJacob Faibussowitsch PetscCall(VecSet(Y_act, 0)); 449c2fc9fa9SBarry Smith if (snes->jacobian != snes->jacobian_pre) { 4509566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(snes->jacobian_pre, vi->IS_inact, vi->IS_inact, MAT_INITIAL_MATRIX, &prejac_inact_inact)); 451c2fc9fa9SBarry Smith } else prejac_inact_inact = jac_inact_inact; 452c2fc9fa9SBarry Smith 4539566063dSJacob Faibussowitsch PetscCall(ISEqual(vi->IS_inact_prev, vi->IS_inact, &isequal)); 454c2fc9fa9SBarry Smith if (!isequal) { 4559566063dSJacob Faibussowitsch PetscCall(SNESVIResetPCandKSP(snes, jac_inact_inact, prejac_inact_inact)); 4569566063dSJacob Faibussowitsch PetscCall(PCFieldSplitRestrictIS(pc, vi->IS_inact)); 457c2fc9fa9SBarry Smith } 458c2fc9fa9SBarry Smith 4599566063dSJacob Faibussowitsch /* PetscCall(ISView(vi->IS_inact,0)); */ 4609566063dSJacob Faibussowitsch /* PetscCall(ISView(IS_act,0));*/ 461c2fc9fa9SBarry Smith /* ierr = MatView(snes->jacobian_pre,0); */ 462c2fc9fa9SBarry Smith 4639566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(snes->ksp, jac_inact_inact, prejac_inact_inact)); 4649566063dSJacob Faibussowitsch PetscCall(KSPSetUp(snes->ksp)); 465c2fc9fa9SBarry Smith { 466c2fc9fa9SBarry Smith PC pc; 467c2fc9fa9SBarry Smith PetscBool flg; 4689566063dSJacob Faibussowitsch PetscCall(KSPGetPC(snes->ksp, &pc)); 4699566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &flg)); 470c2fc9fa9SBarry Smith if (flg) { 471c2fc9fa9SBarry Smith KSP *subksps; 4729566063dSJacob Faibussowitsch PetscCall(PCFieldSplitGetSubKSP(pc, NULL, &subksps)); 4739566063dSJacob Faibussowitsch PetscCall(KSPGetPC(subksps[0], &pc)); 4749566063dSJacob Faibussowitsch PetscCall(PetscFree(subksps)); 4759566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCBJACOBI, &flg)); 476c2fc9fa9SBarry Smith if (flg) { 477c2fc9fa9SBarry Smith PetscInt n, N = 101 * 101, j, cnts[3] = {0, 0, 0}; 478c2fc9fa9SBarry Smith const PetscInt *ii; 479c2fc9fa9SBarry Smith 4809566063dSJacob Faibussowitsch PetscCall(ISGetSize(vi->IS_inact, &n)); 4819566063dSJacob Faibussowitsch PetscCall(ISGetIndices(vi->IS_inact, &ii)); 482c2fc9fa9SBarry Smith for (j = 0; j < n; j++) { 483c2fc9fa9SBarry Smith if (ii[j] < N) cnts[0]++; 484c2fc9fa9SBarry Smith else if (ii[j] < 2 * N) cnts[1]++; 485c2fc9fa9SBarry Smith else if (ii[j] < 3 * N) cnts[2]++; 486c2fc9fa9SBarry Smith } 4879566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(vi->IS_inact, &ii)); 488c2fc9fa9SBarry Smith 4899566063dSJacob Faibussowitsch PetscCall(PCBJacobiSetTotalBlocks(pc, 3, cnts)); 490c2fc9fa9SBarry Smith } 491c2fc9fa9SBarry Smith } 492c2fc9fa9SBarry Smith } 493c2fc9fa9SBarry Smith 4949566063dSJacob Faibussowitsch PetscCall(KSPSolve(snes->ksp, F_inact, Y_inact)); 4959566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(scat_act, Y_act, Y, INSERT_VALUES, SCATTER_REVERSE)); 4969566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(scat_act, Y_act, Y, INSERT_VALUES, SCATTER_REVERSE)); 4979566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(scat_inact, Y_inact, Y, INSERT_VALUES, SCATTER_REVERSE)); 4989566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(scat_inact, Y_inact, Y, INSERT_VALUES, SCATTER_REVERSE)); 499c2fc9fa9SBarry Smith 5009566063dSJacob Faibussowitsch PetscCall(VecDestroy(&F_inact)); 5019566063dSJacob Faibussowitsch PetscCall(VecDestroy(&Y_act)); 5029566063dSJacob Faibussowitsch PetscCall(VecDestroy(&Y_inact)); 5039566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&scat_act)); 5049566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&scat_inact)); 5059566063dSJacob Faibussowitsch PetscCall(ISDestroy(&IS_act)); 506c2fc9fa9SBarry Smith if (!isequal) { 5079566063dSJacob Faibussowitsch PetscCall(ISDestroy(&vi->IS_inact_prev)); 5089566063dSJacob Faibussowitsch PetscCall(ISDuplicate(vi->IS_inact, &vi->IS_inact_prev)); 509c2fc9fa9SBarry Smith } 5109566063dSJacob Faibussowitsch PetscCall(ISDestroy(&vi->IS_inact)); 5119566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac_inact_inact)); 51248a46eb9SPierre Jolivet if (snes->jacobian != snes->jacobian_pre) PetscCall(MatDestroy(&prejac_inact_inact)); 513fa6eefd1SCian Wilson 5149566063dSJacob Faibussowitsch PetscCall(KSPGetConvergedReason(snes->ksp, &kspreason)); 515fa6eefd1SCian Wilson if (kspreason < 0) { 516fa6eefd1SCian Wilson if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { 51763a3b9bcSJacob 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)); 518fa6eefd1SCian Wilson snes->reason = SNES_DIVERGED_LINEAR_SOLVE; 519fa6eefd1SCian Wilson break; 520fa6eefd1SCian Wilson } 521fa6eefd1SCian Wilson } 522fa6eefd1SCian Wilson 5239566063dSJacob Faibussowitsch PetscCall(KSPGetIterationNumber(snes->ksp, &lits)); 524c2fc9fa9SBarry Smith snes->linear_its += lits; 52563a3b9bcSJacob Faibussowitsch PetscCall(PetscInfo(snes, "iter=%" PetscInt_FMT ", linear solve iterations=%" PetscInt_FMT "\n", snes->iter, lits)); 526c2fc9fa9SBarry Smith /* 5276b2b7091SBarry Smith if (snes->ops->precheck) { 528c2fc9fa9SBarry Smith PetscBool changed_y = PETSC_FALSE; 529dbbe0bcdSBarry Smith PetscUseTypeMethod(snes,precheck ,X,Y,snes->precheck,&changed_y); 530c2fc9fa9SBarry Smith } 531c2fc9fa9SBarry Smith 5321baa6e33SBarry Smith if (PetscLogPrintInfo) PetscCall(SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W)); 533c2fc9fa9SBarry Smith */ 534c2fc9fa9SBarry Smith /* Compute a (scaled) negative update in the line search routine: 535c2fc9fa9SBarry Smith Y <- X - lambda*Y 536c2fc9fa9SBarry Smith and evaluate G = function(Y) (depends on the line search). 537c2fc9fa9SBarry Smith */ 5389566063dSJacob Faibussowitsch PetscCall(VecCopy(Y, snes->vec_sol_update)); 5399371c9d4SSatish Balay ynorm = 1; 5409371c9d4SSatish Balay gnorm = fnorm; 5419566063dSJacob Faibussowitsch PetscCall(SNESLineSearchApply(snes->linesearch, X, F, &gnorm, Y)); 5429566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetReason(snes->linesearch, &lssucceed)); 5439566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetNorms(snes->linesearch, &xnorm, &gnorm, &ynorm)); 5449566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes, "fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n", (double)fnorm, (double)gnorm, (double)ynorm, (int)lssucceed)); 545c2fc9fa9SBarry Smith if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; 546c2fc9fa9SBarry Smith if (snes->domainerror) { 547c2fc9fa9SBarry Smith snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 5489566063dSJacob Faibussowitsch PetscCall(DMDestroyVI(snes->dm)); 5493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 550c2fc9fa9SBarry Smith } 551422a814eSBarry Smith if (lssucceed) { 552c2fc9fa9SBarry Smith if (++snes->numFailures >= snes->maxFailures) { 553c2fc9fa9SBarry Smith PetscBool ismin; 554c2fc9fa9SBarry Smith snes->reason = SNES_DIVERGED_LINE_SEARCH; 5559566063dSJacob Faibussowitsch PetscCall(SNESVICheckLocalMin_Private(snes, snes->jacobian, F, X, gnorm, &ismin)); 556c2fc9fa9SBarry Smith if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; 557c2fc9fa9SBarry Smith break; 558c2fc9fa9SBarry Smith } 559c2fc9fa9SBarry Smith } 5609566063dSJacob Faibussowitsch PetscCall(DMDestroyVI(snes->dm)); 561c2fc9fa9SBarry Smith /* Update function and solution vectors */ 562c2fc9fa9SBarry Smith fnorm = gnorm; 563c2fc9fa9SBarry Smith /* Monitor convergence */ 5649566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 565c2fc9fa9SBarry Smith snes->iter = i + 1; 566c2fc9fa9SBarry Smith snes->norm = fnorm; 567c1e67a49SFande Kong snes->xnorm = xnorm; 568c1e67a49SFande Kong snes->ynorm = ynorm; 5699566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 5709566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes, snes->norm, lits)); 571c2fc9fa9SBarry Smith /* Test for convergence, xnorm = || X || */ 5729566063dSJacob Faibussowitsch if (snes->ops->converged != SNESConvergedSkip) PetscCall(VecNorm(X, NORM_2, &xnorm)); 5732d157150SStefano Zampini PetscCall(SNESConverged(snes, snes->iter, xnorm, ynorm, fnorm)); 5742d157150SStefano Zampini PetscCall(SNESMonitor(snes, snes->iter, snes->norm)); 575c2fc9fa9SBarry Smith if (snes->reason) break; 576c2fc9fa9SBarry Smith } 57791a42fcfSBarry 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 */ 5789566063dSJacob Faibussowitsch PetscCall(DMDestroyVI(snes->dm)); 5793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 580c2fc9fa9SBarry Smith } 581c2fc9fa9SBarry Smith 582f6dfbefdSBarry Smith /*@C 583f6dfbefdSBarry Smith SNESVISetRedundancyCheck - Provide a function to check for any redundancy in the VI active set 584f6dfbefdSBarry Smith 585c3339decSBarry Smith Logically Collective 586f6dfbefdSBarry Smith 587f6dfbefdSBarry Smith Input Parameters: 588f6dfbefdSBarry Smith + snes - the `SNESVINEWTONRSLS` context 589f6dfbefdSBarry Smith . func - the function to check of redundancies 590f6dfbefdSBarry Smith - ctx - optional context used by the function 591f6dfbefdSBarry Smith 592f6dfbefdSBarry Smith Level: advanced 593f6dfbefdSBarry Smith 594f6dfbefdSBarry Smith Note: 595f6dfbefdSBarry Smith Sometimes the inactive set will result in a non-singular sub-Jacobian problem that needs to be solved, this allows the user, 596f6dfbefdSBarry Smith when they know more about their specific problem to provide a function that removes the redundancy that results in the singular linear system 597f6dfbefdSBarry Smith 598f6dfbefdSBarry Smith .seealso: `SNESVINEWTONRSLS`, `SNESVIGetInactiveSet()`, `DMSetVI()` 599f6dfbefdSBarry Smith @*/ 600d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESVISetRedundancyCheck(SNES snes, PetscErrorCode (*func)(SNES, IS, IS *, void *), void *ctx) 601d71ae5a4SJacob Faibussowitsch { 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; 6083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 609c2fc9fa9SBarry Smith } 610c2fc9fa9SBarry Smith 611d1e78c4fSBarry Smith #if defined(PETSC_HAVE_MATLAB) 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 619d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESVIRedundancyCheck_Matlab(SNES snes, IS is_act, IS *is_redact, void *ctx) 620d71ae5a4SJacob Faibussowitsch { 621c2fc9fa9SBarry Smith SNESMatlabContext *sctx = (SNESMatlabContext *)ctx; 622c2fc9fa9SBarry Smith int nlhs = 1, nrhs = 5; 623c2fc9fa9SBarry Smith mxArray *plhs[1], *prhs[5]; 624c2fc9fa9SBarry Smith long long int l1 = 0, l2 = 0, ls = 0; 6250298fd71SBarry Smith PetscInt *indices = NULL; 626c2fc9fa9SBarry Smith 627c2fc9fa9SBarry Smith PetscFunctionBegin; 628c2fc9fa9SBarry Smith PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 629c2fc9fa9SBarry Smith PetscValidHeaderSpecific(is_act, IS_CLASSID, 2); 6304f572ea9SToby Isaac PetscAssertPointer(is_redact, 3); 631c2fc9fa9SBarry Smith PetscCheckSameComm(snes, 1, is_act, 2); 632c2fc9fa9SBarry Smith 633c2fc9fa9SBarry Smith /* Create IS for reduced active set of size 0, its size and indices will 634c2fc9fa9SBarry Smith bet set by the Matlab function */ 6359566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)snes), 0, indices, PETSC_OWN_POINTER, is_redact)); 636c2fc9fa9SBarry Smith /* call Matlab function in ctx */ 6379566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(&ls, &snes, 1)); 6389566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(&l1, &is_act, 1)); 6399566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(&l2, is_redact, 1)); 640c2fc9fa9SBarry Smith prhs[0] = mxCreateDoubleScalar((double)ls); 641c2fc9fa9SBarry Smith prhs[1] = mxCreateDoubleScalar((double)l1); 642c2fc9fa9SBarry Smith prhs[2] = mxCreateDoubleScalar((double)l2); 643c2fc9fa9SBarry Smith prhs[3] = mxCreateString(sctx->funcname); 644c2fc9fa9SBarry Smith prhs[4] = sctx->ctx; 6459566063dSJacob Faibussowitsch PetscCall(mexCallMATLAB(nlhs, plhs, nrhs, prhs, "PetscSNESVIRedundancyCheckInternal")); 6469566063dSJacob Faibussowitsch PetscCall(mxGetScalar(plhs[0])); 647c2fc9fa9SBarry Smith mxDestroyArray(prhs[0]); 648c2fc9fa9SBarry Smith mxDestroyArray(prhs[1]); 649c2fc9fa9SBarry Smith mxDestroyArray(prhs[2]); 650c2fc9fa9SBarry Smith mxDestroyArray(prhs[3]); 651c2fc9fa9SBarry Smith mxDestroyArray(plhs[0]); 6523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 653c2fc9fa9SBarry Smith } 654c2fc9fa9SBarry Smith 655d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESVISetRedundancyCheckMatlab(SNES snes, const char *func, mxArray *ctx) 656d71ae5a4SJacob Faibussowitsch { 657c2fc9fa9SBarry Smith SNESMatlabContext *sctx; 658c2fc9fa9SBarry Smith 659c2fc9fa9SBarry Smith PetscFunctionBegin; 660c2fc9fa9SBarry Smith /* currently sctx is memory bleed */ 6619566063dSJacob Faibussowitsch PetscCall(PetscNew(&sctx)); 6629566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(func, &sctx->funcname)); 663c2fc9fa9SBarry Smith sctx->ctx = mxDuplicateArray(ctx); 6649566063dSJacob Faibussowitsch PetscCall(SNESVISetRedundancyCheck(snes, SNESVIRedundancyCheck_Matlab, sctx)); 6653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 666c2fc9fa9SBarry Smith } 667c2fc9fa9SBarry Smith 668c2fc9fa9SBarry Smith #endif 669c2fc9fa9SBarry Smith 670*ba38deedSJacob Faibussowitsch static PetscErrorCode SNESSetUp_VINEWTONRSLS(SNES snes) 671d71ae5a4SJacob Faibussowitsch { 672f450aa47SBarry Smith SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data; 673c2fc9fa9SBarry Smith PetscInt *indices; 674c2fc9fa9SBarry Smith PetscInt i, n, rstart, rend; 675f1c6b773SPeter Brune SNESLineSearch linesearch; 676c2fc9fa9SBarry Smith 677c2fc9fa9SBarry Smith PetscFunctionBegin; 6789566063dSJacob Faibussowitsch PetscCall(SNESSetUp_VI(snes)); 679c2fc9fa9SBarry Smith 680c2fc9fa9SBarry Smith /* Set up previous active index set for the first snes solve 681c2fc9fa9SBarry Smith vi->IS_inact_prev = 0,1,2,....N */ 682c2fc9fa9SBarry Smith 6839566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(snes->vec_sol, &rstart, &rend)); 6849566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(snes->vec_sol, &n)); 6859566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &indices)); 686c2fc9fa9SBarry Smith for (i = 0; i < n; i++) indices[i] = rstart + i; 6879566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)snes), n, indices, PETSC_OWN_POINTER, &vi->IS_inact_prev)); 6889bd66eb0SPeter Brune 6899bd66eb0SPeter Brune /* set the line search functions */ 6909bd66eb0SPeter Brune if (!snes->linesearch) { 6919566063dSJacob Faibussowitsch PetscCall(SNESGetLineSearch(snes, &linesearch)); 6929566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBT)); 6939bd66eb0SPeter Brune } 6943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 695c2fc9fa9SBarry Smith } 696f6dfbefdSBarry Smith 697*ba38deedSJacob Faibussowitsch static PetscErrorCode SNESReset_VINEWTONRSLS(SNES snes) 698d71ae5a4SJacob Faibussowitsch { 699f450aa47SBarry Smith SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS *)snes->data; 700c2fc9fa9SBarry Smith 701c2fc9fa9SBarry Smith PetscFunctionBegin; 7029566063dSJacob Faibussowitsch PetscCall(SNESReset_VI(snes)); 7039566063dSJacob Faibussowitsch PetscCall(ISDestroy(&vi->IS_inact_prev)); 7043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 705c2fc9fa9SBarry Smith } 706c2fc9fa9SBarry Smith 707c2fc9fa9SBarry Smith /*MC 708f450aa47SBarry Smith SNESVINEWTONRSLS - Reduced space active set solvers for variational inequalities based on Newton's method 709c2fc9fa9SBarry Smith 710f6dfbefdSBarry Smith Options Database Keys: 711b621fa8fSRichard Tran Mills + -snes_type <vinewtonssls,vinewtonrsls> - a semi-smooth solver, a reduced space active set method 71261589011SJed Brown - -snes_vi_monitor - prints the number of active constraints at each iteration. 713c2fc9fa9SBarry Smith 714c2fc9fa9SBarry Smith Level: beginner 715c2fc9fa9SBarry Smith 716b80f3ac1SShri Abhyankar References: 717606c0280SSatish Balay . * - T. S. Munson, and S. Benson. Flexible Complementarity Solvers for Large Scale 718b80f3ac1SShri Abhyankar Applications, Optimization Methods and Software, 21 (2006). 719b80f3ac1SShri Abhyankar 720f6dfbefdSBarry Smith Note: 721f6dfbefdSBarry Smith At each set of this methods the algorithm produces an inactive set of variables that are constrained to their current values 722f6dfbefdSBarry Smith (because changing these values would result in those variables no longer satisfying the inequality constraints) 723f6dfbefdSBarry Smith and produces a step direction by solving the linear system arising from the Jacobian with the inactive variables removed. In other 724f6dfbefdSBarry 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. 725c2fc9fa9SBarry Smith 7264a221d59SStefano Zampini .seealso: `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESVINEWTONSSLS`, `SNESNEWTONTR`, `SNESLineSearchSetType()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESVIGetInactiveSet()`, `DMSetVI()`, `SNESVISetRedundancyCheck()` 727c2fc9fa9SBarry Smith M*/ 728d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode SNESCreate_VINEWTONRSLS(SNES snes) 729d71ae5a4SJacob Faibussowitsch { 730f450aa47SBarry Smith SNES_VINEWTONRSLS *vi; 731d8d34be6SBarry Smith SNESLineSearch linesearch; 732c2fc9fa9SBarry Smith 733c2fc9fa9SBarry Smith PetscFunctionBegin; 734f450aa47SBarry Smith snes->ops->reset = SNESReset_VINEWTONRSLS; 735f450aa47SBarry Smith snes->ops->setup = SNESSetUp_VINEWTONRSLS; 736f450aa47SBarry Smith snes->ops->solve = SNESSolve_VINEWTONRSLS; 737c2fc9fa9SBarry Smith snes->ops->destroy = SNESDestroy_VI; 738c2fc9fa9SBarry Smith snes->ops->setfromoptions = SNESSetFromOptions_VI; 7390298fd71SBarry Smith snes->ops->view = NULL; 7408d359177SBarry Smith snes->ops->converged = SNESConvergedDefault_VI; 741c2fc9fa9SBarry Smith 742c2fc9fa9SBarry Smith snes->usesksp = PETSC_TRUE; 743efd4aadfSBarry Smith snes->usesnpc = PETSC_FALSE; 744c2fc9fa9SBarry Smith 7459566063dSJacob Faibussowitsch PetscCall(SNESGetLineSearch(snes, &linesearch)); 74648a46eb9SPierre Jolivet if (!((PetscObject)linesearch)->type_name) PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBT)); 7479566063dSJacob Faibussowitsch PetscCall(SNESLineSearchBTSetAlpha(linesearch, 0.0)); 748d8d34be6SBarry Smith 7494fc747eaSLawrence Mitchell snes->alwayscomputesfinalresidual = PETSC_TRUE; 7504fc747eaSLawrence Mitchell 7514dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&vi)); 752c2fc9fa9SBarry Smith snes->data = (void *)vi; 7530298fd71SBarry Smith vi->checkredundancy = NULL; 754c2fc9fa9SBarry Smith 7559566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESVISetVariableBounds_C", SNESVISetVariableBounds_VI)); 7569566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESVISetComputeVariableBounds_C", SNESVISetComputeVariableBounds_VI)); 7573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 758c2fc9fa9SBarry Smith } 759