1a312c225SMatthew G Knepley /* Defines the basic SNES object */ 219653cdaSPeter Brune #include <../src/snes/impls/ngmres/snesngmres.h> 319653cdaSPeter Brune #include <petscblaslapack.h> 4a312c225SMatthew G Knepley 5a312c225SMatthew G Knepley #undef __FUNCT__ 6a312c225SMatthew G Knepley #define __FUNCT__ "SNESReset_NGMRES" 7a312c225SMatthew G Knepley PetscErrorCode SNESReset_NGMRES(SNES snes) 8a312c225SMatthew G Knepley { 9a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data; 10a312c225SMatthew G Knepley PetscErrorCode ierr; 11a312c225SMatthew G Knepley 12a312c225SMatthew G Knepley PetscFunctionBegin; 13f109b39eSPeter Brune ierr = VecDestroyVecs(ngmres->msize, &ngmres->Fdot);CHKERRQ(ierr); 14f109b39eSPeter Brune ierr = VecDestroyVecs(ngmres->msize, &ngmres->Xdot);CHKERRQ(ierr); 15a312c225SMatthew G Knepley PetscFunctionReturn(0); 16a312c225SMatthew G Knepley } 17a312c225SMatthew G Knepley 18a312c225SMatthew G Knepley #undef __FUNCT__ 19a312c225SMatthew G Knepley #define __FUNCT__ "SNESDestroy_NGMRES" 20a312c225SMatthew G Knepley PetscErrorCode SNESDestroy_NGMRES(SNES snes) 21a312c225SMatthew G Knepley { 22a312c225SMatthew G Knepley PetscErrorCode ierr; 2378440776SJed Brown SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data; 24a312c225SMatthew G Knepley 25a312c225SMatthew G Knepley PetscFunctionBegin; 26a312c225SMatthew G Knepley ierr = SNESReset_NGMRES(snes);CHKERRQ(ierr); 27f109b39eSPeter Brune ierr = PetscFree5(ngmres->h, ngmres->beta, ngmres->xi, ngmres->fnorms, ngmres->q);CHKERRQ(ierr); 2819653cdaSPeter Brune ierr = PetscFree(ngmres->s);CHKERRQ(ierr); 2919653cdaSPeter Brune #if PETSC_USE_COMPLEX 3019653cdaSPeter Brune ierr = PetscFree(ngmres->rwork); 3119653cdaSPeter Brune #endif 3219653cdaSPeter Brune ierr = PetscFree(ngmres->work); 3319653cdaSPeter Brune ierr = PetscFree(snes->data); 34a312c225SMatthew G Knepley PetscFunctionReturn(0); 35a312c225SMatthew G Knepley } 36a312c225SMatthew G Knepley 37a312c225SMatthew G Knepley #undef __FUNCT__ 38a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetUp_NGMRES" 39a312c225SMatthew G Knepley PetscErrorCode SNESSetUp_NGMRES(SNES snes) 40a312c225SMatthew G Knepley { 41a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES *) snes->data; 4219653cdaSPeter Brune PetscInt msize,hsize; 43a312c225SMatthew G Knepley PetscErrorCode ierr; 44a312c225SMatthew G Knepley 45a312c225SMatthew G Knepley PetscFunctionBegin; 4678440776SJed Brown ierr = SNESDefaultGetWork(snes,5);CHKERRQ(ierr); 4778440776SJed Brown if (!ngmres->Xdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);} 4878440776SJed Brown if (!ngmres->Fdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);} 4978440776SJed Brown if (!ngmres->setup_called) { 50087dfb9eSxuemin msize = ngmres->msize; /* restart size */ 5119653cdaSPeter Brune hsize = msize * msize; 52087dfb9eSxuemin 5398b3e84cSPeter Brune /* explicit least squares minimization solve */ 5419653cdaSPeter Brune ierr = PetscMalloc5(hsize,PetscScalar,&ngmres->h, 5519653cdaSPeter Brune msize,PetscScalar,&ngmres->beta, 5619653cdaSPeter Brune msize,PetscScalar,&ngmres->xi, 57f109b39eSPeter Brune msize,PetscReal, &ngmres->fnorms, 5819653cdaSPeter Brune hsize,PetscScalar,&ngmres->q);CHKERRQ(ierr); 5919653cdaSPeter Brune ngmres->nrhs = 1; 6019653cdaSPeter Brune ngmres->lda = msize; 6119653cdaSPeter Brune ngmres->ldb = msize; 6219653cdaSPeter Brune ierr = PetscMalloc(msize*sizeof(PetscScalar),&ngmres->s);CHKERRQ(ierr); 6319653cdaSPeter Brune ierr = PetscMemzero(ngmres->h, hsize*sizeof(PetscScalar));CHKERRQ(ierr); 6419653cdaSPeter Brune ierr = PetscMemzero(ngmres->q, hsize*sizeof(PetscScalar));CHKERRQ(ierr); 6519653cdaSPeter Brune ierr = PetscMemzero(ngmres->xi, msize*sizeof(PetscScalar));CHKERRQ(ierr); 6619653cdaSPeter Brune ierr = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr); 6719653cdaSPeter Brune ngmres->lwork = 12*msize; 6819653cdaSPeter Brune #if PETSC_USE_COMPLEX 6919653cdaSPeter Brune ierr = PetscMalloc(sizeof(PetscReal)*ngmres->lwork,&ngmres->rwork); 7019653cdaSPeter Brune #endif 7119653cdaSPeter Brune ierr = PetscMalloc(sizeof(PetscScalar)*ngmres->lwork,&ngmres->work); 7278440776SJed Brown } 7378440776SJed Brown ngmres->setup_called = PETSC_TRUE; 74a312c225SMatthew G Knepley PetscFunctionReturn(0); 75a312c225SMatthew G Knepley } 76a312c225SMatthew G Knepley 77a312c225SMatthew G Knepley #undef __FUNCT__ 78a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES" 79a312c225SMatthew G Knepley PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes) 80a312c225SMatthew G Knepley { 81a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES *) snes->data; 82a312c225SMatthew G Knepley PetscErrorCode ierr; 83dfbf837cSBarry Smith PetscBool debug; 84a312c225SMatthew G Knepley 85a312c225SMatthew G Knepley PetscFunctionBegin; 86a312c225SMatthew G Knepley ierr = PetscOptionsHead("SNES NGMRES options");CHKERRQ(ierr); 879f425c49SPeter Brune ierr = PetscOptionsBool("-snes_ngmres_additive", "Use additive variant vs. choice", "SNES", ngmres->additive, &ngmres->additive, PETSC_NULL);CHKERRQ(ierr); 8819653cdaSPeter Brune ierr = PetscOptionsInt("-snes_ngmres_m", "Number of directions", "SNES", ngmres->msize, &ngmres->msize, PETSC_NULL);CHKERRQ(ierr); 8928ed4a04SPeter Brune ierr = PetscOptionsInt("-snes_ngmres_restart_it","Tolerance iterations before restart","SNES", ngmres->restart_it, &ngmres->restart_it, PETSC_NULL);CHKERRQ(ierr); 90dfbf837cSBarry Smith ierr = PetscOptionsBool("-snes_ngmres_monitor", "Monitor actions of NGMRES", "SNES", ngmres->monitor ? PETSC_TRUE: PETSC_FALSE, &debug, PETSC_NULL);CHKERRQ(ierr); 91dfbf837cSBarry Smith if (debug) { 92dfbf837cSBarry Smith ngmres->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr); 93dfbf837cSBarry Smith } 946a7cf640SPeter Brune ierr = PetscOptionsReal("-snes_ngmres_gammaA", "Residual selection constant", "SNES", ngmres->gammaA, &ngmres->gammaA, PETSC_NULL);CHKERRQ(ierr); 956a7cf640SPeter Brune ierr = PetscOptionsReal("-snes_ngmres_gammaC", " Residual restart constant", "SNES", ngmres->gammaC, &ngmres->gammaC, PETSC_NULL);CHKERRQ(ierr); 966a7cf640SPeter Brune ierr = PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES", ngmres->epsilonB, &ngmres->epsilonB, PETSC_NULL);CHKERRQ(ierr); 976a7cf640SPeter Brune ierr = PetscOptionsReal("-snes_ngmres_deltaB", "Difference residual selection constant", "SNES", ngmres->deltaB, &ngmres->deltaB, PETSC_NULL);CHKERRQ(ierr); 98a312c225SMatthew G Knepley ierr = PetscOptionsTail();CHKERRQ(ierr); 996a7cf640SPeter Brune if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA; 100a312c225SMatthew G Knepley PetscFunctionReturn(0); 101a312c225SMatthew G Knepley } 102a312c225SMatthew G Knepley 103a312c225SMatthew G Knepley #undef __FUNCT__ 104a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES" 105a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes, PetscViewer viewer) 106a312c225SMatthew G Knepley { 107a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES *) snes->data; 108a312c225SMatthew G Knepley PetscBool iascii; 109f109b39eSPeter Brune const char *cstr; 110a312c225SMatthew G Knepley PetscErrorCode ierr; 111a312c225SMatthew G Knepley 112a312c225SMatthew G Knepley PetscFunctionBegin; 113a312c225SMatthew G Knepley ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 114a312c225SMatthew G Knepley if (iascii) { 115f109b39eSPeter Brune cstr = SNESLineSearchTypeName(snes->ls_type); 116f109b39eSPeter Brune ierr = PetscViewerASCIIPrintf(viewer, " line search variant: %s\n",cstr);CHKERRQ(ierr); 117f109b39eSPeter Brune ierr = PetscViewerASCIIPrintf(viewer, " Number of stored past updates: %d\n", ngmres->msize);CHKERRQ(ierr); 118f109b39eSPeter Brune ierr = PetscViewerASCIIPrintf(viewer, " Residual selection: gammaA=%1.0e, gammaC=%1.0e\n", ngmres->gammaA, ngmres->gammaC);CHKERRQ(ierr); 119f109b39eSPeter Brune ierr = PetscViewerASCIIPrintf(viewer, " Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n", ngmres->epsilonB, ngmres->deltaB);CHKERRQ(ierr); 120a312c225SMatthew G Knepley } 121a312c225SMatthew G Knepley PetscFunctionReturn(0); 122a312c225SMatthew G Knepley } 123a312c225SMatthew G Knepley 124f109b39eSPeter Brune EXTERN_C_BEGIN 125f109b39eSPeter Brune #undef __FUNCT__ 126f109b39eSPeter Brune #define __FUNCT__ "SNESLineSearchSetType_NGMRES" 127f109b39eSPeter Brune PetscErrorCode SNESLineSearchSetType_NGMRES(SNES snes, SNESLineSearchType type) 128f109b39eSPeter Brune { 129f109b39eSPeter Brune PetscErrorCode ierr; 130f109b39eSPeter Brune PetscFunctionBegin; 131f109b39eSPeter Brune 132f109b39eSPeter Brune switch (type) { 133f109b39eSPeter Brune case SNES_LS_BASIC: 134f109b39eSPeter Brune ierr = SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);CHKERRQ(ierr); 135f109b39eSPeter Brune break; 136f109b39eSPeter Brune case SNES_LS_BASIC_NONORMS: 137f109b39eSPeter Brune ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr); 138f109b39eSPeter Brune break; 139f109b39eSPeter Brune case SNES_LS_QUADRATIC: 140f109b39eSPeter Brune ierr = SNESLineSearchSet(snes,SNESLineSearchQuadraticSecant,PETSC_NULL);CHKERRQ(ierr); 141f109b39eSPeter Brune break; 142f109b39eSPeter Brune default: 143f109b39eSPeter Brune SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP,"Unknown line search type."); 144f109b39eSPeter Brune break; 145f109b39eSPeter Brune } 146f109b39eSPeter Brune snes->ls_type = type; 147f109b39eSPeter Brune PetscFunctionReturn(0); 148f109b39eSPeter Brune } 149f109b39eSPeter Brune EXTERN_C_END 150f109b39eSPeter Brune 15119653cdaSPeter Brune 152a312c225SMatthew G Knepley #undef __FUNCT__ 153a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES" 154211b2d39SPeter Brune 155a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes) 156a312c225SMatthew G Knepley { 157087dfb9eSxuemin SNES_NGMRES *ngmres = (SNES_NGMRES *) snes->data; 15898b3e84cSPeter Brune /* present solution, residual, and preconditioned residual */ 1599f425c49SPeter Brune Vec X, F, B, D, Y; 160f109b39eSPeter Brune 161f109b39eSPeter Brune /* candidate linear combination answers */ 1624b32a720SPeter Brune Vec XA, FA, XM, FM, FPC; 16319653cdaSPeter Brune 16498b3e84cSPeter Brune /* previous iterations to construct the subspace */ 165f109b39eSPeter Brune Vec *Fdot = ngmres->Fdot; 166f109b39eSPeter Brune Vec *Xdot = ngmres->Xdot; 16719653cdaSPeter Brune 16898b3e84cSPeter Brune /* coefficients and RHS to the minimization problem */ 16919653cdaSPeter Brune PetscScalar *beta = ngmres->beta; 17019653cdaSPeter Brune PetscScalar *xi = ngmres->xi; 1719f425c49SPeter Brune PetscReal fnorm, fMnorm, fAnorm, ynorm, xnorm = 0.0; 17219653cdaSPeter Brune PetscReal nu; 17319653cdaSPeter Brune PetscScalar alph_total = 0.; 17419653cdaSPeter Brune PetscScalar qentry; 17528ed4a04SPeter Brune PetscInt i, j, k, k_restart, l, ivec, restart_count = 0; 17619653cdaSPeter Brune 17798b3e84cSPeter Brune /* solution selection data */ 17819653cdaSPeter Brune PetscBool selectA, selectRestart; 179f109b39eSPeter Brune PetscReal dnorm, dminnorm, dcurnorm; 180f109b39eSPeter Brune PetscReal fminnorm; 18119653cdaSPeter Brune 1821e633543SBarry Smith SNESConvergedReason reason; 183f109b39eSPeter Brune PetscBool lssucceed; 184a312c225SMatthew G Knepley PetscErrorCode ierr; 185a312c225SMatthew G Knepley 186a312c225SMatthew G Knepley PetscFunctionBegin; 18798b3e84cSPeter Brune /* variable initialization */ 188a312c225SMatthew G Knepley snes->reason = SNES_CONVERGED_ITERATING; 189f109b39eSPeter Brune X = snes->vec_sol; 190f109b39eSPeter Brune F = snes->vec_func; 191f109b39eSPeter Brune B = snes->vec_rhs; 192f109b39eSPeter Brune XA = snes->vec_sol_update; 193f109b39eSPeter Brune FA = snes->work[0]; 194f109b39eSPeter Brune D = snes->work[1]; 195f109b39eSPeter Brune 196f109b39eSPeter Brune /* work for the line search */ 197f109b39eSPeter Brune Y = snes->work[2]; 1989f425c49SPeter Brune XM = snes->work[3]; 1999f425c49SPeter Brune FM = snes->work[4]; 200a312c225SMatthew G Knepley 201a312c225SMatthew G Knepley ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 202a312c225SMatthew G Knepley snes->iter = 0; 203a312c225SMatthew G Knepley snes->norm = 0.; 204a312c225SMatthew G Knepley ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 20519653cdaSPeter Brune 20698b3e84cSPeter Brune /* initialization */ 20719653cdaSPeter Brune 20898b3e84cSPeter Brune /* r = F(x) */ 209f109b39eSPeter Brune ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 210a312c225SMatthew G Knepley if (snes->domainerror) { 211a312c225SMatthew G Knepley snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 212a312c225SMatthew G Knepley PetscFunctionReturn(0); 213a312c225SMatthew G Knepley } 21419653cdaSPeter Brune 21598b3e84cSPeter Brune /* nu = (r, r) */ 216f109b39eSPeter Brune ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); 217f109b39eSPeter Brune fminnorm = fnorm; 218f109b39eSPeter Brune nu = fnorm*fnorm; 219f109b39eSPeter Brune if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Infinite or not-a-number generated in function evaluation"); 22019653cdaSPeter Brune 22198b3e84cSPeter Brune /* q_{00} = nu */ 22219653cdaSPeter Brune Q(0,0) = nu; 223f109b39eSPeter Brune ngmres->fnorms[0] = fnorm; 224f109b39eSPeter Brune /* Fdot[0] = F */ 225f109b39eSPeter Brune ierr = VecCopy(X, Xdot[0]);CHKERRQ(ierr); 226f109b39eSPeter Brune ierr = VecCopy(F, Fdot[0]);CHKERRQ(ierr); 227087dfb9eSxuemin 228a312c225SMatthew G Knepley ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 229f109b39eSPeter Brune snes->norm = fnorm; 230a312c225SMatthew G Knepley ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 231f109b39eSPeter Brune SNESLogConvHistory(snes, fnorm, 0); 232f109b39eSPeter Brune ierr = SNESMonitor(snes, 0, fnorm);CHKERRQ(ierr); 233f109b39eSPeter Brune ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 234a312c225SMatthew G Knepley if (snes->reason) PetscFunctionReturn(0); 235a312c225SMatthew G Knepley 23619653cdaSPeter Brune k_restart = 1; 23719653cdaSPeter Brune l = 1; 23809c08436SPeter Brune for (k=1; k < snes->max_its+1; k++) { 23998b3e84cSPeter Brune /* select which vector of the stored subspace will be updated */ 24098b3e84cSPeter Brune ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */ 24119653cdaSPeter Brune 24298b3e84cSPeter Brune /* Computation of x^M */ 2438cc86e31SPeter Brune if (snes->pc) { 2449f425c49SPeter Brune ierr = VecCopy(X, XM);CHKERRQ(ierr); 2459f425c49SPeter Brune ierr = SNESSolve(snes->pc, B, XM);CHKERRQ(ierr); 2468cc86e31SPeter Brune ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); 2478cc86e31SPeter Brune if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 2488cc86e31SPeter Brune snes->reason = SNES_DIVERGED_INNER; 2498cc86e31SPeter Brune PetscFunctionReturn(0); 2508cc86e31SPeter Brune } 2514b32a720SPeter Brune ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); 2524b32a720SPeter Brune ierr = VecCopy(FPC, FM);CHKERRQ(ierr); 2534b32a720SPeter Brune ierr = SNESGetFunctionNorm(snes->pc, &fMnorm);CHKERRQ(ierr); 2548cc86e31SPeter Brune } else { 255f109b39eSPeter Brune /* no preconditioner -- just take gradient descent with line search */ 256f109b39eSPeter Brune ierr = VecCopy(F, Y);CHKERRQ(ierr); 2579f425c49SPeter Brune ierr = (*snes->ops->linesearch)(snes,snes->lsP,X,F,Y,fnorm,xnorm,FM,XM,&ynorm,&fMnorm,&lssucceed);CHKERRQ(ierr); 258f109b39eSPeter Brune if (!lssucceed) { 259f109b39eSPeter Brune if (++snes->numFailures >= snes->maxFailures) { 260f109b39eSPeter Brune snes->reason = SNES_DIVERGED_LINE_SEARCH; 261f109b39eSPeter Brune PetscFunctionReturn(0); 262f109b39eSPeter Brune } 263f109b39eSPeter Brune } 2646634f59bSPeter Brune } 2651e633543SBarry Smith 26698b3e84cSPeter Brune /* r = F(x) */ 2679f425c49SPeter Brune nu = fMnorm*fMnorm; 2689f425c49SPeter Brune if (fminnorm > fMnorm) fminnorm = fMnorm; /* the minimum norm is now of F^M */ 26919653cdaSPeter Brune 27098b3e84cSPeter Brune /* construct the right hand side and xi factors */ 2718c09b6b7SPeter Brune ierr = VecMDot(FM, l, Fdot, xi);CHKERRQ(ierr); 2728c09b6b7SPeter Brune 27319653cdaSPeter Brune for (i = 0; i < l; i++) { 27419653cdaSPeter Brune beta[i] = nu - xi[i]; 27519653cdaSPeter Brune } 27619653cdaSPeter Brune 27798b3e84cSPeter Brune /* construct h */ 27819653cdaSPeter Brune for (j = 0; j < l; j++) { 27919653cdaSPeter Brune for (i = 0; i < l; i++) { 28019653cdaSPeter Brune H(i, j) = Q(i, j) - xi[i] - xi[j] + nu; 28119653cdaSPeter Brune } 28219653cdaSPeter Brune } 283f109b39eSPeter Brune 284f109b39eSPeter Brune if(l == 1) { 285f109b39eSPeter Brune /* simply set alpha[0] = beta[0] / H[0, 0] */ 286f109b39eSPeter Brune beta[0] = beta[0] / H(0, 0); 287f109b39eSPeter Brune } else { 28819653cdaSPeter Brune #ifdef PETSC_MISSING_LAPACK_GELSS 28919653cdaSPeter Brune SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "NGMRES with LS requires the LAPACK GELSS routine."); 2904a0c5b0cSMatthew G Knepley #else 29119653cdaSPeter Brune ngmres->m = PetscBLASIntCast(l); 29219653cdaSPeter Brune ngmres->n = PetscBLASIntCast(l); 29319653cdaSPeter Brune ngmres->info = PetscBLASIntCast(0); 29419653cdaSPeter Brune ngmres->rcond = -1.; 29519653cdaSPeter Brune #ifdef PETSC_USE_COMPLEX 29619653cdaSPeter Brune LAPACKgelss_(&ngmres->m, 29719653cdaSPeter Brune &ngmres->n, 29819653cdaSPeter Brune &ngmres->nrhs, 29919653cdaSPeter Brune ngmres->h, 30019653cdaSPeter Brune &ngmres->lda, 30119653cdaSPeter Brune ngmres->beta, 30219653cdaSPeter Brune &ngmres->ldb, 30319653cdaSPeter Brune ngmres->s, 30419653cdaSPeter Brune &ngmres->rcond, 30519653cdaSPeter Brune &ngmres->rank, 30619653cdaSPeter Brune ngmres->work, 30719653cdaSPeter Brune &ngmres->lwork, 30819653cdaSPeter Brune ngmres->rwork, 30919653cdaSPeter Brune &ngmres->info); 31019653cdaSPeter Brune #else 31119653cdaSPeter Brune LAPACKgelss_(&ngmres->m, 31219653cdaSPeter Brune &ngmres->n, 31319653cdaSPeter Brune &ngmres->nrhs, 31419653cdaSPeter Brune ngmres->h, 31519653cdaSPeter Brune &ngmres->lda, 31619653cdaSPeter Brune ngmres->beta, 31719653cdaSPeter Brune &ngmres->ldb, 31819653cdaSPeter Brune ngmres->s, 31919653cdaSPeter Brune &ngmres->rcond, 32019653cdaSPeter Brune &ngmres->rank, 32119653cdaSPeter Brune ngmres->work, 32219653cdaSPeter Brune &ngmres->lwork, 32319653cdaSPeter Brune &ngmres->info); 32419653cdaSPeter Brune #endif 32519653cdaSPeter Brune if (ngmres->info < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Bad argument to GELSS"); 32619653cdaSPeter Brune if (ngmres->info > 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SVD failed to converge"); 327a312c225SMatthew G Knepley #endif 328f109b39eSPeter Brune } 329a312c225SMatthew G Knepley 33019653cdaSPeter Brune alph_total = 0.; 33119653cdaSPeter Brune for (i = 0; i < l; i++) { 33219653cdaSPeter Brune alph_total += beta[i]; 333c0bbabecSxuemin } 334f109b39eSPeter Brune 3359f425c49SPeter Brune ierr = VecCopy(XM, XA);CHKERRQ(ierr); 336f109b39eSPeter Brune ierr = VecScale(XA, 1. - alph_total);CHKERRQ(ierr); 337087dfb9eSxuemin 3388c09b6b7SPeter Brune ierr = VecMAXPY(XA, l, beta, Xdot);CHKERRQ(ierr); 339f109b39eSPeter Brune ierr = SNESComputeFunction(snes, XA, FA);CHKERRQ(ierr); 340f109b39eSPeter Brune ierr = VecNorm(FA, NORM_2, &fAnorm);CHKERRQ(ierr); 34119653cdaSPeter Brune 3429f425c49SPeter Brune /* differences for selection and restart */ 343f109b39eSPeter Brune ierr=VecCopy(XA, D);CHKERRQ(ierr); 344f109b39eSPeter Brune ierr=VecAXPY(D, -1.0, X);CHKERRQ(ierr); 345f109b39eSPeter Brune ierr=VecNorm(D, NORM_2, &dnorm);CHKERRQ(ierr); 346f109b39eSPeter Brune dminnorm = -1.0; 34719653cdaSPeter Brune for(i=0;i<l;i++) { 348f109b39eSPeter Brune ierr=VecCopy(XA, D);CHKERRQ(ierr); 349f109b39eSPeter Brune ierr=VecAXPY(D, -1.0, Xdot[i]);CHKERRQ(ierr); 350f109b39eSPeter Brune ierr=VecNorm(D, NORM_2, &dcurnorm);CHKERRQ(ierr); 351f109b39eSPeter Brune if((dcurnorm < dminnorm) || (dminnorm < 0.0)) dminnorm = dcurnorm; 35219653cdaSPeter Brune } 3539f425c49SPeter Brune 3549f425c49SPeter Brune /* combination (additive) or selection (multiplicative) of the N-GMRES solution */ 3559f425c49SPeter Brune if (ngmres->additive) { 3569f425c49SPeter Brune /* X = X + \lambda(XA - X) */ 3579f425c49SPeter Brune if (ngmres->monitor) { 3589f425c49SPeter Brune ierr = PetscViewerASCIIPrintf(ngmres->monitor, "||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fMnorm);CHKERRQ(ierr); 3599f425c49SPeter Brune } 3609f425c49SPeter Brune ierr = VecCopy(XA, Y);CHKERRQ(ierr); 361eb1825c3SPeter Brune ierr = VecAYPX(Y, -1.0, X);CHKERRQ(ierr); 3629f425c49SPeter Brune ierr = (*snes->ops->linesearch)(snes,snes->lsP,X,F,Y,fnorm,xnorm,FA,XA,&ynorm,&fnorm,&lssucceed);CHKERRQ(ierr); 3639f425c49SPeter Brune if (!lssucceed) { 3649f425c49SPeter Brune if (++snes->numFailures >= snes->maxFailures) { 3659f425c49SPeter Brune snes->reason = SNES_DIVERGED_LINE_SEARCH; 3669f425c49SPeter Brune PetscFunctionReturn(0); 3679f425c49SPeter Brune } 3689f425c49SPeter Brune } 3699f425c49SPeter Brune if (ngmres->monitor) { 3709f425c49SPeter Brune ierr = PetscViewerASCIIPrintf(ngmres->monitor, "Additive solution: ||F||_2 = %e\n", fnorm);CHKERRQ(ierr); 3719f425c49SPeter Brune } 3729f425c49SPeter Brune ierr = VecCopy(FA, F);CHKERRQ(ierr); 3739f425c49SPeter Brune ierr = VecCopy(XA, X);CHKERRQ(ierr); 3749f425c49SPeter Brune } else { 3759f425c49SPeter Brune selectA = PETSC_TRUE; 3769f425c49SPeter Brune /* Conditions for choosing the accelerated answer */ 3779f425c49SPeter Brune /* Criterion A -- the norm of the function isn't increased above the minimum by too much */ 3789f425c49SPeter Brune if (fAnorm >= ngmres->gammaA*fminnorm) { 3799f425c49SPeter Brune selectA = PETSC_FALSE; 3809f425c49SPeter Brune } 3819f425c49SPeter Brune /* Criterion B -- the choice of x^A isn't too close to some other choice */ 382cf22de31SPeter Brune if (ngmres->epsilonB*dnorm<dminnorm || PetscSqrtReal(fnorm)<ngmres->deltaB*PetscSqrtReal(fminnorm)) { 38319653cdaSPeter Brune } else { 38419653cdaSPeter Brune selectA=PETSC_FALSE; 38519653cdaSPeter Brune } 38619653cdaSPeter Brune if (selectA) { 387dfbf837cSBarry Smith if (ngmres->monitor) { 388f109b39eSPeter Brune ierr = PetscViewerASCIIPrintf(ngmres->monitor, "picked X_A, ||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fnorm);CHKERRQ(ierr); 389dfbf837cSBarry Smith } 39098b3e84cSPeter Brune /* copy it over */ 391f109b39eSPeter Brune fnorm = fAnorm; 392f109b39eSPeter Brune nu = fnorm*fnorm; 393f109b39eSPeter Brune ierr = VecCopy(FA, F);CHKERRQ(ierr); 394f109b39eSPeter Brune ierr = VecCopy(XA, X);CHKERRQ(ierr); 39519653cdaSPeter Brune } else { 396dfbf837cSBarry Smith if (ngmres->monitor) { 397f109b39eSPeter Brune ierr = PetscViewerASCIIPrintf(ngmres->monitor, "picked X_M, ||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fnorm);CHKERRQ(ierr); 398dfbf837cSBarry Smith } 3999f425c49SPeter Brune fnorm = fMnorm; 4009f425c49SPeter Brune nu = fnorm*fnorm; 4019f425c49SPeter Brune ierr = VecCopy(FM, F);CHKERRQ(ierr); 4029f425c49SPeter Brune ierr = VecCopy(XM, X);CHKERRQ(ierr); 4039f425c49SPeter Brune } 40419653cdaSPeter Brune } 405211b2d39SPeter Brune 40619653cdaSPeter Brune selectRestart = PETSC_FALSE; 40719653cdaSPeter Brune 40898b3e84cSPeter Brune /* difference stagnation restart */ 409cf22de31SPeter Brune if((ngmres->epsilonB*dnorm > dminnorm) && (PetscSqrtReal(fAnorm) > ngmres->deltaB*PetscSqrtReal(fminnorm))) { 410dfbf837cSBarry Smith if (ngmres->monitor) { 411f109b39eSPeter Brune ierr = PetscViewerASCIIPrintf(ngmres->monitor, "difference restart: %e > %e\n", ngmres->epsilonB*dnorm, dminnorm);CHKERRQ(ierr); 412dfbf837cSBarry Smith } 41319653cdaSPeter Brune selectRestart = PETSC_TRUE; 41419653cdaSPeter Brune } 41598b3e84cSPeter Brune /* residual stagnation restart */ 416cf22de31SPeter Brune if (PetscSqrtReal(fAnorm) > ngmres->gammaC*PetscSqrtReal(fminnorm)) { 417dfbf837cSBarry Smith if (ngmres->monitor) { 418cf22de31SPeter Brune ierr = PetscViewerASCIIPrintf(ngmres->monitor, "residual restart: %e > %e\n", PetscSqrtReal(fAnorm), ngmres->gammaC*PetscSqrtReal(fminnorm));CHKERRQ(ierr); 419dfbf837cSBarry Smith } 42019653cdaSPeter Brune selectRestart = PETSC_TRUE; 42119653cdaSPeter Brune } 42219653cdaSPeter Brune 42328ed4a04SPeter Brune /* if the restart conditions persist for more than restart_it iterations, restart. */ 42419653cdaSPeter Brune if (selectRestart) { 42528ed4a04SPeter Brune restart_count++; 42628ed4a04SPeter Brune } else { 42728ed4a04SPeter Brune restart_count = 0; 42828ed4a04SPeter Brune } 42928ed4a04SPeter Brune 43028ed4a04SPeter Brune /* restart after restart conditions have persisted for a fixed number of iterations */ 43128ed4a04SPeter Brune if (restart_count >= ngmres->restart_it) { 432dfbf837cSBarry Smith if (ngmres->monitor){ 433dfbf837cSBarry Smith ierr = PetscViewerASCIIPrintf(ngmres->monitor, "Restarted at iteration %d\n", k_restart);CHKERRQ(ierr); 434dfbf837cSBarry Smith } 43528ed4a04SPeter Brune restart_count = 0; 43619653cdaSPeter Brune k_restart = 1; 43719653cdaSPeter Brune l = 1; 43898b3e84cSPeter Brune /* q_{00} = nu */ 439f109b39eSPeter Brune ngmres->fnorms[0] = fnorm; 440f109b39eSPeter Brune nu = fnorm*fnorm; 44119653cdaSPeter Brune Q(0,0) = nu; 442f109b39eSPeter Brune /* Fdot[0] = F */ 443f109b39eSPeter Brune ierr = VecCopy(X, Xdot[0]);CHKERRQ(ierr); 444f109b39eSPeter Brune ierr = VecCopy(F, Fdot[0]);CHKERRQ(ierr); 44519653cdaSPeter Brune } else { 44698b3e84cSPeter Brune /* select the current size of the subspace */ 4471e633543SBarry Smith if (l < ngmres->msize) l++; 44819653cdaSPeter Brune k_restart++; 44998b3e84cSPeter Brune /* place the current entry in the list of previous entries */ 450f109b39eSPeter Brune ierr = VecCopy(F, Fdot[ivec]);CHKERRQ(ierr); 451f109b39eSPeter Brune ierr = VecCopy(X, Xdot[ivec]);CHKERRQ(ierr); 452f109b39eSPeter Brune ngmres->fnorms[ivec] = fnorm; 453f109b39eSPeter Brune if (fminnorm > fnorm) fminnorm = fnorm; /* the minimum norm is now of r^A */ 45419653cdaSPeter Brune for (i = 0; i < l; i++) { 455f109b39eSPeter Brune ierr = VecDot(F, Fdot[i], &qentry);CHKERRQ(ierr); 45619653cdaSPeter Brune Q(i, ivec) = qentry; 45719653cdaSPeter Brune Q(ivec, i) = qentry; 45819653cdaSPeter Brune } 45919653cdaSPeter Brune } 46019653cdaSPeter Brune 4618409ca45SMatthew G Knepley ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 462087dfb9eSxuemin snes->iter = k; 463f109b39eSPeter Brune snes->norm = fnorm; 4648409ca45SMatthew G Knepley ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 4658409ca45SMatthew G Knepley SNESLogConvHistory(snes, snes->norm, snes->iter); 4668409ca45SMatthew G Knepley ierr = SNESMonitor(snes, snes->iter, snes->norm);CHKERRQ(ierr); 4678409ca45SMatthew G Knepley 468f109b39eSPeter Brune ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 469087dfb9eSxuemin if (snes->reason) PetscFunctionReturn(0); 470a312c225SMatthew G Knepley } 471a312c225SMatthew G Knepley snes->reason = SNES_DIVERGED_MAX_IT; 472a312c225SMatthew G Knepley PetscFunctionReturn(0); 473a312c225SMatthew G Knepley } 474a312c225SMatthew G Knepley 475dfbf837cSBarry Smith /*MC 476dfbf837cSBarry Smith SNESNGMRES - The Nonlinear Generalized Minimum Residual (NGMRES) method of Oosterlee and Washio. 477a312c225SMatthew G Knepley 478dfbf837cSBarry Smith Level: beginner 479dfbf837cSBarry Smith 480dfbf837cSBarry Smith "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio, 481dfbf837cSBarry Smith SIAM Journal on Scientific Computing, 21(5), 2000. 482dfbf837cSBarry Smith 483dfbf837cSBarry Smith This is also the same as the algorithm called Anderson acceleration introduced in "D. G. Anderson. Iterative procedures for nonlinear integral equations. 484dfbf837cSBarry Smith J. Assoc. Comput. Mach., 12:547–560, 1965." 485dfbf837cSBarry Smith 486dfbf837cSBarry Smith .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types) 487dfbf837cSBarry Smith M*/ 488a312c225SMatthew G Knepley 489a312c225SMatthew G Knepley EXTERN_C_BEGIN 490a312c225SMatthew G Knepley #undef __FUNCT__ 491a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES" 492a312c225SMatthew G Knepley PetscErrorCode SNESCreate_NGMRES(SNES snes) 493a312c225SMatthew G Knepley { 494a312c225SMatthew G Knepley SNES_NGMRES *ngmres; 495a312c225SMatthew G Knepley PetscErrorCode ierr; 496a312c225SMatthew G Knepley 497a312c225SMatthew G Knepley PetscFunctionBegin; 498a312c225SMatthew G Knepley snes->ops->destroy = SNESDestroy_NGMRES; 499a312c225SMatthew G Knepley snes->ops->setup = SNESSetUp_NGMRES; 500a312c225SMatthew G Knepley snes->ops->setfromoptions = SNESSetFromOptions_NGMRES; 501a312c225SMatthew G Knepley snes->ops->view = SNESView_NGMRES; 502a312c225SMatthew G Knepley snes->ops->solve = SNESSolve_NGMRES; 503a312c225SMatthew G Knepley snes->ops->reset = SNESReset_NGMRES; 504a312c225SMatthew G Knepley 50542f4f86dSBarry Smith snes->usespc = PETSC_TRUE; 5062c155ee1SBarry Smith snes->usesksp = PETSC_FALSE; 5072c155ee1SBarry Smith 508a312c225SMatthew G Knepley ierr = PetscNewLog(snes, SNES_NGMRES, &ngmres);CHKERRQ(ierr); 509a312c225SMatthew G Knepley snes->data = (void*) ngmres; 51019653cdaSPeter Brune ngmres->msize = 10; 51119653cdaSPeter Brune 512*0e444f03SPeter Brune snes->max_funcs = 30000; 513*0e444f03SPeter Brune snes->max_its = 10000; 514*0e444f03SPeter Brune 51528ed4a04SPeter Brune ngmres->restart_it = 2; 516f109b39eSPeter Brune ngmres->gammaA = 2.0; 517f109b39eSPeter Brune ngmres->gammaC = 2.0; 518cac108bcSPeter Brune ngmres->deltaB = 0.9; 519cac108bcSPeter Brune ngmres->epsilonB = 0.1; 520f109b39eSPeter Brune ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetType_C","SNESLineSearchSetType_NGMRES",SNESLineSearchSetType_NGMRES);CHKERRQ(ierr); 521f109b39eSPeter Brune ierr = SNESLineSearchSetType(snes, SNES_LS_QUADRATIC);CHKERRQ(ierr); 522a312c225SMatthew G Knepley PetscFunctionReturn(0); 523a312c225SMatthew G Knepley } 524a312c225SMatthew G Knepley EXTERN_C_END 525