1: /*
2: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3: SLEPc - Scalable Library for Eigenvalue Problem Computations
4: Copyright (c) 2002-2020, Universitat Politecnica de Valencia, Spain
6: This file is part of SLEPc.
7: SLEPc is distributed under a 2-clause BSD license (see LICENSE).
8: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
9: */
10: /*
11: SLEPc eigensolver: "krylovschur"
13: Method: Krylov-Schur
15: Algorithm:
17: Single-vector Krylov-Schur method for non-symmetric problems,
18: including harmonic extraction.
20: References:
22: [1] "Krylov-Schur Methods in SLEPc", SLEPc Technical Report STR-7,
23: available at https://slepc.upv.es.
25: [2] G.W. Stewart, "A Krylov-Schur Algorithm for Large Eigenproblems",
26: SIAM J. Matrix Anal. App. 23(3):601-614, 2001.
28: [3] "Practical Implementation of Harmonic Krylov-Schur", SLEPc Technical
29: Report STR-9, available at https://slepc.upv.es.
30: */
32: #include <slepc/private/epsimpl.h> /*I "slepceps.h" I*/
33: #include "krylovschur.h"
35: PetscErrorCode EPSGetArbitraryValues(EPS eps,PetscScalar *rr,PetscScalar *ri) 36: {
38: PetscInt i,newi,ld,n,l;
39: Vec xr=eps->work[0],xi=eps->work[1];
40: PetscScalar re,im,*Zr,*Zi,*X;
43: DSGetLeadingDimension(eps->ds,&ld);
44: DSGetDimensions(eps->ds,&n,NULL,&l,NULL,NULL);
45: for (i=l;i<n;i++) {
46: re = eps->eigr[i];
47: im = eps->eigi[i];
48: STBackTransform(eps->st,1,&re,&im);
49: newi = i;
50: DSVectors(eps->ds,DS_MAT_X,&newi,NULL);
51: DSGetArray(eps->ds,DS_MAT_X,&X);
52: Zr = X+i*ld;
53: if (newi==i+1) Zi = X+newi*ld;
54: else Zi = NULL;
55: EPSComputeRitzVector(eps,Zr,Zi,eps->V,xr,xi);
56: DSRestoreArray(eps->ds,DS_MAT_X,&X);
57: (*eps->arbitrary)(re,im,xr,xi,rr+i,ri+i,eps->arbitraryctx);
58: }
59: return(0);
60: }
62: static PetscErrorCode EstimateRange(Mat A,PetscReal *left,PetscReal *right) 63: {
65: PetscInt nconv;
66: PetscScalar eig0;
67: EPS eps;
70: *left = 0.0; *right = 0.0;
71: EPSCreate(PetscObjectComm((PetscObject)A),&eps);
72: EPSSetOptionsPrefix(eps,"eps_filter_");
73: EPSSetOperators(eps,A,NULL);
74: EPSSetProblemType(eps,EPS_HEP);
75: EPSSetTolerances(eps,1e-3,50);
76: EPSSetWhichEigenpairs(eps,EPS_SMALLEST_REAL);
77: EPSSolve(eps);
78: EPSGetConverged(eps,&nconv);
79: if (nconv>0) {
80: EPSGetEigenvalue(eps,0,&eig0,NULL);
81: } else eig0 = eps->eigr[0];
82: *left = PetscRealPart(eig0);
83: EPSSetWhichEigenpairs(eps,EPS_LARGEST_REAL);
84: EPSSolve(eps);
85: EPSGetConverged(eps,&nconv);
86: if (nconv>0) {
87: EPSGetEigenvalue(eps,0,&eig0,NULL);
88: } else eig0 = eps->eigr[0];
89: *right = PetscRealPart(eig0);
90: EPSDestroy(&eps);
91: return(0);
92: }
94: static PetscErrorCode EPSSetUp_KrylovSchur_Filter(EPS eps) 95: {
97: SlepcSC sc;
98: PetscReal rleft,rright;
99: Mat A;
102: if (eps->intb >= PETSC_MAX_REAL && eps->inta <= PETSC_MIN_REAL) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"The defined computational interval should have at least one of their sides bounded");
103: if (!eps->ishermitian) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Polynomial filter only available for symmetric/Hermitian eigenproblems");
104: if (eps->isgeneralized) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Polynomial filters not available for generalized eigenproblems");
105: if (eps->arbitrary) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Arbitrary selection of eigenpairs cannot be used with polynomial filters");
106: if (eps->tol==PETSC_DEFAULT) eps->tol = SLEPC_DEFAULT_TOL*1e-2; /* use tighter tolerance */
107: STFilterSetInterval(eps->st,eps->inta,eps->intb);
108: STGetMatrix(eps->st,0,&A);
109: STFilterGetRange(eps->st,&rleft,&rright);
110: if (!rleft && !rright) {
111: EstimateRange(A,&rleft,&rright);
112: PetscInfo2(eps,"Setting eigenvalue range to [%g,%g]\n",(double)rleft,(double)rright);
113: STFilterSetRange(eps->st,rleft,rright);
114: }
115: if (!eps->ncv && eps->nev==1) eps->nev = 40; /* user did not provide nev estimation */
116: EPSSetDimensions_Default(eps,eps->nev,&eps->ncv,&eps->mpd);
117: if (eps->ncv>eps->nev+eps->mpd) SETERRQ(PetscObjectComm((PetscObject)eps),1,"The value of ncv must not be larger than nev+mpd");
118: if (!eps->max_it) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
120: DSGetSlepcSC(eps->ds,&sc);
121: sc->rg = NULL;
122: sc->comparison = SlepcCompareLargestReal;
123: sc->comparisonctx = NULL;
124: sc->map = NULL;
125: sc->mapobj = NULL;
126: return(0);
127: }
129: PetscErrorCode EPSSetUp_KrylovSchur(EPS eps)130: {
131: PetscErrorCode ierr;
132: PetscReal eta;
133: PetscBool isfilt=PETSC_FALSE;
134: BVOrthogType otype;
135: BVOrthogBlockType obtype;
136: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
137: enum { EPS_KS_DEFAULT,EPS_KS_SYMM,EPS_KS_SLICE,EPS_KS_FILTER,EPS_KS_INDEF,EPS_KS_TWOSIDED } variant;
140: /* spectrum slicing requires special treatment of default values */
141: if (eps->which==EPS_ALL) {
142: PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt);
143: if (isfilt) {
144: EPSSetUp_KrylovSchur_Filter(eps);
145: } else {
146: EPSSetUp_KrylovSchur_Slice(eps);
147: }
148: } else {
149: EPSSetDimensions_Default(eps,eps->nev,&eps->ncv,&eps->mpd);
150: if (eps->ncv>eps->nev+eps->mpd) SETERRQ(PetscObjectComm((PetscObject)eps),1,"The value of ncv must not be larger than nev+mpd");
151: if (!eps->max_it) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
152: if (!eps->which) { EPSSetWhichEigenpairs_Default(eps); }
153: }
154: if (!ctx->lock && eps->mpd<eps->ncv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Should not use mpd parameter in non-locking variant");
156: if (eps->isgeneralized && eps->ishermitian && !eps->ispositive && eps->arbitrary) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Arbitrary selection of eigenpairs not implemented for indefinite problems");
157: if (eps->ishermitian && eps->ispositive && (eps->which==EPS_LARGEST_IMAGINARY || eps->which==EPS_SMALLEST_IMAGINARY)) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Wrong value of eps->which");
159: if (!eps->extraction) {
160: EPSSetExtraction(eps,EPS_RITZ);
161: } else if (eps->extraction!=EPS_RITZ && eps->extraction!=EPS_HARMONIC) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Unsupported extraction type");
163: if (!ctx->keep) ctx->keep = 0.5;
165: EPSAllocateSolution(eps,1);
166: EPS_SetInnerProduct(eps);
167: if (eps->arbitrary) {
168: EPSSetWorkVecs(eps,2);
169: } else if (eps->ishermitian && !eps->ispositive){
170: EPSSetWorkVecs(eps,1);
171: }
173: /* dispatch solve method */
174: if (eps->ishermitian) {
175: if (eps->which==EPS_ALL) {
176: if (eps->isgeneralized && !eps->ispositive) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Spectrum slicing not implemented for indefinite problems");
177: else variant = isfilt? EPS_KS_FILTER: EPS_KS_SLICE;
178: } else if (eps->isgeneralized && !eps->ispositive) {
179: variant = EPS_KS_INDEF;
180: } else {
181: switch (eps->extraction) {
182: case EPS_RITZ: variant = EPS_KS_SYMM; break;
183: case EPS_HARMONIC: variant = EPS_KS_DEFAULT; break;
184: default: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Unsupported extraction type");
185: }
186: }
187: } else if (eps->twosided) {
188: variant = EPS_KS_TWOSIDED;
189: } else {
190: switch (eps->extraction) {
191: case EPS_RITZ: variant = EPS_KS_DEFAULT; break;
192: case EPS_HARMONIC: variant = EPS_KS_DEFAULT; break;
193: default: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Unsupported extraction type");
194: }
195: }
196: switch (variant) {
197: case EPS_KS_DEFAULT:
198: eps->ops->solve = EPSSolve_KrylovSchur_Default;
199: eps->ops->computevectors = EPSComputeVectors_Schur;
200: DSSetType(eps->ds,DSNHEP);
201: DSAllocate(eps->ds,eps->ncv+1);
202: break;
203: case EPS_KS_SYMM:
204: case EPS_KS_FILTER:
205: eps->ops->solve = EPSSolve_KrylovSchur_Symm;
206: eps->ops->computevectors = EPSComputeVectors_Hermitian;
207: DSSetType(eps->ds,DSHEP);
208: DSSetCompact(eps->ds,PETSC_TRUE);
209: DSSetExtraRow(eps->ds,PETSC_TRUE);
210: DSAllocate(eps->ds,eps->ncv+1);
211: break;
212: case EPS_KS_SLICE:
213: if (eps->stopping!=EPSStoppingBasic) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Spectrum slicing does not support user-defined stopping test");
214: eps->ops->solve = EPSSolve_KrylovSchur_Slice;
215: eps->ops->computevectors = EPSComputeVectors_Slice;
216: break;
217: case EPS_KS_INDEF:
218: eps->ops->solve = EPSSolve_KrylovSchur_Indefinite;
219: eps->ops->computevectors = EPSComputeVectors_Indefinite;
220: DSSetType(eps->ds,DSGHIEP);
221: DSSetCompact(eps->ds,PETSC_TRUE);
222: DSAllocate(eps->ds,eps->ncv+1);
223: /* force reorthogonalization for pseudo-Lanczos */
224: BVGetOrthogonalization(eps->V,&otype,NULL,&eta,&obtype);
225: BVSetOrthogonalization(eps->V,otype,BV_ORTHOG_REFINE_ALWAYS,eta,obtype);
226: break;
227: case EPS_KS_TWOSIDED:
228: eps->ops->solve = EPSSolve_KrylovSchur_TwoSided;
229: eps->ops->computevectors = EPSComputeVectors_Schur;
230: DSSetType(eps->ds,DSNHEP);
231: DSAllocate(eps->ds,eps->ncv+1);
232: DSSetType(eps->dsts,DSNHEP);
233: DSAllocate(eps->dsts,eps->ncv+1);
234: break;
235: default: SETERRQ(PetscObjectComm((PetscObject)eps),1,"Unexpected error");
236: }
237: return(0);
238: }
240: PetscErrorCode EPSSolve_KrylovSchur_Default(EPS eps)241: {
242: PetscErrorCode ierr;
243: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
244: PetscInt i,j,*pj,k,l,nv,ld,nconv;
245: Mat U,Op;
246: PetscScalar *S,*Q,*g;
247: PetscReal beta,gamma=1.0;
248: PetscBool breakdown,harmonic;
251: DSGetLeadingDimension(eps->ds,&ld);
252: harmonic = (eps->extraction==EPS_HARMONIC || eps->extraction==EPS_REFINED_HARMONIC)?PETSC_TRUE:PETSC_FALSE;
253: if (harmonic) { PetscMalloc1(ld,&g); }
254: if (eps->arbitrary) pj = &j;
255: else pj = NULL;
257: /* Get the starting Arnoldi vector */
258: EPSGetStartVector(eps,0,NULL);
259: l = 0;
261: /* Restart loop */
262: while (eps->reason == EPS_CONVERGED_ITERATING) {
263: eps->its++;
265: /* Compute an nv-step Arnoldi factorization */
266: nv = PetscMin(eps->nconv+eps->mpd,eps->ncv);
267: STGetOperator(eps->st,&Op);
268: DSGetArray(eps->ds,DS_MAT_A,&S);
269: BVMatArnoldi(eps->V,Op,S,ld,eps->nconv+l,&nv,&beta,&breakdown);
270: DSRestoreArray(eps->ds,DS_MAT_A,&S);
271: STRestoreOperator(eps->st,&Op);
272: DSSetDimensions(eps->ds,nv,0,eps->nconv,eps->nconv+l);
273: if (l==0) {
274: DSSetState(eps->ds,DS_STATE_INTERMEDIATE);
275: } else {
276: DSSetState(eps->ds,DS_STATE_RAW);
277: }
278: BVSetActiveColumns(eps->V,eps->nconv,nv);
280: /* Compute translation of Krylov decomposition if harmonic extraction used */
281: if (harmonic) {
282: DSTranslateHarmonic(eps->ds,eps->target,beta,PETSC_FALSE,g,&gamma);
283: }
285: /* Solve projected problem */
286: DSSolve(eps->ds,eps->eigr,eps->eigi);
287: if (eps->arbitrary) {
288: EPSGetArbitraryValues(eps,eps->rr,eps->ri);
289: j=1;
290: }
291: DSSort(eps->ds,eps->eigr,eps->eigi,eps->rr,eps->ri,pj);
292: DSSynchronize(eps->ds,eps->eigr,eps->eigi);
294: /* Check convergence */
295: EPSKrylovConvergence(eps,PETSC_FALSE,eps->nconv,nv-eps->nconv,beta,0.0,gamma,&k);
296: (*eps->stopping)(eps,eps->its,eps->max_it,k,eps->nev,&eps->reason,eps->stoppingctx);
297: nconv = k;
299: /* Update l */
300: if (eps->reason != EPS_CONVERGED_ITERATING || breakdown || k==nv) l = 0;
301: else {
302: l = PetscMax(1,(PetscInt)((nv-k)*ctx->keep));
303: #if !defined(PETSC_USE_COMPLEX)
304: DSGetArray(eps->ds,DS_MAT_A,&S);
305: if (S[k+l+(k+l-1)*ld] != 0.0) {
306: if (k+l<nv-1) l = l+1;
307: else l = l-1;
308: }
309: DSRestoreArray(eps->ds,DS_MAT_A,&S);
310: #endif
311: }
312: if (!ctx->lock && l>0) { l += k; k = 0; } /* non-locking variant: reset no. of converged pairs */
314: if (eps->reason == EPS_CONVERGED_ITERATING) {
315: if (breakdown || k==nv) {
316: /* Start a new Arnoldi factorization */
317: PetscInfo2(eps,"Breakdown in Krylov-Schur method (it=%D norm=%g)\n",eps->its,(double)beta);
318: if (k<eps->nev) {
319: EPSGetStartVector(eps,k,&breakdown);
320: if (breakdown) {
321: eps->reason = EPS_DIVERGED_BREAKDOWN;
322: PetscInfo(eps,"Unable to generate more start vectors\n");
323: }
324: }
325: } else {
326: /* Undo translation of Krylov decomposition */
327: if (harmonic) {
328: DSSetDimensions(eps->ds,nv,0,k,l);
329: DSTranslateHarmonic(eps->ds,0.0,beta,PETSC_TRUE,g,&gamma);
330: /* gamma u^ = u - U*g~ */
331: BVSetActiveColumns(eps->V,0,nv);
332: BVMultColumn(eps->V,-1.0,1.0,nv,g);
333: BVScaleColumn(eps->V,nv,1.0/gamma);
334: BVSetActiveColumns(eps->V,eps->nconv,nv);
335: }
336: /* Prepare the Rayleigh quotient for restart */
337: DSGetArray(eps->ds,DS_MAT_A,&S);
338: DSGetArray(eps->ds,DS_MAT_Q,&Q);
339: for (i=k;i<k+l;i++) {
340: S[k+l+i*ld] = Q[nv-1+i*ld]*beta*gamma;
341: }
342: DSRestoreArray(eps->ds,DS_MAT_A,&S);
343: DSRestoreArray(eps->ds,DS_MAT_Q,&Q);
344: }
345: }
346: /* Update the corresponding vectors V(:,idx) = V*Q(:,idx) */
347: DSGetMat(eps->ds,DS_MAT_Q,&U);
348: BVMultInPlace(eps->V,U,eps->nconv,k+l);
349: MatDestroy(&U);
351: if (eps->reason == EPS_CONVERGED_ITERATING && !breakdown) {
352: BVCopyColumn(eps->V,nv,k+l);
353: }
354: eps->nconv = k;
355: EPSMonitor(eps,eps->its,nconv,eps->eigr,eps->eigi,eps->errest,nv);
356: }
358: if (harmonic) { PetscFree(g); }
359: /* truncate Schur decomposition and change the state to raw so that
360: DSVectors() computes eigenvectors from scratch */
361: DSSetDimensions(eps->ds,eps->nconv,0,0,0);
362: DSSetState(eps->ds,DS_STATE_RAW);
363: return(0);
364: }
366: static PetscErrorCode EPSKrylovSchurSetRestart_KrylovSchur(EPS eps,PetscReal keep)367: {
368: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
371: if (keep==PETSC_DEFAULT) ctx->keep = 0.5;
372: else {
373: if (keep<0.1 || keep>0.9) SETERRQ1(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The keep argument %g must be in the range [0.1,0.9]",keep);
374: ctx->keep = keep;
375: }
376: return(0);
377: }
379: /*@
380: EPSKrylovSchurSetRestart - Sets the restart parameter for the Krylov-Schur
381: method, in particular the proportion of basis vectors that must be kept
382: after restart.
384: Logically Collective on eps
386: Input Parameters:
387: + eps - the eigenproblem solver context
388: - keep - the number of vectors to be kept at restart
390: Options Database Key:
391: . -eps_krylovschur_restart - Sets the restart parameter
393: Notes:
394: Allowed values are in the range [0.1,0.9]. The default is 0.5.
396: Level: advanced
398: .seealso: EPSKrylovSchurGetRestart()
399: @*/
400: PetscErrorCode EPSKrylovSchurSetRestart(EPS eps,PetscReal keep)401: {
407: PetscTryMethod(eps,"EPSKrylovSchurSetRestart_C",(EPS,PetscReal),(eps,keep));
408: return(0);
409: }
411: static PetscErrorCode EPSKrylovSchurGetRestart_KrylovSchur(EPS eps,PetscReal *keep)412: {
413: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
416: *keep = ctx->keep;
417: return(0);
418: }
420: /*@
421: EPSKrylovSchurGetRestart - Gets the restart parameter used in the
422: Krylov-Schur method.
424: Not Collective
426: Input Parameter:
427: . eps - the eigenproblem solver context
429: Output Parameter:
430: . keep - the restart parameter
432: Level: advanced
434: .seealso: EPSKrylovSchurSetRestart()
435: @*/
436: PetscErrorCode EPSKrylovSchurGetRestart(EPS eps,PetscReal *keep)437: {
443: PetscUseMethod(eps,"EPSKrylovSchurGetRestart_C",(EPS,PetscReal*),(eps,keep));
444: return(0);
445: }
447: static PetscErrorCode EPSKrylovSchurSetLocking_KrylovSchur(EPS eps,PetscBool lock)448: {
449: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
452: ctx->lock = lock;
453: return(0);
454: }
456: /*@
457: EPSKrylovSchurSetLocking - Choose between locking and non-locking variants of
458: the Krylov-Schur method.
460: Logically Collective on eps
462: Input Parameters:
463: + eps - the eigenproblem solver context
464: - lock - true if the locking variant must be selected
466: Options Database Key:
467: . -eps_krylovschur_locking - Sets the locking flag
469: Notes:
470: The default is to lock converged eigenpairs when the method restarts.
471: This behaviour can be changed so that all directions are kept in the
472: working subspace even if already converged to working accuracy (the
473: non-locking variant).
475: Level: advanced
477: .seealso: EPSKrylovSchurGetLocking()
478: @*/
479: PetscErrorCode EPSKrylovSchurSetLocking(EPS eps,PetscBool lock)480: {
486: PetscTryMethod(eps,"EPSKrylovSchurSetLocking_C",(EPS,PetscBool),(eps,lock));
487: return(0);
488: }
490: static PetscErrorCode EPSKrylovSchurGetLocking_KrylovSchur(EPS eps,PetscBool *lock)491: {
492: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
495: *lock = ctx->lock;
496: return(0);
497: }
499: /*@
500: EPSKrylovSchurGetLocking - Gets the locking flag used in the Krylov-Schur
501: method.
503: Not Collective
505: Input Parameter:
506: . eps - the eigenproblem solver context
508: Output Parameter:
509: . lock - the locking flag
511: Level: advanced
513: .seealso: EPSKrylovSchurSetLocking()
514: @*/
515: PetscErrorCode EPSKrylovSchurGetLocking(EPS eps,PetscBool *lock)516: {
522: PetscUseMethod(eps,"EPSKrylovSchurGetLocking_C",(EPS,PetscBool*),(eps,lock));
523: return(0);
524: }
526: static PetscErrorCode EPSKrylovSchurSetPartitions_KrylovSchur(EPS eps,PetscInt npart)527: {
528: PetscErrorCode ierr;
529: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
530: PetscMPIInt size;
533: if (ctx->npart!=npart) {
534: if (ctx->commset) { PetscSubcommDestroy(&ctx->subc); }
535: EPSDestroy(&ctx->eps);
536: }
537: if (npart == PETSC_DEFAULT || npart == PETSC_DECIDE) {
538: ctx->npart = 1;
539: } else {
540: MPI_Comm_size(PetscObjectComm((PetscObject)eps),&size);
541: if (npart<1 || npart>size) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of npart");
542: ctx->npart = npart;
543: }
544: eps->state = EPS_STATE_INITIAL;
545: return(0);
546: }
548: /*@
549: EPSKrylovSchurSetPartitions - Sets the number of partitions for the
550: case of doing spectrum slicing for a computational interval with the
551: communicator split in several sub-communicators.
553: Logically Collective on eps
555: Input Parameters:
556: + eps - the eigenproblem solver context
557: - npart - number of partitions
559: Options Database Key:
560: . -eps_krylovschur_partitions <npart> - Sets the number of partitions
562: Notes:
563: By default, npart=1 so all processes in the communicator participate in
564: the processing of the whole interval. If npart>1 then the interval is
565: divided into npart subintervals, each of them being processed by a
566: subset of processes.
568: The interval is split proportionally unless the separation points are
569: specified with EPSKrylovSchurSetSubintervals().
571: Level: advanced
573: .seealso: EPSKrylovSchurSetSubintervals(), EPSSetInterval()
574: @*/
575: PetscErrorCode EPSKrylovSchurSetPartitions(EPS eps,PetscInt npart)576: {
582: PetscTryMethod(eps,"EPSKrylovSchurSetPartitions_C",(EPS,PetscInt),(eps,npart));
583: return(0);
584: }
586: static PetscErrorCode EPSKrylovSchurGetPartitions_KrylovSchur(EPS eps,PetscInt *npart)587: {
588: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
591: *npart = ctx->npart;
592: return(0);
593: }
595: /*@
596: EPSKrylovSchurGetPartitions - Gets the number of partitions of the
597: communicator in case of spectrum slicing.
599: Not Collective
601: Input Parameter:
602: . eps - the eigenproblem solver context
604: Output Parameter:
605: . npart - number of partitions
607: Level: advanced
609: .seealso: EPSKrylovSchurSetPartitions()
610: @*/
611: PetscErrorCode EPSKrylovSchurGetPartitions(EPS eps,PetscInt *npart)612: {
618: PetscUseMethod(eps,"EPSKrylovSchurGetPartitions_C",(EPS,PetscInt*),(eps,npart));
619: return(0);
620: }
622: static PetscErrorCode EPSKrylovSchurSetDetectZeros_KrylovSchur(EPS eps,PetscBool detect)623: {
624: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
627: ctx->detect = detect;
628: eps->state = EPS_STATE_INITIAL;
629: return(0);
630: }
632: /*@
633: EPSKrylovSchurSetDetectZeros - Sets a flag to enforce detection of
634: zeros during the factorizations throughout the spectrum slicing computation.
636: Logically Collective on eps
638: Input Parameters:
639: + eps - the eigenproblem solver context
640: - detect - check for zeros
642: Options Database Key:
643: . -eps_krylovschur_detect_zeros - Check for zeros; this takes an optional
644: bool value (0/1/no/yes/true/false)
646: Notes:
647: A zero in the factorization indicates that a shift coincides with an eigenvalue.
649: This flag is turned off by default, and may be necessary in some cases,
650: especially when several partitions are being used. This feature currently
651: requires an external package for factorizations with support for zero
652: detection, e.g. MUMPS.
654: Level: advanced
656: .seealso: EPSKrylovSchurSetPartitions(), EPSSetInterval()
657: @*/
658: PetscErrorCode EPSKrylovSchurSetDetectZeros(EPS eps,PetscBool detect)659: {
665: PetscTryMethod(eps,"EPSKrylovSchurSetDetectZeros_C",(EPS,PetscBool),(eps,detect));
666: return(0);
667: }
669: static PetscErrorCode EPSKrylovSchurGetDetectZeros_KrylovSchur(EPS eps,PetscBool *detect)670: {
671: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
674: *detect = ctx->detect;
675: return(0);
676: }
678: /*@
679: EPSKrylovSchurGetDetectZeros - Gets the flag that enforces zero detection
680: in spectrum slicing.
682: Not Collective
684: Input Parameter:
685: . eps - the eigenproblem solver context
687: Output Parameter:
688: . detect - whether zeros detection is enforced during factorizations
690: Level: advanced
692: .seealso: EPSKrylovSchurSetDetectZeros()
693: @*/
694: PetscErrorCode EPSKrylovSchurGetDetectZeros(EPS eps,PetscBool *detect)695: {
701: PetscUseMethod(eps,"EPSKrylovSchurGetDetectZeros_C",(EPS,PetscBool*),(eps,detect));
702: return(0);
703: }
705: static PetscErrorCode EPSKrylovSchurSetDimensions_KrylovSchur(EPS eps,PetscInt nev,PetscInt ncv,PetscInt mpd)706: {
707: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
710: if (nev<1) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of nev. Must be > 0");
711: ctx->nev = nev;
712: if (ncv == PETSC_DECIDE || ncv == PETSC_DEFAULT) {
713: ctx->ncv = 0;
714: } else {
715: if (ncv<1) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of ncv. Must be > 0");
716: ctx->ncv = ncv;
717: }
718: if (mpd == PETSC_DECIDE || mpd == PETSC_DEFAULT) {
719: ctx->mpd = 0;
720: } else {
721: if (mpd<1) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of mpd. Must be > 0");
722: ctx->mpd = mpd;
723: }
724: eps->state = EPS_STATE_INITIAL;
725: return(0);
726: }
728: /*@
729: EPSKrylovSchurSetDimensions - Sets the dimensions used for each subsolve
730: step in case of doing spectrum slicing for a computational interval.
731: The meaning of the parameters is the same as in EPSSetDimensions().
733: Logically Collective on eps
735: Input Parameters:
736: + eps - the eigenproblem solver context
737: . nev - number of eigenvalues to compute
738: . ncv - the maximum dimension of the subspace to be used by the subsolve
739: - mpd - the maximum dimension allowed for the projected problem
741: Options Database Key:
742: + -eps_krylovschur_nev <nev> - Sets the number of eigenvalues
743: . -eps_krylovschur_ncv <ncv> - Sets the dimension of the subspace
744: - -eps_krylovschur_mpd <mpd> - Sets the maximum projected dimension
746: Level: advanced
748: .seealso: EPSKrylovSchurGetDimensions(), EPSSetDimensions(), EPSSetInterval()
749: @*/
750: PetscErrorCode EPSKrylovSchurSetDimensions(EPS eps,PetscInt nev,PetscInt ncv,PetscInt mpd)751: {
759: PetscTryMethod(eps,"EPSKrylovSchurSetDimensions_C",(EPS,PetscInt,PetscInt,PetscInt),(eps,nev,ncv,mpd));
760: return(0);
761: }
763: static PetscErrorCode EPSKrylovSchurGetDimensions_KrylovSchur(EPS eps,PetscInt *nev,PetscInt *ncv,PetscInt *mpd)764: {
765: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
768: if (nev) *nev = ctx->nev;
769: if (ncv) *ncv = ctx->ncv;
770: if (mpd) *mpd = ctx->mpd;
771: return(0);
772: }
774: /*@
775: EPSKrylovSchurGetDimensions - Gets the dimensions used for each subsolve
776: step in case of doing spectrum slicing for a computational interval.
778: Not Collective
780: Input Parameter:
781: . eps - the eigenproblem solver context
783: Output Parameters:
784: + nev - number of eigenvalues to compute
785: . ncv - the maximum dimension of the subspace to be used by the subsolve
786: - mpd - the maximum dimension allowed for the projected problem
788: Level: advanced
790: .seealso: EPSKrylovSchurSetDimensions()
791: @*/
792: PetscErrorCode EPSKrylovSchurGetDimensions(EPS eps,PetscInt *nev,PetscInt *ncv,PetscInt *mpd)793: {
798: PetscUseMethod(eps,"EPSKrylovSchurGetDimensions_C",(EPS,PetscInt*,PetscInt*,PetscInt*),(eps,nev,ncv,mpd));
799: return(0);
800: }
802: static PetscErrorCode EPSKrylovSchurSetSubintervals_KrylovSchur(EPS eps,PetscReal* subint)803: {
804: PetscErrorCode ierr;
805: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
806: PetscInt i;
809: if (subint[0]!=eps->inta || subint[ctx->npart]!=eps->intb) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"First and last values must match the endpoints of EPSSetInterval()");
810: for (i=0;i<ctx->npart;i++) if (subint[i]>subint[i+1]) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"Array must contain values in ascending order");
811: if (ctx->subintervals) { PetscFree(ctx->subintervals); }
812: PetscMalloc1(ctx->npart+1,&ctx->subintervals);
813: for (i=0;i<ctx->npart+1;i++) ctx->subintervals[i] = subint[i];
814: ctx->subintset = PETSC_TRUE;
815: eps->state = EPS_STATE_INITIAL;
816: return(0);
817: }
819: /*@C
820: EPSKrylovSchurSetSubintervals - Sets the points that delimit the
821: subintervals to be used in spectrum slicing with several partitions.
823: Logically Collective on eps
825: Input Parameters:
826: + eps - the eigenproblem solver context
827: - subint - array of real values specifying subintervals
829: Notes:
830: This function must be called after EPSKrylovSchurSetPartitions(). For npart
831: partitions, the argument subint must contain npart+1 real values sorted in
832: ascending order: subint_0, subint_1, ..., subint_npart, where the first
833: and last values must coincide with the interval endpoints set with
834: EPSSetInterval().
836: The subintervals are then defined by two consecutive points: [subint_0,subint_1],
837: [subint_1,subint_2], and so on.
839: Level: advanced
841: .seealso: EPSKrylovSchurSetPartitions(), EPSKrylovSchurGetSubintervals(), EPSSetInterval()
842: @*/
843: PetscErrorCode EPSKrylovSchurSetSubintervals(EPS eps,PetscReal *subint)844: {
849: PetscTryMethod(eps,"EPSKrylovSchurSetSubintervals_C",(EPS,PetscReal*),(eps,subint));
850: return(0);
851: }
853: static PetscErrorCode EPSKrylovSchurGetSubintervals_KrylovSchur(EPS eps,PetscReal **subint)854: {
855: PetscErrorCode ierr;
856: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
857: PetscInt i;
860: if (!ctx->subintset) {
861: if (!eps->state) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
862: if (!ctx->sr) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
863: }
864: PetscMalloc1(ctx->npart+1,subint);
865: for (i=0;i<=ctx->npart;i++) (*subint)[i] = ctx->subintervals[i];
866: return(0);
867: }
869: /*@C
870: EPSKrylovSchurGetSubintervals - Returns the points that delimit the
871: subintervals used in spectrum slicing with several partitions.
873: Logically Collective on eps
875: Input Parameter:
876: . eps - the eigenproblem solver context
878: Output Parameter:
879: . subint - array of real values specifying subintervals
881: Notes:
882: If the user passed values with EPSKrylovSchurSetSubintervals(), then the
883: same values are returned. Otherwise, the values computed internally are
884: obtained.
886: This function is only available for spectrum slicing runs.
888: The returned array has length npart+1 (see EPSKrylovSchurGetPartitions())
889: and should be freed by the user.
891: Fortran Notes:
892: The calling sequence from Fortran is
893: .vb
894: EPSKrylovSchurGetSubintervals(eps,subint,ierr)
895: double precision subint(npart+1) output
896: .ve
898: Level: advanced
900: .seealso: EPSKrylovSchurSetSubintervals(), EPSKrylovSchurGetPartitions(), EPSSetInterval()
901: @*/
902: PetscErrorCode EPSKrylovSchurGetSubintervals(EPS eps,PetscReal **subint)903: {
909: PetscUseMethod(eps,"EPSKrylovSchurGetSubintervals_C",(EPS,PetscReal**),(eps,subint));
910: return(0);
911: }
913: static PetscErrorCode EPSKrylovSchurGetInertias_KrylovSchur(EPS eps,PetscInt *n,PetscReal **shifts,PetscInt **inertias)914: {
915: PetscErrorCode ierr;
916: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
917: PetscInt i,numsh;
918: EPS_SR sr = ctx->sr;
921: if (!eps->state) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
922: if (!ctx->sr) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
923: switch (eps->state) {
924: case EPS_STATE_INITIAL:
925: break;
926: case EPS_STATE_SETUP:
927: numsh = ctx->npart+1;
928: if (n) *n = numsh;
929: if (shifts) {
930: PetscMalloc1(numsh,shifts);
931: (*shifts)[0] = eps->inta;
932: if (ctx->npart==1) (*shifts)[1] = eps->intb;
933: else for (i=1;i<numsh;i++) (*shifts)[i] = ctx->subintervals[i];
934: }
935: if (inertias) {
936: PetscMalloc1(numsh,inertias);
937: (*inertias)[0] = (sr->dir==1)?sr->inertia0:sr->inertia1;
938: if (ctx->npart==1) (*inertias)[1] = (sr->dir==1)?sr->inertia1:sr->inertia0;
939: else for (i=1;i<numsh;i++) (*inertias)[i] = (*inertias)[i-1]+ctx->nconv_loc[i-1];
940: }
941: break;
942: case EPS_STATE_SOLVED:
943: case EPS_STATE_EIGENVECTORS:
944: numsh = ctx->nshifts;
945: if (n) *n = numsh;
946: if (shifts) {
947: PetscMalloc1(numsh,shifts);
948: for (i=0;i<numsh;i++) (*shifts)[i] = ctx->shifts[i];
949: }
950: if (inertias) {
951: PetscMalloc1(numsh,inertias);
952: for (i=0;i<numsh;i++) (*inertias)[i] = ctx->inertias[i];
953: }
954: break;
955: }
956: return(0);
957: }
959: /*@C
960: EPSKrylovSchurGetInertias - Gets the values of the shifts and their
961: corresponding inertias in case of doing spectrum slicing for a
962: computational interval.
964: Not Collective
966: Input Parameter:
967: . eps - the eigenproblem solver context
969: Output Parameters:
970: + n - number of shifts, including the endpoints of the interval
971: . shifts - the values of the shifts used internally in the solver
972: - inertias - the values of the inertia in each shift
974: Notes:
975: If called after EPSSolve(), all shifts used internally by the solver are
976: returned (including both endpoints and any intermediate ones). If called
977: before EPSSolve() and after EPSSetUp() then only the information of the
978: endpoints of subintervals is available.
980: This function is only available for spectrum slicing runs.
982: The returned arrays should be freed by the user. Can pass NULL in any of
983: the two arrays if not required.
985: Fortran Notes:
986: The calling sequence from Fortran is
987: .vb
988: EPSKrylovSchurGetInertias(eps,n,shifts,inertias,ierr)
989: integer n
990: double precision shifts(*)
991: integer inertias(*)
992: .ve
993: The arrays should be at least of length n. The value of n can be determined
994: by an initial call
995: .vb
996: EPSKrylovSchurGetInertias(eps,n,PETSC_NULL_REAL,PETSC_NULL_INTEGER,ierr)
997: .ve
999: Level: advanced
1001: .seealso: EPSSetInterval(), EPSKrylovSchurSetSubintervals()
1002: @*/
1003: PetscErrorCode EPSKrylovSchurGetInertias(EPS eps,PetscInt *n,PetscReal **shifts,PetscInt **inertias)1004: {
1010: PetscUseMethod(eps,"EPSKrylovSchurGetInertias_C",(EPS,PetscInt*,PetscReal**,PetscInt**),(eps,n,shifts,inertias));
1011: return(0);
1012: }
1014: static PetscErrorCode EPSKrylovSchurGetSubcommInfo_KrylovSchur(EPS eps,PetscInt *k,PetscInt *n,Vec *v)1015: {
1016: PetscErrorCode ierr;
1017: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
1018: EPS_SR sr = ((EPS_KRYLOVSCHUR*)ctx->eps->data)->sr;
1021: if (!eps->state) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
1022: if (!ctx->sr) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
1023: if (k) *k = (ctx->npart==1)? 0: ctx->subc->color;
1024: if (n) *n = sr->numEigs;
1025: if (v) {
1026: BVCreateVec(sr->V,v);
1027: }
1028: return(0);
1029: }
1031: /*@C
1032: EPSKrylovSchurGetSubcommInfo - Gets information related to the case of
1033: doing spectrum slicing for a computational interval with multiple
1034: communicators.
1036: Collective on the subcommunicator (if v is given)
1038: Input Parameter:
1039: . eps - the eigenproblem solver context
1041: Output Parameters:
1042: + k - index of the subinterval for the calling process
1043: . n - number of eigenvalues found in the k-th subinterval
1044: - v - a vector owned by processes in the subcommunicator with dimensions
1045: compatible for locally computed eigenvectors (or NULL)
1047: Notes:
1048: This function is only available for spectrum slicing runs.
1050: The returned Vec should be destroyed by the user.
1052: Level: advanced
1054: .seealso: EPSSetInterval(), EPSKrylovSchurSetPartitions(), EPSKrylovSchurGetSubcommPairs()
1055: @*/
1056: PetscErrorCode EPSKrylovSchurGetSubcommInfo(EPS eps,PetscInt *k,PetscInt *n,Vec *v)1057: {
1062: PetscUseMethod(eps,"EPSKrylovSchurGetSubcommInfo_C",(EPS,PetscInt*,PetscInt*,Vec*),(eps,k,n,v));
1063: return(0);
1064: }
1066: static PetscErrorCode EPSKrylovSchurGetSubcommPairs_KrylovSchur(EPS eps,PetscInt i,PetscScalar *eig,Vec v)1067: {
1068: PetscErrorCode ierr;
1069: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
1070: EPS_SR sr = ((EPS_KRYLOVSCHUR*)ctx->eps->data)->sr;
1073: EPSCheckSolved(eps,1);
1074: if (!ctx->sr) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
1075: if (i<0 || i>=sr->numEigs) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
1076: if (eig) *eig = sr->eigr[sr->perm[i]];
1077: if (v) { BVCopyVec(sr->V,sr->perm[i],v); }
1078: return(0);
1079: }
1081: /*@
1082: EPSKrylovSchurGetSubcommPairs - Gets the i-th eigenpair stored
1083: internally in the subcommunicator to which the calling process belongs.
1085: Collective on the subcommunicator (if v is given)
1087: Input Parameter:
1088: + eps - the eigenproblem solver context
1089: - i - index of the solution
1091: Output Parameters:
1092: + eig - the eigenvalue
1093: - v - the eigenvector
1095: Notes:
1096: It is allowed to pass NULL for v if the eigenvector is not required.
1097: Otherwise, the caller must provide a valid Vec objects, i.e.,
1098: it must be created by the calling program with EPSKrylovSchurGetSubcommInfo().
1100: The index i should be a value between 0 and n-1, where n is the number of
1101: vectors in the local subinterval, see EPSKrylovSchurGetSubcommInfo().
1103: Level: advanced
1105: .seealso: EPSSetInterval(), EPSKrylovSchurSetPartitions(), EPSKrylovSchurGetSubcommInfo(), EPSKrylovSchurGetSubcommMats()
1106: @*/
1107: PetscErrorCode EPSKrylovSchurGetSubcommPairs(EPS eps,PetscInt i,PetscScalar *eig,Vec v)1108: {
1114: PetscUseMethod(eps,"EPSKrylovSchurGetSubcommPairs_C",(EPS,PetscInt,PetscScalar*,Vec),(eps,i,eig,v));
1115: return(0);
1116: }
1118: static PetscErrorCode EPSKrylovSchurGetSubcommMats_KrylovSchur(EPS eps,Mat *A,Mat *B)1119: {
1120: PetscErrorCode ierr;
1121: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
1124: if (!ctx->sr) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
1125: if (!eps->state) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
1126: EPSGetOperators(ctx->eps,A,B);
1127: return(0);
1128: }
1130: /*@C
1131: EPSKrylovSchurGetSubcommMats - Gets the eigenproblem matrices stored
1132: internally in the subcommunicator to which the calling process belongs.
1134: Collective on the subcommunicator
1136: Input Parameter:
1137: . eps - the eigenproblem solver context
1139: Output Parameters:
1140: + A - the matrix associated with the eigensystem
1141: - B - the second matrix in the case of generalized eigenproblems
1143: Notes:
1144: This is the analog of EPSGetOperators(), but returns the matrices distributed
1145: differently (in the subcommunicator rather than in the parent communicator).
1147: These matrices should not be modified by the user.
1149: Level: advanced
1151: .seealso: EPSSetInterval(), EPSKrylovSchurSetPartitions(), EPSKrylovSchurGetSubcommInfo()
1152: @*/
1153: PetscErrorCode EPSKrylovSchurGetSubcommMats(EPS eps,Mat *A,Mat *B)1154: {
1159: PetscTryMethod(eps,"EPSKrylovSchurGetSubcommMats_C",(EPS,Mat*,Mat*),(eps,A,B));
1160: return(0);
1161: }
1163: static PetscErrorCode EPSKrylovSchurUpdateSubcommMats_KrylovSchur(EPS eps,PetscScalar a,PetscScalar ap,Mat Au,PetscScalar b,PetscScalar bp, Mat Bu,MatStructure str,PetscBool globalup)1164: {
1165: PetscErrorCode ierr;
1166: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data,*subctx;
1167: Mat A,B=NULL,Ag,Bg=NULL;
1168: PetscBool reuse=PETSC_TRUE;
1171: if (!ctx->sr) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Only available in interval computations, see EPSSetInterval()");
1172: if (!eps->state) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must call EPSSetUp() first");
1173: EPSGetOperators(eps,&Ag,&Bg);
1174: EPSGetOperators(ctx->eps,&A,&B);
1176: MatScale(A,a);
1177: if (Au) {
1178: MatAXPY(A,ap,Au,str);
1179: }
1180: if (B) MatScale(B,b);
1181: if (Bu) {
1182: MatAXPY(B,bp,Bu,str);
1183: }
1184: EPSSetOperators(ctx->eps,A,B);
1186: /* Update stored matrix state */
1187: subctx = (EPS_KRYLOVSCHUR*)ctx->eps->data;
1188: PetscObjectStateGet((PetscObject)A,&subctx->Astate);
1189: if (B) { PetscObjectStateGet((PetscObject)B,&subctx->Bstate); }
1191: /* Update matrices in the parent communicator if requested by user */
1192: if (globalup) {
1193: if (ctx->npart>1) {
1194: if (!ctx->isrow) {
1195: MatGetOwnershipIS(Ag,&ctx->isrow,&ctx->iscol);
1196: reuse = PETSC_FALSE;
1197: }
1198: if (str==DIFFERENT_NONZERO_PATTERN) reuse = PETSC_FALSE;
1199: if (ctx->submata && !reuse) {
1200: MatDestroyMatrices(1,&ctx->submata);
1201: }
1202: MatCreateSubMatrices(A,1,&ctx->isrow,&ctx->iscol,(reuse)?MAT_REUSE_MATRIX:MAT_INITIAL_MATRIX,&ctx->submata);
1203: MatCreateMPIMatConcatenateSeqMat(((PetscObject)Ag)->comm,ctx->submata[0],PETSC_DECIDE,MAT_REUSE_MATRIX,&Ag);
1204: if (B) {
1205: if (ctx->submatb && !reuse) {
1206: MatDestroyMatrices(1,&ctx->submatb);
1207: }
1208: MatCreateSubMatrices(B,1,&ctx->isrow,&ctx->iscol,(reuse)?MAT_REUSE_MATRIX:MAT_INITIAL_MATRIX,&ctx->submatb);
1209: MatCreateMPIMatConcatenateSeqMat(((PetscObject)Bg)->comm,ctx->submatb[0],PETSC_DECIDE,MAT_REUSE_MATRIX,&Bg);
1210: }
1211: }
1212: PetscObjectStateGet((PetscObject)Ag,&ctx->Astate);
1213: if (Bg) { PetscObjectStateGet((PetscObject)Bg,&ctx->Bstate); }
1214: }
1215: EPSSetOperators(eps,Ag,Bg);
1216: return(0);
1217: }
1219: /*@
1220: EPSKrylovSchurUpdateSubcommMats - Update the eigenproblem matrices stored
1221: internally in the subcommunicator to which the calling process belongs.
1223: Collective on eps
1225: Input Parameters:
1226: + eps - the eigenproblem solver context
1227: . s - scalar that multiplies the existing A matrix
1228: . a - scalar used in the axpy operation on A
1229: . Au - matrix used in the axpy operation on A
1230: . t - scalar that multiplies the existing B matrix
1231: . b - scalar used in the axpy operation on B
1232: . Bu - matrix used in the axpy operation on B
1233: . str - structure flag
1234: - globalup - flag indicating if global matrices must be updated
1236: Notes:
1237: This function modifies the eigenproblem matrices at the subcommunicator level,
1238: and optionally updates the global matrices in the parent communicator. The updates
1239: are expressed as A <-- s*A + a*Au, B <-- t*B + b*Bu.
1241: It is possible to update one of the matrices, or both.
1243: The matrices Au and Bu must be equal in all subcommunicators.
1245: The str flag is passed to the MatAXPY() operations to perform the updates.
1247: If globalup is true, communication is carried out to reconstruct the updated
1248: matrices in the parent communicator. The user must be warned that if global
1249: matrices are not in sync with subcommunicator matrices, the errors computed
1250: by EPSComputeError() will be wrong even if the computed solution is correct
1251: (the synchronization may be done only once at the end).
1253: Level: advanced
1255: .seealso: EPSSetInterval(), EPSKrylovSchurSetPartitions(), EPSKrylovSchurGetSubcommMats()
1256: @*/
1257: PetscErrorCode EPSKrylovSchurUpdateSubcommMats(EPS eps,PetscScalar s,PetscScalar a,Mat Au,PetscScalar t,PetscScalar b,Mat Bu,MatStructure str,PetscBool globalup)1258: {
1271: PetscTryMethod(eps,"EPSKrylovSchurUpdateSubcommMats_C",(EPS,PetscScalar,PetscScalar,Mat,PetscScalar,PetscScalar,Mat,MatStructure,PetscBool),(eps,s,a,Au,t,b,Bu,str,globalup));
1272: return(0);
1273: }
1275: PetscErrorCode EPSSetFromOptions_KrylovSchur(PetscOptionItems *PetscOptionsObject,EPS eps)1276: {
1277: PetscErrorCode ierr;
1278: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
1279: PetscBool flg,lock,b,f1,f2,f3;
1280: PetscReal keep;
1281: PetscInt i,j,k;
1284: PetscOptionsHead(PetscOptionsObject,"EPS Krylov-Schur Options");
1286: PetscOptionsReal("-eps_krylovschur_restart","Proportion of vectors kept after restart","EPSKrylovSchurSetRestart",0.5,&keep,&flg);
1287: if (flg) { EPSKrylovSchurSetRestart(eps,keep); }
1289: PetscOptionsBool("-eps_krylovschur_locking","Choose between locking and non-locking variants","EPSKrylovSchurSetLocking",PETSC_TRUE,&lock,&flg);
1290: if (flg) { EPSKrylovSchurSetLocking(eps,lock); }
1292: i = ctx->npart;
1293: PetscOptionsInt("-eps_krylovschur_partitions","Number of partitions of the communicator for spectrum slicing","EPSKrylovSchurSetPartitions",ctx->npart,&i,&flg);
1294: if (flg) { EPSKrylovSchurSetPartitions(eps,i); }
1296: b = ctx->detect;
1297: PetscOptionsBool("-eps_krylovschur_detect_zeros","Check zeros during factorizations at subinterval boundaries","EPSKrylovSchurSetDetectZeros",ctx->detect,&b,&flg);
1298: if (flg) { EPSKrylovSchurSetDetectZeros(eps,b); }
1300: i = 1;
1301: j = k = PETSC_DECIDE;
1302: PetscOptionsInt("-eps_krylovschur_nev","Number of eigenvalues to compute in each subsolve (only for spectrum slicing)","EPSKrylovSchurSetDimensions",40,&i,&f1);
1303: PetscOptionsInt("-eps_krylovschur_ncv","Number of basis vectors in each subsolve (only for spectrum slicing)","EPSKrylovSchurSetDimensions",80,&j,&f2);
1304: PetscOptionsInt("-eps_krylovschur_mpd","Maximum dimension of projected problem in each subsolve (only for spectrum slicing)","EPSKrylovSchurSetDimensions",80,&k,&f3);
1305: if (f1 || f2 || f3) { EPSKrylovSchurSetDimensions(eps,i,j,k); }
1307: PetscOptionsTail();
1308: return(0);
1309: }
1311: PetscErrorCode EPSView_KrylovSchur(EPS eps,PetscViewer viewer)1312: {
1313: PetscErrorCode ierr;
1314: EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
1315: PetscBool isascii,isfilt;
1318: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
1319: if (isascii) {
1320: PetscViewerASCIIPrintf(viewer," %d%% of basis vectors kept after restart\n",(int)(100*ctx->keep));
1321: PetscViewerASCIIPrintf(viewer," using the %slocking variant\n",ctx->lock?"":"non-");
1322: if (eps->which==EPS_ALL) {
1323: PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt);
1324: if (isfilt) {
1325: PetscViewerASCIIPrintf(viewer," using filtering to extract all eigenvalues in an interval\n");
1326: } else {
1327: PetscViewerASCIIPrintf(viewer," doing spectrum slicing with nev=%D, ncv=%D, mpd=%D\n",ctx->nev,ctx->ncv,ctx->mpd);
1328: if (ctx->npart>1) {
1329: PetscViewerASCIIPrintf(viewer," multi-communicator spectrum slicing with %D partitions\n",ctx->npart);
1330: if (ctx->detect) { PetscViewerASCIIPrintf(viewer," detecting zeros when factorizing at subinterval boundaries\n"); }
1331: }
1332: }
1333: }
1334: }
1335: return(0);
1336: }
1338: PetscErrorCode EPSDestroy_KrylovSchur(EPS eps)1339: {
1343: PetscFree(eps->data);
1344: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetRestart_C",NULL);
1345: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetRestart_C",NULL);
1346: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetLocking_C",NULL);
1347: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetLocking_C",NULL);
1348: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetPartitions_C",NULL);
1349: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetPartitions_C",NULL);
1350: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetDetectZeros_C",NULL);
1351: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetDetectZeros_C",NULL);
1352: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetDimensions_C",NULL);
1353: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetDimensions_C",NULL);
1354: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetSubintervals_C",NULL);
1355: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubintervals_C",NULL);
1356: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetInertias_C",NULL);
1357: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommInfo_C",NULL);
1358: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommPairs_C",NULL);
1359: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommMats_C",NULL);
1360: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurUpdateSubcommMats_C",NULL);
1361: return(0);
1362: }
1364: PetscErrorCode EPSReset_KrylovSchur(EPS eps)1365: {
1367: PetscBool isfilt;
1370: PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilt);
1371: if (eps->which==EPS_ALL && !isfilt) {
1372: EPSReset_KrylovSchur_Slice(eps);
1373: }
1374: return(0);
1375: }
1377: PetscErrorCode EPSSetDefaultST_KrylovSchur(EPS eps)1378: {
1382: if (eps->which==EPS_ALL) {
1383: if (!((PetscObject)eps->st)->type_name) {
1384: STSetType(eps->st,STSINVERT);
1385: }
1386: }
1387: return(0);
1388: }
1390: SLEPC_EXTERN PetscErrorCode EPSCreate_KrylovSchur(EPS eps)1391: {
1392: EPS_KRYLOVSCHUR *ctx;
1393: PetscErrorCode ierr;
1396: PetscNewLog(eps,&ctx);
1397: eps->data = (void*)ctx;
1398: ctx->lock = PETSC_TRUE;
1399: ctx->nev = 1;
1400: ctx->npart = 1;
1401: ctx->detect = PETSC_FALSE;
1402: ctx->global = PETSC_TRUE;
1404: eps->useds = PETSC_TRUE;
1405: eps->hasts = PETSC_TRUE;
1407: /* solve and computevectors determined at setup */
1408: eps->ops->setup = EPSSetUp_KrylovSchur;
1409: eps->ops->setfromoptions = EPSSetFromOptions_KrylovSchur;
1410: eps->ops->destroy = EPSDestroy_KrylovSchur;
1411: eps->ops->reset = EPSReset_KrylovSchur;
1412: eps->ops->view = EPSView_KrylovSchur;
1413: eps->ops->backtransform = EPSBackTransform_Default;
1414: eps->ops->setdefaultst = EPSSetDefaultST_KrylovSchur;
1416: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetRestart_C",EPSKrylovSchurSetRestart_KrylovSchur);
1417: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetRestart_C",EPSKrylovSchurGetRestart_KrylovSchur);
1418: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetLocking_C",EPSKrylovSchurSetLocking_KrylovSchur);
1419: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetLocking_C",EPSKrylovSchurGetLocking_KrylovSchur);
1420: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetPartitions_C",EPSKrylovSchurSetPartitions_KrylovSchur);
1421: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetPartitions_C",EPSKrylovSchurGetPartitions_KrylovSchur);
1422: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetDetectZeros_C",EPSKrylovSchurSetDetectZeros_KrylovSchur);
1423: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetDetectZeros_C",EPSKrylovSchurGetDetectZeros_KrylovSchur);
1424: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetDimensions_C",EPSKrylovSchurSetDimensions_KrylovSchur);
1425: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetDimensions_C",EPSKrylovSchurGetDimensions_KrylovSchur);
1426: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetSubintervals_C",EPSKrylovSchurSetSubintervals_KrylovSchur);
1427: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubintervals_C",EPSKrylovSchurGetSubintervals_KrylovSchur);
1428: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetInertias_C",EPSKrylovSchurGetInertias_KrylovSchur);
1429: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommInfo_C",EPSKrylovSchurGetSubcommInfo_KrylovSchur);
1430: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommPairs_C",EPSKrylovSchurGetSubcommPairs_KrylovSchur);
1431: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetSubcommMats_C",EPSKrylovSchurGetSubcommMats_KrylovSchur);
1432: PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurUpdateSubcommMats_C",EPSKrylovSchurUpdateSubcommMats_KrylovSchur);
1433: return(0);
1434: }