Actual source code: pjd.c

slepc-3.6.1 2015-09-03
Report Typos and Errors
  1: /*

  3:    SLEPc polynomial eigensolver: "jd"

  5:    Method: Jacobi-Davidson

  7:    Algorithm:

  9:        Jacobi-Davidson for polynomial eigenvalue problems.
 10:        Based on code contributed by the authors of [2] below.

 12:    References:

 14:        [1] G.L.G. Sleijpen et al., "Jacobi-Davidson type methods for
 15:            generalized eigenproblems and polynomial eigenproblems", BIT
 16:            36(3):595-633, 1996.

 18:        [2] Feng-Nan Hwang, Zih-Hao Wei, Tsung-Ming Huang, Weichung Wang,
 19:            "A Parallel Additive Schwarz Preconditioned Jacobi-Davidson
 20:            Algorithm for Polynomial Eigenvalue Problems in Quantum Dot
 21:            Simulation", J. Comput. Phys. 229(8):2932-2947, 2010.

 23:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 24:    SLEPc - Scalable Library for Eigenvalue Problem Computations
 25:    Copyright (c) 2002-2015, Universitat Politecnica de Valencia, Spain

 27:    This file is part of SLEPc.

 29:    SLEPc is free software: you can redistribute it and/or modify it under  the
 30:    terms of version 3 of the GNU Lesser General Public License as published by
 31:    the Free Software Foundation.

 33:    SLEPc  is  distributed in the hope that it will be useful, but WITHOUT  ANY
 34:    WARRANTY;  without even the implied warranty of MERCHANTABILITY or  FITNESS
 35:    FOR  A  PARTICULAR PURPOSE. See the GNU Lesser General Public  License  for
 36:    more details.

 38:    You  should have received a copy of the GNU Lesser General  Public  License
 39:    along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
 40:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 41: */

 43: #include <slepc/private/pepimpl.h>    /*I "slepcpep.h" I*/
 44: #include <slepc/private/dsimpl.h>
 45:  #include pjdp.h

 49: PetscErrorCode PEPSetUp_JD(PEP pep)
 50: {
 52:   PEP_JD         *pjd = (PEP_JD*)pep->data;
 53:   PetscBool      isshift,flg;
 54:   PetscInt       i;

 57:   pep->lineariz = PETSC_FALSE;
 58:   PEPSetDimensions_Default(pep,pep->nev,&pep->ncv,&pep->mpd);
 59:   if (!pep->max_it) pep->max_it = PetscMax(100,2*pep->n/pep->ncv);
 60:   if (!pep->which) pep->which = PEP_LARGEST_MAGNITUDE;
 61:   if (pep->nev>1) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Polynomial JD does not support nev>1 yet");

 63:   /* Set STSHIFT as the default ST */
 64:   if (!((PetscObject)pep->st)->type_name) {
 65:     STSetType(pep->st,STSHIFT);
 66:   }
 67:   PetscObjectTypeCompare((PetscObject)pep->st,STSHIFT,&isshift);
 68:   if (!isshift) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"JD only works with shift spectral transformation");

 70:   if (pep->basis!=PEP_BASIS_MONOMIAL) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Solver not implemented for non-monomial bases");
 71:   STGetTransform(pep->st,&flg);
 72:   if (flg) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Solver requires the ST transformation flag unset, see STSetTransform()");

 74:   if (!pjd->keep) pjd->keep = 0.5;

 76:   PEPAllocateSolution(pep,0);
 77:   PEPSetWorkVecs(pep,4);
 78:   PetscMalloc1(pep->nmat,&pjd->W);
 79:   for (i=0;i<pep->nmat;i++) {
 80:     BVDuplicate(pep->V,pjd->W+i);
 81:   }
 82:   DSSetType(pep->ds,DSPEP);
 83:   DSPEPSetDegree(pep->ds,pep->nmat-1);
 84:   DSAllocate(pep->ds,pep->ncv);
 85:   return(0);
 86: }

 90: /*
 91:    Check for multiple eigenvalues.
 92: */
 93: static PetscErrorCode PEPJDPurgeDuplicates(PEP pep)
 94: {
 95:   PEP_JD   *pjd = (PEP_JD*)pep->data;
 96:   PetscInt i,k;

 99:   k = pep->nconv;  /* TODO: should have a while loop here */
100:   for (i=0;i<pep->nconv;i++) {
101:     if (SlepcAbsEigenvalue(pep->eigr[i]-pep->eigr[k],pep->eigi[i]-pep->eigi[k])<pjd->mtol) {
102:       pep->eigr[k] = PETSC_INFINITY;
103:       pep->eigi[k] = PETSC_INFINITY;
104:       break;
105:     }
106:   }
107:   return(0);
108: }

112: /*
113:    Multiplication of derivative of P, i.e.
114:       P'(\lambda) x = \sum_{i=1}^{n} (i*\lambda^{i-1} A_i)x 
115: */
116: static PetscErrorCode PEPJDDiffMatMult(PEP pep,PetscScalar theta,Vec x,Vec y,Vec w)
117: {
119:   PetscScalar    fact=1.0;
120:   PetscInt       i;

123:   VecSet(y,1.0);
124:   for (i=1;i<pep->nmat;i++) {
125:     MatMult(pep->A[i],x,w);
126:     VecAXPY(y,fact*(PetscReal)i,w);
127:     fact *= theta;
128:   }
129:   return(0);
130: }

134: /*
135:    Application of shell preconditioner:
136:       y = B\x - eta*B\p,  with eta = (u'*B\x)/(u'*B\p)
137: */
138: static PetscErrorCode PCShellApply_PEPJD(PC pc,Vec x,Vec y)
139: {
141:   PetscScalar    eta;
142:   PEP_JD_PCSHELL *pcctx;

145:   PCShellGetContext(pc,(void**)&pcctx);

147:   /* y = B\x */
148:   PCApply(pcctx->pc,x,y);

150:   /* Compute eta = u'*y / u'*Bp */
151:   VecDot(y,pcctx->u,&eta);
152:   eta /= pcctx->gamma;
153:   
154:   /* y = y - eta*Bp */
155:   VecAXPY(y,-eta,pcctx->Bp); 
156:   return(0);
157: }

161: PetscErrorCode PEPSolve_JD(PEP pep)
162: {
164:   PEP_JD         *pjd = (PEP_JD*)pep->data;
165:   PEP_JD_PCSHELL *pcctx;
166:   PetscInt       k,nv,ld,minv,low,high;
167:   PetscScalar    theta,*pX;
168:   PetscReal      norm;
169:   PetscBool      lindep;
170:   Vec            t,u=pep->work[0],p=pep->work[1],r=pep->work[2],w=pep->work[3];
171:   Mat            G,X,Ptheta;
172:   KSP            ksp;

175:   DSGetLeadingDimension(pep->ds,&ld);
176:   if (pep->nini==0) {  
177:     nv = 1;
178:     BVSetRandomColumn(pep->V,0,pep->rand);
179:     BVNormColumn(pep->V,0,NORM_2,&norm);
180:     BVScaleColumn(pep->V,0,1.0/norm);
181:   } else nv = pep->nini;

183:   /* Restart loop */
184:   while (pep->reason == PEP_CONVERGED_ITERATING) {
185:     pep->its++;

187:     low = (pjd->flglk || pjd->flgre)? 0: nv-1;
188:     high = nv;
189:     DSSetDimensions(pep->ds,nv,0,0,0);
190:     BVSetActiveColumns(pep->V,low,high);
191:     for (k=0;k<pep->nmat;k++) {
192:       BVSetActiveColumns(pjd->W[k],low,high);
193:       BVMatMult(pep->V,pep->A[k],pjd->W[k]);
194:       DSGetMat(pep->ds,DSMatExtra[k],&G);
195:       BVMatProject(pjd->W[k],NULL,pep->V,G);
196:       DSRestoreMat(pep->ds,DSMatExtra[k],&G);
197:     }
198:     BVSetActiveColumns(pep->V,0,nv);

200:     /* Solve projected problem */
201:     DSSetState(pep->ds,DS_STATE_RAW);
202:     DSSolve(pep->ds,pep->eigr+pep->nconv,pep->eigi+pep->nconv);
203:     DSSort(pep->ds,pep->eigr+pep->nconv,pep->eigi+pep->nconv,NULL,NULL,NULL);
204:     PEPJDPurgeDuplicates(pep);
205:     DSSort(pep->ds,pep->eigr+pep->nconv,pep->eigi+pep->nconv,NULL,NULL,NULL);
206:     theta = pep->eigr[pep->nconv];
207: #if !defined(PETSC_USE_COMPLEX)
208:     if (PetscAbsScalar(pep->eigi[pep->nconv])!=0.0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"PJD solver not implemented for complex Ritz values in real arithmetic");
209: #endif

211:     /* Compute Ritz vector u=V*X(:,1) */
212:     DSGetArray(pep->ds,DS_MAT_X,&pX);
213:     BVSetActiveColumns(pep->V,0,nv);
214:     BVMultVec(pep->V,1.0,0.0,u,pX);
215:     DSRestoreArray(pep->ds,DS_MAT_X,&pX);

217:     /* Compute p=P'(theta)*u  */
218:     PEPJDDiffMatMult(pep,theta,u,p,w);

220:     /* Form matrix P(theta) and compute residual r=P(theta)*u */
221:     STMatSetUp(pep->st,theta,NULL);
222:     STGetKSP(pep->st,&ksp);
223:     KSPGetOperators(ksp,&Ptheta,NULL);
224:     MatMult(Ptheta,u,r);

226:     /* Replace preconditioner with one containing projectors */
227:     if (!pjd->pcshell) {
228:       PCCreate(PetscObjectComm((PetscObject)ksp),&pjd->pcshell);
229:       PCSetType(pjd->pcshell,PCSHELL);
230:       PCShellSetName(pjd->pcshell,"PCPEPJD");
231:       PCShellSetApply(pjd->pcshell,PCShellApply_PEPJD);
232:       PetscNew(&pcctx);
233:       PCShellSetContext(pjd->pcshell,pcctx);
234:       PCSetOperators(pjd->pcshell,Ptheta,Ptheta);
235:       VecDuplicate(u,&pcctx->Bp);
236:       KSPGetPC(ksp,&pcctx->pc);
237:       PetscObjectReference((PetscObject)pcctx->pc);
238:     } else {
239:       KSPGetPC(ksp,&pcctx->pc);
240:     }
241:     KSPSetPC(ksp,pjd->pcshell);
242:     pcctx->u = u;

244:     /* Check convergence */
245:     VecNorm(r,NORM_2,&norm);
246:     (*pep->converged)(pep,theta,0,norm,&pep->errest[pep->nconv],pep->convergedctx);
247:     if (pep->its >= pep->max_it) pep->reason = PEP_DIVERGED_ITS;

249:     if (pep->errest[pep->nconv]<pep->tol) {

251:       /* Ritz pair converged */
252:       minv = PetscMin(nv,pjd->keep*pep->ncv);
253:       DSOrthogonalize(pep->ds,DS_MAT_X,nv,NULL);
254:       DSGetMat(pep->ds,DS_MAT_X,&X);
255:       BVMultInPlace(pep->V,X,pep->nconv,minv);
256:       DSRestoreMat(pep->ds,DS_MAT_X,&X);
257:       pep->nconv++;
258:       if (pep->nconv >= pep->nev) pep->reason = PEP_CONVERGED_TOL;
259:       else nv = minv + pep->nconv;
260:       pjd->flglk = PETSC_TRUE;

262:     } else if (nv==pep->ncv-1) {

264:       /* Basis full, force restart */
265:       minv = PetscMin(nv,pjd->keep*pep->ncv);
266:       DSOrthogonalize(pep->ds,DS_MAT_X,nv,NULL);
267:       DSGetMat(pep->ds,DS_MAT_X,&X);
268:       BVMultInPlace(pep->V,X,pep->nconv,minv);
269:       DSRestoreMat(pep->ds,DS_MAT_X,&X);
270:       nv = minv + pep->nconv;
271:       pjd->flgre = PETSC_TRUE;

273:     } else {

275:       /* Solve correction equation to expand basis */
276:       PCApply(pcctx->pc,p,pcctx->Bp);
277:       VecScale(r,-1.0);
278:       VecDot(pcctx->Bp,u,&pcctx->gamma);
279:       BVGetColumn(pep->V,nv,&t);
280:       KSPSolve(ksp,r,t);
281:       BVRestoreColumn(pep->V,nv,&t);
282:       BVOrthogonalizeColumn(pep->V,nv,NULL,&norm,&lindep);
283:       if (lindep) SETERRQ(PETSC_COMM_SELF,1,"Linearly dependent continuation vector");
284:       BVScaleColumn(pep->V,nv,1.0/norm);
285:       nv++;
286:       pjd->flglk = PETSC_FALSE;
287:       pjd->flgre = PETSC_FALSE;
288:     }

290:     /* Restore preconditioner */
291:     KSPGetPC(ksp,&pjd->pcshell);
292:     KSPSetPC(ksp,pcctx->pc);

294:     PEPMonitor(pep,pep->its,pep->nconv,pep->eigr,pep->eigi,pep->errest,nv);
295:   }

297:   VecDestroy(&pcctx->Bp);
298:   PCDestroy(&pcctx->pc);
299:   PetscFree(pcctx);
300:   PCDestroy(&pjd->pcshell);
301:   return(0);
302: }

306: PetscErrorCode PEPComputeVectors_JD(PEP pep)
307: {
309:   PetscInt       k;
310:   PEP_JD         *pjd = (PEP_JD*)pep->data;
311:   Mat            G,X;

314:   DSSetDimensions(pep->ds,pep->nconv,0,0,0);
315:   BVSetActiveColumns(pep->V,0,pep->nconv);
316:   for (k=0;k<pep->nmat;k++) {
317:     BVSetActiveColumns(pjd->W[k],0,pep->nconv);
318:     BVMatMult(pep->V,pep->A[k],pjd->W[k]);
319:     DSGetMat(pep->ds,DSMatExtra[k],&G);
320:     BVMatProject(pjd->W[k],NULL,pep->V,G);
321:     DSRestoreMat(pep->ds,DSMatExtra[k],&G);
322:   }

324:   /* Solve projected problem */
325:   DSSetState(pep->ds,DS_STATE_RAW);
326:   DSSolve(pep->ds,pep->eigr,pep->eigi);
327:   DSSort(pep->ds,pep->eigr,pep->eigi,NULL,NULL,NULL);

329:   /* Compute Ritz vectors */
330:   DSGetMat(pep->ds,DS_MAT_X,&X);
331:   BVMultInPlace(pep->V,X,0,pep->nconv);
332:   DSRestoreMat(pep->ds,DS_MAT_X,&X);
333:   return(0);
334: }

338: PetscErrorCode PEPReset_JD(PEP pep)
339: {
341:   PEP_JD         *pjd = (PEP_JD*)pep->data;
342:   PetscInt       i;

345:   for (i=0;i<pep->nmat;i++) {
346:     BVDestroy(pjd->W+i);
347:   }
348:   PetscFree(pjd->W);
349:   return(0);
350: }

354: PetscErrorCode PEPDestroy_JD(PEP pep)
355: {

359:   PetscFree(pep->data);
360:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDSetRestart_C",NULL);
361:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDGetRestart_C",NULL);
362:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDSetTolerances_C",NULL);
363:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDGetTolerances_C",NULL);
364:   return(0);
365: }

369: PETSC_EXTERN PetscErrorCode PEPCreate_JD(PEP pep)
370: {
371:   PEP_JD         *pjd;

375:   PetscNewLog(pep,&pjd);
376:   pep->data = (void*)pjd;

378:   pjd->keep = 0;
379:   pjd->mtol = 1e-5;
380:   pjd->htol = 1e-2;
381:   pjd->stol = 1e-2;

383:   pep->ops->solve          = PEPSolve_JD;
384:   pep->ops->setup          = PEPSetUp_JD;
385:   pep->ops->setfromoptions = PEPSetFromOptions_JD;
386:   pep->ops->reset          = PEPReset_JD;
387:   pep->ops->destroy        = PEPDestroy_JD;
388:   pep->ops->view           = PEPView_JD;
389:   pep->ops->computevectors = PEPComputeVectors_JD;
390:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDSetRestart_C",PEPJDSetRestart_JD);
391:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDGetRestart_C",PEPJDGetRestart_JD);
392:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDSetTolerances_C",PEPJDSetTolerances_JD);
393:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDGetTolerances_C",PEPJDGetTolerances_JD);
394:   return(0);
395: }