Actual source code: slp.c
slepc-3.10.1 2018-10-23
Report Typos and Errors

      1: /*
      2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      4:    Copyright (c) 2002-2018, 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 nonlinear eigensolver: "slp"

     13:    Method: Succesive linear problems

     15:    Algorithm:

     17:        Newton-type iteration based on first order Taylor approximation.

     19:    References:

     21:        [1] A. Ruhe, "Algorithms for the nonlinear eigenvalue problem", SIAM J.
     22:            Numer. Anal. 10(4):674-689, 1973.
     23: */

     25: #include <slepc/private/nepimpl.h>         /*I "slepcnep.h" I*/
     26: #include <../src/nep/impls/nepdefl.h>

     28: typedef struct {
     29:   EPS        eps;      /* linear eigensolver for T*z = mu*Tp*z */
     30:   KSP        ksp;
     31: } NEP_SLP;

     33: typedef struct {
     34:   NEP_EXT_OP extop;
     35:   Vec        w;
     36: } NEP_SLP_EPS_MSHELL;

     38: PetscErrorCode NEPSetUp_SLP(NEP nep)
     39: {
     41:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;
     42:   PetscBool      istrivial,flg;
     43:   ST             st;

     46:   if (nep->ncv) { PetscInfo(nep,"Setting ncv = nev, ignoring user-provided value\n"); }
     47:   nep->ncv = nep->nev;
     48:   if (nep->mpd) { PetscInfo(nep,"Setting mpd = nev, ignoring user-provided value\n"); }
     49:   nep->mpd = nep->nev;
     50:   if (nep->ncv>nep->nev+nep->mpd) SETERRQ(PetscObjectComm((PetscObject)nep),1,"The value of ncv must not be larger than nev+mpd");
     51:   if (!nep->max_it) nep->max_it = PetscMax(5000,2*nep->n/nep->ncv);
     52:   if (nep->which && nep->which!=NEP_TARGET_MAGNITUDE) SETERRQ(PetscObjectComm((PetscObject)nep),1,"Wrong value of which");

     54:   RGIsTrivial(nep->rg,&istrivial);
     55:   if (!istrivial) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"This solver does not support region filtering");

     57:   if (!ctx->eps) { NEPSLPGetEPS(nep,&ctx->eps); }
     58:   EPSGetST(ctx->eps,&st);
     59:   PetscObjectTypeCompareAny((PetscObject)st,&flg,STSINVERT,STCAYLEY,"");
     60:   if (flg) SETERRQ(PetscObjectComm((PetscObject)nep),1,"SLP does not support spectral transformation");
     61:   EPSSetDimensions(ctx->eps,1,PETSC_DECIDE,PETSC_DECIDE);
     62:   EPSSetWhichEigenpairs(ctx->eps,EPS_LARGEST_MAGNITUDE);
     63:   EPSSetTolerances(ctx->eps,nep->tol==PETSC_DEFAULT?SLEPC_DEFAULT_TOL/10.0:nep->tol/10.0,nep->max_it?nep->max_it:PETSC_DEFAULT);

     65:   NEPAllocateSolution(nep,0);
     66:   return(0);
     67: }

     69: PetscErrorCode NEPSLPEPSMatShell_MatMult(Mat M,Vec x,Vec y)
     70: {
     71:   PetscErrorCode     ierr;
     72:   NEP_SLP_EPS_MSHELL *ctx;

     75:   MatShellGetContext(M,(void**)&ctx);
     76:   MatMult(ctx->extop->MJ,x,ctx->w);
     77:   NEPDeflationFunctionSolve(ctx->extop,ctx->w,y);
     78:   return(0);
     79: }

     81: PetscErrorCode NEPSLPEPSMatShell_Destroy(Mat M)
     82: {
     83:   PetscErrorCode     ierr;
     84:   NEP_SLP_EPS_MSHELL *ctx;

     87:   MatShellGetContext(M,(void**)&ctx);
     88:   VecDestroy(&ctx->w);
     89:   PetscFree(ctx);
     90:   return(0);
     91: }

     93: PetscErrorCode NEPSLPEPSMatShell_CreateVecs(Mat M,Vec *left,Vec *right)
     94: {
     95:   PetscErrorCode     ierr;
     96:   NEP_SLP_EPS_MSHELL *ctx;

     99:   MatShellGetContext(M,(void**)&ctx);
    100:   if (right) {
    101:     VecDuplicate(ctx->w,right);
    102:   }
    103:   if (left) {
    104:     VecDuplicate(ctx->w,left);
    105:   }
    106:   return(0);
    107: }

    109: static PetscErrorCode NEPSLPSetUpLinearEP(NEP nep,NEP_EXT_OP extop,PetscScalar lambda,Vec u,PetscBool ini)
    110: {
    111:   PetscErrorCode     ierr;
    112:   NEP_SLP            *slpctx = (NEP_SLP*)nep->data;
    113:   Mat                Mshell;
    114:   PetscInt           nloc,mloc;
    115:   NEP_SLP_EPS_MSHELL *shellctx;

    118:   if (ini) {
    119:     /* Create mat shell */
    120:     PetscNew(&shellctx);
    121:     shellctx->extop = extop;
    122:     NEPDeflationCreateVec(extop,&shellctx->w);
    123:     MatGetLocalSize(nep->function,&mloc,&nloc);
    124:     nloc += extop->szd; mloc += extop->szd;
    125:     MatCreateShell(PetscObjectComm((PetscObject)nep),nloc,mloc,PETSC_DETERMINE,PETSC_DETERMINE,shellctx,&Mshell);
    126:     MatShellSetOperation(Mshell,MATOP_MULT,(void(*)())NEPSLPEPSMatShell_MatMult);
    127:     MatShellSetOperation(Mshell,MATOP_DESTROY,(void(*)())NEPSLPEPSMatShell_Destroy);
    128:     MatShellSetOperation(Mshell,MATOP_CREATE_VECS,(void(*)())NEPSLPEPSMatShell_CreateVecs);
    129:     EPSSetOperators(slpctx->eps,Mshell,NULL);
    130:     MatDestroy(&Mshell);
    131:   }
    132:   NEPDeflationSolveSetUp(extop,lambda);
    133:   NEPDeflationComputeJacobian(extop,lambda,NULL);
    134:   EPSSetInitialSpace(slpctx->eps,1,&u);
    135:   return(0);
    136: }

    138: PetscErrorCode NEPSolve_SLP(NEP nep)
    139: {
    141:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;
    142:   Mat            F,H;
    143:   Vec            uu,u,r;
    144:   PetscScalar    sigma,lambda,mu,im,*Hp,*Ap;
    145:   PetscReal      resnorm;
    146:   PetscInt       nconv,ldh,ldds,i,j;
    147:   PetscBool      skip=PETSC_FALSE;
    148:   NEP_EXT_OP     extop=NULL;    /* Extended operator for deflation */

    151:   /* get initial approximation of eigenvalue and eigenvector */
    152:   NEPGetDefaultShift(nep,&sigma);
    153:   if (!nep->nini) {
    154:     BVSetRandomColumn(nep->V,0);
    155:   }
    156:   lambda = sigma;
    157:   if (!ctx->ksp) { NEPSLPGetKSP(nep,&ctx->ksp); }
    158:   NEPDeflationInitialize(nep,nep->V,ctx->ksp,PETSC_TRUE,nep->nev,&extop);
    159:   NEPDeflationCreateVec(extop,&u);
    160:   VecDuplicate(u,&r);
    161:   BVGetColumn(nep->V,0,&uu);
    162:   NEPDeflationCopyToExtendedVec(extop,uu,NULL,u,PETSC_FALSE);
    163:   BVRestoreColumn(nep->V,0,&uu);

    165:   /* Restart loop */
    166:   while (nep->reason == NEP_CONVERGED_ITERATING) {
    167:     nep->its++;

    169:     /* form residual,  r = T(lambda)*u (used in convergence test only) */
    170:     NEPDeflationComputeFunction(extop,lambda,&F);
    171:     MatMult(F,u,r);

    173:     /* convergence test */
    174:     VecNorm(r,NORM_2,&resnorm);
    175:     (*nep->converged)(nep,lambda,0,resnorm,&nep->errest[nep->nconv],nep->convergedctx);
    176:     nep->eigr[nep->nconv] = lambda;
    177:     if (nep->errest[nep->nconv]<=nep->tol) {
    178:       nep->nconv = nep->nconv + 1;
    179:       skip = PETSC_TRUE;
    180:       NEPDeflationLocking(extop,u,lambda);
    181:     }
    182:     (*nep->stopping)(nep,nep->its,nep->max_it,nep->nconv,nep->nev,&nep->reason,nep->stoppingctx);
    183:     if (!skip || nep->reason>0) {
    184:       NEPMonitor(nep,nep->its,nep->nconv,nep->eigr,nep->eigi,nep->errest,(nep->reason>0)?nep->nconv:nep->nconv+1);
    185:     }

    187:     if (nep->reason == NEP_CONVERGED_ITERATING) {
    188:       if (!skip) {
    189:         /* evaluate T(lambda) and T'(lambda) */
    190:         NEPSLPSetUpLinearEP(nep,extop,lambda,u,nep->its==1?PETSC_TRUE:PETSC_FALSE);
    191:         /* compute new eigenvalue correction mu and eigenvector approximation u */
    192:         EPSSolve(ctx->eps);
    193:         EPSGetConverged(ctx->eps,&nconv);
    194:         if (!nconv) {
    195:           PetscInfo1(nep,"iter=%D, inner iteration failed, stopping solve\n",nep->its);
    196:           nep->reason = NEP_DIVERGED_LINEAR_SOLVE;
    197:           break;
    198:         }
    199:         EPSGetEigenpair(ctx->eps,0,&mu,&im,u,NULL);
    200:         mu = 1.0/mu;
    201:         if (PetscAbsScalar(im)>PETSC_MACHINE_EPSILON) SETERRQ(PetscObjectComm((PetscObject)nep),1,"Complex eigenvalue approximation - not implemented in real scalars");
    202:       } else {
    203:         nep->its--;  /* do not count this as a full iteration */
    204:         /* use second eigenpair computed in previous iteration */
    205:         EPSGetConverged(ctx->eps,&nconv);
    206:         if (nconv>=2) {
    207:           EPSGetEigenpair(ctx->eps,1,&mu,&im,u,NULL);
    208:           mu = 1.0/mu;
    209:         } else {
    210:           NEPDeflationSetRandomVec(extop,u);
    211:           mu = lambda-sigma;
    212:         }
    213:         skip = PETSC_FALSE;
    214:       }
    215:       /* correct eigenvalue */
    216:       lambda = lambda - mu;
    217:     }
    218:   }
    219:   NEPDeflationGetInvariantPair(extop,NULL,&H);
    220:   MatGetSize(H,NULL,&ldh);
    221:   DSSetType(nep->ds,DSNHEP);
    222:   DSAllocate(nep->ds,PetscMax(nep->nconv,1));
    223:   DSGetLeadingDimension(nep->ds,&ldds);
    224:   MatDenseGetArray(H,&Hp);
    225:   DSGetArray(nep->ds,DS_MAT_A,&Ap);
    226:   for (j=0;j<nep->nconv;j++)
    227:     for (i=0;i<nep->nconv;i++) Ap[j*ldds+i] = Hp[j*ldh+i];
    228:   DSRestoreArray(nep->ds,DS_MAT_A,&Ap);
    229:   MatDenseRestoreArray(H,&Hp);
    230:   MatDestroy(&H);
    231:   DSSetDimensions(nep->ds,nep->nconv,0,0,nep->nconv);
    232:   DSSolve(nep->ds,nep->eigr,nep->eigi);
    233:   NEPDeflationReset(extop);
    234:   VecDestroy(&u);
    235:   VecDestroy(&r);
    236:   return(0);
    237: }

    239: PetscErrorCode NEPSetFromOptions_SLP(PetscOptionItems *PetscOptionsObject,NEP nep)
    240: {
    242:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;

    245:   PetscOptionsHead(PetscOptionsObject,"NEP SLP Options");
    246:   PetscOptionsTail();

    248:   if (!ctx->eps) { NEPSLPGetEPS(nep,&ctx->eps); }
    249:   EPSSetFromOptions(ctx->eps);
    250:   if (!ctx->ksp) { NEPSLPGetKSP(nep,&ctx->ksp); }
    251:   KSPSetFromOptions(ctx->ksp);
    252:   return(0);
    253: }

    255: static PetscErrorCode NEPSLPSetEPS_SLP(NEP nep,EPS eps)
    256: {
    258:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;

    261:   PetscObjectReference((PetscObject)eps);
    262:   EPSDestroy(&ctx->eps);
    263:   ctx->eps = eps;
    264:   PetscLogObjectParent((PetscObject)nep,(PetscObject)ctx->eps);
    265:   nep->state = NEP_STATE_INITIAL;
    266:   return(0);
    267: }

    269: /*@
    270:    NEPSLPSetEPS - Associate a linear eigensolver object (EPS) to the
    271:    nonlinear eigenvalue solver.

    273:    Collective on NEP

    275:    Input Parameters:
    276: +  nep - nonlinear eigenvalue solver
    277: -  eps - the eigensolver object

    279:    Level: advanced

    281: .seealso: NEPSLPGetEPS()
    282: @*/
    283: PetscErrorCode NEPSLPSetEPS(NEP nep,EPS eps)
    284: {

    291:   PetscTryMethod(nep,"NEPSLPSetEPS_C",(NEP,EPS),(nep,eps));
    292:   return(0);
    293: }

    295: static PetscErrorCode NEPSLPGetEPS_SLP(NEP nep,EPS *eps)
    296: {
    298:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;

    301:   if (!ctx->eps) {
    302:     EPSCreate(PetscObjectComm((PetscObject)nep),&ctx->eps);
    303:     PetscObjectIncrementTabLevel((PetscObject)ctx->eps,(PetscObject)nep,1);
    304:     EPSSetOptionsPrefix(ctx->eps,((PetscObject)nep)->prefix);
    305:     EPSAppendOptionsPrefix(ctx->eps,"nep_slp_");
    306:     PetscLogObjectParent((PetscObject)nep,(PetscObject)ctx->eps);
    307:   }
    308:   *eps = ctx->eps;
    309:   return(0);
    310: }

    312: /*@
    313:    NEPSLPGetEPS - Retrieve the linear eigensolver object (EPS) associated
    314:    to the nonlinear eigenvalue solver.

    316:    Not Collective

    318:    Input Parameter:
    319: .  nep - nonlinear eigenvalue solver

    321:    Output Parameter:
    322: .  eps - the eigensolver object

    324:    Level: advanced

    326: .seealso: NEPSLPSetEPS()
    327: @*/
    328: PetscErrorCode NEPSLPGetEPS(NEP nep,EPS *eps)
    329: {

    335:   PetscUseMethod(nep,"NEPSLPGetEPS_C",(NEP,EPS*),(nep,eps));
    336:   return(0);
    337: }

    339: static PetscErrorCode NEPSLPSetKSP_SLP(NEP nep,KSP ksp)
    340: {
    342:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;

    345:   PetscObjectReference((PetscObject)ksp);
    346:   KSPDestroy(&ctx->ksp);
    347:   ctx->ksp = ksp;
    348:   PetscLogObjectParent((PetscObject)nep,(PetscObject)ctx->ksp);
    349:   nep->state = NEP_STATE_INITIAL;
    350:   return(0);
    351: }

    353: /*@
    354:    NEPSLPSetKSP - Associate a linear solver object (KSP) to the nonlinear
    355:    eigenvalue solver.

    357:    Collective on NEP

    359:    Input Parameters:
    360: +  nep - eigenvalue solver
    361: -  ksp - the linear solver object

    363:    Level: advanced

    365: .seealso: NEPSLPGetKSP()
    366: @*/
    367: PetscErrorCode NEPSLPSetKSP(NEP nep,KSP ksp)
    368: {

    375:   PetscTryMethod(nep,"NEPSLPSetKSP_C",(NEP,KSP),(nep,ksp));
    376:   return(0);
    377: }

    379: static PetscErrorCode NEPSLPGetKSP_SLP(NEP nep,KSP *ksp)
    380: {
    382:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;

    385:   if (!ctx->ksp) {
    386:     KSPCreate(PetscObjectComm((PetscObject)nep),&ctx->ksp);
    387:     PetscObjectIncrementTabLevel((PetscObject)ctx->ksp,(PetscObject)nep,1);
    388:     KSPSetOptionsPrefix(ctx->ksp,((PetscObject)nep)->prefix);
    389:     KSPAppendOptionsPrefix(ctx->ksp,"nep_slp_");
    390:     PetscLogObjectParent((PetscObject)nep,(PetscObject)ctx->ksp);
    391:     KSPSetErrorIfNotConverged(ctx->ksp,PETSC_TRUE);
    392:     KSPSetTolerances(ctx->ksp,SLEPC_DEFAULT_TOL,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
    393:   }
    394:   *ksp = ctx->ksp;
    395:   return(0);
    396: }

    398: /*@
    399:    NEPSLPGetKSP - Retrieve the linear solver object (KSP) associated with
    400:    the nonlinear eigenvalue solver.

    402:    Not Collective

    404:    Input Parameter:
    405: .  nep - nonlinear eigenvalue solver

    407:    Output Parameter:
    408: .  ksp - the linear solver object

    410:    Level: advanced

    412: .seealso: NEPSLPSetKSP()
    413: @*/
    414: PetscErrorCode NEPSLPGetKSP(NEP nep,KSP *ksp)
    415: {

    421:   PetscUseMethod(nep,"NEPSLPGetKSP_C",(NEP,KSP*),(nep,ksp));
    422:   return(0);
    423: }

    425: PetscErrorCode NEPView_SLP(NEP nep,PetscViewer viewer)
    426: {
    428:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;
    429:   PetscBool      isascii;

    432:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
    433:   if (isascii) {
    434:     if (!ctx->eps) { NEPSLPGetEPS(nep,&ctx->eps); }
    435:     EPSView(ctx->eps,viewer);
    436:   }
    437:   return(0);
    438: }

    440: PetscErrorCode NEPReset_SLP(NEP nep)
    441: {
    443:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;

    446:   EPSReset(ctx->eps);
    447:   KSPReset(ctx->ksp);
    448:   return(0);
    449: }

    451: PetscErrorCode NEPDestroy_SLP(NEP nep)
    452: {
    454:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;

    457:   KSPDestroy(&ctx->ksp);
    458:   EPSDestroy(&ctx->eps);
    459:   PetscFree(nep->data);
    460:   PetscObjectComposeFunction((PetscObject)nep,"NEPSLPSetEPS_C",NULL);
    461:   PetscObjectComposeFunction((PetscObject)nep,"NEPSLPGetEPS_C",NULL);
    462:   PetscObjectComposeFunction((PetscObject)nep,"NEPSLPSetKSP_C",NULL);
    463:   PetscObjectComposeFunction((PetscObject)nep,"NEPSLPGetKSP_C",NULL);
    464:   return(0);
    465: }

    467: PETSC_EXTERN PetscErrorCode NEPCreate_SLP(NEP nep)
    468: {
    470:   NEP_SLP        *ctx;

    473:   PetscNewLog(nep,&ctx);
    474:   nep->data = (void*)ctx;

    476:   nep->ops->solve          = NEPSolve_SLP;
    477:   nep->ops->setup          = NEPSetUp_SLP;
    478:   nep->ops->setfromoptions = NEPSetFromOptions_SLP;
    479:   nep->ops->reset          = NEPReset_SLP;
    480:   nep->ops->destroy        = NEPDestroy_SLP;
    481:   nep->ops->view           = NEPView_SLP;
    482:   nep->ops->computevectors = NEPComputeVectors_Schur;

    484:   PetscObjectComposeFunction((PetscObject)nep,"NEPSLPSetEPS_C",NEPSLPSetEPS_SLP);
    485:   PetscObjectComposeFunction((PetscObject)nep,"NEPSLPGetEPS_C",NEPSLPGetEPS_SLP);
    486:   PetscObjectComposeFunction((PetscObject)nep,"NEPSLPSetKSP_C",NEPSLPSetKSP_SLP);
    487:   PetscObjectComposeFunction((PetscObject)nep,"NEPSLPGetKSP_C",NEPSLPGetKSP_SLP);
    488:   return(0);
    489: }