113a62661SPeter Brune #include <../src/snes/impls/ngmres/snesngmres.h> /*I "petscsnes.h" I*/ 219653cdaSPeter Brune #include <petscblaslapack.h> 3fced5a79SAsbjørn Nilsen Riseth #include <petscdm.h> 4a312c225SMatthew G Knepley 59e5d0892SLisandro Dalcin const char *const SNESNGMRESRestartTypes[] = {"NONE","PERIODIC","DIFFERENCE","SNESNGMRESRestartType","SNES_NGMRES_RESTART_",NULL}; 69e5d0892SLisandro Dalcin const char *const SNESNGMRESSelectTypes[] = {"NONE","DIFFERENCE","LINESEARCH","SNESNGMRESSelectType","SNES_NGMRES_SELECT_",NULL}; 713a62661SPeter Brune 8a312c225SMatthew G Knepley PetscErrorCode SNESReset_NGMRES(SNES snes) 9a312c225SMatthew G Knepley { 10a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data; 11a312c225SMatthew G Knepley 12a312c225SMatthew G Knepley PetscFunctionBegin; 139566063dSJacob Faibussowitsch PetscCall(VecDestroyVecs(ngmres->msize,&ngmres->Fdot)); 149566063dSJacob Faibussowitsch PetscCall(VecDestroyVecs(ngmres->msize,&ngmres->Xdot)); 159566063dSJacob Faibussowitsch PetscCall(SNESLineSearchDestroy(&ngmres->additive_linesearch)); 16a312c225SMatthew G Knepley PetscFunctionReturn(0); 17a312c225SMatthew G Knepley } 18a312c225SMatthew G Knepley 19a312c225SMatthew G Knepley PetscErrorCode SNESDestroy_NGMRES(SNES snes) 20a312c225SMatthew G Knepley { 2178440776SJed Brown SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data; 22a312c225SMatthew G Knepley 23a312c225SMatthew G Knepley PetscFunctionBegin; 249566063dSJacob Faibussowitsch PetscCall(SNESReset_NGMRES(snes)); 259566063dSJacob Faibussowitsch PetscCall(PetscFree4(ngmres->h,ngmres->beta,ngmres->xi,ngmres->q)); 269566063dSJacob Faibussowitsch PetscCall(PetscFree3(ngmres->xnorms,ngmres->fnorms,ngmres->s)); 27dd63322aSSatish Balay #if defined(PETSC_USE_COMPLEX) 289566063dSJacob Faibussowitsch PetscCall(PetscFree(ngmres->rwork)); 2919653cdaSPeter Brune #endif 309566063dSJacob Faibussowitsch PetscCall(PetscFree(ngmres->work)); 319566063dSJacob Faibussowitsch PetscCall(PetscFree(snes->data)); 32a312c225SMatthew G Knepley PetscFunctionReturn(0); 33a312c225SMatthew G Knepley } 34a312c225SMatthew G Knepley 35a312c225SMatthew G Knepley PetscErrorCode SNESSetUp_NGMRES(SNES snes) 36a312c225SMatthew G Knepley { 37a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data; 38e7058c64SPeter Brune const char *optionsprefix; 3919653cdaSPeter Brune PetscInt msize,hsize; 40fced5a79SAsbjørn Nilsen Riseth DM dm; 41a312c225SMatthew G Knepley 42a312c225SMatthew G Knepley PetscFunctionBegin; 43efd4aadfSBarry Smith if (snes->npc && snes->npcside== PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { 4446159c86SPeter Brune SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"SNESNGMRES does not support left preconditioning with unpreconditioned function"); 4546159c86SPeter Brune } 46efd4aadfSBarry Smith if (snes->npcside== PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_PRECONDITIONED; 479566063dSJacob Faibussowitsch PetscCall(SNESSetWorkVecs(snes,5)); 48fced5a79SAsbjørn Nilsen Riseth 49fced5a79SAsbjørn Nilsen Riseth if (!snes->vec_sol) { 509566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes,&dm)); 519566063dSJacob Faibussowitsch PetscCall(DMCreateGlobalVector(dm,&snes->vec_sol)); 52fced5a79SAsbjørn Nilsen Riseth } 53fced5a79SAsbjørn Nilsen Riseth 549566063dSJacob Faibussowitsch if (!ngmres->Xdot) PetscCall(VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Xdot)); 559566063dSJacob Faibussowitsch if (!ngmres->Fdot) PetscCall(VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Fdot)); 5678440776SJed Brown if (!ngmres->setup_called) { 57087dfb9eSxuemin msize = ngmres->msize; /* restart size */ 5819653cdaSPeter Brune hsize = msize * msize; 59087dfb9eSxuemin 6098b3e84cSPeter Brune /* explicit least squares minimization solve */ 619566063dSJacob Faibussowitsch PetscCall(PetscCalloc4(hsize,&ngmres->h, msize,&ngmres->beta, msize,&ngmres->xi, hsize,&ngmres->q)); 629566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(msize,&ngmres->xnorms,msize,&ngmres->fnorms,msize,&ngmres->s)); 6319653cdaSPeter Brune ngmres->nrhs = 1; 6419653cdaSPeter Brune ngmres->lda = msize; 6519653cdaSPeter Brune ngmres->ldb = msize; 6619653cdaSPeter Brune ngmres->lwork = 12*msize; 67dd63322aSSatish Balay #if defined(PETSC_USE_COMPLEX) 689566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(ngmres->lwork,&ngmres->rwork)); 6919653cdaSPeter Brune #endif 709566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(ngmres->lwork,&ngmres->work)); 7178440776SJed Brown } 72e7058c64SPeter Brune 73e7058c64SPeter Brune /* linesearch setup */ 749566063dSJacob Faibussowitsch PetscCall(SNESGetOptionsPrefix(snes,&optionsprefix)); 75e7058c64SPeter Brune 7613a62661SPeter Brune if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) { 779566063dSJacob Faibussowitsch PetscCall(SNESLineSearchCreate(PetscObjectComm((PetscObject)snes),&ngmres->additive_linesearch)); 789566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetSNES(ngmres->additive_linesearch,snes)); 79ec786807SJed Brown if (!((PetscObject)ngmres->additive_linesearch)->type_name) { 809566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetType(ngmres->additive_linesearch,SNESLINESEARCHL2)); 81ec786807SJed Brown } 829566063dSJacob Faibussowitsch PetscCall(SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,"additive_")); 839566063dSJacob Faibussowitsch PetscCall(SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,optionsprefix)); 849566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetFromOptions(ngmres->additive_linesearch)); 85e7058c64SPeter Brune } 86e7058c64SPeter Brune 8778440776SJed Brown ngmres->setup_called = PETSC_TRUE; 88a312c225SMatthew G Knepley PetscFunctionReturn(0); 89a312c225SMatthew G Knepley } 90a312c225SMatthew G Knepley 914416b707SBarry Smith PetscErrorCode SNESSetFromOptions_NGMRES(PetscOptionItems *PetscOptionsObject,SNES snes) 92a312c225SMatthew G Knepley { 93a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data; 9494ae4db5SBarry Smith PetscBool debug = PETSC_FALSE; 950adebc6cSBarry Smith 96a312c225SMatthew G Knepley PetscFunctionBegin; 97d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject,"SNES NGMRES options"); 98d0609cedSBarry Smith PetscCall(PetscOptionsEnum("-snes_ngmres_select_type","Select type","SNESNGMRESSetSelectType",SNESNGMRESSelectTypes,(PetscEnum)ngmres->select_type,(PetscEnum*)&ngmres->select_type,NULL)); 99d0609cedSBarry Smith PetscCall(PetscOptionsEnum("-snes_ngmres_restart_type","Restart type","SNESNGMRESSetRestartType",SNESNGMRESRestartTypes,(PetscEnum)ngmres->restart_type,(PetscEnum*)&ngmres->restart_type,NULL)); 1009566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_ngmres_candidate", "Use candidate storage", "SNES",ngmres->candidate,&ngmres->candidate,NULL)); 1019566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_ngmres_approxfunc","Linearly approximate the function", "SNES",ngmres->approxfunc,&ngmres->approxfunc,NULL)); 1029566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-snes_ngmres_m", "Number of directions", "SNES",ngmres->msize,&ngmres->msize,NULL)); 1039566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-snes_ngmres_restart", "Iterations before forced restart", "SNES",ngmres->restart_periodic,&ngmres->restart_periodic,NULL)); 1049566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-snes_ngmres_restart_it", "Tolerance iterations before restart","SNES",ngmres->restart_it,&ngmres->restart_it,NULL)); 1059566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_ngmres_monitor", "Monitor actions of NGMRES", "SNES",ngmres->monitor ? PETSC_TRUE : PETSC_FALSE,&debug,NULL)); 106dfbf837cSBarry Smith if (debug) { 1072f613bf5SBarry Smith ngmres->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes)); 108dfbf837cSBarry Smith } 1099566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_ngmres_gammaA", "Residual selection constant", "SNES",ngmres->gammaA,&ngmres->gammaA,NULL)); 1109566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_ngmres_gammaC", "Residual restart constant", "SNES",ngmres->gammaC,&ngmres->gammaC,NULL)); 1119566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES",ngmres->epsilonB,&ngmres->epsilonB,NULL)); 1129566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_ngmres_deltaB", "Difference residual selection constant", "SNES",ngmres->deltaB,&ngmres->deltaB,NULL)); 1139566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_ngmres_single_reduction", "Aggregate reductions", "SNES",ngmres->singlereduction,&ngmres->singlereduction,NULL)); 1149566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_ngmres_restart_fm_rise", "Restart on F_M residual rise", "SNESNGMRESSetRestartFmRise",ngmres->restart_fm_rise,&ngmres->restart_fm_rise,NULL)); 115d0609cedSBarry Smith PetscOptionsHeadEnd(); 1166a7cf640SPeter Brune if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA; 117a312c225SMatthew G Knepley PetscFunctionReturn(0); 118a312c225SMatthew G Knepley } 119a312c225SMatthew G Knepley 120a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes,PetscViewer viewer) 121a312c225SMatthew G Knepley { 122a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data; 123a312c225SMatthew G Knepley PetscBool iascii; 124a312c225SMatthew G Knepley 125a312c225SMatthew G Knepley PetscFunctionBegin; 1269566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject) viewer,PETSCVIEWERASCII,&iascii)); 127a312c225SMatthew G Knepley if (iascii) { 128*63a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer," Number of stored past updates: %" PetscInt_FMT "\n", ngmres->msize)); 129*63a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer," Residual selection: gammaA=%1.0e, gammaC=%1.0e\n",(double)ngmres->gammaA,(double)ngmres->gammaC)); 130*63a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer," Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n",(double)ngmres->epsilonB,(double)ngmres->deltaB)); 131*63a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer," Restart on F_M residual increase: %s\n",PetscBools[ngmres->restart_fm_rise])); 132a312c225SMatthew G Knepley } 133a312c225SMatthew G Knepley PetscFunctionReturn(0); 134a312c225SMatthew G Knepley } 135a312c225SMatthew G Knepley 136a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes) 137a312c225SMatthew G Knepley { 138087dfb9eSxuemin SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data; 13998b3e84cSPeter Brune /* present solution, residual, and preconditioned residual */ 1409f425c49SPeter Brune Vec X,F,B,D,Y; 141f109b39eSPeter Brune 142f109b39eSPeter Brune /* candidate linear combination answers */ 143ddd40ce5SPeter Brune Vec XA,FA,XM,FM; 14419653cdaSPeter Brune 14598b3e84cSPeter Brune /* coefficients and RHS to the minimization problem */ 14618aa0c0cSPeter Brune PetscReal fnorm,fMnorm,fAnorm; 147b3c6a99cSPeter Brune PetscReal xnorm,xMnorm,xAnorm; 148b3c6a99cSPeter Brune PetscReal ynorm,yMnorm,yAnorm; 14938774f0aSPeter Brune PetscInt k,k_restart,l,ivec,restart_count = 0; 15019653cdaSPeter Brune 15198b3e84cSPeter Brune /* solution selection data */ 15238774f0aSPeter Brune PetscBool selectRestart; 15361ba4676SBarry Smith /* 15461ba4676SBarry Smith These two variables are initialized to prevent compilers/analyzers from producing false warnings about these variables being passed 15561ba4676SBarry Smith to SNESNGMRESSelect_Private() without being set when SNES_NGMRES_RESTART_DIFFERENCE, the values are not used in the subroutines in that case 15661ba4676SBarry Smith so the code is correct as written. 15761ba4676SBarry Smith */ 15861ba4676SBarry Smith PetscReal dnorm = 0.0,dminnorm = 0.0; 159b3c6a99cSPeter Brune PetscReal fminnorm; 16019653cdaSPeter Brune 1611e633543SBarry Smith SNESConvergedReason reason; 162422a814eSBarry Smith SNESLineSearchReason lssucceed; 163a312c225SMatthew G Knepley 164a312c225SMatthew G Knepley PetscFunctionBegin; 1652c71b3e2SJacob Faibussowitsch PetscCheckFalse(snes->xl || snes->xu || snes->ops->computevariablebounds,PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name); 166c579b300SPatrick Farrell 1679566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(SNESCitation,&SNEScite)); 16898b3e84cSPeter Brune /* variable initialization */ 169a312c225SMatthew G Knepley snes->reason = SNES_CONVERGED_ITERATING; 170f109b39eSPeter Brune X = snes->vec_sol; 171f109b39eSPeter Brune F = snes->vec_func; 172f109b39eSPeter Brune B = snes->vec_rhs; 173f109b39eSPeter Brune XA = snes->vec_sol_update; 174f109b39eSPeter Brune FA = snes->work[0]; 175f109b39eSPeter Brune D = snes->work[1]; 176f109b39eSPeter Brune 177f109b39eSPeter Brune /* work for the line search */ 178f109b39eSPeter Brune Y = snes->work[2]; 1799f425c49SPeter Brune XM = snes->work[3]; 1809f425c49SPeter Brune FM = snes->work[4]; 181a312c225SMatthew G Knepley 1829566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 183a312c225SMatthew G Knepley snes->iter = 0; 184a312c225SMatthew G Knepley snes->norm = 0.; 1859566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 18619653cdaSPeter Brune 18798b3e84cSPeter Brune /* initialization */ 18819653cdaSPeter Brune 189efd4aadfSBarry Smith if (snes->npc && snes->npcside== PC_LEFT) { 1909566063dSJacob Faibussowitsch PetscCall(SNESApplyNPC(snes,X,NULL,F)); 1919566063dSJacob Faibussowitsch PetscCall(SNESGetConvergedReason(snes->npc,&reason)); 1923a2ae377SPeter Brune if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 1933a2ae377SPeter Brune snes->reason = SNES_DIVERGED_INNER; 1943a2ae377SPeter Brune PetscFunctionReturn(0); 1953a2ae377SPeter Brune } 1969566063dSJacob Faibussowitsch PetscCall(VecNorm(F,NORM_2,&fnorm)); 1973a2ae377SPeter Brune } else { 198e4ed7901SPeter Brune if (!snes->vec_func_init_set) { 1999566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes,X,F)); 2001aa26658SKarl Rupp } else snes->vec_func_init_set = PETSC_FALSE; 201c1c75074SPeter Brune 2029566063dSJacob Faibussowitsch PetscCall(VecNorm(F,NORM_2,&fnorm)); 203422a814eSBarry Smith SNESCheckFunctionNorm(snes,fnorm); 2043a2ae377SPeter Brune } 205e4ed7901SPeter Brune fminnorm = fnorm; 20619653cdaSPeter Brune 2079566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 208f109b39eSPeter Brune snes->norm = fnorm; 2099566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 2109566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes,fnorm,0)); 2119566063dSJacob Faibussowitsch PetscCall(SNESMonitor(snes,0,fnorm)); 2129566063dSJacob Faibussowitsch PetscCall((*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP)); 213a312c225SMatthew G Knepley if (snes->reason) PetscFunctionReturn(0); 214b3c6a99cSPeter Brune SNESNGMRESUpdateSubspace_Private(snes,0,0,F,fnorm,X); 215a312c225SMatthew G Knepley 21619653cdaSPeter Brune k_restart = 1; 21719653cdaSPeter Brune l = 1; 218b3c6a99cSPeter Brune ivec = 0; 21909c08436SPeter Brune for (k=1; k < snes->max_its+1; k++) { 22098b3e84cSPeter Brune /* Computation of x^M */ 221efd4aadfSBarry Smith if (snes->npc && snes->npcside== PC_RIGHT) { 2229566063dSJacob Faibussowitsch PetscCall(VecCopy(X,XM)); 2239566063dSJacob Faibussowitsch PetscCall(SNESSetInitialFunction(snes->npc,F)); 22463e7833aSPeter Brune 2259566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(SNES_NPCSolve,snes->npc,XM,B,0)); 2269566063dSJacob Faibussowitsch PetscCall(SNESSolve(snes->npc,B,XM)); 2279566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(SNES_NPCSolve,snes->npc,XM,B,0)); 22863e7833aSPeter Brune 2299566063dSJacob Faibussowitsch PetscCall(SNESGetConvergedReason(snes->npc,&reason)); 2308cc86e31SPeter Brune if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 2318cc86e31SPeter Brune snes->reason = SNES_DIVERGED_INNER; 2328cc86e31SPeter Brune PetscFunctionReturn(0); 2338cc86e31SPeter Brune } 2349566063dSJacob Faibussowitsch PetscCall(SNESGetNPCFunction(snes,FM,&fMnorm)); 2358cc86e31SPeter Brune } else { 236f109b39eSPeter Brune /* no preconditioner -- just take gradient descent with line search */ 2379566063dSJacob Faibussowitsch PetscCall(VecCopy(F,Y)); 2389566063dSJacob Faibussowitsch PetscCall(VecCopy(F,FM)); 2399566063dSJacob Faibussowitsch PetscCall(VecCopy(X,XM)); 2401aa26658SKarl Rupp 241e7058c64SPeter Brune fMnorm = fnorm; 2421aa26658SKarl Rupp 2439566063dSJacob Faibussowitsch PetscCall(SNESLineSearchApply(snes->linesearch,XM,FM,&fMnorm,Y)); 2449566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetReason(snes->linesearch,&lssucceed)); 245422a814eSBarry Smith if (lssucceed) { 246f109b39eSPeter Brune if (++snes->numFailures >= snes->maxFailures) { 247f109b39eSPeter Brune snes->reason = SNES_DIVERGED_LINE_SEARCH; 248f109b39eSPeter Brune PetscFunctionReturn(0); 249f109b39eSPeter Brune } 250f109b39eSPeter Brune } 2516634f59bSPeter Brune } 25223b3e82cSAsbjørn Nilsen Riseth 2539566063dSJacob Faibussowitsch PetscCall(SNESNGMRESFormCombinedSolution_Private(snes,ivec,l,XM,FM,fMnorm,X,XA,FA)); 25498b3e84cSPeter Brune /* r = F(x) */ 2559f425c49SPeter Brune if (fminnorm > fMnorm) fminnorm = fMnorm; /* the minimum norm is now of F^M */ 25619653cdaSPeter Brune 2579f425c49SPeter Brune /* differences for selection and restart */ 25813a62661SPeter Brune if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) { 2599566063dSJacob Faibussowitsch PetscCall(SNESNGMRESNorms_Private(snes,l,X,F,XM,FM,XA,FA,D,&dnorm,&dminnorm,&xMnorm,NULL,&yMnorm,&xAnorm,&fAnorm,&yAnorm)); 26013a62661SPeter Brune } else { 2619566063dSJacob Faibussowitsch PetscCall(SNESNGMRESNorms_Private(snes,l,X,F,XM,FM,XA,FA,D,NULL,NULL,&xMnorm,NULL,&yMnorm,&xAnorm,&fAnorm,&yAnorm)); 26213a62661SPeter Brune } 263422a814eSBarry Smith SNESCheckFunctionNorm(snes,fnorm); 2641aa26658SKarl Rupp 2659f425c49SPeter Brune /* combination (additive) or selection (multiplicative) of the N-GMRES solution */ 2669566063dSJacob Faibussowitsch PetscCall(SNESNGMRESSelect_Private(snes,k_restart,XM,FM,xMnorm,fMnorm,yMnorm,XA,FA,xAnorm,fAnorm,yAnorm,dnorm,fminnorm,dminnorm,X,F,Y,&xnorm,&fnorm,&ynorm)); 26719653cdaSPeter Brune selectRestart = PETSC_FALSE; 26823b3e82cSAsbjørn Nilsen Riseth 26913a62661SPeter Brune if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) { 2709566063dSJacob Faibussowitsch PetscCall(SNESNGMRESSelectRestart_Private(snes,l,fMnorm,fAnorm,dnorm,fminnorm,dminnorm,&selectRestart)); 27123b3e82cSAsbjørn Nilsen Riseth 27228ed4a04SPeter Brune /* if the restart conditions persist for more than restart_it iterations, restart. */ 2731aa26658SKarl Rupp if (selectRestart) restart_count++; 2741aa26658SKarl Rupp else restart_count = 0; 27513a62661SPeter Brune } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) { 27613a62661SPeter Brune if (k_restart > ngmres->restart_periodic) { 277*63a3b9bcSJacob Faibussowitsch if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor,"periodic restart after %" PetscInt_FMT " iterations\n",k_restart)); 27813a62661SPeter Brune restart_count = ngmres->restart_it; 27913a62661SPeter Brune } 28013a62661SPeter Brune } 28123b3e82cSAsbjørn Nilsen Riseth 282b3c6a99cSPeter Brune ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */ 28323b3e82cSAsbjørn Nilsen Riseth 28428ed4a04SPeter Brune /* restart after restart conditions have persisted for a fixed number of iterations */ 28528ed4a04SPeter Brune if (restart_count >= ngmres->restart_it) { 286dfbf837cSBarry Smith if (ngmres->monitor) { 287*63a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(ngmres->monitor,"Restarted at iteration %" PetscInt_FMT "\n",k_restart)); 288dfbf837cSBarry Smith } 28928ed4a04SPeter Brune restart_count = 0; 29019653cdaSPeter Brune k_restart = 1; 29119653cdaSPeter Brune l = 1; 292b3c6a99cSPeter Brune ivec = 0; 29398b3e84cSPeter Brune /* q_{00} = nu */ 2949566063dSJacob Faibussowitsch PetscCall(SNESNGMRESUpdateSubspace_Private(snes,0,0,FM,fMnorm,XM)); 295d2e16ddcSPeter Brune } else { 29698b3e84cSPeter Brune /* select the current size of the subspace */ 2971e633543SBarry Smith if (l < ngmres->msize) l++; 29819653cdaSPeter Brune k_restart++; 29998b3e84cSPeter Brune /* place the current entry in the list of previous entries */ 30038774f0aSPeter Brune if (ngmres->candidate) { 30138774f0aSPeter Brune if (fminnorm > fMnorm) fminnorm = fMnorm; 3029566063dSJacob Faibussowitsch PetscCall(SNESNGMRESUpdateSubspace_Private(snes,ivec,l,FM,fMnorm,XM)); 303d2e16ddcSPeter Brune } else { 30438774f0aSPeter Brune if (fminnorm > fnorm) fminnorm = fnorm; 3059566063dSJacob Faibussowitsch PetscCall(SNESNGMRESUpdateSubspace_Private(snes,ivec,l,F,fnorm,X)); 30619653cdaSPeter Brune } 307d2e16ddcSPeter Brune } 30819653cdaSPeter Brune 3099566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 310087dfb9eSxuemin snes->iter = k; 311f109b39eSPeter Brune snes->norm = fnorm; 3129566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 3139566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes,snes->norm,snes->iter)); 3149566063dSJacob Faibussowitsch PetscCall(SNESMonitor(snes,snes->iter,snes->norm)); 3159566063dSJacob Faibussowitsch PetscCall((*snes->ops->converged)(snes,snes->iter,0,0,fnorm,&snes->reason,snes->cnvP)); 316087dfb9eSxuemin if (snes->reason) PetscFunctionReturn(0); 317a312c225SMatthew G Knepley } 318a312c225SMatthew G Knepley snes->reason = SNES_DIVERGED_MAX_IT; 319a312c225SMatthew G Knepley PetscFunctionReturn(0); 320a312c225SMatthew G Knepley } 321a312c225SMatthew G Knepley 32223b3e82cSAsbjørn Nilsen Riseth /*@ 32323b3e82cSAsbjørn Nilsen Riseth SNESNGMRESSetRestartFmRise - Increase the restart count if the step x_M increases the residual F_M 32423b3e82cSAsbjørn Nilsen Riseth 32523b3e82cSAsbjørn Nilsen Riseth Input Parameters: 32623b3e82cSAsbjørn Nilsen Riseth + snes - the SNES context. 32723b3e82cSAsbjørn Nilsen Riseth - flg - boolean value deciding whether to use the option or not 32823b3e82cSAsbjørn Nilsen Riseth 32923b3e82cSAsbjørn Nilsen Riseth Options Database: 33023b3e82cSAsbjørn Nilsen Riseth + -snes_ngmres_restart_fm_rise - Increase the restart count if the step x_M increases the residual F_M 33123b3e82cSAsbjørn Nilsen Riseth 33223b3e82cSAsbjørn Nilsen Riseth Level: intermediate 33323b3e82cSAsbjørn Nilsen Riseth 33423b3e82cSAsbjørn Nilsen Riseth Notes: 33523b3e82cSAsbjørn Nilsen Riseth If the proposed step x_M increases the residual F_M, it might be trying to get out of a stagnation area. 33623b3e82cSAsbjørn Nilsen Riseth To help the solver do that, reset the Krylov subspace whenever F_M increases. 33723b3e82cSAsbjørn Nilsen Riseth 33823b3e82cSAsbjørn Nilsen Riseth This option must be used with SNES_NGMRES_RESTART_DIFFERENCE 33923b3e82cSAsbjørn Nilsen Riseth 34023b3e82cSAsbjørn Nilsen Riseth The default is FALSE. 34123b3e82cSAsbjørn Nilsen Riseth .seealso: SNES_NGMRES_RESTART_DIFFERENCE 34223b3e82cSAsbjørn Nilsen Riseth @*/ 34323b3e82cSAsbjørn Nilsen Riseth PetscErrorCode SNESNGMRESSetRestartFmRise(SNES snes,PetscBool flg) 34423b3e82cSAsbjørn Nilsen Riseth { 34523b3e82cSAsbjørn Nilsen Riseth PetscErrorCode (*f)(SNES,PetscBool); 34623b3e82cSAsbjørn Nilsen Riseth 34723b3e82cSAsbjørn Nilsen Riseth PetscFunctionBegin; 3489566063dSJacob Faibussowitsch PetscCall(PetscObjectQueryFunction((PetscObject)snes,"SNESNGMRESSetRestartFmRise_C",&f)); 3499566063dSJacob Faibussowitsch if (f) PetscCall((f)(snes,flg)); 35023b3e82cSAsbjørn Nilsen Riseth PetscFunctionReturn(0); 35123b3e82cSAsbjørn Nilsen Riseth } 35223b3e82cSAsbjørn Nilsen Riseth 35323b3e82cSAsbjørn Nilsen Riseth PetscErrorCode SNESNGMRESSetRestartFmRise_NGMRES(SNES snes,PetscBool flg) 35423b3e82cSAsbjørn Nilsen Riseth { 35523b3e82cSAsbjørn Nilsen Riseth SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data; 35623b3e82cSAsbjørn Nilsen Riseth 35723b3e82cSAsbjørn Nilsen Riseth PetscFunctionBegin; 35823b3e82cSAsbjørn Nilsen Riseth ngmres->restart_fm_rise = flg; 35923b3e82cSAsbjørn Nilsen Riseth PetscFunctionReturn(0); 36023b3e82cSAsbjørn Nilsen Riseth } 36123b3e82cSAsbjørn Nilsen Riseth 36223b3e82cSAsbjørn Nilsen Riseth PetscErrorCode SNESNGMRESGetRestartFmRise(SNES snes,PetscBool *flg) 36323b3e82cSAsbjørn Nilsen Riseth { 36423b3e82cSAsbjørn Nilsen Riseth PetscErrorCode (*f)(SNES,PetscBool*); 36523b3e82cSAsbjørn Nilsen Riseth 36623b3e82cSAsbjørn Nilsen Riseth PetscFunctionBegin; 3679566063dSJacob Faibussowitsch PetscCall(PetscObjectQueryFunction((PetscObject)snes,"SNESNGMRESGetRestartFmRise_C",&f)); 3689566063dSJacob Faibussowitsch if (f) PetscCall((f)(snes,flg)); 36923b3e82cSAsbjørn Nilsen Riseth PetscFunctionReturn(0); 37023b3e82cSAsbjørn Nilsen Riseth } 37123b3e82cSAsbjørn Nilsen Riseth 37223b3e82cSAsbjørn Nilsen Riseth PetscErrorCode SNESNGMRESGetRestartFmRise_NGMRES(SNES snes,PetscBool *flg) 37323b3e82cSAsbjørn Nilsen Riseth { 37423b3e82cSAsbjørn Nilsen Riseth SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data; 37523b3e82cSAsbjørn Nilsen Riseth 37623b3e82cSAsbjørn Nilsen Riseth PetscFunctionBegin; 37723b3e82cSAsbjørn Nilsen Riseth *flg = ngmres->restart_fm_rise; 37823b3e82cSAsbjørn Nilsen Riseth PetscFunctionReturn(0); 37923b3e82cSAsbjørn Nilsen Riseth } 38023b3e82cSAsbjørn Nilsen Riseth 38113a62661SPeter Brune /*@ 38213a62661SPeter Brune SNESNGMRESSetRestartType - Sets the restart type for SNESNGMRES. 38313a62661SPeter Brune 38413a62661SPeter Brune Logically Collective on SNES 38513a62661SPeter Brune 38613a62661SPeter Brune Input Parameters: 38713a62661SPeter Brune + snes - the iterative context 38813a62661SPeter Brune - rtype - restart type 38913a62661SPeter Brune 39013a62661SPeter Brune Options Database: 39113a62661SPeter Brune + -snes_ngmres_restart_type<difference,periodic,none> - set the restart type 3920c777b0cSPeter Brune - -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic 39313a62661SPeter Brune 39413a62661SPeter Brune Level: intermediate 39513a62661SPeter Brune 39613a62661SPeter Brune SNESNGMRESRestartTypes: 39713a62661SPeter Brune + SNES_NGMRES_RESTART_NONE - never restart 39813a62661SPeter Brune . SNES_NGMRES_RESTART_DIFFERENCE - restart based upon difference criteria 39913a62661SPeter Brune - SNES_NGMRES_RESTART_PERIODIC - restart after a fixed number of iterations 40013a62661SPeter Brune 40113a62661SPeter Brune Notes: 40213a62661SPeter Brune The default line search used is the L2 line search and it requires two additional function evaluations. 40313a62661SPeter Brune 40413a62661SPeter Brune @*/ 4050adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType(SNES snes,SNESNGMRESRestartType rtype) 4060adebc6cSBarry Smith { 40713a62661SPeter Brune PetscFunctionBegin; 40813a62661SPeter Brune PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 409cac4c232SBarry Smith PetscTryMethod(snes,"SNESNGMRESSetRestartType_C",(SNES,SNESNGMRESRestartType),(snes,rtype)); 41013a62661SPeter Brune PetscFunctionReturn(0); 41113a62661SPeter Brune } 41213a62661SPeter Brune 41313a62661SPeter Brune /*@ 41413a62661SPeter Brune SNESNGMRESSetSelectType - Sets the selection type for SNESNGMRES. This determines how the candidate solution and 41513a62661SPeter Brune combined solution are used to create the next iterate. 41613a62661SPeter Brune 41713a62661SPeter Brune Logically Collective on SNES 41813a62661SPeter Brune 41913a62661SPeter Brune Input Parameters: 42013a62661SPeter Brune + snes - the iterative context 42113a62661SPeter Brune - stype - selection type 42213a62661SPeter Brune 42313a62661SPeter Brune Options Database: 42467b8a455SSatish Balay . -snes_ngmres_select_type<difference,none,linesearch> - select type 42513a62661SPeter Brune 42613a62661SPeter Brune Level: intermediate 42713a62661SPeter Brune 42813a62661SPeter Brune SNESNGMRESSelectTypes: 42913a62661SPeter Brune + SNES_NGMRES_SELECT_NONE - choose the combined solution all the time 43013a62661SPeter Brune . SNES_NGMRES_SELECT_DIFFERENCE - choose based upon the selection criteria 43113a62661SPeter Brune - SNES_NGMRES_SELECT_LINESEARCH - choose based upon line search combination 43213a62661SPeter Brune 43313a62661SPeter Brune Notes: 43413a62661SPeter Brune The default line search used is the L2 line search and it requires two additional function evaluations. 43513a62661SPeter Brune 43613a62661SPeter Brune @*/ 4370adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType(SNES snes,SNESNGMRESSelectType stype) 4380adebc6cSBarry Smith { 43913a62661SPeter Brune PetscFunctionBegin; 44013a62661SPeter Brune PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 441cac4c232SBarry Smith PetscTryMethod(snes,"SNESNGMRESSetSelectType_C",(SNES,SNESNGMRESSelectType),(snes,stype)); 44213a62661SPeter Brune PetscFunctionReturn(0); 44313a62661SPeter Brune } 44413a62661SPeter Brune 4450adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes,SNESNGMRESSelectType stype) 4460adebc6cSBarry Smith { 44713a62661SPeter Brune SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data; 4485fd66863SKarl Rupp 44913a62661SPeter Brune PetscFunctionBegin; 45013a62661SPeter Brune ngmres->select_type = stype; 45113a62661SPeter Brune PetscFunctionReturn(0); 45213a62661SPeter Brune } 45313a62661SPeter Brune 4540adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes,SNESNGMRESRestartType rtype) 4550adebc6cSBarry Smith { 45613a62661SPeter Brune SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data; 4575fd66863SKarl Rupp 45813a62661SPeter Brune PetscFunctionBegin; 45913a62661SPeter Brune ngmres->restart_type = rtype; 46013a62661SPeter Brune PetscFunctionReturn(0); 46113a62661SPeter Brune } 46213a62661SPeter Brune 463dfbf837cSBarry Smith /*MC 4641867fe5bSPeter Brune SNESNGMRES - The Nonlinear Generalized Minimum Residual method. 465a312c225SMatthew G Knepley 466dfbf837cSBarry Smith Level: beginner 467dfbf837cSBarry Smith 4681867fe5bSPeter Brune Options Database: 46913a62661SPeter Brune + -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution 47038774f0aSPeter Brune . -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions 47138774f0aSPeter Brune . -snes_ngmres_candidate - Use NGMRES variant which combines candidate solutions instead of actual solutions 47213a62661SPeter Brune . -snes_ngmres_m - Number of stored previous solutions and residuals 47313a62661SPeter Brune . -snes_ngmres_restart_it - Number of iterations the restart conditions hold before restart 47413a62661SPeter Brune . -snes_ngmres_gammaA - Residual tolerance for solution select between the candidate and combination 47513a62661SPeter Brune . -snes_ngmres_gammaC - Residual tolerance for restart 47613a62661SPeter Brune . -snes_ngmres_epsilonB - Difference tolerance between subsequent solutions triggering restart 47713a62661SPeter Brune . -snes_ngmres_deltaB - Difference tolerance between residuals triggering restart 47823b3e82cSAsbjørn Nilsen Riseth . -snes_ngmres_restart_fm_rise - Restart on residual rise from x_M step 47913a62661SPeter Brune . -snes_ngmres_monitor - Prints relevant information about the ngmres iteration 4805c3e6ab7SPeter Brune . -snes_linesearch_type <basic,l2,cp> - Line search type used for the default smoother 48113a62661SPeter Brune - -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type 4821867fe5bSPeter Brune 4831867fe5bSPeter Brune Notes: 4841867fe5bSPeter Brune 4851867fe5bSPeter Brune The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized 4861867fe5bSPeter Brune optimization problem at each iteration. 4871867fe5bSPeter Brune 4884f02bc6aSBarry Smith Very similar to the SNESANDERSON algorithm. 4894f02bc6aSBarry Smith 4901867fe5bSPeter Brune References: 491606c0280SSatish Balay + * - C. W. Oosterlee and T. Washio, "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", 492dfbf837cSBarry Smith SIAM Journal on Scientific Computing, 21(5), 2000. 493606c0280SSatish Balay - * - Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers", 4944f02bc6aSBarry Smith SIAM Review, 57(4), 2015 4954f02bc6aSBarry Smith 496dfbf837cSBarry Smith .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types) 497dfbf837cSBarry Smith M*/ 498a312c225SMatthew G Knepley 4998cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_NGMRES(SNES snes) 500a312c225SMatthew G Knepley { 501a312c225SMatthew G Knepley SNES_NGMRES *ngmres; 502d8d34be6SBarry Smith SNESLineSearch linesearch; 503a312c225SMatthew G Knepley 504a312c225SMatthew G Knepley PetscFunctionBegin; 505a312c225SMatthew G Knepley snes->ops->destroy = SNESDestroy_NGMRES; 506a312c225SMatthew G Knepley snes->ops->setup = SNESSetUp_NGMRES; 507a312c225SMatthew G Knepley snes->ops->setfromoptions = SNESSetFromOptions_NGMRES; 508a312c225SMatthew G Knepley snes->ops->view = SNESView_NGMRES; 509a312c225SMatthew G Knepley snes->ops->solve = SNESSolve_NGMRES; 510a312c225SMatthew G Knepley snes->ops->reset = SNESReset_NGMRES; 511a312c225SMatthew G Knepley 512efd4aadfSBarry Smith snes->usesnpc = PETSC_TRUE; 5132c155ee1SBarry Smith snes->usesksp = PETSC_FALSE; 514efd4aadfSBarry Smith snes->npcside = PC_RIGHT; 5152c155ee1SBarry Smith 5164fc747eaSLawrence Mitchell snes->alwayscomputesfinalresidual = PETSC_TRUE; 5174fc747eaSLawrence Mitchell 5189566063dSJacob Faibussowitsch PetscCall(PetscNewLog(snes,&ngmres)); 519a312c225SMatthew G Knepley snes->data = (void*) ngmres; 520d2e16ddcSPeter Brune ngmres->msize = 30; 52119653cdaSPeter Brune 52288976e71SPeter Brune if (!snes->tolerancesset) { 5230e444f03SPeter Brune snes->max_funcs = 30000; 5240e444f03SPeter Brune snes->max_its = 10000; 52588976e71SPeter Brune } 5260e444f03SPeter Brune 52738774f0aSPeter Brune ngmres->candidate = PETSC_FALSE; 528d2e16ddcSPeter Brune 5299566063dSJacob Faibussowitsch PetscCall(SNESGetLineSearch(snes,&linesearch)); 530ec786807SJed Brown if (!((PetscObject)linesearch)->type_name) { 5319566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetType(linesearch,SNESLINESEARCHBASIC)); 532ec786807SJed Brown } 533d8d34be6SBarry Smith 5340298fd71SBarry Smith ngmres->additive_linesearch = NULL; 535077c4231SPeter Brune ngmres->approxfunc = PETSC_FALSE; 53628ed4a04SPeter Brune ngmres->restart_it = 2; 53713a62661SPeter Brune ngmres->restart_periodic = 30; 538f109b39eSPeter Brune ngmres->gammaA = 2.0; 539f109b39eSPeter Brune ngmres->gammaC = 2.0; 540cac108bcSPeter Brune ngmres->deltaB = 0.9; 541cac108bcSPeter Brune ngmres->epsilonB = 0.1; 54223b3e82cSAsbjørn Nilsen Riseth ngmres->restart_fm_rise = PETSC_FALSE; 543e7058c64SPeter Brune 54413a62661SPeter Brune ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE; 54513a62661SPeter Brune ngmres->select_type = SNES_NGMRES_SELECT_DIFFERENCE; 54613a62661SPeter Brune 5479566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetSelectType_C",SNESNGMRESSetSelectType_NGMRES)); 5489566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetRestartType_C",SNESNGMRESSetRestartType_NGMRES)); 5499566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetRestartFmRise_C",SNESNGMRESSetRestartFmRise_NGMRES)); 5509566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESGetRestartFmRise_C",SNESNGMRESGetRestartFmRise_NGMRES)); 551a312c225SMatthew G Knepley PetscFunctionReturn(0); 552a312c225SMatthew G Knepley } 553