LCOV - code coverage report
Current view: top level - eps/impls/krylov/krylovschur - ks-slice.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 844 911 92.6 %
Date: 2024-04-23 01:05:21 Functions: 21 21 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14