123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- #ifndef SRC_SPECIAL_FUNCTIONS_IMPL_HPP_
- #define SRC_SPECIAL_FUNCTIONS_IMPL_HPP_
- #include <iostream>
- #include <iomanip>
- #include <stdexcept>
- #include <vector>
- #include "nmie.hpp"
- #include "nmie-precision.hpp"
- namespace nmie {
- template <typename FloatType>
- int evalKapteynNumberOfLostSignificantDigits(const int ni,
- const std::complex<FloatType> zz) {
- using std::abs; using std::imag; using std::real; using std::log; using std::sqrt; using std::round;
- std::complex<double> z = ConvertComplex<double>(zz);
- if (abs(z) == 0.) return 0;
- auto n = static_cast<double>(ni);
- auto one = std::complex<double> (1, 0);
- auto lost_digits = round((
- abs(imag(z)) - log(2.) - n * ( real( log( z/n) + sqrt(one
- - pow2(z/n)) - log (one + sqrt (one
- - pow2(z/n)))
- )))/ log(10.));
- return lost_digits;
- }
- template <typename FloatType>
- int getNStar(int nmax, std::complex<FloatType> z, const int valid_digits) {
- if (nmax == 0) nmax = 1;
- int nstar = nmax;
- auto z_dp = ConvertComplex<double>(z);
- if (std::abs(z_dp) == 0.) return nstar;
- int forwardLoss = evalKapteynNumberOfLostSignificantDigits(nmax, z_dp);
- int increment = static_cast<int>(std::ceil(
- std::max(4* std::pow(std::abs( z_dp), 1/3.0), 5.0)
- ));
- int backwardLoss =evalKapteynNumberOfLostSignificantDigits(nstar, z_dp);
- while ( backwardLoss - forwardLoss < valid_digits) {
- nstar += increment;
- backwardLoss = evalKapteynNumberOfLostSignificantDigits(nstar,z_dp);
- };
- return nstar;
- }
- template <typename FloatType>
- std::complex<FloatType> complex_cot(const std::complex<FloatType> z) {
- auto Remx = z.real();
- auto Immx = z.imag();
- int sign = (Immx>0) ? 1: -1;
- auto exp = nmm::exp(-2*sign*Immx);
- auto tan = nmm::tan(Remx);
- auto a = tan - exp*tan;
- auto b = 1 + exp;
- auto c = -1 + exp;
- auto d = tan + exp* tan;
- auto c_one = std::complex<FloatType>(0, 1);
- return (a*c + b*d)/(pow2(c) + pow2(d)) +
- c_one * (sign* (b*c - a*d)/(pow2(c) + pow2(d)));
- }
- template <typename FloatType>
- void evalForwardR (const std::complex<FloatType> z,
- std::vector<std::complex<FloatType> > &r) {
- if (r.size() < 1) throw std::invalid_argument(
- "We need non-zero evaluations of ratio of the Riccati–Bessel functions.\n");
-
- r[0] = complex_cot(z);
- for (unsigned int n = 0; n < r.size() - 1; n++) {
- r[n+1] = static_cast<FloatType>(1)/( static_cast<FloatType>(2*n+1)/z - r[n] );
- }
- }
- template <typename FloatType>
- void evalBackwardR (const std::complex<FloatType> z,
- std::vector<std::complex<FloatType> > &r) {
- if (r.size() < 1) throw std::invalid_argument(
- "We need non-zero evaluations of ratio of the Riccati–Bessel functions.\n");
- int nmax = r.size()-1 ;
- auto tmp = static_cast<FloatType>(2*nmax + 1)/z;
- r[nmax] = tmp;
- for (int n = nmax -1; n >= 0; n--) {
- r[n] = -static_cast<FloatType>(1)/r[n+1] + static_cast<FloatType>(2*n+1)/z;
- }
- r[0] = complex_cot(z);
- }
- template <typename FloatType>
- void convertRtoD1(const std::complex<FloatType> z,
- std::vector<std::complex<FloatType> > &r,
- std::vector<std::complex<FloatType> > &D1) {
- if (D1.size() > r.size()) throw std::invalid_argument(
- "Not enough elements in array of ratio of the Riccati–Bessel functions to convert it into logarithmic derivative array.\n");
- std::complex<FloatType> Dold;
- for (unsigned int n = 0; n < D1.size(); n++) {
- Dold = D1[n];
- D1[n] = r[n] - static_cast<FloatType>(n)/z;
- }
- }
- template <typename FloatType>
- void evalForwardD (const std::complex<FloatType> z,
- std::vector<std::complex<FloatType> > &D) {
- int nmax = D.size();
- FloatType one = static_cast<FloatType >(1);
- for (int n = 1; n < nmax; n++) {
- FloatType nf = static_cast<FloatType > (n);
- D[n] = one/ (nf/z - D[n-1]) - nf/z;
- }
- }
- template <typename FloatType>
- void evalForwardD1 (const std::complex<FloatType> z,
- std::vector<std::complex<FloatType> > &D) {
- if (D.size()<1) throw std::invalid_argument("Should have a leas one element!\n");
- D[0] = nmm::cos(z)/nmm::sin(z);
- evalForwardD(z,D);
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- template <typename FloatType>
- void evalDownwardD1 (const std::complex<FloatType> z,
- std::vector<std::complex<FloatType> >& D1) {
- int nmax = D1.size() - 1;
- int valid_digits = 16;
- #ifdef MULTI_PRECISION
- valid_digits += MULTI_PRECISION;
- #endif
- int nstar = nmie::getNStar(nmax, z, valid_digits);
- D1.resize(nstar+1);
-
- D1[nstar] = std::complex<FloatType>(0.0, 0.0);
- std::complex<FloatType> c_one(1.0, 0.0);
- const std::complex<FloatType> zinv = std::complex<FloatType>(1.0, 0.0)/z;
- for (unsigned int n = nstar; n > 0; n--) {
- D1[n - 1] = static_cast<FloatType>(n)*zinv - c_one/
- (D1[n] + static_cast<FloatType>(n)*zinv);
- }
-
- D1[0] = complex_cot(z);
- D1.resize(nmax+1);
- }
- template <typename FloatType>
- void evalUpwardD3 (const std::complex<FloatType> z,
- const std::vector<std::complex<FloatType> >& D1,
- std::vector<std::complex<FloatType> >& D3,
- std::vector<std::complex<FloatType> >& PsiZeta) {
- int nmax = D1.size()-1;
-
- PsiZeta[0] = static_cast<FloatType>(0.5)*(static_cast<FloatType>(1.0) - std::complex<FloatType>(nmm::cos(2.0*z.real()), nmm::sin(2.0*z.real()))
- *static_cast<FloatType>(nmm::exp(-2.0*z.imag())));
- D3[0] = std::complex<FloatType>(0.0, 1.0);
- const std::complex<FloatType> zinv = std::complex<FloatType>(1.0, 0.0)/z;
- for (int n = 1; n <= nmax; n++) {
- PsiZeta[n] = PsiZeta[n - 1]*(static_cast<FloatType>(n)*zinv - D1[n - 1])
- *(static_cast<FloatType>(n)*zinv - D3[n - 1]);
- D3[n] = D1[n] + std::complex<FloatType>(0.0, 1.0)/PsiZeta[n];
- }
- }
- template <typename FloatType>
- std::complex<FloatType> complex_sin (const std::complex<FloatType> z){
- auto a = z.real();
- auto b = z.imag();
- auto i = std::complex<FloatType>(0,1);
- using nmm::sin; using nmm::cos; using nmm::exp;
- return ((cos(a)+i*sin(a))*exp(-b)
- - (cos(-a)+i*sin(-a))*exp(b)
- )/(static_cast<FloatType>(2)*i);
- }
- template <typename FloatType>
- void evalUpwardPsi (const std::complex<FloatType> z,
- const std::vector<std::complex<FloatType> > D1,
- std::vector<std::complex<FloatType> >& Psi) {
- int nmax = Psi.size() - 1;
-
- Psi[0] = complex_sin(z);
- for (int n = 1; n <= nmax; n++) {
- Psi[n] = Psi[n - 1]*(std::complex<FloatType>(n,0.0)/z - D1[n - 1]);
- }
- }
- template <typename FloatType>
- void evalUpwardZeta (const std::complex<FloatType> z,
- const std::vector<std::complex<FloatType> > D3,
- std::vector<std::complex<FloatType> >& Zeta) {
- int nmax = Zeta.size() - 1;
- std::complex<FloatType> c_i(0.0, 1.0);
-
- Zeta[0] = nmm::sin(z) - c_i*nmm::cos(z);
- for (int n = 1; n <= nmax; n++) {
- Zeta[n] = Zeta[n - 1]*(std::complex<FloatType>(n, 0.0)/z - D3[n - 1]);
- }
- }
- }
- #endif
|