//**********************************************************************************// // Copyright (C) 2009-2015 Ovidio Pena // // Copyright (C) 2013-2015 Konstantin Ladutenko // // // // This file is part of scattnlay // // // // This program is free software: you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // // the Free Software Foundation, either version 3 of the License, or // // (at your option) any later version. // // // // This program 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. // // // // The only additional remark is that we expect that all publications // // describing work using this software, or all commercial products // // using it, cite the following reference: // // [1] O. Pena and U. Pal, "Scattering of electromagnetic radiation by // // a multilayered sphere," Computer Physics Communications, // // vol. 180, Nov. 2009, pp. 2348-2354. // // // // You should have received a copy of the GNU General Public License // // along with this program. If not, see . // //**********************************************************************************// #include "bessel.h" #include #include #include #include #include #include namespace nmie { namespace bessel { void calcZeta(int n, std::complexz, std::vector< std::complex >& Zeta, std::vector< std::complex >& dZeta) { std::vector< std::complex > csj, cdj, csy, cdy; int nm; csphjy (n, z, nm, csj, cdj, csy, cdy ); Zeta.resize(n+1); dZeta.resize(n+1); auto c_i = std::complex(0.0,1.0); for (int i = 0; i < n+1; ++i) { Zeta[i]=z*(csj[i] + c_i*csy[i]); dZeta[i]=z*(cdj[i] + c_i*cdy[i])+csj[i] + c_i*csy[i]; } } // end of calcZeta() void calcPsi(int n, std::complexz, std::vector< std::complex >& Psi, std::vector< std::complex >& dPsi) { std::vector< std::complex > csj, cdj, csy, cdy; int nm; csphjy (n, z, nm, csj, cdj, csy, cdy ); Psi.resize(n+1); dPsi.resize(n+1); for (int i = 0; i < n+1; ++i) { Psi[i]=z*(csj[i]); dPsi[i]=z*(cdj[i])+csj[i]; } } // end of calcPsi() // !*****************************************************************************80 // // C++ port of fortran code // // !! CSPHJY: spherical Bessel functions jn(z) and yn(z) for complex argument. // ! // ! Discussion: // ! // ! This procedure computes spherical Bessel functions jn(z) and yn(z) // ! and their derivatives for a complex argument. // ! // ! Licensing: // ! // ! This routine is copyrighted by Shanjie Zhang and Jianming Jin. However, // ! they give permission to incorporate this routine into a user program // ! provided that the copyright is acknowledged. // ! // ! Modified: // ! // ! 01 August 2012 // ! // ! Author: // ! // ! Shanjie Zhang, Jianming Jin // ! // ! Reference: // ! // ! Shanjie Zhang, Jianming Jin, // ! Computation of Special Functions, // ! Wiley, 1996, // ! ISBN: 0-471-11963-6, // ! LC: QA351.C45. // ! // ! Parameters: // ! // ! Input, integer ( kind = 4 ) N, the order of jn(z) and yn(z). // ! // ! Input, complex ( kind = 8 ) Z, the argument. // ! // ! Output, integer ( kind = 4 ) NM, the highest order computed. // ! // ! Output, complex ( kind = 8 ) CSJ(0:N0, CDJ(0:N), CSY(0:N), CDY(0:N), // ! the values of jn(z), jn'(z), yn(z), yn'(z). // ! void csphjy (int n, std::complexz, int& nm, std::vector< std::complex >& csj, std::vector< std::complex >& cdj, std::vector< std::complex >& csy, std::vector< std::complex >& cdy ) { double a0; csj.resize(n+1); cdj.resize(n+1); csy.resize(n+1); cdy.resize(n+1); std::complex cf, cf0, cf1, cs, csa, csb; int m; a0 = std::abs(z); nm = n; if (a0 < 1.0e-60) { for (int k = 0; k < n+1; ++k) { csj[k] = 0.0; cdj[k] = 0.0; csy[k] = -1.0e+300; cdy[k] = 1.0e+300; } csj[0] = std::complex( 1.0, 0.0); cdj[1] = std::complex( 0.3333333333333333, 0.0); return; } csj[0] = std::sin ( z ) / z; csj[1] = ( csj[0] - std::cos ( z ) ) / z; if ( 2 <= n ) { csa = csj[0]; csb = csj[1]; int precision = 1; m = msta1 ( a0, 200*precision); if ( m < n ) nm = m; else m = msta2 ( a0, n, 15*precision); cf0 = 0.0; cf1 = 1.0e-100; for (int k = m; k>=0; --k) { cf = ( 2.0 * k + 3.0 ) * cf1 / z - cf0; if ( k <= nm ) csj[k] = cf; cf0 = cf1; cf1 = cf; } if ( std::abs ( csa ) <= std::abs ( csb ) ) cs = csb / cf0; else cs = csa / cf; for (int k = 0; k <= nm; ++k) { csj[k] = cs * csj[k]; } } cdj[0] = ( std::cos ( z ) - std::sin ( z ) / z ) / z; for (int k = 1; k <=nm; ++k) { cdj[k] = csj[k-1] - ( k + 1.0 ) * csj[k] / z; } csy[0] = - std::cos ( z ) / z; csy[1] = ( csy[0] - std::sin ( z ) ) / z; cdy[0] = ( std::sin ( z ) + std::cos ( z ) / z ) / z; cdy[1] = ( 2.0 * cdy[0] - std::cos ( z ) ) / z; for (int k = 2; k<=nm; ++k) { if ( std::abs ( csj[k-2] ) < std::abs ( csj[k-1] ) ) { csy[k] = ( csj[k] * csy[k-1] - 1.0 / ( z * z ) ) / csj[k-1]; } else { csy[k] = ( csj[k] * csy[k-2] - ( 2.0 * k - 1.0 ) / std::pow(z,3) ) / csj[k-2]; } } for (int k = 2; k<=nm; ++k) { cdy[k] = csy[k-1] - ( k + 1.0 ) * csy[k] / z; } return; } // function msta2 ( x, n, mp ) // !*****************************************************************************80 // ! // !! MSTA2 determines a backward recurrence starting point for Jn(x). // ! // ! Discussion: // ! // ! This procedure determines the starting point for a backward // ! recurrence such that all Jn(x) has MP significant digits. // ! // ! Licensing: // ! // ! This routine is copyrighted by Shanjie Zhang and Jianming Jin. However, // ! they give permission to incorporate this routine into a user program // ! provided that the copyright is acknowledged. // ! // ! Modified: // ! // ! 08 July 2012 // ! // ! Author: // ! // ! Shanjie Zhang, Jianming Jin // ! // ! Reference: // ! // ! Shanjie Zhang, Jianming Jin, // ! Computation of Special Functions, // ! Wiley, 1996, // ! ISBN: 0-471-11963-6, // ! LC: QA351.C45. // ! // ! Parameters: // ! // ! Input, real ( kind = 8 ) X, the argument of Jn(x). // ! // ! Input, integer ( kind = 4 ) N, the order of Jn(x). // ! // ! Input, integer ( kind = 4 ) MP, the number of significant digits. // ! // ! Output, integer ( kind = 4 ) MSTA2, the starting point. // ! int msta2 ( double x, int n, int mp ) { double a0, ejn, f, f0, f1, hmp; int n0, n1, nn; double obj; a0 = std::abs ( x ); hmp = 0.5 * mp; ejn = envj ( n, a0 ); if ( ejn <= hmp ) { obj = mp; n0 = static_cast ( 1.1 * a0 ); } else { obj = hmp + ejn; n0 = n; } f0 = envj ( n0, a0 ) - obj; n1 = n0 + 5; f1 = envj ( n1, a0 ) - obj; for (int it = 1; it < 21; ++it) { nn = n1 - ( n1 - n0 ) / ( 1.0 - f0 / f1 ); f = envj ( nn, a0 ) - obj; if ( std::abs ( nn - n1 ) < 1 ) break; n0 = n1; f0 = f1; n1 = nn; f1 = f; } return nn + 10; } // !*****************************************************************************80 // ! // !! MSTA1 determines a backward recurrence starting point for Jn(x). // ! // ! Discussion: // ! // ! This procedure determines the starting point for backward // ! recurrence such that the magnitude of // ! Jn(x) at that point is about 10^(-MP). // ! // ! Licensing: // ! // ! This routine is copyrighted by Shanjie Zhang and Jianming Jin. However, // ! they give permission to incorporate this routine into a user program // ! provided that the copyright is acknowledged. // ! // ! Modified: // ! // ! 08 July 2012 // ! // ! Author: // ! // ! Shanjie Zhang, Jianming Jin // ! // ! Reference: // ! // ! Shanjie Zhang, Jianming Jin, // ! Computation of Special Functions, // ! Wiley, 1996, // ! ISBN: 0-471-11963-6, // ! LC: QA351.C45. // ! // ! Parameters: // ! // ! Input, real ( kind = 8 ) X, the argument. // ! // ! Input, integer ( kind = 4 ) MP, the negative logarithm of the // ! desired magnitude. // ! // ! Output, integer ( kind = 4 ) MSTA1, the starting point. // ! int msta1 ( double x, int mp ) { double a0, f, f0, f1; int n0, n1, nn; a0 = std::abs ( x ); n0 = static_cast (1.1 * a0 ) + 1; f0 = envj ( n0, a0 ) - mp; n1 = n0 + 5; f1 = envj ( n1, a0 ) - mp; for (int it = 1; it <= 20; ++it) { nn = n1 - ( n1 - n0 ) / ( 1.0 - f0 / f1 ); f = envj ( nn, a0 ) - mp; if ( abs ( nn - n1 ) < 1 ) break; n0 = n1; f0 = f1; n1 = nn; f1 = f; } return nn; } // function envj ( n, x ) // !*****************************************************************************80 // ! // !! ENVJ is a utility function used by MSTA1 and MSTA2. // ! // ! Licensing: // ! // ! This routine is copyrighted by Shanjie Zhang and Jianming Jin. However, // ! they give permission to incorporate this routine into a user program // ! provided that the copyright is acknowledged. // ! // ! Modified: // ! // ! 14 March 2012 // ! // ! Author: // ! // ! Shanjie Zhang, Jianming Jin // ! // ! Reference: // ! // ! Shanjie Zhang, Jianming Jin, // ! Computation of Special Functions, // ! Wiley, 1996, // ! ISBN: 0-471-11963-6, // ! LC: QA351.C45. // ! // ! Parameters: // ! // ! Input, integer ( kind = 4 ) N, ? // ! // ! Input, real ( kind = 8 ) X, ? // ! // ! Output, real ( kind = 8 ) ENVJ, ? // ! double envj (int n, double x ) { return 0.5 * std::log10(6.28 * n) - n * std::log10(1.36 * x / static_cast(n) ); } } // end of namespace bessel } // end of namespace nmie