bessel.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. //**********************************************************************************//
  2. // Copyright (C) 2009-2015 Ovidio Pena <ovidio@bytesfall.com> //
  3. // Copyright (C) 2013-2015 Konstantin Ladutenko <kostyfisik@gmail.com> //
  4. // //
  5. // This file is part of scattnlay //
  6. // //
  7. // This program is free software: you can redistribute it and/or modify //
  8. // it under the terms of the GNU General Public License as published by //
  9. // the Free Software Foundation, either version 3 of the License, or //
  10. // (at your option) any later version. //
  11. // //
  12. // This program is distributed in the hope that it will be useful, //
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of //
  14. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
  15. // GNU General Public License for more details. //
  16. // //
  17. // The only additional remark is that we expect that all publications //
  18. // describing work using this software, or all commercial products //
  19. // using it, cite the following reference: //
  20. // [1] O. Pena and U. Pal, "Scattering of electromagnetic radiation by //
  21. // a multilayered sphere," Computer Physics Communications, //
  22. // vol. 180, Nov. 2009, pp. 2348-2354. //
  23. // //
  24. // You should have received a copy of the GNU General Public License //
  25. // along with this program. If not, see <http://www.gnu.org/licenses/>. //
  26. //**********************************************************************************//
  27. #include "bessel.h"
  28. #include <algorithm>
  29. #include <complex>
  30. #include <cmath>
  31. #include <limits>
  32. #include <stdexcept>
  33. #include <vector>
  34. namespace nmie {
  35. namespace bessel {
  36. void calcZeta(int n, std::complex<double>z, std::vector< std::complex<double> > &Zeta,
  37. std::vector< std::complex<double> > &dZeta) {
  38. std::vector< std::complex<double> > csj, cdj, csy, cdy;
  39. int nm;
  40. csphjy (n, z, nm, csj, cdj, csy, cdy );
  41. Zeta.resize(n+1);
  42. dZeta.resize(n+1);
  43. auto c_i = std::complex<double>(0.0,1.0);
  44. for (int i = 0; i < n+1; ++i) {
  45. Zeta[i]=z*(csj[i] + c_i*csy[i]);
  46. dZeta[i]=z*(cdj[i] + c_i*cdy[i])+csj[i] + c_i*csy[i];
  47. }
  48. } // end of calcZeta()
  49. void calcPsi(int n, std::complex<double>z, std::vector< std::complex<double> > &Psi,
  50. std::vector< std::complex<double> > &dPsi) {
  51. std::vector< std::complex<double> > csj, cdj, csy, cdy;
  52. int nm;
  53. csphjy (n, z, nm, csj, cdj, csy, cdy );
  54. Psi.resize(n+1);
  55. dPsi.resize(n+1);
  56. for (int i = 0; i < n+1; ++i) {
  57. Psi[i]=z*(csj[i]);
  58. dPsi[i]=z*(cdj[i])+csj[i];
  59. }
  60. } // end of calcPsi()
  61. // !*****************************************************************************80
  62. //
  63. // C++ port of fortran code
  64. //
  65. // !! CSPHJY: spherical Bessel functions jn(z) and yn(z) for complex argument.
  66. // !
  67. // ! Discussion:
  68. // !
  69. // ! This procedure computes spherical Bessel functions jn(z) and yn(z)
  70. // ! and their derivatives for a complex argument.
  71. // !
  72. // ! Licensing:
  73. // !
  74. // ! This routine is copyrighted by Shanjie Zhang and Jianming Jin. However,
  75. // ! they give permission to incorporate this routine into a user program
  76. // ! provided that the copyright is acknowledged.
  77. // !
  78. // ! Modified:
  79. // !
  80. // ! 01 August 2012
  81. // !
  82. // ! Author:
  83. // !
  84. // ! Shanjie Zhang, Jianming Jin
  85. // !
  86. // ! Reference:
  87. // !
  88. // ! Shanjie Zhang, Jianming Jin,
  89. // ! Computation of Special Functions,
  90. // ! Wiley, 1996,
  91. // ! ISBN: 0-471-11963-6,
  92. // ! LC: QA351.C45.
  93. // !
  94. // ! Parameters:
  95. // !
  96. // ! Input, integer ( kind = 4 ) N, the order of jn(z) and yn(z).
  97. // !
  98. // ! Input, complex ( kind = 8 ) Z, the argument.
  99. // !
  100. // ! Output, integer ( kind = 4 ) NM, the highest order computed.
  101. // !
  102. // ! Output, complex ( kind = 8 ) CSJ(0:N0, CDJ(0:N), CSY(0:N), CDY(0:N),
  103. // ! the values of jn(z), jn'(z), yn(z), yn'(z).
  104. // !
  105. void csphjy (int n, std::complex<double>z, int &nm,
  106. std::vector< std::complex<double> > &csj,
  107. std::vector< std::complex<double> > &cdj,
  108. std::vector< std::complex<double> > &csy,
  109. std::vector< std::complex<double> > &cdy ) {
  110. double a0;
  111. csj.resize(n+1);
  112. cdj.resize(n+1);
  113. csy.resize(n+1);
  114. cdy.resize(n+1);
  115. std::complex<double> cf, cf0, cf1, cs, csa, csb;
  116. int m;
  117. a0 = std::abs(z);
  118. nm = n;
  119. if (a0 < 1.0e-60) {
  120. for (int k = 0; k < n+1; ++k) {
  121. csj[k] = 0.0;
  122. cdj[k] = 0.0;
  123. csy[k] = -1.0e+300;
  124. cdy[k] = 1.0e+300;
  125. }
  126. csj[0] = std::complex<double>( 1.0, 0.0);
  127. cdj[1] = std::complex<double>( 0.3333333333333333, 0.0);
  128. return;
  129. }
  130. csj[0] = std::sin ( z ) / z;
  131. csj[1] = ( csj[0] - std::cos ( z ) ) / z;
  132. if ( 2 <= n ) {
  133. csa = csj[0];
  134. csb = csj[1];
  135. int precision = 1;
  136. m = msta1 ( a0, 200*precision);
  137. if ( m < n ) nm = m;
  138. else m = msta2 ( a0, n, 15*precision);
  139. cf0 = 0.0;
  140. cf1 = 1.0e-100;
  141. for (int k = m; k>=0; --k) {
  142. cf = ( 2.0 * k + 3.0 ) * cf1 / z - cf0;
  143. if ( k <= nm ) csj[k] = cf;
  144. cf0 = cf1;
  145. cf1 = cf;
  146. }
  147. if ( std::abs ( csa ) <= std::abs ( csb ) ) cs = csb / cf0;
  148. else cs = csa / cf;
  149. for (int k = 0; k <= nm; ++k) {
  150. csj[k] = cs * csj[k];
  151. }
  152. }
  153. cdj[0] = ( std::cos ( z ) - std::sin ( z ) / z ) / z;
  154. for (int k = 1; k <=nm; ++k) {
  155. cdj[k] = csj[k-1] - ( k + 1.0 ) * csj[k] / z;
  156. }
  157. csy[0] = - std::cos ( z ) / z;
  158. csy[1] = ( csy[0] - std::sin ( z ) ) / z;
  159. cdy[0] = ( std::sin ( z ) + std::cos ( z ) / z ) / z;
  160. cdy[1] = ( 2.0 * cdy[0] - std::cos ( z ) ) / z;
  161. for (int k = 2; k<=nm; ++k) {
  162. if ( std::abs ( csj[k-2] ) < std::abs ( csj[k-1] ) ) {
  163. csy[k] = ( csj[k] * csy[k-1] - 1.0 / ( z * z ) ) / csj[k-1];
  164. } else {
  165. csy[k] = ( csj[k] * csy[k-2] - ( 2.0 * k - 1.0 ) / std::pow(z,3) )
  166. / csj[k-2];
  167. }
  168. }
  169. for (int k = 2; k<=nm; ++k) {
  170. cdy[k] = csy[k-1] - ( k + 1.0 ) * csy[k] / z;
  171. }
  172. return;
  173. }
  174. // function msta2 ( x, n, mp )
  175. // !*****************************************************************************80
  176. // !
  177. // !! MSTA2 determines a backward recurrence starting point for Jn(x).
  178. // !
  179. // ! Discussion:
  180. // !
  181. // ! This procedure determines the starting point for a backward
  182. // ! recurrence such that all Jn(x) has MP significant digits.
  183. // !
  184. // ! Licensing:
  185. // !
  186. // ! This routine is copyrighted by Shanjie Zhang and Jianming Jin. However,
  187. // ! they give permission to incorporate this routine into a user program
  188. // ! provided that the copyright is acknowledged.
  189. // !
  190. // ! Modified:
  191. // !
  192. // ! 08 July 2012
  193. // !
  194. // ! Author:
  195. // !
  196. // ! Shanjie Zhang, Jianming Jin
  197. // !
  198. // ! Reference:
  199. // !
  200. // ! Shanjie Zhang, Jianming Jin,
  201. // ! Computation of Special Functions,
  202. // ! Wiley, 1996,
  203. // ! ISBN: 0-471-11963-6,
  204. // ! LC: QA351.C45.
  205. // !
  206. // ! Parameters:
  207. // !
  208. // ! Input, real ( kind = 8 ) X, the argument of Jn(x).
  209. // !
  210. // ! Input, integer ( kind = 4 ) N, the order of Jn(x).
  211. // !
  212. // ! Input, integer ( kind = 4 ) MP, the number of significant digits.
  213. // !
  214. // ! Output, integer ( kind = 4 ) MSTA2, the starting point.
  215. // !
  216. int msta2 ( double x, int n, int mp ) {
  217. double a0, ejn, f, f0, f1, hmp;
  218. int n0, n1, nn;
  219. double obj;
  220. a0 = std::abs ( x );
  221. hmp = 0.5 * mp;
  222. ejn = envj ( n, a0 );
  223. if ( ejn <= hmp ) {
  224. obj = mp;
  225. n0 = static_cast<int> ( 1.1 * a0 );
  226. } else {
  227. obj = hmp + ejn;
  228. n0 = n;
  229. }
  230. f0 = envj ( n0, a0 ) - obj;
  231. n1 = n0 + 5;
  232. f1 = envj ( n1, a0 ) - obj;
  233. for (int it = 1; it < 21; ++it) {
  234. nn = n1 - ( n1 - n0 ) / ( 1.0 - f0 / f1 );
  235. f = envj ( nn, a0 ) - obj;
  236. if ( std::abs ( nn - n1 ) < 1 ) break;
  237. n0 = n1;
  238. f0 = f1;
  239. n1 = nn;
  240. f1 = f;
  241. }
  242. return nn + 10;
  243. }
  244. // !*****************************************************************************80
  245. // !
  246. // !! MSTA1 determines a backward recurrence starting point for Jn(x).
  247. // !
  248. // ! Discussion:
  249. // !
  250. // ! This procedure determines the starting point for backward
  251. // ! recurrence such that the magnitude of
  252. // ! Jn(x) at that point is about 10^(-MP).
  253. // !
  254. // ! Licensing:
  255. // !
  256. // ! This routine is copyrighted by Shanjie Zhang and Jianming Jin. However,
  257. // ! they give permission to incorporate this routine into a user program
  258. // ! provided that the copyright is acknowledged.
  259. // !
  260. // ! Modified:
  261. // !
  262. // ! 08 July 2012
  263. // !
  264. // ! Author:
  265. // !
  266. // ! Shanjie Zhang, Jianming Jin
  267. // !
  268. // ! Reference:
  269. // !
  270. // ! Shanjie Zhang, Jianming Jin,
  271. // ! Computation of Special Functions,
  272. // ! Wiley, 1996,
  273. // ! ISBN: 0-471-11963-6,
  274. // ! LC: QA351.C45.
  275. // !
  276. // ! Parameters:
  277. // !
  278. // ! Input, real ( kind = 8 ) X, the argument.
  279. // !
  280. // ! Input, integer ( kind = 4 ) MP, the negative logarithm of the
  281. // ! desired magnitude.
  282. // !
  283. // ! Output, integer ( kind = 4 ) MSTA1, the starting point.
  284. // !
  285. int msta1 ( double x, int mp ) {
  286. double a0, f, f0, f1;
  287. int n0, n1, nn;
  288. a0 = std::abs ( x );
  289. n0 = static_cast<int> (1.1 * a0 ) + 1;
  290. f0 = envj ( n0, a0 ) - mp;
  291. n1 = n0 + 5;
  292. f1 = envj ( n1, a0 ) - mp;
  293. for (int it = 1; it <= 20; ++it) {
  294. nn = n1 - ( n1 - n0 ) / ( 1.0 - f0 / f1 );
  295. f = envj ( nn, a0 ) - mp;
  296. if ( abs ( nn - n1 ) < 1 ) break;
  297. n0 = n1;
  298. f0 = f1;
  299. n1 = nn;
  300. f1 = f;
  301. }
  302. return nn;
  303. }
  304. // function envj ( n, x )
  305. // !*****************************************************************************80
  306. // !
  307. // !! ENVJ is a utility function used by MSTA1 and MSTA2.
  308. // !
  309. // ! Licensing:
  310. // !
  311. // ! This routine is copyrighted by Shanjie Zhang and Jianming Jin. However,
  312. // ! they give permission to incorporate this routine into a user program
  313. // ! provided that the copyright is acknowledged.
  314. // !
  315. // ! Modified:
  316. // !
  317. // ! 14 March 2012
  318. // !
  319. // ! Author:
  320. // !
  321. // ! Shanjie Zhang, Jianming Jin
  322. // !
  323. // ! Reference:
  324. // !
  325. // ! Shanjie Zhang, Jianming Jin,
  326. // ! Computation of Special Functions,
  327. // ! Wiley, 1996,
  328. // ! ISBN: 0-471-11963-6,
  329. // ! LC: QA351.C45.
  330. // !
  331. // ! Parameters:
  332. // !
  333. // ! Input, integer ( kind = 4 ) N, ?
  334. // !
  335. // ! Input, real ( kind = 8 ) X, ?
  336. // !
  337. // ! Output, real ( kind = 8 ) ENVJ, ?
  338. // !
  339. double envj (int n, double x ) {
  340. return 0.5 * std::log10(6.28 * n) - n * std::log10(1.36 * x / static_cast<double>(n) );
  341. }
  342. } // end of namespace bessel
  343. } // end of namespace nmie