Date: 2026-05-01T10:02:37+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"
     14:   "  -R <filename>, R matrix.\n"
     15:   "  -C <filename>, C matrix.\n\n";

     17: #include <slepceps.h>

     19: /*
     20:    This example computes eigenvalues of a matrix

     22:         H = [  R    C
     23:               -C^H -R^T ],

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

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

     31:    where a,b,d are complex scalars, and c is real.

     33:    Alternatively, use -R and -C command-line options to load matrices from file.
     34: */

     36: int main(int argc,char **argv)
     37: {
     38:   Mat            H,R,C;      /* problem matrices */
     39:   EPS            eps;        /* eigenproblem solver context */
     40:   PetscScalar    a,b,c,d;
     41:   PetscReal      lev;
     42:   PetscInt       n=24,Istart,Iend,i,nconv;
     43:   PetscBool      flg,terse,checkorthog,nest=PETSC_FALSE;
     44:   Vec            t,*x,*y;
     45:   PetscViewer    viewer;
     46:   char           filename[PETSC_MAX_PATH_LEN];

     48:   PetscFunctionBeginUser;
     49:   PetscCall(SlepcInitialize(&argc,&argv,NULL,help));

     51:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     52:              Compute (or load) the problem matrices R and C
     53:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

     55:   PetscCall(PetscOptionsHasName(NULL,NULL,"-R",&flg));

     57:   if (flg) {

     59:     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\nBethe-Salpeter eigenproblem stored in file\n\n"));
     60:     PetscCall(PetscPrintf(PETSC_COMM_WORLD," Reading %s matrices from a binary file...\n",PetscDefined(USE_COMPLEX)?"COMPLEX":"REAL"));

     62:     PetscCall(PetscOptionsGetString(NULL,NULL,"-R",filename,sizeof(filename),&flg));
     63:     PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD,filename,FILE_MODE_READ,&viewer));
     64:     PetscCall(MatCreate(PETSC_COMM_WORLD,&R));
     65:     PetscCall(MatSetFromOptions(R));
     66:     PetscCall(MatLoad(R,viewer));
     67:     PetscCall(PetscViewerDestroy(&viewer));

     69:     PetscCall(PetscOptionsGetString(NULL,NULL,"-C",filename,sizeof(filename),&flg));
     70:     PetscCheck(flg,PETSC_COMM_WORLD,PETSC_ERR_USER_INPUT,"Must indicate file for both R and C matrices");
     71:     PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD,filename,FILE_MODE_READ,&viewer));
     72:     PetscCall(MatCreate(PETSC_COMM_WORLD,&C));
     73:     PetscCall(MatSetFromOptions(C));
     74:     PetscCall(MatLoad(C,viewer));
     75:     PetscCall(PetscViewerDestroy(&viewer));

     77:   } else {

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

     82: #if defined(PETSC_USE_COMPLEX)
     83:     a = PetscCMPLX(-0.1,0.2);
     84:     b = PetscCMPLX(1.0,0.5);
     85:     d = PetscCMPLX(2.0,0.2);
     86: #else
     87:     a = -0.1;
     88:     b = 1.0;
     89:     d = 2.0;
     90: #endif
     91:     c = 4.5;

     93:     PetscCall(MatCreate(PETSC_COMM_WORLD,&R));
     94:     PetscCall(MatSetSizes(R,PETSC_DECIDE,PETSC_DECIDE,n,n));
     95:     PetscCall(MatSetFromOptions(R));

     97:     PetscCall(MatCreate(PETSC_COMM_WORLD,&C));
     98:     PetscCall(MatSetSizes(C,PETSC_DECIDE,PETSC_DECIDE,n,n));
     99:     PetscCall(MatSetFromOptions(C));

    101:     PetscCall(MatGetOwnershipRange(R,&Istart,&Iend));
    102:     for (i=Istart;i<Iend;i++) {
    103:       if (i>1) PetscCall(MatSetValue(R,i,i-2,a,INSERT_VALUES));
    104:       if (i>0) PetscCall(MatSetValue(R,i,i-1,b,INSERT_VALUES));
    105:       PetscCall(MatSetValue(R,i,i,c,INSERT_VALUES));
    106:       if (i<n-1) PetscCall(MatSetValue(R,i,i+1,PetscConj(b),INSERT_VALUES));
    107:       if (i<n-2) PetscCall(MatSetValue(R,i,i+2,PetscConj(a),INSERT_VALUES));
    108:     }

    110:     PetscCall(MatGetOwnershipRange(C,&Istart,&Iend));
    111:     for (i=Istart;i<Iend;i++) {
    112:       if (i>0) PetscCall(MatSetValue(C,i,i-1,b,INSERT_VALUES));
    113:       PetscCall(MatSetValue(C,i,i,d,INSERT_VALUES));
    114:       if (i<n-1) PetscCall(MatSetValue(C,i,i+1,b,INSERT_VALUES));
    115:     }

    117:     PetscCall(MatAssemblyBegin(R,MAT_FINAL_ASSEMBLY));
    118:     PetscCall(MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY));
    119:     PetscCall(MatAssemblyEnd(R,MAT_FINAL_ASSEMBLY));
    120:     PetscCall(MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY));
    121:   }

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

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

    129:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    130:                 Create the eigensolver and set various options
    131:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    133:   PetscCall(EPSCreate(PETSC_COMM_WORLD,&eps));
    134:   PetscCall(EPSSetOperators(eps,H,NULL));
    135:   PetscCall(EPSSetProblemType(eps,EPS_BSE));
    136:   PetscCall(EPSSetFromOptions(eps));

    138:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    139:                  Solve the eigensystem and display solution
    140:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    142:   PetscCall(EPSSolve(eps));

    144:   /* show detailed info unless -terse option is given by user */
    145:   PetscCall(PetscOptionsHasName(NULL,NULL,"-terse",&terse));
    146:   if (terse) PetscCall(EPSErrorView(eps,EPS_ERROR_RELATIVE,NULL));
    147:   else {
    148:     PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD,PETSC_VIEWER_ASCII_INFO_DETAIL));
    149:     PetscCall(EPSConvergedReasonView(eps,PETSC_VIEWER_STDOUT_WORLD));
    150:     PetscCall(EPSErrorView(eps,EPS_ERROR_RELATIVE,PETSC_VIEWER_STDOUT_WORLD));
    151:     PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD));
    152:   }

    154:   /* check bi-orthogonality */
    155:   PetscCall(PetscOptionsHasName(NULL,NULL,"-checkorthog",&checkorthog));
    156:   PetscCall(EPSGetConverged(eps,&nconv));
    157:   if (checkorthog && nconv>0) {
    158:     PetscCall(MatCreateVecs(H,&t,NULL));
    159:     PetscCall(VecDuplicateVecs(t,nconv,&x));
    160:     PetscCall(VecDuplicateVecs(t,nconv,&y));
    161:     for (i=0;i<nconv;i++) {
    162:       PetscCall(EPSGetEigenvector(eps,i,x[i],NULL));
    163:       PetscCall(EPSGetLeftEigenvector(eps,i,y[i],NULL));
    164:     }
    165:     PetscCall(VecCheckOrthogonality(x,nconv,y,nconv,NULL,NULL,&lev));
    166:     if (lev<100*PETSC_MACHINE_EPSILON) PetscCall(PetscPrintf(PETSC_COMM_WORLD," Level of bi-orthogonality of eigenvectors < 100*eps\n\n"));
    167:     else PetscCall(PetscPrintf(PETSC_COMM_WORLD," Level of bi-orthogonality of eigenvectors: %g\n\n",(double)lev));
    168:     PetscCall(VecDestroy(&t));
    169:     PetscCall(VecDestroyVecs(nconv,&x));
    170:     PetscCall(VecDestroyVecs(nconv,&y));
    171:   }

    173:   PetscCall(EPSDestroy(&eps));
    174:   PetscCall(MatDestroy(&R));
    175:   PetscCall(MatDestroy(&C));
    176:   PetscCall(MatDestroy(&H));
    177:   PetscCall(SlepcFinalize());
    178:   return 0;
    179: }

    181: /*TEST

    183:    testset:
    184:       args: -eps_nev 4 -eps_ncv 16 -eps_krylovschur_bse_type {{shao gruning projectedbse}} -terse -checkorthog -nest {{0 1}}
    185:       filter: sed -e "s/17496/17495/g" | sed -e "s/38566/38567/g" | sed -e "s/32172/32173/g"
    186:       nsize: {{1 2}}
    187:       test:
    188:          suffix: 1
    189:          requires: complex
    190:       test:
    191:          suffix: 1_real
    192:          requires: !complex
    193:       test:
    194:          suffix: 1_dense
    195:          args: -mat_type dense
    196:          requires: complex
    197:          output_file: output/ex55_1.out
    198:       test:
    199:          suffix: 1_cuda
    200:          args: -mat_type aijcusparse
    201:          requires: cuda complex
    202:          output_file: output/ex55_1.out
    203:       test:
    204:          suffix: 1_real_cuda
    205:          args: -mat_type aijcusparse
    206:          requires: cuda !complex
    207:          output_file: output/ex55_1_real.out
    208:       test:
    209:          suffix: 1_hip
    210:          args: -mat_type aijhipsparse
    211:          requires: hip complex
    212:          output_file: output/ex55_1.out
    213:       test:
    214:          suffix: 1_real_hip
    215:          args: -mat_type aijhipsparse
    216:          requires: hip !complex
    217:          output_file: output/ex55_1_real.out

    219:    testset:
    220:       args: -eps_nev 4 -eps_ncv 16 -eps_krylovschur_bse_type {{shao gruning projectedbse}} -st_type sinvert -terse
    221:       filter: sed -e "s/17496/17495/g" | sed -e "s/38566/38567/g"
    222:       test:
    223:          suffix: 1_sinvert
    224:          requires: complex
    225:       test:
    226:          nsize: 4
    227:          args: -mat_type scalapack
    228:          suffix: 1_sinvert_scalapack
    229:          requires: complex scalapack !__float128
    230:          output_file: output/ex55_1_sinvert.out
    231:       test:
    232:          suffix: 1_real_sinvert
    233:          requires: !complex
    234:       test:
    235:          nsize: 4
    236:          args: -mat_type scalapack
    237:          suffix: 1_real_sinvert_scalapack
    238:          requires: !complex scalapack !__float128
    239:          output_file: output/ex55_1_real_sinvert.out

    241:    testset:
    242:       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
    243:       test:
    244:          suffix: 2
    245:          requires: double complex
    246:       test:
    247:          suffix: 2_real
    248:          requires: double !complex

    250:    testset:
    251:       args: -eps_nev 28 -eps_ncv 18 -terse
    252:       test:
    253:          suffix: 3
    254:          requires: !complex !single

    256: TEST*/