Actual source code: blopex.c

  1: /*
  2:        This file implements a wrapper to the BLOPEX solver

  4:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  5:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  6:    Copyright (c) 2002-2011, Universitat Politecnica de Valencia, Spain

  8:    This file is part of SLEPc.
  9:       
 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 <private/stimpl.h>       /*I "slepcst.h" I*/
 25: #include <private/epsimpl.h>      /*I "slepceps.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:   KSP                        ksp;
 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;
 51:   PetscInt       lits;
 52: 
 54:   KSPSolve(blopex->ksp,(Vec)x,(Vec)y); CHKERRABORT(PETSC_COMM_WORLD,ierr);
 55:   KSPGetIterationNumber(blopex->ksp,&lits); CHKERRABORT(PETSC_COMM_WORLD,ierr);
 56:   eps->OP->lineariterations+= lits;
 57:   PetscFunctionReturnVoid();
 58: }

 62: static void Precond_FnMultiVector(void *data,void *x,void *y)
 63: {
 64:   EPS        eps = (EPS)data;
 65:   EPS_BLOPEX *blopex = (EPS_BLOPEX*)eps->data;

 68:   blopex->ii.Eval(Precond_FnSingleVector,data,x,y);
 69:   PetscFunctionReturnVoid();
 70: }

 74: static void OperatorASingleVector(void *data,void *x,void *y)
 75: {
 77:   EPS            eps = (EPS)data;
 78:   EPS_BLOPEX     *blopex = (EPS_BLOPEX*)eps->data;
 79:   Mat            A,B;
 80: 
 82:   STGetOperators(eps->OP,&A,&B);CHKERRABORT(PETSC_COMM_WORLD,ierr);
 83:   MatMult(A,(Vec)x,(Vec)y);CHKERRABORT(PETSC_COMM_WORLD,ierr);
 84:   if (eps->OP->sigma != 0.0) {
 85:     if (B) { MatMult(B,(Vec)x,blopex->w);CHKERRABORT(PETSC_COMM_WORLD,ierr); }
 86:     else { VecCopy((Vec)x,blopex->w);CHKERRABORT(PETSC_COMM_WORLD,ierr); }
 87:     VecAXPY((Vec)y,-eps->OP->sigma,blopex->w);CHKERRABORT(PETSC_COMM_WORLD,ierr);
 88:   }
 89:   PetscFunctionReturnVoid();
 90: }

 94: static void OperatorAMultiVector(void *data,void *x,void *y)
 95: {
 96:   EPS        eps = (EPS)data;
 97:   EPS_BLOPEX *blopex = (EPS_BLOPEX*)eps->data;

100:   blopex->ii.Eval(OperatorASingleVector,data,x,y);
101:   PetscFunctionReturnVoid();
102: }

106: static void OperatorBSingleVector(void *data,void *x,void *y)
107: {
109:   EPS            eps = (EPS)data;
110:   Mat            B;
111: 
113:   STGetOperators(eps->OP,PETSC_NULL,&B);CHKERRABORT(PETSC_COMM_WORLD,ierr);
114:   MatMult(B,(Vec)x,(Vec)y);CHKERRABORT(PETSC_COMM_WORLD,ierr);
115:   PetscFunctionReturnVoid();
116: }

120: static void OperatorBMultiVector(void *data,void *x,void *y)
121: {
122:   EPS        eps = (EPS)data;
123:   EPS_BLOPEX *blopex = (EPS_BLOPEX*)eps->data;

126:   blopex->ii.Eval(OperatorBSingleVector,data,x,y);
127:   PetscFunctionReturnVoid();
128: }

132: PetscErrorCode EPSSetUp_BLOPEX(EPS eps)
133: {
135:   PetscInt       i;
136:   EPS_BLOPEX     *blopex = (EPS_BLOPEX *)eps->data;
137:   PetscBool      isPrecond;

140:   if (!eps->ishermitian) {
141:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_SUP,"blopex only works for hermitian problems");
142:   }
143:   if (!eps->which) eps->which = EPS_SMALLEST_REAL;
144:   if (eps->which!=EPS_SMALLEST_REAL) {
145:     SETERRQ(((PetscObject)eps)->comm,1,"Wrong value of eps->which");
146:   }

148:   /* Change the default sigma to inf if necessary */
149:   if (eps->which == EPS_LARGEST_MAGNITUDE || eps->which == EPS_LARGEST_REAL ||
150:       eps->which == EPS_LARGEST_IMAGINARY) {
151:     STSetDefaultShift(eps->OP,3e300);
152:   }

154:   STSetUp(eps->OP);
155:   PetscTypeCompare((PetscObject)eps->OP,STPRECOND,&isPrecond);
156:   if (!isPrecond) SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_SUP,"blopex only works with STPRECOND");
157:   STGetKSP(eps->OP,&blopex->ksp);

159:   eps->ncv = eps->nev = PetscMin(eps->nev,eps->n);
160:   if (eps->mpd) { PetscInfo(eps,"Warning: parameter mpd ignored\n"); }
161:   if (!eps->max_it) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);

163:   EPSAllocateSolution(eps);
164:   EPSDefaultGetWork(eps,1);
165: 
166:   blopex->tol.absolute = eps->tol==PETSC_DEFAULT?SLEPC_DEFAULT_TOL:eps->tol;
167:   blopex->tol.relative = 1e-50;
168: 
169:   SLEPCSetupInterpreter(&blopex->ii);
170:   blopex->eigenvectors = mv_MultiVectorCreateFromSampleVector(&blopex->ii,eps->ncv,eps->V);
171:   for (i=0;i<eps->ncv;i++) { PetscObjectReference((PetscObject)eps->V[i]); }
172:   mv_MultiVectorSetRandom(blopex->eigenvectors,1234);
173:   VecDuplicate(eps->V[0],&blopex->w);

175:   if (eps->nds > 0) {
176:     blopex->Y = mv_MultiVectorCreateFromSampleVector(&blopex->ii,eps->nds,eps->DS);
177:     for (i=0;i<eps->nds;i++) { PetscObjectReference((PetscObject)eps->DS[i]); }
178:   } else
179:     blopex->Y = PETSC_NULL;

181: #if defined(PETSC_USE_COMPLEX)
182:   blopex->blap_fn.zpotrf = PETSC_zpotrf_interface;
183:   blopex->blap_fn.zhegv = PETSC_zsygv_interface;
184: #else
185:   blopex->blap_fn.dpotrf = PETSC_dpotrf_interface;
186:   blopex->blap_fn.dsygv = PETSC_dsygv_interface;
187: #endif

189:   if (eps->extraction) { PetscInfo(eps,"Warning: extraction type ignored\n"); }

191:   /* dispatch solve method */
192:   if (eps->leftvecs) SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_SUP,"Left vectors not supported in this solver");
193:   eps->ops->solve = EPSSolve_BLOPEX;
194:   return(0);
195: }

199: PetscErrorCode EPSSolve_BLOPEX(EPS eps)
200: {
201:   EPS_BLOPEX     *blopex = (EPS_BLOPEX *)eps->data;
202:   int            i,j,info,its,nconv;
203:   double         *residhist=PETSC_NULL;
205: #if defined(PETSC_USE_COMPLEX)
206:   komplex        *lambdahist=PETSC_NULL;
207: #else
208:   double         *lambdahist=PETSC_NULL;
209: #endif
210: 
212:   if (eps->numbermonitors>0) {
213: #if defined(PETSC_USE_COMPLEX)
214:     PetscMalloc(eps->ncv*(eps->max_it+1)*sizeof(komplex),&lambdahist);
215: #else
216:     PetscMalloc(eps->ncv*(eps->max_it+1)*sizeof(double),&lambdahist);
217: #endif
218:     PetscMalloc(eps->ncv*(eps->max_it+1)*sizeof(double),&residhist);
219:   }

221: #if defined(PETSC_USE_COMPLEX)
222:   info = lobpcg_solve_complex(blopex->eigenvectors,eps,OperatorAMultiVector,
223:         eps->isgeneralized?eps:PETSC_NULL,eps->isgeneralized?OperatorBMultiVector:PETSC_NULL,
224:         eps,Precond_FnMultiVector,blopex->Y,
225:         blopex->blap_fn,blopex->tol,eps->max_it,0,&its,
226:         (komplex*)eps->eigr,lambdahist,eps->ncv,eps->errest,residhist,eps->ncv);
227: #else
228:   info = lobpcg_solve_double(blopex->eigenvectors,eps,OperatorAMultiVector,
229:         eps->isgeneralized?eps:PETSC_NULL,eps->isgeneralized?OperatorBMultiVector:PETSC_NULL,
230:         eps,Precond_FnMultiVector,blopex->Y,
231:         blopex->blap_fn,blopex->tol,eps->max_it,0,&its,
232:         eps->eigr,lambdahist,eps->ncv,eps->errest,residhist,eps->ncv);
233: #endif
234:   if (info>0) SETERRQ1(((PetscObject)eps)->comm,PETSC_ERR_LIB,"Error in blopex (code=%d)",info);

236:   if (eps->numbermonitors>0) {
237:     for (i=0;i<its;i++) {
238:       nconv = 0;
239:       for (j=0;j<eps->ncv;j++) { if (residhist[j+i*eps->ncv]>eps->tol) break; else nconv++; }
240:       EPSMonitor(eps,i,nconv,(PetscScalar*)lambdahist+i*eps->ncv,eps->eigi,residhist+i*eps->ncv,eps->ncv);
241:     }
242:     PetscFree(lambdahist);
243:     PetscFree(residhist);
244:   }

246:   eps->its = its;
247:   eps->nconv = eps->ncv;
248:   if (eps->OP->sigma != 0.0) {
249:     for (i=0;i<eps->nconv;i++) eps->eigr[i]+=eps->OP->sigma;
250:   }
251:   if (info==-1) eps->reason = EPS_DIVERGED_ITS;
252:   else eps->reason = EPS_CONVERGED_TOL;
253:   return(0);
254: }

258: PetscErrorCode EPSReset_BLOPEX(EPS eps)
259: {
261:   EPS_BLOPEX     *blopex = (EPS_BLOPEX *)eps->data;

264:   mv_MultiVectorDestroy(blopex->eigenvectors);
265:   mv_MultiVectorDestroy(blopex->Y);
266:   VecDestroy(&blopex->w);
267:   EPSReset_Default(eps);
268:   return(0);
269: }

273: PetscErrorCode EPSDestroy_BLOPEX(EPS eps)
274: {

278:   LOBPCG_DestroyRandomContext();
279:   PetscFree(eps->data);
280:   return(0);
281: }

285: PetscErrorCode EPSSetFromOptions_BLOPEX(EPS eps)
286: {
287:   PetscErrorCode  ierr;

290:   PetscOptionsHead("EPS BLOPEX Options");
291:   LOBPCG_SetFromOptionsRandomContext();
292:   PetscOptionsTail();
293:   return(0);
294: }

296: EXTERN_C_BEGIN
299: PetscErrorCode EPSCreate_BLOPEX(EPS eps)
300: {

304:   PetscNewLog(eps,EPS_BLOPEX,&eps->data);
305:   eps->ops->setup                = EPSSetUp_BLOPEX;
306:   eps->ops->setfromoptions       = EPSSetFromOptions_BLOPEX;
307:   eps->ops->destroy              = EPSDestroy_BLOPEX;
308:   eps->ops->reset                = EPSReset_BLOPEX;
309:   eps->ops->backtransform        = EPSBackTransform_Default;
310:   eps->ops->computevectors       = EPSComputeVectors_Default;
311:   STSetType(eps->OP,STPRECOND);
312:   STPrecondSetKSPHasMat(eps->OP,PETSC_TRUE);
313:   LOBPCG_InitRandomContext(((PetscObject)eps)->comm,eps->rand);
314:   return(0);
315: }
316: EXTERN_C_END