Date: 2017-05-17T08:25:37+00:00

Actual source code: epsdefault.c
slepc-3.7.4 2017-05-17
Report Typos and Errors

      1: /*
      2:      This file contains some simple default routines for common operations.

      4:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      5:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      6:    Copyright (c) 2002-2016, 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 <slepcvec.h>

     29: PetscErrorCode EPSBackTransform_Default(EPS eps)
     30: {

     34:   STBackTransform(eps->st,eps->nconv,eps->eigr,eps->eigi);
     35:   return(0);
     36: }

     40: /*
     41:   EPSComputeVectors_Hermitian - Copies the Lanczos vectors as eigenvectors
     42:   using purification for generalized eigenproblems.
     43:  */
     44: PetscErrorCode EPSComputeVectors_Hermitian(EPS eps)
     45: {
     47:   PetscInt       i;
     48:   PetscReal      norm;
     49:   Vec            w,z;

     52:   if (eps->isgeneralized && eps->purify) {
     53:     /* Purify eigenvectors */
     54:     BVCreateVec(eps->V,&w);
     55:     for (i=0;i<eps->nconv;i++) {
     56:       BVCopyVec(eps->V,i,w);
     57:       BVGetColumn(eps->V,i,&z);
     58:       STApply(eps->st,w,z);
     59:       BVRestoreColumn(eps->V,i,&z);
     60:       BVNormColumn(eps->V,i,NORM_2,&norm);
     61:       BVScaleColumn(eps->V,i,1.0/norm);
     62:     }
     63:     VecDestroy(&w);
     64:   }
     65:   return(0);
     66: }

     70: /*
     71:   EPSComputeVectors_Indefinite - similar to the Schur version but
     72:   for indefinite problems
     73:  */
     74: PetscErrorCode EPSComputeVectors_Indefinite(EPS eps)
     75: {
     77:   PetscInt       n,i;
     78:   Mat            X;
     79:   Vec            v,z;
     80: #if !defined(PETSC_USE_COMPLEX)
     81:   Vec            v1;
     82:   PetscScalar    tmp;
     83:   PetscReal      norm,normi;
     84: #endif

     87:   DSGetDimensions(eps->ds,&n,NULL,NULL,NULL,NULL);
     88:   DSVectors(eps->ds,DS_MAT_X,NULL,NULL);
     89:   DSGetMat(eps->ds,DS_MAT_X,&X);
     90:   BVSetActiveColumns(eps->V,0,n);
     91:   BVMultInPlace(eps->V,X,0,n);
     92:   MatDestroy(&X);

     94:   /* purification */
     95:   if (eps->purify) {
     96:     BVCreateVec(eps->V,&v);
     97:     for (i=0;i<eps->nconv;i++) {
     98:       BVCopyVec(eps->V,i,v);
     99:       BVGetColumn(eps->V,i,&z);
    100:       STApply(eps->st,v,z);
    101:       BVRestoreColumn(eps->V,i,&z);
    102:     }
    103:     VecDestroy(&v);
    104:   }

    106:   /* normalization */
    107:   for (i=0;i<n;i++) {
    108: #if !defined(PETSC_USE_COMPLEX)
    109:     if (eps->eigi[i] != 0.0) {
    110:       BVGetColumn(eps->V,i,&v);
    111:       BVGetColumn(eps->V,i+1,&v1);
    112:       VecNorm(v,NORM_2,&norm);
    113:       VecNorm(v1,NORM_2,&normi);
    114:       tmp = 1.0 / SlepcAbsEigenvalue(norm,normi);
    115:       VecScale(v,tmp);
    116:       VecScale(v1,tmp);
    117:       BVRestoreColumn(eps->V,i,&v);
    118:       BVRestoreColumn(eps->V,i+1,&v1);
    119:       i++;
    120:     } else
    121: #endif
    122:     {
    123:       BVGetColumn(eps->V,i,&v);
    124:       VecNormalize(v,NULL);
    125:       BVRestoreColumn(eps->V,i,&v);
    126:     }
    127:   }
    128:   return(0);
    129: }

    133: /*
    134:   EPSComputeVectors_Schur - Compute eigenvectors from the vectors
    135:   provided by the eigensolver. This version is intended for solvers
    136:   that provide Schur vectors. Given the partial Schur decomposition
    137:   OP*V=V*T, the following steps are performed:
    138:       1) compute eigenvectors of T: T*Z=Z*D
    139:       2) compute eigenvectors of OP: X=V*Z
    140:  */
    141: PetscErrorCode EPSComputeVectors_Schur(EPS eps)
    142: {
    144:   PetscInt       n,i;
    145:   Mat            Z;
    146:   Vec            w,z,v;
    147: #if !defined(PETSC_USE_COMPLEX)
    148:   Vec            v1;
    149:   PetscScalar    tmp;
    150:   PetscReal      norm,normi;
    151: #endif

    154:   if (eps->ishermitian) {
    155:     if (eps->isgeneralized && !eps->ispositive) {
    156:        EPSComputeVectors_Indefinite(eps);
    157:     } else {
    158:       EPSComputeVectors_Hermitian(eps);
    159:     }
    160:     return(0);
    161:   }
    162:   DSGetDimensions(eps->ds,&n,NULL,NULL,NULL,NULL);

    164:   /* right eigenvectors */
    165:   DSVectors(eps->ds,DS_MAT_X,NULL,NULL);

    167:   /* V = V * Z */
    168:   DSGetMat(eps->ds,DS_MAT_X,&Z);
    169:   BVSetActiveColumns(eps->V,0,n);
    170:   BVMultInPlace(eps->V,Z,0,n);
    171:   MatDestroy(&Z);

    173:   /* Purify eigenvectors */
    174:   if (eps->ispositive && eps->purify) {
    175:     BVCreateVec(eps->V,&w);
    176:     for (i=0;i<n;i++) {
    177:       BVCopyVec(eps->V,i,w);
    178:       BVGetColumn(eps->V,i,&z);
    179:       STApply(eps->st,w,z);
    180:       BVRestoreColumn(eps->V,i,&z);
    181:     }
    182:     VecDestroy(&w);
    183:   }

    185:   /* Fix eigenvectors if balancing was used */
    186:   if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
    187:     for (i=0;i<n;i++) {
    188:       BVGetColumn(eps->V,i,&z);
    189:       VecPointwiseDivide(z,z,eps->D);
    190:       BVRestoreColumn(eps->V,i,&z);
    191:     }
    192:   }

    194:   /* normalize eigenvectors (when using purification or balancing) */
    195:   if ((eps->ispositive && eps->purify) || (eps->balance!=EPS_BALANCE_NONE && eps->D)) {
    196:     for (i=0;i<n;i++) {
    197: #if !defined(PETSC_USE_COMPLEX)
    198:       if (eps->eigi[i] != 0.0) {
    199:         BVGetColumn(eps->V,i,&v);
    200:         BVGetColumn(eps->V,i+1,&v1);
    201:         VecNorm(v,NORM_2,&norm);
    202:         VecNorm(v1,NORM_2,&normi);
    203:         tmp = 1.0 / SlepcAbsEigenvalue(norm,normi);
    204:         VecScale(v,tmp);
    205:         VecScale(v1,tmp);
    206:         BVRestoreColumn(eps->V,i,&v);
    207:         BVRestoreColumn(eps->V,i+1,&v1);
    208:         i++;
    209:       } else
    210: #endif
    211:       {
    212:         BVGetColumn(eps->V,i,&v);
    213:         VecNormalize(v,NULL);
    214:         BVRestoreColumn(eps->V,i,&v);
    215:       }
    216:     }
    217:   }
    218:   return(0);
    219: }

    223: /*@
    224:    EPSSetWorkVecs - Sets a number of work vectors into an EPS object.

    226:    Collective on EPS

    228:    Input Parameters:
    229: +  eps - eigensolver context
    230: -  nw  - number of work vectors to allocate

    232:    Developers Note:
    233:    This is PETSC_EXTERN because it may be required by user plugin EPS
    234:    implementations.

    236:    Level: developer
    237: @*/
    238: PetscErrorCode EPSSetWorkVecs(EPS eps,PetscInt nw)
    239: {
    241:   Vec            t;

    244:   if (eps->nwork < nw) {
    245:     VecDestroyVecs(eps->nwork,&eps->work);
    246:     eps->nwork = nw;
    247:     BVGetColumn(eps->V,0,&t);
    248:     VecDuplicateVecs(t,nw,&eps->work);
    249:     BVRestoreColumn(eps->V,0,&t);
    250:     PetscLogObjectParents(eps,nw,eps->work);
    251:   }
    252:   return(0);
    253: }

    257: /*
    258:   EPSSetWhichEigenpairs_Default - Sets the default value for which,
    259:   depending on the ST.
    260:  */
    261: PetscErrorCode EPSSetWhichEigenpairs_Default(EPS eps)
    262: {
    263:   PetscBool      target;

    267:   PetscObjectTypeCompareAny((PetscObject)eps->st,&target,STSINVERT,STCAYLEY,"");
    268:   if (target) eps->which = EPS_TARGET_MAGNITUDE;
    269:   else eps->which = EPS_LARGEST_MAGNITUDE;
    270:   return(0);
    271: }

    275: /*
    276:   EPSConvergedRelative - Checks convergence relative to the eigenvalue.
    277: */
    278: PetscErrorCode EPSConvergedRelative(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
    279: {
    280:   PetscReal w;

    283:   w = SlepcAbsEigenvalue(eigr,eigi);
    284:   *errest = res/w;
    285:   return(0);
    286: }

    290: /*
    291:   EPSConvergedAbsolute - Checks convergence absolutely.
    292: */
    293: PetscErrorCode EPSConvergedAbsolute(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
    294: {
    296:   *errest = res;
    297:   return(0);
    298: }

    302: /*
    303:   EPSConvergedNorm - Checks convergence relative to the eigenvalue and
    304:   the matrix norms.
    305: */
    306: PetscErrorCode EPSConvergedNorm(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
    307: {
    308:   PetscReal w;

    311:   w = SlepcAbsEigenvalue(eigr,eigi);
    312:   *errest = res / (eps->nrma + w*eps->nrmb);
    313:   return(0);
    314: }

    318: /*@C
    319:    EPSStoppingBasic - Default routine to determine whether the outer eigensolver
    320:    iteration must be stopped.

    322:    Collective on EPS

    324:    Input Parameters:
    325: +  eps    - eigensolver context obtained from EPSCreate()
    326: .  its    - current number of iterations
    327: .  max_it - maximum number of iterations
    328: .  nconv  - number of currently converged eigenpairs
    329: .  nev    - number of requested eigenpairs
    330: -  ctx    - context (not used here)

    332:    Output Parameter:
    333: .  reason - result of the stopping test

    335:    Notes:
    336:    A positive value of reason indicates that the iteration has finished successfully
    337:    (converged), and a negative value indicates an error condition (diverged). If
    338:    the iteration needs to be continued, reason must be set to EPS_CONVERGED_ITERATING
    339:    (zero).

    341:    EPSStoppingBasic() will stop if all requested eigenvalues are converged, or if
    342:    the maximum number of iterations has been reached.

    344:    Use EPSSetStoppingTest() to provide your own test instead of using this one.

    346:    Level: advanced

    348: .seealso: EPSSetStoppingTest(), EPSConvergedReason, EPSGetConvergedReason()
    349: @*/
    350: PetscErrorCode EPSStoppingBasic(EPS eps,PetscInt its,PetscInt max_it,PetscInt nconv,PetscInt nev,EPSConvergedReason *reason,void *ctx)
    351: {

    355:   *reason = EPS_CONVERGED_ITERATING;
    356:   if (nconv >= nev) {
    357:     PetscInfo2(eps,"Linear eigensolver finished successfully: %D eigenpairs converged at iteration %D\n",nconv,its);
    358:     *reason = EPS_CONVERGED_TOL;
    359:   } else if (its >= max_it) {
    360:     *reason = EPS_DIVERGED_ITS;
    361:     PetscInfo1(eps,"Linear eigensolver iteration reached maximum number of iterations (%D)\n",its);
    362:   }
    363:   return(0);
    364: }

    368: /*
    369:   EPSComputeRitzVector - Computes the current Ritz vector.

    371:   Simple case (complex scalars or real scalars with Zi=NULL):
    372:     x = V*Zr  (V is a basis of nv vectors, Zr has length nv)

    374:   Split case:
    375:     x = V*Zr  y = V*Zi  (Zr and Zi have length nv)
    376: */
    377: PetscErrorCode EPSComputeRitzVector(EPS eps,PetscScalar *Zr,PetscScalar *Zi,BV V,Vec x,Vec y)
    378: {
    380:   PetscReal      norm;
    381: #if !defined(PETSC_USE_COMPLEX)
    382:   Vec            z;
    383: #endif

    386:   /* compute eigenvector */
    387:   BVMultVec(V,1.0,0.0,x,Zr);

    389:   /* purify eigenvector in positive generalized problems */
    390:   if (eps->ispositive && eps->purify) {
    391:     STApply(eps->st,x,y);
    392:     if (eps->ishermitian) {
    393:       BVNormVec(eps->V,y,NORM_2,&norm);
    394:     } else {
    395:       VecNorm(y,NORM_2,&norm);
    396:     }
    397:     VecScale(y,1.0/norm);
    398:     VecCopy(y,x);
    399:   }
    400:   /* fix eigenvector if balancing is used */
    401:   if (!eps->ishermitian && eps->balance!=EPS_BALANCE_NONE && eps->D) {
    402:     VecPointwiseDivide(x,x,eps->D);
    403:     VecNormalize(x,&norm);
    404:   }
    405: #if !defined(PETSC_USE_COMPLEX)
    406:   /* compute imaginary part of eigenvector */
    407:   if (Zi) {
    408:     BVMultVec(V,1.0,0.0,y,Zi);
    409:     if (eps->ispositive) {
    410:       BVCreateVec(V,&z);
    411:       STApply(eps->st,y,z);
    412:       VecNorm(z,NORM_2,&norm);
    413:       VecScale(z,1.0/norm);
    414:       VecCopy(z,y);
    415:       VecDestroy(&z);
    416:     }
    417:     if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
    418:       VecPointwiseDivide(y,y,eps->D);
    419:       VecNormalize(y,&norm);
    420:     }
    421:   } else
    422: #endif
    423:   { VecSet(y,0.0); }
    424:   return(0);
    425: }

    429: /*
    430:   EPSBuildBalance_Krylov - uses a Krylov subspace method to compute the
    431:   diagonal matrix to be applied for balancing in non-Hermitian problems.
    432: */
    433: PetscErrorCode EPSBuildBalance_Krylov(EPS eps)
    434: {
    435:   Vec               z,p,r;
    436:   PetscInt          i,j;
    437:   PetscReal         norma;
    438:   PetscScalar       *pz,*pD;
    439:   const PetscScalar *pr,*pp;
    440:   PetscRandom       rand;
    441:   PetscErrorCode    ierr;

    444:   EPSSetWorkVecs(eps,3);
    445:   BVGetRandomContext(eps->V,&rand);
    446:   r = eps->work[0];
    447:   p = eps->work[1];
    448:   z = eps->work[2];
    449:   VecSet(eps->D,1.0);

    451:   for (j=0;j<eps->balance_its;j++) {

    453:     /* Build a random vector of +-1's */
    454:     VecSetRandom(z,rand);
    455:     VecGetArray(z,&pz);
    456:     for (i=0;i<eps->nloc;i++) {
    457:       if (PetscRealPart(pz[i])<0.5) pz[i]=-1.0;
    458:       else pz[i]=1.0;
    459:     }
    460:     VecRestoreArray(z,&pz);

    462:     /* Compute p=DA(D\z) */
    463:     VecPointwiseDivide(r,z,eps->D);
    464:     STApply(eps->st,r,p);
    465:     VecPointwiseMult(p,p,eps->D);
    466:     if (j==0) {
    467:       /* Estimate the matrix inf-norm */
    468:       VecAbs(p);
    469:       VecMax(p,NULL,&norma);
    470:     }
    471:     if (eps->balance == EPS_BALANCE_TWOSIDE) {
    472:       /* Compute r=D\(A'Dz) */
    473:       VecPointwiseMult(z,z,eps->D);
    474:       STApplyTranspose(eps->st,z,r);
    475:       VecPointwiseDivide(r,r,eps->D);
    476:     }

    478:     /* Adjust values of D */
    479:     VecGetArrayRead(r,&pr);
    480:     VecGetArrayRead(p,&pp);
    481:     VecGetArray(eps->D,&pD);
    482:     for (i=0;i<eps->nloc;i++) {
    483:       if (eps->balance == EPS_BALANCE_TWOSIDE) {
    484:         if (PetscAbsScalar(pp[i])>eps->balance_cutoff*norma && pr[i]!=0.0)
    485:           pD[i] *= PetscSqrtReal(PetscAbsScalar(pr[i]/pp[i]));
    486:       } else {
    487:         if (pp[i]!=0.0) pD[i] *= 1.0/PetscAbsScalar(pp[i]);
    488:       }
    489:     }
    490:     VecRestoreArrayRead(r,&pr);
    491:     VecRestoreArrayRead(p,&pp);
    492:     VecRestoreArray(eps->D,&pD);
    493:   }
    494:   return(0);
    495: }