123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- //**********************************************************************************//
- // Copyright (C) 2009-2015 Ovidio Pena <ovidio@bytesfall.com> //
- // Copyright (C) 2013-2015 Konstantin Ladutenko <kostyfisik@gmail.com> //
- // //
- // 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 <http://www.gnu.org/licenses/>. //
- //**********************************************************************************//
- #include "bessel.h"
- #include <algorithm>
- #include <complex>
- #include <cmath>
- #include <limits>
- #include <stdexcept>
- #include <vector>
- namespace nmie {
- namespace bessel {
- void calcZeta(int n, std::complex<double>z, std::vector< std::complex<double> >& Zeta,
- std::vector< std::complex<double> >& dZeta) {
- std::vector< std::complex<double> > 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<double>(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::complex<double>z, std::vector< std::complex<double> >& Psi,
- std::vector< std::complex<double> >& dPsi) {
- std::vector< std::complex<double> > 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::complex<double>z, int& nm,
- std::vector< std::complex<double> >& csj,
- std::vector< std::complex<double> >& cdj,
- std::vector< std::complex<double> >& csy,
- std::vector< std::complex<double> >& cdy ) {
- double a0;
- csj.resize(n+1);
- cdj.resize(n+1);
- csy.resize(n+1);
- cdy.resize(n+1);
- std::complex<double> 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<double>( 1.0, 0.0);
- cdj[1] = std::complex<double>( 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<int> ( 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<int> (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<double>(n) );
- }
- } // end of namespace bessel
- } // end of namespace nmie
|