Date: 2026-03-31T13:23:19+00:00

Actual source code: shell.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:    This provides a simple shell interface for programmers to create
     12:    their own spectral transformations without writing much interface code
     13: */

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

     17: typedef struct {
     18:   void                             *ctx;        /* user-provided context */
     19:   STShellDestroyFn                 *destroy;    /* context destroy */
     20:   STShellApplyFn                   *apply;
     21:   STShellApplyTransposeFn          *applytrans;
     22:   STShellApplyHermitianTransposeFn *applyhermtrans;
     23:   STShellBackTransformFn           *backtransform;
     24: } ST_SHELL;

     26: static PetscErrorCode STShellGetContext_Shell(ST st,PetscCtxRt ctx)
     27: {
     28:   ST_SHELL *shell = (ST_SHELL*)st->data;

     30:   PetscFunctionBegin;
     31:   *(void**)ctx = shell->ctx;
     32:   PetscFunctionReturn(PETSC_SUCCESS);
     33: }

     35: /*@C
     36:    STShellGetContext - Returns the user-provided context associated with an `STSHELL`.

     38:    Not Collective

     40:    Input Parameter:
     41: .  st - spectral transformation context

     43:    Output Parameter:
     44: .  ctx - the user provided context

     46:    Level: advanced

     48: .seealso: [](ch:st), `STSHELL`, `STShellSetContext()`
     49: @*/
     50: PetscErrorCode STShellGetContext(ST st,PetscCtxRt ctx)
     51: {
     52:   PetscFunctionBegin;
     54:   PetscAssertPointer(ctx,2);
     55:   PetscUseMethod(st,"STShellGetContext_C",(ST,PetscCtxRt),(st,ctx));
     56:   PetscFunctionReturn(PETSC_SUCCESS);
     57: }

     59: static PetscErrorCode STShellSetContext_Shell(ST st,PetscCtx ctx)
     60: {
     61:   ST_SHELL *shell = (ST_SHELL*)st->data;

     63:   PetscFunctionBegin;
     64:   if (shell->destroy) PetscCall((*shell->destroy)(st));
     65:   shell->ctx = ctx;
     66:   PetscFunctionReturn(PETSC_SUCCESS);
     67: }

     69: /*@
     70:    STShellSetContext - Sets the user-defined context for an `STSHELL`.

     72:    Logically Collective

     74:    Input Parameters:
     75: +  st  - the shell `ST`
     76: -  ctx - the context

     78:    Level: advanced

     80:    Fortran Notes:
     81:    To use this from Fortran you must write a Fortran interface definition
     82:    for this function that tells Fortran the Fortran derived data type that
     83:    you are passing in as the `ctx` argument.

     85: .seealso: [](ch:st), `STSHELL`, `STShellGetContext()`, `STShellSetDestroy()`
     86: @*/
     87: PetscErrorCode STShellSetContext(ST st,PetscCtx ctx)
     88: {
     89:   PetscFunctionBegin;
     91:   PetscTryMethod(st,"STShellSetContext_C",(ST,PetscCtx),(st,ctx));
     92:   PetscFunctionReturn(PETSC_SUCCESS);
     93: }

     95: static PetscErrorCode STShellSetDestroy_Shell(ST st,STShellDestroyFn *destroy)
     96: {
     97:   ST_SHELL *shell = (ST_SHELL*)st->data;

     99:   PetscFunctionBegin;
    100:   shell->destroy = destroy;
    101:   PetscFunctionReturn(PETSC_SUCCESS);
    102: }

    104: /*@C
    105:    STShellSetDestroy - Set a context destroy function for the `STSHELL` context.

    107:    Logically Collective

    109:    Input Parameters:
    110: +  st      - the shell `ST`
    111: -  destroy - context destroy function, see `STShellDestroyFn` for its calling sequence

    113:    Level: advanced

    115: .seealso: [](ch:st), `STSHELL`, `STShellSetContext()`
    116: @*/
    117: PetscErrorCode STShellSetDestroy(ST st,STShellDestroyFn *destroy)
    118: {
    119:   PetscFunctionBegin;
    121:   PetscTryMethod(st,"STShellSetDestroy_C",(ST,STShellDestroyFn*),(st,destroy));
    122:   PetscFunctionReturn(PETSC_SUCCESS);
    123: }

    125: static PetscErrorCode STApply_Shell(ST st,Vec x,Vec y)
    126: {
    127:   ST_SHELL         *shell = (ST_SHELL*)st->data;
    128:   PetscObjectState instate,outstate;

    130:   PetscFunctionBegin;
    131:   PetscCheck(shell->apply,PetscObjectComm((PetscObject)st),PETSC_ERR_USER,"No apply() routine provided to Shell ST");
    132:   PetscCall(VecGetState(y,&instate));
    133:   PetscCallBack("STSHELL user function apply()",(*shell->apply)(st,x,y));
    134:   PetscCall(VecGetState(y,&outstate));
    135:   if (instate == outstate) {
    136:     /* user forgot to increase the state of the output vector */
    137:     PetscCall(PetscObjectStateIncrease((PetscObject)y));
    138:   }
    139:   PetscFunctionReturn(PETSC_SUCCESS);
    140: }

    142: static PetscErrorCode STApplyTranspose_Shell(ST st,Vec x,Vec y)
    143: {
    144:   ST_SHELL         *shell = (ST_SHELL*)st->data;
    145:   PetscObjectState instate,outstate;

    147:   PetscFunctionBegin;
    148:   PetscCheck(shell->applytrans,PetscObjectComm((PetscObject)st),PETSC_ERR_USER,"No applytrans() routine provided to Shell ST");
    149:   PetscCall(VecGetState(y,&instate));
    150:   PetscCallBack("STSHELL user function applytrans()",(*shell->applytrans)(st,x,y));
    151:   PetscCall(VecGetState(y,&outstate));
    152:   if (instate == outstate) {
    153:     /* user forgot to increase the state of the output vector */
    154:     PetscCall(PetscObjectStateIncrease((PetscObject)y));
    155:   }
    156:   PetscFunctionReturn(PETSC_SUCCESS);
    157: }

    159: #if defined(PETSC_USE_COMPLEX)
    160: static PetscErrorCode STApplyHermitianTranspose_Shell(ST st,Vec x,Vec y)
    161: {
    162:   ST_SHELL         *shell = (ST_SHELL*)st->data;
    163:   PetscObjectState instate,outstate;
    164:   Vec              w;

    166:   PetscFunctionBegin;
    167:   if (shell->applyhermtrans) {
    168:     PetscCall(VecGetState(y,&instate));
    169:     PetscCallBack("STSHELL user function applyhermtrans()",(*shell->applyhermtrans)(st,x,y));
    170:     PetscCall(VecGetState(y,&outstate));
    171:     if (instate == outstate) {
    172:       /* user forgot to increase the state of the output vector */
    173:       PetscCall(PetscObjectStateIncrease((PetscObject)y));
    174:     }
    175:   } else {
    176:     PetscCall(VecDuplicate(x,&w));
    177:     PetscCall(VecCopy(x,w));
    178:     PetscCall(VecConjugate(w));
    179:     PetscCall(STApplyTranspose_Shell(st,w,y));
    180:     PetscCall(VecDestroy(&w));
    181:     PetscCall(VecConjugate(y));
    182:   }
    183:   PetscFunctionReturn(PETSC_SUCCESS);
    184: }
    185: #endif

    187: static PetscErrorCode STBackTransform_Shell(ST st,PetscInt n,PetscScalar *eigr,PetscScalar *eigi)
    188: {
    189:   ST_SHELL       *shell = (ST_SHELL*)st->data;

    191:   PetscFunctionBegin;
    192:   if (shell->backtransform) PetscCallBack("STSHELL user function backtransform()",(*shell->backtransform)(st,n,eigr,eigi));
    193:   PetscFunctionReturn(PETSC_SUCCESS);
    194: }

    196: /*
    197:    STIsInjective_Shell - Check if the user has provided the backtransform operation.
    198: */
    199: PetscErrorCode STIsInjective_Shell(ST st,PetscBool* is)
    200: {
    201:   ST_SHELL *shell = (ST_SHELL*)st->data;

    203:   PetscFunctionBegin;
    204:   *is = shell->backtransform? PETSC_TRUE: PETSC_FALSE;
    205:   PetscFunctionReturn(PETSC_SUCCESS);
    206: }

    208: static PetscErrorCode STDestroy_Shell(ST st)
    209: {
    210:   ST_SHELL *shell = (ST_SHELL*)st->data;

    212:   PetscFunctionBegin;
    213:   if (shell->destroy) PetscCall((*shell->destroy)(st));
    214:   PetscCall(PetscFree(st->data));
    215:   PetscCall(PetscObjectComposeFunction((PetscObject)st,"STShellGetContext_C",NULL));
    216:   PetscCall(PetscObjectComposeFunction((PetscObject)st,"STShellSetContext_C",NULL));
    217:   PetscCall(PetscObjectComposeFunction((PetscObject)st,"STShellSetDestroy_C",NULL));
    218:   PetscCall(PetscObjectComposeFunction((PetscObject)st,"STShellSetApply_C",NULL));
    219:   PetscCall(PetscObjectComposeFunction((PetscObject)st,"STShellSetApplyTranspose_C",NULL));
    220:   PetscCall(PetscObjectComposeFunction((PetscObject)st,"STShellSetApplyHermitianTranspose_C",NULL));
    221:   PetscCall(PetscObjectComposeFunction((PetscObject)st,"STShellSetBackTransform_C",NULL));
    222:   PetscFunctionReturn(PETSC_SUCCESS);
    223: }

    225: static PetscErrorCode STShellSetApply_Shell(ST st,STShellApplyFn *apply)
    226: {
    227:   ST_SHELL *shell = (ST_SHELL*)st->data;

    229:   PetscFunctionBegin;
    230:   shell->apply = apply;
    231:   PetscFunctionReturn(PETSC_SUCCESS);
    232: }

    234: /*@C
    235:    STShellSetApply - Sets routine to use as the application of the
    236:    operator to a vector in the user-defined spectral transformation.

    238:    Logically Collective

    240:    Input Parameters:
    241: +  st    - the spectral transformation context
    242: -  apply - the application-provided transformation routine

    244:    Level: advanced

    246: .seealso: [](ch:st), `STSHELL`, `STShellSetBackTransform()`, `STShellSetApplyTranspose()`, `STShellSetApplyHermitianTranspose()`
    247: @*/
    248: PetscErrorCode STShellSetApply(ST st,STShellApplyFn *apply)
    249: {
    250:   PetscFunctionBegin;
    252:   PetscTryMethod(st,"STShellSetApply_C",(ST,STShellApplyFn*),(st,apply));
    253:   PetscFunctionReturn(PETSC_SUCCESS);
    254: }

    256: static PetscErrorCode STShellSetApplyTranspose_Shell(ST st,STShellApplyTransposeFn *applytrans)
    257: {
    258:   ST_SHELL *shell = (ST_SHELL*)st->data;

    260:   PetscFunctionBegin;
    261:   shell->applytrans = applytrans;
    262:   PetscFunctionReturn(PETSC_SUCCESS);
    263: }

    265: /*@C
    266:    STShellSetApplyTranspose - Sets routine to use as the application of the
    267:    transposed operator to a vector in the user-defined spectral transformation.

    269:    Logically Collective

    271:    Input Parameters:
    272: +  st    - the spectral transformation context
    273: -  applytrans - the application-provided transformation routine

    275:    Level: advanced

    277: .seealso: [](ch:st), `STSHELL`, `STShellSetApply()`, `STShellSetBackTransform()`
    278: @*/
    279: PetscErrorCode STShellSetApplyTranspose(ST st,STShellApplyTransposeFn *applytrans)
    280: {
    281:   PetscFunctionBegin;
    283:   PetscTryMethod(st,"STShellSetApplyTranspose_C",(ST,STShellApplyTransposeFn*),(st,applytrans));
    284:   PetscFunctionReturn(PETSC_SUCCESS);
    285: }

    287: #if defined(PETSC_USE_COMPLEX)
    288: static PetscErrorCode STShellSetApplyHermitianTranspose_Shell(ST st,STShellApplyHermitianTransposeFn *applyhermtrans)
    289: {
    290:   ST_SHELL *shell = (ST_SHELL*)st->data;

    292:   PetscFunctionBegin;
    293:   shell->applyhermtrans = applyhermtrans;
    294:   PetscFunctionReturn(PETSC_SUCCESS);
    295: }
    296: #endif

    298: /*@C
    299:    STShellSetApplyHermitianTranspose - Sets routine to use as the application of the
    300:    conjugate-transposed operator to a vector in the user-defined spectral transformation.

    302:    Logically Collective

    304:    Input Parameters:
    305: +  st    - the spectral transformation context
    306: -  applyhermtrans - the application-provided transformation routine

    308:    Note:
    309:    If configured with real scalars, this function has the same effect as `STShellSetApplyTranspose()`,
    310:    so no need to call both.

    312:    Level: advanced

    314: .seealso: [](ch:st), `STSHELL`, `STShellSetApply()`, `STShellSetApplyTranspose()`, `STShellSetBackTransform()`
    315: @*/
    316: PetscErrorCode STShellSetApplyHermitianTranspose(ST st,STShellApplyHermitianTransposeFn *applyhermtrans)
    317: {
    318:   PetscFunctionBegin;
    320:   PetscTryMethod(st,"STShellSetApplyHermitianTranspose_C",(ST,STShellApplyHermitianTransposeFn*),(st,applyhermtrans));
    321:   PetscFunctionReturn(PETSC_SUCCESS);
    322: }

    324: static PetscErrorCode STShellSetBackTransform_Shell(ST st,STShellBackTransformFn *backtr)
    325: {
    326:   ST_SHELL *shell = (ST_SHELL*)st->data;

    328:   PetscFunctionBegin;
    329:   shell->backtransform = backtr;
    330:   PetscFunctionReturn(PETSC_SUCCESS);
    331: }

    333: /*@C
    334:    STShellSetBackTransform - Sets the routine to be called after the
    335:    eigensolution process has finished in order to transform back the
    336:    computed eigenvalues.

    338:    Logically Collective

    340:    Input Parameters:
    341: +  st     - the spectral transformation context
    342: -  backtr - the application-provided backtransform routine

    344:    Level: advanced

    346: .seealso: [](ch:st), `STSHELL`, `STShellSetApply()`, `STShellSetApplyTranspose()`
    347: @*/
    348: PetscErrorCode STShellSetBackTransform(ST st,STShellBackTransformFn *backtr)
    349: {
    350:   PetscFunctionBegin;
    352:   PetscTryMethod(st,"STShellSetBackTransform_C",(ST,STShellBackTransformFn*),(st,backtr));
    353:   PetscFunctionReturn(PETSC_SUCCESS);
    354: }

    356: /*MC
    357:    STSHELL - STSHELL = "shell" - User-defined spectral transformation via callback
    358:    functions for the application of the operator to a vector and (optionally) the
    359:    backtransform operation.

    361:    Level: beginner

    363:    Note:
    364:    In order to define a `shell` spectral transformation, the user has to provide
    365:    the `apply` operation via `STShellSetApply()` and related functions, and
    366:    optionally a `backtransform` operation via `STShellSetBackTransform()`, and
    367:    in some cases a user-defined context containing relevant data via
    368:    `STShellSetContext()`.

    370: .seealso: [](ch:st), `ST`, `STType`, `STSetType()`, `STShellSetApply()`, `STShellSetBackTransform()`, `STShellSetContext()`
    371: M*/

    373: SLEPC_EXTERN PetscErrorCode STCreate_Shell(ST st)
    374: {
    375:   ST_SHELL       *ctx;

    377:   PetscFunctionBegin;
    378:   PetscCall(PetscNew(&ctx));
    379:   st->data = (void*)ctx;

    381:   st->usesksp = PETSC_FALSE;

    383:   st->ops->apply           = STApply_Shell;
    384:   st->ops->applytrans      = STApplyTranspose_Shell;
    385: #if defined(PETSC_USE_COMPLEX)
    386:   st->ops->applyhermtrans  = STApplyHermitianTranspose_Shell;
    387: #else
    388:   st->ops->applyhermtrans  = STApplyTranspose_Shell;
    389: #endif
    390:   st->ops->backtransform   = STBackTransform_Shell;
    391:   st->ops->destroy         = STDestroy_Shell;

    393:   PetscCall(PetscObjectComposeFunction((PetscObject)st,"STShellGetContext_C",STShellGetContext_Shell));
    394:   PetscCall(PetscObjectComposeFunction((PetscObject)st,"STShellSetContext_C",STShellSetContext_Shell));
    395:   PetscCall(PetscObjectComposeFunction((PetscObject)st,"STShellSetDestroy_C",STShellSetDestroy_Shell));
    396:   PetscCall(PetscObjectComposeFunction((PetscObject)st,"STShellSetApply_C",STShellSetApply_Shell));
    397:   PetscCall(PetscObjectComposeFunction((PetscObject)st,"STShellSetApplyTranspose_C",STShellSetApplyTranspose_Shell));
    398: #if defined(PETSC_USE_COMPLEX)
    399:   PetscCall(PetscObjectComposeFunction((PetscObject)st,"STShellSetApplyHermitianTranspose_C",STShellSetApplyHermitianTranspose_Shell));
    400: #else
    401:   PetscCall(PetscObjectComposeFunction((PetscObject)st,"STShellSetApplyHermitianTranspose_C",STShellSetApplyTranspose_Shell));
    402: #endif
    403:   PetscCall(PetscObjectComposeFunction((PetscObject)st,"STShellSetBackTransform_C",STShellSetBackTransform_Shell));
    404:   PetscFunctionReturn(PETSC_SUCCESS);
    405: }