Date: 2013-09-02T10:07:12+00:00

Actual source code: qepsolve.c

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

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

     27: typedef struct {
     28:   PetscErrorCode (*comparison)(PetscScalar,PetscScalar,PetscScalar,PetscScalar,PetscInt*,void*);
     29:   void *comparisonctx;
     30:   ST st;
     31: } QEPSortForSTData;

     35: static PetscErrorCode QEPSortForSTFunc(PetscScalar ar,PetscScalar ai,
     36:                                 PetscScalar br,PetscScalar bi,PetscInt *r,void *ctx)
     37: {
     38:   QEPSortForSTData *data = (QEPSortForSTData*)ctx;
     39:   PetscErrorCode   ierr;

     42:   STBackTransform(data->st,1,&ar,&ai);
     43:   STBackTransform(data->st,1,&br,&bi);
     44:   (*data->comparison)(ar,ai,br,bi,r,data->comparisonctx);
     45:   return(0);
     46: }

     50: /*@
     51:    QEPSolve - Solves the quadratic eigensystem.

     53:    Collective on QEP

     55:    Input Parameter:
     56: .  qep - eigensolver context obtained from QEPCreate()

     58:    Options Database Keys:
     59: +  -qep_view - print information about the solver used
     60: .  -qep_view_mat0 binary - save the first matrix (M) to the default binary viewer
     61: .  -qep_view_mat1 binary - save the second matrix (C) to the default binary viewer
     62: .  -qep_view_mat2 binary - save the third matrix (K) to the default binary viewer
     63: -  -qep_plot_eigs - plot computed eigenvalues

     65:    Level: beginner

     67: .seealso: QEPCreate(), QEPSetUp(), QEPDestroy(), QEPSetTolerances()
     68: @*/
     69: PetscErrorCode QEPSolve(QEP qep)
     70: {
     71:   PetscErrorCode    ierr;
     72:   PetscInt          i;
     73:   PetscReal         re,im;
     74:   PetscBool         flg,islinear;
     75:   PetscViewer       viewer;
     76:   PetscViewerFormat format;
     77:   PetscDraw         draw;
     78:   PetscDrawSP       drawsp;
     79:   QEPSortForSTData  data;

     83:   PetscLogEventBegin(QEP_Solve,qep,0,0,0);

     85:   /* call setup */
     86:   QEPSetUp(qep);
     87:   qep->nconv = 0;
     88:   qep->its   = 0;
     89:   for (i=0;i<qep->ncv;i++) {
     90:     qep->eigr[i]   = 0.0;
     91:     qep->eigi[i]   = 0.0;
     92:     qep->errest[i] = 0.0;
     93:   }
     94:   QEPMonitor(qep,qep->its,qep->nconv,qep->eigr,qep->eigi,qep->errest,qep->ncv);

     96:   PetscObjectTypeCompare((PetscObject)qep,QEPLINEAR,&islinear);
     97:   if (!islinear) {
     98:     /* temporarily change eigenvalue comparison function */
     99:     data.comparison    = qep->comparison;
    100:     data.comparisonctx = qep->comparisonctx;
    101:     data.st            = qep->st;
    102:     qep->comparison    = QEPSortForSTFunc;
    103:     qep->comparisonctx = &data;
    104:   }
    105:   DSSetEigenvalueComparison(qep->ds,qep->comparison,qep->comparisonctx);

    107:   (*qep->ops->solve)(qep);
    108:   if (!islinear) {
    109:     STPostSolve(qep->st);
    110:   }

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

    114:   if (!islinear) {
    115:     /* restore comparison function */
    116:     qep->comparison    = data.comparison;
    117:     qep->comparisonctx = data.comparisonctx;
    118:     /* Map eigenvalues back to the original problem */
    119:     STBackTransform(qep->st,qep->nconv,qep->eigr,qep->eigi);
    120:   }

    122: #if !defined(PETSC_USE_COMPLEX)
    123:   /* reorder conjugate eigenvalues (positive imaginary first) */
    124:   for (i=0;i<qep->nconv-1;i++) {
    125:     if (qep->eigi[i] != 0) {
    126:       if (qep->eigi[i] < 0) {
    127:         qep->eigi[i] = -qep->eigi[i];
    128:         qep->eigi[i+1] = -qep->eigi[i+1];
    129:         VecScale(qep->V[i+1],-1.0);
    130:       }
    131:       i++;
    132:     }
    133:   }
    134: #endif

    136:   /* sort eigenvalues according to qep->which parameter */
    137:   QEPSortEigenvalues(qep,qep->nconv,qep->eigr,qep->eigi,qep->perm);

    139:   PetscLogEventEnd(QEP_Solve,qep,0,0,0);

    141:   /* various viewers */
    142:   MatViewFromOptions(qep->M,((PetscObject)qep)->prefix,"-qep_view_mat0");
    143:   MatViewFromOptions(qep->C,((PetscObject)qep)->prefix,"-qep_view_mat1");
    144:   MatViewFromOptions(qep->K,((PetscObject)qep)->prefix,"-qep_view_mat2");

    146:   PetscOptionsGetViewer(PetscObjectComm((PetscObject)qep),((PetscObject)qep)->prefix,"-qep_view",&viewer,&format,&flg);
    147:   if (flg && !PetscPreLoadingOn) {
    148:     PetscViewerPushFormat(viewer,format);
    149:     QEPView(qep,viewer);
    150:     PetscViewerPopFormat(viewer);
    151:     PetscViewerDestroy(&viewer);
    152:   }

    154:   flg = PETSC_FALSE;
    155:   PetscOptionsGetBool(((PetscObject)qep)->prefix,"-qep_plot_eigs",&flg,NULL);
    156:   if (flg) {
    157:     PetscViewerDrawOpen(PETSC_COMM_SELF,0,"Computed Eigenvalues",PETSC_DECIDE,PETSC_DECIDE,300,300,&viewer);
    158:     PetscViewerDrawGetDraw(viewer,0,&draw);
    159:     PetscDrawSPCreate(draw,1,&drawsp);
    160:     for (i=0;i<qep->nconv;i++) {
    161: #if defined(PETSC_USE_COMPLEX)
    162:       re = PetscRealPart(qep->eigr[i]);
    163:       im = PetscImaginaryPart(qep->eigi[i]);
    164: #else
    165:       re = qep->eigr[i];
    166:       im = qep->eigi[i];
    167: #endif
    168:       PetscDrawSPAddPoint(drawsp,&re,&im);
    169:     }
    170:     PetscDrawSPDraw(drawsp,PETSC_TRUE);
    171:     PetscDrawSPDestroy(&drawsp);
    172:     PetscViewerDestroy(&viewer);
    173:   }

    175:   /* Remove the initial subspace */
    176:   qep->nini = 0;
    177:   return(0);
    178: }

    182: /*@
    183:    QEPGetIterationNumber - Gets the current iteration number. If the
    184:    call to QEPSolve() is complete, then it returns the number of iterations
    185:    carried out by the solution method.

    187:    Not Collective

    189:    Input Parameter:
    190: .  qep - the quadratic eigensolver context

    192:    Output Parameter:
    193: .  its - number of iterations

    195:    Level: intermediate

    197:    Note:
    198:    During the i-th iteration this call returns i-1. If QEPSolve() is
    199:    complete, then parameter "its" contains either the iteration number at
    200:    which convergence was successfully reached, or failure was detected.
    201:    Call QEPGetConvergedReason() to determine if the solver converged or
    202:    failed and why.

    204: .seealso: QEPGetConvergedReason(), QEPSetTolerances()
    205: @*/
    206: PetscErrorCode QEPGetIterationNumber(QEP qep,PetscInt *its)
    207: {
    211:   *its = qep->its;
    212:   return(0);
    213: }

    217: /*@
    218:    QEPGetConverged - Gets the number of converged eigenpairs.

    220:    Not Collective

    222:    Input Parameter:
    223: .  qep - the quadratic eigensolver context

    225:    Output Parameter:
    226: .  nconv - number of converged eigenpairs

    228:    Note:
    229:    This function should be called after QEPSolve() has finished.

    231:    Level: beginner

    233: .seealso: QEPSetDimensions(), QEPSolve()
    234: @*/
    235: PetscErrorCode QEPGetConverged(QEP qep,PetscInt *nconv)
    236: {
    240:   *nconv = qep->nconv;
    241:   return(0);
    242: }

    246: /*@C
    247:    QEPGetConvergedReason - Gets the reason why the QEPSolve() iteration was
    248:    stopped.

    250:    Not Collective

    252:    Input Parameter:
    253: .  qep - the quadratic eigensolver context

    255:    Output Parameter:
    256: .  reason - negative value indicates diverged, positive value converged

    258:    Possible values for reason:
    259: +  QEP_CONVERGED_TOL - converged up to tolerance
    260: .  QEP_DIVERGED_ITS - required more than its to reach convergence
    261: -  QEP_DIVERGED_BREAKDOWN - generic breakdown in method

    263:    Note:
    264:    Can only be called after the call to QEPSolve() is complete.

    266:    Level: intermediate

    268: .seealso: QEPSetTolerances(), QEPSolve(), QEPConvergedReason
    269: @*/
    270: PetscErrorCode QEPGetConvergedReason(QEP qep,QEPConvergedReason *reason)
    271: {
    275:   *reason = qep->reason;
    276:   return(0);
    277: }

    281: /*@
    282:    QEPGetEigenpair - Gets the i-th solution of the eigenproblem as computed by
    283:    QEPSolve(). The solution consists in both the eigenvalue and the eigenvector.

    285:    Logically Collective on EPS

    287:    Input Parameters:
    288: +  qep - quadratic eigensolver context
    289: -  i   - index of the solution

    291:    Output Parameters:
    292: +  eigr - real part of eigenvalue
    293: .  eigi - imaginary part of eigenvalue
    294: .  Vr   - real part of eigenvector
    295: -  Vi   - imaginary part of eigenvector

    297:    Notes:
    298:    If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is
    299:    configured with complex scalars the eigenvalue is stored
    300:    directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is
    301:    set to zero).

    303:    The index i should be a value between 0 and nconv-1 (see QEPGetConverged()).
    304:    Eigenpairs are indexed according to the ordering criterion established
    305:    with QEPSetWhichEigenpairs().

    307:    Level: beginner

    309: .seealso: QEPSolve(), QEPGetConverged(), QEPSetWhichEigenpairs()
    310: @*/
    311: PetscErrorCode QEPGetEigenpair(QEP qep,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
    312: {
    313:   PetscInt       k;

    321:   if (!qep->eigr || !qep->eigi || !qep->V) SETERRQ(PetscObjectComm((PetscObject)qep),PETSC_ERR_ARG_WRONGSTATE,"QEPSolve must be called first");
    322:   if (i<0 || i>=qep->nconv) SETERRQ(PetscObjectComm((PetscObject)qep),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");

    324:   if (!qep->perm) k = i;
    325:   else k = qep->perm[i];

    327:   /* eigenvalue */
    328: #if defined(PETSC_USE_COMPLEX)
    329:   if (eigr) *eigr = qep->eigr[k];
    330:   if (eigi) *eigi = 0;
    331: #else
    332:   if (eigr) *eigr = qep->eigr[k];
    333:   if (eigi) *eigi = qep->eigi[k];
    334: #endif

    336:   /* eigenvector */
    337: #if defined(PETSC_USE_COMPLEX)
    338:   if (Vr) { VecCopy(qep->V[k],Vr); }
    339:   if (Vi) { VecSet(Vi,0.0); }
    340: #else
    341:   if (qep->eigi[k]>0) { /* first value of conjugate pair */
    342:     if (Vr) { VecCopy(qep->V[k],Vr); }
    343:     if (Vi) { VecCopy(qep->V[k+1],Vi); }
    344:   } else if (qep->eigi[k]<0) { /* second value of conjugate pair */
    345:     if (Vr) { VecCopy(qep->V[k-1],Vr); }
    346:     if (Vi) {
    347:       VecCopy(qep->V[k],Vi);
    348:       VecScale(Vi,-1.0);
    349:     }
    350:   } else { /* real eigenvalue */
    351:     if (Vr) { VecCopy(qep->V[k],Vr); }
    352:     if (Vi) { VecSet(Vi,0.0); }
    353:   }
    354: #endif
    355:   return(0);
    356: }

    360: /*@
    361:    QEPGetErrorEstimate - Returns the error estimate associated to the i-th
    362:    computed eigenpair.

    364:    Not Collective

    366:    Input Parameter:
    367: +  qep - quadratic eigensolver context
    368: -  i   - index of eigenpair

    370:    Output Parameter:
    371: .  errest - the error estimate

    373:    Notes:
    374:    This is the error estimate used internally by the eigensolver. The actual
    375:    error bound can be computed with QEPComputeRelativeError(). See also the users
    376:    manual for details.

    378:    Level: advanced

    380: .seealso: QEPComputeRelativeError()
    381: @*/
    382: PetscErrorCode QEPGetErrorEstimate(QEP qep,PetscInt i,PetscReal *errest)
    383: {
    387:   if (!qep->eigr || !qep->eigi) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"QEPSolve must be called first");
    388:   if (i<0 || i>=qep->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    389:   if (qep->perm) i = qep->perm[i];
    390:   if (errest) *errest = qep->errest[i];
    391:   return(0);
    392: }

    396: /*
    397:    QEPComputeResidualNorm_Private - Computes the norm of the residual vector
    398:    associated with an eigenpair.
    399: */
    400: PetscErrorCode QEPComputeResidualNorm_Private(QEP qep,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *norm)
    401: {
    403:   Vec            u,w;
    404:   Mat            M=qep->M,C=qep->C,K=qep->K;
    405: #if !defined(PETSC_USE_COMPLEX)
    406:   Vec            v,y,z;
    407:   PetscReal      ni,nr;
    408:   PetscScalar    a1,a2;
    409: #endif

    412:   VecDuplicate(qep->V[0],&u);
    413:   VecDuplicate(u,&w);

    415: #if !defined(PETSC_USE_COMPLEX)
    416:   if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
    417: #endif
    418:     MatMult(K,xr,u);                 /* u=K*x */
    419:     if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
    420:       MatMult(C,xr,w);               /* w=C*x */
    421:       VecAXPY(u,kr,w);               /* u=l*C*x+K*x */
    422:       MatMult(M,xr,w);               /* w=M*x */
    423:       VecAXPY(u,kr*kr,w);            /* u=l^2*M*x+l*C*x+K*x */
    424:     }
    425:     VecNorm(u,NORM_2,norm);
    426: #if !defined(PETSC_USE_COMPLEX)
    427:   } else {
    428:     VecDuplicate(u,&v);
    429:     VecDuplicate(u,&y);
    430:     VecDuplicate(u,&z);
    431:     a1 = kr*kr-ki*ki;
    432:     a2 = 2.0*kr*ki;
    433:     MatMult(K,xr,u);           /* u=K*xr */
    434:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
    435:       MatMult(C,xr,v);         /* v=C*xr */
    436:       MatMult(C,xi,w);         /* w=C*xi */
    437:       MatMult(M,xr,y);         /* y=M*xr */
    438:       MatMult(M,xi,z);         /* z=M*xi */
    439:       VecAXPY(u,kr,v);         /* u=kr*C*xr+K*xr */
    440:       VecAXPY(u,-ki,w);        /* u=kr*C*xr-ki*C*xi+K*xr */
    441:       VecAXPY(u,a1,y);         /* u=a1*M*xr+kr*C*xr-ki*C*xi+K*xr */
    442:       VecAXPY(u,-a2,z);        /* u=a1*M*xr-a2*M*xi+kr*C*xr-ki*C*xi+K*xr */
    443:     }
    444:     VecNorm(u,NORM_2,&nr);
    445:     MatMult(K,xi,u);         /* u=K*xi */
    446:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
    447:       VecAXPY(u,kr,w);         /* u=kr*C*xi+K*xi */
    448:       VecAXPY(u,ki,v);         /* u=kr*C*xi+ki*C*xi+K*xi */
    449:       VecAXPY(u,a1,z);         /* u=a1*M*xi+kr*C*xi+ki*C*xi+K*xi */
    450:       VecAXPY(u,a2,y);         /* u=a1*M*xi+a2*M*ki+kr*C*xi+ki*C*xi+K*xi */
    451:     }
    452:     VecNorm(u,NORM_2,&ni);
    453:     *norm = SlepcAbsEigenvalue(nr,ni);
    454:     VecDestroy(&v);
    455:     VecDestroy(&y);
    456:     VecDestroy(&z);
    457:   }
    458: #endif

    460:   VecDestroy(&w);
    461:   VecDestroy(&u);
    462:   return(0);
    463: }

    467: /*@
    468:    QEPComputeResidualNorm - Computes the norm of the residual vector associated with
    469:    the i-th computed eigenpair.

    471:    Collective on QEP

    473:    Input Parameter:
    474: +  qep - the quadratic eigensolver context
    475: -  i   - the solution index

    477:    Output Parameter:
    478: .  norm - the residual norm, computed as ||(l^2*M+l*C+K)x||_2 where l is the
    479:    eigenvalue and x is the eigenvector.
    480:    If l=0 then the residual norm is computed as ||Kx||_2.

    482:    Notes:
    483:    The index i should be a value between 0 and nconv-1 (see QEPGetConverged()).
    484:    Eigenpairs are indexed according to the ordering criterion established
    485:    with QEPSetWhichEigenpairs().

    487:    Level: beginner

    489: .seealso: QEPSolve(), QEPGetConverged(), QEPSetWhichEigenpairs()
    490: @*/
    491: PetscErrorCode QEPComputeResidualNorm(QEP qep,PetscInt i,PetscReal *norm)
    492: {
    494:   Vec            xr,xi;
    495:   PetscScalar    kr,ki;

    501:   VecDuplicate(qep->V[0],&xr);
    502:   VecDuplicate(qep->V[0],&xi);
    503:   QEPGetEigenpair(qep,i,&kr,&ki,xr,xi);
    504:   QEPComputeResidualNorm_Private(qep,kr,ki,xr,xi,norm);
    505:   VecDestroy(&xr);
    506:   VecDestroy(&xi);
    507:   return(0);
    508: }

    512: /*
    513:    QEPComputeRelativeError_Private - Computes the relative error bound
    514:    associated with an eigenpair.
    515: */
    516: PetscErrorCode QEPComputeRelativeError_Private(QEP qep,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *error)
    517: {
    519:   PetscReal      norm,er;
    520: #if !defined(PETSC_USE_COMPLEX)
    521:   PetscReal      ei;
    522: #endif

    525:   QEPComputeResidualNorm_Private(qep,kr,ki,xr,xi,&norm);
    526: #if !defined(PETSC_USE_COMPLEX)
    527:   if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
    528: #endif
    529:     VecNorm(xr,NORM_2,&er);
    530:     if (PetscAbsScalar(kr) > norm) {
    531:       *error = norm/(PetscAbsScalar(kr)*er);
    532:     } else {
    533:       *error = norm/er;
    534:     }
    535: #if !defined(PETSC_USE_COMPLEX)
    536:   } else {
    537:     VecNorm(xr,NORM_2,&er);
    538:     VecNorm(xi,NORM_2,&ei);
    539:     if (SlepcAbsEigenvalue(kr,ki) > norm) {
    540:       *error = norm/(SlepcAbsEigenvalue(kr,ki)*SlepcAbsEigenvalue(er,ei));
    541:     } else {
    542:       *error = norm/SlepcAbsEigenvalue(er,ei);
    543:     }
    544:   }
    545: #endif
    546:   return(0);
    547: }

    551: /*@
    552:    QEPComputeRelativeError - Computes the relative error bound associated
    553:    with the i-th computed eigenpair.

    555:    Collective on QEP

    557:    Input Parameter:
    558: +  qep - the quadratic eigensolver context
    559: -  i   - the solution index

    561:    Output Parameter:
    562: .  error - the relative error bound, computed as ||(l^2*M+l*C+K)x||_2/||lx||_2 where
    563:    l is the eigenvalue and x is the eigenvector.
    564:    If l=0 the relative error is computed as ||Kx||_2/||x||_2.

    566:    Level: beginner

    568: .seealso: QEPSolve(), QEPComputeResidualNorm(), QEPGetErrorEstimate()
    569: @*/
    570: PetscErrorCode QEPComputeRelativeError(QEP qep,PetscInt i,PetscReal *error)
    571: {
    573:   Vec            xr,xi;
    574:   PetscScalar    kr,ki;

    580:   VecDuplicate(qep->V[0],&xr);
    581:   VecDuplicate(qep->V[0],&xi);
    582:   QEPGetEigenpair(qep,i,&kr,&ki,xr,xi);
    583:   QEPComputeRelativeError_Private(qep,kr,ki,xr,xi,error);
    584:   VecDestroy(&xr);
    585:   VecDestroy(&xi);
    586:   return(0);
    587: }

    591: /*@
    592:    QEPSortEigenvalues - Sorts a list of eigenvalues according to the criterion
    593:    specified via QEPSetWhichEigenpairs().

    595:    Not Collective

    597:    Input Parameters:
    598: +  qep   - the quadratic eigensolver context
    599: .  n     - number of eigenvalues in the list
    600: .  eigr  - pointer to the array containing the eigenvalues
    601: -  eigi  - imaginary part of the eigenvalues (only when using real numbers)

    603:    Output Parameter:
    604: .  perm  - resulting permutation

    606:    Note:
    607:    The result is a list of indices in the original eigenvalue array
    608:    corresponding to the first nev eigenvalues sorted in the specified
    609:    criterion.

    611:    Level: developer

    613: .seealso: QEPSetWhichEigenpairs()
    614: @*/
    615: PetscErrorCode QEPSortEigenvalues(QEP qep,PetscInt n,PetscScalar *eigr,PetscScalar *eigi,PetscInt *perm)
    616: {
    618:   PetscScalar    re,im;
    619:   PetscInt       i,j,result,tmp;

    626:   for (i=0;i<n;i++) perm[i] = i;
    627:   /* insertion sort */
    628:   for (i=n-1; i>=0; i--) {
    629:     re = eigr[perm[i]];
    630:     im = eigi[perm[i]];
    631:     j = i + 1;
    632: #if !defined(PETSC_USE_COMPLEX)
    633:     if (im != 0) {
    634:       /* complex eigenvalue */
    635:       i--;
    636:       im = eigi[perm[i]];
    637:     }
    638: #endif
    639:     while (j<n) {
    640:       QEPCompareEigenvalues(qep,re,im,eigr[perm[j]],eigi[perm[j]],&result);
    641:       if (result < 0) break;
    642: #if !defined(PETSC_USE_COMPLEX)
    643:       /* keep together every complex conjugated eigenpair */
    644:       if (im == 0) {
    645:         if (eigi[perm[j]] == 0) {
    646: #endif
    647:           tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = tmp;
    648:           j++;
    649: #if !defined(PETSC_USE_COMPLEX)
    650:         } else {
    651:           tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = perm[j+1]; perm[j+1] = tmp;
    652:           j+=2;
    653:         }
    654:       } else {
    655:         if (eigi[perm[j]] == 0) {
    656:           tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = perm[j-1]; perm[j-1] = tmp;
    657:           j++;
    658:         } else {
    659:           tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = tmp;
    660:           tmp = perm[j-1]; perm[j-1] = perm[j+1]; perm[j+1] = tmp;
    661:           j+=2;
    662:         }
    663:       }
    664: #endif
    665:     }
    666:   }
    667:   return(0);
    668: }

    672: /*@
    673:    QEPCompareEigenvalues - Compares two (possibly complex) eigenvalues according
    674:    to a certain criterion.

    676:    Not Collective

    678:    Input Parameters:
    679: +  qep    - the quadratic eigensolver context
    680: .  ar     - real part of the 1st eigenvalue
    681: .  ai     - imaginary part of the 1st eigenvalue
    682: .  br     - real part of the 2nd eigenvalue
    683: -  bi     - imaginary part of the 2nd eigenvalue

    685:    Output Parameter:
    686: .  res    - result of comparison

    688:    Notes:
    689:    Returns an integer less than, equal to, or greater than zero if the first
    690:    eigenvalue is considered to be respectively less than, equal to, or greater
    691:    than the second one.

    693:    The criterion of comparison is related to the 'which' parameter set with
    694:    QEPSetWhichEigenpairs().

    696:    Level: developer

    698: .seealso: QEPSortEigenvalues(), QEPSetWhichEigenpairs()
    699: @*/
    700: PetscErrorCode QEPCompareEigenvalues(QEP qep,PetscScalar ar,PetscScalar ai,PetscScalar br,PetscScalar bi,PetscInt *result)
    701: {

    707:   if (!qep->comparison) SETERRQ(PETSC_COMM_SELF,1,"Undefined eigenvalue comparison function");
    708:   (*qep->comparison)(ar,ai,br,bi,result,qep->comparisonctx);
    709:   return(0);
    710: }

    714: /*@
    715:    QEPGetOperationCounters - Gets the total number of matrix-vector products, dot
    716:    products, and linear solve iterations used by the QEP object during the last
    717:    QEPSolve() call.

    719:    Not Collective

    721:    Input Parameter:
    722: .  qep - quadratic eigensolver context

    724:    Output Parameter:
    725: +  matvecs - number of matrix-vector product operations
    726: .  dots    - number of dot product operations
    727: -  lits    - number of linear iterations

    729:    Notes:
    730:    These counters are reset to zero at each successive call to QEPSolve().

    732:    Level: intermediate

    734: @*/
    735: PetscErrorCode QEPGetOperationCounters(QEP qep,PetscInt* matvecs,PetscInt* dots,PetscInt* lits)
    736: {

    741:   if (matvecs) *matvecs = qep->matvecs;
    742:   if (dots) {
    743:     if (!qep->ip) { QEPGetIP(qep,&qep->ip); }
    744:     IPGetOperationCounters(qep->ip,dots);
    745:   }
    746:   if (lits) *lits = qep->linits;
    747:   return(0);
    748: }