Date: 2013-09-02T10:05:01+00:00

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: }