1: /*
2: NEP routines related to the solution process.
4: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5: SLEPc - Scalable Library for Eigenvalue Problem Computations
6: Copyright (c) 2002-2015, 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/nepimpl.h> /*I "slepcnep.h" I*/
25: #include <petscdraw.h>
29: PetscErrorCode NEPComputeVectors(NEP nep) 30: {
34: NEPCheckSolved(nep,1);
35: switch (nep->state) {
36: case NEP_STATE_SOLVED:
37: if (nep->ops->computevectors) {
38: (*nep->ops->computevectors)(nep);
39: }
40: break;
41: default: 42: break;
43: }
44: nep->state = NEP_STATE_EIGENVECTORS;
45: return(0);
46: }
50: /*@
51: NEPSolve - Solves the nonlinear eigensystem.
53: Collective on NEP 55: Input Parameter:
56: . nep - eigensolver context obtained from NEPCreate()
58: Options Database Keys:
59: + -nep_view - print information about the solver used
60: . -nep_view_vectors binary - save the computed eigenvectors to the default binary viewer
61: . -nep_view_values - print computed eigenvalues
62: . -nep_converged_reason - print reason for convergence, and number of iterations
63: . -nep_error_absolute - print absolute errors of each eigenpair
64: - -nep_error_relative - print relative errors of each eigenpair
66: Level: beginner
68: .seealso: NEPCreate(), NEPSetUp(), NEPDestroy(), NEPSetTolerances()
69: @*/
70: PetscErrorCode NEPSolve(NEP nep) 71: {
73: PetscInt i;
77: PetscLogEventBegin(NEP_Solve,nep,0,0,0);
79: /* call setup */
80: NEPSetUp(nep);
81: nep->nconv = 0;
82: nep->its = 0;
83: for (i=0;i<nep->ncv;i++) {
84: nep->eigr[i] = 0.0;
85: nep->eigi[i] = 0.0;
86: nep->errest[i] = 0.0;
87: nep->perm[i] = i;
88: }
89: nep->ktol = 0.1;
90: NEPMonitor(nep,nep->its,nep->nconv,nep->eigr,nep->errest,nep->ncv);
91: NEPViewFromOptions(nep,NULL,"-nep_view_pre");
93: (*nep->ops->solve)(nep);
94: nep->state = NEP_STATE_SOLVED;
96: if (!nep->reason) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_PLIB,"Internal error, solver returned without setting converged reason");
98: if (nep->refine==NEP_REFINE_SIMPLE && nep->rits>0) {
99: NEPComputeVectors(nep);
100: NEPNewtonRefinementSimple(nep,&nep->rits,&nep->reftol,nep->nconv);
101: nep->state = NEP_STATE_EIGENVECTORS;
102: }
104: /* sort eigenvalues according to nep->which parameter */
105: SlepcSortEigenvalues(nep->sc,nep->nconv,nep->eigr,nep->eigi,nep->perm);
106: PetscLogEventEnd(NEP_Solve,nep,0,0,0);
108: /* various viewers */
109: NEPViewFromOptions(nep,NULL,"-nep_view");
110: NEPReasonViewFromOptions(nep);
111: NEPErrorViewFromOptions(nep);
112: NEPValuesViewFromOptions(nep);
113: NEPVectorsViewFromOptions(nep);
115: /* Remove the initial subspace */
116: nep->nini = 0;
117: return(0);
118: }
122: /*@
123: NEPProjectOperator - Computes the projection of the nonlinear operator.
125: Collective on NEP127: Input Parameters:
128: + nep - the nonlinear eigensolver context
129: . j0 - initial index
130: - j1 - final index
132: Notes:
133: This is available for split operator only.
135: The nonlinear operator T(lambda) is projected onto span(V), where V is
136: an orthonormal basis built internally by the solver. The projected
137: operator is equal to sum_i V'*A_i*V*f_i(lambda), so this function
138: computes all matrices Ei = V'*A_i*V, and stores them in the extra
139: matrices inside DS. Only rows/columns in the range [j0,j1-1] are computed,
140: the previous ones are assumed to be available already.
142: Level: developer
144: .seealso: NEPSetSplitOperator()
145: @*/
146: PetscErrorCode NEPProjectOperator(NEP nep,PetscInt j0,PetscInt j1)147: {
149: PetscInt k;
150: Mat G;
156: if (!nep->split) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_WRONGSTATE,"This solver requires a split operator");
157: BVSetActiveColumns(nep->V,j0,j1);
158: for (k=0;k<nep->nt;k++) {
159: DSGetMat(nep->ds,DSMatExtra[k],&G);
160: BVMatProject(nep->V,nep->A[k],nep->V,G);
161: DSRestoreMat(nep->ds,DSMatExtra[k],&G);
162: }
163: return(0);
164: }
168: /*@
169: NEPApplyFunction - Applies the nonlinear function T(lambda) to a given vector.
171: Collective on NEP173: Input Parameters:
174: + nep - the nonlinear eigensolver context
175: . lambda - scalar argument
176: . x - vector to be multiplied against
177: - v - workspace vector
179: Output Parameters:
180: + y - result vector
181: . A - Function matrix
182: - B - optional preconditioning matrix
184: Note:
185: If the nonlinear operator is represented in split form, the result
186: y = T(lambda)*x is computed without building T(lambda) explicitly. In
187: that case, parameters A and B are not used. Otherwise, the matrix
188: T(lambda) is built and the effect is the same as a call to
189: NEPComputeFunction() followed by a MatMult().
191: Level: developer
193: .seealso: NEPSetSplitOperator(), NEPComputeFunction()
194: @*/
195: PetscErrorCode NEPApplyFunction(NEP nep,PetscScalar lambda,Vec x,Vec v,Vec y,Mat A,Mat B)196: {
198: PetscInt i;
199: PetscScalar alpha;
207: if (nep->split) {
208: VecSet(y,0.0);
209: for (i=0;i<nep->nt;i++) {
210: FNEvaluateFunction(nep->f[i],lambda,&alpha);
211: MatMult(nep->A[i],x,v);
212: VecAXPY(y,alpha,v);
213: }
214: } else {
215: NEPComputeFunction(nep,lambda,A,B);
216: MatMult(A,x,y);
217: }
218: return(0);
219: }
223: /*@
224: NEPApplyJacobian - Applies the nonlinear Jacobian T'(lambda) to a given vector.
226: Collective on NEP228: Input Parameters:
229: + nep - the nonlinear eigensolver context
230: . lambda - scalar argument
231: . x - vector to be multiplied against
232: - v - workspace vector
234: Output Parameters:
235: + y - result vector
236: - A - Jacobian matrix
238: Note:
239: If the nonlinear operator is represented in split form, the result
240: y = T'(lambda)*x is computed without building T'(lambda) explicitly. In
241: that case, parameter A is not used. Otherwise, the matrix
242: T'(lambda) is built and the effect is the same as a call to
243: NEPComputeJacobian() followed by a MatMult().
245: Level: developer
247: .seealso: NEPSetSplitOperator(), NEPComputeJacobian()
248: @*/
249: PetscErrorCode NEPApplyJacobian(NEP nep,PetscScalar lambda,Vec x,Vec v,Vec y,Mat A)250: {
252: PetscInt i;
253: PetscScalar alpha;
261: if (nep->split) {
262: VecSet(y,0.0);
263: for (i=0;i<nep->nt;i++) {
264: FNEvaluateDerivative(nep->f[i],lambda,&alpha);
265: MatMult(nep->A[i],x,v);
266: VecAXPY(y,alpha,v);
267: }
268: } else {
269: NEPComputeJacobian(nep,lambda,A);
270: MatMult(A,x,y);
271: }
272: return(0);
273: }
277: /*@
278: NEPGetIterationNumber - Gets the current iteration number. If the
279: call to NEPSolve() is complete, then it returns the number of iterations
280: carried out by the solution method.
282: Not Collective
284: Input Parameter:
285: . nep - the nonlinear eigensolver context
287: Output Parameter:
288: . its - number of iterations
290: Level: intermediate
292: Note:
293: During the i-th iteration this call returns i-1. If NEPSolve() is
294: complete, then parameter "its" contains either the iteration number at
295: which convergence was successfully reached, or failure was detected.
296: Call NEPGetConvergedReason() to determine if the solver converged or
297: failed and why.
299: .seealso: NEPGetConvergedReason(), NEPSetTolerances()
300: @*/
301: PetscErrorCode NEPGetIterationNumber(NEP nep,PetscInt *its)302: {
306: *its = nep->its;
307: return(0);
308: }
312: /*@
313: NEPGetConverged - Gets the number of converged eigenpairs.
315: Not Collective
317: Input Parameter:
318: . nep - the nonlinear eigensolver context
320: Output Parameter:
321: . nconv - number of converged eigenpairs
323: Note:
324: This function should be called after NEPSolve() has finished.
326: Level: beginner
328: .seealso: NEPSetDimensions(), NEPSolve()
329: @*/
330: PetscErrorCode NEPGetConverged(NEP nep,PetscInt *nconv)331: {
335: NEPCheckSolved(nep,1);
336: *nconv = nep->nconv;
337: return(0);
338: }
342: /*@
343: NEPGetConvergedReason - Gets the reason why the NEPSolve() iteration was
344: stopped.
346: Not Collective
348: Input Parameter:
349: . nep - the nonlinear eigensolver context
351: Output Parameter:
352: . reason - negative value indicates diverged, positive value converged
354: Possible values for reason:
355: + NEP_CONVERGED_FNORM_ABS - function norm satisfied absolute tolerance
356: . NEP_CONVERGED_FNORM_RELATIVE - function norm satisfied relative tolerance
357: . NEP_CONVERGED_SNORM_RELATIVE - step norm satisfied relative tolerance
358: . NEP_DIVERGED_LINEAR_SOLVE - inner linear solve failed
359: . NEP_DIVERGED_FUNCTION_COUNT - reached maximum allowed function evaluations
360: . NEP_DIVERGED_MAX_IT - required more than its to reach convergence
361: . NEP_DIVERGED_BREAKDOWN - generic breakdown in method
362: - NEP_DIVERGED_FNORM_NAN - Inf or NaN detected in function evaluation
364: Note:
365: Can only be called after the call to NEPSolve() is complete.
367: Level: intermediate
369: .seealso: NEPSetTolerances(), NEPSolve(), NEPConvergedReason370: @*/
371: PetscErrorCode NEPGetConvergedReason(NEP nep,NEPConvergedReason *reason)372: {
376: NEPCheckSolved(nep,1);
377: *reason = nep->reason;
378: return(0);
379: }
383: /*@
384: NEPGetEigenpair - Gets the i-th solution of the eigenproblem as computed by
385: NEPSolve(). The solution consists in both the eigenvalue and the eigenvector.
387: Logically Collective on NEP389: Input Parameters:
390: + nep - nonlinear eigensolver context
391: - i - index of the solution
393: Output Parameters:
394: + eigr - real part of eigenvalue
395: . eigi - imaginary part of eigenvalue
396: . Vr - real part of eigenvector
397: - Vi - imaginary part of eigenvector
399: Notes:
400: It is allowed to pass NULL for Vr and Vi, if the eigenvector is not
401: required. Otherwise, the caller must provide valid Vec objects, i.e.,
402: they must be created by the calling program with e.g. MatCreateVecs().
404: If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is
405: configured with complex scalars the eigenvalue is stored
406: directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is
407: set to zero). In both cases, the user can pass NULL in eigi and Vi.
409: The index i should be a value between 0 and nconv-1 (see NEPGetConverged()).
410: Eigenpairs are indexed according to the ordering criterion established
411: with NEPSetWhichEigenpairs().
413: Level: beginner
415: .seealso: NEPSolve(), NEPGetConverged(), NEPSetWhichEigenpairs()
416: @*/
417: PetscErrorCode NEPGetEigenpair(NEP nep,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)418: {
419: PetscInt k;
427: NEPCheckSolved(nep,1);
428: if (i<0 || i>=nep->nconv) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
430: NEPComputeVectors(nep);
431: k = nep->perm[i];
433: /* eigenvalue */
434: #if defined(PETSC_USE_COMPLEX)
435: if (eigr) *eigr = nep->eigr[k];
436: if (eigi) *eigi = 0;
437: #else
438: if (eigr) *eigr = nep->eigr[k];
439: if (eigi) *eigi = nep->eigi[k];
440: #endif
442: /* eigenvector */
443: #if defined(PETSC_USE_COMPLEX)
444: if (Vr) { BVCopyVec(nep->V,k,Vr); }
445: if (Vi) { VecSet(Vi,0.0); }
446: #else
447: if (nep->eigi[k]>0) { /* first value of conjugate pair */
448: if (Vr) { BVCopyVec(nep->V,k,Vr); }
449: if (Vi) { BVCopyVec(nep->V,k+1,Vi); }
450: } else if (nep->eigi[k]<0) { /* second value of conjugate pair */
451: if (Vr) { BVCopyVec(nep->V,k-1,Vr); }
452: if (Vi) {
453: BVCopyVec(nep->V,k,Vi);
454: VecScale(Vi,-1.0);
455: }
456: } else { /* real eigenvalue */
457: if (Vr) { BVCopyVec(nep->V,k,Vr); }
458: if (Vi) { VecSet(Vi,0.0); }
459: }
460: #endif
461: return(0);
462: }
466: /*@
467: NEPGetErrorEstimate - Returns the error estimate associated to the i-th
468: computed eigenpair.
470: Not Collective
472: Input Parameter:
473: + nep - nonlinear eigensolver context
474: - i - index of eigenpair
476: Output Parameter:
477: . errest - the error estimate
479: Notes:
480: This is the error estimate used internally by the eigensolver. The actual
481: error bound can be computed with NEPComputeRelativeError().
483: Level: advanced
485: .seealso: NEPComputeRelativeError()
486: @*/
487: PetscErrorCode NEPGetErrorEstimate(NEP nep,PetscInt i,PetscReal *errest)488: {
492: NEPCheckSolved(nep,1);
493: if (i<0 || i>=nep->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
494: if (errest) *errest = nep->errest[nep->perm[i]];
495: return(0);
496: }
500: /*
501: NEPComputeResidualNorm_Private - Computes the norm of the residual vector
502: associated with an eigenpair.
504: Input Parameters:
505: lambda - eigenvalue
506: x - eigenvector
507: w - array of work vectors (only one vector)
508: */
509: PetscErrorCode NEPComputeResidualNorm_Private(NEP nep,PetscScalar lambda,Vec x,Vec *w,PetscReal *norm)510: {
512: Mat T=nep->function;
515: NEPComputeFunction(nep,lambda,T,T);
516: MatMult(T,x,*w);
517: VecNorm(*w,NORM_2,norm);
518: return(0);
519: }
523: /*@
524: NEPComputeError - Computes the error (based on the residual norm) associated
525: with the i-th computed eigenpair.
527: Collective on NEP529: Input Parameter:
530: + nep - the nonlinear eigensolver context
531: . i - the solution index
532: - type - the type of error to compute
534: Output Parameter:
535: . error - the error
537: Notes:
538: The error can be computed in various ways, all of them based on the residual
539: norm computed as ||T(lambda)x||_2 where lambda is the eigenvalue and x is the
540: eigenvector.
542: Level: beginner
544: .seealso: NEPErrorType, NEPSolve(), NEPGetErrorEstimate()
545: @*/
546: PetscErrorCode NEPComputeError(NEP nep,PetscInt i,NEPErrorType type,PetscReal *error)547: {
549: Vec xr,xi=NULL,w;
550: PetscScalar kr,ki;
551: PetscReal er;
558: NEPCheckSolved(nep,1);
560: /* allocate work vectors */
561: #if defined(PETSC_USE_COMPLEX)
562: NEPSetWorkVecs(nep,2);
563: #else
564: NEPSetWorkVecs(nep,3);
565: xi = nep->work[2];
566: #endif
567: xr = nep->work[0];
568: w = nep->work[1];
570: /* compute residual norms */
571: NEPGetEigenpair(nep,i,&kr,&ki,xr,xi);
572: #if !defined(PETSC_USE_COMPLEX)
573: if (ki) SETERRQ(PETSC_COMM_SELF,1,"Not implemented for complex eigenvalues with real scalars");
574: #endif
575: NEPComputeResidualNorm_Private(nep,kr,xr,&w,error);
576: VecNorm(xr,NORM_2,&er);
578: /* compute error */
579: switch (type) {
580: case NEP_ERROR_ABSOLUTE:
581: break;
582: case NEP_ERROR_RELATIVE:
583: *error /= PetscAbsScalar(kr)*er;
584: break;
585: default:586: SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"Invalid error type");
587: }
588: return(0);
589: }
593: /*@
594: NEPComputeFunction - Computes the function matrix T(lambda) that has been
595: set with NEPSetFunction().
597: Collective on NEP and Mat
599: Input Parameters:
600: + nep - the NEP context
601: - lambda - the scalar argument
603: Output Parameters:
604: + A - Function matrix
605: - B - optional preconditioning matrix
607: Notes:
608: NEPComputeFunction() is typically used within nonlinear eigensolvers
609: implementations, so most users would not generally call this routine
610: themselves.
612: Level: developer
614: .seealso: NEPSetFunction(), NEPGetFunction()
615: @*/
616: PetscErrorCode NEPComputeFunction(NEP nep,PetscScalar lambda,Mat A,Mat B)617: {
619: PetscInt i;
620: PetscScalar alpha;
625: if (nep->split) {
627: MatZeroEntries(A);
628: for (i=0;i<nep->nt;i++) {
629: FNEvaluateFunction(nep->f[i],lambda,&alpha);
630: MatAXPY(A,alpha,nep->A[i],nep->mstr);
631: }
632: if (A != B) SETERRQ(PetscObjectComm((PetscObject)nep),1,"Not implemented");
634: } else {
636: if (!nep->computefunction) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_USER,"Must call NEPSetFunction() first");
638: PetscLogEventBegin(NEP_FunctionEval,nep,A,B,0);
640: PetscStackPush("NEP user Function function");
641: (*nep->computefunction)(nep,lambda,A,B,nep->functionctx);
642: PetscStackPop;
644: PetscLogEventEnd(NEP_FunctionEval,nep,A,B,0);
645: nep->nfuncs++;
647: }
648: return(0);
649: }
653: /*@
654: NEPComputeJacobian - Computes the Jacobian matrix T'(lambda) that has been
655: set with NEPSetJacobian().
657: Collective on NEP and Mat
659: Input Parameters:
660: + nep - the NEP context
661: - lambda - the scalar argument
663: Output Parameters:
664: . A - Jacobian matrix
666: Notes:
667: Most users should not need to explicitly call this routine, as it
668: is used internally within the nonlinear eigensolvers.
670: Level: developer
672: .seealso: NEPSetJacobian(), NEPGetJacobian()
673: @*/
674: PetscErrorCode NEPComputeJacobian(NEP nep,PetscScalar lambda,Mat A)675: {
677: PetscInt i;
678: PetscScalar alpha;
683: if (nep->split) {
685: MatZeroEntries(A);
686: for (i=0;i<nep->nt;i++) {
687: FNEvaluateDerivative(nep->f[i],lambda,&alpha);
688: MatAXPY(A,alpha,nep->A[i],nep->mstr);
689: }
691: } else {
693: if (!nep->computejacobian) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_USER,"Must call NEPSetJacobian() first");
695: PetscLogEventBegin(NEP_JacobianEval,nep,A,0,0);
697: PetscStackPush("NEP user Jacobian function");
698: (*nep->computejacobian)(nep,lambda,A,nep->jacobianctx);
699: PetscStackPop;
701: PetscLogEventEnd(NEP_JacobianEval,nep,A,0,0);
703: }
704: return(0);
705: }