2 // (C) Copyright John Maddock 2006.
3 // Use, modification and distribution are subject to the
4 // Boost Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 #ifndef BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP
8 #define BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP
14 #include <boost/math/special_functions/legendre.hpp>
15 #include <boost/math/tools/workaround.hpp>
24 // Calculates the prefix term that's common to the real
25 // and imaginary parts. Does *not* fix up the sign of the result
28 template <class T, class Policy>
29 inline T spherical_harmonic_prefix(unsigned n, unsigned m, T theta, const Policy& pol)
36 T sin_theta = sin(theta);
39 T leg = detail::legendre_p_imp(n, m, x, static_cast<T>(pow(fabs(sin_theta), T(m))), pol);
41 T prefix = boost::math::tgamma_delta_ratio(static_cast<T>(n - m + 1), static_cast<T>(2 * m), pol);
42 prefix *= (2 * n + 1) / (4 * constants::pi<T>());
43 prefix = sqrt(prefix);
49 template <class T, class Policy>
50 T spherical_harmonic_r(unsigned n, int m, T theta, T phi, const Policy& pol)
52 BOOST_MATH_STD_USING // ADL of std functions
57 // Reflect and adjust sign if m < 0:
63 // Check phase if theta is outside [0, PI]:
64 T mod = boost::math::tools::fmod_workaround(theta, T(2 * constants::pi<T>()));
66 mod += 2 * constants::pi<T>();
67 if(mod > constants::pi<T>())
70 // Get the value and adjust sign as required:
71 T prefix = spherical_harmonic_prefix(n, m, theta, pol);
72 prefix *= cos(m * phi);
73 return sign ? T(-prefix) : prefix;
76 template <class T, class Policy>
77 T spherical_harmonic_i(unsigned n, int m, T theta, T phi, const Policy& pol)
79 BOOST_MATH_STD_USING // ADL of std functions
84 // Reflect and adjust sign if m < 0:
90 // Check phase if theta is outside [0, PI]:
91 T mod = boost::math::tools::fmod_workaround(theta, T(2 * constants::pi<T>()));
93 mod += 2 * constants::pi<T>();
94 if(mod > constants::pi<T>())
97 // Get the value and adjust sign as required:
98 T prefix = spherical_harmonic_prefix(n, m, theta, pol);
99 prefix *= sin(m * phi);
100 return sign ? T(-prefix) : prefix;
103 template <class T, class U, class Policy>
104 std::complex<T> spherical_harmonic(unsigned n, int m, U theta, U phi, const Policy& pol)
108 // Sort out the signs:
114 // Reflect and adjust sign if m < 0:
121 // Check phase if theta is outside [0, PI]:
122 U mod = boost::math::tools::fmod_workaround(theta, U(2 * constants::pi<U>()));
124 mod += 2 * constants::pi<U>();
125 if(mod > constants::pi<U>())
132 // Calculate the value:
134 U prefix = spherical_harmonic_prefix(n, m, theta, pol);
135 U r = prefix * cos(m * phi);
136 U i = prefix * sin(m * phi);
144 static const char* function = "boost::math::spherical_harmonic<%1%>(int, int, %1%, %1%)";
145 return std::complex<T>(policies::checked_narrowing_cast<T, Policy>(r, function), policies::checked_narrowing_cast<T, Policy>(i, function));
148 } // namespace detail
150 template <class T1, class T2, class Policy>
151 inline std::complex<typename tools::promote_args<T1, T2>::type>
152 spherical_harmonic(unsigned n, int m, T1 theta, T2 phi, const Policy& pol)
154 typedef typename tools::promote_args<T1, T2>::type result_type;
155 typedef typename policies::evaluation<result_type, Policy>::type value_type;
156 return detail::spherical_harmonic<result_type, value_type>(n, m, static_cast<value_type>(theta), static_cast<value_type>(phi), pol);
159 template <class T1, class T2>
160 inline std::complex<typename tools::promote_args<T1, T2>::type>
161 spherical_harmonic(unsigned n, int m, T1 theta, T2 phi)
163 return boost::math::spherical_harmonic(n, m, theta, phi, policies::policy<>());
166 template <class T1, class T2, class Policy>
167 inline typename tools::promote_args<T1, T2>::type
168 spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi, const Policy& pol)
170 typedef typename tools::promote_args<T1, T2>::type result_type;
171 typedef typename policies::evaluation<result_type, Policy>::type value_type;
172 return policies::checked_narrowing_cast<result_type, Policy>(detail::spherical_harmonic_r(n, m, static_cast<value_type>(theta), static_cast<value_type>(phi), pol), "bost::math::spherical_harmonic_r<%1%>(unsigned, int, %1%, %1%)");
175 template <class T1, class T2>
176 inline typename tools::promote_args<T1, T2>::type
177 spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi)
179 return boost::math::spherical_harmonic_r(n, m, theta, phi, policies::policy<>());
182 template <class T1, class T2, class Policy>
183 inline typename tools::promote_args<T1, T2>::type
184 spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi, const Policy& pol)
186 typedef typename tools::promote_args<T1, T2>::type result_type;
187 typedef typename policies::evaluation<result_type, Policy>::type value_type;
188 return policies::checked_narrowing_cast<result_type, Policy>(detail::spherical_harmonic_i(n, m, static_cast<value_type>(theta), static_cast<value_type>(phi), pol), "boost::math::spherical_harmonic_i<%1%>(unsigned, int, %1%, %1%)");
191 template <class T1, class T2>
192 inline typename tools::promote_args<T1, T2>::type
193 spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi)
195 return boost::math::spherical_harmonic_i(n, m, theta, phi, policies::policy<>());
201 #endif // BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP