Line data Source code
1 : /*
2 : - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3 : SLEPc - Scalable Library for Eigenvalue Problem Computations
4 : Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
5 :
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"
12 :
13 : Method: Krylov-Schur
14 :
15 : Algorithm:
16 :
17 : Single-vector Krylov-Schur method for non-symmetric problems,
18 : including harmonic extraction.
19 :
20 : References:
21 :
22 : [1] "Krylov-Schur Methods in SLEPc", SLEPc Technical Report STR-7,
23 : available at https://slepc.upv.es.
24 :
25 : [2] G.W. Stewart, "A Krylov-Schur Algorithm for Large Eigenproblems",
26 : SIAM J. Matrix Anal. App. 23(3):601-614, 2001.
27 :
28 : [3] "Practical Implementation of Harmonic Krylov-Schur", SLEPc Technical
29 : Report STR-9, available at https://slepc.upv.es.
30 : */
31 :
32 : #include <slepc/private/epsimpl.h> /*I "slepceps.h" I*/
33 : #include "krylovschur.h"
34 :
35 22 : PetscErrorCode EPSGetArbitraryValues(EPS eps,PetscScalar *rr,PetscScalar *ri)
36 : {
37 22 : PetscInt i,newi,ld,n,l;
38 22 : Vec xr=eps->work[0],xi=eps->work[1];
39 22 : PetscScalar re,im,*Zr,*Zi,*X;
40 :
41 22 : PetscFunctionBegin;
42 22 : PetscCall(DSGetLeadingDimension(eps->ds,&ld));
43 22 : PetscCall(DSGetDimensions(eps->ds,&n,&l,NULL,NULL));
44 374 : for (i=l;i<n;i++) {
45 352 : re = eps->eigr[i];
46 352 : im = eps->eigi[i];
47 352 : PetscCall(STBackTransform(eps->st,1,&re,&im));
48 352 : newi = i;
49 352 : PetscCall(DSVectors(eps->ds,DS_MAT_X,&newi,NULL));
50 352 : PetscCall(DSGetArray(eps->ds,DS_MAT_X,&X));
51 352 : Zr = X+i*ld;
52 352 : if (newi==i+1) Zi = X+newi*ld;
53 : else Zi = NULL;
54 352 : PetscCall(EPSComputeRitzVector(eps,Zr,Zi,eps->V,xr,xi));
55 352 : PetscCall(DSRestoreArray(eps->ds,DS_MAT_X,&X));
56 352 : PetscCall((*eps->arbitrary)(re,im,xr,xi,rr+i,ri+i,eps->arbitraryctx));
57 : }
58 22 : PetscFunctionReturn(PETSC_SUCCESS);
59 : }
60 :
61 8 : static PetscErrorCode EPSSetUp_KrylovSchur_Filter(EPS eps)
62 : {
63 8 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
64 8 : PetscBool estimaterange=PETSC_TRUE;
65 8 : PetscReal rleft,rright;
66 8 : Mat A;
67 :
68 8 : PetscFunctionBegin;
69 8 : EPSCheckHermitianCondition(eps,PETSC_TRUE," with polynomial filter");
70 8 : EPSCheckStandardCondition(eps,PETSC_TRUE," with polynomial filter");
71 8 : 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 8 : EPSCheckUnsupportedCondition(eps,EPS_FEATURE_ARBITRARY | EPS_FEATURE_REGION | EPS_FEATURE_EXTRACTION | EPS_FEATURE_THRESHOLD,PETSC_TRUE," with polynomial filter");
73 8 : if (eps->tol==(PetscReal)PETSC_DETERMINE) eps->tol = SLEPC_DEFAULT_TOL*1e-2; /* use tighter tolerance */
74 8 : PetscCall(STFilterSetInterval(eps->st,eps->inta,eps->intb));
75 8 : if (!ctx->estimatedrange) {
76 6 : PetscCall(STFilterGetRange(eps->st,&rleft,&rright));
77 6 : estimaterange = (!rleft && !rright)? PETSC_TRUE: PETSC_FALSE;
78 : }
79 6 : if (estimaterange) { /* user did not set a range */
80 6 : PetscCall(STGetMatrix(eps->st,0,&A));
81 6 : PetscCall(MatEstimateSpectralRange_EPS(A,&rleft,&rright));
82 6 : PetscCall(PetscInfo(eps,"Setting eigenvalue range to [%g,%g]\n",(double)rleft,(double)rright));
83 6 : PetscCall(STFilterSetRange(eps->st,rleft,rright));
84 6 : ctx->estimatedrange = PETSC_TRUE;
85 : }
86 8 : if (eps->ncv==PETSC_DETERMINE && eps->nev==0) eps->nev = 40; /* user did not provide nev estimation */
87 8 : PetscCall(EPSSetDimensions_Default(eps,&eps->nev,&eps->ncv,&eps->mpd));
88 8 : 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 8 : if (eps->max_it==PETSC_DETERMINE) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
90 8 : PetscFunctionReturn(PETSC_SUCCESS);
91 : }
92 :
93 501 : static PetscErrorCode EPSSetUp_KrylovSchur(EPS eps)
94 : {
95 501 : PetscReal eta;
96 501 : PetscBool isfilt=PETSC_FALSE;
97 501 : BVOrthogType otype;
98 501 : BVOrthogBlockType obtype;
99 501 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
100 501 : enum { EPS_KS_DEFAULT,EPS_KS_SYMM,EPS_KS_SLICE,EPS_KS_FILTER,EPS_KS_INDEF,EPS_KS_TWOSIDED } variant;
101 :
102 501 : PetscFunctionBegin;
103 501 : if (eps->which==EPS_ALL) { /* default values in case of spectrum slicing or polynomial filter */
104 44 : PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt));
105 44 : if (isfilt) PetscCall(EPSSetUp_KrylovSchur_Filter(eps));
106 36 : else PetscCall(EPSSetUp_KrylovSchur_Slice(eps));
107 457 : } else if (eps->isstructured) {
108 20 : PetscCall(EPSSetUp_KrylovSchur_BSE(eps));
109 20 : PetscFunctionReturn(PETSC_SUCCESS);
110 : } else {
111 437 : PetscCall(EPSSetDimensions_Default(eps,&eps->nev,&eps->ncv,&eps->mpd));
112 437 : 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");
113 636 : if (eps->max_it==PETSC_DETERMINE) eps->max_it = PetscMax(100,2*eps->n/eps->ncv)*((eps->stop==EPS_STOP_THRESHOLD)?10:1);
114 437 : if (!eps->which) PetscCall(EPSSetWhichEigenpairs_Default(eps));
115 : }
116 481 : PetscCheck(ctx->lock || eps->mpd>=eps->ncv,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Should not use mpd parameter in non-locking variant");
117 :
118 481 : EPSCheckDefiniteCondition(eps,eps->arbitrary," with arbitrary selection of eigenpairs");
119 :
120 481 : PetscCheck(eps->extraction==EPS_RITZ || eps->extraction==EPS_HARMONIC,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Unsupported extraction type");
121 :
122 481 : if (!ctx->keep) ctx->keep = 0.5;
123 :
124 481 : PetscCall(EPSAllocateSolution(eps,1));
125 481 : PetscCall(EPS_SetInnerProduct(eps));
126 481 : if (eps->arbitrary) PetscCall(EPSSetWorkVecs(eps,2));
127 479 : else if (eps->ishermitian && !eps->ispositive) PetscCall(EPSSetWorkVecs(eps,1));
128 :
129 : /* dispatch solve method */
130 481 : if (eps->ishermitian) {
131 237 : if (eps->which==EPS_ALL) {
132 44 : EPSCheckDefiniteCondition(eps,eps->which==EPS_ALL," with spectrum slicing");
133 44 : variant = isfilt? EPS_KS_FILTER: EPS_KS_SLICE;
134 193 : } else if (eps->isgeneralized && !eps->ispositive) {
135 : variant = EPS_KS_INDEF;
136 : } else {
137 180 : switch (eps->extraction) {
138 : case EPS_RITZ: variant = EPS_KS_SYMM; break;
139 : case EPS_HARMONIC: variant = EPS_KS_DEFAULT; break;
140 0 : default: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Unsupported extraction type");
141 : }
142 : }
143 244 : } else if (eps->twosided) {
144 : variant = EPS_KS_TWOSIDED;
145 : } else {
146 231 : switch (eps->extraction) {
147 : case EPS_RITZ: variant = EPS_KS_DEFAULT; break;
148 : case EPS_HARMONIC: variant = EPS_KS_DEFAULT; break;
149 0 : default: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Unsupported extraction type");
150 : }
151 : }
152 62 : switch (variant) {
153 236 : case EPS_KS_DEFAULT:
154 236 : eps->ops->solve = EPSSolve_KrylovSchur_Default;
155 236 : eps->ops->computevectors = EPSComputeVectors_Schur;
156 236 : PetscCall(DSSetType(eps->ds,DSNHEP));
157 236 : PetscCall(DSSetExtraRow(eps->ds,PETSC_TRUE));
158 236 : PetscCall(DSAllocate(eps->ds,eps->ncv+1));
159 : break;
160 183 : case EPS_KS_SYMM:
161 : case EPS_KS_FILTER:
162 183 : eps->ops->solve = EPSSolve_KrylovSchur_Default;
163 183 : eps->ops->computevectors = EPSComputeVectors_Hermitian;
164 183 : PetscCall(DSSetType(eps->ds,DSHEP));
165 183 : PetscCall(DSSetCompact(eps->ds,PETSC_TRUE));
166 183 : PetscCall(DSSetExtraRow(eps->ds,PETSC_TRUE));
167 183 : PetscCall(DSAllocate(eps->ds,eps->ncv+1));
168 : break;
169 : case EPS_KS_SLICE:
170 36 : eps->ops->solve = EPSSolve_KrylovSchur_Slice;
171 36 : eps->ops->computevectors = EPSComputeVectors_Slice;
172 36 : break;
173 : case EPS_KS_INDEF:
174 13 : eps->ops->solve = EPSSolve_KrylovSchur_Indefinite;
175 13 : eps->ops->computevectors = EPSComputeVectors_Indefinite;
176 13 : PetscCall(DSSetType(eps->ds,DSGHIEP));
177 13 : PetscCall(DSSetCompact(eps->ds,PETSC_TRUE));
178 13 : PetscCall(DSSetExtraRow(eps->ds,PETSC_TRUE));
179 13 : PetscCall(DSAllocate(eps->ds,eps->ncv+1));
180 : /* force reorthogonalization for pseudo-Lanczos */
181 13 : PetscCall(BVGetOrthogonalization(eps->V,&otype,NULL,&eta,&obtype));
182 13 : PetscCall(BVSetOrthogonalization(eps->V,otype,BV_ORTHOG_REFINE_ALWAYS,eta,obtype));
183 : break;
184 : case EPS_KS_TWOSIDED:
185 13 : eps->ops->solve = EPSSolve_KrylovSchur_TwoSided;
186 13 : eps->ops->computevectors = EPSComputeVectors_Schur;
187 13 : PetscCall(DSSetType(eps->ds,DSNHEPTS));
188 13 : PetscCall(DSAllocate(eps->ds,eps->ncv+1));
189 13 : PetscCall(DSSetExtraRow(eps->ds,PETSC_TRUE));
190 : break;
191 481 : default: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Unexpected error");
192 : }
193 481 : PetscFunctionReturn(PETSC_SUCCESS);
194 : }
195 :
196 501 : static PetscErrorCode EPSSetUpSort_KrylovSchur(EPS eps)
197 : {
198 501 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
199 501 : SlepcSC sc;
200 501 : PetscBool isfilt;
201 :
202 501 : PetscFunctionBegin;
203 501 : PetscCall(EPSSetUpSort_Default(eps));
204 501 : if (eps->which==EPS_ALL) {
205 44 : PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt));
206 44 : if (isfilt) {
207 8 : PetscCall(DSGetSlepcSC(eps->ds,&sc));
208 8 : sc->rg = NULL;
209 8 : sc->comparison = SlepcCompareLargestReal;
210 8 : sc->comparisonctx = NULL;
211 8 : sc->map = NULL;
212 8 : sc->mapobj = NULL;
213 : } else {
214 36 : if (!ctx->global && ctx->sr->numEigs>0) {
215 18 : PetscCall(DSGetSlepcSC(eps->ds,&sc));
216 18 : sc->rg = NULL;
217 18 : sc->comparison = SlepcCompareLargestMagnitude;
218 18 : sc->comparisonctx = NULL;
219 18 : sc->map = NULL;
220 18 : sc->mapobj = NULL;
221 : }
222 : }
223 : }
224 501 : PetscFunctionReturn(PETSC_SUCCESS);
225 : }
226 :
227 419 : PetscErrorCode EPSSolve_KrylovSchur_Default(EPS eps)
228 : {
229 419 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
230 419 : PetscInt i,j,*pj,k,l,nv,ld,nconv;
231 419 : Mat U,Op,H,T;
232 419 : PetscScalar *g;
233 419 : PetscReal beta,gamma=1.0;
234 419 : PetscBool breakdown,harmonic,hermitian;
235 :
236 419 : PetscFunctionBegin;
237 419 : PetscCall(DSGetLeadingDimension(eps->ds,&ld));
238 419 : harmonic = (eps->extraction==EPS_HARMONIC || eps->extraction==EPS_REFINED_HARMONIC)?PETSC_TRUE:PETSC_FALSE;
239 419 : hermitian = (eps->ishermitian && !harmonic)?PETSC_TRUE:PETSC_FALSE;
240 419 : if (harmonic) PetscCall(PetscMalloc1(ld,&g));
241 419 : if (eps->arbitrary) pj = &j;
242 417 : else pj = NULL;
243 :
244 : /* Get the starting Arnoldi vector */
245 419 : PetscCall(EPSGetStartVector(eps,0,NULL));
246 419 : l = 0;
247 :
248 : /* Restart loop */
249 419 : while (eps->reason == EPS_CONVERGED_ITERATING) {
250 2358 : eps->its++;
251 :
252 : /* Compute an nv-step Arnoldi factorization */
253 2358 : nv = PetscMin(eps->nconv+eps->mpd,eps->ncv);
254 2358 : PetscCall(DSSetDimensions(eps->ds,nv,eps->nconv,eps->nconv+l));
255 2358 : PetscCall(STGetOperator(eps->st,&Op));
256 2358 : if (hermitian) {
257 1308 : PetscCall(DSGetMat(eps->ds,DS_MAT_T,&T));
258 1308 : PetscCall(BVMatLanczos(eps->V,Op,T,eps->nconv+l,&nv,&beta,&breakdown));
259 1308 : PetscCall(DSRestoreMat(eps->ds,DS_MAT_T,&T));
260 : } else {
261 1050 : PetscCall(DSGetMat(eps->ds,DS_MAT_A,&H));
262 1050 : PetscCall(BVMatArnoldi(eps->V,Op,H,eps->nconv+l,&nv,&beta,&breakdown));
263 1050 : PetscCall(DSRestoreMat(eps->ds,DS_MAT_A,&H));
264 : }
265 2358 : PetscCall(STRestoreOperator(eps->st,&Op));
266 2358 : PetscCall(DSSetDimensions(eps->ds,nv,eps->nconv,eps->nconv+l));
267 2358 : PetscCall(DSSetState(eps->ds,l?DS_STATE_RAW:DS_STATE_INTERMEDIATE));
268 2358 : PetscCall(BVSetActiveColumns(eps->V,eps->nconv,nv));
269 :
270 : /* Compute translation of Krylov decomposition if harmonic extraction used */
271 2358 : if (PetscUnlikely(harmonic)) PetscCall(DSTranslateHarmonic(eps->ds,eps->target,beta,PETSC_FALSE,g,&gamma));
272 :
273 : /* Solve projected problem */
274 2358 : PetscCall(DSSolve(eps->ds,eps->eigr,eps->eigi));
275 2358 : if (PetscUnlikely(eps->arbitrary)) {
276 22 : PetscCall(EPSGetArbitraryValues(eps,eps->rr,eps->ri));
277 22 : j=1;
278 : }
279 2358 : PetscCall(DSSort(eps->ds,eps->eigr,eps->eigi,eps->rr,eps->ri,pj));
280 2358 : PetscCall(DSUpdateExtraRow(eps->ds));
281 2358 : PetscCall(DSSynchronize(eps->ds,eps->eigr,eps->eigi));
282 :
283 : /* Check convergence */
284 2358 : PetscCall(EPSKrylovConvergence(eps,PETSC_FALSE,eps->nconv,nv-eps->nconv,beta,0.0,gamma,&k));
285 2358 : EPSSetCtxThreshold(eps,eps->eigr,eps->eigi,k);
286 2358 : PetscCall((*eps->stopping)(eps,eps->its,eps->max_it,k,eps->nev,&eps->reason,eps->stoppingctx));
287 2358 : nconv = k;
288 :
289 : /* Update l */
290 2358 : if (eps->reason != EPS_CONVERGED_ITERATING || breakdown || k==nv) l = 0;
291 : else {
292 1939 : l = PetscMax(1,(PetscInt)((nv-k)*ctx->keep));
293 1939 : if (!hermitian) PetscCall(DSGetTruncateSize(eps->ds,k,nv,&l));
294 : }
295 2358 : if (!ctx->lock && l>0) { l += k; k = 0; } /* non-locking variant: reset no. of converged pairs */
296 2358 : if (l) PetscCall(PetscInfo(eps,"Preparing to restart keeping l=%" PetscInt_FMT " vectors\n",l));
297 :
298 2358 : if (eps->reason == EPS_CONVERGED_ITERATING) {
299 1939 : if (PetscUnlikely(breakdown || k==nv)) {
300 : /* Start a new Arnoldi factorization */
301 0 : PetscCall(PetscInfo(eps,"Breakdown in Krylov-Schur method (it=%" PetscInt_FMT " norm=%g)\n",eps->its,(double)beta));
302 0 : if (k<eps->nev) {
303 0 : PetscCall(EPSGetStartVector(eps,k,&breakdown));
304 0 : if (breakdown) {
305 0 : eps->reason = EPS_DIVERGED_BREAKDOWN;
306 0 : PetscCall(PetscInfo(eps,"Unable to generate more start vectors\n"));
307 : }
308 : }
309 : } else {
310 : /* Undo translation of Krylov decomposition */
311 1939 : if (PetscUnlikely(harmonic)) {
312 24 : PetscCall(DSSetDimensions(eps->ds,nv,k,l));
313 24 : PetscCall(DSTranslateHarmonic(eps->ds,0.0,beta,PETSC_TRUE,g,&gamma));
314 : /* gamma u^ = u - U*g~ */
315 24 : PetscCall(BVSetActiveColumns(eps->V,0,nv));
316 24 : PetscCall(BVMultColumn(eps->V,-1.0,1.0,nv,g));
317 24 : PetscCall(BVScaleColumn(eps->V,nv,1.0/gamma));
318 24 : PetscCall(BVSetActiveColumns(eps->V,eps->nconv,nv));
319 24 : PetscCall(DSSetDimensions(eps->ds,nv,k,nv));
320 : }
321 : /* Prepare the Rayleigh quotient for restart */
322 1939 : PetscCall(DSTruncate(eps->ds,k+l,PETSC_FALSE));
323 : }
324 : }
325 : /* Update the corresponding vectors V(:,idx) = V*Q(:,idx) */
326 2358 : PetscCall(DSGetMat(eps->ds,DS_MAT_Q,&U));
327 2358 : PetscCall(BVMultInPlace(eps->V,U,eps->nconv,k+l));
328 2358 : PetscCall(DSRestoreMat(eps->ds,DS_MAT_Q,&U));
329 :
330 2358 : if (eps->reason == EPS_CONVERGED_ITERATING && !breakdown) {
331 1939 : PetscCall(BVCopyColumn(eps->V,nv,k+l)); /* copy restart vector from the last column */
332 1939 : if (eps->stop==EPS_STOP_THRESHOLD && nv-k<5) { /* reallocate */
333 3 : eps->ncv = eps->mpd+k;
334 3 : PetscCall(EPSReallocateSolution(eps,eps->ncv+1));
335 21 : for (i=nv;i<eps->ncv;i++) eps->perm[i] = i;
336 3 : PetscCall(DSReallocate(eps->ds,eps->ncv+1));
337 3 : PetscCall(DSGetLeadingDimension(eps->ds,&ld));
338 : }
339 : }
340 :
341 2358 : eps->nconv = k;
342 2777 : PetscCall(EPSMonitor(eps,eps->its,nconv,eps->eigr,eps->eigi,eps->errest,nv));
343 : }
344 :
345 419 : if (harmonic) PetscCall(PetscFree(g));
346 419 : PetscCall(DSTruncate(eps->ds,eps->nconv,PETSC_TRUE));
347 419 : PetscFunctionReturn(PETSC_SUCCESS);
348 : }
349 :
350 6 : static PetscErrorCode EPSKrylovSchurSetRestart_KrylovSchur(EPS eps,PetscReal keep)
351 : {
352 6 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
353 :
354 6 : PetscFunctionBegin;
355 6 : if (keep==(PetscReal)PETSC_DEFAULT || keep==(PetscReal)PETSC_DECIDE) ctx->keep = 0.5;
356 : else {
357 6 : 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);
358 6 : ctx->keep = keep;
359 : }
360 6 : PetscFunctionReturn(PETSC_SUCCESS);
361 : }
362 :
363 : /*@
364 : EPSKrylovSchurSetRestart - Sets the restart parameter for the Krylov-Schur
365 : method, in particular the proportion of basis vectors that must be kept
366 : after restart.
367 :
368 : Logically Collective
369 :
370 : Input Parameters:
371 : + eps - the eigenproblem solver context
372 : - keep - the number of vectors to be kept at restart
373 :
374 : Options Database Key:
375 : . -eps_krylovschur_restart - Sets the restart parameter
376 :
377 : Notes:
378 : Allowed values are in the range [0.1,0.9]. The default is 0.5.
379 :
380 : Level: advanced
381 :
382 : .seealso: EPSKrylovSchurGetRestart()
383 : @*/
384 6 : PetscErrorCode EPSKrylovSchurSetRestart(EPS eps,PetscReal keep)
385 : {
386 6 : PetscFunctionBegin;
387 6 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
388 18 : PetscValidLogicalCollectiveReal(eps,keep,2);
389 6 : PetscTryMethod(eps,"EPSKrylovSchurSetRestart_C",(EPS,PetscReal),(eps,keep));
390 6 : PetscFunctionReturn(PETSC_SUCCESS);
391 : }
392 :
393 6 : static PetscErrorCode EPSKrylovSchurGetRestart_KrylovSchur(EPS eps,PetscReal *keep)
394 : {
395 6 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
396 :
397 6 : PetscFunctionBegin;
398 6 : *keep = ctx->keep;
399 6 : PetscFunctionReturn(PETSC_SUCCESS);
400 : }
401 :
402 : /*@
403 : EPSKrylovSchurGetRestart - Gets the restart parameter used in the
404 : Krylov-Schur method.
405 :
406 : Not Collective
407 :
408 : Input Parameter:
409 : . eps - the eigenproblem solver context
410 :
411 : Output Parameter:
412 : . keep - the restart parameter
413 :
414 : Level: advanced
415 :
416 : .seealso: EPSKrylovSchurSetRestart()
417 : @*/
418 6 : PetscErrorCode EPSKrylovSchurGetRestart(EPS eps,PetscReal *keep)
419 : {
420 6 : PetscFunctionBegin;
421 6 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
422 6 : PetscAssertPointer(keep,2);
423 6 : PetscUseMethod(eps,"EPSKrylovSchurGetRestart_C",(EPS,PetscReal*),(eps,keep));
424 6 : PetscFunctionReturn(PETSC_SUCCESS);
425 : }
426 :
427 39 : static PetscErrorCode EPSKrylovSchurSetLocking_KrylovSchur(EPS eps,PetscBool lock)
428 : {
429 39 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
430 :
431 39 : PetscFunctionBegin;
432 39 : ctx->lock = lock;
433 39 : PetscFunctionReturn(PETSC_SUCCESS);
434 : }
435 :
436 : /*@
437 : EPSKrylovSchurSetLocking - Choose between locking and non-locking variants of
438 : the Krylov-Schur method.
439 :
440 : Logically Collective
441 :
442 : Input Parameters:
443 : + eps - the eigenproblem solver context
444 : - lock - true if the locking variant must be selected
445 :
446 : Options Database Key:
447 : . -eps_krylovschur_locking - Sets the locking flag
448 :
449 : Notes:
450 : The default is to lock converged eigenpairs when the method restarts.
451 : This behaviour can be changed so that all directions are kept in the
452 : working subspace even if already converged to working accuracy (the
453 : non-locking variant).
454 :
455 : Level: advanced
456 :
457 : .seealso: EPSKrylovSchurGetLocking()
458 : @*/
459 39 : PetscErrorCode EPSKrylovSchurSetLocking(EPS eps,PetscBool lock)
460 : {
461 39 : PetscFunctionBegin;
462 39 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
463 117 : PetscValidLogicalCollectiveBool(eps,lock,2);
464 39 : PetscTryMethod(eps,"EPSKrylovSchurSetLocking_C",(EPS,PetscBool),(eps,lock));
465 39 : PetscFunctionReturn(PETSC_SUCCESS);
466 : }
467 :
468 6 : static PetscErrorCode EPSKrylovSchurGetLocking_KrylovSchur(EPS eps,PetscBool *lock)
469 : {
470 6 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
471 :
472 6 : PetscFunctionBegin;
473 6 : *lock = ctx->lock;
474 6 : PetscFunctionReturn(PETSC_SUCCESS);
475 : }
476 :
477 : /*@
478 : EPSKrylovSchurGetLocking - Gets the locking flag used in the Krylov-Schur
479 : method.
480 :
481 : Not Collective
482 :
483 : Input Parameter:
484 : . eps - the eigenproblem solver context
485 :
486 : Output Parameter:
487 : . lock - the locking flag
488 :
489 : Level: advanced
490 :
491 : .seealso: EPSKrylovSchurSetLocking()
492 : @*/
493 6 : PetscErrorCode EPSKrylovSchurGetLocking(EPS eps,PetscBool *lock)
494 : {
495 6 : PetscFunctionBegin;
496 6 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
497 6 : PetscAssertPointer(lock,2);
498 6 : PetscUseMethod(eps,"EPSKrylovSchurGetLocking_C",(EPS,PetscBool*),(eps,lock));
499 6 : PetscFunctionReturn(PETSC_SUCCESS);
500 : }
501 :
502 5 : static PetscErrorCode EPSKrylovSchurSetPartitions_KrylovSchur(EPS eps,PetscInt npart)
503 : {
504 5 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
505 5 : PetscMPIInt size;
506 5 : PetscInt newnpart;
507 :
508 5 : PetscFunctionBegin;
509 5 : if (npart == PETSC_DEFAULT || npart == PETSC_DECIDE) {
510 : newnpart = 1;
511 : } else {
512 5 : PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)eps),&size));
513 5 : PetscCheck(npart>0 && npart<=size,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of npart");
514 : newnpart = npart;
515 : }
516 5 : if (ctx->npart!=newnpart) {
517 5 : if (ctx->npart>1) {
518 0 : PetscCall(PetscSubcommDestroy(&ctx->subc));
519 0 : if (ctx->commset) {
520 0 : PetscCallMPI(MPI_Comm_free(&ctx->commrank));
521 0 : ctx->commset = PETSC_FALSE;
522 : }
523 : }
524 5 : PetscCall(EPSDestroy(&ctx->eps));
525 5 : ctx->npart = newnpart;
526 5 : eps->state = EPS_STATE_INITIAL;
527 : }
528 5 : PetscFunctionReturn(PETSC_SUCCESS);
529 : }
530 :
531 : /*@
532 : EPSKrylovSchurSetPartitions - Sets the number of partitions for the
533 : case of doing spectrum slicing for a computational interval with the
534 : communicator split in several sub-communicators.
535 :
536 : Logically Collective
537 :
538 : Input Parameters:
539 : + eps - the eigenproblem solver context
540 : - npart - number of partitions
541 :
542 : Options Database Key:
543 : . -eps_krylovschur_partitions <npart> - Sets the number of partitions
544 :
545 : Notes:
546 : By default, npart=1 so all processes in the communicator participate in
547 : the processing of the whole interval. If npart>1 then the interval is
548 : divided into npart subintervals, each of them being processed by a
549 : subset of processes.
550 :
551 : The interval is split proportionally unless the separation points are
552 : specified with EPSKrylovSchurSetSubintervals().
553 :
554 : Level: advanced
555 :
556 : .seealso: EPSKrylovSchurSetSubintervals(), EPSSetInterval()
557 : @*/
558 5 : PetscErrorCode EPSKrylovSchurSetPartitions(EPS eps,PetscInt npart)
559 : {
560 5 : PetscFunctionBegin;
561 5 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
562 15 : PetscValidLogicalCollectiveInt(eps,npart,2);
563 5 : PetscTryMethod(eps,"EPSKrylovSchurSetPartitions_C",(EPS,PetscInt),(eps,npart));
564 5 : PetscFunctionReturn(PETSC_SUCCESS);
565 : }
566 :
567 2 : static PetscErrorCode EPSKrylovSchurGetPartitions_KrylovSchur(EPS eps,PetscInt *npart)
568 : {
569 2 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
570 :
571 2 : PetscFunctionBegin;
572 2 : *npart = ctx->npart;
573 2 : PetscFunctionReturn(PETSC_SUCCESS);
574 : }
575 :
576 : /*@
577 : EPSKrylovSchurGetPartitions - Gets the number of partitions of the
578 : communicator in case of spectrum slicing.
579 :
580 : Not Collective
581 :
582 : Input Parameter:
583 : . eps - the eigenproblem solver context
584 :
585 : Output Parameter:
586 : . npart - number of partitions
587 :
588 : Level: advanced
589 :
590 : .seealso: EPSKrylovSchurSetPartitions()
591 : @*/
592 2 : PetscErrorCode EPSKrylovSchurGetPartitions(EPS eps,PetscInt *npart)
593 : {
594 2 : PetscFunctionBegin;
595 2 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
596 2 : PetscAssertPointer(npart,2);
597 2 : PetscUseMethod(eps,"EPSKrylovSchurGetPartitions_C",(EPS,PetscInt*),(eps,npart));
598 2 : PetscFunctionReturn(PETSC_SUCCESS);
599 : }
600 :
601 3 : static PetscErrorCode EPSKrylovSchurSetDetectZeros_KrylovSchur(EPS eps,PetscBool detect)
602 : {
603 3 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
604 :
605 3 : PetscFunctionBegin;
606 3 : ctx->detect = detect;
607 3 : eps->state = EPS_STATE_INITIAL;
608 3 : PetscFunctionReturn(PETSC_SUCCESS);
609 : }
610 :
611 : /*@
612 : EPSKrylovSchurSetDetectZeros - Sets a flag to enforce detection of
613 : zeros during the factorizations throughout the spectrum slicing computation.
614 :
615 : Logically Collective
616 :
617 : Input Parameters:
618 : + eps - the eigenproblem solver context
619 : - detect - check for zeros
620 :
621 : Options Database Key:
622 : . -eps_krylovschur_detect_zeros - Check for zeros; this takes an optional
623 : bool value (0/1/no/yes/true/false)
624 :
625 : Notes:
626 : A zero in the factorization indicates that a shift coincides with an eigenvalue.
627 :
628 : This flag is turned off by default, and may be necessary in some cases,
629 : especially when several partitions are being used. This feature currently
630 : requires an external package for factorizations with support for zero
631 : detection, e.g. MUMPS.
632 :
633 : Level: advanced
634 :
635 : .seealso: EPSKrylovSchurSetPartitions(), EPSSetInterval()
636 : @*/
637 3 : PetscErrorCode EPSKrylovSchurSetDetectZeros(EPS eps,PetscBool detect)
638 : {
639 3 : PetscFunctionBegin;
640 3 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
641 9 : PetscValidLogicalCollectiveBool(eps,detect,2);
642 3 : PetscTryMethod(eps,"EPSKrylovSchurSetDetectZeros_C",(EPS,PetscBool),(eps,detect));
643 3 : PetscFunctionReturn(PETSC_SUCCESS);
644 : }
645 :
646 6 : static PetscErrorCode EPSKrylovSchurGetDetectZeros_KrylovSchur(EPS eps,PetscBool *detect)
647 : {
648 6 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
649 :
650 6 : PetscFunctionBegin;
651 6 : *detect = ctx->detect;
652 6 : PetscFunctionReturn(PETSC_SUCCESS);
653 : }
654 :
655 : /*@
656 : EPSKrylovSchurGetDetectZeros - Gets the flag that enforces zero detection
657 : in spectrum slicing.
658 :
659 : Not Collective
660 :
661 : Input Parameter:
662 : . eps - the eigenproblem solver context
663 :
664 : Output Parameter:
665 : . detect - whether zeros detection is enforced during factorizations
666 :
667 : Level: advanced
668 :
669 : .seealso: EPSKrylovSchurSetDetectZeros()
670 : @*/
671 6 : PetscErrorCode EPSKrylovSchurGetDetectZeros(EPS eps,PetscBool *detect)
672 : {
673 6 : PetscFunctionBegin;
674 6 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
675 6 : PetscAssertPointer(detect,2);
676 6 : PetscUseMethod(eps,"EPSKrylovSchurGetDetectZeros_C",(EPS,PetscBool*),(eps,detect));
677 6 : PetscFunctionReturn(PETSC_SUCCESS);
678 : }
679 :
680 3 : static PetscErrorCode EPSKrylovSchurSetDimensions_KrylovSchur(EPS eps,PetscInt nev,PetscInt ncv,PetscInt mpd)
681 : {
682 3 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
683 :
684 3 : PetscFunctionBegin;
685 3 : if (nev != PETSC_CURRENT) {
686 3 : PetscCheck(nev>0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of nev. Must be > 0");
687 3 : ctx->nev = nev;
688 : }
689 3 : if (ncv == PETSC_DETERMINE) {
690 0 : ctx->ncv = PETSC_DETERMINE;
691 3 : } else if (ncv != PETSC_CURRENT) {
692 3 : PetscCheck(ncv>0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of ncv. Must be > 0");
693 3 : ctx->ncv = ncv;
694 : }
695 3 : if (mpd == PETSC_DETERMINE) {
696 0 : ctx->mpd = PETSC_DETERMINE;
697 3 : } else if (mpd != PETSC_CURRENT) {
698 3 : PetscCheck(mpd>0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of mpd. Must be > 0");
699 3 : ctx->mpd = mpd;
700 : }
701 3 : eps->state = EPS_STATE_INITIAL;
702 3 : PetscFunctionReturn(PETSC_SUCCESS);
703 : }
704 :
705 : /*@
706 : EPSKrylovSchurSetDimensions - Sets the dimensions used for each subsolve
707 : step in case of doing spectrum slicing for a computational interval.
708 : The meaning of the parameters is the same as in EPSSetDimensions().
709 :
710 : Logically Collective
711 :
712 : Input Parameters:
713 : + eps - the eigenproblem solver context
714 : . nev - number of eigenvalues to compute
715 : . ncv - the maximum dimension of the subspace to be used by the subsolve
716 : - mpd - the maximum dimension allowed for the projected problem
717 :
718 : Options Database Key:
719 : + -eps_krylovschur_nev <nev> - Sets the number of eigenvalues
720 : . -eps_krylovschur_ncv <ncv> - Sets the dimension of the subspace
721 : - -eps_krylovschur_mpd <mpd> - Sets the maximum projected dimension
722 :
723 : Note:
724 : Use PETSC_DETERMINE for ncv and mpd to assign a default value. For any
725 : of the arguments, use PETSC_CURRENT to preserve the current value.
726 :
727 : Level: advanced
728 :
729 : .seealso: EPSKrylovSchurGetDimensions(), EPSSetDimensions(), EPSSetInterval()
730 : @*/
731 3 : PetscErrorCode EPSKrylovSchurSetDimensions(EPS eps,PetscInt nev,PetscInt ncv,PetscInt mpd)
732 : {
733 3 : PetscFunctionBegin;
734 3 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
735 9 : PetscValidLogicalCollectiveInt(eps,nev,2);
736 9 : PetscValidLogicalCollectiveInt(eps,ncv,3);
737 9 : PetscValidLogicalCollectiveInt(eps,mpd,4);
738 3 : PetscTryMethod(eps,"EPSKrylovSchurSetDimensions_C",(EPS,PetscInt,PetscInt,PetscInt),(eps,nev,ncv,mpd));
739 3 : PetscFunctionReturn(PETSC_SUCCESS);
740 : }
741 :
742 6 : static PetscErrorCode EPSKrylovSchurGetDimensions_KrylovSchur(EPS eps,PetscInt *nev,PetscInt *ncv,PetscInt *mpd)
743 : {
744 6 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
745 :
746 6 : PetscFunctionBegin;
747 6 : if (nev) *nev = ctx->nev;
748 6 : if (ncv) *ncv = ctx->ncv;
749 6 : if (mpd) *mpd = ctx->mpd;
750 6 : PetscFunctionReturn(PETSC_SUCCESS);
751 : }
752 :
753 : /*@
754 : EPSKrylovSchurGetDimensions - Gets the dimensions used for each subsolve
755 : step in case of doing spectrum slicing for a computational interval.
756 :
757 : Not Collective
758 :
759 : Input Parameter:
760 : . eps - the eigenproblem solver context
761 :
762 : Output Parameters:
763 : + nev - number of eigenvalues to compute
764 : . ncv - the maximum dimension of the subspace to be used by the subsolve
765 : - mpd - the maximum dimension allowed for the projected problem
766 :
767 : Level: advanced
768 :
769 : .seealso: EPSKrylovSchurSetDimensions()
770 : @*/
771 6 : PetscErrorCode EPSKrylovSchurGetDimensions(EPS eps,PetscInt *nev,PetscInt *ncv,PetscInt *mpd)
772 : {
773 6 : PetscFunctionBegin;
774 6 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
775 6 : PetscUseMethod(eps,"EPSKrylovSchurGetDimensions_C",(EPS,PetscInt*,PetscInt*,PetscInt*),(eps,nev,ncv,mpd));
776 6 : PetscFunctionReturn(PETSC_SUCCESS);
777 : }
778 :
779 2 : static PetscErrorCode EPSKrylovSchurSetSubintervals_KrylovSchur(EPS eps,PetscReal* subint)
780 : {
781 2 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
782 2 : PetscInt i;
783 :
784 2 : PetscFunctionBegin;
785 2 : 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()");
786 6 : 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");
787 2 : if (ctx->subintervals) PetscCall(PetscFree(ctx->subintervals));
788 2 : PetscCall(PetscMalloc1(ctx->npart+1,&ctx->subintervals));
789 8 : for (i=0;i<ctx->npart+1;i++) ctx->subintervals[i] = subint[i];
790 2 : ctx->subintset = PETSC_TRUE;
791 2 : eps->state = EPS_STATE_INITIAL;
792 2 : PetscFunctionReturn(PETSC_SUCCESS);
793 : }
794 :
795 : /*@
796 : EPSKrylovSchurSetSubintervals - Sets the points that delimit the
797 : subintervals to be used in spectrum slicing with several partitions.
798 :
799 : Logically Collective
800 :
801 : Input Parameters:
802 : + eps - the eigenproblem solver context
803 : - subint - array of real values specifying subintervals
804 :
805 : Notes:
806 : This function must be called after EPSKrylovSchurSetPartitions(). For npart
807 : partitions, the argument subint must contain npart+1 real values sorted in
808 : ascending order, subint_0, subint_1, ..., subint_npart, where the first
809 : and last values must coincide with the interval endpoints set with
810 : EPSSetInterval().
811 :
812 : The subintervals are then defined by two consecutive points [subint_0,subint_1],
813 : [subint_1,subint_2], and so on.
814 :
815 : Level: advanced
816 :
817 : .seealso: EPSKrylovSchurSetPartitions(), EPSKrylovSchurGetSubintervals(), EPSSetInterval()
818 : @*/
819 2 : PetscErrorCode EPSKrylovSchurSetSubintervals(EPS eps,PetscReal subint[])
820 : {
821 2 : PetscFunctionBegin;
822 2 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
823 2 : PetscAssertPointer(subint,2);
824 2 : PetscTryMethod(eps,"EPSKrylovSchurSetSubintervals_C",(EPS,PetscReal*),(eps,subint));
825 2 : PetscFunctionReturn(PETSC_SUCCESS);
826 : }
827 :
828 2 : static PetscErrorCode EPSKrylovSchurGetSubintervals_KrylovSchur(EPS eps,PetscReal **subint)
829 : {
830 2 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
831 2 : PetscInt i;
832 :
833 2 : PetscFunctionBegin;
834 2 : if (!ctx->subintset) {
835 0 : PetscCheck(eps->state,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
836 0 : PetscCheck(ctx->sr,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
837 : }
838 2 : PetscCall(PetscMalloc1(ctx->npart+1,subint));
839 8 : for (i=0;i<=ctx->npart;i++) (*subint)[i] = ctx->subintervals[i];
840 2 : PetscFunctionReturn(PETSC_SUCCESS);
841 : }
842 :
843 : /*@C
844 : EPSKrylovSchurGetSubintervals - Returns the points that delimit the
845 : subintervals used in spectrum slicing with several partitions.
846 :
847 : Not Collective
848 :
849 : Input Parameter:
850 : . eps - the eigenproblem solver context
851 :
852 : Output Parameter:
853 : . subint - array of real values specifying subintervals
854 :
855 : Notes:
856 : If the user passed values with EPSKrylovSchurSetSubintervals(), then the
857 : same values are returned. Otherwise, the values computed internally are
858 : obtained.
859 :
860 : This function is only available for spectrum slicing runs.
861 :
862 : The returned array has length npart+1 (see EPSKrylovSchurGetPartitions())
863 : and should be freed by the user.
864 :
865 : Fortran Notes:
866 : The calling sequence from Fortran is
867 : .vb
868 : EPSKrylovSchurGetSubintervals(eps,subint,ierr)
869 : double precision subint(npart+1) output
870 : .ve
871 :
872 : Level: advanced
873 :
874 : .seealso: EPSKrylovSchurSetSubintervals(), EPSKrylovSchurGetPartitions(), EPSSetInterval()
875 : @*/
876 2 : PetscErrorCode EPSKrylovSchurGetSubintervals(EPS eps,PetscReal **subint)
877 : {
878 2 : PetscFunctionBegin;
879 2 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
880 2 : PetscAssertPointer(subint,2);
881 2 : PetscUseMethod(eps,"EPSKrylovSchurGetSubintervals_C",(EPS,PetscReal**),(eps,subint));
882 2 : PetscFunctionReturn(PETSC_SUCCESS);
883 : }
884 :
885 3 : static PetscErrorCode EPSKrylovSchurGetInertias_KrylovSchur(EPS eps,PetscInt *n,PetscReal **shifts,PetscInt **inertias)
886 : {
887 3 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
888 3 : PetscInt i,numsh;
889 3 : EPS_SR sr = ctx->sr;
890 :
891 3 : PetscFunctionBegin;
892 3 : PetscCheck(eps->state,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
893 3 : PetscCheck(ctx->sr,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
894 3 : switch (eps->state) {
895 : case EPS_STATE_INITIAL:
896 : break;
897 3 : case EPS_STATE_SETUP:
898 3 : numsh = ctx->npart+1;
899 3 : if (n) *n = numsh;
900 3 : if (shifts) {
901 3 : PetscCall(PetscMalloc1(numsh,shifts));
902 3 : (*shifts)[0] = eps->inta;
903 3 : if (ctx->npart==1) (*shifts)[1] = eps->intb;
904 6 : else for (i=1;i<numsh;i++) (*shifts)[i] = ctx->subintervals[i];
905 : }
906 3 : if (inertias) {
907 3 : PetscCall(PetscMalloc1(numsh,inertias));
908 3 : (*inertias)[0] = (sr->dir==1)?sr->inertia0:sr->inertia1;
909 3 : if (ctx->npart==1) (*inertias)[1] = (sr->dir==1)?sr->inertia1:sr->inertia0;
910 6 : else for (i=1;i<numsh;i++) (*inertias)[i] = (*inertias)[i-1]+ctx->nconv_loc[i-1];
911 : }
912 : break;
913 0 : case EPS_STATE_SOLVED:
914 : case EPS_STATE_EIGENVECTORS:
915 0 : numsh = ctx->nshifts;
916 0 : if (n) *n = numsh;
917 0 : if (shifts) {
918 0 : PetscCall(PetscMalloc1(numsh,shifts));
919 0 : for (i=0;i<numsh;i++) (*shifts)[i] = ctx->shifts[i];
920 : }
921 0 : if (inertias) {
922 0 : PetscCall(PetscMalloc1(numsh,inertias));
923 0 : for (i=0;i<numsh;i++) (*inertias)[i] = ctx->inertias[i];
924 : }
925 : break;
926 : }
927 3 : PetscFunctionReturn(PETSC_SUCCESS);
928 : }
929 :
930 : /*@C
931 : EPSKrylovSchurGetInertias - Gets the values of the shifts and their
932 : corresponding inertias in case of doing spectrum slicing for a
933 : computational interval.
934 :
935 : Not Collective
936 :
937 : Input Parameter:
938 : . eps - the eigenproblem solver context
939 :
940 : Output Parameters:
941 : + n - number of shifts, including the endpoints of the interval
942 : . shifts - the values of the shifts used internally in the solver
943 : - inertias - the values of the inertia in each shift
944 :
945 : Notes:
946 : If called after EPSSolve(), all shifts used internally by the solver are
947 : returned (including both endpoints and any intermediate ones). If called
948 : before EPSSolve() and after EPSSetUp() then only the information of the
949 : endpoints of subintervals is available.
950 :
951 : This function is only available for spectrum slicing runs.
952 :
953 : The returned arrays should be freed by the user. Can pass NULL in any of
954 : the two arrays if not required.
955 :
956 : Fortran Notes:
957 : The calling sequence from Fortran is
958 : .vb
959 : EPSKrylovSchurGetInertias(eps,n,shifts,inertias,ierr)
960 : integer n
961 : double precision shifts(*)
962 : integer inertias(*)
963 : .ve
964 : The arrays should be at least of length n. The value of n can be determined
965 : by an initial call
966 : .vb
967 : EPSKrylovSchurGetInertias(eps,n,PETSC_NULL_REAL_ARRAY,PETSC_NULL_INTEGER_ARRAY,ierr)
968 : .ve
969 :
970 : Level: advanced
971 :
972 : .seealso: EPSSetInterval(), EPSKrylovSchurSetSubintervals()
973 : @*/
974 3 : PetscErrorCode EPSKrylovSchurGetInertias(EPS eps,PetscInt *n,PetscReal *shifts[],PetscInt *inertias[])
975 : {
976 3 : PetscFunctionBegin;
977 3 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
978 3 : PetscAssertPointer(n,2);
979 3 : PetscUseMethod(eps,"EPSKrylovSchurGetInertias_C",(EPS,PetscInt*,PetscReal**,PetscInt**),(eps,n,shifts,inertias));
980 3 : PetscFunctionReturn(PETSC_SUCCESS);
981 : }
982 :
983 2 : static PetscErrorCode EPSKrylovSchurGetSubcommInfo_KrylovSchur(EPS eps,PetscInt *k,PetscInt *n,Vec *v)
984 : {
985 2 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
986 2 : EPS_SR sr = ((EPS_KRYLOVSCHUR*)ctx->eps->data)->sr;
987 :
988 2 : PetscFunctionBegin;
989 2 : PetscCheck(eps->state,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
990 2 : PetscCheck(ctx->sr,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
991 2 : if (k) *k = (ctx->npart==1)? 0: ctx->subc->color;
992 2 : if (n) *n = sr->numEigs;
993 2 : if (v) PetscCall(BVCreateVec(sr->V,v));
994 2 : PetscFunctionReturn(PETSC_SUCCESS);
995 : }
996 :
997 : /*@
998 : EPSKrylovSchurGetSubcommInfo - Gets information related to the case of
999 : doing spectrum slicing for a computational interval with multiple
1000 : communicators.
1001 :
1002 : Collective on the subcommunicator (if v is given)
1003 :
1004 : Input Parameter:
1005 : . eps - the eigenproblem solver context
1006 :
1007 : Output Parameters:
1008 : + k - index of the subinterval for the calling process
1009 : . n - number of eigenvalues found in the k-th subinterval
1010 : - v - a vector owned by processes in the subcommunicator with dimensions
1011 : compatible for locally computed eigenvectors (or NULL)
1012 :
1013 : Notes:
1014 : This function is only available for spectrum slicing runs.
1015 :
1016 : The returned Vec should be destroyed by the user.
1017 :
1018 : Level: advanced
1019 :
1020 : .seealso: EPSSetInterval(), EPSKrylovSchurSetPartitions(), EPSKrylovSchurGetSubcommPairs()
1021 : @*/
1022 2 : PetscErrorCode EPSKrylovSchurGetSubcommInfo(EPS eps,PetscInt *k,PetscInt *n,Vec *v)
1023 : {
1024 2 : PetscFunctionBegin;
1025 2 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
1026 2 : PetscUseMethod(eps,"EPSKrylovSchurGetSubcommInfo_C",(EPS,PetscInt*,PetscInt*,Vec*),(eps,k,n,v));
1027 2 : PetscFunctionReturn(PETSC_SUCCESS);
1028 : }
1029 :
1030 58 : static PetscErrorCode EPSKrylovSchurGetSubcommPairs_KrylovSchur(EPS eps,PetscInt i,PetscScalar *eig,Vec v)
1031 : {
1032 58 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
1033 58 : EPS_SR sr = ((EPS_KRYLOVSCHUR*)ctx->eps->data)->sr;
1034 :
1035 58 : PetscFunctionBegin;
1036 58 : EPSCheckSolved(eps,1);
1037 58 : PetscCheck(ctx->sr,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
1038 58 : PetscCheck(i>=0 && i<sr->numEigs,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
1039 58 : if (eig) *eig = sr->eigr[sr->perm[i]];
1040 58 : if (v) PetscCall(BVCopyVec(sr->V,sr->perm[i],v));
1041 58 : PetscFunctionReturn(PETSC_SUCCESS);
1042 : }
1043 :
1044 : /*@
1045 : EPSKrylovSchurGetSubcommPairs - Gets the i-th eigenpair stored
1046 : internally in the subcommunicator to which the calling process belongs.
1047 :
1048 : Collective on the subcommunicator (if v is given)
1049 :
1050 : Input Parameters:
1051 : + eps - the eigenproblem solver context
1052 : - i - index of the solution
1053 :
1054 : Output Parameters:
1055 : + eig - the eigenvalue
1056 : - v - the eigenvector
1057 :
1058 : Notes:
1059 : It is allowed to pass NULL for v if the eigenvector is not required.
1060 : Otherwise, the caller must provide a valid Vec objects, i.e.,
1061 : it must be created by the calling program with EPSKrylovSchurGetSubcommInfo().
1062 :
1063 : The index i should be a value between 0 and n-1, where n is the number of
1064 : vectors in the local subinterval, see EPSKrylovSchurGetSubcommInfo().
1065 :
1066 : Level: advanced
1067 :
1068 : .seealso: EPSSetInterval(), EPSKrylovSchurSetPartitions(), EPSKrylovSchurGetSubcommInfo(), EPSKrylovSchurGetSubcommMats()
1069 : @*/
1070 58 : PetscErrorCode EPSKrylovSchurGetSubcommPairs(EPS eps,PetscInt i,PetscScalar *eig,Vec v)
1071 : {
1072 58 : PetscFunctionBegin;
1073 58 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
1074 174 : if (v) PetscValidLogicalCollectiveInt(v,i,2);
1075 58 : PetscUseMethod(eps,"EPSKrylovSchurGetSubcommPairs_C",(EPS,PetscInt,PetscScalar*,Vec),(eps,i,eig,v));
1076 58 : PetscFunctionReturn(PETSC_SUCCESS);
1077 : }
1078 :
1079 2 : static PetscErrorCode EPSKrylovSchurGetSubcommMats_KrylovSchur(EPS eps,Mat *A,Mat *B)
1080 : {
1081 2 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
1082 :
1083 2 : PetscFunctionBegin;
1084 2 : PetscCheck(ctx->sr,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
1085 2 : PetscCheck(eps->state,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
1086 2 : PetscCall(EPSGetOperators(ctx->eps,A,B));
1087 2 : PetscFunctionReturn(PETSC_SUCCESS);
1088 : }
1089 :
1090 : /*@
1091 : EPSKrylovSchurGetSubcommMats - Gets the eigenproblem matrices stored
1092 : internally in the subcommunicator to which the calling process belongs.
1093 :
1094 : Collective on the subcommunicator
1095 :
1096 : Input Parameter:
1097 : . eps - the eigenproblem solver context
1098 :
1099 : Output Parameters:
1100 : + A - the matrix associated with the eigensystem
1101 : - B - the second matrix in the case of generalized eigenproblems
1102 :
1103 : Notes:
1104 : This is the analog of EPSGetOperators(), but returns the matrices distributed
1105 : differently (in the subcommunicator rather than in the parent communicator).
1106 :
1107 : These matrices should not be modified by the user.
1108 :
1109 : Level: advanced
1110 :
1111 : .seealso: EPSSetInterval(), EPSKrylovSchurSetPartitions(), EPSKrylovSchurGetSubcommInfo()
1112 : @*/
1113 2 : PetscErrorCode EPSKrylovSchurGetSubcommMats(EPS eps,Mat *A,Mat *B)
1114 : {
1115 2 : PetscFunctionBegin;
1116 2 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
1117 2 : PetscTryMethod(eps,"EPSKrylovSchurGetSubcommMats_C",(EPS,Mat*,Mat*),(eps,A,B));
1118 2 : PetscFunctionReturn(PETSC_SUCCESS);
1119 : }
1120 :
1121 2 : static PetscErrorCode EPSKrylovSchurUpdateSubcommMats_KrylovSchur(EPS eps,PetscScalar a,PetscScalar ap,Mat Au,PetscScalar b,PetscScalar bp, Mat Bu,MatStructure str,PetscBool globalup)
1122 : {
1123 2 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data,*subctx;
1124 2 : Mat A,B=NULL,Ag,Bg=NULL;
1125 2 : PetscBool reuse=PETSC_TRUE;
1126 :
1127 2 : PetscFunctionBegin;
1128 2 : PetscCheck(ctx->sr,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
1129 2 : PetscCheck(eps->state,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
1130 2 : PetscCall(EPSGetOperators(eps,&Ag,&Bg));
1131 2 : PetscCall(EPSGetOperators(ctx->eps,&A,&B));
1132 :
1133 2 : PetscCall(MatScale(A,a));
1134 2 : if (Au) PetscCall(MatAXPY(A,ap,Au,str));
1135 2 : if (B) PetscCall(MatScale(B,b));
1136 2 : if (Bu) PetscCall(MatAXPY(B,bp,Bu,str));
1137 2 : PetscCall(EPSSetOperators(ctx->eps,A,B));
1138 :
1139 : /* Update stored matrix state */
1140 2 : subctx = (EPS_KRYLOVSCHUR*)ctx->eps->data;
1141 2 : PetscCall(MatGetState(A,&subctx->Astate));
1142 2 : if (B) PetscCall(MatGetState(B,&subctx->Bstate));
1143 :
1144 : /* Update matrices in the parent communicator if requested by user */
1145 2 : if (globalup) {
1146 2 : if (ctx->npart>1) {
1147 2 : if (!ctx->isrow) {
1148 2 : PetscCall(MatGetOwnershipIS(Ag,&ctx->isrow,&ctx->iscol));
1149 : reuse = PETSC_FALSE;
1150 : }
1151 2 : if (str==DIFFERENT_NONZERO_PATTERN || str==UNKNOWN_NONZERO_PATTERN) reuse = PETSC_FALSE;
1152 2 : if (ctx->submata && !reuse) PetscCall(MatDestroyMatrices(1,&ctx->submata));
1153 2 : PetscCall(MatCreateSubMatrices(A,1,&ctx->isrow,&ctx->iscol,(reuse)?MAT_REUSE_MATRIX:MAT_INITIAL_MATRIX,&ctx->submata));
1154 2 : PetscCall(MatCreateMPIMatConcatenateSeqMat(((PetscObject)Ag)->comm,ctx->submata[0],PETSC_DECIDE,MAT_REUSE_MATRIX,&Ag));
1155 2 : if (B) {
1156 2 : if (ctx->submatb && !reuse) PetscCall(MatDestroyMatrices(1,&ctx->submatb));
1157 2 : PetscCall(MatCreateSubMatrices(B,1,&ctx->isrow,&ctx->iscol,(reuse)?MAT_REUSE_MATRIX:MAT_INITIAL_MATRIX,&ctx->submatb));
1158 2 : PetscCall(MatCreateMPIMatConcatenateSeqMat(((PetscObject)Bg)->comm,ctx->submatb[0],PETSC_DECIDE,MAT_REUSE_MATRIX,&Bg));
1159 : }
1160 : }
1161 2 : PetscCall(MatGetState(Ag,&ctx->Astate));
1162 2 : if (Bg) PetscCall(MatGetState(Bg,&ctx->Bstate));
1163 : }
1164 2 : PetscCall(EPSSetOperators(eps,Ag,Bg));
1165 2 : PetscFunctionReturn(PETSC_SUCCESS);
1166 : }
1167 :
1168 : /*@
1169 : EPSKrylovSchurUpdateSubcommMats - Update the eigenproblem matrices stored
1170 : internally in the subcommunicator to which the calling process belongs.
1171 :
1172 : Collective
1173 :
1174 : Input Parameters:
1175 : + eps - the eigenproblem solver context
1176 : . s - scalar that multiplies the existing A matrix
1177 : . a - scalar used in the axpy operation on A
1178 : . Au - matrix used in the axpy operation on A
1179 : . t - scalar that multiplies the existing B matrix
1180 : . b - scalar used in the axpy operation on B
1181 : . Bu - matrix used in the axpy operation on B
1182 : . str - structure flag
1183 : - globalup - flag indicating if global matrices must be updated
1184 :
1185 : Notes:
1186 : This function modifies the eigenproblem matrices at the subcommunicator level,
1187 : and optionally updates the global matrices in the parent communicator. The updates
1188 : are expressed as A <-- s*A + a*Au, B <-- t*B + b*Bu.
1189 :
1190 : It is possible to update one of the matrices, or both.
1191 :
1192 : The matrices Au and Bu must be equal in all subcommunicators.
1193 :
1194 : The str flag is passed to the MatAXPY() operations to perform the updates.
1195 :
1196 : If globalup is true, communication is carried out to reconstruct the updated
1197 : matrices in the parent communicator. The user must be warned that if global
1198 : matrices are not in sync with subcommunicator matrices, the errors computed
1199 : by EPSComputeError() will be wrong even if the computed solution is correct
1200 : (the synchronization may be done only once at the end).
1201 :
1202 : Level: advanced
1203 :
1204 : .seealso: EPSSetInterval(), EPSKrylovSchurSetPartitions(), EPSKrylovSchurGetSubcommMats()
1205 : @*/
1206 2 : PetscErrorCode EPSKrylovSchurUpdateSubcommMats(EPS eps,PetscScalar s,PetscScalar a,Mat Au,PetscScalar t,PetscScalar b,Mat Bu,MatStructure str,PetscBool globalup)
1207 : {
1208 2 : PetscFunctionBegin;
1209 2 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
1210 6 : PetscValidLogicalCollectiveScalar(eps,s,2);
1211 6 : PetscValidLogicalCollectiveScalar(eps,a,3);
1212 2 : if (Au) PetscValidHeaderSpecific(Au,MAT_CLASSID,4);
1213 6 : PetscValidLogicalCollectiveScalar(eps,t,5);
1214 6 : PetscValidLogicalCollectiveScalar(eps,b,6);
1215 2 : if (Bu) PetscValidHeaderSpecific(Bu,MAT_CLASSID,7);
1216 6 : PetscValidLogicalCollectiveEnum(eps,str,8);
1217 6 : PetscValidLogicalCollectiveBool(eps,globalup,9);
1218 2 : PetscTryMethod(eps,"EPSKrylovSchurUpdateSubcommMats_C",(EPS,PetscScalar,PetscScalar,Mat,PetscScalar,PetscScalar,Mat,MatStructure,PetscBool),(eps,s,a,Au,t,b,Bu,str,globalup));
1219 2 : PetscFunctionReturn(PETSC_SUCCESS);
1220 : }
1221 :
1222 38 : PetscErrorCode EPSKrylovSchurGetChildEPS(EPS eps,EPS *childeps)
1223 : {
1224 38 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data,*ctx_local;
1225 38 : Mat A,B=NULL,Ar=NULL,Br=NULL;
1226 38 : PetscMPIInt rank;
1227 38 : PetscObjectState Astate,Bstate=0;
1228 38 : PetscObjectId Aid,Bid=0;
1229 38 : STType sttype;
1230 38 : PetscInt nmat;
1231 38 : const char *prefix;
1232 38 : MPI_Comm child;
1233 :
1234 38 : PetscFunctionBegin;
1235 38 : PetscCall(EPSGetOperators(eps,&A,&B));
1236 38 : if (ctx->npart==1) {
1237 24 : if (!ctx->eps) PetscCall(EPSCreate(((PetscObject)eps)->comm,&ctx->eps));
1238 24 : PetscCall(EPSGetOptionsPrefix(eps,&prefix));
1239 24 : PetscCall(EPSSetOptionsPrefix(ctx->eps,prefix));
1240 24 : PetscCall(EPSSetOperators(ctx->eps,A,B));
1241 : } else {
1242 14 : PetscCall(MatGetState(A,&Astate));
1243 14 : PetscCall(PetscObjectGetId((PetscObject)A,&Aid));
1244 14 : if (B) {
1245 14 : PetscCall(MatGetState(B,&Bstate));
1246 14 : PetscCall(PetscObjectGetId((PetscObject)B,&Bid));
1247 : }
1248 14 : if (!ctx->subc) {
1249 : /* Create context for subcommunicators */
1250 5 : PetscCall(PetscSubcommCreate(PetscObjectComm((PetscObject)eps),&ctx->subc));
1251 5 : PetscCall(PetscSubcommSetNumber(ctx->subc,ctx->npart));
1252 5 : PetscCall(PetscSubcommSetType(ctx->subc,PETSC_SUBCOMM_CONTIGUOUS));
1253 5 : PetscCall(PetscSubcommGetChild(ctx->subc,&child));
1254 :
1255 : /* Duplicate matrices */
1256 5 : PetscCall(MatCreateRedundantMatrix(A,0,child,MAT_INITIAL_MATRIX,&Ar));
1257 5 : ctx->Astate = Astate;
1258 5 : ctx->Aid = Aid;
1259 5 : PetscCall(MatPropagateSymmetryOptions(A,Ar));
1260 5 : if (B) {
1261 5 : PetscCall(MatCreateRedundantMatrix(B,0,child,MAT_INITIAL_MATRIX,&Br));
1262 5 : ctx->Bstate = Bstate;
1263 5 : ctx->Bid = Bid;
1264 5 : PetscCall(MatPropagateSymmetryOptions(B,Br));
1265 : }
1266 : } else {
1267 9 : PetscCall(PetscSubcommGetChild(ctx->subc,&child));
1268 9 : if (ctx->Astate != Astate || (B && ctx->Bstate != Bstate) || ctx->Aid != Aid || (B && ctx->Bid != Bid)) {
1269 0 : PetscCall(STGetNumMatrices(ctx->eps->st,&nmat));
1270 0 : if (nmat) PetscCall(EPSGetOperators(ctx->eps,&Ar,&Br));
1271 0 : PetscCall(MatCreateRedundantMatrix(A,0,child,MAT_INITIAL_MATRIX,&Ar));
1272 0 : ctx->Astate = Astate;
1273 0 : ctx->Aid = Aid;
1274 0 : PetscCall(MatPropagateSymmetryOptions(A,Ar));
1275 0 : if (B) {
1276 0 : PetscCall(MatCreateRedundantMatrix(B,0,child,MAT_INITIAL_MATRIX,&Br));
1277 0 : ctx->Bstate = Bstate;
1278 0 : ctx->Bid = Bid;
1279 0 : PetscCall(MatPropagateSymmetryOptions(B,Br));
1280 : }
1281 0 : PetscCall(EPSSetOperators(ctx->eps,Ar,Br));
1282 0 : PetscCall(MatDestroy(&Ar));
1283 0 : PetscCall(MatDestroy(&Br));
1284 : }
1285 : }
1286 :
1287 : /* Create auxiliary EPS */
1288 14 : if (!ctx->eps) {
1289 5 : PetscCall(EPSCreate(child,&ctx->eps));
1290 5 : PetscCall(EPSGetOptionsPrefix(eps,&prefix));
1291 5 : PetscCall(EPSSetOptionsPrefix(ctx->eps,prefix));
1292 5 : PetscCall(EPSSetOperators(ctx->eps,Ar,Br));
1293 5 : PetscCall(MatDestroy(&Ar));
1294 5 : PetscCall(MatDestroy(&Br));
1295 : }
1296 : /* Create subcommunicator grouping processes with same rank */
1297 14 : if (!ctx->commset) {
1298 5 : PetscCallMPI(MPI_Comm_rank(child,&rank));
1299 5 : PetscCallMPI(MPI_Comm_split(((PetscObject)eps)->comm,rank,ctx->subc->color,&ctx->commrank));
1300 5 : ctx->commset = PETSC_TRUE;
1301 : }
1302 : }
1303 38 : PetscCall(EPSSetType(ctx->eps,((PetscObject)eps)->type_name));
1304 38 : PetscCall(STGetType(eps->st,&sttype));
1305 38 : PetscCall(STSetType(ctx->eps->st,sttype));
1306 :
1307 38 : ctx_local = (EPS_KRYLOVSCHUR*)ctx->eps->data;
1308 38 : ctx_local->npart = ctx->npart;
1309 38 : ctx_local->global = PETSC_FALSE;
1310 38 : ctx_local->eps = eps;
1311 38 : ctx_local->subc = ctx->subc;
1312 38 : ctx_local->commrank = ctx->commrank;
1313 38 : *childeps = ctx->eps;
1314 38 : PetscFunctionReturn(PETSC_SUCCESS);
1315 : }
1316 :
1317 20 : static PetscErrorCode EPSKrylovSchurGetKSP_KrylovSchur(EPS eps,KSP *ksp)
1318 : {
1319 20 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
1320 20 : ST st;
1321 20 : PetscBool isfilt;
1322 :
1323 20 : PetscFunctionBegin;
1324 20 : PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt));
1325 20 : PetscCheck(eps->which==EPS_ALL && !isfilt,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations with spectrum slicing");
1326 20 : PetscCall(EPSKrylovSchurGetChildEPS(eps,&ctx->eps));
1327 20 : PetscCall(EPSGetST(ctx->eps,&st));
1328 20 : PetscCall(STGetOperator(st,NULL));
1329 20 : PetscCall(STGetKSP(st,ksp));
1330 20 : PetscFunctionReturn(PETSC_SUCCESS);
1331 : }
1332 :
1333 : /*@
1334 : EPSKrylovSchurGetKSP - Retrieve the linear solver object associated with the
1335 : internal EPS object in case of doing spectrum slicing for a computational interval.
1336 :
1337 : Collective
1338 :
1339 : Input Parameter:
1340 : . eps - the eigenproblem solver context
1341 :
1342 : Output Parameter:
1343 : . ksp - the internal KSP object
1344 :
1345 : Notes:
1346 : When invoked to compute all eigenvalues in an interval with spectrum
1347 : slicing, EPSKRYLOVSCHUR creates another EPS object internally that is
1348 : used to compute eigenvalues by chunks near selected shifts. This function
1349 : allows access to the KSP object associated to this internal EPS object.
1350 :
1351 : This function is only available for spectrum slicing runs. In case of
1352 : having more than one partition, the returned KSP will be different
1353 : in MPI processes belonging to different partitions. Hence, if required,
1354 : EPSKrylovSchurSetPartitions() must be called BEFORE this function.
1355 :
1356 : Level: advanced
1357 :
1358 : .seealso: EPSSetInterval(), EPSKrylovSchurSetPartitions()
1359 : @*/
1360 6 : PetscErrorCode EPSKrylovSchurGetKSP(EPS eps,KSP *ksp)
1361 : {
1362 6 : PetscFunctionBegin;
1363 6 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
1364 6 : PetscUseMethod(eps,"EPSKrylovSchurGetKSP_C",(EPS,KSP*),(eps,ksp));
1365 6 : PetscFunctionReturn(PETSC_SUCCESS);
1366 : }
1367 :
1368 20 : static PetscErrorCode EPSKrylovSchurSetBSEType_KrylovSchur(EPS eps,EPSKrylovSchurBSEType bse)
1369 : {
1370 20 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
1371 :
1372 20 : PetscFunctionBegin;
1373 20 : switch (bse) {
1374 20 : case EPS_KRYLOVSCHUR_BSE_SHAO:
1375 : case EPS_KRYLOVSCHUR_BSE_GRUNING:
1376 : case EPS_KRYLOVSCHUR_BSE_PROJECTEDBSE:
1377 20 : if (ctx->bse != bse) {
1378 13 : ctx->bse = bse;
1379 13 : eps->state = EPS_STATE_INITIAL;
1380 : }
1381 20 : break;
1382 0 : default:
1383 0 : SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Invalid BSE type");
1384 : }
1385 20 : PetscFunctionReturn(PETSC_SUCCESS);
1386 : }
1387 :
1388 : /*@
1389 : EPSKrylovSchurSetBSEType - Sets the method to be used for BSE structured eigenproblems
1390 : in the Krylov-Schur solver.
1391 :
1392 : Logically Collective
1393 :
1394 : Input Parameters:
1395 : + eps - the eigenproblem solver context
1396 : - bse - the BSE method
1397 :
1398 : Options Database Key:
1399 : . -eps_krylovschur_bse_type - Sets the BSE type (either 'shao', 'gruning', or 'projectedbse')
1400 :
1401 : Level: advanced
1402 :
1403 : .seealso: EPSKrylovSchurGetBSEType(), EPSKrylovSchurBSEType, MatCreateBSE()
1404 : @*/
1405 20 : PetscErrorCode EPSKrylovSchurSetBSEType(EPS eps,EPSKrylovSchurBSEType bse)
1406 : {
1407 20 : PetscFunctionBegin;
1408 20 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
1409 60 : PetscValidLogicalCollectiveEnum(eps,bse,2);
1410 20 : PetscTryMethod(eps,"EPSKrylovSchurSetBSEType_C",(EPS,EPSKrylovSchurBSEType),(eps,bse));
1411 20 : PetscFunctionReturn(PETSC_SUCCESS);
1412 : }
1413 :
1414 0 : static PetscErrorCode EPSKrylovSchurGetBSEType_KrylovSchur(EPS eps,EPSKrylovSchurBSEType *bse)
1415 : {
1416 0 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
1417 :
1418 0 : PetscFunctionBegin;
1419 0 : *bse = ctx->bse;
1420 0 : PetscFunctionReturn(PETSC_SUCCESS);
1421 : }
1422 :
1423 : /*@
1424 : EPSKrylovSchurGetBSEType - Gets the method used for BSE structured eigenproblems
1425 : in the Krylov-Schur solver.
1426 :
1427 : Not Collective
1428 :
1429 : Input Parameter:
1430 : . eps - the eigenproblem solver context
1431 :
1432 : Output Parameter:
1433 : . bse - the BSE method
1434 :
1435 : Level: advanced
1436 :
1437 : .seealso: EPSKrylovSchurSetBSEType(), EPSKrylovSchurBSEType, MatCreateBSE()
1438 : @*/
1439 0 : PetscErrorCode EPSKrylovSchurGetBSEType(EPS eps,EPSKrylovSchurBSEType *bse)
1440 : {
1441 0 : PetscFunctionBegin;
1442 0 : PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
1443 0 : PetscAssertPointer(bse,2);
1444 0 : PetscUseMethod(eps,"EPSKrylovSchurGetBSEType_C",(EPS,EPSKrylovSchurBSEType*),(eps,bse));
1445 0 : PetscFunctionReturn(PETSC_SUCCESS);
1446 : }
1447 :
1448 305 : static PetscErrorCode EPSSetFromOptions_KrylovSchur(EPS eps,PetscOptionItems *PetscOptionsObject)
1449 : {
1450 305 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
1451 305 : PetscBool flg,lock,b,f1,f2,f3,isfilt;
1452 305 : PetscReal keep;
1453 305 : PetscInt i,j,k;
1454 305 : KSP ksp;
1455 305 : EPSKrylovSchurBSEType bse;
1456 :
1457 305 : PetscFunctionBegin;
1458 305 : PetscOptionsHeadBegin(PetscOptionsObject,"EPS Krylov-Schur Options");
1459 :
1460 305 : PetscCall(PetscOptionsReal("-eps_krylovschur_restart","Proportion of vectors kept after restart","EPSKrylovSchurSetRestart",0.5,&keep,&flg));
1461 305 : if (flg) PetscCall(EPSKrylovSchurSetRestart(eps,keep));
1462 :
1463 305 : PetscCall(PetscOptionsBool("-eps_krylovschur_locking","Choose between locking and non-locking variants","EPSKrylovSchurSetLocking",PETSC_TRUE,&lock,&flg));
1464 305 : if (flg) PetscCall(EPSKrylovSchurSetLocking(eps,lock));
1465 :
1466 305 : i = ctx->npart;
1467 305 : PetscCall(PetscOptionsInt("-eps_krylovschur_partitions","Number of partitions of the communicator for spectrum slicing","EPSKrylovSchurSetPartitions",ctx->npart,&i,&flg));
1468 305 : if (flg) PetscCall(EPSKrylovSchurSetPartitions(eps,i));
1469 :
1470 305 : b = ctx->detect;
1471 305 : PetscCall(PetscOptionsBool("-eps_krylovschur_detect_zeros","Check zeros during factorizations at subinterval boundaries","EPSKrylovSchurSetDetectZeros",ctx->detect,&b,&flg));
1472 305 : if (flg) PetscCall(EPSKrylovSchurSetDetectZeros(eps,b));
1473 :
1474 305 : i = 1;
1475 305 : j = k = PETSC_DECIDE;
1476 305 : PetscCall(PetscOptionsInt("-eps_krylovschur_nev","Number of eigenvalues to compute in each subsolve (only for spectrum slicing)","EPSKrylovSchurSetDimensions",40,&i,&f1));
1477 305 : PetscCall(PetscOptionsInt("-eps_krylovschur_ncv","Number of basis vectors in each subsolve (only for spectrum slicing)","EPSKrylovSchurSetDimensions",80,&j,&f2));
1478 305 : PetscCall(PetscOptionsInt("-eps_krylovschur_mpd","Maximum dimension of projected problem in each subsolve (only for spectrum slicing)","EPSKrylovSchurSetDimensions",80,&k,&f3));
1479 305 : if (f1 || f2 || f3) PetscCall(EPSKrylovSchurSetDimensions(eps,i,j,k));
1480 :
1481 305 : PetscCall(PetscOptionsEnum("-eps_krylovschur_bse_type","Method for BSE structured eigenproblems","EPSKrylovSchurSetBSEType",EPSKrylovSchurBSETypes,(PetscEnum)ctx->bse,(PetscEnum*)&bse,&flg));
1482 305 : if (flg) PetscCall(EPSKrylovSchurSetBSEType(eps,bse));
1483 :
1484 305 : PetscOptionsHeadEnd();
1485 :
1486 : /* set options of child KSP in spectrum slicing */
1487 305 : if (eps->which==EPS_ALL) {
1488 19 : if (!eps->st) PetscCall(EPSGetST(eps,&eps->st));
1489 19 : PetscCall(EPSSetDefaultST(eps));
1490 19 : PetscCall(STSetFromOptions(eps->st)); /* need to advance this to check ST type */
1491 19 : PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt));
1492 19 : if (!isfilt) {
1493 14 : PetscCall(EPSKrylovSchurGetKSP_KrylovSchur(eps,&ksp));
1494 14 : PetscCall(KSPSetFromOptions(ksp));
1495 : }
1496 : }
1497 305 : PetscFunctionReturn(PETSC_SUCCESS);
1498 : }
1499 :
1500 4 : static PetscErrorCode EPSView_KrylovSchur(EPS eps,PetscViewer viewer)
1501 : {
1502 4 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
1503 4 : PetscBool isascii,isfilt;
1504 4 : KSP ksp;
1505 4 : PetscViewer sviewer;
1506 :
1507 4 : PetscFunctionBegin;
1508 4 : PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
1509 4 : if (isascii) {
1510 4 : PetscCall(PetscViewerASCIIPrintf(viewer," %d%% of basis vectors kept after restart\n",(int)(100*ctx->keep)));
1511 4 : PetscCall(PetscViewerASCIIPrintf(viewer," using the %slocking variant\n",ctx->lock?"":"non-"));
1512 4 : if (eps->problem_type==EPS_BSE) PetscCall(PetscViewerASCIIPrintf(viewer," BSE method: %s\n",EPSKrylovSchurBSETypes[ctx->bse]));
1513 4 : if (eps->which==EPS_ALL) {
1514 0 : PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt));
1515 0 : if (isfilt) PetscCall(PetscViewerASCIIPrintf(viewer," using filtering to extract all eigenvalues in an interval\n"));
1516 : else {
1517 0 : PetscCall(PetscViewerASCIIPrintf(viewer," doing spectrum slicing with nev=%" PetscInt_FMT ", ncv=%" PetscInt_FMT ", mpd=%" PetscInt_FMT "\n",ctx->nev,ctx->ncv,ctx->mpd));
1518 0 : if (ctx->npart>1) {
1519 0 : PetscCall(PetscViewerASCIIPrintf(viewer," multi-communicator spectrum slicing with %" PetscInt_FMT " partitions\n",ctx->npart));
1520 0 : if (ctx->detect) PetscCall(PetscViewerASCIIPrintf(viewer," detecting zeros when factorizing at subinterval boundaries\n"));
1521 : }
1522 : /* view child KSP */
1523 0 : PetscCall(EPSKrylovSchurGetKSP_KrylovSchur(eps,&ksp));
1524 0 : PetscCall(PetscViewerASCIIPushTab(viewer));
1525 0 : if (ctx->npart>1 && ctx->subc) {
1526 0 : PetscCall(PetscViewerGetSubViewer(viewer,ctx->subc->child,&sviewer));
1527 0 : if (!ctx->subc->color) PetscCall(KSPView(ksp,sviewer));
1528 0 : PetscCall(PetscViewerFlush(sviewer));
1529 0 : PetscCall(PetscViewerRestoreSubViewer(viewer,ctx->subc->child,&sviewer));
1530 : /* extra call needed because of the two calls to PetscViewerASCIIPushSynchronized() in PetscViewerGetSubViewer() */
1531 0 : PetscCall(PetscViewerASCIIPopSynchronized(viewer));
1532 0 : } else PetscCall(KSPView(ksp,viewer));
1533 0 : PetscCall(PetscViewerASCIIPopTab(viewer));
1534 : }
1535 : }
1536 : }
1537 4 : PetscFunctionReturn(PETSC_SUCCESS);
1538 : }
1539 :
1540 338 : static PetscErrorCode EPSDestroy_KrylovSchur(EPS eps)
1541 : {
1542 338 : PetscBool isfilt;
1543 :
1544 338 : PetscFunctionBegin;
1545 338 : PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt));
1546 338 : if (eps->which==EPS_ALL && !isfilt) PetscCall(EPSDestroy_KrylovSchur_Slice(eps));
1547 338 : PetscCall(PetscFree(eps->data));
1548 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetRestart_C",NULL));
1549 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetRestart_C",NULL));
1550 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetLocking_C",NULL));
1551 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetLocking_C",NULL));
1552 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetPartitions_C",NULL));
1553 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetPartitions_C",NULL));
1554 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetDetectZeros_C",NULL));
1555 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetDetectZeros_C",NULL));
1556 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetDimensions_C",NULL));
1557 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetDimensions_C",NULL));
1558 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetSubintervals_C",NULL));
1559 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubintervals_C",NULL));
1560 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetInertias_C",NULL));
1561 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommInfo_C",NULL));
1562 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommPairs_C",NULL));
1563 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommMats_C",NULL));
1564 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurUpdateSubcommMats_C",NULL));
1565 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetKSP_C",NULL));
1566 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetBSEType_C",NULL));
1567 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetBSEType_C",NULL));
1568 338 : PetscFunctionReturn(PETSC_SUCCESS);
1569 : }
1570 :
1571 478 : static PetscErrorCode EPSReset_KrylovSchur(EPS eps)
1572 : {
1573 478 : PetscBool isfilt;
1574 :
1575 478 : PetscFunctionBegin;
1576 478 : PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt));
1577 478 : if (eps->which==EPS_ALL && !isfilt) PetscCall(EPSReset_KrylovSchur_Slice(eps));
1578 478 : PetscFunctionReturn(PETSC_SUCCESS);
1579 : }
1580 :
1581 825 : static PetscErrorCode EPSSetDefaultST_KrylovSchur(EPS eps)
1582 : {
1583 825 : PetscFunctionBegin;
1584 825 : if (eps->which==EPS_ALL) {
1585 82 : if (!((PetscObject)eps->st)->type_name) PetscCall(STSetType(eps->st,STSINVERT));
1586 : }
1587 825 : PetscFunctionReturn(PETSC_SUCCESS);
1588 : }
1589 :
1590 338 : SLEPC_EXTERN PetscErrorCode EPSCreate_KrylovSchur(EPS eps)
1591 : {
1592 338 : EPS_KRYLOVSCHUR *ctx;
1593 :
1594 338 : PetscFunctionBegin;
1595 338 : PetscCall(PetscNew(&ctx));
1596 338 : eps->data = (void*)ctx;
1597 338 : ctx->lock = PETSC_TRUE;
1598 338 : ctx->nev = 1;
1599 338 : ctx->ncv = PETSC_DETERMINE;
1600 338 : ctx->mpd = PETSC_DETERMINE;
1601 338 : ctx->npart = 1;
1602 338 : ctx->detect = PETSC_FALSE;
1603 338 : ctx->global = PETSC_TRUE;
1604 :
1605 338 : eps->useds = PETSC_TRUE;
1606 :
1607 : /* solve and computevectors determined at setup */
1608 338 : eps->ops->setup = EPSSetUp_KrylovSchur;
1609 338 : eps->ops->setupsort = EPSSetUpSort_KrylovSchur;
1610 338 : eps->ops->setfromoptions = EPSSetFromOptions_KrylovSchur;
1611 338 : eps->ops->destroy = EPSDestroy_KrylovSchur;
1612 338 : eps->ops->reset = EPSReset_KrylovSchur;
1613 338 : eps->ops->view = EPSView_KrylovSchur;
1614 338 : eps->ops->backtransform = EPSBackTransform_Default;
1615 338 : eps->ops->setdefaultst = EPSSetDefaultST_KrylovSchur;
1616 :
1617 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetRestart_C",EPSKrylovSchurSetRestart_KrylovSchur));
1618 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetRestart_C",EPSKrylovSchurGetRestart_KrylovSchur));
1619 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetLocking_C",EPSKrylovSchurSetLocking_KrylovSchur));
1620 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetLocking_C",EPSKrylovSchurGetLocking_KrylovSchur));
1621 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetPartitions_C",EPSKrylovSchurSetPartitions_KrylovSchur));
1622 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetPartitions_C",EPSKrylovSchurGetPartitions_KrylovSchur));
1623 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetDetectZeros_C",EPSKrylovSchurSetDetectZeros_KrylovSchur));
1624 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetDetectZeros_C",EPSKrylovSchurGetDetectZeros_KrylovSchur));
1625 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetDimensions_C",EPSKrylovSchurSetDimensions_KrylovSchur));
1626 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetDimensions_C",EPSKrylovSchurGetDimensions_KrylovSchur));
1627 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetSubintervals_C",EPSKrylovSchurSetSubintervals_KrylovSchur));
1628 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubintervals_C",EPSKrylovSchurGetSubintervals_KrylovSchur));
1629 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetInertias_C",EPSKrylovSchurGetInertias_KrylovSchur));
1630 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommInfo_C",EPSKrylovSchurGetSubcommInfo_KrylovSchur));
1631 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommPairs_C",EPSKrylovSchurGetSubcommPairs_KrylovSchur));
1632 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommMats_C",EPSKrylovSchurGetSubcommMats_KrylovSchur));
1633 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurUpdateSubcommMats_C",EPSKrylovSchurUpdateSubcommMats_KrylovSchur));
1634 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetKSP_C",EPSKrylovSchurGetKSP_KrylovSchur));
1635 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetBSEType_C",EPSKrylovSchurSetBSEType_KrylovSchur));
1636 338 : PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetBSEType_C",EPSKrylovSchurGetBSEType_KrylovSchur));
1637 338 : PetscFunctionReturn(PETSC_SUCCESS);
1638 : }
|