Actual source code: krylovschur.c

slepc-3.13.1 2020-04-12
Report Typos and Errors
  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: }