Actual source code: pjd.c
slepc-3.6.1 2015-09-03
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: }