LCOV - code coverage report
Current view: top level - mfn/impls/expokit - mfnexpokit.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 112 121 92.6 %
Date: 2024-12-18 00:42:09 Functions: 3 3 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             :    SLEPc matrix function solver: "expokit"
      12             : 
      13             :    Method: Arnoldi method tailored for the matrix exponential
      14             : 
      15             :    Algorithm:
      16             : 
      17             :        Uses Arnoldi relations to compute exp(t_step*A)*v_last for
      18             :        several time steps.
      19             : 
      20             :    References:
      21             : 
      22             :        [1] R. Sidje, "Expokit: a software package for computing matrix
      23             :            exponentials", ACM Trans. Math. Softw. 24(1):130-156, 1998.
      24             : */
      25             : 
      26             : #include <slepc/private/mfnimpl.h>
      27             : 
      28           3 : static PetscErrorCode MFNSetUp_Expokit(MFN mfn)
      29             : {
      30           3 :   PetscInt       N;
      31           3 :   PetscBool      isexp;
      32             : 
      33           3 :   PetscFunctionBegin;
      34           3 :   PetscCall(MatGetSize(mfn->A,&N,NULL));
      35           3 :   if (mfn->ncv==PETSC_DETERMINE) mfn->ncv = PetscMin(30,N);
      36           3 :   if (mfn->max_it==PETSC_DETERMINE) mfn->max_it = 100;
      37           3 :   PetscCall(MFNAllocateSolution(mfn,2));
      38             : 
      39           3 :   PetscCall(PetscObjectTypeCompare((PetscObject)mfn->fn,FNEXP,&isexp));
      40           3 :   PetscCheck(isexp,PETSC_COMM_SELF,PETSC_ERR_SUP,"This solver only supports the exponential function");
      41           3 :   PetscFunctionReturn(PETSC_SUCCESS);
      42             : }
      43             : 
      44           8 : static PetscErrorCode MFNSolve_Expokit(MFN mfn,Vec b,Vec x)
      45             : {
      46           8 :   PetscInt          mxstep,mxrej,m,mb,ld,i,j,ireject,mx,k1;
      47           8 :   Vec               v,r;
      48           8 :   Mat               H,M=NULL,K=NULL;
      49           8 :   FN                fn;
      50           8 :   PetscScalar       *Harray,*B,*F,*betaF,t,sgn,sfactor;
      51           8 :   const PetscScalar *pK;
      52           8 :   PetscReal         anorm,avnorm,tol,err_loc,rndoff,t_out,t_new,t_now,t_step;
      53           8 :   PetscReal         xm,fact,s,p1,p2,beta,beta2,gamma,delta;
      54           8 :   PetscBool         breakdown;
      55             : 
      56           8 :   PetscFunctionBegin;
      57           8 :   m   = mfn->ncv;
      58           8 :   tol = mfn->tol;
      59           8 :   mxstep = mfn->max_it;
      60           8 :   mxrej = 10;
      61           8 :   gamma = 0.9;
      62           8 :   delta = 1.2;
      63           8 :   mb    = m;
      64           8 :   PetscCall(FNGetScale(mfn->fn,&t,&sfactor));
      65           8 :   PetscCall(FNDuplicate(mfn->fn,PetscObjectComm((PetscObject)mfn->fn),&fn));
      66           8 :   PetscCall(FNSetScale(fn,1.0,1.0));
      67           8 :   t_out = PetscAbsScalar(t);
      68           8 :   t_now = 0.0;
      69           8 :   PetscCall(MatNorm(mfn->A,NORM_INFINITY,&anorm));
      70           8 :   rndoff = anorm*PETSC_MACHINE_EPSILON;
      71             : 
      72           8 :   k1 = 2;
      73           8 :   xm = 1.0/(PetscReal)m;
      74           8 :   beta = mfn->bnorm;
      75           8 :   fact = PetscPowRealInt((m+1)/2.72,m+1)*PetscSqrtReal(2.0*PETSC_PI*(m+1));
      76           8 :   t_new = (1.0/anorm)*PetscPowReal((fact*tol)/(4.0*beta*anorm),xm);
      77           8 :   s = PetscPowReal(10.0,PetscFloorReal(PetscLog10Real(t_new))-1);
      78           8 :   t_new = PetscCeilReal(t_new/s)*s;
      79           8 :   sgn = t/PetscAbsScalar(t);
      80             : 
      81           8 :   PetscCall(VecCopy(b,x));
      82           8 :   ld = m+2;
      83           8 :   PetscCall(PetscCalloc2(m+1,&betaF,ld*ld,&B));
      84           8 :   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,ld,ld,NULL,&H));
      85           8 :   PetscCall(MatDenseGetArray(H,&Harray));
      86             : 
      87          17 :   while (mfn->reason == MFN_CONVERGED_ITERATING) {
      88           9 :     mfn->its++;
      89           9 :     if (PetscIsInfOrNanReal(t_new)) t_new = PETSC_MAX_REAL;
      90           9 :     t_step = PetscMin(t_out-t_now,t_new);
      91           9 :     PetscCall(BVInsertVec(mfn->V,0,x));
      92           9 :     PetscCall(BVScaleColumn(mfn->V,0,1.0/beta));
      93           9 :     PetscCall(BVMatArnoldi(mfn->V,mfn->transpose_solve?mfn->AT:mfn->A,H,0,&mb,&beta2,&breakdown));
      94           9 :     if (breakdown) {
      95             :       k1 = 0;
      96             :       t_step = t_out-t_now;
      97             :     }
      98           9 :     if (k1!=0) {
      99           9 :       Harray[m+1+ld*m] = 1.0;
     100           9 :       PetscCall(BVGetColumn(mfn->V,m,&v));
     101           9 :       PetscCall(BVGetColumn(mfn->V,m+1,&r));
     102           9 :       PetscCall(MatMult(mfn->transpose_solve?mfn->AT:mfn->A,v,r));
     103           9 :       PetscCall(BVRestoreColumn(mfn->V,m,&v));
     104           9 :       PetscCall(BVRestoreColumn(mfn->V,m+1,&r));
     105           9 :       PetscCall(BVNormColumn(mfn->V,m+1,NORM_2,&avnorm));
     106             :     }
     107           9 :     PetscCall(PetscArraycpy(B,Harray,ld*ld));
     108             : 
     109             :     ireject = 0;
     110           9 :     while (ireject <= mxrej) {
     111           9 :       mx = mb + k1;
     112         273 :       for (i=0;i<mx;i++) {
     113        8088 :         for (j=0;j<mx;j++) {
     114        7824 :           Harray[i+j*ld] = sgn*B[i+j*ld]*t_step;
     115             :         }
     116             :       }
     117           9 :       PetscCall(MFN_CreateDenseMat(mx,&M));
     118           9 :       PetscCall(MFN_CreateDenseMat(mx,&K));
     119           9 :       PetscCall(MatDenseGetArray(M,&F));
     120         273 :       for (j=0;j<mx;j++) PetscCall(PetscArraycpy(F+j*mx,Harray+j*ld,mx));
     121           9 :       PetscCall(MatDenseRestoreArray(M,&F));
     122           9 :       PetscCall(FNEvaluateFunctionMat(fn,M,K));
     123             : 
     124           9 :       if (k1==0) {
     125             :         err_loc = tol;
     126             :         break;
     127             :       } else {
     128           9 :         PetscCall(MatDenseGetArrayRead(K,&pK));
     129           9 :         p1 = PetscAbsScalar(beta*pK[m]);
     130           9 :         p2 = PetscAbsScalar(beta*pK[m+1]*avnorm);
     131           9 :         PetscCall(MatDenseRestoreArrayRead(K,&pK));
     132           9 :         if (p1 > 10*p2) {
     133             :           err_loc = p2;
     134             :           xm = 1.0/(PetscReal)m;
     135           0 :         } else if (p1 > p2) {
     136           0 :           err_loc = (p1*p2)/(p1-p2);
     137           0 :           xm = 1.0/(PetscReal)m;
     138             :         } else {
     139           0 :           err_loc = p1;
     140           0 :           xm = 1.0/(PetscReal)(m-1);
     141             :         }
     142             :       }
     143           9 :       if (err_loc <= delta*t_step*tol) break;
     144             :       else {
     145           0 :         t_step = gamma*t_step*PetscPowReal(t_step*tol/err_loc,xm);
     146           0 :         s = PetscPowReal(10.0,PetscFloorReal(PetscLog10Real(t_step))-1);
     147           0 :         t_step = PetscCeilReal(t_step/s)*s;
     148           0 :         ireject = ireject+1;
     149             :       }
     150             :     }
     151             : 
     152           9 :     mx = mb + PetscMax(0,k1-1);
     153           9 :     PetscCall(MatDenseGetArrayRead(K,&pK));
     154         264 :     for (j=0;j<mx;j++) betaF[j] = beta*pK[j];
     155           9 :     PetscCall(MatDenseRestoreArrayRead(K,&pK));
     156           9 :     PetscCall(BVSetActiveColumns(mfn->V,0,mx));
     157           9 :     PetscCall(BVMultVec(mfn->V,1.0,0.0,x,betaF));
     158           9 :     PetscCall(VecNorm(x,NORM_2,&beta));
     159             : 
     160           9 :     t_now = t_now+t_step;
     161           9 :     if (t_now>=t_out) mfn->reason = MFN_CONVERGED_TOL;
     162             :     else {
     163           1 :       t_new = gamma*t_step*PetscPowReal((t_step*tol)/err_loc,xm);
     164           1 :       s = PetscPowReal(10.0,PetscFloorReal(PetscLog10Real(t_new))-1);
     165           1 :       t_new = PetscCeilReal(t_new/s)*s;
     166             :     }
     167           9 :     err_loc = PetscMax(err_loc,rndoff);
     168           9 :     if (mfn->its==mxstep) mfn->reason = MFN_DIVERGED_ITS;
     169          17 :     PetscCall(MFNMonitor(mfn,mfn->its,err_loc));
     170             :   }
     171           8 :   PetscCall(VecScale(x,sfactor));
     172             : 
     173           8 :   PetscCall(MatDestroy(&M));
     174           8 :   PetscCall(MatDestroy(&K));
     175           8 :   PetscCall(FNDestroy(&fn));
     176           8 :   PetscCall(MatDenseRestoreArray(H,&Harray));
     177           8 :   PetscCall(MatDestroy(&H));
     178           8 :   PetscCall(PetscFree2(betaF,B));
     179           8 :   PetscFunctionReturn(PETSC_SUCCESS);
     180             : }
     181             : 
     182           4 : SLEPC_EXTERN PetscErrorCode MFNCreate_Expokit(MFN mfn)
     183             : {
     184           4 :   PetscFunctionBegin;
     185           4 :   mfn->ops->solve          = MFNSolve_Expokit;
     186           4 :   mfn->ops->setup          = MFNSetUp_Expokit;
     187           4 :   PetscFunctionReturn(PETSC_SUCCESS);
     188             : }

Generated by: LCOV version 1.14