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