mpmath_riccati_bessel.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. #!/usr/bin/env python3
  2. import mpmath as mp
  3. # APPLIED OPTICS / Vol. 53, No. 31 / 1 November 2014, eq(13)
  4. def LeRu_cutoff(z):
  5. x = mp.fabs(z)
  6. return int(x + 11 * x**(1/3) + 1)
  7. # Wu, Wang, Radio Science, Volume 26, Number 6, Pages 1393-1401, November-December 1991,
  8. # after eq 13f.
  9. # Riccati-Bessel z*j_n(z)
  10. def psi(n, z):
  11. return mp.sqrt((mp.pi * z)/2) * mp.autoprec(mp.besselj)(n+1/2, z)
  12. # Riccati-Bessel -z*y_n(z)
  13. def xi(n, z):
  14. return -mp.sqrt((mp.pi * z)/2) * mp.autoprec(mp.bessely)(n+1/2, z)
  15. # Riccati-Bessel psi - i* xi
  16. def ksi(n, z):
  17. return psi(n, z) - 1.j * xi(n, z)
  18. def psi_div_ksi(n, z):
  19. return psi(n, z)/ksi(n, z)
  20. def psi_mul_ksi(n, z):
  21. return psi(n, z)*ksi(n, z)
  22. def psi_div_xi(n, z):
  23. return psi(n, z)/xi(n, z)
  24. # to compare r(n,z) with Wolfram Alpha
  25. # n=49, z=1.3-2.1i, SphericalBesselJ[n-1,z]/SphericalBesselJ[n,z]
  26. def r(n, z):
  27. if n > 0:
  28. return psi(n-1, z)/psi(n, z)
  29. return mp.cos(z)/mp.sin(z)
  30. def D(n, z, f):
  31. return f(n-1, z)/f(n, z) - n/z
  32. def D1(n, z):
  33. if n == 0:
  34. return mp.cos(z)/mp.sin(z)
  35. return D(n, z, psi)
  36. # Wolfram Alpha example D2(10, 10-10j): SphericalBesselY[9, 10-10i]/SphericalBesselY[10,10-10i]-10/(10-10i)
  37. def D2(n, z):
  38. if n == 0:
  39. return -mp.sin(z)/mp.cos(z)
  40. return D(n, z, xi)
  41. def D3(n, z):
  42. if n == 0:
  43. return 1j
  44. return D(n, z, ksi)
  45. # bulk sphere
  46. # Le Ru
  47. def an_lr(n, x, m):
  48. print(f'D1(x) = {D1(n, x)}\n\
  49. D1(mx) = {D1(n, m*x)}\n\
  50. D3(x) = {D3(n, x)}\n\
  51. psi_n = {psi(n,x)}\n\
  52. ksi_n = {ksi(n,x)}\n\
  53. ')
  54. return (
  55. (
  56. psi(n, x)*(m*D1(n, x)-D1(n, m*x))
  57. ) /
  58. (
  59. ksi(n, x)*(m * D3(n, x)-D1(n, m*x))
  60. )
  61. )
  62. # Ovidio
  63. def an(n, x, m):
  64. # print(f'D1 = {D1(n, m*x)}\n\
  65. # psi_n = {psi(n,x)}\n\
  66. # psi_nm1 = {psi(n-1,x)}\n\
  67. # ksi_n = {ksi(n,x)}\n\
  68. # ksi_nm1 = {ksi(n-1,x)}\n\
  69. # ')
  70. return (
  71. ((D1(n, m*x)/m + n/x)*psi(n, x) - psi(n-1, x)) /
  72. ((D1(n, m*x)/m + n/x)*ksi(n, x) - ksi(n-1, x))
  73. )
  74. def bn(n, x, m):
  75. # print(f'D1 = {D1(n, m*x)}\n\
  76. # psi_n = {psi(n,x)}\n\
  77. # psi_nm1 = {psi(n-1,x)}\n\
  78. # ksi_n = {ksi(n,x)}\n\
  79. # ksi_nm1 = {ksi(n-1,x)}\n\
  80. # ')
  81. return (
  82. ((D1(n, m*x)*m + n/x) * psi(n, x) - psi(n-1, x)) /
  83. ((D1(n, m*x)*m + n/x) * ksi(n, x) - ksi(n-1, x))
  84. )
  85. # # Du
  86. # def an(n, x, m):
  87. # mx = m*x
  88. # return (
  89. # ((r(n,mx)/m + n*(1-1/m**2)/x)*psi(n,x)-psi(n-1,x))/
  90. # ((r(n,mx)/m + n*(1-1/m**2)/x)*ksi(n,x)-ksi(n-1,x))
  91. # )
  92. # def bn(n,x,m):
  93. # mx = m*x
  94. # return (
  95. # (r(n,mx)*m*psi(n,x)-psi(n-1,x))/
  96. # (r(n,mx)*m*ksi(n,x)-ksi(n-1,x))
  97. # )
  98. def Qext_diff(n, x, m):
  99. return ((2*n + 1)*2/x**2) * (an(n, x, m) + bn(n, x, m)).real
  100. def Qsca_diff(n, x, m):
  101. return ((2*n + 1)*2/x**2) * (abs(an(n, x, m))**2 + abs(bn(n, x, m))**2)
  102. def Qany(x, m, nmax, output_dps, Qdiff):
  103. Qany = 0
  104. Qlist = []
  105. Qprev = ""
  106. convergence_max_length = 35
  107. i = 0
  108. for n in range(1, nmax+1):
  109. diff = Qdiff(n, x, m)
  110. Qany += diff
  111. Qnext = mp.nstr(Qany, output_dps)
  112. Qlist.append(Qany)
  113. i += 1
  114. if Qprev != Qnext:
  115. i = 0
  116. Qprev = Qnext
  117. print(n, ' ', end='', flush=True)
  118. if i >= convergence_max_length:
  119. break
  120. print('')
  121. Qlist.append(Qany)
  122. return Qlist
  123. def Qsca(x, m, nmax, output_dps):
  124. return Qany(x, m, nmax, output_dps, Qsca_diff)
  125. def Qext(x, m, nmax, output_dps):
  126. return Qany(x, m, nmax, output_dps, Qext_diff)