Actual source code: nepsolve.c

slepc-3.6.1 2015-09-03
Report Typos and Errors
  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 NEP

127:    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 NEP

173:    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 NEP

228:    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(), NEPConvergedReason
370: @*/
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 NEP

389:    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 NEP

529:    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: }