Date: 2017-05-17T08:26:48+00:00

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

      1: /*
      2:       PEP routines related to problem setup.

      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/pepimpl.h>       /*I "slepcpep.h" I*/

     28: /*@
     29:    PEPSetUp - Sets up all the internal data structures necessary for the
     30:    execution of the PEP solver.

     32:    Collective on PEP

     34:    Input Parameter:
     35: .  pep   - solver context

     37:    Notes:
     38:    This function need not be called explicitly in most cases, since PEPSolve()
     39:    calls it. It can be useful when one wants to measure the set-up time
     40:    separately from the solve time.

     42:    Level: developer

     44: .seealso: PEPCreate(), PEPSolve(), PEPDestroy()
     45: @*/
     46: PetscErrorCode PEPSetUp(PEP pep)
     47: {
     49:   SlepcSC        sc;
     50:   PetscBool      istrivial,flg;
     51:   PetscInt       k;
     52:   KSP            ksp;
     53:   PC             pc;
     54:   PetscMPIInt    size;
     55:   const MatSolverPackage stype;

     59:   if (pep->state) return(0);
     60:   PetscLogEventBegin(PEP_SetUp,pep,0,0,0);

     62:   /* reset the convergence flag from the previous solves */
     63:   pep->reason = PEP_CONVERGED_ITERATING;

     65:   /* set default solver type (PEPSetFromOptions was not called) */
     66:   if (!((PetscObject)pep)->type_name) {
     67:     PEPSetType(pep,PEPTOAR);
     68:   }
     69:   if (!pep->st) { PEPGetST(pep,&pep->st); }
     70:   if (!pep->ds) { PEPGetDS(pep,&pep->ds); }
     71:   DSReset(pep->ds);
     72:   if (!pep->rg) { PEPGetRG(pep,&pep->rg); }
     73:   if (!((PetscObject)pep->rg)->type_name) {
     74:     RGSetType(pep->rg,RGINTERVAL);
     75:   }

     77:   /* check matrices, transfer them to ST */
     78:   if (!pep->A) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_WRONGSTATE,"PEPSetOperators must be called first");
     79:   STSetOperators(pep->st,pep->nmat,pep->A);

     81:   /* set problem dimensions */
     82:   MatGetSize(pep->A[0],&pep->n,NULL);
     83:   MatGetLocalSize(pep->A[0],&pep->nloc,NULL);

     85:   /* set default problem type */
     86:   if (!pep->problem_type) {
     87:     PEPSetProblemType(pep,PEP_GENERAL);
     88:   }

     90:   /* check consistency of refinement options */
     91:   if (pep->refine) {
     92:     if (!pep->scheme) {  /* set default scheme */
     93:       PEPRefineGetKSP(pep,&ksp);
     94:       KSPGetPC(ksp,&pc);
     95:       PetscObjectTypeCompare((PetscObject)ksp,KSPPREONLY,&flg);
     96:       if (flg) {
     97:         PetscObjectTypeCompareAny((PetscObject)pc,&flg,PCLU,PCCHOLESKY,"");
     98:       }
     99:       pep->scheme = flg? PEP_REFINE_SCHEME_MBE: PEP_REFINE_SCHEME_SCHUR;
    100:     }
    101:     if (pep->scheme==PEP_REFINE_SCHEME_MBE) {
    102:       PEPRefineGetKSP(pep,&ksp);
    103:       KSPGetPC(ksp,&pc);
    104:       PetscObjectTypeCompare((PetscObject)ksp,KSPPREONLY,&flg);
    105:       if (flg) {
    106:         PetscObjectTypeCompareAny((PetscObject)pc,&flg,PCLU,PCCHOLESKY,"");
    107:       }
    108:       if (!flg) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"The MBE scheme for refinement requires a direct solver in KSP");
    109:       MPI_Comm_size(PetscObjectComm((PetscObject)pc),&size);
    110:       if (size>1) {   /* currently selected PC is a factorization */
    111:         PCFactorGetMatSolverPackage(pc,&stype);
    112:         PetscStrcmp(stype,MATSOLVERPETSC,&flg);
    113:         if (flg) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"For Newton refinement, you chose to solve linear systems with a factorization, but in parallel runs you need to select an external package");
    114:       }
    115:     }
    116:     if (pep->scheme==PEP_REFINE_SCHEME_SCHUR) {
    117:       if (pep->npart>1) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"The Schur scheme for refinement does not support subcommunicators");
    118:     }
    119:   }
    120:   /* call specific solver setup */
    121:   (*pep->ops->setup)(pep);

    123:   /* set tolerance if not yet set */
    124:   if (pep->tol==PETSC_DEFAULT) pep->tol = SLEPC_DEFAULT_TOL;
    125:   if (pep->refine) {
    126:     if (pep->rtol==PETSC_DEFAULT) pep->rtol = PetscMax(pep->tol/1000,PETSC_MACHINE_EPSILON);
    127:     if (pep->rits==PETSC_DEFAULT) pep->rits = (pep->refine==PEP_REFINE_SIMPLE)? 10: 1;
    128:   }

    130:   /* set default extraction */
    131:   if (!pep->extract) {
    132:     pep->extract = (pep->basis==PEP_BASIS_MONOMIAL)? PEP_EXTRACT_NORM: PEP_EXTRACT_NONE;
    133:   }

    135:   /* fill sorting criterion context */
    136:   switch (pep->which) {
    137:     case PEP_LARGEST_MAGNITUDE:
    138:       pep->sc->comparison    = SlepcCompareLargestMagnitude;
    139:       pep->sc->comparisonctx = NULL;
    140:       break;
    141:     case PEP_SMALLEST_MAGNITUDE:
    142:       pep->sc->comparison    = SlepcCompareSmallestMagnitude;
    143:       pep->sc->comparisonctx = NULL;
    144:       break;
    145:     case PEP_LARGEST_REAL:
    146:       pep->sc->comparison    = SlepcCompareLargestReal;
    147:       pep->sc->comparisonctx = NULL;
    148:       break;
    149:     case PEP_SMALLEST_REAL:
    150:       pep->sc->comparison    = SlepcCompareSmallestReal;
    151:       pep->sc->comparisonctx = NULL;
    152:       break;
    153:     case PEP_LARGEST_IMAGINARY:
    154:       pep->sc->comparison    = SlepcCompareLargestImaginary;
    155:       pep->sc->comparisonctx = NULL;
    156:       break;
    157:     case PEP_SMALLEST_IMAGINARY:
    158:       pep->sc->comparison    = SlepcCompareSmallestImaginary;
    159:       pep->sc->comparisonctx = NULL;
    160:       break;
    161:     case PEP_TARGET_MAGNITUDE:
    162:       pep->sc->comparison    = SlepcCompareTargetMagnitude;
    163:       pep->sc->comparisonctx = &pep->target;
    164:       break;
    165:     case PEP_TARGET_REAL:
    166:       pep->sc->comparison    = SlepcCompareTargetReal;
    167:       pep->sc->comparisonctx = &pep->target;
    168:       break;
    169:     case PEP_TARGET_IMAGINARY:
    170:       pep->sc->comparison    = SlepcCompareTargetImaginary;
    171:       pep->sc->comparisonctx = &pep->target;
    172:       break;
    173:     case PEP_WHICH_USER:
    174:       break;
    175:   }
    176:   pep->sc->map    = NULL;
    177:   pep->sc->mapobj = NULL;

    179:   /* fill sorting criterion for DS */
    180:   DSGetSlepcSC(pep->ds,&sc);
    181:   RGIsTrivial(pep->rg,&istrivial);
    182:   sc->rg            = istrivial? NULL: pep->rg;
    183:   sc->comparison    = pep->sc->comparison;
    184:   sc->comparisonctx = pep->sc->comparisonctx;
    185:   sc->map           = SlepcMap_ST;
    186:   sc->mapobj        = (PetscObject)pep->st;

    188:   /* setup ST */
    189:   STSetUp(pep->st);
    190:   /* compute matrix coefficients */
    191:   STGetTransform(pep->st,&flg);
    192:   if (!flg) {
    193:     if (pep->solvematcoeffs) { STMatSetUp(pep->st,1.0,pep->solvematcoeffs); }
    194:   } else {
    195:     if (pep->basis!=PEP_BASIS_MONOMIAL) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Cannot use ST-transform with non-monomial basis in PEP");
    196:   }

    198:   /* compute scale factor if no set by user */
    199:   PEPComputeScaleFactor(pep);

    201:   /* build balancing matrix if required */
    202:   if (pep->scale==PEP_SCALE_DIAGONAL || pep->scale==PEP_SCALE_BOTH) {
    203:     if (!pep->Dl) {
    204:       BVCreateVec(pep->V,&pep->Dl);
    205:       PetscLogObjectParent((PetscObject)pep,(PetscObject)pep->Dl);
    206:     }
    207:     if (!pep->Dr) {
    208:       BVCreateVec(pep->V,&pep->Dr);
    209:       PetscLogObjectParent((PetscObject)pep,(PetscObject)pep->Dr);
    210:     }
    211:     PEPBuildDiagonalScaling(pep);
    212:   }

    214:   /* process initial vectors */
    215:   if (pep->nini<0) {
    216:     k = -pep->nini;
    217:     if (k>pep->ncv) SETERRQ(PetscObjectComm((PetscObject)pep),1,"The number of initial vectors is larger than ncv");
    218:     BVInsertVecs(pep->V,0,&k,pep->IS,PETSC_TRUE);
    219:     SlepcBasisDestroy_Private(&pep->nini,&pep->IS);
    220:     pep->nini = k;
    221:   }
    222:   PetscLogEventEnd(PEP_SetUp,pep,0,0,0);
    223:   pep->state = PEP_STATE_SETUP;
    224:   return(0);
    225: }

    229: /*@
    230:    PEPSetOperators - Sets the coefficient matrices associated with the polynomial
    231:    eigenvalue problem.

    233:    Collective on PEP and Mat

    235:    Input Parameters:
    236: +  pep  - the eigenproblem solver context
    237: .  nmat - number of matrices in array A
    238: -  A    - the array of matrices associated with the eigenproblem

    240:    Notes:
    241:    The polynomial eigenproblem is defined as P(l)*x=0, where l is
    242:    the eigenvalue, x is the eigenvector, and P(l) is defined as
    243:    P(l) = A_0 + l*A_1 + ... + l^d*A_d, with d=nmat-1 (the degree of P).
    244:    For non-monomial bases, this expression is different.

    246:    Level: beginner

    248: .seealso: PEPSolve(), PEPGetOperators(), PEPGetNumMatrices(), PEPSetBasis()
    249: @*/
    250: PetscErrorCode PEPSetOperators(PEP pep,PetscInt nmat,Mat A[])
    251: {
    253:   PetscInt       i,n,m,m0=0;

    258:   if (nmat <= 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Non-positive value of nmat: %D",nmat);
    259:   if (nmat <= 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Cannot solve linear eigenproblems with PEP; use EPS instead");

    262:   if (pep->state) { PEPReset(pep); }
    263:   PetscMalloc1(nmat,&pep->A);
    264:   PetscCalloc2(3*nmat,&pep->pbc,nmat,&pep->nrma);
    265:   for (i=0;i<nmat;i++) pep->pbc[i] = 1.0;  /* default to monomial basis */
    266:   PetscLogObjectMemory((PetscObject)pep,nmat*sizeof(Mat)+4*nmat*sizeof(PetscReal)+nmat*sizeof(PetscScalar));
    267:   for (i=0;i<nmat;i++) {
    270:     MatGetSize(A[i],&m,&n);
    271:     if (m!=n) SETERRQ1(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_WRONG,"A[%D] is a non-square matrix",i);
    272:     if (!i) m0 = m;
    273:     if (m!=m0) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_INCOMP,"Dimensions of matrices do not match with each other");
    274:     PetscObjectReference((PetscObject)A[i]);
    275:     pep->A[i] = A[i];
    276:   }
    277:   pep->nmat = nmat;
    278:   return(0);
    279: }

    283: /*@
    284:    PEPGetOperators - Gets the matrices associated with the polynomial eigensystem.

    286:    Not collective, though parallel Mats are returned if the PEP is parallel

    288:    Input Parameters:
    289: +  pep - the PEP context
    290: -  k   - the index of the requested matrix (starting in 0)

    292:    Output Parameter:
    293: .  A - the requested matrix

    295:    Level: intermediate

    297: .seealso: PEPSolve(), PEPSetOperators(), PEPGetNumMatrices()
    298: @*/
    299: PetscErrorCode PEPGetOperators(PEP pep,PetscInt k,Mat *A)
    300: {
    304:   if (k<0 || k>=pep->nmat) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"k must be between 0 and %D",pep->nmat-1);
    305:   *A = pep->A[k];
    306:   return(0);
    307: }

    311: /*@
    312:    PEPGetNumMatrices - Returns the number of matrices stored in the PEP.

    314:    Not collective

    316:    Input Parameter:
    317: .  pep - the PEP context

    319:    Output Parameters:
    320: .  nmat - the number of matrices passed in PEPSetOperators()

    322:    Level: intermediate

    324: .seealso: PEPSetOperators()
    325: @*/
    326: PetscErrorCode PEPGetNumMatrices(PEP pep,PetscInt *nmat)
    327: {
    331:   *nmat = pep->nmat;
    332:   return(0);
    333: }

    337: /*@
    338:    PEPSetInitialSpace - Specify a basis of vectors that constitute the initial
    339:    space, that is, the subspace from which the solver starts to iterate.

    341:    Collective on PEP and Vec

    343:    Input Parameter:
    344: +  pep   - the polynomial eigensolver context
    345: .  n     - number of vectors
    346: -  is    - set of basis vectors of the initial space

    348:    Notes:
    349:    Some solvers start to iterate on a single vector (initial vector). In that case,
    350:    the other vectors are ignored.

    352:    These vectors do not persist from one PEPSolve() call to the other, so the
    353:    initial space should be set every time.

    355:    The vectors do not need to be mutually orthonormal, since they are explicitly
    356:    orthonormalized internally.

    358:    Common usage of this function is when the user can provide a rough approximation
    359:    of the wanted eigenspace. Then, convergence may be faster.

    361:    Level: intermediate
    362: @*/
    363: PetscErrorCode PEPSetInitialSpace(PEP pep,PetscInt n,Vec *is)
    364: {

    370:   if (n<0) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_OUTOFRANGE,"Argument n cannot be negative");
    371:   SlepcBasisReference_Private(n,is,&pep->nini,&pep->IS);
    372:   if (n>0) pep->state = PEP_STATE_INITIAL;
    373:   return(0);
    374: }

    378: /*
    379:   PEPSetDimensions_Default - Set reasonable values for ncv, mpd if not set
    380:   by the user. This is called at setup.
    381:  */
    382: PetscErrorCode PEPSetDimensions_Default(PEP pep,PetscInt nev,PetscInt *ncv,PetscInt *mpd)
    383: {
    385:   PetscBool      krylov;
    386:   PetscInt       dim;

    389:   PetscObjectTypeCompareAny((PetscObject)pep,&krylov,PEPTOAR,PEPQARNOLDI,"");
    390:   dim = krylov?(pep->nmat-1)*pep->n:pep->n;
    391:   if (*ncv) { /* ncv set */
    392:     if (krylov) {
    393:       if (*ncv<nev+1 && !(*ncv==nev && *ncv==dim)) SETERRQ(PetscObjectComm((PetscObject)pep),1,"The value of ncv must be at least nev+1");
    394:     } else {
    395:       if (*ncv<nev) SETERRQ(PetscObjectComm((PetscObject)pep),1,"The value of ncv must be at least nev");
    396:     }
    397:   } else if (*mpd) { /* mpd set */
    398:     *ncv = PetscMin(dim,nev+(*mpd));
    399:   } else { /* neither set: defaults depend on nev being small or large */
    400:     if (nev<500) *ncv = PetscMin(dim,PetscMax(2*nev,nev+15));
    401:     else {
    402:       *mpd = 500;
    403:       *ncv = PetscMin(dim,nev+(*mpd));
    404:     }
    405:   }
    406:   if (!*mpd) *mpd = *ncv;
    407:   return(0);
    408: }

    412: /*@
    413:    PEPAllocateSolution - Allocate memory storage for common variables such
    414:    as eigenvalues and eigenvectors.

    416:    Collective on PEP

    418:    Input Parameters:
    419: +  pep   - eigensolver context
    420: -  extra - number of additional positions, used for methods that require a
    421:            working basis slightly larger than ncv

    423:    Developers Note:
    424:    This is PETSC_EXTERN because it may be required by user plugin PEP
    425:    implementations.

    427:    Level: developer
    428: @*/
    429: PetscErrorCode PEPAllocateSolution(PEP pep,PetscInt extra)
    430: {
    432:   PetscInt       oldsize,newc,requested,requestedbv;
    433:   PetscLogDouble cnt;
    434:   Vec            t;

    437:   requested = (pep->lineariz? pep->ncv: pep->ncv*(pep->nmat-1)) + extra;
    438:   requestedbv = pep->ncv + extra;

    440:   /* oldsize is zero if this is the first time setup is called */
    441:   BVGetSizes(pep->V,NULL,NULL,&oldsize);

    443:   /* allocate space for eigenvalues and friends */
    444:   if (requested != oldsize || !pep->eigr) {
    445:     if (oldsize) {
    446:       PetscFree4(pep->eigr,pep->eigi,pep->errest,pep->perm);
    447:     }
    448:     PetscMalloc4(requested,&pep->eigr,requested,&pep->eigi,requested,&pep->errest,requested,&pep->perm);
    449:     newc = PetscMax(0,requested-oldsize);
    450:     cnt = 2*newc*sizeof(PetscScalar) + newc*sizeof(PetscReal) + newc*sizeof(PetscInt);
    451:     PetscLogObjectMemory((PetscObject)pep,cnt);
    452:   }

    454:   /* allocate V */
    455:   if (!pep->V) { PEPGetBV(pep,&pep->V); }
    456:   if (!oldsize) {
    457:     if (!((PetscObject)(pep->V))->type_name) {
    458:       BVSetType(pep->V,BVSVEC);
    459:     }
    460:     STMatCreateVecs(pep->st,&t,NULL);
    461:     BVSetSizesFromVec(pep->V,t,requestedbv);
    462:     VecDestroy(&t);
    463:   } else {
    464:     BVResize(pep->V,requestedbv,PETSC_FALSE);
    465:   }
    466:   return(0);
    467: }