Date: 2026-05-01T10:02:20+00:00

Actual source code: stfunc.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:    The ST interface routines, callable by users
     12: */

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

     16: PetscClassId     ST_CLASSID = 0;
     17: PetscLogEvent    ST_SetUp = 0,ST_ComputeOperator = 0,ST_Apply = 0,ST_ApplyTranspose = 0,ST_ApplyHermitianTranspose = 0,ST_MatSetUp = 0,ST_MatMult = 0,ST_MatMultTranspose = 0,ST_MatSolve = 0,ST_MatSolveTranspose = 0;
     18: static PetscBool STPackageInitialized = PETSC_FALSE;

     20: const char *STMatModes[] = {"COPY","INPLACE","SHELL","STMatMode","ST_MATMODE_",NULL};

     22: /*@C
     23:    STFinalizePackage - This function destroys everything in the SLEPc interface
     24:    to the `ST` package. It is called from `SlepcFinalize()`.

     26:    Level: developer

     28: .seealso: [](ch:st), `SlepcFinalize()`, `STInitializePackage()`
     29: @*/
     30: PetscErrorCode STFinalizePackage(void)
     31: {
     32:   PetscFunctionBegin;
     33:   PetscCall(PetscFunctionListDestroy(&STList));
     34:   STPackageInitialized = PETSC_FALSE;
     35:   STRegisterAllCalled  = PETSC_FALSE;
     36:   PetscFunctionReturn(PETSC_SUCCESS);
     37: }

     39: /*@C
     40:    STInitializePackage - This function initializes everything in the `ST` package.
     41:    It is called from `PetscDLLibraryRegister_slepc()` when using dynamic libraries, and
     42:    on the first call to `STCreate()` when using shared or static libraries.

     44:    Note:
     45:    This function never needs to be called by SLEPc users.

     47:    Level: developer

     49: .seealso: [](ch:st), `ST`, `SlepcInitialize()`, `STFinalizePackage()`
     50: @*/
     51: PetscErrorCode STInitializePackage(void)
     52: {
     53:   char           logList[256];
     54:   PetscBool      opt,pkg;
     55:   PetscClassId   classids[1];

     57:   PetscFunctionBegin;
     58:   if (STPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS);
     59:   STPackageInitialized = PETSC_TRUE;
     60:   /* Register Classes */
     61:   PetscCall(PetscClassIdRegister("Spectral Transform",&ST_CLASSID));
     62:   /* Register Constructors */
     63:   PetscCall(STRegisterAll());
     64:   /* Register Events */
     65:   PetscCall(PetscLogEventRegister("STSetUp",ST_CLASSID,&ST_SetUp));
     66:   PetscCall(PetscLogEventRegister("STComputeOperatr",ST_CLASSID,&ST_ComputeOperator));
     67:   PetscCall(PetscLogEventRegister("STApply",ST_CLASSID,&ST_Apply));
     68:   PetscCall(PetscLogEventRegister("STApplyTranspose",ST_CLASSID,&ST_ApplyTranspose));
     69:   PetscCall(PetscLogEventRegister("STApplyHermTrans",ST_CLASSID,&ST_ApplyHermitianTranspose));
     70:   PetscCall(PetscLogEventRegister("STMatSetUp",ST_CLASSID,&ST_MatSetUp));
     71:   PetscCall(PetscLogEventRegister("STMatMult",ST_CLASSID,&ST_MatMult));
     72:   PetscCall(PetscLogEventRegister("STMatMultTranspose",ST_CLASSID,&ST_MatMultTranspose));
     73:   PetscCall(PetscLogEventRegister("STMatSolve",ST_CLASSID,&ST_MatSolve));
     74:   PetscCall(PetscLogEventRegister("STMatSolveTranspose",ST_CLASSID,&ST_MatSolveTranspose));
     75:   /* Process Info */
     76:   classids[0] = ST_CLASSID;
     77:   PetscCall(PetscInfoProcessClass("st",1,&classids[0]));
     78:   /* Process summary exclusions */
     79:   PetscCall(PetscOptionsGetString(NULL,NULL,"-log_exclude",logList,sizeof(logList),&opt));
     80:   if (opt) {
     81:     PetscCall(PetscStrInList("st",logList,',',&pkg));
     82:     if (pkg) PetscCall(PetscLogEventDeactivateClass(ST_CLASSID));
     83:   }
     84:   /* Register package finalizer */
     85:   PetscCall(PetscRegisterFinalize(STFinalizePackage));
     86:   PetscFunctionReturn(PETSC_SUCCESS);
     87: }

     89: /*@
     90:    STReset - Resets the `ST` context to the initial state (prior to setup)
     91:    and destroys any allocated `Vec`s and `Mat`s.

     93:    Collective

     95:    Input Parameter:
     96: .  st - the spectral transformation context

     98:    Level: advanced

    100: .seealso: [](ch:st), `STDestroy()`
    101: @*/
    102: PetscErrorCode STReset(ST st)
    103: {
    104:   PetscFunctionBegin;
    106:   if (!st) PetscFunctionReturn(PETSC_SUCCESS);
    107:   STCheckNotSeized(st,1);
    108:   PetscTryTypeMethod(st,reset);
    109:   if (st->ksp) PetscCall(KSPReset(st->ksp));
    110:   PetscCall(MatDestroyMatrices(PetscMax(2,st->nmat),&st->T));
    111:   PetscCall(MatDestroyMatrices(PetscMax(2,st->nmat),&st->A));
    112:   st->nmat = 0;
    113:   PetscCall(PetscFree(st->Astate));
    114:   PetscCall(MatDestroy(&st->Op));
    115:   PetscCall(MatDestroy(&st->P));
    116:   PetscCall(MatDestroy(&st->Pmat));
    117:   PetscCall(MatDestroyMatrices(st->nsplit,&st->Psplit));
    118:   st->nsplit = 0;
    119:   PetscCall(VecDestroyVecs(st->nwork,&st->work));
    120:   st->nwork = 0;
    121:   PetscCall(VecDestroy(&st->wb));
    122:   PetscCall(VecDestroy(&st->wht));
    123:   PetscCall(VecDestroy(&st->D));
    124:   st->state   = ST_STATE_INITIAL;
    125:   st->opready = PETSC_FALSE;
    126:   PetscFunctionReturn(PETSC_SUCCESS);
    127: }

    129: /*@
    130:    STDestroy - Destroys ST context that was created with `STCreate()`.

    132:    Collective

    134:    Input Parameter:
    135: .  st - the spectral transformation context

    137:    Level: beginner

    139: .seealso: [](ch:st), `STCreate()`, `STSetUp()`
    140: @*/
    141: PetscErrorCode STDestroy(ST *st)
    142: {
    143:   PetscFunctionBegin;
    144:   if (!*st) PetscFunctionReturn(PETSC_SUCCESS);
    146:   if (--((PetscObject)*st)->refct > 0) { *st = NULL; PetscFunctionReturn(PETSC_SUCCESS); }
    147:   PetscCall(STReset(*st));
    148:   PetscTryTypeMethod(*st,destroy);
    149:   PetscCall(KSPDestroy(&(*st)->ksp));
    150:   PetscCall(PetscHeaderDestroy(st));
    151:   PetscFunctionReturn(PETSC_SUCCESS);
    152: }

    154: /*@
    155:    STCreate - Creates a spectral transformation context.

    157:    Collective

    159:    Input Parameter:
    160: .  comm - MPI communicator

    162:    Output Parameter:
    163: .  newst - location to put the spectral transformation context

    165:    Level: beginner

    167: .seealso: [](ch:st), `STSetUp()`, `STApply()`, `STDestroy()`, `ST`
    168: @*/
    169: PetscErrorCode STCreate(MPI_Comm comm,ST *newst)
    170: {
    171:   ST             st;

    173:   PetscFunctionBegin;
    174:   PetscAssertPointer(newst,2);
    175:   PetscCall(STInitializePackage());
    176:   PetscCall(SlepcHeaderCreate(st,ST_CLASSID,"ST","Spectral Transformation","ST",comm,STDestroy,STView));

    178:   st->A            = NULL;
    179:   st->nmat         = 0;
    180:   st->sigma        = 0.0;
    181:   st->defsigma     = 0.0;
    182:   st->matmode      = ST_MATMODE_COPY;
    183:   st->str          = UNKNOWN_NONZERO_PATTERN;
    184:   st->transform    = PETSC_FALSE;
    185:   st->structured   = PETSC_FALSE;
    186:   st->D            = NULL;
    187:   st->Pmat         = NULL;
    188:   st->Pmat_set     = PETSC_FALSE;
    189:   st->Psplit       = NULL;
    190:   st->nsplit       = 0;
    191:   st->strp         = UNKNOWN_NONZERO_PATTERN;

    193:   st->ksp          = NULL;
    194:   st->usesksp      = PETSC_FALSE;
    195:   st->nwork        = 0;
    196:   st->work         = NULL;
    197:   st->wb           = NULL;
    198:   st->wht          = NULL;
    199:   st->state        = ST_STATE_INITIAL;
    200:   st->Astate       = NULL;
    201:   st->T            = NULL;
    202:   st->Op           = NULL;
    203:   st->opseized     = PETSC_FALSE;
    204:   st->opready      = PETSC_FALSE;
    205:   st->P            = NULL;
    206:   st->M            = NULL;
    207:   st->sigma_set    = PETSC_FALSE;
    208:   st->asymm        = PETSC_FALSE;
    209:   st->aherm        = PETSC_FALSE;
    210:   st->data         = NULL;

    212:   *newst = st;
    213:   PetscFunctionReturn(PETSC_SUCCESS);
    214: }

    216: /*
    217:    Checks whether the ST matrices are all symmetric or hermitian.
    218: */
    219: static inline PetscErrorCode STMatIsSymmetricKnown(ST st,PetscBool *symm,PetscBool *herm)
    220: {
    221:   PetscInt       i;
    222:   PetscBool      sbaij=PETSC_FALSE,set,flg=PETSC_FALSE;

    224:   PetscFunctionBegin;
    225:   /* check if problem matrices are all sbaij */
    226:   for (i=0;i<st->nmat;i++) {
    227:     PetscCall(PetscObjectTypeCompareAny((PetscObject)st->A[i],&sbaij,MATSEQSBAIJ,MATMPISBAIJ,""));
    228:     if (!sbaij) break;
    229:   }
    230:   /* check if user has set the symmetric flag */
    231:   *symm = PETSC_TRUE;
    232:   for (i=0;i<st->nmat;i++) {
    233:     PetscCall(MatIsSymmetricKnown(st->A[i],&set,&flg));
    234:     if (!set || !flg) { *symm = PETSC_FALSE; break; }
    235:   }
    236:   if (sbaij) *symm = PETSC_TRUE;
    237: #if defined(PETSC_USE_COMPLEX)
    238:   /* check if user has set the hermitian flag */
    239:   *herm = PETSC_TRUE;
    240:   for (i=0;i<st->nmat;i++) {
    241:     PetscCall(MatIsHermitianKnown(st->A[i],&set,&flg));
    242:     if (!set || !flg) { *herm = PETSC_FALSE; break; }
    243:   }
    244: #else
    245:   *herm = *symm;
    246: #endif
    247:   PetscFunctionReturn(PETSC_SUCCESS);
    248: }

    250: /*@
    251:    STSetMatrices - Sets the matrices associated with the eigenvalue problem.

    253:    Collective

    255:    Input Parameters:
    256: +  st - the spectral transformation context
    257: .  n  - number of matrices in array `A`
    258: -  A  - the array of matrices associated with the eigensystem

    260:    Notes:
    261:    It must be called before `STSetUp()`. If it is called again after `STSetUp()` then
    262:    the `ST` object is reset.

    264:    In standard eigenproblems only one matrix is passed, while in generalized
    265:    problems two matrices are provided. The number of matrices is larger in
    266:    polynomial eigenproblems.

    268:    In normal usage, matrices are provided via the corresponding `EPS` of `PEP`
    269:    interface function.

    271:    Level: intermediate

    273: .seealso: [](ch:st), `STGetMatrix()`, `STGetNumMatrices()`, `STSetUp()`, `STReset()`
    274: @*/
    275: PetscErrorCode STSetMatrices(ST st,PetscInt n,Mat A[])
    276: {
    277:   PetscInt       i;
    278:   PetscBool      same=PETSC_TRUE;

    280:   PetscFunctionBegin;
    283:   PetscCheck(n>0,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_OUTOFRANGE,"Must have one or more matrices, you have %" PetscInt_FMT,n);
    284:   PetscAssertPointer(A,3);
    285:   PetscCheckSameComm(st,1,*A,3);
    286:   STCheckNotSeized(st,1);
    287:   PetscCheck(!st->nsplit || st->nsplit==n,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"The number of matrices must be the same as in STSetSplitPreconditioner()");

    289:   if (st->state) {
    290:     if (n!=st->nmat) same = PETSC_FALSE;
    291:     for (i=0;same&&i<n;i++) {
    292:       if (A[i]!=st->A[i]) same = PETSC_FALSE;
    293:     }
    294:     if (!same) PetscCall(STReset(st));
    295:   } else same = PETSC_FALSE;
    296:   if (!same) {
    297:     PetscCall(MatDestroyMatrices(PetscMax(2,st->nmat),&st->A));
    298:     PetscCall(PetscCalloc1(PetscMax(2,n),&st->A));
    299:     PetscCall(PetscFree(st->Astate));
    300:     PetscCall(PetscMalloc1(PetscMax(2,n),&st->Astate));
    301:   }
    302:   for (i=0;i<n;i++) {
    304:     PetscCall(PetscObjectReference((PetscObject)A[i]));
    305:     PetscCall(MatDestroy(&st->A[i]));
    306:     st->A[i] = A[i];
    307:     st->Astate[i] = ((PetscObject)A[i])->state;
    308:   }
    309:   if (n==1) {
    310:     st->A[1] = NULL;
    311:     st->Astate[1] = 0;
    312:   }
    313:   st->nmat = n;
    314:   if (same) st->state = ST_STATE_UPDATED;
    315:   else st->state = ST_STATE_INITIAL;
    316:   PetscCheck(!same || !st->Psplit,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"Support for changing the matrices while using a split preconditioner is not implemented yet");
    317:   st->opready = PETSC_FALSE;
    318:   if (!same) PetscCall(STMatIsSymmetricKnown(st,&st->asymm,&st->aherm));
    319:   PetscFunctionReturn(PETSC_SUCCESS);
    320: }

    322: /*@
    323:    STGetMatrix - Gets the matrices associated with the original eigensystem.

    325:    Collective

    327:    Input Parameters:
    328: +  st - the spectral transformation context
    329: -  k  - the index of the requested matrix (starting in 0)

    331:    Output Parameter:
    332: .  A - the requested matrix

    334:    Level: intermediate

    336: .seealso: [](ch:st), `STSetMatrices()`, `STGetNumMatrices()`
    337: @*/
    338: PetscErrorCode STGetMatrix(ST st,PetscInt k,Mat *A)
    339: {
    340:   PetscFunctionBegin;
    343:   PetscAssertPointer(A,3);
    344:   STCheckMatrices(st,1);
    345:   PetscCheck(k>=0 && k<st->nmat,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_OUTOFRANGE,"k must be between 0 and %" PetscInt_FMT,st->nmat-1);
    346:   PetscCheck(((PetscObject)st->A[k])->state==st->Astate[k],PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"Cannot retrieve original matrices (have been modified)");
    347:   *A = st->A[k];
    348:   PetscFunctionReturn(PETSC_SUCCESS);
    349: }

    351: /*@
    352:    STGetMatrixTransformed - Gets the matrices associated with the transformed eigensystem.

    354:    Not Collective

    356:    Input Parameters:
    357: +  st - the spectral transformation context
    358: -  k  - the index of the requested matrix (starting in 0)

    360:    Output Parameter:
    361: .  T - the requested matrix

    363:    Level: developer

    365: .seealso: [](ch:st), `STGetMatrix()`, `STGetNumMatrices()`
    366: @*/
    367: PetscErrorCode STGetMatrixTransformed(ST st,PetscInt k,Mat *T)
    368: {
    369:   PetscFunctionBegin;
    372:   PetscAssertPointer(T,3);
    373:   STCheckMatrices(st,1);
    374:   PetscCheck(k>=0 && k<st->nmat,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_OUTOFRANGE,"k must be between 0 and %" PetscInt_FMT,st->nmat-1);
    375:   PetscCheck(st->T,PetscObjectComm((PetscObject)st),PETSC_ERR_POINTER,"There are no transformed matrices");
    376:   *T = st->T[k];
    377:   PetscFunctionReturn(PETSC_SUCCESS);
    378: }

    380: /*@
    381:    STGetNumMatrices - Returns the number of matrices stored in the `ST`.

    383:    Not Collective

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

    388:    Output Parameter:
    389: .  n - the number of matrices passed in `STSetMatrices()`

    391:    Level: intermediate

    393: .seealso: [](ch:st), `STSetMatrices()`
    394: @*/
    395: PetscErrorCode STGetNumMatrices(ST st,PetscInt *n)
    396: {
    397:   PetscFunctionBegin;
    399:   PetscAssertPointer(n,2);
    400:   *n = st->nmat;
    401:   PetscFunctionReturn(PETSC_SUCCESS);
    402: }

    404: /*@
    405:    STResetMatrixState - Resets the stored state of the matrices in the `ST`.

    407:    Logically Collective

    409:    Input Parameter:
    410: .  st - the spectral transformation context

    412:    Note:
    413:    This is useful in solvers where the user matrices are modified during
    414:    the computation, as in nonlinear inverse iteration. The effect is that
    415:    `STGetMatrix()` will retrieve the modified matrices as if they were
    416:    the matrices originally provided by the user.

    418:    Level: developer

    420: .seealso: [](ch:st), `STGetMatrix()`, `EPSPowerSetNonlinear()`
    421: @*/
    422: PetscErrorCode STResetMatrixState(ST st)
    423: {
    424:   PetscInt i;

    426:   PetscFunctionBegin;
    428:   for (i=0;i<st->nmat;i++) st->Astate[i] = ((PetscObject)st->A[i])->state;
    429:   PetscFunctionReturn(PETSC_SUCCESS);
    430: }

    432: /*@
    433:    STSetPreconditionerMat - Sets the matrix to be used to build the preconditioner.

    435:    Collective

    437:    Input Parameters:
    438: +  st  - the spectral transformation context
    439: -  mat - the matrix that will be used in constructing the preconditioner

    441:    Notes:
    442:    This matrix will be passed to the internal `KSP` object (via the last argument
    443:    of `KSPSetOperators()`) as the matrix to be used when constructing the preconditioner.
    444:    If no matrix is set or `mat` is set to `NULL`, then $A-\sigma B$ will be used
    445:    to build the preconditioner, being $\sigma$ the value set by `STSetShift()`.

    447:    More precisely, this is relevant for spectral transformations that represent
    448:    a rational matrix function, and use a `KSP` object for the denominator, called
    449:    $K$ in the description of `STGetOperator()`. It includes also the `STPRECOND` case.
    450:    If the user has a good approximation to matrix $K$ that can be used to build a
    451:    cheap preconditioner, it can be passed with this function. Note that it affects
    452:    only the `Pmat` argument of `KSPSetOperators()`, not the `Amat` argument.

    454:    If a preconditioner matrix is set, the default is to use an iterative `KSP`
    455:    rather than a direct method.

    457:    An alternative to pass an approximation of $A-\sigma B$ with this function is
    458:    to provide approximations of $A$ and $B$ via `STSetSplitPreconditioner()`. The
    459:    difference is that when $\sigma$ changes the preconditioner is recomputed.

    461:    Use `NULL` to remove a previously set matrix.

    463:    Level: advanced

    465: .seealso: [](ch:st), `STGetPreconditionerMat()`, `STSetShift()`, `STGetOperator()`, `STSetSplitPreconditioner()`
    466: @*/
    467: PetscErrorCode STSetPreconditionerMat(ST st,Mat mat)
    468: {
    469:   PetscFunctionBegin;
    471:   if (mat) {
    473:     PetscCheckSameComm(st,1,mat,2);
    474:   }
    475:   STCheckNotSeized(st,1);
    476:   PetscCheck(!mat || !st->Psplit,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"Cannot call both STSetPreconditionerMat and STSetSplitPreconditioner");
    477:   PetscCall(PetscObjectReference((PetscObject)mat));
    478:   PetscCall(MatDestroy(&st->Pmat));
    479:   st->Pmat     = mat;
    480:   st->Pmat_set = mat? PETSC_TRUE: PETSC_FALSE;
    481:   st->state    = ST_STATE_INITIAL;
    482:   st->opready  = PETSC_FALSE;
    483:   PetscFunctionReturn(PETSC_SUCCESS);
    484: }

    486: /*@
    487:    STGetPreconditionerMat - Returns the matrix previously set by `STSetPreconditionerMat()`.

    489:    Not Collective

    491:    Input Parameter:
    492: .  st - the spectral transformation context

    494:    Output Parameter:
    495: .  mat - the matrix that will be used in constructing the preconditioner or
    496:    `NULL` if no matrix was set by `STSetPreconditionerMat()`.

    498:    Level: advanced

    500: .seealso: [](ch:st), `STSetPreconditionerMat()`
    501: @*/
    502: PetscErrorCode STGetPreconditionerMat(ST st,Mat *mat)
    503: {
    504:   PetscFunctionBegin;
    506:   PetscAssertPointer(mat,2);
    507:   *mat = st->Pmat_set? st->Pmat: NULL;
    508:   PetscFunctionReturn(PETSC_SUCCESS);
    509: }

    511: /*@
    512:    STSetSplitPreconditioner - Sets the matrices from which to build the preconditioner
    513:    in split form.

    515:    Collective

    517:    Input Parameters:
    518: +  st     - the spectral transformation context
    519: .  n      - number of matrices
    520: .  Psplit - array of matrices
    521: -  strp   - structure flag for `Psplit` matrices

    523:    Notes:
    524:    The number of matrices passed here must be the same as in `STSetMatrices()`.

    526:    For linear eigenproblems, the preconditioner matrix is computed as
    527:    $P(\sigma) = A_0-\sigma B_0$, where $A_0$ and $B_0$ are approximations of $A$ and $B$
    528:    (the eigenproblem matrices) provided via the `Psplit` array in this function.
    529:    Compared to `STSetPreconditionerMat()`, this function allows setting a preconditioner
    530:    in a way that is independent of the shift $\sigma$. Whenever the value of $\sigma$
    531:    changes the preconditioner is recomputed.

    533:    Similarly, for polynomial eigenproblems the matrix for the preconditioner
    534:    is expressed as $P(\sigma) = \sum_i P_i \phi_i(\sigma)$, for $i=1,\dots,n$, where
    535:    $P_i$ are given in `Psplit` and the $\phi_i$'s are the polynomial basis functions.

    537:    The structure flag provides information about the relative nonzero pattern of the
    538:    `Psplit` matrices, in the same way as in `STSetMatStructure()`.

    540:    Use `n=0` to reset a previously set split preconditioner.

    542:    Level: advanced

    544: .seealso: [](ch:st), `STGetSplitPreconditionerTerm()`, `STGetSplitPreconditionerInfo()`, `STSetPreconditionerMat()`, `STSetMatrices()`, `STSetMatStructure()`
    545: @*/
    546: PetscErrorCode STSetSplitPreconditioner(ST st,PetscInt n,Mat Psplit[],MatStructure strp)
    547: {
    548:   PetscInt       i,N=0,M,M0=0,mloc,nloc,mloc0=0;

    550:   PetscFunctionBegin;
    553:   PetscCheck(n>=0,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_OUTOFRANGE,"Negative value of n = %" PetscInt_FMT,n);
    554:   PetscCheck(!n || !st->Pmat_set,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"Cannot call both STSetPreconditionerMat and STSetSplitPreconditioner");
    555:   PetscCheck(!n || !st->nmat || st->nmat==n,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"The number of matrices must be the same as in STSetMatrices()");
    556:   if (n) PetscAssertPointer(Psplit,3);
    558:   STCheckNotSeized(st,1);

    560:   for (i=0;i<n;i++) {
    562:     PetscCheckSameComm(st,1,Psplit[i],3);
    563:     PetscCall(MatGetSize(Psplit[i],&M,&N));
    564:     PetscCall(MatGetLocalSize(Psplit[i],&mloc,&nloc));
    565:     PetscCheck(M==N,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_WRONG,"Psplit[%" PetscInt_FMT "] is a non-square matrix (%" PetscInt_FMT " rows, %" PetscInt_FMT " cols)",i,M,N);
    566:     PetscCheck(mloc==nloc,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_WRONG,"Psplit[%" PetscInt_FMT "] does not have equal row and column local sizes (%" PetscInt_FMT ", %" PetscInt_FMT ")",i,mloc,nloc);
    567:     if (!i) { M0 = M; mloc0 = mloc; }
    568:     PetscCheck(M==M0,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_INCOMP,"Dimensions of Psplit[%" PetscInt_FMT "] do not match with previous matrices (%" PetscInt_FMT ", %" PetscInt_FMT ")",i,M,M0);
    569:     PetscCheck(mloc==mloc0,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_INCOMP,"Local dimensions of Psplit[%" PetscInt_FMT "] do not match with previous matrices (%" PetscInt_FMT ", %" PetscInt_FMT ")",i,mloc,mloc0);
    570:     PetscCall(PetscObjectReference((PetscObject)Psplit[i]));
    571:   }

    573:   if (st->Psplit) PetscCall(MatDestroyMatrices(st->nsplit,&st->Psplit));

    575:   /* allocate space and copy matrices */
    576:   if (n) {
    577:     PetscCall(PetscMalloc1(n,&st->Psplit));
    578:     for (i=0;i<n;i++) st->Psplit[i] = Psplit[i];
    579:   }
    580:   st->nsplit = n;
    581:   st->strp   = strp;
    582:   st->state  = ST_STATE_INITIAL;
    583:   PetscFunctionReturn(PETSC_SUCCESS);
    584: }

    586: /*@
    587:    STGetSplitPreconditionerTerm - Gets the matrices associated with
    588:    the split preconditioner.

    590:    Not Collective

    592:    Input Parameters:
    593: +  st - the spectral transformation context
    594: -  k  - the index of the requested matrix (starting in 0)

    596:    Output Parameter:
    597: .  Psplit - the returned matrix

    599:    Level: advanced

    601: .seealso: [](ch:st), `STSetSplitPreconditioner()`, `STGetSplitPreconditionerInfo()`
    602: @*/
    603: PetscErrorCode STGetSplitPreconditionerTerm(ST st,PetscInt k,Mat *Psplit)
    604: {
    605:   PetscFunctionBegin;
    608:   PetscAssertPointer(Psplit,3);
    609:   PetscCheck(k>=0 && k<st->nsplit,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_OUTOFRANGE,"k must be between 0 and %" PetscInt_FMT,st->nsplit-1);
    610:   PetscCheck(st->Psplit,PetscObjectComm((PetscObject)st),PETSC_ERR_ORDER,"You have not called STSetSplitPreconditioner()");
    611:   *Psplit = st->Psplit[k];
    612:   PetscFunctionReturn(PETSC_SUCCESS);
    613: }

    615: /*@
    616:    STGetSplitPreconditionerInfo - Returns the number of matrices of the split
    617:    preconditioner, as well as the structure flag.

    619:    Not Collective

    621:    Input Parameter:
    622: .  st - the spectral transformation context

    624:    Output Parameters:
    625: +  n    - the number of matrices passed in `STSetSplitPreconditioner()`
    626: -  strp - the matrix structure flag passed in `STSetSplitPreconditioner()`

    628:    Level: advanced

    630: .seealso: [](ch:st), `STSetSplitPreconditioner()`, `STGetSplitPreconditionerTerm()`
    631: @*/
    632: PetscErrorCode STGetSplitPreconditionerInfo(ST st,PetscInt *n,MatStructure *strp)
    633: {
    634:   PetscFunctionBegin;
    636:   if (n)    *n    = st->nsplit;
    637:   if (strp) *strp = st->strp;
    638:   PetscFunctionReturn(PETSC_SUCCESS);
    639: }

    641: /*@
    642:    STSetShift - Sets the shift associated with the spectral transformation.

    644:    Collective

    646:    Input Parameters:
    647: +  st - the spectral transformation context
    648: -  shift - the value of the shift

    650:    Notes:
    651:    In some spectral transformations, changing the shift may have associated
    652:    a lot of work, for example recomputing a factorization.

    654:    This function is normally not directly called by users, since the shift is
    655:    indirectly set by `EPSSetTarget()`.

    657:    Level: intermediate

    659: .seealso: [](ch:st), `EPSSetTarget()`, `STGetShift()`, `STSetDefaultShift()`
    660: @*/
    661: PetscErrorCode STSetShift(ST st,PetscScalar shift)
    662: {
    663:   PetscFunctionBegin;
    667:   if (st->sigma != shift) {
    668:     STCheckNotSeized(st,1);
    669:     if (st->state==ST_STATE_SETUP) PetscTryTypeMethod(st,setshift,shift);
    670:     st->sigma = shift;
    671:   }
    672:   st->sigma_set = PETSC_TRUE;
    673:   PetscFunctionReturn(PETSC_SUCCESS);
    674: }

    676: /*@
    677:    STGetShift - Gets the shift associated with the spectral transformation.

    679:    Not Collective

    681:    Input Parameter:
    682: .  st - the spectral transformation context

    684:    Output Parameter:
    685: .  shift - the value of the shift

    687:    Level: intermediate

    689: .seealso: [](ch:st), `STSetShift()`
    690: @*/
    691: PetscErrorCode STGetShift(ST st,PetscScalar* shift)
    692: {
    693:   PetscFunctionBegin;
    695:   PetscAssertPointer(shift,2);
    696:   *shift = st->sigma;
    697:   PetscFunctionReturn(PETSC_SUCCESS);
    698: }

    700: /*@
    701:    STSetDefaultShift - Sets the value of the shift that should be employed if
    702:    the user did not specify one.

    704:    Logically Collective

    706:    Input Parameters:
    707: +  st - the spectral transformation context
    708: -  defaultshift - the default value of the shift

    710:    Level: developer

    712: .seealso: [](ch:st), `STSetShift()`
    713: @*/
    714: PetscErrorCode STSetDefaultShift(ST st,PetscScalar defaultshift)
    715: {
    716:   PetscFunctionBegin;
    719:   if (st->defsigma != defaultshift) {
    720:     st->defsigma = defaultshift;
    721:     st->state    = ST_STATE_INITIAL;
    722:     st->opready  = PETSC_FALSE;
    723:   }
    724:   PetscFunctionReturn(PETSC_SUCCESS);
    725: }

    727: /*@
    728:    STScaleShift - Multiply the shift by a given factor.

    730:    Logically Collective

    732:    Input Parameters:
    733: +  st     - the spectral transformation context
    734: -  factor - the scaling factor

    736:    Note:
    737:    This function does not update the transformation matrices, as opposed to
    738:    `STSetShift()`.

    740:    Level: developer

    742: .seealso: [](ch:st), `STSetShift()`
    743: @*/
    744: PetscErrorCode STScaleShift(ST st,PetscScalar factor)
    745: {
    746:   PetscFunctionBegin;
    749:   st->sigma *= factor;
    750:   PetscFunctionReturn(PETSC_SUCCESS);
    751: }

    753: /*@
    754:    STSetBalanceMatrix - Sets the diagonal matrix to be used for balancing.

    756:    Collective

    758:    Input Parameters:
    759: +  st - the spectral transformation context
    760: -  D  - the diagonal matrix (represented as a vector)

    762:    Notes:
    763:    If this matrix is set, `STApply()` will effectively apply $D K^{-1} M D^{-1}$,
    764:    see discussion at `STGetOperator()`. Use `NULL` to reset a previously passed `D`.

    766:    Balancing is usually set via `EPSSetBalance()`, but the advanced user may use
    767:    this function to bypass the usual balancing methods.

    769:    Level: developer

    771: .seealso: [](ch:st), `EPSSetBalance()`, `STApply()`, `STGetBalanceMatrix()`, `STGetOperator()`
    772: @*/
    773: PetscErrorCode STSetBalanceMatrix(ST st,Vec D)
    774: {
    775:   PetscFunctionBegin;
    777:   if (st->D == D) PetscFunctionReturn(PETSC_SUCCESS);
    778:   STCheckNotSeized(st,1);
    779:   if (D) {
    781:     PetscCheckSameComm(st,1,D,2);
    782:     PetscCall(PetscObjectReference((PetscObject)D));
    783:   }
    784:   PetscCall(VecDestroy(&st->D));
    785:   st->D = D;
    786:   st->state   = ST_STATE_INITIAL;
    787:   st->opready = PETSC_FALSE;
    788:   PetscFunctionReturn(PETSC_SUCCESS);
    789: }

    791: /*@
    792:    STGetBalanceMatrix - Gets the balance matrix used by the spectral transformation.

    794:    Not Collective

    796:    Input Parameter:
    797: .  st - the spectral transformation context

    799:    Output Parameter:
    800: .  D  - the diagonal matrix (represented as a vector)

    802:    Note:
    803:    If the matrix was not set, a `NULL` pointer will be returned.

    805:    Level: developer

    807: .seealso: [](ch:st), `STSetBalanceMatrix()`
    808: @*/
    809: PetscErrorCode STGetBalanceMatrix(ST st,Vec *D)
    810: {
    811:   PetscFunctionBegin;
    813:   PetscAssertPointer(D,2);
    814:   *D = st->D;
    815:   PetscFunctionReturn(PETSC_SUCCESS);
    816: }

    818: /*@
    819:    STMatCreateVecs - Get vector(s) compatible with the `ST` matrices.

    821:    Collective

    823:    Input Parameter:
    824: .  st - the spectral transformation context

    826:    Output Parameters:
    827: +  right - (optional) vector that the matrix can be multiplied against
    828: -  left  - (optional) vector that the matrix vector product can be stored in

    830:    Level: developer

    832: .seealso: [](ch:st), `STMatCreateVecsEmpty()`
    833: @*/
    834: PetscErrorCode STMatCreateVecs(ST st,Vec *right,Vec *left)
    835: {
    836:   PetscFunctionBegin;
    837:   STCheckMatrices(st,1);
    838:   PetscCall(MatCreateVecs(st->A[0],right,left));
    839:   PetscFunctionReturn(PETSC_SUCCESS);
    840: }

    842: /*@
    843:    STMatCreateVecsEmpty - Get vector(s) compatible with the `ST` matrices, i.e.,
    844:    with the same parallel layout, but without internal array.

    846:    Collective

    848:    Input Parameter:
    849: .  st - the spectral transformation context

    851:    Output Parameters:
    852: +  right - (optional) vector that the matrix can be multiplied against
    853: -  left  - (optional) vector that the matrix vector product can be stored in

    855:    Level: developer

    857: .seealso: [](ch:st), `STMatCreateVecs()`, `MatCreateVecsEmpty()`
    858: @*/
    859: PetscErrorCode STMatCreateVecsEmpty(ST st,Vec *right,Vec *left)
    860: {
    861:   PetscFunctionBegin;
    862:   STCheckMatrices(st,1);
    863:   PetscCall(MatCreateVecsEmpty(st->A[0],right,left));
    864:   PetscFunctionReturn(PETSC_SUCCESS);
    865: }

    867: /*@
    868:    STMatGetSize - Returns the number of rows and columns of the `ST` matrices.

    870:    Not Collective

    872:    Input Parameter:
    873: .  st - the spectral transformation context

    875:    Output Parameters:
    876: +  m - the number of global rows
    877: -  n - the number of global columns

    879:    Level: developer

    881: .seealso: [](ch:st), `STMatGetLocalSize()`
    882: @*/
    883: PetscErrorCode STMatGetSize(ST st,PetscInt *m,PetscInt *n)
    884: {
    885:   PetscFunctionBegin;
    886:   STCheckMatrices(st,1);
    887:   PetscCall(MatGetSize(st->A[0],m,n));
    888:   PetscFunctionReturn(PETSC_SUCCESS);
    889: }

    891: /*@
    892:    STMatGetLocalSize - Returns the number of local rows and columns of the `ST` matrices.

    894:    Not Collective

    896:    Input Parameter:
    897: .  st - the spectral transformation context

    899:    Output Parameters:
    900: +  m - the number of local rows
    901: -  n - the number of local columns

    903:    Level: developer

    905: .seealso: [](ch:st), `STMatGetSize()`
    906: @*/
    907: PetscErrorCode STMatGetLocalSize(ST st,PetscInt *m,PetscInt *n)
    908: {
    909:   PetscFunctionBegin;
    910:   STCheckMatrices(st,1);
    911:   PetscCall(MatGetLocalSize(st->A[0],m,n));
    912:   PetscFunctionReturn(PETSC_SUCCESS);
    913: }

    915: /*@
    916:    STSetOptionsPrefix - Sets the prefix used for searching for all
    917:    `ST` options in the database.

    919:    Logically Collective

    921:    Input Parameters:
    922: +  st     - the spectral transformation context
    923: -  prefix - the prefix string to prepend to all `ST` option requests

    925:    Notes:
    926:    A hyphen (-) must NOT be given at the beginning of the prefix name.
    927:    The first character of all runtime options is AUTOMATICALLY the
    928:    hyphen.

    930:    Level: advanced

    932: .seealso: [](ch:st), `STAppendOptionsPrefix()`, `STGetOptionsPrefix()`
    933: @*/
    934: PetscErrorCode STSetOptionsPrefix(ST st,const char prefix[])
    935: {
    936:   PetscFunctionBegin;
    938:   if (!st->ksp) PetscCall(STGetKSP(st,&st->ksp));
    939:   PetscCall(KSPSetOptionsPrefix(st->ksp,prefix));
    940:   PetscCall(KSPAppendOptionsPrefix(st->ksp,"st_"));
    941:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)st,prefix));
    942:   PetscFunctionReturn(PETSC_SUCCESS);
    943: }

    945: /*@
    946:    STAppendOptionsPrefix - Appends to the prefix used for searching for all
    947:    `ST` options in the database.

    949:    Logically Collective

    951:    Input Parameters:
    952: +  st     - the spectral transformation context
    953: -  prefix - the prefix string to prepend to all `ST` option requests

    955:    Notes:
    956:    A hyphen (-) must NOT be given at the beginning of the prefix name.
    957:    The first character of all runtime options is AUTOMATICALLY the
    958:    hyphen.

    960:    Level: advanced

    962: .seealso: [](ch:st), `STSetOptionsPrefix()`, `STGetOptionsPrefix()`
    963: @*/
    964: PetscErrorCode STAppendOptionsPrefix(ST st,const char prefix[])
    965: {
    966:   PetscFunctionBegin;
    968:   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)st,prefix));
    969:   if (!st->ksp) PetscCall(STGetKSP(st,&st->ksp));
    970:   PetscCall(KSPSetOptionsPrefix(st->ksp,((PetscObject)st)->prefix));
    971:   PetscCall(KSPAppendOptionsPrefix(st->ksp,"st_"));
    972:   PetscFunctionReturn(PETSC_SUCCESS);
    973: }

    975: /*@
    976:    STGetOptionsPrefix - Gets the prefix used for searching for all
    977:    `ST` options in the database.

    979:    Not Collective

    981:    Input Parameter:
    982: .  st - the spectral transformation context

    984:    Output Parameter:
    985: .  prefix - pointer to the prefix string used, is returned

    987:    Level: advanced

    989: .seealso: [](ch:st), `STSetOptionsPrefix()`, `STAppendOptionsPrefix()`
    990: @*/
    991: PetscErrorCode STGetOptionsPrefix(ST st,const char *prefix[])
    992: {
    993:   PetscFunctionBegin;
    995:   PetscAssertPointer(prefix,2);
    996:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)st,prefix));
    997:   PetscFunctionReturn(PETSC_SUCCESS);
    998: }

    1000: /*@
    1001:    STView - Prints the `ST` data structure.

    1003:    Collective

    1005:    Input Parameters:
    1006: +  st - the ST context
    1007: -  viewer - optional visualization context

    1009:    Note:
    1010:    The available visualization contexts include
    1011: +     `PETSC_VIEWER_STDOUT_SELF` - standard output (default)
    1012: -     `PETSC_VIEWER_STDOUT_WORLD` - synchronized standard output where only the
    1013:          first process opens the file; all other processes send their data to the
    1014:          first one to print

    1016:    The user can open an alternative visualization context with `PetscViewerASCIIOpen()`
    1017:    to output to a specified file.

    1019:    Use `STViewFromOptions()` to allow the user to select many different `PetscViewerType`
    1020:    and formats from the options database.

    1022:    Level: beginner

    1024: .seealso: [](ch:st), `STCreate()`, `STViewFromOptions()`
    1025: @*/
    1026: PetscErrorCode STView(ST st,PetscViewer viewer)
    1027: {
    1028:   STType         cstr;
    1029:   char           str[50];
    1030:   PetscBool      isascii,isstring;

    1032:   PetscFunctionBegin;
    1034:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)st),&viewer));
    1036:   PetscCheckSameComm(st,1,viewer,2);

    1038:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
    1039:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERSTRING,&isstring));
    1040:   if (isascii) {
    1041:     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)st,viewer));
    1042:     PetscCall(PetscViewerASCIIPushTab(viewer));
    1043:     PetscTryTypeMethod(st,view,viewer);
    1044:     PetscCall(PetscViewerASCIIPopTab(viewer));
    1045:     PetscCall(SlepcSNPrintfScalar(str,sizeof(str),st->sigma,PETSC_FALSE));
    1046:     PetscCall(PetscViewerASCIIPrintf(viewer,"  shift: %s\n",str));
    1047:     PetscCall(PetscViewerASCIIPrintf(viewer,"  number of matrices: %" PetscInt_FMT "\n",st->nmat));
    1048:     switch (st->matmode) {
    1049:     case ST_MATMODE_COPY:
    1050:       break;
    1051:     case ST_MATMODE_INPLACE:
    1052:       PetscCall(PetscViewerASCIIPrintf(viewer,"  shifting the matrix and unshifting at exit\n"));
    1053:       break;
    1054:     case ST_MATMODE_SHELL:
    1055:       PetscCall(PetscViewerASCIIPrintf(viewer,"  using a shell matrix\n"));
    1056:       break;
    1057:     }
    1058:     if (st->nmat>1 && st->matmode != ST_MATMODE_SHELL) PetscCall(PetscViewerASCIIPrintf(viewer,"  nonzero pattern of the matrices: %s\n",MatStructures[st->str]));
    1059:     if (st->Psplit) PetscCall(PetscViewerASCIIPrintf(viewer,"  using split preconditioner matrices with %s\n",MatStructures[st->strp]));
    1060:     if (st->transform && st->nmat>2) PetscCall(PetscViewerASCIIPrintf(viewer,"  computing transformed matrices\n"));
    1061:     if (st->structured) PetscCall(PetscViewerASCIIPrintf(viewer,"  exploiting structure in the application of the operator\n"));
    1062:   } else if (isstring) {
    1063:     PetscCall(STGetType(st,&cstr));
    1064:     PetscCall(PetscViewerStringSPrintf(viewer," %-7.7s",cstr));
    1065:     PetscTryTypeMethod(st,view,viewer);
    1066:   }
    1067:   if (st->usesksp) {
    1068:     if (!st->ksp) PetscCall(STGetKSP(st,&st->ksp));
    1069:     PetscCall(PetscViewerASCIIPushTab(viewer));
    1070:     PetscCall(KSPView(st->ksp,viewer));
    1071:     PetscCall(PetscViewerASCIIPopTab(viewer));
    1072:   }
    1073:   PetscFunctionReturn(PETSC_SUCCESS);
    1074: }

    1076: /*@
    1077:    STViewFromOptions - View (print) an `ST` object based on values in the options database

    1079:    Collective

    1081:    Input Parameters:
    1082: +  st   - the spectral transformation context
    1083: .  obj  - optional object that provides the options prefix used to query the options database
    1084: -  name - command line option

    1086:    Level: intermediate

    1088: .seealso: [](ch:st), `STView()`, `STCreate()`, `PetscObjectViewFromOptions()`
    1089: @*/
    1090: PetscErrorCode STViewFromOptions(ST st,PetscObject obj,const char name[])
    1091: {
    1092:   PetscFunctionBegin;
    1094:   PetscCall(PetscObjectViewFromOptions((PetscObject)st,obj,name));
    1095:   PetscFunctionReturn(PETSC_SUCCESS);
    1096: }

    1098: /*@C
    1099:    STRegister - Adds a method to the spectral transformation package.

    1101:    Not Collective

    1103:    Input Parameters:
    1104: +  name - name of a new user-defined transformation
    1105: -  function - routine to create method

    1107:    Notes:
    1108:    `STRegister()` may be called multiple times to add several user-defined
    1109:    spectral transformations.

    1111:    Example Usage:
    1112: .vb
    1113:     STRegister("my_transform",MyTransformCreate);
    1114: .ve

    1116:    Then, your spectral transform can be chosen with the procedural interface via
    1117: .vb
    1118:     STSetType(st,"my_transform")
    1119: .ve
    1120:    or at runtime via the option `-st_type my_transform`

    1122:    Level: advanced

    1124: .seealso: [](ch:st), `STSetType()`, `STRegisterAll()`
    1125: @*/
    1126: PetscErrorCode STRegister(const char *name,PetscErrorCode (*function)(ST))
    1127: {
    1128:   PetscFunctionBegin;
    1129:   PetscCall(STInitializePackage());
    1130:   PetscCall(PetscFunctionListAdd(&STList,name,function));
    1131:   PetscFunctionReturn(PETSC_SUCCESS);
    1132: }