Date: 2015-09-03T15:05:45+00:00

Actual source code: pjd.c
slepc-3.6.1 2015-09-03
Report Typos and Errors

      1: /*

      3:    SLEPc polynomial eigensolver: "jd"

      5:    Method: Jacobi-Davidson

      7:    Algorithm:

      9:        Jacobi-Davidson for polynomial eigenvalue problems.
     10:        Based on code contributed by the authors of [2] below.

     12:    References:

     14:        [1] G.L.G. Sleijpen et al., "Jacobi-Davidson type methods for
     15:            generalized eigenproblems and polynomial eigenproblems", BIT
     16:            36(3):595-633, 1996.

     18:        [2] Feng-Nan Hwang, Zih-Hao Wei, Tsung-Ming Huang, Weichung Wang,
     19:            "A Parallel Additive Schwarz Preconditioned Jacobi-Davidson
     20:            Algorithm for Polynomial Eigenvalue Problems in Quantum Dot
     21:            Simulation", J. Comput. Phys. 229(8):2932-2947, 2010.

     23:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     24:    SLEPc - Scalable Library for Eigenvalue Problem Computations
     25:    Copyright (c) 2002-2015, Universitat Politecnica de Valencia, Spain

     27:    This file is part of SLEPc.

     29:    SLEPc is free software: you can redistribute it and/or modify it under  the
     30:    terms of version 3 of the GNU Lesser General Public License as published by
     31:    the Free Software Foundation.

     33:    SLEPc  is  distributed in the hope that it will be useful, but WITHOUT  ANY
     34:    WARRANTY;  without even the implied warranty of MERCHANTABILITY or  FITNESS
     35:    FOR  A  PARTICULAR PURPOSE. See the GNU Lesser General Public  License  for
     36:    more details.

     38:    You  should have received a copy of the GNU Lesser General  Public  License
     39:    along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
     40:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     41: */

     43: #include <slepc/private/pepimpl.h>    /*I "slepcpep.h" I*/
     44: #include <slepc/private/dsimpl.h>
     45:  #include pjdp.h

     49: PetscErrorCode PEPSetUp_JD(PEP pep)
     50: {
     52:   PEP_JD         *pjd = (PEP_JD*)pep->data;
     53:   PetscBool      isshift,flg;
     54:   PetscInt       i;

     57:   pep->lineariz = PETSC_FALSE;
     58:   PEPSetDimensions_Default(pep,pep->nev,&pep->ncv,&pep->mpd);
     59:   if (!pep->max_it) pep->max_it = PetscMax(100,2*pep->n/pep->ncv);
     60:   if (!pep->which) pep->which = PEP_LARGEST_MAGNITUDE;
     61:   if (pep->nev>1) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Polynomial JD does not support nev>1 yet");

     63:   /* Set STSHIFT as the default ST */
     64:   if (!((PetscObject)pep->st)->type_name) {
     65:     STSetType(pep->st,STSHIFT);
     66:   }
     67:   PetscObjectTypeCompare((PetscObject)pep->st,STSHIFT,&isshift);
     68:   if (!isshift) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"JD only works with shift spectral transformation");

     70:   if (pep->basis!=PEP_BASIS_MONOMIAL) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Solver not implemented for non-monomial bases");
     71:   STGetTransform(pep->st,&flg);
     72:   if (flg) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Solver requires the ST transformation flag unset, see STSetTransform()");

     74:   if (!pjd->keep) pjd->keep = 0.5;

     76:   PEPAllocateSolution(pep,0);
     77:   PEPSetWorkVecs(pep,4);
     78:   PetscMalloc1(pep->nmat,&pjd->W);
     79:   for (i=0;i<pep->nmat;i++) {
     80:     BVDuplicate(pep->V,pjd->W+i);
     81:   }
     82:   DSSetType(pep->ds,DSPEP);
     83:   DSPEPSetDegree(pep->ds,pep->nmat-1);
     84:   DSAllocate(pep->ds,pep->ncv);
     85:   return(0);
     86: }

     90: /*
     91:    Check for multiple eigenvalues.
     92: */
     93: static PetscErrorCode PEPJDPurgeDuplicates(PEP pep)
     94: {
     95:   PEP_JD   *pjd = (PEP_JD*)pep->data;
     96:   PetscInt i,k;

     99:   k = pep->nconv;  /* TODO: should have a while loop here */
    100:   for (i=0;i<pep->nconv;i++) {
    101:     if (SlepcAbsEigenvalue(pep->eigr[i]-pep->eigr[k],pep->eigi[i]-pep->eigi[k])<pjd->mtol) {
    102:       pep->eigr[k] = PETSC_INFINITY;
    103:       pep->eigi[k] = PETSC_INFINITY;
    104:       break;
    105:     }
    106:   }
    107:   return(0);
    108: }

    112: /*
    113:    Multiplication of derivative of P, i.e.
    114:       P'(\lambda) x = \sum_{i=1}^{n} (i*\lambda^{i-1} A_i)x
    115: */
    116: static PetscErrorCode PEPJDDiffMatMult(PEP pep,PetscScalar theta,Vec x,Vec y,Vec w)
    117: {
    119:   PetscScalar    fact=1.0;
    120:   PetscInt       i;

    123:   VecSet(y,1.0);
    124:   for (i=1;i<pep->nmat;i++) {
    125:     MatMult(pep->A[i],x,w);
    126:     VecAXPY(y,fact*(PetscReal)i,w);
    127:     fact *= theta;
    128:   }
    129:   return(0);
    130: }

    134: /*
    135:    Application of shell preconditioner:
    136:       y = B\x - eta*B\p,  with eta = (u'*B\x)/(u'*B\p)
    137: */
    138: static PetscErrorCode PCShellApply_PEPJD(PC pc,Vec x,Vec y)
    139: {
    141:   PetscScalar    eta;
    142:   PEP_JD_PCSHELL *pcctx;

    145:   PCShellGetContext(pc,(void**)&pcctx);

    147:   /* y = B\x */
    148:   PCApply(pcctx->pc,x,y);

    150:   /* Compute eta = u'*y / u'*Bp */
    151:   VecDot(y,pcctx->u,&eta);
    152:   eta /= pcctx->gamma;
    153:
    154:   /* y = y - eta*Bp */
    155:   VecAXPY(y,-eta,pcctx->Bp);
    156:   return(0);
    157: }

    161: PetscErrorCode PEPSolve_JD(PEP pep)
    162: {
    164:   PEP_JD         *pjd = (PEP_JD*)pep->data;
    165:   PEP_JD_PCSHELL *pcctx;
    166:   PetscInt       k,nv,ld,minv,low,high;
    167:   PetscScalar    theta,*pX;
    168:   PetscReal      norm;
    169:   PetscBool      lindep;
    170:   Vec            t,u=pep->work[0],p=pep->work[1],r=pep->work[2],w=pep->work[3];
    171:   Mat            G,X,Ptheta;
    172:   KSP            ksp;

    175:   DSGetLeadingDimension(pep->ds,&ld);
    176:   if (pep->nini==0) {
    177:     nv = 1;
    178:     BVSetRandomColumn(pep->V,0,pep->rand);
    179:     BVNormColumn(pep->V,0,NORM_2,&norm);
    180:     BVScaleColumn(pep->V,0,1.0/norm);
    181:   } else nv = pep->nini;

    183:   /* Restart loop */
    184:   while (pep->reason == PEP_CONVERGED_ITERATING) {
    185:     pep->its++;

    187:     low = (pjd->flglk || pjd->flgre)? 0: nv-1;
    188:     high = nv;
    189:     DSSetDimensions(pep->ds,nv,0,0,0);
    190:     BVSetActiveColumns(pep->V,low,high);
    191:     for (k=0;k<pep->nmat;k++) {
    192:       BVSetActiveColumns(pjd->W[k],low,high);
    193:       BVMatMult(pep->V,pep->A[k],pjd->W[k]);
    194:       DSGetMat(pep->ds,DSMatExtra[k],&G);
    195:       BVMatProject(pjd->W[k],NULL,pep->V,G);
    196:       DSRestoreMat(pep->ds,DSMatExtra[k],&G);
    197:     }
    198:     BVSetActiveColumns(pep->V,0,nv);

    200:     /* Solve projected problem */
    201:     DSSetState(pep->ds,DS_STATE_RAW);
    202:     DSSolve(pep->ds,pep->eigr+pep->nconv,pep->eigi+pep->nconv);
    203:     DSSort(pep->ds,pep->eigr+pep->nconv,pep->eigi+pep->nconv,NULL,NULL,NULL);
    204:     PEPJDPurgeDuplicates(pep);
    205:     DSSort(pep->ds,pep->eigr+pep->nconv,pep->eigi+pep->nconv,NULL,NULL,NULL);
    206:     theta = pep->eigr[pep->nconv];
    207: #if !defined(PETSC_USE_COMPLEX)
    208:     if (PetscAbsScalar(pep->eigi[pep->nconv])!=0.0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"PJD solver not implemented for complex Ritz values in real arithmetic");
    209: #endif

    211:     /* Compute Ritz vector u=V*X(:,1) */
    212:     DSGetArray(pep->ds,DS_MAT_X,&pX);
    213:     BVSetActiveColumns(pep->V,0,nv);
    214:     BVMultVec(pep->V,1.0,0.0,u,pX);
    215:     DSRestoreArray(pep->ds,DS_MAT_X,&pX);

    217:     /* Compute p=P'(theta)*u  */
    218:     PEPJDDiffMatMult(pep,theta,u,p,w);

    220:     /* Form matrix P(theta) and compute residual r=P(theta)*u */
    221:     STMatSetUp(pep->st,theta,NULL);
    222:     STGetKSP(pep->st,&ksp);
    223:     KSPGetOperators(ksp,&Ptheta,NULL);
    224:     MatMult(Ptheta,u,r);

    226:     /* Replace preconditioner with one containing projectors */
    227:     if (!pjd->pcshell) {
    228:       PCCreate(PetscObjectComm((PetscObject)ksp),&pjd->pcshell);
    229:       PCSetType(pjd->pcshell,PCSHELL);
    230:       PCShellSetName(pjd->pcshell,"PCPEPJD");
    231:       PCShellSetApply(pjd->pcshell,PCShellApply_PEPJD);
    232:       PetscNew(&pcctx);
    233:       PCShellSetContext(pjd->pcshell,pcctx);
    234:       PCSetOperators(pjd->pcshell,Ptheta,Ptheta);
    235:       VecDuplicate(u,&pcctx->Bp);
    236:       KSPGetPC(ksp,&pcctx->pc);
    237:       PetscObjectReference((PetscObject)pcctx->pc);
    238:     } else {
    239:       KSPGetPC(ksp,&pcctx->pc);
    240:     }
    241:     KSPSetPC(ksp,pjd->pcshell);
    242:     pcctx->u = u;

    244:     /* Check convergence */
    245:     VecNorm(r,NORM_2,&norm);
    246:     (*pep->converged)(pep,theta,0,norm,&pep->errest[pep->nconv],pep->convergedctx);
    247:     if (pep->its >= pep->max_it) pep->reason = PEP_DIVERGED_ITS;

    249:     if (pep->errest[pep->nconv]<pep->tol) {

    251:       /* Ritz pair converged */
    252:       minv = PetscMin(nv,pjd->keep*pep->ncv);
    253:       DSOrthogonalize(pep->ds,DS_MAT_X,nv,NULL);
    254:       DSGetMat(pep->ds,DS_MAT_X,&X);
    255:       BVMultInPlace(pep->V,X,pep->nconv,minv);
    256:       DSRestoreMat(pep->ds,DS_MAT_X,&X);
    257:       pep->nconv++;
    258:       if (pep->nconv >= pep->nev) pep->reason = PEP_CONVERGED_TOL;
    259:       else nv = minv + pep->nconv;
    260:       pjd->flglk = PETSC_TRUE;

    262:     } else if (nv==pep->ncv-1) {

    264:       /* Basis full, force restart */
    265:       minv = PetscMin(nv,pjd->keep*pep->ncv);
    266:       DSOrthogonalize(pep->ds,DS_MAT_X,nv,NULL);
    267:       DSGetMat(pep->ds,DS_MAT_X,&X);
    268:       BVMultInPlace(pep->V,X,pep->nconv,minv);
    269:       DSRestoreMat(pep->ds,DS_MAT_X,&X);
    270:       nv = minv + pep->nconv;
    271:       pjd->flgre = PETSC_TRUE;

    273:     } else {

    275:       /* Solve correction equation to expand basis */
    276:       PCApply(pcctx->pc,p,pcctx->Bp);
    277:       VecScale(r,-1.0);
    278:       VecDot(pcctx->Bp,u,&pcctx->gamma);
    279:       BVGetColumn(pep->V,nv,&t);
    280:       KSPSolve(ksp,r,t);
    281:       BVRestoreColumn(pep->V,nv,&t);
    282:       BVOrthogonalizeColumn(pep->V,nv,NULL,&norm,&lindep);
    283:       if (lindep) SETERRQ(PETSC_COMM_SELF,1,"Linearly dependent continuation vector");
    284:       BVScaleColumn(pep->V,nv,1.0/norm);
    285:       nv++;
    286:       pjd->flglk = PETSC_FALSE;
    287:       pjd->flgre = PETSC_FALSE;
    288:     }

    290:     /* Restore preconditioner */
    291:     KSPGetPC(ksp,&pjd->pcshell);
    292:     KSPSetPC(ksp,pcctx->pc);

    294:     PEPMonitor(pep,pep->its,pep->nconv,pep->eigr,pep->eigi,pep->errest,nv);
    295:   }

    297:   VecDestroy(&pcctx->Bp);
    298:   PCDestroy(&pcctx->pc);
    299:   PetscFree(pcctx);
    300:   PCDestroy(&pjd->pcshell);
    301:   return(0);
    302: }

    306: PetscErrorCode PEPComputeVectors_JD(PEP pep)
    307: {
    309:   PetscInt       k;
    310:   PEP_JD         *pjd = (PEP_JD*)pep->data;
    311:   Mat            G,X;

    314:   DSSetDimensions(pep->ds,pep->nconv,0,0,0);
    315:   BVSetActiveColumns(pep->V,0,pep->nconv);
    316:   for (k=0;k<pep->nmat;k++) {
    317:     BVSetActiveColumns(pjd->W[k],0,pep->nconv);
    318:     BVMatMult(pep->V,pep->A[k],pjd->W[k]);
    319:     DSGetMat(pep->ds,DSMatExtra[k],&G);
    320:     BVMatProject(pjd->W[k],NULL,pep->V,G);
    321:     DSRestoreMat(pep->ds,DSMatExtra[k],&G);
    322:   }

    324:   /* Solve projected problem */
    325:   DSSetState(pep->ds,DS_STATE_RAW);
    326:   DSSolve(pep->ds,pep->eigr,pep->eigi);
    327:   DSSort(pep->ds,pep->eigr,pep->eigi,NULL,NULL,NULL);

    329:   /* Compute Ritz vectors */
    330:   DSGetMat(pep->ds,DS_MAT_X,&X);
    331:   BVMultInPlace(pep->V,X,0,pep->nconv);
    332:   DSRestoreMat(pep->ds,DS_MAT_X,&X);
    333:   return(0);
    334: }

    338: PetscErrorCode PEPReset_JD(PEP pep)
    339: {
    341:   PEP_JD         *pjd = (PEP_JD*)pep->data;
    342:   PetscInt       i;

    345:   for (i=0;i<pep->nmat;i++) {
    346:     BVDestroy(pjd->W+i);
    347:   }
    348:   PetscFree(pjd->W);
    349:   return(0);
    350: }

    354: PetscErrorCode PEPDestroy_JD(PEP pep)
    355: {

    359:   PetscFree(pep->data);
    360:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDSetRestart_C",NULL);
    361:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDGetRestart_C",NULL);
    362:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDSetTolerances_C",NULL);
    363:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDGetTolerances_C",NULL);
    364:   return(0);
    365: }

    369: PETSC_EXTERN PetscErrorCode PEPCreate_JD(PEP pep)
    370: {
    371:   PEP_JD         *pjd;

    375:   PetscNewLog(pep,&pjd);
    376:   pep->data = (void*)pjd;

    378:   pjd->keep = 0;
    379:   pjd->mtol = 1e-5;
    380:   pjd->htol = 1e-2;
    381:   pjd->stol = 1e-2;

    383:   pep->ops->solve          = PEPSolve_JD;
    384:   pep->ops->setup          = PEPSetUp_JD;
    385:   pep->ops->setfromoptions = PEPSetFromOptions_JD;
    386:   pep->ops->reset          = PEPReset_JD;
    387:   pep->ops->destroy        = PEPDestroy_JD;
    388:   pep->ops->view           = PEPView_JD;
    389:   pep->ops->computevectors = PEPComputeVectors_JD;
    390:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDSetRestart_C",PEPJDSetRestart_JD);
    391:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDGetRestart_C",PEPJDGetRestart_JD);
    392:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDSetTolerances_C",PEPJDSetTolerances_JD);
    393:   PetscObjectComposeFunction((PetscObject)pep,"PEPJDGetTolerances_C",PEPJDGetTolerances_JD);
    394:   return(0);
    395: }