Actual source code: broyden.c

  2: #include <../src/ksp/ksp/impls/broyden/broydenimpl.h>       /*I "petscksp.h" I*/


  5: /*
  6:      KSPSetUp_Broyden - Sets up the workspace needed by the Broyden method. 

  8:       This is called once, usually automatically by KSPSolve() or KSPSetUp().
  9: */
 12: PetscErrorCode KSPSetUp_Broyden(KSP ksp)
 13: {
 14:   KSP_Broyden    *cgP = (KSP_Broyden*)ksp->data;

 18:   /* 
 19:        This implementation of Broyden only handles left preconditioning
 20:      so generate an error otherwise.
 21:   */
 22:   if (ksp->pc_side == PC_RIGHT) SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"No right preconditioning for KSPBroyden");
 23:   else if (ksp->pc_side == PC_SYMMETRIC) SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"No symmetric preconditioning for KSPBroyden");
 24:   KSPGetVecs(ksp,cgP->msize,&cgP->v,cgP->msize,&cgP->w);
 25:   KSPDefaultGetWork(ksp,3);
 26:   return(0);
 27: }

 29: /*
 30:        KSPSolve_Broyden - This routine actually applies the method


 33:    Input Parameter:
 34: .     ksp - the Krylov space object that was set to use conjugate gradient, by, for 
 35:             example, KSPCreate(MPI_Comm,KSP *ksp); KSPSetType(ksp,KSPBROYDEN);
 36: */
 39: PetscErrorCode  KSPSolve_Broyden(KSP ksp)
 40: {
 42:   PetscInt       i,j,k;
 43:   KSP_Broyden    *cg = (KSP_Broyden*)ksp->data;
 44:   Mat            Amat;
 45:   Vec            X,B,R,Pold,P,*V = cg->v,*W = cg->w;
 46:   PetscScalar    gdot,A0;
 47:   PetscReal      gnorm;

 50:   X             = ksp->vec_sol;
 51:   B             = ksp->vec_rhs;
 52:   R             = ksp->work[0];
 53:   Pold          = ksp->work[1];
 54:   P             = ksp->work[2];
 55:   PCGetOperators(ksp->pc,&Amat,PETSC_NULL,PETSC_NULL);

 57:   if (!ksp->guess_zero) {
 58:     KSP_MatMult(ksp,Amat,X,R);            /*     r <- b - Ax     */
 59:     VecAYPX(R,-1.0,B);
 60:   } else {
 61:     VecCopy(B,R);                         /*     r <- b (x is 0) */
 62:   }
 63:   PCApply(ksp->pc,R,Pold);                /*     p = B r */
 64:   if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {
 65:     VecNorm(R,NORM_2,&gnorm);
 66:   } else if (ksp->normtype == KSP_NORM_PRECONDITIONED) {
 67:     VecNorm(Pold,NORM_2,&gnorm);
 68:   } else SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"NormType not supported");
 69:   KSPLogResidualHistory(ksp,gnorm);
 70:   KSPMonitor(ksp,0,gnorm);
 71:   (*ksp->converged)(ksp,0,gnorm,&ksp->reason,ksp->cnvP);

 73:   if (1) {
 74:     PetscScalar rdot,abr;
 75:     Vec         y,w;
 76:     VecDuplicate(P,&y);
 77:     VecDuplicate(P,&w);
 78:     MatMult(Amat,Pold,y);
 79:     KSP_PCApplyBAorAB(ksp,Pold,y,w);      /* y = BAp */
 80:     VecDotNorm2(Pold,y,&rdot,&abr);   /*   rdot = (p)^T(BAp); abr = (BAp)^T (BAp) */
 81:     VecDestroy(&y);
 82:     VecDestroy(&w);
 83:     A0 = rdot/abr;
 84:     VecAXPY(X,A0,Pold);             /*   x  <- x + scale p */
 85:   } else {
 86:     VecAXPY(X,1.0,Pold);                    /*     x = x + p */
 87:   }

 89:   for (k=0; k<ksp->max_it; k += cg->msize) {
 90:     for (i=0; i<cg->msize && k+i<ksp->max_it; i++) {
 91:       KSP_MatMult(ksp,Amat,X,R);            /*     r <- b - Ax     */
 92:       VecAYPX(R,-1.0,B);

 94:       PCApply(ksp->pc,R,P);                 /*     p = B r */
 95:       if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {
 96:         VecNorm(R,NORM_2,&gnorm);
 97:       } else if (ksp->normtype == KSP_NORM_PRECONDITIONED) {
 98:         VecNorm(P,NORM_2,&gnorm);
 99:       } else SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"NormType not supported");
100:       KSPLogResidualHistory(ksp,gnorm);
101:       KSPMonitor(ksp,(1+k+i),gnorm);
102:       (*ksp->converged)(ksp,1+k+i,gnorm,&ksp->reason,ksp->cnvP);
103:       if (ksp->reason) return(0);

105:       if (1) {
106:         VecScale(P,A0);
107:       }

109:       for (j=0; j<i; j++) {                                     /* p = product_{j<i} [I+v(j)w(j)^T]*p */
110:         VecDot(W[j],P,&gdot);
111:         VecAXPY(P,gdot,V[j]);
112:       }
113:       VecCopy(Pold,W[i]);                   /* w[i] = Pold */

115:       VecAXPY(Pold,-1.0,P);                 /* v[i] =       p           */
116:       VecDot(W[i],Pold,&gdot);             /*        ----------------- */
117:       VecCopy(P,V[i]);                      /*         w[i]'*(Pold - p)    */
118:       VecScale(V[i],1.0/gdot);

120:       VecDot(W[i],P,&gdot);                /* p = (I + v[i]*w[i]')*p  */
121:       VecAXPY(P,gdot,V[i]);
122:       VecCopy(P,Pold);

124:       if (1) {
125:         PetscScalar rdot,abr;
126:         Vec         y,w;
127:         VecDuplicate(P,&y);
128:         VecDuplicate(P,&w);
129:         MatMult(Amat,P,y);
130:     KSP_PCApplyBAorAB(ksp,P,y,w);      /* y = BAp */
131:         VecDotNorm2(P,y,&rdot,&abr);   /*   rdot = (p)^T(BAp); abr = (BAp)^T (BAp) */
132:         VecDestroy(&y);
133:         VecDestroy(&w);
134:         VecAXPY(X,rdot/abr,P);             /*   x  <- x + scale p */
135:       } else {
136:         VecAXPY(X,1.0,P);                    /* x = x + p */
137:       }
138:     }
139:   }
140:   ksp->reason = KSP_DIVERGED_ITS;
141:   return(0);
142: }
143: /*
144:        KSPDestroy_Broyden - Frees all memory space used by the Krylov method

146: */
149: PetscErrorCode KSPReset_Broyden(KSP ksp)
150: {
151:   KSP_Broyden    *cg = (KSP_Broyden*)ksp->data;

155:   if (cg->v) {VecDestroyVecs(cg->msize,&cg->v);}
156:   if (cg->w) {VecDestroyVecs(cg->msize,&cg->w);}
157:   return(0);
158: }

162: PetscErrorCode KSPDestroy_Broyden(KSP ksp)
163: {

167:   KSPReset_Broyden(ksp);
168:   KSPDefaultDestroy(ksp);
169:   return(0);
170: }

172: /*
173:      KSPView_Broyden - Prints information about the current Krylov method being used

175: */
178: PetscErrorCode KSPView_Broyden(KSP ksp,PetscViewer viewer)
179: {
180:   KSP_Broyden    *cg = (KSP_Broyden *)ksp->data;
182:   PetscBool      iascii;

185:   PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
186:   if (iascii) {
187:     PetscViewerASCIIPrintf(viewer,"  Size of space %d\n",cg->msize);
188:   } else {
189:     SETERRQ1(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for KSP cg",((PetscObject)viewer)->type_name);
190:   }
191:   return(0);
192: }

194: /*
195:     KSPSetFromOptions_Broyden - Checks the options database for options related to the  method
196: */
199: PetscErrorCode KSPSetFromOptions_Broyden(KSP ksp)
200: {
202:   KSP_Broyden    *cg = (KSP_Broyden *)ksp->data;

205:   PetscOptionsHead("KSP Broyden options");
206:     PetscOptionsInt("-ksp_broyden_restart","Number of directions","None",cg->msize,&cg->msize,PETSC_NULL);
207:   PetscOptionsTail();
208:   return(0);
209: }

211: /*
212:     KSPCreate_Broyden - Creates the data structure for the Krylov method Broyden and sets the 
213:        function pointers for all the routines it needs to call (KSPSolve_Broyden() etc)

216: */
217: /*MC
218:      KSPBROYDEN - Limited memory "bad" Broyden method implemented for linear problems.

220:    Level: beginner

222:    Notes: Supports only left preconditioning

224:           Implemented for experimentation reasons, not intended to replace any of the Krylov methods

226: .seealso:  KSPCreate(), KSPSetType(), KSPType (for list of available types), KSP

228: M*/
232: PetscErrorCode  KSPCreate_Broyden(KSP ksp)
233: {
235:   KSP_Broyden    *cg;

238:   PetscNewLog(ksp,KSP_Broyden,&cg);
239:   ksp->data = (void*)cg;
240:   cg->msize = 30;
241:   cg->csize = 0;

243:   KSPSetSupportedNorm(ksp,KSP_NORM_PRECONDITIONED,PC_LEFT,2);
244:   KSPSetSupportedNorm(ksp,KSP_NORM_UNPRECONDITIONED,PC_LEFT,1);

246:   /*
247:        Sets the functions that are associated with this data structure 
248:        (in C++ this is the same as defining virtual functions)
249:   */
250:   ksp->ops->setup                = KSPSetUp_Broyden;
251:   ksp->ops->solve                = KSPSolve_Broyden;
252:   ksp->ops->reset                = KSPReset_Broyden;
253:   ksp->ops->destroy              = KSPDestroy_Broyden;
254:   ksp->ops->view                 = KSPView_Broyden;
255:   ksp->ops->setfromoptions       = KSPSetFromOptions_Broyden;
256:   ksp->ops->buildsolution        = KSPDefaultBuildSolution;
257:   ksp->ops->buildresidual        = KSPDefaultBuildResidual;
258:   return(0);
259: }