7 #ifndef NIHU_HELMHOLTZ_3D_HF_FMM_HPP_INCLUDED
8 #define NIHU_HELMHOLTZ_3D_HF_FMM_HPP_INCLUDED
20 #include "library/helmholtz_3d.hpp"
22 #include <boost/math/constants/constants.hpp>
23 #include <boost/math/special_functions/hankel.hpp>
24 #include <boost/math/special_functions/legendre.hpp>
26 #define L2L_SHIFT_FIRST 1
28 #include <Eigen/Dense>
38 using cvector_t = Eigen::Matrix<std::complex<double>, Eigen::Dynamic, 1>;
42 : m_level_data(
nullptr)
56 return m_shift.array() * m_level_data->
interp_up(rhs).array();
67 using cvector_t = Eigen::Matrix<std::complex<double>, Eigen::Dynamic, 1>;
71 : m_level_data(
nullptr)
86 return m_level_data->
interp_down(m_shift.array() * rhs.array());
88 return m_shift.array() * m_level_data->
interp_down(rhs).array();
100 template <
class WaveNumber>
107 using cvector_t = Eigen::Matrix<std::complex<double>, Eigen::Dynamic, 1>;
132 using namespace boost::math::double_constants;
133 auto kd = two_pi * drel;
134 return size_t(std::ceil(kd +
C * std::log(kd + pi)));
142 m_accuracy = accuracy;
149 using namespace boost::math::double_constants;
150 double lambda = two_pi / std::real(m_wave_number);
151 m_level_data_vector.clear();
157 auto &ld = m_level_data_vector[i];
160 auto d = tree[idx].get_bounding_box().get_diameter();
162 ld.set_expansion_length(L);
168 auto &ld = m_level_data_vector[i];
169 auto const &Sto = ld.get_unit_sphere();
171 ld.set_interp_dn(
interpolator(m_level_data_vector[i - 1].get_unit_sphere(), Sto));
173 ld.set_interp_up(
interpolator(m_level_data_vector[i + 1].get_unit_sphere(), Sto));
182 return m_level_data_vector[idx];
190 return m_level_data_vector[idx];
203 m2m(wave_number_t
const &wave_number)
210 return bounding_box_t::dist2idx(
217 using namespace std::complex_literals;
221 auto const &k = this->get_wave_number();
222 cvector_t shift = exp((-1.i * k * Sto.get_s().transpose() * D).array());
238 l2l(wave_number_t
const &wave_number)
245 return bounding_box_t::dist2idx(
252 using namespace std::complex_literals;
260 auto const &k = this->get_wave_number();
262 cvector_t shift = exp((-1.i * k * Sfrom.get_s().transpose() * D).array());
264 cvector_t shift = exp((-1.i * k * Sto.get_s().transpose() * D).array());
287 p2m(wave_number_t
const &wave_number)
297 result_t operator()(
test_input_t const &to, trial_input_t
const &tri)
const
299 return eval(to, tri, std::integral_constant<int, Ny>());
304 result_t eval(
test_input_t const &to, trial_input_t
const &tri,
305 std::integral_constant<int, 0>)
const
307 using namespace std::complex_literals;
309 auto const &y = tri.get_x();
311 auto const &k = this->get_wave_number();
313 return Eigen::exp(-1.i * k * (s.transpose() * d).array());
317 result_t eval(
test_input_t const &to, trial_input_t
const &tri,
318 std::integral_constant<int, 1>)
const
320 using namespace std::complex_literals;
322 auto const &y = tri.get_x();
324 auto const &k = this->get_wave_number();
326 return Eigen::exp(-1.i * k * (s.transpose() * d).array())
327 * ((1.i * k) * (s.transpose() * tri.get_unit_normal()).array());
347 p2l(wave_number_t
const &wave_number)
357 result_t operator()(
test_input_t const &to, trial_input_t
const &tri)
const
359 return eval(to, tri, std::integral_constant<int, Ny>());
363 result_t eval(
test_input_t const &to, trial_input_t
const &tri,
364 std::integral_constant<int, 0>)
const
366 throw std::logic_error(
"Unimplemented p2l operator");
369 result_t eval(
test_input_t const &to, trial_input_t
const &tri,
370 std::integral_constant<int, 1>)
const
372 throw std::logic_error(
"Unimplemented p2l operator");
391 using result_t = Eigen::Matrix<std::complex<double>, 1, Eigen::Dynamic>;
393 l2p(wave_number_t
const &wave_number)
403 result_t operator()(test_input_t
const &tsi,
trial_input_t const &from)
const
405 return eval(tsi, from, std::integral_constant<int, Nx>());
409 result_t eval(test_input_t
const &tsi,
trial_input_t const &from,
410 std::integral_constant<int, 0>)
const
412 using namespace std::complex_literals;
414 auto const &x = tsi.get_x();
416 auto const &s = S.
get_s();
417 auto const &w = S.get_w();
418 auto const &k = this->get_wave_number();
420 return Eigen::exp(-1.i * k * (s.transpose() * d).array()) * w.array();
423 result_t eval(test_input_t
const &tsi,
trial_input_t const &from,
424 std::integral_constant<int, 1>)
const
426 using namespace std::complex_literals;
428 auto const &x = tsi.get_x();
430 auto const &s = S.
get_s();
431 auto const &w = S.get_w();
432 auto const &k = this->get_wave_number();
434 return Eigen::exp(-1.i * k * (s.transpose() * d).array())
435 * (-1.i * k) * (s.transpose() * tsi.get_unit_normal()).array()
455 using result_t = Eigen::Matrix<std::complex<double>, 1, Eigen::Dynamic>;
457 m2p(wave_number_t
const &wave_number)
467 result_t operator()(test_input_t
const &tsi,
trial_input_t const &from)
const
469 return eval(tsi, from, std::integral_constant<int, Nx>());
473 result_t eval(test_input_t
const &tsi,
trial_input_t const &from,
474 std::integral_constant<int, 0>)
const
476 throw std::logic_error(
"Unimplemented m2p operator");
479 result_t eval(test_input_t
const &tsi,
trial_input_t const &from,
480 std::integral_constant<int, 1>)
const
482 throw std::logic_error(
"Unimplemented m2p operator");
493 using result_t = Eigen::DiagonalMatrix<std::complex<double>, Eigen::Dynamic>;
508 auto const &k = this->get_wave_number();
517 return m2l_matrix_impl(Dvec, s, k, L).asDiagonal();
522 Eigen::Matrix<double, 3, Eigen::Dynamic>
const &s,
526 using namespace boost::math::double_constants;
527 using namespace std::complex_literals;
529 double D = Dvec.norm();
533 Eigen::Matrix<double, 1, Eigen::Dynamic> x = Uvec.transpose() * s;
538 for (
size_t l = 0; l <= L; ++l)
540 auto h = boost::math::sph_hankel_1(l, z);
541 auto c = double(2 * l + 1) * std::pow(1.i, l) * h;
542 for (
int i = 0; i < s.cols(); ++i)
543 M2L(i) += c * boost::math::legendre_p(
int(l), x(0, i));
545 M2L *= -1.i * k / (4.0 * pi) / (4.0 * pi);
574 template <
int Nx,
int Ny>
621 template <
int Nx,
int Ny>
634 return m2m(m_wave_number);
641 return l2l(m_wave_number);
648 return m2l(m_wave_number);
652 wave_number_t m_wave_number;
653 std::vector<helmholtz_3d_hf_level_data> m_level_data_vector;