Date: 2026-03-09T09:12:32+00:00

Actual source code: ex55.c

      1: /*
      2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      4:    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain

      6:    This file is part of SLEPc.
      7:    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
      8:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      9: */

     11: static char help[] = "Eigenvalue problem with Bethe-Salpeter structure.\n\n"
     12:   "The command line options are:\n"
     13:   "  -n <n>, where <n> = dimension of the blocks.\n\n";

     15: #include <slepceps.h>

     17: /*
     18:    This example computes eigenvalues of a matrix

     20:         H = [  R    C
     21:               -C^H -R^T ],

     23:    where R is Hermitian and C is complex symmetric. In particular, R and C have the
     24:    following Toeplitz structure:

     26:         R = pentadiag{a,b,c,conj(b),conj(a)}
     27:         C = tridiag{b,d,b}

     29:    where a,b,d are complex scalars, and c is real.
     30: */

     32: int main(int argc,char **argv)
     33: {
     34:   Mat            H,R,C;      /* problem matrices */
     35:   EPS            eps;        /* eigenproblem solver context */
     36:   PetscScalar    a,b,c,d;
     37:   PetscReal      lev;
     38:   PetscInt       n=24,Istart,Iend,i,nconv;
     39:   PetscBool      terse,checkorthog,nest=PETSC_FALSE;
     40:   Vec            t,*x,*y;

     42:   PetscFunctionBeginUser;
     43:   PetscCall(SlepcInitialize(&argc,&argv,NULL,help));

     45:   PetscCall(PetscOptionsGetInt(NULL,NULL,"-n",&n,NULL));
     46:   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\nBethe-Salpeter eigenproblem, n=%" PetscInt_FMT "\n\n",n));

     48:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     49:                Compute the problem matrices R and C
     50:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

     52: #if defined(PETSC_USE_COMPLEX)
     53:   a = PetscCMPLX(-0.1,0.2);
     54:   b = PetscCMPLX(1.0,0.5);
     55:   d = PetscCMPLX(2.0,0.2);
     56: #else
     57:   a = -0.1;
     58:   b = 1.0;
     59:   d = 2.0;
     60: #endif
     61:   c = 4.5;

     63:   PetscCall(MatCreate(PETSC_COMM_WORLD,&R));
     64:   PetscCall(MatSetSizes(R,PETSC_DECIDE,PETSC_DECIDE,n,n));
     65:   PetscCall(MatSetFromOptions(R));

     67:   PetscCall(MatCreate(PETSC_COMM_WORLD,&C));
     68:   PetscCall(MatSetSizes(C,PETSC_DECIDE,PETSC_DECIDE,n,n));
     69:   PetscCall(MatSetFromOptions(C));

     71:   PetscCall(MatGetOwnershipRange(R,&Istart,&Iend));
     72:   for (i=Istart;i<Iend;i++) {
     73:     if (i>1) PetscCall(MatSetValue(R,i,i-2,a,INSERT_VALUES));
     74:     if (i>0) PetscCall(MatSetValue(R,i,i-1,b,INSERT_VALUES));
     75:     PetscCall(MatSetValue(R,i,i,c,INSERT_VALUES));
     76:     if (i<n-1) PetscCall(MatSetValue(R,i,i+1,PetscConj(b),INSERT_VALUES));
     77:     if (i<n-2) PetscCall(MatSetValue(R,i,i+2,PetscConj(a),INSERT_VALUES));
     78:   }

     80:   PetscCall(MatGetOwnershipRange(C,&Istart,&Iend));
     81:   for (i=Istart;i<Iend;i++) {
     82:     if (i>0) PetscCall(MatSetValue(C,i,i-1,b,INSERT_VALUES));
     83:     PetscCall(MatSetValue(C,i,i,d,INSERT_VALUES));
     84:     if (i<n-1) PetscCall(MatSetValue(C,i,i+1,b,INSERT_VALUES));
     85:   }

     87:   PetscCall(MatAssemblyBegin(R,MAT_FINAL_ASSEMBLY));
     88:   PetscCall(MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY));
     89:   PetscCall(MatAssemblyEnd(R,MAT_FINAL_ASSEMBLY));
     90:   PetscCall(MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY));

     92:   PetscCall(MatCreateBSE(R,C,&H));

     94:   /* if you prefer, set the vector type so that MatCreateVecs() returns nested vectors */
     95:   PetscCall(PetscOptionsGetBool(NULL,NULL,"-nest",&nest,NULL));
     96:   if (nest) PetscCall(MatNestSetVecType(H,VECNEST));

     98:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     99:                 Create the eigensolver and set various options
    100:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    102:   PetscCall(EPSCreate(PETSC_COMM_WORLD,&eps));
    103:   PetscCall(EPSSetOperators(eps,H,NULL));
    104:   PetscCall(EPSSetProblemType(eps,EPS_BSE));
    105:   PetscCall(EPSSetFromOptions(eps));

    107:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    108:                  Solve the eigensystem and display solution
    109:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    111:   PetscCall(EPSSolve(eps));

    113:   /* show detailed info unless -terse option is given by user */
    114:   PetscCall(PetscOptionsHasName(NULL,NULL,"-terse",&terse));
    115:   if (terse) PetscCall(EPSErrorView(eps,EPS_ERROR_RELATIVE,NULL));
    116:   else {
    117:     PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD,PETSC_VIEWER_ASCII_INFO_DETAIL));
    118:     PetscCall(EPSConvergedReasonView(eps,PETSC_VIEWER_STDOUT_WORLD));
    119:     PetscCall(EPSErrorView(eps,EPS_ERROR_RELATIVE,PETSC_VIEWER_STDOUT_WORLD));
    120:     PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD));
    121:   }

    123:   /* check bi-orthogonality */
    124:   PetscCall(PetscOptionsHasName(NULL,NULL,"-checkorthog",&checkorthog));
    125:   PetscCall(EPSGetConverged(eps,&nconv));
    126:   if (checkorthog && nconv>0) {
    127:     PetscCall(MatCreateVecs(H,&t,NULL));
    128:     PetscCall(VecDuplicateVecs(t,nconv,&x));
    129:     PetscCall(VecDuplicateVecs(t,nconv,&y));
    130:     for (i=0;i<nconv;i++) {
    131:       PetscCall(EPSGetEigenvector(eps,i,x[i],NULL));
    132:       PetscCall(EPSGetLeftEigenvector(eps,i,y[i],NULL));
    133:     }
    134:     PetscCall(VecCheckOrthogonality(x,nconv,y,nconv,NULL,NULL,&lev));
    135:     if (lev<100*PETSC_MACHINE_EPSILON) PetscCall(PetscPrintf(PETSC_COMM_WORLD," Level of bi-orthogonality of eigenvectors < 100*eps\n\n"));
    136:     else PetscCall(PetscPrintf(PETSC_COMM_WORLD," Level of bi-orthogonality of eigenvectors: %g\n\n",(double)lev));
    137:     PetscCall(VecDestroy(&t));
    138:     PetscCall(VecDestroyVecs(nconv,&x));
    139:     PetscCall(VecDestroyVecs(nconv,&y));
    140:   }

    142:   PetscCall(EPSDestroy(&eps));
    143:   PetscCall(MatDestroy(&R));
    144:   PetscCall(MatDestroy(&C));
    145:   PetscCall(MatDestroy(&H));
    146:   PetscCall(SlepcFinalize());
    147:   return 0;
    148: }

    150: /*TEST

    152:    testset:
    153:       args: -eps_nev 4 -eps_ncv 16 -eps_krylovschur_bse_type {{shao gruning projectedbse}} -terse -checkorthog -nest {{0 1}}
    154:       filter: sed -e "s/17496/17495/g" | sed -e "s/38566/38567/g" | sed -e "s/32172/32173/g"
    155:       nsize: {{1 2}}
    156:       test:
    157:          suffix: 1
    158:          requires: complex
    159:       test:
    160:          suffix: 1_real
    161:          requires: !complex
    162:       test:
    163:          suffix: 1_dense
    164:          args: -mat_type dense
    165:          requires: complex
    166:          output_file: output/ex55_1.out
    167:       test:
    168:          suffix: 1_cuda
    169:          args: -mat_type aijcusparse
    170:          requires: cuda complex
    171:          output_file: output/ex55_1.out
    172:       test:
    173:          suffix: 1_real_cuda
    174:          args: -mat_type aijcusparse
    175:          requires: cuda !complex
    176:          output_file: output/ex55_1_real.out
    177:       test:
    178:          suffix: 1_hip
    179:          args: -mat_type aijhipsparse
    180:          requires: hip complex
    181:          output_file: output/ex55_1.out
    182:       test:
    183:          suffix: 1_real_hip
    184:          args: -mat_type aijhipsparse
    185:          requires: hip !complex
    186:          output_file: output/ex55_1_real.out

    188:    testset:
    189:       args: -eps_nev 4 -eps_ncv 16 -eps_krylovschur_bse_type {{shao gruning projectedbse}} -st_type sinvert -terse
    190:       filter: sed -e "s/17496/17495/g" | sed -e "s/38566/38567/g"
    191:       test:
    192:          suffix: 1_sinvert
    193:          requires: complex
    194:       test:
    195:          nsize: 4
    196:          args: -mat_type scalapack
    197:          suffix: 1_sinvert_scalapack
    198:          requires: complex scalapack
    199:          output_file: output/ex55_1_sinvert.out
    200:       test:
    201:          suffix: 1_real_sinvert
    202:          requires: !complex
    203:       test:
    204:          nsize: 4
    205:          args: -mat_type scalapack
    206:          suffix: 1_real_sinvert_scalapack
    207:          requires: !complex scalapack
    208:          output_file: output/ex55_1_real_sinvert.out

    210:    testset:
    211:       args: -n 90 -eps_threshold_absolute 2.5 -eps_ncv {{10 24}} -eps_krylovschur_bse_type {{shao gruning projectedbse}} -eps_tol 1e-14 -terse -checkorthog
    212:       test:
    213:          suffix: 2
    214:          requires: double complex
    215:       test:
    216:          suffix: 2_real
    217:          requires: double !complex

    219:    testset:
    220:       args: -eps_nev 28 -eps_ncv 18 -terse
    221:       test:
    222:          suffix: 3
    223:          requires: !complex !single

    225: TEST*/