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

Generated by: LCOV version 1.14