!>
!> @file math_util.f90
!>
!> @brief
!>
!> @copyright
!> Copyright (©) 2021 EPFL (Ecole Polytechnique Fédérale de Lausanne)
!> SPC (Swiss Plasma Center)
!>
!> SPClibs is free software: you can redistribute it and/or modify it under
!> the terms of the GNU Lesser General Public License as published by the Free
!> Software Foundation, either version 3 of the License, or (at your option)
!> any later version.
!>
!> SPClibs is distributed in the hope that it will be useful, but WITHOUT ANY
!> WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
!> FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
!>
!> You should have received a copy of the GNU Lesser General Public License
!> along with this program. If not, see .
!>
!> @authors
!> (in alphabetical order)
!> @author Trach-Minh Tran
!>
MODULE math_util
!
! MATH_UTIL: Some math utilities.
!
! T.M. Tran, CRPP-EPFL
! December 2012
!
!
! Notes:
! - Assume the Fortran 2008 intrinsic BESSEL_JN(n,x) exists!
!
IMPLICIT NONE
DOUBLE PRECISION, PARAMETER :: pi=4.0d0*ATAN(1.0d0)
!
CONTAINS
ELEMENTAL FUNCTION bessjp(n,x)
!
! Derivative of J_n
!
DOUBLE PRECISION :: bessjp
INTEGER, INTENT(in) :: n
DOUBLE PRECISION, INTENT(in) :: x
!
IF(n.EQ.0) THEN
bessjp = -bessel_jn(1,x)
ELSE
bessjp = 0.5d0*(bessel_jn(n-1,x)-bessel_jn(n+1,x))
END IF
END FUNCTION bessjp
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
FUNCTION root_bessj(n, s, info)
!
! s^th root of j_n
!
DOUBLE PRECISION :: root_bessj
INTEGER, INTENT(in) :: n
INTEGER, INTENT(in) :: s
INTEGER, OPTIONAL, INTENT(out) :: info
!
DOUBLE PRECISION :: b0,b1,b2,b3,b5,b7,t0,t1,t3,t5,t7,fn,fk,f1,f2,f3
DOUBLE PRECISION :: c1=1.8557571d0, c2=1.033150d0, c3=.00397d0, c4=.0908d0,&
& c5=.043d0
DOUBLE PRECISION :: zero
INTEGER :: iter
!
fn = REAL(ABS(n),8)
IF(s.EQ.1) THEN ! first zero
IF(n.EQ.0) THEN
zero = c1+c2-c3-c4+c5
ELSE
f1 = fn**(1.d0/3.d0)
f2 = f1*f1*fn
f3 = f1*fn*fn
zero = fn+c1*f1+(c2/f1)-(c3/fn)-(c4/f2)+(c5/f3)
END IF
ELSE ! Other zeros
t0 = 4.d0*fn*fn
t1 = t0-1.d0
t3 = 4.d0*t1*(7.d0*t0-31.d0)
t5 = 32.d0*t1*((83.d0*t0-982.d0)*t0+3779.d0)
t7 = 64.d0*t1*(((6949.d0*t0-153855.d0)*t0+1585743.d0)*t0 &
-6277237.d0)
fk = REAL(s,8)
!
b0 = (fk+.5d0*fn-.25d0)*pi! mac mahon's series for k>>n
b1 = 8.d0*b0
b2 = b1*b1
b3 = 3.d0*b1*b2
b5 = 5.d0*b3*b2
b7 = 7.d0*b5*b2
zero = b0-(t1/b1)-(t3/b3)-(t5/b5)-(t7/b7)
END IF
CALL newton(iter)
IF(PRESENT(info)) info = iter
root_bessj = zero
CONTAINS
SUBROUTINE newton(iter)
INTEGER, INTENT(out) :: iter
INTEGER :: itermx = 20
DOUBLE PRECISION :: dx, tol
tol = EPSILON(1.0d0)*zero
iter = 0
DO
iter = iter+1
dx = -bessel_jn(n,zero)/bessjp(n,zero)
zero = zero+dx
IF(iter.GE.itermx .OR. ABS(dx).LT.tol) EXIT
END DO
END SUBROUTINE newton
END FUNCTION root_bessj
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
FUNCTION root_bessjp(n, s, info)
!
! s^th root of derivative of j_n
!
DOUBLE PRECISION :: root_bessjp
INTEGER, INTENT(in) :: n
INTEGER, INTENT(in) :: s
INTEGER, OPTIONAL, INTENT(out) :: info
!
DOUBLE PRECISION :: c1=0.8086165D0, c2=0.072490D0, c3=.05097D0, c4=.0094D0
DOUBLE PRECISION :: b0,b1,b2,b3,b5,b7,t0,t1,t3,t5,t7,fn,fk,f1,f2
INTEGER :: iter
DOUBLE PRECISION :: zero
!
IF(n.EQ.0 .AND. s.EQ.1) THEN
root_bessjp = 0.0d0
IF(PRESENT(info)) info = 0
RETURN
END IF
!
fn = REAL(ABS(n),8)
fk = REAL(s,8)
!
IF(s.GT.1) THEN
!
! McMahon's series for s >> n
b0 = (fk+.5d0*fn-.75d0)*pi
b1 = 8.d0*b0
b2 = b1*b1
b3 = 3.d0*b1*b2
b5 = 5.d0*b3*b2
b7 = 7.d0*b5*b2
t0 = 4.d0*fn*fn
t1 = t0+3.d0
t3 = 4.d0*((7.d0*t0+82.d0)*t0-9.d0)
t5 = 32.d0*(((83.d0*t0+2075.d0)*t0-3039.d0)*t0+3537.d0)
t7 = 64.d0*((((6949.d0*t0+296492.d0)*t0-1248002.d0)*t0 &
+7414380.d0)*t0-5853627.d0)
zero = b0-(t1/b1)-(t3/b3)-(t5/b5)-(t7/b7)
ELSE
!
! Tchebychev's series for s <= n
f1 = fn**(1.d0/3.d0)
f2 = f1*f1*fn
zero = fn+c1*f1+(c2/f1)-(c3/fn)+(c4/f2)
END IF
!
CALL newton(iter)
root_bessjp = zero
IF(PRESENT(info)) info = iter
CONTAINS
SUBROUTINE newton(iter)
INTEGER, INTENT(out) :: iter
INTEGER :: itermx = 20
DOUBLE PRECISION :: dx, tol
tol = EPSILON(1.0d0)*zero
iter = 0
DO
iter = iter+1
dx = -bessel_jn(n,zero)/bessjp(n,zero)
dx = -2.0d0 * (bessel_jn(n-1,zero)-bessel_jn(n+1,zero)) / &
& (bessel_jn(n-2,zero)-2.d0*bessel_jn(n,zero)+&
& bessel_jn(n+2,zero))
zero = zero+dx
IF(iter.GE.itermx .OR. ABS(dx).LT.tol) EXIT
END DO
END SUBROUTINE newton
END FUNCTION root_bessjp
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
!!$ PURE FUNCTION BESSEL_JN(n,x) RESULT(bessj)
!!$ DOUBLE PRECISION, INTENT(in) :: x
!!$ DOUBLE PRECISION :: bessj
!!$ DOUBLE PRECISION BIGNO,BIGNI
!!$ INTEGER n,IACC
!!$ PARAMETER (IACC=40,BIGNO=1.d10,BIGNI=1.d-10)
!!$ INTEGER j,jsum,m
!!$ DOUBLE PRECISION ax,bj,bjm,bjp,sum,tox,bessj0,bessj1
!!$ IF( n.EQ.0 ) THEN
!!$ bessj = bessj0(x)
!!$ RETURN
!!$ ELSE IF( n.EQ.1 ) THEN
!!$ bessj = bessj1(x)
!!$ RETURN
!!$ ENDIF
!!$ ax=ABS(x)
!!$ IF(ax.EQ.0.d0)THEN
!!$ bessj=0.d0
!!$ ELSE IF(ax.GT.float(n))THEN
!!$ tox=2./ax
!!$ bjm=bessj0(ax)
!!$ bj=bessj1(ax)
!!$ DO j=1,n-1
!!$ bjp=j*tox*bj-bjm
!!$ bjm=bj
!!$ bj=bjp
!!$ END DO
!!$ bessj=bj
!!$ ELSE
!!$ tox=2./ax
!!$ m=2*((n+INT(SQRT(float(IACC*n))))/2)
!!$ bessj=0.d0
!!$ jsum=0
!!$ sum=0.d0
!!$ bjp=0.d0
!!$ bj=1.
!!$ DO j=m,1,-1
!!$ bjm=j*tox*bj-bjp
!!$ bjp=bj
!!$ bj=bjm
!!$ IF(ABS(bj).GT.BIGNO)THEN
!!$ bj=bj*BIGNI
!!$ bjp=bjp*BIGNI
!!$ bessj=bessj*BIGNI
!!$ sum=sum*BIGNI
!!$ ENDIF
!!$ IF(jsum.NE.0)sum=sum+bj
!!$ jsum=1-jsum
!!$ IF(j.EQ.n)bessj=bjp
!!$ END DO
!!$ sum=2.*sum-bj
!!$ bessj=bessj/sum
!!$ ENDIF
!!$ IF(x.LT.0.d0.AND.MOD(n,2).EQ.1)bessj=-bessj
!!$ RETURN
!!$ END FUNCTION bessel_jn
!!$
!!$ PURE FUNCTION bessj0(x)
!!$ DOUBLE PRECISION, INTENT(in) :: x
!!$ DOUBLE PRECISION bessj0
!!$ DOUBLE PRECISION ax,xx,z
!!$ DOUBLE PRECISION p1,p2,p3,p4,p5,q1,q2,q3,q4,q5,r1,r2,r3,r4,r5,r6,s1,s2,s3,s4,s5,s6,y
!!$ SAVE p1,p2,p3,p4,p5,q1,q2,q3,q4,q5,r1,r2,r3,r4,r5,r6,s1,s2,s3,s4,s5,s6
!!$ DATA p1,p2,p3,p4,p5/1.d0,-.1098628627d-2,.2734510407d-4,-.2073370639d-5,.2093887211d-6/
!!$ DATA q1,q2,q3,q4,q5/-.1562499995d-1,.1430488765d-3,-.6911147651d-5,.7621095161d-6,-.934945152d-7/
!!$ DATA r1,r2,r3,r4,r5,r6/57568490574.d0,-13362590354.d0,651619640.7d0,-11214424.18d0,&
!!$ & 77392.33017d0,-184.9052456d0/
!!$ DATA s1,s2,s3,s4,s5,s6/57568490411.d0,1029532985.d0,9494680.718d0,59272.64853d0,267.8532712d0,1.d0/
!!$ IF(ABS(x).LT.8.)THEN
!!$ y=x**2
!!$ bessj0=(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))))/(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))
!!$ ELSE
!!$ ax=ABS(x)
!!$ z=8./ax
!!$ y=z**2
!!$ xx=ax-.785398164
!!$ bessj0=SQRT(.636619772/ax)*(COS(xx)*(p1+y*(p2+y*(p3+y*(p4+y*p5))))-z*SIN(xx)*(q1+y*(q2+y*(q3+y*(q4+y*q5)))))
!!$ ENDIF
!!$ RETURN
!!$ END FUNCTION bessj0
!!$
!!$ PURE FUNCTION bessj1(x)
!!$ DOUBLE PRECISION, INTENT(in) :: x
!!$ DOUBLE PRECISION bessj1
!!$ DOUBLE PRECISION ax,xx,z
!!$ DOUBLE PRECISION p1,p2,p3,p4,p5,q1,q2,q3,q4,q5,r1,r2,r3,r4,r5,r6,s1,s2,s3,s4,s5,s6,y
!!$ SAVE p1,p2,p3,p4,p5,q1,q2,q3,q4,q5,r1,r2,r3,r4,r5,r6,s1,s2,s3,s4,s5,s6
!!$ DATA r1,r2,r3,r4,r5,r6/72362614232.d0,-7895059235.d0,242396853.1d0,-2972611.439d0,15704.48260d0,-30.16036606d0/
!!$ DATA s1,s2,s3,s4,s5,s6/144725228442.d0,2300535178.d0,18583304.74d0,99447.43394d0,376.9991397d0,1.d0/
!!$ DATA p1,p2,p3,p4,p5/1.d0,.183105d-2,-.3516396496d-4,.2457520174d-5,-.240337019d-6/
!!$ DATA q1,q2,q3,q4,q5/.04687499995d0,-.2002690873d-3,.8449199096d-5,-.88228987d-6,.105787412d-6/
!!$ IF(ABS(x).LT.8.)THEN
!!$ y=x**2
!!$ bessj1=x*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))))/(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))
!!$ ELSE
!!$ ax=ABS(x)
!!$ z=8.d0/ax
!!$ y=z**2
!!$ xx=ax-2.356194491d0
!!$ bessj1=SQRT(.636619772d0/ax)*(COS(xx)*(p1+y*(p2+y*(p3+y*(p4+y*p5))))- &
!!$ & z*SIN(xx)*(q1+y*(q2+y*(q3+y*(q4+y*q5)))))*SIGN(1.d0,x)
!!$ ENDIF
!!$ RETURN
!!$ END FUNCTION bessj1
END MODULE math_util