1a312c225SMatthew G Knepley /* Defines the basic SNES object */ 2a312c225SMatthew G Knepley #include <private/snesimpl.h> 3a312c225SMatthew G Knepley 4a312c225SMatthew G Knepley /* Private structure for the Anderson mixing method aka nonlinear Krylov */ 5a312c225SMatthew G Knepley typedef struct { 6a312c225SMatthew G Knepley Vec *v, *w; 7a312c225SMatthew G Knepley PetscReal *f2; /* 2-norms of function (residual) at each stage */ 8a312c225SMatthew G Knepley PetscInt msize; /* maximum size of space */ 9a312c225SMatthew G Knepley PetscInt csize; /* current size of space */ 10a312c225SMatthew G Knepley } SNES_NGMRES; 11a312c225SMatthew G Knepley 12a312c225SMatthew G Knepley #undef __FUNCT__ 13a312c225SMatthew G Knepley #define __FUNCT__ "SNESReset_NGMRES" 14a312c225SMatthew G Knepley PetscErrorCode SNESReset_NGMRES(SNES snes) 15a312c225SMatthew G Knepley { 16a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data; 17a312c225SMatthew G Knepley PetscErrorCode ierr; 18a312c225SMatthew G Knepley 19a312c225SMatthew G Knepley PetscFunctionBegin; 20a312c225SMatthew G Knepley ierr = VecDestroyVecs(ngmres->msize, &ngmres->v);CHKERRQ(ierr); 21a312c225SMatthew G Knepley ierr = VecDestroyVecs(ngmres->msize, &ngmres->w);CHKERRQ(ierr); 22a312c225SMatthew G Knepley PetscFunctionReturn(0); 23a312c225SMatthew G Knepley } 24a312c225SMatthew G Knepley 25a312c225SMatthew G Knepley #undef __FUNCT__ 26a312c225SMatthew G Knepley #define __FUNCT__ "SNESDestroy_NGMRES" 27a312c225SMatthew G Knepley PetscErrorCode SNESDestroy_NGMRES(SNES snes) 28a312c225SMatthew G Knepley { 29a312c225SMatthew G Knepley PetscErrorCode ierr; 30a312c225SMatthew G Knepley 31a312c225SMatthew G Knepley PetscFunctionBegin; 32a312c225SMatthew G Knepley ierr = SNESReset_NGMRES(snes);CHKERRQ(ierr); 33a312c225SMatthew G Knepley if (snes->work) {ierr = VecDestroyVecs(snes->nwork, &snes->work);CHKERRQ(ierr);} 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; 42a312c225SMatthew G Knepley PetscErrorCode ierr; 43a312c225SMatthew G Knepley 44a312c225SMatthew G Knepley PetscFunctionBegin; 45a312c225SMatthew G Knepley #if 0 46a312c225SMatthew G Knepley if (snes->pc_side != PC_LEFT) {SETERRQ(((PetscObject) snes)->comm, PETSC_ERR_SUP, "Only left preconditioning allowed for SNESNGMRES");} 47a312c225SMatthew G Knepley #endif 48a312c225SMatthew G Knepley ierr = VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->v);CHKERRQ(ierr); 49a312c225SMatthew G Knepley ierr = VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->w);CHKERRQ(ierr); 50*4a0c5b0cSMatthew G Knepley ierr = SNESDefaultGetWork(snes, 1);CHKERRQ(ierr); 51a312c225SMatthew G Knepley PetscFunctionReturn(0); 52a312c225SMatthew G Knepley } 53a312c225SMatthew G Knepley 54a312c225SMatthew G Knepley #undef __FUNCT__ 55a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES" 56a312c225SMatthew G Knepley PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes) 57a312c225SMatthew G Knepley { 58a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES *) snes->data; 59a312c225SMatthew G Knepley PetscErrorCode ierr; 60a312c225SMatthew G Knepley 61a312c225SMatthew G Knepley PetscFunctionBegin; 62a312c225SMatthew G Knepley ierr = PetscOptionsHead("SNES NGMRES options");CHKERRQ(ierr); 63a312c225SMatthew G Knepley ierr = PetscOptionsInt("-snes_gmres_restart", "Number of directions", "SNES", ngmres->msize, &ngmres->msize, PETSC_NULL);CHKERRQ(ierr); 64a312c225SMatthew G Knepley ierr = PetscOptionsTail();CHKERRQ(ierr); 65a312c225SMatthew G Knepley PetscFunctionReturn(0); 66a312c225SMatthew G Knepley } 67a312c225SMatthew G Knepley 68a312c225SMatthew G Knepley #undef __FUNCT__ 69a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES" 70a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes, PetscViewer viewer) 71a312c225SMatthew G Knepley { 72a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES *) snes->data; 73a312c225SMatthew G Knepley PetscBool iascii; 74a312c225SMatthew G Knepley PetscErrorCode ierr; 75a312c225SMatthew G Knepley 76a312c225SMatthew G Knepley PetscFunctionBegin; 77a312c225SMatthew G Knepley ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 78a312c225SMatthew G Knepley if (iascii) { 79a312c225SMatthew G Knepley ierr = PetscViewerASCIIPrintf(viewer, " Size of space %d\n", ngmres->msize);CHKERRQ(ierr); 80a312c225SMatthew G Knepley } else { 81a312c225SMatthew G Knepley SETERRQ1(((PetscObject) snes)->comm, PETSC_ERR_SUP, "Viewer type %s not supported for SNESNGMRES", ((PetscObject) viewer)->type_name); 82a312c225SMatthew G Knepley } 83a312c225SMatthew G Knepley PetscFunctionReturn(0); 84a312c225SMatthew G Knepley } 85a312c225SMatthew G Knepley 86a312c225SMatthew G Knepley #undef __FUNCT__ 87a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES" 88a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes) 89a312c225SMatthew G Knepley { 90a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES *) snes->data; 91*4a0c5b0cSMatthew G Knepley SNES pc; 92*4a0c5b0cSMatthew G Knepley Vec X, Y, F, r, rOld, *V = ngmres->v, *W = ngmres->w; 93a312c225SMatthew G Knepley PetscScalar wdot; 94a312c225SMatthew G Knepley PetscReal fnorm; 95a312c225SMatthew G Knepley PetscInt i, j, k; 96a312c225SMatthew G Knepley PetscErrorCode ierr; 97a312c225SMatthew G Knepley 98a312c225SMatthew G Knepley PetscFunctionBegin; 99a312c225SMatthew G Knepley snes->reason = SNES_CONVERGED_ITERATING; 100a312c225SMatthew G Knepley X = snes->vec_sol; 101a312c225SMatthew G Knepley Y = snes->vec_sol_update; 102a312c225SMatthew G Knepley F = snes->vec_func; 103*4a0c5b0cSMatthew G Knepley rOld = snes->work[0]; 104a312c225SMatthew G Knepley 105*4a0c5b0cSMatthew G Knepley ierr = SNESGetPC(snes, &pc);CHKERRQ(ierr); 106a312c225SMatthew G Knepley ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 107a312c225SMatthew G Knepley snes->iter = 0; 108a312c225SMatthew G Knepley snes->norm = 0.; 109a312c225SMatthew G Knepley ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 110*4a0c5b0cSMatthew G Knepley ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 111a312c225SMatthew G Knepley if (snes->domainerror) { 112a312c225SMatthew G Knepley snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 113a312c225SMatthew G Knepley PetscFunctionReturn(0); 114a312c225SMatthew G Knepley } 115*4a0c5b0cSMatthew G Knepley ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); 116a312c225SMatthew G Knepley if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Infinite or not-a-number generated in norm"); 117a312c225SMatthew G Knepley ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 118a312c225SMatthew G Knepley snes->norm = fnorm; 119a312c225SMatthew G Knepley ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 120a312c225SMatthew G Knepley SNESLogConvHistory(snes, fnorm, 0); 121a312c225SMatthew G Knepley ierr = SNESMonitor(snes, 0, fnorm);CHKERRQ(ierr); 122a312c225SMatthew G Knepley 123a312c225SMatthew G Knepley /* set parameter for default relative tolerance convergence test */ 124a312c225SMatthew G Knepley snes->ttol = fnorm*snes->rtol; 125a312c225SMatthew G Knepley /* test convergence */ 126a312c225SMatthew G Knepley ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 127a312c225SMatthew G Knepley if (snes->reason) PetscFunctionReturn(0); 128a312c225SMatthew G Knepley 129*4a0c5b0cSMatthew G Knepley #ifndef OLD_BARRY_CODE 130*4a0c5b0cSMatthew G Knepley ierr = VecCopy(F, rOld);CHKERRQ(ierr); 131*4a0c5b0cSMatthew G Knepley #else 132*4a0c5b0cSMatthew G Knepley /* Barry: What the heck is this part doing? */ 133a312c225SMatthew G Knepley /* determine optimal scale factor -- slow code */ 134a312c225SMatthew G Knepley ierr = VecDuplicate(P, &y);CHKERRQ(ierr); 135a312c225SMatthew G Knepley ierr = VecDuplicate(P, &w);CHKERRQ(ierr); 136a312c225SMatthew G Knepley ierr = MatMult(Amat, Pold, y);CHKERRQ(ierr); 137a312c225SMatthew G Knepley /*ierr = KSP_PCApplyBAorAB(ksp,Pold,y,w);CHKERRQ(ierr); */ /* y = BAp */ 138a312c225SMatthew G Knepley ierr = VecDotNorm2(Pold, y, &rdot, &abr);CHKERRQ(ierr); /* rdot = (p)^T(BAp); abr = (BAp)^T (BAp) */ 139a312c225SMatthew G Knepley ierr = VecDestroy(&y);CHKERRQ(ierr); 140a312c225SMatthew G Knepley ierr = VecDestroy(&w);CHKERRQ(ierr); 141a312c225SMatthew G Knepley A0 = rdot/abr; 142a312c225SMatthew G Knepley ierr = VecAXPY(X,A0,Pold);CHKERRQ(ierr); /* x <- x + scale p */ 143a312c225SMatthew G Knepley #endif 144a312c225SMatthew G Knepley 145a312c225SMatthew G Knepley /* Loop over batches of directions */ 14631823bd8SMatthew G Knepley /* Code from Barry I do not understand to solve the least-squares problem, Time to try again */ 147a312c225SMatthew G Knepley for(k = 0; k < snes->max_its; k += ngmres->msize) { 148a312c225SMatthew G Knepley /* Loop over updates for this batch */ 149a312c225SMatthew G Knepley /* TODO: Incorporate the variant which use the analytic Jacobian */ 150*4a0c5b0cSMatthew G Knepley /* TODO: Incorporate selection criteria for u^A from paper (need to store residual and update norms) */ 151a312c225SMatthew G Knepley /* TODO: Incorporate criteria for restarting from paper */ 152a312c225SMatthew G Knepley for(i = 0; i < ngmres->msize && k+i < snes->max_its; ++i) { 153*4a0c5b0cSMatthew G Knepley /* Get a new approxiate solution u^k */ 154*4a0c5b0cSMatthew G Knepley ierr = SNESSolve(pc, PETSC_NULL, X);CHKERRQ(ierr); 155*4a0c5b0cSMatthew G Knepley /* Solve least squares problem using last msize iterates */ 156*4a0c5b0cSMatthew G Knepley ierr = SNESGetFunction(pc, &r, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); /* r = F(u^M) */ 157*4a0c5b0cSMatthew G Knepley for(j = 0; j < i; ++j) { /* r = \prod_j (I + v_j w^T_j) r */ 158*4a0c5b0cSMatthew G Knepley ierr = VecDot(W[j], r, &wdot);CHKERRQ(ierr); 159*4a0c5b0cSMatthew G Knepley ierr = VecAXPY(r, wdot, V[j]);CHKERRQ(ierr); 160a312c225SMatthew G Knepley } 161*4a0c5b0cSMatthew G Knepley ierr = VecCopy(rOld, W[i]);CHKERRQ(ierr); /* w_i = r_{old} */ 162*4a0c5b0cSMatthew G Knepley ierr = VecAXPY(rOld, -1.0, r);CHKERRQ(ierr); /* v_i = r */ 163*4a0c5b0cSMatthew G Knepley ierr = VecDot(W[i], rOld, &wdot);CHKERRQ(ierr); /* ------------------- */ 164*4a0c5b0cSMatthew G Knepley ierr = VecCopy(r, V[i]);CHKERRQ(ierr); /* w^T_i (r_{old} - r) */ 165a312c225SMatthew G Knepley ierr = VecScale(V[i], 1.0/wdot);CHKERRQ(ierr); 166*4a0c5b0cSMatthew G Knepley ierr = VecDot(W[i], r, &wdot);CHKERRQ(ierr); /* r = (I + v_i w^T_i) r */ 167*4a0c5b0cSMatthew G Knepley ierr = VecAXPY(r, wdot, V[i]);CHKERRQ(ierr); 168*4a0c5b0cSMatthew G Knepley ierr = VecCopy(r, rOld);CHKERRQ(ierr); /* r_{old} = r */ 169a312c225SMatthew G Knepley 170*4a0c5b0cSMatthew G Knepley ierr = VecAXPY(X, 1.0, r);CHKERRQ(ierr); /* u^A = u^M + r */ 171*4a0c5b0cSMatthew G Knepley /* Monitor and log history */ 172*4a0c5b0cSMatthew G Knepley ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); /* F(u^k) */ 173*4a0c5b0cSMatthew G Knepley ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); 174*4a0c5b0cSMatthew G Knepley SNESLogConvHistory(snes, fnorm, 0); 175*4a0c5b0cSMatthew G Knepley ierr = SNESMonitor(snes, i+k+1, fnorm);CHKERRQ(ierr); 176*4a0c5b0cSMatthew G Knepley /* Check convergence */ 177*4a0c5b0cSMatthew G Knepley ierr = (*snes->ops->converged)(snes, i+k+1, 0.0, 0.0, fnorm, &snes->reason, snes->cnvP);CHKERRQ(ierr); 178*4a0c5b0cSMatthew G Knepley if (snes->reason) PetscFunctionReturn(0); 179*4a0c5b0cSMatthew G Knepley /* Select update between u^M and u^A */ 180*4a0c5b0cSMatthew G Knepley /* Decide whether to restart */ 181a312c225SMatthew G Knepley } 182a312c225SMatthew G Knepley } 183a312c225SMatthew G Knepley snes->reason = SNES_DIVERGED_MAX_IT; 184a312c225SMatthew G Knepley PetscFunctionReturn(0); 185a312c225SMatthew G Knepley } 186a312c225SMatthew G Knepley 187a312c225SMatthew G Knepley /*MC 188a312c225SMatthew G Knepley SNESNGMRES - The Nonlinear Generalized Minimum Residual (NGMRES) method of Oosterlee and Washio. 189a312c225SMatthew G Knepley 190a312c225SMatthew G Knepley Level: beginner 191a312c225SMatthew G Knepley 192a312c225SMatthew G Knepley Notes: Supports only left preconditioning 193a312c225SMatthew G Knepley 194a312c225SMatthew G Knepley "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio, 195a312c225SMatthew G Knepley SIAM Journal on Scientific Computing, 21(5), 2000. 196a312c225SMatthew G Knepley 197a312c225SMatthew G Knepley .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types) 198a312c225SMatthew G Knepley M*/ 199a312c225SMatthew G Knepley EXTERN_C_BEGIN 200a312c225SMatthew G Knepley #undef __FUNCT__ 201a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES" 202a312c225SMatthew G Knepley PetscErrorCode SNESCreate_NGMRES(SNES snes) 203a312c225SMatthew G Knepley { 204a312c225SMatthew G Knepley SNES_NGMRES *ngmres; 205a312c225SMatthew G Knepley PetscErrorCode ierr; 206a312c225SMatthew G Knepley 207a312c225SMatthew G Knepley PetscFunctionBegin; 208a312c225SMatthew G Knepley snes->ops->destroy = SNESDestroy_NGMRES; 209a312c225SMatthew G Knepley snes->ops->setup = SNESSetUp_NGMRES; 210a312c225SMatthew G Knepley snes->ops->setfromoptions = SNESSetFromOptions_NGMRES; 211a312c225SMatthew G Knepley snes->ops->view = SNESView_NGMRES; 212a312c225SMatthew G Knepley snes->ops->solve = SNESSolve_NGMRES; 213a312c225SMatthew G Knepley snes->ops->reset = SNESReset_NGMRES; 214a312c225SMatthew G Knepley 215a312c225SMatthew G Knepley ierr = PetscNewLog(snes, SNES_NGMRES, &ngmres);CHKERRQ(ierr); 216a312c225SMatthew G Knepley snes->data = (void*) ngmres; 217a312c225SMatthew G Knepley ngmres->msize = 30; 218a312c225SMatthew G Knepley ngmres->csize = 0; 219*4a0c5b0cSMatthew G Knepley 220*4a0c5b0cSMatthew G Knepley ierr = SNESGetPC(snes, &snes->pc);CHKERRQ(ierr); 221a312c225SMatthew G Knepley #if 0 222a312c225SMatthew G Knepley if (ksp->pc_side != PC_LEFT) {ierr = PetscInfo(ksp,"WARNING! Setting PC_SIDE for NGMRES to left!\n");CHKERRQ(ierr);} 223a312c225SMatthew G Knepley snes->pc_side = PC_LEFT; 224a312c225SMatthew G Knepley #endif 225a312c225SMatthew G Knepley PetscFunctionReturn(0); 226a312c225SMatthew G Knepley } 227a312c225SMatthew G Knepley EXTERN_C_END 228