Date: 2026-03-31T13:23:32+00:00

Actual source code: krylovschur.c

      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:    SLEPc eigensolver: "krylovschur"

     13:    Method: Krylov-Schur

     15:    Algorithm:

     17:        Single-vector Krylov-Schur method for non-symmetric problems,
     18:        including harmonic extraction.

     20:    References:

     22:        [1] "Krylov-Schur Methods in SLEPc", SLEPc Technical Report STR-7,
     23:            available at https://slepc.upv.es.

     25:        [2] G.W. Stewart, "A Krylov-Schur Algorithm for Large Eigenproblems",
     26:            SIAM J. Matrix Anal. App. 23(3):601-614, 2001.

     28:        [3] "Practical Implementation of Harmonic Krylov-Schur", SLEPc Technical
     29:             Report STR-9, available at https://slepc.upv.es.
     30: */

     32: #include <slepc/private/epsimpl.h>
     33: #include "krylovschur.h"

     35: PetscErrorCode EPSGetArbitraryValues(EPS eps,PetscScalar *rr,PetscScalar *ri)
     36: {
     37:   PetscInt       i,newi,ld,n,l;
     38:   Vec            xr=eps->work[0],xi=eps->work[1];
     39:   PetscScalar    re,im,*Zr,*Zi,*X;

     41:   PetscFunctionBegin;
     42:   PetscCall(DSGetLeadingDimension(eps->ds,&ld));
     43:   PetscCall(DSGetDimensions(eps->ds,&n,&l,NULL,NULL));
     44:   for (i=l;i<n;i++) {
     45:     re = eps->eigr[i];
     46:     im = eps->eigi[i];
     47:     PetscCall(STBackTransform(eps->st,1,&re,&im));
     48:     newi = i;
     49:     PetscCall(DSVectors(eps->ds,DS_MAT_X,&newi,NULL));
     50:     PetscCall(DSGetArray(eps->ds,DS_MAT_X,&X));
     51:     Zr = X+i*ld;
     52:     if (newi==i+1) Zi = X+newi*ld;
     53:     else Zi = NULL;
     54:     PetscCall(EPSComputeRitzVector(eps,Zr,Zi,eps->V,xr,xi));
     55:     PetscCall(DSRestoreArray(eps->ds,DS_MAT_X,&X));
     56:     PetscCall((*eps->arbitrary)(re,im,xr,xi,rr+i,ri+i,eps->arbitraryctx));
     57:   }
     58:   PetscFunctionReturn(PETSC_SUCCESS);
     59: }

     61: static PetscErrorCode EPSSetUp_KrylovSchur_Filter(EPS eps)
     62: {
     63:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
     64:   PetscBool       estimaterange=PETSC_TRUE;
     65:   PetscReal       rleft,rright;
     66:   Mat             A;

     68:   PetscFunctionBegin;
     69:   EPSCheckHermitianCondition(eps,PETSC_TRUE," with polynomial filter");
     70:   EPSCheckStandardCondition(eps,PETSC_TRUE," with polynomial filter");
     71:   PetscCheck(eps->intb<PETSC_MAX_REAL || eps->inta>PETSC_MIN_REAL,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"The defined computational interval should have at least one of their sides bounded");
     72:   EPSCheckUnsupportedCondition(eps,EPS_FEATURE_ARBITRARY | EPS_FEATURE_REGION | EPS_FEATURE_EXTRACTION,PETSC_TRUE," with polynomial filter");
     73:   PetscCall(STFilterSetInterval(eps->st,eps->inta,eps->intb));
     74:   if (!ctx->estimatedrange) {
     75:     PetscCall(STFilterGetRange(eps->st,&rleft,&rright));
     76:     estimaterange = (!rleft && !rright)? PETSC_TRUE: PETSC_FALSE;
     77:   }
     78:   if (estimaterange) { /* user did not set a range */
     79:     PetscCall(STGetMatrix(eps->st,0,&A));
     80:     PetscCall(MatEstimateSpectralRange_EPS(A,&rleft,&rright));
     81:     PetscCall(PetscInfo(eps,"Setting eigenvalue range to [%g,%g]\n",(double)rleft,(double)rright));
     82:     PetscCall(STFilterSetRange(eps->st,rleft,rright));
     83:     ctx->estimatedrange = PETSC_TRUE;
     84:   }
     85:   PetscCall(EPSSetStoppingTest(eps,EPS_STOP_THRESHOLD));
     86:   PetscCall(EPSSetDimensions_Default(eps,&eps->nev,&eps->ncv,&eps->mpd));
     87:   PetscCheck(eps->nev==0 || eps->ncv<=eps->nev+eps->mpd,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER_INPUT,"The value of ncv must not be larger than nev+mpd");
     88:   if (eps->max_it==PETSC_DETERMINE) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
     89:   PetscFunctionReturn(PETSC_SUCCESS);
     90: }

     92: static PetscErrorCode EPSSetUp_KrylovSchur(EPS eps)
     93: {
     94:   PetscReal         eta;
     95:   PetscBool         isfilt=PETSC_FALSE;
     96:   BVOrthogType      otype;
     97:   BVOrthogBlockType obtype;
     98:   EPS_KRYLOVSCHUR   *ctx = (EPS_KRYLOVSCHUR*)eps->data;
     99:   enum { EPS_KS_DEFAULT,EPS_KS_SYMM,EPS_KS_SLICE,EPS_KS_FILTER,EPS_KS_INDEF,EPS_KS_TWOSIDED } variant;

    101:   PetscFunctionBegin;
    102:   if (eps->which==EPS_ALL) {  /* default values in case of spectrum slicing or polynomial filter  */
    103:     PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt));
    104:     if (isfilt) PetscCall(EPSSetUp_KrylovSchur_Filter(eps));
    105:     else PetscCall(EPSSetUp_KrylovSchur_Slice(eps));
    106:   } else if (eps->isstructured) {
    107:     if (eps->problem_type==EPS_BSE) PetscCall(EPSSetUp_KrylovSchur_BSE(eps));
    108:     else if (eps->problem_type==EPS_HAMILT) {
    109:       PetscCheck(!PetscDefined(USE_COMPLEX),PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"The Hamiltonian Krylov-Schur eigensolver is not yet implemented for complex scalars");
    110:       PetscCall(EPSSetUp_KrylovSchur_Hamilt(eps));
    111:     } else if (eps->problem_type==EPS_LREP) {
    112:       PetscCheck(!PetscDefined(USE_COMPLEX),PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"The LREP Krylov-Schur eigensolver does not support complex scalars, use BSE instead");
    113:       PetscCall(EPSSetUp_KrylovSchur_LREP(eps));
    114:     } else SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Unknown matrix structure");
    115:     PetscFunctionReturn(PETSC_SUCCESS);
    116:   } else {
    117:     PetscCall(EPSSetDimensions_Default(eps,&eps->nev,&eps->ncv,&eps->mpd));
    118:     PetscCheck(eps->ncv<=eps->nev+eps->mpd,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER_INPUT,"The value of ncv must not be larger than nev+mpd");
    119:     if (eps->max_it==PETSC_DETERMINE) eps->max_it = PetscMax(100,2*eps->n/eps->ncv)*((eps->stop==EPS_STOP_THRESHOLD)?10:1);
    120:     if (!eps->which) PetscCall(EPSSetWhichEigenpairs_Default(eps));
    121:   }
    122:   PetscCheck(ctx->lock || eps->mpd>=eps->ncv,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Should not use mpd parameter in non-locking variant");

    124:   EPSCheckDefiniteCondition(eps,eps->arbitrary," with arbitrary selection of eigenpairs");

    126:   PetscCheck(eps->extraction==EPS_RITZ || eps->extraction==EPS_HARMONIC,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Unsupported extraction type");

    128:   if (!ctx->keep) ctx->keep = 0.5;

    130:   PetscCall(EPSAllocateSolution(eps,1));
    131:   PetscCall(EPS_SetInnerProduct(eps));
    132:   if (eps->arbitrary) PetscCall(EPSSetWorkVecs(eps,2));
    133:   else if (eps->ishermitian && !eps->ispositive) PetscCall(EPSSetWorkVecs(eps,1));

    135:   /* dispatch solve method */
    136:   if (eps->ishermitian) {
    137:     if (eps->which==EPS_ALL) {
    138:       EPSCheckDefiniteCondition(eps,eps->which==EPS_ALL," with spectrum slicing");
    139:       variant = isfilt? EPS_KS_FILTER: EPS_KS_SLICE;
    140:     } else if (eps->isgeneralized && !eps->ispositive) {
    141:       variant = EPS_KS_INDEF;
    142:     } else {
    143:       switch (eps->extraction) {
    144:         case EPS_RITZ:     variant = EPS_KS_SYMM; break;
    145:         case EPS_HARMONIC: variant = EPS_KS_DEFAULT; break;
    146:         default: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Unsupported extraction type");
    147:       }
    148:     }
    149:   } else if (eps->twosided) {
    150:     variant = EPS_KS_TWOSIDED;
    151:   } else {
    152:     switch (eps->extraction) {
    153:       case EPS_RITZ:     variant = EPS_KS_DEFAULT; break;
    154:       case EPS_HARMONIC: variant = EPS_KS_DEFAULT; break;
    155:       default: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Unsupported extraction type");
    156:     }
    157:   }
    158:   switch (variant) {
    159:     case EPS_KS_DEFAULT:
    160:       eps->ops->solve = EPSSolve_KrylovSchur_Default;
    161:       eps->ops->computevectors = EPSComputeVectors_Schur;
    162:       PetscCall(DSSetType(eps->ds,DSNHEP));
    163:       PetscCall(DSSetExtraRow(eps->ds,PETSC_TRUE));
    164:       PetscCall(DSAllocate(eps->ds,eps->ncv+1));
    165:       break;
    166:     case EPS_KS_SYMM:
    167:     case EPS_KS_FILTER:
    168:       eps->ops->solve = EPSSolve_KrylovSchur_Default;
    169:       eps->ops->computevectors = EPSComputeVectors_Hermitian;
    170:       PetscCall(DSSetType(eps->ds,DSHEP));
    171:       PetscCall(DSSetCompact(eps->ds,PETSC_TRUE));
    172:       PetscCall(DSSetExtraRow(eps->ds,PETSC_TRUE));
    173:       PetscCall(DSAllocate(eps->ds,eps->ncv+1));
    174:       break;
    175:     case EPS_KS_SLICE:
    176:       eps->ops->solve = EPSSolve_KrylovSchur_Slice;
    177:       eps->ops->computevectors = EPSComputeVectors_Slice;
    178:       break;
    179:     case EPS_KS_INDEF:
    180:       eps->ops->solve = EPSSolve_KrylovSchur_Indefinite;
    181:       eps->ops->computevectors = EPSComputeVectors_Indefinite;
    182:       PetscCall(DSSetType(eps->ds,DSGHIEP));
    183:       PetscCall(DSSetCompact(eps->ds,PETSC_TRUE));
    184:       PetscCall(DSSetExtraRow(eps->ds,PETSC_TRUE));
    185:       PetscCall(DSAllocate(eps->ds,eps->ncv+1));
    186:       /* force reorthogonalization for pseudo-Lanczos */
    187:       PetscCall(BVGetOrthogonalization(eps->V,&otype,NULL,&eta,&obtype));
    188:       PetscCall(BVSetOrthogonalization(eps->V,otype,BV_ORTHOG_REFINE_ALWAYS,eta,obtype));
    189:       break;
    190:     case EPS_KS_TWOSIDED:
    191:       eps->ops->solve = EPSSolve_KrylovSchur_TwoSided;
    192:       eps->ops->computevectors = EPSComputeVectors_Schur;
    193:       PetscCall(DSSetType(eps->ds,DSNHEPTS));
    194:       PetscCall(DSAllocate(eps->ds,eps->ncv+1));
    195:       PetscCall(DSSetExtraRow(eps->ds,PETSC_TRUE));
    196:       break;
    197:     default: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Unexpected error");
    198:   }
    199:   PetscFunctionReturn(PETSC_SUCCESS);
    200: }

    202: static PetscErrorCode EPSSetUpSort_KrylovSchur(EPS eps)
    203: {
    204:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
    205:   SlepcSC         sc;
    206:   PetscBool       isfilt;

    208:   PetscFunctionBegin;
    209:   PetscCall(EPSSetUpSort_Default(eps));
    210:   if (eps->which==EPS_ALL) {
    211:     PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt));
    212:     if (isfilt) {
    213:       PetscCall(DSGetSlepcSC(eps->ds,&sc));
    214:       sc->rg            = NULL;
    215:       sc->comparison    = SlepcCompareLargestReal;
    216:       sc->comparisonctx = NULL;
    217:       sc->map           = NULL;
    218:       sc->mapobj        = NULL;
    219:     } else {
    220:       if (!ctx->global && ctx->sr->numEigs>0) {
    221:         PetscCall(DSGetSlepcSC(eps->ds,&sc));
    222:         sc->rg            = NULL;
    223:         sc->comparison    = SlepcCompareLargestMagnitude;
    224:         sc->comparisonctx = NULL;
    225:         sc->map           = NULL;
    226:         sc->mapobj        = NULL;
    227:       }
    228:     }
    229:   }
    230:   PetscFunctionReturn(PETSC_SUCCESS);
    231: }

    233: PetscErrorCode EPSSolve_KrylovSchur_Default(EPS eps)
    234: {
    235:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
    236:   PetscInt        i,j,*pj,k,l,nv,ld,nconv;
    237:   Mat             U,Op,H,T;
    238:   PetscScalar     *g;
    239:   PetscReal       beta,gamma=1.0;
    240:   PetscBool       breakdown,harmonic,hermitian;

    242:   PetscFunctionBegin;
    243:   PetscCall(DSGetLeadingDimension(eps->ds,&ld));
    244:   harmonic = (eps->extraction==EPS_HARMONIC || eps->extraction==EPS_REFINED_HARMONIC)?PETSC_TRUE:PETSC_FALSE;
    245:   hermitian = (eps->ishermitian && !harmonic)?PETSC_TRUE:PETSC_FALSE;
    246:   if (harmonic) PetscCall(PetscMalloc1(ld,&g));
    247:   if (eps->arbitrary) pj = &j;
    248:   else pj = NULL;

    250:   /* Get the starting Arnoldi vector */
    251:   PetscCall(EPSGetStartVector(eps,0,NULL));
    252:   l = 0;

    254:   /* Restart loop */
    255:   while (eps->reason == EPS_CONVERGED_ITERATING) {
    256:     eps->its++;

    258:     /* Compute an nv-step Arnoldi factorization */
    259:     nv = PetscMin(eps->nconv+eps->mpd,eps->ncv);
    260:     PetscCall(DSSetDimensions(eps->ds,nv,eps->nconv,eps->nconv+l));
    261:     PetscCall(STGetOperator(eps->st,&Op));
    262:     if (hermitian) {
    263:       PetscCall(DSGetMat(eps->ds,DS_MAT_T,&T));
    264:       PetscCall(BVMatLanczos(eps->V,Op,T,eps->nconv+l,&nv,&beta,&breakdown));
    265:       PetscCall(DSRestoreMat(eps->ds,DS_MAT_T,&T));
    266:     } else {
    267:       PetscCall(DSGetMat(eps->ds,DS_MAT_A,&H));
    268:       PetscCall(BVMatArnoldi(eps->V,Op,H,eps->nconv+l,&nv,&beta,&breakdown));
    269:       PetscCall(DSRestoreMat(eps->ds,DS_MAT_A,&H));
    270:     }
    271:     PetscCall(STRestoreOperator(eps->st,&Op));
    272:     PetscCall(DSSetDimensions(eps->ds,nv,eps->nconv,eps->nconv+l));
    273:     PetscCall(DSSetState(eps->ds,l?DS_STATE_RAW:DS_STATE_INTERMEDIATE));
    274:     PetscCall(BVSetActiveColumns(eps->V,eps->nconv,nv));

    276:     /* Compute translation of Krylov decomposition if harmonic extraction used */
    277:     if (PetscUnlikely(harmonic)) PetscCall(DSTranslateHarmonic(eps->ds,eps->target,beta,PETSC_FALSE,g,&gamma));

    279:     /* Solve projected problem */
    280:     PetscCall(DSSolve(eps->ds,eps->eigr,eps->eigi));
    281:     if (PetscUnlikely(eps->arbitrary)) {
    282:       PetscCall(EPSGetArbitraryValues(eps,eps->rr,eps->ri));
    283:       j=1;
    284:     }
    285:     PetscCall(DSSort(eps->ds,eps->eigr,eps->eigi,eps->rr,eps->ri,pj));
    286:     PetscCall(DSUpdateExtraRow(eps->ds));
    287:     PetscCall(DSSynchronize(eps->ds,eps->eigr,eps->eigi));

    289:     /* Check convergence */
    290:     PetscCall(EPSKrylovConvergence(eps,PETSC_FALSE,eps->nconv,nv-eps->nconv,beta,0.0,gamma,&k));
    291:     EPSSetCtxThreshold(eps,eps->eigr,eps->eigi,eps->errest,k,nv);
    292:     PetscCall((*eps->stopping)(eps,eps->its,eps->max_it,k,eps->nev,&eps->reason,eps->stoppingctx));
    293:     nconv = k;

    295:     /* Update l */
    296:     if (eps->reason != EPS_CONVERGED_ITERATING || breakdown || k==nv) l = 0;
    297:     else {
    298:       l = PetscMax(1,(PetscInt)((nv-k)*ctx->keep));
    299:       if (!hermitian) PetscCall(DSGetTruncateSize(eps->ds,k,nv,&l));
    300:     }
    301:     if (!ctx->lock && l>0) { l += k; k = 0; } /* non-locking variant: reset no. of converged pairs */
    302:     if (l) PetscCall(PetscInfo(eps,"Preparing to restart keeping l=%" PetscInt_FMT " vectors\n",l));

    304:     if (eps->reason == EPS_CONVERGED_ITERATING) {
    305:       if (PetscUnlikely(breakdown || k==nv)) {
    306:         /* Start a new Arnoldi factorization */
    307:         PetscCall(PetscInfo(eps,"Breakdown in Krylov-Schur method (it=%" PetscInt_FMT " norm=%g)\n",eps->its,(double)beta));
    308:         if (k<eps->nev) {
    309:           PetscCall(EPSGetStartVector(eps,k,&breakdown));
    310:           if (breakdown) {
    311:             eps->reason = EPS_DIVERGED_BREAKDOWN;
    312:             PetscCall(PetscInfo(eps,"Unable to generate more start vectors\n"));
    313:           }
    314:         }
    315:       } else {
    316:         /* Undo translation of Krylov decomposition */
    317:         if (PetscUnlikely(harmonic)) {
    318:           PetscCall(DSSetDimensions(eps->ds,nv,k,l));
    319:           PetscCall(DSTranslateHarmonic(eps->ds,0.0,beta,PETSC_TRUE,g,&gamma));
    320:           /* gamma u^ = u - U*g~ */
    321:           PetscCall(BVSetActiveColumns(eps->V,0,nv));
    322:           PetscCall(BVMultColumn(eps->V,-1.0,1.0,nv,g));
    323:           PetscCall(BVScaleColumn(eps->V,nv,1.0/gamma));
    324:           PetscCall(BVSetActiveColumns(eps->V,eps->nconv,nv));
    325:           PetscCall(DSSetDimensions(eps->ds,nv,k,nv));
    326:         }
    327:         /* Prepare the Rayleigh quotient for restart */
    328:         PetscCall(DSTruncate(eps->ds,k+l,PETSC_FALSE));
    329:       }
    330:     }
    331:     /* Update the corresponding vectors V(:,idx) = V*Q(:,idx) */
    332:     PetscCall(DSGetMat(eps->ds,DS_MAT_Q,&U));
    333:     PetscCall(BVMultInPlace(eps->V,U,eps->nconv,k+l));
    334:     PetscCall(DSRestoreMat(eps->ds,DS_MAT_Q,&U));

    336:     if (eps->reason == EPS_CONVERGED_ITERATING && !breakdown) {
    337:       PetscCall(BVCopyColumn(eps->V,nv,k+l));  /* copy restart vector from the last column */
    338:       if (eps->stop==EPS_STOP_THRESHOLD && nv-k<5) {  /* reallocate */
    339:         eps->ncv = eps->mpd+k;
    340:         PetscCall(EPSReallocateSolution(eps,eps->ncv+1));
    341:         for (i=nv;i<eps->ncv;i++) eps->perm[i] = i;
    342:         PetscCall(DSReallocate(eps->ds,eps->ncv+1));
    343:         PetscCall(DSGetLeadingDimension(eps->ds,&ld));
    344:       }
    345:     }

    347:     eps->nconv = k;
    348:     PetscCall(EPSMonitor(eps,eps->its,nconv,eps->eigr,eps->eigi,eps->errest,nv));
    349:   }

    351:   if (harmonic) PetscCall(PetscFree(g));
    352:   PetscCall(DSTruncate(eps->ds,eps->nconv,PETSC_TRUE));
    353:   PetscFunctionReturn(PETSC_SUCCESS);
    354: }

    356: static PetscErrorCode EPSKrylovSchurSetRestart_KrylovSchur(EPS eps,PetscReal keep)
    357: {
    358:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;

    360:   PetscFunctionBegin;
    361:   if (keep==(PetscReal)PETSC_DEFAULT || keep==(PetscReal)PETSC_DECIDE) ctx->keep = 0.5;
    362:   else {
    363:     PetscCheck(keep>=0.1 && keep<=0.9,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The keep argument %g must be in the range [0.1,0.9]",(double)keep);
    364:     ctx->keep = keep;
    365:   }
    366:   PetscFunctionReturn(PETSC_SUCCESS);
    367: }

    369: /*@
    370:    EPSKrylovSchurSetRestart - Sets the restart parameter for the Krylov-Schur
    371:    method, in particular the proportion of basis vectors that must be kept
    372:    after restart.

    374:    Logically Collective

    376:    Input Parameters:
    377: +  eps - the linear eigensolver context
    378: -  keep - the number of vectors to be kept at restart

    380:    Options Database Key:
    381: .  -eps_krylovschur_restart keep - sets the restart parameter

    383:    Notes:
    384:    Allowed values are in the range [0.1,0.9]. The default is 0.5, which means
    385:    that at restart the current subspace is compressed into another subspace
    386:    with a reduction of 50% in size.

    388:    Implementation details of Krylov-Schur in SLEPc can be found in {cite:p}`Her07b`.

    390:    Level: advanced

    392: .seealso: [](ch:eps), `EPSKRYLOVSCHUR`, `EPSKrylovSchurGetRestart()`
    393: @*/
    394: PetscErrorCode EPSKrylovSchurSetRestart(EPS eps,PetscReal keep)
    395: {
    396:   PetscFunctionBegin;
    399:   PetscTryMethod(eps,"EPSKrylovSchurSetRestart_C",(EPS,PetscReal),(eps,keep));
    400:   PetscFunctionReturn(PETSC_SUCCESS);
    401: }

    403: static PetscErrorCode EPSKrylovSchurGetRestart_KrylovSchur(EPS eps,PetscReal *keep)
    404: {
    405:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;

    407:   PetscFunctionBegin;
    408:   *keep = ctx->keep;
    409:   PetscFunctionReturn(PETSC_SUCCESS);
    410: }

    412: /*@
    413:    EPSKrylovSchurGetRestart - Gets the restart parameter used in the
    414:    Krylov-Schur method.

    416:    Not Collective

    418:    Input Parameter:
    419: .  eps - the linear eigensolver context

    421:    Output Parameter:
    422: .  keep - the restart parameter

    424:    Level: advanced

    426: .seealso: [](ch:eps), `EPSKRYLOVSCHUR`, `EPSKrylovSchurSetRestart()`
    427: @*/
    428: PetscErrorCode EPSKrylovSchurGetRestart(EPS eps,PetscReal *keep)
    429: {
    430:   PetscFunctionBegin;
    432:   PetscAssertPointer(keep,2);
    433:   PetscUseMethod(eps,"EPSKrylovSchurGetRestart_C",(EPS,PetscReal*),(eps,keep));
    434:   PetscFunctionReturn(PETSC_SUCCESS);
    435: }

    437: static PetscErrorCode EPSKrylovSchurSetLocking_KrylovSchur(EPS eps,PetscBool lock)
    438: {
    439:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;

    441:   PetscFunctionBegin;
    442:   ctx->lock = lock;
    443:   PetscFunctionReturn(PETSC_SUCCESS);
    444: }

    446: /*@
    447:    EPSKrylovSchurSetLocking - Choose between locking and non-locking variants of
    448:    the Krylov-Schur method.

    450:    Logically Collective

    452:    Input Parameters:
    453: +  eps  - the linear eigensolver context
    454: -  lock - true if the locking variant must be selected

    456:    Options Database Key:
    457: .  -eps_krylovschur_locking (true|false) - sets the locking flag

    459:    Notes:
    460:    The default is to lock converged eigenpairs when the method restarts.
    461:    This behavior can be changed so that all directions are kept in the
    462:    working subspace even if already converged to working accuracy (the
    463:    non-locking variant).

    465:    Implementation details of Krylov-Schur in SLEPc can be found in {cite:p}`Her07b`.

    467:    Level: advanced

    469: .seealso: [](ch:eps), `EPSKRYLOVSCHUR`, `EPSKrylovSchurGetLocking()`
    470: @*/
    471: PetscErrorCode EPSKrylovSchurSetLocking(EPS eps,PetscBool lock)
    472: {
    473:   PetscFunctionBegin;
    476:   PetscTryMethod(eps,"EPSKrylovSchurSetLocking_C",(EPS,PetscBool),(eps,lock));
    477:   PetscFunctionReturn(PETSC_SUCCESS);
    478: }

    480: static PetscErrorCode EPSKrylovSchurGetLocking_KrylovSchur(EPS eps,PetscBool *lock)
    481: {
    482:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;

    484:   PetscFunctionBegin;
    485:   *lock = ctx->lock;
    486:   PetscFunctionReturn(PETSC_SUCCESS);
    487: }

    489: /*@
    490:    EPSKrylovSchurGetLocking - Gets the locking flag used in the Krylov-Schur
    491:    method.

    493:    Not Collective

    495:    Input Parameter:
    496: .  eps - the linear eigensolver context

    498:    Output Parameter:
    499: .  lock - the locking flag

    501:    Level: advanced

    503: .seealso: [](ch:eps), `EPSKRYLOVSCHUR`, `EPSKrylovSchurSetLocking()`
    504: @*/
    505: PetscErrorCode EPSKrylovSchurGetLocking(EPS eps,PetscBool *lock)
    506: {
    507:   PetscFunctionBegin;
    509:   PetscAssertPointer(lock,2);
    510:   PetscUseMethod(eps,"EPSKrylovSchurGetLocking_C",(EPS,PetscBool*),(eps,lock));
    511:   PetscFunctionReturn(PETSC_SUCCESS);
    512: }

    514: static PetscErrorCode EPSKrylovSchurSetPartitions_KrylovSchur(EPS eps,PetscInt npart)
    515: {
    516:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
    517:   PetscMPIInt     size;
    518:   PetscInt        newnpart;

    520:   PetscFunctionBegin;
    521:   if (npart == PETSC_DEFAULT || npart == PETSC_DECIDE) {
    522:     newnpart = 1;
    523:   } else {
    524:     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)eps),&size));
    525:     PetscCheck(npart>0 && npart<=size,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of npart");
    526:     newnpart = npart;
    527:   }
    528:   if (ctx->npart!=newnpart) {
    529:     if (ctx->npart>1) {
    530:       PetscCall(PetscSubcommDestroy(&ctx->subc));
    531:       if (ctx->commset) {
    532:         PetscCallMPI(MPI_Comm_free(&ctx->commrank));
    533:         ctx->commset = PETSC_FALSE;
    534:       }
    535:     }
    536:     PetscCall(EPSDestroy(&ctx->eps));
    537:     ctx->npart = newnpart;
    538:     eps->state = EPS_STATE_INITIAL;
    539:   }
    540:   PetscFunctionReturn(PETSC_SUCCESS);
    541: }

    543: /*@
    544:    EPSKrylovSchurSetPartitions - Sets the number of partitions for the
    545:    case of doing spectrum slicing for a computational interval with the
    546:    communicator split in several sub-communicators.

    548:    Logically Collective

    550:    Input Parameters:
    551: +  eps   - the linear eigensolver context
    552: -  npart - number of partitions

    554:    Options Database Key:
    555: .  -eps_krylovschur_partitions npart - sets the number of partitions

    557:    Notes:
    558:    This call makes sense only for spectrum slicing runs, that is, when
    559:    an interval has been given with `EPSSetInterval()` and `STSINVERT` is set.
    560:    See more details in section [](#sec:slice).

    562:    By default, `npart`=1 so all processes in the communicator participate in
    563:    the processing of the whole interval. If `npart`>1 then the interval is
    564:    divided into `npart` subintervals, each of them being processed by a
    565:    subset of processes.

    567:    The interval is split proportionally unless the separation points are
    568:    specified with `EPSKrylovSchurSetSubintervals()`.

    570:    Level: advanced

    572: .seealso: [](ch:eps), [](#sec:slice), `EPSKRYLOVSCHUR`, `EPSKrylovSchurSetSubintervals()`, `EPSSetInterval()`
    573: @*/
    574: PetscErrorCode EPSKrylovSchurSetPartitions(EPS eps,PetscInt npart)
    575: {
    576:   PetscFunctionBegin;
    579:   PetscTryMethod(eps,"EPSKrylovSchurSetPartitions_C",(EPS,PetscInt),(eps,npart));
    580:   PetscFunctionReturn(PETSC_SUCCESS);
    581: }

    583: static PetscErrorCode EPSKrylovSchurGetPartitions_KrylovSchur(EPS eps,PetscInt *npart)
    584: {
    585:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;

    587:   PetscFunctionBegin;
    588:   *npart  = ctx->npart;
    589:   PetscFunctionReturn(PETSC_SUCCESS);
    590: }

    592: /*@
    593:    EPSKrylovSchurGetPartitions - Gets the number of partitions of the
    594:    communicator in case of spectrum slicing.

    596:    Not Collective

    598:    Input Parameter:
    599: .  eps - the linear eigensolver context

    601:    Output Parameter:
    602: .  npart - number of partitions

    604:    Level: advanced

    606: .seealso: [](ch:eps), `EPSKRYLOVSCHUR`, `EPSKrylovSchurSetPartitions()`
    607: @*/
    608: PetscErrorCode EPSKrylovSchurGetPartitions(EPS eps,PetscInt *npart)
    609: {
    610:   PetscFunctionBegin;
    612:   PetscAssertPointer(npart,2);
    613:   PetscUseMethod(eps,"EPSKrylovSchurGetPartitions_C",(EPS,PetscInt*),(eps,npart));
    614:   PetscFunctionReturn(PETSC_SUCCESS);
    615: }

    617: static PetscErrorCode EPSKrylovSchurSetDetectZeros_KrylovSchur(EPS eps,PetscBool detect)
    618: {
    619:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;

    621:   PetscFunctionBegin;
    622:   ctx->detect = detect;
    623:   eps->state  = EPS_STATE_INITIAL;
    624:   PetscFunctionReturn(PETSC_SUCCESS);
    625: }

    627: /*@
    628:    EPSKrylovSchurSetDetectZeros - Sets a flag to enforce detection of
    629:    zeros during the factorizations throughout the spectrum slicing computation.

    631:    Logically Collective

    633:    Input Parameters:
    634: +  eps    - the linear eigensolver context
    635: -  detect - check for zeros

    637:    Options Database Key:
    638: .  -eps_krylovschur_detect_zeros (true|false) - check for zeros

    640:    Notes:
    641:    This flag makes sense only for spectrum slicing runs, that is, when
    642:    an interval has been given with `EPSSetInterval()` and `STSINVERT` is set.
    643:    See more details in section [](#sec:slice).

    645:    A zero in the factorization indicates that a shift coincides with an eigenvalue.

    647:    This flag is turned off by default, and may be necessary in some cases,
    648:    especially when several partitions are being used. This feature currently
    649:    requires an external package for factorizations with support for zero
    650:    detection, e.g. MUMPS.

    652:    Level: advanced

    654: .seealso: [](ch:eps), [](#sec:slice), `EPSKRYLOVSCHUR`, `EPSKrylovSchurSetPartitions()`, `EPSSetInterval()`
    655: @*/
    656: PetscErrorCode EPSKrylovSchurSetDetectZeros(EPS eps,PetscBool detect)
    657: {
    658:   PetscFunctionBegin;
    661:   PetscTryMethod(eps,"EPSKrylovSchurSetDetectZeros_C",(EPS,PetscBool),(eps,detect));
    662:   PetscFunctionReturn(PETSC_SUCCESS);
    663: }

    665: static PetscErrorCode EPSKrylovSchurGetDetectZeros_KrylovSchur(EPS eps,PetscBool *detect)
    666: {
    667:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;

    669:   PetscFunctionBegin;
    670:   *detect = ctx->detect;
    671:   PetscFunctionReturn(PETSC_SUCCESS);
    672: }

    674: /*@
    675:    EPSKrylovSchurGetDetectZeros - Gets the flag that enforces zero detection
    676:    in spectrum slicing.

    678:    Not Collective

    680:    Input Parameter:
    681: .  eps - the linear eigensolver context

    683:    Output Parameter:
    684: .  detect - whether zeros detection is enforced during factorizations

    686:    Level: advanced

    688: .seealso: [](ch:eps), `EPSKRYLOVSCHUR`, `EPSKrylovSchurSetDetectZeros()`
    689: @*/
    690: PetscErrorCode EPSKrylovSchurGetDetectZeros(EPS eps,PetscBool *detect)
    691: {
    692:   PetscFunctionBegin;
    694:   PetscAssertPointer(detect,2);
    695:   PetscUseMethod(eps,"EPSKrylovSchurGetDetectZeros_C",(EPS,PetscBool*),(eps,detect));
    696:   PetscFunctionReturn(PETSC_SUCCESS);
    697: }

    699: static PetscErrorCode EPSKrylovSchurSetDimensions_KrylovSchur(EPS eps,PetscInt nev,PetscInt ncv,PetscInt mpd)
    700: {
    701:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;

    703:   PetscFunctionBegin;
    704:   if (nev != PETSC_CURRENT) {
    705:     PetscCheck(nev>0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of nev. Must be > 0");
    706:     ctx->nev = nev;
    707:   }
    708:   if (ncv == PETSC_DETERMINE) {
    709:     ctx->ncv = PETSC_DETERMINE;
    710:   } else if (ncv != PETSC_CURRENT) {
    711:     PetscCheck(ncv>0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of ncv. Must be > 0");
    712:     ctx->ncv = ncv;
    713:   }
    714:   if (mpd == PETSC_DETERMINE) {
    715:     ctx->mpd = PETSC_DETERMINE;
    716:   } else if (mpd != PETSC_CURRENT) {
    717:     PetscCheck(mpd>0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of mpd. Must be > 0");
    718:     ctx->mpd = mpd;
    719:   }
    720:   eps->state = EPS_STATE_INITIAL;
    721:   PetscFunctionReturn(PETSC_SUCCESS);
    722: }

    724: /*@
    725:    EPSKrylovSchurSetDimensions - Sets the dimensions used for each subsolve
    726:    step in case of doing spectrum slicing for a computational interval.

    728:    Logically Collective

    730:    Input Parameters:
    731: +  eps - the linear eigensolver context
    732: .  nev - number of eigenvalues to compute
    733: .  ncv - the maximum dimension of the subspace to be used by the subsolve
    734: -  mpd - the maximum dimension allowed for the projected problem

    736:    Options Database Keys:
    737: +  -eps_krylovschur_nev nev - sets the number of eigenvalues
    738: .  -eps_krylovschur_ncv ncv - sets the dimension of the subspace
    739: -  -eps_krylovschur_mpd mpd - sets the maximum projected dimension

    741:    Notes:
    742:    These parameters are relevant only for spectrum slicing runs, that is, when
    743:    an interval has been given with `EPSSetInterval()` and `STSINVERT` is set.
    744:    See more details in section [](#sec:slice).

    746:    The meaning of the parameters is the same as in `EPSSetDimensions()`, but
    747:    the ones here apply to every subsolve done by the child `EPS` object.

    749:    Use `PETSC_DETERMINE` for `ncv` and `mpd` to assign a default value. For any
    750:    of the arguments, use `PETSC_CURRENT` to preserve the current value.

    752:    Level: advanced

    754: .seealso: [](ch:eps), [](#sec:slice), `EPSKRYLOVSCHUR`, `EPSKrylovSchurGetDimensions()`, `EPSSetDimensions()`, `EPSSetInterval()`
    755: @*/
    756: PetscErrorCode EPSKrylovSchurSetDimensions(EPS eps,PetscInt nev,PetscInt ncv,PetscInt mpd)
    757: {
    758:   PetscFunctionBegin;
    763:   PetscTryMethod(eps,"EPSKrylovSchurSetDimensions_C",(EPS,PetscInt,PetscInt,PetscInt),(eps,nev,ncv,mpd));
    764:   PetscFunctionReturn(PETSC_SUCCESS);
    765: }

    767: static PetscErrorCode EPSKrylovSchurGetDimensions_KrylovSchur(EPS eps,PetscInt *nev,PetscInt *ncv,PetscInt *mpd)
    768: {
    769:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;

    771:   PetscFunctionBegin;
    772:   if (nev) *nev = ctx->nev;
    773:   if (ncv) *ncv = ctx->ncv;
    774:   if (mpd) *mpd = ctx->mpd;
    775:   PetscFunctionReturn(PETSC_SUCCESS);
    776: }

    778: /*@
    779:    EPSKrylovSchurGetDimensions - Gets the dimensions used for each subsolve
    780:    step in case of doing spectrum slicing for a computational interval.

    782:    Not Collective

    784:    Input Parameter:
    785: .  eps - the linear eigensolver context

    787:    Output Parameters:
    788: +  nev - number of eigenvalues to compute
    789: .  ncv - the maximum dimension of the subspace to be used by the subsolve
    790: -  mpd - the maximum dimension allowed for the projected problem

    792:    Level: advanced

    794: .seealso: [](ch:eps), `EPSKRYLOVSCHUR`, `EPSKrylovSchurSetDimensions()`
    795: @*/
    796: PetscErrorCode EPSKrylovSchurGetDimensions(EPS eps,PetscInt *nev,PetscInt *ncv,PetscInt *mpd)
    797: {
    798:   PetscFunctionBegin;
    800:   PetscUseMethod(eps,"EPSKrylovSchurGetDimensions_C",(EPS,PetscInt*,PetscInt*,PetscInt*),(eps,nev,ncv,mpd));
    801:   PetscFunctionReturn(PETSC_SUCCESS);
    802: }

    804: static PetscErrorCode EPSKrylovSchurSetSubintervals_KrylovSchur(EPS eps,PetscReal* subint)
    805: {
    806:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
    807:   PetscInt        i;

    809:   PetscFunctionBegin;
    810:   PetscCheck(subint[0]==eps->inta && subint[ctx->npart]==eps->intb,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"First and last values must match the endpoints of EPSSetInterval()");
    811:   for (i=0;i<ctx->npart;i++) PetscCheck(subint[i]<=subint[i+1],PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"Array must contain values in ascending order");
    812:   PetscCall(PetscFree(ctx->subintervals));
    813:   PetscCall(PetscMalloc1(ctx->npart+1,&ctx->subintervals));
    814:   for (i=0;i<ctx->npart+1;i++) ctx->subintervals[i] = subint[i];
    815:   ctx->subintset = PETSC_TRUE;
    816:   eps->state = EPS_STATE_INITIAL;
    817:   PetscFunctionReturn(PETSC_SUCCESS);
    818: }

    820: /*@
    821:    EPSKrylovSchurSetSubintervals - Sets the points that delimit the
    822:    subintervals to be used in spectrum slicing with several partitions.

    824:    Logically Collective

    826:    Input Parameters:
    827: +  eps    - the linear eigensolver context
    828: -  subint - array of real values specifying subintervals

    830:    Notes:
    831:    This function is relevant only for spectrum slicing runs, that is, when
    832:    an interval has been given with `EPSSetInterval()` and `STSINVERT` is set.
    833:    See more details in section [](#sec:slice).

    835:    It must be called after `EPSKrylovSchurSetPartitions()`. For `npart`
    836:    partitions, the argument `subint` must contain `npart+1` real values sorted in
    837:    ascending order, `subint_0, subint_1, ..., subint_npart`, where the first
    838:    and last values must coincide with the interval endpoints set with
    839:    `EPSSetInterval()`.

    841:    The subintervals are then defined by two consecutive points `[subint_0,subint_1]`,
    842:    `[subint_1,subint_2]`, and so on.

    844:    Level: advanced

    846: .seealso: [](ch:eps), [](#sec:slice), `EPSKRYLOVSCHUR`, `EPSKrylovSchurSetPartitions()`, `EPSKrylovSchurGetSubintervals()`, `EPSSetInterval()`
    847: @*/
    848: PetscErrorCode EPSKrylovSchurSetSubintervals(EPS eps,PetscReal subint[])
    849: {
    850:   PetscFunctionBegin;
    852:   PetscAssertPointer(subint,2);
    853:   PetscTryMethod(eps,"EPSKrylovSchurSetSubintervals_C",(EPS,PetscReal*),(eps,subint));
    854:   PetscFunctionReturn(PETSC_SUCCESS);
    855: }

    857: static PetscErrorCode EPSKrylovSchurGetSubintervals_KrylovSchur(EPS eps,PetscReal *subint[])
    858: {
    859:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
    860:   PetscInt        i;

    862:   PetscFunctionBegin;
    863:   if (!ctx->subintset) {
    864:     PetscCheck(eps->state,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
    865:     PetscCheck(ctx->sr,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
    866:   }
    867:   PetscCall(PetscMalloc1(ctx->npart+1,subint));
    868:   for (i=0;i<=ctx->npart;i++) (*subint)[i] = ctx->subintervals[i];
    869:   PetscFunctionReturn(PETSC_SUCCESS);
    870: }

    872: /*@C
    873:    EPSKrylovSchurGetSubintervals - Returns the points that delimit the
    874:    subintervals used in spectrum slicing with several partitions.

    876:    Not Collective

    878:    Input Parameter:
    879: .  eps    - the linear eigensolver context

    881:    Output Parameter:
    882: .  subint - array of real values specifying subintervals

    884:    Notes:
    885:    If the user passed values with `EPSKrylovSchurSetSubintervals()`, then the
    886:    same values are returned here. Otherwise, the values computed internally are
    887:    obtained.

    889:    This function is only available for spectrum slicing runs, that is, when
    890:    an interval has been given with `EPSSetInterval()` and `STSINVERT` is set.
    891:    See more details in section [](#sec:slice).

    893:    The returned array has length `npart`+1 (see `EPSKrylovSchurGetPartitions()`)
    894:    and should be freed by the user.

    896:    Fortran Notes:
    897:    The calling sequence from Fortran is
    898: .vb
    899:    EPSKrylovSchurGetSubintervals(eps,subint,ierr)
    900:    PetscReal subint(npart+1)
    901: .ve

    903:    Level: advanced

    905: .seealso: [](ch:eps), [](#sec:slice), `EPSKRYLOVSCHUR`, `EPSKrylovSchurSetSubintervals()`, `EPSKrylovSchurGetPartitions()`, `EPSSetInterval()`
    906: @*/
    907: PetscErrorCode EPSKrylovSchurGetSubintervals(EPS eps,PetscReal *subint[]) PeNS
    908: {
    909:   PetscFunctionBegin;
    911:   PetscAssertPointer(subint,2);
    912:   PetscUseMethod(eps,"EPSKrylovSchurGetSubintervals_C",(EPS,PetscReal**),(eps,subint));
    913:   PetscFunctionReturn(PETSC_SUCCESS);
    914: }

    916: static PetscErrorCode EPSKrylovSchurGetInertias_KrylovSchur(EPS eps,PetscInt *n,PetscReal *shifts[],PetscInt *inertias[])
    917: {
    918:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
    919:   PetscInt        i,numsh;
    920:   EPS_SR          sr = ctx->sr;

    922:   PetscFunctionBegin;
    923:   PetscCheck(eps->state,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
    924:   PetscCheck(ctx->sr,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
    925:   switch (eps->state) {
    926:   case EPS_STATE_INITIAL:
    927:     break;
    928:   case EPS_STATE_SETUP:
    929:     numsh = ctx->npart+1;
    930:     if (n) *n = numsh;
    931:     if (shifts) {
    932:       PetscCall(PetscMalloc1(numsh,shifts));
    933:       (*shifts)[0] = eps->inta;
    934:       if (ctx->npart==1) (*shifts)[1] = eps->intb;
    935:       else for (i=1;i<numsh;i++) (*shifts)[i] = ctx->subintervals[i];
    936:     }
    937:     if (inertias) {
    938:       PetscCall(PetscMalloc1(numsh,inertias));
    939:       (*inertias)[0] = (sr->dir==1)?sr->inertia0:sr->inertia1;
    940:       if (ctx->npart==1) (*inertias)[1] = (sr->dir==1)?sr->inertia1:sr->inertia0;
    941:       else for (i=1;i<numsh;i++) (*inertias)[i] = (*inertias)[i-1]+ctx->nconv_loc[i-1];
    942:     }
    943:     break;
    944:   case EPS_STATE_SOLVED:
    945:   case EPS_STATE_EIGENVECTORS:
    946:     numsh = ctx->nshifts;
    947:     if (n) *n = numsh;
    948:     if (shifts) {
    949:       PetscCall(PetscMalloc1(numsh,shifts));
    950:       for (i=0;i<numsh;i++) (*shifts)[i] = ctx->shifts[i];
    951:     }
    952:     if (inertias) {
    953:       PetscCall(PetscMalloc1(numsh,inertias));
    954:       for (i=0;i<numsh;i++) (*inertias)[i] = ctx->inertias[i];
    955:     }
    956:     break;
    957:   }
    958:   PetscFunctionReturn(PETSC_SUCCESS);
    959: }

    961: /*@C
    962:    EPSKrylovSchurGetInertias - Gets the values of the shifts and their
    963:    corresponding inertias in case of doing spectrum slicing for a
    964:    computational interval.

    966:    Not Collective

    968:    Input Parameter:
    969: .  eps - the linear eigensolver context

    971:    Output Parameters:
    972: +  n        - number of shifts, including the endpoints of the interval
    973: .  shifts   - the values of the shifts used internally in the solver
    974: -  inertias - the values of the inertia at each shift

    976:    Notes:
    977:    If called after `EPSSolve()`, all shifts used internally by the solver are
    978:    returned (including both endpoints and any intermediate ones). If called
    979:    before `EPSSolve()` and after `EPSSetUp()` then only the information of the
    980:    endpoints of subintervals is available.

    982:    This function is only available for spectrum slicing runs, that is, when
    983:    an interval has been given with `EPSSetInterval()` and `STSINVERT` is set.
    984:    See more details in section [](#sec:slice).

    986:    The returned arrays should be freed by the user. Can pass `NULL` in any of
    987:    the two arrays if not required.

    989:    Fortran Notes:
    990:    The calling sequence from Fortran is
    991: .vb
    992:    EPSKrylovSchurGetInertias(eps,n,shifts,inertias,ierr)
    993:    PetscInt  n
    994:    PetscReal shifts(*)
    995:    PetscInt  inertias(*)
    996: .ve
    997:    The arrays should be at least of length `n`. The value of `n` can be determined
    998:    by an initial call
    999: .vb
    1000:    EPSKrylovSchurGetInertias(eps,n,PETSC_NULL_REAL_ARRAY,PETSC_NULL_INTEGER_ARRAY,ierr)
    1001: .ve

    1003:    Level: advanced

    1005: .seealso: [](ch:eps), [](#sec:slice), `EPSKRYLOVSCHUR`, `EPSSetInterval()`, `EPSKrylovSchurSetSubintervals()`
    1006: @*/
    1007: PetscErrorCode EPSKrylovSchurGetInertias(EPS eps,PetscInt *n,PetscReal *shifts[],PetscInt *inertias[]) PeNS
    1008: {
    1009:   PetscFunctionBegin;
    1011:   PetscAssertPointer(n,2);
    1012:   PetscUseMethod(eps,"EPSKrylovSchurGetInertias_C",(EPS,PetscInt*,PetscReal**,PetscInt**),(eps,n,shifts,inertias));
    1013:   PetscFunctionReturn(PETSC_SUCCESS);
    1014: }

    1016: static PetscErrorCode EPSKrylovSchurGetSubcommInfo_KrylovSchur(EPS eps,PetscInt *k,PetscInt *n,Vec *v)
    1017: {
    1018:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
    1019:   EPS_SR          sr = ((EPS_KRYLOVSCHUR*)ctx->eps->data)->sr;

    1021:   PetscFunctionBegin;
    1022:   PetscCheck(eps->state,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
    1023:   PetscCheck(ctx->sr,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
    1024:   if (k) *k = (ctx->npart==1)? 0: ctx->subc->color;
    1025:   if (n) *n = sr->numEigs;
    1026:   if (v) PetscCall(BVCreateVec(sr->V,v));
    1027:   PetscFunctionReturn(PETSC_SUCCESS);
    1028: }

    1030: /*@
    1031:    EPSKrylovSchurGetSubcommInfo - Gets information related to the case of
    1032:    doing spectrum slicing for a computational interval with multiple
    1033:    communicators.

    1035:    Collective on the subcommunicator (if `v` is given)

    1037:    Input Parameter:
    1038: .  eps - the linear eigensolver context

    1040:    Output Parameters:
    1041: +  k - index of the subinterval for the calling process
    1042: .  n - number of eigenvalues found in the `k`-th subinterval
    1043: -  v - a vector owned by processes in the subcommunicator with dimensions
    1044:        compatible for locally computed eigenvectors (or `NULL`)

    1046:    Notes:
    1047:    This function is only available for spectrum slicing runs, that is, when
    1048:    an interval has been given with `EPSSetInterval()` and `STSINVERT` is set.
    1049:    See more details in section [](#sec:slice).

    1051:    The returned `Vec` should be destroyed by the user.

    1053:    Level: advanced

    1055: .seealso: [](ch:eps), [](#sec:slice), `EPSKRYLOVSCHUR`, `EPSSetInterval()`, `EPSKrylovSchurSetPartitions()`, `EPSKrylovSchurGetSubcommPairs()`
    1056: @*/
    1057: PetscErrorCode EPSKrylovSchurGetSubcommInfo(EPS eps,PetscInt *k,PetscInt *n,Vec *v)
    1058: {
    1059:   PetscFunctionBegin;
    1061:   PetscUseMethod(eps,"EPSKrylovSchurGetSubcommInfo_C",(EPS,PetscInt*,PetscInt*,Vec*),(eps,k,n,v));
    1062:   PetscFunctionReturn(PETSC_SUCCESS);
    1063: }

    1065: static PetscErrorCode EPSKrylovSchurGetSubcommPairs_KrylovSchur(EPS eps,PetscInt i,PetscScalar *eig,Vec v)
    1066: {
    1067:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
    1068:   EPS_SR          sr = ((EPS_KRYLOVSCHUR*)ctx->eps->data)->sr;

    1070:   PetscFunctionBegin;
    1071:   EPSCheckSolved(eps,1);
    1072:   PetscCheck(ctx->sr,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
    1073:   PetscCheck(i>=0 && i<sr->numEigs,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    1074:   if (eig) *eig = sr->eigr[sr->perm[i]];
    1075:   if (v) PetscCall(BVCopyVec(sr->V,sr->perm[i],v));
    1076:   PetscFunctionReturn(PETSC_SUCCESS);
    1077: }

    1079: /*@
    1080:    EPSKrylovSchurGetSubcommPairs - Gets the `i`-th eigenpair stored
    1081:    internally in the subcommunicator to which the calling process belongs.

    1083:    Collective on the subcommunicator (if `v` is given)

    1085:    Input Parameters:
    1086: +  eps - the linear eigensolver context
    1087: -  i   - index of the solution

    1089:    Output Parameters:
    1090: +  eig - the eigenvalue
    1091: -  v   - the eigenvector

    1093:    Notes:
    1094:    This function is only available for spectrum slicing runs, that is, when
    1095:    an interval has been given with `EPSSetInterval()` and `STSINVERT` is set.
    1096:    And is relevant only when the number of partitions (`EPSKrylovSchurSetPartitions()`)
    1097:    is larger than one. See more details in section [](#sec:slice).

    1099:    It is allowed to pass `NULL` for `v` if the eigenvector is not required.
    1100:    Otherwise, the caller must provide a valid `Vec` object, i.e.,
    1101:    it must be created by the calling program with `EPSKrylovSchurGetSubcommInfo()`.

    1103:    The index `i` should be a value between 0 and `n`-1, where `n` is the number of
    1104:    vectors in the local subinterval, see `EPSKrylovSchurGetSubcommInfo()`.

    1106:    Level: advanced

    1108: .seealso: [](ch:eps), [](#sec:slice), `EPSKRYLOVSCHUR`, `EPSSetInterval()`, `EPSKrylovSchurSetPartitions()`, `EPSKrylovSchurGetSubcommInfo()`, `EPSKrylovSchurGetSubcommMats()`
    1109: @*/
    1110: PetscErrorCode EPSKrylovSchurGetSubcommPairs(EPS eps,PetscInt i,PetscScalar *eig,Vec v)
    1111: {
    1112:   PetscFunctionBegin;
    1115:   PetscUseMethod(eps,"EPSKrylovSchurGetSubcommPairs_C",(EPS,PetscInt,PetscScalar*,Vec),(eps,i,eig,v));
    1116:   PetscFunctionReturn(PETSC_SUCCESS);
    1117: }

    1119: static PetscErrorCode EPSKrylovSchurGetSubcommMats_KrylovSchur(EPS eps,Mat *A,Mat *B)
    1120: {
    1121:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;

    1123:   PetscFunctionBegin;
    1124:   PetscCheck(ctx->sr,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
    1125:   PetscCheck(eps->state,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
    1126:   PetscCall(EPSGetOperators(ctx->eps,A,B));
    1127:   PetscFunctionReturn(PETSC_SUCCESS);
    1128: }

    1130: /*@
    1131:    EPSKrylovSchurGetSubcommMats - Gets the eigenproblem matrices stored
    1132:    internally in the subcommunicator to which the calling process belongs.

    1134:    Collective on the subcommunicator

    1136:    Input Parameter:
    1137: .  eps - the linear eigensolver context

    1139:    Output Parameters:
    1140: +  A  - the matrix associated with the eigensystem
    1141: -  B  - the second matrix in the case of generalized eigenproblems

    1143:    Notes:
    1144:    This function is only available for spectrum slicing runs, that is, when
    1145:    an interval has been given with `EPSSetInterval()` and `STSINVERT` is set.
    1146:    And is relevant only when the number of partitions (`EPSKrylovSchurSetPartitions()`)
    1147:    is larger than one. See more details in section [](#sec:slice).

    1149:    This is the analog of `EPSGetOperators()`, but returns the matrices distributed
    1150:    differently (in the subcommunicator rather than in the parent communicator).

    1152:    These matrices should not be modified by the user.

    1154:    Level: advanced

    1156: .seealso: [](ch:eps), [](#sec:slice), `EPSKRYLOVSCHUR`, `EPSSetInterval()`, `EPSKrylovSchurSetPartitions()`, `EPSKrylovSchurGetSubcommInfo()`
    1157: @*/
    1158: PetscErrorCode EPSKrylovSchurGetSubcommMats(EPS eps,Mat *A,Mat *B)
    1159: {
    1160:   PetscFunctionBegin;
    1162:   PetscTryMethod(eps,"EPSKrylovSchurGetSubcommMats_C",(EPS,Mat*,Mat*),(eps,A,B));
    1163:   PetscFunctionReturn(PETSC_SUCCESS);
    1164: }

    1166: static PetscErrorCode EPSKrylovSchurUpdateSubcommMats_KrylovSchur(EPS eps,PetscScalar a,PetscScalar ap,Mat Au,PetscScalar b,PetscScalar bp, Mat Bu,MatStructure str,PetscBool globalup)
    1167: {
    1168:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data,*subctx;
    1169:   Mat             A,B=NULL,Ag,Bg=NULL;
    1170:   PetscBool       reuse=PETSC_TRUE;

    1172:   PetscFunctionBegin;
    1173:   PetscCheck(ctx->sr,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
    1174:   PetscCheck(eps->state,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
    1175:   PetscCall(EPSGetOperators(eps,&Ag,&Bg));
    1176:   PetscCall(EPSGetOperators(ctx->eps,&A,&B));

    1178:   PetscCall(MatScale(A,a));
    1179:   if (Au) PetscCall(MatAXPY(A,ap,Au,str));
    1180:   if (B) PetscCall(MatScale(B,b));
    1181:   if (Bu) PetscCall(MatAXPY(B,bp,Bu,str));
    1182:   PetscCall(EPSSetOperators(ctx->eps,A,B));

    1184:   /* Update stored matrix state */
    1185:   subctx = (EPS_KRYLOVSCHUR*)ctx->eps->data;
    1186:   PetscCall(MatGetState(A,&subctx->Astate));
    1187:   if (B) PetscCall(MatGetState(B,&subctx->Bstate));

    1189:   /* Update matrices in the parent communicator if requested by user */
    1190:   if (globalup) {
    1191:     if (ctx->npart>1) {
    1192:       if (!ctx->isrow) {
    1193:         PetscCall(MatGetOwnershipIS(Ag,&ctx->isrow,&ctx->iscol));
    1194:         reuse = PETSC_FALSE;
    1195:       }
    1196:       if (str==DIFFERENT_NONZERO_PATTERN || str==UNKNOWN_NONZERO_PATTERN) reuse = PETSC_FALSE;
    1197:       if (ctx->submata && !reuse) PetscCall(MatDestroyMatrices(1,&ctx->submata));
    1198:       PetscCall(MatCreateSubMatrices(A,1,&ctx->isrow,&ctx->iscol,(reuse)?MAT_REUSE_MATRIX:MAT_INITIAL_MATRIX,&ctx->submata));
    1199:       PetscCall(MatCreateMPIMatConcatenateSeqMat(((PetscObject)Ag)->comm,ctx->submata[0],PETSC_DECIDE,MAT_REUSE_MATRIX,&Ag));
    1200:       if (B) {
    1201:         if (ctx->submatb && !reuse) PetscCall(MatDestroyMatrices(1,&ctx->submatb));
    1202:         PetscCall(MatCreateSubMatrices(B,1,&ctx->isrow,&ctx->iscol,(reuse)?MAT_REUSE_MATRIX:MAT_INITIAL_MATRIX,&ctx->submatb));
    1203:         PetscCall(MatCreateMPIMatConcatenateSeqMat(((PetscObject)Bg)->comm,ctx->submatb[0],PETSC_DECIDE,MAT_REUSE_MATRIX,&Bg));
    1204:       }
    1205:     }
    1206:     PetscCall(MatGetState(Ag,&ctx->Astate));
    1207:     if (Bg) PetscCall(MatGetState(Bg,&ctx->Bstate));
    1208:   }
    1209:   PetscCall(EPSSetOperators(eps,Ag,Bg));
    1210:   PetscFunctionReturn(PETSC_SUCCESS);
    1211: }

    1213: /*@
    1214:    EPSKrylovSchurUpdateSubcommMats - Update the eigenproblem matrices stored
    1215:    internally in the subcommunicator to which the calling process belongs.

    1217:    Collective

    1219:    Input Parameters:
    1220: +  eps - the linear eigensolver context
    1221: .  s   - scalar that multiplies the existing $A$ matrix
    1222: .  a   - scalar used in the _axpy_ operation on $A$
    1223: .  Au  - matrix used in the _axpy_ operation on $A$
    1224: .  t   - scalar that multiplies the existing $B$ matrix
    1225: .  b   - scalar used in the _axpy_ operation on $B$
    1226: .  Bu  - matrix used in the _axpy_ operation on $B$
    1227: .  str - structure flag, see `MatStructure`
    1228: -  globalup - flag indicating if global matrices must be updated

    1230:    Notes:
    1231:    This function is only available for spectrum slicing runs, that is, when
    1232:    an interval has been given with `EPSSetInterval()` and `STSINVERT` is set.
    1233:    And is relevant only when the number of partitions (`EPSKrylovSchurSetPartitions()`)
    1234:    is larger than one. See more details in section [](#sec:slice).

    1236:    This function modifies the eigenproblem matrices at the subcommunicator level,
    1237:    and optionally updates the global matrices in the parent communicator. The updates
    1238:    are expressed as $A \leftarrow s A + a A_u$ and $B \leftarrow t B + b B_u$.

    1240:    It is possible to update one of the matrices, or both.

    1242:    The matrices `Au` and `Bu` must be equal in all subcommunicators.

    1244:    The `str` flag is passed to the `MatAXPY()` operations to perform the updates.

    1246:    If `globalup` is `PETSC_TRUE`, communication is carried out to reconstruct the updated
    1247:    matrices in the parent communicator. The user must be warned that if global
    1248:    matrices are not in sync with subcommunicator matrices, the errors computed
    1249:    by `EPSComputeError()` will be wrong even if the computed solution is correct
    1250:    (the synchronization may be done only once at the end).

    1252:    Level: advanced

    1254: .seealso: [](ch:eps), [](#sec:slice), `EPSKRYLOVSCHUR`, `EPSSetInterval()`, `EPSKrylovSchurSetPartitions()`, `EPSKrylovSchurGetSubcommMats()`
    1255: @*/
    1256: PetscErrorCode EPSKrylovSchurUpdateSubcommMats(EPS eps,PetscScalar s,PetscScalar a,Mat Au,PetscScalar t,PetscScalar b,Mat Bu,MatStructure str,PetscBool globalup)
    1257: {
    1258:   PetscFunctionBegin;
    1268:   PetscTryMethod(eps,"EPSKrylovSchurUpdateSubcommMats_C",(EPS,PetscScalar,PetscScalar,Mat,PetscScalar,PetscScalar,Mat,MatStructure,PetscBool),(eps,s,a,Au,t,b,Bu,str,globalup));
    1269:   PetscFunctionReturn(PETSC_SUCCESS);
    1270: }

    1272: PetscErrorCode EPSKrylovSchurGetChildEPS(EPS eps,EPS *childeps)
    1273: {
    1274:   EPS_KRYLOVSCHUR  *ctx=(EPS_KRYLOVSCHUR*)eps->data,*ctx_local;
    1275:   Mat              A,B=NULL,Ar=NULL,Br=NULL;
    1276:   PetscMPIInt      rank;
    1277:   PetscObjectState Astate,Bstate=0;
    1278:   PetscObjectId    Aid,Bid=0;
    1279:   STType           sttype;
    1280:   PetscInt         nmat;
    1281:   const char       *prefix;
    1282:   MPI_Comm         child;

    1284:   PetscFunctionBegin;
    1285:   PetscCall(EPSGetOperators(eps,&A,&B));
    1286:   if (ctx->npart==1) {
    1287:     if (!ctx->eps) PetscCall(EPSCreate(((PetscObject)eps)->comm,&ctx->eps));
    1288:     PetscCall(EPSGetOptionsPrefix(eps,&prefix));
    1289:     PetscCall(EPSSetOptionsPrefix(ctx->eps,prefix));
    1290:     PetscCall(EPSSetOperators(ctx->eps,A,B));
    1291:   } else {
    1292:     PetscCall(MatGetState(A,&Astate));
    1293:     PetscCall(PetscObjectGetId((PetscObject)A,&Aid));
    1294:     if (B) {
    1295:       PetscCall(MatGetState(B,&Bstate));
    1296:       PetscCall(PetscObjectGetId((PetscObject)B,&Bid));
    1297:     }
    1298:     if (!ctx->subc) {
    1299:       /* Create context for subcommunicators */
    1300:       PetscCall(PetscSubcommCreate(PetscObjectComm((PetscObject)eps),&ctx->subc));
    1301:       PetscCall(PetscSubcommSetNumber(ctx->subc,ctx->npart));
    1302:       PetscCall(PetscSubcommSetType(ctx->subc,PETSC_SUBCOMM_CONTIGUOUS));
    1303:       PetscCall(PetscSubcommGetChild(ctx->subc,&child));

    1305:       /* Duplicate matrices */
    1306:       PetscCall(MatCreateRedundantMatrix(A,0,child,MAT_INITIAL_MATRIX,&Ar));
    1307:       ctx->Astate = Astate;
    1308:       ctx->Aid = Aid;
    1309:       PetscCall(MatPropagateSymmetryOptions(A,Ar));
    1310:       if (B) {
    1311:         PetscCall(MatCreateRedundantMatrix(B,0,child,MAT_INITIAL_MATRIX,&Br));
    1312:         ctx->Bstate = Bstate;
    1313:         ctx->Bid = Bid;
    1314:         PetscCall(MatPropagateSymmetryOptions(B,Br));
    1315:       }
    1316:     } else {
    1317:       PetscCall(PetscSubcommGetChild(ctx->subc,&child));
    1318:       if (ctx->Astate != Astate || (B && ctx->Bstate != Bstate) || ctx->Aid != Aid || (B && ctx->Bid != Bid)) {
    1319:         PetscCall(STGetNumMatrices(ctx->eps->st,&nmat));
    1320:         if (nmat) PetscCall(EPSGetOperators(ctx->eps,&Ar,&Br));
    1321:         PetscCall(MatCreateRedundantMatrix(A,0,child,MAT_INITIAL_MATRIX,&Ar));
    1322:         ctx->Astate = Astate;
    1323:         ctx->Aid = Aid;
    1324:         PetscCall(MatPropagateSymmetryOptions(A,Ar));
    1325:         if (B) {
    1326:           PetscCall(MatCreateRedundantMatrix(B,0,child,MAT_INITIAL_MATRIX,&Br));
    1327:           ctx->Bstate = Bstate;
    1328:           ctx->Bid = Bid;
    1329:           PetscCall(MatPropagateSymmetryOptions(B,Br));
    1330:         }
    1331:         PetscCall(EPSSetOperators(ctx->eps,Ar,Br));
    1332:         PetscCall(MatDestroy(&Ar));
    1333:         PetscCall(MatDestroy(&Br));
    1334:       }
    1335:     }

    1337:     /* Create auxiliary EPS */
    1338:     if (!ctx->eps) {
    1339:       PetscCall(EPSCreate(child,&ctx->eps));
    1340:       PetscCall(EPSGetOptionsPrefix(eps,&prefix));
    1341:       PetscCall(EPSSetOptionsPrefix(ctx->eps,prefix));
    1342:       PetscCall(EPSSetOperators(ctx->eps,Ar,Br));
    1343:       PetscCall(MatDestroy(&Ar));
    1344:       PetscCall(MatDestroy(&Br));
    1345:     }
    1346:     /* Create subcommunicator grouping processes with same rank */
    1347:     if (!ctx->commset) {
    1348:       PetscCallMPI(MPI_Comm_rank(child,&rank));
    1349:       PetscCallMPI(MPI_Comm_split(((PetscObject)eps)->comm,rank,ctx->subc->color,&ctx->commrank));
    1350:       ctx->commset = PETSC_TRUE;
    1351:     }
    1352:   }
    1353:   PetscCall(EPSSetType(ctx->eps,((PetscObject)eps)->type_name));
    1354:   PetscCall(STGetType(eps->st,&sttype));
    1355:   PetscCall(STSetType(ctx->eps->st,sttype));

    1357:   ctx_local = (EPS_KRYLOVSCHUR*)ctx->eps->data;
    1358:   ctx_local->npart = ctx->npart;
    1359:   ctx_local->global = PETSC_FALSE;
    1360:   ctx_local->eps = eps;
    1361:   ctx_local->subc = ctx->subc;
    1362:   ctx_local->commrank = ctx->commrank;
    1363:   *childeps = ctx->eps;
    1364:   PetscFunctionReturn(PETSC_SUCCESS);
    1365: }

    1367: static PetscErrorCode EPSKrylovSchurGetKSP_KrylovSchur(EPS eps,KSP *ksp)
    1368: {
    1369:   EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
    1370:   ST              st;
    1371:   PetscBool       isfilt;

    1373:   PetscFunctionBegin;
    1374:   PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt));
    1375:   PetscCheck(eps->which==EPS_ALL && !isfilt,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations with spectrum slicing");
    1376:   PetscCall(EPSKrylovSchurGetChildEPS(eps,&ctx->eps));
    1377:   PetscCall(EPSGetST(ctx->eps,&st));
    1378:   PetscCall(STGetOperator(st,NULL));
    1379:   PetscCall(STGetKSP(st,ksp));
    1380:   PetscFunctionReturn(PETSC_SUCCESS);
    1381: }

    1383: /*@
    1384:    EPSKrylovSchurGetKSP - Retrieve the linear solver object associated with the
    1385:    internal `EPS` object in case of doing spectrum slicing for a computational interval.

    1387:    Collective

    1389:    Input Parameter:
    1390: .  eps - the linear eigensolver context

    1392:    Output Parameter:
    1393: .  ksp - the internal `KSP` object

    1395:    Notes:
    1396:    When invoked to compute all eigenvalues in an interval with spectrum
    1397:    slicing, `EPSKRYLOVSCHUR` creates another `EPS` object internally that is
    1398:    used to compute eigenvalues by chunks near selected shifts. This function
    1399:    allows access to the `KSP` object associated to this internal `EPS` object.

    1401:    This function is only available for spectrum slicing runs, that is, when
    1402:    an interval has been given with `EPSSetInterval()` and `STSINVERT` is set.
    1403:    See more details in section [](#sec:slice).

    1405:    In case of having more than one partition, the returned `KSP` will be different
    1406:    in MPI processes belonging to different partitions. Hence, if required,
    1407:    `EPSKrylovSchurSetPartitions()` must be called BEFORE this function.

    1409:    Level: advanced

    1411: .seealso: [](ch:eps), [](#sec:slice), `EPSKRYLOVSCHUR`, `EPSSetInterval()`, `EPSKrylovSchurSetPartitions()`
    1412: @*/
    1413: PetscErrorCode EPSKrylovSchurGetKSP(EPS eps,KSP *ksp)
    1414: {
    1415:   PetscFunctionBegin;
    1417:   PetscUseMethod(eps,"EPSKrylovSchurGetKSP_C",(EPS,KSP*),(eps,ksp));
    1418:   PetscFunctionReturn(PETSC_SUCCESS);
    1419: }

    1421: static PetscErrorCode EPSKrylovSchurSetBSEType_KrylovSchur(EPS eps,EPSKrylovSchurBSEType bse)
    1422: {
    1423:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;

    1425:   PetscFunctionBegin;
    1426:   switch (bse) {
    1427:     case EPS_KRYLOVSCHUR_BSE_SHAO:
    1428:     case EPS_KRYLOVSCHUR_BSE_GRUNING:
    1429:     case EPS_KRYLOVSCHUR_BSE_PROJECTEDBSE:
    1430:       if (ctx->bse != bse) {
    1431:         ctx->bse = bse;
    1432:         eps->state = EPS_STATE_INITIAL;
    1433:       }
    1434:       break;
    1435:     default:
    1436:       SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Invalid BSE type");
    1437:   }
    1438:   PetscFunctionReturn(PETSC_SUCCESS);
    1439: }

    1441: /*@
    1442:    EPSKrylovSchurSetBSEType - Sets the method to be used for BSE structured eigenproblems
    1443:    in the Krylov-Schur solver.

    1445:    Logically Collective

    1447:    Input Parameters:
    1448: +  eps - the linear eigensolver context, see `EPSKrylovSchurBSEType` for possible values
    1449: -  bse - the BSE method

    1451:    Options Database Key:
    1452: .  -eps_krylovschur_bse_type (shao|gruning|projectedbse) - sets the BSE type

    1454:    Notes:
    1455:    This function is relevant only for `EPS_BSE` problem types, see section
    1456:    on [](#sec:structured).

    1458:    A detailed description of the methods can be found in {cite:p}`Alv25`.

    1460:    Level: advanced

    1462: .seealso: [](ch:eps), [](#sec:structured), `EPS_BSE`, `EPSKRYLOVSCHUR`, `EPSKrylovSchurGetBSEType()`, `EPSKrylovSchurBSEType`, `MatCreateBSE()`
    1463: @*/
    1464: PetscErrorCode EPSKrylovSchurSetBSEType(EPS eps,EPSKrylovSchurBSEType bse)
    1465: {
    1466:   PetscFunctionBegin;
    1469:   PetscTryMethod(eps,"EPSKrylovSchurSetBSEType_C",(EPS,EPSKrylovSchurBSEType),(eps,bse));
    1470:   PetscFunctionReturn(PETSC_SUCCESS);
    1471: }

    1473: static PetscErrorCode EPSKrylovSchurGetBSEType_KrylovSchur(EPS eps,EPSKrylovSchurBSEType *bse)
    1474: {
    1475:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;

    1477:   PetscFunctionBegin;
    1478:   *bse = ctx->bse;
    1479:   PetscFunctionReturn(PETSC_SUCCESS);
    1480: }

    1482: /*@
    1483:    EPSKrylovSchurGetBSEType - Gets the method used for BSE structured eigenproblems
    1484:    in the Krylov-Schur solver.

    1486:    Not Collective

    1488:    Input Parameter:
    1489: .  eps - the linear eigensolver context

    1491:    Output Parameter:
    1492: .  bse - the BSE method

    1494:    Level: advanced

    1496: .seealso: [](ch:eps), [](#sec:structured), `EPS_BSE`, `EPSKRYLOVSCHUR`, `EPSKrylovSchurSetBSEType()`, `EPSKrylovSchurBSEType`, `MatCreateBSE()`
    1497: @*/
    1498: PetscErrorCode EPSKrylovSchurGetBSEType(EPS eps,EPSKrylovSchurBSEType *bse)
    1499: {
    1500:   PetscFunctionBegin;
    1502:   PetscAssertPointer(bse,2);
    1503:   PetscUseMethod(eps,"EPSKrylovSchurGetBSEType_C",(EPS,EPSKrylovSchurBSEType*),(eps,bse));
    1504:   PetscFunctionReturn(PETSC_SUCCESS);
    1505: }

    1507: static PetscErrorCode EPSSetFromOptions_KrylovSchur(EPS eps,PetscOptionItems PetscOptionsObject)
    1508: {
    1509:   EPS_KRYLOVSCHUR       *ctx = (EPS_KRYLOVSCHUR*)eps->data;
    1510:   PetscBool             flg,lock,b,f1,f2,f3,isfilt;
    1511:   PetscReal             keep;
    1512:   PetscInt              i,j,k;
    1513:   KSP                   ksp;
    1514:   EPSKrylovSchurBSEType bse;

    1516:   PetscFunctionBegin;
    1517:   PetscOptionsHeadBegin(PetscOptionsObject,"EPS Krylov-Schur Options");

    1519:     PetscCall(PetscOptionsReal("-eps_krylovschur_restart","Proportion of vectors kept after restart","EPSKrylovSchurSetRestart",0.5,&keep,&flg));
    1520:     if (flg) PetscCall(EPSKrylovSchurSetRestart(eps,keep));

    1522:     PetscCall(PetscOptionsBool("-eps_krylovschur_locking","Choose between locking and non-locking variants","EPSKrylovSchurSetLocking",PETSC_TRUE,&lock,&flg));
    1523:     if (flg) PetscCall(EPSKrylovSchurSetLocking(eps,lock));

    1525:     i = ctx->npart;
    1526:     PetscCall(PetscOptionsInt("-eps_krylovschur_partitions","Number of partitions of the communicator for spectrum slicing","EPSKrylovSchurSetPartitions",ctx->npart,&i,&flg));
    1527:     if (flg) PetscCall(EPSKrylovSchurSetPartitions(eps,i));

    1529:     b = ctx->detect;
    1530:     PetscCall(PetscOptionsBool("-eps_krylovschur_detect_zeros","Check zeros during factorizations at subinterval boundaries","EPSKrylovSchurSetDetectZeros",ctx->detect,&b,&flg));
    1531:     if (flg) PetscCall(EPSKrylovSchurSetDetectZeros(eps,b));

    1533:     i = 1;
    1534:     j = k = PETSC_DECIDE;
    1535:     PetscCall(PetscOptionsInt("-eps_krylovschur_nev","Number of eigenvalues to compute in each subsolve (only for spectrum slicing)","EPSKrylovSchurSetDimensions",40,&i,&f1));
    1536:     PetscCall(PetscOptionsInt("-eps_krylovschur_ncv","Number of basis vectors in each subsolve (only for spectrum slicing)","EPSKrylovSchurSetDimensions",80,&j,&f2));
    1537:     PetscCall(PetscOptionsInt("-eps_krylovschur_mpd","Maximum dimension of projected problem in each subsolve (only for spectrum slicing)","EPSKrylovSchurSetDimensions",80,&k,&f3));
    1538:     if (f1 || f2 || f3) PetscCall(EPSKrylovSchurSetDimensions(eps,i,j,k));

    1540:     PetscCall(PetscOptionsEnum("-eps_krylovschur_bse_type","Method for BSE structured eigenproblems","EPSKrylovSchurSetBSEType",EPSKrylovSchurBSETypes,(PetscEnum)ctx->bse,(PetscEnum*)&bse,&flg));
    1541:     if (flg) PetscCall(EPSKrylovSchurSetBSEType(eps,bse));

    1543:   PetscOptionsHeadEnd();

    1545:   /* set options of child KSP in spectrum slicing */
    1546:   if (eps->which==EPS_ALL) {
    1547:     if (!eps->st) PetscCall(EPSGetST(eps,&eps->st));
    1548:     PetscCall(EPSSetDefaultST(eps));
    1549:     PetscCall(STSetFromOptions(eps->st));  /* need to advance this to check ST type */
    1550:     PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt));
    1551:     if (!isfilt) {
    1552:       PetscCall(EPSKrylovSchurGetKSP_KrylovSchur(eps,&ksp));
    1553:       PetscCall(KSPSetFromOptions(ksp));
    1554:     }
    1555:   }
    1556:   PetscFunctionReturn(PETSC_SUCCESS);
    1557: }

    1559: static PetscErrorCode EPSView_KrylovSchur(EPS eps,PetscViewer viewer)
    1560: {
    1561:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
    1562:   PetscBool       isascii,isfilt;
    1563:   KSP             ksp;
    1564:   PetscViewer     sviewer;

    1566:   PetscFunctionBegin;
    1567:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
    1568:   if (isascii) {
    1569:     PetscCall(PetscViewerASCIIPrintf(viewer,"  %d%% of basis vectors kept after restart\n",(int)(100*ctx->keep)));
    1570:     PetscCall(PetscViewerASCIIPrintf(viewer,"  using the %slocking variant\n",ctx->lock?"":"non-"));
    1571:     if (eps->problem_type==EPS_BSE) PetscCall(PetscViewerASCIIPrintf(viewer,"  BSE method: %s\n",EPSKrylovSchurBSETypes[ctx->bse]));
    1572:     if (eps->which==EPS_ALL) {
    1573:       PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt));
    1574:       if (isfilt) PetscCall(PetscViewerASCIIPrintf(viewer,"  using polynomial filtering%s\n",eps->nev?"":" to extract all eigenvalues in an interval"));
    1575:       else {
    1576:         PetscCall(PetscViewerASCIIPrintf(viewer,"  doing spectrum slicing with nev=%" PetscInt_FMT ", ncv=%" PetscInt_FMT ", mpd=%" PetscInt_FMT "\n",ctx->nev,ctx->ncv,ctx->mpd));
    1577:         if (ctx->npart>1) {
    1578:           PetscCall(PetscViewerASCIIPrintf(viewer,"  multi-communicator spectrum slicing with %" PetscInt_FMT " partitions\n",ctx->npart));
    1579:           if (ctx->detect) PetscCall(PetscViewerASCIIPrintf(viewer,"  detecting zeros when factorizing at subinterval boundaries\n"));
    1580:         }
    1581:         /* view child KSP */
    1582:         PetscCall(EPSKrylovSchurGetKSP_KrylovSchur(eps,&ksp));
    1583:         PetscCall(PetscViewerASCIIPushTab(viewer));
    1584:         if (ctx->npart>1 && ctx->subc) {
    1585:           PetscCall(PetscViewerGetSubViewer(viewer,ctx->subc->child,&sviewer));
    1586:           if (!ctx->subc->color) PetscCall(KSPView(ksp,sviewer));
    1587:           PetscCall(PetscViewerFlush(sviewer));
    1588:           PetscCall(PetscViewerRestoreSubViewer(viewer,ctx->subc->child,&sviewer));
    1589:           /* extra call needed because of the two calls to PetscViewerASCIIPushSynchronized() in PetscViewerGetSubViewer() */
    1590:           PetscCall(PetscViewerASCIIPopSynchronized(viewer));
    1591:         } else PetscCall(KSPView(ksp,viewer));
    1592:         PetscCall(PetscViewerASCIIPopTab(viewer));
    1593:       }
    1594:     }
    1595:   }
    1596:   PetscFunctionReturn(PETSC_SUCCESS);
    1597: }

    1599: static PetscErrorCode EPSDestroy_KrylovSchur(EPS eps)
    1600: {
    1601:   PetscBool      isfilt;

    1603:   PetscFunctionBegin;
    1604:   PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt));
    1605:   if (eps->which==EPS_ALL && !isfilt) PetscCall(EPSDestroy_KrylovSchur_Slice(eps));
    1606:   PetscCall(PetscFree(eps->data));
    1607:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetRestart_C",NULL));
    1608:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetRestart_C",NULL));
    1609:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetLocking_C",NULL));
    1610:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetLocking_C",NULL));
    1611:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetPartitions_C",NULL));
    1612:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetPartitions_C",NULL));
    1613:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetDetectZeros_C",NULL));
    1614:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetDetectZeros_C",NULL));
    1615:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetDimensions_C",NULL));
    1616:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetDimensions_C",NULL));
    1617:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetSubintervals_C",NULL));
    1618:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubintervals_C",NULL));
    1619:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetInertias_C",NULL));
    1620:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommInfo_C",NULL));
    1621:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommPairs_C",NULL));
    1622:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommMats_C",NULL));
    1623:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurUpdateSubcommMats_C",NULL));
    1624:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetKSP_C",NULL));
    1625:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetBSEType_C",NULL));
    1626:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetBSEType_C",NULL));
    1627:   PetscFunctionReturn(PETSC_SUCCESS);
    1628: }

    1630: static PetscErrorCode EPSReset_KrylovSchur(EPS eps)
    1631: {
    1632:   PetscBool      isfilt;

    1634:   PetscFunctionBegin;
    1635:   PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt));
    1636:   if (eps->which==EPS_ALL && !isfilt) PetscCall(EPSReset_KrylovSchur_Slice(eps));
    1637:   PetscFunctionReturn(PETSC_SUCCESS);
    1638: }

    1640: static PetscErrorCode EPSSetDefaultST_KrylovSchur(EPS eps)
    1641: {
    1642:   PetscFunctionBegin;
    1643:   if (eps->which==EPS_ALL) {
    1644:     if (!((PetscObject)eps->st)->type_name) PetscCall(STSetType(eps->st,STSINVERT));
    1645:   }
    1646:   PetscFunctionReturn(PETSC_SUCCESS);
    1647: }

    1649: /*MC
    1650:    EPSKRYLOVSCHUR - EPSKRYLOVSCHUR = "krylovschur" - Krylov-Schur method.

    1652:    Notes:
    1653:    This is the default solver, and is recommended in most situations.

    1655:    The implemented algorithm is the single-vector Krylov-Schur method proposed
    1656:    by {cite:t}`Ste01b` for non-Hermitian eigenproblems. When the problem is
    1657:    Hermitian, the solver will behave as a thick-restart Lanczos method
    1658:    {cite:p}`Wu00` with full reorthogonalization.

    1660:    The solver includes support for many features\:
    1661:    - Harmonic extraction, see `EPSSetExtraction()`.
    1662:    - Inertia-based spectrum slicing to compute all eigenvalues in an interval,
    1663:      see {cite:p}`Cam12`.
    1664:    - Polynomial filter to compute eigenvalues in an interval via `STFILTER`.
    1665:    - Indefinite Lanczos to solve `EPSGHIEP` problems.
    1666:    - Structured variants for problem types such as `EPSBSE`.
    1667:    - A two-sided variant that also computes left eigenvectors.
    1668:    - Arbitrary selection of eigenvalues, see `EPSSetArbitrarySelection()`.

    1670:    Developer Note:
    1671:    In the future, we would like to have a block version of Krylov-Schur.

    1673:    Level: beginner

    1675: .seealso: [](ch:eps), `EPS`, `EPSType`, `EPSSetType()`, `EPSSetProblemType()`, `EPSSetExtraction()`, `EPSSetArbitrarySelection()`, `EPSSetTwoSided()`
    1676: M*/
    1677: SLEPC_EXTERN PetscErrorCode EPSCreate_KrylovSchur(EPS eps)
    1678: {
    1679:   EPS_KRYLOVSCHUR *ctx;

    1681:   PetscFunctionBegin;
    1682:   PetscCall(PetscNew(&ctx));
    1683:   eps->data   = (void*)ctx;
    1684:   ctx->lock   = PETSC_TRUE;
    1685:   ctx->nev    = 1;
    1686:   ctx->ncv    = PETSC_DETERMINE;
    1687:   ctx->mpd    = PETSC_DETERMINE;
    1688:   ctx->npart  = 1;
    1689:   ctx->detect = PETSC_FALSE;
    1690:   ctx->global = PETSC_TRUE;

    1692:   eps->useds = PETSC_TRUE;

    1694:   /* solve and computevectors determined at setup */
    1695:   eps->ops->setup          = EPSSetUp_KrylovSchur;
    1696:   eps->ops->setupsort      = EPSSetUpSort_KrylovSchur;
    1697:   eps->ops->setfromoptions = EPSSetFromOptions_KrylovSchur;
    1698:   eps->ops->destroy        = EPSDestroy_KrylovSchur;
    1699:   eps->ops->reset          = EPSReset_KrylovSchur;
    1700:   eps->ops->view           = EPSView_KrylovSchur;
    1701:   eps->ops->backtransform  = EPSBackTransform_Default;
    1702:   eps->ops->setdefaultst   = EPSSetDefaultST_KrylovSchur;

    1704:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetRestart_C",EPSKrylovSchurSetRestart_KrylovSchur));
    1705:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetRestart_C",EPSKrylovSchurGetRestart_KrylovSchur));
    1706:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetLocking_C",EPSKrylovSchurSetLocking_KrylovSchur));
    1707:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetLocking_C",EPSKrylovSchurGetLocking_KrylovSchur));
    1708:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetPartitions_C",EPSKrylovSchurSetPartitions_KrylovSchur));
    1709:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetPartitions_C",EPSKrylovSchurGetPartitions_KrylovSchur));
    1710:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetDetectZeros_C",EPSKrylovSchurSetDetectZeros_KrylovSchur));
    1711:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetDetectZeros_C",EPSKrylovSchurGetDetectZeros_KrylovSchur));
    1712:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetDimensions_C",EPSKrylovSchurSetDimensions_KrylovSchur));
    1713:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetDimensions_C",EPSKrylovSchurGetDimensions_KrylovSchur));
    1714:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetSubintervals_C",EPSKrylovSchurSetSubintervals_KrylovSchur));
    1715:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubintervals_C",EPSKrylovSchurGetSubintervals_KrylovSchur));
    1716:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetInertias_C",EPSKrylovSchurGetInertias_KrylovSchur));
    1717:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommInfo_C",EPSKrylovSchurGetSubcommInfo_KrylovSchur));
    1718:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommPairs_C",EPSKrylovSchurGetSubcommPairs_KrylovSchur));
    1719:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommMats_C",EPSKrylovSchurGetSubcommMats_KrylovSchur));
    1720:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurUpdateSubcommMats_C",EPSKrylovSchurUpdateSubcommMats_KrylovSchur));
    1721:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetKSP_C",EPSKrylovSchurGetKSP_KrylovSchur));
    1722:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetBSEType_C",EPSKrylovSchurSetBSEType_KrylovSchur));
    1723:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetBSEType_C",EPSKrylovSchurGetBSEType_KrylovSchur));
    1724:   PetscFunctionReturn(PETSC_SUCCESS);
    1725: }