xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision 4a0c5b0c254533510f18d4cc0ff9d9f9e759c2a4)
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