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 with spectrum slicing for symmetric eigenproblems
14 :
15 : References:
16 :
17 : [1] R.G. Grimes et al., "A shifted block Lanczos algorithm for
18 : solving sparse symmetric generalized eigenproblems", SIAM J.
19 : Matrix Anal. Appl. 15(1):228-272, 1994.
20 :
21 : [2] C. Campos and J.E. Roman, "Spectrum slicing strategies based
22 : on restarted Lanczos methods", Numer. Algor. 60(2):279-295,
23 : 2012.
24 : */
25 :
26 : #include <slepc/private/epsimpl.h>
27 : #include "krylovschur.h"
28 :
29 : static PetscBool cited = PETSC_FALSE;
30 : static const char citation[] =
31 : "@Article{slepc-slice,\n"
32 : " author = \"C. Campos and J. E. Roman\",\n"
33 : " title = \"Strategies for spectrum slicing based on restarted {Lanczos} methods\",\n"
34 : " journal = \"Numer. Algorithms\",\n"
35 : " volume = \"60\",\n"
36 : " number = \"2\",\n"
37 : " pages = \"279--295\",\n"
38 : " year = \"2012,\"\n"
39 : " doi = \"https://doi.org/10.1007/s11075-012-9564-z\"\n"
40 : "}\n";
41 :
42 : #define SLICE_PTOL PETSC_SQRT_MACHINE_EPSILON
43 :
44 94 : static PetscErrorCode EPSSliceResetSR(EPS eps)
45 : {
46 94 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
47 94 : EPS_SR sr=ctx->sr;
48 94 : EPS_shift s;
49 :
50 94 : PetscFunctionBegin;
51 94 : if (sr) {
52 36 : if (ctx->npart>1) {
53 14 : PetscCall(BVDestroy(&sr->V));
54 14 : PetscCall(PetscFree4(sr->eigr,sr->eigi,sr->errest,sr->perm));
55 : }
56 : /* Reviewing list of shifts to free memory */
57 36 : s = sr->s0;
58 36 : if (s) {
59 30 : while (s->neighb[1]) {
60 12 : s = s->neighb[1];
61 30 : PetscCall(PetscFree(s->neighb[0]));
62 : }
63 18 : PetscCall(PetscFree(s));
64 : }
65 36 : PetscCall(PetscFree(sr));
66 : }
67 94 : ctx->sr = NULL;
68 94 : PetscFunctionReturn(PETSC_SUCCESS);
69 : }
70 :
71 72 : PetscErrorCode EPSReset_KrylovSchur_Slice(EPS eps)
72 : {
73 72 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
74 :
75 72 : PetscFunctionBegin;
76 72 : if (!ctx->global) PetscFunctionReturn(PETSC_SUCCESS);
77 : /* Reset auxiliary EPS */
78 29 : PetscCall(EPSSliceResetSR(ctx->eps));
79 29 : PetscCall(EPSReset(ctx->eps));
80 29 : PetscCall(EPSSliceResetSR(eps));
81 29 : PetscCall(PetscFree(ctx->inertias));
82 29 : PetscCall(PetscFree(ctx->shifts));
83 29 : PetscFunctionReturn(PETSC_SUCCESS);
84 : }
85 :
86 28 : PetscErrorCode EPSDestroy_KrylovSchur_Slice(EPS eps)
87 : {
88 28 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
89 :
90 28 : PetscFunctionBegin;
91 28 : if (!ctx->global) PetscFunctionReturn(PETSC_SUCCESS);
92 : /* Destroy auxiliary EPS */
93 14 : PetscCall(EPSReset_KrylovSchur_Slice(eps));
94 14 : PetscCall(EPSDestroy(&ctx->eps));
95 14 : if (ctx->npart>1) {
96 5 : PetscCall(PetscSubcommDestroy(&ctx->subc));
97 5 : if (ctx->commset) {
98 5 : PetscCallMPI(MPI_Comm_free(&ctx->commrank));
99 5 : ctx->commset = PETSC_FALSE;
100 : }
101 5 : PetscCall(ISDestroy(&ctx->isrow));
102 5 : PetscCall(ISDestroy(&ctx->iscol));
103 5 : PetscCall(MatDestroyMatrices(1,&ctx->submata));
104 5 : PetscCall(MatDestroyMatrices(1,&ctx->submatb));
105 : }
106 14 : PetscCall(PetscFree(ctx->subintervals));
107 14 : PetscCall(PetscFree(ctx->nconv_loc));
108 14 : PetscFunctionReturn(PETSC_SUCCESS);
109 : }
110 :
111 : /*
112 : EPSSliceAllocateSolution - Allocate memory storage for common variables such
113 : as eigenvalues and eigenvectors. The argument extra is used for methods
114 : that require a working basis slightly larger than ncv.
115 : */
116 7 : static PetscErrorCode EPSSliceAllocateSolution(EPS eps,PetscInt extra)
117 : {
118 7 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
119 7 : PetscReal eta;
120 7 : PetscInt k;
121 7 : BVType type;
122 7 : BVOrthogType orthog_type;
123 7 : BVOrthogRefineType orthog_ref;
124 7 : BVOrthogBlockType ob_type;
125 7 : Mat matrix;
126 7 : Vec t;
127 7 : EPS_SR sr = ctx->sr;
128 :
129 7 : PetscFunctionBegin;
130 : /* allocate space for eigenvalues and friends */
131 7 : k = PetscMax(1,sr->numEigs);
132 7 : PetscCall(PetscFree4(sr->eigr,sr->eigi,sr->errest,sr->perm));
133 7 : PetscCall(PetscMalloc4(k,&sr->eigr,k,&sr->eigi,k,&sr->errest,k,&sr->perm));
134 :
135 : /* allocate sr->V and transfer options from eps->V */
136 7 : PetscCall(BVDestroy(&sr->V));
137 7 : PetscCall(BVCreate(PetscObjectComm((PetscObject)eps),&sr->V));
138 7 : if (!eps->V) PetscCall(EPSGetBV(eps,&eps->V));
139 7 : if (!((PetscObject)eps->V)->type_name) PetscCall(BVSetType(sr->V,BVMAT));
140 : else {
141 7 : PetscCall(BVGetType(eps->V,&type));
142 7 : PetscCall(BVSetType(sr->V,type));
143 : }
144 7 : PetscCall(STMatCreateVecsEmpty(eps->st,&t,NULL));
145 7 : PetscCall(BVSetSizesFromVec(sr->V,t,k));
146 7 : PetscCall(VecDestroy(&t));
147 7 : PetscCall(EPS_SetInnerProduct(eps));
148 7 : PetscCall(BVGetMatrix(eps->V,&matrix,NULL));
149 7 : PetscCall(BVSetMatrix(sr->V,matrix,PETSC_FALSE));
150 7 : PetscCall(BVGetOrthogonalization(eps->V,&orthog_type,&orthog_ref,&eta,&ob_type));
151 7 : PetscCall(BVSetOrthogonalization(sr->V,orthog_type,orthog_ref,eta,ob_type));
152 7 : PetscFunctionReturn(PETSC_SUCCESS);
153 : }
154 :
155 18 : static PetscErrorCode EPSSliceGetEPS(EPS eps)
156 : {
157 18 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data,*ctx_local;
158 18 : BV V;
159 18 : BVType type;
160 18 : PetscReal eta;
161 18 : BVOrthogType orthog_type;
162 18 : BVOrthogRefineType orthog_ref;
163 18 : BVOrthogBlockType ob_type;
164 18 : PetscInt i;
165 18 : PetscReal h,a,b;
166 18 : PetscRandom rand;
167 18 : EPS_SR sr=ctx->sr;
168 :
169 18 : PetscFunctionBegin;
170 18 : if (!ctx->eps) PetscCall(EPSKrylovSchurGetChildEPS(eps,&ctx->eps));
171 :
172 : /* Determine subintervals */
173 18 : if (ctx->npart==1) {
174 11 : a = eps->inta; b = eps->intb;
175 : } else {
176 7 : if (!ctx->subintset) { /* uniform distribution if no set by user */
177 3 : PetscCheck(sr->hasEnd,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"Global interval must be bounded for splitting it in uniform subintervals");
178 3 : h = (eps->intb-eps->inta)/ctx->npart;
179 3 : a = eps->inta+ctx->subc->color*h;
180 3 : b = (ctx->subc->color==ctx->npart-1)?eps->intb:eps->inta+(ctx->subc->color+1)*h;
181 3 : PetscCall(PetscFree(ctx->subintervals));
182 3 : PetscCall(PetscMalloc1(ctx->npart+1,&ctx->subintervals));
183 9 : for (i=0;i<ctx->npart;i++) ctx->subintervals[i] = eps->inta+h*i;
184 3 : ctx->subintervals[ctx->npart] = eps->intb;
185 : } else {
186 4 : a = ctx->subintervals[ctx->subc->color];
187 4 : b = ctx->subintervals[ctx->subc->color+1];
188 : }
189 : }
190 18 : PetscCall(EPSSetInterval(ctx->eps,a,b));
191 18 : PetscCall(EPSSetConvergenceTest(ctx->eps,eps->conv));
192 18 : PetscCall(EPSSetDimensions(ctx->eps,ctx->nev,ctx->ncv,ctx->mpd));
193 18 : PetscCall(EPSKrylovSchurSetLocking(ctx->eps,ctx->lock));
194 :
195 18 : ctx_local = (EPS_KRYLOVSCHUR*)ctx->eps->data;
196 18 : ctx_local->detect = ctx->detect;
197 :
198 : /* transfer options from eps->V */
199 18 : PetscCall(EPSGetBV(ctx->eps,&V));
200 18 : PetscCall(BVGetRandomContext(V,&rand)); /* make sure the random context is available when duplicating */
201 18 : if (!eps->V) PetscCall(EPSGetBV(eps,&eps->V));
202 18 : if (!((PetscObject)eps->V)->type_name) PetscCall(BVSetType(V,BVMAT));
203 : else {
204 17 : PetscCall(BVGetType(eps->V,&type));
205 17 : PetscCall(BVSetType(V,type));
206 : }
207 18 : PetscCall(BVGetOrthogonalization(eps->V,&orthog_type,&orthog_ref,&eta,&ob_type));
208 18 : PetscCall(BVSetOrthogonalization(V,orthog_type,orthog_ref,eta,ob_type));
209 :
210 18 : ctx->eps->which = eps->which;
211 18 : ctx->eps->max_it = eps->max_it;
212 18 : ctx->eps->tol = eps->tol;
213 18 : ctx->eps->purify = eps->purify;
214 18 : if (eps->tol==(PetscReal)PETSC_DETERMINE) eps->tol = SLEPC_DEFAULT_TOL;
215 18 : PetscCall(EPSSetProblemType(ctx->eps,eps->problem_type));
216 18 : PetscCall(EPSSetUp(ctx->eps));
217 18 : ctx->eps->nconv = 0;
218 18 : ctx->eps->its = 0;
219 1358 : for (i=0;i<ctx->eps->ncv;i++) {
220 1340 : ctx->eps->eigr[i] = 0.0;
221 1340 : ctx->eps->eigi[i] = 0.0;
222 1340 : ctx->eps->errest[i] = 0.0;
223 : }
224 18 : PetscFunctionReturn(PETSC_SUCCESS);
225 : }
226 :
227 44 : static PetscErrorCode EPSSliceGetInertia(EPS eps,PetscReal shift,PetscInt *inertia,PetscInt *zeros)
228 : {
229 44 : KSP ksp,kspr;
230 44 : PC pc;
231 44 : Mat F;
232 44 : PetscReal nzshift=shift;
233 44 : PetscBool flg;
234 :
235 44 : PetscFunctionBegin;
236 44 : if (shift >= PETSC_MAX_REAL) { /* Right-open interval */
237 0 : if (inertia) *inertia = eps->n;
238 44 : } else if (shift <= PETSC_MIN_REAL) {
239 1 : if (inertia) *inertia = 0;
240 1 : if (zeros) *zeros = 0;
241 : } else {
242 : /* If the shift is zero, perturb it to a very small positive value.
243 : The goal is that the nonzero pattern is the same in all cases and reuse
244 : the symbolic factorizations */
245 43 : nzshift = (shift==0.0)? 10.0/PETSC_MAX_REAL: shift;
246 43 : PetscCall(STSetShift(eps->st,nzshift));
247 43 : PetscCall(STGetKSP(eps->st,&ksp));
248 43 : PetscCall(KSPGetPC(ksp,&pc));
249 43 : PetscCall(PetscObjectTypeCompare((PetscObject)pc,PCREDUNDANT,&flg));
250 43 : if (flg) {
251 4 : PetscCall(PCRedundantGetKSP(pc,&kspr));
252 4 : PetscCall(KSPGetPC(kspr,&pc));
253 : }
254 43 : PetscCall(PCFactorGetMatrix(pc,&F));
255 43 : PetscCall(MatGetInertia(F,inertia,zeros,NULL));
256 : }
257 44 : if (inertia) PetscCall(PetscInfo(eps,"Computed inertia at shift %g: %" PetscInt_FMT "\n",(double)nzshift,*inertia));
258 44 : PetscFunctionReturn(PETSC_SUCCESS);
259 : }
260 :
261 : /*
262 : Dummy backtransform operation
263 : */
264 18 : static PetscErrorCode EPSBackTransform_Skip(EPS eps)
265 : {
266 18 : PetscFunctionBegin;
267 18 : PetscFunctionReturn(PETSC_SUCCESS);
268 : }
269 :
270 36 : PetscErrorCode EPSSetUp_KrylovSchur_Slice(EPS eps)
271 : {
272 36 : EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data,*ctx_glob;
273 36 : EPS_SR sr,sr_loc,sr_glob;
274 36 : PetscInt nEigs,dssz=1,i,zeros=0,off=0,method,hiteig=0;
275 36 : PetscMPIInt nproc,rank=0,aux;
276 36 : PetscReal r;
277 36 : MPI_Request req;
278 36 : Mat A,B=NULL;
279 36 : DSParallelType ptype;
280 36 : MPI_Comm child;
281 :
282 36 : PetscFunctionBegin;
283 36 : if (ctx->global) {
284 18 : EPSCheckHermitianDefiniteCondition(eps,PETSC_TRUE," with spectrum slicing");
285 18 : EPSCheckSinvertCayleyCondition(eps,PETSC_TRUE," with spectrum slicing");
286 18 : PetscCheck(eps->inta!=eps->intb,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"This solver does not support computing all eigenvalues unless you provide a computational interval with EPSSetInterval()");
287 18 : 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");
288 18 : PetscCheck(eps->nds==0,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Spectrum slicing not supported in combination with deflation space");
289 18 : EPSCheckUnsupportedCondition(eps,EPS_FEATURE_ARBITRARY | EPS_FEATURE_REGION | EPS_FEATURE_STOPPING,PETSC_TRUE," with spectrum slicing");
290 18 : EPSCheckIgnoredCondition(eps,EPS_FEATURE_BALANCE,PETSC_TRUE," with spectrum slicing");
291 18 : if (eps->tol==(PetscReal)PETSC_DETERMINE) {
292 : #if defined(PETSC_USE_REAL_SINGLE)
293 : eps->tol = SLEPC_DEFAULT_TOL;
294 : #else
295 : /* use tighter tolerance */
296 9 : eps->tol = SLEPC_DEFAULT_TOL*1e-2;
297 : #endif
298 : }
299 18 : if (eps->max_it==PETSC_DETERMINE) eps->max_it = 100;
300 18 : if (ctx->nev==1) ctx->nev = PetscMin(40,eps->n); /* nev not set, use default value */
301 18 : PetscCheck(eps->n<=10 || ctx->nev>=10,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"nev cannot be less than 10 in spectrum slicing runs");
302 : }
303 36 : eps->ops->backtransform = EPSBackTransform_Skip;
304 :
305 : /* create spectrum slicing context and initialize it */
306 36 : PetscCall(EPSSliceResetSR(eps));
307 36 : PetscCall(PetscNew(&sr));
308 36 : ctx->sr = sr;
309 36 : sr->itsKs = 0;
310 36 : sr->nleap = 0;
311 36 : sr->nMAXCompl = eps->nev/4;
312 36 : sr->iterCompl = eps->max_it/4;
313 36 : sr->sPres = NULL;
314 36 : sr->nS = 0;
315 :
316 36 : if (ctx->npart==1 || ctx->global) {
317 : /* check presence of ends and finding direction */
318 29 : if ((eps->inta > PETSC_MIN_REAL && !(ctx->subintervals && ctx->subintervals[0]==ctx->subintervals[1])) || eps->intb >= PETSC_MAX_REAL) {
319 27 : sr->int0 = eps->inta;
320 27 : sr->int1 = eps->intb;
321 27 : sr->dir = 1;
322 27 : if (eps->intb >= PETSC_MAX_REAL) { /* Right-open interval */
323 0 : sr->hasEnd = PETSC_FALSE;
324 27 : } else sr->hasEnd = PETSC_TRUE;
325 : } else {
326 2 : sr->int0 = eps->intb;
327 2 : sr->int1 = eps->inta;
328 2 : sr->dir = -1;
329 2 : sr->hasEnd = PetscNot(eps->inta <= PETSC_MIN_REAL);
330 : }
331 : }
332 36 : if (ctx->global) {
333 18 : PetscCall(EPSSetDimensions_Default(eps,ctx->nev,&ctx->ncv,&ctx->mpd));
334 : /* create subintervals and initialize auxiliary eps for slicing runs */
335 18 : PetscCall(EPSKrylovSchurGetChildEPS(eps,&ctx->eps));
336 : /* prevent computation of factorization in global eps */
337 18 : PetscCall(STSetTransform(eps->st,PETSC_FALSE));
338 18 : PetscCall(EPSSliceGetEPS(eps));
339 18 : sr_loc = ((EPS_KRYLOVSCHUR*)ctx->eps->data)->sr;
340 18 : if (ctx->npart>1) {
341 7 : PetscCall(PetscSubcommGetChild(ctx->subc,&child));
342 7 : if ((sr->dir>0&&ctx->subc->color==0)||(sr->dir<0&&ctx->subc->color==ctx->npart-1)) sr->inertia0 = sr_loc->inertia0;
343 7 : PetscCallMPI(MPI_Comm_rank(child,&rank));
344 7 : if (!rank) {
345 6 : PetscCall(PetscMPIIntCast((sr->dir>0)?0:ctx->npart-1,&aux));
346 12 : PetscCallMPI(MPI_Bcast(&sr->inertia0,1,MPIU_INT,aux,ctx->commrank));
347 : }
348 14 : PetscCallMPI(MPI_Bcast(&sr->inertia0,1,MPIU_INT,0,child));
349 7 : PetscCall(PetscFree(ctx->nconv_loc));
350 7 : PetscCall(PetscMalloc1(ctx->npart,&ctx->nconv_loc));
351 7 : PetscCallMPI(MPI_Comm_size(((PetscObject)eps)->comm,&nproc));
352 7 : if (sr->dir<0) off = 1;
353 7 : if (nproc%ctx->npart==0) { /* subcommunicators with the same size */
354 4 : PetscCall(PetscMPIIntCast(sr_loc->numEigs,&aux));
355 8 : PetscCallMPI(MPI_Allgather(&aux,1,MPI_INT,ctx->nconv_loc,1,MPI_INT,ctx->commrank));
356 8 : PetscCallMPI(MPI_Allgather(sr_loc->dir==sr->dir?&sr_loc->int0:&sr_loc->int1,1,MPIU_REAL,ctx->subintervals+off,1,MPIU_REAL,ctx->commrank));
357 : } else {
358 3 : PetscCallMPI(MPI_Comm_rank(child,&rank));
359 3 : if (!rank) {
360 2 : PetscCall(PetscMPIIntCast(sr_loc->numEigs,&aux));
361 4 : PetscCallMPI(MPI_Allgather(&aux,1,MPI_INT,ctx->nconv_loc,1,MPI_INT,ctx->commrank));
362 4 : PetscCallMPI(MPI_Allgather(sr_loc->dir==sr->dir?&sr_loc->int0:&sr_loc->int1,1,MPIU_REAL,ctx->subintervals+off,1,MPIU_REAL,ctx->commrank));
363 : }
364 3 : PetscCall(PetscMPIIntCast(ctx->npart,&aux));
365 6 : PetscCallMPI(MPI_Bcast(ctx->nconv_loc,aux,MPI_INT,0,child));
366 6 : PetscCallMPI(MPI_Bcast(ctx->subintervals+off,aux,MPIU_REAL,0,child));
367 : }
368 7 : nEigs = 0;
369 21 : for (i=0;i<ctx->npart;i++) nEigs += ctx->nconv_loc[i];
370 : } else {
371 11 : nEigs = sr_loc->numEigs;
372 11 : sr->inertia0 = sr_loc->inertia0;
373 11 : sr->dir = sr_loc->dir;
374 : }
375 18 : sr->inertia1 = sr->inertia0+sr->dir*nEigs;
376 18 : sr->numEigs = nEigs;
377 18 : eps->nev = nEigs;
378 18 : eps->ncv = nEigs;
379 18 : eps->mpd = nEigs;
380 : } else {
381 18 : ctx_glob = (EPS_KRYLOVSCHUR*)ctx->eps->data;
382 18 : sr_glob = ctx_glob->sr;
383 18 : if (ctx->npart>1) {
384 7 : sr->dir = sr_glob->dir;
385 7 : sr->int0 = (sr->dir==1)?eps->inta:eps->intb;
386 7 : sr->int1 = (sr->dir==1)?eps->intb:eps->inta;
387 7 : if ((sr->dir>0&&ctx->subc->color==ctx->npart-1)||(sr->dir<0&&ctx->subc->color==0)) sr->hasEnd = sr_glob->hasEnd;
388 4 : else sr->hasEnd = PETSC_TRUE;
389 : }
390 : /* sets first shift */
391 36 : PetscCall(STSetShift(eps->st,(sr->int0==0.0)?10.0/PETSC_MAX_REAL:sr->int0));
392 18 : PetscCall(STSetUp(eps->st));
393 :
394 : /* compute inertia0 */
395 31 : PetscCall(EPSSliceGetInertia(eps,sr->int0,&sr->inertia0,ctx->detect?&zeros:NULL));
396 : /* undocumented option to control what to do when an eigenvalue is found:
397 : - error out if it's the endpoint of the user-provided interval (or sub-interval)
398 : - if it's an endpoint computed internally:
399 : + if hiteig=0 error out
400 : + else if hiteig=1 the subgroup that hit the eigenvalue does nothing
401 : + otherwise the subgroup that hit the eigenvalue perturbs the shift and recomputes inertia
402 : */
403 18 : PetscCall(PetscOptionsGetInt(NULL,NULL,"-eps_krylovschur_hiteigenvalue",&hiteig,NULL));
404 18 : if (zeros) { /* error in factorization */
405 0 : PetscCheck(sr->int0!=ctx->eps->inta && sr->int0!=ctx->eps->intb,((PetscObject)eps)->comm,PETSC_ERR_USER,"Found singular matrix for the transformed problem in the interval endpoint");
406 0 : PetscCheck(!ctx_glob->subintset || hiteig,((PetscObject)eps)->comm,PETSC_ERR_USER,"Found singular matrix for the transformed problem in an interval endpoint defined by user");
407 0 : if (hiteig==1) { /* idle subgroup */
408 0 : sr->inertia0 = -1;
409 : } else { /* perturb shift */
410 0 : sr->int0 *= (1.0+SLICE_PTOL);
411 0 : PetscCall(EPSSliceGetInertia(eps,sr->int0,&sr->inertia0,&zeros));
412 0 : PetscCheck(zeros==0,((PetscObject)eps)->comm,PETSC_ERR_CONV_FAILED,"Inertia computation fails in %g",(double)sr->int1);
413 : }
414 : }
415 18 : if (ctx->npart>1) {
416 7 : PetscCall(PetscSubcommGetChild(ctx->subc,&child));
417 : /* inertia1 is received from neighbour */
418 7 : PetscCallMPI(MPI_Comm_rank(child,&rank));
419 7 : if (!rank) {
420 6 : if (sr->inertia0!=-1 && ((sr->dir>0 && ctx->subc->color>0) || (sr->dir<0 && ctx->subc->color<ctx->npart-1))) { /* send inertia0 to neighbour0 */
421 3 : PetscCall(PetscMPIIntCast(ctx->subc->color-sr->dir,&aux));
422 3 : PetscCallMPI(MPI_Isend(&sr->inertia0,1,MPIU_INT,aux,0,ctx->commrank,&req));
423 3 : PetscCallMPI(MPI_Isend(&sr->int0,1,MPIU_REAL,aux,0,ctx->commrank,&req));
424 : }
425 6 : if ((sr->dir>0 && ctx->subc->color<ctx->npart-1)|| (sr->dir<0 && ctx->subc->color>0)) { /* receive inertia1 from neighbour1 */
426 3 : PetscCall(PetscMPIIntCast(ctx->subc->color+sr->dir,&aux));
427 3 : PetscCallMPI(MPI_Recv(&sr->inertia1,1,MPIU_INT,aux,0,ctx->commrank,MPI_STATUS_IGNORE));
428 3 : PetscCallMPI(MPI_Recv(&sr->int1,1,MPIU_REAL,aux,0,ctx->commrank,MPI_STATUS_IGNORE));
429 : }
430 6 : if (sr->inertia0==-1 && !(sr->dir>0 && ctx->subc->color==ctx->npart-1) && !(sr->dir<0 && ctx->subc->color==0)) {
431 0 : sr->inertia0 = sr->inertia1; sr->int0 = sr->int1;
432 0 : PetscCall(PetscMPIIntCast(ctx->subc->color-sr->dir,&aux));
433 0 : PetscCallMPI(MPI_Isend(&sr->inertia0,1,MPIU_INT,aux,0,ctx->commrank,&req));
434 0 : PetscCallMPI(MPI_Isend(&sr->int0,1,MPIU_REAL,aux,0,ctx->commrank,&req));
435 : }
436 : }
437 7 : if ((sr->dir>0 && ctx->subc->color<ctx->npart-1)||(sr->dir<0 && ctx->subc->color>0)) {
438 8 : PetscCallMPI(MPI_Bcast(&sr->inertia1,1,MPIU_INT,0,child));
439 8 : PetscCallMPI(MPI_Bcast(&sr->int1,1,MPIU_REAL,0,child));
440 3 : } else sr_glob->inertia1 = sr->inertia1;
441 : }
442 :
443 : /* last process in eps comm computes inertia1 */
444 18 : if (ctx->npart==1 || ((sr->dir>0 && ctx->subc->color==ctx->npart-1) || (sr->dir<0 && ctx->subc->color==0))) {
445 25 : PetscCall(EPSSliceGetInertia(eps,sr->int1,&sr->inertia1,ctx->detect?&zeros:NULL));
446 14 : PetscCheck(zeros==0,((PetscObject)eps)->comm,PETSC_ERR_USER,"Found singular matrix for the transformed problem in an interval endpoint defined by user");
447 14 : if (!rank && sr->inertia0==-1) {
448 0 : sr->inertia0 = sr->inertia1; sr->int0 = sr->int1;
449 0 : PetscCall(PetscMPIIntCast(ctx->subc->color-sr->dir,&aux));
450 0 : PetscCallMPI(MPI_Isend(&sr->inertia0,1,MPIU_INT,aux,0,ctx->commrank,&req));
451 0 : PetscCallMPI(MPI_Isend(&sr->int0,1,MPIU_REAL,aux,0,ctx->commrank,&req));
452 : }
453 14 : if (sr->hasEnd) {
454 13 : sr->dir = -sr->dir; r = sr->int0; sr->int0 = sr->int1; sr->int1 = r;
455 13 : i = sr->inertia0; sr->inertia0 = sr->inertia1; sr->inertia1 = i;
456 : }
457 : }
458 :
459 : /* number of eigenvalues in interval */
460 18 : sr->numEigs = (sr->dir)*(sr->inertia1 - sr->inertia0);
461 18 : if (ctx->npart>1) {
462 : /* memory allocate for subinterval eigenpairs */
463 7 : PetscCall(EPSSliceAllocateSolution(eps,1));
464 : }
465 18 : dssz = eps->ncv+1;
466 18 : PetscCall(DSGetParallel(ctx->eps->ds,&ptype));
467 18 : PetscCall(DSSetParallel(eps->ds,ptype));
468 18 : PetscCall(DSGetMethod(ctx->eps->ds,&method));
469 18 : PetscCall(DSSetMethod(eps->ds,method));
470 : }
471 36 : PetscCall(DSSetType(eps->ds,DSHEP));
472 36 : PetscCall(DSSetCompact(eps->ds,PETSC_TRUE));
473 36 : PetscCall(DSAllocate(eps->ds,dssz));
474 : /* keep state of subcomm matrices to check that the user does not modify them */
475 36 : PetscCall(EPSGetOperators(eps,&A,&B));
476 36 : PetscCall(MatGetState(A,&ctx->Astate));
477 36 : PetscCall(PetscObjectGetId((PetscObject)A,&ctx->Aid));
478 36 : if (B) {
479 28 : PetscCall(MatGetState(B,&ctx->Bstate));
480 28 : PetscCall(PetscObjectGetId((PetscObject)B,&ctx->Bid));
481 : } else {
482 8 : ctx->Bstate=0;
483 8 : ctx->Bid=0;
484 : }
485 36 : PetscFunctionReturn(PETSC_SUCCESS);
486 : }
487 :
488 5 : static PetscErrorCode EPSSliceGatherEigenVectors(EPS eps)
489 : {
490 5 : Vec v,vg,v_loc;
491 5 : IS is1,is2;
492 5 : VecScatter vec_sc;
493 5 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
494 5 : PetscInt nloc,m0,n0,i,si,idx,*idx1,*idx2,j;
495 5 : PetscScalar *array;
496 5 : EPS_SR sr_loc;
497 5 : BV V_loc;
498 :
499 5 : PetscFunctionBegin;
500 5 : sr_loc = ((EPS_KRYLOVSCHUR*)ctx->eps->data)->sr;
501 5 : V_loc = sr_loc->V;
502 :
503 : /* Gather parallel eigenvectors */
504 5 : PetscCall(BVGetColumn(eps->V,0,&v));
505 5 : PetscCall(VecGetOwnershipRange(v,&n0,&m0));
506 5 : PetscCall(BVRestoreColumn(eps->V,0,&v));
507 5 : PetscCall(BVGetColumn(ctx->eps->V,0,&v));
508 5 : PetscCall(VecGetLocalSize(v,&nloc));
509 5 : PetscCall(BVRestoreColumn(ctx->eps->V,0,&v));
510 5 : PetscCall(PetscMalloc2(m0-n0,&idx1,m0-n0,&idx2));
511 5 : PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)eps),nloc,PETSC_DECIDE,&vg));
512 : idx = -1;
513 15 : for (si=0;si<ctx->npart;si++) {
514 10 : j = 0;
515 6510 : for (i=n0;i<m0;i++) {
516 6500 : idx1[j] = i;
517 6500 : idx2[j++] = i+eps->n*si;
518 : }
519 10 : PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)eps),(m0-n0),idx1,PETSC_COPY_VALUES,&is1));
520 10 : PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)eps),(m0-n0),idx2,PETSC_COPY_VALUES,&is2));
521 10 : PetscCall(BVGetColumn(eps->V,0,&v));
522 10 : PetscCall(VecScatterCreate(v,is1,vg,is2,&vec_sc));
523 10 : PetscCall(BVRestoreColumn(eps->V,0,&v));
524 10 : PetscCall(ISDestroy(&is1));
525 10 : PetscCall(ISDestroy(&is2));
526 168 : for (i=0;i<ctx->nconv_loc[si];i++) {
527 158 : PetscCall(BVGetColumn(eps->V,++idx,&v));
528 158 : if (ctx->subc->color==si) {
529 78 : PetscCall(BVGetColumn(V_loc,i,&v_loc));
530 78 : PetscCall(VecGetArray(v_loc,&array));
531 78 : PetscCall(VecPlaceArray(vg,array));
532 : }
533 158 : PetscCall(VecScatterBegin(vec_sc,vg,v,INSERT_VALUES,SCATTER_REVERSE));
534 158 : PetscCall(VecScatterEnd(vec_sc,vg,v,INSERT_VALUES,SCATTER_REVERSE));
535 158 : if (ctx->subc->color==si) {
536 78 : PetscCall(VecResetArray(vg));
537 78 : PetscCall(VecRestoreArray(v_loc,&array));
538 78 : PetscCall(BVRestoreColumn(V_loc,i,&v_loc));
539 : }
540 158 : PetscCall(BVRestoreColumn(eps->V,idx,&v));
541 : }
542 10 : PetscCall(VecScatterDestroy(&vec_sc));
543 : }
544 5 : PetscCall(PetscFree2(idx1,idx2));
545 5 : PetscCall(VecDestroy(&vg));
546 5 : PetscFunctionReturn(PETSC_SUCCESS);
547 : }
548 :
549 : /*
550 : EPSComputeVectors_Slice - Recover Eigenvectors from subcomunicators
551 : */
552 21 : PetscErrorCode EPSComputeVectors_Slice(EPS eps)
553 : {
554 21 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
555 :
556 21 : PetscFunctionBegin;
557 21 : if (ctx->global && ctx->npart>1) {
558 5 : PetscCall(EPSComputeVectors(ctx->eps));
559 5 : PetscCall(EPSSliceGatherEigenVectors(eps));
560 : }
561 21 : PetscFunctionReturn(PETSC_SUCCESS);
562 : }
563 :
564 18 : static PetscErrorCode EPSSliceGetInertias(EPS eps,PetscInt *n,PetscReal **shifts,PetscInt **inertias)
565 : {
566 18 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
567 18 : PetscInt i=0,j,tmpi;
568 18 : PetscReal v,tmpr;
569 18 : EPS_shift s;
570 :
571 18 : PetscFunctionBegin;
572 18 : PetscCheck(eps->state,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
573 18 : PetscCheck(ctx->sr,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
574 18 : if (!ctx->sr->s0) { /* EPSSolve not called yet */
575 0 : *n = 2;
576 : } else {
577 18 : *n = 1;
578 18 : s = ctx->sr->s0;
579 48 : while (s) {
580 30 : (*n)++;
581 30 : s = s->neighb[1];
582 : }
583 : }
584 18 : PetscCall(PetscMalloc1(*n,shifts));
585 18 : PetscCall(PetscMalloc1(*n,inertias));
586 18 : if (!ctx->sr->s0) { /* EPSSolve not called yet */
587 0 : (*shifts)[0] = ctx->sr->int0;
588 0 : (*shifts)[1] = ctx->sr->int1;
589 0 : (*inertias)[0] = ctx->sr->inertia0;
590 0 : (*inertias)[1] = ctx->sr->inertia1;
591 : } else {
592 : s = ctx->sr->s0;
593 48 : while (s) {
594 30 : (*shifts)[i] = s->value;
595 30 : (*inertias)[i++] = s->inertia;
596 30 : s = s->neighb[1];
597 : }
598 18 : (*shifts)[i] = ctx->sr->int1;
599 18 : (*inertias)[i] = ctx->sr->inertia1;
600 : }
601 : /* remove possible duplicate in last position */
602 18 : if ((*shifts)[(*n)-1]==(*shifts)[(*n)-2]) (*n)--;
603 : /* sort result */
604 64 : for (i=0;i<*n;i++) {
605 46 : v = (*shifts)[i];
606 87 : for (j=i+1;j<*n;j++) {
607 41 : if (v > (*shifts)[j]) {
608 35 : SlepcSwap((*shifts)[i],(*shifts)[j],tmpr);
609 35 : SlepcSwap((*inertias)[i],(*inertias)[j],tmpi);
610 35 : v = (*shifts)[i];
611 : }
612 : }
613 : }
614 18 : PetscFunctionReturn(PETSC_SUCCESS);
615 : }
616 :
617 7 : static PetscErrorCode EPSSliceGatherSolution(EPS eps)
618 : {
619 7 : PetscMPIInt rank,nproc,*disp,*ns_loc,aux;
620 7 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
621 7 : PetscInt i,idx,j,*perm_loc,off=0,*inertias_loc,ns;
622 7 : PetscScalar *eigr_loc;
623 7 : EPS_SR sr_loc;
624 7 : PetscReal *shifts_loc;
625 7 : MPI_Comm child;
626 :
627 7 : PetscFunctionBegin;
628 7 : eps->nconv = 0;
629 21 : for (i=0;i<ctx->npart;i++) eps->nconv += ctx->nconv_loc[i];
630 7 : sr_loc = ((EPS_KRYLOVSCHUR*)ctx->eps->data)->sr;
631 :
632 : /* Gather the shifts used and the inertias computed */
633 7 : PetscCall(EPSSliceGetInertias(ctx->eps,&ns,&shifts_loc,&inertias_loc));
634 7 : if (ctx->sr->dir>0 && shifts_loc[ns-1]==sr_loc->int1 && ctx->subc->color<ctx->npart-1) ns--;
635 7 : if (ctx->sr->dir<0 && shifts_loc[ns-1]==sr_loc->int0 && ctx->subc->color>0) {
636 0 : ns--;
637 0 : for (i=0;i<ns;i++) {
638 0 : inertias_loc[i] = inertias_loc[i+1];
639 0 : shifts_loc[i] = shifts_loc[i+1];
640 : }
641 : }
642 7 : PetscCall(PetscMalloc1(ctx->npart,&ns_loc));
643 7 : PetscCall(PetscSubcommGetChild(ctx->subc,&child));
644 7 : PetscCallMPI(MPI_Comm_rank(child,&rank));
645 7 : PetscCall(PetscMPIIntCast(ns,&aux));
646 13 : if (!rank) PetscCallMPI(MPI_Allgather(&aux,1,MPI_INT,ns_loc,1,MPI_INT,ctx->commrank));
647 7 : PetscCall(PetscMPIIntCast(ctx->npart,&aux));
648 14 : PetscCallMPI(MPI_Bcast(ns_loc,aux,MPI_INT,0,child));
649 7 : ctx->nshifts = 0;
650 21 : for (i=0;i<ctx->npart;i++) ctx->nshifts += ns_loc[i];
651 7 : PetscCall(PetscFree(ctx->inertias));
652 7 : PetscCall(PetscFree(ctx->shifts));
653 7 : PetscCall(PetscMalloc1(ctx->nshifts,&ctx->inertias));
654 7 : PetscCall(PetscMalloc1(ctx->nshifts,&ctx->shifts));
655 :
656 : /* Gather eigenvalues (same ranks have fully set of eigenvalues)*/
657 7 : eigr_loc = sr_loc->eigr;
658 7 : perm_loc = sr_loc->perm;
659 7 : PetscCallMPI(MPI_Comm_size(((PetscObject)eps)->comm,&nproc));
660 7 : PetscCall(PetscMalloc1(ctx->npart,&disp));
661 7 : disp[0] = 0;
662 14 : for (i=1;i<ctx->npart;i++) disp[i] = disp[i-1]+ctx->nconv_loc[i-1];
663 7 : if (nproc%ctx->npart==0) { /* subcommunicators with the same size */
664 4 : PetscCall(PetscMPIIntCast(sr_loc->numEigs,&aux));
665 8 : PetscCallMPI(MPI_Allgatherv(eigr_loc,aux,MPIU_SCALAR,eps->eigr,ctx->nconv_loc,disp,MPIU_SCALAR,ctx->commrank)); /* eigenvalues */
666 8 : PetscCallMPI(MPI_Allgatherv(perm_loc,aux,MPIU_INT,eps->perm,ctx->nconv_loc,disp,MPIU_INT,ctx->commrank)); /* perm */
667 8 : for (i=1;i<ctx->npart;i++) disp[i] = disp[i-1]+ns_loc[i-1];
668 4 : PetscCall(PetscMPIIntCast(ns,&aux));
669 8 : PetscCallMPI(MPI_Allgatherv(shifts_loc,aux,MPIU_REAL,ctx->shifts,ns_loc,disp,MPIU_REAL,ctx->commrank)); /* shifts */
670 8 : PetscCallMPI(MPI_Allgatherv(inertias_loc,aux,MPIU_INT,ctx->inertias,ns_loc,disp,MPIU_INT,ctx->commrank)); /* inertias */
671 12 : PetscCallMPI(MPIU_Allreduce(&sr_loc->itsKs,&eps->its,1,MPIU_INT,MPI_SUM,ctx->commrank));
672 : } else { /* subcommunicators with different size */
673 3 : if (!rank) {
674 2 : PetscCall(PetscMPIIntCast(sr_loc->numEigs,&aux));
675 4 : PetscCallMPI(MPI_Allgatherv(eigr_loc,aux,MPIU_SCALAR,eps->eigr,ctx->nconv_loc,disp,MPIU_SCALAR,ctx->commrank)); /* eigenvalues */
676 4 : PetscCallMPI(MPI_Allgatherv(perm_loc,aux,MPIU_INT,eps->perm,ctx->nconv_loc,disp,MPIU_INT,ctx->commrank)); /* perm */
677 4 : for (i=1;i<ctx->npart;i++) disp[i] = disp[i-1]+ns_loc[i-1];
678 2 : PetscCall(PetscMPIIntCast(ns,&aux));
679 4 : PetscCallMPI(MPI_Allgatherv(shifts_loc,aux,MPIU_REAL,ctx->shifts,ns_loc,disp,MPIU_REAL,ctx->commrank)); /* shifts */
680 4 : PetscCallMPI(MPI_Allgatherv(inertias_loc,aux,MPIU_INT,ctx->inertias,ns_loc,disp,MPIU_INT,ctx->commrank)); /* inertias */
681 6 : PetscCallMPI(MPIU_Allreduce(&sr_loc->itsKs,&eps->its,1,MPIU_INT,MPI_SUM,ctx->commrank));
682 : }
683 3 : PetscCall(PetscMPIIntCast(eps->nconv,&aux));
684 6 : PetscCallMPI(MPI_Bcast(eps->eigr,aux,MPIU_SCALAR,0,child));
685 6 : PetscCallMPI(MPI_Bcast(eps->perm,aux,MPIU_INT,0,child));
686 3 : PetscCall(PetscMPIIntCast(ctx->nshifts,&aux));
687 6 : PetscCallMPI(MPI_Bcast(ctx->shifts,aux,MPIU_REAL,0,child));
688 6 : PetscCallMPI(MPI_Bcast(ctx->inertias,aux,MPIU_INT,0,child));
689 6 : PetscCallMPI(MPI_Bcast(&eps->its,1,MPIU_INT,0,child));
690 : }
691 : /* Update global array eps->perm */
692 7 : idx = ctx->nconv_loc[0];
693 14 : for (i=1;i<ctx->npart;i++) {
694 7 : off += ctx->nconv_loc[i-1];
695 169 : for (j=0;j<ctx->nconv_loc[i];j++) eps->perm[idx++] += off;
696 : }
697 :
698 : /* Gather parallel eigenvectors */
699 7 : PetscCall(PetscFree(ns_loc));
700 7 : PetscCall(PetscFree(disp));
701 7 : PetscCall(PetscFree(shifts_loc));
702 7 : PetscCall(PetscFree(inertias_loc));
703 7 : PetscFunctionReturn(PETSC_SUCCESS);
704 : }
705 :
706 : /*
707 : Fills the fields of a shift structure
708 : */
709 30 : static PetscErrorCode EPSCreateShift(EPS eps,PetscReal val,EPS_shift neighb0,EPS_shift neighb1)
710 : {
711 30 : EPS_shift s,*pending2;
712 30 : PetscInt i;
713 30 : EPS_SR sr;
714 30 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
715 :
716 30 : PetscFunctionBegin;
717 30 : sr = ctx->sr;
718 30 : if ((neighb0 && val==neighb0->value) || (neighb1 && val==neighb1->value)) {
719 0 : sr->nPend++;
720 0 : PetscFunctionReturn(PETSC_SUCCESS);
721 : }
722 30 : PetscCall(PetscNew(&s));
723 30 : s->value = val;
724 30 : s->neighb[0] = neighb0;
725 30 : if (neighb0) neighb0->neighb[1] = s;
726 30 : s->neighb[1] = neighb1;
727 30 : if (neighb1) neighb1->neighb[0] = s;
728 30 : s->comp[0] = PETSC_FALSE;
729 30 : s->comp[1] = PETSC_FALSE;
730 30 : s->index = -1;
731 30 : s->neigs = 0;
732 30 : s->nconv[0] = s->nconv[1] = 0;
733 30 : s->nsch[0] = s->nsch[1]=0;
734 : /* Inserts in the stack of pending shifts */
735 : /* If needed, the array is resized */
736 30 : if (sr->nPend >= sr->maxPend) {
737 0 : sr->maxPend *= 2;
738 0 : PetscCall(PetscMalloc1(sr->maxPend,&pending2));
739 0 : for (i=0;i<sr->nPend;i++) pending2[i] = sr->pending[i];
740 0 : PetscCall(PetscFree(sr->pending));
741 0 : sr->pending = pending2;
742 : }
743 30 : sr->pending[sr->nPend++]=s;
744 30 : PetscFunctionReturn(PETSC_SUCCESS);
745 : }
746 :
747 : /* Prepare for Rational Krylov update */
748 12 : static PetscErrorCode EPSPrepareRational(EPS eps)
749 : {
750 12 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
751 12 : PetscInt dir,i,k,ld,nv;
752 12 : PetscScalar *A;
753 12 : EPS_SR sr = ctx->sr;
754 12 : Vec v;
755 :
756 12 : PetscFunctionBegin;
757 12 : PetscCall(DSGetLeadingDimension(eps->ds,&ld));
758 12 : dir = (sr->sPres->neighb[0] == sr->sPrev)?1:-1;
759 12 : dir*=sr->dir;
760 12 : k = 0;
761 340 : for (i=0;i<sr->nS;i++) {
762 335 : if (dir*PetscRealPart(sr->S[i])>0.0) {
763 167 : sr->S[k] = sr->S[i];
764 167 : sr->S[sr->nS+k] = sr->S[sr->nS+i];
765 167 : PetscCall(BVGetColumn(sr->Vnext,k,&v));
766 167 : PetscCall(BVCopyVec(eps->V,eps->nconv+i,v));
767 167 : PetscCall(BVRestoreColumn(sr->Vnext,k,&v));
768 167 : k++;
769 167 : if (k>=sr->nS/2) break;
770 : }
771 : }
772 : /* Copy to DS */
773 12 : PetscCall(DSSetCompact(eps->ds,PETSC_FALSE)); /* make sure DS_MAT_A is allocated */
774 12 : PetscCall(DSGetArray(eps->ds,DS_MAT_A,&A));
775 12 : PetscCall(PetscArrayzero(A,ld*ld));
776 179 : for (i=0;i<k;i++) {
777 167 : A[i*(1+ld)] = sr->S[i];
778 167 : A[k+i*ld] = sr->S[sr->nS+i];
779 : }
780 12 : sr->nS = k;
781 12 : PetscCall(DSRestoreArray(eps->ds,DS_MAT_A,&A));
782 12 : PetscCall(DSGetDimensions(eps->ds,&nv,NULL,NULL,NULL));
783 12 : PetscCall(DSSetDimensions(eps->ds,nv,0,k));
784 : /* Append u to V */
785 12 : PetscCall(BVGetColumn(sr->Vnext,sr->nS,&v));
786 12 : PetscCall(BVCopyVec(eps->V,sr->nv,v));
787 12 : PetscCall(BVRestoreColumn(sr->Vnext,sr->nS,&v));
788 12 : PetscFunctionReturn(PETSC_SUCCESS);
789 : }
790 :
791 : /* Provides next shift to be computed */
792 30 : static PetscErrorCode EPSExtractShift(EPS eps)
793 : {
794 30 : PetscInt iner,zeros=0;
795 30 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
796 30 : EPS_SR sr;
797 30 : PetscReal newShift,diam,ptol;
798 30 : EPS_shift sPres;
799 :
800 30 : PetscFunctionBegin;
801 30 : sr = ctx->sr;
802 30 : if (sr->nPend > 0) {
803 12 : if (sr->sPres==sr->pending[sr->nPend-1]) {
804 0 : eps->reason = EPS_CONVERGED_ITERATING;
805 0 : eps->its = 0;
806 0 : sr->nPend--;
807 0 : sr->sPres->rep = PETSC_TRUE;
808 0 : PetscFunctionReturn(PETSC_SUCCESS);
809 : }
810 12 : sr->sPrev = sr->sPres;
811 12 : sr->sPres = sr->pending[--sr->nPend];
812 12 : sPres = sr->sPres;
813 19 : PetscCall(EPSSliceGetInertia(eps,sPres->value,&iner,ctx->detect?&zeros:NULL));
814 12 : if (zeros) {
815 0 : diam = PetscMin(PetscAbsReal(sPres->neighb[0]->value-sPres->value),PetscAbsReal(sPres->neighb[1]->value-sPres->value));
816 0 : ptol = PetscMin(SLICE_PTOL,diam/2);
817 0 : newShift = sPres->value*(1.0+ptol);
818 0 : if (sr->dir*(sPres->neighb[0] && newShift-sPres->neighb[0]->value) < 0) newShift = (sPres->value+sPres->neighb[0]->value)/2;
819 0 : else if (sPres->neighb[1] && sr->dir*(sPres->neighb[1]->value-newShift) < 0) newShift = (sPres->value+sPres->neighb[1]->value)/2;
820 0 : PetscCall(EPSSliceGetInertia(eps,newShift,&iner,&zeros));
821 0 : PetscCheck(zeros==0,((PetscObject)eps)->comm,PETSC_ERR_CONV_FAILED,"Inertia computation fails in %g",(double)newShift);
822 0 : sPres->value = newShift;
823 : }
824 12 : sr->sPres->inertia = iner;
825 12 : eps->target = sr->sPres->value;
826 12 : eps->reason = EPS_CONVERGED_ITERATING;
827 12 : eps->its = 0;
828 18 : } else sr->sPres = NULL;
829 30 : PetscFunctionReturn(PETSC_SUCCESS);
830 : }
831 :
832 : /*
833 : Symmetric KrylovSchur adapted to spectrum slicing:
834 : Allows searching an specific amount of eigenvalues in the subintervals left and right.
835 : Returns whether the search has succeeded
836 : */
837 30 : static PetscErrorCode EPSKrylovSchur_Slice(EPS eps)
838 : {
839 30 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
840 30 : PetscInt i,k,l,ld,nv,*iwork,j,count0,count1,iterCompl=0,n0,n1;
841 30 : Mat U,Op,T;
842 30 : PetscScalar *Q,*A;
843 30 : PetscReal *a,*b,beta,lambda;
844 30 : EPS_shift sPres;
845 30 : PetscBool breakdown,complIterating,sch0,sch1;
846 30 : EPS_SR sr = ctx->sr;
847 :
848 30 : PetscFunctionBegin;
849 : /* Spectrum slicing data */
850 30 : sPres = sr->sPres;
851 30 : complIterating =PETSC_FALSE;
852 30 : sch1 = sch0 = PETSC_TRUE;
853 30 : PetscCall(DSGetLeadingDimension(eps->ds,&ld));
854 30 : PetscCall(PetscMalloc1(2*ld,&iwork));
855 30 : count0=0;count1=0; /* Found on both sides */
856 30 : if (!sPres->rep && sr->nS > 0 && (sPres->neighb[0] == sr->sPrev || sPres->neighb[1] == sr->sPrev)) {
857 : /* Rational Krylov */
858 12 : PetscCall(DSTranslateRKS(eps->ds,sr->sPrev->value-sPres->value));
859 12 : PetscCall(DSGetDimensions(eps->ds,NULL,NULL,&l,NULL));
860 12 : PetscCall(DSSetDimensions(eps->ds,l+1,0,0));
861 12 : PetscCall(BVSetActiveColumns(eps->V,0,l+1));
862 12 : PetscCall(DSGetMat(eps->ds,DS_MAT_Q,&U));
863 12 : PetscCall(BVMultInPlace(eps->V,U,0,l+1));
864 12 : PetscCall(DSRestoreMat(eps->ds,DS_MAT_Q,&U));
865 : } else {
866 : /* Get the starting Lanczos vector */
867 18 : PetscCall(EPSGetStartVector(eps,0,NULL));
868 18 : l = 0;
869 : }
870 : /* Restart loop */
871 92 : while (eps->reason == EPS_CONVERGED_ITERATING) {
872 62 : eps->its++; sr->itsKs++;
873 : /* Compute an nv-step Lanczos factorization */
874 62 : nv = PetscMin(eps->nconv+eps->mpd,eps->ncv);
875 62 : PetscCall(DSSetDimensions(eps->ds,nv,eps->nconv,eps->nconv+l));
876 62 : PetscCall(DSGetMat(eps->ds,DS_MAT_T,&T));
877 62 : PetscCall(STGetOperator(eps->st,&Op));
878 62 : PetscCall(BVMatLanczos(eps->V,Op,T,eps->nconv+l,&nv,&beta,&breakdown));
879 62 : PetscCall(STRestoreOperator(eps->st,&Op));
880 62 : sr->nv = nv;
881 62 : PetscCall(DSRestoreMat(eps->ds,DS_MAT_T,&T));
882 62 : PetscCall(DSSetDimensions(eps->ds,nv,eps->nconv,eps->nconv+l));
883 62 : if (l==0) PetscCall(DSSetState(eps->ds,DS_STATE_INTERMEDIATE));
884 44 : else PetscCall(DSSetState(eps->ds,DS_STATE_RAW));
885 62 : PetscCall(BVSetActiveColumns(eps->V,eps->nconv,nv));
886 :
887 : /* Solve projected problem and compute residual norm estimates */
888 62 : if (eps->its == 1 && l > 0) { /* After rational update, DS_MAT_A is available */
889 12 : PetscCall(DSGetArray(eps->ds,DS_MAT_A,&A));
890 12 : PetscCall(DSGetArrayReal(eps->ds,DS_MAT_T,&a));
891 12 : b = a + ld;
892 12 : k = eps->nconv+l;
893 12 : A[k*ld+k-1] = A[(k-1)*ld+k];
894 12 : A[k*ld+k] = a[k];
895 693 : for (j=k+1; j< nv; j++) {
896 681 : A[j*ld+j] = a[j];
897 681 : A[j*ld+j-1] = b[j-1] ;
898 681 : A[(j-1)*ld+j] = b[j-1];
899 : }
900 12 : PetscCall(DSRestoreArray(eps->ds,DS_MAT_A,&A));
901 12 : PetscCall(DSRestoreArrayReal(eps->ds,DS_MAT_T,&a));
902 12 : PetscCall(DSSolve(eps->ds,eps->eigr,NULL));
903 12 : PetscCall(DSSort(eps->ds,eps->eigr,NULL,NULL,NULL,NULL));
904 12 : PetscCall(DSSetCompact(eps->ds,PETSC_TRUE));
905 : } else { /* Restart */
906 50 : PetscCall(DSSolve(eps->ds,eps->eigr,NULL));
907 50 : PetscCall(DSSort(eps->ds,eps->eigr,NULL,NULL,NULL,NULL));
908 : }
909 62 : PetscCall(DSSynchronize(eps->ds,eps->eigr,NULL));
910 :
911 : /* Residual */
912 62 : PetscCall(EPSKrylovConvergence(eps,PETSC_TRUE,eps->nconv,nv-eps->nconv,beta,0.0,1.0,&k));
913 : /* Checking values obtained for completing */
914 1949 : for (i=0;i<k;i++) {
915 1887 : sr->back[i]=eps->eigr[i];
916 : }
917 62 : PetscCall(STBackTransform(eps->st,k,sr->back,eps->eigi));
918 : count0=count1=0;
919 1949 : for (i=0;i<k;i++) {
920 1887 : lambda = PetscRealPart(sr->back[i]);
921 1887 : if ((sr->dir*(sPres->value - lambda) > 0) && (sr->dir*(lambda - sPres->ext[0]) > 0)) count0++;
922 1887 : if ((sr->dir*(lambda - sPres->value) > 0) && (sr->dir*(sPres->ext[1] - lambda) > 0)) count1++;
923 : }
924 62 : if (k>eps->nev && eps->ncv-k<5) eps->reason = EPS_CONVERGED_TOL;
925 : else {
926 : /* Checks completion */
927 62 : if ((!sch0||count0 >= sPres->nsch[0]) && (!sch1 ||count1 >= sPres->nsch[1])) {
928 18 : eps->reason = EPS_CONVERGED_TOL;
929 : } else {
930 44 : if (!complIterating && eps->its >= eps->max_it) eps->reason = EPS_DIVERGED_ITS;
931 44 : if (complIterating) {
932 5 : if (--iterCompl <= 0) eps->reason = EPS_DIVERGED_ITS;
933 39 : } else if (k >= eps->nev) {
934 13 : n0 = sPres->nsch[0]-count0;
935 13 : n1 = sPres->nsch[1]-count1;
936 13 : if (sr->iterCompl>0 && ((n0>0 && n0<= sr->nMAXCompl)||(n1>0&&n1<=sr->nMAXCompl))) {
937 : /* Iterating for completion*/
938 1 : complIterating = PETSC_TRUE;
939 1 : if (n0 >sr->nMAXCompl)sch0 = PETSC_FALSE;
940 1 : if (n1 >sr->nMAXCompl)sch1 = PETSC_FALSE;
941 : iterCompl = sr->iterCompl;
942 12 : } else eps->reason = EPS_CONVERGED_TOL;
943 : }
944 : }
945 : }
946 : /* Update l */
947 62 : if (eps->reason == EPS_CONVERGED_ITERATING) l = PetscMax(1,(PetscInt)((nv-k)*ctx->keep));
948 30 : else l = nv-k;
949 62 : if (breakdown) l=0;
950 62 : if (!ctx->lock && l>0 && eps->reason == EPS_CONVERGED_ITERATING) { l += k; k = 0; } /* non-locking variant: reset no. of converged pairs */
951 :
952 62 : if (eps->reason == EPS_CONVERGED_ITERATING) {
953 32 : if (breakdown) {
954 : /* Start a new Lanczos factorization */
955 0 : PetscCall(PetscInfo(eps,"Breakdown in Krylov-Schur method (it=%" PetscInt_FMT " norm=%g)\n",eps->its,(double)beta));
956 0 : PetscCall(EPSGetStartVector(eps,k,&breakdown));
957 0 : if (breakdown) {
958 0 : eps->reason = EPS_DIVERGED_BREAKDOWN;
959 0 : PetscCall(PetscInfo(eps,"Unable to generate more start vectors\n"));
960 : }
961 : } else {
962 : /* Prepare the Rayleigh quotient for restart */
963 32 : PetscCall(DSGetArrayReal(eps->ds,DS_MAT_T,&a));
964 32 : PetscCall(DSGetArray(eps->ds,DS_MAT_Q,&Q));
965 32 : b = a + ld;
966 1190 : for (i=k;i<k+l;i++) {
967 1158 : a[i] = PetscRealPart(eps->eigr[i]);
968 1158 : b[i] = PetscRealPart(Q[nv-1+i*ld]*beta);
969 : }
970 32 : PetscCall(DSRestoreArrayReal(eps->ds,DS_MAT_T,&a));
971 32 : PetscCall(DSRestoreArray(eps->ds,DS_MAT_Q,&Q));
972 : }
973 : }
974 : /* Update the corresponding vectors V(:,idx) = V*Q(:,idx) */
975 62 : PetscCall(DSGetMat(eps->ds,DS_MAT_Q,&U));
976 62 : PetscCall(BVMultInPlace(eps->V,U,eps->nconv,k+l));
977 62 : PetscCall(DSRestoreMat(eps->ds,DS_MAT_Q,&U));
978 :
979 : /* Normalize u and append it to V */
980 62 : if (eps->reason == EPS_CONVERGED_ITERATING && !breakdown) PetscCall(BVCopyColumn(eps->V,nv,k+l));
981 62 : eps->nconv = k;
982 62 : if (eps->reason != EPS_CONVERGED_ITERATING) {
983 : /* Store approximated values for next shift */
984 30 : PetscCall(DSGetArray(eps->ds,DS_MAT_Q,&Q));
985 30 : sr->nS = l;
986 1151 : for (i=0;i<l;i++) {
987 1121 : sr->S[i] = eps->eigr[i+k];/* Diagonal elements */
988 1121 : sr->S[i+l] = Q[nv-1+(i+k)*ld]*beta; /* Out of diagonal elements */
989 : }
990 122 : PetscCall(DSRestoreArray(eps->ds,DS_MAT_Q,&Q));
991 : }
992 : }
993 : /* Check for completion */
994 1109 : for (i=0;i< eps->nconv; i++) {
995 1079 : if (sr->dir*PetscRealPart(eps->eigr[i])>0) sPres->nconv[1]++;
996 571 : else sPres->nconv[0]++;
997 : }
998 30 : sPres->comp[0] = PetscNot(count0 < sPres->nsch[0]);
999 30 : sPres->comp[1] = PetscNot(count1 < sPres->nsch[1]);
1000 42 : PetscCall(PetscInfo(eps,"Lanczos: %" PetscInt_FMT " evals in [%g,%g]%s and %" PetscInt_FMT " evals in [%g,%g]%s\n",count0,(double)(sr->dir==1?sPres->ext[0]:sPres->value),(double)(sr->dir==1?sPres->value:sPres->ext[0]),sPres->comp[0]?"*":"",count1,(double)(sr->dir==1?sPres->value:sPres->ext[1]),(double)(sr->dir==1?sPres->ext[1]:sPres->value),sPres->comp[1]?"*":""));
1001 30 : PetscCheck(count0<=sPres->nsch[0] && count1<=sPres->nsch[1],PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Mismatch between number of values found and information from inertia%s",ctx->detect?"":", consider using EPSKrylovSchurSetDetectZeros()");
1002 30 : PetscCall(PetscFree(iwork));
1003 30 : PetscFunctionReturn(PETSC_SUCCESS);
1004 : }
1005 :
1006 : /*
1007 : Obtains value of subsequent shift
1008 : */
1009 12 : static PetscErrorCode EPSGetNewShiftValue(EPS eps,PetscInt side,PetscReal *newS)
1010 : {
1011 12 : PetscReal lambda,d_prev;
1012 12 : PetscInt i,idxP;
1013 12 : EPS_SR sr;
1014 12 : EPS_shift sPres,s;
1015 12 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
1016 :
1017 12 : PetscFunctionBegin;
1018 12 : sr = ctx->sr;
1019 12 : sPres = sr->sPres;
1020 12 : if (sPres->neighb[side]) {
1021 : /* Completing a previous interval */
1022 2 : *newS = (sPres->value + sPres->neighb[side]->value)/2;
1023 2 : if (PetscAbsReal(sPres->value - *newS)/PetscAbsReal(sPres->value)<=100*PETSC_SQRT_MACHINE_EPSILON) *newS = sPres->value;
1024 : } else { /* (Only for side=1). Creating a new interval. */
1025 10 : if (sPres->neigs==0) {/* No value has been accepted*/
1026 0 : if (sPres->neighb[0]) {
1027 : /* Multiplying by 10 the previous distance */
1028 0 : *newS = sPres->value + 10*sr->dir*PetscAbsReal(sPres->value - sPres->neighb[0]->value);
1029 0 : sr->nleap++;
1030 : /* Stops when the interval is open and no values are found in the last 5 shifts (there might be infinite eigenvalues) */
1031 0 : PetscCheck(sr->hasEnd || sr->nleap<=5,PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Unable to compute the wanted eigenvalues with open interval");
1032 : } else { /* First shift */
1033 0 : PetscCheck(eps->nconv!=0,PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"First shift renders no information");
1034 : /* Unaccepted values give information for next shift */
1035 : idxP=0;/* Number of values left from shift */
1036 0 : for (i=0;i<eps->nconv;i++) {
1037 0 : lambda = PetscRealPart(eps->eigr[i]);
1038 0 : if (sr->dir*(lambda - sPres->value) <0) idxP++;
1039 : else break;
1040 : }
1041 : /* Avoiding subtraction of eigenvalues (might be the same).*/
1042 0 : if (idxP>0) {
1043 0 : d_prev = PetscAbsReal(sPres->value - PetscRealPart(eps->eigr[0]))/(idxP+0.3);
1044 : } else {
1045 0 : d_prev = PetscAbsReal(sPres->value - PetscRealPart(eps->eigr[eps->nconv-1]))/(eps->nconv+0.3);
1046 : }
1047 0 : *newS = sPres->value + (sr->dir*d_prev*eps->nev)/2;
1048 : }
1049 : } else { /* Accepted values found */
1050 10 : sr->nleap = 0;
1051 : /* Average distance of values in previous subinterval */
1052 10 : s = sPres->neighb[0];
1053 10 : while (s && PetscAbs(s->inertia - sPres->inertia)==0) {
1054 0 : s = s->neighb[0];/* Looking for previous shifts with eigenvalues within */
1055 : }
1056 10 : if (s) {
1057 0 : d_prev = PetscAbsReal((sPres->value - s->value)/(sPres->inertia - s->inertia));
1058 : } else { /* First shift. Average distance obtained with values in this shift */
1059 : /* first shift might be too far from first wanted eigenvalue (no values found outside the interval)*/
1060 10 : if (sr->dir*(PetscRealPart(sr->eigr[0])-sPres->value)>0 && PetscAbsReal((PetscRealPart(sr->eigr[sr->indexEig-1]) - PetscRealPart(sr->eigr[0]))/PetscRealPart(sr->eigr[0])) > PetscSqrtReal(eps->tol)) {
1061 10 : d_prev = PetscAbsReal((PetscRealPart(sr->eigr[sr->indexEig-1]) - PetscRealPart(sr->eigr[0])))/(sPres->neigs+0.3);
1062 : } else {
1063 0 : d_prev = PetscAbsReal(PetscRealPart(sr->eigr[sr->indexEig-1]) - sPres->value)/(sPres->neigs+0.3);
1064 : }
1065 : }
1066 : /* Average distance is used for next shift by adding it to value on the right or to shift */
1067 10 : if (sr->dir*(PetscRealPart(sr->eigr[sPres->index + sPres->neigs -1]) - sPres->value)>0) {
1068 10 : *newS = PetscRealPart(sr->eigr[sPres->index + sPres->neigs -1])+ (sr->dir*d_prev*eps->nev)/2;
1069 : } else { /* Last accepted value is on the left of shift. Adding to shift */
1070 0 : *newS = sPres->value + (sr->dir*d_prev*eps->nev)/2;
1071 : }
1072 : }
1073 : /* End of interval can not be surpassed */
1074 10 : if (sr->dir*(sr->int1 - *newS) < 0) *newS = sr->int1;
1075 : }/* of neighb[side]==null */
1076 12 : PetscFunctionReturn(PETSC_SUCCESS);
1077 : }
1078 :
1079 : /*
1080 : Function for sorting an array of real values
1081 : */
1082 60 : static PetscErrorCode sortRealEigenvalues(PetscScalar *r,PetscInt *perm,PetscInt nr,PetscBool prev,PetscInt dir)
1083 : {
1084 60 : PetscReal re;
1085 60 : PetscInt i,j,tmp;
1086 :
1087 60 : PetscFunctionBegin;
1088 1139 : if (!prev) for (i=0;i<nr;i++) perm[i] = i;
1089 : /* Insertion sort */
1090 1852 : for (i=1;i<nr;i++) {
1091 1792 : re = PetscRealPart(r[perm[i]]);
1092 1792 : j = i-1;
1093 12224 : while (j>=0 && dir*(re - PetscRealPart(r[perm[j]])) <= 0) {
1094 10432 : tmp = perm[j]; perm[j] = perm[j+1]; perm[j+1] = tmp; j--;
1095 : }
1096 : }
1097 60 : PetscFunctionReturn(PETSC_SUCCESS);
1098 : }
1099 :
1100 : /* Stores the pairs obtained since the last shift in the global arrays */
1101 30 : static PetscErrorCode EPSStoreEigenpairs(EPS eps)
1102 : {
1103 30 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
1104 30 : PetscReal lambda,err,norm;
1105 30 : PetscInt i,count;
1106 30 : PetscBool iscayley;
1107 30 : EPS_SR sr = ctx->sr;
1108 30 : EPS_shift sPres;
1109 30 : Vec v,w;
1110 :
1111 30 : PetscFunctionBegin;
1112 30 : sPres = sr->sPres;
1113 30 : sPres->index = sr->indexEig;
1114 30 : count = sr->indexEig;
1115 : /* Back-transform */
1116 30 : PetscCall(STBackTransform(eps->st,eps->nconv,eps->eigr,eps->eigi));
1117 30 : PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STCAYLEY,&iscayley));
1118 : /* Sort eigenvalues */
1119 30 : PetscCall(sortRealEigenvalues(eps->eigr,eps->perm,eps->nconv,PETSC_FALSE,sr->dir));
1120 : /* Values stored in global array */
1121 1109 : for (i=0;i<eps->nconv;i++) {
1122 1079 : lambda = PetscRealPart(eps->eigr[eps->perm[i]]);
1123 1079 : err = eps->errest[eps->perm[i]];
1124 :
1125 1079 : if (sr->dir*(lambda - sPres->ext[0]) > 0 && (sr->dir)*(sPres->ext[1] - lambda) > 0) {/* Valid value */
1126 496 : PetscCheck(count<sr->numEigs,PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Unexpected error in Spectrum Slicing");
1127 496 : sr->eigr[count] = lambda;
1128 496 : sr->errest[count] = err;
1129 : /* Explicit purification */
1130 496 : PetscCall(BVGetColumn(eps->V,eps->perm[i],&w));
1131 496 : if (eps->purify) {
1132 419 : PetscCall(BVGetColumn(sr->V,count,&v));
1133 419 : PetscCall(STApply(eps->st,w,v));
1134 419 : PetscCall(BVRestoreColumn(sr->V,count,&v));
1135 77 : } else PetscCall(BVInsertVec(sr->V,count,w));
1136 496 : PetscCall(BVRestoreColumn(eps->V,eps->perm[i],&w));
1137 496 : PetscCall(BVNormColumn(sr->V,count,NORM_2,&norm));
1138 496 : PetscCall(BVScaleColumn(sr->V,count,1.0/norm));
1139 496 : count++;
1140 : }
1141 : }
1142 30 : sPres->neigs = count - sr->indexEig;
1143 30 : sr->indexEig = count;
1144 : /* Global ordering array updating */
1145 30 : PetscCall(sortRealEigenvalues(sr->eigr,sr->perm,count,PETSC_TRUE,sr->dir));
1146 30 : PetscFunctionReturn(PETSC_SUCCESS);
1147 : }
1148 :
1149 30 : static PetscErrorCode EPSLookForDeflation(EPS eps)
1150 : {
1151 30 : PetscReal val;
1152 30 : PetscInt i,count0=0,count1=0;
1153 30 : EPS_shift sPres;
1154 30 : PetscInt ini,fin,k,idx0,idx1;
1155 30 : EPS_SR sr;
1156 30 : Vec v;
1157 30 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
1158 :
1159 30 : PetscFunctionBegin;
1160 30 : sr = ctx->sr;
1161 30 : sPres = sr->sPres;
1162 :
1163 30 : if (sPres->neighb[0]) ini = (sr->dir)*(sPres->neighb[0]->inertia - sr->inertia0);
1164 : else ini = 0;
1165 30 : fin = sr->indexEig;
1166 : /* Selection of ends for searching new values */
1167 30 : if (!sPres->neighb[0]) sPres->ext[0] = sr->int0;/* First shift */
1168 12 : else sPres->ext[0] = sPres->neighb[0]->value;
1169 30 : if (!sPres->neighb[1]) {
1170 28 : if (sr->hasEnd) sPres->ext[1] = sr->int1;
1171 4 : else sPres->ext[1] = (sr->dir > 0)?PETSC_MAX_REAL:PETSC_MIN_REAL;
1172 2 : } else sPres->ext[1] = sPres->neighb[1]->value;
1173 : /* Selection of values between right and left ends */
1174 279 : for (i=ini;i<fin;i++) {
1175 251 : val=PetscRealPart(sr->eigr[sr->perm[i]]);
1176 : /* Values to the right of left shift */
1177 251 : if (sr->dir*(val - sPres->ext[1]) < 0) {
1178 249 : if (sr->dir*(val - sPres->value) < 0) count0++;
1179 20 : else count1++;
1180 : } else break;
1181 : }
1182 : /* The number of values on each side are found */
1183 30 : if (sPres->neighb[0]) {
1184 12 : sPres->nsch[0] = (sr->dir)*(sPres->inertia - sPres->neighb[0]->inertia)-count0;
1185 12 : PetscCheck(sPres->nsch[0]>=0,PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Mismatch between number of values found and information from inertia%s",ctx->detect?"":", consider using EPSKrylovSchurSetDetectZeros()");
1186 18 : } else sPres->nsch[0] = 0;
1187 :
1188 30 : if (sPres->neighb[1]) {
1189 2 : sPres->nsch[1] = (sr->dir)*(sPres->neighb[1]->inertia - sPres->inertia) - count1;
1190 2 : PetscCheck(sPres->nsch[1]>=0,PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Mismatch between number of values found and information from inertia%s",ctx->detect?"":", consider using EPSKrylovSchurSetDetectZeros()");
1191 28 : } else sPres->nsch[1] = (sr->dir)*(sr->inertia1 - sPres->inertia);
1192 :
1193 : /* Completing vector of indexes for deflation */
1194 30 : idx0 = ini;
1195 30 : idx1 = ini+count0+count1;
1196 30 : k=0;
1197 279 : for (i=idx0;i<idx1;i++) sr->idxDef[k++]=sr->perm[i];
1198 30 : PetscCall(BVDuplicateResize(eps->V,k+eps->ncv+1,&sr->Vnext));
1199 30 : PetscCall(BVSetNumConstraints(sr->Vnext,k));
1200 279 : for (i=0;i<k;i++) {
1201 249 : PetscCall(BVGetColumn(sr->Vnext,-i-1,&v));
1202 249 : PetscCall(BVCopyVec(sr->V,sr->idxDef[i],v));
1203 249 : PetscCall(BVRestoreColumn(sr->Vnext,-i-1,&v));
1204 : }
1205 :
1206 : /* For rational Krylov */
1207 30 : if (!sr->sPres->rep && sr->nS>0 && (sr->sPrev == sr->sPres->neighb[0] || sr->sPrev == sr->sPres->neighb[1])) PetscCall(EPSPrepareRational(eps));
1208 30 : eps->nconv = 0;
1209 : /* Get rid of temporary Vnext */
1210 30 : PetscCall(BVDestroy(&eps->V));
1211 30 : eps->V = sr->Vnext;
1212 30 : sr->Vnext = NULL;
1213 30 : PetscFunctionReturn(PETSC_SUCCESS);
1214 : }
1215 :
1216 36 : PetscErrorCode EPSSolve_KrylovSchur_Slice(EPS eps)
1217 : {
1218 36 : PetscInt i,lds,ti;
1219 36 : PetscReal newS;
1220 36 : EPS_KRYLOVSCHUR *ctx=(EPS_KRYLOVSCHUR*)eps->data;
1221 36 : EPS_SR sr=ctx->sr;
1222 36 : Mat A,B=NULL;
1223 36 : PetscObjectState Astate,Bstate=0;
1224 36 : PetscObjectId Aid,Bid=0;
1225 :
1226 36 : PetscFunctionBegin;
1227 36 : PetscCall(PetscCitationsRegister(citation,&cited));
1228 36 : if (ctx->global) {
1229 18 : PetscCall(EPSSolve_KrylovSchur_Slice(ctx->eps));
1230 18 : ctx->eps->state = EPS_STATE_SOLVED;
1231 18 : eps->reason = EPS_CONVERGED_TOL;
1232 18 : if (ctx->npart>1) {
1233 : /* Gather solution from subsolvers */
1234 7 : PetscCall(EPSSliceGatherSolution(eps));
1235 : } else {
1236 11 : eps->nconv = sr->numEigs;
1237 11 : eps->its = ctx->eps->its;
1238 11 : PetscCall(PetscFree(ctx->inertias));
1239 11 : PetscCall(PetscFree(ctx->shifts));
1240 11 : PetscCall(EPSSliceGetInertias(ctx->eps,&ctx->nshifts,&ctx->shifts,&ctx->inertias));
1241 : }
1242 : } else {
1243 18 : if (ctx->npart==1) {
1244 11 : sr->eigr = ctx->eps->eigr;
1245 11 : sr->eigi = ctx->eps->eigi;
1246 11 : sr->perm = ctx->eps->perm;
1247 11 : sr->errest = ctx->eps->errest;
1248 11 : sr->V = ctx->eps->V;
1249 : }
1250 : /* Check that the user did not modify subcomm matrices */
1251 18 : PetscCall(EPSGetOperators(eps,&A,&B));
1252 18 : PetscCall(MatGetState(A,&Astate));
1253 18 : PetscCall(PetscObjectGetId((PetscObject)A,&Aid));
1254 18 : if (B) {
1255 14 : PetscCall(MatGetState(B,&Bstate));
1256 14 : PetscCall(PetscObjectGetId((PetscObject)B,&Bid));
1257 : }
1258 18 : PetscCheck(Astate==ctx->Astate && (!B || Bstate==ctx->Bstate) && Aid==ctx->Aid && (!B || Bid==ctx->Bid),PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Subcomm matrices have been modified by user");
1259 : /* Only with eigenvalues present in the interval ...*/
1260 18 : if (sr->numEigs==0) {
1261 0 : eps->reason = EPS_CONVERGED_TOL;
1262 0 : PetscFunctionReturn(PETSC_SUCCESS);
1263 : }
1264 : /* Array of pending shifts */
1265 18 : sr->maxPend = 100; /* Initial size */
1266 18 : sr->nPend = 0;
1267 18 : PetscCall(PetscMalloc1(sr->maxPend,&sr->pending));
1268 18 : PetscCall(EPSCreateShift(eps,sr->int0,NULL,NULL));
1269 : /* extract first shift */
1270 18 : sr->sPrev = NULL;
1271 18 : sr->sPres = sr->pending[--sr->nPend];
1272 18 : sr->sPres->inertia = sr->inertia0;
1273 18 : eps->target = sr->sPres->value;
1274 18 : sr->s0 = sr->sPres;
1275 18 : sr->indexEig = 0;
1276 : /* Memory reservation for auxiliary variables */
1277 18 : lds = PetscMin(eps->mpd,eps->ncv);
1278 18 : PetscCall(PetscCalloc1(lds*lds,&sr->S));
1279 18 : PetscCall(PetscMalloc1(eps->ncv,&sr->back));
1280 514 : for (i=0;i<sr->numEigs;i++) {
1281 496 : sr->eigr[i] = 0.0;
1282 496 : sr->eigi[i] = 0.0;
1283 496 : sr->errest[i] = 0.0;
1284 496 : sr->perm[i] = i;
1285 : }
1286 : /* Vectors for deflation */
1287 18 : PetscCall(PetscMalloc1(sr->numEigs,&sr->idxDef));
1288 18 : sr->indexEig = 0;
1289 : /* Main loop */
1290 18 : while (sr->sPres) {
1291 : /* Search for deflation */
1292 30 : PetscCall(EPSLookForDeflation(eps));
1293 : /* KrylovSchur */
1294 30 : PetscCall(EPSKrylovSchur_Slice(eps));
1295 :
1296 30 : PetscCall(EPSStoreEigenpairs(eps));
1297 : /* Select new shift */
1298 30 : if (!sr->sPres->comp[1]) {
1299 11 : PetscCall(EPSGetNewShiftValue(eps,1,&newS));
1300 11 : PetscCall(EPSCreateShift(eps,newS,sr->sPres,sr->sPres->neighb[1]));
1301 : }
1302 30 : if (!sr->sPres->comp[0]) {
1303 : /* Completing earlier interval */
1304 1 : PetscCall(EPSGetNewShiftValue(eps,0,&newS));
1305 1 : PetscCall(EPSCreateShift(eps,newS,sr->sPres->neighb[0],sr->sPres));
1306 : }
1307 : /* Preparing for a new search of values */
1308 48 : PetscCall(EPSExtractShift(eps));
1309 : }
1310 :
1311 : /* Updating eps values prior to exit */
1312 18 : PetscCall(PetscFree(sr->S));
1313 18 : PetscCall(PetscFree(sr->idxDef));
1314 18 : PetscCall(PetscFree(sr->pending));
1315 18 : PetscCall(PetscFree(sr->back));
1316 18 : PetscCall(BVDuplicateResize(eps->V,eps->ncv+1,&sr->Vnext));
1317 18 : PetscCall(BVSetNumConstraints(sr->Vnext,0));
1318 18 : PetscCall(BVDestroy(&eps->V));
1319 18 : eps->V = sr->Vnext;
1320 18 : eps->nconv = sr->indexEig;
1321 18 : eps->reason = EPS_CONVERGED_TOL;
1322 18 : eps->its = sr->itsKs;
1323 18 : eps->nds = 0;
1324 18 : if (sr->dir<0) {
1325 218 : for (i=0;i<eps->nconv/2;i++) {
1326 204 : ti = sr->perm[i]; sr->perm[i] = sr->perm[eps->nconv-1-i]; sr->perm[eps->nconv-1-i] = ti;
1327 : }
1328 : }
1329 : }
1330 36 : PetscFunctionReturn(PETSC_SUCCESS);
1331 : }
|