7 #ifndef NIHU_LAPLACE_3D_FMM_HPP_INCLUDED
8 #define NIHU_LAPLACE_3D_FMM_HPP_INCLUDED
14 #include "library/laplace_3d.hpp"
16 #include <boost/math/constants/constants.hpp>
17 #include <boost/math/special_functions/spherical_harmonic.hpp>
18 #include <boost/math/special_functions/factorials.hpp>
20 #include <Eigen/Dense>
30 class laplace_3d_cluster;
37 typedef Eigen::Matrix<std::complex<double>, Eigen::Dynamic, 1> cvector_t;
41 static size_t const dimension = 3;
67 size_t data_size()
const;
75 Eigen::Index linear_index(Eigen::Index n, Eigen::Index m)
const;
78 size_t m_expansion_length;
97 template <
int Nx,
int Ny>
109 static std::complex<double> Y(
size_t n,
int m,
double theta,
double phi)
111 using boost::math::spherical_harmonic;
112 using namespace boost::math::double_constants;
114 std::complex<double> res =
115 spherical_harmonic(
unsigned(n), std::abs(m), theta, phi)
116 / std::sqrt((2 * n + 1.0) / (4.0 * pi));
117 return (m < 0) ? std::conj(res) : res;
120 static double A(
int n,
int m)
122 using boost::math::factorial;
123 double res = std::pow(-1, n) / std::sqrt(
124 factorial<double>(n - m) * factorial<double>(n + m));
131 template <
unsigned Ny>
141 >::trial_input_t trial_input_t;
147 return to.data_size();
150 result_t operator()(
test_input_t const &to, trial_input_t
const & from)
const
152 return eval(to, from, std::integral_constant<unsigned, Ny>());
156 trial_input_t
const &from,
157 std::integral_constant<unsigned, 0>)
const
159 using namespace boost::math::double_constants;
161 result_t res(to.data_size(), 1);
165 double phi = std::atan2(x(1), x(0));
166 double theta = std::acos(x(2) / r);
170 double rn = std::pow(r, n);
171 for (
int m = -n; m <= n; ++m)
173 auto idx = to.linear_index(n, m);
174 res(idx, 0) = rn * Y(n, -m, theta, phi);
178 return res / (4. * pi);
182 trial_input_t
const &from,
183 std::integral_constant<unsigned, 1>)
const
185 using namespace boost::math::double_constants;
188 return res / (4. * pi);
195 template <
unsigned Ny>
204 >::trial_input_t trial_input_t;
205 typedef Eigen::Matrix<std::complex<double>, Eigen::Dynamic, 1> result_t;
209 return to.data_size();
212 result_t operator()(
test_input_t const &to, trial_input_t
const &from)
const
214 return eval(to, from, std::integral_constant<unsigned, Ny>());
218 result_t eval(
test_input_t const &to, trial_input_t
const & from,
219 std::integral_constant<unsigned, 0>)
const
221 using namespace boost::math::double_constants;
223 result_t res(rows(to), 1);
227 double phi = std::atan2(x(1), x(0));
228 double theta = std::acos(x(2) / r);
232 double rn = std::pow(r, -(n + 1));
233 for (
int m = -n; m <= n; ++m)
235 auto idx = to.linear_index(n, m);
236 res(idx, 0) = rn * Y(n, -m, theta, phi);
240 return res / (4.0 * pi);
243 result_t eval(
test_input_t const &to, trial_input_t
const & from,
244 std::integral_constant<unsigned, 1>)
const
246 throw std::logic_error(
"Unimplemented");
254 template <
unsigned Nx>
261 >::test_input_t test_input_t;
265 typedef Eigen::Matrix<std::complex<double>, 1, Eigen::Dynamic> complex_result_t;
266 typedef complex_result_t result_t;
270 return from.data_size();
273 result_t operator()(test_input_t
const &to,
trial_input_t const & from)
const
275 return eval(to, from, std::integral_constant<unsigned, Nx>());
279 result_t eval(test_input_t
const &to,
281 std::integral_constant<unsigned, 0>)
const
283 result_t res(1, from.data_size());
287 double phi = std::atan2(x(1), x(0));
288 double theta = std::acos(x(2) / r);
292 double rn = std::pow(r, n);
293 for (
int m = -n; m <= n; ++m)
295 auto idx = from.linear_index(n, m);
296 res(0, idx) = rn * Y(n, m, theta, phi);
303 result_t eval(test_input_t
const &to,
305 std::integral_constant<unsigned, 1>)
const
307 throw std::logic_error(
"Unimplemented");
315 template <
unsigned Nx>
322 >::test_input_t test_input_t;
324 typedef Eigen::Matrix<std::complex<double>, 1, Eigen::Dynamic> complex_result_t;
325 typedef complex_result_t result_t;
330 return from.data_size();
333 result_t operator()(test_input_t
const &to,
trial_input_t const &from)
const
335 return eval(to, from, std::integral_constant<unsigned, Nx>());
339 result_t eval(test_input_t
const &to,
341 std::integral_constant<unsigned, 0>)
const
343 result_t res(1, from.data_size());
347 double phi = std::atan2(x(1), x(0));
348 double theta = std::acos(x(2) / r);
352 double rn = std::pow(r, -
int(n+1));
353 for (
int m = -
int(n); m <= int(n); ++m)
355 auto idx = from.linear_index(n, m);
356 res(0, idx) = rn * Y(n, m, theta, phi);
363 result_t eval(test_input_t
const &to,
365 std::integral_constant<unsigned, 1>)
const
367 throw std::logic_error(
"Unimplemented");
377 typedef Eigen::Matrix<std::complex<double>, Eigen::Dynamic, Eigen::Dynamic> result_t;
390 typedef Eigen::Matrix<std::complex<double>, Eigen::Dynamic, Eigen::Dynamic> result_t;
403 typedef Eigen::Matrix<std::complex<double>, Eigen::Dynamic, Eigen::Dynamic> result_t;
415 template <
unsigned Ny>
425 template <
unsigned Ny>
435 template <
unsigned Nx>
445 template <
unsigned Nx>