LCOV - code coverage report
Current view: top level - sys/classes/fn/impls/phi - fnphi.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 143 143 100.0 %
Date: 2024-12-18 00:42:09 Functions: 12 12 100.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             :    Phi functions
      12             :       phi_0(x) = exp(x)
      13             :       phi_1(x) = (exp(x)-1)/x
      14             :       phi_k(x) = (phi_{k-1}(x)-1/(k-1)!)/x
      15             : */
      16             : 
      17             : #include <slepc/private/fnimpl.h>      /*I "slepcfn.h" I*/
      18             : 
      19             : typedef struct {
      20             :   PetscInt k;    /* index of the phi-function, defaults to k=1 */
      21             :   Mat      H;    /* auxiliary matrix of order m+k */
      22             :   Mat      F;    /* auxiliary matrix to store exp(H) */
      23             : } FN_PHI;
      24             : 
      25             : #define MAX_INDEX 10
      26             : 
      27             : static const PetscReal rfactorial[MAX_INDEX+2] = { 1, 1, 0.5, 1.0/6, 1.0/24, 1.0/120, 1.0/720, 1.0/5040, 1.0/40320, 1.0/362880, 1.0/3628800, 1.0/39916800 };
      28             : 
      29          27 : static PetscErrorCode FNEvaluateFunction_Phi(FN fn,PetscScalar x,PetscScalar *y)
      30             : {
      31          27 :   FN_PHI      *ctx = (FN_PHI*)fn->data;
      32          27 :   PetscInt    i;
      33          27 :   PetscScalar phi[MAX_INDEX+1];
      34             : 
      35          27 :   PetscFunctionBegin;
      36          27 :   if (x==0.0) *y = rfactorial[ctx->k];
      37             :   else {
      38          27 :     phi[0] = PetscExpScalar(x);
      39          63 :     for (i=1;i<=ctx->k;i++) phi[i] = (phi[i-1]-rfactorial[i-1])/x;
      40          27 :     *y = phi[ctx->k];
      41             :   }
      42          27 :   PetscFunctionReturn(PETSC_SUCCESS);
      43             : }
      44             : 
      45           3 : static PetscErrorCode FNEvaluateDerivative_Phi(FN fn,PetscScalar x,PetscScalar *y)
      46             : {
      47           3 :   FN_PHI      *ctx = (FN_PHI*)fn->data;
      48           3 :   PetscInt    i;
      49           3 :   PetscScalar phi[MAX_INDEX+2];
      50             : 
      51           3 :   PetscFunctionBegin;
      52           3 :   if (x==0.0) *y = rfactorial[ctx->k+1];
      53             :   else {
      54           3 :     phi[0] = PetscExpScalar(x);
      55          10 :     for (i=1;i<=ctx->k+1;i++) phi[i] = (phi[i-1]-rfactorial[i-1])/x;
      56           3 :     *y = phi[ctx->k] - phi[ctx->k+1]*(PetscReal)ctx->k;
      57             :   }
      58           3 :   PetscFunctionReturn(PETSC_SUCCESS);
      59             : }
      60             : 
      61          23 : static PetscErrorCode FNEvaluateFunctionMatVec_Phi(FN fn,Mat A,Vec v)
      62             : {
      63          23 :   FN_PHI            *ctx = (FN_PHI*)fn->data;
      64          23 :   PetscInt          i,j,m,n,nh;
      65          23 :   PetscScalar       *Ha,*va,sfactor=1.0;
      66          23 :   const PetscScalar *Aa,*Fa;
      67             : 
      68          23 :   PetscFunctionBegin;
      69          23 :   PetscCall(MatGetSize(A,&m,NULL));
      70          23 :   n = m+ctx->k;
      71          23 :   if (ctx->H) {
      72          19 :     PetscCall(MatGetSize(ctx->H,&nh,NULL));
      73          19 :     if (n!=nh) {
      74          19 :       PetscCall(MatDestroy(&ctx->H));
      75          19 :       PetscCall(MatDestroy(&ctx->F));
      76             :     }
      77             :   }
      78          23 :   if (!ctx->H) {
      79          23 :     PetscCall(MatCreateDense(PETSC_COMM_SELF,n,n,n,n,NULL,&ctx->H));
      80          23 :     PetscCall(MatCreateDense(PETSC_COMM_SELF,n,n,n,n,NULL,&ctx->F));
      81             :   }
      82          23 :   PetscCall(MatDenseGetArray(ctx->H,&Ha));
      83          23 :   PetscCall(MatDenseGetArrayRead(A,&Aa));
      84        1547 :   for (j=0;j<m;j++) PetscCall(PetscArraycpy(Ha+j*n,Aa+j*m,m));
      85          23 :   PetscCall(MatDenseRestoreArrayRead(A,&Aa));
      86          23 :   if (ctx->k) {
      87        3070 :     for (j=0;j<m;j++) for (i=m;i<n;i++) Ha[i+j*n] = 0.0;
      88        1608 :     for (j=m;j<n;j++) for (i=0;i<n;i++) Ha[i+j*n] = 0.0;
      89          22 :     Ha[0+m*n] = fn->alpha;
      90          24 :     for (j=m+1;j<n;j++) Ha[j-1+j*n] = fn->alpha;
      91             :   }
      92          23 :   PetscCall(MatDenseRestoreArray(ctx->H,&Ha));
      93             : 
      94          23 :   PetscCall(FNEvaluateFunctionMat_Exp_Higham(fn,ctx->H,ctx->F));
      95             : 
      96          23 :   PetscCall(MatDenseGetArrayRead(ctx->F,&Fa));
      97          23 :   PetscCall(VecGetArray(v,&va));
      98          23 :   if (ctx->k) {
      99          22 :     sfactor = PetscPowScalarInt(fn->alpha,-ctx->k);
     100        1560 :     for (i=0;i<m;i++) va[i] = sfactor*Fa[i+(n-1)*n];
     101             :   } else {
     102           9 :     for (i=0;i<m;i++) va[i] = sfactor*Fa[i+0*n];
     103             :   }
     104          23 :   PetscCall(VecRestoreArray(v,&va));
     105          23 :   PetscCall(MatDenseRestoreArrayRead(ctx->F,&Fa));
     106          23 :   PetscFunctionReturn(PETSC_SUCCESS);
     107             : }
     108             : 
     109           3 : static PetscErrorCode FNPhiSetIndex_Phi(FN fn,PetscInt k)
     110             : {
     111           3 :   FN_PHI         *ctx = (FN_PHI*)fn->data;
     112             : 
     113           3 :   PetscFunctionBegin;
     114           3 :   PetscCheck(k>=0,PetscObjectComm((PetscObject)fn),PETSC_ERR_ARG_OUTOFRANGE,"Index cannot be negative");
     115           3 :   PetscCheck(k<=MAX_INDEX,PetscObjectComm((PetscObject)fn),PETSC_ERR_ARG_OUTOFRANGE,"Phi functions only implemented for k<=%d",MAX_INDEX);
     116           3 :   if (k!=ctx->k) {
     117           2 :     ctx->k = k;
     118           2 :     PetscCall(MatDestroy(&ctx->H));
     119           2 :     PetscCall(MatDestroy(&ctx->F));
     120             :   }
     121           3 :   PetscFunctionReturn(PETSC_SUCCESS);
     122             : }
     123             : 
     124             : /*@
     125             :    FNPhiSetIndex - Sets the index of the phi-function.
     126             : 
     127             :    Logically Collective
     128             : 
     129             :    Input Parameters:
     130             : +  fn - the math function context
     131             : -  k  - the index
     132             : 
     133             :    Notes:
     134             :    The phi-functions are defined as follows. The default is k=1.
     135             : .vb
     136             :       phi_0(x) = exp(x)
     137             :       phi_1(x) = (exp(x)-1)/x
     138             :       phi_k(x) = (phi_{k-1}(x)-1/(k-1)!)/x
     139             : .ve
     140             : 
     141             :    Level: intermediate
     142             : 
     143             : .seealso: FNPhiGetIndex()
     144             : @*/
     145           3 : PetscErrorCode FNPhiSetIndex(FN fn,PetscInt k)
     146             : {
     147           3 :   PetscFunctionBegin;
     148           3 :   PetscValidHeaderSpecific(fn,FN_CLASSID,1);
     149           9 :   PetscValidLogicalCollectiveInt(fn,k,2);
     150           3 :   PetscTryMethod(fn,"FNPhiSetIndex_C",(FN,PetscInt),(fn,k));
     151           3 :   PetscFunctionReturn(PETSC_SUCCESS);
     152             : }
     153             : 
     154           1 : static PetscErrorCode FNPhiGetIndex_Phi(FN fn,PetscInt *k)
     155             : {
     156           1 :   FN_PHI *ctx = (FN_PHI*)fn->data;
     157             : 
     158           1 :   PetscFunctionBegin;
     159           1 :   *k = ctx->k;
     160           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     161             : }
     162             : 
     163             : /*@
     164             :    FNPhiGetIndex - Gets the index of the phi-function.
     165             : 
     166             :    Not Collective
     167             : 
     168             :    Input Parameter:
     169             : .  fn - the math function context
     170             : 
     171             :    Output Parameter:
     172             : .  k  - the index
     173             : 
     174             :    Level: intermediate
     175             : 
     176             : .seealso: FNPhiSetIndex()
     177             : @*/
     178           1 : PetscErrorCode FNPhiGetIndex(FN fn,PetscInt *k)
     179             : {
     180           1 :   PetscFunctionBegin;
     181           1 :   PetscValidHeaderSpecific(fn,FN_CLASSID,1);
     182           1 :   PetscAssertPointer(k,2);
     183           1 :   PetscUseMethod(fn,"FNPhiGetIndex_C",(FN,PetscInt*),(fn,k));
     184           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     185             : }
     186             : 
     187           3 : static PetscErrorCode FNView_Phi(FN fn,PetscViewer viewer)
     188             : {
     189           3 :   FN_PHI         *ctx = (FN_PHI*)fn->data;
     190           3 :   PetscBool      isascii;
     191           3 :   char           str[50],strx[50];
     192             : 
     193           3 :   PetscFunctionBegin;
     194           3 :   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
     195           3 :   if (isascii) {
     196           3 :     PetscCall(PetscViewerASCIIPrintf(viewer,"  phi_%" PetscInt_FMT ": ",ctx->k));
     197           3 :     PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_FALSE));
     198           3 :     if (fn->beta!=(PetscScalar)1.0) {
     199           1 :       PetscCall(SlepcSNPrintfScalar(str,sizeof(str),fn->beta,PETSC_TRUE));
     200           1 :       PetscCall(PetscViewerASCIIPrintf(viewer,"%s*",str));
     201             :     }
     202           3 :     if (fn->alpha==(PetscScalar)1.0) PetscCall(PetscSNPrintf(strx,sizeof(strx),"x"));
     203             :     else {
     204           1 :       PetscCall(SlepcSNPrintfScalar(str,sizeof(str),fn->alpha,PETSC_TRUE));
     205           1 :       PetscCall(PetscSNPrintf(strx,sizeof(strx),"(%s*x)",str));
     206             :     }
     207           3 :     if (!ctx->k) PetscCall(PetscViewerASCIIPrintf(viewer,"exp(%s)\n",strx));
     208           2 :     else if (ctx->k==1) PetscCall(PetscViewerASCIIPrintf(viewer,"(exp(%s)-1)/%s\n",strx,strx));
     209           1 :     else PetscCall(PetscViewerASCIIPrintf(viewer,"(phi_%" PetscInt_FMT "(%s)-1/%" PetscInt_FMT "!)/%s\n",ctx->k-1,strx,ctx->k-1,strx));
     210           3 :     PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_TRUE));
     211             :   }
     212           3 :   PetscFunctionReturn(PETSC_SUCCESS);
     213             : }
     214             : 
     215           2 : static PetscErrorCode FNSetFromOptions_Phi(FN fn,PetscOptionItems *PetscOptionsObject)
     216             : {
     217           2 :   FN_PHI         *ctx = (FN_PHI*)fn->data;
     218           2 :   PetscInt       k;
     219           2 :   PetscBool      flag;
     220             : 
     221           2 :   PetscFunctionBegin;
     222           2 :   PetscOptionsHeadBegin(PetscOptionsObject,"FN Phi Options");
     223             : 
     224           2 :     PetscCall(PetscOptionsInt("-fn_phi_index","Index of the phi-function","FNPhiSetIndex",ctx->k,&k,&flag));
     225           2 :     if (flag) PetscCall(FNPhiSetIndex(fn,k));
     226             : 
     227           2 :   PetscOptionsHeadEnd();
     228           2 :   PetscFunctionReturn(PETSC_SUCCESS);
     229             : }
     230             : 
     231           1 : static PetscErrorCode FNDuplicate_Phi(FN fn,MPI_Comm comm,FN *newfn)
     232             : {
     233           1 :   FN_PHI *ctx = (FN_PHI*)fn->data,*ctx2 = (FN_PHI*)(*newfn)->data;
     234             : 
     235           1 :   PetscFunctionBegin;
     236           1 :   ctx2->k = ctx->k;
     237           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     238             : }
     239             : 
     240           5 : static PetscErrorCode FNDestroy_Phi(FN fn)
     241             : {
     242           5 :   FN_PHI         *ctx = (FN_PHI*)fn->data;
     243             : 
     244           5 :   PetscFunctionBegin;
     245           5 :   PetscCall(MatDestroy(&ctx->H));
     246           5 :   PetscCall(MatDestroy(&ctx->F));
     247           5 :   PetscCall(PetscFree(fn->data));
     248           5 :   PetscCall(PetscObjectComposeFunction((PetscObject)fn,"FNPhiSetIndex_C",NULL));
     249           5 :   PetscCall(PetscObjectComposeFunction((PetscObject)fn,"FNPhiGetIndex_C",NULL));
     250           5 :   PetscFunctionReturn(PETSC_SUCCESS);
     251             : }
     252             : 
     253           5 : SLEPC_EXTERN PetscErrorCode FNCreate_Phi(FN fn)
     254             : {
     255           5 :   FN_PHI         *ctx;
     256             : 
     257           5 :   PetscFunctionBegin;
     258           5 :   PetscCall(PetscNew(&ctx));
     259           5 :   fn->data = (void*)ctx;
     260           5 :   ctx->k   = 1;
     261             : 
     262           5 :   fn->ops->evaluatefunction          = FNEvaluateFunction_Phi;
     263           5 :   fn->ops->evaluatederivative        = FNEvaluateDerivative_Phi;
     264           5 :   fn->ops->evaluatefunctionmatvec[0] = FNEvaluateFunctionMatVec_Phi;
     265           5 :   fn->ops->setfromoptions            = FNSetFromOptions_Phi;
     266           5 :   fn->ops->view                      = FNView_Phi;
     267           5 :   fn->ops->duplicate                 = FNDuplicate_Phi;
     268           5 :   fn->ops->destroy                   = FNDestroy_Phi;
     269           5 :   PetscCall(PetscObjectComposeFunction((PetscObject)fn,"FNPhiSetIndex_C",FNPhiSetIndex_Phi));
     270           5 :   PetscCall(PetscObjectComposeFunction((PetscObject)fn,"FNPhiGetIndex_C",FNPhiGetIndex_Phi));
     271           5 :   PetscFunctionReturn(PETSC_SUCCESS);
     272             : }

Generated by: LCOV version 1.14