21 #ifndef NIHU_HELMHOLTZ_2D_SINGULAR_COLLOCATION_INTEGRALS_HPP_INCLUDED
22 #define NIHU_HELMHOLTZ_2D_SINGULAR_COLLOCATION_INTEGRALS_HPP_INCLUDED
24 #include <boost/math/constants/constants.hpp>
27 #include "field_type_helpers.hpp"
30 #include "normal_derivative_singular_integrals.hpp"
31 #include "../core/match_types.hpp"
32 #include "../core/singular_integral_shortcut.hpp"
33 #include "../util/math_functions.hpp"
47 template <
class TestField,
class TrialField,
size_t order>
50 typedef TestField test_field_t;
51 typedef TrialField trial_field_t;
53 typedef typename test_field_t::nset_t test_shape_t;
54 typedef typename trial_field_t::nset_t trial_shape_t;
56 static size_t const nTest = test_shape_t::num_nodes;
57 static size_t const nTrial = trial_shape_t::num_nodes;
59 typedef Eigen::Matrix<std::complex<double>, nTest, nTrial> result_t;
61 typedef typename trial_field_t::elem_t elem_t;
64 typedef typename domain_t::xi_t xi_t;
76 template <
class WaveNumber>
77 static result_t
eval(elem_t
const &elem, WaveNumber
const &k)
79 #ifdef NIHU_PRINT_DEBUG
80 static bool printed =
false;
82 std::cout <<
"Using helmholtz_2d_SLP_collocation_curved" << std::endl;
87 using namespace boost::math::double_constants;
91 result_t result = result_t::Zero();
94 for (
size_t i = 0; i < nTest; ++i) {
95 xi_t
const &xi0 = test_shape_t::corner_at(i);
98 x_t x = elem.get_x(xi0);
101 for (
int dom = 0; dom < 2; ++dom) {
102 xi_t xi_lim = domain_t::get_corner(dom);
103 double jac = std::abs(xi_lim(0) - xi0(0));
108 double v = (q.get_xi()(0) + 1.) / 2.;
109 double wv = q.get_w() / 2;
111 xi_t eta = xi0 + v * (xi_lim - xi0);
112 double r = (elem.get_x(eta) - x).norm();
113 double Jeta = elem.get_dx(eta).norm();
116 std::complex<double> Gtot;
117 kernel.template eval<0>(r, &Gtot);
118 double Glog = -std::log(v) / two_pi;
119 std::complex<double> Greg = Gtot - Glog;
122 result.row(i) += Greg * Jeta * jac * wv
123 * trial_shape_t::template eval_shape<0>(eta);
128 double v = q.get_xi()(0);
129 double wv = q.get_w();
131 xi_t eta = xi0 + v * (xi_lim - xi0);
132 double Jeta = elem.get_dx(eta).norm();
135 double Glog = 1.0 / two_pi;
138 result.row(i) += Glog * Jeta * jac * wv
139 * trial_shape_t::template eval_shape<0>(eta);
155 template <
unsigned expansion_length>
165 template <
class wavenumber_t>
166 static std::complex<double>
eval(
169 wavenumber_t
const &k)
171 #ifdef NIHU_PRINT_DEBUG
172 static bool printed =
false;
174 std::cout <<
"Using helmholtz_2d_SLP_collocation_constant_line" << std::endl;
179 using namespace boost::math::double_constants;
181 std::complex<double>
const c(euler, half_pi);
184 auto R = (x0 - elem.get_coords().col(0)).norm();
187 auto clnq = c + std::log(Q);
192 for (
unsigned n = 1; n <= expansion_length; ++n) {
195 res += B / (2 * n + 1) * (clnq - Cn - 1. / (2 * n + 1));
198 return -R / pi * res;
204 template <
class TestField,
class TrialField,
size_t order>
207 typedef TestField test_field_t;
208 typedef TrialField trial_field_t;
210 typedef typename test_field_t::nset_t test_shape_t;
211 typedef typename trial_field_t::nset_t trial_shape_t;
213 static size_t const nTest = test_shape_t::num_nodes;
214 static size_t const nTrial = trial_shape_t::num_nodes;
216 typedef Eigen::Matrix<std::complex<double>, nTest, nTrial> result_t;
218 typedef typename trial_field_t::elem_t elem_t;
221 typedef typename domain_t::xi_t xi_t;
228 template <
class wave_number_t>
229 static result_t
eval(elem_t
const &elem, wave_number_t
const &k)
231 #ifdef NIHU_PRINT_DEBUG
232 static bool printed =
false;
234 std::cout <<
"Using helmholtz_2d_DLP_collocation_general" << std::endl;
239 result_t result = result_t::Zero();
244 for (
size_t i = 0; i < nTest; ++i) {
245 xi_t xi0 = test_shape_t::corner_at(i);
248 x_t x = elem.get_x(xi0);
250 for (
size_t dom = 0; dom < 2; ++dom) {
251 xi_t
const &a = domain_t::get_corner(dom);
254 for (
auto it = quadr_t::quadrature.begin(); it != quadr_t::quadrature.end(); ++it) {
256 xi_t xi = it->get_xi() * ((xi0(0)-a(0))/2.) + (xi0+a)/2.;
257 double w = it->get_w() * std::abs(xi0(0)-a(0))/2.;
258 double rho = xi(0) - xi0(0);
261 x_t y = elem.get_x(xi);
262 x_t Jyvec = elem.get_normal(xi);
265 std::complex<double> G = kernel(x, y, Jyvec);
267 auto N = trial_shape_t::template eval_shape<0>(xi);
271 result.row(i) += F * w;
286 template <
class TestField,
class TrialField,
size_t order>
289 typedef TestField test_field_t;
290 typedef TrialField trial_field_t;
292 typedef typename test_field_t::nset_t test_shape_t;
293 typedef typename trial_field_t::nset_t trial_shape_t;
295 static size_t const nTest = test_shape_t::num_nodes;
296 static size_t const nTrial = trial_shape_t::num_nodes;
298 typedef Eigen::Matrix<std::complex<double>, nTest, nTrial> result_t;
300 typedef typename trial_field_t::elem_t elem_t;
303 typedef typename domain_t::xi_t xi_t;
309 template <
class wave_number_t>
310 static result_t
eval(elem_t
const &elem, wave_number_t
const &k)
312 #ifdef NIHU_PRINT_DEBUG
313 static bool printed =
false;
315 std::cout <<
"Using helmholtz_2d_DLPt_collocation_general" << std::endl;
320 result_t result = result_t::Zero();
325 for (
size_t i = 0; i < nTest; ++i)
327 xi_t xi0 = test_shape_t::corner_at(i);
330 x_t x = elem.get_x(xi0);
331 x_t Jxvec = elem.get_normal(xi0);
332 x_t nx = Jxvec.normalized();
334 for (
size_t dom = 0; dom < 2; ++dom) {
335 xi_t
const &a = domain_t::get_corner(dom);
338 for (
auto it = quadr_t::quadrature.begin(); it != quadr_t::quadrature.end(); ++it) {
340 xi_t xi = it->get_xi() * ((xi0(0)-a(0))/2.) + (xi0+a)/2.;
341 double w = it->get_w() * std::abs(xi0(0)-a(0)) / 2.;
342 double rho = xi(0) - xi0(0);
345 x_t y = elem.get_x(xi);
346 x_t Jyvec = elem.get_normal(xi);
347 double jac = Jyvec.norm();
350 std::complex<double> G = kernel(x, y, nx);
352 auto N = trial_shape_t::template eval_shape<0>(xi);
353 auto F = G * jac * N;
356 result.row(i) += F * w;
370 template <
class TestField,
class TrialField,
size_t order>
373 typedef TestField test_field_t;
374 typedef TrialField trial_field_t;
376 typedef typename test_field_t::nset_t test_shape_t;
377 typedef typename trial_field_t::nset_t trial_shape_t;
379 static size_t const nTest = test_shape_t::num_nodes;
380 static size_t const nTrial = trial_shape_t::num_nodes;
382 typedef Eigen::Matrix<std::complex<double>, nTest, nTrial> result_t;
384 typedef typename trial_field_t::elem_t elem_t;
387 typedef typename domain_t::xi_t xi_t;
398 template <
class WaveNumber>
399 static result_t
eval(elem_t
const &elem, WaveNumber
const &k)
401 #ifdef NIHU_PRINT_DEBUG
402 static bool printed =
false;
404 std::cout <<
"Using helmholtz_2d_HSP_collocation_general" << std::endl;
409 using namespace boost::math::double_constants;
412 result_t result = result_t::Zero();
418 xi_t
const &a = domain_t::get_corner(0);
419 xi_t
const &b = domain_t::get_corner(1);
422 for (
size_t i = 0; i < nTest; ++i)
425 xi_t
const &xi0 = test_shape_t::corner_at(i);
428 auto N0 = trial_shape_t::template eval_shape<0>(xi0);
429 auto N1 = trial_shape_t::template eval_shape<1>(xi0);
432 x_t x = elem.get_x(xi0);
433 x_t Jxvec = elem.get_normal(xi0);
434 x_t nx = Jxvec.normalized();
435 double jac0 = Jxvec.norm();
438 for (
auto it = quadr_t::quadrature.begin(); it != quadr_t::quadrature.end(); ++it)
441 xi_t xi = it->get_xi() * ((xi0(0)-a(0))/2.) + (xi0+a)/2.;
442 double w = it->get_w() * ((xi0(0)-a(0))/2.);
443 double rho = xi(0) - xi0(0);
446 x_t y = elem.get_x(xi);
447 x_t Jyvec = elem.get_normal(xi);
448 x_t ny = Jyvec.normalized();
449 double jac = Jyvec.norm();
452 std::complex<double> G = kernel(x, y, nx, ny);
454 auto N = trial_shape_t::template eval_shape<0>(xi);
455 auto F = (G * jac) * N;
458 (N0/rho + N1)/rho/jac0
459 - k*k/2. * N0 * jac0 * std::log(std::abs(rho) * jac0)
463 result.row(i) += (F - F0) * w;
467 for (
auto it = quadr_t::quadrature.begin(); it != quadr_t::quadrature.end(); ++it)
470 xi_t xi = it->get_xi() * ((b(0)-xi0(0))/2.) + (xi0+b)/2.;
471 double w = it->get_w() * ((b(0)-xi0(0))/2.);
472 double rho = xi(0) - xi0(0);
475 x_t y = elem.get_x(xi);
476 x_t Jyvec = elem.get_normal(xi);
477 x_t ny = Jyvec.normalized();
478 double jac = Jyvec.norm();
481 std::complex<double> G = kernel(x, y, nx, ny);
483 auto N = trial_shape_t::template eval_shape<0>(xi);
484 auto F = (G * jac) * N;
487 (N0/rho + N1)/rho/jac0
488 - k*k/2. * N0 * jac0 * std::log(std::abs(rho) * jac0)
492 result.row(i) += (F - F0) * w;
496 double d1 = std::abs(a(0) - xi0(0)) * jac0;
497 double d2 = std::abs(b(0) - xi0(0)) * jac0;
499 ((1./(a(0)-xi0(0)) - 1./(b(0)-xi0(0))) * N0 +
500 std::log(std::abs((b(0)-xi0(0)) / (a(0)-xi0(0)))) * N1) / jac0
502 N0 * (d1 * (std::log(d1) - 1.) + d2 * (std::log(d2) - 1.))
511 template <
class TestField,
class TrialField,
size_t order>
514 typedef TestField test_field_t;
515 typedef TrialField trial_field_t;
517 typedef typename test_field_t::nset_t test_shape_t;
518 typedef typename trial_field_t::nset_t trial_shape_t;
520 static size_t const nTest = test_shape_t::num_nodes;
521 static size_t const nTrial = trial_shape_t::num_nodes;
523 typedef Eigen::Matrix<std::complex<double>, nTest, nTrial> result_t;
528 typedef typename domain_t::xi_t xi_t;
539 template <
class WaveNumber>
540 static result_t
eval(
elem_t const &elem, WaveNumber
const &k)
542 #ifdef NIHU_PRINT_DEBUG
543 static bool printed =
false;
545 std::cout <<
"Using helmholtz_2d_HSP_collocation_straight_line" << std::endl;
550 using namespace boost::math::double_constants;
553 result_t result = result_t::Zero();
559 xi_t
const &a = domain_t::get_corner(0);
560 xi_t
const &b = domain_t::get_corner(1);
563 for (
size_t i = 0; i < nTest; ++i)
566 xi_t
const &xi0 = test_shape_t::corner_at(i);
569 auto N0 = trial_shape_t::template eval_shape<0>(xi0);
570 auto N1 = trial_shape_t::template eval_shape<1>(xi0);
573 x_t x = elem.get_x(xi0);
575 x_t n = Jvec.normalized();
576 double jac = Jvec.norm();
579 for (
auto it = quadr_t::quadrature.begin(); it != quadr_t::quadrature.end(); ++it)
582 xi_t xi = it->get_xi() * ((xi0(0)-a(0))/2.) + (xi0+a)/2.;
583 double w = it->get_w() * ((xi0(0)-a(0))/2.);
584 double rho = xi(0) - xi0(0);
587 x_t y = elem.get_x(xi);
590 std::complex<double> G = kernel(x, y, n, n);
592 auto N = trial_shape_t::template eval_shape<0>(xi);
593 auto F = (G * jac) * N;
596 (N0/rho + N1)/rho/jac
597 - k*k/2. * N0 * jac * std::log(std::abs(rho) * jac)
601 result.row(i) += (F - F0) * w;
605 for (
auto it = quadr_t::quadrature.begin(); it != quadr_t::quadrature.end(); ++it)
608 xi_t xi = it->get_xi() * ((b(0)-xi0(0))/2.) + (xi0+b)/2.;
609 double w = it->get_w() * ((b(0)-xi0(0))/2.);
610 double rho = xi(0) - xi0(0);
613 x_t y = elem.get_x(xi);
616 std::complex<double> G = kernel(x, y, n, n);
618 auto N = trial_shape_t::template eval_shape<0>(xi);
619 auto F = (G * jac) * N;
622 (N0/rho + N1)/rho/jac
623 - k*k/2. * N0 * jac * std::log(std::abs(rho) * jac)
627 result.row(i) += (F - F0) * w;
631 double d1 = std::abs(a(0) - xi0(0)) * jac;
632 double d2 = std::abs(b(0) - xi0(0)) * jac;
634 ((1./(a(0)-xi0(0)) - 1./(b(0)-xi0(0))) * N0 +
635 std::log(std::abs((b(0)-xi0(0)) / (a(0)-xi0(0)))) * N1) / jac
637 N0 * (d1 * (std::log(d1) - 1.) + d2 * (std::log(d2) - 1.))
649 template <
class WaveNumber,
class TestField,
class TrialField>
652 typename std::enable_if<
653 is_collocational<TestField, TrialField>::value &&
654 is_constant_line<TrialField>::value
666 template <
class result_t>
676 trial_field.
get_elem().get_center(),
677 kernel.derived().get_wave_number());
688 template <
class WaveNumber,
class TestField,
class TrialField>
691 typename std::enable_if<
692 is_collocational<TestField, TrialField>::value &&
693 !is_constant_line<TrialField>::value
705 template <
class result_t>
714 TestField, TrialField, 30
716 kernel.derived().get_wave_number());
727 template <
class WaveNumber,
class TestField,
class TrialField>
730 typename std::enable_if<
731 is_collocational<TestField, TrialField>::value &&
732 !(std::is_same<typename TrialField::elem_t::lset_t, line_1_shape_set>::value)
744 template <
class result_t>
754 kernel.derived().get_wave_number());
765 template <
class WaveNumber,
class TestField,
class TrialField>
768 typename std::enable_if<
769 is_collocational<TestField, TrialField>::value &&
770 !(std::is_same<typename TrialField::elem_t::lset_t, line_1_shape_set>::value)
782 template <
class result_t>
792 kernel.derived().get_wave_number());
803 template <
class WaveNumber,
class TestField,
class TrialField>
806 typename std::enable_if<
807 is_collocational<TestField, TrialField>::value &&
808 std::is_same<typename TrialField::elem_t::lset_t, line_1_shape_set>::value
820 template <
class result_t>
830 kernel.derived().get_wave_number());
841 template <
class WaveNumber,
class TestField,
class TrialField>
844 typename std::enable_if<
845 is_collocational<TestField, TrialField>::value &&
846 !std::is_same<typename TrialField::elem_t::lset_t, line_1_shape_set>::value
858 template <
class result_t>
868 kernel.derived().get_wave_number());
876 #endif // NIHU_HELMHOLTZ_2D_SINGULAR_COLLOCATION_INTEGRALS_HPP_INCLUDED