22 #ifndef NIHU_HELMHOLTZ_2D_SINGULAR_DOUBLE_INTEGRALS_HPP_INCLUDED
23 #define NIHU_HELMHOLTZ_2D_SINGULAR_DOUBLE_INTEGRALS_HPP_INCLUDED
25 #include <boost/math/constants/constants.hpp>
28 #include "field_type_helpers.hpp"
31 #include "normal_derivative_singular_integrals.hpp"
32 #include "../core/match_types.hpp"
33 #include "../core/singular_integral_shortcut.hpp"
34 #include "../util/math_functions.hpp"
50 template <
class TestField,
class TrialField,
size_t order>
53 typedef TestField test_field_t;
54 typedef TrialField trial_field_t;
56 typedef typename test_field_t::nset_t test_shape_t;
57 typedef typename trial_field_t::nset_t trial_shape_t;
59 static size_t const nTest = test_shape_t::num_nodes;
60 static size_t const nTrial = trial_shape_t::num_nodes;
62 typedef Eigen::Matrix<std::complex<double>, nTest, nTrial> result_t;
64 typedef typename trial_field_t::elem_t elem_t;
67 typedef typename domain_t::xi_t xi_t;
77 template <
class wave_number_t>
78 static result_t
eval(elem_t
const &elem, wave_number_t
const &k)
80 using namespace boost::math::double_constants;
82 #ifdef NIHU_PRINT_DEBUG
83 static bool printed =
false;
85 std::cout <<
"Using helmholtz_2d_SLP_galerkin_face_general" << std::endl;
92 result_t I = result_t::Zero();
96 xi_t u = itu->get_xi();
97 double wu = itu->get_w();
99 result_t NNt0 = test_shape_t::template eval_shape<0>(u) *
100 trial_shape_t::template eval_shape<0>(u).transpose();
101 double J0 = elem.get_dx(u).norm();
105 double v = (itv->get_xi()(0) + 1.) / 2.;
106 double wv = itv->get_w() / 2.;
111 for (
int d = 0; d < 2; ++d) {
113 xi(0) = u(0) + (+1. - u(0)) * v;
114 eta(0) = u(0) + (-1. - u(0)) * v;
117 xi(0) = u(0) + (-1. - u(0)) * v;
118 eta(0) = u(0) + (+1. - u(0)) * v;
121 std::complex<double> G = kernel(elem.get_x(xi), elem.get_x(eta));
122 double Jxi = elem.get_dx(xi).norm();
123 double Jeta = elem.get_dx(eta).norm();
124 auto Nxi = test_shape_t::template eval_shape<0>(xi);
125 auto Neta = trial_shape_t::template eval_shape<0>(eta);
128 result_t F = G * Jxi * Jeta * (Nxi * Neta.transpose());
131 double G0 = -std::log(2. * v * J0) / two_pi;
132 result_t F0 = G0 * J0 * J0 * NNt0;
135 I += (F - F0) * (2. * (1. - v)) * wu * wv;
140 I += 2. * (1.5 - std::log(2. * J0)) / two_pi * J0 * J0 * NNt0 * wu;
154 template <
unsigned expansion_length>
163 template <
class wavenumber_t>
164 static std::complex<double>
eval(
double R, wavenumber_t
const &k)
166 #ifdef NIHU_PRINT_DEBUG
167 static bool printed =
false;
169 std::cout <<
"Using helmholtz_2d_SLP_galerkin_face_constant_line" << std::endl;
174 using namespace boost::math::double_constants;
175 using namespace std::complex_literals;
177 wavenumber_t kR = k * R;
178 wavenumber_t logkR = std::log(kR);
180 auto I = 1. - 2.i/pi * (logkR - 1.5 + euler);
182 wavenumber_t q = -kR * kR;
183 wavenumber_t pow = 1.;
186 for (
unsigned n = 1; n <= expansion_length; ++n) {
187 unsigned d = (n+1) * (2*n+1);
189 wavenumber_t Gn = logkR/d - (4*n + 3)/2./(d*d);
192 I += (Fn-(2.i/pi)*(Gn+(euler - Cn)*Fn)) * pow;
195 return I * (R*R) * -1.0i;
210 template <
class TestField,
class TrialField,
size_t order>
213 typedef TestField test_field_t;
214 typedef TrialField trial_field_t;
216 typedef typename test_field_t::nset_t test_shape_t;
217 typedef typename trial_field_t::nset_t trial_shape_t;
219 static size_t const nTest = test_shape_t::num_nodes;
220 static size_t const nTrial = trial_shape_t::num_nodes;
222 typedef Eigen::Matrix<std::complex<double>, nTest, nTrial> result_t;
224 typedef typename trial_field_t::elem_t elem_t;
227 typedef typename domain_t::xi_t xi_t;
238 template <
class wave_number_t>
239 static result_t
eval(elem_t
const &elem, wave_number_t
const &k)
241 #ifdef NIHU_PRINT_DEBUG
242 static bool printed =
false;
244 std::cout <<
"Using helmholtz_2d_DLP_galerkin_face_general" << std::endl;
249 using namespace boost::math::double_constants;
254 result_t I = result_t::Zero();
258 xi_t v = itv->get_xi();
259 v(0) = (v(0) + 1.) / 2.;
260 double wv = itv->get_w() / 2.;
264 xi_t u = itu->get_xi();
265 double wu = itu->get_w();
268 for (
int d = 0; d < 2; ++d) {
272 xi(0) = u(0) + (+1. - u(0)) * v(0);
273 eta(0) = u(0) + (-1. - u(0)) * v(0);
276 xi(0) = u(0) + (-1. - u(0)) * v(0);
277 eta(0) = u(0) + (+1. - u(0)) * v(0);
280 double Jxi = elem.get_normal(xi).norm();
281 std::complex<double> G = kernel(elem.get_x(xi), elem.get_x(eta), elem.get_normal(eta));
283 auto Nxi = test_shape_t::template eval_shape<0>(xi);
284 auto Neta = trial_shape_t::template eval_shape<0>(eta);
287 result_t F = G * (Jxi * 2 * (1. - v(0))) * (Nxi * Neta.transpose());
308 template <
class TestField,
class TrialField,
size_t order>
311 typedef TestField test_field_t;
312 typedef TrialField trial_field_t;
314 typedef typename test_field_t::nset_t test_shape_t;
315 typedef typename trial_field_t::nset_t trial_shape_t;
317 static size_t const nTest = test_shape_t::num_nodes;
318 static size_t const nTrial = trial_shape_t::num_nodes;
320 typedef Eigen::Matrix<std::complex<double>, nTest, nTrial> result_t;
322 typedef typename trial_field_t::elem_t elem_t;
325 typedef typename domain_t::xi_t xi_t;
336 template <
class wave_number_t>
337 static result_t
eval(elem_t
const &elem, wave_number_t
const &k)
339 #ifdef NIHU_PRINT_DEBUG
340 static bool printed =
false;
342 std::cout <<
"Using helmholtz_2d_DLPt_galerkin_face_general" << std::endl;
347 using namespace boost::math::double_constants;
352 result_t I = result_t::Zero();
356 xi_t v = itv->get_xi();
357 v(0) = (v(0) + 1.) / 2.;
358 double wv = itv->get_w() / 2.;
362 xi_t u = itu->get_xi();
363 double wu = itu->get_w();
366 for (
int d = 0; d < 2; ++d) {
370 xi(0) = u(0) + (+1. - u(0)) * v(0);
371 eta(0) = u(0) + (-1. - u(0)) * v(0);
374 xi(0) = u(0) + (-1. - u(0)) * v(0);
375 eta(0) = u(0) + (+1. - u(0)) * v(0);
378 double Jeta = elem.get_normal(eta).norm();
379 std::complex<double> G = kernel(elem.get_x(xi), elem.get_x(eta), elem.get_normal(xi));
381 auto Nxi = test_shape_t::template eval_shape<0>(xi);
382 auto Neta = trial_shape_t::template eval_shape<0>(eta);
385 result_t F = G * (Jeta * 2 * (1. - v(0))) * (Nxi * Neta.transpose());
407 template <
class TestField,
class TrialField,
size_t order>
410 typedef TestField test_field_t;
411 typedef TrialField trial_field_t;
413 typedef typename test_field_t::nset_t test_shape_t;
414 typedef typename trial_field_t::nset_t trial_shape_t;
416 static size_t const nTest = test_shape_t::num_nodes;
417 static size_t const nTrial = trial_shape_t::num_nodes;
419 typedef Eigen::Matrix<std::complex<double>, nTest, nTrial> result_t;
421 typedef typename trial_field_t::elem_t elem_t;
424 typedef typename domain_t::xi_t xi_t;
429 static result_t F2(xi_t
const &u)
431 using namespace boost::math::double_constants;
432 return test_shape_t::template eval_shape<0>(u)
433 * trial_shape_t::template eval_shape<0>(u).transpose() / (2.0 * two_pi);
440 template <
class wave_number_t>
441 static result_t
eval(elem_t
const &elem, wave_number_t
const &k)
443 #ifdef NIHU_PRINT_DEBUG
444 static bool printed =
false;
446 std::cout <<
"Using helmholtz_2d_HSP_galerkin_face_general" << std::endl;
451 using namespace boost::math::double_constants;
456 result_t I = result_t::Zero();
460 xi_t v = it->get_xi();
461 v(0) = (v(0) + 1.) / 2.;
462 double wv = it->get_w() / 2.;
466 xi_t u = jt->get_xi();
467 double wu = jt->get_w();
470 for (
int d = 0; d < 2; ++d) {
474 xi(0) = u(0) + (+1. - u(0)) * v(0);
475 eta(0) = u(0) + (-1. - u(0)) * v(0);
478 xi(0) = u(0) + (-1. - u(0)) * v(0);
479 eta(0) = u(0) + (+1. - u(0)) * v(0);
482 x_t x = elem.get_x(xi);
483 x_t y = elem.get_x(eta);
484 x_t Jeta = elem.get_normal(eta);
485 x_t Jxi = elem.get_normal(xi);
486 std::complex<double> G = kernel(x, y, Jxi, Jeta);
488 auto Nxi = test_shape_t::template eval_shape<0>(xi);
489 auto Neta = trial_shape_t::template eval_shape<0>(eta);
492 result_t F = G * 2. * (1. - v(0)) * (Nxi * Neta.transpose());
497 I -= 2.0 * F2(u) / (v(0) * v(0)) * wv * wu;
500 I += 2.0 * (F2(xi_t(1.)) + F2(xi_t(-1.0))) / v(0) * wv;
504 xi_t u = jt->get_xi();
505 double wu = jt->get_w();
506 I -= 2.0 * F2(u) * wu;
509 I -= 2.0 * (F2(xi_t(1.0)) * std::log(2.0 * elem.get_dx(xi_t(1.0)).norm())
510 + F2(xi_t(-1.0)) * std::log(2.0 * elem.get_dx(xi_t(-1.0)).norm()));
528 template <
class TestField,
class TrialField,
size_t order>
531 typedef TestField test_field_t;
532 typedef TrialField trial_field_t;
534 typedef typename test_field_t::nset_t test_shape_t;
535 typedef typename test_shape_t::shape_t test_N_t;
536 typedef typename trial_field_t::nset_t trial_shape_t;
537 typedef typename trial_shape_t::shape_t trial_N_t;
539 static size_t const nTest = test_shape_t::num_nodes;
540 static size_t const nTrial = trial_shape_t::num_nodes;
542 typedef Eigen::Matrix<std::complex<double> , nTest, nTrial> result_t;
544 typedef typename trial_field_t::elem_t trial_elem_t;
545 typedef typename test_field_t::elem_t test_elem_t;
547 typedef typename trial_elem_t::domain_t domain_t;
548 typedef typename domain_t::xi_t xi_t;
549 typedef typename trial_elem_t::x_t x_t;
559 template<
class wave_number_t>
561 test_elem_t
const &test_elem,
562 trial_elem_t
const &trial_elem,
563 wave_number_t
const &k)
565 #ifdef NIHU_PRINT_DEBUG
566 static bool printed =
false;
568 std::cout <<
"Using helmholtz_2d_HSP_galerkin_edge_general" << std::endl;
572 using namespace boost::math::double_constants;
577 result_t I = result_t::Zero();
580 if (test_elem.get_nodes()(test_elem_t::num_nodes - 1) == trial_elem.get_nodes()(0))
582 else if (test_elem.get_nodes()(0) == trial_elem.get_nodes()(trial_elem_t::num_nodes - 1))
584 else throw std::logic_error(
"Invalid singular case detected");
587 for (
int d = 0; d < 2; ++d) {
598 bool singular = singular_domain == d;
600 x_t ax0, ay0, Jx0, Jy0;
606 ax0 = test_elem.get_dx(xi0);
607 ay0 = trial_elem.get_dx(eta0);
608 Jx0 = test_elem.get_normal(xi0);
609 Jy0 = trial_elem.get_normal(eta0);
610 Nx0 = test_shape_t::template eval_shape<0>(xi0);
611 Ny0 = trial_shape_t::template eval_shape<0>(eta0);
616 xi_t u = itu->get_xi();
617 double wu = itu->get_w();
624 x_t svec = ay0 * (u - eta0)(0) - ax0 * (u - xi0)(0);
626 x_t es = svec.normalized();
627 F1 = (Jx0.dot(Jy0) - 2 * es.dot(Jx0) * es.dot(Jy0)) / pi / s / s *
628 (Nx0 * Ny0.transpose());
633 xi_t v = itv->get_xi();
635 v(0) = (v(0) + 1.) / 2.;
636 double wv = itv->get_w() / 2.;
639 xi_t xi = xi0 + (u - xi0) * v;
640 xi_t eta = eta0 + (u - eta0) * v;
643 x_t x = test_elem.get_x(xi);
644 x_t y = trial_elem.get_x(eta);
645 x_t Jxi = test_elem.get_normal(xi);
646 x_t Jeta = trial_elem.get_normal(eta);
647 std::complex<double> G = kernel(x, y, Jxi, Jeta);
649 test_N_t Nxi = test_shape_t::template eval_shape<0>(xi);
650 trial_N_t Neta = trial_shape_t::template eval_shape<0>(eta);
653 result_t F = G * 2. * v(0) * (Nxi * Neta.transpose());
659 I -= F1 / v(0) * wv * wu;
664 I += F1 * std::log(s) * wu;
678 template <
class WaveNumber,
class TestField,
class TrialField>
681 typename std::enable_if<
682 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value &&
683 !(is_constant_line<TrialField>::value && is_constant_line<TestField>::value)
695 template <
class result_t>
704 trial_field.
get_elem(), kernel.derived().get_wave_number());
713 template <
class WaveNumber,
class TestField,
class TrialField>
716 typename std::enable_if<
717 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value &&
718 is_constant_line<TrialField>::value &&
719 is_constant_line<TestField>::value
731 template <
class result_t>
739 auto const &elem = trial_field.
get_elem();
740 double R = (elem.get_coords().col(1) - elem.get_coords().col(0)).norm()/2.;
742 R, kernel.derived().get_wave_number());
753 template <
class TestField,
class TrialField,
class WaveNumber>
756 typename std::enable_if<
757 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value &&
758 !std::is_same<typename TrialField::elem_t::lset_t, line_1_shape_set>::value
770 template <
class result_t>
779 test_field.
get_elem(), kernel.derived().get_wave_number());
789 template <
class TestField,
class TrialField,
class WaveNumber>
792 typename std::enable_if<
793 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value &&
794 !std::is_same<typename TrialField::elem_t::lset_t, line_1_shape_set>::value
806 template <
class result_t>
815 test_field.
get_elem(), kernel.derived().get_wave_number());
825 template <
class TestField,
class TrialField,
class WaveNumber>
828 typename std::enable_if<
829 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value
841 template <
class result_t>
850 test_field.
get_elem(), kernel.derived().get_wave_number());
859 template <
class TestField,
class TrialField,
class WaveNumber>
862 typename std::enable_if<
863 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value
875 template <
class result_t>
886 kernel.derived().get_wave_number());
893 #endif // NIHU_HELMHOLTZ_2D_SINGULAR_DOUBLE_INTEGRALS_HPP_INCLUDED