Date: 2024-12-02T08:56:50+00:00

Actual source code: blopex.c
slepc-3.22.2 2024-12-02
Report Typos and Errors

      1: /*
      2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      4:    Copyright (c) 2002-, 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:    This file implements a wrapper to the BLOPEX package
     12: */

     14: #include <slepc/private/epsimpl.h>
     15: #include "blopex.h"
     16: #include <lobpcg.h>
     17: #include <interpreter.h>
     18: #include <multivector.h>
     19: #include <temp_multivector.h>

     21: PetscInt slepc_blopex_useconstr = -1;

     23: typedef struct {
     24:   lobpcg_Tolerance           tol;
     25:   lobpcg_BLASLAPACKFunctions blap_fn;
     26:   mv_InterfaceInterpreter    ii;
     27:   ST                         st;
     28:   Vec                        w;
     29:   PetscInt                   bs;     /* block size */
     30: } EPS_BLOPEX;

     32: static void Precond_FnSingleVector(void *data,void *x,void *y)
     33: {
     34:   EPS_BLOPEX     *blopex = (EPS_BLOPEX*)data;
     35:   MPI_Comm       comm = PetscObjectComm((PetscObject)blopex->st);
     36:   KSP            ksp;

     38:   PetscFunctionBegin;
     39:   PetscCallAbort(comm,STGetKSP(blopex->st,&ksp));
     40:   PetscCallAbort(comm,KSPSolve(ksp,(Vec)x,(Vec)y));
     41:   PetscFunctionReturnVoid();
     42: }

     44: static void Precond_FnMultiVector(void *data,void *x,void *y)
     45: {
     46:   EPS_BLOPEX *blopex = (EPS_BLOPEX*)data;

     48:   PetscFunctionBegin;
     49:   blopex->ii.Eval(Precond_FnSingleVector,data,x,y);
     50:   PetscFunctionReturnVoid();
     51: }

     53: static void OperatorASingleVector(void *data,void *x,void *y)
     54: {
     55:   EPS_BLOPEX     *blopex = (EPS_BLOPEX*)data;
     56:   MPI_Comm       comm = PetscObjectComm((PetscObject)blopex->st);
     57:   Mat            A,B;
     58:   PetscScalar    sigma;
     59:   PetscInt       nmat;

     61:   PetscFunctionBegin;
     62:   PetscCallAbort(comm,STGetNumMatrices(blopex->st,&nmat));
     63:   PetscCallAbort(comm,STGetMatrix(blopex->st,0,&A));
     64:   if (nmat>1) PetscCallAbort(comm,STGetMatrix(blopex->st,1,&B));
     65:   PetscCallAbort(comm,MatMult(A,(Vec)x,(Vec)y));
     66:   PetscCallAbort(comm,STGetShift(blopex->st,&sigma));
     67:   if (sigma != 0.0) {
     68:     if (nmat>1) PetscCallAbort(comm,MatMult(B,(Vec)x,blopex->w));
     69:     else PetscCallAbort(comm,VecCopy((Vec)x,blopex->w));
     70:     PetscCallAbort(comm,VecAXPY((Vec)y,-sigma,blopex->w));
     71:   }
     72:   PetscFunctionReturnVoid();
     73: }

     75: static void OperatorAMultiVector(void *data,void *x,void *y)
     76: {
     77:   EPS_BLOPEX *blopex = (EPS_BLOPEX*)data;

     79:   PetscFunctionBegin;
     80:   blopex->ii.Eval(OperatorASingleVector,data,x,y);
     81:   PetscFunctionReturnVoid();
     82: }

     84: static void OperatorBSingleVector(void *data,void *x,void *y)
     85: {
     86:   EPS_BLOPEX     *blopex = (EPS_BLOPEX*)data;
     87:   MPI_Comm       comm = PetscObjectComm((PetscObject)blopex->st);
     88:   Mat            B;

     90:   PetscFunctionBegin;
     91:   PetscCallAbort(comm,STGetMatrix(blopex->st,1,&B));
     92:   PetscCallAbort(comm,MatMult(B,(Vec)x,(Vec)y));
     93:   PetscFunctionReturnVoid();
     94: }

     96: static void OperatorBMultiVector(void *data,void *x,void *y)
     97: {
     98:   EPS_BLOPEX *blopex = (EPS_BLOPEX*)data;

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

    105: static PetscErrorCode EPSSetDimensions_BLOPEX(EPS eps,PetscInt nev,PetscInt *ncv,PetscInt *mpd)
    106: {
    107:   EPS_BLOPEX     *ctx = (EPS_BLOPEX*)eps->data;
    108:   PetscInt       k;

    110:   PetscFunctionBegin;
    111:   k = ((eps->nev-1)/ctx->bs+1)*ctx->bs;
    112:   if (*ncv!=PETSC_DETERMINE) { /* ncv set */
    113:     PetscCheck(*ncv>=k,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER_INPUT,"The value of ncv is not sufficiently large");
    114:   } else *ncv = k;
    115:   if (*mpd==PETSC_DETERMINE) *mpd = *ncv;
    116:   else PetscCall(PetscInfo(eps,"Warning: given value of mpd ignored\n"));
    117:   PetscFunctionReturn(PETSC_SUCCESS);
    118: }

    120: static PetscErrorCode EPSSetUp_BLOPEX(EPS eps)
    121: {
    122:   EPS_BLOPEX     *blopex = (EPS_BLOPEX*)eps->data;
    123:   PetscBool      flg;
    124:   KSP            ksp;

    126:   PetscFunctionBegin;
    127:   EPSCheckHermitianDefinite(eps);
    128:   EPSCheckNotStructured(eps);
    129:   if (!blopex->bs) blopex->bs = PetscMin(16,eps->nev);
    130:   PetscCall(EPSSetDimensions_BLOPEX(eps,eps->nev,&eps->ncv,&eps->mpd));
    131:   if (eps->max_it==PETSC_DETERMINE) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
    132:   if (!eps->which) eps->which = EPS_SMALLEST_REAL;
    133:   PetscCheck(eps->which==EPS_SMALLEST_REAL,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"This solver supports only smallest real eigenvalues");
    134:   EPSCheckUnsupported(eps,EPS_FEATURE_ARBITRARY | EPS_FEATURE_REGION | EPS_FEATURE_STOPPING);
    135:   EPSCheckIgnored(eps,EPS_FEATURE_BALANCE | EPS_FEATURE_EXTRACTION);

    137:   blopex->st = eps->st;

    139:   PetscCheck(eps->converged==EPSConvergedRelative || eps->converged==EPSConvergedAbsolute,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Convergence test not supported in this solver");
    140:   if (eps->converged == EPSConvergedRelative) {
    141:     blopex->tol.absolute = 0.0;
    142:     blopex->tol.relative = SlepcDefaultTol(eps->tol);
    143:   } else {  /* EPSConvergedAbsolute */
    144:     blopex->tol.absolute = SlepcDefaultTol(eps->tol);
    145:     blopex->tol.relative = 0.0;
    146:   }

    148:   SLEPCSetupInterpreter(&blopex->ii);

    150:   PetscCall(STGetKSP(eps->st,&ksp));
    151:   PetscCall(PetscObjectTypeCompare((PetscObject)ksp,KSPPREONLY,&flg));
    152:   if (!flg) PetscCall(PetscInfo(eps,"Warning: ignoring KSP, should use KSPPREONLY\n"));

    154:   /* allocate memory */
    155:   if (!eps->V) PetscCall(EPSGetBV(eps,&eps->V));
    156:   PetscCall(PetscObjectTypeCompareAny((PetscObject)eps->V,&flg,BVVECS,BVCONTIGUOUS,""));
    157:   if (!flg) {  /* blopex only works with BVVECS or BVCONTIGUOUS */
    158:     PetscCall(BVSetType(eps->V,BVCONTIGUOUS));
    159:   }
    160:   PetscCall(EPSAllocateSolution(eps,0));
    161:   if (!blopex->w) PetscCall(BVCreateVec(eps->V,&blopex->w));

    163: #if defined(PETSC_USE_COMPLEX)
    164:   blopex->blap_fn.zpotrf = PETSC_zpotrf_interface;
    165:   blopex->blap_fn.zhegv = PETSC_zsygv_interface;
    166: #else
    167:   blopex->blap_fn.dpotrf = PETSC_dpotrf_interface;
    168:   blopex->blap_fn.dsygv = PETSC_dsygv_interface;
    169: #endif
    170:   PetscFunctionReturn(PETSC_SUCCESS);
    171: }

    173: static PetscErrorCode EPSSolve_BLOPEX(EPS eps)
    174: {
    175:   EPS_BLOPEX        *blopex = (EPS_BLOPEX*)eps->data;
    176:   PetscScalar       sigma,*eigr=NULL;
    177:   PetscReal         *errest=NULL;
    178:   int               i,j,info,its,nconv;
    179:   double            *residhist=NULL;
    180:   mv_MultiVectorPtr eigenvectors,constraints;
    181: #if defined(PETSC_USE_COMPLEX)
    182:   komplex           *lambda=NULL,*lambdahist=NULL;
    183: #else
    184:   double            *lambda=NULL,*lambdahist=NULL;
    185: #endif

    187:   PetscFunctionBegin;
    188:   PetscCall(STGetShift(eps->st,&sigma));
    189:   PetscCall(PetscMalloc1(blopex->bs,&lambda));
    190:   if (eps->numbermonitors>0) PetscCall(PetscMalloc4(blopex->bs*(eps->max_it+1),&lambdahist,eps->ncv,&eigr,blopex->bs*(eps->max_it+1),&residhist,eps->ncv,&errest));

    192:   /* Complete the initial basis with random vectors */
    193:   for (i=0;i<eps->nini;i++) {  /* in case the initial vectors were also set with VecSetRandom */
    194:     PetscCall(BVSetRandomColumn(eps->V,eps->nini));
    195:   }
    196:   for (i=eps->nini;i<eps->ncv;i++) PetscCall(BVSetRandomColumn(eps->V,i));

    198:   while (eps->reason == EPS_CONVERGED_ITERATING) {

    200:     /* Create multivector of constraints from leading columns of V */
    201:     PetscCall(PetscObjectComposedDataSetInt((PetscObject)eps->V,slepc_blopex_useconstr,1));
    202:     PetscCall(BVSetActiveColumns(eps->V,0,eps->nconv));
    203:     constraints = mv_MultiVectorCreateFromSampleVector(&blopex->ii,eps->nds+eps->nconv,eps->V);

    205:     /* Create multivector where eigenvectors of this run will be stored */
    206:     PetscCall(PetscObjectComposedDataSetInt((PetscObject)eps->V,slepc_blopex_useconstr,0));
    207:     PetscCall(BVSetActiveColumns(eps->V,eps->nconv,eps->nconv+blopex->bs));
    208:     eigenvectors = mv_MultiVectorCreateFromSampleVector(&blopex->ii,blopex->bs,eps->V);

    210: #if defined(PETSC_USE_COMPLEX)
    211:     info = lobpcg_solve_complex(eigenvectors,blopex,OperatorAMultiVector,
    212:           eps->isgeneralized?blopex:NULL,eps->isgeneralized?OperatorBMultiVector:NULL,
    213:           blopex,Precond_FnMultiVector,constraints,
    214:           blopex->blap_fn,blopex->tol,eps->max_it,0,&its,
    215:           lambda,lambdahist,blopex->bs,eps->errest+eps->nconv,residhist,blopex->bs);
    216: #else
    217:     info = lobpcg_solve_double(eigenvectors,blopex,OperatorAMultiVector,
    218:           eps->isgeneralized?blopex:NULL,eps->isgeneralized?OperatorBMultiVector:NULL,
    219:           blopex,Precond_FnMultiVector,constraints,
    220:           blopex->blap_fn,blopex->tol,eps->max_it,0,&its,
    221:           lambda,lambdahist,blopex->bs,eps->errest+eps->nconv,residhist,blopex->bs);
    222: #endif
    223:     PetscCheck(info==0,PetscObjectComm((PetscObject)eps),PETSC_ERR_LIB,"BLOPEX failed with exit code=%d",info);
    224:     mv_MultiVectorDestroy(constraints);
    225:     mv_MultiVectorDestroy(eigenvectors);

    227:     for (j=0;j<blopex->bs;j++) {
    228: #if defined(PETSC_USE_COMPLEX)
    229:       eps->eigr[eps->nconv+j] = PetscCMPLX(lambda[j].real,lambda[j].imag);
    230: #else
    231:       eps->eigr[eps->nconv+j] = lambda[j];
    232: #endif
    233:     }

    235:     if (eps->numbermonitors>0) {
    236:       for (i=0;i<its;i++) {
    237:         nconv = 0;
    238:         for (j=0;j<blopex->bs;j++) {
    239: #if defined(PETSC_USE_COMPLEX)
    240:           eigr[eps->nconv+j] = PetscCMPLX(lambdahist[j+i*blopex->bs].real,lambdahist[j+i*blopex->bs].imag);
    241: #else
    242:           eigr[eps->nconv+j] = lambdahist[j+i*blopex->bs];
    243: #endif
    244:           errest[eps->nconv+j] = residhist[j+i*blopex->bs];
    245:           if (residhist[j+i*blopex->bs]<=eps->tol) nconv++;
    246:         }
    247:         PetscCall(EPSMonitor(eps,eps->its+i,eps->nconv+nconv,eigr,eps->eigi,errest,eps->nconv+blopex->bs));
    248:       }
    249:     }

    251:     eps->its += its;
    252:     if (info==-1) {
    253:       eps->reason = EPS_DIVERGED_ITS;
    254:       break;
    255:     } else {
    256:       for (i=0;i<blopex->bs;i++) {
    257:         if (sigma != 0.0) eps->eigr[eps->nconv+i] += sigma;
    258:       }
    259:       eps->nconv += blopex->bs;
    260:       if (eps->nconv>=eps->nev) eps->reason = EPS_CONVERGED_TOL;
    261:     }
    262:   }

    264:   PetscCall(PetscFree(lambda));
    265:   if (eps->numbermonitors>0) PetscCall(PetscFree4(lambdahist,eigr,residhist,errest));
    266:   PetscFunctionReturn(PETSC_SUCCESS);
    267: }

    269: static PetscErrorCode EPSBLOPEXSetBlockSize_BLOPEX(EPS eps,PetscInt bs)
    270: {
    271:   EPS_BLOPEX *ctx = (EPS_BLOPEX*)eps->data;

    273:   PetscFunctionBegin;
    274:   if (bs==PETSC_DEFAULT || bs==PETSC_DECIDE) {
    275:     ctx->bs    = 0;
    276:     eps->state = EPS_STATE_INITIAL;
    277:   } else {
    278:     PetscCheck(bs>0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Block size must be >0");
    279:     ctx->bs = bs;
    280:   }
    281:   PetscFunctionReturn(PETSC_SUCCESS);
    282: }

    284: /*@
    285:    EPSBLOPEXSetBlockSize - Sets the block size of the BLOPEX solver.

    287:    Logically Collective

    289:    Input Parameters:
    290: +  eps - the eigenproblem solver context
    291: -  bs  - the block size

    293:    Options Database Key:
    294: .  -eps_blopex_blocksize - Sets the block size

    296:    Level: advanced

    298: .seealso: EPSBLOPEXGetBlockSize()
    299: @*/
    300: PetscErrorCode EPSBLOPEXSetBlockSize(EPS eps,PetscInt bs)
    301: {
    302:   PetscFunctionBegin;
    305:   PetscTryMethod(eps,"EPSBLOPEXSetBlockSize_C",(EPS,PetscInt),(eps,bs));
    306:   PetscFunctionReturn(PETSC_SUCCESS);
    307: }

    309: static PetscErrorCode EPSBLOPEXGetBlockSize_BLOPEX(EPS eps,PetscInt *bs)
    310: {
    311:   EPS_BLOPEX *ctx = (EPS_BLOPEX*)eps->data;

    313:   PetscFunctionBegin;
    314:   *bs = ctx->bs;
    315:   PetscFunctionReturn(PETSC_SUCCESS);
    316: }

    318: /*@
    319:    EPSBLOPEXGetBlockSize - Gets the block size used in the BLOPEX solver.

    321:    Not Collective

    323:    Input Parameter:
    324: .  eps - the eigenproblem solver context

    326:    Output Parameter:
    327: .  bs - the block size

    329:    Level: advanced

    331: .seealso: EPSBLOPEXSetBlockSize()
    332: @*/
    333: PetscErrorCode EPSBLOPEXGetBlockSize(EPS eps,PetscInt *bs)
    334: {
    335:   PetscFunctionBegin;
    337:   PetscAssertPointer(bs,2);
    338:   PetscUseMethod(eps,"EPSBLOPEXGetBlockSize_C",(EPS,PetscInt*),(eps,bs));
    339:   PetscFunctionReturn(PETSC_SUCCESS);
    340: }

    342: static PetscErrorCode EPSReset_BLOPEX(EPS eps)
    343: {
    344:   EPS_BLOPEX     *blopex = (EPS_BLOPEX*)eps->data;

    346:   PetscFunctionBegin;
    347:   PetscCall(VecDestroy(&blopex->w));
    348:   PetscFunctionReturn(PETSC_SUCCESS);
    349: }

    351: static PetscErrorCode EPSDestroy_BLOPEX(EPS eps)
    352: {
    353:   PetscFunctionBegin;
    354:   LOBPCG_DestroyRandomContext();
    355:   PetscCall(PetscFree(eps->data));
    356:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSBLOPEXSetBlockSize_C",NULL));
    357:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSBLOPEXGetBlockSize_C",NULL));
    358:   PetscFunctionReturn(PETSC_SUCCESS);
    359: }

    361: static PetscErrorCode EPSView_BLOPEX(EPS eps,PetscViewer viewer)
    362: {
    363:   EPS_BLOPEX     *ctx = (EPS_BLOPEX*)eps->data;
    364:   PetscBool      isascii;

    366:   PetscFunctionBegin;
    367:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
    368:   if (isascii) PetscCall(PetscViewerASCIIPrintf(viewer,"  block size %" PetscInt_FMT "\n",ctx->bs));
    369:   PetscFunctionReturn(PETSC_SUCCESS);
    370: }

    372: static PetscErrorCode EPSSetFromOptions_BLOPEX(EPS eps,PetscOptionItems *PetscOptionsObject)
    373: {
    374:   PetscBool      flg;
    375:   PetscInt       bs;

    377:   PetscFunctionBegin;
    378:   PetscOptionsHeadBegin(PetscOptionsObject,"EPS BLOPEX Options");

    380:     PetscCall(PetscOptionsInt("-eps_blopex_blocksize","Block size","EPSBLOPEXSetBlockSize",20,&bs,&flg));
    381:     if (flg) PetscCall(EPSBLOPEXSetBlockSize(eps,bs));

    383:   PetscOptionsHeadEnd();

    385:   LOBPCG_SetFromOptionsRandomContext();
    386:   PetscFunctionReturn(PETSC_SUCCESS);
    387: }

    389: SLEPC_EXTERN PetscErrorCode EPSCreate_BLOPEX(EPS eps)
    390: {
    391:   EPS_BLOPEX     *ctx;

    393:   PetscFunctionBegin;
    394:   PetscCall(PetscNew(&ctx));
    395:   eps->data = (void*)ctx;

    397:   eps->categ = EPS_CATEGORY_PRECOND;

    399:   eps->ops->solve          = EPSSolve_BLOPEX;
    400:   eps->ops->setup          = EPSSetUp_BLOPEX;
    401:   eps->ops->setupsort      = EPSSetUpSort_Basic;
    402:   eps->ops->setfromoptions = EPSSetFromOptions_BLOPEX;
    403:   eps->ops->destroy        = EPSDestroy_BLOPEX;
    404:   eps->ops->reset          = EPSReset_BLOPEX;
    405:   eps->ops->view           = EPSView_BLOPEX;
    406:   eps->ops->backtransform  = EPSBackTransform_Default;
    407:   eps->ops->setdefaultst   = EPSSetDefaultST_GMRES;

    409:   LOBPCG_InitRandomContext(PetscObjectComm((PetscObject)eps),NULL);
    410:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSBLOPEXSetBlockSize_C",EPSBLOPEXSetBlockSize_BLOPEX));
    411:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSBLOPEXGetBlockSize_C",EPSBLOPEXGetBlockSize_BLOPEX));
    412:   if (slepc_blopex_useconstr < 0) PetscCall(PetscObjectComposedDataRegister(&slepc_blopex_useconstr));
    413:   PetscFunctionReturn(PETSC_SUCCESS);
    414: }