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-2013, 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/epsimpl.h> /*I "slepceps.h" I*/
25: #include <petscdraw.h>
27: typedef struct {
28: PetscErrorCode (*comparison)(PetscScalar,PetscScalar,PetscScalar,PetscScalar,PetscInt*,void*);
29: void *comparisonctx;
30: ST st;
31: } EPSSortForSTData;
35: static PetscErrorCode EPSSortForSTFunc(PetscScalar ar,PetscScalar ai,
36: PetscScalar br,PetscScalar bi,PetscInt *r,void *ctx)
37: {
38: EPSSortForSTData *data = (EPSSortForSTData*)ctx;
39: PetscErrorCode ierr;
42: STBackTransform(data->st,1,&ar,&ai);
43: STBackTransform(data->st,1,&br,&bi);
44: (*data->comparison)(ar,ai,br,bi,r,data->comparisonctx);
45: return(0);
46: }
50: /*@
51: EPSSolve - Solves the eigensystem.
53: Collective on EPS
55: Input Parameter:
56: . eps - eigensolver context obtained from EPSCreate()
58: Options Database Keys:
59: + -eps_view - print information about the solver used
60: . -eps_view_mat0 binary - save the first matrix (A) to the default binary viewer
61: . -eps_view_mat1 binary - save the second matrix (B) to the default binary viewer
62: - -eps_plot_eigs - plot computed eigenvalues
64: Level: beginner
66: .seealso: EPSCreate(), EPSSetUp(), EPSDestroy(), EPSSetTolerances()
67: @*/
68: PetscErrorCode EPSSolve(EPS eps)
69: {
70: PetscErrorCode ierr;
71: PetscInt i,nmat;
72: PetscReal re,im;
73: PetscScalar dot;
74: PetscBool flg,isfold,iscayley;
75: PetscViewer viewer;
76: PetscViewerFormat format;
77: PetscDraw draw;
78: PetscDrawSP drawsp;
79: STMatMode matmode;
80: EPSSortForSTData data;
81: Mat A,B;
82: KSP ksp;
83: Vec w,x;
87: PetscLogEventBegin(EPS_Solve,eps,0,0,0);
89: /* call setup */
90: EPSSetUp(eps);
91: STGetNumMatrices(eps->st,&nmat);
92: STGetOperators(eps->st,0,&A);
93: if (nmat>1) { STGetOperators(eps->st,1,&B); }
94: eps->evecsavailable = PETSC_FALSE;
95: eps->nconv = 0;
96: eps->its = 0;
97: for (i=0;i<eps->ncv;i++) {
98: eps->eigr[i] = 0.0;
99: eps->eigi[i] = 0.0;
100: eps->errest[i] = 0.0;
101: }
102: EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,eps->ncv);
104: PetscObjectTypeCompareAny((PetscObject)eps,&flg,EPSARPACK,EPSBLZPACK,EPSTRLAN,EPSBLOPEX,EPSPRIMME,"");
105: if (!flg) {
106: /* temporarily change eigenvalue comparison function */
107: data.comparison = eps->comparison;
108: data.comparisonctx = eps->comparisonctx;
109: data.st = eps->st;
110: eps->comparison = (eps->which==EPS_ALL)? SlepcCompareLargestMagnitude: EPSSortForSTFunc;
111: eps->comparisonctx = (eps->which==EPS_ALL)? NULL: &data;
112: }
113: DSSetEigenvalueComparison(eps->ds,eps->comparison,eps->comparisonctx);
115: /* call solver */
116: (*eps->ops->solve)(eps);
118: if (!flg) {
119: /* restore comparison function */
120: eps->comparison = data.comparison;
121: eps->comparisonctx = data.comparisonctx;
122: }
124: STGetMatMode(eps->st,&matmode);
125: if (matmode == ST_MATMODE_INPLACE && eps->ispositive) {
126: /* Purify eigenvectors before reverting operator */
127: (*eps->ops->computevectors)(eps);
128: }
129: STPostSolve(eps->st);
131: if (!eps->reason) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Internal error, solver returned without setting converged reason");
133: /* Map eigenvalues back to the original problem, necessary in some
134: * spectral transformations */
135: if (eps->ops->backtransform) {
136: (*eps->ops->backtransform)(eps);
137: }
139: /* Adjust left eigenvectors in generalized problems: y = B^T y */
140: if (eps->isgeneralized && eps->leftvecs) {
141: KSPCreate(PetscObjectComm((PetscObject)eps),&ksp);
142: KSPSetOperators(ksp,B,B,DIFFERENT_NONZERO_PATTERN);
143: KSPSetFromOptions(ksp);
144: MatGetVecs(B,NULL,&w);
145: for (i=0;i<eps->nconv;i++) {
146: VecCopy(eps->W[i],w);
147: KSPSolveTranspose(ksp,w,eps->W[i]);
148: }
149: KSPDestroy(&ksp);
150: VecDestroy(&w);
151: }
153: #if !defined(PETSC_USE_COMPLEX)
154: /* reorder conjugate eigenvalues (positive imaginary first) */
155: for (i=0; i<eps->nconv-1; i++) {
156: if (eps->eigi[i] != 0) {
157: if (eps->eigi[i] < 0) {
158: eps->eigi[i] = -eps->eigi[i];
159: eps->eigi[i+1] = -eps->eigi[i+1];
160: if (!eps->evecsavailable) {
161: /* the next correction only works with eigenvectors */
162: (*eps->ops->computevectors)(eps);
163: }
164: VecScale(eps->V[i+1],-1.0);
165: }
166: i++;
167: }
168: }
169: #endif
171: /* quick and dirty solution for FOLD: recompute eigenvalues as Rayleigh quotients */
172: PetscObjectTypeCompare((PetscObject)eps->st,STFOLD,&isfold);
173: if (isfold) {
174: MatGetVecs(A,&w,NULL);
175: if (!eps->evecsavailable) { (*eps->ops->computevectors)(eps); }
176: for (i=0;i<eps->nconv;i++) {
177: x = eps->V[i];
178: MatMult(A,x,w);
179: VecDot(w,x,&eps->eigr[i]);
180: if (eps->isgeneralized) {
181: MatMult(B,x,w);
182: VecDot(w,x,&dot);
183: eps->eigr[i] /= dot;
184: }
185: }
186: VecDestroy(&w);
187: }
189: /* In the case of Cayley transform, eigenvectors need to be B-normalized */
190: PetscObjectTypeCompare((PetscObject)eps->st,STCAYLEY,&iscayley);
191: if (iscayley && eps->isgeneralized && eps->ishermitian) {
192: MatGetVecs(B,NULL,&w);
193: if (!eps->evecsavailable) { (*eps->ops->computevectors)(eps); }
194: for (i=0;i<eps->nconv;i++) {
195: x = eps->V[i];
196: MatMult(B,x,w);
197: VecDot(w,x,&dot);
198: VecScale(x,1.0/PetscSqrtScalar(dot));
199: }
200: VecDestroy(&w);
201: }
203: /* sort eigenvalues according to eps->which parameter */
204: EPSSortEigenvalues(eps,eps->nconv,eps->eigr,eps->eigi,eps->perm);
206: PetscLogEventEnd(EPS_Solve,eps,0,0,0);
208: /* various viewers */
209: MatViewFromOptions(A,((PetscObject)eps)->prefix,"-eps_view_mat0");
210: if (nmat>1) { MatViewFromOptions(B,((PetscObject)eps)->prefix,"-eps_view_mat1"); }
212: PetscOptionsGetViewer(PetscObjectComm((PetscObject)eps),((PetscObject)eps)->prefix,"-eps_view",&viewer,&format,&flg);
213: if (flg && !PetscPreLoadingOn) {
214: PetscViewerPushFormat(viewer,format);
215: EPSView(eps,viewer);
216: PetscViewerPopFormat(viewer);
217: PetscViewerDestroy(&viewer);
218: }
220: flg = PETSC_FALSE;
221: PetscOptionsGetBool(((PetscObject)eps)->prefix,"-eps_plot_eigs",&flg,NULL);
222: if (flg) {
223: PetscViewerDrawOpen(PETSC_COMM_SELF,0,"Computed Eigenvalues",PETSC_DECIDE,PETSC_DECIDE,300,300,&viewer);
224: PetscViewerDrawGetDraw(viewer,0,&draw);
225: PetscDrawSPCreate(draw,1,&drawsp);
226: for (i=0;i<eps->nconv;i++) {
227: #if defined(PETSC_USE_COMPLEX)
228: re = PetscRealPart(eps->eigr[i]);
229: im = PetscImaginaryPart(eps->eigi[i]);
230: #else
231: re = eps->eigr[i];
232: im = eps->eigi[i];
233: #endif
234: PetscDrawSPAddPoint(drawsp,&re,&im);
235: }
236: PetscDrawSPDraw(drawsp,PETSC_TRUE);
237: PetscDrawSPDestroy(&drawsp);
238: PetscViewerDestroy(&viewer);
239: }
241: /* Remove the initial subspaces */
242: eps->nini = 0;
243: eps->ninil = 0;
244: return(0);
245: }
249: /*@
250: EPSGetIterationNumber - Gets the current iteration number. If the
251: call to EPSSolve() is complete, then it returns the number of iterations
252: carried out by the solution method.
254: Not Collective
256: Input Parameter:
257: . eps - the eigensolver context
259: Output Parameter:
260: . its - number of iterations
262: Level: intermediate
264: Note:
265: During the i-th iteration this call returns i-1. If EPSSolve() is
266: complete, then parameter "its" contains either the iteration number at
267: which convergence was successfully reached, or failure was detected.
268: Call EPSGetConvergedReason() to determine if the solver converged or
269: failed and why.
271: .seealso: EPSGetConvergedReason(), EPSSetTolerances()
272: @*/
273: PetscErrorCode EPSGetIterationNumber(EPS eps,PetscInt *its)
274: {
278: *its = eps->its;
279: return(0);
280: }
284: /*@
285: EPSGetOperationCounters - Gets the total number of operator applications,
286: inner product operations and linear iterations used by the ST object
287: during the last EPSSolve() call.
289: Not Collective
291: Input Parameter:
292: . eps - EPS context
294: Output Parameter:
295: + ops - number of operator applications
296: . dots - number of inner product operations
297: - lits - number of linear iterations
299: Notes:
300: When the eigensolver algorithm invokes STApply() then a linear system
301: must be solved (except in the case of standard eigenproblems and shift
302: transformation). The number of iterations required in this solve is
303: accumulated into a counter whose value is returned by this function.
305: These counters are reset to zero at each successive call to EPSSolve().
307: Level: intermediate
309: @*/
310: PetscErrorCode EPSGetOperationCounters(EPS eps,PetscInt* ops,PetscInt* dots,PetscInt* lits)
311: {
316: if (!eps->st) { EPSGetST(eps,&eps->st); }
317: STGetOperationCounters(eps->st,ops,lits);
318: if (dots) {
319: if (!eps->ip) { EPSGetIP(eps,&eps->ip); }
320: IPGetOperationCounters(eps->ip,dots);
321: }
322: return(0);
323: }
327: /*@
328: EPSGetConverged - Gets the number of converged eigenpairs.
330: Not Collective
332: Input Parameter:
333: . eps - the eigensolver context
335: Output Parameter:
336: . nconv - number of converged eigenpairs
338: Note:
339: This function should be called after EPSSolve() has finished.
341: Level: beginner
343: .seealso: EPSSetDimensions(), EPSSolve()
344: @*/
345: PetscErrorCode EPSGetConverged(EPS eps,PetscInt *nconv)
346: {
350: *nconv = eps->nconv;
351: return(0);
352: }
356: /*@C
357: EPSGetConvergedReason - Gets the reason why the EPSSolve() iteration was
358: stopped.
360: Not Collective
362: Input Parameter:
363: . eps - the eigensolver context
365: Output Parameter:
366: . reason - negative value indicates diverged, positive value converged
368: Possible values for reason:
369: + EPS_CONVERGED_TOL - converged up to tolerance
370: . EPS_DIVERGED_ITS - required more than its to reach convergence
371: - EPS_DIVERGED_BREAKDOWN - generic breakdown in method
373: Note:
374: Can only be called after the call to EPSSolve() is complete.
376: Level: intermediate
378: .seealso: EPSSetTolerances(), EPSSolve(), EPSConvergedReason
379: @*/
380: PetscErrorCode EPSGetConvergedReason(EPS eps,EPSConvergedReason *reason)
381: {
385: *reason = eps->reason;
386: return(0);
387: }
391: /*@
392: EPSGetInvariantSubspace - Gets an orthonormal basis of the computed invariant
393: subspace.
395: Not Collective, but vectors are shared by all processors that share the EPS
397: Input Parameter:
398: . eps - the eigensolver context
400: Output Parameter:
401: . v - an array of vectors
403: Notes:
404: This function should be called after EPSSolve() has finished.
406: The user should provide in v an array of nconv vectors, where nconv is
407: the value returned by EPSGetConverged().
409: The first k vectors returned in v span an invariant subspace associated
410: with the first k computed eigenvalues (note that this is not true if the
411: k-th eigenvalue is complex and matrix A is real; in this case the first
412: k+1 vectors should be used). An invariant subspace X of A satisfies Ax
413: in X for all x in X (a similar definition applies for generalized
414: eigenproblems).
416: Level: intermediate
418: .seealso: EPSGetEigenpair(), EPSGetConverged(), EPSSolve(), EPSGetInvariantSubspaceLeft()
419: @*/
420: PetscErrorCode EPSGetInvariantSubspace(EPS eps,Vec *v)
421: {
423: PetscInt i;
429: if (!eps->V) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
430: if (!eps->ishermitian && eps->evecsavailable) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSGetInvariantSubspace must be called before EPSGetEigenpair,EPSGetEigenvector,EPSComputeRelativeError or EPSComputeResidualNorm");
431: if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
432: for (i=0;i<eps->nconv;i++) {
433: VecPointwiseDivide(v[i],eps->V[i],eps->D);
434: VecNormalize(v[i],NULL);
435: }
436: } else {
437: for (i=0;i<eps->nconv;i++) {
438: VecCopy(eps->V[i],v[i]);
439: }
440: }
441: return(0);
442: }
446: /*@
447: EPSGetInvariantSubspaceLeft - Gets an orthonormal basis of the computed left
448: invariant subspace (only available in two-sided eigensolvers).
450: Not Collective, but vectors are shared by all processors that share the EPS
452: Input Parameter:
453: . eps - the eigensolver context
455: Output Parameter:
456: . v - an array of vectors
458: Notes:
459: This function should be called after EPSSolve() has finished.
461: The user should provide in v an array of nconv vectors, where nconv is
462: the value returned by EPSGetConverged().
464: The first k vectors returned in v span a left invariant subspace associated
465: with the first k computed eigenvalues (note that this is not true if the
466: k-th eigenvalue is complex and matrix A is real; in this case the first
467: k+1 vectors should be used). A left invariant subspace Y of A satisfies y'A
468: in Y for all y in Y (a similar definition applies for generalized
469: eigenproblems).
471: Level: intermediate
473: .seealso: EPSGetEigenpair(), EPSGetConverged(), EPSSolve(), EPSGetInvariantSubspace
474: @*/
475: PetscErrorCode EPSGetInvariantSubspaceLeft(EPS eps,Vec *v)
476: {
478: PetscInt i;
484: if (!eps->leftvecs) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
485: if (!eps->W) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
486: if (!eps->ishermitian && eps->evecsavailable) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSGetInvariantSubspaceLeft must be called before EPSGetEigenpairLeft,EPSComputeRelativeErrorLeft or EPSComputeResidualNormLeft");
487: for (i=0;i<eps->nconv;i++) {
488: VecCopy(eps->W[i],v[i]);
489: }
490: return(0);
491: }
495: /*@
496: EPSGetEigenpair - Gets the i-th solution of the eigenproblem as computed by
497: EPSSolve(). The solution consists in both the eigenvalue and the eigenvector.
499: Logically Collective on EPS
501: Input Parameters:
502: + eps - eigensolver context
503: - i - index of the solution
505: Output Parameters:
506: + eigr - real part of eigenvalue
507: . eigi - imaginary part of eigenvalue
508: . Vr - real part of eigenvector
509: - Vi - imaginary part of eigenvector
511: Notes:
512: If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is
513: configured with complex scalars the eigenvalue is stored
514: directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is
515: set to zero).
517: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
518: Eigenpairs are indexed according to the ordering criterion established
519: with EPSSetWhichEigenpairs().
521: The 2-norm of the eigenvector is one unless the problem is generalized
522: Hermitian. In this case the eigenvector is normalized with respect to the
523: norm defined by the B matrix.
525: Level: beginner
527: .seealso: EPSGetEigenvalue(), EPSGetEigenvector(), EPSGetEigenvectorLeft(), EPSSolve(),
528: EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetInvariantSubspace()
529: @*/
530: PetscErrorCode EPSGetEigenpair(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
531: {
537: if (!eps->eigr || !eps->eigi || !eps->V) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
538: if (i<0 || i>=eps->nconv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
539: EPSGetEigenvalue(eps,i,eigr,eigi);
540: if (Vr || Vi) { EPSGetEigenvector(eps,i,Vr,Vi); }
541: return(0);
542: }
546: /*@
547: EPSGetEigenvalue - Gets the i-th eigenvalue as computed by EPSSolve().
549: Not Collective
551: Input Parameters:
552: + eps - eigensolver context
553: - i - index of the solution
555: Output Parameters:
556: + eigr - real part of eigenvalue
557: - eigi - imaginary part of eigenvalue
559: Notes:
560: If the eigenvalue is real, then eigi is set to zero. If PETSc is
561: configured with complex scalars the eigenvalue is stored
562: directly in eigr (eigi is set to zero).
564: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
565: Eigenpairs are indexed according to the ordering criterion established
566: with EPSSetWhichEigenpairs().
568: Level: beginner
570: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(),
571: EPSGetEigenpair()
572: @*/
573: PetscErrorCode EPSGetEigenvalue(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi)
574: {
575: PetscInt k;
579: if (!eps->eigr || !eps->eigi) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
580: if (i<0 || i>=eps->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
581: if (!eps->perm) k = i;
582: else k = eps->perm[i];
583: #if defined(PETSC_USE_COMPLEX)
584: if (eigr) *eigr = eps->eigr[k];
585: if (eigi) *eigi = 0;
586: #else
587: if (eigr) *eigr = eps->eigr[k];
588: if (eigi) *eigi = eps->eigi[k];
589: #endif
590: return(0);
591: }
595: /*@
596: EPSGetEigenvector - Gets the i-th right eigenvector as computed by EPSSolve().
598: Logically Collective on EPS
600: Input Parameters:
601: + eps - eigensolver context
602: - i - index of the solution
604: Output Parameters:
605: + Vr - real part of eigenvector
606: - Vi - imaginary part of eigenvector
608: Notes:
609: If the corresponding eigenvalue is real, then Vi is set to zero. If PETSc is
610: configured with complex scalars the eigenvector is stored
611: directly in Vr (Vi is set to zero).
613: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
614: Eigenpairs are indexed according to the ordering criterion established
615: with EPSSetWhichEigenpairs().
617: The 2-norm of the eigenvector is one unless the problem is generalized
618: Hermitian. In this case the eigenvector is normalized with respect to the
619: norm defined by the B matrix.
621: Level: beginner
623: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(),
624: EPSGetEigenpair(), EPSGetEigenvectorLeft()
625: @*/
626: PetscErrorCode EPSGetEigenvector(EPS eps,PetscInt i,Vec Vr,Vec Vi)
627: {
629: PetscInt k;
637: if (!eps->V) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
638: if (i<0 || i>=eps->nconv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
639: if (!eps->evecsavailable) {
640: (*eps->ops->computevectors)(eps);
641: }
642: if (!eps->perm) k = i;
643: else k = eps->perm[i];
644: #if defined(PETSC_USE_COMPLEX)
645: VecCopy(eps->V[k],Vr);
646: if (Vi) { VecSet(Vi,0.0); }
647: #else
648: if (eps->eigi[k] > 0) { /* first value of conjugate pair */
649: VecCopy(eps->V[k],Vr);
650: if (Vi) {
651: VecCopy(eps->V[k+1],Vi);
652: }
653: } else if (eps->eigi[k] < 0) { /* second value of conjugate pair */
654: VecCopy(eps->V[k-1],Vr);
655: if (Vi) {
656: VecCopy(eps->V[k],Vi);
657: VecScale(Vi,-1.0);
658: }
659: } else { /* real eigenvalue */
660: VecCopy(eps->V[k],Vr);
661: if (Vi) { VecSet(Vi,0.0); }
662: }
663: #endif
664: return(0);
665: }
669: /*@
670: EPSGetEigenvectorLeft - Gets the i-th left eigenvector as computed by EPSSolve()
671: (only available in two-sided eigensolvers).
673: Logically Collective on EPS
675: Input Parameters:
676: + eps - eigensolver context
677: - i - index of the solution
679: Output Parameters:
680: + Wr - real part of eigenvector
681: - Wi - imaginary part of eigenvector
683: Notes:
684: If the corresponding eigenvalue is real, then Wi is set to zero. If PETSc is
685: configured with complex scalars the eigenvector is stored
686: directly in Wr (Wi is set to zero).
688: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
689: Eigenpairs are indexed according to the ordering criterion established
690: with EPSSetWhichEigenpairs().
692: Level: beginner
694: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(),
695: EPSGetEigenpair(), EPSGetEigenvector()
696: @*/
697: PetscErrorCode EPSGetEigenvectorLeft(EPS eps,PetscInt i,Vec Wr,Vec Wi)
698: {
700: PetscInt k;
708: if (!eps->leftvecs) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
709: if (!eps->W) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
710: if (i<0 || i>=eps->nconv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
711: if (!eps->evecsavailable) {
712: (*eps->ops->computevectors)(eps);
713: }
714: if (!eps->perm) k = i;
715: else k = eps->perm[i];
716: #if defined(PETSC_USE_COMPLEX)
717: VecCopy(eps->W[k],Wr);
718: if (Wi) { VecSet(Wi,0.0); }
719: #else
720: if (eps->eigi[k] > 0) { /* first value of conjugate pair */
721: VecCopy(eps->W[k],Wr);
722: if (Wi) {
723: VecCopy(eps->W[k+1],Wi);
724: }
725: } else if (eps->eigi[k] < 0) { /* second value of conjugate pair */
726: VecCopy(eps->W[k-1],Wr);
727: if (Wi) {
728: VecCopy(eps->W[k],Wi);
729: VecScale(Wi,-1.0);
730: }
731: } else { /* real eigenvalue */
732: VecCopy(eps->W[k],Wr);
733: if (Wi) { VecSet(Wi,0.0); }
734: }
735: #endif
736: return(0);
737: }
741: /*@
742: EPSGetErrorEstimate - Returns the error estimate associated to the i-th
743: computed eigenpair.
745: Not Collective
747: Input Parameter:
748: + eps - eigensolver context
749: - i - index of eigenpair
751: Output Parameter:
752: . errest - the error estimate
754: Notes:
755: This is the error estimate used internally by the eigensolver. The actual
756: error bound can be computed with EPSComputeRelativeError(). See also the users
757: manual for details.
759: Level: advanced
761: .seealso: EPSComputeRelativeError()
762: @*/
763: PetscErrorCode EPSGetErrorEstimate(EPS eps,PetscInt i,PetscReal *errest)
764: {
768: if (!eps->eigr || !eps->eigi) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
769: if (i<0 || i>=eps->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
770: if (eps->perm) i = eps->perm[i];
771: if (errest) *errest = eps->errest[i];
772: return(0);
773: }
777: /*@
778: EPSGetErrorEstimateLeft - Returns the left error estimate associated to the i-th
779: computed eigenpair (only available in two-sided eigensolvers).
781: Not Collective
783: Input Parameter:
784: + eps - eigensolver context
785: - i - index of eigenpair
787: Output Parameter:
788: . errest - the left error estimate
790: Notes:
791: This is the error estimate used internally by the eigensolver. The actual
792: error bound can be computed with EPSComputeRelativeErrorLeft(). See also the users
793: manual for details.
795: Level: advanced
797: .seealso: EPSComputeRelativeErrorLeft()
798: @*/
799: PetscErrorCode EPSGetErrorEstimateLeft(EPS eps,PetscInt i,PetscReal *errest)
800: {
804: if (!eps->eigr || !eps->eigi) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
805: if (!eps->leftvecs) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
806: if (i<0 || i>=eps->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
807: if (eps->perm) i = eps->perm[i];
808: if (errest) *errest = eps->errest_left[i];
809: return(0);
810: }
814: /*
815: EPSComputeResidualNorm_Private - Computes the norm of the residual vector
816: associated with an eigenpair.
817: */
818: PetscErrorCode EPSComputeResidualNorm_Private(EPS eps,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *norm)
819: {
821: PetscInt nmat;
822: Vec u,w;
823: Mat A,B;
824: #if !defined(PETSC_USE_COMPLEX)
825: Vec v;
826: PetscReal ni,nr;
827: #endif
830: STGetNumMatrices(eps->st,&nmat);
831: STGetOperators(eps->st,0,&A);
832: if (nmat>1) { STGetOperators(eps->st,1,&B); }
833: VecDuplicate(eps->V[0],&u);
834: VecDuplicate(eps->V[0],&w);
836: #if !defined(PETSC_USE_COMPLEX)
837: if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
838: #endif
839: MatMult(A,xr,u); /* u=A*x */
840: if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
841: if (eps->isgeneralized) { MatMult(B,xr,w); }
842: else { VecCopy(xr,w); } /* w=B*x */
843: VecAXPY(u,-kr,w); /* u=A*x-k*B*x */
844: }
845: VecNorm(u,NORM_2,norm);
846: #if !defined(PETSC_USE_COMPLEX)
847: } else {
848: VecDuplicate(eps->V[0],&v);
849: MatMult(A,xr,u); /* u=A*xr */
850: if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
851: if (eps->isgeneralized) { MatMult(B,xr,v); }
852: else { VecCopy(xr,v); } /* v=B*xr */
853: VecAXPY(u,-kr,v); /* u=A*xr-kr*B*xr */
854: if (eps->isgeneralized) { MatMult(B,xi,w); }
855: else { VecCopy(xi,w); } /* w=B*xi */
856: VecAXPY(u,ki,w); /* u=A*xr-kr*B*xr+ki*B*xi */
857: }
858: VecNorm(u,NORM_2,&nr);
859: MatMult(A,xi,u); /* u=A*xi */
860: if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
861: VecAXPY(u,-kr,w); /* u=A*xi-kr*B*xi */
862: VecAXPY(u,-ki,v); /* u=A*xi-kr*B*xi-ki*B*xr */
863: }
864: VecNorm(u,NORM_2,&ni);
865: *norm = SlepcAbsEigenvalue(nr,ni);
866: VecDestroy(&v);
867: }
868: #endif
870: VecDestroy(&w);
871: VecDestroy(&u);
872: return(0);
873: }
877: /*@
878: EPSComputeResidualNorm - Computes the norm of the residual vector associated with
879: the i-th computed eigenpair.
881: Collective on EPS
883: Input Parameter:
884: + eps - the eigensolver context
885: - i - the solution index
887: Output Parameter:
888: . norm - the residual norm, computed as ||Ax-kBx||_2 where k is the
889: eigenvalue and x is the eigenvector.
890: If k=0 then the residual norm is computed as ||Ax||_2.
892: Notes:
893: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
894: Eigenpairs are indexed according to the ordering criterion established
895: with EPSSetWhichEigenpairs().
897: Level: beginner
899: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs()
900: @*/
901: PetscErrorCode EPSComputeResidualNorm(EPS eps,PetscInt i,PetscReal *norm)
902: {
904: Vec xr,xi;
905: PetscScalar kr,ki;
911: VecDuplicate(eps->V[0],&xr);
912: VecDuplicate(eps->V[0],&xi);
913: EPSGetEigenpair(eps,i,&kr,&ki,xr,xi);
914: EPSComputeResidualNorm_Private(eps,kr,ki,xr,xi,norm);
915: VecDestroy(&xr);
916: VecDestroy(&xi);
917: return(0);
918: }
922: /*@
923: EPSComputeResidualNormLeft - Computes the norm of the residual vector associated with
924: the i-th computed left eigenvector (only available in two-sided eigensolvers).
926: Collective on EPS
928: Input Parameter:
929: + eps - the eigensolver context
930: - i - the solution index
932: Output Parameter:
933: . norm - the residual norm, computed as ||y'A-ky'B||_2 where k is the
934: eigenvalue and y is the left eigenvector.
935: If k=0 then the residual norm is computed as ||y'A||_2.
937: Notes:
938: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
939: Eigenpairs are indexed according to the ordering criterion established
940: with EPSSetWhichEigenpairs().
942: Level: beginner
944: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs()
945: @*/
946: PetscErrorCode EPSComputeResidualNormLeft(EPS eps,PetscInt i,PetscReal *norm)
947: {
949: Vec u,v,w,xr,xi;
950: Mat A,B;
951: PetscInt nmat;
952: PetscScalar kr,ki;
953: #if !defined(PETSC_USE_COMPLEX)
954: PetscReal ni,nr;
955: #endif
961: if (!eps->leftvecs) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
962: STGetNumMatrices(eps->st,&nmat);
963: STGetOperators(eps->st,0,&A);
964: if (nmat>1) { STGetOperators(eps->st,1,&B); }
965: VecDuplicate(eps->W[0],&u);
966: VecDuplicate(eps->W[0],&v);
967: VecDuplicate(eps->W[0],&w);
968: VecDuplicate(eps->W[0],&xr);
969: VecDuplicate(eps->W[0],&xi);
970: EPSGetEigenvalue(eps,i,&kr,&ki);
971: EPSGetEigenvectorLeft(eps,i,xr,xi);
973: #if !defined(PETSC_USE_COMPLEX)
974: if (ki == 0 ||
975: PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
976: #endif
977: MatMultTranspose(A,xr,u); /* u=A'*x */
978: if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
979: if (eps->isgeneralized) { MatMultTranspose(B,xr,w); }
980: else { VecCopy(xr,w); } /* w=B'*x */
981: VecAXPY(u,-kr,w); /* u=A'*x-k*B'*x */
982: }
983: VecNorm(u,NORM_2,norm);
984: #if !defined(PETSC_USE_COMPLEX)
985: } else {
986: MatMultTranspose(A,xr,u); /* u=A'*xr */
987: if (eps->isgeneralized) { MatMultTranspose(B,xr,v); }
988: else { VecCopy(xr,v); } /* v=B'*xr */
989: VecAXPY(u,-kr,v); /* u=A'*xr-kr*B'*xr */
990: if (eps->isgeneralized) { MatMultTranspose(B,xi,w); }
991: else { VecCopy(xi,w); } /* w=B'*xi */
992: VecAXPY(u,ki,w); /* u=A'*xr-kr*B'*xr+ki*B'*xi */
993: VecNorm(u,NORM_2,&nr);
994: MatMultTranspose(A,xi,u); /* u=A'*xi */
995: VecAXPY(u,-kr,w); /* u=A'*xi-kr*B'*xi */
996: VecAXPY(u,-ki,v); /* u=A'*xi-kr*B'*xi-ki*B'*xr */
997: VecNorm(u,NORM_2,&ni);
998: *norm = SlepcAbsEigenvalue(nr,ni);
999: }
1000: #endif
1002: VecDestroy(&w);
1003: VecDestroy(&v);
1004: VecDestroy(&u);
1005: VecDestroy(&xr);
1006: VecDestroy(&xi);
1007: return(0);
1008: }
1012: /*
1013: EPSComputeRelativeError_Private - Computes the relative error bound
1014: associated with an eigenpair.
1015: */
1016: PetscErrorCode EPSComputeRelativeError_Private(EPS eps,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *error)
1017: {
1019: PetscReal norm,er;
1020: #if !defined(PETSC_USE_COMPLEX)
1021: PetscReal ei;
1022: #endif
1025: EPSComputeResidualNorm_Private(eps,kr,ki,xr,xi,&norm);
1027: #if !defined(PETSC_USE_COMPLEX)
1028: if (ki == 0) {
1029: #endif
1030: VecNorm(xr,NORM_2,&er);
1031: #if !defined(PETSC_USE_COMPLEX)
1032: } else {
1033: VecNorm(xr,NORM_2,&er);
1034: VecNorm(xi,NORM_2,&ei);
1035: er = SlepcAbsEigenvalue(er,ei);
1036: }
1037: #endif
1038: (*eps->converged)(eps,kr,ki,norm/er,error,eps->convergedctx);
1039: return(0);
1040: }
1044: /*@
1045: EPSComputeRelativeError - Computes the relative error bound associated
1046: with the i-th computed eigenpair.
1048: Collective on EPS
1050: Input Parameter:
1051: + eps - the eigensolver context
1052: - i - the solution index
1054: Output Parameter:
1055: . error - the relative error bound, computed as ||Ax-kBx||_2/||kx||_2 where
1056: k is the eigenvalue and x is the eigenvector.
1057: If k=0 the relative error is computed as ||Ax||_2/||x||_2.
1059: Level: beginner
1061: .seealso: EPSSolve(), EPSComputeResidualNorm(), EPSGetErrorEstimate()
1062: @*/
1063: PetscErrorCode EPSComputeRelativeError(EPS eps,PetscInt i,PetscReal *error)
1064: {
1066: Vec xr,xi;
1067: PetscScalar kr,ki;
1073: VecDuplicate(eps->V[0],&xr);
1074: VecDuplicate(eps->V[0],&xi);
1075: EPSGetEigenpair(eps,i,&kr,&ki,xr,xi);
1076: EPSComputeRelativeError_Private(eps,kr,ki,xr,xi,error);
1077: VecDestroy(&xr);
1078: VecDestroy(&xi);
1079: return(0);
1080: }
1084: /*@
1085: EPSComputeRelativeErrorLeft - Computes the relative error bound associated
1086: with the i-th computed eigenvalue and left eigenvector (only available in
1087: two-sided eigensolvers).
1089: Collective on EPS
1091: Input Parameter:
1092: + eps - the eigensolver context
1093: - i - the solution index
1095: Output Parameter:
1096: . error - the relative error bound, computed as ||y'A-ky'B||_2/||ky||_2 where
1097: k is the eigenvalue and y is the left eigenvector.
1098: If k=0 the relative error is computed as ||y'A||_2/||y||_2.
1100: Level: beginner
1102: .seealso: EPSSolve(), EPSComputeResidualNormLeft(), EPSGetErrorEstimateLeft()
1103: @*/
1104: PetscErrorCode EPSComputeRelativeErrorLeft(EPS eps,PetscInt i,PetscReal *error)
1105: {
1107: Vec xr,xi;
1108: PetscScalar kr,ki;
1109: PetscReal norm,er;
1110: #if !defined(PETSC_USE_COMPLEX)
1111: Vec u;
1112: PetscReal ei;
1113: #endif
1117: EPSComputeResidualNormLeft(eps,i,&norm);
1120: VecDuplicate(eps->W[0],&xr);
1121: VecDuplicate(eps->W[0],&xi);
1122: EPSGetEigenvalue(eps,i,&kr,&ki);
1123: EPSGetEigenvectorLeft(eps,i,xr,xi);
1125: #if !defined(PETSC_USE_COMPLEX)
1126: if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
1127: #endif
1128: VecNorm(xr,NORM_2,&er);
1129: if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) *error = norm/(PetscAbsScalar(kr)*er);
1130: else *error = norm / er;
1131: #if !defined(PETSC_USE_COMPLEX)
1132: } else {
1133: VecDuplicate(xi,&u);
1134: VecCopy(xi,u);
1135: VecAXPBY(u,kr,-ki,xr);
1136: VecNorm(u,NORM_2,&er);
1137: VecAXPBY(xi,kr,ki,xr);
1138: VecNorm(xi,NORM_2,&ei);
1139: VecDestroy(&u);
1140: *error = norm / SlepcAbsEigenvalue(er,ei);
1141: }
1142: #endif
1144: VecDestroy(&xr);
1145: VecDestroy(&xi);
1146: return(0);
1147: }
1151: /*@
1152: EPSSortEigenvalues - Sorts a list of eigenvalues according to the criterion
1153: specified via EPSSetWhichEigenpairs().
1155: Not Collective
1157: Input Parameters:
1158: + eps - the eigensolver context
1159: . n - number of eigenvalues in the list
1160: . eigr - pointer to the array containing the eigenvalues
1161: - eigi - imaginary part of the eigenvalues (only when using real numbers)
1163: Output Parameter:
1164: . perm - resulting permutation
1166: Note:
1167: The result is a list of indices in the original eigenvalue array
1168: corresponding to the first nev eigenvalues sorted in the specified
1169: criterion.
1171: Level: developer
1173: .seealso: EPSSetWhichEigenpairs()
1174: @*/
1175: PetscErrorCode EPSSortEigenvalues(EPS eps,PetscInt n,PetscScalar *eigr,PetscScalar *eigi,PetscInt *perm)
1176: {
1178: PetscScalar re,im;
1179: PetscInt i,j,result,tmp;
1186: for (i=0; i<n; i++) { perm[i] = i; }
1187: /* insertion sort */
1188: for (i=n-1; i>=0; i--) {
1189: re = eigr[perm[i]];
1190: im = eigi[perm[i]];
1191: j = i + 1;
1192: #if !defined(PETSC_USE_COMPLEX)
1193: if (im != 0) {
1194: /* complex eigenvalue */
1195: i--;
1196: im = eigi[perm[i]];
1197: }
1198: #endif
1199: while (j<n) {
1200: EPSCompareEigenvalues(eps,re,im,eigr[perm[j]],eigi[perm[j]],&result);
1201: if (result < 0) break;
1202: #if !defined(PETSC_USE_COMPLEX)
1203: /* keep together every complex conjugated eigenpair */
1204: if (im == 0) {
1205: if (eigi[perm[j]] == 0) {
1206: #endif
1207: tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = tmp;
1208: j++;
1209: #if !defined(PETSC_USE_COMPLEX)
1210: } else {
1211: tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = perm[j+1]; perm[j+1] = tmp;
1212: j+=2;
1213: }
1214: } else {
1215: if (eigi[perm[j]] == 0) {
1216: tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = perm[j-1]; perm[j-1] = tmp;
1217: j++;
1218: } else {
1219: tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = tmp;
1220: tmp = perm[j-1]; perm[j-1] = perm[j+1]; perm[j+1] = tmp;
1221: j+=2;
1222: }
1223: }
1224: #endif
1225: }
1226: }
1227: return(0);
1228: }
1232: /*@
1233: EPSCompareEigenvalues - Compares two (possibly complex) eigenvalues according
1234: to a certain criterion.
1236: Not Collective
1238: Input Parameters:
1239: + eps - the eigensolver context
1240: . ar - real part of the 1st eigenvalue
1241: . ai - imaginary part of the 1st eigenvalue
1242: . br - real part of the 2nd eigenvalue
1243: - bi - imaginary part of the 2nd eigenvalue
1245: Output Parameter:
1246: . res - result of comparison
1248: Notes:
1249: The returning parameter 'res' can be:
1250: + negative - if the 1st eigenvalue is preferred to the 2st one
1251: . zero - if both eigenvalues are equally preferred
1252: - positive - if the 2st eigenvalue is preferred to the 1st one
1254: The criterion of comparison is related to the 'which' parameter set with
1255: EPSSetWhichEigenpairs().
1257: Level: developer
1259: .seealso: EPSSortEigenvalues(), EPSSetWhichEigenpairs()
1260: @*/
1261: PetscErrorCode EPSCompareEigenvalues(EPS eps,PetscScalar ar,PetscScalar ai,PetscScalar br,PetscScalar bi,PetscInt *result)
1262: {
1268: if (!eps->comparison) SETERRQ(PETSC_COMM_SELF,1,"Undefined eigenvalue comparison function");
1269: (*eps->comparison)(ar,ai,br,bi,result,eps->comparisonctx);
1270: return(0);
1271: }
1275: /*@
1276: EPSGetStartVector - Gets a suitable vector to be used as the starting vector
1277: for the recurrence that builds the right subspace.
1279: Collective on EPS and Vec
1281: Input Parameters:
1282: + eps - the eigensolver context
1283: - i - iteration number
1285: Output Parameters:
1286: + vec - the start vector
1287: - breakdown - flag indicating that a breakdown has occurred
1289: Notes:
1290: The start vector is computed from another vector: for the first step (i=0),
1291: the first initial vector is used (see EPSSetInitialSpace()); otherwise a random
1292: vector is created. Then this vector is forced to be in the range of OP (only
1293: for generalized definite problems) and orthonormalized with respect to all
1294: V-vectors up to i-1.
1296: The flag breakdown is set to true if either i=0 and the vector belongs to the
1297: deflation space, or i>0 and the vector is linearly dependent with respect
1298: to the V-vectors.
1300: The caller must pass a vector already allocated with dimensions conforming
1301: to the initial vector. This vector is overwritten.
1303: Level: developer
1305: .seealso: EPSSetInitialSpace()
1306: @*/
1307: PetscErrorCode EPSGetStartVector(EPS eps,PetscInt i,Vec vec,PetscBool *breakdown)
1308: {
1310: PetscReal norm;
1311: PetscBool lindep;
1312: Vec w;
1320: VecDuplicate(eps->V[0],&w);
1322: /* For the first step, use the first initial vector, otherwise a random one */
1323: if (i==0 && eps->nini>0) {
1324: VecCopy(eps->V[0],w);
1325: } else {
1326: SlepcVecSetRandom(w,eps->rand);
1327: }
1329: /* Force the vector to be in the range of OP for definite generalized problems */
1330: if (eps->ispositive || (eps->isgeneralized && eps->ishermitian)) {
1331: STApply(eps->st,w,vec);
1332: } else {
1333: VecCopy(w,vec);
1334: }
1336: /* Orthonormalize the vector with respect to previous vectors */
1337: IPOrthogonalize(eps->ip,eps->nds,eps->defl,i,NULL,eps->V,vec,NULL,&norm,&lindep);
1338: if (breakdown) *breakdown = lindep;
1339: else if (lindep || norm == 0.0) {
1340: if (i==0) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Initial vector is zero or belongs to the deflation space");
1341: else SETERRQ(PetscObjectComm((PetscObject)eps),1,"Unable to generate more start vectors");
1342: }
1343: VecScale(vec,1.0/norm);
1345: VecDestroy(&w);
1346: return(0);
1347: }
1351: /*@
1352: EPSGetStartVectorLeft - Gets a suitable vector to be used as the starting vector
1353: in the recurrence that builds the left subspace (in methods that work with two
1354: subspaces).
1356: Collective on EPS and Vec
1358: Input Parameters:
1359: + eps - the eigensolver context
1360: - i - iteration number
1362: Output Parameter:
1363: + vec - the start vector
1364: - breakdown - flag indicating that a breakdown has occurred
1366: Notes:
1367: The start vector is computed from another vector: for the first step (i=0),
1368: the first left initial vector is used (see EPSSetInitialSpaceLeft()); otherwise
1369: a random vector is created. Then this vector is forced to be in the range
1370: of OP' and orthonormalized with respect to all W-vectors up to i-1.
1372: The flag breakdown is set to true if i>0 and the vector is linearly dependent
1373: with respect to the W-vectors.
1375: The caller must pass a vector already allocated with dimensions conforming
1376: to the left initial vector. This vector is overwritten.
1378: Level: developer
1380: .seealso: EPSSetInitialSpaceLeft()
1381: @*/
1382: PetscErrorCode EPSGetStartVectorLeft(EPS eps,PetscInt i,Vec vec,PetscBool *breakdown)
1383: {
1385: PetscReal norm;
1386: PetscBool lindep;
1387: Vec w;
1395: VecDuplicate(eps->W[0],&w);
1397: /* For the first step, use the first initial left vector, otherwise a random one */
1398: if (i==0 && eps->ninil>0) {
1399: VecCopy(eps->W[0],w);
1400: } else {
1401: SlepcVecSetRandom(w,eps->rand);
1402: }
1404: /* Force the vector to be in the range of OP' */
1405: STApplyTranspose(eps->st,w,vec);
1407: /* Orthonormalize the vector with respect to previous vectors */
1408: IPOrthogonalize(eps->ip,0,NULL,i,NULL,eps->W,vec,NULL,&norm,&lindep);
1409: if (breakdown) *breakdown = lindep;
1410: else if (lindep || norm == 0.0) {
1411: if (i==0) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Left initial vector is zero");
1412: else SETERRQ(PetscObjectComm((PetscObject)eps),1,"Unable to generate more left start vectors");
1413: }
1414: VecScale(vec,1/norm);
1416: VecDestroy(&w);
1417: return(0);
1418: }