LCOV - code coverage report
Current view: top level - sys/classes/st/interface - stsolve.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 333 341 97.7 %
Date: 2024-11-23 00:34:26 Functions: 24 25 96.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       3             :    SLEPc - Scalable Library for Eigenvalue Problem Computations
       4             :    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
       5             : 
       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, callable by users
      12             : */
      13             : 
      14             : #include <slepc/private/stimpl.h>            /*I "slepcst.h" I*/
      15             : 
      16      144069 : PetscErrorCode STApply_Generic(ST st,Vec x,Vec y)
      17             : {
      18      144069 :   PetscFunctionBegin;
      19      144069 :   if (st->M && st->P) {
      20       57499 :     PetscCall(MatMult(st->M,x,st->work[0]));
      21       57499 :     PetscCall(STMatSolve(st,st->work[0],y));
      22       86570 :   } else if (st->M) PetscCall(MatMult(st->M,x,y));
      23       15704 :   else PetscCall(STMatSolve(st,x,y));
      24      144069 :   PetscFunctionReturn(PETSC_SUCCESS);
      25             : }
      26             : 
      27             : /*@
      28             :    STApply - Applies the spectral transformation operator to a vector, for
      29             :    instance (A - sB)^-1 B in the case of the shift-and-invert transformation
      30             :    and generalized eigenproblem.
      31             : 
      32             :    Collective
      33             : 
      34             :    Input Parameters:
      35             : +  st - the spectral transformation context
      36             : -  x  - input vector
      37             : 
      38             :    Output Parameter:
      39             : .  y - output vector
      40             : 
      41             :    Level: developer
      42             : 
      43             : .seealso: STApplyTranspose(), STApplyHermitianTranspose()
      44             : @*/
      45       84725 : PetscErrorCode STApply(ST st,Vec x,Vec y)
      46             : {
      47       84725 :   Mat            Op;
      48             : 
      49       84725 :   PetscFunctionBegin;
      50       84725 :   PetscValidHeaderSpecific(st,ST_CLASSID,1);
      51       84725 :   PetscValidHeaderSpecific(x,VEC_CLASSID,2);
      52       84725 :   PetscValidHeaderSpecific(y,VEC_CLASSID,3);
      53       84725 :   PetscValidType(st,1);
      54       84725 :   STCheckMatrices(st,1);
      55       84725 :   PetscCheck(x!=y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
      56       84725 :   PetscCall(VecSetErrorIfLocked(y,3));
      57       84725 :   PetscCall(STGetOperator_Private(st,&Op));
      58       84725 :   PetscCall(MatMult(Op,x,y));
      59       84725 :   PetscFunctionReturn(PETSC_SUCCESS);
      60             : }
      61             : 
      62        4986 : PetscErrorCode STApplyMat_Generic(ST st,Mat B,Mat C)
      63             : {
      64        4986 :   Mat            work;
      65             : 
      66        4986 :   PetscFunctionBegin;
      67        4986 :   if (st->M && st->P) {
      68        1936 :     PetscCall(MatMatMult(st->M,B,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&work));
      69        1936 :     PetscCall(STMatMatSolve(st,work,C));
      70        1936 :     PetscCall(MatDestroy(&work));
      71        3050 :   } else if (st->M) PetscCall(MatMatMult(st->M,B,MAT_REUSE_MATRIX,PETSC_DEFAULT,&C));
      72        1704 :   else PetscCall(STMatMatSolve(st,B,C));
      73        4986 :   PetscFunctionReturn(PETSC_SUCCESS);
      74             : }
      75             : 
      76             : /*@
      77             :    STApplyMat - Applies the spectral transformation operator to a matrix, for
      78             :    instance (A - sB)^-1 B in the case of the shift-and-invert transformation
      79             :    and generalized eigenproblem.
      80             : 
      81             :    Collective
      82             : 
      83             :    Input Parameters:
      84             : +  st - the spectral transformation context
      85             : -  X  - input matrix
      86             : 
      87             :    Output Parameter:
      88             : .  Y - output matrix
      89             : 
      90             :    Level: developer
      91             : 
      92             : .seealso: STApply()
      93             : @*/
      94        1658 : PetscErrorCode STApplyMat(ST st,Mat X,Mat Y)
      95             : {
      96        1658 :   PetscFunctionBegin;
      97        1658 :   PetscValidHeaderSpecific(st,ST_CLASSID,1);
      98        1658 :   PetscValidHeaderSpecific(X,MAT_CLASSID,2);
      99        1658 :   PetscValidHeaderSpecific(Y,MAT_CLASSID,3);
     100        1658 :   PetscValidType(st,1);
     101        1658 :   STCheckMatrices(st,1);
     102        1658 :   PetscCheck(X!=Y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"X and Y must be different matrices");
     103        1658 :   PetscUseTypeMethod(st,applymat,X,Y);
     104        1658 :   PetscFunctionReturn(PETSC_SUCCESS);
     105             : }
     106             : 
     107        1244 : PetscErrorCode STApplyTranspose_Generic(ST st,Vec x,Vec y)
     108             : {
     109        1244 :   PetscFunctionBegin;
     110        1244 :   if (st->M && st->P) {
     111          37 :     PetscCall(STMatSolveTranspose(st,x,st->work[0]));
     112          37 :     PetscCall(MatMultTranspose(st->M,st->work[0],y));
     113        1207 :   } else if (st->M) PetscCall(MatMultTranspose(st->M,x,y));
     114         510 :   else PetscCall(STMatSolveTranspose(st,x,y));
     115        1244 :   PetscFunctionReturn(PETSC_SUCCESS);
     116             : }
     117             : 
     118             : /*@
     119             :    STApplyTranspose - Applies the transpose of the operator to a vector, for
     120             :    instance B^T(A - sB)^-T in the case of the shift-and-invert transformation
     121             :    and generalized eigenproblem.
     122             : 
     123             :    Collective
     124             : 
     125             :    Input Parameters:
     126             : +  st - the spectral transformation context
     127             : -  x  - input vector
     128             : 
     129             :    Output Parameter:
     130             : .  y - output vector
     131             : 
     132             :    Level: developer
     133             : 
     134             : .seealso: STApply(), STApplyHermitianTranspose()
     135             : @*/
     136           6 : PetscErrorCode STApplyTranspose(ST st,Vec x,Vec y)
     137             : {
     138           6 :   Mat            Op;
     139             : 
     140           6 :   PetscFunctionBegin;
     141           6 :   PetscValidHeaderSpecific(st,ST_CLASSID,1);
     142           6 :   PetscValidHeaderSpecific(x,VEC_CLASSID,2);
     143           6 :   PetscValidHeaderSpecific(y,VEC_CLASSID,3);
     144           6 :   PetscValidType(st,1);
     145           6 :   STCheckMatrices(st,1);
     146           6 :   PetscCheck(x!=y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
     147           6 :   PetscCall(VecSetErrorIfLocked(y,3));
     148           6 :   PetscCall(STGetOperator_Private(st,&Op));
     149           6 :   PetscCall(MatMultTranspose(Op,x,y));
     150           6 :   PetscFunctionReturn(PETSC_SUCCESS);
     151             : }
     152             : 
     153           0 : PetscErrorCode STApplyHermitianTranspose_Generic(ST st,Vec x,Vec y)
     154             : {
     155           0 :   PetscFunctionBegin;
     156           0 :   if (st->M && st->P) {
     157           0 :     PetscCall(STMatSolveHermitianTranspose(st,x,st->work[0]));
     158           0 :     PetscCall(MatMultHermitianTranspose(st->M,st->work[0],y));
     159           0 :   } else if (st->M) PetscCall(MatMultHermitianTranspose(st->M,x,y));
     160           0 :   else PetscCall(STMatSolveHermitianTranspose(st,x,y));
     161           0 :   PetscFunctionReturn(PETSC_SUCCESS);
     162             : }
     163             : 
     164             : /*@
     165             :    STApplyHermitianTranspose - Applies the hermitian-transpose of the operator
     166             :    to a vector, for instance B^H(A - sB)^-H in the case of the shift-and-invert
     167             :    transformation and generalized eigenproblem.
     168             : 
     169             :    Collective
     170             : 
     171             :    Input Parameters:
     172             : +  st - the spectral transformation context
     173             : -  x  - input vector
     174             : 
     175             :    Output Parameter:
     176             : .  y - output vector
     177             : 
     178             :    Note:
     179             :    Currently implemented via STApplyTranspose() with appropriate conjugation.
     180             : 
     181             :    Level: developer
     182             : 
     183             : .seealso: STApply(), STApplyTranspose()
     184             : @*/
     185         463 : PetscErrorCode STApplyHermitianTranspose(ST st,Vec x,Vec y)
     186             : {
     187         463 :   Mat            Op;
     188             : 
     189         463 :   PetscFunctionBegin;
     190         463 :   PetscValidHeaderSpecific(st,ST_CLASSID,1);
     191         463 :   PetscValidHeaderSpecific(x,VEC_CLASSID,2);
     192         463 :   PetscValidHeaderSpecific(y,VEC_CLASSID,3);
     193         463 :   PetscValidType(st,1);
     194         463 :   STCheckMatrices(st,1);
     195         463 :   PetscCheck(x!=y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
     196         463 :   PetscCall(VecSetErrorIfLocked(y,3));
     197         463 :   PetscCall(STGetOperator_Private(st,&Op));
     198         463 :   PetscCall(MatMultHermitianTranspose(Op,x,y));
     199         463 :   PetscFunctionReturn(PETSC_SUCCESS);
     200             : }
     201             : 
     202             : /*@
     203             :    STGetBilinearForm - Returns the matrix used in the bilinear form with a
     204             :    generalized problem with semi-definite B.
     205             : 
     206             :    Logically Collective
     207             : 
     208             :    Input Parameters:
     209             : .  st - the spectral transformation context
     210             : 
     211             :    Output Parameter:
     212             : .  B - output matrix
     213             : 
     214             :    Notes:
     215             :    The output matrix B must be destroyed after use. It will be NULL in
     216             :    case of standard eigenproblems.
     217             : 
     218             :    Level: developer
     219             : 
     220             : .seealso: BVSetMatrix()
     221             : @*/
     222         154 : PetscErrorCode STGetBilinearForm(ST st,Mat *B)
     223             : {
     224         154 :   PetscFunctionBegin;
     225         154 :   PetscValidHeaderSpecific(st,ST_CLASSID,1);
     226         154 :   PetscValidType(st,1);
     227         154 :   PetscAssertPointer(B,2);
     228         154 :   STCheckMatrices(st,1);
     229         154 :   PetscUseTypeMethod(st,getbilinearform,B);
     230         154 :   PetscFunctionReturn(PETSC_SUCCESS);
     231             : }
     232             : 
     233         147 : PetscErrorCode STGetBilinearForm_Default(ST st,Mat *B)
     234             : {
     235         147 :   PetscFunctionBegin;
     236         147 :   if (st->nmat==1) *B = NULL;
     237             :   else {
     238         147 :     *B = st->A[1];
     239         147 :     PetscCall(PetscObjectReference((PetscObject)*B));
     240             :   }
     241         147 :   PetscFunctionReturn(PETSC_SUCCESS);
     242             : }
     243             : 
     244      147634 : static PetscErrorCode MatMult_STOperator(Mat Op,Vec x,Vec y)
     245             : {
     246      147634 :   ST             st;
     247             : 
     248      147634 :   PetscFunctionBegin;
     249      147634 :   PetscCall(MatShellGetContext(Op,&st));
     250      147634 :   PetscCall(STSetUp(st));
     251      147634 :   PetscCall(PetscLogEventBegin(ST_Apply,st,x,y,0));
     252      147634 :   if (st->D) { /* with balancing */
     253         697 :     PetscCall(VecPointwiseDivide(st->wb,x,st->D));
     254         697 :     PetscUseTypeMethod(st,apply,st->wb,y);
     255         697 :     PetscCall(VecPointwiseMult(y,y,st->D));
     256      146937 :   } else PetscUseTypeMethod(st,apply,x,y);
     257      147634 :   PetscCall(PetscLogEventEnd(ST_Apply,st,x,y,0));
     258      147634 :   PetscFunctionReturn(PETSC_SUCCESS);
     259             : }
     260             : 
     261        1320 : static PetscErrorCode MatMultTranspose_STOperator(Mat Op,Vec x,Vec y)
     262             : {
     263        1320 :   ST             st;
     264             : 
     265        1320 :   PetscFunctionBegin;
     266        1320 :   PetscCall(MatShellGetContext(Op,&st));
     267        1320 :   PetscCall(STSetUp(st));
     268        1320 :   PetscCall(PetscLogEventBegin(ST_ApplyTranspose,st,x,y,0));
     269        1320 :   if (st->D) { /* with balancing */
     270          50 :     PetscCall(VecPointwiseMult(st->wb,x,st->D));
     271          50 :     PetscUseTypeMethod(st,applytrans,st->wb,y);
     272          50 :     PetscCall(VecPointwiseDivide(y,y,st->D));
     273        1270 :   } else PetscUseTypeMethod(st,applytrans,x,y);
     274        1320 :   PetscCall(PetscLogEventEnd(ST_ApplyTranspose,st,x,y,0));
     275        1320 :   PetscFunctionReturn(PETSC_SUCCESS);
     276             : }
     277             : 
     278             : #if defined(PETSC_USE_COMPLEX)
     279             : static PetscErrorCode MatMultHermitianTranspose_STOperator(Mat Op,Vec x,Vec y)
     280             : {
     281             :   ST             st;
     282             : 
     283             :   PetscFunctionBegin;
     284             :   PetscCall(MatShellGetContext(Op,&st));
     285             :   PetscCall(STSetUp(st));
     286             :   PetscCall(PetscLogEventBegin(ST_ApplyHermitianTranspose,st,x,y,0));
     287             :   if (st->ops->applyhermtrans) {
     288             :     if (st->D) { /* with balancing */
     289             :       PetscCall(VecConjugate(st->D));
     290             :       PetscCall(VecPointwiseMult(st->wb,x,st->D));
     291             :       PetscUseTypeMethod(st,applyhermtrans,st->wb,y);
     292             :       PetscCall(VecPointwiseDivide(y,y,st->D));
     293             :       PetscCall(VecConjugate(st->D));
     294             :     } else PetscUseTypeMethod(st,applyhermtrans,x,y);
     295             :   } else {
     296             :     if (!st->wht) PetscCall(MatCreateVecs(st->A[0],&st->wht,NULL));
     297             :     PetscCall(VecCopy(x,st->wht));
     298             :     PetscCall(VecConjugate(st->wht));
     299             :     if (st->D) { /* with balancing */
     300             :       PetscCall(VecPointwiseMult(st->wb,st->wht,st->D));
     301             :       PetscUseTypeMethod(st,applytrans,st->wb,y);
     302             :       PetscCall(VecPointwiseDivide(y,y,st->D));
     303             :     } else PetscUseTypeMethod(st,applytrans,st->wht,y);
     304             :     PetscCall(VecConjugate(y));
     305             :   }
     306             :   PetscCall(PetscLogEventEnd(ST_ApplyHermitianTranspose,st,x,y,0));
     307             :   PetscFunctionReturn(PETSC_SUCCESS);
     308             : }
     309             : #endif
     310             : 
     311        3328 : static PetscErrorCode MatMatMult_STOperator(Mat Op,Mat B,Mat C,void *ctx)
     312             : {
     313        3328 :   ST             st;
     314             : 
     315        3328 :   PetscFunctionBegin;
     316        3328 :   PetscCall(MatShellGetContext(Op,&st));
     317        3328 :   PetscCall(STSetUp(st));
     318        3328 :   PetscCall(PetscLogEventBegin(ST_Apply,st,B,C,0));
     319        3328 :   PetscCall(STApplyMat_Generic(st,B,C));
     320        3328 :   PetscCall(PetscLogEventEnd(ST_Apply,st,B,C,0));
     321        3328 :   PetscFunctionReturn(PETSC_SUCCESS);
     322             : }
     323             : 
     324       90039 : PetscErrorCode STGetOperator_Private(ST st,Mat *Op)
     325             : {
     326       90039 :   PetscInt       m,n,M,N;
     327       90039 :   Vec            v;
     328       90039 :   VecType        vtype;
     329             : 
     330       90039 :   PetscFunctionBegin;
     331       90039 :   if (!st->Op) {
     332         508 :     if (Op) *Op = NULL;
     333             :     /* create the shell matrix */
     334         508 :     PetscCall(MatGetLocalSize(st->A[0],&m,&n));
     335         508 :     PetscCall(MatGetSize(st->A[0],&M,&N));
     336         508 :     PetscCall(MatCreateShell(PetscObjectComm((PetscObject)st),m,n,M,N,st,&st->Op));
     337         508 :     PetscCall(MatShellSetOperation(st->Op,MATOP_MULT,(void(*)(void))MatMult_STOperator));
     338         508 :     PetscCall(MatShellSetOperation(st->Op,MATOP_MULT_TRANSPOSE,(void(*)(void))MatMultTranspose_STOperator));
     339             : #if defined(PETSC_USE_COMPLEX)
     340             :     PetscCall(MatShellSetOperation(st->Op,MATOP_MULT_HERMITIAN_TRANSPOSE,(void(*)(void))MatMultHermitianTranspose_STOperator));
     341             : #else
     342         508 :     PetscCall(MatShellSetOperation(st->Op,MATOP_MULT_HERMITIAN_TRANSPOSE,(void(*)(void))MatMultTranspose_STOperator));
     343             : #endif
     344         508 :     if (!st->D && st->ops->apply==STApply_Generic) {
     345         466 :       PetscCall(MatShellSetMatProductOperation(st->Op,MATPRODUCT_AB,NULL,MatMatMult_STOperator,NULL,MATDENSE,MATDENSE));
     346         466 :       PetscCall(MatShellSetMatProductOperation(st->Op,MATPRODUCT_AB,NULL,MatMatMult_STOperator,NULL,MATDENSECUDA,MATDENSECUDA));
     347         466 :       PetscCall(MatShellSetMatProductOperation(st->Op,MATPRODUCT_AB,NULL,MatMatMult_STOperator,NULL,MATDENSEHIP,MATDENSEHIP));
     348             :     }
     349             :     /* make sure the shell matrix generates a vector of the same type as the problem matrices */
     350         508 :     PetscCall(MatCreateVecs(st->A[0],&v,NULL));
     351         508 :     PetscCall(VecGetType(v,&vtype));
     352         508 :     PetscCall(MatShellSetVecType(st->Op,vtype));
     353         508 :     PetscCall(VecDestroy(&v));
     354             :     /* build the operator matrices */
     355         508 :     PetscCall(STComputeOperator(st));
     356             :   }
     357       90039 :   if (Op) *Op = st->Op;
     358       90039 :   PetscFunctionReturn(PETSC_SUCCESS);
     359             : }
     360             : 
     361             : /*@
     362             :    STGetOperator - Returns a shell matrix that represents the operator of the
     363             :    spectral transformation.
     364             : 
     365             :    Collective
     366             : 
     367             :    Input Parameter:
     368             : .  st - the spectral transformation context
     369             : 
     370             :    Output Parameter:
     371             : .  Op - operator matrix
     372             : 
     373             :    Notes:
     374             :    The operator is defined in linear eigenproblems only, not in polynomial ones,
     375             :    so the call will fail if more than 2 matrices were passed in STSetMatrices().
     376             : 
     377             :    The returned shell matrix is essentially a wrapper to the STApply() and
     378             :    STApplyTranspose() operations. The operator can often be expressed as
     379             : 
     380             : $     Op = D*inv(K)*M*inv(D)
     381             : 
     382             :    where D is the balancing matrix, and M and K are two matrices corresponding
     383             :    to the numerator and denominator for spectral transformations that represent
     384             :    a rational matrix function. In the case of STSHELL, the inner part inv(K)*M
     385             :    is replaced by the user-provided operation from STShellSetApply().
     386             : 
     387             :    The preconditioner matrix K typically depends on the value of the shift, and
     388             :    its inverse is handled via an internal KSP object. Normal usage does not
     389             :    require explicitly calling STGetOperator(), but it can be used to force the
     390             :    creation of K and M, and then K is passed to the KSP. This is useful for
     391             :    setting options associated with the PCFactor (to set MUMPS options, for instance).
     392             : 
     393             :    The returned matrix must NOT be destroyed by the user. Instead, when no
     394             :    longer needed it must be returned with STRestoreOperator(). In particular,
     395             :    this is required before modifying the ST matrices or the shift.
     396             : 
     397             :    A NULL pointer can be passed in Op in case the matrix is not required but we
     398             :    want to force its creation. In this case, STRestoreOperator() should not be
     399             :    called.
     400             : 
     401             :    Level: advanced
     402             : 
     403             : .seealso: STApply(), STApplyTranspose(), STSetBalanceMatrix(), STShellSetApply(),
     404             :           STGetKSP(), STSetShift(), STRestoreOperator(), STSetMatrices()
     405             : @*/
     406        4845 : PetscErrorCode STGetOperator(ST st,Mat *Op)
     407             : {
     408        4845 :   PetscFunctionBegin;
     409        4845 :   PetscValidHeaderSpecific(st,ST_CLASSID,1);
     410        4845 :   PetscValidType(st,1);
     411        4845 :   STCheckMatrices(st,1);
     412        4845 :   STCheckNotSeized(st,1);
     413        4845 :   PetscCheck(st->nmat<=2,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_WRONGSTATE,"The operator is not defined in polynomial eigenproblems");
     414        4845 :   PetscCall(STGetOperator_Private(st,Op));
     415        4845 :   if (Op) st->opseized = PETSC_TRUE;
     416        4845 :   PetscFunctionReturn(PETSC_SUCCESS);
     417             : }
     418             : 
     419             : /*@
     420             :    STRestoreOperator - Restore the previously seized operator matrix.
     421             : 
     422             :    Logically Collective
     423             : 
     424             :    Input Parameters:
     425             : +  st - the spectral transformation context
     426             : -  Op - operator matrix
     427             : 
     428             :    Notes:
     429             :    The arguments must match the corresponding call to STGetOperator().
     430             : 
     431             :    Level: advanced
     432             : 
     433             : .seealso: STGetOperator()
     434             : @*/
     435        4815 : PetscErrorCode STRestoreOperator(ST st,Mat *Op)
     436             : {
     437        4815 :   PetscFunctionBegin;
     438        4815 :   PetscValidHeaderSpecific(st,ST_CLASSID,1);
     439        4815 :   PetscAssertPointer(Op,2);
     440        4815 :   PetscValidHeaderSpecific(*Op,MAT_CLASSID,2);
     441        4815 :   PetscCheck(st->opseized,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_WRONGSTATE,"Must be called after STGetOperator()");
     442        4815 :   *Op = NULL;
     443        4815 :   st->opseized = PETSC_FALSE;
     444        4815 :   PetscFunctionReturn(PETSC_SUCCESS);
     445             : }
     446             : 
     447             : /*
     448             :    STComputeOperator - Computes the matrices that constitute the operator
     449             : 
     450             :       Op = D*inv(K)*M*inv(D).
     451             : 
     452             :    K and M are computed here (D is user-provided) from the system matrices
     453             :    and the shift sigma (whenever these are changed, this function recomputes
     454             :    K and M). This is used only in linear eigenproblems (nmat<3).
     455             : 
     456             :    K is the "preconditioner matrix": it is the denominator in rational operators,
     457             :    e.g. (A-sigma*B) in shift-and-invert. In non-rational transformations such
     458             :    as STFILTER, K=NULL which means identity. After computing K, it is passed to
     459             :    the internal KSP object via KSPSetOperators.
     460             : 
     461             :    M is the numerator in rational operators. If unused it is set to NULL (e.g.
     462             :    in STPRECOND).
     463             : 
     464             :    STSHELL does not compute anything here, but sets the flag as if it was ready.
     465             : */
     466        1307 : PetscErrorCode STComputeOperator(ST st)
     467             : {
     468        1307 :   PC             pc;
     469             : 
     470        1307 :   PetscFunctionBegin;
     471        1307 :   PetscValidHeaderSpecific(st,ST_CLASSID,1);
     472        1307 :   PetscValidType(st,1);
     473        1307 :   if (!st->opready && st->ops->computeoperator) {
     474         780 :     PetscCall(PetscInfo(st,"Building the operator matrices\n"));
     475         780 :     STCheckMatrices(st,1);
     476         780 :     if (!st->T) PetscCall(PetscCalloc1(PetscMax(2,st->nmat),&st->T));
     477         780 :     PetscCall(PetscLogEventBegin(ST_ComputeOperator,st,0,0,0));
     478         780 :     PetscUseTypeMethod(st,computeoperator);
     479         780 :     PetscCall(PetscLogEventEnd(ST_ComputeOperator,st,0,0,0));
     480         780 :     if (st->usesksp) {
     481         421 :       if (!st->ksp) PetscCall(STGetKSP(st,&st->ksp));
     482         421 :       if (st->P) {
     483         384 :         PetscCall(STSetDefaultKSP(st));
     484         384 :         PetscCall(ST_KSPSetOperators(st,st->P,st->Pmat?st->Pmat:st->P));
     485             :       } else {
     486             :         /* STPRECOND defaults to PCNONE if st->P is empty */
     487          37 :         PetscCall(KSPGetPC(st->ksp,&pc));
     488          37 :         PetscCall(PCSetType(pc,PCNONE));
     489             :       }
     490             :     }
     491             :   }
     492        1307 :   st->opready = PETSC_TRUE;
     493        1307 :   PetscFunctionReturn(PETSC_SUCCESS);
     494             : }
     495             : 
     496             : /*@
     497             :    STSetUp - Prepares for the use of a spectral transformation.
     498             : 
     499             :    Collective
     500             : 
     501             :    Input Parameter:
     502             : .  st - the spectral transformation context
     503             : 
     504             :    Level: advanced
     505             : 
     506             : .seealso: STCreate(), STApply(), STDestroy()
     507             : @*/
     508      153538 : PetscErrorCode STSetUp(ST st)
     509             : {
     510      153538 :   PetscInt       i,n,k;
     511             : 
     512      153538 :   PetscFunctionBegin;
     513      153538 :   PetscValidHeaderSpecific(st,ST_CLASSID,1);
     514      153538 :   PetscValidType(st,1);
     515      153538 :   STCheckMatrices(st,1);
     516      153538 :   switch (st->state) {
     517         967 :     case ST_STATE_INITIAL:
     518         967 :       PetscCall(PetscInfo(st,"Setting up new ST\n"));
     519         967 :       if (!((PetscObject)st)->type_name) PetscCall(STSetType(st,STSHIFT));
     520             :       break;
     521      152537 :     case ST_STATE_SETUP:
     522      152537 :       PetscFunctionReturn(PETSC_SUCCESS);
     523          34 :     case ST_STATE_UPDATED:
     524          34 :       PetscCall(PetscInfo(st,"Setting up updated ST\n"));
     525             :       break;
     526             :   }
     527        1001 :   PetscCall(PetscLogEventBegin(ST_SetUp,st,0,0,0));
     528        1001 :   if (st->state!=ST_STATE_UPDATED) {
     529         967 :     if (!(st->nmat<3 && st->opready)) {
     530         942 :       if (st->T) {
     531         249 :         for (i=0;i<PetscMax(2,st->nmat);i++) PetscCall(MatDestroy(&st->T[i]));
     532             :       }
     533         942 :       PetscCall(MatDestroy(&st->P));
     534             :     }
     535             :   }
     536        1001 :   if (st->D) {
     537          13 :     PetscCall(MatGetLocalSize(st->A[0],NULL,&n));
     538          13 :     PetscCall(VecGetLocalSize(st->D,&k));
     539          13 :     PetscCheck(n==k,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_SIZ,"Balance matrix has wrong dimension %" PetscInt_FMT " (should be %" PetscInt_FMT ")",k,n);
     540          13 :     if (!st->wb) PetscCall(VecDuplicate(st->D,&st->wb));
     541             :   }
     542        1001 :   if (st->nmat<3 && st->transform) PetscCall(STComputeOperator(st));
     543             :   else {
     544         202 :     if (!st->T) PetscCall(PetscCalloc1(PetscMax(2,st->nmat),&st->T));
     545             :   }
     546        1001 :   PetscTryTypeMethod(st,setup);
     547        1001 :   st->state = ST_STATE_SETUP;
     548        1001 :   PetscCall(PetscLogEventEnd(ST_SetUp,st,0,0,0));
     549        1001 :   PetscFunctionReturn(PETSC_SUCCESS);
     550             : }
     551             : 
     552             : /*
     553             :    Computes coefficients for the transformed polynomial,
     554             :    and stores the result in argument S.
     555             : 
     556             :    alpha - value of the parameter of the transformed polynomial
     557             :    beta - value of the previous shift (only used in inplace mode)
     558             :    k - index of first matrix included in the computation
     559             :    coeffs - coefficients of the expansion
     560             :    initial - true if this is the first time
     561             :    precond - whether the preconditioner matrix must be computed
     562             : */
     563        1415 : PetscErrorCode STMatMAXPY_Private(ST st,PetscScalar alpha,PetscScalar beta,PetscInt k,PetscScalar *coeffs,PetscBool initial,PetscBool precond,Mat *S)
     564             : {
     565        1415 :   PetscInt       *matIdx=NULL,nmat,i,ini=-1;
     566        1415 :   PetscScalar    t=1.0,ta,gamma;
     567        1415 :   PetscBool      nz=PETSC_FALSE;
     568        1415 :   Mat            *A=precond?st->Psplit:st->A;
     569        1415 :   MatStructure   str=precond?st->strp:st->str;
     570             : 
     571        1415 :   PetscFunctionBegin;
     572        1415 :   nmat = st->nmat-k;
     573        1415 :   switch (st->matmode) {
     574          20 :   case ST_MATMODE_INPLACE:
     575          20 :     PetscCheck(st->nmat<=2,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST_MATMODE_INPLACE not supported for polynomial eigenproblems");
     576          20 :     PetscCheck(!precond,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST_MATMODE_INPLACE not supported for split preconditioner");
     577          20 :     if (initial) {
     578          11 :       PetscCall(PetscObjectReference((PetscObject)A[0]));
     579          11 :       *S = A[0];
     580          11 :       gamma = alpha;
     581           9 :     } else gamma = alpha-beta;
     582          20 :     if (gamma != 0.0) {
     583          16 :       if (st->nmat>1) PetscCall(MatAXPY(*S,gamma,A[1],str));
     584          11 :       else PetscCall(MatShift(*S,gamma));
     585             :     }
     586             :     break;
     587         101 :   case ST_MATMODE_SHELL:
     588         101 :     PetscCheck(!precond,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST_MATMODE_SHELL not supported for split preconditioner");
     589         101 :     if (initial) {
     590          82 :       if (st->nmat>2) {
     591          10 :         PetscCall(PetscMalloc1(nmat,&matIdx));
     592          39 :         for (i=0;i<nmat;i++) matIdx[i] = k+i;
     593             :       }
     594          82 :       PetscCall(STMatShellCreate(st,alpha,nmat,matIdx,coeffs,S));
     595          82 :       if (st->nmat>2) PetscCall(PetscFree(matIdx));
     596          19 :     } else PetscCall(STMatShellShift(*S,alpha));
     597             :     break;
     598        1294 :   case ST_MATMODE_COPY:
     599        1294 :     if (coeffs) {
     600         546 :       for (i=0;i<nmat && ini==-1;i++) {
     601         318 :         if (coeffs[i]!=0.0) ini = i;
     602          90 :         else t *= alpha;
     603             :       }
     604         228 :       if (coeffs[ini] != 1.0) nz = PETSC_TRUE;
     605         430 :       for (i=ini+1;i<nmat&&!nz;i++) if (coeffs[i]!=0.0) nz = PETSC_TRUE;
     606             :     } else { nz = PETSC_TRUE; ini = 0; }
     607        1294 :     if ((alpha == 0.0 || !nz) && t==1.0) {
     608         650 :       PetscCall(PetscObjectReference((PetscObject)A[k+ini]));
     609         650 :       PetscCall(MatDestroy(S));
     610         650 :       *S = A[k+ini];
     611             :     } else {
     612         644 :       if (*S && *S!=A[k+ini]) {
     613         427 :         PetscCall(MatSetOption(*S,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE));
     614         427 :         PetscCall(MatCopy(A[k+ini],*S,DIFFERENT_NONZERO_PATTERN));
     615             :       } else {
     616         217 :         PetscCall(MatDestroy(S));
     617         217 :         PetscCall(MatDuplicate(A[k+ini],MAT_COPY_VALUES,S));
     618         217 :         PetscCall(MatSetOption(*S,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE));
     619             :       }
     620         644 :       if (coeffs && coeffs[ini]!=1.0) PetscCall(MatScale(*S,coeffs[ini]));
     621        1535 :       for (i=ini+k+1;i<PetscMax(2,st->nmat);i++) {
     622         891 :         t *= alpha;
     623         891 :         ta = t;
     624         891 :         if (coeffs) ta *= coeffs[i-k];
     625         891 :         if (ta!=0.0) {
     626         890 :           if (st->nmat>1) PetscCall(MatAXPY(*S,ta,A[i],str));
     627         891 :           else PetscCall(MatShift(*S,ta));
     628             :         }
     629             :       }
     630             :     }
     631             :   }
     632        1415 :   PetscCall(MatSetOption(*S,MAT_SYMMETRIC,st->asymm));
     633        1415 :   PetscCall(MatSetOption(*S,MAT_HERMITIAN,(PetscImaginaryPart(st->sigma)==0.0)?st->aherm:PETSC_FALSE));
     634        1415 :   PetscFunctionReturn(PETSC_SUCCESS);
     635             : }
     636             : 
     637             : /*
     638             :    Computes the values of the coefficients required by STMatMAXPY_Private
     639             :    for the case of monomial basis.
     640             : */
     641          40 : PetscErrorCode STCoeffs_Monomial(ST st, PetscScalar *coeffs)
     642             : {
     643          40 :   PetscInt  k,i,ini,inip;
     644             : 
     645          40 :   PetscFunctionBegin;
     646             :   /* Compute binomial coefficients */
     647          40 :   ini = (st->nmat*(st->nmat-1))/2;
     648         170 :   for (i=0;i<st->nmat;i++) coeffs[ini+i]=1.0;
     649         130 :   for (k=st->nmat-1;k>=1;k--) {
     650          90 :     inip = ini+1;
     651          90 :     ini = (k*(k-1))/2;
     652          90 :     coeffs[ini] = 1.0;
     653         150 :     for (i=1;i<k;i++) coeffs[ini+i] = coeffs[ini+i-1]+coeffs[inip+i-1];
     654             :   }
     655          40 :   PetscFunctionReturn(PETSC_SUCCESS);
     656             : }
     657             : 
     658             : /*@
     659             :    STPostSolve - Optional post-solve phase, intended for any actions that must
     660             :    be performed on the ST object after the eigensolver has finished.
     661             : 
     662             :    Collective
     663             : 
     664             :    Input Parameters:
     665             : .  st  - the spectral transformation context
     666             : 
     667             :    Level: developer
     668             : 
     669             : .seealso: EPSSolve()
     670             : @*/
     671        1032 : PetscErrorCode STPostSolve(ST st)
     672             : {
     673        1032 :   PetscFunctionBegin;
     674        1032 :   PetscValidHeaderSpecific(st,ST_CLASSID,1);
     675        1032 :   PetscValidType(st,1);
     676        1032 :   PetscTryTypeMethod(st,postsolve);
     677        1032 :   PetscFunctionReturn(PETSC_SUCCESS);
     678             : }
     679             : 
     680             : /*@
     681             :    STBackTransform - Back-transformation phase, intended for
     682             :    spectral transformations which require to transform the computed
     683             :    eigenvalues back to the original eigenvalue problem.
     684             : 
     685             :    Not Collective
     686             : 
     687             :    Input Parameters:
     688             : +  st   - the spectral transformation context
     689             : .  n    - number of eigenvalues
     690             : .  eigr - real part of a computed eigenvalues
     691             : -  eigi - imaginary part of a computed eigenvalues
     692             : 
     693             :    Level: developer
     694             : 
     695             : .seealso: STIsInjective()
     696             : @*/
     697     2170843 : PetscErrorCode STBackTransform(ST st,PetscInt n,PetscScalar* eigr,PetscScalar* eigi)
     698             : {
     699     2170843 :   PetscFunctionBegin;
     700     2170843 :   PetscValidHeaderSpecific(st,ST_CLASSID,1);
     701     2170843 :   PetscValidType(st,1);
     702     2170843 :   PetscTryTypeMethod(st,backtransform,n,eigr,eigi);
     703     2170843 :   PetscFunctionReturn(PETSC_SUCCESS);
     704             : }
     705             : 
     706             : /*@
     707             :    STIsInjective - Ask if this spectral transformation is injective or not
     708             :    (that is, if it corresponds to a one-to-one mapping). If not, then it
     709             :    does not make sense to call STBackTransform().
     710             : 
     711             :    Not Collective
     712             : 
     713             :    Input Parameter:
     714             : .  st   - the spectral transformation context
     715             : 
     716             :    Output Parameter:
     717             : .  is - the answer
     718             : 
     719             :    Level: developer
     720             : 
     721             : .seealso: STBackTransform()
     722             : @*/
     723         653 : PetscErrorCode STIsInjective(ST st,PetscBool* is)
     724             : {
     725         653 :   PetscBool      shell;
     726             : 
     727         653 :   PetscFunctionBegin;
     728         653 :   PetscValidHeaderSpecific(st,ST_CLASSID,1);
     729         653 :   PetscValidType(st,1);
     730         653 :   PetscAssertPointer(is,2);
     731             : 
     732         653 :   PetscCall(PetscObjectTypeCompare((PetscObject)st,STSHELL,&shell));
     733         653 :   if (shell) PetscCall(STIsInjective_Shell(st,is));
     734         622 :   else *is = st->ops->backtransform? PETSC_TRUE: PETSC_FALSE;
     735         653 :   PetscFunctionReturn(PETSC_SUCCESS);
     736             : }
     737             : 
     738             : /*@
     739             :    STMatSetUp - Build the preconditioner matrix used in STMatSolve().
     740             : 
     741             :    Collective
     742             : 
     743             :    Input Parameters:
     744             : +  st     - the spectral transformation context
     745             : .  sigma  - the shift
     746             : -  coeffs - the coefficients (may be NULL)
     747             : 
     748             :    Note:
     749             :    This function is not intended to be called by end users, but by SLEPc
     750             :    solvers that use ST. It builds matrix st->P as follows, then calls KSPSetUp().
     751             : .vb
     752             :     If (coeffs)  st->P = Sum_{i=0..nmat-1} coeffs[i]*sigma^i*A_i
     753             :     else         st->P = Sum_{i=0..nmat-1} sigma^i*A_i
     754             : .ve
     755             : 
     756             :    Level: developer
     757             : 
     758             : .seealso: STMatSolve()
     759             : @*/
     760         145 : PetscErrorCode STMatSetUp(ST st,PetscScalar sigma,PetscScalar *coeffs)
     761             : {
     762         145 :   PetscFunctionBegin;
     763         145 :   PetscValidHeaderSpecific(st,ST_CLASSID,1);
     764         435 :   PetscValidLogicalCollectiveScalar(st,sigma,2);
     765         145 :   STCheckMatrices(st,1);
     766             : 
     767         145 :   PetscCall(PetscLogEventBegin(ST_MatSetUp,st,0,0,0));
     768         145 :   PetscCall(STMatMAXPY_Private(st,sigma,0.0,0,coeffs,PETSC_TRUE,PETSC_FALSE,&st->P));
     769         145 :   if (st->Psplit) PetscCall(STMatMAXPY_Private(st,sigma,0.0,0,coeffs,PETSC_TRUE,PETSC_TRUE,&st->Pmat));
     770         145 :   PetscCall(ST_KSPSetOperators(st,st->P,st->Pmat?st->Pmat:st->P));
     771         145 :   PetscCall(KSPSetUp(st->ksp));
     772         145 :   PetscCall(PetscLogEventEnd(ST_MatSetUp,st,0,0,0));
     773         145 :   PetscFunctionReturn(PETSC_SUCCESS);
     774             : }
     775             : 
     776             : /*@
     777             :    STSetWorkVecs - Sets a number of work vectors into the ST object.
     778             : 
     779             :    Collective
     780             : 
     781             :    Input Parameters:
     782             : +  st - the spectral transformation context
     783             : -  nw - number of work vectors to allocate
     784             : 
     785             :    Developer Notes:
     786             :    This is SLEPC_EXTERN because it may be required by shell STs.
     787             : 
     788             :    Level: developer
     789             : 
     790             : .seealso: STMatCreateVecs()
     791             : @*/
     792         362 : PetscErrorCode STSetWorkVecs(ST st,PetscInt nw)
     793             : {
     794         362 :   PetscInt       i;
     795             : 
     796         362 :   PetscFunctionBegin;
     797         362 :   PetscValidHeaderSpecific(st,ST_CLASSID,1);
     798        1086 :   PetscValidLogicalCollectiveInt(st,nw,2);
     799         362 :   PetscCheck(nw>0,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_OUTOFRANGE,"nw must be > 0: nw = %" PetscInt_FMT,nw);
     800         362 :   if (st->nwork < nw) {
     801         342 :     PetscCall(VecDestroyVecs(st->nwork,&st->work));
     802         342 :     st->nwork = nw;
     803         342 :     PetscCall(PetscMalloc1(nw,&st->work));
     804         715 :     for (i=0;i<nw;i++) PetscCall(STMatCreateVecs(st,&st->work[i],NULL));
     805             :   }
     806         362 :   PetscFunctionReturn(PETSC_SUCCESS);
     807             : }

Generated by: LCOV version 1.14