Actual source code: lobpcg.c
slepc-3.14.2 2021-02-01
1: /*
2: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3: SLEPc - Scalable Library for Eigenvalue Problem Computations
4: Copyright (c) 2002-2020, Universitat Politecnica de Valencia, Spain
6: This file is part of SLEPc.
7: SLEPc is distributed under a 2-clause BSD license (see LICENSE).
8: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
9: */
10: /*
11: SLEPc eigensolver: "lobpcg"
13: Method: Locally Optimal Block Preconditioned Conjugate Gradient
15: Algorithm:
17: LOBPCG with soft and hard locking. Follows the implementation
18: in BLOPEX [2].
20: References:
22: [1] A. V. Knyazev, "Toward the optimal preconditioned eigensolver:
23: locally optimal block preconditioned conjugate gradient method",
24: SIAM J. Sci. Comput. 23(2):517-541, 2001.
26: [2] A. V. Knyazev et al., "Block Locally Optimal Preconditioned
27: Eigenvalue Xolvers (BLOPEX) in Hypre and PETSc", SIAM J. Sci.
28: Comput. 29(5):2224-2239, 2007.
29: */
31: #include <slepc/private/epsimpl.h>
33: typedef struct {
34: PetscInt bs; /* block size */
35: PetscBool lock; /* soft locking active/inactive */
36: PetscReal restart; /* restart parameter */
37: PetscInt guard; /* number of guard vectors */
38: } EPS_LOBPCG;
40: PetscErrorCode EPSSetDimensions_LOBPCG(EPS eps,PetscInt nev,PetscInt *ncv,PetscInt *mpd)
41: {
42: EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
43: PetscInt k;
46: k = PetscMax(3*ctx->bs,((eps->nev-1)/ctx->bs+3)*ctx->bs);
47: if (*ncv!=PETSC_DEFAULT) { /* ncv set */
48: if (*ncv<k) SETERRQ(PetscObjectComm((PetscObject)eps),1,"The value of ncv is not sufficiently large");
49: } else *ncv = k;
50: if (*mpd==PETSC_DEFAULT) *mpd = 3*ctx->bs;
51: else if (*mpd!=3*ctx->bs) SETERRQ(PetscObjectComm((PetscObject)eps),1,"This solver does not allow a value of mpd different from 3*blocksize");
52: return(0);
53: }
55: PetscErrorCode EPSSetUp_LOBPCG(EPS eps)
56: {
58: EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
61: EPSCheckHermitianDefinite(eps);
62: if (!ctx->bs) ctx->bs = PetscMin(16,eps->nev);
63: if (eps->n-eps->nds<5*ctx->bs) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"The problem size is too small relative to the block size");
64: EPSSetDimensions_LOBPCG(eps,eps->nev,&eps->ncv,&eps->mpd);
65: if (eps->max_it==PETSC_DEFAULT) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
66: if (!eps->which) eps->which = EPS_SMALLEST_REAL;
67: if (eps->which!=EPS_SMALLEST_REAL && eps->which!=EPS_LARGEST_REAL) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"This solver supports only smallest real or largest real eigenvalues");
68: EPSCheckUnsupported(eps,EPS_FEATURE_ARBITRARY | EPS_FEATURE_REGION | EPS_FEATURE_EXTRACTION);
69: EPSCheckIgnored(eps,EPS_FEATURE_BALANCE);
71: if (!ctx->restart) ctx->restart = 0.9;
73: /* number of guard vectors */
74: if (ctx->bs==1) ctx->guard = 0;
75: else ctx->guard = PetscMin((PetscInt)((1.0-ctx->restart)*ctx->bs+0.45),ctx->bs-1);
77: EPSAllocateSolution(eps,0);
78: EPS_SetInnerProduct(eps);
79: DSSetType(eps->ds,DSGHEP);
80: DSAllocate(eps->ds,eps->mpd);
81: EPSSetWorkVecs(eps,1);
82: return(0);
83: }
85: PetscErrorCode EPSSolve_LOBPCG(EPS eps)
86: {
88: EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
89: PetscInt i,j,k,ld,nv,ini,nmat,nc,nconv,locked,its,prev=0;
90: PetscReal norm;
91: PetscScalar *eigr,dot;
92: PetscBool breakdown,countc,flip=PETSC_FALSE,checkprecond=PETSC_FALSE;
93: Mat A,B,M,V=NULL,W=NULL;
94: Vec v,z,w=eps->work[0];
95: BV X,Y=NULL,Z,R,P,AX,BX;
96: SlepcSC sc;
99: DSGetLeadingDimension(eps->ds,&ld);
100: STGetNumMatrices(eps->st,&nmat);
101: STGetMatrix(eps->st,0,&A);
102: if (nmat>1) { STGetMatrix(eps->st,1,&B); }
103: else B = NULL;
105: if (eps->which==EPS_LARGEST_REAL) { /* flip spectrum */
106: flip = PETSC_TRUE;
107: DSGetSlepcSC(eps->ds,&sc);
108: sc->comparison = SlepcCompareSmallestReal;
109: }
111: /* undocumented option to check for a positive-definite preconditioner (turn-off by default) */
112: PetscOptionsGetBool(NULL,NULL,"-eps_lobpcg_checkprecond",&checkprecond,NULL);
114: /* 1. Allocate memory */
115: PetscCalloc1(3*ctx->bs,&eigr);
116: BVDuplicateResize(eps->V,3*ctx->bs,&Z);
117: BVDuplicateResize(eps->V,ctx->bs,&X);
118: BVDuplicateResize(eps->V,ctx->bs,&R);
119: BVDuplicateResize(eps->V,ctx->bs,&P);
120: BVDuplicateResize(eps->V,ctx->bs,&AX);
121: if (B) {
122: BVDuplicateResize(eps->V,ctx->bs,&BX);
123: }
124: nc = eps->nds;
125: if (nc>0 || eps->nev>ctx->bs-ctx->guard) {
126: BVDuplicateResize(eps->V,nc+eps->nev,&Y);
127: }
128: if (nc>0) {
129: for (j=0;j<nc;j++) {
130: BVGetColumn(eps->V,-nc+j,&v);
131: BVInsertVec(Y,j,v);
132: BVRestoreColumn(eps->V,-nc+j,&v);
133: }
134: BVSetActiveColumns(Y,0,nc);
135: }
137: /* 2. Apply the constraints to the initial vectors */
138: /* 3. B-orthogonalize initial vectors */
139: for (k=eps->nini;k<eps->ncv-ctx->bs;k++) { /* Generate more initial vectors if necessary */
140: BVSetRandomColumn(eps->V,k);
141: BVOrthonormalizeColumn(eps->V,k,PETSC_TRUE,NULL,NULL);
142: }
143: nv = ctx->bs;
144: BVSetActiveColumns(eps->V,0,nv);
145: BVSetActiveColumns(Z,0,nv);
146: BVCopy(eps->V,Z);
147: BVCopy(Z,X);
149: /* 4. Compute initial Ritz vectors */
150: BVMatMult(X,A,AX);
151: DSSetDimensions(eps->ds,nv,0,0,0);
152: DSGetMat(eps->ds,DS_MAT_A,&M);
153: BVMatProject(AX,NULL,X,M);
154: if (flip) { MatScale(M,-1.0); }
155: DSRestoreMat(eps->ds,DS_MAT_A,&M);
156: DSSetIdentity(eps->ds,DS_MAT_B);
157: DSSetState(eps->ds,DS_STATE_RAW);
158: DSSolve(eps->ds,eigr,NULL);
159: DSSort(eps->ds,eigr,NULL,NULL,NULL,NULL);
160: DSSynchronize(eps->ds,eigr,NULL);
161: for (j=0;j<nv;j++) eps->eigr[j] = flip? -eigr[j]: eigr[j];
162: DSVectors(eps->ds,DS_MAT_X,NULL,NULL);
163: DSGetMat(eps->ds,DS_MAT_X,&M);
164: BVMultInPlace(X,M,0,nv);
165: BVMultInPlace(AX,M,0,nv);
166: MatDestroy(&M);
168: /* 5. Initialize range of active iterates */
169: locked = 0; /* hard-locked vectors, the leading locked columns of V are eigenvectors */
170: nconv = 0; /* number of converged eigenvalues in the current block */
171: its = 0; /* iterations for the current block */
173: /* 6. Main loop */
174: while (eps->reason == EPS_CONVERGED_ITERATING) {
176: if (ctx->lock) {
177: BVSetActiveColumns(R,nconv,ctx->bs);
178: BVSetActiveColumns(AX,nconv,ctx->bs);
179: if (B) {
180: BVSetActiveColumns(BX,nconv,ctx->bs);
181: }
182: }
184: /* 7. Compute residuals */
185: ini = (ctx->lock)? nconv: 0;
186: BVCopy(AX,R);
187: if (B) { BVMatMult(X,B,BX); }
188: for (j=ini;j<ctx->bs;j++) {
189: BVGetColumn(R,j,&v);
190: BVGetColumn(B?BX:X,j,&z);
191: VecAXPY(v,-eps->eigr[locked+j],z);
192: BVRestoreColumn(R,j,&v);
193: BVRestoreColumn(B?BX:X,j,&z);
194: }
196: /* 8. Compute residual norms and update index set of active iterates */
197: k = ini;
198: countc = PETSC_TRUE;
199: for (j=ini;j<ctx->bs;j++) {
200: i = locked+j;
201: BVGetColumn(R,j,&v);
202: VecNorm(v,NORM_2,&norm);
203: BVRestoreColumn(R,j,&v);
204: (*eps->converged)(eps,eps->eigr[i],eps->eigi[i],norm,&eps->errest[i],eps->convergedctx);
205: if (countc) {
206: if (eps->errest[i] < eps->tol) k++;
207: else countc = PETSC_FALSE;
208: }
209: if (!countc && !eps->trackall) break;
210: }
211: nconv = k;
212: eps->nconv = locked + nconv;
213: if (its) {
214: EPSMonitor(eps,eps->its+its,eps->nconv,eps->eigr,eps->eigi,eps->errest,locked+ctx->bs);
215: }
216: (*eps->stopping)(eps,eps->its+its,eps->max_it,eps->nconv,eps->nev,&eps->reason,eps->stoppingctx);
217: if (eps->reason != EPS_CONVERGED_ITERATING || nconv >= ctx->bs-ctx->guard) {
218: BVSetActiveColumns(eps->V,locked,eps->nconv);
219: BVSetActiveColumns(X,0,nconv);
220: BVCopy(X,eps->V);
221: }
222: if (eps->reason != EPS_CONVERGED_ITERATING) {
223: break;
224: } else if (nconv >= ctx->bs-ctx->guard) {
225: eps->its += its-1;
226: its = 0;
227: } else its++;
229: if (nconv >= ctx->bs-ctx->guard) { /* force hard locking of vectors and compute new R */
231: /* extend constraints */
232: BVSetActiveColumns(Y,nc+locked,nc+locked+nconv);
233: BVCopy(X,Y);
234: BVSetActiveColumns(Y,0,nc+locked+nconv);
236: /* shift work BV's */
237: for (j=nconv;j<ctx->bs;j++) {
238: BVCopyColumn(X,j,j-nconv);
239: BVCopyColumn(R,j,j-nconv);
240: BVCopyColumn(P,j,j-nconv);
241: BVCopyColumn(AX,j,j-nconv);
242: if (B) {
243: BVCopyColumn(BX,j,j-nconv);
244: }
245: }
247: /* set new initial vectors */
248: BVSetActiveColumns(eps->V,locked+ctx->bs,locked+ctx->bs+nconv);
249: BVSetActiveColumns(X,ctx->bs-nconv,ctx->bs);
250: BVCopy(eps->V,X);
251: for (j=ctx->bs-nconv;j<ctx->bs;j++) {
252: BVGetColumn(X,j,&v);
253: BVOrthogonalizeVec(Y,v,NULL,&norm,&breakdown);
254: if (norm>0.0 && !breakdown) {
255: VecScale(v,1.0/norm);
256: } else {
257: PetscInfo(eps,"Orthogonalization of initial vector failed\n");
258: eps->reason = EPS_DIVERGED_BREAKDOWN;
259: goto diverged;
260: }
261: BVRestoreColumn(X,j,&v);
262: }
263: locked += nconv;
264: nconv = 0;
265: BVSetActiveColumns(X,nconv,ctx->bs);
267: /* B-orthogonalize initial vectors */
268: BVOrthogonalize(X,NULL);
269: BVSetActiveColumns(Z,nconv,ctx->bs);
270: BVSetActiveColumns(AX,nconv,ctx->bs);
271: BVCopy(X,Z);
273: /* compute initial Ritz vectors */
274: nv = ctx->bs;
275: BVMatMult(X,A,AX);
276: DSSetDimensions(eps->ds,nv,0,0,0);
277: DSGetMat(eps->ds,DS_MAT_A,&M);
278: BVMatProject(AX,NULL,X,M);
279: if (flip) { MatScale(M,-1.0); }
280: DSRestoreMat(eps->ds,DS_MAT_A,&M);
281: DSSetIdentity(eps->ds,DS_MAT_B);
282: DSSetState(eps->ds,DS_STATE_RAW);
283: DSSolve(eps->ds,eigr,NULL);
284: DSSort(eps->ds,eigr,NULL,NULL,NULL,NULL);
285: DSSynchronize(eps->ds,eigr,NULL);
286: for (j=0;j<nv;j++) if (locked+j<eps->ncv) eps->eigr[locked+j] = flip? -eigr[j]: eigr[j];
287: DSVectors(eps->ds,DS_MAT_X,NULL,NULL);
288: DSGetMat(eps->ds,DS_MAT_X,&M);
289: BVMultInPlace(X,M,0,nv);
290: BVMultInPlace(AX,M,0,nv);
291: MatDestroy(&M);
293: continue; /* skip the rest of the iteration */
294: }
296: ini = (ctx->lock)? nconv: 0;
297: if (ctx->lock) {
298: BVSetActiveColumns(R,nconv,ctx->bs);
299: BVSetActiveColumns(P,nconv,ctx->bs);
300: BVSetActiveColumns(AX,nconv,ctx->bs);
301: if (B) {
302: BVSetActiveColumns(BX,nconv,ctx->bs);
303: }
304: }
306: /* 9. Apply preconditioner to the residuals */
307: BVGetMat(R,&V);
308: if (prev != ctx->bs-ini) {
309: prev = ctx->bs-ini;
310: MatDestroy(&W);
311: MatDuplicate(V,MAT_SHARE_NONZERO_PATTERN,&W);
312: }
313: STApplyMat(eps->st,V,W);
314: if (checkprecond) {
315: for (j=ini;j<ctx->bs;j++) {
316: MatDenseGetColumnVecRead(V,j-ini,&v);
317: MatDenseGetColumnVecRead(W,j-ini,&w);
318: VecDot(v,w,&dot);
319: MatDenseRestoreColumnVecRead(W,j-ini,&w);
320: MatDenseRestoreColumnVecRead(V,j-ini,&v);
321: if (PetscRealPart(dot)<0.0) {
322: PetscInfo(eps,"The preconditioner is not positive-definite\n");
323: eps->reason = EPS_DIVERGED_BREAKDOWN;
324: goto diverged;
325: }
326: }
327: }
328: if (nc+locked>0) {
329: for (j=ini;j<ctx->bs;j++) {
330: MatDenseGetColumnVecWrite(W,j-ini,&w);
331: BVOrthogonalizeVec(Y,w,NULL,&norm,&breakdown);
332: if (norm>0.0 && !breakdown) {
333: VecScale(w,1.0/norm);
334: }
335: MatDenseRestoreColumnVecWrite(W,j-ini,&w);
336: if (norm<=0.0 || breakdown) {
337: PetscInfo(eps,"Orthogonalization of preconditioned residual failed\n");
338: eps->reason = EPS_DIVERGED_BREAKDOWN;
339: goto diverged;
340: }
341: }
342: }
343: MatCopy(W,V,SAME_NONZERO_PATTERN);
344: BVRestoreMat(R,&V);
346: /* 11. B-orthonormalize preconditioned residuals */
347: BVOrthogonalize(R,NULL);
349: /* 13-16. B-orthonormalize conjugate directions */
350: if (its>1) {
351: BVOrthogonalize(P,NULL);
352: }
354: /* 17-23. Compute symmetric Gram matrices */
355: BVSetActiveColumns(Z,0,ctx->bs);
356: BVSetActiveColumns(X,0,ctx->bs);
357: BVCopy(X,Z);
358: BVSetActiveColumns(Z,ctx->bs,2*ctx->bs-ini);
359: BVCopy(R,Z);
360: if (its>1) {
361: BVSetActiveColumns(Z,2*ctx->bs-ini,3*ctx->bs-2*ini);
362: BVCopy(P,Z);
363: }
365: if (its>1) nv = 3*ctx->bs-2*ini;
366: else nv = 2*ctx->bs-ini;
368: BVSetActiveColumns(Z,0,nv);
369: DSSetDimensions(eps->ds,nv,0,0,0);
370: DSGetMat(eps->ds,DS_MAT_A,&M);
371: BVMatProject(Z,A,Z,M);
372: if (flip) { MatScale(M,-1.0); }
373: DSRestoreMat(eps->ds,DS_MAT_A,&M);
374: DSGetMat(eps->ds,DS_MAT_B,&M);
375: BVMatProject(Z,B,Z,M); /* covers also the case B=NULL */
376: DSRestoreMat(eps->ds,DS_MAT_B,&M);
378: /* 24. Solve the generalized eigenvalue problem */
379: DSSetState(eps->ds,DS_STATE_RAW);
380: DSSolve(eps->ds,eigr,NULL);
381: DSSort(eps->ds,eigr,NULL,NULL,NULL,NULL);
382: DSSynchronize(eps->ds,eigr,NULL);
383: for (j=0;j<nv;j++) if (locked+j<eps->ncv) eps->eigr[locked+j] = flip? -eigr[j]: eigr[j];
384: DSVectors(eps->ds,DS_MAT_X,NULL,NULL);
386: /* 25-33. Compute Ritz vectors */
387: DSGetMat(eps->ds,DS_MAT_X,&M);
388: BVSetActiveColumns(Z,ctx->bs,nv);
389: if (ctx->lock) {
390: BVSetActiveColumns(P,0,ctx->bs);
391: }
392: BVMult(P,1.0,0.0,Z,M);
393: BVCopy(P,X);
394: if (ctx->lock) {
395: BVSetActiveColumns(P,nconv,ctx->bs);
396: }
397: BVSetActiveColumns(Z,0,ctx->bs);
398: BVMult(X,1.0,1.0,Z,M);
399: if (ctx->lock) {
400: BVSetActiveColumns(X,nconv,ctx->bs);
401: }
402: BVMatMult(X,A,AX);
403: MatDestroy(&M);
404: }
406: diverged:
407: eps->its += its;
409: if (flip) sc->comparison = SlepcCompareLargestReal;
410: PetscFree(eigr);
411: MatDestroy(&W);
412: if (V) { /* only needed when goto diverged is reached */
413: BVRestoreMat(R,&V);
414: }
415: BVDestroy(&Z);
416: BVDestroy(&X);
417: BVDestroy(&R);
418: BVDestroy(&P);
419: BVDestroy(&AX);
420: if (B) {
421: BVDestroy(&BX);
422: }
423: if (nc>0 || eps->nev>ctx->bs-ctx->guard) {
424: BVDestroy(&Y);
425: }
426: return(0);
427: }
429: static PetscErrorCode EPSLOBPCGSetBlockSize_LOBPCG(EPS eps,PetscInt bs)
430: {
431: EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
434: if (bs == PETSC_DEFAULT || bs == PETSC_DECIDE) bs = 1;
435: if (bs <= 0) SETERRQ1(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Invalid block size %D",bs);
436: if (ctx->bs != bs) {
437: ctx->bs = bs;
438: eps->state = EPS_STATE_INITIAL;
439: }
440: return(0);
441: }
443: /*@
444: EPSLOBPCGSetBlockSize - Sets the block size of the LOBPCG method.
446: Logically Collective on eps
448: Input Parameters:
449: + eps - the eigenproblem solver context
450: - bs - the block size
452: Options Database Key:
453: . -eps_lobpcg_blocksize - Sets the block size
455: Level: advanced
457: .seealso: EPSLOBPCGGetBlockSize()
458: @*/
459: PetscErrorCode EPSLOBPCGSetBlockSize(EPS eps,PetscInt bs)
460: {
466: PetscTryMethod(eps,"EPSLOBPCGSetBlockSize_C",(EPS,PetscInt),(eps,bs));
467: return(0);
468: }
470: static PetscErrorCode EPSLOBPCGGetBlockSize_LOBPCG(EPS eps,PetscInt *bs)
471: {
472: EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
475: *bs = ctx->bs;
476: return(0);
477: }
479: /*@
480: EPSLOBPCGGetBlockSize - Gets the block size used in the LOBPCG method.
482: Not Collective
484: Input Parameter:
485: . eps - the eigenproblem solver context
487: Output Parameter:
488: . bs - the block size
490: Level: advanced
492: .seealso: EPSLOBPCGSetBlockSize()
493: @*/
494: PetscErrorCode EPSLOBPCGGetBlockSize(EPS eps,PetscInt *bs)
495: {
501: PetscUseMethod(eps,"EPSLOBPCGGetBlockSize_C",(EPS,PetscInt*),(eps,bs));
502: return(0);
503: }
505: static PetscErrorCode EPSLOBPCGSetRestart_LOBPCG(EPS eps,PetscReal restart)
506: {
507: EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
510: if (restart==PETSC_DEFAULT) restart = 0.9;
511: if (restart<0.1 || restart>1.0) SETERRQ1(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The restart argument %g must be in the range [0.1,1.0]",(double)restart);
512: if (restart != ctx->restart) {
513: ctx->restart = restart;
514: eps->state = EPS_STATE_INITIAL;
515: }
516: return(0);
517: }
519: /*@
520: EPSLOBPCGSetRestart - Sets the restart parameter for the LOBPCG method.
521: The meaning of this parameter is the proportion of vectors within the
522: current block iterate that must have converged in order to force a
523: restart with hard locking.
525: Logically Collective on eps
527: Input Parameters:
528: + eps - the eigenproblem solver context
529: - restart - the percentage of the block of vectors to force a restart
531: Options Database Key:
532: . -eps_lobpcg_restart - Sets the restart parameter
534: Notes:
535: Allowed values are in the range [0.1,1.0]. The default is 0.6.
537: Level: advanced
539: .seealso: EPSLOBPCGGetRestart()
540: @*/
541: PetscErrorCode EPSLOBPCGSetRestart(EPS eps,PetscReal restart)
542: {
548: PetscTryMethod(eps,"EPSLOBPCGSetRestart_C",(EPS,PetscReal),(eps,restart));
549: return(0);
550: }
552: static PetscErrorCode EPSLOBPCGGetRestart_LOBPCG(EPS eps,PetscReal *restart)
553: {
554: EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
557: *restart = ctx->restart;
558: return(0);
559: }
561: /*@
562: EPSLOBPCGGetRestart - Gets the restart parameter used in the LOBPCG method.
564: Not Collective
566: Input Parameter:
567: . eps - the eigenproblem solver context
569: Output Parameter:
570: . restart - the restart parameter
572: Level: advanced
574: .seealso: EPSLOBPCGSetRestart()
575: @*/
576: PetscErrorCode EPSLOBPCGGetRestart(EPS eps,PetscReal *restart)
577: {
583: PetscUseMethod(eps,"EPSLOBPCGGetRestart_C",(EPS,PetscReal*),(eps,restart));
584: return(0);
585: }
587: static PetscErrorCode EPSLOBPCGSetLocking_LOBPCG(EPS eps,PetscBool lock)
588: {
589: EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
592: ctx->lock = lock;
593: return(0);
594: }
596: /*@
597: EPSLOBPCGSetLocking - Choose between locking and non-locking variants of
598: the LOBPCG method.
600: Logically Collective on eps
602: Input Parameters:
603: + eps - the eigenproblem solver context
604: - lock - true if the locking variant must be selected
606: Options Database Key:
607: . -eps_lobpcg_locking - Sets the locking flag
609: Notes:
610: This flag refers to soft locking (converged vectors within the current
611: block iterate), since hard locking is always used (when nev is larger
612: than the block size).
614: Level: advanced
616: .seealso: EPSLOBPCGGetLocking()
617: @*/
618: PetscErrorCode EPSLOBPCGSetLocking(EPS eps,PetscBool lock)
619: {
625: PetscTryMethod(eps,"EPSLOBPCGSetLocking_C",(EPS,PetscBool),(eps,lock));
626: return(0);
627: }
629: static PetscErrorCode EPSLOBPCGGetLocking_LOBPCG(EPS eps,PetscBool *lock)
630: {
631: EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
634: *lock = ctx->lock;
635: return(0);
636: }
638: /*@
639: EPSLOBPCGGetLocking - Gets the locking flag used in the LOBPCG method.
641: Not Collective
643: Input Parameter:
644: . eps - the eigenproblem solver context
646: Output Parameter:
647: . lock - the locking flag
649: Level: advanced
651: .seealso: EPSLOBPCGSetLocking()
652: @*/
653: PetscErrorCode EPSLOBPCGGetLocking(EPS eps,PetscBool *lock)
654: {
660: PetscUseMethod(eps,"EPSLOBPCGGetLocking_C",(EPS,PetscBool*),(eps,lock));
661: return(0);
662: }
664: PetscErrorCode EPSView_LOBPCG(EPS eps,PetscViewer viewer)
665: {
667: EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
668: PetscBool isascii;
671: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
672: if (isascii) {
673: PetscViewerASCIIPrintf(viewer," block size %D\n",ctx->bs);
674: PetscViewerASCIIPrintf(viewer," restart parameter=%g (using %D guard vectors)\n",(double)ctx->restart,ctx->guard);
675: PetscViewerASCIIPrintf(viewer," soft locking %sactivated\n",ctx->lock?"":"de");
676: }
677: return(0);
678: }
680: PetscErrorCode EPSSetFromOptions_LOBPCG(PetscOptionItems *PetscOptionsObject,EPS eps)
681: {
683: PetscBool lock,flg;
684: PetscInt bs;
685: PetscReal restart;
688: PetscOptionsHead(PetscOptionsObject,"EPS LOBPCG Options");
690: PetscOptionsInt("-eps_lobpcg_blocksize","Block size","EPSLOBPCGSetBlockSize",20,&bs,&flg);
691: if (flg) { EPSLOBPCGSetBlockSize(eps,bs); }
693: PetscOptionsReal("-eps_lobpcg_restart","Percentage of the block of vectors to force a restart","EPSLOBPCGSetRestart",0.5,&restart,&flg);
694: if (flg) { EPSLOBPCGSetRestart(eps,restart); }
696: PetscOptionsBool("-eps_lobpcg_locking","Choose between locking and non-locking variants","EPSLOBPCGSetLocking",PETSC_TRUE,&lock,&flg);
697: if (flg) { EPSLOBPCGSetLocking(eps,lock); }
699: PetscOptionsTail();
700: return(0);
701: }
703: PetscErrorCode EPSDestroy_LOBPCG(EPS eps)
704: {
708: PetscFree(eps->data);
709: PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetBlockSize_C",NULL);
710: PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetBlockSize_C",NULL);
711: PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetRestart_C",NULL);
712: PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetRestart_C",NULL);
713: PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetLocking_C",NULL);
714: PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetLocking_C",NULL);
715: return(0);
716: }
718: SLEPC_EXTERN PetscErrorCode EPSCreate_LOBPCG(EPS eps)
719: {
720: EPS_LOBPCG *lobpcg;
724: PetscNewLog(eps,&lobpcg);
725: eps->data = (void*)lobpcg;
726: lobpcg->lock = PETSC_TRUE;
728: eps->useds = PETSC_TRUE;
729: eps->categ = EPS_CATEGORY_PRECOND;
731: eps->ops->solve = EPSSolve_LOBPCG;
732: eps->ops->setup = EPSSetUp_LOBPCG;
733: eps->ops->setupsort = EPSSetUpSort_Default;
734: eps->ops->setfromoptions = EPSSetFromOptions_LOBPCG;
735: eps->ops->destroy = EPSDestroy_LOBPCG;
736: eps->ops->view = EPSView_LOBPCG;
737: eps->ops->backtransform = EPSBackTransform_Default;
738: eps->ops->setdefaultst = EPSSetDefaultST_GMRES;
740: PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetBlockSize_C",EPSLOBPCGSetBlockSize_LOBPCG);
741: PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetBlockSize_C",EPSLOBPCGGetBlockSize_LOBPCG);
742: PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetRestart_C",EPSLOBPCGSetRestart_LOBPCG);
743: PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetRestart_C",EPSLOBPCGGetRestart_LOBPCG);
744: PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetLocking_C",EPSLOBPCGSetLocking_LOBPCG);
745: PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetLocking_C",EPSLOBPCGGetLocking_LOBPCG);
746: return(0);
747: }