Date: 2024-12-02T08:58:30+00:00

Actual source code: sinvert.c
slepc-3.22.2 2024-12-02
Report Typos and Errors

      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: */
     10: /*
     11:    Implements the shift-and-invert technique for eigenvalue problems
     12: */

     14: #include <slepc/private/stimpl.h>

     16: static PetscErrorCode STBackTransform_Sinvert(ST st,PetscInt n,PetscScalar *eigr,PetscScalar *eigi)
     17: {
     18:   PetscInt    j;
     19: #if !defined(PETSC_USE_COMPLEX)
     20:   PetscScalar t;
     21: #endif

     23:   PetscFunctionBegin;
     24: #if !defined(PETSC_USE_COMPLEX)
     25:   for (j=0;j<n;j++) {
     26:     if (eigi[j] == 0) eigr[j] = 1.0 / eigr[j] + st->sigma;
     27:     else {
     28:       t = eigr[j] * eigr[j] + eigi[j] * eigi[j];
     29:       eigr[j] = eigr[j] / t + st->sigma;
     30:       eigi[j] = - eigi[j] / t;
     31:     }
     32:   }
     33: #else
     34:   for (j=0;j<n;j++) {
     35:     eigr[j] = 1.0 / eigr[j] + st->sigma;
     36:   }
     37: #endif
     38:   PetscFunctionReturn(PETSC_SUCCESS);
     39: }

     41: static PetscErrorCode STPostSolve_Sinvert(ST st)
     42: {
     43:   PetscFunctionBegin;
     44:   if (st->matmode == ST_MATMODE_INPLACE) {
     45:     if (st->nmat>1) PetscCall(MatAXPY(st->A[0],st->sigma,st->A[1],st->str));
     46:     else PetscCall(MatShift(st->A[0],st->sigma));
     47:     st->Astate[0] = ((PetscObject)st->A[0])->state;
     48:     st->state   = ST_STATE_INITIAL;
     49:     st->opready = PETSC_FALSE;
     50:   }
     51:   PetscFunctionReturn(PETSC_SUCCESS);
     52: }

     54: /*
     55:    Operator (sinvert):
     56:                Op               P         M
     57:    if nmat=1:  (A-sI)^-1        A-sI      NULL
     58:    if nmat=2:  (A-sB)^-1 B      A-sB      B
     59: */
     60: static PetscErrorCode STComputeOperator_Sinvert(ST st)
     61: {
     62:   PetscFunctionBegin;
     63:   /* if the user did not set the shift, use the target value */
     64:   if (!st->sigma_set) st->sigma = st->defsigma;
     65:   PetscCall(PetscObjectReference((PetscObject)st->A[1]));
     66:   PetscCall(MatDestroy(&st->T[0]));
     67:   st->T[0] = st->A[1];
     68:   PetscCall(STMatMAXPY_Private(st,-st->sigma,0.0,0,NULL,PetscNot(st->state==ST_STATE_UPDATED),PETSC_FALSE,&st->T[1]));
     69:   PetscCall(PetscObjectReference((PetscObject)st->T[1]));
     70:   PetscCall(MatDestroy(&st->P));
     71:   st->P = st->T[1];
     72:   st->M = (st->nmat>1)? st->T[0]: NULL;
     73:   if (st->Psplit) {  /* build custom preconditioner from the split matrices */
     74:     PetscCall(STMatMAXPY_Private(st,-st->sigma,0.0,0,NULL,PETSC_TRUE,PETSC_TRUE,&st->Pmat));
     75:   }
     76:   PetscFunctionReturn(PETSC_SUCCESS);
     77: }

     79: static PetscErrorCode STSetUp_Sinvert(ST st)
     80: {
     81:   PetscInt       k,nc,nmat=st->nmat,nsub;
     82:   PetscScalar    *coeffs=NULL;
     83:   PetscBool      islu;
     84:   KSP            *subksp;
     85:   PC             pc,pcsub;
     86:   Mat            A00;
     87:   MatType        type;
     88:   PetscBool      flg;
     89:   char           str[64];

     91:   PetscFunctionBegin;
     92:   if (nmat>1) PetscCall(STSetWorkVecs(st,1));
     93:   /* if the user did not set the shift, use the target value */
     94:   if (!st->sigma_set) st->sigma = st->defsigma;
     95:   if (nmat>2) {  /* set-up matrices for polynomial eigenproblems */
     96:     if (st->transform) {
     97:       nc = (nmat*(nmat+1))/2;
     98:       PetscCall(PetscMalloc1(nc,&coeffs));
     99:       /* Compute coeffs */
    100:       PetscCall(STCoeffs_Monomial(st,coeffs));
    101:       /* T[0] = A_n */
    102:       k = nmat-1;
    103:       PetscCall(PetscObjectReference((PetscObject)st->A[k]));
    104:       PetscCall(MatDestroy(&st->T[0]));
    105:       st->T[0] = st->A[k];
    106:       for (k=1;k<nmat;k++) PetscCall(STMatMAXPY_Private(st,nmat>2?st->sigma:-st->sigma,0.0,nmat-k-1,coeffs?coeffs+(k*(k+1))/2:NULL,PetscNot(st->state==ST_STATE_UPDATED),PETSC_FALSE,&st->T[k]));
    107:       PetscCall(PetscFree(coeffs));
    108:       PetscCall(PetscObjectReference((PetscObject)st->T[nmat-1]));
    109:       PetscCall(MatDestroy(&st->P));
    110:       st->P = st->T[nmat-1];
    111:       if (st->Psplit) {  /* build custom preconditioner from the split matrices */
    112:         PetscCall(STMatMAXPY_Private(st,st->sigma,0.0,0,coeffs?coeffs+((nmat-1)*nmat)/2:NULL,PETSC_TRUE,PETSC_TRUE,&st->Pmat));
    113:       }
    114:       PetscCall(ST_KSPSetOperators(st,st->P,st->Pmat?st->Pmat:st->P));
    115:     } else {
    116:       for (k=0;k<nmat;k++) {
    117:         PetscCall(PetscObjectReference((PetscObject)st->A[k]));
    118:         PetscCall(MatDestroy(&st->T[k]));
    119:         st->T[k] = st->A[k];
    120:       }
    121:     }
    122:   }
    123:   if (st->structured) {
    124:     /* ./ex55 -st_type sinvert -eps_target 0 -eps_target_magnitude
    125:               -st_ksp_type preonly -st_pc_type fieldsplit
    126:               -st_fieldsplit_0_ksp_type preonly -st_fieldsplit_0_pc_type lu
    127:               -st_fieldsplit_1_ksp_type preonly -st_fieldsplit_1_pc_type lu
    128:               -st_pc_fieldsplit_type schur -st_pc_fieldsplit_schur_fact_type full
    129:               -st_pc_fieldsplit_schur_precondition full */
    130:     PetscCall(KSPGetPC(st->ksp,&pc));
    131:     PetscCall(PetscObjectTypeCompare((PetscObject)pc,PCLU,&islu));
    132:     if (islu) {  /* assume PCLU means the user has not set any options */
    133:       PetscCall(KSPSetType(st->ksp,KSPPREONLY));
    134:       PetscCall(PCSetType(pc,PCFIELDSPLIT));
    135:       PetscCall(PCFieldSplitSetType(pc,PC_COMPOSITE_SCHUR));
    136:       PetscCall(PCFieldSplitSetSchurFactType(pc,PC_FIELDSPLIT_SCHUR_FACT_FULL));
    137:       PetscCall(PCFieldSplitSetSchurPre(pc,PC_FIELDSPLIT_SCHUR_PRE_FULL,NULL));
    138:       /* hack to set Mat type of Schur complement equal to A00, assumes default prefixes */
    139:       PetscCall(PetscOptionsHasName(((PetscObject)st)->options,((PetscObject)st)->prefix,"-st_fieldsplit_1_explicit_operator_mat_type",&flg));
    140:       if (!flg) {
    141:         PetscCall(MatNestGetSubMat(st->A[0],0,0,&A00));
    142:         PetscCall(MatGetType(A00,&type));
    143:         PetscCall(PetscSNPrintf(str,sizeof(str),"-%sst_fieldsplit_1_explicit_operator_mat_type %s",((PetscObject)st)->prefix?((PetscObject)st)->prefix:"",type));
    144:         PetscCall(PetscOptionsInsertString(((PetscObject)st)->options,str));
    145:       }
    146:       /* set preonly+lu on block solvers */
    147:       PetscCall(KSPSetUp(st->ksp));
    148:       PetscCall(PCFieldSplitGetSubKSP(pc,&nsub,&subksp));
    149:       PetscCall(KSPSetType(subksp[0],KSPPREONLY));
    150:       PetscCall(KSPGetPC(subksp[0],&pcsub));
    151:       PetscCall(PCSetType(pcsub,PCLU));
    152:       PetscCall(KSPSetType(subksp[1],KSPPREONLY));
    153:       PetscCall(KSPGetPC(subksp[1],&pcsub));
    154:       PetscCall(PCSetType(pcsub,PCLU));
    155:       PetscCall(PetscFree(subksp));
    156:     }
    157:   } else {
    158:     if (st->P) PetscCall(KSPSetUp(st->ksp));
    159:   }
    160:   PetscFunctionReturn(PETSC_SUCCESS);
    161: }

    163: static PetscErrorCode STSetShift_Sinvert(ST st,PetscScalar newshift)
    164: {
    165:   PetscInt       nmat=PetscMax(st->nmat,2),k,nc;
    166:   PetscScalar    *coeffs=NULL;

    168:   PetscFunctionBegin;
    169:   if (st->transform) {
    170:     if (st->matmode == ST_MATMODE_COPY && nmat>2) {
    171:       nc = (nmat*(nmat+1))/2;
    172:       PetscCall(PetscMalloc1(nc,&coeffs));
    173:       /* Compute coeffs */
    174:       PetscCall(STCoeffs_Monomial(st,coeffs));
    175:     }
    176:     for (k=1;k<nmat;k++) PetscCall(STMatMAXPY_Private(st,nmat>2?newshift:-newshift,nmat>2?st->sigma:-st->sigma,nmat-k-1,coeffs?coeffs+(k*(k+1))/2:NULL,PETSC_FALSE,PETSC_FALSE,&st->T[k]));
    177:     if (st->matmode == ST_MATMODE_COPY && nmat>2) PetscCall(PetscFree(coeffs));
    178:     if (st->P!=st->T[nmat-1]) {
    179:       PetscCall(PetscObjectReference((PetscObject)st->T[nmat-1]));
    180:       PetscCall(MatDestroy(&st->P));
    181:       st->P = st->T[nmat-1];
    182:     }
    183:     if (st->Psplit) {  /* build custom preconditioner from the split matrices */
    184:       PetscCall(STMatMAXPY_Private(st,nmat>2?newshift:-newshift,nmat>2?st->sigma:-st->sigma,0,coeffs?coeffs+((nmat-1)*nmat)/2:NULL,PETSC_FALSE,PETSC_TRUE,&st->Pmat));
    185:     }
    186:   }
    187:   if (st->P) {
    188:     PetscCall(ST_KSPSetOperators(st,st->P,st->Pmat?st->Pmat:st->P));
    189:     PetscCall(KSPSetUp(st->ksp));
    190:   }
    191:   PetscFunctionReturn(PETSC_SUCCESS);
    192: }

    194: SLEPC_EXTERN PetscErrorCode STCreate_Sinvert(ST st)
    195: {
    196:   PetscFunctionBegin;
    197:   st->usesksp = PETSC_TRUE;

    199:   st->ops->apply           = STApply_Generic;
    200:   st->ops->applytrans      = STApplyTranspose_Generic;
    201:   st->ops->applyhermtrans  = STApplyHermitianTranspose_Generic;
    202:   st->ops->backtransform   = STBackTransform_Sinvert;
    203:   st->ops->setshift        = STSetShift_Sinvert;
    204:   st->ops->getbilinearform = STGetBilinearForm_Default;
    205:   st->ops->setup           = STSetUp_Sinvert;
    206:   st->ops->computeoperator = STComputeOperator_Sinvert;
    207:   st->ops->postsolve       = STPostSolve_Sinvert;
    208:   st->ops->checknullspace  = STCheckNullSpace_Default;
    209:   st->ops->setdefaultksp   = STSetDefaultKSP_Default;
    210:   PetscFunctionReturn(PETSC_SUCCESS);
    211: }