Date: 2026-01-20T11:35:28+00:00

Actual source code: stsles.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: */
     10: /*
     11:    ST interface routines related to the KSP object associated with it
     12: */

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

     16: /*
     17:    This is used to set a default type for the KSP and PC objects.
     18:    It is called at STSetFromOptions (before KSPSetFromOptions)
     19:    and also at STSetUp (in case STSetFromOptions was not called).
     20: */
     21: PetscErrorCode STSetDefaultKSP(ST st)
     22: {
     23:   PetscFunctionBegin;
     26:   if (!st->ksp) PetscCall(STGetKSP(st,&st->ksp));
     27:   PetscTryTypeMethod(st,setdefaultksp);
     28:   PetscFunctionReturn(PETSC_SUCCESS);
     29: }

     31: /*
     32:    This is done by all ST types except PRECOND.
     33:    The default is an LU direct solver, or GMRES+Jacobi if matmode=shell.
     34: */
     35: PetscErrorCode STSetDefaultKSP_Default(ST st)
     36: {
     37:   PC             pc;
     38:   PCType         pctype;
     39:   KSPType        ksptype;

     41:   PetscFunctionBegin;
     42:   PetscCall(KSPGetPC(st->ksp,&pc));
     43:   PetscCall(KSPGetType(st->ksp,&ksptype));
     44:   PetscCall(PCGetType(pc,&pctype));
     45:   if (!pctype && !ksptype) {
     46:     if (st->Pmat || st->Psplit) {
     47:       PetscCall(KSPSetType(st->ksp,KSPBCGS));
     48:       PetscCall(PCSetType(pc,PCBJACOBI));
     49:     } else if (st->matmode == ST_MATMODE_SHELL) {
     50:       PetscCall(KSPSetType(st->ksp,KSPGMRES));
     51:       PetscCall(PCSetType(pc,PCJACOBI));
     52:     } else {
     53:       PetscCall(KSPSetType(st->ksp,KSPPREONLY));
     54:       PetscCall(PCSetType(pc,st->asymm?PCCHOLESKY:PCLU));
     55:     }
     56:   }
     57:   PetscCall(KSPSetErrorIfNotConverged(st->ksp,PETSC_TRUE));
     58:   PetscFunctionReturn(PETSC_SUCCESS);
     59: }

     61: /*@
     62:    STMatMult - Computes the matrix-vector product $y = T_k x$, where $T_k$ is
     63:    the $k$-th (transformed) matrix of the spectral transformation.

     65:    Neighbor-wise Collective

     67:    Input Parameters:
     68: +  st - the spectral transformation context
     69: .  k  - index of matrix to use
     70: -  x  - the vector to be multiplied

     72:    Output Parameter:
     73: .  y - the result

     75:    Level: developer

     77: .seealso: [](ch:st), `STMatMultTranspose()`, `STMatMultHermitianTranspose()`, `STGetMatrixTransformed()`
     78: @*/
     79: PetscErrorCode STMatMult(ST st,PetscInt k,Vec x,Vec y)
     80: {
     81:   PetscFunctionBegin;
     86:   STCheckMatrices(st,1);
     87:   PetscCheck(k>=0 && k<PetscMax(2,st->nmat),PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_OUTOFRANGE,"k must be between 0 and %" PetscInt_FMT,st->nmat);
     88:   PetscCheck(x!=y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
     89:   PetscCall(VecSetErrorIfLocked(y,3));

     91:   if (st->state!=ST_STATE_SETUP) PetscCall(STSetUp(st));
     92:   PetscCall(VecLockReadPush(x));
     93:   PetscCall(PetscLogEventBegin(ST_MatMult,st,x,y,0));
     94:   if (!st->T[k]) PetscCall(VecCopy(x,y)); /* T[k]=NULL means identity matrix */
     95:   else PetscCall(MatMult(st->T[k],x,y));
     96:   PetscCall(PetscLogEventEnd(ST_MatMult,st,x,y,0));
     97:   PetscCall(VecLockReadPop(x));
     98:   PetscFunctionReturn(PETSC_SUCCESS);
     99: }

    101: /*@
    102:    STMatMultTranspose - Computes the matrix-vector product $y = T_k^T x$, where $T_k$
    103:    is the $k$-th (transformed) matrix of the spectral transformation.

    105:    Neighbor-wise Collective

    107:    Input Parameters:
    108: +  st - the spectral transformation context
    109: .  k  - index of matrix to use
    110: -  x  - the vector to be multiplied

    112:    Output Parameter:
    113: .  y - the result

    115:    Level: developer

    117: .seealso: [](ch:st), `STMatMult()`, `STMatMultHermitianTranspose()`, `STGetMatrixTransformed()`
    118: @*/
    119: PetscErrorCode STMatMultTranspose(ST st,PetscInt k,Vec x,Vec y)
    120: {
    121:   PetscFunctionBegin;
    126:   STCheckMatrices(st,1);
    127:   PetscCheck(k>=0 && k<PetscMax(2,st->nmat),PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_OUTOFRANGE,"k must be between 0 and %" PetscInt_FMT,st->nmat);
    128:   PetscCheck(x!=y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
    129:   PetscCall(VecSetErrorIfLocked(y,3));

    131:   if (st->state!=ST_STATE_SETUP) PetscCall(STSetUp(st));
    132:   PetscCall(VecLockReadPush(x));
    133:   PetscCall(PetscLogEventBegin(ST_MatMultTranspose,st,x,y,0));
    134:   if (!st->T[k]) PetscCall(VecCopy(x,y)); /* T[k]=NULL means identity matrix */
    135:   else PetscCall(MatMultTranspose(st->T[k],x,y));
    136:   PetscCall(PetscLogEventEnd(ST_MatMultTranspose,st,x,y,0));
    137:   PetscCall(VecLockReadPop(x));
    138:   PetscFunctionReturn(PETSC_SUCCESS);
    139: }

    141: /*@
    142:    STMatMultHermitianTranspose - Computes the matrix-vector product $y = T_k^* x$,
    143:    where $T_k$ is the $k$-th (transformed) matrix of the spectral transformation.

    145:    Neighbor-wise Collective

    147:    Input Parameters:
    148: +  st - the spectral transformation context
    149: .  k  - index of matrix to use
    150: -  x  - the vector to be multiplied

    152:    Output Parameter:
    153: .  y - the result

    155:    Level: developer

    157: .seealso: [](ch:st), `STMatMult()`, `STMatMultTranspose()`, `STGetMatrixTransformed()`
    158: @*/
    159: PetscErrorCode STMatMultHermitianTranspose(ST st,PetscInt k,Vec x,Vec y)
    160: {
    161:   PetscFunctionBegin;
    166:   STCheckMatrices(st,1);
    167:   PetscCheck(k>=0 && k<PetscMax(2,st->nmat),PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_OUTOFRANGE,"k must be between 0 and %" PetscInt_FMT,st->nmat);
    168:   PetscCheck(x!=y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
    169:   PetscCall(VecSetErrorIfLocked(y,3));

    171:   if (st->state!=ST_STATE_SETUP) PetscCall(STSetUp(st));
    172:   PetscCall(VecLockReadPush(x));
    173:   PetscCall(PetscLogEventBegin(ST_MatMultTranspose,st,x,y,0));
    174:   if (!st->T[k]) PetscCall(VecCopy(x,y)); /* T[k]=NULL means identity matrix */
    175:   else PetscCall(MatMultHermitianTranspose(st->T[k],x,y));
    176:   PetscCall(PetscLogEventEnd(ST_MatMultTranspose,st,x,y,0));
    177:   PetscCall(VecLockReadPop(x));
    178:   PetscFunctionReturn(PETSC_SUCCESS);
    179: }

    181: /*@
    182:    STMatSolve - Solves $P x = b$, where $P$ is the preconditioner matrix of
    183:    the spectral transformation, using a `KSP` object stored internally.

    185:    Collective

    187:    Input Parameters:
    188: +  st - the spectral transformation context
    189: -  b  - right hand side vector

    191:    Output Parameter:
    192: .  x - computed solution

    194:    Level: developer

    196: .seealso: [](ch:st), `STMatSolveTranspose()`, `STMatSolveHermitianTranspose()`, `STMatMatSolve()`
    197: @*/
    198: PetscErrorCode STMatSolve(ST st,Vec b,Vec x)
    199: {
    200:   PetscFunctionBegin;
    204:   STCheckMatrices(st,1);
    205:   PetscCheck(x!=b,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and b must be different vectors");
    206:   PetscCall(VecSetErrorIfLocked(x,3));

    208:   if (st->state!=ST_STATE_SETUP) PetscCall(STSetUp(st));
    209:   PetscCall(VecLockReadPush(b));
    210:   PetscCall(PetscLogEventBegin(ST_MatSolve,st,b,x,0));
    211:   if (!st->P) PetscCall(VecCopy(b,x)); /* P=NULL means identity matrix */
    212:   else PetscCall(KSPSolve(st->ksp,b,x));
    213:   PetscCall(PetscLogEventEnd(ST_MatSolve,st,b,x,0));
    214:   PetscCall(VecLockReadPop(b));
    215:   PetscFunctionReturn(PETSC_SUCCESS);
    216: }

    218: /*@
    219:    STMatMatSolve - Solves $P X = B$, where $P$ is the preconditioner matrix of
    220:    the spectral transformation, using a `KSP` object stored internally.

    222:    Collective

    224:    Input Parameters:
    225: +  st - the spectral transformation context
    226: -  B  - right hand side vectors

    228:    Output Parameter:
    229: .  X - computed solutions

    231:    Level: developer

    233: .seealso: [](ch:st), `STMatSolve()`
    234: @*/
    235: PetscErrorCode STMatMatSolve(ST st,Mat B,Mat X)
    236: {
    237:   PetscFunctionBegin;
    241:   STCheckMatrices(st,1);

    243:   if (st->state!=ST_STATE_SETUP) PetscCall(STSetUp(st));
    244:   PetscCall(PetscLogEventBegin(ST_MatSolve,st,B,X,0));
    245:   if (!st->P) PetscCall(MatCopy(B,X,SAME_NONZERO_PATTERN)); /* P=NULL means identity matrix */
    246:   else PetscCall(KSPMatSolve(st->ksp,B,X));
    247:   PetscCall(PetscLogEventEnd(ST_MatSolve,st,B,X,0));
    248:   PetscFunctionReturn(PETSC_SUCCESS);
    249: }

    251: /*@
    252:    STMatSolveTranspose - Solves $P^T x = b$, where $P$ is the preconditioner matrix of
    253:    the spectral transformation, using a `KSP` object stored internally.

    255:    Collective

    257:    Input Parameters:
    258: +  st - the spectral transformation context
    259: -  b  - right hand side vector

    261:    Output Parameter:
    262: .  x - computed solution

    264:    Level: developer

    266: .seealso: [](ch:st), `STMatSolve()`
    267: @*/
    268: PetscErrorCode STMatSolveTranspose(ST st,Vec b,Vec x)
    269: {
    270:   PetscFunctionBegin;
    274:   STCheckMatrices(st,1);
    275:   PetscCheck(x!=b,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and b must be different vectors");
    276:   PetscCall(VecSetErrorIfLocked(x,3));

    278:   if (st->state!=ST_STATE_SETUP) PetscCall(STSetUp(st));
    279:   PetscCall(VecLockReadPush(b));
    280:   PetscCall(PetscLogEventBegin(ST_MatSolveTranspose,st,b,x,0));
    281:   if (!st->P) PetscCall(VecCopy(b,x)); /* P=NULL means identity matrix */
    282:   else PetscCall(KSPSolveTranspose(st->ksp,b,x));
    283:   PetscCall(PetscLogEventEnd(ST_MatSolveTranspose,st,b,x,0));
    284:   PetscCall(VecLockReadPop(b));
    285:   PetscFunctionReturn(PETSC_SUCCESS);
    286: }

    288: /*@
    289:    STMatSolveHermitianTranspose - Solves $P^* x = b$, where $P$ is the preconditioner matrix of
    290:    the spectral transformation, using a `KSP` object stored internally.

    292:    Collective

    294:    Input Parameters:
    295: +  st - the spectral transformation context
    296: -  b  - right hand side vector

    298:    Output Parameter:
    299: .  x - computed solution

    301:    Level: developer

    303: .seealso: [](ch:st), `STMatSolve()`
    304: @*/
    305: PetscErrorCode STMatSolveHermitianTranspose(ST st,Vec b,Vec x)
    306: {
    307:   Vec  w;

    309:   PetscFunctionBegin;
    313:   STCheckMatrices(st,1);
    314:   PetscCheck(x!=b,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and b must be different vectors");
    315:   PetscCall(VecSetErrorIfLocked(x,3));

    317:   if (st->state!=ST_STATE_SETUP) PetscCall(STSetUp(st));
    318:   PetscCall(VecLockReadPush(b));
    319:   PetscCall(PetscLogEventBegin(ST_MatSolveTranspose,st,b,x,0));
    320:   if (!st->P) PetscCall(VecCopy(b,x)); /* P=NULL means identity matrix */
    321:   else {
    322:     PetscCall(VecDuplicate(b,&w));
    323:     PetscCall(VecCopy(b,w));
    324:     PetscCall(VecConjugate(w));
    325:     PetscCall(KSPSolveTranspose(st->ksp,w,x));
    326:     PetscCall(VecDestroy(&w));
    327:     PetscCall(VecConjugate(x));
    328:   }
    329:   PetscCall(PetscLogEventEnd(ST_MatSolveTranspose,st,b,x,0));
    330:   PetscCall(VecLockReadPop(b));
    331:   PetscFunctionReturn(PETSC_SUCCESS);
    332: }

    334: PetscErrorCode STCheckFactorPackage(ST st)
    335: {
    336:   PC             pc;
    337:   PetscMPIInt    size;
    338:   PetscBool      flg;
    339:   MatSolverType  stype;

    341:   PetscFunctionBegin;
    342:   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)st),&size));
    343:   if (size==1) PetscFunctionReturn(PETSC_SUCCESS);
    344:   PetscCall(KSPGetPC(st->ksp,&pc));
    345:   PetscCall(PCFactorGetMatSolverType(pc,&stype));
    346:   if (stype) {   /* currently selected PC is a factorization */
    347:     PetscCall(PetscStrcmp(stype,MATSOLVERPETSC,&flg));
    348:     PetscCheck(!flg,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"You chose to solve linear systems with a factorization, but in parallel runs you need to select an external package; see the users guide for details");
    349:   }
    350:   PetscFunctionReturn(PETSC_SUCCESS);
    351: }

    353: /*@
    354:    STSetKSP - Sets the `KSP` object associated with the spectral
    355:    transformation.

    357:    Collective

    359:    Input Parameters:
    360: +  st   - the spectral transformation context
    361: -  ksp  - the linear solver context

    363:    Level: advanced

    365: .seealso: [](ch:st), `STGetKSP()`
    366: @*/
    367: PetscErrorCode STSetKSP(ST st,KSP ksp)
    368: {
    369:   PetscFunctionBegin;
    372:   PetscCheckSameComm(st,1,ksp,2);
    373:   STCheckNotSeized(st,1);
    374:   PetscCall(PetscObjectReference((PetscObject)ksp));
    375:   PetscCall(KSPDestroy(&st->ksp));
    376:   st->ksp = ksp;
    377:   PetscFunctionReturn(PETSC_SUCCESS);
    378: }

    380: /*@
    381:    STGetKSP - Gets the KSP object associated with the spectral
    382:    transformation.

    384:    Collective

    386:    Input Parameter:
    387: .  st - the spectral transformation context

    389:    Output Parameter:
    390: .  ksp  - the linear system context

    392:    Level: intermediate

    394: .seealso: [](ch:st), `STSetKSP()`
    395: @*/
    396: PetscErrorCode STGetKSP(ST st,KSP* ksp)
    397: {
    398:   PetscFunctionBegin;
    400:   PetscAssertPointer(ksp,2);
    401:   if (!st->ksp) {
    402:     PetscCall(KSPCreate(PetscObjectComm((PetscObject)st),&st->ksp));
    403:     PetscCall(PetscObjectIncrementTabLevel((PetscObject)st->ksp,(PetscObject)st,1));
    404:     PetscCall(KSPSetOptionsPrefix(st->ksp,((PetscObject)st)->prefix));
    405:     PetscCall(KSPAppendOptionsPrefix(st->ksp,"st_"));
    406:     PetscCall(PetscObjectSetOptions((PetscObject)st->ksp,((PetscObject)st)->options));
    407:     PetscCall(KSPSetTolerances(st->ksp,SLEPC_DEFAULT_TOL,PETSC_CURRENT,PETSC_CURRENT,PETSC_CURRENT));
    408:   }
    409:   *ksp = st->ksp;
    410:   PetscFunctionReturn(PETSC_SUCCESS);
    411: }

    413: PetscErrorCode STCheckNullSpace_Default(ST st,BV V)
    414: {
    415:   PetscInt       nc,i,c;
    416:   PetscReal      norm;
    417:   Vec            *T,w,vi;
    418:   Mat            A;
    419:   PC             pc;
    420:   MatNullSpace   nullsp;

    422:   PetscFunctionBegin;
    423:   PetscCall(BVGetNumConstraints(V,&nc));
    424:   PetscCall(PetscMalloc1(nc,&T));
    425:   if (!st->ksp) PetscCall(STGetKSP(st,&st->ksp));
    426:   PetscCall(KSPGetPC(st->ksp,&pc));
    427:   PetscCall(PCGetOperators(pc,&A,NULL));
    428:   PetscCall(MatCreateVecs(A,NULL,&w));
    429:   c = 0;
    430:   for (i=0;i<nc;i++) {
    431:     PetscCall(BVGetColumn(V,-nc+i,&vi));
    432:     PetscCall(MatMult(A,vi,w));
    433:     PetscCall(VecNorm(w,NORM_2,&norm));
    434:     if (norm < 10.0*PETSC_SQRT_MACHINE_EPSILON) {
    435:       PetscCall(PetscInfo(st,"Vector %" PetscInt_FMT " included in the nullspace of OP, norm=%g\n",i,(double)norm));
    436:       PetscCall(BVCreateVec(V,T+c));
    437:       PetscCall(VecCopy(vi,T[c]));
    438:       PetscCall(VecNormalize(T[c],NULL));
    439:       c++;
    440:     } else PetscCall(PetscInfo(st,"Vector %" PetscInt_FMT " discarded as possible nullspace of OP, norm=%g\n",i,(double)norm));
    441:     PetscCall(BVRestoreColumn(V,-nc+i,&vi));
    442:   }
    443:   PetscCall(VecDestroy(&w));
    444:   if (c>0) {
    445:     PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)st),PETSC_FALSE,c,T,&nullsp));
    446:     PetscCall(MatSetNullSpace(A,nullsp));
    447:     PetscCall(MatNullSpaceDestroy(&nullsp));
    448:     PetscCall(VecDestroyVecs(c,&T));
    449:   } else PetscCall(PetscFree(T));
    450:   PetscFunctionReturn(PETSC_SUCCESS);
    451: }

    453: /*@
    454:    STCheckNullSpace - Tests if constraint vectors are nullspace vectors.

    456:    Collective

    458:    Input Parameters:
    459: +  st - the spectral transformation context
    460: -  V  - basis vectors to be checked

    462:    Notes:
    463:    Given a basis vectors object, this function tests each of its constraint
    464:    vectors to be a nullspace vector of the coefficient matrix of the
    465:    associated `KSP` object. All these nullspace vectors are passed to the `KSP`
    466:    object with `MatSetNullSpace()`.

    468:    This function allows handling singular pencils (i.e., when $A$ and $B$ share
    469:    a common nullspace), and solving some problems in which the nullspace is important.

    471:    Level: developer

    473: .seealso: [](ch:st), `EPSSetDeflationSpace()`, `MatSetNullSpace()`
    474: @*/
    475: PetscErrorCode STCheckNullSpace(ST st,BV V)
    476: {
    477:   PetscInt       nc;

    479:   PetscFunctionBegin;
    483:   PetscCheckSameComm(st,1,V,2);
    484:   PetscCheck(st->state,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_WRONGSTATE,"Must call STSetUp() first");

    486:   PetscCall(BVGetNumConstraints(V,&nc));
    487:   if (nc) PetscTryTypeMethod(st,checknullspace,V);
    488:   PetscFunctionReturn(PETSC_SUCCESS);
    489: }