Actual source code: epsdefault.c
slepc-3.17.2 2022-08-09
1: /*
2: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3: SLEPc - Scalable Library for Eigenvalue Problem Computations
4: Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
6: This file is part of SLEPc.
7: SLEPc is distributed under a 2-clause BSD license (see LICENSE).
8: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
9: */
10: /*
11: This file contains some simple default routines for common operations
12: */
14: #include <slepc/private/epsimpl.h>
15: #include <slepcvec.h>
17: PetscErrorCode EPSBackTransform_Default(EPS eps)
18: {
19: STBackTransform(eps->st,eps->nconv,eps->eigr,eps->eigi);
20: PetscFunctionReturn(0);
21: }
23: /*
24: EPSComputeVectors_Hermitian - Copies the Lanczos vectors as eigenvectors
25: using purification for generalized eigenproblems.
26: */
27: PetscErrorCode EPSComputeVectors_Hermitian(EPS eps)
28: {
29: PetscBool iscayley,indef;
30: Mat B,C;
32: if (eps->purify) {
33: EPS_Purify(eps,eps->nconv);
34: BVNormalize(eps->V,NULL);
35: } else {
36: /* In the case of Cayley transform, eigenvectors need to be B-normalized */
37: PetscObjectTypeCompare((PetscObject)eps->st,STCAYLEY,&iscayley);
38: if (iscayley && eps->isgeneralized) {
39: STGetMatrix(eps->st,1,&B);
40: BVGetMatrix(eps->V,&C,&indef);
42: BVSetMatrix(eps->V,B,PETSC_FALSE);
43: BVNormalize(eps->V,NULL);
44: BVSetMatrix(eps->V,C,PETSC_FALSE); /* restore original matrix */
45: }
46: }
47: PetscFunctionReturn(0);
48: }
50: /*
51: EPSComputeVectors_Indefinite - similar to the Schur version but
52: for indefinite problems
53: */
54: PetscErrorCode EPSComputeVectors_Indefinite(EPS eps)
55: {
56: PetscInt n;
57: Mat X;
59: DSGetDimensions(eps->ds,&n,NULL,NULL,NULL);
60: DSVectors(eps->ds,DS_MAT_X,NULL,NULL);
61: DSGetMat(eps->ds,DS_MAT_X,&X);
62: BVMultInPlace(eps->V,X,0,n);
63: MatDestroy(&X);
65: /* purification */
66: if (eps->purify) EPS_Purify(eps,eps->nconv);
68: /* normalization */
69: BVNormalize(eps->V,eps->eigi);
70: PetscFunctionReturn(0);
71: }
73: /*
74: EPSComputeVectors_Twosided - Adjust left eigenvectors in generalized problems: y = B^-* y.
75: */
76: PetscErrorCode EPSComputeVectors_Twosided(EPS eps)
77: {
78: PetscInt i;
79: Vec w,y;
81: if (!eps->twosided || !eps->isgeneralized) PetscFunctionReturn(0);
82: EPSSetWorkVecs(eps,1);
83: w = eps->work[0];
84: for (i=0;i<eps->nconv;i++) {
85: BVCopyVec(eps->W,i,w);
86: VecConjugate(w);
87: BVGetColumn(eps->W,i,&y);
88: STMatSolveTranspose(eps->st,w,y);
89: VecConjugate(y);
90: BVRestoreColumn(eps->W,i,&y);
91: }
92: PetscFunctionReturn(0);
93: }
95: /*
96: EPSComputeVectors_Schur - Compute eigenvectors from the vectors
97: provided by the eigensolver. This version is intended for solvers
98: that provide Schur vectors. Given the partial Schur decomposition
99: OP*V=V*T, the following steps are performed:
100: 1) compute eigenvectors of T: T*Z=Z*D
101: 2) compute eigenvectors of OP: X=V*Z
102: */
103: PetscErrorCode EPSComputeVectors_Schur(EPS eps)
104: {
105: PetscInt i;
106: Mat Z;
107: Vec z;
109: if (eps->ishermitian) {
110: if (eps->isgeneralized && !eps->ispositive) EPSComputeVectors_Indefinite(eps);
111: else EPSComputeVectors_Hermitian(eps);
112: PetscFunctionReturn(0);
113: }
115: /* right eigenvectors */
116: DSVectors(eps->ds,DS_MAT_X,NULL,NULL);
118: /* V = V * Z */
119: DSGetMat(eps->ds,DS_MAT_X,&Z);
120: BVMultInPlace(eps->V,Z,0,eps->nconv);
121: MatDestroy(&Z);
123: /* Purify eigenvectors */
124: if (eps->purify) EPS_Purify(eps,eps->nconv);
126: /* Fix eigenvectors if balancing was used */
127: if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
128: for (i=0;i<eps->nconv;i++) {
129: BVGetColumn(eps->V,i,&z);
130: VecPointwiseDivide(z,z,eps->D);
131: BVRestoreColumn(eps->V,i,&z);
132: }
133: }
135: /* normalize eigenvectors (when using purification or balancing) */
136: if (eps->purify || (eps->balance!=EPS_BALANCE_NONE && eps->D)) BVNormalize(eps->V,eps->eigi);
138: /* left eigenvectors */
139: if (eps->twosided) {
140: DSVectors(eps->ds,DS_MAT_Y,NULL,NULL);
141: /* W = W * Z */
142: DSGetMat(eps->ds,DS_MAT_Y,&Z);
143: BVMultInPlace(eps->W,Z,0,eps->nconv);
144: MatDestroy(&Z);
145: /* Fix left eigenvectors if balancing was used */
146: if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
147: for (i=0;i<eps->nconv;i++) {
148: BVGetColumn(eps->W,i,&z);
149: VecPointwiseMult(z,z,eps->D);
150: BVRestoreColumn(eps->W,i,&z);
151: }
152: }
153: EPSComputeVectors_Twosided(eps);
154: /* normalize */
155: BVNormalize(eps->W,eps->eigi);
156: #if !defined(PETSC_USE_COMPLEX)
157: for (i=0;i<eps->nconv-1;i++) {
158: if (eps->eigi[i] != 0.0) {
159: if (eps->eigi[i] > 0.0) BVScaleColumn(eps->W,i+1,-1.0);
160: i++;
161: }
162: }
163: #endif
164: }
165: PetscFunctionReturn(0);
166: }
168: /*@
169: EPSSetWorkVecs - Sets a number of work vectors into an EPS object.
171: Collective on eps
173: Input Parameters:
174: + eps - eigensolver context
175: - nw - number of work vectors to allocate
177: Developer Notes:
178: This is SLEPC_EXTERN because it may be required by user plugin EPS
179: implementations.
181: Level: developer
183: .seealso: EPSSetUp()
184: @*/
185: PetscErrorCode EPSSetWorkVecs(EPS eps,PetscInt nw)
186: {
187: Vec t;
192: if (eps->nwork < nw) {
193: VecDestroyVecs(eps->nwork,&eps->work);
194: eps->nwork = nw;
195: BVGetColumn(eps->V,0,&t);
196: VecDuplicateVecs(t,nw,&eps->work);
197: BVRestoreColumn(eps->V,0,&t);
198: PetscLogObjectParents(eps,nw,eps->work);
199: }
200: PetscFunctionReturn(0);
201: }
203: /*
204: EPSSetWhichEigenpairs_Default - Sets the default value for which,
205: depending on the ST.
206: */
207: PetscErrorCode EPSSetWhichEigenpairs_Default(EPS eps)
208: {
209: PetscBool target;
211: PetscObjectTypeCompareAny((PetscObject)eps->st,&target,STSINVERT,STCAYLEY,"");
212: if (target) eps->which = EPS_TARGET_MAGNITUDE;
213: else eps->which = EPS_LARGEST_MAGNITUDE;
214: PetscFunctionReturn(0);
215: }
217: /*
218: EPSConvergedRelative - Checks convergence relative to the eigenvalue.
219: */
220: PetscErrorCode EPSConvergedRelative(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
221: {
222: PetscReal w;
224: w = SlepcAbsEigenvalue(eigr,eigi);
225: *errest = res/w;
226: PetscFunctionReturn(0);
227: }
229: /*
230: EPSConvergedAbsolute - Checks convergence absolutely.
231: */
232: PetscErrorCode EPSConvergedAbsolute(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
233: {
234: *errest = res;
235: PetscFunctionReturn(0);
236: }
238: /*
239: EPSConvergedNorm - Checks convergence relative to the eigenvalue and
240: the matrix norms.
241: */
242: PetscErrorCode EPSConvergedNorm(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
243: {
244: PetscReal w;
246: w = SlepcAbsEigenvalue(eigr,eigi);
247: *errest = res / (eps->nrma + w*eps->nrmb);
248: PetscFunctionReturn(0);
249: }
251: /*@C
252: EPSStoppingBasic - Default routine to determine whether the outer eigensolver
253: iteration must be stopped.
255: Collective on eps
257: Input Parameters:
258: + eps - eigensolver context obtained from EPSCreate()
259: . its - current number of iterations
260: . max_it - maximum number of iterations
261: . nconv - number of currently converged eigenpairs
262: . nev - number of requested eigenpairs
263: - ctx - context (not used here)
265: Output Parameter:
266: . reason - result of the stopping test
268: Notes:
269: A positive value of reason indicates that the iteration has finished successfully
270: (converged), and a negative value indicates an error condition (diverged). If
271: the iteration needs to be continued, reason must be set to EPS_CONVERGED_ITERATING
272: (zero).
274: EPSStoppingBasic() will stop if all requested eigenvalues are converged, or if
275: the maximum number of iterations has been reached.
277: Use EPSSetStoppingTest() to provide your own test instead of using this one.
279: Level: advanced
281: .seealso: EPSSetStoppingTest(), EPSConvergedReason, EPSGetConvergedReason()
282: @*/
283: PetscErrorCode EPSStoppingBasic(EPS eps,PetscInt its,PetscInt max_it,PetscInt nconv,PetscInt nev,EPSConvergedReason *reason,void *ctx)
284: {
285: *reason = EPS_CONVERGED_ITERATING;
286: if (nconv >= nev) {
287: PetscInfo(eps,"Linear eigensolver finished successfully: %" PetscInt_FMT " eigenpairs converged at iteration %" PetscInt_FMT "\n",nconv,its);
288: *reason = EPS_CONVERGED_TOL;
289: } else if (its >= max_it) {
290: *reason = EPS_DIVERGED_ITS;
291: PetscInfo(eps,"Linear eigensolver iteration reached maximum number of iterations (%" PetscInt_FMT ")\n",its);
292: }
293: PetscFunctionReturn(0);
294: }
296: /*
297: EPSComputeRitzVector - Computes the current Ritz vector.
299: Simple case (complex scalars or real scalars with Zi=NULL):
300: x = V*Zr (V is a basis of nv vectors, Zr has length nv)
302: Split case:
303: x = V*Zr y = V*Zi (Zr and Zi have length nv)
304: */
305: PetscErrorCode EPSComputeRitzVector(EPS eps,PetscScalar *Zr,PetscScalar *Zi,BV V,Vec x,Vec y)
306: {
307: PetscInt l,k;
308: PetscReal norm;
309: #if !defined(PETSC_USE_COMPLEX)
310: Vec z;
311: #endif
313: /* compute eigenvector */
314: BVGetActiveColumns(V,&l,&k);
315: BVSetActiveColumns(V,0,k);
316: BVMultVec(V,1.0,0.0,x,Zr);
318: /* purify eigenvector if necessary */
319: if (eps->purify) {
320: STApply(eps->st,x,y);
321: if (eps->ishermitian) BVNormVec(eps->V,y,NORM_2,&norm);
322: else VecNorm(y,NORM_2,&norm);
323: VecScale(y,1.0/norm);
324: VecCopy(y,x);
325: }
326: /* fix eigenvector if balancing is used */
327: if (!eps->ishermitian && eps->balance!=EPS_BALANCE_NONE && eps->D) VecPointwiseDivide(x,x,eps->D);
328: #if !defined(PETSC_USE_COMPLEX)
329: /* compute imaginary part of eigenvector */
330: if (Zi) {
331: BVMultVec(V,1.0,0.0,y,Zi);
332: if (eps->ispositive) {
333: BVCreateVec(V,&z);
334: STApply(eps->st,y,z);
335: VecNorm(z,NORM_2,&norm);
336: VecScale(z,1.0/norm);
337: VecCopy(z,y);
338: VecDestroy(&z);
339: }
340: if (eps->balance!=EPS_BALANCE_NONE && eps->D) VecPointwiseDivide(y,y,eps->D);
341: } else
342: #endif
343: VecSet(y,0.0);
345: /* normalize eigenvectors (when using balancing) */
346: if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
347: #if !defined(PETSC_USE_COMPLEX)
348: if (Zi) VecNormalizeComplex(x,y,PETSC_TRUE,NULL);
349: else
350: #endif
351: VecNormalize(x,NULL);
352: }
353: BVSetActiveColumns(V,l,k);
354: PetscFunctionReturn(0);
355: }
357: /*
358: EPSBuildBalance_Krylov - uses a Krylov subspace method to compute the
359: diagonal matrix to be applied for balancing in non-Hermitian problems.
360: */
361: PetscErrorCode EPSBuildBalance_Krylov(EPS eps)
362: {
363: Vec z,p,r;
364: PetscInt i,j;
365: PetscReal norma;
366: PetscScalar *pz,*pD;
367: const PetscScalar *pr,*pp;
368: PetscRandom rand;
370: EPSSetWorkVecs(eps,3);
371: BVGetRandomContext(eps->V,&rand);
372: r = eps->work[0];
373: p = eps->work[1];
374: z = eps->work[2];
375: VecSet(eps->D,1.0);
377: for (j=0;j<eps->balance_its;j++) {
379: /* Build a random vector of +-1's */
380: VecSetRandom(z,rand);
381: VecGetArray(z,&pz);
382: for (i=0;i<eps->nloc;i++) {
383: if (PetscRealPart(pz[i])<0.5) pz[i]=-1.0;
384: else pz[i]=1.0;
385: }
386: VecRestoreArray(z,&pz);
388: /* Compute p=DA(D\z) */
389: VecPointwiseDivide(r,z,eps->D);
390: STApply(eps->st,r,p);
391: VecPointwiseMult(p,p,eps->D);
392: if (eps->balance == EPS_BALANCE_TWOSIDE) {
393: if (j==0) {
394: /* Estimate the matrix inf-norm */
395: VecAbs(p);
396: VecMax(p,NULL,&norma);
397: }
398: /* Compute r=D\(A'Dz) */
399: VecPointwiseMult(z,z,eps->D);
400: STApplyHermitianTranspose(eps->st,z,r);
401: VecPointwiseDivide(r,r,eps->D);
402: }
404: /* Adjust values of D */
405: VecGetArrayRead(r,&pr);
406: VecGetArrayRead(p,&pp);
407: VecGetArray(eps->D,&pD);
408: for (i=0;i<eps->nloc;i++) {
409: if (eps->balance == EPS_BALANCE_TWOSIDE) {
410: if (PetscAbsScalar(pp[i])>eps->balance_cutoff*norma && pr[i]!=0.0)
411: pD[i] *= PetscSqrtReal(PetscAbsScalar(pr[i]/pp[i]));
412: } else {
413: if (pp[i]!=0.0) pD[i] /= PetscAbsScalar(pp[i]);
414: }
415: }
416: VecRestoreArrayRead(r,&pr);
417: VecRestoreArrayRead(p,&pp);
418: VecRestoreArray(eps->D,&pD);
419: }
420: PetscFunctionReturn(0);
421: }