Actual source code: blopex.c
1: /*
2: This file implements a wrapper to the BLOPEX package
4: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5: SLEPc - Scalable Library for Eigenvalue Problem Computations
6: Copyright (c) 2002-2013, Universitat Politecnica de Valencia, Spain
8: This file is part of SLEPc.
10: SLEPc is free software: you can redistribute it and/or modify it under the
11: terms of version 3 of the GNU Lesser General Public License as published by
12: the Free Software Foundation.
14: SLEPc is distributed in the hope that it will be useful, but WITHOUT ANY
15: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16: FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
17: more details.
19: You should have received a copy of the GNU Lesser General Public License
20: along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
21: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22: */
24: #include <slepc-private/epsimpl.h> /*I "slepceps.h" I*/
25: #include <slepc-private/stimpl.h> /*I "slepcst.h" I*/
26: #include "slepc-interface.h"
27: #include <blopex_lobpcg.h>
28: #include <blopex_interpreter.h>
29: #include <blopex_multivector.h>
30: #include <blopex_temp_multivector.h>
32: PetscErrorCode EPSSolve_BLOPEX(EPS);
34: typedef struct {
35: lobpcg_Tolerance tol;
36: lobpcg_BLASLAPACKFunctions blap_fn;
37: mv_MultiVectorPtr eigenvectors;
38: mv_MultiVectorPtr Y;
39: mv_InterfaceInterpreter ii;
40: ST st;
41: Vec w;
42: } EPS_BLOPEX;
46: static void Precond_FnSingleVector(void *data,void *x,void *y)
47: {
49: EPS eps = (EPS)data;
50: EPS_BLOPEX *blopex = (EPS_BLOPEX*)eps->data;
53: KSPSolve(blopex->st->ksp,(Vec)x,(Vec)y);CHKERRABORT(PetscObjectComm((PetscObject)eps),ierr);
54: PetscFunctionReturnVoid();
55: }
59: static void Precond_FnMultiVector(void *data,void *x,void *y)
60: {
61: EPS eps = (EPS)data;
62: EPS_BLOPEX *blopex = (EPS_BLOPEX*)eps->data;
65: blopex->ii.Eval(Precond_FnSingleVector,data,x,y);
66: PetscFunctionReturnVoid();
67: }
71: static void OperatorASingleVector(void *data,void *x,void *y)
72: {
74: EPS eps = (EPS)data;
75: EPS_BLOPEX *blopex = (EPS_BLOPEX*)eps->data;
76: Mat A,B;
77: PetscScalar sigma;
78: PetscInt nmat;
81: STGetNumMatrices(eps->st,&nmat);CHKERRABORT(PetscObjectComm((PetscObject)eps),ierr);
82: STGetOperators(eps->st,0,&A);CHKERRABORT(PetscObjectComm((PetscObject)eps),ierr);
83: if (nmat>1) { STGetOperators(eps->st,1,&B);CHKERRABORT(PetscObjectComm((PetscObject)eps),ierr); }
84: MatMult(A,(Vec)x,(Vec)y);CHKERRABORT(PetscObjectComm((PetscObject)eps),ierr);
85: STGetShift(eps->st,&sigma);CHKERRABORT(PetscObjectComm((PetscObject)eps),ierr);
86: if (sigma != 0.0) {
87: if (nmat>1) {
88: MatMult(B,(Vec)x,blopex->w);CHKERRABORT(PetscObjectComm((PetscObject)eps),ierr);
89: } else {
90: VecCopy((Vec)x,blopex->w);CHKERRABORT(PetscObjectComm((PetscObject)eps),ierr);
91: }
92: VecAXPY((Vec)y,-sigma,blopex->w);CHKERRABORT(PetscObjectComm((PetscObject)eps),ierr);
93: }
94: PetscFunctionReturnVoid();
95: }
99: static void OperatorAMultiVector(void *data,void *x,void *y)
100: {
101: EPS eps = (EPS)data;
102: EPS_BLOPEX *blopex = (EPS_BLOPEX*)eps->data;
105: blopex->ii.Eval(OperatorASingleVector,data,x,y);
106: PetscFunctionReturnVoid();
107: }
111: static void OperatorBSingleVector(void *data,void *x,void *y)
112: {
114: EPS eps = (EPS)data;
115: Mat B;
118: STGetOperators(eps->st,1,&B);CHKERRABORT(PetscObjectComm((PetscObject)eps),ierr);
119: MatMult(B,(Vec)x,(Vec)y);CHKERRABORT(PetscObjectComm((PetscObject)eps),ierr);
120: PetscFunctionReturnVoid();
121: }
125: static void OperatorBMultiVector(void *data,void *x,void *y)
126: {
127: EPS eps = (EPS)data;
128: EPS_BLOPEX *blopex = (EPS_BLOPEX*)eps->data;
131: blopex->ii.Eval(OperatorBSingleVector,data,x,y);
132: PetscFunctionReturnVoid();
133: }
137: PetscErrorCode EPSSetUp_BLOPEX(EPS eps)
138: {
139: #if defined(PETSC_MISSING_LAPACK_POTRF) || defined(PETSC_MISSING_LAPACK_SYGV)
141: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"POTRF/SYGV - Lapack routine is unavailable");
142: #else
144: PetscInt i;
145: EPS_BLOPEX *blopex = (EPS_BLOPEX*)eps->data;
146: PetscBool isPrecond;
149: if (!eps->ishermitian) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"blopex only works for hermitian problems");
150: if (!eps->which) eps->which = EPS_SMALLEST_REAL;
151: if (eps->which!=EPS_SMALLEST_REAL) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Wrong value of eps->which");
153: /* Change the default sigma to inf if necessary */
154: if (eps->which == EPS_LARGEST_MAGNITUDE || eps->which == EPS_LARGEST_REAL ||
155: eps->which == EPS_LARGEST_IMAGINARY) {
156: STSetDefaultShift(eps->st,3e300);
157: }
159: STSetUp(eps->st);
160: PetscObjectTypeCompare((PetscObject)eps->st,STPRECOND,&isPrecond);
161: if (!isPrecond) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"blopex only works with STPRECOND");
162: blopex->st = eps->st;
164: eps->ncv = eps->nev = PetscMin(eps->nev,eps->n);
165: if (eps->mpd) { PetscInfo(eps,"Warning: parameter mpd ignored\n"); }
166: if (!eps->max_it) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
167: if (eps->arbitrary) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Arbitrary selection of eigenpairs not supported in this solver");
169: EPSAllocateSolution(eps);
170: EPSSetWorkVecs(eps,1);
172: if (eps->converged == EPSConvergedEigRelative) {
173: blopex->tol.absolute = 0.0;
174: blopex->tol.relative = eps->tol==PETSC_DEFAULT?SLEPC_DEFAULT_TOL:eps->tol;
175: } else if (eps->converged == EPSConvergedAbsolute) {
176: blopex->tol.absolute = eps->tol==PETSC_DEFAULT?SLEPC_DEFAULT_TOL:eps->tol;
177: blopex->tol.relative = 0.0;
178: } else {
179: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Convergence test not supported in this solver");
180: }
182: SLEPCSetupInterpreter(&blopex->ii);
183: blopex->eigenvectors = mv_MultiVectorCreateFromSampleVector(&blopex->ii,eps->ncv,eps->V);
184: for (i=0;i<eps->ncv;i++) { PetscObjectReference((PetscObject)eps->V[i]); }
186: VecDuplicate(eps->V[0],&blopex->w);
187: PetscLogObjectParent(eps,blopex->w);
188: if (eps->nds > 0) {
189: blopex->Y = mv_MultiVectorCreateFromSampleVector(&blopex->ii,eps->nds,eps->defl);
190: for (i=0;i<eps->nds;i++) { PetscObjectReference((PetscObject)eps->defl[i]); }
191: } else blopex->Y = NULL;
193: #if defined(PETSC_USE_COMPLEX)
194: blopex->blap_fn.zpotrf = PETSC_zpotrf_interface;
195: blopex->blap_fn.zhegv = PETSC_zsygv_interface;
196: #else
197: blopex->blap_fn.dpotrf = PETSC_dpotrf_interface;
198: blopex->blap_fn.dsygv = PETSC_dsygv_interface;
199: #endif
201: if (eps->extraction) { PetscInfo(eps,"Warning: extraction type ignored\n"); }
203: /* dispatch solve method */
204: if (eps->leftvecs) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Left vectors not supported in this solver");
205: eps->ops->solve = EPSSolve_BLOPEX;
206: return(0);
207: #endif
208: }
212: PetscErrorCode EPSSolve_BLOPEX(EPS eps)
213: {
214: EPS_BLOPEX *blopex = (EPS_BLOPEX*)eps->data;
215: PetscScalar sigma;
216: int i,j,info,its,nconv;
217: double *residhist=NULL;
219: #if defined(PETSC_USE_COMPLEX)
220: komplex *lambdahist=NULL;
221: #else
222: double *lambdahist=NULL;
223: #endif
226: /* Complete the initial basis with random vectors */
227: for (i=eps->nini;i<eps->ncv;i++) {
228: SlepcVecSetRandom(eps->V[i],eps->rand);
229: }
231: if (eps->numbermonitors>0) {
232: #if defined(PETSC_USE_COMPLEX)
233: PetscMalloc(eps->ncv*(eps->max_it+1)*sizeof(komplex),&lambdahist);
234: #else
235: PetscMalloc(eps->ncv*(eps->max_it+1)*sizeof(double),&lambdahist);
236: #endif
237: PetscMalloc(eps->ncv*(eps->max_it+1)*sizeof(double),&residhist);
238: }
240: #if defined(PETSC_USE_COMPLEX)
241: info = lobpcg_solve_complex(blopex->eigenvectors,eps,OperatorAMultiVector,
242: eps->isgeneralized?eps:NULL,eps->isgeneralized?OperatorBMultiVector:NULL,
243: eps,Precond_FnMultiVector,blopex->Y,
244: blopex->blap_fn,blopex->tol,eps->max_it,0,&its,
245: (komplex*)eps->eigr,lambdahist,eps->ncv,eps->errest,residhist,eps->ncv);
246: #else
247: info = lobpcg_solve_double(blopex->eigenvectors,eps,OperatorAMultiVector,
248: eps->isgeneralized?eps:NULL,eps->isgeneralized?OperatorBMultiVector:NULL,
249: eps,Precond_FnMultiVector,blopex->Y,
250: blopex->blap_fn,blopex->tol,eps->max_it,0,&its,
251: eps->eigr,lambdahist,eps->ncv,eps->errest,residhist,eps->ncv);
252: #endif
253: if (info>0) SETERRQ1(PetscObjectComm((PetscObject)eps),PETSC_ERR_LIB,"Error in blopex (code=%d)",info);
255: if (eps->numbermonitors>0) {
256: for (i=0;i<its;i++) {
257: nconv = 0;
258: for (j=0;j<eps->ncv;j++) {
259: if (residhist[j+i*eps->ncv]>eps->tol) break;
260: else nconv++;
261: }
262: EPSMonitor(eps,i,nconv,(PetscScalar*)lambdahist+i*eps->ncv,eps->eigi,residhist+i*eps->ncv,eps->ncv);
263: }
264: PetscFree(lambdahist);
265: PetscFree(residhist);
266: }
268: eps->its = its;
269: eps->nconv = eps->ncv;
270: STGetShift(eps->st,&sigma);
271: if (sigma != 0.0) {
272: for (i=0;i<eps->nconv;i++) eps->eigr[i]+=sigma;
273: }
274: if (info==-1) eps->reason = EPS_DIVERGED_ITS;
275: else eps->reason = EPS_CONVERGED_TOL;
276: return(0);
277: }
281: PetscErrorCode EPSReset_BLOPEX(EPS eps)
282: {
284: EPS_BLOPEX *blopex = (EPS_BLOPEX*)eps->data;
287: mv_MultiVectorDestroy(blopex->eigenvectors);
288: mv_MultiVectorDestroy(blopex->Y);
289: VecDestroy(&blopex->w);
290: EPSReset_Default(eps);
291: return(0);
292: }
296: PetscErrorCode EPSDestroy_BLOPEX(EPS eps)
297: {
301: LOBPCG_DestroyRandomContext();
302: PetscFree(eps->data);
303: return(0);
304: }
308: PetscErrorCode EPSSetFromOptions_BLOPEX(EPS eps)
309: {
310: PetscErrorCode ierr;
311: KSP ksp;
314: PetscOptionsHead("EPS BLOPEX Options");
315: LOBPCG_SetFromOptionsRandomContext();
317: /* Set STPrecond as the default ST */
318: if (!((PetscObject)eps->st)->type_name) {
319: STSetType(eps->st,STPRECOND);
320: }
321: STPrecondSetKSPHasMat(eps->st,PETSC_TRUE);
323: /* Set the default options of the KSP */
324: STGetKSP(eps->st,&ksp);
325: if (!((PetscObject)ksp)->type_name) {
326: KSPSetType(ksp,KSPPREONLY);
327: }
328: PetscOptionsTail();
329: return(0);
330: }
334: PETSC_EXTERN PetscErrorCode EPSCreate_BLOPEX(EPS eps)
335: {
339: PetscNewLog(eps,EPS_BLOPEX,&eps->data);
340: eps->ops->setup = EPSSetUp_BLOPEX;
341: eps->ops->setfromoptions = EPSSetFromOptions_BLOPEX;
342: eps->ops->destroy = EPSDestroy_BLOPEX;
343: eps->ops->reset = EPSReset_BLOPEX;
344: eps->ops->backtransform = EPSBackTransform_Default;
345: eps->ops->computevectors = EPSComputeVectors_Default;
346: LOBPCG_InitRandomContext(PetscObjectComm((PetscObject)eps),eps->rand);
347: return(0);
348: }