Actual source code: pepsetup.c

slepc-3.6.1 2015-09-03
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-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/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;

 55:   if (pep->state) return(0);
 56:   PetscLogEventBegin(PEP_SetUp,pep,0,0,0);

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

 61:   /* set default solver type (PEPSetFromOptions was not called) */
 62:   if (!((PetscObject)pep)->type_name) {
 63:     PEPSetType(pep,PEPTOAR);
 64:   }
 65:   if (!pep->st) { PEPGetST(pep,&pep->st); }
 66:   PetscObjectTypeCompare((PetscObject)pep,PEPLINEAR,&islinear);
 67:   if (!((PetscObject)pep->st)->type_name) {
 68:     STSetType(pep->st,STSHIFT);
 69:   }
 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:   }
 76:   if (!((PetscObject)pep->rand)->type_name) {
 77:     PetscRandomSetFromOptions(pep->rand);
 78:   }

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

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

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

 93:   /* call specific solver setup */
 94:   (*pep->ops->setup)(pep);

 96:   /* set tolerance if not yet set */
 97:   if (pep->tol==PETSC_DEFAULT) pep->tol = SLEPC_DEFAULT_TOL;
 98:   if (pep->refine) {
 99:     if (pep->rtol==PETSC_DEFAULT) pep->rtol = pep->tol;
100:     if (pep->rits==PETSC_DEFAULT) pep->rits = (pep->refine==PEP_REFINE_SIMPLE)? 10: 1;
101:   }

103:   /* set default extraction */
104:   if (!pep->extract) {
105:     pep->extract = (pep->basis==PEP_BASIS_MONOMIAL)? PEP_EXTRACT_NORM: PEP_EXTRACT_NONE;
106:   }

108:   /* fill sorting criterion context */
109:   switch (pep->which) {
110:     case PEP_LARGEST_MAGNITUDE:
111:       pep->sc->comparison    = SlepcCompareLargestMagnitude;
112:       pep->sc->comparisonctx = NULL;
113:       break;
114:     case PEP_SMALLEST_MAGNITUDE:
115:       pep->sc->comparison    = SlepcCompareSmallestMagnitude;
116:       pep->sc->comparisonctx = NULL;
117:       break;
118:     case PEP_LARGEST_REAL:
119:       pep->sc->comparison    = SlepcCompareLargestReal;
120:       pep->sc->comparisonctx = NULL;
121:       break;
122:     case PEP_SMALLEST_REAL:
123:       pep->sc->comparison    = SlepcCompareSmallestReal;
124:       pep->sc->comparisonctx = NULL;
125:       break;
126:     case PEP_LARGEST_IMAGINARY:
127:       pep->sc->comparison    = SlepcCompareLargestImaginary;
128:       pep->sc->comparisonctx = NULL;
129:       break;
130:     case PEP_SMALLEST_IMAGINARY:
131:       pep->sc->comparison    = SlepcCompareSmallestImaginary;
132:       pep->sc->comparisonctx = NULL;
133:       break;
134:     case PEP_TARGET_MAGNITUDE:
135:       pep->sc->comparison    = SlepcCompareTargetMagnitude;
136:       pep->sc->comparisonctx = &pep->target;
137:       break;
138:     case PEP_TARGET_REAL:
139:       pep->sc->comparison    = SlepcCompareTargetReal;
140:       pep->sc->comparisonctx = &pep->target;
141:       break;
142:     case PEP_TARGET_IMAGINARY:
143:       pep->sc->comparison    = SlepcCompareTargetImaginary;
144:       pep->sc->comparisonctx = &pep->target;
145:       break;
146:     case PEP_WHICH_USER:
147:       break;
148:   }
149:   pep->sc->map    = NULL;
150:   pep->sc->mapobj = NULL;

152:   /* fill sorting criterion for DS */
153:   DSGetSlepcSC(pep->ds,&sc);
154:   RGIsTrivial(pep->rg,&istrivial);
155:   sc->rg            = istrivial? NULL: pep->rg;
156:   sc->comparison    = pep->sc->comparison;
157:   sc->comparisonctx = pep->sc->comparisonctx;
158:   sc->map           = SlepcMap_ST;
159:   sc->mapobj        = (PetscObject)pep->st;

161:   /* setup ST */
162:   PetscObjectTypeCompareAny((PetscObject)pep->st,&flg,STSHIFT,STSINVERT,"");
163:   if (!flg) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Only STSHIFT and STSINVERT spectral transformations can be used in PEP");
164:   STSetUp(pep->st);
165:   /* compute matrix coefficients */
166:   STGetTransform(pep->st,&flg);
167:   if (!flg) {
168:     if (pep->solvematcoeffs) { STMatSetUp(pep->st,1.0,pep->solvematcoeffs); }
169:   } else {
170:     if (pep->basis!=PEP_BASIS_MONOMIAL) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Cannot use ST-transform with non-monomial basis in PEP");
171:   }

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

176:   /* build balancing matrix if required */
177:   if (pep->scale==PEP_SCALE_DIAGONAL || pep->scale==PEP_SCALE_BOTH) {
178:     if (!pep->Dl) {
179:       BVCreateVec(pep->V,&pep->Dl);
180:       PetscLogObjectParent((PetscObject)pep,(PetscObject)pep->Dl);
181:     }
182:     if (!pep->Dr) {
183:       BVCreateVec(pep->V,&pep->Dr);
184:       PetscLogObjectParent((PetscObject)pep,(PetscObject)pep->Dr);
185:     }
186:     PEPBuildDiagonalScaling(pep);
187:   }

189:   if (pep->conv==PEP_CONV_LINEAR) {
190:     PEPComputeLinearNorms(pep);
191:   }

193:   /* process initial vectors */
194:   if (pep->nini<0) {
195:     k = -pep->nini;
196:     if (k>pep->ncv) SETERRQ(PetscObjectComm((PetscObject)pep),1,"The number of initial vectors is larger than ncv");
197:     BVInsertVecs(pep->V,0,&k,pep->IS,PETSC_TRUE);
198:     SlepcBasisDestroy_Private(&pep->nini,&pep->IS);
199:     pep->nini = k;
200:   }
201:   PetscLogEventEnd(PEP_SetUp,pep,0,0,0);
202:   pep->state = PEP_STATE_SETUP;
203:   return(0);
204: }

208: /*@
209:    PEPSetOperators - Sets the coefficient matrices associated with the polynomial
210:    eigenvalue problem.

212:    Collective on PEP and Mat

214:    Input Parameters:
215: +  pep  - the eigenproblem solver context
216: .  nmat - number of matrices in array A
217: -  A    - the array of matrices associated with the eigenproblem

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

225:    Level: beginner

227: .seealso: PEPSolve(), PEPGetOperators(), PEPGetNumMatrices(), PEPSetBasis()
228: @*/
229: PetscErrorCode PEPSetOperators(PEP pep,PetscInt nmat,Mat A[])
230: {
232:   PetscInt       i,n,m,m0=0;

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

241:   if (pep->state) { PEPReset(pep); }
242:   PetscMalloc1(nmat,&pep->A);
243:   PetscCalloc2(3*nmat,&pep->pbc,nmat,&pep->nrma);
244:   for (i=0;i<nmat;i++) pep->pbc[i] = 1.0;  /* default to monomial basis */
245:   PetscLogObjectMemory((PetscObject)pep,nmat*sizeof(Mat)+4*nmat*sizeof(PetscReal)+nmat*sizeof(PetscScalar));
246:   for (i=0;i<nmat;i++) {
249:     MatGetSize(A[i],&m,&n);
250:     if (m!=n) SETERRQ1(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_WRONG,"A[%D] is a non-square matrix",i);
251:     if (!i) m0 = m;
252:     if (m!=m0) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_INCOMP,"Dimensions of matrices do not match with each other");
253:     PetscObjectReference((PetscObject)A[i]);
254:     pep->A[i] = A[i];
255:   }
256:   pep->nmat = nmat;
257:   return(0);
258: }

262: /*@
263:    PEPGetOperators - Gets the matrices associated with the polynomial eigensystem.

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

267:    Input Parameters:
268: +  pep - the PEP context
269: -  k   - the index of the requested matrix (starting in 0)

271:    Output Parameter:
272: .  A - the requested matrix

274:    Level: intermediate

276: .seealso: PEPSolve(), PEPSetOperators(), PEPGetNumMatrices()
277: @*/
278: PetscErrorCode PEPGetOperators(PEP pep,PetscInt k,Mat *A)
279: {
283:   if (k<0 || k>=pep->nmat) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"k must be between 0 and %d",pep->nmat-1);
284:   *A = pep->A[k];
285:   return(0);
286: }

290: /*@
291:    PEPGetNumMatrices - Returns the number of matrices stored in the PEP.

293:    Not collective

295:    Input Parameter:
296: .  pep - the PEP context

298:    Output Parameters:
299: .  nmat - the number of matrices passed in PEPSetOperators()

301:    Level: intermediate

303: .seealso: PEPSetOperators()
304: @*/
305: PetscErrorCode PEPGetNumMatrices(PEP pep,PetscInt *nmat)
306: {
310:   *nmat = pep->nmat;
311:   return(0);
312: }

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

320:    Collective on PEP and Vec

322:    Input Parameter:
323: +  pep   - the polynomial eigensolver context
324: .  n     - number of vectors
325: -  is    - set of basis vectors of the initial space

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

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

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

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

340:    Level: intermediate
341: @*/
342: PetscErrorCode PEPSetInitialSpace(PEP pep,PetscInt n,Vec *is)
343: {

349:   if (n<0) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_OUTOFRANGE,"Argument n cannot be negative");
350:   SlepcBasisReference_Private(n,is,&pep->nini,&pep->IS);
351:   if (n>0) pep->state = PEP_STATE_INITIAL;
352:   return(0);
353: }

357: /*
358:   PEPSetDimensions_Default - Set reasonable values for ncv, mpd if not set
359:   by the user. This is called at setup.
360:  */
361: PetscErrorCode PEPSetDimensions_Default(PEP pep,PetscInt nev,PetscInt *ncv,PetscInt *mpd)
362: {
364:   PetscBool      krylov;
365:   PetscInt       dim;

368:   PetscObjectTypeCompareAny((PetscObject)pep,&krylov,PEPTOAR,PEPQARNOLDI,"");
369:   dim = krylov?(pep->nmat-1)*pep->n:pep->n;
370:   if (*ncv) { /* ncv set */
371:     if (krylov) {
372:       if (*ncv<nev+1 && !(*ncv==nev && *ncv==dim)) SETERRQ(PetscObjectComm((PetscObject)pep),1,"The value of ncv must be at least nev+1");
373:     } else {
374:       if (*ncv<nev) SETERRQ(PetscObjectComm((PetscObject)pep),1,"The value of ncv must be at least nev");
375:     }
376:   } else if (*mpd) { /* mpd set */
377:     *ncv = PetscMin(dim,nev+(*mpd));
378:   } else { /* neither set: defaults depend on nev being small or large */
379:     if (nev<500) *ncv = PetscMin(dim,PetscMax(2*nev,nev+15));
380:     else {
381:       *mpd = 500;
382:       *ncv = PetscMin(dim,nev+(*mpd));
383:     }
384:   }
385:   if (!*mpd) *mpd = *ncv;
386:   return(0);
387: }

391: /*@
392:    PEPAllocateSolution - Allocate memory storage for common variables such
393:    as eigenvalues and eigenvectors.

395:    Collective on PEP

397:    Input Parameters:
398: +  pep   - eigensolver context
399: -  extra - number of additional positions, used for methods that require a
400:            working basis slightly larger than ncv

402:    Developers Note:
403:    This is PETSC_EXTERN because it may be required by user plugin PEP
404:    implementations.

406:    Level: developer
407: @*/
408: PetscErrorCode PEPAllocateSolution(PEP pep,PetscInt extra)
409: {
411:   PetscInt       oldsize,newc,requested,requestedbv;
412:   PetscLogDouble cnt;
413:   Vec            t;

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

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

422:   /* allocate space for eigenvalues and friends */
423:   if (requested != oldsize || !pep->eigr) {
424:     if (oldsize) {
425:       PetscFree4(pep->eigr,pep->eigi,pep->errest,pep->perm);
426:     }
427:     PetscMalloc4(requested,&pep->eigr,requested,&pep->eigi,requested,&pep->errest,requested,&pep->perm);
428:     newc = PetscMax(0,requested-oldsize);
429:     cnt = 2*newc*sizeof(PetscScalar) + newc*sizeof(PetscReal) + newc*sizeof(PetscInt);
430:     PetscLogObjectMemory((PetscObject)pep,cnt);
431:   }

433:   /* allocate V */
434:   if (!pep->V) { PEPGetBV(pep,&pep->V); }
435:   if (!oldsize) {
436:     if (!((PetscObject)(pep->V))->type_name) {
437:       BVSetType(pep->V,BVSVEC);
438:     }
439:     STMatCreateVecs(pep->st,&t,NULL);
440:     BVSetSizesFromVec(pep->V,t,requestedbv);
441:     VecDestroy(&t);
442:   } else {
443:     BVResize(pep->V,requestedbv,PETSC_FALSE);
444:   }
445:   return(0);
446: }