7 #ifndef NIHU_CONVECTED_HELMHOLTZ_3D_HF_FMM_HPP_INCLUDED
8 #define NIHU_CONVECTED_HELMHOLTZ_3D_HF_FMM_HPP_INCLUDED
13 #include "helmholtz_3d_hf_shift.h"
17 #include "library/convected_helmholtz_3d_kernel.hpp"
18 #include "library/convected_helmholtz_3d_singular_integrals.hpp"
19 #include "library/convected_helmholtz_3d_nearly_singular_integrals.hpp"
21 #include <boost/math/constants/constants.hpp>
22 #include <boost/math/special_functions/hankel.hpp>
23 #include <boost/math/special_functions/legendre.hpp>
37 template <
class WaveNumber>
42 typedef Eigen::Matrix<double, 3, 3> dmatrix3_t;
43 typedef WaveNumber wave_number_t;
78 wave_number_t
const m_kappa;
87 template <
class WaveNumber>
104 using cvector_t = Eigen::Matrix<std::complex<double>, Eigen::Dynamic, 1>;
111 , m_mach_vector(mach_vector)
112 , m_mach_number(mach_vector.norm())
113 , m_kappa(m_wave_number / (1. - m_mach_number * m_mach_number))
119 m_T = (dmatrix3_t::Identity() - E) * std::sqrt(1 - m_mach_number*m_mach_number) + E;
127 using namespace boost::math::double_constants;
128 auto kd = two_pi * drel;
129 return size_t(std::ceil(kd +
C * std::log(kd + pi)));
143 using namespace boost::math::double_constants;
144 double lambda_scaled = two_pi / std::real(m_kappa);
145 m_level_data_vector.clear();
151 auto &ld = m_level_data_vector[i];
154 auto d = tree[idx].get_bounding_box().get_diameter();
156 ld.set_expansion_length(L);
162 auto &ld = m_level_data_vector[i];
163 auto const &Sto = ld.get_unit_sphere();
165 ld.set_interp_dn(
interpolator(m_level_data_vector[i - 1].get_unit_sphere(), Sto));
167 ld.set_interp_up(
interpolator(m_level_data_vector[i + 1].get_unit_sphere(), Sto));
176 return m_level_data_vector[idx];
184 return m_level_data_vector[idx];
204 return bounding_box_t::dist2idx(
211 using namespace std::complex_literals;
216 cvector_t shift = exp((-1.i * kappa * Sto.get_s().transpose() * TD).array());
232 l2l(wave_number_t
const &wave_number, wave_number_t
const &kappa, dmatrix3_t
const &T)
239 return bounding_box_t::dist2idx(
246 using namespace std::complex_literals;
256 cvector_t shift = exp((-1.i * kappa * Sfrom.get_s().transpose() * TD).array());
258 cvector_t shift = exp((-1.i * kappa * Sto.get_s().transpose() * TD).array());
272 using result_t = Eigen::DiagonalMatrix<std::complex<double>, Eigen::Dynamic>;
275 m2l(wave_number_t
const &wave_number, wave_number_t
const &kappa, dmatrix3_t
const &T)
296 return m2l_matrix_impl(TDvec, s, kappa, L).asDiagonal();
301 Eigen::Matrix<double, 3, Eigen::Dynamic>
const &s,
302 wave_number_t
const &kappa,
305 using namespace boost::math::double_constants;
306 using namespace std::complex_literals;
307 using boost::math::legendre_p;
308 using boost::math::sph_hankel_1;
310 double TD = TDvec.norm();
314 Eigen::Matrix<double, 1, Eigen::Dynamic> x = TUvec.transpose() * s;
315 auto z = -kappa * TD;
319 for (
size_t l = 0; l <= L; ++l)
321 auto h = sph_hankel_1(l, z);
322 auto c = double(2 * l + 1) * std::pow(1.i, l) * h;
323 for (
int i = 0; i < s.cols(); ++i)
324 M2L(i) += c * legendre_p(
int(l), x(0, i));
326 M2L *= -1.i * kappa / (4.0 * pi) / (4.0 * pi);
340 using result_t = Eigen::Matrix<std::complex<double>, Eigen::Dynamic, 1>;
342 p2m_SLP(wave_number_t
const &k, wave_number_t
const &kappa, dmatrix3_t
const &T,
location_t const &mach_vector)
344 , m_mach_vector(mach_vector)
353 result_t operator()(
test_input_t const &to, trial_input_t
const &tri)
const
355 return eval(to, tri);
360 result_t eval(
test_input_t const &to, trial_input_t
const &tri)
const
362 using namespace std::complex_literals;
364 auto const &y = tri.get_x();
367 auto const &Mvec = this->m_mach_vector;
369 double M_dot_ny = Mvec.dot(tri.get_unit_normal());
370 return Eigen::exp(-1.i * kappa * (s.transpose() * Td).array())
371 * std::exp(-1.i * kappa * Mvec.dot(y))
372 * (1. - M_dot_ny*M_dot_ny);
386 using result_t = Eigen::Matrix<std::complex<double>, Eigen::Dynamic, 1>;
388 p2m_DLP(wave_number_t
const &k, wave_number_t
const &kappa, dmatrix3_t
const &T,
location_t const &mach_vector)
390 , m_mach_vector(mach_vector)
399 result_t operator()(
test_input_t const &to, trial_input_t
const &tri)
const
401 return eval(to, tri);
406 result_t eval(
test_input_t const &to, trial_input_t
const &tri)
const
408 using namespace std::complex_literals;
410 auto const &y = tri.get_x();
411 auto const &ny = tri.get_unit_normal();
414 auto const &Mvec = this->m_mach_vector;
415 double M2 = Mvec.dot(Mvec);
416 auto const &T = this->
get_T();
418 return Eigen::exp(-1.i * kappa * (s.transpose() * Td).array()) * std::exp(-1.i * kappa * Mvec.dot(y))
420 ((s.transpose() * (T * ny)).array() + Mvec.dot(ny) * (1. - M2 - (s.transpose()*Mvec).array()));
434 using result_t = Eigen::Matrix<std::complex<double>, Eigen::Dynamic, 1>;
436 p2l(wave_number_t
const &k, wave_number_t
const &kappa, dmatrix3_t
const &T,
location_t const &mach_vector)
438 , m_mach_vector(mach_vector)
447 result_t operator()(
test_input_t const &to, trial_input_t
const &tri)
const
449 return eval(to, tri);
453 result_t eval(
test_input_t const &to, trial_input_t
const &tri)
const
455 throw std::logic_error(
"Unimplemented p2l operator");
469 using result_t = Eigen::Matrix<std::complex<double>, Eigen::Dynamic, 1>;
471 m2p(wave_number_t
const &k, wave_number_t
const &kappa, dmatrix3_t
const &T,
location_t const &mach_vector)
473 , m_mach_vector(mach_vector)
482 result_t operator()(test_input_t
const &tsi,
trial_input_t const &from)
const
484 return eval(tsi, from);
488 result_t eval(test_input_t
const &tsi,
trial_input_t const &from)
const
490 throw std::logic_error(
"Unimplemented m2p operator");
504 using result_t = Eigen::Matrix<std::complex<double>, 1, Eigen::Dynamic>;
506 l2p(wave_number_t
const &k, wave_number_t
const &kappa, dmatrix3_t
const &T,
location_t const &mach_vector)
508 , m_mach_vector(mach_vector)
517 result_t operator()(test_input_t
const &tsi,
trial_input_t const &from)
const
519 return eval(tsi, from);
524 result_t eval(test_input_t
const &tsi,
trial_input_t const &from)
const
526 using namespace std::complex_literals;
528 auto const &x = tsi.get_x();
530 auto const &s = S.
get_s();
531 auto const &w = S.get_w();
533 auto const &Mvec = this->m_mach_vector;
535 return Eigen::exp(-1.i * kappa * (s.transpose() * Td).array()) * w.array() * std::exp(1.i * kappa * Mvec.dot(x));
547 typedef typename kernel_t::result_t result_t;
548 typedef typename kernel_t::test_input_t test_input_t;
549 typedef typename kernel_t::trial_input_t trial_input_t;
556 result_t operator()(test_input_t
const &tsi, trial_input_t
const &tri)
const
558 return m_kernel(tsi, tri);
576 typedef typename kernel_t::result_t result_t;
577 typedef typename kernel_t::test_input_t test_input_t;
578 typedef typename kernel_t::trial_input_t trial_input_t;
585 result_t operator()(test_input_t
const &tsi, trial_input_t
const &tri)
const
587 return m_kernel(tsi, tri);
603 return m2m(m_wave_number, m_kappa, m_T);
610 return l2l(m_wave_number, m_kappa, m_T);
617 return m2l(m_wave_number, m_kappa, m_T);
620 p2l create_p2l()
const
622 return p2l(m_wave_number, m_kappa, m_T, m_mach_vector);
625 m2p create_m2p()
const
627 return m2p(m_wave_number, m_kappa, m_T, m_mach_vector);
634 return p2m_SLP(m_wave_number, m_kappa, m_T, m_mach_vector);
641 return p2m_DLP(m_wave_number, m_kappa, m_T, m_mach_vector);
648 return l2p(m_wave_number, m_kappa, m_T, m_mach_vector);
655 return p2p_SLP(m_wave_number, m_mach_vector);
662 return p2p_DLP(m_wave_number, m_mach_vector);
666 wave_number_t m_wave_number;
667 location_t m_mach_vector;
668 double m_mach_number;
669 wave_number_t m_kappa;
672 std::vector<helmholtz_3d_hf_level_data> m_level_data_vector;
678 #endif // NIHU_CONVECTED_HELMHOLTZ_3D_HF_FMM_HPP_INCLUDED