Actual source code: qepsolve.c
1: /*
2: QEP 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/qepimpl.h> /*I "slepcqep.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: } QEPSortForSTData;
35: static PetscErrorCode QEPSortForSTFunc(PetscScalar ar,PetscScalar ai,
36: PetscScalar br,PetscScalar bi,PetscInt *r,void *ctx)
37: {
38: QEPSortForSTData *data = (QEPSortForSTData*)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: QEPSolve - Solves the quadratic eigensystem.
53: Collective on QEP
55: Input Parameter:
56: . qep - eigensolver context obtained from QEPCreate()
58: Options Database Keys:
59: + -qep_view - print information about the solver used
60: . -qep_view_mat0 binary - save the first matrix (M) to the default binary viewer
61: . -qep_view_mat1 binary - save the second matrix (C) to the default binary viewer
62: . -qep_view_mat2 binary - save the third matrix (K) to the default binary viewer
63: - -qep_plot_eigs - plot computed eigenvalues
65: Level: beginner
67: .seealso: QEPCreate(), QEPSetUp(), QEPDestroy(), QEPSetTolerances()
68: @*/
69: PetscErrorCode QEPSolve(QEP qep)
70: {
71: PetscErrorCode ierr;
72: PetscInt i;
73: PetscReal re,im;
74: PetscBool flg,islinear;
75: PetscViewer viewer;
76: PetscViewerFormat format;
77: PetscDraw draw;
78: PetscDrawSP drawsp;
79: QEPSortForSTData data;
83: PetscLogEventBegin(QEP_Solve,qep,0,0,0);
85: /* call setup */
86: QEPSetUp(qep);
87: qep->nconv = 0;
88: qep->its = 0;
89: for (i=0;i<qep->ncv;i++) {
90: qep->eigr[i] = 0.0;
91: qep->eigi[i] = 0.0;
92: qep->errest[i] = 0.0;
93: }
94: QEPMonitor(qep,qep->its,qep->nconv,qep->eigr,qep->eigi,qep->errest,qep->ncv);
96: PetscObjectTypeCompare((PetscObject)qep,QEPLINEAR,&islinear);
97: if (!islinear) {
98: /* temporarily change eigenvalue comparison function */
99: data.comparison = qep->comparison;
100: data.comparisonctx = qep->comparisonctx;
101: data.st = qep->st;
102: qep->comparison = QEPSortForSTFunc;
103: qep->comparisonctx = &data;
104: }
105: DSSetEigenvalueComparison(qep->ds,qep->comparison,qep->comparisonctx);
107: (*qep->ops->solve)(qep);
108: if (!islinear) {
109: STPostSolve(qep->st);
110: }
112: if (!qep->reason) SETERRQ(PetscObjectComm((PetscObject)qep),PETSC_ERR_PLIB,"Internal error, solver returned without setting converged reason");
114: if (!islinear) {
115: /* restore comparison function */
116: qep->comparison = data.comparison;
117: qep->comparisonctx = data.comparisonctx;
118: /* Map eigenvalues back to the original problem */
119: STBackTransform(qep->st,qep->nconv,qep->eigr,qep->eigi);
120: }
122: #if !defined(PETSC_USE_COMPLEX)
123: /* reorder conjugate eigenvalues (positive imaginary first) */
124: for (i=0;i<qep->nconv-1;i++) {
125: if (qep->eigi[i] != 0) {
126: if (qep->eigi[i] < 0) {
127: qep->eigi[i] = -qep->eigi[i];
128: qep->eigi[i+1] = -qep->eigi[i+1];
129: VecScale(qep->V[i+1],-1.0);
130: }
131: i++;
132: }
133: }
134: #endif
136: /* sort eigenvalues according to qep->which parameter */
137: QEPSortEigenvalues(qep,qep->nconv,qep->eigr,qep->eigi,qep->perm);
139: PetscLogEventEnd(QEP_Solve,qep,0,0,0);
141: /* various viewers */
142: MatViewFromOptions(qep->M,((PetscObject)qep)->prefix,"-qep_view_mat0");
143: MatViewFromOptions(qep->C,((PetscObject)qep)->prefix,"-qep_view_mat1");
144: MatViewFromOptions(qep->K,((PetscObject)qep)->prefix,"-qep_view_mat2");
146: PetscOptionsGetViewer(PetscObjectComm((PetscObject)qep),((PetscObject)qep)->prefix,"-qep_view",&viewer,&format,&flg);
147: if (flg && !PetscPreLoadingOn) {
148: PetscViewerPushFormat(viewer,format);
149: QEPView(qep,viewer);
150: PetscViewerPopFormat(viewer);
151: PetscViewerDestroy(&viewer);
152: }
154: flg = PETSC_FALSE;
155: PetscOptionsGetBool(((PetscObject)qep)->prefix,"-qep_plot_eigs",&flg,NULL);
156: if (flg) {
157: PetscViewerDrawOpen(PETSC_COMM_SELF,0,"Computed Eigenvalues",PETSC_DECIDE,PETSC_DECIDE,300,300,&viewer);
158: PetscViewerDrawGetDraw(viewer,0,&draw);
159: PetscDrawSPCreate(draw,1,&drawsp);
160: for (i=0;i<qep->nconv;i++) {
161: #if defined(PETSC_USE_COMPLEX)
162: re = PetscRealPart(qep->eigr[i]);
163: im = PetscImaginaryPart(qep->eigi[i]);
164: #else
165: re = qep->eigr[i];
166: im = qep->eigi[i];
167: #endif
168: PetscDrawSPAddPoint(drawsp,&re,&im);
169: }
170: PetscDrawSPDraw(drawsp,PETSC_TRUE);
171: PetscDrawSPDestroy(&drawsp);
172: PetscViewerDestroy(&viewer);
173: }
175: /* Remove the initial subspace */
176: qep->nini = 0;
177: return(0);
178: }
182: /*@
183: QEPGetIterationNumber - Gets the current iteration number. If the
184: call to QEPSolve() is complete, then it returns the number of iterations
185: carried out by the solution method.
187: Not Collective
189: Input Parameter:
190: . qep - the quadratic eigensolver context
192: Output Parameter:
193: . its - number of iterations
195: Level: intermediate
197: Note:
198: During the i-th iteration this call returns i-1. If QEPSolve() is
199: complete, then parameter "its" contains either the iteration number at
200: which convergence was successfully reached, or failure was detected.
201: Call QEPGetConvergedReason() to determine if the solver converged or
202: failed and why.
204: .seealso: QEPGetConvergedReason(), QEPSetTolerances()
205: @*/
206: PetscErrorCode QEPGetIterationNumber(QEP qep,PetscInt *its)
207: {
211: *its = qep->its;
212: return(0);
213: }
217: /*@
218: QEPGetConverged - Gets the number of converged eigenpairs.
220: Not Collective
222: Input Parameter:
223: . qep - the quadratic eigensolver context
225: Output Parameter:
226: . nconv - number of converged eigenpairs
228: Note:
229: This function should be called after QEPSolve() has finished.
231: Level: beginner
233: .seealso: QEPSetDimensions(), QEPSolve()
234: @*/
235: PetscErrorCode QEPGetConverged(QEP qep,PetscInt *nconv)
236: {
240: *nconv = qep->nconv;
241: return(0);
242: }
246: /*@C
247: QEPGetConvergedReason - Gets the reason why the QEPSolve() iteration was
248: stopped.
250: Not Collective
252: Input Parameter:
253: . qep - the quadratic eigensolver context
255: Output Parameter:
256: . reason - negative value indicates diverged, positive value converged
258: Possible values for reason:
259: + QEP_CONVERGED_TOL - converged up to tolerance
260: . QEP_DIVERGED_ITS - required more than its to reach convergence
261: - QEP_DIVERGED_BREAKDOWN - generic breakdown in method
263: Note:
264: Can only be called after the call to QEPSolve() is complete.
266: Level: intermediate
268: .seealso: QEPSetTolerances(), QEPSolve(), QEPConvergedReason
269: @*/
270: PetscErrorCode QEPGetConvergedReason(QEP qep,QEPConvergedReason *reason)
271: {
275: *reason = qep->reason;
276: return(0);
277: }
281: /*@
282: QEPGetEigenpair - Gets the i-th solution of the eigenproblem as computed by
283: QEPSolve(). The solution consists in both the eigenvalue and the eigenvector.
285: Logically Collective on EPS
287: Input Parameters:
288: + qep - quadratic eigensolver context
289: - i - index of the solution
291: Output Parameters:
292: + eigr - real part of eigenvalue
293: . eigi - imaginary part of eigenvalue
294: . Vr - real part of eigenvector
295: - Vi - imaginary part of eigenvector
297: Notes:
298: If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is
299: configured with complex scalars the eigenvalue is stored
300: directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is
301: set to zero).
303: The index i should be a value between 0 and nconv-1 (see QEPGetConverged()).
304: Eigenpairs are indexed according to the ordering criterion established
305: with QEPSetWhichEigenpairs().
307: Level: beginner
309: .seealso: QEPSolve(), QEPGetConverged(), QEPSetWhichEigenpairs()
310: @*/
311: PetscErrorCode QEPGetEigenpair(QEP qep,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
312: {
313: PetscInt k;
321: if (!qep->eigr || !qep->eigi || !qep->V) SETERRQ(PetscObjectComm((PetscObject)qep),PETSC_ERR_ARG_WRONGSTATE,"QEPSolve must be called first");
322: if (i<0 || i>=qep->nconv) SETERRQ(PetscObjectComm((PetscObject)qep),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
324: if (!qep->perm) k = i;
325: else k = qep->perm[i];
327: /* eigenvalue */
328: #if defined(PETSC_USE_COMPLEX)
329: if (eigr) *eigr = qep->eigr[k];
330: if (eigi) *eigi = 0;
331: #else
332: if (eigr) *eigr = qep->eigr[k];
333: if (eigi) *eigi = qep->eigi[k];
334: #endif
336: /* eigenvector */
337: #if defined(PETSC_USE_COMPLEX)
338: if (Vr) { VecCopy(qep->V[k],Vr); }
339: if (Vi) { VecSet(Vi,0.0); }
340: #else
341: if (qep->eigi[k]>0) { /* first value of conjugate pair */
342: if (Vr) { VecCopy(qep->V[k],Vr); }
343: if (Vi) { VecCopy(qep->V[k+1],Vi); }
344: } else if (qep->eigi[k]<0) { /* second value of conjugate pair */
345: if (Vr) { VecCopy(qep->V[k-1],Vr); }
346: if (Vi) {
347: VecCopy(qep->V[k],Vi);
348: VecScale(Vi,-1.0);
349: }
350: } else { /* real eigenvalue */
351: if (Vr) { VecCopy(qep->V[k],Vr); }
352: if (Vi) { VecSet(Vi,0.0); }
353: }
354: #endif
355: return(0);
356: }
360: /*@
361: QEPGetErrorEstimate - Returns the error estimate associated to the i-th
362: computed eigenpair.
364: Not Collective
366: Input Parameter:
367: + qep - quadratic eigensolver context
368: - i - index of eigenpair
370: Output Parameter:
371: . errest - the error estimate
373: Notes:
374: This is the error estimate used internally by the eigensolver. The actual
375: error bound can be computed with QEPComputeRelativeError(). See also the users
376: manual for details.
378: Level: advanced
380: .seealso: QEPComputeRelativeError()
381: @*/
382: PetscErrorCode QEPGetErrorEstimate(QEP qep,PetscInt i,PetscReal *errest)
383: {
387: if (!qep->eigr || !qep->eigi) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"QEPSolve must be called first");
388: if (i<0 || i>=qep->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
389: if (qep->perm) i = qep->perm[i];
390: if (errest) *errest = qep->errest[i];
391: return(0);
392: }
396: /*
397: QEPComputeResidualNorm_Private - Computes the norm of the residual vector
398: associated with an eigenpair.
399: */
400: PetscErrorCode QEPComputeResidualNorm_Private(QEP qep,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *norm)
401: {
403: Vec u,w;
404: Mat M=qep->M,C=qep->C,K=qep->K;
405: #if !defined(PETSC_USE_COMPLEX)
406: Vec v,y,z;
407: PetscReal ni,nr;
408: PetscScalar a1,a2;
409: #endif
412: VecDuplicate(qep->V[0],&u);
413: VecDuplicate(u,&w);
415: #if !defined(PETSC_USE_COMPLEX)
416: if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
417: #endif
418: MatMult(K,xr,u); /* u=K*x */
419: if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
420: MatMult(C,xr,w); /* w=C*x */
421: VecAXPY(u,kr,w); /* u=l*C*x+K*x */
422: MatMult(M,xr,w); /* w=M*x */
423: VecAXPY(u,kr*kr,w); /* u=l^2*M*x+l*C*x+K*x */
424: }
425: VecNorm(u,NORM_2,norm);
426: #if !defined(PETSC_USE_COMPLEX)
427: } else {
428: VecDuplicate(u,&v);
429: VecDuplicate(u,&y);
430: VecDuplicate(u,&z);
431: a1 = kr*kr-ki*ki;
432: a2 = 2.0*kr*ki;
433: MatMult(K,xr,u); /* u=K*xr */
434: if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
435: MatMult(C,xr,v); /* v=C*xr */
436: MatMult(C,xi,w); /* w=C*xi */
437: MatMult(M,xr,y); /* y=M*xr */
438: MatMult(M,xi,z); /* z=M*xi */
439: VecAXPY(u,kr,v); /* u=kr*C*xr+K*xr */
440: VecAXPY(u,-ki,w); /* u=kr*C*xr-ki*C*xi+K*xr */
441: VecAXPY(u,a1,y); /* u=a1*M*xr+kr*C*xr-ki*C*xi+K*xr */
442: VecAXPY(u,-a2,z); /* u=a1*M*xr-a2*M*xi+kr*C*xr-ki*C*xi+K*xr */
443: }
444: VecNorm(u,NORM_2,&nr);
445: MatMult(K,xi,u); /* u=K*xi */
446: if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
447: VecAXPY(u,kr,w); /* u=kr*C*xi+K*xi */
448: VecAXPY(u,ki,v); /* u=kr*C*xi+ki*C*xi+K*xi */
449: VecAXPY(u,a1,z); /* u=a1*M*xi+kr*C*xi+ki*C*xi+K*xi */
450: VecAXPY(u,a2,y); /* u=a1*M*xi+a2*M*ki+kr*C*xi+ki*C*xi+K*xi */
451: }
452: VecNorm(u,NORM_2,&ni);
453: *norm = SlepcAbsEigenvalue(nr,ni);
454: VecDestroy(&v);
455: VecDestroy(&y);
456: VecDestroy(&z);
457: }
458: #endif
460: VecDestroy(&w);
461: VecDestroy(&u);
462: return(0);
463: }
467: /*@
468: QEPComputeResidualNorm - Computes the norm of the residual vector associated with
469: the i-th computed eigenpair.
471: Collective on QEP
473: Input Parameter:
474: + qep - the quadratic eigensolver context
475: - i - the solution index
477: Output Parameter:
478: . norm - the residual norm, computed as ||(l^2*M+l*C+K)x||_2 where l is the
479: eigenvalue and x is the eigenvector.
480: If l=0 then the residual norm is computed as ||Kx||_2.
482: Notes:
483: The index i should be a value between 0 and nconv-1 (see QEPGetConverged()).
484: Eigenpairs are indexed according to the ordering criterion established
485: with QEPSetWhichEigenpairs().
487: Level: beginner
489: .seealso: QEPSolve(), QEPGetConverged(), QEPSetWhichEigenpairs()
490: @*/
491: PetscErrorCode QEPComputeResidualNorm(QEP qep,PetscInt i,PetscReal *norm)
492: {
494: Vec xr,xi;
495: PetscScalar kr,ki;
501: VecDuplicate(qep->V[0],&xr);
502: VecDuplicate(qep->V[0],&xi);
503: QEPGetEigenpair(qep,i,&kr,&ki,xr,xi);
504: QEPComputeResidualNorm_Private(qep,kr,ki,xr,xi,norm);
505: VecDestroy(&xr);
506: VecDestroy(&xi);
507: return(0);
508: }
512: /*
513: QEPComputeRelativeError_Private - Computes the relative error bound
514: associated with an eigenpair.
515: */
516: PetscErrorCode QEPComputeRelativeError_Private(QEP qep,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *error)
517: {
519: PetscReal norm,er;
520: #if !defined(PETSC_USE_COMPLEX)
521: PetscReal ei;
522: #endif
525: QEPComputeResidualNorm_Private(qep,kr,ki,xr,xi,&norm);
526: #if !defined(PETSC_USE_COMPLEX)
527: if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
528: #endif
529: VecNorm(xr,NORM_2,&er);
530: if (PetscAbsScalar(kr) > norm) {
531: *error = norm/(PetscAbsScalar(kr)*er);
532: } else {
533: *error = norm/er;
534: }
535: #if !defined(PETSC_USE_COMPLEX)
536: } else {
537: VecNorm(xr,NORM_2,&er);
538: VecNorm(xi,NORM_2,&ei);
539: if (SlepcAbsEigenvalue(kr,ki) > norm) {
540: *error = norm/(SlepcAbsEigenvalue(kr,ki)*SlepcAbsEigenvalue(er,ei));
541: } else {
542: *error = norm/SlepcAbsEigenvalue(er,ei);
543: }
544: }
545: #endif
546: return(0);
547: }
551: /*@
552: QEPComputeRelativeError - Computes the relative error bound associated
553: with the i-th computed eigenpair.
555: Collective on QEP
557: Input Parameter:
558: + qep - the quadratic eigensolver context
559: - i - the solution index
561: Output Parameter:
562: . error - the relative error bound, computed as ||(l^2*M+l*C+K)x||_2/||lx||_2 where
563: l is the eigenvalue and x is the eigenvector.
564: If l=0 the relative error is computed as ||Kx||_2/||x||_2.
566: Level: beginner
568: .seealso: QEPSolve(), QEPComputeResidualNorm(), QEPGetErrorEstimate()
569: @*/
570: PetscErrorCode QEPComputeRelativeError(QEP qep,PetscInt i,PetscReal *error)
571: {
573: Vec xr,xi;
574: PetscScalar kr,ki;
580: VecDuplicate(qep->V[0],&xr);
581: VecDuplicate(qep->V[0],&xi);
582: QEPGetEigenpair(qep,i,&kr,&ki,xr,xi);
583: QEPComputeRelativeError_Private(qep,kr,ki,xr,xi,error);
584: VecDestroy(&xr);
585: VecDestroy(&xi);
586: return(0);
587: }
591: /*@
592: QEPSortEigenvalues - Sorts a list of eigenvalues according to the criterion
593: specified via QEPSetWhichEigenpairs().
595: Not Collective
597: Input Parameters:
598: + qep - the quadratic eigensolver context
599: . n - number of eigenvalues in the list
600: . eigr - pointer to the array containing the eigenvalues
601: - eigi - imaginary part of the eigenvalues (only when using real numbers)
603: Output Parameter:
604: . perm - resulting permutation
606: Note:
607: The result is a list of indices in the original eigenvalue array
608: corresponding to the first nev eigenvalues sorted in the specified
609: criterion.
611: Level: developer
613: .seealso: QEPSetWhichEigenpairs()
614: @*/
615: PetscErrorCode QEPSortEigenvalues(QEP qep,PetscInt n,PetscScalar *eigr,PetscScalar *eigi,PetscInt *perm)
616: {
618: PetscScalar re,im;
619: PetscInt i,j,result,tmp;
626: for (i=0;i<n;i++) perm[i] = i;
627: /* insertion sort */
628: for (i=n-1; i>=0; i--) {
629: re = eigr[perm[i]];
630: im = eigi[perm[i]];
631: j = i + 1;
632: #if !defined(PETSC_USE_COMPLEX)
633: if (im != 0) {
634: /* complex eigenvalue */
635: i--;
636: im = eigi[perm[i]];
637: }
638: #endif
639: while (j<n) {
640: QEPCompareEigenvalues(qep,re,im,eigr[perm[j]],eigi[perm[j]],&result);
641: if (result < 0) break;
642: #if !defined(PETSC_USE_COMPLEX)
643: /* keep together every complex conjugated eigenpair */
644: if (im == 0) {
645: if (eigi[perm[j]] == 0) {
646: #endif
647: tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = tmp;
648: j++;
649: #if !defined(PETSC_USE_COMPLEX)
650: } else {
651: tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = perm[j+1]; perm[j+1] = tmp;
652: j+=2;
653: }
654: } else {
655: if (eigi[perm[j]] == 0) {
656: tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = perm[j-1]; perm[j-1] = tmp;
657: j++;
658: } else {
659: tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = tmp;
660: tmp = perm[j-1]; perm[j-1] = perm[j+1]; perm[j+1] = tmp;
661: j+=2;
662: }
663: }
664: #endif
665: }
666: }
667: return(0);
668: }
672: /*@
673: QEPCompareEigenvalues - Compares two (possibly complex) eigenvalues according
674: to a certain criterion.
676: Not Collective
678: Input Parameters:
679: + qep - the quadratic eigensolver context
680: . ar - real part of the 1st eigenvalue
681: . ai - imaginary part of the 1st eigenvalue
682: . br - real part of the 2nd eigenvalue
683: - bi - imaginary part of the 2nd eigenvalue
685: Output Parameter:
686: . res - result of comparison
688: Notes:
689: Returns an integer less than, equal to, or greater than zero if the first
690: eigenvalue is considered to be respectively less than, equal to, or greater
691: than the second one.
693: The criterion of comparison is related to the 'which' parameter set with
694: QEPSetWhichEigenpairs().
696: Level: developer
698: .seealso: QEPSortEigenvalues(), QEPSetWhichEigenpairs()
699: @*/
700: PetscErrorCode QEPCompareEigenvalues(QEP qep,PetscScalar ar,PetscScalar ai,PetscScalar br,PetscScalar bi,PetscInt *result)
701: {
707: if (!qep->comparison) SETERRQ(PETSC_COMM_SELF,1,"Undefined eigenvalue comparison function");
708: (*qep->comparison)(ar,ai,br,bi,result,qep->comparisonctx);
709: return(0);
710: }
714: /*@
715: QEPGetOperationCounters - Gets the total number of matrix-vector products, dot
716: products, and linear solve iterations used by the QEP object during the last
717: QEPSolve() call.
719: Not Collective
721: Input Parameter:
722: . qep - quadratic eigensolver context
724: Output Parameter:
725: + matvecs - number of matrix-vector product operations
726: . dots - number of dot product operations
727: - lits - number of linear iterations
729: Notes:
730: These counters are reset to zero at each successive call to QEPSolve().
732: Level: intermediate
734: @*/
735: PetscErrorCode QEPGetOperationCounters(QEP qep,PetscInt* matvecs,PetscInt* dots,PetscInt* lits)
736: {
741: if (matvecs) *matvecs = qep->matvecs;
742: if (dots) {
743: if (!qep->ip) { QEPGetIP(qep,&qep->ip); }
744: IPGetOperationCounters(qep->ip,dots);
745: }
746: if (lits) *lits = qep->linits;
747: return(0);
748: }