LCOV - code coverage report
Current view: top level - mfn/impls/krylov - mfnkrylov.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 70 70 100.0 %
Date: 2024-12-04 00:44:48 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: "krylov"
      12             : 
      13             :    Method: Arnoldi with Eiermann-Ernst restart
      14             : 
      15             :    Algorithm:
      16             : 
      17             :        Build Arnoldi approximations using f(H) for the Hessenberg matrix H,
      18             :        restart by discarding the Krylov basis but keeping H.
      19             : 
      20             :    References:
      21             : 
      22             :        [1] M. Eiermann and O. Ernst, "A restarted Krylov subspace method
      23             :            for the evaluation of matrix functions", SIAM J. Numer. Anal.
      24             :            44(6):2481-2504, 2006.
      25             : */
      26             : 
      27             : #include <slepc/private/mfnimpl.h>
      28             : #include <slepcblaslapack.h>
      29             : 
      30          14 : static PetscErrorCode MFNSetUp_Krylov(MFN mfn)
      31             : {
      32          14 :   PetscInt       N;
      33             : 
      34          14 :   PetscFunctionBegin;
      35          14 :   PetscCall(MatGetSize(mfn->A,&N,NULL));
      36          14 :   if (mfn->ncv==PETSC_DETERMINE) mfn->ncv = PetscMin(30,N);
      37          14 :   if (mfn->max_it==PETSC_DETERMINE) mfn->max_it = 100;
      38          14 :   PetscCall(MFNAllocateSolution(mfn,1));
      39          14 :   PetscFunctionReturn(PETSC_SUCCESS);
      40             : }
      41             : 
      42          95 : static PetscErrorCode MFNSolve_Krylov(MFN mfn,Vec b,Vec x)
      43             : {
      44          95 :   PetscInt          n=0,m,ld,ldh,j;
      45          95 :   PetscBLASInt      m_,inc=1;
      46          95 :   Mat               M,G=NULL,H=NULL;
      47          95 :   Vec               F=NULL;
      48          95 :   PetscScalar       *marray,*farray,*harray;
      49          95 :   const PetscScalar *garray;
      50          95 :   PetscReal         beta,betaold=0.0,nrm=1.0;
      51          95 :   PetscBool         breakdown;
      52             : 
      53          95 :   PetscFunctionBegin;
      54          95 :   m  = mfn->ncv;
      55          95 :   ld = m+1;
      56          95 :   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,ld,m,NULL,&M));
      57          95 :   PetscCall(MatDenseGetArray(M,&marray));
      58             : 
      59             :   /* set initial vector to b/||b|| */
      60          95 :   PetscCall(BVInsertVec(mfn->V,0,b));
      61          95 :   PetscCall(BVScaleColumn(mfn->V,0,1.0/mfn->bnorm));
      62          95 :   PetscCall(VecSet(x,0.0));
      63             : 
      64             :   /* Restart loop */
      65         320 :   while (mfn->reason == MFN_CONVERGED_ITERATING) {
      66         225 :     mfn->its++;
      67             : 
      68             :     /* compute Arnoldi factorization */
      69         225 :     PetscCall(BVMatArnoldi(mfn->V,mfn->transpose_solve?mfn->AT:mfn->A,M,0,&m,&beta,&breakdown));
      70             : 
      71             :     /* save previous Hessenberg matrix in G; allocate new storage for H and f(H) */
      72         225 :     if (mfn->its>1) { G = H; H = NULL; }
      73         225 :     ldh = n+m;
      74         225 :     PetscCall(MFN_CreateVec(ldh,&F));
      75         225 :     PetscCall(MFN_CreateDenseMat(ldh,&H));
      76             : 
      77             :     /* glue together the previous H and the new H obtained with Arnoldi */
      78         225 :     PetscCall(MatDenseGetArray(H,&harray));
      79        5087 :     for (j=0;j<m;j++) PetscCall(PetscArraycpy(harray+n+(j+n)*ldh,marray+j*ld,m));
      80         225 :     if (mfn->its>1) {
      81         130 :       PetscCall(MatDenseGetArrayRead(G,&garray));
      82        4388 :       for (j=0;j<n;j++) PetscCall(PetscArraycpy(harray+j*ldh,garray+j*n,n));
      83         130 :       PetscCall(MatDenseRestoreArrayRead(G,&garray));
      84         130 :       PetscCall(MatDestroy(&G));
      85         130 :       harray[n+(n-1)*ldh] = betaold;
      86             :     }
      87         225 :     PetscCall(MatDenseRestoreArray(H,&harray));
      88             : 
      89         225 :     if (mfn->its==1) {
      90             :       /* set symmetry flag of H from A */
      91          95 :       PetscCall(MatPropagateSymmetryOptions(mfn->A,H));
      92             :     }
      93             : 
      94             :     /* evaluate f(H) */
      95         225 :     PetscCall(FNEvaluateFunctionMatVec(mfn->fn,H,F));
      96             : 
      97             :     /* x += ||b||*V*f(H)*e_1 */
      98         225 :     PetscCall(VecGetArray(F,&farray));
      99         225 :     PetscCall(PetscBLASIntCast(m,&m_));
     100         225 :     nrm = BLASnrm2_(&m_,farray+n,&inc);   /* relative norm of the update ||u||/||b|| */
     101         225 :     PetscCall(MFNMonitor(mfn,mfn->its,nrm));
     102        5087 :     for (j=0;j<m;j++) farray[j+n] *= mfn->bnorm;
     103         225 :     PetscCall(BVSetActiveColumns(mfn->V,0,m));
     104         225 :     PetscCall(BVMultVec(mfn->V,1.0,1.0,x,farray+n));
     105         225 :     PetscCall(VecRestoreArray(F,&farray));
     106             : 
     107             :     /* check convergence */
     108         225 :     if (mfn->its >= mfn->max_it) mfn->reason = MFN_DIVERGED_ITS;
     109         225 :     if (mfn->its>1) {
     110         130 :       if (m<mfn->ncv || breakdown || beta==0.0 || nrm<mfn->tol) mfn->reason = MFN_CONVERGED_TOL;
     111             :     }
     112             : 
     113             :     /* restart with vector v_{m+1} */
     114         225 :     if (mfn->reason == MFN_CONVERGED_ITERATING) {
     115         130 :       PetscCall(BVCopyColumn(mfn->V,m,0));
     116         130 :       n += m;
     117         130 :       betaold = beta;
     118             :     }
     119             :   }
     120             : 
     121          95 :   PetscCall(MatDestroy(&H));
     122          95 :   PetscCall(MatDestroy(&G));
     123          95 :   PetscCall(VecDestroy(&F));
     124          95 :   PetscCall(MatDenseRestoreArray(M,&marray));
     125          95 :   PetscCall(MatDestroy(&M));
     126          95 :   PetscFunctionReturn(PETSC_SUCCESS);
     127             : }
     128             : 
     129          14 : SLEPC_EXTERN PetscErrorCode MFNCreate_Krylov(MFN mfn)
     130             : {
     131          14 :   PetscFunctionBegin;
     132          14 :   mfn->ops->solve          = MFNSolve_Krylov;
     133          14 :   mfn->ops->setup          = MFNSetUp_Krylov;
     134          14 :   PetscFunctionReturn(PETSC_SUCCESS);
     135             : }

Generated by: LCOV version 1.14