LCOV - code coverage report
Current view: top level - eps/impls/ciss - ciss.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 751 813 92.4 %
Date: 2024-12-18 00:51:33 Functions: 38 39 97.4 %
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: "ciss"
      12             : 
      13             :    Method: Contour Integral Spectral Slicing
      14             : 
      15             :    Algorithm:
      16             : 
      17             :        Contour integral based on Sakurai-Sugiura method to construct a
      18             :        subspace, with various eigenpair extractions (Rayleigh-Ritz,
      19             :        explicit moment).
      20             : 
      21             :    Based on code contributed by Y. Maeda, T. Sakurai.
      22             : 
      23             :    References:
      24             : 
      25             :        [1] T. Sakurai and H. Sugiura, "A projection method for generalized
      26             :            eigenvalue problems", J. Comput. Appl. Math. 159:119-128, 2003.
      27             : 
      28             :        [2] T. Sakurai and H. Tadano, "CIRR: a Rayleigh-Ritz type method with
      29             :            contour integral for generalized eigenvalue problems", Hokkaido
      30             :            Math. J. 36:745-757, 2007.
      31             : */
      32             : 
      33             : #include <slepc/private/epsimpl.h>                /*I "slepceps.h" I*/
      34             : #include <slepc/private/slepccontour.h>
      35             : #include <slepcblaslapack.h>
      36             : 
      37             : typedef struct {
      38             :   /* user parameters */
      39             :   PetscInt          N;          /* number of integration points (32) */
      40             :   PetscInt          L;          /* block size (16) */
      41             :   PetscInt          M;          /* moment degree (N/4 = 4) */
      42             :   PetscReal         delta;      /* threshold of singular value (1e-12) */
      43             :   PetscInt          L_max;      /* maximum number of columns of the source matrix V */
      44             :   PetscReal         spurious_threshold; /* discard spurious eigenpairs */
      45             :   PetscBool         isreal;     /* A and B are real */
      46             :   PetscInt          npart;      /* number of partitions */
      47             :   PetscInt          refine_inner;
      48             :   PetscInt          refine_blocksize;
      49             :   EPSCISSQuadRule   quad;
      50             :   EPSCISSExtraction extraction;
      51             :   PetscBool         usest;
      52             :   /* private data */
      53             :   SlepcContourData  contour;
      54             :   PetscReal         *sigma;     /* threshold for numerical rank */
      55             :   PetscScalar       *weight;
      56             :   PetscScalar       *omega;
      57             :   PetscScalar       *pp;
      58             :   BV                V;
      59             :   BV                S;
      60             :   BV                pV;
      61             :   BV                Y;
      62             :   PetscBool         useconj;
      63             :   PetscBool         usest_set;  /* whether the user set the usest flag or not */
      64             :   PetscObjectId     rgid;
      65             :   PetscObjectState  rgstate;
      66             : } EPS_CISS;
      67             : 
      68             : /*
      69             :   Set up KSP solvers for every integration point, only called if !ctx->usest
      70             : */
      71          18 : static PetscErrorCode EPSCISSSetUp(EPS eps,Mat A,Mat B,Mat Pa,Mat Pb)
      72             : {
      73          18 :   EPS_CISS         *ctx = (EPS_CISS*)eps->data;
      74          18 :   SlepcContourData contour;
      75          18 :   PetscInt         i,p_id,nsplit;
      76          18 :   Mat              Amat,Pmat;
      77          18 :   MatStructure     str,strp;
      78             : 
      79          18 :   PetscFunctionBegin;
      80          18 :   if (!ctx->contour || !ctx->contour->ksp) PetscCall(EPSCISSGetKSPs(eps,NULL,NULL));
      81          18 :   PetscAssert(ctx->contour && ctx->contour->ksp,PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Something went wrong with EPSCISSGetKSPs()");
      82          18 :   contour = ctx->contour;
      83          18 :   PetscCall(STGetMatStructure(eps->st,&str));
      84          18 :   PetscCall(STGetSplitPreconditionerInfo(eps->st,&nsplit,&strp));
      85         386 :   for (i=0;i<contour->npoints;i++) {
      86         368 :     p_id = i*contour->subcomm->n + contour->subcomm->color;
      87         368 :     PetscCall(MatDuplicate(A,MAT_COPY_VALUES,&Amat));
      88         368 :     if (B) PetscCall(MatAXPY(Amat,-ctx->omega[p_id],B,str));
      89         228 :     else PetscCall(MatShift(Amat,-ctx->omega[p_id]));
      90         368 :     if (nsplit) {
      91          64 :       PetscCall(MatDuplicate(Pa,MAT_COPY_VALUES,&Pmat));
      92          64 :       if (Pb) PetscCall(MatAXPY(Pmat,-ctx->omega[p_id],Pb,strp));
      93           0 :       else PetscCall(MatShift(Pmat,-ctx->omega[p_id]));
      94         304 :     } else Pmat = Amat;
      95         368 :     PetscCall(EPS_KSPSetOperators(contour->ksp[i],Amat,Amat));
      96         368 :     PetscCall(MatDestroy(&Amat));
      97         368 :     if (nsplit) PetscCall(MatDestroy(&Pmat));
      98             :   }
      99          18 :   PetscFunctionReturn(PETSC_SUCCESS);
     100             : }
     101             : 
     102             : /*
     103             :   Y_i = (A-z_i B)^{-1}BV for every integration point, Y=[Y_i] is in the context
     104             : */
     105          37 : static PetscErrorCode EPSCISSSolve(EPS eps,Mat B,BV V,PetscInt L_start,PetscInt L_end)
     106             : {
     107          37 :   EPS_CISS         *ctx = (EPS_CISS*)eps->data;
     108          37 :   SlepcContourData contour;
     109          37 :   PetscInt         i,p_id;
     110          37 :   Mat              MV,BMV=NULL,MC;
     111          37 :   KSP              ksp;
     112             : 
     113          37 :   PetscFunctionBegin;
     114          37 :   if (!ctx->contour || !ctx->contour->ksp) PetscCall(EPSCISSGetKSPs(eps,NULL,NULL));
     115          37 :   contour = ctx->contour;
     116          37 :   PetscAssert(ctx->contour && ctx->contour->ksp,PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Something went wrong with EPSCISSGetKSPs()");
     117          37 :   PetscCall(BVSetActiveColumns(V,L_start,L_end));
     118          37 :   PetscCall(BVGetMat(V,&MV));
     119         941 :   for (i=0;i<contour->npoints;i++) {
     120         904 :     p_id = i*contour->subcomm->n + contour->subcomm->color;
     121         904 :     if (ctx->usest)  {
     122         504 :       PetscCall(STSetShift(eps->st,ctx->omega[p_id]));
     123         504 :       PetscCall(STGetKSP(eps->st,&ksp));
     124         400 :     } else ksp = contour->ksp[i];
     125         904 :     PetscCall(BVSetActiveColumns(ctx->Y,i*ctx->L+L_start,i*ctx->L+L_end));
     126         904 :     PetscCall(BVGetMat(ctx->Y,&MC));
     127         904 :     if (B) {
     128         324 :       if (!i) {
     129          13 :         PetscCall(MatProductCreate(B,MV,NULL,&BMV));
     130          13 :         PetscCall(MatProductSetType(BMV,MATPRODUCT_AB));
     131          13 :         PetscCall(MatProductSetFromOptions(BMV));
     132          13 :         PetscCall(MatProductSymbolic(BMV));
     133             :       }
     134         324 :       PetscCall(MatProductNumeric(BMV));
     135         324 :       PetscCall(KSPMatSolve(ksp,BMV,MC));
     136         580 :     } else PetscCall(KSPMatSolve(ksp,MV,MC));
     137         904 :     PetscCall(BVRestoreMat(ctx->Y,&MC));
     138         904 :     if (ctx->usest && i<contour->npoints-1) PetscCall(KSPReset(ksp));
     139             :   }
     140          37 :   PetscCall(MatDestroy(&BMV));
     141          37 :   PetscCall(BVRestoreMat(V,&MV));
     142          37 :   PetscFunctionReturn(PETSC_SUCCESS);
     143             : }
     144             : 
     145          70 : static PetscErrorCode rescale_eig(EPS eps,PetscInt nv)
     146             : {
     147          70 :   EPS_CISS       *ctx = (EPS_CISS*)eps->data;
     148          70 :   PetscInt       i;
     149          70 :   PetscScalar    center;
     150          70 :   PetscReal      radius,a,b,c,d,rgscale;
     151             : #if defined(PETSC_USE_COMPLEX)
     152          70 :   PetscReal      start_ang,end_ang,vscale,theta;
     153             : #endif
     154          70 :   PetscBool      isring,isellipse,isinterval;
     155             : 
     156          70 :   PetscFunctionBegin;
     157          70 :   PetscCall(PetscObjectTypeCompare((PetscObject)eps->rg,RGELLIPSE,&isellipse));
     158          70 :   PetscCall(PetscObjectTypeCompare((PetscObject)eps->rg,RGRING,&isring));
     159          70 :   PetscCall(PetscObjectTypeCompare((PetscObject)eps->rg,RGINTERVAL,&isinterval));
     160          70 :   PetscCall(RGGetScale(eps->rg,&rgscale));
     161          70 :   if (isinterval) {
     162          20 :     PetscCall(RGIntervalGetEndpoints(eps->rg,NULL,NULL,&c,&d));
     163          20 :     if (c==d) {
     164         226 :       for (i=0;i<nv;i++) {
     165             : #if defined(PETSC_USE_COMPLEX)
     166         210 :         eps->eigr[i] = PetscRealPart(eps->eigr[i]);
     167             : #else
     168             :         eps->eigi[i] = 0;
     169             : #endif
     170             :       }
     171             :     }
     172             :   }
     173          70 :   if (ctx->extraction == EPS_CISS_EXTRACTION_HANKEL) {
     174          14 :     if (isellipse) {
     175           6 :       PetscCall(RGEllipseGetParameters(eps->rg,&center,&radius,NULL));
     176          54 :       for (i=0;i<nv;i++) eps->eigr[i] = rgscale*(center + radius*eps->eigr[i]);
     177           8 :     } else if (isinterval) {
     178           4 :       PetscCall(RGIntervalGetEndpoints(eps->rg,&a,&b,&c,&d));
     179           4 :       if (ctx->quad == EPS_CISS_QUADRULE_CHEBYSHEV) {
     180          14 :         for (i=0;i<nv;i++) {
     181          12 :           if (c==d) eps->eigr[i] = ((b-a)*(eps->eigr[i]+1.0)/2.0+a)*rgscale;
     182          12 :           if (a==b) {
     183             : #if defined(PETSC_USE_COMPLEX)
     184           0 :             eps->eigr[i] = ((d-c)*(eps->eigr[i]+1.0)/2.0+c)*rgscale*PETSC_i;
     185             : #else
     186             :             SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Integration points on a vertical line require complex arithmetic");
     187             : #endif
     188             :           }
     189             :         }
     190             :       } else {
     191           2 :         center = (b+a)/2.0+(d+c)/2.0*PETSC_PI;
     192           4 :         radius = PetscSqrtReal(PetscPowRealInt((b-a)/2.0,2)+PetscPowRealInt((d-c)/2.0,2));
     193          14 :         for (i=0;i<nv;i++) eps->eigr[i] = center + radius*eps->eigr[i];
     194             :       }
     195           4 :     } else if (isring) {  /* only supported in complex scalars */
     196             : #if defined(PETSC_USE_COMPLEX)
     197           4 :       PetscCall(RGRingGetParameters(eps->rg,&center,&radius,&vscale,&start_ang,&end_ang,NULL));
     198           4 :       if (ctx->quad == EPS_CISS_QUADRULE_CHEBYSHEV) {
     199           0 :         for (i=0;i<nv;i++) {
     200           0 :           theta = (start_ang*2.0+(end_ang-start_ang)*(PetscRealPart(eps->eigr[i])+1.0))*PETSC_PI;
     201           0 :           eps->eigr[i] = rgscale*center + (rgscale*radius+PetscImaginaryPart(eps->eigr[i]))*PetscCMPLX(PetscCosReal(theta),vscale*PetscSinReal(theta));
     202             :         }
     203             :       } else {
     204          34 :         for (i=0;i<nv;i++) eps->eigr[i] = rgscale*(center + radius*eps->eigr[i]);
     205             :       }
     206             : #endif
     207             :     }
     208             :   }
     209          70 :   PetscFunctionReturn(PETSC_SUCCESS);
     210             : }
     211             : 
     212          33 : static PetscErrorCode EPSSetUp_CISS(EPS eps)
     213             : {
     214          33 :   EPS_CISS         *ctx = (EPS_CISS*)eps->data;
     215          33 :   SlepcContourData contour;
     216          33 :   PetscBool        istrivial,isring,isellipse,isinterval,flg;
     217          33 :   PetscReal        c,d;
     218          33 :   PetscInt         nsplit;
     219          33 :   PetscRandom      rand;
     220          33 :   PetscObjectId    id;
     221          33 :   PetscObjectState state;
     222          33 :   Mat              A[2],Psplit[2];
     223          33 :   Vec              v0;
     224             : 
     225          33 :   PetscFunctionBegin;
     226          33 :   EPSCheckNotStructured(eps);
     227          33 :   if (eps->ncv==PETSC_DETERMINE) {
     228          31 :     if (eps->nev==0) eps->nev = 1;
     229          31 :     eps->ncv = ctx->L_max*ctx->M;
     230          31 :     if (eps->ncv>eps->n) {
     231          19 :       eps->ncv = eps->n;
     232          19 :       ctx->L_max = eps->ncv/ctx->M;
     233          19 :       PetscCheck(ctx->L_max,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Cannot adjust solver parameters, try setting a smaller value of M (moment size)");
     234             :     }
     235             :   } else {
     236           2 :     PetscCall(EPSSetDimensions_Default(eps,&eps->nev,&eps->ncv,&eps->mpd));
     237           2 :     ctx->L_max = eps->ncv/ctx->M;
     238           2 :     if (!ctx->L_max) {
     239           0 :       ctx->L_max = 1;
     240           0 :       eps->ncv = ctx->L_max*ctx->M;
     241             :     }
     242             :   }
     243          33 :   ctx->L = PetscMin(ctx->L,ctx->L_max);
     244          33 :   if (eps->max_it==PETSC_DETERMINE) eps->max_it = 5;
     245          33 :   if (eps->mpd==PETSC_DETERMINE) eps->mpd = eps->ncv;
     246          33 :   if (!eps->which) eps->which = EPS_ALL;
     247          33 :   PetscCheck(eps->which==EPS_ALL,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"This solver supports only computing all eigenvalues");
     248          33 :   EPSCheckUnsupported(eps,EPS_FEATURE_BALANCE | EPS_FEATURE_ARBITRARY | EPS_FEATURE_EXTRACTION | EPS_FEATURE_STOPPING | EPS_FEATURE_TWOSIDED);
     249             : 
     250             :   /* check region */
     251          33 :   PetscCall(RGIsTrivial(eps->rg,&istrivial));
     252          33 :   PetscCheck(!istrivial,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"CISS requires a nontrivial region, e.g. -rg_type ellipse ...");
     253          33 :   PetscCall(RGGetComplement(eps->rg,&flg));
     254          33 :   PetscCheck(!flg,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"A region with complement flag set is not allowed");
     255          33 :   PetscCall(PetscObjectTypeCompare((PetscObject)eps->rg,RGELLIPSE,&isellipse));
     256          33 :   PetscCall(PetscObjectTypeCompare((PetscObject)eps->rg,RGRING,&isring));
     257          33 :   PetscCall(PetscObjectTypeCompare((PetscObject)eps->rg,RGINTERVAL,&isinterval));
     258          33 :   PetscCheck(isellipse || isring || isinterval,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Currently only implemented for interval, elliptic or ring regions");
     259             : 
     260             :   /* if the region has changed, then reset contour data */
     261          33 :   PetscCall(PetscObjectGetId((PetscObject)eps->rg,&id));
     262          33 :   PetscCall(PetscObjectStateGet((PetscObject)eps->rg,&state));
     263          33 :   if (ctx->rgid && (id != ctx->rgid || state != ctx->rgstate)) {
     264           0 :     PetscCall(SlepcContourDataDestroy(&ctx->contour));
     265           0 :     PetscCall(PetscInfo(eps,"Resetting the contour data structure due to a change of region\n"));
     266           0 :     ctx->rgid = id; ctx->rgstate = state;
     267             :   }
     268             : 
     269             : #if !defined(PETSC_USE_COMPLEX)
     270             :   PetscCheck(!isring,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Ring region only supported for complex scalars");
     271             : #endif
     272          33 :   if (isinterval) {
     273          10 :     PetscCall(RGIntervalGetEndpoints(eps->rg,NULL,NULL,&c,&d));
     274             : #if !defined(PETSC_USE_COMPLEX)
     275             :     PetscCheck(c==d && c==0.0,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"In real scalars, endpoints of the imaginary axis must be both zero");
     276             : #endif
     277          10 :     if (!ctx->quad && c==d) ctx->quad = EPS_CISS_QUADRULE_CHEBYSHEV;
     278             :   }
     279          33 :   if (!ctx->quad) ctx->quad = EPS_CISS_QUADRULE_TRAPEZOIDAL;
     280             : 
     281             :   /* create contour data structure */
     282          33 :   if (!ctx->contour) {
     283           0 :     PetscCall(RGCanUseConjugates(eps->rg,ctx->isreal,&ctx->useconj));
     284           0 :     PetscCall(SlepcContourDataCreate(ctx->useconj?ctx->N/2:ctx->N,ctx->npart,(PetscObject)eps,&ctx->contour));
     285             :   }
     286             : 
     287          33 :   PetscCall(EPSAllocateSolution(eps,0));
     288          33 :   PetscCall(BVGetRandomContext(eps->V,&rand));  /* make sure the random context is available when duplicating */
     289          33 :   if (ctx->weight) PetscCall(PetscFree4(ctx->weight,ctx->omega,ctx->pp,ctx->sigma));
     290          33 :   PetscCall(PetscMalloc4(ctx->N,&ctx->weight,ctx->N+1,&ctx->omega,ctx->N,&ctx->pp,ctx->L_max*ctx->M,&ctx->sigma));
     291             : 
     292             :   /* allocate basis vectors */
     293          33 :   PetscCall(BVDestroy(&ctx->S));
     294          33 :   PetscCall(BVDuplicateResize(eps->V,ctx->L*ctx->M,&ctx->S));
     295          33 :   PetscCall(BVDestroy(&ctx->V));
     296          33 :   PetscCall(BVDuplicateResize(eps->V,ctx->L,&ctx->V));
     297             : 
     298          33 :   PetscCall(STGetMatrix(eps->st,0,&A[0]));
     299          33 :   PetscCall(MatIsShell(A[0],&flg));
     300          33 :   PetscCheck(!flg,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Matrix type shell is not supported in this solver");
     301          33 :   if (eps->isgeneralized) PetscCall(STGetMatrix(eps->st,1,&A[1]));
     302             : 
     303          33 :   if (!ctx->usest_set) ctx->usest = (ctx->npart>1)? PETSC_FALSE: PETSC_TRUE;
     304          33 :   PetscCheck(!ctx->usest || ctx->npart==1,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"The usest flag is not supported when partitions > 1");
     305             : 
     306             :   /* check if a user-defined split preconditioner has been set */
     307          33 :   PetscCall(STGetSplitPreconditionerInfo(eps->st,&nsplit,NULL));
     308          33 :   if (nsplit) {
     309           4 :     PetscCall(STGetSplitPreconditionerTerm(eps->st,0,&Psplit[0]));
     310           4 :     if (eps->isgeneralized) PetscCall(STGetSplitPreconditionerTerm(eps->st,1,&Psplit[1]));
     311             :   }
     312             : 
     313          33 :   contour = ctx->contour;
     314          82 :   PetscCall(SlepcContourRedundantMat(contour,eps->isgeneralized?2:1,A,nsplit?Psplit:NULL));
     315          33 :   if (contour->pA) {
     316           8 :     PetscCall(BVGetColumn(ctx->V,0,&v0));
     317           8 :     PetscCall(SlepcContourScatterCreate(contour,v0));
     318           8 :     PetscCall(BVRestoreColumn(ctx->V,0,&v0));
     319           8 :     PetscCall(BVDestroy(&ctx->pV));
     320           8 :     PetscCall(BVCreate(PetscObjectComm((PetscObject)contour->xsub),&ctx->pV));
     321           8 :     PetscCall(BVSetSizesFromVec(ctx->pV,contour->xsub,eps->n));
     322           8 :     PetscCall(BVSetFromOptions(ctx->pV));
     323           8 :     PetscCall(BVResize(ctx->pV,ctx->L,PETSC_FALSE));
     324             :   }
     325             : 
     326          33 :   EPSCheckDefinite(eps);
     327          33 :   EPSCheckSinvertCondition(eps,ctx->usest," (with the usest flag set)");
     328             : 
     329          33 :   PetscCall(BVDestroy(&ctx->Y));
     330          33 :   if (contour->pA) {
     331           8 :     PetscCall(BVCreate(PetscObjectComm((PetscObject)contour->xsub),&ctx->Y));
     332           8 :     PetscCall(BVSetSizesFromVec(ctx->Y,contour->xsub,eps->n));
     333           8 :     PetscCall(BVSetFromOptions(ctx->Y));
     334           8 :     PetscCall(BVResize(ctx->Y,contour->npoints*ctx->L,PETSC_FALSE));
     335          25 :   } else PetscCall(BVDuplicateResize(eps->V,contour->npoints*ctx->L,&ctx->Y));
     336             : 
     337          33 :   if (ctx->extraction == EPS_CISS_EXTRACTION_HANKEL) PetscCall(DSSetType(eps->ds,DSGNHEP));
     338          27 :   else if (eps->isgeneralized) {
     339          11 :     if (eps->ishermitian && eps->ispositive) PetscCall(DSSetType(eps->ds,DSGHEP));
     340           2 :     else PetscCall(DSSetType(eps->ds,DSGNHEP));
     341             :   } else {
     342          16 :     if (eps->ishermitian) PetscCall(DSSetType(eps->ds,DSHEP));
     343           9 :     else PetscCall(DSSetType(eps->ds,DSNHEP));
     344             :   }
     345          33 :   PetscCall(DSAllocate(eps->ds,eps->ncv));
     346             : 
     347             : #if !defined(PETSC_USE_COMPLEX)
     348             :   PetscCall(EPSSetWorkVecs(eps,3));
     349             :   if (!eps->ishermitian) PetscCall(PetscInfo(eps,"Warning: complex eigenvalues are not calculated exactly without --with-scalar-type=complex in PETSc\n"));
     350             : #else
     351          33 :   PetscCall(EPSSetWorkVecs(eps,2));
     352             : #endif
     353          33 :   PetscFunctionReturn(PETSC_SUCCESS);
     354             : }
     355             : 
     356          33 : static PetscErrorCode EPSSetUpSort_CISS(EPS eps)
     357             : {
     358          33 :   SlepcSC        sc;
     359             : 
     360          33 :   PetscFunctionBegin;
     361             :   /* fill sorting criterion context */
     362          33 :   eps->sc->comparison    = SlepcCompareSmallestReal;
     363          33 :   eps->sc->comparisonctx = NULL;
     364          33 :   eps->sc->map           = NULL;
     365          33 :   eps->sc->mapobj        = NULL;
     366             : 
     367             :   /* fill sorting criterion for DS */
     368          33 :   PetscCall(DSGetSlepcSC(eps->ds,&sc));
     369          33 :   sc->comparison    = SlepcCompareLargestMagnitude;
     370          33 :   sc->comparisonctx = NULL;
     371          33 :   sc->map           = NULL;
     372          33 :   sc->mapobj        = NULL;
     373          33 :   PetscFunctionReturn(PETSC_SUCCESS);
     374             : }
     375             : 
     376          33 : static PetscErrorCode EPSSolve_CISS(EPS eps)
     377             : {
     378          33 :   EPS_CISS         *ctx = (EPS_CISS*)eps->data;
     379          33 :   SlepcContourData contour = ctx->contour;
     380          33 :   Mat              A,B,X,M,pA,pB,T,J,Pa=NULL,Pb=NULL;
     381          33 :   BV               V;
     382          33 :   PetscInt         i,j,ld,nmat,L_add=0,nv=0,L_base=ctx->L,inner,nlocal,*inside,nsplit;
     383          33 :   PetscScalar      *Mu,*H0,*H1=NULL,*rr,*temp;
     384          33 :   PetscReal        error,max_error,norm;
     385          33 :   PetscBool        *fl1;
     386          33 :   Vec              si,si1=NULL,w[3];
     387          33 :   PetscRandom      rand;
     388             : #if defined(PETSC_USE_COMPLEX)
     389          33 :   PetscBool        isellipse;
     390          33 :   PetscReal        est_eig,eta;
     391             : #else
     392             :   PetscReal        normi;
     393             : #endif
     394             : 
     395          33 :   PetscFunctionBegin;
     396          33 :   w[0] = eps->work[0];
     397             : #if defined(PETSC_USE_COMPLEX)
     398          33 :   w[1] = NULL;
     399             : #else
     400             :   w[1] = eps->work[2];
     401             : #endif
     402          33 :   w[2] = eps->work[1];
     403          33 :   PetscCall(VecGetLocalSize(w[0],&nlocal));
     404          33 :   PetscCall(DSGetLeadingDimension(eps->ds,&ld));
     405          55 :   PetscCall(RGComputeQuadrature(eps->rg,ctx->quad==EPS_CISS_QUADRULE_CHEBYSHEV?RG_QUADRULE_CHEBYSHEV:RG_QUADRULE_TRAPEZOIDAL,ctx->N,ctx->omega,ctx->pp,ctx->weight));
     406          33 :   PetscCall(STGetNumMatrices(eps->st,&nmat));
     407          33 :   PetscCall(STGetMatrix(eps->st,0,&A));
     408          33 :   if (nmat>1) PetscCall(STGetMatrix(eps->st,1,&B));
     409          20 :   else B = NULL;
     410          33 :   J = (contour->pA && nmat>1)? contour->pA[1]: B;
     411          33 :   V = contour->pA? ctx->pV: ctx->V;
     412          33 :   if (!ctx->usest) {
     413          18 :     T = contour->pA? contour->pA[0]: A;
     414          18 :     PetscCall(STGetSplitPreconditionerInfo(eps->st,&nsplit,NULL));
     415          18 :     if (nsplit) {
     416           3 :       if (contour->pA) {
     417           2 :         Pa = contour->pP[0];
     418           2 :         if (nsplit>1) Pb = contour->pP[1];
     419             :       } else {
     420           1 :         PetscCall(STGetSplitPreconditionerTerm(eps->st,0,&Pa));
     421           1 :         if (nsplit>1) PetscCall(STGetSplitPreconditionerTerm(eps->st,1,&Pb));
     422             :       }
     423             :     }
     424          18 :     PetscCall(EPSCISSSetUp(eps,T,J,Pa,Pb));
     425             :   }
     426          33 :   PetscCall(BVSetActiveColumns(ctx->V,0,ctx->L));
     427          33 :   PetscCall(BVSetRandomSign(ctx->V));
     428          33 :   PetscCall(BVGetRandomContext(ctx->V,&rand));
     429             : 
     430          33 :   if (contour->pA) PetscCall(BVScatter(ctx->V,ctx->pV,contour->scatterin,contour->xdup));
     431          33 :   PetscCall(EPSCISSSolve(eps,J,V,0,ctx->L));
     432             : #if defined(PETSC_USE_COMPLEX)
     433          33 :   PetscCall(PetscObjectTypeCompare((PetscObject)eps->rg,RGELLIPSE,&isellipse));
     434          33 :   if (isellipse) {
     435          20 :     PetscCall(BVTraceQuadrature(ctx->Y,ctx->V,ctx->L,ctx->L,ctx->weight,contour->scatterin,contour->subcomm,contour->npoints,ctx->useconj,&est_eig));
     436          20 :     PetscCall(PetscInfo(eps,"Estimated eigenvalue count: %f\n",(double)est_eig));
     437          20 :     eta = PetscPowReal(10.0,-PetscLog10Real(eps->tol)/ctx->N);
     438          20 :     L_add = PetscMax(0,(PetscInt)PetscCeilReal((est_eig*eta)/ctx->M)-ctx->L);
     439          20 :     if (L_add>ctx->L_max-ctx->L) {
     440           1 :       PetscCall(PetscInfo(eps,"Number of eigenvalues inside the contour path may be too large\n"));
     441           1 :       L_add = ctx->L_max-ctx->L;
     442             :     }
     443             :   }
     444             : #endif
     445          20 :   if (L_add>0) {
     446           2 :     PetscCall(PetscInfo(eps,"Changing L %" PetscInt_FMT " -> %" PetscInt_FMT " by Estimate #Eig\n",ctx->L,ctx->L+L_add));
     447           2 :     PetscCall(BVCISSResizeBases(ctx->S,contour->pA?ctx->pV:ctx->V,ctx->Y,ctx->L,ctx->L+L_add,ctx->M,contour->npoints));
     448           2 :     PetscCall(BVSetActiveColumns(ctx->V,ctx->L,ctx->L+L_add));
     449           2 :     PetscCall(BVSetRandomSign(ctx->V));
     450           2 :     if (contour->pA) PetscCall(BVScatter(ctx->V,ctx->pV,contour->scatterin,contour->xdup));
     451           2 :     ctx->L += L_add;
     452           2 :     PetscCall(EPSCISSSolve(eps,J,V,ctx->L-L_add,ctx->L));
     453             :   }
     454          33 :   PetscCall(PetscMalloc2(ctx->L*ctx->L*ctx->M*2,&Mu,ctx->L*ctx->M*ctx->L*ctx->M,&H0));
     455          33 :   for (i=0;i<ctx->refine_blocksize;i++) {
     456           1 :     PetscCall(BVDotQuadrature(ctx->Y,(contour->pA)?ctx->pV:ctx->V,Mu,ctx->M,ctx->L,ctx->L,ctx->weight,ctx->pp,contour->subcomm,contour->npoints,ctx->useconj));
     457           1 :     PetscCall(CISS_BlockHankel(Mu,0,ctx->L,ctx->M,H0));
     458           1 :     PetscCall(PetscLogEventBegin(EPS_CISS_SVD,eps,0,0,0));
     459           1 :     PetscCall(SlepcCISS_BH_SVD(H0,ctx->L*ctx->M,ctx->delta,ctx->sigma,&nv));
     460           1 :     PetscCall(PetscLogEventEnd(EPS_CISS_SVD,eps,0,0,0));
     461           1 :     if (ctx->sigma[0]<=ctx->delta || nv < ctx->L*ctx->M || ctx->L == ctx->L_max) break;
     462           0 :     L_add = L_base;
     463           0 :     if (ctx->L+L_add>ctx->L_max) L_add = ctx->L_max-ctx->L;
     464           0 :     PetscCall(PetscInfo(eps,"Changing L %" PetscInt_FMT " -> %" PetscInt_FMT " by SVD(H0)\n",ctx->L,ctx->L+L_add));
     465           0 :     PetscCall(BVCISSResizeBases(ctx->S,contour->pA?ctx->pV:ctx->V,ctx->Y,ctx->L,ctx->L+L_add,ctx->M,contour->npoints));
     466           0 :     PetscCall(BVSetActiveColumns(ctx->V,ctx->L,ctx->L+L_add));
     467           0 :     PetscCall(BVSetRandomSign(ctx->V));
     468           0 :     if (contour->pA) PetscCall(BVScatter(ctx->V,ctx->pV,contour->scatterin,contour->xdup));
     469           0 :     ctx->L += L_add;
     470           0 :     PetscCall(EPSCISSSolve(eps,J,V,ctx->L-L_add,ctx->L));
     471           0 :     if (L_add) {
     472           0 :       PetscCall(PetscFree2(Mu,H0));
     473           0 :       PetscCall(PetscMalloc2(ctx->L*ctx->L*ctx->M*2,&Mu,ctx->L*ctx->M*ctx->L*ctx->M,&H0));
     474             :     }
     475             :   }
     476          33 :   if (ctx->extraction == EPS_CISS_EXTRACTION_HANKEL) PetscCall(PetscMalloc1(ctx->L*ctx->M*ctx->L*ctx->M,&H1));
     477             : 
     478          68 :   while (eps->reason == EPS_CONVERGED_ITERATING) {
     479          35 :     eps->its++;
     480          35 :     for (inner=0;inner<=ctx->refine_inner;inner++) {
     481          35 :       if (ctx->extraction == EPS_CISS_EXTRACTION_HANKEL) {
     482           7 :         PetscCall(BVDotQuadrature(ctx->Y,(contour->pA)?ctx->pV:ctx->V,Mu,ctx->M,ctx->L,ctx->L,ctx->weight,ctx->pp,contour->subcomm,contour->npoints,ctx->useconj));
     483           7 :         PetscCall(CISS_BlockHankel(Mu,0,ctx->L,ctx->M,H0));
     484           7 :         PetscCall(PetscLogEventBegin(EPS_CISS_SVD,eps,0,0,0));
     485           7 :         PetscCall(SlepcCISS_BH_SVD(H0,ctx->L*ctx->M,ctx->delta,ctx->sigma,&nv));
     486           7 :         PetscCall(PetscLogEventEnd(EPS_CISS_SVD,eps,0,0,0));
     487             :         break;
     488             :       } else {
     489          28 :         PetscCall(BVSumQuadrature(ctx->S,ctx->Y,ctx->M,ctx->L,ctx->L,ctx->weight,ctx->pp,contour->scatterin,contour->subcomm,contour->npoints,ctx->useconj));
     490          28 :         PetscCall(BVSetActiveColumns(ctx->S,0,ctx->L));
     491          28 :         PetscCall(BVSetActiveColumns(ctx->V,0,ctx->L));
     492          28 :         PetscCall(BVCopy(ctx->S,ctx->V));
     493          28 :         PetscCall(BVSVDAndRank(ctx->S,ctx->M,ctx->L,ctx->delta,BV_SVD_METHOD_REFINE,H0,ctx->sigma,&nv));
     494          28 :         if (ctx->sigma[0]>ctx->delta && nv==ctx->L*ctx->M && inner!=ctx->refine_inner) {
     495           0 :           if (contour->pA) PetscCall(BVScatter(ctx->V,ctx->pV,contour->scatterin,contour->xdup));
     496           0 :           PetscCall(EPSCISSSolve(eps,J,V,0,ctx->L));
     497             :         } else break;
     498             :       }
     499             :     }
     500          35 :     eps->nconv = 0;
     501          35 :     if (nv == 0) eps->reason = EPS_CONVERGED_TOL;
     502             :     else {
     503          35 :       PetscCall(DSSetDimensions(eps->ds,nv,0,0));
     504          35 :       PetscCall(DSSetState(eps->ds,DS_STATE_RAW));
     505             : 
     506          35 :       if (ctx->extraction == EPS_CISS_EXTRACTION_HANKEL) {
     507           7 :         PetscCall(CISS_BlockHankel(Mu,0,ctx->L,ctx->M,H0));
     508           7 :         PetscCall(CISS_BlockHankel(Mu,1,ctx->L,ctx->M,H1));
     509           7 :         PetscCall(DSGetArray(eps->ds,DS_MAT_A,&temp));
     510          58 :         for (j=0;j<nv;j++) {
     511         438 :           for (i=0;i<nv;i++) {
     512         387 :             temp[i+j*ld] = H1[i+j*ctx->L*ctx->M];
     513             :           }
     514             :         }
     515           7 :         PetscCall(DSRestoreArray(eps->ds,DS_MAT_A,&temp));
     516           7 :         PetscCall(DSGetArray(eps->ds,DS_MAT_B,&temp));
     517          58 :         for (j=0;j<nv;j++) {
     518         438 :           for (i=0;i<nv;i++) {
     519         387 :             temp[i+j*ld] = H0[i+j*ctx->L*ctx->M];
     520             :           }
     521             :         }
     522           7 :         PetscCall(DSRestoreArray(eps->ds,DS_MAT_B,&temp));
     523             :       } else {
     524          28 :         PetscCall(BVSetActiveColumns(ctx->S,0,nv));
     525          28 :         PetscCall(DSGetMat(eps->ds,DS_MAT_A,&pA));
     526          28 :         PetscCall(MatZeroEntries(pA));
     527          28 :         PetscCall(BVMatProject(ctx->S,A,ctx->S,pA));
     528          28 :         PetscCall(DSRestoreMat(eps->ds,DS_MAT_A,&pA));
     529          28 :         if (B) {
     530          11 :           PetscCall(DSGetMat(eps->ds,DS_MAT_B,&pB));
     531          11 :           PetscCall(MatZeroEntries(pB));
     532          11 :           PetscCall(BVMatProject(ctx->S,B,ctx->S,pB));
     533          11 :           PetscCall(DSRestoreMat(eps->ds,DS_MAT_B,&pB));
     534             :         }
     535             :       }
     536             : 
     537          35 :       PetscCall(DSSolve(eps->ds,eps->eigr,eps->eigi));
     538          35 :       PetscCall(DSSynchronize(eps->ds,eps->eigr,eps->eigi));
     539             : 
     540          35 :       PetscCall(PetscMalloc3(nv,&fl1,nv,&inside,nv,&rr));
     541          35 :       PetscCall(rescale_eig(eps,nv));
     542          35 :       PetscCall(DSVectors(eps->ds,DS_MAT_X,NULL,NULL));
     543          35 :       PetscCall(DSGetMat(eps->ds,DS_MAT_X,&X));
     544          35 :       PetscCall(SlepcCISS_isGhost(X,nv,ctx->sigma,ctx->spurious_threshold,fl1));
     545          35 :       PetscCall(DSRestoreMat(eps->ds,DS_MAT_X,&X));
     546          35 :       PetscCall(RGCheckInside(eps->rg,nv,eps->eigr,eps->eigi,inside));
     547        1195 :       for (i=0;i<nv;i++) {
     548        1160 :         if (fl1[i] && inside[i]>=0) {
     549         269 :           rr[i] = 1.0;
     550         269 :           eps->nconv++;
     551         891 :         } else rr[i] = 0.0;
     552             :       }
     553          35 :       PetscCall(DSSort(eps->ds,eps->eigr,eps->eigi,rr,NULL,&eps->nconv));
     554          35 :       PetscCall(DSSynchronize(eps->ds,eps->eigr,eps->eigi));
     555          35 :       PetscCall(rescale_eig(eps,nv));
     556          35 :       PetscCall(PetscFree3(fl1,inside,rr));
     557          35 :       PetscCall(BVSetActiveColumns(eps->V,0,nv));
     558          35 :       if (ctx->extraction == EPS_CISS_EXTRACTION_HANKEL) {
     559           7 :         PetscCall(BVSumQuadrature(ctx->S,ctx->Y,ctx->M,ctx->L,ctx->L,ctx->weight,ctx->pp,contour->scatterin,contour->subcomm,contour->npoints,ctx->useconj));
     560           7 :         PetscCall(BVSetActiveColumns(ctx->S,0,ctx->L));
     561           7 :         PetscCall(BVCopy(ctx->S,ctx->V));
     562           7 :         PetscCall(BVSetActiveColumns(ctx->S,0,nv));
     563             :       }
     564          35 :       PetscCall(BVCopy(ctx->S,eps->V));
     565             : 
     566          35 :       PetscCall(DSVectors(eps->ds,DS_MAT_X,NULL,NULL));
     567          35 :       PetscCall(DSGetMat(eps->ds,DS_MAT_X,&X));
     568          35 :       PetscCall(BVMultInPlace(ctx->S,X,0,eps->nconv));
     569          35 :       if (eps->ishermitian) PetscCall(BVMultInPlace(eps->V,X,0,eps->nconv));
     570          35 :       PetscCall(DSRestoreMat(eps->ds,DS_MAT_X,&X));
     571             :       max_error = 0.0;
     572         304 :       for (i=0;i<eps->nconv;i++) {
     573         269 :         PetscCall(BVGetColumn(ctx->S,i,&si));
     574             : #if !defined(PETSC_USE_COMPLEX)
     575             :         if (eps->eigi[i]!=0.0) PetscCall(BVGetColumn(ctx->S,i+1,&si1));
     576             : #endif
     577         269 :         PetscCall(EPSComputeResidualNorm_Private(eps,PETSC_FALSE,eps->eigr[i],eps->eigi[i],si,si1,w,&error));
     578         269 :         if (ctx->extraction == EPS_CISS_EXTRACTION_HANKEL) {  /* vector is not normalized */
     579          35 :           PetscCall(VecNorm(si,NORM_2,&norm));
     580             : #if !defined(PETSC_USE_COMPLEX)
     581             :           if (eps->eigi[i]!=0.0) {
     582             :             PetscCall(VecNorm(si1,NORM_2,&normi));
     583             :             norm = SlepcAbsEigenvalue(norm,normi);
     584             :           }
     585             : #endif
     586          35 :           error /= norm;
     587             :         }
     588         269 :         PetscCall((*eps->converged)(eps,eps->eigr[i],eps->eigi[i],error,&error,eps->convergedctx));
     589         269 :         PetscCall(BVRestoreColumn(ctx->S,i,&si));
     590             : #if !defined(PETSC_USE_COMPLEX)
     591             :         if (eps->eigi[i]!=0.0) {
     592             :           PetscCall(BVRestoreColumn(ctx->S,i+1,&si1));
     593             :           i++;
     594             :         }
     595             : #endif
     596         369 :         max_error = PetscMax(max_error,error);
     597             :       }
     598             : 
     599          35 :       if (max_error <= eps->tol) eps->reason = EPS_CONVERGED_TOL;
     600           3 :       else if (eps->its >= eps->max_it) eps->reason = EPS_DIVERGED_ITS;
     601             :       else {
     602           2 :         if (eps->nconv > ctx->L) nv = eps->nconv;
     603           0 :         else if (ctx->L > nv) nv = ctx->L;
     604           2 :         nv = PetscMin(nv,ctx->L*ctx->M);
     605           2 :         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,nv,ctx->L,NULL,&M));
     606           2 :         PetscCall(MatSetRandom(M,rand));
     607           2 :         PetscCall(BVSetActiveColumns(ctx->S,0,nv));
     608           2 :         PetscCall(BVMultInPlace(ctx->S,M,0,ctx->L));
     609           2 :         PetscCall(MatDestroy(&M));
     610           2 :         PetscCall(BVSetActiveColumns(ctx->S,0,ctx->L));
     611           2 :         PetscCall(BVSetActiveColumns(ctx->V,0,ctx->L));
     612           2 :         PetscCall(BVCopy(ctx->S,ctx->V));
     613           2 :         if (contour->pA) PetscCall(BVScatter(ctx->V,ctx->pV,contour->scatterin,contour->xdup));
     614          70 :         PetscCall(EPSCISSSolve(eps,J,V,0,ctx->L));
     615             :       }
     616             :     }
     617             :   }
     618          33 :   if (ctx->extraction == EPS_CISS_EXTRACTION_HANKEL) PetscCall(PetscFree(H1));
     619          33 :   PetscCall(PetscFree2(Mu,H0));
     620          33 :   PetscFunctionReturn(PETSC_SUCCESS);
     621             : }
     622             : 
     623          33 : static PetscErrorCode EPSComputeVectors_CISS(EPS eps)
     624             : {
     625          33 :   EPS_CISS       *ctx = (EPS_CISS*)eps->data;
     626          33 :   PetscInt       n;
     627          33 :   Mat            Z,B=NULL;
     628             : 
     629          33 :   PetscFunctionBegin;
     630          33 :   if (eps->ishermitian) {
     631          18 :     if (eps->isgeneralized && !eps->ispositive) PetscCall(EPSComputeVectors_Indefinite(eps));
     632          18 :     else PetscCall(EPSComputeVectors_Hermitian(eps));
     633          18 :     if (eps->isgeneralized && eps->ispositive && ctx->extraction == EPS_CISS_EXTRACTION_HANKEL) {
     634             :       /* normalize to have unit B-norm */
     635           2 :       PetscCall(STGetMatrix(eps->st,1,&B));
     636           2 :       PetscCall(BVSetMatrix(eps->V,B,PETSC_FALSE));
     637           2 :       PetscCall(BVNormalize(eps->V,NULL));
     638           2 :       PetscCall(BVSetMatrix(eps->V,NULL,PETSC_FALSE));
     639             :     }
     640          18 :     PetscFunctionReturn(PETSC_SUCCESS);
     641             :   }
     642          15 :   PetscCall(DSGetDimensions(eps->ds,&n,NULL,NULL,NULL));
     643          15 :   PetscCall(BVSetActiveColumns(eps->V,0,n));
     644             : 
     645             :   /* right eigenvectors */
     646          15 :   PetscCall(DSVectors(eps->ds,DS_MAT_X,NULL,NULL));
     647             : 
     648             :   /* V = V * Z */
     649          15 :   PetscCall(DSGetMat(eps->ds,DS_MAT_X,&Z));
     650          15 :   PetscCall(BVMultInPlace(eps->V,Z,0,n));
     651          15 :   PetscCall(DSRestoreMat(eps->ds,DS_MAT_X,&Z));
     652          15 :   PetscCall(BVSetActiveColumns(eps->V,0,eps->nconv));
     653             : 
     654             :   /* normalize */
     655          15 :   if (ctx->extraction == EPS_CISS_EXTRACTION_HANKEL) PetscCall(BVNormalize(eps->V,NULL));
     656          15 :   PetscFunctionReturn(PETSC_SUCCESS);
     657             : }
     658             : 
     659          15 : static PetscErrorCode EPSCISSSetSizes_CISS(EPS eps,PetscInt ip,PetscInt bs,PetscInt ms,PetscInt npart,PetscInt bsmax,PetscBool realmats)
     660             : {
     661          15 :   EPS_CISS       *ctx = (EPS_CISS*)eps->data;
     662          15 :   PetscInt       oN,oL,oM,oLmax,onpart;
     663          15 :   PetscMPIInt    size;
     664             : 
     665          15 :   PetscFunctionBegin;
     666          15 :   oN = ctx->N;
     667          15 :   if (ip == PETSC_DETERMINE) {
     668           0 :     if (ctx->N!=32) { ctx->N =32; ctx->M = ctx->N/4; }
     669          15 :   } else if (ip != PETSC_CURRENT) {
     670          15 :     PetscCheck(ip>0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The ip argument must be > 0");
     671          15 :     PetscCheck(ip%2==0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The ip argument must be an even number");
     672          15 :     if (ctx->N!=ip) { ctx->N = ip; ctx->M = ctx->N/4; }
     673             :   }
     674          15 :   oL = ctx->L;
     675          15 :   if (bs == PETSC_DETERMINE) {
     676           0 :     ctx->L = 16;
     677          15 :   } else if (bs != PETSC_CURRENT) {
     678          15 :     PetscCheck(bs>0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The bs argument must be > 0");
     679          15 :     ctx->L = bs;
     680             :   }
     681          15 :   oM = ctx->M;
     682          15 :   if (ms == PETSC_DETERMINE) {
     683           0 :     ctx->M = ctx->N/4;
     684          15 :   } else if (ms != PETSC_CURRENT) {
     685          15 :     PetscCheck(ms>0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The ms argument must be > 0");
     686          15 :     PetscCheck(ms<=ctx->N,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The ms argument must be less than or equal to the number of integration points");
     687          15 :     ctx->M = ms;
     688             :   }
     689          15 :   onpart = ctx->npart;
     690          15 :   if (npart == PETSC_DETERMINE) {
     691           0 :     ctx->npart = 1;
     692          15 :   } else if (npart != PETSC_CURRENT) {
     693          15 :     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)eps),&size));
     694          15 :     PetscCheck(npart>0 && npart<=size,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of npart");
     695          15 :     ctx->npart = npart;
     696             :   }
     697          15 :   oLmax = ctx->L_max;
     698          15 :   if (bsmax == PETSC_DETERMINE) {
     699           0 :     ctx->L_max = 64;
     700          15 :   } else if (bsmax != PETSC_CURRENT) {
     701          15 :     PetscCheck(bsmax>0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The bsmax argument must be > 0");
     702          15 :     ctx->L_max = PetscMax(bsmax,ctx->L);
     703             :   }
     704          15 :   if (onpart != ctx->npart || oN != ctx->N || realmats != ctx->isreal) {
     705          14 :     PetscCall(SlepcContourDataDestroy(&ctx->contour));
     706          14 :     PetscCall(PetscInfo(eps,"Resetting the contour data structure due to a change of parameters\n"));
     707          14 :     eps->state = EPS_STATE_INITIAL;
     708             :   }
     709          15 :   ctx->isreal = realmats;
     710          15 :   if (oL != ctx->L || oM != ctx->M || oLmax != ctx->L_max) eps->state = EPS_STATE_INITIAL;
     711          15 :   PetscFunctionReturn(PETSC_SUCCESS);
     712             : }
     713             : 
     714             : /*@
     715             :    EPSCISSSetSizes - Sets the values of various size parameters in the CISS solver.
     716             : 
     717             :    Logically Collective
     718             : 
     719             :    Input Parameters:
     720             : +  eps   - the eigenproblem solver context
     721             : .  ip    - number of integration points
     722             : .  bs    - block size
     723             : .  ms    - moment size
     724             : .  npart - number of partitions when splitting the communicator
     725             : .  bsmax - max block size
     726             : -  realmats - A and B are real
     727             : 
     728             :    Options Database Keys:
     729             : +  -eps_ciss_integration_points - Sets the number of integration points
     730             : .  -eps_ciss_blocksize - Sets the block size
     731             : .  -eps_ciss_moments - Sets the moment size
     732             : .  -eps_ciss_partitions - Sets the number of partitions
     733             : .  -eps_ciss_maxblocksize - Sets the maximum block size
     734             : -  -eps_ciss_realmats - A and B are real
     735             : 
     736             :    Note:
     737             :    For all integer arguments, you can use PETSC_CURRENT to keep the current value, and
     738             :    PETSC_DETERMINE to set them to a default value.
     739             : 
     740             :    The default number of partitions is 1. This means the internal KSP object is shared
     741             :    among all processes of the EPS communicator. Otherwise, the communicator is split
     742             :    into npart communicators, so that npart KSP solves proceed simultaneously.
     743             : 
     744             :    Level: advanced
     745             : 
     746             : .seealso: EPSCISSGetSizes()
     747             : @*/
     748          15 : PetscErrorCode EPSCISSSetSizes(EPS eps,PetscInt ip,PetscInt bs,PetscInt ms,PetscInt npart,PetscInt bsmax,PetscBool realmats)
     749             : {
     750          15 :   PetscFunctionBegin;
     751          15 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     752          45 :   PetscValidLogicalCollectiveInt(eps,ip,2);
     753          45 :   PetscValidLogicalCollectiveInt(eps,bs,3);
     754          45 :   PetscValidLogicalCollectiveInt(eps,ms,4);
     755          45 :   PetscValidLogicalCollectiveInt(eps,npart,5);
     756          45 :   PetscValidLogicalCollectiveInt(eps,bsmax,6);
     757          45 :   PetscValidLogicalCollectiveBool(eps,realmats,7);
     758          15 :   PetscTryMethod(eps,"EPSCISSSetSizes_C",(EPS,PetscInt,PetscInt,PetscInt,PetscInt,PetscInt,PetscBool),(eps,ip,bs,ms,npart,bsmax,realmats));
     759          15 :   PetscFunctionReturn(PETSC_SUCCESS);
     760             : }
     761             : 
     762          33 : static PetscErrorCode EPSCISSGetSizes_CISS(EPS eps,PetscInt *ip,PetscInt *bs,PetscInt *ms,PetscInt *npart,PetscInt *bsmax,PetscBool *realmats)
     763             : {
     764          33 :   EPS_CISS *ctx = (EPS_CISS*)eps->data;
     765             : 
     766          33 :   PetscFunctionBegin;
     767          33 :   if (ip) *ip = ctx->N;
     768          33 :   if (bs) *bs = ctx->L;
     769          33 :   if (ms) *ms = ctx->M;
     770          33 :   if (npart) *npart = ctx->npart;
     771          33 :   if (bsmax) *bsmax = ctx->L_max;
     772          33 :   if (realmats) *realmats = ctx->isreal;
     773          33 :   PetscFunctionReturn(PETSC_SUCCESS);
     774             : }
     775             : 
     776             : /*@
     777             :    EPSCISSGetSizes - Gets the values of various size parameters in the CISS solver.
     778             : 
     779             :    Not Collective
     780             : 
     781             :    Input Parameter:
     782             : .  eps - the eigenproblem solver context
     783             : 
     784             :    Output Parameters:
     785             : +  ip    - number of integration points
     786             : .  bs    - block size
     787             : .  ms    - moment size
     788             : .  npart - number of partitions when splitting the communicator
     789             : .  bsmax - max block size
     790             : -  realmats - A and B are real
     791             : 
     792             :    Level: advanced
     793             : 
     794             : .seealso: EPSCISSSetSizes()
     795             : @*/
     796          33 : PetscErrorCode EPSCISSGetSizes(EPS eps,PetscInt *ip,PetscInt *bs,PetscInt *ms,PetscInt *npart,PetscInt *bsmax,PetscBool *realmats)
     797             : {
     798          33 :   PetscFunctionBegin;
     799          33 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     800          33 :   PetscUseMethod(eps,"EPSCISSGetSizes_C",(EPS,PetscInt*,PetscInt*,PetscInt*,PetscInt*,PetscInt*,PetscBool*),(eps,ip,bs,ms,npart,bsmax,realmats));
     801          33 :   PetscFunctionReturn(PETSC_SUCCESS);
     802             : }
     803             : 
     804           2 : static PetscErrorCode EPSCISSSetThreshold_CISS(EPS eps,PetscReal delta,PetscReal spur)
     805             : {
     806           2 :   EPS_CISS *ctx = (EPS_CISS*)eps->data;
     807             : 
     808           2 :   PetscFunctionBegin;
     809           2 :   if (delta == (PetscReal)PETSC_DETERMINE) {
     810           0 :     ctx->delta = SLEPC_DEFAULT_TOL*1e-4;
     811           2 :   } else if (delta != (PetscReal)PETSC_CURRENT) {
     812           2 :     PetscCheck(delta>0.0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The delta argument must be > 0.0");
     813           2 :     ctx->delta = delta;
     814             :   }
     815           2 :   if (spur == (PetscReal)PETSC_DETERMINE) {
     816           0 :     ctx->spurious_threshold = PetscSqrtReal(SLEPC_DEFAULT_TOL);
     817           2 :   } else if (spur != (PetscReal)PETSC_CURRENT) {
     818           2 :     PetscCheck(spur>0.0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The spurious threshold argument must be > 0.0");
     819           2 :     ctx->spurious_threshold = spur;
     820             :   }
     821           2 :   PetscFunctionReturn(PETSC_SUCCESS);
     822             : }
     823             : 
     824             : /*@
     825             :    EPSCISSSetThreshold - Sets the values of various threshold parameters in
     826             :    the CISS solver.
     827             : 
     828             :    Logically Collective
     829             : 
     830             :    Input Parameters:
     831             : +  eps   - the eigenproblem solver context
     832             : .  delta - threshold for numerical rank
     833             : -  spur  - spurious threshold (to discard spurious eigenpairs)
     834             : 
     835             :    Options Database Keys:
     836             : +  -eps_ciss_delta - Sets the delta
     837             : -  -eps_ciss_spurious_threshold - Sets the spurious threshold
     838             : 
     839             :    Note:
     840             :    PETSC_CURRENT can be used to preserve the current value of any of the
     841             :    arguments, and PETSC_DETERMINE to set them to a default value.
     842             : 
     843             :    Level: advanced
     844             : 
     845             : .seealso: EPSCISSGetThreshold()
     846             : @*/
     847           2 : PetscErrorCode EPSCISSSetThreshold(EPS eps,PetscReal delta,PetscReal spur)
     848             : {
     849           2 :   PetscFunctionBegin;
     850           2 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     851           6 :   PetscValidLogicalCollectiveReal(eps,delta,2);
     852           6 :   PetscValidLogicalCollectiveReal(eps,spur,3);
     853           2 :   PetscTryMethod(eps,"EPSCISSSetThreshold_C",(EPS,PetscReal,PetscReal),(eps,delta,spur));
     854           2 :   PetscFunctionReturn(PETSC_SUCCESS);
     855             : }
     856             : 
     857          33 : static PetscErrorCode EPSCISSGetThreshold_CISS(EPS eps,PetscReal *delta,PetscReal *spur)
     858             : {
     859          33 :   EPS_CISS *ctx = (EPS_CISS*)eps->data;
     860             : 
     861          33 :   PetscFunctionBegin;
     862          33 :   if (delta) *delta = ctx->delta;
     863          33 :   if (spur)  *spur = ctx->spurious_threshold;
     864          33 :   PetscFunctionReturn(PETSC_SUCCESS);
     865             : }
     866             : 
     867             : /*@
     868             :    EPSCISSGetThreshold - Gets the values of various threshold parameters
     869             :    in the CISS solver.
     870             : 
     871             :    Not Collective
     872             : 
     873             :    Input Parameter:
     874             : .  eps - the eigenproblem solver context
     875             : 
     876             :    Output Parameters:
     877             : +  delta - threshold for numerical rank
     878             : -  spur  - spurious threshold (to discard spurious eigenpairs)
     879             : 
     880             :    Level: advanced
     881             : 
     882             : .seealso: EPSCISSSetThreshold()
     883             : @*/
     884          33 : PetscErrorCode EPSCISSGetThreshold(EPS eps,PetscReal *delta,PetscReal *spur)
     885             : {
     886          33 :   PetscFunctionBegin;
     887          33 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     888          33 :   PetscUseMethod(eps,"EPSCISSGetThreshold_C",(EPS,PetscReal*,PetscReal*),(eps,delta,spur));
     889          33 :   PetscFunctionReturn(PETSC_SUCCESS);
     890             : }
     891             : 
     892           1 : static PetscErrorCode EPSCISSSetRefinement_CISS(EPS eps,PetscInt inner,PetscInt blsize)
     893             : {
     894           1 :   EPS_CISS *ctx = (EPS_CISS*)eps->data;
     895             : 
     896           1 :   PetscFunctionBegin;
     897           1 :   if (inner == PETSC_DETERMINE) {
     898           0 :     ctx->refine_inner = 0;
     899           1 :   } else if (inner != PETSC_CURRENT) {
     900           1 :     PetscCheck(inner>=0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The refine inner argument must be >= 0");
     901           1 :     ctx->refine_inner = inner;
     902             :   }
     903           1 :   if (blsize == PETSC_DETERMINE) {
     904           0 :     ctx->refine_blocksize = 0;
     905           1 :   } else if (blsize != PETSC_CURRENT) {
     906           1 :     PetscCheck(blsize>=0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The refine blocksize argument must be >= 0");
     907           1 :     ctx->refine_blocksize = blsize;
     908             :   }
     909           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     910             : }
     911             : 
     912             : /*@
     913             :    EPSCISSSetRefinement - Sets the values of various refinement parameters
     914             :    in the CISS solver.
     915             : 
     916             :    Logically Collective
     917             : 
     918             :    Input Parameters:
     919             : +  eps    - the eigenproblem solver context
     920             : .  inner  - number of iterative refinement iterations (inner loop)
     921             : -  blsize - number of iterative refinement iterations (blocksize loop)
     922             : 
     923             :    Options Database Keys:
     924             : +  -eps_ciss_refine_inner - Sets number of inner iterations
     925             : -  -eps_ciss_refine_blocksize - Sets number of blocksize iterations
     926             : 
     927             :    Note:
     928             :    PETSC_CURRENT can be used to preserve the current value of any of the
     929             :    arguments, and PETSC_DETERMINE to set them to a default of 0.
     930             : 
     931             :    Level: advanced
     932             : 
     933             : .seealso: EPSCISSGetRefinement()
     934             : @*/
     935           1 : PetscErrorCode EPSCISSSetRefinement(EPS eps,PetscInt inner,PetscInt blsize)
     936             : {
     937           1 :   PetscFunctionBegin;
     938           1 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     939           3 :   PetscValidLogicalCollectiveInt(eps,inner,2);
     940           3 :   PetscValidLogicalCollectiveInt(eps,blsize,3);
     941           1 :   PetscTryMethod(eps,"EPSCISSSetRefinement_C",(EPS,PetscInt,PetscInt),(eps,inner,blsize));
     942           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     943             : }
     944             : 
     945          33 : static PetscErrorCode EPSCISSGetRefinement_CISS(EPS eps,PetscInt *inner,PetscInt *blsize)
     946             : {
     947          33 :   EPS_CISS *ctx = (EPS_CISS*)eps->data;
     948             : 
     949          33 :   PetscFunctionBegin;
     950          33 :   if (inner)  *inner = ctx->refine_inner;
     951          33 :   if (blsize) *blsize = ctx->refine_blocksize;
     952          33 :   PetscFunctionReturn(PETSC_SUCCESS);
     953             : }
     954             : 
     955             : /*@
     956             :    EPSCISSGetRefinement - Gets the values of various refinement parameters
     957             :    in the CISS solver.
     958             : 
     959             :    Not Collective
     960             : 
     961             :    Input Parameter:
     962             : .  eps - the eigenproblem solver context
     963             : 
     964             :    Output Parameters:
     965             : +  inner  - number of iterative refinement iterations (inner loop)
     966             : -  blsize - number of iterative refinement iterations (blocksize loop)
     967             : 
     968             :    Level: advanced
     969             : 
     970             : .seealso: EPSCISSSetRefinement()
     971             : @*/
     972          33 : PetscErrorCode EPSCISSGetRefinement(EPS eps, PetscInt *inner, PetscInt *blsize)
     973             : {
     974          33 :   PetscFunctionBegin;
     975          33 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     976          33 :   PetscUseMethod(eps,"EPSCISSGetRefinement_C",(EPS,PetscInt*,PetscInt*),(eps,inner,blsize));
     977          33 :   PetscFunctionReturn(PETSC_SUCCESS);
     978             : }
     979             : 
     980          11 : static PetscErrorCode EPSCISSSetUseST_CISS(EPS eps,PetscBool usest)
     981             : {
     982          11 :   EPS_CISS *ctx = (EPS_CISS*)eps->data;
     983             : 
     984          11 :   PetscFunctionBegin;
     985          11 :   ctx->usest     = usest;
     986          11 :   ctx->usest_set = PETSC_TRUE;
     987          11 :   eps->state     = EPS_STATE_INITIAL;
     988          11 :   PetscFunctionReturn(PETSC_SUCCESS);
     989             : }
     990             : 
     991             : /*@
     992             :    EPSCISSSetUseST - Sets a flag indicating that the CISS solver will
     993             :    use the ST object for the linear solves.
     994             : 
     995             :    Logically Collective
     996             : 
     997             :    Input Parameters:
     998             : +  eps    - the eigenproblem solver context
     999             : -  usest  - boolean flag to use the ST object or not
    1000             : 
    1001             :    Options Database Keys:
    1002             : .  -eps_ciss_usest <bool> - whether the ST object will be used or not
    1003             : 
    1004             :    Level: advanced
    1005             : 
    1006             : .seealso: EPSCISSGetUseST()
    1007             : @*/
    1008          11 : PetscErrorCode EPSCISSSetUseST(EPS eps,PetscBool usest)
    1009             : {
    1010          11 :   PetscFunctionBegin;
    1011          11 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
    1012          33 :   PetscValidLogicalCollectiveBool(eps,usest,2);
    1013          11 :   PetscTryMethod(eps,"EPSCISSSetUseST_C",(EPS,PetscBool),(eps,usest));
    1014          11 :   PetscFunctionReturn(PETSC_SUCCESS);
    1015             : }
    1016             : 
    1017          33 : static PetscErrorCode EPSCISSGetUseST_CISS(EPS eps,PetscBool *usest)
    1018             : {
    1019          33 :   EPS_CISS *ctx = (EPS_CISS*)eps->data;
    1020             : 
    1021          33 :   PetscFunctionBegin;
    1022          33 :   *usest = ctx->usest;
    1023          33 :   PetscFunctionReturn(PETSC_SUCCESS);
    1024             : }
    1025             : 
    1026             : /*@
    1027             :    EPSCISSGetUseST - Gets the flag for using the ST object
    1028             :    in the CISS solver.
    1029             : 
    1030             :    Not Collective
    1031             : 
    1032             :    Input Parameter:
    1033             : .  eps - the eigenproblem solver context
    1034             : 
    1035             :    Output Parameters:
    1036             : .  usest - boolean flag indicating if the ST object is being used
    1037             : 
    1038             :    Level: advanced
    1039             : 
    1040             : .seealso: EPSCISSSetUseST()
    1041             : @*/
    1042          33 : PetscErrorCode EPSCISSGetUseST(EPS eps,PetscBool *usest)
    1043             : {
    1044          33 :   PetscFunctionBegin;
    1045          33 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
    1046          33 :   PetscAssertPointer(usest,2);
    1047          33 :   PetscUseMethod(eps,"EPSCISSGetUseST_C",(EPS,PetscBool*),(eps,usest));
    1048          33 :   PetscFunctionReturn(PETSC_SUCCESS);
    1049             : }
    1050             : 
    1051           6 : static PetscErrorCode EPSCISSSetQuadRule_CISS(EPS eps,EPSCISSQuadRule quad)
    1052             : {
    1053           6 :   EPS_CISS *ctx = (EPS_CISS*)eps->data;
    1054             : 
    1055           6 :   PetscFunctionBegin;
    1056           6 :   if (ctx->quad != quad) {
    1057           6 :     ctx->quad  = quad;
    1058           6 :     eps->state = EPS_STATE_INITIAL;
    1059             :   }
    1060           6 :   PetscFunctionReturn(PETSC_SUCCESS);
    1061             : }
    1062             : 
    1063             : /*@
    1064             :    EPSCISSSetQuadRule - Sets the quadrature rule used in the CISS solver.
    1065             : 
    1066             :    Logically Collective
    1067             : 
    1068             :    Input Parameters:
    1069             : +  eps  - the eigenproblem solver context
    1070             : -  quad - the quadrature rule
    1071             : 
    1072             :    Options Database Key:
    1073             : .  -eps_ciss_quadrule - Sets the quadrature rule (either 'trapezoidal' or
    1074             :                            'chebyshev')
    1075             : 
    1076             :    Notes:
    1077             :    By default, the trapezoidal rule is used (EPS_CISS_QUADRULE_TRAPEZOIDAL).
    1078             : 
    1079             :    If the 'chebyshev' option is specified (EPS_CISS_QUADRULE_CHEBYSHEV), then
    1080             :    Chebyshev points are used as quadrature points.
    1081             : 
    1082             :    Level: advanced
    1083             : 
    1084             : .seealso: EPSCISSGetQuadRule(), EPSCISSQuadRule
    1085             : @*/
    1086           6 : PetscErrorCode EPSCISSSetQuadRule(EPS eps,EPSCISSQuadRule quad)
    1087             : {
    1088           6 :   PetscFunctionBegin;
    1089           6 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
    1090          18 :   PetscValidLogicalCollectiveEnum(eps,quad,2);
    1091           6 :   PetscTryMethod(eps,"EPSCISSSetQuadRule_C",(EPS,EPSCISSQuadRule),(eps,quad));
    1092           6 :   PetscFunctionReturn(PETSC_SUCCESS);
    1093             : }
    1094             : 
    1095           1 : static PetscErrorCode EPSCISSGetQuadRule_CISS(EPS eps,EPSCISSQuadRule *quad)
    1096             : {
    1097           1 :   EPS_CISS *ctx = (EPS_CISS*)eps->data;
    1098             : 
    1099           1 :   PetscFunctionBegin;
    1100           1 :   *quad = ctx->quad;
    1101           1 :   PetscFunctionReturn(PETSC_SUCCESS);
    1102             : }
    1103             : 
    1104             : /*@
    1105             :    EPSCISSGetQuadRule - Gets the quadrature rule used in the CISS solver.
    1106             : 
    1107             :    Not Collective
    1108             : 
    1109             :    Input Parameter:
    1110             : .  eps - the eigenproblem solver context
    1111             : 
    1112             :    Output Parameters:
    1113             : .  quad - quadrature rule
    1114             : 
    1115             :    Level: advanced
    1116             : 
    1117             : .seealso: EPSCISSSetQuadRule() EPSCISSQuadRule
    1118             : @*/
    1119           1 : PetscErrorCode EPSCISSGetQuadRule(EPS eps,EPSCISSQuadRule *quad)
    1120             : {
    1121           1 :   PetscFunctionBegin;
    1122           1 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
    1123           1 :   PetscAssertPointer(quad,2);
    1124           1 :   PetscUseMethod(eps,"EPSCISSGetQuadRule_C",(EPS,EPSCISSQuadRule*),(eps,quad));
    1125           1 :   PetscFunctionReturn(PETSC_SUCCESS);
    1126             : }
    1127             : 
    1128           8 : static PetscErrorCode EPSCISSSetExtraction_CISS(EPS eps,EPSCISSExtraction extraction)
    1129             : {
    1130           8 :   EPS_CISS *ctx = (EPS_CISS*)eps->data;
    1131             : 
    1132           8 :   PetscFunctionBegin;
    1133           8 :   if (ctx->extraction != extraction) {
    1134           6 :     ctx->extraction = extraction;
    1135           6 :     eps->state      = EPS_STATE_INITIAL;
    1136             :   }
    1137           8 :   PetscFunctionReturn(PETSC_SUCCESS);
    1138             : }
    1139             : 
    1140             : /*@
    1141             :    EPSCISSSetExtraction - Sets the extraction technique used in the CISS solver.
    1142             : 
    1143             :    Logically Collective
    1144             : 
    1145             :    Input Parameters:
    1146             : +  eps        - the eigenproblem solver context
    1147             : -  extraction - the extraction technique
    1148             : 
    1149             :    Options Database Key:
    1150             : .  -eps_ciss_extraction - Sets the extraction technique (either 'ritz' or
    1151             :                            'hankel')
    1152             : 
    1153             :    Notes:
    1154             :    By default, the Rayleigh-Ritz extraction is used (EPS_CISS_EXTRACTION_RITZ).
    1155             : 
    1156             :    If the 'hankel' option is specified (EPS_CISS_EXTRACTION_HANKEL), then
    1157             :    the Block Hankel method is used for extracting eigenpairs.
    1158             : 
    1159             :    Level: advanced
    1160             : 
    1161             : .seealso: EPSCISSGetExtraction(), EPSCISSExtraction
    1162             : @*/
    1163           8 : PetscErrorCode EPSCISSSetExtraction(EPS eps,EPSCISSExtraction extraction)
    1164             : {
    1165           8 :   PetscFunctionBegin;
    1166           8 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
    1167          24 :   PetscValidLogicalCollectiveEnum(eps,extraction,2);
    1168           8 :   PetscTryMethod(eps,"EPSCISSSetExtraction_C",(EPS,EPSCISSExtraction),(eps,extraction));
    1169           8 :   PetscFunctionReturn(PETSC_SUCCESS);
    1170             : }
    1171             : 
    1172           1 : static PetscErrorCode EPSCISSGetExtraction_CISS(EPS eps,EPSCISSExtraction *extraction)
    1173             : {
    1174           1 :   EPS_CISS *ctx = (EPS_CISS*)eps->data;
    1175             : 
    1176           1 :   PetscFunctionBegin;
    1177           1 :   *extraction = ctx->extraction;
    1178           1 :   PetscFunctionReturn(PETSC_SUCCESS);
    1179             : }
    1180             : 
    1181             : /*@
    1182             :    EPSCISSGetExtraction - Gets the extraction technique used in the CISS solver.
    1183             : 
    1184             :    Not Collective
    1185             : 
    1186             :    Input Parameter:
    1187             : .  eps - the eigenproblem solver context
    1188             : 
    1189             :    Output Parameters:
    1190             : .  extraction - extraction technique
    1191             : 
    1192             :    Level: advanced
    1193             : 
    1194             : .seealso: EPSCISSSetExtraction() EPSCISSExtraction
    1195             : @*/
    1196           1 : PetscErrorCode EPSCISSGetExtraction(EPS eps,EPSCISSExtraction *extraction)
    1197             : {
    1198           1 :   PetscFunctionBegin;
    1199           1 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
    1200           1 :   PetscAssertPointer(extraction,2);
    1201           1 :   PetscUseMethod(eps,"EPSCISSGetExtraction_C",(EPS,EPSCISSExtraction*),(eps,extraction));
    1202           1 :   PetscFunctionReturn(PETSC_SUCCESS);
    1203             : }
    1204             : 
    1205          33 : static PetscErrorCode EPSCISSGetKSPs_CISS(EPS eps,PetscInt *nsolve,KSP **ksp)
    1206             : {
    1207          33 :   EPS_CISS         *ctx = (EPS_CISS*)eps->data;
    1208          33 :   SlepcContourData contour;
    1209          33 :   PetscInt         i,nsplit;
    1210          33 :   PC               pc;
    1211          33 :   MPI_Comm         child;
    1212             : 
    1213          33 :   PetscFunctionBegin;
    1214          33 :   if (!ctx->contour) {  /* initialize contour data structure first */
    1215          33 :     PetscCall(RGCanUseConjugates(eps->rg,ctx->isreal,&ctx->useconj));
    1216          33 :     PetscCall(SlepcContourDataCreate(ctx->useconj?ctx->N/2:ctx->N,ctx->npart,(PetscObject)eps,&ctx->contour));
    1217             :   }
    1218          33 :   contour = ctx->contour;
    1219          33 :   if (!contour->ksp) {
    1220          33 :     PetscCall(PetscMalloc1(contour->npoints,&contour->ksp));
    1221          33 :     PetscCall(EPSGetST(eps,&eps->st));
    1222          33 :     PetscCall(STGetSplitPreconditionerInfo(eps->st,&nsplit,NULL));
    1223          33 :     PetscCall(PetscSubcommGetChild(contour->subcomm,&child));
    1224         841 :     for (i=0;i<contour->npoints;i++) {
    1225         808 :       PetscCall(KSPCreate(child,&contour->ksp[i]));
    1226         808 :       PetscCall(PetscObjectIncrementTabLevel((PetscObject)contour->ksp[i],(PetscObject)eps,1));
    1227         808 :       PetscCall(KSPSetOptionsPrefix(contour->ksp[i],((PetscObject)eps)->prefix));
    1228         808 :       PetscCall(KSPAppendOptionsPrefix(contour->ksp[i],"eps_ciss_"));
    1229         808 :       PetscCall(PetscObjectSetOptions((PetscObject)contour->ksp[i],((PetscObject)eps)->options));
    1230         808 :       PetscCall(KSPSetErrorIfNotConverged(contour->ksp[i],PETSC_TRUE));
    1231        1224 :       PetscCall(KSPSetTolerances(contour->ksp[i],SlepcDefaultTol(eps->tol),PETSC_CURRENT,PETSC_CURRENT,PETSC_CURRENT));
    1232         808 :       PetscCall(KSPGetPC(contour->ksp[i],&pc));
    1233         808 :       if (nsplit) {
    1234          96 :         PetscCall(KSPSetType(contour->ksp[i],KSPBCGS));
    1235          96 :         PetscCall(PCSetType(pc,PCBJACOBI));
    1236             :       } else {
    1237         712 :         PetscCall(KSPSetType(contour->ksp[i],KSPPREONLY));
    1238         808 :         PetscCall(PCSetType(pc,PCLU));
    1239             :       }
    1240             :     }
    1241             :   }
    1242          33 :   if (nsolve) *nsolve = contour->npoints;
    1243          33 :   if (ksp)    *ksp    = contour->ksp;
    1244          33 :   PetscFunctionReturn(PETSC_SUCCESS);
    1245             : }
    1246             : 
    1247             : /*@C
    1248             :    EPSCISSGetKSPs - Retrieve the array of linear solver objects associated with
    1249             :    the CISS solver.
    1250             : 
    1251             :    Not Collective
    1252             : 
    1253             :    Input Parameter:
    1254             : .  eps - the eigenproblem solver solver
    1255             : 
    1256             :    Output Parameters:
    1257             : +  nsolve - number of solver objects
    1258             : -  ksp - array of linear solver object
    1259             : 
    1260             :    Notes:
    1261             :    The number of KSP solvers is equal to the number of integration points divided by
    1262             :    the number of partitions. This value is halved in the case of real matrices with
    1263             :    a region centered at the real axis.
    1264             : 
    1265             :    Level: advanced
    1266             : 
    1267             : .seealso: EPSCISSSetSizes()
    1268             : @*/
    1269          33 : PetscErrorCode EPSCISSGetKSPs(EPS eps,PetscInt *nsolve,KSP **ksp)
    1270             : {
    1271          33 :   PetscFunctionBegin;
    1272          33 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
    1273          33 :   PetscUseMethod(eps,"EPSCISSGetKSPs_C",(EPS,PetscInt*,KSP**),(eps,nsolve,ksp));
    1274          33 :   PetscFunctionReturn(PETSC_SUCCESS);
    1275             : }
    1276             : 
    1277          33 : static PetscErrorCode EPSReset_CISS(EPS eps)
    1278             : {
    1279          33 :   EPS_CISS       *ctx = (EPS_CISS*)eps->data;
    1280             : 
    1281          33 :   PetscFunctionBegin;
    1282          33 :   PetscCall(BVDestroy(&ctx->S));
    1283          33 :   PetscCall(BVDestroy(&ctx->V));
    1284          33 :   PetscCall(BVDestroy(&ctx->Y));
    1285          33 :   if (!ctx->usest) PetscCall(SlepcContourDataReset(ctx->contour));
    1286          33 :   PetscCall(BVDestroy(&ctx->pV));
    1287          33 :   PetscFunctionReturn(PETSC_SUCCESS);
    1288             : }
    1289             : 
    1290          33 : static PetscErrorCode EPSSetFromOptions_CISS(EPS eps,PetscOptionItems *PetscOptionsObject)
    1291             : {
    1292          33 :   PetscReal         r3,r4;
    1293          33 :   PetscInt          i,i1,i2,i3,i4,i5,i6,i7;
    1294          33 :   PetscBool         b1,b2,flg,flg2,flg3,flg4,flg5,flg6;
    1295          33 :   EPS_CISS          *ctx = (EPS_CISS*)eps->data;
    1296          33 :   EPSCISSQuadRule   quad;
    1297          33 :   EPSCISSExtraction extraction;
    1298             : 
    1299          33 :   PetscFunctionBegin;
    1300          33 :   PetscOptionsHeadBegin(PetscOptionsObject,"EPS CISS Options");
    1301             : 
    1302          33 :     PetscCall(EPSCISSGetSizes(eps,&i1,&i2,&i3,&i4,&i5,&b1));
    1303          33 :     PetscCall(PetscOptionsInt("-eps_ciss_integration_points","Number of integration points","EPSCISSSetSizes",i1,&i1,&flg));
    1304          33 :     PetscCall(PetscOptionsInt("-eps_ciss_blocksize","Block size","EPSCISSSetSizes",i2,&i2,&flg2));
    1305          33 :     PetscCall(PetscOptionsInt("-eps_ciss_moments","Moment size","EPSCISSSetSizes",i3,&i3,&flg3));
    1306          33 :     PetscCall(PetscOptionsInt("-eps_ciss_partitions","Number of partitions","EPSCISSSetSizes",i4,&i4,&flg4));
    1307          33 :     PetscCall(PetscOptionsInt("-eps_ciss_maxblocksize","Maximum block size","EPSCISSSetSizes",i5,&i5,&flg5));
    1308          33 :     PetscCall(PetscOptionsBool("-eps_ciss_realmats","True if A and B are real","EPSCISSSetSizes",b1,&b1,&flg6));
    1309          33 :     if (flg || flg2 || flg3 || flg4 || flg5 || flg6) PetscCall(EPSCISSSetSizes(eps,i1,i2,i3,i4,i5,b1));
    1310             : 
    1311          33 :     PetscCall(EPSCISSGetThreshold(eps,&r3,&r4));
    1312          33 :     PetscCall(PetscOptionsReal("-eps_ciss_delta","Threshold for numerical rank","EPSCISSSetThreshold",r3,&r3,&flg));
    1313          33 :     PetscCall(PetscOptionsReal("-eps_ciss_spurious_threshold","Threshold for the spurious eigenpairs","EPSCISSSetThreshold",r4,&r4,&flg2));
    1314          33 :     if (flg || flg2) PetscCall(EPSCISSSetThreshold(eps,r3,r4));
    1315             : 
    1316          33 :     PetscCall(EPSCISSGetRefinement(eps,&i6,&i7));
    1317          33 :     PetscCall(PetscOptionsInt("-eps_ciss_refine_inner","Number of inner iterative refinement iterations","EPSCISSSetRefinement",i6,&i6,&flg));
    1318          33 :     PetscCall(PetscOptionsInt("-eps_ciss_refine_blocksize","Number of blocksize iterative refinement iterations","EPSCISSSetRefinement",i7,&i7,&flg2));
    1319          33 :     if (flg || flg2) PetscCall(EPSCISSSetRefinement(eps,i6,i7));
    1320             : 
    1321          33 :     PetscCall(EPSCISSGetUseST(eps,&b2));
    1322          33 :     PetscCall(PetscOptionsBool("-eps_ciss_usest","Use ST for linear solves","EPSCISSSetUseST",b2,&b2,&flg));
    1323          33 :     if (flg) PetscCall(EPSCISSSetUseST(eps,b2));
    1324             : 
    1325          33 :     PetscCall(PetscOptionsEnum("-eps_ciss_quadrule","Quadrature rule","EPSCISSSetQuadRule",EPSCISSQuadRules,(PetscEnum)ctx->quad,(PetscEnum*)&quad,&flg));
    1326          33 :     if (flg) PetscCall(EPSCISSSetQuadRule(eps,quad));
    1327             : 
    1328          33 :     PetscCall(PetscOptionsEnum("-eps_ciss_extraction","Extraction technique","EPSCISSSetExtraction",EPSCISSExtractions,(PetscEnum)ctx->extraction,(PetscEnum*)&extraction,&flg));
    1329          33 :     if (flg) PetscCall(EPSCISSSetExtraction(eps,extraction));
    1330             : 
    1331          33 :   PetscOptionsHeadEnd();
    1332             : 
    1333          33 :   if (!eps->rg) PetscCall(EPSGetRG(eps,&eps->rg));
    1334          33 :   PetscCall(RGSetFromOptions(eps->rg)); /* this is necessary here to set useconj */
    1335          33 :   if (!ctx->contour || !ctx->contour->ksp) PetscCall(EPSCISSGetKSPs(eps,NULL,NULL));
    1336          33 :   PetscAssert(ctx->contour && ctx->contour->ksp,PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Something went wrong with EPSCISSGetKSPs()");
    1337         841 :   for (i=0;i<ctx->contour->npoints;i++) PetscCall(KSPSetFromOptions(ctx->contour->ksp[i]));
    1338          33 :   PetscCall(PetscSubcommSetFromOptions(ctx->contour->subcomm));
    1339          33 :   PetscFunctionReturn(PETSC_SUCCESS);
    1340             : }
    1341             : 
    1342          33 : static PetscErrorCode EPSDestroy_CISS(EPS eps)
    1343             : {
    1344          33 :   EPS_CISS       *ctx = (EPS_CISS*)eps->data;
    1345             : 
    1346          33 :   PetscFunctionBegin;
    1347          33 :   PetscCall(SlepcContourDataDestroy(&ctx->contour));
    1348          33 :   PetscCall(PetscFree4(ctx->weight,ctx->omega,ctx->pp,ctx->sigma));
    1349          33 :   PetscCall(PetscFree(eps->data));
    1350          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSSetSizes_C",NULL));
    1351          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSGetSizes_C",NULL));
    1352          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSSetThreshold_C",NULL));
    1353          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSGetThreshold_C",NULL));
    1354          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSSetRefinement_C",NULL));
    1355          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSGetRefinement_C",NULL));
    1356          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSSetUseST_C",NULL));
    1357          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSGetUseST_C",NULL));
    1358          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSSetQuadRule_C",NULL));
    1359          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSGetQuadRule_C",NULL));
    1360          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSSetExtraction_C",NULL));
    1361          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSGetExtraction_C",NULL));
    1362          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSGetKSPs_C",NULL));
    1363          33 :   PetscFunctionReturn(PETSC_SUCCESS);
    1364             : }
    1365             : 
    1366           0 : static PetscErrorCode EPSView_CISS(EPS eps,PetscViewer viewer)
    1367             : {
    1368           0 :   EPS_CISS       *ctx = (EPS_CISS*)eps->data;
    1369           0 :   PetscBool      isascii;
    1370           0 :   PetscViewer    sviewer;
    1371             : 
    1372           0 :   PetscFunctionBegin;
    1373           0 :   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
    1374           0 :   if (isascii) {
    1375           0 :     PetscCall(PetscViewerASCIIPrintf(viewer,"  sizes { integration points: %" PetscInt_FMT ", block size: %" PetscInt_FMT ", moment size: %" PetscInt_FMT ", partitions: %" PetscInt_FMT ", maximum block size: %" PetscInt_FMT " }\n",ctx->N,ctx->L,ctx->M,ctx->npart,ctx->L_max));
    1376           0 :     if (ctx->isreal) PetscCall(PetscViewerASCIIPrintf(viewer,"  exploiting symmetry of integration points\n"));
    1377           0 :     PetscCall(PetscViewerASCIIPrintf(viewer,"  threshold { delta: %g, spurious threshold: %g }\n",(double)ctx->delta,(double)ctx->spurious_threshold));
    1378           0 :     PetscCall(PetscViewerASCIIPrintf(viewer,"  iterative refinement { inner: %" PetscInt_FMT ", blocksize: %" PetscInt_FMT " }\n",ctx->refine_inner, ctx->refine_blocksize));
    1379           0 :     PetscCall(PetscViewerASCIIPrintf(viewer,"  extraction: %s\n",EPSCISSExtractions[ctx->extraction]));
    1380           0 :     PetscCall(PetscViewerASCIIPrintf(viewer,"  quadrature rule: %s\n",EPSCISSQuadRules[ctx->quad]));
    1381           0 :     if (ctx->usest) PetscCall(PetscViewerASCIIPrintf(viewer,"  using ST for linear solves\n"));
    1382             :     else {
    1383           0 :       if (!ctx->contour || !ctx->contour->ksp) PetscCall(EPSCISSGetKSPs(eps,NULL,NULL));
    1384           0 :       PetscAssert(ctx->contour && ctx->contour->ksp,PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Something went wrong with EPSCISSGetKSPs()");
    1385           0 :       PetscCall(PetscViewerASCIIPushTab(viewer));
    1386           0 :       if (ctx->npart>1 && ctx->contour->subcomm) {
    1387           0 :         PetscCall(PetscViewerGetSubViewer(viewer,ctx->contour->subcomm->child,&sviewer));
    1388           0 :         if (!ctx->contour->subcomm->color) PetscCall(KSPView(ctx->contour->ksp[0],sviewer));
    1389           0 :         PetscCall(PetscViewerFlush(sviewer));
    1390           0 :         PetscCall(PetscViewerRestoreSubViewer(viewer,ctx->contour->subcomm->child,&sviewer));
    1391             :         /* extra call needed because of the two calls to PetscViewerASCIIPushSynchronized() in PetscViewerGetSubViewer() */
    1392           0 :         PetscCall(PetscViewerASCIIPopSynchronized(viewer));
    1393           0 :       } else PetscCall(KSPView(ctx->contour->ksp[0],viewer));
    1394           0 :       PetscCall(PetscViewerASCIIPopTab(viewer));
    1395             :     }
    1396             :   }
    1397           0 :   PetscFunctionReturn(PETSC_SUCCESS);
    1398             : }
    1399             : 
    1400          66 : static PetscErrorCode EPSSetDefaultST_CISS(EPS eps)
    1401             : {
    1402          66 :   EPS_CISS       *ctx = (EPS_CISS*)eps->data;
    1403          66 :   PetscBool      usest = ctx->usest;
    1404          66 :   KSP            ksp;
    1405          66 :   PC             pc;
    1406             : 
    1407          66 :   PetscFunctionBegin;
    1408          66 :   if (!((PetscObject)eps->st)->type_name) {
    1409          28 :     if (!ctx->usest_set) usest = (ctx->npart>1)? PETSC_FALSE: PETSC_TRUE;
    1410          28 :     if (usest) PetscCall(STSetType(eps->st,STSINVERT));
    1411             :     else {
    1412             :       /* we are not going to use ST, so avoid factorizing the matrix */
    1413          15 :       PetscCall(STSetType(eps->st,STSHIFT));
    1414          15 :       if (eps->isgeneralized) {
    1415           3 :         PetscCall(STGetKSP(eps->st,&ksp));
    1416           3 :         PetscCall(KSPGetPC(ksp,&pc));
    1417           3 :         PetscCall(PCSetType(pc,PCNONE));
    1418             :       }
    1419             :     }
    1420             :   }
    1421          66 :   PetscFunctionReturn(PETSC_SUCCESS);
    1422             : }
    1423             : 
    1424          33 : SLEPC_EXTERN PetscErrorCode EPSCreate_CISS(EPS eps)
    1425             : {
    1426          33 :   EPS_CISS       *ctx = (EPS_CISS*)eps->data;
    1427             : 
    1428          33 :   PetscFunctionBegin;
    1429          33 :   PetscCall(PetscNew(&ctx));
    1430          33 :   eps->data = ctx;
    1431             : 
    1432          33 :   eps->useds = PETSC_TRUE;
    1433          33 :   eps->categ = EPS_CATEGORY_CONTOUR;
    1434             : 
    1435          33 :   eps->ops->solve          = EPSSolve_CISS;
    1436          33 :   eps->ops->setup          = EPSSetUp_CISS;
    1437          33 :   eps->ops->setupsort      = EPSSetUpSort_CISS;
    1438          33 :   eps->ops->setfromoptions = EPSSetFromOptions_CISS;
    1439          33 :   eps->ops->destroy        = EPSDestroy_CISS;
    1440          33 :   eps->ops->reset          = EPSReset_CISS;
    1441          33 :   eps->ops->view           = EPSView_CISS;
    1442          33 :   eps->ops->computevectors = EPSComputeVectors_CISS;
    1443          33 :   eps->ops->setdefaultst   = EPSSetDefaultST_CISS;
    1444             : 
    1445          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSSetSizes_C",EPSCISSSetSizes_CISS));
    1446          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSGetSizes_C",EPSCISSGetSizes_CISS));
    1447          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSSetThreshold_C",EPSCISSSetThreshold_CISS));
    1448          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSGetThreshold_C",EPSCISSGetThreshold_CISS));
    1449          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSSetRefinement_C",EPSCISSSetRefinement_CISS));
    1450          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSGetRefinement_C",EPSCISSGetRefinement_CISS));
    1451          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSSetUseST_C",EPSCISSSetUseST_CISS));
    1452          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSGetUseST_C",EPSCISSGetUseST_CISS));
    1453          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSSetQuadRule_C",EPSCISSSetQuadRule_CISS));
    1454          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSGetQuadRule_C",EPSCISSGetQuadRule_CISS));
    1455          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSSetExtraction_C",EPSCISSSetExtraction_CISS));
    1456          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSGetExtraction_C",EPSCISSGetExtraction_CISS));
    1457          33 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSCISSGetKSPs_C",EPSCISSGetKSPs_CISS));
    1458             : 
    1459             :   /* set default values of parameters */
    1460          33 :   ctx->N                  = 32;
    1461          33 :   ctx->L                  = 16;
    1462          33 :   ctx->M                  = ctx->N/4;
    1463          33 :   ctx->delta              = SLEPC_DEFAULT_TOL*1e-4;
    1464          33 :   ctx->L_max              = 64;
    1465          33 :   ctx->spurious_threshold = PetscSqrtReal(SLEPC_DEFAULT_TOL);
    1466          33 :   ctx->usest              = PETSC_TRUE;
    1467          33 :   ctx->usest_set          = PETSC_FALSE;
    1468          33 :   ctx->isreal             = PETSC_FALSE;
    1469          33 :   ctx->refine_inner       = 0;
    1470          33 :   ctx->refine_blocksize   = 0;
    1471          33 :   ctx->npart              = 1;
    1472          33 :   ctx->quad               = (EPSCISSQuadRule)0;
    1473          33 :   ctx->extraction         = EPS_CISS_EXTRACTION_RITZ;
    1474          33 :   PetscFunctionReturn(PETSC_SUCCESS);
    1475             : }

Generated by: LCOV version 1.14