LCOV - code coverage report
Current view: top level - eps/impls/krylov/krylovschur - ks-bse.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 672 673 99.9 %
Date: 2024-11-21 00:34:55 Functions: 17 17 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       3             :    SLEPc - Scalable Library for Eigenvalue Problem Computations
       4             :    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
       5             : 
       6             :    This file is part of SLEPc.
       7             :    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
       8             :    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       9             : */
      10             : /*
      11             :    SLEPc eigensolver: "krylovschur"
      12             : 
      13             :    Method: thick-restarted Lanczos for Bethe-Salpeter pseudo-Hermitan matrices
      14             : 
      15             :    References:
      16             : 
      17             :        [1] M. Shao et al, "A structure preserving Lanczos algorithm for computing
      18             :            the optical absorption spectrum", SIAM J. Matrix Anal. App. 39(2), 2018.
      19             : 
      20             : */
      21             : #include <slepc/private/epsimpl.h>
      22             : #include "krylovschur.h"
      23             : 
      24         152 : static PetscErrorCode Orthog_Shao(Vec x,BV U,BV V,PetscInt j,PetscScalar *h,PetscScalar *c,PetscBool *breakdown)
      25             : {
      26         152 :   PetscInt i;
      27             : 
      28         152 :   PetscFunctionBegin;
      29         152 :   PetscCall(BVSetActiveColumns(U,0,j));
      30         152 :   PetscCall(BVSetActiveColumns(V,0,j));
      31             :   /* c = real(V^* x) ; c2 = imag(U^* x)*1i */
      32             : #if defined(PETSC_USE_COMPLEX)
      33             :   PetscCall(BVDotVecBegin(V,x,c));
      34             :   PetscCall(BVDotVecBegin(U,x,c+j));
      35             :   PetscCall(BVDotVecEnd(V,x,c));
      36             :   PetscCall(BVDotVecEnd(U,x,c+j));
      37             : #else
      38         152 :   PetscCall(BVDotVec(V,x,c));
      39             : #endif
      40             : #if defined(PETSC_USE_COMPLEX)
      41             :   for (i=0; i<j; i++) {
      42             :     c[i] = PetscRealPart(c[i]);
      43             :     c[j+i] = PetscCMPLX(0.0,PetscImaginaryPart(c[j+i]));
      44             :   }
      45             : #endif
      46             :   /* x = x-U*c-V*c2 */
      47         152 :   PetscCall(BVMultVec(U,-1.0,1.0,x,c));
      48             : #if defined(PETSC_USE_COMPLEX)
      49             :   PetscCall(BVMultVec(V,-1.0,1.0,x,c+j));
      50             : #endif
      51             :   /* accumulate orthog coeffs into h */
      52        3312 :   for (i=0; i<2*j; i++) h[i] += c[i];
      53         152 :   PetscFunctionReturn(PETSC_SUCCESS);
      54             : }
      55             : 
      56             : /* Orthogonalize vector x against first j vectors in U and V
      57             : v is column j-1 of V */
      58         152 : static PetscErrorCode OrthogonalizeVector_Shao(Vec x,BV U,BV V,PetscInt j,Vec v,PetscReal *beta,PetscInt k,PetscScalar *h,PetscBool *breakdown)
      59             : {
      60         152 :   PetscReal alpha;
      61         152 :   PetscInt  i,l;
      62             : 
      63         152 :   PetscFunctionBegin;
      64         152 :   PetscCall(PetscArrayzero(h,2*j));
      65             : 
      66             :   /* Local orthogonalization */
      67         152 :   l = j==k+1?0:j-2;  /* 1st column to orthogonalize against */
      68         152 :   PetscCall(VecDotRealPart(x,v,&alpha));
      69         362 :   for (i=l; i<j-1; i++) h[i] = beta[i];
      70         152 :   h[j-1] = alpha;
      71             :   /* x = x-U(:,l:j-1)*h(l:j-1) */
      72         152 :   PetscCall(BVSetActiveColumns(U,l,j));
      73         152 :   PetscCall(BVMultVec(U,-1.0,1.0,x,h+l));
      74             : 
      75             :   /* Full orthogonalization */
      76         152 :   PetscCall(Orthog_Shao(x,U,V,j,h,h+2*j,breakdown));
      77         152 :   PetscFunctionReturn(PETSC_SUCCESS);
      78             : }
      79             : 
      80          14 : static PetscErrorCode EPSBSELanczos_Shao(EPS eps,BV U,BV V,PetscReal *alpha,PetscReal *beta,PetscInt k,PetscInt *M,PetscBool *breakdown)
      81             : {
      82          14 :   PetscInt       j,m = *M;
      83          14 :   Vec            v,x,y,w,f,g,vecs[2];
      84          14 :   Mat            H;
      85          14 :   IS             is[2];
      86          14 :   PetscReal      nrm;
      87          14 :   PetscScalar    *hwork,lhwork[100],gamma;
      88             : 
      89          14 :   PetscFunctionBegin;
      90          14 :   if (4*m > 100) PetscCall(PetscMalloc1(4*m,&hwork));
      91          14 :   else hwork = lhwork;
      92          14 :   PetscCall(STGetMatrix(eps->st,0,&H));
      93          14 :   PetscCall(MatNestGetISs(H,is,NULL));
      94             : 
      95             :   /* create work vectors */
      96          14 :   PetscCall(BVGetColumn(V,0,&v));
      97          14 :   PetscCall(VecDuplicate(v,&w));
      98          14 :   vecs[0] = v;
      99          14 :   vecs[1] = w;
     100          14 :   PetscCall(VecCreateNest(PetscObjectComm((PetscObject)eps),2,is,vecs,&f));
     101          14 :   PetscCall(VecCreateNest(PetscObjectComm((PetscObject)eps),2,is,vecs,&g));
     102          14 :   PetscCall(BVRestoreColumn(V,0,&v));
     103             : 
     104             :   /* Normalize initial vector */
     105          14 :   if (k==0) {
     106           5 :     if (eps->nini==0) PetscCall(BVSetRandomColumn(eps->V,0));
     107           5 :     PetscCall(BVGetColumn(U,0,&x));
     108           5 :     PetscCall(BVGetColumn(V,0,&y));
     109           5 :     PetscCall(VecCopy(x,w));
     110           5 :     PetscCall(VecConjugate(w));
     111           5 :     PetscCall(VecNestSetSubVec(f,0,x));
     112           5 :     PetscCall(VecNestSetSubVec(g,0,y));
     113           5 :     PetscCall(STApply(eps->st,f,g));
     114           5 :     PetscCall(VecDot(y,x,&gamma));
     115           5 :     nrm = PetscSqrtReal(PetscRealPart(gamma));
     116           5 :     PetscCall(VecScale(x,1.0/nrm));
     117           5 :     PetscCall(VecScale(y,1.0/nrm));
     118           5 :     PetscCall(BVRestoreColumn(U,0,&x));
     119           5 :     PetscCall(BVRestoreColumn(V,0,&y));
     120             :   }
     121             : 
     122         166 :   for (j=k;j<m;j++) {
     123             :     /* j+1 columns (indexes 0 to j) have been computed */
     124         152 :     PetscCall(BVGetColumn(V,j,&v));
     125         152 :     PetscCall(BVGetColumn(U,j+1,&x));
     126         152 :     PetscCall(BVGetColumn(V,j+1,&y));
     127         152 :     PetscCall(VecCopy(v,w));
     128         152 :     PetscCall(VecConjugate(w));
     129         152 :     PetscCall(VecScale(w,-1.0));
     130         152 :     PetscCall(VecNestSetSubVec(f,0,v));
     131         152 :     PetscCall(VecNestSetSubVec(g,0,x));
     132         152 :     PetscCall(STApply(eps->st,f,g));
     133         152 :     PetscCall(OrthogonalizeVector_Shao(x,U,V,j+1,v,beta,k,hwork,breakdown));
     134         152 :     alpha[j] = PetscRealPart(hwork[j]);
     135         152 :     PetscCall(VecCopy(x,w));
     136         152 :     PetscCall(VecConjugate(w));
     137         152 :     PetscCall(VecNestSetSubVec(f,0,x));
     138         152 :     PetscCall(VecNestSetSubVec(g,0,y));
     139         152 :     PetscCall(STApply(eps->st,f,g));
     140         152 :     PetscCall(VecDot(x,y,&gamma));
     141         152 :     beta[j] = PetscSqrtReal(PetscRealPart(gamma));
     142         152 :     PetscCall(VecScale(x,1.0/beta[j]));
     143         152 :     PetscCall(VecScale(y,1.0/beta[j]));
     144         152 :     PetscCall(BVRestoreColumn(V,j,&v));
     145         152 :     PetscCall(BVRestoreColumn(U,j+1,&x));
     146         152 :     PetscCall(BVRestoreColumn(V,j+1,&y));
     147             :   }
     148          14 :   if (4*m > 100) PetscCall(PetscFree(hwork));
     149          14 :   PetscCall(VecDestroy(&w));
     150          14 :   PetscCall(VecDestroy(&f));
     151          14 :   PetscCall(VecDestroy(&g));
     152          14 :   PetscFunctionReturn(PETSC_SUCCESS);
     153             : }
     154             : 
     155           5 : static PetscErrorCode EPSComputeVectors_BSE_Shao(EPS eps)
     156             : {
     157           5 :   Mat         H;
     158           5 :   Vec         u1,v1;
     159           5 :   BV          U,V;
     160           5 :   IS          is[2];
     161           5 :   PetscInt    k;
     162           5 :   PetscScalar lambda;
     163             : 
     164           5 :   PetscFunctionBegin;
     165           5 :   PetscCall(STGetMatrix(eps->st,0,&H));
     166           5 :   PetscCall(MatNestGetISs(H,is,NULL));
     167           5 :   PetscCall(BVGetSplitRows(eps->V,is[0],is[1],&U,&V));
     168          40 :   for (k=0; k<eps->nconv; k++) {
     169          35 :     PetscCall(BVGetColumn(U,k,&u1));
     170          35 :     PetscCall(BVGetColumn(V,k,&v1));
     171             :     /* approx eigenvector is [    (eigr[k]*u1+v1)]
     172             :                              [conj(eigr[k]*u1-v1)]  */
     173          35 :     lambda = eps->eigr[k];
     174          35 :     PetscCall(STBackTransform(eps->st,1,&lambda,&eps->eigi[k]));
     175          35 :     PetscCall(VecAYPX(u1,lambda,v1));
     176          35 :     PetscCall(VecAYPX(v1,-2.0,u1));
     177          35 :     PetscCall(VecConjugate(v1));
     178          35 :     PetscCall(BVRestoreColumn(U,k,&u1));
     179          35 :     PetscCall(BVRestoreColumn(V,k,&v1));
     180             :   }
     181           5 :   PetscCall(BVRestoreSplitRows(eps->V,is[0],is[1],&U,&V));
     182             :   /* Normalize eigenvectors */
     183           5 :   PetscCall(BVSetActiveColumns(eps->V,0,eps->nconv));
     184           5 :   PetscCall(BVNormalize(eps->V,NULL));
     185           5 :   PetscFunctionReturn(PETSC_SUCCESS);
     186             : }
     187             : 
     188         304 : static PetscErrorCode Orthog_Gruning(Vec x,BV U,BV V,BV HU,BV HV,PetscInt j,PetscScalar *h,PetscScalar *c,PetscBool s,PetscBool *breakdown)
     189             : {
     190         304 :   PetscInt i;
     191             : 
     192         304 :   PetscFunctionBegin;
     193         304 :   PetscCall(BVSetActiveColumns(U,0,j));
     194         304 :   PetscCall(BVSetActiveColumns(HU,0,j));
     195         304 :   if (s) {
     196         152 :     PetscCall(BVSetActiveColumns(V,0,j));
     197         152 :     PetscCall(BVSetActiveColumns(HV,0,j));
     198             :   } else {
     199         152 :     PetscCall(BVSetActiveColumns(V,0,j-1));
     200         152 :     PetscCall(BVSetActiveColumns(HV,0,j-1));
     201             :   }
     202             : #if defined(PETSC_USE_COMPLEX)
     203             :   PetscCall(BVDotVecBegin(HU,x,c));
     204             :   if (s || j>1) PetscCall(BVDotVecBegin(HV,x,c+j));
     205             :   PetscCall(BVDotVecEnd(HU,x,c));
     206             :   if (s || j>1) PetscCall(BVDotVecEnd(HV,x,c+j));
     207             : #else
     208         304 :   if (s) PetscCall(BVDotVec(HU,x,c));
     209         152 :   else PetscCall(BVDotVec(HV,x,c+j));
     210             : #endif
     211        3464 :   for (i=0; i<j; i++) {
     212        3160 :     if (s) {   /* c1 = 2*real(HU^* x) ; c2 = 2*imag(HV^* x)*1i */
     213             : #if defined(PETSC_USE_COMPLEX)
     214             :       c[i] = PetscRealPart(c[i]);
     215             :       c[j+i] = PetscCMPLX(0.0,PetscImaginaryPart(c[j+i]));
     216             : #else
     217        1580 :       c[j+i] = 0.0;
     218             : #endif
     219             :     } else {   /* c1 = 2*imag(HU^* x)*1i ; c2 = 2*real(HV^* x) */
     220             : #if defined(PETSC_USE_COMPLEX)
     221             :       c[i] = PetscCMPLX(0.0,PetscImaginaryPart(c[i]));
     222             :       c[j+i] = PetscRealPart(c[j+i]);
     223             : #else
     224        1580 :       c[i] = 0.0;
     225             : #endif
     226             :     }
     227             :   }
     228             :   /* x = x-U*c1-V*c2 */
     229             : #if defined(PETSC_USE_COMPLEX)
     230             :   PetscCall(BVMultVec(U,-2.0,1.0,x,c));
     231             :   PetscCall(BVMultVec(V,-2.0,1.0,x,c+j));
     232             : #else
     233         304 :   if (s) PetscCall(BVMultVec(U,-2.0,1.0,x,c));
     234         152 :   else PetscCall(BVMultVec(V,-2.0,1.0,x,c+j));
     235             : #endif
     236             :   /* accumulate orthog coeffs into h */
     237        6624 :   for (i=0; i<2*j; i++) h[i] += 2*c[i];
     238         304 :   PetscFunctionReturn(PETSC_SUCCESS);
     239             : }
     240             : 
     241             : /* Orthogonalize vector x against first j vectors in U and V */
     242         304 : static PetscErrorCode OrthogonalizeVector_Gruning(Vec x,BV U,BV V,BV HU,BV HV,PetscInt j,PetscReal *beta,PetscInt k,PetscScalar *h,PetscBool s,PetscBool *breakdown)
     243             : {
     244         304 :   PetscInt l,i;
     245         304 :   Vec      u;
     246             : 
     247         304 :   PetscFunctionBegin;
     248         304 :   PetscCall(PetscArrayzero(h,4*j));
     249             : 
     250             :   /* Local orthogonalization */
     251         304 :   if (s) {
     252         152 :     PetscCall(BVGetColumn(U,j-1,&u));
     253         152 :     PetscCall(VecAXPY(x,-*beta,u));
     254         152 :     PetscCall(BVRestoreColumn(U,j-1,&u));
     255         152 :     h[j-1] = *beta;
     256             :   } else {
     257         152 :     l = j==k+1?0:j-2;  /* 1st column to orthogonalize against */
     258         362 :     for (i=l; i<j-1; i++) h[j+i] = beta[i];
     259             :     /* x = x-V(:,l:j-2)*h(l:j-2) */
     260         152 :     PetscCall(BVSetActiveColumns(V,l,j-1));
     261         152 :     PetscCall(BVMultVec(V,-1.0,1.0,x,h+j+l));
     262             :   }
     263             : 
     264             :   /* Full orthogonalization */
     265         304 :   PetscCall(Orthog_Gruning(x,U,V,HU,HV,j,h,h+2*j,s,breakdown));
     266         304 :   PetscFunctionReturn(PETSC_SUCCESS);
     267             : }
     268             : 
     269          14 : static PetscErrorCode EPSBSELanczos_Gruning(EPS eps,BV U,BV V,BV HU,BV HV,PetscReal *beta1,PetscReal *beta2,PetscInt k,PetscInt *M,PetscBool *breakdown)
     270             : {
     271          14 :   PetscInt       j,m = *M;
     272          14 :   Vec            v,x,y,w,f,g,vecs[2];
     273          14 :   Mat            H;
     274          14 :   IS             is[2];
     275          14 :   PetscReal      nrm;
     276          14 :   PetscScalar    *hwork,lhwork[100],dot;
     277             : 
     278          14 :   PetscFunctionBegin;
     279          14 :   if (4*m > 100) PetscCall(PetscMalloc1(4*m,&hwork));
     280          14 :   else hwork = lhwork;
     281          14 :   PetscCall(STGetMatrix(eps->st,0,&H));
     282          14 :   PetscCall(MatNestGetISs(H,is,NULL));
     283             : 
     284             :   /* create work vectors */
     285          14 :   PetscCall(BVGetColumn(V,0,&v));
     286          14 :   PetscCall(VecDuplicate(v,&w));
     287          14 :   vecs[0] = v;
     288          14 :   vecs[1] = w;
     289          14 :   PetscCall(VecCreateNest(PetscObjectComm((PetscObject)eps),2,is,vecs,&f));
     290          14 :   PetscCall(VecCreateNest(PetscObjectComm((PetscObject)eps),2,is,vecs,&g));
     291          14 :   PetscCall(BVRestoreColumn(V,0,&v));
     292             : 
     293             :   /* Normalize initial vector */
     294          14 :   if (k==0 && eps->nini==0) PetscCall(BVSetRandomColumn(eps->V,0));
     295             : 
     296             :   /* y = Hmult(v1,1) */
     297          14 :   PetscCall(BVGetColumn(U,k,&x));
     298          14 :   PetscCall(BVGetColumn(HU,k,&y));
     299          14 :   PetscCall(VecCopy(x,w));
     300          14 :   PetscCall(VecConjugate(w));
     301          14 :   PetscCall(VecNestSetSubVec(f,0,x));
     302          14 :   PetscCall(VecNestSetSubVec(g,0,y));
     303          14 :   PetscCall(STApply(eps->st,f,g));
     304             :   /* nrm = sqrt(2*real(u1'*y)); */
     305          14 :   PetscCall(VecDot(x,y,&dot));
     306          14 :   nrm = PetscSqrtReal(PetscRealPart(2*dot));
     307             :   /* U(:,j) = u1/nrm; */
     308             :   /* HU(:,j) = y/nrm; */
     309          14 :   PetscCall(VecScale(x,1.0/nrm));
     310          14 :   PetscCall(VecScale(y,1.0/nrm));
     311          14 :   PetscCall(BVRestoreColumn(U,k,&x));
     312          14 :   PetscCall(BVRestoreColumn(HU,k,&y));
     313             : 
     314         166 :   for (j=k;j<m;j++) {
     315             :     /* j+1 columns (indexes 0 to j) have been computed */
     316         152 :     PetscCall(BVGetColumn(HU,j,&x));
     317         152 :     PetscCall(BVGetColumn(V,j,&v));
     318         152 :     PetscCall(BVGetColumn(HV,j,&y));
     319         152 :     PetscCall(VecCopy(x,v));
     320         152 :     PetscCall(BVRestoreColumn(HU,j,&x));
     321             :     /* v = Orthogonalize HU(:,j) */
     322         152 :     PetscCall(OrthogonalizeVector_Gruning(v,U,V,HU,HV,j+1,beta2,k,hwork,PETSC_FALSE,breakdown));
     323             :     /* y = Hmult(v,-1) */
     324         152 :     PetscCall(VecCopy(v,w));
     325         152 :     PetscCall(VecConjugate(w));
     326         152 :     PetscCall(VecScale(w,-1.0));
     327         152 :     PetscCall(VecNestSetSubVec(f,0,v));
     328         152 :     PetscCall(VecNestSetSubVec(g,0,y));
     329         152 :     PetscCall(STApply(eps->st,f,g));
     330             :     /* beta = sqrt(2*real(v'*y)); */
     331         152 :     PetscCall(VecDot(v,y,&dot));
     332         152 :     beta1[j] = PetscSqrtReal(PetscRealPart(2*dot)); //FIXME Check beta != 0?
     333             :     /* V(:,j) = v/beta1; */
     334             :     /* HV(:,j) = y/beta1; */
     335         152 :     PetscCall(VecScale(v,1.0/beta1[j]));
     336         152 :     PetscCall(VecScale(y,1.0/beta1[j]));
     337         152 :     PetscCall(BVRestoreColumn(V,j,&v));
     338         152 :     PetscCall(BVRestoreColumn(HV,j,&y));
     339             : 
     340         152 :     PetscCall(BVGetColumn(HV,j,&x));
     341         152 :     PetscCall(BVGetColumn(U,j+1,&v));
     342         152 :     PetscCall(BVGetColumn(HU,j+1,&y));
     343         152 :     PetscCall(VecCopy(x,v));
     344         152 :     PetscCall(BVRestoreColumn(HV,j,&x));
     345             :     /* v = Orthogonalize HV(:,j) */
     346         152 :     PetscCall(OrthogonalizeVector_Gruning(v,U,V,HU,HV,j+1,&beta1[j],k,hwork,PETSC_TRUE,breakdown));
     347             :     /* y = Hmult(v,1) */
     348         152 :     PetscCall(VecCopy(v,w));
     349         152 :     PetscCall(VecConjugate(w));
     350         152 :     PetscCall(VecNestSetSubVec(f,0,v));
     351         152 :     PetscCall(VecNestSetSubVec(g,0,y));
     352         152 :     PetscCall(STApply(eps->st,f,g));
     353             :     /* beta = sqrt(2*real(v'*y)); */
     354         152 :     PetscCall(VecDot(v,y,&dot));
     355         152 :     beta2[j] = PetscSqrtReal(PetscRealPart(2*dot)); //FIXME Check beta != 0?
     356             :     /* U(:,j) = v/beta2; */
     357             :     /* HU(:,j) = y/beta2; */
     358         152 :     PetscCall(VecScale(v,1.0/beta2[j]));
     359         152 :     PetscCall(VecScale(y,1.0/beta2[j]));
     360         152 :     PetscCall(BVRestoreColumn(U,j+1,&v));
     361         152 :     PetscCall(BVRestoreColumn(HU,j+1,&y));
     362             :   }
     363          14 :   if (4*m > 100) PetscCall(PetscFree(hwork));
     364          14 :   PetscCall(VecDestroy(&w));
     365          14 :   PetscCall(VecDestroy(&f));
     366          14 :   PetscCall(VecDestroy(&g));
     367          14 :   PetscFunctionReturn(PETSC_SUCCESS);
     368             : }
     369             : 
     370           5 : static PetscErrorCode EPSComputeVectors_BSE_Gruning(EPS eps)
     371             : {
     372           5 :   Mat         H;
     373           5 :   Vec         u1,v1;
     374           5 :   BV          U,V;
     375           5 :   IS          is[2];
     376           5 :   PetscInt    k;
     377             : 
     378           5 :   PetscFunctionBegin;
     379           5 :   PetscCall(STGetMatrix(eps->st,0,&H));
     380           5 :   PetscCall(MatNestGetISs(H,is,NULL));
     381           5 :   PetscCall(BVGetSplitRows(eps->V,is[0],is[1],&U,&V));
     382             :   /* approx eigenvector [x1] is [     u1+v1       ]
     383             :                         [x2]    [conj(u1)-conj(v1)]  */
     384          42 :   for (k=0; k<eps->nconv; k++) {
     385          37 :     PetscCall(BVGetColumn(U,k,&u1));
     386          37 :     PetscCall(BVGetColumn(V,k,&v1));
     387             :     /* x1 = u1 + v1 */
     388          37 :     PetscCall(VecAXPY(u1,1.0,v1));
     389             :     /* x2 = conj(u1) - conj(v1) = conj(u1 - v1) = conj((u1 + v1) - 2*v1) */
     390          37 :     PetscCall(VecAYPX(v1,-2.0,u1));
     391          37 :     PetscCall(VecConjugate(v1));
     392          37 :     PetscCall(BVRestoreColumn(U,k,&u1));
     393          37 :     PetscCall(BVRestoreColumn(V,k,&v1));
     394             :   }
     395           5 :   PetscCall(BVRestoreSplitRows(eps->V,is[0],is[1],&U,&V));
     396             :   /* Normalize eigenvectors */
     397           5 :   PetscCall(BVSetActiveColumns(eps->V,0,eps->nconv));
     398           5 :   PetscCall(BVNormalize(eps->V,NULL));
     399           5 :   PetscFunctionReturn(PETSC_SUCCESS);
     400             : }
     401             : 
     402         120 : static PetscErrorCode Orthog_ProjectedBSE(Vec hx,Vec hy,BV X,BV Y,PetscInt j,PetscScalar *h,PetscScalar *c,PetscBool *breakdown)
     403             : {
     404         120 :   PetscInt          i;
     405         120 :   Mat               MX,MY,MXl,MYl;
     406         120 :   Vec               c1,c2,hxl,hyl,hz;
     407         120 :   PetscScalar       *cx1,*cx2;
     408         120 :   PetscMPIInt       len;
     409             : 
     410         120 :   PetscFunctionBegin;
     411         120 :   PetscCall(PetscMPIIntCast(j,&len));
     412         120 :   PetscCall(BVSetActiveColumns(X,0,j));
     413         120 :   PetscCall(BVSetActiveColumns(Y,0,j));
     414             :   /* BVTDotVec does not exist yet, implemented via MatMult operations */
     415         120 :   PetscCall(BVGetMat(X,&MX));
     416         120 :   PetscCall(BVGetMat(Y,&MY));
     417         120 :   PetscCall(MatDenseGetLocalMatrix(MX,&MXl));
     418         120 :   PetscCall(MatDenseGetLocalMatrix(MY,&MYl));
     419         120 :   PetscCall(MatCreateVecs(MXl,&c1,&hyl));
     420         120 :   PetscCall(MatCreateVecs(MXl,&c2,&hxl));
     421             : 
     422             :   /* c1 =  X^* hx - Y^* hy
     423             :    * c2 = -Y^T hx + X^T hy */
     424             : 
     425         120 :   PetscCall(VecGetLocalVector(hx,hxl));
     426         120 :   PetscCall(VecGetLocalVector(hy,hyl));
     427         120 :   PetscCall(VecDuplicate(hx,&hz));
     428             :   /* c1 = -(Y^* hy) */
     429         120 :   PetscCall(MatMultHermitianTranspose(MYl,hyl,c1));
     430         120 :   PetscCall(VecScale(c1,-1));
     431             :   /* c1 = c1 + X^* hx */
     432         120 :   PetscCall(MatMultHermitianTransposeAdd(MXl,hxl,c1,c1));
     433         120 :   PetscCall(VecGetArray(c1,&cx1));
     434         360 :   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE,cx1,len,MPIU_SCALAR,MPIU_SUM,PetscObjectComm((PetscObject)hx)));
     435         120 :   PetscCall(VecRestoreArray(c1,&cx1));
     436             :   /* c2 = -(Y^T hx) */
     437         120 :   PetscCall(MatMultTranspose(MYl,hxl,c2));
     438         120 :   PetscCall(VecScale(c2,-1));
     439             :   /* c2 = c2 + X^T hy */
     440         120 :   PetscCall(MatMultTransposeAdd(MXl,hyl,c2,c2));
     441         120 :   PetscCall(VecGetArray(c2,&cx2));
     442         360 :   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE,cx2,len,MPIU_SCALAR,MPIU_SUM,PetscObjectComm((PetscObject)hx)));
     443         120 :   PetscCall(VecRestoreArray(c2,&cx2));
     444         120 :   PetscCall(VecRestoreLocalVector(hx,hxl));
     445         120 :   PetscCall(VecRestoreLocalVector(hy,hyl));
     446             : 
     447             :   /* accumulate orthog coeffs into h */
     448         120 :   PetscCall(VecGetArrayRead(c1,(const PetscScalar**)&cx1));
     449         120 :   PetscCall(VecGetArrayRead(c2,(const PetscScalar**)&cx2));
     450        1364 :   for (i=0; i<j; i++) h[i] += cx1[i];
     451        1364 :   for (i=0; i<j; i++) h[i+j] += cx2[i];
     452         120 :   PetscCall(VecRestoreArrayRead(c1,(const PetscScalar**)&cx1));
     453         120 :   PetscCall(VecRestoreArrayRead(c2,(const PetscScalar**)&cx2));
     454             : 
     455             :   /* u = hx - X c1 - conj(Y) c2 */
     456             : 
     457             :   /* conj(Y) c2 */
     458         120 :   PetscCall(VecConjugate(c2));
     459         120 :   PetscCall(VecGetLocalVector(hz,hxl));
     460         120 :   PetscCall(MatMult(MYl,c2,hxl));
     461         120 :   PetscCall(VecConjugate(hxl));
     462             :   /* X c1 */
     463         120 :   PetscCall(MatMultAdd(MXl,c1,hxl,hxl));
     464         120 :   PetscCall(VecRestoreLocalVector(hz,hxl));
     465         120 :   PetscCall(VecAXPY(hx,-1,hz));
     466             : 
     467         120 :   PetscCall(BVRestoreMat(X,&MX));
     468         120 :   PetscCall(BVRestoreMat(Y,&MY));
     469         120 :   PetscCall(VecDestroy(&c1));
     470         120 :   PetscCall(VecDestroy(&c2));
     471         120 :   PetscCall(VecDestroy(&hxl));
     472         120 :   PetscCall(VecDestroy(&hyl));
     473         120 :   PetscCall(VecDestroy(&hz));
     474         120 :   PetscFunctionReturn(PETSC_SUCCESS);
     475             : }
     476             : 
     477             : /* Orthogonalize vector x against first j vectors in X and Y */
     478         120 : static PetscErrorCode OrthogonalizeVector_ProjectedBSE(Vec hx,Vec hy,BV X,BV Y,PetscInt j,PetscReal *beta,PetscInt k,PetscScalar *h,PetscBool *breakdown)
     479             : {
     480         120 :   PetscInt    l,i;
     481         120 :   PetscScalar alpha,alpha1,alpha2;
     482         120 :   Vec         x,y;
     483             : 
     484         120 :   PetscFunctionBegin;
     485         120 :   PetscCall(PetscArrayzero(h,2*j));
     486             : 
     487             :   /* Local orthogonalization */
     488         120 :   l = j==k+1?0:j-2;  /* 1st column to orthogonalize against */
     489             :   /* alpha = X(:,j-1)'*hx-Y(:,j-1)'*hy */
     490         120 :   PetscCall(BVGetColumn(X,j-1,&x));
     491         120 :   PetscCall(BVGetColumn(Y,j-1,&y));
     492         120 :   PetscCall(VecDotBegin(hx,x,&alpha1));
     493         120 :   PetscCall(VecDotBegin(hy,y,&alpha2));
     494         120 :   PetscCall(VecDotEnd(hx,x,&alpha1));
     495         120 :   PetscCall(VecDotEnd(hy,y,&alpha2));
     496         120 :   PetscCall(BVRestoreColumn(X,j-1,&x));
     497         120 :   PetscCall(BVRestoreColumn(Y,j-1,&y));
     498         120 :   alpha = alpha1-alpha2;
     499             :   /* Store coeffs into h */
     500         285 :   for (i=l; i<j-1; i++) h[i] = h[j+i] = beta[i];
     501         120 :   h[j-1] = alpha;
     502         120 :   h[2*j-1] = alpha-1.0;
     503             :   /* Orthogonalize: hx = hx - X(:,l:j-1)*h1 - conj(Y(:,l:j-1))*h2 */
     504         120 :   PetscCall(BVSetActiveColumns(X,l,j));
     505         120 :   PetscCall(BVSetActiveColumns(Y,l,j));
     506         120 :   PetscCall(BVMultVec(X,-1.0,1.0,hx,h+l));
     507         120 :   PetscCall(VecConjugate(hx));
     508         405 :   for (i=j+l; i<2*j; i++) h[j+i] = PetscConj(h[i]);
     509         120 :   PetscCall(BVMultVec(Y,-1.0,1.0,hx,h+2*j+l));
     510         120 :   PetscCall(VecConjugate(hx));
     511             : 
     512             :   /* Full orthogonalization */
     513         120 :   PetscCall(VecCopy(hx,hy));
     514         120 :   PetscCall(VecConjugate(hy));
     515         120 :   PetscCall(Orthog_ProjectedBSE(hx,hy,X,Y,j,h,h+2*j,breakdown));
     516         120 :   PetscFunctionReturn(PETSC_SUCCESS);
     517             : }
     518             : 
     519          11 : static PetscErrorCode EPSBSELanczos_ProjectedBSE(EPS eps,BV X,BV Y,Vec v,PetscReal *alpha,PetscReal *beta,PetscInt k,PetscInt *M,PetscBool *breakdown)
     520             : {
     521          11 :   PetscInt       j,m = *M;
     522          11 :   Vec            u,x,y,w,f,g,vecs[2];
     523          11 :   Mat            H;
     524          11 :   IS             is[2];
     525          11 :   PetscReal      nrm;
     526          11 :   PetscScalar    *hwork,lhwork[100],gamma;
     527             : 
     528          11 :   PetscFunctionBegin;
     529          11 :   if (4*m > 100) PetscCall(PetscMalloc1(4*m,&hwork));
     530          11 :   else hwork = lhwork;
     531          11 :   PetscCall(STGetMatrix(eps->st,0,&H));
     532          11 :   PetscCall(MatNestGetISs(H,is,NULL));
     533             : 
     534             :   /* create work vectors */
     535          11 :   PetscCall(BVGetColumn(Y,0,&u));
     536          11 :   PetscCall(VecDuplicate(u,&w));
     537          11 :   vecs[0] = u;
     538          11 :   vecs[1] = w;
     539          11 :   PetscCall(VecCreateNest(PetscObjectComm((PetscObject)eps),2,is,vecs,&f));
     540          11 :   PetscCall(VecCreateNest(PetscObjectComm((PetscObject)eps),2,is,vecs,&g));
     541          11 :   PetscCall(BVRestoreColumn(Y,0,&u));
     542             : 
     543             :   /* Normalize initial vector */
     544          11 :   if (k==0) {
     545           4 :     if (eps->nini==0) PetscCall(BVSetRandomColumn(eps->V,0));
     546           4 :     PetscCall(BVGetColumn(X,0,&x));
     547             :     /* v = Hmult(u,1) */
     548           4 :     PetscCall(BVGetColumn(Y,0,&y));
     549           4 :     PetscCall(VecCopy(x,w));
     550           4 :     PetscCall(VecConjugate(w));
     551           4 :     PetscCall(VecNestSetSubVec(f,0,x));
     552           4 :     PetscCall(VecNestSetSubVec(g,0,y));
     553           4 :     PetscCall(STApply(eps->st,f,g));
     554             :     /* nrm = sqrt(real(u'v)) */
     555           4 :     PetscCall(VecDot(y,x,&gamma));
     556           4 :     nrm = PetscSqrtReal(PetscRealPart(gamma));
     557             :     /* u = u /(nrm*2) */
     558           4 :     PetscCall(VecScale(x,1.0/(2.0*nrm)));
     559             :     /* v = v /(nrm*2) */
     560           4 :     PetscCall(VecScale(y,1.0/(2.0*nrm)));
     561           4 :     PetscCall(VecCopy(y,v));
     562             :     /* X(:,1) = (u+v) */
     563           4 :     PetscCall(VecAXPY(x,1,y));
     564             :     /* Y(:,1) = conj(u-v) */
     565           4 :     PetscCall(VecAYPX(y,-2,x));
     566           4 :     PetscCall(VecConjugate(y));
     567           4 :     PetscCall(BVRestoreColumn(X,0,&x));
     568           4 :     PetscCall(BVRestoreColumn(Y,0,&y));
     569             :   }
     570             : 
     571         131 :   for (j=k;j<m;j++) {
     572             :     /* j+1 columns (indexes 0 to j) have been computed */
     573         120 :     PetscCall(BVGetColumn(X,j+1,&x));
     574         120 :     PetscCall(BVGetColumn(Y,j+1,&y));
     575             :     /* u = Hmult(v,-1)*/
     576         120 :     PetscCall(VecCopy(v,w));
     577         120 :     PetscCall(VecConjugate(w));
     578         120 :     PetscCall(VecScale(w,-1.0));
     579         120 :     PetscCall(VecNestSetSubVec(f,0,v));
     580         120 :     PetscCall(VecNestSetSubVec(g,0,x));
     581         120 :     PetscCall(STApply(eps->st,f,g));
     582             :     /* hx = (u+v) */
     583         120 :     PetscCall(VecCopy(x,y));
     584         120 :     PetscCall(VecAXPY(x,1,v));
     585             :     /* hy = conj(u-v) */
     586         120 :     PetscCall(VecAXPY(y,-1,v));
     587         120 :     PetscCall(VecConjugate(y));
     588             :     /* [u,cd] = orthog(hx,hy,X(:,1:j),Y(:,1:j),opt)*/
     589         120 :     PetscCall(OrthogonalizeVector_ProjectedBSE(x,y,X,Y,j+1,beta,k,hwork,breakdown));
     590             :     /* alpha(j) = real(cd(j))-1/2 */
     591         120 :     alpha[j] = 2*(PetscRealPart(hwork[j]) - 0.5);
     592             :     /* v = Hmult(u,1) */
     593         120 :     PetscCall(VecCopy(x,w));
     594         120 :     PetscCall(VecConjugate(w));
     595         120 :     PetscCall(VecNestSetSubVec(f,0,x));
     596         120 :     PetscCall(VecNestSetSubVec(g,0,y));
     597         120 :     PetscCall(STApply(eps->st,f,g));
     598             :     /* nrm = sqrt(real(u'*v)) */
     599             :     /* beta(j) = nrm */
     600         120 :     PetscCall(VecDot(x,y,&gamma));
     601         120 :     beta[j] = 2.0*PetscSqrtReal(PetscRealPart(gamma));
     602             :     /* u = u/(nrm*2) */
     603         120 :     PetscCall(VecScale(x,1.0/beta[j]));
     604             :     /* v = v/(nrm*2) */
     605         120 :     PetscCall(VecScale(y,1.0/beta[j]));
     606         120 :     PetscCall(VecCopy(y,v));
     607             :     /* X(:,j+1) = (u+v) */
     608         120 :     PetscCall(VecAXPY(x,1,y));
     609             :     /* Y(:,j+1) = conj(u-v) */
     610         120 :     PetscCall(VecAYPX(y,-2,x));
     611         120 :     PetscCall(VecConjugate(y));
     612             :     /* Restore */
     613         120 :     PetscCall(BVRestoreColumn(X,j+1,&x));
     614         120 :     PetscCall(BVRestoreColumn(Y,j+1,&y));
     615             :   }
     616          11 :   if (4*m > 100) PetscCall(PetscFree(hwork));
     617          11 :   PetscCall(VecDestroy(&w));
     618          11 :   PetscCall(VecDestroy(&f));
     619          11 :   PetscCall(VecDestroy(&g));
     620          11 :   PetscFunctionReturn(PETSC_SUCCESS);
     621             : }
     622             : 
     623           4 : static PetscErrorCode EPSComputeVectors_BSE_ProjectedBSE(EPS eps)
     624             : {
     625           4 :   Mat         H;
     626           4 :   Vec         x1,y1,cx1,cy1;
     627           4 :   BV          X,Y;
     628           4 :   IS          is[2];
     629           4 :   PetscInt    k;
     630           4 :   PetscScalar delta1,delta2,lambda;
     631             : 
     632           4 :   PetscFunctionBegin;
     633           4 :   PetscCall(STGetMatrix(eps->st,0,&H));
     634           4 :   PetscCall(MatNestGetISs(H,is,NULL));
     635           4 :   PetscCall(BVGetSplitRows(eps->V,is[0],is[1],&X,&Y));
     636           4 :   PetscCall(BVCreateVec(X,&cx1));
     637           4 :   PetscCall(BVCreateVec(Y,&cy1));
     638          32 :   for (k=0; k<eps->nconv; k++) {
     639             :     /* approx eigenvector is [ delta1*x1 + delta2*conj(y1) ]
     640             :                              [ delta1*y1 + delta2*conj(x1) ] */
     641          28 :     lambda = eps->eigr[k];
     642          28 :     PetscCall(STBackTransform(eps->st,1,&lambda,&eps->eigi[k]));
     643          28 :     delta1 = lambda+1.0;
     644          28 :     delta2 = lambda-1.0;
     645          28 :     PetscCall(BVGetColumn(X,k,&x1));
     646          28 :     PetscCall(BVGetColumn(Y,k,&y1));
     647          28 :     PetscCall(VecCopy(x1,cx1));
     648          28 :     PetscCall(VecCopy(y1,cy1));
     649          28 :     PetscCall(VecConjugate(cx1));
     650          28 :     PetscCall(VecConjugate(cy1));
     651          28 :     PetscCall(VecScale(x1,delta1));
     652          28 :     PetscCall(VecScale(y1,delta1));
     653          28 :     PetscCall(VecAXPY(x1,delta2,cy1));
     654          28 :     PetscCall(VecAXPY(y1,delta2,cx1));
     655          28 :     PetscCall(BVRestoreColumn(X,k,&x1));
     656          28 :     PetscCall(BVRestoreColumn(Y,k,&y1));
     657             :   }
     658           4 :   PetscCall(BVRestoreSplitRows(eps->V,is[0],is[1],&X,&Y));
     659           4 :   PetscCall(BVSetActiveColumns(eps->V,0,eps->nconv));
     660             :   /* Normalize eigenvector */
     661           4 :   PetscCall(BVNormalize(eps->V,NULL));
     662           4 :   PetscCall(VecDestroy(&cx1));
     663           4 :   PetscCall(VecDestroy(&cy1));
     664           4 :   PetscFunctionReturn(PETSC_SUCCESS);
     665             : }
     666             : 
     667          14 : PetscErrorCode EPSSetUp_KrylovSchur_BSE(EPS eps)
     668             : {
     669          14 :   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
     670          14 :   PetscBool       flg,sinvert;
     671          14 :   PetscInt        nev=(eps->nev+1)/2;
     672             : 
     673          14 :   PetscFunctionBegin;
     674          14 :   PetscCheck((eps->problem_type==EPS_BSE),PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Problem type should be BSE");
     675          14 :   EPSCheckUnsupportedCondition(eps,EPS_FEATURE_ARBITRARY | EPS_FEATURE_REGION | EPS_FEATURE_EXTRACTION | EPS_FEATURE_BALANCE,PETSC_TRUE," with BSE structure");
     676          14 :   PetscCall(EPSSetDimensions_Default(eps,nev,&eps->ncv,&eps->mpd));
     677          14 :   PetscCheck(eps->ncv<=nev+eps->mpd,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER_INPUT,"The value of ncv must not be larger than nev+mpd");
     678          14 :   if (eps->max_it==PETSC_DETERMINE) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
     679             : 
     680          14 :   PetscCall(PetscObjectTypeCompareAny((PetscObject)eps->st,&flg,STSINVERT,STSHIFT,""));
     681          14 :   PetscCheck(flg,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Krylov-Schur BSE only supports shift and shift-and-invert ST");
     682          14 :   PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STSINVERT,&sinvert));
     683          14 :   if (!eps->which) {
     684          12 :     if (sinvert) eps->which = EPS_TARGET_MAGNITUDE;
     685           9 :     else eps->which = EPS_SMALLEST_MAGNITUDE;
     686             :   }
     687             : 
     688          14 :   if (!ctx->keep) ctx->keep = 0.5;
     689          14 :   PetscCall(STSetStructured(eps->st,PETSC_TRUE));
     690             : 
     691          14 :   PetscCall(EPSAllocateSolution(eps,1));
     692          14 :   switch (ctx->bse) {
     693           5 :     case EPS_KRYLOVSCHUR_BSE_SHAO:
     694           5 :       eps->ops->solve = EPSSolve_KrylovSchur_BSE_Shao;
     695           5 :       eps->ops->computevectors = EPSComputeVectors_BSE_Shao;
     696           5 :       PetscCall(DSSetType(eps->ds,DSHEP));
     697           5 :       PetscCall(DSSetCompact(eps->ds,PETSC_TRUE));
     698           5 :       PetscCall(DSSetExtraRow(eps->ds,PETSC_TRUE));
     699           5 :       PetscCall(DSAllocate(eps->ds,eps->ncv+1));
     700             :       break;
     701           5 :     case EPS_KRYLOVSCHUR_BSE_GRUNING:
     702           5 :       eps->ops->solve = EPSSolve_KrylovSchur_BSE_Gruning;
     703           5 :       eps->ops->computevectors = EPSComputeVectors_BSE_Gruning;
     704           5 :       PetscCall(DSSetType(eps->ds,DSSVD));
     705           5 :       PetscCall(DSSetCompact(eps->ds,PETSC_TRUE));
     706           5 :       PetscCall(DSSetExtraRow(eps->ds,PETSC_TRUE));
     707           5 :       PetscCall(DSAllocate(eps->ds,eps->ncv+1));
     708             :       break;
     709           4 :     case EPS_KRYLOVSCHUR_BSE_PROJECTEDBSE:
     710           4 :       eps->ops->solve = EPSSolve_KrylovSchur_BSE_ProjectedBSE;
     711           4 :       eps->ops->computevectors = EPSComputeVectors_BSE_ProjectedBSE;
     712           4 :       PetscCall(DSSetType(eps->ds,DSHEP));
     713           4 :       PetscCall(DSSetCompact(eps->ds,PETSC_TRUE));
     714           4 :       PetscCall(DSSetExtraRow(eps->ds,PETSC_TRUE));
     715           4 :       PetscCall(DSAllocate(eps->ds,eps->ncv+1));
     716             :       break;
     717           0 :     default: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Unexpected error");
     718             :   }
     719          14 :   PetscFunctionReturn(PETSC_SUCCESS);
     720             : }
     721             : 
     722           5 : PetscErrorCode EPSSolve_KrylovSchur_BSE_Shao(EPS eps)
     723             : {
     724           5 :   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
     725           5 :   PetscInt        i,k,l,ld,nv,nconv=0,nevsave;
     726           5 :   Mat             H,Q;
     727           5 :   BV              U,V;
     728           5 :   IS              is[2];
     729           5 :   PetscReal       *a,*b,beta;
     730           5 :   PetscBool       breakdown=PETSC_FALSE;
     731             : 
     732           5 :   PetscFunctionBegin;
     733           5 :   PetscCall(DSGetLeadingDimension(eps->ds,&ld));
     734             : 
     735             :   /* Extract matrix blocks */
     736           5 :   PetscCall(STGetMatrix(eps->st,0,&H));
     737           5 :   PetscCall(MatNestGetISs(H,is,NULL));
     738             : 
     739             :   /* Get the split bases */
     740           5 :   PetscCall(BVGetSplitRows(eps->V,is[0],is[1],&U,&V));
     741             : 
     742           5 :   nevsave  = eps->nev;
     743           5 :   eps->nev = (eps->nev+1)/2;
     744           5 :   l = 0;
     745             : 
     746             :   /* Restart loop */
     747           5 :   while (eps->reason == EPS_CONVERGED_ITERATING) {
     748          14 :     eps->its++;
     749             : 
     750             :     /* Compute an nv-step Lanczos factorization */
     751          14 :     nv = PetscMin(eps->nconv+eps->mpd,eps->ncv);
     752          14 :     PetscCall(DSSetDimensions(eps->ds,nv,eps->nconv,eps->nconv+l));
     753          14 :     PetscCall(DSGetArrayReal(eps->ds,DS_MAT_T,&a));
     754          14 :     b = a + ld;
     755          14 :     PetscCall(EPSBSELanczos_Shao(eps,U,V,a,b,eps->nconv+l,&nv,&breakdown));
     756          14 :     beta = b[nv-1];
     757          14 :     PetscCall(DSRestoreArrayReal(eps->ds,DS_MAT_T,&a));
     758          14 :     PetscCall(DSSetDimensions(eps->ds,nv,eps->nconv,eps->nconv+l));
     759          14 :     PetscCall(DSSetState(eps->ds,l?DS_STATE_RAW:DS_STATE_INTERMEDIATE));
     760          14 :     PetscCall(BVSetActiveColumns(eps->V,eps->nconv,nv));
     761             : 
     762             :     /* Solve projected problem */
     763          14 :     PetscCall(DSSolve(eps->ds,eps->eigr,eps->eigi));
     764          14 :     PetscCall(DSSort(eps->ds,eps->eigr,eps->eigi,NULL,NULL,NULL));
     765          14 :     PetscCall(DSUpdateExtraRow(eps->ds));
     766          14 :     PetscCall(DSSynchronize(eps->ds,eps->eigr,eps->eigi));
     767             : 
     768             :     /* Check convergence */
     769         238 :     for (i=0;i<eps->ncv;i++) eps->eigr[i] = PetscSqrtReal(PetscRealPart(eps->eigr[i]));
     770          14 :     PetscCall(EPSKrylovConvergence(eps,PETSC_FALSE,eps->nconv,nv-eps->nconv,beta,0.0,1.0,&k));
     771          14 :     PetscCall((*eps->stopping)(eps,eps->its,eps->max_it,k,eps->nev,&eps->reason,eps->stoppingctx));
     772          14 :     nconv = k;
     773             : 
     774             :     /* Update l */
     775          14 :     if (eps->reason != EPS_CONVERGED_ITERATING || breakdown || k==nv) l = 0;
     776           9 :     else l = PetscMax(1,(PetscInt)((nv-k)*ctx->keep));
     777          14 :     if (!ctx->lock && l>0) { l += k; k = 0; } /* non-locking variant: reset no. of converged pairs */
     778          14 :     if (l) PetscCall(PetscInfo(eps,"Preparing to restart keeping l=%" PetscInt_FMT " vectors\n",l));
     779             : 
     780          14 :     if (eps->reason == EPS_CONVERGED_ITERATING) {
     781           9 :       PetscCheck(!breakdown,PetscObjectComm((PetscObject)eps),PETSC_ERR_CONV_FAILED,"Breakdown in BSE Krylov-Schur (beta=%g)",(double)beta);
     782             :       /* Prepare the Rayleigh quotient for restart */
     783           9 :       PetscCall(DSTruncate(eps->ds,k+l,PETSC_FALSE));
     784             :     }
     785             :     /* Update the corresponding vectors
     786             :        U(:,idx) = U*Q(:,idx),  V(:,idx) = V*Q(:,idx) */
     787          14 :     PetscCall(DSGetMat(eps->ds,DS_MAT_Q,&Q));
     788          14 :     PetscCall(BVMultInPlace(U,Q,eps->nconv,k+l));
     789          14 :     PetscCall(BVMultInPlace(V,Q,eps->nconv,k+l));
     790          14 :     PetscCall(DSRestoreMat(eps->ds,DS_MAT_Q,&Q));
     791             : 
     792          14 :     if (eps->reason == EPS_CONVERGED_ITERATING && !breakdown) PetscCall(BVCopyColumn(eps->V,nv,k+l));
     793          14 :     eps->nconv = k;
     794          19 :     PetscCall(EPSMonitor(eps,eps->its,nconv,eps->eigr,eps->eigi,eps->errest,nv));
     795             :   }
     796             : 
     797           5 :   eps->nev = nevsave;
     798             : 
     799           5 :   PetscCall(DSTruncate(eps->ds,eps->nconv,PETSC_TRUE));
     800           5 :   PetscCall(BVRestoreSplitRows(eps->V,is[0],is[1],&U,&V));
     801           5 :   PetscFunctionReturn(PETSC_SUCCESS);
     802             : }
     803             : 
     804             : /*
     805             :    EPSConvergence_Gruning - convergence check based on SVDKrylovConvergence().
     806             : */
     807          14 : static PetscErrorCode EPSConvergence_Gruning(EPS eps,PetscBool getall,PetscInt kini,PetscInt nits,PetscInt *kout)
     808             : {
     809          14 :   PetscInt       k,marker,ld;
     810          14 :   PetscReal      *alpha,*beta,resnorm;
     811          14 :   PetscBool      extra;
     812             : 
     813          14 :   PetscFunctionBegin;
     814          14 :   *kout = 0;
     815          14 :   PetscCall(DSGetLeadingDimension(eps->ds,&ld));
     816          14 :   PetscCall(DSGetExtraRow(eps->ds,&extra));
     817          14 :   PetscCheck(extra,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Only implemented for DS with extra row");
     818          14 :   marker = -1;
     819          14 :   if (eps->trackall) getall = PETSC_TRUE;
     820          14 :   PetscCall(DSGetArrayReal(eps->ds,DS_MAT_T,&alpha));
     821          14 :   beta = alpha + ld;
     822          51 :   for (k=kini;k<kini+nits;k++) {
     823          51 :     resnorm = PetscAbsReal(beta[k]);
     824          51 :     PetscCall((*eps->converged)(eps,eps->eigr[k],eps->eigi[k],resnorm,&eps->errest[k],eps->convergedctx));
     825          51 :     if (marker==-1 && eps->errest[k] >= eps->tol) marker = k;
     826          51 :     if (marker!=-1 && !getall) break;
     827             :   }
     828          14 :   PetscCall(DSRestoreArrayReal(eps->ds,DS_MAT_T,&alpha));
     829          14 :   if (marker!=-1) k = marker;
     830          14 :   *kout = k;
     831          14 :   PetscFunctionReturn(PETSC_SUCCESS);
     832             : }
     833             : 
     834           5 : PetscErrorCode EPSSolve_KrylovSchur_BSE_Gruning(EPS eps)
     835             : {
     836           5 :   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
     837           5 :   PetscInt        k,l,ld,nv,nconv=0,nevsave;
     838           5 :   Mat             H,Q,Z;
     839           5 :   BV              U,V,HU,HV;
     840           5 :   IS              is[2];
     841           5 :   PetscReal       *d1,*d2,beta;
     842           5 :   PetscBool       breakdown=PETSC_FALSE;
     843             : 
     844           5 :   PetscFunctionBegin;
     845           5 :   PetscCall(DSGetLeadingDimension(eps->ds,&ld));
     846             : 
     847             :   /* Extract matrix blocks */
     848           5 :   PetscCall(STGetMatrix(eps->st,0,&H));
     849           5 :   PetscCall(MatNestGetISs(H,is,NULL));
     850             : 
     851             :   /* Get the split bases */
     852           5 :   PetscCall(BVGetSplitRows(eps->V,is[0],is[1],&U,&V));
     853             : 
     854             :   /* Create HU and HV */
     855           5 :   PetscCall(BVDuplicate(U,&HU));
     856           5 :   PetscCall(BVDuplicate(V,&HV));
     857             : 
     858           5 :   nevsave  = eps->nev;
     859           5 :   eps->nev = (eps->nev+1)/2;
     860           5 :   l = 0;
     861             : 
     862             :   /* Restart loop */
     863           5 :   while (eps->reason == EPS_CONVERGED_ITERATING) {
     864          14 :     eps->its++;
     865             : 
     866             :     /* Compute an nv-step Lanczos factorization */
     867          14 :     nv = PetscMin(eps->nconv+eps->mpd,eps->ncv);
     868          14 :     PetscCall(DSSetDimensions(eps->ds,nv,eps->nconv,eps->nconv+l));
     869          14 :     PetscCall(DSGetArrayReal(eps->ds,DS_MAT_T,&d1));
     870          14 :     d2 = d1 + ld;
     871          14 :     PetscCall(EPSBSELanczos_Gruning(eps,U,V,HU,HV,d1,d2,eps->nconv+l,&nv,&breakdown));
     872          14 :     beta = d1[nv-1];
     873          14 :     PetscCall(DSRestoreArrayReal(eps->ds,DS_MAT_T,&d1));
     874             : 
     875             :     /* Compute SVD */
     876          14 :     PetscCall(DSSetDimensions(eps->ds,nv,eps->nconv,eps->nconv+l));
     877          14 :     PetscCall(DSSVDSetDimensions(eps->ds,nv));
     878          14 :     PetscCall(DSSetState(eps->ds,l?DS_STATE_RAW:DS_STATE_INTERMEDIATE));
     879          14 :     PetscCall(BVSetActiveColumns(eps->V,eps->nconv,nv));
     880             : 
     881          14 :     PetscCall(DSSolve(eps->ds,eps->eigr,eps->eigi));
     882          14 :     PetscCall(DSSort(eps->ds,eps->eigr,eps->eigi,NULL,NULL,NULL));
     883          14 :     PetscCall(DSUpdateExtraRow(eps->ds));
     884          14 :     PetscCall(DSSynchronize(eps->ds,eps->eigr,eps->eigi));
     885             : 
     886             :     /* Check convergence */
     887          14 :     PetscCall(EPSConvergence_Gruning(eps,PETSC_FALSE,eps->nconv,nv-eps->nconv,&k));
     888          14 :     PetscCall((*eps->stopping)(eps,eps->its,eps->max_it,k,eps->nev,&eps->reason,eps->stoppingctx));
     889          14 :     nconv = k;
     890             : 
     891             :     /* Update l */
     892          14 :     if (eps->reason != EPS_CONVERGED_ITERATING || breakdown || k==nv) l = 0;
     893           9 :     else l = PetscMax(1,(PetscInt)((nv-k)*ctx->keep));
     894          14 :     if (!ctx->lock && l>0) { l += k; k = 0; } /* non-locking variant: reset no. of converged pairs */
     895          14 :     if (l) PetscCall(PetscInfo(eps,"Preparing to restart keeping l=%" PetscInt_FMT " vectors\n",l));
     896             : 
     897          14 :     if (eps->reason == EPS_CONVERGED_ITERATING) {
     898           9 :       PetscCheck(!breakdown,PetscObjectComm((PetscObject)eps),PETSC_ERR_CONV_FAILED,"Breakdown in BSE Krylov-Schur (beta=%g)",(double)beta);
     899             :       /* Prepare the Rayleigh quotient for restart */
     900           9 :       PetscCall(DSTruncate(eps->ds,k+l,PETSC_FALSE));
     901             :     }
     902             :     /* Update the corresponding vectors
     903             :        U(:,idx) = U*Q(:,idx),  V(:,idx) = V*Z(:,idx) */
     904          14 :     PetscCall(DSGetMat(eps->ds,DS_MAT_U,&Q));
     905          14 :     PetscCall(DSGetMat(eps->ds,DS_MAT_V,&Z));
     906          14 :     PetscCall(BVMultInPlace(U,Z,eps->nconv,k+l));
     907          14 :     PetscCall(BVMultInPlace(V,Q,eps->nconv,k+l));
     908          14 :     PetscCall(BVMultInPlace(HU,Z,eps->nconv,k+l));
     909          14 :     PetscCall(BVMultInPlace(HV,Q,eps->nconv,k+l));
     910          14 :     PetscCall(DSRestoreMat(eps->ds,DS_MAT_U,&Q));
     911          14 :     PetscCall(DSRestoreMat(eps->ds,DS_MAT_V,&Z));
     912             : 
     913          14 :     if (eps->reason == EPS_CONVERGED_ITERATING && !breakdown) PetscCall(BVCopyColumn(U,nv,k+l));
     914          14 :     eps->nconv = k;
     915          19 :     PetscCall(EPSMonitor(eps,eps->its,nconv,eps->eigr,eps->eigi,eps->errest,nv));
     916             :   }
     917             : 
     918           5 :   eps->nev = nevsave;
     919             : 
     920           5 :   PetscCall(DSTruncate(eps->ds,eps->nconv,PETSC_TRUE));
     921           5 :   PetscCall(BVRestoreSplitRows(eps->V,is[0],is[1],&U,&V));
     922             : 
     923           5 :   PetscCall(BVDestroy(&HU));
     924           5 :   PetscCall(BVDestroy(&HV));
     925           5 :   PetscFunctionReturn(PETSC_SUCCESS);
     926             : }
     927             : 
     928           4 : PetscErrorCode EPSSolve_KrylovSchur_BSE_ProjectedBSE(EPS eps)
     929             : {
     930           4 :   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
     931           4 :   PetscInt        i,k,l,ld,nv,nconv=0,nevsave;
     932           4 :   Mat             H,Q;
     933           4 :   Vec             v;
     934           4 :   BV              U,V;
     935           4 :   IS              is[2];
     936           4 :   PetscReal       *a,*b,beta;
     937           4 :   PetscBool       breakdown=PETSC_FALSE;
     938             : 
     939           4 :   PetscFunctionBegin;
     940           4 :   PetscCall(DSGetLeadingDimension(eps->ds,&ld));
     941             : 
     942             :   /* Extract matrix blocks */
     943           4 :   PetscCall(STGetMatrix(eps->st,0,&H));
     944           4 :   PetscCall(MatNestGetISs(H,is,NULL));
     945             : 
     946             :   /* Get the split bases */
     947           4 :   PetscCall(BVGetSplitRows(eps->V,is[0],is[1],&U,&V));
     948             : 
     949             :   /* Vector v */
     950           4 :   PetscCall(BVCreateVec(V,&v));
     951             : 
     952           4 :   nevsave  = eps->nev;
     953           4 :   eps->nev = (eps->nev+1)/2;
     954           4 :   l = 0;
     955             : 
     956             :   /* Restart loop */
     957           4 :   while (eps->reason == EPS_CONVERGED_ITERATING) {
     958          11 :     eps->its++;
     959             : 
     960             :     /* Compute an nv-step Lanczos factorization */
     961          11 :     nv = PetscMin(eps->nconv+eps->mpd,eps->ncv);
     962          11 :     PetscCall(DSSetDimensions(eps->ds,nv,eps->nconv,eps->nconv+l));
     963          11 :     PetscCall(DSGetArrayReal(eps->ds,DS_MAT_T,&a));
     964          11 :     b = a + ld;
     965          11 :     PetscCall(EPSBSELanczos_ProjectedBSE(eps,U,V,v,a,b,eps->nconv+l,&nv,&breakdown));
     966          11 :     beta = b[nv-1];
     967          11 :     PetscCall(DSRestoreArrayReal(eps->ds,DS_MAT_T,&a));
     968          11 :     PetscCall(DSSetDimensions(eps->ds,nv,eps->nconv,eps->nconv+l));
     969          11 :     PetscCall(DSSetState(eps->ds,l?DS_STATE_RAW:DS_STATE_INTERMEDIATE));
     970          11 :     PetscCall(BVSetActiveColumns(eps->V,eps->nconv,nv));
     971             : 
     972             :     /* Solve projected problem */
     973          11 :     PetscCall(DSSolve(eps->ds,eps->eigr,eps->eigi));
     974          11 :     PetscCall(DSSort(eps->ds,eps->eigr,eps->eigi,NULL,NULL,NULL));
     975          11 :     PetscCall(DSUpdateExtraRow(eps->ds));
     976          11 :     PetscCall(DSSynchronize(eps->ds,eps->eigr,eps->eigi));
     977             : 
     978             :     /* Check convergence */
     979         187 :     for (i=0;i<eps->ncv;i++) eps->eigr[i] = PetscSqrtReal(PetscRealPart(eps->eigr[i]));
     980          11 :     PetscCall(EPSKrylovConvergence(eps,PETSC_FALSE,eps->nconv,nv-eps->nconv,beta,0.0,1.0,&k));
     981          11 :     PetscCall((*eps->stopping)(eps,eps->its,eps->max_it,k,eps->nev,&eps->reason,eps->stoppingctx));
     982          11 :     nconv = k;
     983             : 
     984             :     /* Update l */
     985          11 :     if (eps->reason != EPS_CONVERGED_ITERATING || breakdown || k==nv) l = 0;
     986           7 :     else l = PetscMax(1,(PetscInt)((nv-k)*ctx->keep));
     987          11 :     if (!ctx->lock && l>0) { l += k; k = 0; } /* non-locking variant: reset no. of converged pairs */
     988          11 :     if (l) PetscCall(PetscInfo(eps,"Preparing to restart keeping l=%" PetscInt_FMT " vectors\n",l));
     989             : 
     990          11 :     if (eps->reason == EPS_CONVERGED_ITERATING) {
     991           7 :       PetscCheck(!breakdown,PetscObjectComm((PetscObject)eps),PETSC_ERR_CONV_FAILED,"Breakdown in BSE Krylov-Schur (beta=%g)",(double)beta);
     992             :       /* Prepare the Rayleigh quotient for restart */
     993           7 :       PetscCall(DSTruncate(eps->ds,k+l,PETSC_FALSE));
     994             :     }
     995             :     /* Update the corresponding vectors
     996             :        U(:,idx) = U*Q(:,idx),  V(:,idx) = V*Q(:,idx) */
     997          11 :     PetscCall(DSGetMat(eps->ds,DS_MAT_Q,&Q));
     998          11 :     PetscCall(BVMultInPlace(U,Q,eps->nconv,k+l));
     999          11 :     PetscCall(BVMultInPlace(V,Q,eps->nconv,k+l));
    1000          11 :     PetscCall(DSRestoreMat(eps->ds,DS_MAT_Q,&Q));
    1001             : 
    1002          11 :     if (eps->reason == EPS_CONVERGED_ITERATING && !breakdown) PetscCall(BVCopyColumn(eps->V,nv,k+l));
    1003          11 :     eps->nconv = k;
    1004          15 :     PetscCall(EPSMonitor(eps,eps->its,nconv,eps->eigr,eps->eigi,eps->errest,nv));
    1005             :   }
    1006             : 
    1007           4 :   eps->nev = nevsave;
    1008             : 
    1009           4 :   PetscCall(DSTruncate(eps->ds,eps->nconv,PETSC_TRUE));
    1010           4 :   PetscCall(BVRestoreSplitRows(eps->V,is[0],is[1],&U,&V));
    1011             : 
    1012           4 :   PetscCall(VecDestroy(&v));
    1013           4 :   PetscFunctionReturn(PETSC_SUCCESS);
    1014             : }

Generated by: LCOV version 1.14