22 #ifndef LAPLACE_2D_SINGULAR_DOUBLE_INTEGRALS_HPP_INCLUDED
23 #define LAPLACE_2D_SINGULAR_DOUBLE_INTEGRALS_HPP_INCLUDED
25 #include "../core/match_types.hpp"
26 #include "../core/singular_integral_shortcut.hpp"
27 #include "../util/math_functions.hpp"
28 #include "field_type_helpers.hpp"
31 #include "normal_derivative_singular_integrals.hpp"
32 #include "quadrature_store_helper.hpp"
34 #include <boost/math/constants/constants.hpp>
36 #define NIHU_PRINT_DEBUG
38 #ifdef NIHU_PRINT_DEBUG
49 template <
class TestField,
class TrialField,
size_t order>
52 typedef TestField test_field_t;
53 typedef TrialField trial_field_t;
55 typedef typename test_field_t::nset_t test_shape_t;
56 typedef typename trial_field_t::nset_t trial_shape_t;
58 static size_t const nTest = test_shape_t::num_nodes;
59 static size_t const nTrial = trial_shape_t::num_nodes;
61 typedef Eigen::Matrix<double, nTest, nTrial> result_t;
63 typedef typename trial_field_t::elem_t elem_t;
66 typedef typename domain_t::xi_t xi_t;
70 static size_t const inner_order =
71 elem_t::lset_t::jacobian_order * 2 +
72 elem_t::lset_t::jacobian_order * 2 +
73 trial_field_t::nset_t::polynomial_order +
74 test_field_t::nset_t::polynomial_order +
82 static result_t
eval(elem_t
const &elem)
84 using namespace boost::math::double_constants;
86 #ifdef NIHU_PRINT_DEBUG
87 static bool printed =
false;
89 std::cout <<
"Using laplace_2d_SLP_galerkin_face_general, inner order: " << inner_order << std::endl;
94 result_t I = result_t::Zero();
98 double u = qu.get_xi()(0);
99 double wu = qu.get_w();
103 double v = (qv.get_xi()(0) + 1.) / 2.;
104 double wv = qv.get_w() / 2.;
109 for (
int d = 0; d < 2; ++d) {
111 xi(0) = u + (+1. - u) * v;
112 eta(0) = u + (-1. - u) * v;
115 xi(0) = u + (-1. - u) * v;
116 eta(0) = u + (+1. - u) * v;
119 x_t x = elem.get_x(xi);
120 x_t y = elem.get_x(eta);
121 double r = (y - x).norm();
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 double Greg = -std::log(r / v) / two_pi;
130 I += Greg * Jxi * Jeta * (2. * (1. - v)) * wu * wv
131 * (Nxi * Neta.transpose());
137 double v = quad.get_xi()(0);
138 double wv = quad.get_w();
143 for (
int d = 0; d < 2; ++d) {
145 xi(0) = u + (+1. - u) * v;
146 eta(0) = u + (-1. - u) * v;
149 xi(0) = u + (-1. - u) * v;
150 eta(0) = u + (+1. - u) * v;
153 double Jxi = elem.get_dx(xi).norm();
154 double Jeta = elem.get_dx(eta).norm();
155 auto Nxi = test_shape_t::template eval_shape<0>(xi);
156 auto Neta = trial_shape_t::template eval_shape<0>(eta);
158 double Gsing = 1.0 / two_pi;
161 result_t F = Gsing * Jxi * Jeta * (Nxi * Neta.transpose());
162 I += F * (2. * (1. - v)) * wu * wv;
180 using namespace boost::math::double_constants;
182 #ifdef NIHU_PRINT_DEBUG
183 static bool printed =
false;
185 std::cout <<
"Using laplace_2d_SLP_galerkin_face_constant_line" << std::endl;
190 auto const &
C = elem.get_coords();
191 double d = (
C.col(1) -
C.col(0)).norm();
192 return d * d * (1.5 - std::log(d)) / two_pi;
206 using namespace boost::math::double_constants;
208 #ifdef NIHU_PRINT_DEBUG
209 static bool printed =
false;
211 std::cout <<
"Using laplace_2d_SLP_galerkin_face_linear_line" << std::endl;
216 auto const &
C = elem.get_coords();
217 double d = (
C.col(1) -
C.col(0)).norm();
218 double c = d * d / (8. * pi);
219 double lnd = std::log(d);
220 i1 = c * (1.75 - lnd);
221 i2 = c * (1.25 - lnd);
234 template <
class TestField,
class TrialField,
size_t order>
237 typedef TestField test_field_t;
238 typedef TrialField trial_field_t;
240 typedef typename test_field_t::nset_t test_shape_t;
241 typedef typename test_shape_t::shape_t test_N_t;
242 typedef typename trial_field_t::nset_t trial_shape_t;
243 typedef typename trial_shape_t::shape_t trial_N_t;
245 static size_t const nTest = test_shape_t::num_nodes;
246 static size_t const nTrial = trial_shape_t::num_nodes;
248 typedef Eigen::Matrix<double, nTest, nTrial> result_t;
250 typedef typename trial_field_t::elem_t trial_elem_t;
251 typedef typename test_field_t::elem_t test_elem_t;
253 typedef typename trial_elem_t::domain_t domain_t;
254 typedef typename domain_t::xi_t xi_t;
255 typedef typename trial_elem_t::x_t x_t;
258 static size_t const inner_order =
259 trial_elem_t::lset_t::jacobian_order * 2 +
260 test_elem_t::lset_t::jacobian_order * 2 +
261 trial_field_t::nset_t::polynomial_order +
262 test_field_t::nset_t::polynomial_order +
272 test_elem_t
const &test_elem,
273 trial_elem_t
const &trial_elem)
275 #ifdef NIHU_PRINT_DEBUG
276 static bool printed =
false;
278 std::cout <<
"Using laplace_2d_SLP_galerkin_edge_general, inner order: " << inner_order << std::endl;
282 using namespace boost::math::double_constants;
286 result_t I = result_t::Zero();
289 if (test_elem.get_nodes()(test_elem_t::num_nodes - 1) == trial_elem.get_nodes()(0))
291 else if (test_elem.get_nodes()(0) == trial_elem.get_nodes()(trial_elem_t::num_nodes - 1))
293 else throw std::logic_error(
"Invalid singular case detected");
296 for (
int d = 0; d < 2; ++d) {
307 bool singular = singular_domain == d;
310 for (
auto const &qu : reg_quadrature_t::quadrature) {
311 xi_t u = qu.get_xi();
312 double wu = qu.get_w();
315 for (
auto const &qv : reg_quadrature_t::quadrature) {
316 double v = (qv.get_xi()(0) + 1.) / 2.;
317 double wv = qv.get_w() / 2.;
320 xi_t xi = xi0 + (u - xi0) * v;
321 xi_t eta = eta0 + (u - eta0) * v;
324 double r = (trial_elem.get_x(eta) - test_elem.get_x(xi)).norm();
325 double G = -std::log(r) / two_pi;
327 G -= -std::log(v) / two_pi;
329 double Jxi = test_elem.get_normal(xi).norm();
330 double Jeta = trial_elem.get_normal(eta).norm();
331 test_N_t Nxi = test_shape_t::template eval_shape<0>(xi);
332 trial_N_t Neta = trial_shape_t::template eval_shape<0>(eta);
335 I += G * Jxi * Jeta * (Nxi * Neta.transpose()) * 2. * v * wv * wu;
343 double v = qv.get_xi()(0);
344 double wv = qv.get_w();
347 xi_t xi = xi0 + (u - xi0) * v;
348 xi_t eta = eta0 + (u - eta0) * v;
351 double G = 1.0 / two_pi;
352 double Jxi = test_elem.get_normal(xi).norm();
353 double Jeta = trial_elem.get_normal(eta).norm();
354 test_N_t Nxi = test_shape_t::template eval_shape<0>(xi);
355 trial_N_t Neta = trial_shape_t::template eval_shape<0>(eta);
358 I += G * Jxi * Jeta * (Nxi * Neta.transpose()) * 2. * v * wv * wu;
371 static double qfunc(
double a,
double phi)
373 using namespace boost::math::double_constants;
375 if (std::abs(phi) < 1e-3)
377 double cotphi = std::tan(half_pi - phi);
378 return std::atan(a / std::sin(phi) + cotphi) - std::atan(cotphi);
388 using namespace boost::math::double_constants;
390 #ifdef NIHU_PRINT_DEBUG
391 static bool printed =
false;
393 std::cout <<
"Using laplace_2d_SLP_galerkin_edge_constant_line" << std::endl;
399 auto const &C1 = elem1.get_coords();
400 auto const &C2 = elem2.get_coords();
402 auto r1vec = (C1.col(1) - C1.col(0)).
eval(), r2vec = (C2.col(1) - C2.col(0)).
eval();
404 double r1 = r1vec.norm(), r2 = r2vec.norm();
406 double phi = std::asin(r1vec(0) * r2vec(1) - r2vec(0) * r1vec(1)) / (r1 * r2);
408 double r3 = std::sqrt(r1 * r1 + 2 * r1 * r2 * std::cos(phi) + r2 * r2);
410 r1 * r2 * (3. - 2. * std::log(r3))
411 + std::cos(phi) * (r1 * r1 * std::log(r1 / r3) + r2 * r2 * std::log(r2 / r3))
412 - std::sin(phi) * (r1 * r1 * qfunc(r2 / r1, phi) + r2 * r2 * qfunc(r1 / r2, phi))
428 template <
class TestField,
class TrialField,
size_t order>
431 typedef TestField test_field_t;
432 typedef TrialField trial_field_t;
434 typedef typename test_field_t::nset_t test_shape_t;
435 typedef typename trial_field_t::nset_t trial_shape_t;
437 static size_t const nTest = test_shape_t::num_nodes;
438 static size_t const nTrial = trial_shape_t::num_nodes;
440 typedef Eigen::Matrix<double, nTest, nTrial> result_t;
442 typedef typename trial_field_t::elem_t elem_t;
445 typedef typename domain_t::xi_t xi_t;
456 static result_t
eval(elem_t
const &elem)
458 #ifdef NIHU_PRINT_DEBUG
459 static bool printed =
false;
461 std::cout <<
"Using laplace_2d_DLP_galerkin_face_general" << std::endl;
466 using namespace boost::math::double_constants;
470 result_t I = result_t::Zero();
474 xi_t v = qv.get_xi();
475 v(0) = (v(0) + 1.) / 2.;
476 double wv = qv.get_w() / 2.;
480 xi_t u = qu.get_xi();
481 double wu = qu.get_w();
484 for (
int d = 0; d < 2; ++d) {
488 xi(0) = u(0) + (+1. - u(0)) * v(0);
489 eta(0) = u(0) + (-1. - u(0)) * v(0);
492 xi(0) = u(0) + (-1. - u(0)) * v(0);
493 eta(0) = u(0) + (+1. - u(0)) * v(0);
496 double Jxi = elem.get_normal(xi).norm();
497 double G = kernel(elem.get_x(xi), elem.get_x(eta), elem.get_normal(eta));
499 auto Nxi = test_shape_t::template eval_shape<0>(xi);
500 auto Neta = trial_shape_t::template eval_shape<0>(eta);
503 result_t F = G * Jxi * 2 * (1. - v(0)) * (Nxi * Neta.transpose());
519 static double qfunc(
double a,
double phi)
521 using namespace boost::math::double_constants;
523 if (std::abs(phi) < 1e-3)
525 double cotphi = std::tan(half_pi - phi);
526 return std::atan(a / std::sin(phi) + cotphi) - std::atan(cotphi);
536 using namespace boost::math::double_constants;
538 #ifdef NIHU_PRINT_DEBUG
539 static bool printed =
false;
541 std::cout <<
"Using laplace_2d_DLP_galerkin_edge_constant_line" << std::endl;
547 auto const &C1 = elem1.get_coords();
548 auto const &C2 = elem2.get_coords();
550 auto r1vec = (C1.col(1) - C1.col(0)).
eval(), r2vec = (C2.col(1) - C2.col(0)).
eval();
552 double r1 = r1vec.norm(), r2 = r2vec.norm();
554 double phi = std::asin(r1vec(0) * r2vec(1) - r2vec(0) * r1vec(1)) / (r1 * r2);
556 double r3 = std::sqrt(r1 * r1 + 2 * r1 * r2 * std::cos(phi) + r2 * r2);
558 r2 * std::cos(phi) * qfunc(r1 / r2, phi)
559 - r1 * qfunc(r2 / r1, phi)
560 + r2 * std::sin(phi) * std::log(r2 / r3)
563 if (elem1.get_nodes()(0) == elem2.get_nodes()(1))
581 template <
class TestField,
class TrialField,
size_t order>
584 typedef TestField test_field_t;
585 typedef TrialField trial_field_t;
587 typedef typename test_field_t::nset_t test_shape_t;
588 typedef typename trial_field_t::nset_t trial_shape_t;
590 static size_t const nTest = test_shape_t::num_nodes;
591 static size_t const nTrial = trial_shape_t::num_nodes;
593 typedef Eigen::Matrix<double, nTest, nTrial> result_t;
595 typedef typename trial_field_t::elem_t elem_t;
598 typedef typename domain_t::xi_t xi_t;
609 static result_t
eval(elem_t
const &elem)
611 #ifdef NIHU_PRINT_DEBUG
612 static bool printed =
false;
614 std::cout <<
"Using laplace_2d_DLPt_galerkin_face_general" << std::endl;
619 using namespace boost::math::double_constants;
623 result_t I = result_t::Zero();
627 xi_t v = qv.get_xi();
628 v(0) = (v(0) + 1.) / 2.;
629 double wv = qv.get_w() / 2.;
633 xi_t u = qu.get_xi();
634 double wu = qu.get_w();
637 for (
int d = 0; d < 2; ++d) {
641 xi(0) = u(0) + (+1. - u(0)) * v(0);
642 eta(0) = u(0) + (-1. - u(0)) * v(0);
645 xi(0) = u(0) + (-1. - u(0)) * v(0);
646 eta(0) = u(0) + (+1. - u(0)) * v(0);
649 double Jeta = elem.get_normal(xi).norm();
650 double G = kernel(elem.get_x(xi), elem.get_x(eta), elem.get_normal(xi));
652 auto Nxi = test_shape_t::template eval_shape<0>(xi);
653 auto Neta = trial_shape_t::template eval_shape<0>(eta);
656 result_t F = G * Jeta * 2 * (1. - v(0)) * (Nxi * Neta.transpose());
678 template <
class TestField,
class TrialField,
size_t order>
681 typedef TestField test_field_t;
682 typedef TrialField trial_field_t;
684 typedef typename test_field_t::nset_t test_shape_t;
685 typedef typename trial_field_t::nset_t trial_shape_t;
687 static size_t const nTest = test_shape_t::num_nodes;
688 static size_t const nTrial = trial_shape_t::num_nodes;
690 typedef Eigen::Matrix<double, nTest, nTrial> result_t;
692 typedef typename trial_field_t::elem_t elem_t;
695 typedef typename domain_t::xi_t xi_t;
702 static result_t F2(xi_t
const &u)
704 using namespace boost::math::double_constants;
705 return test_shape_t::template eval_shape<0>(u)
706 * trial_shape_t::template eval_shape<0>(u).transpose()
714 static result_t
eval(elem_t
const &elem)
716 #ifdef NIHU_PRINT_DEBUG
717 static bool printed =
false;
719 std::cout <<
"Using laplace_2d_HSP_galerkin_face_general" << std::endl;
724 using namespace boost::math::double_constants;
728 result_t I = result_t::Zero();
732 xi_t v = qv.get_xi();
733 v(0) = (v(0) + 1.) / 2.;
734 double wv = qv.get_w() / 2.;
738 xi_t u = jt->get_xi();
739 double wu = jt->get_w();
742 for (
int d = 0; d < 2; ++d) {
746 xi(0) = u(0) + (+1. - u(0)) * v(0);
747 eta(0) = u(0) + (-1. - u(0)) * v(0);
750 xi(0) = u(0) + (-1. - u(0)) * v(0);
751 eta(0) = u(0) + (+1. - u(0)) * v(0);
754 x_t x = elem.get_x(xi);
755 x_t y = elem.get_x(eta);
756 x_t Jeta = elem.get_normal(eta);
757 x_t Jxi = elem.get_normal(xi);
758 double G = kernel(x, y, Jxi, Jeta);
760 auto Nxi = test_shape_t::template eval_shape<0>(xi);
761 auto Neta = trial_shape_t::template eval_shape<0>(eta);
764 result_t F = G * 2 * (1. - v(0)) * (Nxi * Neta.transpose());
769 I -= 2.0 * F2(u) / (v(0) * v(0)) * wv * wu;
772 I += 2.0 * (F2(xi_t(1.)) + F2(xi_t(-1.0))) / v(0) * wv;
776 xi_t u = jt->get_xi();
777 double wu = jt->get_w();
778 I -= 2.0 * F2(u) * wu;
781 I -= 2.0 * (F2(xi_t(1.0)) * std::log(2.0 * elem.get_dx(xi_t(1.0)).norm())
782 + F2(xi_t(-1.0)) * std::log(2.0 * elem.get_dx(xi_t(-1.0)).norm()));
803 #ifdef NIHU_PRINT_DEBUG
804 static bool printed =
false;
806 std::cout <<
"Using laplace_2d_HSP_galerkin_face_constant_line" << std::endl;
811 using namespace boost::math::double_constants;
813 return -(1.0 + std::log(2.0 *
J)) / pi;
828 template <
class TestField,
class TrialField,
size_t order>
831 typedef TestField test_field_t;
832 typedef TrialField trial_field_t;
834 typedef typename test_field_t::nset_t test_shape_t;
835 typedef typename test_shape_t::shape_t test_N_t;
836 typedef typename trial_field_t::nset_t trial_shape_t;
837 typedef typename trial_shape_t::shape_t trial_N_t;
839 static size_t const nTest = test_shape_t::num_nodes;
840 static size_t const nTrial = trial_shape_t::num_nodes;
842 typedef Eigen::Matrix<double, nTest, nTrial> result_t;
844 typedef typename trial_field_t::elem_t trial_elem_t;
845 typedef typename test_field_t::elem_t test_elem_t;
847 typedef typename trial_elem_t::domain_t domain_t;
848 typedef typename domain_t::xi_t xi_t;
849 typedef typename trial_elem_t::x_t x_t;
861 test_elem_t
const &test_elem,
862 trial_elem_t
const &trial_elem)
864 #ifdef NIHU_PRINT_DEBUG
865 static bool printed =
false;
867 std::cout <<
"Using laplace_2d_HSP_galerkin_edge_general" << std::endl;
871 using namespace boost::math::double_constants;
875 result_t I = result_t::Zero();
878 if (test_elem.get_nodes()(test_elem_t::num_nodes - 1) == trial_elem.get_nodes()(0))
880 else if (test_elem.get_nodes()(0) == trial_elem.get_nodes()(trial_elem_t::num_nodes - 1))
882 else throw std::logic_error(
"Invalid singular case detected");
885 for (
int d = 0; d < 2; ++d) {
896 bool singular = singular_domain == d;
898 x_t ax0, ay0, Jx0, Jy0;
904 ax0 = test_elem.get_dx(xi0);
905 ay0 = trial_elem.get_dx(eta0);
906 Jx0 = test_elem.get_normal(xi0);
907 Jy0 = trial_elem.get_normal(eta0);
908 Nx0 = test_shape_t::template eval_shape<0>(xi0);
909 Ny0 = trial_shape_t::template eval_shape<0>(eta0);
914 xi_t u = qu.get_xi();
915 double wu = qu.get_w();
922 x_t svec = ay0 * (u - eta0)(0) - ax0 * (u - xi0)(0);
924 x_t es = svec.normalized();
925 F1 = (Jx0.dot(Jy0) - 2 * es.dot(Jx0) * es.dot(Jy0)) / pi / s / s *
926 (Nx0 * Ny0.transpose());
931 xi_t v = qv.get_xi();
933 v(0) = (v(0) + 1.) / 2.;
934 double wv = qv.get_w() / 2.;
937 xi_t xi = xi0 + (u - xi0) * v;
938 xi_t eta = eta0 + (u - eta0) * v;
941 x_t x = test_elem.get_x(xi);
942 x_t y = trial_elem.get_x(eta);
943 x_t Jxi = test_elem.get_normal(xi);
944 x_t Jeta = trial_elem.get_normal(eta);
945 double G = kernel(x, y, Jxi, Jeta);
947 test_N_t Nxi = test_shape_t::template eval_shape<0>(xi);
948 trial_N_t Neta = trial_shape_t::template eval_shape<0>(eta);
951 result_t F = G * 2. * v(0) * (Nxi * Neta.transpose());
957 I -= F1 / v(0) * wv * wu;
962 I += F1 * std::log(s) * wu;
975 template <
class TestField,
class TrialField>
978 typename std::enable_if<
979 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value &&
980 is_constant_line<TestField>::value &&
981 is_constant_line<TrialField>::value
992 template <
class result_t>
1009 template <
class TestField,
class TrialField>
1012 typename std::enable_if<
1013 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value &&
1014 is_linear_line<TrialField>::value &&
1015 is_linear_line<TestField>::value
1026 template <
class result_t>
1035 result(1, 0) = result(0, 1);
1036 result(1, 1) = result(0, 0);
1045 template <
class TestField,
class TrialField>
1048 typename std::enable_if<
1049 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value &&
1050 !(is_linear_line<TrialField>::value &&is_linear_line<TestField>::value) &&
1051 !(is_constant_line<TrialField>::value &&is_constant_line<TestField>::value)
1062 template <
class result_t>
1080 template <
class TestField,
class TrialField>
1083 typename std::enable_if<
1084 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value &&
1085 is_constant_line<TrialField>::value &&is_constant_line<TestField>::value
1097 template <
class result_t>
1115 template <
class TestField,
class TrialField>
1118 typename std::enable_if<
1119 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value &&
1120 !(is_constant_line<TrialField>::value &&is_constant_line<TestField>::value)
1132 template <
class result_t>
1141 TestField, TrialField, 8
1151 template <
class TestField,
class TrialField>
1154 typename std::enable_if<
1155 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value &&
1156 !std::is_same<typename TrialField::elem_t::lset_t, line_1_shape_set>::value
1169 template <
class result_t>
1187 template <
class TestField,
class TrialField>
1190 typename std::enable_if<
1191 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value &&
1192 is_constant_line<TrialField>::value &&
1193 is_constant_line<TestField>::value
1204 template <
class result_t>
1222 template <
class TestField,
class TrialField>
1225 typename std::enable_if<
1226 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value &&
1227 !std::is_same<typename TrialField::elem_t::lset_t, line_1_shape_set>::value
1237 template <
class result_t>
1255 template <
class TestField,
class TrialField>
1258 typename std::enable_if<
1259 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value &&
1260 !(is_constant_line<TestField>::value &&is_constant_line<TrialField>::value)
1265 template <
class result_t>
1266 static result_t &
eval(
1284 template <
class TestField,
class TrialField>
1287 typename std::enable_if<
1288 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value &&
1289 is_constant_line<TestField>::value &&is_constant_line<TrialField>::value
1294 template <
class result_t>
1295 static result_t &
eval(
1311 template <
class TestField,
class TrialField>
1314 typename std::enable_if<
1315 std::is_same<typename get_formalism<TestField, TrialField>::type, formalism::general>::value
1326 template <
class result_t>
1335 TestField, TrialField, 11>
::eval(