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: }