Date: 2016-03-29T14:59:18+00:00

Actual source code: nepsolve.c
slepc-3.6.3 2016-03-29
Report Typos and Errors

      1: /*
      2:       NEP routines related to the solution process.

      4:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      5:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      6:    Copyright (c) 2002-2015, 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/nepimpl.h>       /*I "slepcnep.h" I*/
     25: #include <petscdraw.h>

     29: PetscErrorCode NEPComputeVectors(NEP nep)
     30: {

     34:   NEPCheckSolved(nep,1);
     35:   switch (nep->state) {
     36:   case NEP_STATE_SOLVED:
     37:     if (nep->ops->computevectors) {
     38:       (*nep->ops->computevectors)(nep);
     39:     }
     40:     break;
     41:   default:
     42:     break;
     43:   }
     44:   nep->state = NEP_STATE_EIGENVECTORS;
     45:   return(0);
     46: }

     50: /*@
     51:    NEPSolve - Solves the nonlinear eigensystem.

     53:    Collective on NEP

     55:    Input Parameter:
     56: .  nep - eigensolver context obtained from NEPCreate()

     58:    Options Database Keys:
     59: +  -nep_view - print information about the solver used
     60: .  -nep_view_vectors binary - save the computed eigenvectors to the default binary viewer
     61: .  -nep_view_values - print computed eigenvalues
     62: .  -nep_converged_reason - print reason for convergence, and number of iterations
     63: .  -nep_error_absolute - print absolute errors of each eigenpair
     64: -  -nep_error_relative - print relative errors of each eigenpair

     66:    Level: beginner

     68: .seealso: NEPCreate(), NEPSetUp(), NEPDestroy(), NEPSetTolerances()
     69: @*/
     70: PetscErrorCode NEPSolve(NEP nep)
     71: {
     73:   PetscInt       i;

     77:   PetscLogEventBegin(NEP_Solve,nep,0,0,0);

     79:   /* call setup */
     80:   NEPSetUp(nep);
     81:   nep->nconv = 0;
     82:   nep->its = 0;
     83:   for (i=0;i<nep->ncv;i++) {
     84:     nep->eigr[i]   = 0.0;
     85:     nep->eigi[i]   = 0.0;
     86:     nep->errest[i] = 0.0;
     87:     nep->perm[i]   = i;
     88:   }
     89:   nep->ktol = 0.1;
     90:   NEPMonitor(nep,nep->its,nep->nconv,nep->eigr,nep->errest,nep->ncv);
     91:   NEPViewFromOptions(nep,NULL,"-nep_view_pre");

     93:   (*nep->ops->solve)(nep);
     94:   nep->state = NEP_STATE_SOLVED;

     96:   if (!nep->reason) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_PLIB,"Internal error, solver returned without setting converged reason");

     98:   if (nep->refine==NEP_REFINE_SIMPLE && nep->rits>0) {
     99:     NEPComputeVectors(nep);
    100:     NEPNewtonRefinementSimple(nep,&nep->rits,&nep->reftol,nep->nconv);
    101:     nep->state = NEP_STATE_EIGENVECTORS;
    102:   }

    104:   /* sort eigenvalues according to nep->which parameter */
    105:   SlepcSortEigenvalues(nep->sc,nep->nconv,nep->eigr,nep->eigi,nep->perm);
    106:   PetscLogEventEnd(NEP_Solve,nep,0,0,0);

    108:   /* various viewers */
    109:   NEPViewFromOptions(nep,NULL,"-nep_view");
    110:   NEPReasonViewFromOptions(nep);
    111:   NEPErrorViewFromOptions(nep);
    112:   NEPValuesViewFromOptions(nep);
    113:   NEPVectorsViewFromOptions(nep);

    115:   /* Remove the initial subspace */
    116:   nep->nini = 0;
    117:   return(0);
    118: }

    122: /*@
    123:    NEPProjectOperator - Computes the projection of the nonlinear operator.

    125:    Collective on NEP

    127:    Input Parameters:
    128: +  nep - the nonlinear eigensolver context
    129: .  j0  - initial index
    130: -  j1  - final index

    132:    Notes:
    133:    This is available for split operator only.

    135:    The nonlinear operator T(lambda) is projected onto span(V), where V is
    136:    an orthonormal basis built internally by the solver. The projected
    137:    operator is equal to sum_i V'*A_i*V*f_i(lambda), so this function
    138:    computes all matrices Ei = V'*A_i*V, and stores them in the extra
    139:    matrices inside DS. Only rows/columns in the range [j0,j1-1] are computed,
    140:    the previous ones are assumed to be available already.

    142:    Level: developer

    144: .seealso: NEPSetSplitOperator()
    145: @*/
    146: PetscErrorCode NEPProjectOperator(NEP nep,PetscInt j0,PetscInt j1)
    147: {
    149:   PetscInt       k;
    150:   Mat            G;

    156:   if (!nep->split) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_WRONGSTATE,"This solver requires a split operator");
    157:   BVSetActiveColumns(nep->V,j0,j1);
    158:   for (k=0;k<nep->nt;k++) {
    159:     DSGetMat(nep->ds,DSMatExtra[k],&G);
    160:     BVMatProject(nep->V,nep->A[k],nep->V,G);
    161:     DSRestoreMat(nep->ds,DSMatExtra[k],&G);
    162:   }
    163:   return(0);
    164: }

    168: /*@
    169:    NEPApplyFunction - Applies the nonlinear function T(lambda) to a given vector.

    171:    Collective on NEP

    173:    Input Parameters:
    174: +  nep    - the nonlinear eigensolver context
    175: .  lambda - scalar argument
    176: .  x      - vector to be multiplied against
    177: -  v      - workspace vector

    179:    Output Parameters:
    180: +  y   - result vector
    181: .  A   - Function matrix
    182: -  B   - optional preconditioning matrix

    184:    Note:
    185:    If the nonlinear operator is represented in split form, the result
    186:    y = T(lambda)*x is computed without building T(lambda) explicitly. In
    187:    that case, parameters A and B are not used. Otherwise, the matrix
    188:    T(lambda) is built and the effect is the same as a call to
    189:    NEPComputeFunction() followed by a MatMult().

    191:    Level: developer

    193: .seealso: NEPSetSplitOperator(), NEPComputeFunction()
    194: @*/
    195: PetscErrorCode NEPApplyFunction(NEP nep,PetscScalar lambda,Vec x,Vec v,Vec y,Mat A,Mat B)
    196: {
    198:   PetscInt       i;
    199:   PetscScalar    alpha;

    207:   if (nep->split) {
    208:     VecSet(y,0.0);
    209:     for (i=0;i<nep->nt;i++) {
    210:       FNEvaluateFunction(nep->f[i],lambda,&alpha);
    211:       MatMult(nep->A[i],x,v);
    212:       VecAXPY(y,alpha,v);
    213:     }
    214:   } else {
    215:     NEPComputeFunction(nep,lambda,A,B);
    216:     MatMult(A,x,y);
    217:   }
    218:   return(0);
    219: }

    223: /*@
    224:    NEPApplyJacobian - Applies the nonlinear Jacobian T'(lambda) to a given vector.

    226:    Collective on NEP

    228:    Input Parameters:
    229: +  nep    - the nonlinear eigensolver context
    230: .  lambda - scalar argument
    231: .  x      - vector to be multiplied against
    232: -  v      - workspace vector

    234:    Output Parameters:
    235: +  y   - result vector
    236: -  A   - Jacobian matrix

    238:    Note:
    239:    If the nonlinear operator is represented in split form, the result
    240:    y = T'(lambda)*x is computed without building T'(lambda) explicitly. In
    241:    that case, parameter A is not used. Otherwise, the matrix
    242:    T'(lambda) is built and the effect is the same as a call to
    243:    NEPComputeJacobian() followed by a MatMult().

    245:    Level: developer

    247: .seealso: NEPSetSplitOperator(), NEPComputeJacobian()
    248: @*/
    249: PetscErrorCode NEPApplyJacobian(NEP nep,PetscScalar lambda,Vec x,Vec v,Vec y,Mat A)
    250: {
    252:   PetscInt       i;
    253:   PetscScalar    alpha;

    261:   if (nep->split) {
    262:     VecSet(y,0.0);
    263:     for (i=0;i<nep->nt;i++) {
    264:       FNEvaluateDerivative(nep->f[i],lambda,&alpha);
    265:       MatMult(nep->A[i],x,v);
    266:       VecAXPY(y,alpha,v);
    267:     }
    268:   } else {
    269:     NEPComputeJacobian(nep,lambda,A);
    270:     MatMult(A,x,y);
    271:   }
    272:   return(0);
    273: }

    277: /*@
    278:    NEPGetIterationNumber - Gets the current iteration number. If the
    279:    call to NEPSolve() is complete, then it returns the number of iterations
    280:    carried out by the solution method.

    282:    Not Collective

    284:    Input Parameter:
    285: .  nep - the nonlinear eigensolver context

    287:    Output Parameter:
    288: .  its - number of iterations

    290:    Level: intermediate

    292:    Note:
    293:    During the i-th iteration this call returns i-1. If NEPSolve() is
    294:    complete, then parameter "its" contains either the iteration number at
    295:    which convergence was successfully reached, or failure was detected.
    296:    Call NEPGetConvergedReason() to determine if the solver converged or
    297:    failed and why.

    299: .seealso: NEPGetConvergedReason(), NEPSetTolerances()
    300: @*/
    301: PetscErrorCode NEPGetIterationNumber(NEP nep,PetscInt *its)
    302: {
    306:   *its = nep->its;
    307:   return(0);
    308: }

    312: /*@
    313:    NEPGetConverged - Gets the number of converged eigenpairs.

    315:    Not Collective

    317:    Input Parameter:
    318: .  nep - the nonlinear eigensolver context

    320:    Output Parameter:
    321: .  nconv - number of converged eigenpairs

    323:    Note:
    324:    This function should be called after NEPSolve() has finished.

    326:    Level: beginner

    328: .seealso: NEPSetDimensions(), NEPSolve()
    329: @*/
    330: PetscErrorCode NEPGetConverged(NEP nep,PetscInt *nconv)
    331: {
    335:   NEPCheckSolved(nep,1);
    336:   *nconv = nep->nconv;
    337:   return(0);
    338: }

    342: /*@
    343:    NEPGetConvergedReason - Gets the reason why the NEPSolve() iteration was
    344:    stopped.

    346:    Not Collective

    348:    Input Parameter:
    349: .  nep - the nonlinear eigensolver context

    351:    Output Parameter:
    352: .  reason - negative value indicates diverged, positive value converged

    354:    Possible values for reason:
    355: +  NEP_CONVERGED_FNORM_ABS - function norm satisfied absolute tolerance
    356: .  NEP_CONVERGED_FNORM_RELATIVE - function norm satisfied relative tolerance
    357: .  NEP_CONVERGED_SNORM_RELATIVE - step norm satisfied relative tolerance
    358: .  NEP_DIVERGED_LINEAR_SOLVE - inner linear solve failed
    359: .  NEP_DIVERGED_FUNCTION_COUNT - reached maximum allowed function evaluations
    360: .  NEP_DIVERGED_MAX_IT - required more than its to reach convergence
    361: .  NEP_DIVERGED_BREAKDOWN - generic breakdown in method
    362: -  NEP_DIVERGED_FNORM_NAN - Inf or NaN detected in function evaluation

    364:    Note:
    365:    Can only be called after the call to NEPSolve() is complete.

    367:    Level: intermediate

    369: .seealso: NEPSetTolerances(), NEPSolve(), NEPConvergedReason
    370: @*/
    371: PetscErrorCode NEPGetConvergedReason(NEP nep,NEPConvergedReason *reason)
    372: {
    376:   NEPCheckSolved(nep,1);
    377:   *reason = nep->reason;
    378:   return(0);
    379: }

    383: /*@
    384:    NEPGetEigenpair - Gets the i-th solution of the eigenproblem as computed by
    385:    NEPSolve(). The solution consists in both the eigenvalue and the eigenvector.

    387:    Logically Collective on NEP

    389:    Input Parameters:
    390: +  nep - nonlinear eigensolver context
    391: -  i   - index of the solution

    393:    Output Parameters:
    394: +  eigr - real part of eigenvalue
    395: .  eigi - imaginary part of eigenvalue
    396: .  Vr   - real part of eigenvector
    397: -  Vi   - imaginary part of eigenvector

    399:    Notes:
    400:    It is allowed to pass NULL for Vr and Vi, if the eigenvector is not
    401:    required. Otherwise, the caller must provide valid Vec objects, i.e.,
    402:    they must be created by the calling program with e.g. MatCreateVecs().

    404:    If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is
    405:    configured with complex scalars the eigenvalue is stored
    406:    directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is
    407:    set to zero). In both cases, the user can pass NULL in eigi and Vi.

    409:    The index i should be a value between 0 and nconv-1 (see NEPGetConverged()).
    410:    Eigenpairs are indexed according to the ordering criterion established
    411:    with NEPSetWhichEigenpairs().

    413:    Level: beginner

    415: .seealso: NEPSolve(), NEPGetConverged(), NEPSetWhichEigenpairs()
    416: @*/
    417: PetscErrorCode NEPGetEigenpair(NEP nep,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
    418: {
    419:   PetscInt       k;

    427:   NEPCheckSolved(nep,1);
    428:   if (i<0 || i>=nep->nconv) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");

    430:   NEPComputeVectors(nep);
    431:   k = nep->perm[i];

    433:   /* eigenvalue */
    434: #if defined(PETSC_USE_COMPLEX)
    435:   if (eigr) *eigr = nep->eigr[k];
    436:   if (eigi) *eigi = 0;
    437: #else
    438:   if (eigr) *eigr = nep->eigr[k];
    439:   if (eigi) *eigi = nep->eigi[k];
    440: #endif

    442:   /* eigenvector */
    443: #if defined(PETSC_USE_COMPLEX)
    444:   if (Vr) { BVCopyVec(nep->V,k,Vr); }
    445:   if (Vi) { VecSet(Vi,0.0); }
    446: #else
    447:   if (nep->eigi[k]>0) { /* first value of conjugate pair */
    448:     if (Vr) { BVCopyVec(nep->V,k,Vr); }
    449:     if (Vi) { BVCopyVec(nep->V,k+1,Vi); }
    450:   } else if (nep->eigi[k]<0) { /* second value of conjugate pair */
    451:     if (Vr) { BVCopyVec(nep->V,k-1,Vr); }
    452:     if (Vi) {
    453:       BVCopyVec(nep->V,k,Vi);
    454:       VecScale(Vi,-1.0);
    455:     }
    456:   } else { /* real eigenvalue */
    457:     if (Vr) { BVCopyVec(nep->V,k,Vr); }
    458:     if (Vi) { VecSet(Vi,0.0); }
    459:   }
    460: #endif
    461:   return(0);
    462: }

    466: /*@
    467:    NEPGetErrorEstimate - Returns the error estimate associated to the i-th
    468:    computed eigenpair.

    470:    Not Collective

    472:    Input Parameter:
    473: +  nep - nonlinear eigensolver context
    474: -  i   - index of eigenpair

    476:    Output Parameter:
    477: .  errest - the error estimate

    479:    Notes:
    480:    This is the error estimate used internally by the eigensolver. The actual
    481:    error bound can be computed with NEPComputeRelativeError().

    483:    Level: advanced

    485: .seealso: NEPComputeRelativeError()
    486: @*/
    487: PetscErrorCode NEPGetErrorEstimate(NEP nep,PetscInt i,PetscReal *errest)
    488: {
    492:   NEPCheckSolved(nep,1);
    493:   if (i<0 || i>=nep->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    494:   if (errest) *errest = nep->errest[nep->perm[i]];
    495:   return(0);
    496: }

    500: /*
    501:    NEPComputeResidualNorm_Private - Computes the norm of the residual vector
    502:    associated with an eigenpair.

    504:    Input Parameters:
    505:      lambda - eigenvalue
    506:      x      - eigenvector
    507:      w      - array of work vectors (only one vector)
    508: */
    509: PetscErrorCode NEPComputeResidualNorm_Private(NEP nep,PetscScalar lambda,Vec x,Vec *w,PetscReal *norm)
    510: {
    512:   Mat            T=nep->function;

    515:   NEPComputeFunction(nep,lambda,T,T);
    516:   MatMult(T,x,*w);
    517:   VecNorm(*w,NORM_2,norm);
    518:   return(0);
    519: }

    523: /*@
    524:    NEPComputeError - Computes the error (based on the residual norm) associated
    525:    with the i-th computed eigenpair.

    527:    Collective on NEP

    529:    Input Parameter:
    530: +  nep  - the nonlinear eigensolver context
    531: .  i    - the solution index
    532: -  type - the type of error to compute

    534:    Output Parameter:
    535: .  error - the error

    537:    Notes:
    538:    The error can be computed in various ways, all of them based on the residual
    539:    norm computed as ||T(lambda)x||_2 where lambda is the eigenvalue and x is the
    540:    eigenvector.

    542:    Level: beginner

    544: .seealso: NEPErrorType, NEPSolve(), NEPGetErrorEstimate()
    545: @*/
    546: PetscErrorCode NEPComputeError(NEP nep,PetscInt i,NEPErrorType type,PetscReal *error)
    547: {
    549:   Vec            xr,xi=NULL,w;
    550:   PetscScalar    kr,ki;
    551:   PetscReal      er;

    558:   NEPCheckSolved(nep,1);

    560:   /* allocate work vectors */
    561: #if defined(PETSC_USE_COMPLEX)
    562:   NEPSetWorkVecs(nep,2);
    563: #else
    564:   NEPSetWorkVecs(nep,3);
    565:   xi = nep->work[2];
    566: #endif
    567:   xr = nep->work[0];
    568:   w  = nep->work[1];

    570:   /* compute residual norms */
    571:   NEPGetEigenpair(nep,i,&kr,&ki,xr,xi);
    572: #if !defined(PETSC_USE_COMPLEX)
    573:   if (ki) SETERRQ(PETSC_COMM_SELF,1,"Not implemented for complex eigenvalues with real scalars");
    574: #endif
    575:   NEPComputeResidualNorm_Private(nep,kr,xr,&w,error);
    576:   VecNorm(xr,NORM_2,&er);

    578:   /* compute error */
    579:   switch (type) {
    580:     case NEP_ERROR_ABSOLUTE:
    581:       break;
    582:     case NEP_ERROR_RELATIVE:
    583:       *error /= PetscAbsScalar(kr)*er;
    584:       break;
    585:     default:
    586:       SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"Invalid error type");
    587:   }
    588:   return(0);
    589: }

    593: /*@
    594:    NEPComputeFunction - Computes the function matrix T(lambda) that has been
    595:    set with NEPSetFunction().

    597:    Collective on NEP and Mat

    599:    Input Parameters:
    600: +  nep    - the NEP context
    601: -  lambda - the scalar argument

    603:    Output Parameters:
    604: +  A   - Function matrix
    605: -  B   - optional preconditioning matrix

    607:    Notes:
    608:    NEPComputeFunction() is typically used within nonlinear eigensolvers
    609:    implementations, so most users would not generally call this routine
    610:    themselves.

    612:    Level: developer

    614: .seealso: NEPSetFunction(), NEPGetFunction()
    615: @*/
    616: PetscErrorCode NEPComputeFunction(NEP nep,PetscScalar lambda,Mat A,Mat B)
    617: {
    619:   PetscInt       i;
    620:   PetscScalar    alpha;

    625:   if (nep->split) {

    627:     MatZeroEntries(A);
    628:     for (i=0;i<nep->nt;i++) {
    629:       FNEvaluateFunction(nep->f[i],lambda,&alpha);
    630:       MatAXPY(A,alpha,nep->A[i],nep->mstr);
    631:     }
    632:     if (A != B) SETERRQ(PetscObjectComm((PetscObject)nep),1,"Not implemented");

    634:   } else {

    636:     if (!nep->computefunction) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_USER,"Must call NEPSetFunction() first");

    638:     PetscLogEventBegin(NEP_FunctionEval,nep,A,B,0);

    640:     PetscStackPush("NEP user Function function");
    641:     (*nep->computefunction)(nep,lambda,A,B,nep->functionctx);
    642:     PetscStackPop;

    644:     PetscLogEventEnd(NEP_FunctionEval,nep,A,B,0);
    645:     nep->nfuncs++;

    647:   }
    648:   return(0);
    649: }

    653: /*@
    654:    NEPComputeJacobian - Computes the Jacobian matrix T'(lambda) that has been
    655:    set with NEPSetJacobian().

    657:    Collective on NEP and Mat

    659:    Input Parameters:
    660: +  nep    - the NEP context
    661: -  lambda - the scalar argument

    663:    Output Parameters:
    664: .  A   - Jacobian matrix

    666:    Notes:
    667:    Most users should not need to explicitly call this routine, as it
    668:    is used internally within the nonlinear eigensolvers.

    670:    Level: developer

    672: .seealso: NEPSetJacobian(), NEPGetJacobian()
    673: @*/
    674: PetscErrorCode NEPComputeJacobian(NEP nep,PetscScalar lambda,Mat A)
    675: {
    677:   PetscInt       i;
    678:   PetscScalar    alpha;

    683:   if (nep->split) {

    685:     MatZeroEntries(A);
    686:     for (i=0;i<nep->nt;i++) {
    687:       FNEvaluateDerivative(nep->f[i],lambda,&alpha);
    688:       MatAXPY(A,alpha,nep->A[i],nep->mstr);
    689:     }

    691:   } else {

    693:     if (!nep->computejacobian) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_USER,"Must call NEPSetJacobian() first");

    695:     PetscLogEventBegin(NEP_JacobianEval,nep,A,0,0);

    697:     PetscStackPush("NEP user Jacobian function");
    698:     (*nep->computejacobian)(nep,lambda,A,nep->jacobianctx);
    699:     PetscStackPop;

    701:     PetscLogEventEnd(NEP_JacobianEval,nep,A,0,0);

    703:   }
    704:   return(0);
    705: }