Actual source code: solve.c
1: /*
2: EPS routines related to the solution process.
4: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5: SLEPc - Scalable Library for Eigenvalue Problem Computations
6: Copyright (c) 2002-2011, Universitat Politecnica de Valencia, Spain
8: This file is part of SLEPc.
9:
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 <private/epsimpl.h> /*I "slepceps.h" I*/
26: typedef struct {
27: /* old values of eps */
28: EPSWhich old_which;
29: PetscErrorCode (*old_which_func)(EPS,PetscScalar,PetscScalar,PetscScalar,PetscScalar, PetscInt*,void*);
30: void *old_which_ctx;
31: } EPSSortForSTData;
35: PetscErrorCode EPSSortForSTFunc(EPS eps,PetscScalar ar,PetscScalar ai,
36: PetscScalar br,PetscScalar bi,PetscInt *r,void *ctx)
37: {
38: EPSSortForSTData *data = (EPSSortForSTData*)ctx;
39: PetscErrorCode ierr;
42: /* Back-transform the harmonic values */
43: STBackTransform(eps->OP,1,&ar,&ai);
44: STBackTransform(eps->OP,1,&br,&bi);
46: /* Compare values using the user options for the eigenpairs selection */
47: if (data->old_which==EPS_ALL) eps->which = EPS_TARGET_MAGNITUDE;
48: else eps->which = data->old_which;
49: eps->which_func = data->old_which_func;
50: eps->which_ctx = data->old_which_ctx;
51: EPSCompareEigenvalues(eps,ar,ai,br,bi,r);
53: /* Restore the eps values */
54: eps->which = EPS_WHICH_USER;
55: eps->which_func = EPSSortForSTFunc;
56: eps->which_ctx = data;
57: return(0);
58: }
62: /*@
63: EPSSolve - Solves the eigensystem.
65: Collective on EPS
67: Input Parameter:
68: . eps - eigensolver context obtained from EPSCreate()
70: Options Database:
71: + -eps_view - print information about the solver used
72: . -eps_view_binary - save the matrices to the default binary file
73: - -eps_plot_eigs - plot computed eigenvalues
75: Level: beginner
77: .seealso: EPSCreate(), EPSSetUp(), EPSDestroy(), EPSSetTolerances()
78: @*/
79: PetscErrorCode EPSSolve(EPS eps)
80: {
82: PetscInt i;
83: PetscReal re,im;
84: PetscScalar dot;
85: PetscBool flg,isfold,iscayley,viewed=PETSC_FALSE;
86: PetscViewer viewer;
87: PetscDraw draw;
88: PetscDrawSP drawsp;
89: STMatMode matmode;
90: char filename[PETSC_MAX_PATH_LEN];
91: char view[10];
92: EPSSortForSTData data;
93: Mat A,B;
94: KSP ksp;
95: Vec w,x;
100: flg = PETSC_FALSE;
101: PetscOptionsGetBool(((PetscObject)eps)->prefix,"-eps_view_binary",&flg,PETSC_NULL);
102: if (flg) {
103: STGetOperators(eps->OP,&A,&B);
104: MatView(A,PETSC_VIEWER_BINARY_(((PetscObject)eps)->comm));
105: if (B) MatView(B,PETSC_VIEWER_BINARY_(((PetscObject)eps)->comm));
106: }
108: PetscOptionsGetString(((PetscObject)eps)->prefix,"-eps_view",view,10,&flg);
109: if (flg) {
110: PetscStrcmp(view,"before",&viewed);
111: if (viewed){
112: PetscViewer viewer;
113: PetscViewerASCIIGetStdout(((PetscObject)eps)->comm,&viewer);
114: EPSView(eps,viewer);
115: }
116: }
118: /* reset the convergence flag from the previous solves */
119: eps->reason = EPS_CONVERGED_ITERATING;
121: /* call setup */
122: if (!eps->setupcalled) { EPSSetUp(eps); }
123: eps->evecsavailable = PETSC_FALSE;
124: eps->nconv = 0;
125: eps->its = 0;
126: for (i=0;i<eps->ncv;i++) eps->eigr[i]=eps->eigi[i]=eps->errest[i]=0.0;
127: EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,eps->ncv);
129: PetscLogEventBegin(EPS_Solve,eps,eps->V[0],eps->V[0],0);
131: PetscTypeCompareAny((PetscObject)eps,&flg,EPSARPACK,EPSBLZPACK,EPSTRLAN,EPSBLOPEX,EPSPRIMME,"");
132: if (!flg) {
133: /* temporarily change which */
134: data.old_which = eps->which;
135: data.old_which_func = eps->which_func;
136: data.old_which_ctx = eps->which_ctx;
137: eps->which = EPS_WHICH_USER;
138: eps->which_func = EPSSortForSTFunc;
139: eps->which_ctx = &data;
140: }
142: /* call solver */
143: (*eps->ops->solve)(eps);
145: if (!flg) {
146: /* restore which */
147: eps->which = data.old_which;
148: eps->which_func = data.old_which_func;
149: eps->which_ctx = data.old_which_ctx;
150: }
152: STGetMatMode(eps->OP,&matmode);
153: if (matmode == ST_MATMODE_INPLACE && eps->ispositive) {
154: /* Purify eigenvectors before reverting operator */
155: (*eps->ops->computevectors)(eps);
156: }
157: STPostSolve(eps->OP);
158: PetscLogEventEnd(EPS_Solve,eps,eps->V[0],eps->V[0],0);
160: if (!eps->reason) {
161: SETERRQ(((PetscObject)eps)->comm,1,"Internal error, solver returned without setting converged reason");
162: }
164: /* Map eigenvalues back to the original problem, necessary in some
165: * spectral transformations */
166: if (eps->ops->backtransform) {
167: (*eps->ops->backtransform)(eps);
168: }
170: /* Adjust left eigenvectors in generalized problems: y = B^T y */
171: if (eps->isgeneralized && eps->leftvecs) {
172: STGetOperators(eps->OP,PETSC_NULL,&B);
173: KSPCreate(((PetscObject)eps)->comm,&ksp);
174: KSPSetOperators(ksp,B,B,DIFFERENT_NONZERO_PATTERN);
175: KSPSetFromOptions(ksp);
176: MatGetVecs(B,PETSC_NULL,&w);
177: for (i=0;i<eps->nconv;i++) {
178: VecCopy(eps->W[i],w);
179: KSPSolveTranspose(ksp,w,eps->W[i]);
180: }
181: KSPDestroy(&ksp);
182: VecDestroy(&w);
183: }
185: #if !defined(PETSC_USE_COMPLEX)
186: /* reorder conjugate eigenvalues (positive imaginary first) */
187: for (i=0; i<eps->nconv-1; i++) {
188: if (eps->eigi[i] != 0) {
189: if (eps->eigi[i] < 0) {
190: eps->eigi[i] = -eps->eigi[i];
191: eps->eigi[i+1] = -eps->eigi[i+1];
192: if (!eps->evecsavailable) {
193: /* the next correction only works with eigenvectors */
194: (*eps->ops->computevectors)(eps);
195: }
196: VecScale(eps->V[i+1],-1.0);
197: }
198: i++;
199: }
200: }
201: #endif
203: /* quick and dirty solution for FOLD: recompute eigenvalues as Rayleigh quotients */
204: PetscTypeCompare((PetscObject)eps->OP,STFOLD,&isfold);
205: if (isfold) {
206: STGetOperators(eps->OP,&A,&B);
207: MatGetVecs(A,&w,PETSC_NULL);
208: if (!eps->evecsavailable) { (*eps->ops->computevectors)(eps); }
209: for (i=0;i<eps->nconv;i++) {
210: x = eps->V[i];
211: MatMult(A,x,w);
212: VecDot(w,x,&eps->eigr[i]);
213: if (eps->isgeneralized) {
214: MatMult(B,x,w);
215: VecDot(w,x,&dot);
216: eps->eigr[i] /= dot;
217: }
218: }
219: VecDestroy(&w);
220: }
222: /* In the case of Cayley transform, eigenvectors need to be B-normalized */
223: PetscTypeCompare((PetscObject)eps->OP,STCAYLEY,&iscayley);
224: if (iscayley && eps->isgeneralized && eps->ishermitian) {
225: STGetOperators(eps->OP,PETSC_NULL,&B);
226: MatGetVecs(B,PETSC_NULL,&w);
227: if (!eps->evecsavailable) { (*eps->ops->computevectors)(eps); }
228: for (i=0;i<eps->nconv;i++) {
229: x = eps->V[i];
230: MatMult(B,x,w);
231: VecDot(w,x,&dot);
232: VecScale(x,1.0/PetscSqrtScalar(dot));
233: }
234: VecDestroy(&w);
235: }
237: /* sort eigenvalues according to eps->which parameter */
238: flg = (eps->which == EPS_ALL)? PETSC_TRUE: PETSC_FALSE;
239: if (flg) eps->which = EPS_SMALLEST_REAL;
240: EPSSortEigenvalues(eps,eps->nconv,eps->eigr,eps->eigi,eps->perm);
241: if (flg) eps->which = EPS_ALL;
243: if (!viewed) {
244: PetscOptionsGetString(((PetscObject)eps)->prefix,"-eps_view",filename,PETSC_MAX_PATH_LEN,&flg);
245: if (flg && !PetscPreLoadingOn) {
246: PetscViewerASCIIOpen(((PetscObject)eps)->comm,filename,&viewer);
247: EPSView(eps,viewer);
248: PetscViewerDestroy(&viewer);
249: }
250: }
252: flg = PETSC_FALSE;
253: PetscOptionsGetBool(((PetscObject)eps)->prefix,"-eps_plot_eigs",&flg,PETSC_NULL);
254: if (flg) {
255: PetscViewerDrawOpen(PETSC_COMM_SELF,0,"Computed Eigenvalues",
256: PETSC_DECIDE,PETSC_DECIDE,300,300,&viewer);
257: PetscViewerDrawGetDraw(viewer,0,&draw);
258: PetscDrawSPCreate(draw,1,&drawsp);
259: for (i=0;i<eps->nconv;i++) {
260: #if defined(PETSC_USE_COMPLEX)
261: re = PetscRealPart(eps->eigr[i]);
262: im = PetscImaginaryPart(eps->eigi[i]);
263: #else
264: re = eps->eigr[i];
265: im = eps->eigi[i];
266: #endif
267: PetscDrawSPAddPoint(drawsp,&re,&im);
268: }
269: PetscDrawSPDraw(drawsp);
270: PetscDrawSPDestroy(&drawsp);
271: PetscViewerDestroy(&viewer);
272: }
274: /* Remove the initial subspaces */
275: eps->nini = 0;
276: eps->ninil = 0;
277: return(0);
278: }
282: /*@
283: EPSGetIterationNumber - Gets the current iteration number. If the
284: call to EPSSolve() is complete, then it returns the number of iterations
285: carried out by the solution method.
286:
287: Not Collective
289: Input Parameter:
290: . eps - the eigensolver context
292: Output Parameter:
293: . its - number of iterations
295: Level: intermediate
297: Note:
298: During the i-th iteration this call returns i-1. If EPSSolve() is
299: complete, then parameter "its" contains either the iteration number at
300: which convergence was successfully reached, or failure was detected.
301: Call EPSGetConvergedReason() to determine if the solver converged or
302: failed and why.
304: .seealso: EPSGetConvergedReason(), EPSSetTolerances()
305: @*/
306: PetscErrorCode EPSGetIterationNumber(EPS eps,PetscInt *its)
307: {
311: *its = eps->its;
312: return(0);
313: }
317: /*@
318: EPSGetOperationCounters - Gets the total number of operator applications,
319: inner product operations and linear iterations used by the ST object
320: during the last EPSSolve() call.
322: Not Collective
324: Input Parameter:
325: . eps - EPS context
327: Output Parameter:
328: + ops - number of operator applications
329: . dots - number of inner product operations
330: - lits - number of linear iterations
332: Notes:
333: When the eigensolver algorithm invokes STApply() then a linear system
334: must be solved (except in the case of standard eigenproblems and shift
335: transformation). The number of iterations required in this solve is
336: accumulated into a counter whose value is returned by this function.
338: These counters are reset to zero at each successive call to EPSSolve().
340: Level: intermediate
342: @*/
343: PetscErrorCode EPSGetOperationCounters(EPS eps,PetscInt* ops,PetscInt* dots,PetscInt* lits)
344: {
349: if (!eps->OP) { EPSGetST(eps,&eps->OP); }
350: STGetOperationCounters(eps->OP,ops,lits);
351: if (dots) {
352: if (!eps->ip) { EPSGetIP(eps,&eps->ip); }
353: IPGetOperationCounters(eps->ip,dots);
354: }
355: return(0);
356: }
360: /*@
361: EPSGetConverged - Gets the number of converged eigenpairs.
363: Not Collective
365: Input Parameter:
366: . eps - the eigensolver context
367:
368: Output Parameter:
369: . nconv - number of converged eigenpairs
371: Note:
372: This function should be called after EPSSolve() has finished.
374: Level: beginner
376: .seealso: EPSSetDimensions(), EPSSolve()
377: @*/
378: PetscErrorCode EPSGetConverged(EPS eps,PetscInt *nconv)
379: {
383: *nconv = eps->nconv;
384: return(0);
385: }
390: /*@C
391: EPSGetConvergedReason - Gets the reason why the EPSSolve() iteration was
392: stopped.
394: Not Collective
396: Input Parameter:
397: . eps - the eigensolver context
399: Output Parameter:
400: . reason - negative value indicates diverged, positive value converged
402: Possible values for reason:
403: + EPS_CONVERGED_TOL - converged up to tolerance
404: . EPS_DIVERGED_ITS - required more than its to reach convergence
405: - EPS_DIVERGED_BREAKDOWN - generic breakdown in method
407: Note:
408: Can only be called after the call to EPSSolve() is complete.
410: Level: intermediate
412: .seealso: EPSSetTolerances(), EPSSolve(), EPSConvergedReason
413: @*/
414: PetscErrorCode EPSGetConvergedReason(EPS eps,EPSConvergedReason *reason)
415: {
419: *reason = eps->reason;
420: return(0);
421: }
425: /*@
426: EPSGetInvariantSubspace - Gets an orthonormal basis of the computed invariant
427: subspace.
429: Not Collective, but vectors are shared by all processors that share the EPS
431: Input Parameter:
432: . eps - the eigensolver context
433:
434: Output Parameter:
435: . v - an array of vectors
437: Notes:
438: This function should be called after EPSSolve() has finished.
440: The user should provide in v an array of nconv vectors, where nconv is
441: the value returned by EPSGetConverged().
443: The first k vectors returned in v span an invariant subspace associated
444: with the first k computed eigenvalues (note that this is not true if the
445: k-th eigenvalue is complex and matrix A is real; in this case the first
446: k+1 vectors should be used). An invariant subspace X of A satisfies Ax
447: in X for all x in X (a similar definition applies for generalized
448: eigenproblems).
450: Level: intermediate
452: .seealso: EPSGetEigenpair(), EPSGetConverged(), EPSSolve(), EPSGetInvariantSubspaceLeft()
453: @*/
454: PetscErrorCode EPSGetInvariantSubspace(EPS eps,Vec *v)
455: {
457: PetscInt i;
463: if (!eps->V) {
464: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
465: }
466: if (!eps->ishermitian && eps->evecsavailable) {
467: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSGetInvariantSubspace must be called before EPSGetEigenpair,EPSGetEigenvector,EPSComputeRelativeError or EPSComputeResidualNorm");
468: }
469: if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
470: for (i=0;i<eps->nconv;i++) {
471: VecPointwiseDivide(v[i],eps->V[i],eps->D);
472: VecNormalize(v[i],PETSC_NULL);
473: }
474: }
475: else {
476: for (i=0;i<eps->nconv;i++) {
477: VecCopy(eps->V[i],v[i]);
478: }
479: }
480: return(0);
481: }
485: /*@
486: EPSGetInvariantSubspaceLeft - Gets an orthonormal basis of the computed left
487: invariant subspace (only available in two-sided eigensolvers).
489: Not Collective, but vectors are shared by all processors that share the EPS
491: Input Parameter:
492: . eps - the eigensolver context
493:
494: Output Parameter:
495: . v - an array of vectors
497: Notes:
498: This function should be called after EPSSolve() has finished.
500: The user should provide in v an array of nconv vectors, where nconv is
501: the value returned by EPSGetConverged().
503: The first k vectors returned in v span a left invariant subspace associated
504: with the first k computed eigenvalues (note that this is not true if the
505: k-th eigenvalue is complex and matrix A is real; in this case the first
506: k+1 vectors should be used). A left invariant subspace Y of A satisfies y'A
507: in Y for all y in Y (a similar definition applies for generalized
508: eigenproblems).
510: Level: intermediate
512: .seealso: EPSGetEigenpair(), EPSGetConverged(), EPSSolve(), EPSGetInvariantSubspace
513: @*/
514: PetscErrorCode EPSGetInvariantSubspaceLeft(EPS eps,Vec *v)
515: {
517: PetscInt i;
523: if (!eps->leftvecs) {
524: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
525: }
526: if (!eps->W) {
527: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
528: }
529: if (!eps->ishermitian && eps->evecsavailable) {
530: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSGetInvariantSubspaceLeft must be called before EPSGetEigenpairLeft,EPSComputeRelativeErrorLeft or EPSComputeResidualNormLeft");
531: }
532: for (i=0;i<eps->nconv;i++) {
533: VecCopy(eps->W[i],v[i]);
534: }
535: return(0);
536: }
540: /*@
541: EPSGetEigenpair - Gets the i-th solution of the eigenproblem as computed by
542: EPSSolve(). The solution consists in both the eigenvalue and the eigenvector.
544: Not Collective, but vectors are shared by all processors that share the EPS
546: Input Parameters:
547: + eps - eigensolver context
548: - i - index of the solution
550: Output Parameters:
551: + eigr - real part of eigenvalue
552: . eigi - imaginary part of eigenvalue
553: . Vr - real part of eigenvector
554: - Vi - imaginary part of eigenvector
556: Notes:
557: If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is
558: configured with complex scalars the eigenvalue is stored
559: directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is
560: set to zero).
562: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
563: Eigenpairs are indexed according to the ordering criterion established
564: with EPSSetWhichEigenpairs().
566: The 2-norm of the eigenvector is one unless the problem is generalized
567: Hermitian. In this case the eigenvector is normalized with respect to the
568: norm defined by the B matrix.
570: Level: beginner
572: .seealso: EPSGetEigenvalue(), EPSGetEigenvector(), EPSGetEigenvectorLeft(), EPSSolve(),
573: EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetInvariantSubspace()
574: @*/
575: PetscErrorCode EPSGetEigenpair(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
576: {
581: if (!eps->eigr || !eps->eigi || !eps->V) {
582: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
583: }
584: if (i<0 || i>=eps->nconv) {
585: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
586: }
587: EPSGetEigenvalue(eps,i,eigr,eigi);
588: EPSGetEigenvector(eps,i,Vr,Vi);
589: return(0);
590: }
594: /*@
595: EPSGetEigenvalue - Gets the i-th eigenvalue as computed by EPSSolve().
597: Not Collective
599: Input Parameters:
600: + eps - eigensolver context
601: - i - index of the solution
603: Output Parameters:
604: + eigr - real part of eigenvalue
605: - eigi - imaginary part of eigenvalue
607: Notes:
608: If the eigenvalue is real, then eigi is set to zero. If PETSc is
609: configured with complex scalars the eigenvalue is stored
610: directly in eigr (eigi is set to zero).
612: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
613: Eigenpairs are indexed according to the ordering criterion established
614: with EPSSetWhichEigenpairs().
616: Level: beginner
618: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(),
619: EPSGetEigenpair()
620: @*/
621: PetscErrorCode EPSGetEigenvalue(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi)
622: {
623: PetscInt k;
627: if (!eps->eigr || !eps->eigi) {
628: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
629: }
630: if (i<0 || i>=eps->nconv) {
631: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
632: }
633: if (!eps->perm) k = i;
634: else k = eps->perm[i];
635: #if defined(PETSC_USE_COMPLEX)
636: if (eigr) *eigr = eps->eigr[k];
637: if (eigi) *eigi = 0;
638: #else
639: if (eigr) *eigr = eps->eigr[k];
640: if (eigi) *eigi = eps->eigi[k];
641: #endif
642: return(0);
643: }
647: /*@
648: EPSGetEigenvector - Gets the i-th right eigenvector as computed by EPSSolve().
650: Not Collective, but vectors are shared by all processors that share the EPS
652: Input Parameters:
653: + eps - eigensolver context
654: - i - index of the solution
656: Output Parameters:
657: + Vr - real part of eigenvector
658: - Vi - imaginary part of eigenvector
660: Notes:
661: If the corresponding eigenvalue is real, then Vi is set to zero. If PETSc is
662: configured with complex scalars the eigenvector is stored
663: directly in Vr (Vi is set to zero).
665: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
666: Eigenpairs are indexed according to the ordering criterion established
667: with EPSSetWhichEigenpairs().
669: The 2-norm of the eigenvector is one unless the problem is generalized
670: Hermitian. In this case the eigenvector is normalized with respect to the
671: norm defined by the B matrix.
673: Level: beginner
675: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(),
676: EPSGetEigenpair(), EPSGetEigenvectorLeft()
677: @*/
678: PetscErrorCode EPSGetEigenvector(EPS eps,PetscInt i,Vec Vr,Vec Vi)
679: {
681: PetscInt k;
687: if (!eps->V) {
688: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
689: }
690: if (i<0 || i>=eps->nconv) {
691: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
692: }
693: if (!eps->evecsavailable && (Vr || Vi)) {
694: (*eps->ops->computevectors)(eps);
695: }
696: if (!eps->perm) k = i;
697: else k = eps->perm[i];
698: #if defined(PETSC_USE_COMPLEX)
699: if (Vr) { VecCopy(eps->V[k],Vr); }
700: if (Vi) { VecSet(Vi,0.0); }
701: #else
702: if (eps->eigi[k] > 0) { /* first value of conjugate pair */
703: if (Vr) { VecCopy(eps->V[k],Vr); }
704: if (Vi) { VecCopy(eps->V[k+1],Vi); }
705: } else if (eps->eigi[k] < 0) { /* second value of conjugate pair */
706: if (Vr) { VecCopy(eps->V[k-1],Vr); }
707: if (Vi) {
708: VecCopy(eps->V[k],Vi);
709: VecScale(Vi,-1.0);
710: }
711: } else { /* real eigenvalue */
712: if (Vr) { VecCopy(eps->V[k],Vr); }
713: if (Vi) { VecSet(Vi,0.0); }
714: }
715: #endif
716: return(0);
717: }
721: /*@
722: EPSGetEigenvectorLeft - Gets the i-th left eigenvector as computed by EPSSolve()
723: (only available in two-sided eigensolvers).
725: Not Collective, but vectors are shared by all processors that share the EPS
727: Input Parameters:
728: + eps - eigensolver context
729: - i - index of the solution
731: Output Parameters:
732: + Wr - real part of eigenvector
733: - Wi - imaginary part of eigenvector
735: Notes:
736: If the corresponding eigenvalue is real, then Wi is set to zero. If PETSc is
737: configured with complex scalars the eigenvector is stored
738: directly in Wr (Wi is set to zero).
740: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
741: Eigenpairs are indexed according to the ordering criterion established
742: with EPSSetWhichEigenpairs().
744: Level: beginner
746: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(),
747: EPSGetEigenpair(), EPSGetEigenvector()
748: @*/
749: PetscErrorCode EPSGetEigenvectorLeft(EPS eps,PetscInt i,Vec Wr,Vec Wi)
750: {
752: PetscInt k;
758: if (!eps->leftvecs) {
759: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
760: }
761: if (!eps->W) {
762: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
763: }
764: if (i<0 || i>=eps->nconv) {
765: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
766: }
767: if (!eps->evecsavailable && (Wr || Wi)) {
768: (*eps->ops->computevectors)(eps);
769: }
770: if (!eps->perm) k = i;
771: else k = eps->perm[i];
772: #if defined(PETSC_USE_COMPLEX)
773: if (Wr) { VecCopy(eps->W[k],Wr); }
774: if (Wi) { VecSet(Wi,0.0); }
775: #else
776: if (eps->eigi[k] > 0) { /* first value of conjugate pair */
777: if (Wr) { VecCopy(eps->W[k],Wr); }
778: if (Wi) { VecCopy(eps->W[k+1],Wi); }
779: } else if (eps->eigi[k] < 0) { /* second value of conjugate pair */
780: if (Wr) { VecCopy(eps->W[k-1],Wr); }
781: if (Wi) {
782: VecCopy(eps->W[k],Wi);
783: VecScale(Wi,-1.0);
784: }
785: } else { /* real eigenvalue */
786: if (Wr) { VecCopy(eps->W[k],Wr); }
787: if (Wi) { VecSet(Wi,0.0); }
788: }
789: #endif
790: return(0);
791: }
795: /*@
796: EPSGetErrorEstimate - Returns the error estimate associated to the i-th
797: computed eigenpair.
799: Not Collective
801: Input Parameter:
802: + eps - eigensolver context
803: - i - index of eigenpair
805: Output Parameter:
806: . errest - the error estimate
808: Notes:
809: This is the error estimate used internally by the eigensolver. The actual
810: error bound can be computed with EPSComputeRelativeError(). See also the users
811: manual for details.
813: Level: advanced
815: .seealso: EPSComputeRelativeError()
816: @*/
817: PetscErrorCode EPSGetErrorEstimate(EPS eps,PetscInt i,PetscReal *errest)
818: {
822: if (!eps->eigr || !eps->eigi) {
823: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
824: }
825: if (i<0 || i>=eps->nconv) {
826: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
827: }
828: if (eps->perm) i = eps->perm[i];
829: if (errest) *errest = eps->errest[i];
830: return(0);
831: }
835: /*@
836: EPSGetErrorEstimateLeft - Returns the left error estimate associated to the i-th
837: computed eigenpair (only available in two-sided eigensolvers).
839: Not Collective
841: Input Parameter:
842: + eps - eigensolver context
843: - i - index of eigenpair
845: Output Parameter:
846: . errest - the left error estimate
848: Notes:
849: This is the error estimate used internally by the eigensolver. The actual
850: error bound can be computed with EPSComputeRelativeErrorLeft(). See also the users
851: manual for details.
853: Level: advanced
855: .seealso: EPSComputeRelativeErrorLeft()
856: @*/
857: PetscErrorCode EPSGetErrorEstimateLeft(EPS eps,PetscInt i,PetscReal *errest)
858: {
862: if (!eps->eigr || !eps->eigi) {
863: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
864: }
865: if (!eps->leftvecs) {
866: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
867: }
868: if (i<0 || i>=eps->nconv) {
869: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
870: }
871: if (eps->perm) i = eps->perm[i];
872: if (errest) *errest = eps->errest_left[i];
873: return(0);
874: }
878: /*
879: EPSComputeResidualNorm_Private - Computes the norm of the residual vector
880: associated with an eigenpair.
881: */
882: PetscErrorCode EPSComputeResidualNorm_Private(EPS eps,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *norm)
883: {
885: Vec u,w;
886: Mat A,B;
887: #if !defined(PETSC_USE_COMPLEX)
888: Vec v;
889: PetscReal ni,nr;
890: #endif
891:
893: STGetOperators(eps->OP,&A,&B);
894: VecDuplicate(eps->V[0],&u);
895: VecDuplicate(eps->V[0],&w);
896:
897: #if !defined(PETSC_USE_COMPLEX)
898: if (ki == 0 ||
899: PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
900: #endif
901: MatMult(A,xr,u); /* u=A*x */
902: if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
903: if (eps->isgeneralized) { MatMult(B,xr,w); }
904: else { VecCopy(xr,w); } /* w=B*x */
905: VecAXPY(u,-kr,w); /* u=A*x-k*B*x */
906: }
907: VecNorm(u,NORM_2,norm);
908: #if !defined(PETSC_USE_COMPLEX)
909: } else {
910: VecDuplicate(eps->V[0],&v);
911: MatMult(A,xr,u); /* u=A*xr */
912: if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
913: if (eps->isgeneralized) { MatMult(B,xr,v); }
914: else { VecCopy(xr,v); } /* v=B*xr */
915: VecAXPY(u,-kr,v); /* u=A*xr-kr*B*xr */
916: if (eps->isgeneralized) { MatMult(B,xi,w); }
917: else { VecCopy(xi,w); } /* w=B*xi */
918: VecAXPY(u,ki,w); /* u=A*xr-kr*B*xr+ki*B*xi */
919: }
920: VecNorm(u,NORM_2,&nr);
921: MatMult(A,xi,u); /* u=A*xi */
922: if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
923: VecAXPY(u,-kr,w); /* u=A*xi-kr*B*xi */
924: VecAXPY(u,-ki,v); /* u=A*xi-kr*B*xi-ki*B*xr */
925: }
926: VecNorm(u,NORM_2,&ni);
927: *norm = SlepcAbsEigenvalue(nr,ni);
928: VecDestroy(&v);
929: }
930: #endif
932: VecDestroy(&w);
933: VecDestroy(&u);
934: return(0);
935: }
939: /*@
940: EPSComputeResidualNorm - Computes the norm of the residual vector associated with
941: the i-th computed eigenpair.
943: Collective on EPS
945: Input Parameter:
946: . eps - the eigensolver context
947: . i - the solution index
949: Output Parameter:
950: . norm - the residual norm, computed as ||Ax-kBx||_2 where k is the
951: eigenvalue and x is the eigenvector.
952: If k=0 then the residual norm is computed as ||Ax||_2.
954: Notes:
955: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
956: Eigenpairs are indexed according to the ordering criterion established
957: with EPSSetWhichEigenpairs().
959: Level: beginner
961: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs()
962: @*/
963: PetscErrorCode EPSComputeResidualNorm(EPS eps,PetscInt i,PetscReal *norm)
964: {
966: Vec xr,xi;
967: PetscScalar kr,ki;
968:
973: VecDuplicate(eps->V[0],&xr);
974: VecDuplicate(eps->V[0],&xi);
975: EPSGetEigenpair(eps,i,&kr,&ki,xr,xi);
976: EPSComputeResidualNorm_Private(eps,kr,ki,xr,xi,norm);
977: VecDestroy(&xr);
978: VecDestroy(&xi);
979: return(0);
980: }
984: /*@
985: EPSComputeResidualNormLeft - Computes the norm of the residual vector associated with
986: the i-th computed left eigenvector (only available in two-sided eigensolvers).
988: Collective on EPS
990: Input Parameter:
991: . eps - the eigensolver context
992: . i - the solution index
994: Output Parameter:
995: . norm - the residual norm, computed as ||y'A-ky'B||_2 where k is the
996: eigenvalue and y is the left eigenvector.
997: If k=0 then the residual norm is computed as ||y'A||_2.
999: Notes:
1000: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
1001: Eigenpairs are indexed according to the ordering criterion established
1002: with EPSSetWhichEigenpairs().
1004: Level: beginner
1006: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs()
1007: @*/
1008: PetscErrorCode EPSComputeResidualNormLeft(EPS eps,PetscInt i,PetscReal *norm)
1009: {
1011: Vec u,v,w,xr,xi;
1012: Mat A,B;
1013: PetscScalar kr,ki;
1014: #if !defined(PETSC_USE_COMPLEX)
1015: PetscReal ni,nr;
1016: #endif
1017:
1022: if (!eps->leftvecs) {
1023: SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
1024: }
1025: STGetOperators(eps->OP,&A,&B);
1026: VecDuplicate(eps->W[0],&u);
1027: VecDuplicate(eps->W[0],&v);
1028: VecDuplicate(eps->W[0],&w);
1029: VecDuplicate(eps->W[0],&xr);
1030: VecDuplicate(eps->W[0],&xi);
1031: EPSGetEigenvalue(eps,i,&kr,&ki);
1032: EPSGetEigenvectorLeft(eps,i,xr,xi);
1034: #if !defined(PETSC_USE_COMPLEX)
1035: if (ki == 0 ||
1036: PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
1037: #endif
1038: MatMultTranspose(A,xr,u); /* u=A'*x */
1039: if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
1040: if (eps->isgeneralized) { MatMultTranspose(B,xr,w); }
1041: else { VecCopy(xr,w); } /* w=B'*x */
1042: VecAXPY(u,-kr,w); /* u=A'*x-k*B'*x */
1043: }
1044: VecNorm(u,NORM_2,norm);
1045: #if !defined(PETSC_USE_COMPLEX)
1046: } else {
1047: MatMultTranspose(A,xr,u); /* u=A'*xr */
1048: if (eps->isgeneralized) { MatMultTranspose(B,xr,v); }
1049: else { VecCopy(xr,v); } /* v=B'*xr */
1050: VecAXPY(u,-kr,v); /* u=A'*xr-kr*B'*xr */
1051: if (eps->isgeneralized) { MatMultTranspose(B,xi,w); }
1052: else { VecCopy(xi,w); } /* w=B'*xi */
1053: VecAXPY(u,ki,w); /* u=A'*xr-kr*B'*xr+ki*B'*xi */
1054: VecNorm(u,NORM_2,&nr);
1055: MatMultTranspose(A,xi,u); /* u=A'*xi */
1056: VecAXPY(u,-kr,w); /* u=A'*xi-kr*B'*xi */
1057: VecAXPY(u,-ki,v); /* u=A'*xi-kr*B'*xi-ki*B'*xr */
1058: VecNorm(u,NORM_2,&ni);
1059: *norm = SlepcAbsEigenvalue(nr,ni);
1060: }
1061: #endif
1063: VecDestroy(&w);
1064: VecDestroy(&v);
1065: VecDestroy(&u);
1066: VecDestroy(&xr);
1067: VecDestroy(&xi);
1068: return(0);
1069: }
1073: /*
1074: EPSComputeRelativeError_Private - Computes the relative error bound
1075: associated with an eigenpair.
1076: */
1077: PetscErrorCode EPSComputeRelativeError_Private(EPS eps,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *error)
1078: {
1080: PetscReal norm,er;
1081: #if !defined(PETSC_USE_COMPLEX)
1082: PetscReal ei;
1083: #endif
1084:
1086: EPSComputeResidualNorm_Private(eps,kr,ki,xr,xi,&norm);
1088: #if !defined(PETSC_USE_COMPLEX)
1089: if (ki == 0) {
1090: #endif
1091: VecNorm(xr,NORM_2,&er);
1092: #if !defined(PETSC_USE_COMPLEX)
1093: } else {
1094: VecNorm(xr,NORM_2,&er);
1095: VecNorm(xi,NORM_2,&ei);
1096: er = SlepcAbsEigenvalue(er,ei);
1097: }
1098: #endif
1099: (*eps->conv_func)(eps,kr,ki,norm/er,error,eps->conv_ctx);
1100: return(0);
1101: }
1105: /*@
1106: EPSComputeRelativeError - Computes the relative error bound associated
1107: with the i-th computed eigenpair.
1109: Collective on EPS
1111: Input Parameter:
1112: . eps - the eigensolver context
1113: . i - the solution index
1115: Output Parameter:
1116: . error - the relative error bound, computed as ||Ax-kBx||_2/||kx||_2 where
1117: k is the eigenvalue and x is the eigenvector.
1118: If k=0 the relative error is computed as ||Ax||_2/||x||_2.
1120: Level: beginner
1122: .seealso: EPSSolve(), EPSComputeResidualNorm(), EPSGetErrorEstimate()
1123: @*/
1124: PetscErrorCode EPSComputeRelativeError(EPS eps,PetscInt i,PetscReal *error)
1125: {
1127: Vec xr,xi;
1128: PetscScalar kr,ki;
1129:
1134: VecDuplicate(eps->V[0],&xr);
1135: VecDuplicate(eps->V[0],&xi);
1136: EPSGetEigenpair(eps,i,&kr,&ki,xr,xi);
1137: EPSComputeRelativeError_Private(eps,kr,ki,xr,xi,error);
1138: VecDestroy(&xr);
1139: VecDestroy(&xi);
1140: return(0);
1141: }
1145: /*@
1146: EPSComputeRelativeErrorLeft - Computes the relative error bound associated
1147: with the i-th computed eigenvalue and left eigenvector (only available in
1148: two-sided eigensolvers).
1150: Collective on EPS
1152: Input Parameter:
1153: . eps - the eigensolver context
1154: . i - the solution index
1156: Output Parameter:
1157: . error - the relative error bound, computed as ||y'A-ky'B||_2/||ky||_2 where
1158: k is the eigenvalue and y is the left eigenvector.
1159: If k=0 the relative error is computed as ||y'A||_2/||y||_2.
1161: Level: beginner
1163: .seealso: EPSSolve(), EPSComputeResidualNormLeft(), EPSGetErrorEstimateLeft()
1164: @*/
1165: PetscErrorCode EPSComputeRelativeErrorLeft(EPS eps,PetscInt i,PetscReal *error)
1166: {
1168: Vec xr,xi;
1169: PetscScalar kr,ki;
1170: PetscReal norm,er;
1171: #if !defined(PETSC_USE_COMPLEX)
1172: Vec u;
1173: PetscReal ei;
1174: #endif
1175:
1178: EPSComputeResidualNormLeft(eps,i,&norm);
1181: VecDuplicate(eps->W[0],&xr);
1182: VecDuplicate(eps->W[0],&xi);
1183: EPSGetEigenvalue(eps,i,&kr,&ki);
1184: EPSGetEigenvectorLeft(eps,i,xr,xi);
1186: #if !defined(PETSC_USE_COMPLEX)
1187: if (ki == 0 ||
1188: PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
1189: #endif
1190: VecNorm(xr,NORM_2,&er);
1191: if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
1192: *error = norm / (PetscAbsScalar(kr) * er);
1193: } else {
1194: *error = norm / er;
1195: }
1196: #if !defined(PETSC_USE_COMPLEX)
1197: } else {
1198: VecDuplicate(xi,&u);
1199: VecCopy(xi,u);
1200: VecAXPBY(u,kr,-ki,xr);
1201: VecNorm(u,NORM_2,&er);
1202: VecAXPBY(xi,kr,ki,xr);
1203: VecNorm(xi,NORM_2,&ei);
1204: VecDestroy(&u);
1205: *error = norm / SlepcAbsEigenvalue(er,ei);
1206: }
1207: #endif
1208:
1209: VecDestroy(&xr);
1210: VecDestroy(&xi);
1211: return(0);
1212: }
1214: #define SWAP(a,b,t) {t=a;a=b;b=t;}
1218: /*@
1219: EPSSortEigenvalues - Sorts a list of eigenvalues according to the criterion
1220: specified via EPSSetWhichEigenpairs().
1222: Not Collective
1224: Input Parameters:
1225: + eps - the eigensolver context
1226: . n - number of eigenvalues in the list
1227: . eigr - pointer to the array containing the eigenvalues
1228: - eigi - imaginary part of the eigenvalues (only when using real numbers)
1230: Output Parameter:
1231: . perm - resulting permutation
1233: Note:
1234: The result is a list of indices in the original eigenvalue array
1235: corresponding to the first nev eigenvalues sorted in the specified
1236: criterion.
1238: Level: developer
1240: .seealso: EPSSortEigenvaluesReal(), EPSSetWhichEigenpairs()
1241: @*/
1242: PetscErrorCode EPSSortEigenvalues(EPS eps,PetscInt n,PetscScalar *eigr,PetscScalar *eigi,PetscInt *perm)
1243: {
1245: PetscScalar re,im;
1246: PetscInt i,j,result,tmp;
1253: for (i=0; i<n; i++) { perm[i] = i; }
1254: /* insertion sort */
1255: for (i=n-1; i>=0; i--) {
1256: re = eigr[perm[i]];
1257: im = eigi[perm[i]];
1258: j = i + 1;
1259: #if !defined(PETSC_USE_COMPLEX)
1260: if (im != 0) {
1261: /* complex eigenvalue */
1262: i--;
1263: im = eigi[perm[i]];
1264: }
1265: #endif
1266: while (j<n) {
1267: EPSCompareEigenvalues(eps,re,im,eigr[perm[j]],eigi[perm[j]],&result);
1268: if (result < 0) break;
1269: #if !defined(PETSC_USE_COMPLEX)
1270: /* keep together every complex conjugated eigenpair */
1271: if (im == 0) {
1272: if (eigi[perm[j]] == 0) {
1273: #endif
1274: tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = tmp;
1275: j++;
1276: #if !defined(PETSC_USE_COMPLEX)
1277: } else {
1278: tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = perm[j+1]; perm[j+1] = tmp;
1279: j+=2;
1280: }
1281: } else {
1282: if (eigi[perm[j]] == 0) {
1283: tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = perm[j-1]; perm[j-1] = tmp;
1284: j++;
1285: } else {
1286: tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = tmp;
1287: tmp = perm[j-1]; perm[j-1] = perm[j+1]; perm[j+1] = tmp;
1288: j+=2;
1289: }
1290: }
1291: #endif
1292: }
1293: }
1294: return(0);
1295: }
1299: /*@
1300: EPSSortEigenvaluesReal - Sorts a list of eigenvalues according to a certain
1301: criterion (version for real eigenvalues only).
1303: Not Collective
1305: Input Parameters:
1306: + eps - the eigensolver context
1307: . n - number of eigenvalue in the list
1308: - eig - pointer to the array containing the eigenvalues (real)
1310: Output Parameter:
1311: . perm - resulting permutation
1313: Note:
1314: The result is a list of indices in the original eigenvalue array
1315: corresponding to the first nev eigenvalues sorted in the specified
1316: criterion.
1318: Level: developer
1320: .seealso: EPSSortEigenvalues(), EPSSetWhichEigenpairs(), EPSCompareEigenvalues()
1321: @*/
1322: PetscErrorCode EPSSortEigenvaluesReal(EPS eps,PetscInt n,PetscReal *eig,PetscInt *perm)
1323: {
1325: PetscScalar re;
1326: PetscInt i,j,result,tmp;
1332: for (i=0; i<n; i++) { perm[i] = i; }
1333: /* insertion sort */
1334: for (i=1; i<n; i++) {
1335: re = eig[perm[i]];
1336: j = i-1;
1337: EPSCompareEigenvalues(eps,re,0.0,eig[perm[j]],0.0,&result);
1338: while (result<=0 && j>=0) {
1339: tmp = perm[j]; perm[j] = perm[j+1]; perm[j+1] = tmp; j--;
1340: if (j>=0) {
1341: EPSCompareEigenvalues(eps,re,0.0,eig[perm[j]],0.0,&result);
1342: }
1343: }
1344: }
1345: return(0);
1346: }
1350: /*@
1351: EPSCompareEigenvalues - Compares two (possibly complex) eigenvalues according
1352: to a certain criterion.
1354: Not Collective
1356: Input Parameters:
1357: + eps - the eigensolver context
1358: . ar - real part of the 1st eigenvalue
1359: . ai - imaginary part of the 1st eigenvalue
1360: . br - real part of the 2nd eigenvalue
1361: - bi - imaginary part of the 2nd eigenvalue
1363: Output Parameter:
1364: . res - result of comparison
1366: Notes:
1367: The returning parameter 'res' can be:
1368: + negative - if the 1st eigenvalue is preferred to the 2st one
1369: . zero - if both eigenvalues are equally preferred
1370: - positive - if the 2st eigenvalue is preferred to the 1st one
1372: The criterion of comparison is related to the 'which' parameter set with
1373: EPSSetWhichEigenpairs().
1375: Level: developer
1377: .seealso: EPSSortEigenvalues(), EPSSetWhichEigenpairs()
1378: @*/
1379: PetscErrorCode EPSCompareEigenvalues(EPS eps,PetscScalar ar,PetscScalar ai,PetscScalar br,PetscScalar bi,PetscInt *result)
1380: {
1382: PetscReal a,b;
1387: switch(eps->which) {
1388: case EPS_WHICH_USER:
1389: if (!eps->which_func) SETERRQ(((PetscObject)eps)->comm,1,"Undefined eigenvalue comparison function");
1390: (*eps->which_func)(eps,ar,ai,br,bi,result,eps->which_ctx);
1391: a = 0.0; b = 0.0;
1392: break;
1393: case EPS_LARGEST_MAGNITUDE:
1394: case EPS_SMALLEST_MAGNITUDE:
1395: a = SlepcAbsEigenvalue(ar,ai);
1396: b = SlepcAbsEigenvalue(br,bi);
1397: break;
1398: case EPS_LARGEST_REAL:
1399: case EPS_SMALLEST_REAL:
1400: a = PetscRealPart(ar);
1401: b = PetscRealPart(br);
1402: break;
1403: case EPS_LARGEST_IMAGINARY:
1404: case EPS_SMALLEST_IMAGINARY:
1405: #if defined(PETSC_USE_COMPLEX)
1406: a = PetscImaginaryPart(ar);
1407: b = PetscImaginaryPart(br);
1408: #else
1409: a = PetscAbsReal(ai);
1410: b = PetscAbsReal(bi);
1411: #endif
1412: break;
1413: case EPS_TARGET_MAGNITUDE:
1414: /* complex target only allowed if scalartype=complex */
1415: a = SlepcAbsEigenvalue(ar-eps->target,ai);
1416: b = SlepcAbsEigenvalue(br-eps->target,bi);
1417: break;
1418: case EPS_TARGET_REAL:
1419: a = PetscAbsReal(PetscRealPart(ar-eps->target));
1420: b = PetscAbsReal(PetscRealPart(br-eps->target));
1421: break;
1422: case EPS_TARGET_IMAGINARY:
1423: #if !defined(PETSC_USE_COMPLEX)
1424: /* complex target only allowed if scalartype=complex */
1425: a = PetscAbsReal(ai);
1426: b = PetscAbsReal(bi);
1427: #else
1428: a = PetscAbsReal(PetscImaginaryPart(ar-eps->target));
1429: b = PetscAbsReal(PetscImaginaryPart(br-eps->target));
1430: #endif
1431: break;
1432: default: SETERRQ(((PetscObject)eps)->comm,1,"Wrong value of which");
1433: }
1434: switch(eps->which) {
1435: case EPS_WHICH_USER:
1436: break;
1437: case EPS_LARGEST_MAGNITUDE:
1438: case EPS_LARGEST_REAL:
1439: case EPS_LARGEST_IMAGINARY:
1440: if (a<b) *result = 1;
1441: else if (a>b) *result = -1;
1442: else *result = 0;
1443: break;
1444: default:
1445: if (a>b) *result = 1;
1446: else if (a<b) *result = -1;
1447: else *result = 0;
1448: }
1449: return(0);
1450: }
1454: /*@
1455: EPSGetStartVector - Gets a suitable vector to be used as the starting vector
1456: for the recurrence that builds the right subspace.
1458: Collective on EPS and Vec
1460: Input Parameters:
1461: + eps - the eigensolver context
1462: - i - iteration number
1464: Output Parameters:
1465: + vec - the start vector
1466: - breakdown - flag indicating that a breakdown has occurred
1468: Notes:
1469: The start vector is computed from another vector: for the first step (i=0),
1470: the first initial vector is used (see EPSSetInitialSpace()); otherwise a random
1471: vector is created. Then this vector is forced to be in the range of OP (only
1472: for generalized definite problems) and orthonormalized with respect to all
1473: V-vectors up to i-1.
1475: The flag breakdown is set to true if either i=0 and the vector belongs to the
1476: deflation space, or i>0 and the vector is linearly dependent with respect
1477: to the V-vectors.
1479: The caller must pass a vector already allocated with dimensions conforming
1480: to the initial vector. This vector is overwritten.
1482: Level: developer
1484: .seealso: EPSSetInitialSpace()
1485: @*/
1486: PetscErrorCode EPSGetStartVector(EPS eps,PetscInt i,Vec vec,PetscBool *breakdown)
1487: {
1489: PetscReal norm;
1490: PetscBool lindep;
1491: Vec w;
1492:
1499: VecDuplicate(eps->V[0],&w);
1501: /* For the first step, use the first initial vector, otherwise a random one */
1502: if (i==0 && eps->nini>0) {
1503: VecCopy(eps->V[0],w);
1504: } else {
1505: SlepcVecSetRandom(w,eps->rand);
1506: }
1508: /* Force the vector to be in the range of OP for definite generalized problems */
1509: if (eps->ispositive) {
1510: STApply(eps->OP,w,vec);
1511: } else {
1512: VecCopy(w,vec);
1513: }
1515: /* Orthonormalize the vector with respect to previous vectors */
1516: IPOrthogonalize(eps->ip,eps->nds,eps->DS,i,PETSC_NULL,eps->V,vec,PETSC_NULL,&norm,&lindep);
1517: if (breakdown) *breakdown = lindep;
1518: else if (lindep || norm == 0.0) {
1519: if (i==0) { SETERRQ(((PetscObject)eps)->comm,1,"Initial vector is zero or belongs to the deflation space"); }
1520: else { SETERRQ(((PetscObject)eps)->comm,1,"Unable to generate more start vectors"); }
1521: }
1522: VecScale(vec,1.0/norm);
1524: VecDestroy(&w);
1525: return(0);
1526: }
1530: /*@
1531: EPSGetStartVectorLeft - Gets a suitable vector to be used as the starting vector
1532: in the recurrence that builds the left subspace (in methods that work with two
1533: subspaces).
1535: Collective on EPS and Vec
1537: Input Parameters:
1538: + eps - the eigensolver context
1539: - i - iteration number
1541: Output Parameter:
1542: + vec - the start vector
1543: - breakdown - flag indicating that a breakdown has occurred
1545: Notes:
1546: The start vector is computed from another vector: for the first step (i=0),
1547: the first left initial vector is used (see EPSSetInitialSpaceLeft()); otherwise
1548: a random vector is created. Then this vector is forced to be in the range
1549: of OP' and orthonormalized with respect to all W-vectors up to i-1.
1551: The flag breakdown is set to true if i>0 and the vector is linearly dependent
1552: with respect to the W-vectors.
1554: The caller must pass a vector already allocated with dimensions conforming
1555: to the left initial vector. This vector is overwritten.
1557: Level: developer
1559: .seealso: EPSSetInitialSpaceLeft()
1561: @*/
1562: PetscErrorCode EPSGetStartVectorLeft(EPS eps,PetscInt i,Vec vec,PetscBool *breakdown)
1563: {
1565: PetscReal norm;
1566: PetscBool lindep;
1567: Vec w;
1568:
1575: VecDuplicate(eps->W[0],&w);
1577: /* For the first step, use the first initial left vector, otherwise a random one */
1578: if (i==0 && eps->ninil>0) {
1579: VecCopy(eps->W[0],w);
1580: } else {
1581: SlepcVecSetRandom(w,eps->rand);
1582: }
1584: /* Force the vector to be in the range of OP' */
1585: STApplyTranspose(eps->OP,w,vec);
1587: /* Orthonormalize the vector with respect to previous vectors */
1588: IPOrthogonalize(eps->ip,0,PETSC_NULL,i,PETSC_NULL,eps->W,vec,PETSC_NULL,&norm,&lindep);
1589: if (breakdown) *breakdown = lindep;
1590: else if (lindep || norm == 0.0) {
1591: if (i==0) { SETERRQ(((PetscObject)eps)->comm,1,"Left initial vector is zero"); }
1592: else { SETERRQ(((PetscObject)eps)->comm,1,"Unable to generate more left start vectors"); }
1593: }
1594: VecScale(vec,1/norm);
1596: VecDestroy(&w);
1597: return(0);
1598: }