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 | EPS_FEATURE_THRESHOLD,PETSC_TRUE," with polynomial filter");
 73:   if (eps->tol==(PetscReal)PETSC_DETERMINE) eps->tol = SLEPC_DEFAULT_TOL*1e-2;  /* use tighter tolerance */
 74:   PetscCall(STFilterSetInterval(eps->st,eps->inta,eps->intb));
 75:   if (!ctx->estimatedrange) {
 76:     PetscCall(STFilterGetRange(eps->st,&rleft,&rright));
 77:     estimaterange = (!rleft && !rright)? PETSC_TRUE: PETSC_FALSE;
 78:   }
 79:   if (estimaterange) { /* user did not set a range */
 80:     PetscCall(STGetMatrix(eps->st,0,&A));
 81:     PetscCall(MatEstimateSpectralRange_EPS(A,&rleft,&rright));
 82:     PetscCall(PetscInfo(eps,"Setting eigenvalue range to [%g,%g]\n",(double)rleft,(double)rright));
 83:     PetscCall(STFilterSetRange(eps->st,rleft,rright));
 84:     ctx->estimatedrange = PETSC_TRUE;
 85:   }
 86:   if (eps->ncv==PETSC_DETERMINE && eps->nev==0) eps->nev = 40;  /* user did not provide nev estimation */
 87:   PetscCall(EPSSetDimensions_Default(eps,&eps->nev,&eps->ncv,&eps->mpd));
 88:   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");
 89:   if (eps->max_it==PETSC_DETERMINE) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
 90:   PetscFunctionReturn(PETSC_SUCCESS);
 91: }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

358:   PetscFunctionBegin;
359:   if (keep==(PetscReal)PETSC_DEFAULT || keep==(PetscReal)PETSC_DECIDE) ctx->keep = 0.5;
360:   else {
361:     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);
362:     ctx->keep = keep;
363:   }
364:   PetscFunctionReturn(PETSC_SUCCESS);
365: }

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

372:    Logically Collective

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

378:    Options Database Key:
379: .  -eps_krylovschur_restart \<keep\> - sets the restart parameter

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

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

388:    Level: advanced

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

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

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

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

414:    Not Collective

416:    Input Parameter:
417: .  eps - the linear eigensolver context

419:    Output Parameter:
420: .  keep - the restart parameter

422:    Level: advanced

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

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

439:   PetscFunctionBegin;
440:   ctx->lock = lock;
441:   PetscFunctionReturn(PETSC_SUCCESS);
442: }

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

448:    Logically Collective

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

454:    Options Database Key:
455: .  -eps_krylovschur_locking - sets the locking flag

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

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

465:    Level: advanced

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

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

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

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

491:    Not Collective

493:    Input Parameter:
494: .  eps - the linear eigensolver context

496:    Output Parameter:
497: .  lock - the locking flag

499:    Level: advanced

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

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

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

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

546:    Logically Collective

548:    Input Parameters:
549: +  eps   - the linear eigensolver context
550: -  npart - number of partitions

552:    Options Database Key:
553: .  -eps_krylovschur_partitions \<npart\> - sets the number of partitions

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

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

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

568:    Level: advanced

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

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

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

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

594:    Not Collective

596:    Input Parameter:
597: .  eps - the linear eigensolver context

599:    Output Parameter:
600: .  npart - number of partitions

602:    Level: advanced

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

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

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

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

629:    Logically Collective

631:    Input Parameters:
632: +  eps    - the linear eigensolver context
633: -  detect - check for zeros

635:    Options Database Key:
636: .  -eps_krylovschur_detect_zeros - check for zeros

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

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

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

650:    Level: advanced

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

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

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

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

676:    Not Collective

678:    Input Parameter:
679: .  eps - the linear eigensolver context

681:    Output Parameter:
682: .  detect - whether zeros detection is enforced during factorizations

684:    Level: advanced

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

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

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

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

726:    Logically Collective

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

734:    Options Database Keys:
735: +  -eps_krylovschur_nev \<nev\> - sets the number of eigenvalues
736: .  -eps_krylovschur_ncv \<ncv\> - sets the dimension of the subspace
737: -  -eps_krylovschur_mpd \<mpd\> - sets the maximum projected dimension

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

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

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

750:    Level: advanced

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

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

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

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

780:    Not Collective

782:    Input Parameter:
783: .  eps - the linear eigensolver context

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

790:    Level: advanced

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

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

807:   PetscFunctionBegin;
808:   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()");
809:   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");
810:   if (ctx->subintervals) PetscCall(PetscFree(ctx->subintervals));
811:   PetscCall(PetscMalloc1(ctx->npart+1,&ctx->subintervals));
812:   for (i=0;i<ctx->npart+1;i++) ctx->subintervals[i] = subint[i];
813:   ctx->subintset = PETSC_TRUE;
814:   eps->state = EPS_STATE_INITIAL;
815:   PetscFunctionReturn(PETSC_SUCCESS);
816: }

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

822:    Logically Collective

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

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

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

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

842:    Level: advanced

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

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

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

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

874:    Not Collective

876:    Input Parameter:
877: .  eps    - the linear eigensolver context

879:    Output Parameter:
880: .  subint - array of real values specifying subintervals

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

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

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

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

901:    Level: advanced

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

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

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

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

964:    Not Collective

966:    Input Parameter:
967: .  eps - the linear eigensolver context

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

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

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

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

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

1001:    Level: advanced

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

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

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

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

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

1035:    Input Parameter:
1036: .  eps - the linear eigensolver context

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

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

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

1051:    Level: advanced

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

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

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

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

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

1083:    Input Parameters:
1084: +  eps - the linear eigensolver context
1085: -  i   - index of the solution

1087:    Output Parameters:
1088: +  eig - the eigenvalue
1089: -  v   - the eigenvector

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

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

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

1104:    Level: advanced

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

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

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

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

1132:    Collective on the subcommunicator

1134:    Input Parameter:
1135: .  eps - the linear eigensolver context

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

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

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

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

1152:    Level: advanced

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

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

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

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

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

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

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

1215:    Collective

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

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

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

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

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

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

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

1250:    Level: advanced

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

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

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

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

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

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

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

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

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

1385:    Collective

1387:    Input Parameter:
1388: .  eps - the linear eigensolver context

1390:    Output Parameter:
1391: .  ksp - the internal `KSP` object

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

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

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

1407:    Level: advanced

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

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

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

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

1443:    Logically Collective

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

1449:    Options Database Key:
1450: .  -eps_krylovschur_bse_type \<bse\> - sets the BSE type, either `shao`, `gruning`, or `projectedbse`

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

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

1458:    Level: advanced

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

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

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

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

1484:    Not Collective

1486:    Input Parameter:
1487: .  eps - the linear eigensolver context

1489:    Output Parameter:
1490: .  bse - the BSE method

1492:    Level: advanced

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

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

1514:   PetscFunctionBegin;
1515:   PetscOptionsHeadBegin(PetscOptionsObject,"EPS Krylov-Schur Options");

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

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

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

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

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

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

1541:   PetscOptionsHeadEnd();

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

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

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

1597: static PetscErrorCode EPSDestroy_KrylovSchur(EPS eps)
1598: {
1599:   PetscBool      isfilt;

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

1628: static PetscErrorCode EPSReset_KrylovSchur(EPS eps)
1629: {
1630:   PetscBool      isfilt;

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

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

1647: /*MC
1648:    EPSKRYLOVSCHUR - EPSKRYLOVSCHUR = "krylovschur" - Krylov-Schur method.

1650:    Notes:
1651:    This is the default solver, and is recommended in most situations.

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

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

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

1671:    Level: beginner

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

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

1690:   eps->useds = PETSC_TRUE;

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

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