Actual source code: nepsolve.c

slepc-3.22.2 2024-12-02
Report Typos and Errors
  1: /*
  2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  4:    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain

  6:    This file is part of SLEPc.
  7:    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
  8:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  9: */
 10: /*
 11:    NEP routines related to the solution process

 13:    References:

 15:        [1] C. Campos and J.E. Roman, "NEP: a module for the parallel solution
 16:            of nonlinear eigenvalue problems in SLEPc", ACM Trans. Math. Soft.
 17:            47(3), 23:1--23:29, 2021.
 18: */

 20: #include <slepc/private/nepimpl.h>
 21: #include <slepc/private/bvimpl.h>
 22: #include <petscdraw.h>

 24: static PetscBool  cited = PETSC_FALSE;
 25: static const char citation[] =
 26:   "@Article{slepc-nep,\n"
 27:   "   author = \"C. Campos and J. E. Roman\",\n"
 28:   "   title = \"{NEP}: a module for the parallel solution of nonlinear eigenvalue problems in {SLEPc}\",\n"
 29:   "   journal = \"{ACM} Trans. Math. Software\",\n"
 30:   "   volume = \"47\",\n"
 31:   "   number = \"3\",\n"
 32:   "   pages = \"23:1--23:29\",\n"
 33:   "   year = \"2021\",\n"
 34:   "   doi = \"10.1145/3447544\"\n"
 35:   "}\n";

 37: PetscErrorCode NEPComputeVectors(NEP nep)
 38: {
 39:   PetscFunctionBegin;
 40:   NEPCheckSolved(nep,1);
 41:   if (nep->state==NEP_STATE_SOLVED) PetscTryTypeMethod(nep,computevectors);
 42:   nep->state = NEP_STATE_EIGENVECTORS;
 43:   PetscFunctionReturn(PETSC_SUCCESS);
 44: }

 46: /*@
 47:    NEPSolve - Solves the nonlinear eigensystem.

 49:    Collective

 51:    Input Parameter:
 52: .  nep - eigensolver context obtained from NEPCreate()

 54:    Options Database Keys:
 55: +  -nep_view - print information about the solver used
 56: .  -nep_view_matk - view the split form matrix Ak (replace k by an integer from 0 to nt-1)
 57: .  -nep_view_fnk - view the split form function fk (replace k by an integer from 0 to nt-1)
 58: .  -nep_view_vectors - view the computed eigenvectors
 59: .  -nep_view_values - view the computed eigenvalues
 60: .  -nep_converged_reason - print reason for convergence, and number of iterations
 61: .  -nep_error_absolute - print absolute errors of each eigenpair
 62: .  -nep_error_relative - print relative errors of each eigenpair
 63: -  -nep_error_backward - print backward errors of each eigenpair

 65:    Notes:
 66:    All the command-line options listed above admit an optional argument specifying
 67:    the viewer type and options. For instance, use '-nep_view_vectors binary:myvecs.bin'
 68:    to save the eigenvectors to a binary file, '-nep_view_values draw' to draw the computed
 69:    eigenvalues graphically, or '-nep_error_relative :myerr.m:ascii_matlab' to save
 70:    the errors in a file that can be executed in Matlab.

 72:    Level: beginner

 74: .seealso: NEPCreate(), NEPSetUp(), NEPDestroy(), NEPSetTolerances()
 75: @*/
 76: PetscErrorCode NEPSolve(NEP nep)
 77: {
 78:   PetscInt       i;
 79:   char           str[16];

 81:   PetscFunctionBegin;
 83:   if (nep->state>=NEP_STATE_SOLVED) PetscFunctionReturn(PETSC_SUCCESS);
 84:   PetscCall(PetscCitationsRegister(citation,&cited));
 85:   PetscCall(PetscLogEventBegin(NEP_Solve,nep,0,0,0));

 87:   /* call setup */
 88:   PetscCall(NEPSetUp(nep));
 89:   nep->nconv = 0;
 90:   nep->its = 0;
 91:   for (i=0;i<nep->ncv;i++) {
 92:     nep->eigr[i]   = 0.0;
 93:     nep->eigi[i]   = 0.0;
 94:     nep->errest[i] = 0.0;
 95:     nep->perm[i]   = i;
 96:   }
 97:   PetscCall(NEPViewFromOptions(nep,NULL,"-nep_view_pre"));
 98:   PetscCall(RGViewFromOptions(nep->rg,NULL,"-rg_view"));

100:   /* call solver */
101:   PetscUseTypeMethod(nep,solve);
102:   PetscCheck(nep->reason,PetscObjectComm((PetscObject)nep),PETSC_ERR_PLIB,"Internal error, solver returned without setting converged reason");
103:   nep->state = NEP_STATE_SOLVED;

105:   /* Only the first nconv columns contain useful information */
106:   PetscCall(BVSetActiveColumns(nep->V,0,nep->nconv));
107:   if (nep->twosided) PetscCall(BVSetActiveColumns(nep->W,0,nep->nconv));

109:   if (nep->refine==NEP_REFINE_SIMPLE && nep->rits>0 && nep->nconv>0) {
110:     PetscCall(NEPComputeVectors(nep));
111:     PetscCall(NEPNewtonRefinementSimple(nep,&nep->rits,nep->rtol,nep->nconv));
112:     nep->state = NEP_STATE_EIGENVECTORS;
113:   }

115:   /* sort eigenvalues according to nep->which parameter */
116:   PetscCall(SlepcSortEigenvalues(nep->sc,nep->nconv,nep->eigr,nep->eigi,nep->perm));
117:   PetscCall(PetscLogEventEnd(NEP_Solve,nep,0,0,0));

119:   /* various viewers */
120:   PetscCall(NEPViewFromOptions(nep,NULL,"-nep_view"));
121:   PetscCall(NEPConvergedReasonViewFromOptions(nep));
122:   PetscCall(NEPErrorViewFromOptions(nep));
123:   PetscCall(NEPValuesViewFromOptions(nep));
124:   PetscCall(NEPVectorsViewFromOptions(nep));
125:   if (nep->fui==NEP_USER_INTERFACE_SPLIT) {
126:     for (i=0;i<nep->nt;i++) {
127:       PetscCall(PetscSNPrintf(str,sizeof(str),"-nep_view_mat%" PetscInt_FMT,i));
128:       PetscCall(MatViewFromOptions(nep->A[i],(PetscObject)nep,str));
129:       PetscCall(PetscSNPrintf(str,sizeof(str),"-nep_view_fn%" PetscInt_FMT,i));
130:       PetscCall(FNViewFromOptions(nep->f[i],(PetscObject)nep,str));
131:     }
132:   }

134:   /* Remove the initial subspace */
135:   nep->nini = 0;

137:   /* Reset resolvent information */
138:   PetscCall(MatDestroy(&nep->resolvent));
139:   PetscFunctionReturn(PETSC_SUCCESS);
140: }

142: /*@
143:    NEPProjectOperator - Computes the projection of the nonlinear operator.

145:    Collective

147:    Input Parameters:
148: +  nep - the nonlinear eigensolver context
149: .  j0  - initial index
150: -  j1  - final index

152:    Notes:
153:    This is available for split operator only.

155:    The nonlinear operator T(lambda) is projected onto span(V), where V is
156:    an orthonormal basis built internally by the solver. The projected
157:    operator is equal to sum_i V'*A_i*V*f_i(lambda), so this function
158:    computes all matrices Ei = V'*A_i*V, and stores them in the extra
159:    matrices inside DS. Only rows/columns in the range [j0,j1-1] are computed,
160:    the previous ones are assumed to be available already.

162:    Level: developer

164: .seealso: NEPSetSplitOperator()
165: @*/
166: PetscErrorCode NEPProjectOperator(NEP nep,PetscInt j0,PetscInt j1)
167: {
168:   PetscInt       k;
169:   Mat            G;

171:   PetscFunctionBegin;
175:   NEPCheckProblem(nep,1);
176:   NEPCheckSplit(nep,1);
177:   PetscCall(BVSetActiveColumns(nep->V,j0,j1));
178:   for (k=0;k<nep->nt;k++) {
179:     PetscCall(DSGetMat(nep->ds,DSMatExtra[k],&G));
180:     PetscCall(BVMatProject(nep->V,nep->A[k],nep->V,G));
181:     PetscCall(DSRestoreMat(nep->ds,DSMatExtra[k],&G));
182:   }
183:   PetscFunctionReturn(PETSC_SUCCESS);
184: }

186: /*@
187:    NEPApplyFunction - Applies the nonlinear function T(lambda) to a given vector.

189:    Collective

191:    Input Parameters:
192: +  nep    - the nonlinear eigensolver context
193: .  lambda - scalar argument
194: .  x      - vector to be multiplied against
195: -  v      - workspace vector (used only in the case of split form)

197:    Output Parameters:
198: +  y   - result vector
199: .  A   - (optional) Function matrix, for callback interface only
200: -  B   - (unused) preconditioning matrix

202:    Note:
203:    If the nonlinear operator is represented in split form, the result
204:    y = T(lambda)*x is computed without building T(lambda) explicitly. In
205:    that case, parameters A and B are not used. Otherwise, the matrix
206:    T(lambda) is built and the effect is the same as a call to
207:    NEPComputeFunction() followed by a MatMult().

209:    Level: developer

211: .seealso: NEPSetSplitOperator(), NEPComputeFunction(), NEPApplyAdjoint()
212: @*/
213: PetscErrorCode NEPApplyFunction(NEP nep,PetscScalar lambda,Vec x,Vec v,Vec y,Mat A,Mat B)
214: {
215:   PetscInt       i;
216:   PetscScalar    alpha;

218:   PetscFunctionBegin;

227:   if (nep->fui==NEP_USER_INTERFACE_SPLIT) {
228:     PetscCall(VecSet(y,0.0));
229:     for (i=0;i<nep->nt;i++) {
230:       PetscCall(FNEvaluateFunction(nep->f[i],lambda,&alpha));
231:       PetscCall(MatMult(nep->A[i],x,v));
232:       PetscCall(VecAXPY(y,alpha,v));
233:     }
234:   } else {
235:     if (!A) A = nep->function;
236:     PetscCall(NEPComputeFunction(nep,lambda,A,A));
237:     PetscCall(MatMult(A,x,y));
238:   }
239:   PetscFunctionReturn(PETSC_SUCCESS);
240: }

242: /*@
243:    NEPApplyAdjoint - Applies the adjoint nonlinear function T(lambda)^* to a given vector.

245:    Collective

247:    Input Parameters:
248: +  nep    - the nonlinear eigensolver context
249: .  lambda - scalar argument
250: .  x      - vector to be multiplied against
251: -  v      - workspace vector (used only in the case of split form)

253:    Output Parameters:
254: +  y   - result vector
255: .  A   - (optional) Function matrix, for callback interface only
256: -  B   - (unused) preconditioning matrix

258:    Level: developer

260: .seealso: NEPSetSplitOperator(), NEPComputeFunction(), NEPApplyFunction()
261: @*/
262: PetscErrorCode NEPApplyAdjoint(NEP nep,PetscScalar lambda,Vec x,Vec v,Vec y,Mat A,Mat B)
263: {
264:   PetscInt       i;
265:   PetscScalar    alpha;
266:   Vec            w;

268:   PetscFunctionBegin;

277:   PetscCall(VecDuplicate(x,&w));
278:   PetscCall(VecCopy(x,w));
279:   PetscCall(VecConjugate(w));
280:   if (nep->fui==NEP_USER_INTERFACE_SPLIT) {
281:     PetscCall(VecSet(y,0.0));
282:     for (i=0;i<nep->nt;i++) {
283:       PetscCall(FNEvaluateFunction(nep->f[i],lambda,&alpha));
284:       PetscCall(MatMultTranspose(nep->A[i],w,v));
285:       PetscCall(VecAXPY(y,alpha,v));
286:     }
287:   } else {
288:     if (!A) A = nep->function;
289:     PetscCall(NEPComputeFunction(nep,lambda,A,A));
290:     PetscCall(MatMultTranspose(A,w,y));
291:   }
292:   PetscCall(VecDestroy(&w));
293:   PetscCall(VecConjugate(y));
294:   PetscFunctionReturn(PETSC_SUCCESS);
295: }

297: /*@
298:    NEPApplyJacobian - Applies the nonlinear Jacobian T'(lambda) to a given vector.

300:    Collective

302:    Input Parameters:
303: +  nep    - the nonlinear eigensolver context
304: .  lambda - scalar argument
305: .  x      - vector to be multiplied against
306: -  v      - workspace vector (used only in the case of split form)

308:    Output Parameters:
309: +  y   - result vector
310: -  A   - (optional) Jacobian matrix, for callback interface only

312:    Note:
313:    If the nonlinear operator is represented in split form, the result
314:    y = T'(lambda)*x is computed without building T'(lambda) explicitly. In
315:    that case, parameter A is not used. Otherwise, the matrix
316:    T'(lambda) is built and the effect is the same as a call to
317:    NEPComputeJacobian() followed by a MatMult().

319:    Level: developer

321: .seealso: NEPSetSplitOperator(), NEPComputeJacobian()
322: @*/
323: PetscErrorCode NEPApplyJacobian(NEP nep,PetscScalar lambda,Vec x,Vec v,Vec y,Mat A)
324: {
325:   PetscInt       i;
326:   PetscScalar    alpha;

328:   PetscFunctionBegin;

336:   if (nep->fui==NEP_USER_INTERFACE_SPLIT) {
337:     PetscCall(VecSet(y,0.0));
338:     for (i=0;i<nep->nt;i++) {
339:       PetscCall(FNEvaluateDerivative(nep->f[i],lambda,&alpha));
340:       PetscCall(MatMult(nep->A[i],x,v));
341:       PetscCall(VecAXPY(y,alpha,v));
342:     }
343:   } else {
344:     if (!A) A = nep->jacobian;
345:     PetscCall(NEPComputeJacobian(nep,lambda,A));
346:     PetscCall(MatMult(A,x,y));
347:   }
348:   PetscFunctionReturn(PETSC_SUCCESS);
349: }

351: /*@
352:    NEPGetIterationNumber - Gets the current iteration number. If the
353:    call to NEPSolve() is complete, then it returns the number of iterations
354:    carried out by the solution method.

356:    Not Collective

358:    Input Parameter:
359: .  nep - the nonlinear eigensolver context

361:    Output Parameter:
362: .  its - number of iterations

364:    Note:
365:    During the i-th iteration this call returns i-1. If NEPSolve() is
366:    complete, then parameter "its" contains either the iteration number at
367:    which convergence was successfully reached, or failure was detected.
368:    Call NEPGetConvergedReason() to determine if the solver converged or
369:    failed and why.

371:    Level: intermediate

373: .seealso: NEPGetConvergedReason(), NEPSetTolerances()
374: @*/
375: PetscErrorCode NEPGetIterationNumber(NEP nep,PetscInt *its)
376: {
377:   PetscFunctionBegin;
379:   PetscAssertPointer(its,2);
380:   *its = nep->its;
381:   PetscFunctionReturn(PETSC_SUCCESS);
382: }

384: /*@
385:    NEPGetConverged - Gets the number of converged eigenpairs.

387:    Not Collective

389:    Input Parameter:
390: .  nep - the nonlinear eigensolver context

392:    Output Parameter:
393: .  nconv - number of converged eigenpairs

395:    Note:
396:    This function should be called after NEPSolve() has finished.

398:    Level: beginner

400: .seealso: NEPSetDimensions(), NEPSolve(), NEPGetEigenpair()
401: @*/
402: PetscErrorCode NEPGetConverged(NEP nep,PetscInt *nconv)
403: {
404:   PetscFunctionBegin;
406:   PetscAssertPointer(nconv,2);
407:   NEPCheckSolved(nep,1);
408:   *nconv = nep->nconv;
409:   PetscFunctionReturn(PETSC_SUCCESS);
410: }

412: /*@
413:    NEPGetConvergedReason - Gets the reason why the NEPSolve() iteration was
414:    stopped.

416:    Not Collective

418:    Input Parameter:
419: .  nep - the nonlinear eigensolver context

421:    Output Parameter:
422: .  reason - negative value indicates diverged, positive value converged

424:    Options Database Key:
425: .  -nep_converged_reason - print the reason to a viewer

427:    Notes:
428:    Possible values for reason are
429: +  NEP_CONVERGED_TOL - converged up to tolerance
430: .  NEP_CONVERGED_USER - converged due to a user-defined condition
431: .  NEP_DIVERGED_ITS - required more than max_it iterations to reach convergence
432: .  NEP_DIVERGED_BREAKDOWN - generic breakdown in method
433: .  NEP_DIVERGED_LINEAR_SOLVE - inner linear solve failed
434: -  NEP_DIVERGED_SUBSPACE_EXHAUSTED - run out of space for the basis in an
435:    unrestarted solver

437:    Can only be called after the call to NEPSolve() is complete.

439:    Level: intermediate

441: .seealso: NEPSetTolerances(), NEPSolve(), NEPConvergedReason
442: @*/
443: PetscErrorCode NEPGetConvergedReason(NEP nep,NEPConvergedReason *reason)
444: {
445:   PetscFunctionBegin;
447:   PetscAssertPointer(reason,2);
448:   NEPCheckSolved(nep,1);
449:   *reason = nep->reason;
450:   PetscFunctionReturn(PETSC_SUCCESS);
451: }

453: /*@
454:    NEPGetEigenpair - Gets the i-th solution of the eigenproblem as computed by
455:    NEPSolve(). The solution consists in both the eigenvalue and the eigenvector.

457:    Collective

459:    Input Parameters:
460: +  nep - nonlinear eigensolver context
461: -  i   - index of the solution

463:    Output Parameters:
464: +  eigr - real part of eigenvalue
465: .  eigi - imaginary part of eigenvalue
466: .  Vr   - real part of eigenvector
467: -  Vi   - imaginary part of eigenvector

469:    Notes:
470:    It is allowed to pass NULL for Vr and Vi, if the eigenvector is not
471:    required. Otherwise, the caller must provide valid Vec objects, i.e.,
472:    they must be created by the calling program with e.g. MatCreateVecs().

474:    If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is
475:    configured with complex scalars the eigenvalue is stored
476:    directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is
477:    set to zero). In any case, the user can pass NULL in Vr or Vi if one of
478:    them is not required.

480:    The index i should be a value between 0 and nconv-1 (see NEPGetConverged()).
481:    Eigenpairs are indexed according to the ordering criterion established
482:    with NEPSetWhichEigenpairs().

484:    Level: beginner

486: .seealso: NEPSolve(), NEPGetConverged(), NEPSetWhichEigenpairs(), NEPGetLeftEigenvector()
487: @*/
488: PetscErrorCode NEPGetEigenpair(NEP nep,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
489: {
490:   PetscInt       k;

492:   PetscFunctionBegin;
497:   NEPCheckSolved(nep,1);
498:   PetscCheck(i>=0,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The index cannot be negative");
499:   PetscCheck(i<nep->nconv,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The index can be nconv-1 at most, see NEPGetConverged()");

501:   PetscCall(NEPComputeVectors(nep));
502:   k = nep->perm[i];

504:   /* eigenvalue */
505: #if defined(PETSC_USE_COMPLEX)
506:   if (eigr) *eigr = nep->eigr[k];
507:   if (eigi) *eigi = 0;
508: #else
509:   if (eigr) *eigr = nep->eigr[k];
510:   if (eigi) *eigi = nep->eigi[k];
511: #endif

513:   /* eigenvector */
514:   PetscCall(BV_GetEigenvector(nep->V,k,nep->eigi[k],Vr,Vi));
515:   PetscFunctionReturn(PETSC_SUCCESS);
516: }

518: /*@
519:    NEPGetLeftEigenvector - Gets the i-th left eigenvector as computed by NEPSolve().

521:    Collective

523:    Input Parameters:
524: +  nep - eigensolver context
525: -  i   - index of the solution

527:    Output Parameters:
528: +  Wr   - real part of left eigenvector
529: -  Wi   - imaginary part of left eigenvector

531:    Notes:
532:    The caller must provide valid Vec objects, i.e., they must be created
533:    by the calling program with e.g. MatCreateVecs().

535:    If the corresponding eigenvalue is real, then Wi is set to zero. If PETSc is
536:    configured with complex scalars the eigenvector is stored directly in Wr
537:    (Wi is set to zero). In any case, the user can pass NULL in Wr or Wi if one of
538:    them is not required.

540:    The index i should be a value between 0 and nconv-1 (see NEPGetConverged()).
541:    Eigensolutions are indexed according to the ordering criterion established
542:    with NEPSetWhichEigenpairs().

544:    Left eigenvectors are available only if the twosided flag was set, see
545:    NEPSetTwoSided().

547:    Level: intermediate

549: .seealso: NEPGetEigenpair(), NEPGetConverged(), NEPSetWhichEigenpairs(), NEPSetTwoSided()
550: @*/
551: PetscErrorCode NEPGetLeftEigenvector(NEP nep,PetscInt i,Vec Wr,Vec Wi)
552: {
553:   PetscInt       k;

555:   PetscFunctionBegin;
560:   NEPCheckSolved(nep,1);
561:   PetscCheck(nep->twosided,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with NEPSetTwoSided");
562:   PetscCheck(i>=0,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The index cannot be negative");
563:   PetscCheck(i<nep->nconv,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The index can be nconv-1 at most, see NEPGetConverged()");
564:   PetscCall(NEPComputeVectors(nep));
565:   k = nep->perm[i];
566:   PetscCall(BV_GetEigenvector(nep->W,k,nep->eigi[k],Wr,Wi));
567:   PetscFunctionReturn(PETSC_SUCCESS);
568: }

570: /*@
571:    NEPGetErrorEstimate - Returns the error estimate associated to the i-th
572:    computed eigenpair.

574:    Not Collective

576:    Input Parameters:
577: +  nep - nonlinear eigensolver context
578: -  i   - index of eigenpair

580:    Output Parameter:
581: .  errest - the error estimate

583:    Notes:
584:    This is the error estimate used internally by the eigensolver. The actual
585:    error bound can be computed with NEPComputeError().

587:    Level: advanced

589: .seealso: NEPComputeError()
590: @*/
591: PetscErrorCode NEPGetErrorEstimate(NEP nep,PetscInt i,PetscReal *errest)
592: {
593:   PetscFunctionBegin;
595:   PetscAssertPointer(errest,3);
596:   NEPCheckSolved(nep,1);
597:   PetscCheck(i>=0,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The index cannot be negative");
598:   PetscCheck(i<nep->nconv,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The index can be nconv-1 at most, see NEPGetConverged()");
599:   *errest = nep->errest[nep->perm[i]];
600:   PetscFunctionReturn(PETSC_SUCCESS);
601: }

603: /*
604:    NEPComputeResidualNorm_Private - Computes the norm of the residual vector
605:    associated with an eigenpair.

607:    Input Parameters:
608:      adj    - whether the adjoint T^* must be used instead of T
609:      lambda - eigenvalue
610:      x      - eigenvector
611:      w      - array of work vectors (two vectors in split form, one vector otherwise)
612: */
613: PetscErrorCode NEPComputeResidualNorm_Private(NEP nep,PetscBool adj,PetscScalar lambda,Vec x,Vec *w,PetscReal *norm)
614: {
615:   Vec            y,z=NULL;

617:   PetscFunctionBegin;
618:   y = w[0];
619:   if (nep->fui==NEP_USER_INTERFACE_SPLIT) z = w[1];
620:   if (adj) PetscCall(NEPApplyAdjoint(nep,lambda,x,z,y,NULL,NULL));
621:   else PetscCall(NEPApplyFunction(nep,lambda,x,z,y,NULL,NULL));
622:   PetscCall(VecNorm(y,NORM_2,norm));
623:   PetscFunctionReturn(PETSC_SUCCESS);
624: }

626: /*@
627:    NEPComputeError - Computes the error (based on the residual norm) associated
628:    with the i-th computed eigenpair.

630:    Collective

632:    Input Parameters:
633: +  nep  - the nonlinear eigensolver context
634: .  i    - the solution index
635: -  type - the type of error to compute

637:    Output Parameter:
638: .  error - the error

640:    Notes:
641:    The error can be computed in various ways, all of them based on the residual
642:    norm computed as ||T(lambda)x||_2 where lambda is the eigenvalue and x is the
643:    eigenvector.

645:    Level: beginner

647: .seealso: NEPErrorType, NEPSolve(), NEPGetErrorEstimate()
648: @*/
649: PetscErrorCode NEPComputeError(NEP nep,PetscInt i,NEPErrorType type,PetscReal *error)
650: {
651:   Vec            xr,xi=NULL;
652:   PetscInt       j,nwork,issplit=0;
653:   PetscScalar    kr,ki,s;
654:   PetscReal      er,z=0.0,errorl,nrm;
655:   PetscBool      flg;

657:   PetscFunctionBegin;
661:   PetscAssertPointer(error,4);
662:   NEPCheckSolved(nep,1);

664:   /* allocate work vectors */
665: #if defined(PETSC_USE_COMPLEX)
666:   nwork = 2;
667: #else
668:   nwork = 3;
669: #endif
670:   if (nep->fui==NEP_USER_INTERFACE_SPLIT) {
671:     issplit = 1;
672:     nwork++;  /* need an extra work vector for NEPComputeResidualNorm_Private */
673:   }
674:   PetscCall(NEPSetWorkVecs(nep,nwork));
675:   xr = nep->work[issplit+1];
676: #if !defined(PETSC_USE_COMPLEX)
677:   xi = nep->work[issplit+2];
678: #endif

680:   /* compute residual norms */
681:   PetscCall(NEPGetEigenpair(nep,i,&kr,&ki,xr,xi));
682: #if !defined(PETSC_USE_COMPLEX)
683:   PetscCheck(ki==0.0,PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"Not implemented for complex eigenvalues with real scalars");
684: #endif
685:   PetscCall(NEPComputeResidualNorm_Private(nep,PETSC_FALSE,kr,xr,nep->work,error));
686:   PetscCall(VecNorm(xr,NORM_2,&er));

688:   /* if two-sided, compute left residual norm and take the maximum */
689:   if (nep->twosided) {
690:     PetscCall(NEPGetLeftEigenvector(nep,i,xr,xi));
691:     PetscCall(NEPComputeResidualNorm_Private(nep,PETSC_TRUE,kr,xr,nep->work,&errorl));
692:     *error = PetscMax(*error,errorl);
693:   }

695:   /* compute error */
696:   switch (type) {
697:     case NEP_ERROR_ABSOLUTE:
698:       break;
699:     case NEP_ERROR_RELATIVE:
700:       *error /= PetscAbsScalar(kr)*er;
701:       break;
702:     case NEP_ERROR_BACKWARD:
703:       if (nep->fui!=NEP_USER_INTERFACE_SPLIT) {
704:         PetscCall(NEPComputeFunction(nep,kr,nep->function,nep->function));
705:         PetscCall(MatHasOperation(nep->function,MATOP_NORM,&flg));
706:         PetscCheck(flg,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_WRONG,"The computation of backward errors requires a matrix norm operation");
707:         PetscCall(MatNorm(nep->function,NORM_INFINITY,&nrm));
708:         *error /= nrm*er;
709:         break;
710:       }
711:       /* initialization of matrix norms */
712:       if (!nep->nrma[0]) {
713:         for (j=0;j<nep->nt;j++) {
714:           PetscCall(MatHasOperation(nep->A[j],MATOP_NORM,&flg));
715:           PetscCheck(flg,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_WRONG,"The computation of backward errors requires a matrix norm operation");
716:           PetscCall(MatNorm(nep->A[j],NORM_INFINITY,&nep->nrma[j]));
717:         }
718:       }
719:       for (j=0;j<nep->nt;j++) {
720:         PetscCall(FNEvaluateFunction(nep->f[j],kr,&s));
721:         z = z + nep->nrma[j]*PetscAbsScalar(s);
722:       }
723:       *error /= z*er;
724:       break;
725:     default:
726:       SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"Invalid error type");
727:   }
728:   PetscFunctionReturn(PETSC_SUCCESS);
729: }

731: /*@
732:    NEPComputeFunction - Computes the function matrix T(lambda) that has been
733:    set with NEPSetFunction().

735:    Collective

737:    Input Parameters:
738: +  nep    - the NEP context
739: -  lambda - the scalar argument

741:    Output Parameters:
742: +  A   - Function matrix
743: -  B   - optional preconditioning matrix

745:    Notes:
746:    NEPComputeFunction() is typically used within nonlinear eigensolvers
747:    implementations, so most users would not generally call this routine
748:    themselves.

750:    Level: developer

752: .seealso: NEPSetFunction(), NEPGetFunction()
753: @*/
754: PetscErrorCode NEPComputeFunction(NEP nep,PetscScalar lambda,Mat A,Mat B)
755: {
756:   PetscInt       i;
757:   PetscScalar    alpha;

759:   PetscFunctionBegin;
761:   NEPCheckProblem(nep,1);
762:   switch (nep->fui) {
763:   case NEP_USER_INTERFACE_CALLBACK:
764:     PetscCheck(nep->computefunction,PetscObjectComm((PetscObject)nep),PETSC_ERR_USER,"Must call NEPSetFunction() first");
765:     PetscCall(PetscLogEventBegin(NEP_FunctionEval,nep,A,B,0));
766:     PetscCallBack("NEP user Function function",(*nep->computefunction)(nep,lambda,A,B,nep->functionctx));
767:     PetscCall(PetscLogEventEnd(NEP_FunctionEval,nep,A,B,0));
768:     break;
769:   case NEP_USER_INTERFACE_SPLIT:
770:     PetscCall(MatZeroEntries(A));
771:     if (A != B) PetscCall(MatZeroEntries(B));
772:     for (i=0;i<nep->nt;i++) {
773:       PetscCall(FNEvaluateFunction(nep->f[i],lambda,&alpha));
774:       PetscCall(MatAXPY(A,alpha,nep->A[i],nep->mstr));
775:       if (A != B) PetscCall(MatAXPY(B,alpha,nep->P[i],nep->mstrp));
776:     }
777:     break;
778:   }
779:   PetscFunctionReturn(PETSC_SUCCESS);
780: }

782: /*@
783:    NEPComputeJacobian - Computes the Jacobian matrix T'(lambda) that has been
784:    set with NEPSetJacobian().

786:    Collective

788:    Input Parameters:
789: +  nep    - the NEP context
790: -  lambda - the scalar argument

792:    Output Parameters:
793: .  A   - Jacobian matrix

795:    Notes:
796:    Most users should not need to explicitly call this routine, as it
797:    is used internally within the nonlinear eigensolvers.

799:    Level: developer

801: .seealso: NEPSetJacobian(), NEPGetJacobian()
802: @*/
803: PetscErrorCode NEPComputeJacobian(NEP nep,PetscScalar lambda,Mat A)
804: {
805:   PetscInt       i;
806:   PetscScalar    alpha;

808:   PetscFunctionBegin;
810:   NEPCheckProblem(nep,1);
811:   switch (nep->fui) {
812:   case NEP_USER_INTERFACE_CALLBACK:
813:     PetscCheck(nep->computejacobian,PetscObjectComm((PetscObject)nep),PETSC_ERR_USER,"Must call NEPSetJacobian() first");
814:     PetscCall(PetscLogEventBegin(NEP_JacobianEval,nep,A,0,0));
815:     PetscCallBack("NEP user Jacobian function",(*nep->computejacobian)(nep,lambda,A,nep->jacobianctx));
816:     PetscCall(PetscLogEventEnd(NEP_JacobianEval,nep,A,0,0));
817:     break;
818:   case NEP_USER_INTERFACE_SPLIT:
819:     PetscCall(MatZeroEntries(A));
820:     for (i=0;i<nep->nt;i++) {
821:       PetscCall(FNEvaluateDerivative(nep->f[i],lambda,&alpha));
822:       PetscCall(MatAXPY(A,alpha,nep->A[i],nep->mstr));
823:     }
824:     break;
825:   }
826:   PetscFunctionReturn(PETSC_SUCCESS);
827: }