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

Generated by: LCOV version 1.14