1: /*
2: NEP routines related to the solution process.
4: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5: SLEPc - Scalable Library for Eigenvalue Problem Computations
6: Copyright (c) 2002-2016, 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: if (nep->state>=NEP_STATE_SOLVED) return(0);
78: PetscLogEventBegin(NEP_Solve,nep,0,0,0);
80: /* call setup */
81: NEPSetUp(nep);
82: nep->nconv = 0;
83: nep->its = 0;
84: for (i=0;i<nep->ncv;i++) {
85: nep->eigr[i] = 0.0;
86: nep->eigi[i] = 0.0;
87: nep->errest[i] = 0.0;
88: nep->perm[i] = i;
89: }
90: NEPViewFromOptions(nep,NULL,"-nep_view_pre");
92: (*nep->ops->solve)(nep);
93: nep->state = NEP_STATE_SOLVED;
95: if (!nep->reason) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_PLIB,"Internal error, solver returned without setting converged reason");
97: if (nep->refine==NEP_REFINE_SIMPLE && nep->rits>0 && nep->nconv>0) {
98: NEPComputeVectors(nep);
99: NEPNewtonRefinementSimple(nep,&nep->rits,nep->rtol,nep->nconv);
100: nep->state = NEP_STATE_EIGENVECTORS;
101: }
103: /* sort eigenvalues according to nep->which parameter */
104: SlepcSortEigenvalues(nep->sc,nep->nconv,nep->eigr,nep->eigi,nep->perm);
105: PetscLogEventEnd(NEP_Solve,nep,0,0,0);
107: /* various viewers */
108: NEPViewFromOptions(nep,NULL,"-nep_view");
109: NEPReasonViewFromOptions(nep);
110: NEPErrorViewFromOptions(nep);
111: NEPValuesViewFromOptions(nep);
112: NEPVectorsViewFromOptions(nep);
114: /* Remove the initial subspace */
115: nep->nini = 0;
116: return(0);
117: }
121: /*@
122: NEPProjectOperator - Computes the projection of the nonlinear operator.
124: Collective on NEP126: Input Parameters:
127: + nep - the nonlinear eigensolver context
128: . j0 - initial index
129: - j1 - final index
131: Notes:
132: This is available for split operator only.
134: The nonlinear operator T(lambda) is projected onto span(V), where V is
135: an orthonormal basis built internally by the solver. The projected
136: operator is equal to sum_i V'*A_i*V*f_i(lambda), so this function
137: computes all matrices Ei = V'*A_i*V, and stores them in the extra
138: matrices inside DS. Only rows/columns in the range [j0,j1-1] are computed,
139: the previous ones are assumed to be available already.
141: Level: developer
143: .seealso: NEPSetSplitOperator()
144: @*/
145: PetscErrorCode NEPProjectOperator(NEP nep,PetscInt j0,PetscInt j1)146: {
148: PetscInt k;
149: Mat G;
155: NEPCheckProblem(nep,1);
156: NEPCheckSplit(nep,1);
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 (used only in the case of split form)
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;
210: if (nep->fui==NEP_USER_INTERFACE_SPLIT) {
211: VecSet(y,0.0);
212: for (i=0;i<nep->nt;i++) {
213: FNEvaluateFunction(nep->f[i],lambda,&alpha);
214: MatMult(nep->A[i],x,v);
215: VecAXPY(y,alpha,v);
216: }
217: } else {
218: NEPComputeFunction(nep,lambda,A,B);
219: MatMult(A,x,y);
220: }
221: return(0);
222: }
226: /*@
227: NEPApplyJacobian - Applies the nonlinear Jacobian T'(lambda) to a given vector.
229: Collective on NEP231: Input Parameters:
232: + nep - the nonlinear eigensolver context
233: . lambda - scalar argument
234: . x - vector to be multiplied against
235: - v - workspace vector (used only in the case of split form)
237: Output Parameters:
238: + y - result vector
239: - A - Jacobian matrix
241: Note:
242: If the nonlinear operator is represented in split form, the result
243: y = T'(lambda)*x is computed without building T'(lambda) explicitly. In
244: that case, parameter A is not used. Otherwise, the matrix
245: T'(lambda) is built and the effect is the same as a call to
246: NEPComputeJacobian() followed by a MatMult().
248: Level: developer
250: .seealso: NEPSetSplitOperator(), NEPComputeJacobian()
251: @*/
252: PetscErrorCode NEPApplyJacobian(NEP nep,PetscScalar lambda,Vec x,Vec v,Vec y,Mat A)253: {
255: PetscInt i;
256: PetscScalar alpha;
266: if (nep->fui==NEP_USER_INTERFACE_SPLIT) {
267: VecSet(y,0.0);
268: for (i=0;i<nep->nt;i++) {
269: FNEvaluateDerivative(nep->f[i],lambda,&alpha);
270: MatMult(nep->A[i],x,v);
271: VecAXPY(y,alpha,v);
272: }
273: } else {
274: NEPComputeJacobian(nep,lambda,A);
275: MatMult(A,x,y);
276: }
277: return(0);
278: }
282: /*@
283: NEPGetIterationNumber - Gets the current iteration number. If the
284: call to NEPSolve() is complete, then it returns the number of iterations
285: carried out by the solution method.
287: Not Collective
289: Input Parameter:
290: . nep - the nonlinear 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 NEPSolve() is
299: complete, then parameter "its" contains either the iteration number at
300: which convergence was successfully reached, or failure was detected.
301: Call NEPGetConvergedReason() to determine if the solver converged or
302: failed and why.
304: .seealso: NEPGetConvergedReason(), NEPSetTolerances()
305: @*/
306: PetscErrorCode NEPGetIterationNumber(NEP nep,PetscInt *its)307: {
311: *its = nep->its;
312: return(0);
313: }
317: /*@
318: NEPGetConverged - Gets the number of converged eigenpairs.
320: Not Collective
322: Input Parameter:
323: . nep - the nonlinear eigensolver context
325: Output Parameter:
326: . nconv - number of converged eigenpairs
328: Note:
329: This function should be called after NEPSolve() has finished.
331: Level: beginner
333: .seealso: NEPSetDimensions(), NEPSolve()
334: @*/
335: PetscErrorCode NEPGetConverged(NEP nep,PetscInt *nconv)336: {
340: NEPCheckSolved(nep,1);
341: *nconv = nep->nconv;
342: return(0);
343: }
347: /*@
348: NEPGetConvergedReason - Gets the reason why the NEPSolve() iteration was
349: stopped.
351: Not Collective
353: Input Parameter:
354: . nep - the nonlinear eigensolver context
356: Output Parameter:
357: . reason - negative value indicates diverged, positive value converged
359: Notes:
361: Possible values for reason are
362: + NEP_CONVERGED_TOL - converged up to tolerance
363: . NEP_CONVERGED_USER - converged due to a user-defined condition
364: . NEP_DIVERGED_ITS - required more than max_it iterations to reach convergence
365: . NEP_DIVERGED_BREAKDOWN - generic breakdown in method
366: - NEP_DIVERGED_LINEAR_SOLVE - inner linear solve failed
368: Can only be called after the call to NEPSolve() is complete.
370: Level: intermediate
372: .seealso: NEPSetTolerances(), NEPSolve(), NEPConvergedReason373: @*/
374: PetscErrorCode NEPGetConvergedReason(NEP nep,NEPConvergedReason *reason)375: {
379: NEPCheckSolved(nep,1);
380: *reason = nep->reason;
381: return(0);
382: }
386: /*@
387: NEPGetEigenpair - Gets the i-th solution of the eigenproblem as computed by
388: NEPSolve(). The solution consists in both the eigenvalue and the eigenvector.
390: Logically Collective on NEP392: Input Parameters:
393: + nep - nonlinear eigensolver context
394: - i - index of the solution
396: Output Parameters:
397: + eigr - real part of eigenvalue
398: . eigi - imaginary part of eigenvalue
399: . Vr - real part of eigenvector
400: - Vi - imaginary part of eigenvector
402: Notes:
403: It is allowed to pass NULL for Vr and Vi, if the eigenvector is not
404: required. Otherwise, the caller must provide valid Vec objects, i.e.,
405: they must be created by the calling program with e.g. MatCreateVecs().
407: If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is
408: configured with complex scalars the eigenvalue is stored
409: directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is
410: set to zero). In both cases, the user can pass NULL in eigi and Vi.
412: The index i should be a value between 0 and nconv-1 (see NEPGetConverged()).
413: Eigenpairs are indexed according to the ordering criterion established
414: with NEPSetWhichEigenpairs().
416: Level: beginner
418: .seealso: NEPSolve(), NEPGetConverged(), NEPSetWhichEigenpairs()
419: @*/
420: PetscErrorCode NEPGetEigenpair(NEP nep,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)421: {
422: PetscInt k;
430: NEPCheckSolved(nep,1);
431: if (i<0 || i>=nep->nconv) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
433: NEPComputeVectors(nep);
434: k = nep->perm[i];
436: /* eigenvalue */
437: #if defined(PETSC_USE_COMPLEX)
438: if (eigr) *eigr = nep->eigr[k];
439: if (eigi) *eigi = 0;
440: #else
441: if (eigr) *eigr = nep->eigr[k];
442: if (eigi) *eigi = nep->eigi[k];
443: #endif
445: /* eigenvector */
446: #if defined(PETSC_USE_COMPLEX)
447: if (Vr) { BVCopyVec(nep->V,k,Vr); }
448: if (Vi) { VecSet(Vi,0.0); }
449: #else
450: if (nep->eigi[k]>0) { /* first value of conjugate pair */
451: if (Vr) { BVCopyVec(nep->V,k,Vr); }
452: if (Vi) { BVCopyVec(nep->V,k+1,Vi); }
453: } else if (nep->eigi[k]<0) { /* second value of conjugate pair */
454: if (Vr) { BVCopyVec(nep->V,k-1,Vr); }
455: if (Vi) {
456: BVCopyVec(nep->V,k,Vi);
457: VecScale(Vi,-1.0);
458: }
459: } else { /* real eigenvalue */
460: if (Vr) { BVCopyVec(nep->V,k,Vr); }
461: if (Vi) { VecSet(Vi,0.0); }
462: }
463: #endif
464: return(0);
465: }
469: /*@
470: NEPGetErrorEstimate - Returns the error estimate associated to the i-th
471: computed eigenpair.
473: Not Collective
475: Input Parameter:
476: + nep - nonlinear eigensolver context
477: - i - index of eigenpair
479: Output Parameter:
480: . errest - the error estimate
482: Notes:
483: This is the error estimate used internally by the eigensolver. The actual
484: error bound can be computed with NEPComputeRelativeError().
486: Level: advanced
488: .seealso: NEPComputeRelativeError()
489: @*/
490: PetscErrorCode NEPGetErrorEstimate(NEP nep,PetscInt i,PetscReal *errest)491: {
495: NEPCheckSolved(nep,1);
496: if (i<0 || i>=nep->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
497: if (errest) *errest = nep->errest[nep->perm[i]];
498: return(0);
499: }
503: /*
504: NEPComputeResidualNorm_Private - Computes the norm of the residual vector
505: associated with an eigenpair.
507: Input Parameters:
508: lambda - eigenvalue
509: x - eigenvector
510: w - array of work vectors (two vectors in split form, one vector otherwise)
511: */
512: PetscErrorCode NEPComputeResidualNorm_Private(NEP nep,PetscScalar lambda,Vec x,Vec *w,PetscReal *norm)513: {
515: Vec y,z=NULL;
518: y = w[0];
519: if (nep->fui==NEP_USER_INTERFACE_SPLIT) z = w[1];
520: NEPApplyFunction(nep,lambda,x,z,y,nep->function,nep->function_pre);
521: VecNorm(y,NORM_2,norm);
522: return(0);
523: }
527: /*@
528: NEPComputeError - Computes the error (based on the residual norm) associated
529: with the i-th computed eigenpair.
531: Collective on NEP533: Input Parameter:
534: + nep - the nonlinear eigensolver context
535: . i - the solution index
536: - type - the type of error to compute
538: Output Parameter:
539: . error - the error
541: Notes:
542: The error can be computed in various ways, all of them based on the residual
543: norm computed as ||T(lambda)x||_2 where lambda is the eigenvalue and x is the
544: eigenvector.
546: Level: beginner
548: .seealso: NEPErrorType, NEPSolve(), NEPGetErrorEstimate()
549: @*/
550: PetscErrorCode NEPComputeError(NEP nep,PetscInt i,NEPErrorType type,PetscReal *error)551: {
553: Vec xr,xi=NULL;
554: PetscInt j,nwork,issplit=0;
555: PetscScalar kr,ki,s;
556: PetscReal er,z=0.0;
557: PetscBool flg;
564: NEPCheckSolved(nep,1);
566: /* allocate work vectors */
567: #if defined(PETSC_USE_COMPLEX)
568: nwork = 2;
569: #else
570: nwork = 3;
571: #endif
572: if (nep->fui==NEP_USER_INTERFACE_SPLIT) {
573: issplit = 1;
574: nwork++; /* need an extra work vector for NEPComputeResidualNorm_Private */
575: }
576: NEPSetWorkVecs(nep,nwork);
577: xr = nep->work[issplit+1];
578: #if !defined(PETSC_USE_COMPLEX)
579: xi = nep->work[issplit+2];
580: #endif
582: /* compute residual norms */
583: NEPGetEigenpair(nep,i,&kr,&ki,xr,xi);
584: #if !defined(PETSC_USE_COMPLEX)
585: if (ki) SETERRQ(PETSC_COMM_SELF,1,"Not implemented for complex eigenvalues with real scalars");
586: #endif
587: NEPComputeResidualNorm_Private(nep,kr,xr,nep->work,error);
588: VecNorm(xr,NORM_2,&er);
590: /* compute error */
591: switch (type) {
592: case NEP_ERROR_ABSOLUTE:
593: break;
594: case NEP_ERROR_RELATIVE:
595: *error /= PetscAbsScalar(kr)*er;
596: break;
597: case NEP_ERROR_BACKWARD:
598: if (nep->fui!=NEP_USER_INTERFACE_SPLIT) {
599: *error = 0.0;
600: PetscInfo(nep,"Backward error only available in split form\n");
601: break;
602: }
603: /* initialization of matrix norms */
604: if (!nep->nrma[0]) {
605: for (j=0;j<nep->nt;j++) {
606: MatHasOperation(nep->A[j],MATOP_NORM,&flg);
607: if (!flg) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_WRONG,"The computation of backward errors requires a matrix norm operation");
608: MatNorm(nep->A[j],NORM_INFINITY,&nep->nrma[j]);
609: }
610: }
611: for (j=0;j<nep->nt;j++) {
612: FNEvaluateFunction(nep->f[j],kr,&s);
613: z = z + nep->nrma[j]*PetscAbsScalar(s);
614: }
615: *error /= z;
616: break;
617: default:618: SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"Invalid error type");
619: }
620: return(0);
621: }
625: /*@
626: NEPComputeFunction - Computes the function matrix T(lambda) that has been
627: set with NEPSetFunction().
629: Collective on NEP and Mat
631: Input Parameters:
632: + nep - the NEP context
633: - lambda - the scalar argument
635: Output Parameters:
636: + A - Function matrix
637: - B - optional preconditioning matrix
639: Notes:
640: NEPComputeFunction() is typically used within nonlinear eigensolvers
641: implementations, so most users would not generally call this routine
642: themselves.
644: Level: developer
646: .seealso: NEPSetFunction(), NEPGetFunction()
647: @*/
648: PetscErrorCode NEPComputeFunction(NEP nep,PetscScalar lambda,Mat A,Mat B)649: {
651: PetscInt i;
652: PetscScalar alpha;
656: NEPCheckProblem(nep,1);
657: switch (nep->fui) {
658: case NEP_USER_INTERFACE_CALLBACK:
659: if (!nep->computefunction) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_USER,"Must call NEPSetFunction() first");
660: PetscLogEventBegin(NEP_FunctionEval,nep,A,B,0);
661: PetscStackPush("NEP user Function function");
662: (*nep->computefunction)(nep,lambda,A,B,nep->functionctx);
663: PetscStackPop;
664: PetscLogEventEnd(NEP_FunctionEval,nep,A,B,0);
665: break;
666: case NEP_USER_INTERFACE_SPLIT:
667: MatZeroEntries(A);
668: for (i=0;i<nep->nt;i++) {
669: FNEvaluateFunction(nep->f[i],lambda,&alpha);
670: MatAXPY(A,alpha,nep->A[i],nep->mstr);
671: }
672: if (A != B) SETERRQ(PetscObjectComm((PetscObject)nep),1,"Not implemented");
673: break;
674: case NEP_USER_INTERFACE_DERIVATIVES:
675: PetscLogEventBegin(NEP_DerivativesEval,nep,A,B,0);
676: PetscStackPush("NEP user Derivatives function");
677: (*nep->computederivatives)(nep,lambda,0,A,nep->derivativesctx);
678: PetscStackPop;
679: PetscLogEventEnd(NEP_DerivativesEval,nep,A,B,0);
680: break;
681: }
682: return(0);
683: }
687: /*@
688: NEPComputeJacobian - Computes the Jacobian matrix T'(lambda) that has been
689: set with NEPSetJacobian().
691: Collective on NEP and Mat
693: Input Parameters:
694: + nep - the NEP context
695: - lambda - the scalar argument
697: Output Parameters:
698: . A - Jacobian matrix
700: Notes:
701: Most users should not need to explicitly call this routine, as it
702: is used internally within the nonlinear eigensolvers.
704: Level: developer
706: .seealso: NEPSetJacobian(), NEPGetJacobian()
707: @*/
708: PetscErrorCode NEPComputeJacobian(NEP nep,PetscScalar lambda,Mat A)709: {
711: PetscInt i;
712: PetscScalar alpha;
716: NEPCheckProblem(nep,1);
717: switch (nep->fui) {
718: case NEP_USER_INTERFACE_CALLBACK:
719: if (!nep->computejacobian) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_USER,"Must call NEPSetJacobian() first");
720: PetscLogEventBegin(NEP_JacobianEval,nep,A,0,0);
721: PetscStackPush("NEP user Jacobian function");
722: (*nep->computejacobian)(nep,lambda,A,nep->jacobianctx);
723: PetscStackPop;
724: PetscLogEventEnd(NEP_JacobianEval,nep,A,0,0);
725: break;
726: case NEP_USER_INTERFACE_SPLIT:
727: MatZeroEntries(A);
728: for (i=0;i<nep->nt;i++) {
729: FNEvaluateDerivative(nep->f[i],lambda,&alpha);
730: MatAXPY(A,alpha,nep->A[i],nep->mstr);
731: }
732: break;
733: case NEP_USER_INTERFACE_DERIVATIVES:
734: PetscLogEventBegin(NEP_DerivativesEval,nep,A,0,0);
735: PetscStackPush("NEP user Derivatives function");
736: (*nep->computederivatives)(nep,lambda,1,A,nep->derivativesctx);
737: PetscStackPop;
738: PetscLogEventEnd(NEP_DerivativesEval,nep,A,0,0);
739: break;
740: }
741: return(0);
742: }