LCOV - code coverage report
Current view: top level - src/common - bessel_lib.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:1f285aa) Lines: 40 61 65.6 %
Date: 2024-04-23 06:49:27 Functions: 3 5 60.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Calculates Bessel functions
      10             : !> \note
      11             : !>      Functions adapted from netlib
      12             : !> \par History
      13             : !>      March-2006: Bessel Transform (JGH)
      14             : !> \author JGH (10-02-2001)
      15             : ! **************************************************************************************************
      16             : MODULE bessel_lib
      17             : 
      18             :    USE kinds,                           ONLY: dp
      19             :    USE mathconstants,                   ONLY: fac,&
      20             :                                               pi
      21             : #include "../base/base_uses.f90"
      22             : 
      23             :    IMPLICIT NONE
      24             : 
      25             :    PRIVATE
      26             :    PUBLIC :: bessk0, bessk1, bessel0
      27             : 
      28             : CONTAINS
      29             : 
      30             : ! **************************************************************************************************
      31             : !> \brief ...
      32             : !> \param x must be positive
      33             : !> \return ...
      34             : ! **************************************************************************************************
      35      187200 :    ELEMENTAL FUNCTION bessk0(x)
      36             : 
      37             :       REAL(KIND=dp), INTENT(IN)                          :: x
      38             :       REAL(KIND=dp)                                      :: bessk0
      39             : 
      40             :       REAL(KIND=dp), PARAMETER :: p1 = -0.57721566_dp, p2 = 0.42278420_dp, p3 = 0.23069756_dp, &
      41             :          p4 = 0.3488590e-1_dp, p5 = 0.262698e-2_dp, p6 = 0.10750e-3_dp, p7 = 0.74e-5_dp, &
      42             :          q1 = 1.25331414_dp, q2 = -0.7832358e-1_dp, q3 = 0.2189568e-1_dp, q4 = -0.1062446e-1_dp, &
      43             :          q5 = 0.587872e-2_dp, q6 = -0.251540e-2_dp, q7 = 0.53208e-3_dp
      44             : 
      45             :       REAL(KIND=dp)                                      :: y
      46             : 
      47      187200 :       IF (x < 2.0_dp) THEN
      48           0 :          y = x*x/4.0_dp
      49             :          bessk0 = (-LOG(x/2.0_dp)*bessi0(x)) + (p1 + y* &
      50           0 :                                                 (p2 + y*(p3 + y*(p4 + y*(p5 + y*(p6 + y*p7))))))
      51             :       ELSE
      52      187200 :          y = (2.0_dp/x)
      53             :          bessk0 = (EXP(-x)/SQRT(x))*(q1 + y*(q2 + y* &
      54      187200 :                                              (q3 + y*(q4 + y*(q5 + y*(q6 + y*q7))))))
      55             :       END IF
      56             : 
      57      187200 :    END FUNCTION bessk0
      58             : 
      59             : ! **************************************************************************************************
      60             : !> \brief ...
      61             : !> \param x must be positive
      62             : !> \return ...
      63             : ! **************************************************************************************************
      64      187200 :    ELEMENTAL FUNCTION bessk1(x)
      65             : 
      66             :       REAL(KIND=dp), INTENT(IN)                          :: x
      67             :       REAL(KIND=dp)                                      :: bessk1
      68             : 
      69             :       REAL(KIND=dp), PARAMETER :: p1 = 1.0_dp, p2 = 0.15443144_dp, p3 = -0.67278579_dp, &
      70             :          p4 = -0.18156897_dp, p5 = -0.1919402e-1_dp, p6 = -0.110404e-2_dp, p7 = -0.4686e-4_dp, &
      71             :          q1 = 1.25331414_dp, q2 = 0.23498619_dp, q3 = -0.3655620e-1_dp, q4 = 0.1504268e-1_dp, &
      72             :          q5 = -0.780353e-2_dp, q6 = 0.325614e-2_dp, q7 = -0.68245e-3_dp
      73             : 
      74             :       REAL(KIND=dp)                                      :: y
      75             : 
      76      187200 :       IF (x < 2.0_dp) THEN
      77           0 :          y = x*x/4.0_dp
      78             :          bessk1 = (LOG(x/2.0_dp)*bessi1(x)) + (1.0_dp/x)* &
      79             :                   (p1 + y*(p2 + y*(p3 + y*(p4 + y*(p5 + y* &
      80           0 :                                                    (p6 + y*p7))))))
      81             :       ELSE
      82      187200 :          y = 2.0_dp/x
      83             :          bessk1 = (EXP(-x)/SQRT(x))*(q1 + y*(q2 + y* &
      84      187200 :                                              (q3 + y*(q4 + y*(q5 + y*(q6 + y*q7))))))
      85             :       END IF
      86             : 
      87      187200 :    END FUNCTION bessk1
      88             : 
      89             : ! **************************************************************************************************
      90             : !> \brief ...
      91             : !> \param x ...
      92             : !> \return ...
      93             : ! **************************************************************************************************
      94           0 :    ELEMENTAL FUNCTION bessi0(x)
      95             : 
      96             :       REAL(KIND=dp), INTENT(IN)                          :: x
      97             :       REAL(KIND=dp)                                      :: bessi0
      98             : 
      99             :       REAL(KIND=dp), PARAMETER :: p1 = 1.0_dp, p2 = 3.5156229_dp, p3 = 3.0899424_dp, &
     100             :          p4 = 1.2067492_dp, p5 = 0.2659732_dp, p6 = 0.360768e-1_dp, p7 = 0.45813e-2_dp, &
     101             :          q1 = 0.39894228_dp, q2 = 0.1328592e-1_dp, q3 = 0.225319e-2_dp, q4 = -0.157565e-2_dp, &
     102             :          q5 = 0.916281e-2_dp, q6 = -0.2057706e-1_dp, q7 = 0.2635537e-1_dp, q8 = -0.1647633e-1_dp, &
     103             :          q9 = 0.392377e-2_dp
     104             : 
     105             :       REAL(KIND=dp)                                      :: ax, y
     106             : 
     107           0 :       IF (ABS(x) < 3.75_dp) THEN
     108           0 :          y = (x/3.75_dp)**2
     109             :          bessi0 = p1 + y*(p2 + y*(p3 + y*(p4 + y* &
     110           0 :                                           (p5 + y*(p6 + y*p7)))))
     111             :       ELSE
     112           0 :          ax = ABS(x)
     113           0 :          y = 3.75_dp/ax
     114             :          bessi0 = (EXP(ax)/SQRT(ax))*(q1 + y*(q2 + y* &
     115             :                                               (q3 + y*(q4 + y*(q5 + y*(q6 + y*(q7 + y* &
     116           0 :                                                                                (q8 + y*q9))))))))
     117             :       END IF
     118             : 
     119           0 :    END FUNCTION bessi0
     120             : 
     121             : ! **************************************************************************************************
     122             : !> \brief ...
     123             : !> \param x ...
     124             : !> \return ...
     125             : ! **************************************************************************************************
     126           0 :    ELEMENTAL FUNCTION bessi1(x)
     127             : 
     128             :       REAL(KIND=dp), INTENT(IN)                          :: x
     129             :       REAL(KIND=dp)                                      :: bessi1
     130             : 
     131             :       REAL(KIND=dp), PARAMETER :: p1 = 0.5_dp, p2 = 0.87890594_dp, p3 = 0.51498869_dp, &
     132             :          p4 = 0.15084934e0_dp, p5 = 0.2658733e-1_dp, p6 = 0.301532e-2_dp, p7 = 0.32411e-3_dp, &
     133             :          q1 = 0.39894228_dp, q2 = -0.3988024e-1_dp, q3 = -0.362018e-2_dp, q4 = 0.163801e-2_dp, &
     134             :          q5 = -0.1031555e-1_dp, q6 = 0.2282967e-1_dp, q7 = -0.2895312e-1_dp, q8 = 0.1787654e-1_dp, &
     135             :          q9 = -0.420059e-2_dp
     136             : 
     137             :       REAL(KIND=dp)                                      :: ax, y
     138             : 
     139           0 :       IF (ABS(x) < 3.75_dp) THEN
     140           0 :          y = (x/3.75_dp)**2
     141             :          bessi1 = p1 + y*(p2 + y*(p3 + y*(p4 + y* &
     142           0 :                                           (p5 + y*(p6 + y*p7)))))
     143             :       ELSE
     144           0 :          ax = ABS(x)
     145           0 :          y = 3.75_dp/ax
     146             :          bessi1 = (EXP(ax)/SQRT(ax))*(q1 + y*(q2 + y* &
     147             :                                               (q3 + y*(q4 + y*(q5 + y*(q6 + y*(q7 + y* &
     148           0 :                                                                                (q8 + y*q9))))))))
     149           0 :          IF (x < 0.0_dp) bessi1 = -bessi1
     150             :       END IF
     151             : 
     152           0 :    END FUNCTION bessi1
     153             : 
     154             : ! **************************************************************************************************
     155             : !> \brief ...
     156             : !> \param x ...
     157             : !> \param l ...
     158             : !> \return ...
     159             : ! **************************************************************************************************
     160      801600 :    ELEMENTAL IMPURE FUNCTION bessel0(x, l)
     161             :       !
     162             :       ! Calculates spherical Bessel functions
     163             :       ! Abramowitz & Stegun using Formulas 10.1.2, 10.1.8, 10.1.9
     164             :       ! Adapted from P. Bloechl
     165             :       !
     166             :       REAL(KIND=dp), INTENT(IN)                          :: x
     167             :       INTEGER, INTENT(IN)                                :: l
     168             :       REAL(KIND=dp)                                      :: bessel0
     169             : 
     170             :       REAL(KIND=dp), PARAMETER                           :: tol = 1.e-12_dp
     171             : 
     172             :       INTEGER                                            :: i, ii, il, isvar, k
     173             :       REAL(KIND=dp)                                      :: arg, fact, xsq
     174             :       REAL(KIND=dp), DIMENSION(4)                        :: trig
     175             : 
     176      801600 :       IF (x > SQRT(REAL(l, KIND=dp) + 0.5_dp)) THEN
     177      390913 :          arg = x - 0.5_dp*REAL(l, KIND=dp)*pi
     178      390913 :          trig(1) = SIN(arg)/x
     179      390913 :          trig(2) = COS(arg)/x
     180      390913 :          trig(3) = -trig(1)
     181      390913 :          trig(4) = -trig(2)
     182      390913 :          bessel0 = trig(1)
     183      390913 :          IF (l /= 0) THEN
     184      283552 :             xsq = 0.5_dp/x
     185      283552 :             fact = 1._dp
     186      843252 :             DO k = 1, l
     187      559700 :                ii = MOD(k, 4) + 1
     188      559700 :                fact = fac(k + l)/fac(k)/fac(l - k)*xsq**k
     189      843252 :                bessel0 = bessel0 + fact*trig(ii)
     190             :             END DO
     191             :          END IF
     192             :       ELSE
     193             :          ! Taylor expansion for small arguments
     194             :          isvar = 1
     195     1053387 :          DO il = 1, l
     196     1053387 :             isvar = isvar*(2*il + 1)
     197             :          END DO
     198      410687 :          IF (l /= 0._dp) THEN
     199      317648 :             fact = x**l/REAL(isvar, KIND=dp)
     200             :          ELSE
     201       93039 :             fact = 1._dp/REAL(isvar, KIND=dp)
     202             :          END IF
     203      410687 :          bessel0 = fact
     204      410687 :          xsq = -0.5_dp*x*x
     205      410687 :          isvar = 2*l + 1
     206     1193216 :          DO i = 1, 1000
     207     1193216 :             isvar = isvar + 2
     208     1193216 :             fact = fact*xsq/REAL(i*isvar, KIND=dp)
     209     1193216 :             bessel0 = bessel0 + fact
     210     1193216 :             IF (ABS(fact) < tol) EXIT
     211             :          END DO
     212      410687 :          IF (ABS(fact) > tol) CPABORT("BESSEL0 NOT CONVERGED")
     213             :       END IF
     214             : 
     215      801600 :    END FUNCTION bessel0
     216             : 
     217             : END MODULE bessel_lib
     218             : 

Generated by: LCOV version 1.15