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