Actual source code: pepsetup.c

slepc-3.7.0 2016-05-16
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      islinear,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:   PetscObjectTypeCompare((PetscObject)pep,PEPLINEAR,&islinear);
 71:   if (!((PetscObject)pep->st)->type_name) {
 72:     STSetType(pep->st,STSHIFT);
 73:   }
 74:   if (!pep->ds) { PEPGetDS(pep,&pep->ds); }
 75:   DSReset(pep->ds);
 76:   if (!pep->rg) { PEPGetRG(pep,&pep->rg); }
 77:   if (!((PetscObject)pep->rg)->type_name) {
 78:     RGSetType(pep->rg,RGINTERVAL);
 79:   }

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

 85:   /* set problem dimensions */
 86:   MatGetSize(pep->A[0],&pep->n,NULL);
 87:   MatGetLocalSize(pep->A[0],&pep->nloc,NULL);

 89:   /* set default problem type */
 90:   if (!pep->problem_type) {
 91:     PEPSetProblemType(pep,PEP_GENERAL);
 92:   }

 94:   /* check consistency of refinement options */
 95:   if (pep->refine) {
 96:     if (!pep->scheme) {  /* set default scheme */
 97:       PEPRefineGetKSP(pep,&ksp);
 98:       KSPGetPC(ksp,&pc);
 99:       PetscObjectTypeCompare((PetscObject)ksp,KSPPREONLY,&flg);
100:       if (flg) {
101:         PetscObjectTypeCompareAny((PetscObject)pc,&flg,PCLU,PCCHOLESKY,"");
102:       }
103:       pep->scheme = flg? PEP_REFINE_SCHEME_MBE: PEP_REFINE_SCHEME_SCHUR;
104:     }
105:     if (pep->scheme==PEP_REFINE_SCHEME_MBE) {
106:       PEPRefineGetKSP(pep,&ksp);
107:       KSPGetPC(ksp,&pc);
108:       PetscObjectTypeCompare((PetscObject)ksp,KSPPREONLY,&flg);
109:       if (flg) {
110:         PetscObjectTypeCompareAny((PetscObject)pc,&flg,PCLU,PCCHOLESKY,"");
111:       }
112:       if (!flg) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"The MBE scheme for refinement requires a direct solver in KSP");
113:       MPI_Comm_size(PetscObjectComm((PetscObject)pc),&size);
114:       if (size>1) {   /* currently selected PC is a factorization */
115:         PCFactorGetMatSolverPackage(pc,&stype);
116:         PetscStrcmp(stype,MATSOLVERPETSC,&flg);
117:         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");
118:       }
119:     }
120:     if (pep->scheme==PEP_REFINE_SCHEME_SCHUR) {
121:       if (pep->npart>1) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"The Schur scheme for refinement does not support subcommunicators"); 
122:     }
123:   }
124:   /* call specific solver setup */
125:   (*pep->ops->setup)(pep);

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

134:   /* set default extraction */
135:   if (!pep->extract) {
136:     pep->extract = (pep->basis==PEP_BASIS_MONOMIAL)? PEP_EXTRACT_NORM: PEP_EXTRACT_NONE;
137:   }

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

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

192:   /* setup ST */
193:   PetscObjectTypeCompareAny((PetscObject)pep->st,&flg,STSHIFT,STSINVERT,"");
194:   if (!flg) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Only STSHIFT and STSINVERT spectral transformations can be used in PEP");
195:   STSetUp(pep->st);
196:   /* compute matrix coefficients */
197:   STGetTransform(pep->st,&flg);
198:   if (!flg) {
199:     if (pep->solvematcoeffs) { STMatSetUp(pep->st,1.0,pep->solvematcoeffs); }
200:   } else {
201:     if (pep->basis!=PEP_BASIS_MONOMIAL) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Cannot use ST-transform with non-monomial basis in PEP");
202:   }

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

207:   /* build balancing matrix if required */
208:   if (pep->scale==PEP_SCALE_DIAGONAL || pep->scale==PEP_SCALE_BOTH) {
209:     if (!pep->Dl) {
210:       BVCreateVec(pep->V,&pep->Dl);
211:       PetscLogObjectParent((PetscObject)pep,(PetscObject)pep->Dl);
212:     }
213:     if (!pep->Dr) {
214:       BVCreateVec(pep->V,&pep->Dr);
215:       PetscLogObjectParent((PetscObject)pep,(PetscObject)pep->Dr);
216:     }
217:     PEPBuildDiagonalScaling(pep);
218:   }

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

235: /*@
236:    PEPSetOperators - Sets the coefficient matrices associated with the polynomial
237:    eigenvalue problem.

239:    Collective on PEP and Mat

241:    Input Parameters:
242: +  pep  - the eigenproblem solver context
243: .  nmat - number of matrices in array A
244: -  A    - the array of matrices associated with the eigenproblem

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

252:    Level: beginner

254: .seealso: PEPSolve(), PEPGetOperators(), PEPGetNumMatrices(), PEPSetBasis()
255: @*/
256: PetscErrorCode PEPSetOperators(PEP pep,PetscInt nmat,Mat A[])
257: {
259:   PetscInt       i,n,m,m0=0;

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

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

289: /*@
290:    PEPGetOperators - Gets the matrices associated with the polynomial eigensystem.

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

294:    Input Parameters:
295: +  pep - the PEP context
296: -  k   - the index of the requested matrix (starting in 0)

298:    Output Parameter:
299: .  A - the requested matrix

301:    Level: intermediate

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

317: /*@
318:    PEPGetNumMatrices - Returns the number of matrices stored in the PEP.

320:    Not collective

322:    Input Parameter:
323: .  pep - the PEP context

325:    Output Parameters:
326: .  nmat - the number of matrices passed in PEPSetOperators()

328:    Level: intermediate

330: .seealso: PEPSetOperators()
331: @*/
332: PetscErrorCode PEPGetNumMatrices(PEP pep,PetscInt *nmat)
333: {
337:   *nmat = pep->nmat;
338:   return(0);
339: }

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

347:    Collective on PEP and Vec

349:    Input Parameter:
350: +  pep   - the polynomial eigensolver context
351: .  n     - number of vectors
352: -  is    - set of basis vectors of the initial space

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

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

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

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

367:    Level: intermediate
368: @*/
369: PetscErrorCode PEPSetInitialSpace(PEP pep,PetscInt n,Vec *is)
370: {

376:   if (n<0) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_OUTOFRANGE,"Argument n cannot be negative");
377:   SlepcBasisReference_Private(n,is,&pep->nini,&pep->IS);
378:   if (n>0) pep->state = PEP_STATE_INITIAL;
379:   return(0);
380: }

384: /*
385:   PEPSetDimensions_Default - Set reasonable values for ncv, mpd if not set
386:   by the user. This is called at setup.
387:  */
388: PetscErrorCode PEPSetDimensions_Default(PEP pep,PetscInt nev,PetscInt *ncv,PetscInt *mpd)
389: {
391:   PetscBool      krylov;
392:   PetscInt       dim;

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

418: /*@
419:    PEPAllocateSolution - Allocate memory storage for common variables such
420:    as eigenvalues and eigenvectors.

422:    Collective on PEP

424:    Input Parameters:
425: +  pep   - eigensolver context
426: -  extra - number of additional positions, used for methods that require a
427:            working basis slightly larger than ncv

429:    Developers Note:
430:    This is PETSC_EXTERN because it may be required by user plugin PEP
431:    implementations.

433:    Level: developer
434: @*/
435: PetscErrorCode PEPAllocateSolution(PEP pep,PetscInt extra)
436: {
438:   PetscInt       oldsize,newc,requested,requestedbv;
439:   PetscLogDouble cnt;
440:   Vec            t;

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

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

449:   /* allocate space for eigenvalues and friends */
450:   if (requested != oldsize || !pep->eigr) {
451:     if (oldsize) {
452:       PetscFree4(pep->eigr,pep->eigi,pep->errest,pep->perm);
453:     }
454:     PetscMalloc4(requested,&pep->eigr,requested,&pep->eigi,requested,&pep->errest,requested,&pep->perm);
455:     newc = PetscMax(0,requested-oldsize);
456:     cnt = 2*newc*sizeof(PetscScalar) + newc*sizeof(PetscReal) + newc*sizeof(PetscInt);
457:     PetscLogObjectMemory((PetscObject)pep,cnt);
458:   }

460:   /* allocate V */
461:   if (!pep->V) { PEPGetBV(pep,&pep->V); }
462:   if (!oldsize) {
463:     if (!((PetscObject)(pep->V))->type_name) {
464:       BVSetType(pep->V,BVSVEC);
465:     }
466:     STMatCreateVecs(pep->st,&t,NULL);
467:     BVSetSizesFromVec(pep->V,t,requestedbv);
468:     VecDestroy(&t);
469:   } else {
470:     BVResize(pep->V,requestedbv,PETSC_FALSE);
471:   }
472:   return(0);
473: }