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