41 #ifndef NIHU_LAPLACE_3D_NEARLY_SINGULAR_INTEGRALS_HPP_INCLUDED
42 #define NIHU_LAPLACE_3D_NEARLY_SINGULAR_INTEGRALS_HPP_INCLUDED
44 #include <boost/math/constants/constants.hpp>
46 #include "../core/formalism.hpp"
47 #include "../core/nearly_singular_integral.hpp"
48 #include "../core/nearly_singular_planar_constant_collocation_shortcut.hpp"
49 #include "../util/math_functions.hpp"
50 #include "field_type_helpers.hpp"
52 #include "nearly_singular_collocational.hpp"
54 #include "quadrature_store_helper.hpp"
66 enum { quadrature_order = 10 };
70 template <
class elem_t>
73 using namespace boost::math::double_constants;
77 enum { N = elem_t::domain_t::num_corners };
79 Eigen::Matrix<double, 3, N> corners;
80 for (
unsigned i = 0; i < N; ++i)
81 corners.col(i) = elem.get_x(elem_t::domain_t::get_corner(i));
84 auto Tdec = T.partialPivLu();
85 corners = Tdec.solve(corners);
86 x_t x0 = Tdec.solve(x0_in);
89 double ref_distance[N];
92 plane_elem_helper_mid(corners, x0, ref_distance, theta_lim, theta0);
95 double z = x0(2) - corners(2, 0);
100 for (
unsigned i = 0; i < N; ++i)
102 double th1 = theta_lim[i];
103 double th2 = theta_lim[(i + 1) % N];
106 if (std::abs(th2 - th1) > pi)
113 double jac = (th2 - th1) / 2.;
115 if (std::abs(jac) < 1e-10)
122 double xi = it->get_xi()(0);
123 double w = it->get_w();
126 double theta = th1 * (1. - xi) / 2. + th2 * (1. + xi) / 2.;
128 double R = ref_distance[i] / std::cos(theta - theta0[i]);
129 double r = std::sqrt(R*R + z * z);
133 result += (r - std::abs(z)) * jac * w;
137 return result / (4. * pi);
145 enum { quadrature_order = 10 };
149 template <
class elem_t>
152 using namespace boost::math::double_constants;
156 enum { N = elem_t::domain_t::num_corners };
158 Eigen::Matrix<double, 3, N> corners;
159 for (
unsigned i = 0; i < N; ++i)
160 corners.col(i) = elem.get_x(elem_t::domain_t::get_corner(i));
162 auto T =
plane_elem_transform(corners.col(1) - corners.col(0), corners.col(2) - corners.col(0));
163 auto Tdec = T.partialPivLu();
164 corners = Tdec.solve(corners);
165 x_t x0 = Tdec.solve(x0_in);
166 double z = x0(2) - corners(2, 0);
169 double ref_distance[N];
172 plane_elem_helper_mid(corners, x0, ref_distance, theta_lim, theta0);
177 for (
unsigned i = 0; i < N; ++i)
179 double th1 = theta_lim[i];
180 double th2 = theta_lim[(i + 1) % N];
183 if (std::abs(th2 - th1) > pi)
185 if (th2 > th1) th1 += two_pi;
189 double jac = (th2 - th1) / 2.;
191 if (std::abs(jac) < 1e-10)
198 double xi = it->get_xi()(0);
199 double w = it->get_w();
202 double theta = th1 * (1. - xi) / 2. + th2 * (1. + xi) / 2.;
204 double R = ref_distance[i] / std::cos(theta - theta0[i]);
205 double r = std::sqrt(R*R + z * z);
209 result += (1.0 - std::abs(z) / r) * jac * w;
213 return sgn(z) * result / (4. * pi);
222 enum { quadrature_order = 10 };
226 template <
class elem_t>
232 using namespace boost::math::double_constants;
236 enum { N = elem_t::domain_t::num_corners };
238 Eigen::Matrix<double, 3, N> corners;
239 for (
unsigned i = 0; i < N; ++i)
240 corners.col(i) = elem.get_x(elem_t::domain_t::get_corner(i));
243 corners.col(2) - corners.col(0));
244 auto Tdec = T.partialPivLu();
245 corners = Tdec.solve(corners);
246 x_t x0 = Tdec.solve(x0_in);
247 x_t nx = Tdec.solve(nx_in);
249 double z = x0(2) - corners(2, 0);
252 double ref_distance[N];
255 plane_elem_helper_mid(corners, x0, ref_distance, theta_lim, theta0);
260 for (
unsigned i = 0; i < N; ++i)
262 double th1 = theta_lim[i];
263 double th2 = theta_lim[(i + 1) % N];
266 if (std::abs(th2 - th1) > pi)
273 double jac = (th2 - th1) / 2.;
276 if (std::abs(jac) < 1e-10)
283 double xi = it->get_xi()(0);
284 double w = it->get_w();
287 double theta = th1 * (1. - xi) / 2. + th2 * (1. + xi) / 2.;
289 double R = ref_distance[i] / std::cos(theta - theta0[i]);
290 double r = std::sqrt(R*R + z * z);
293 rvec(0) = R * std::cos(theta);
294 rvec(1) = R * std::sin(theta);
301 (nx(0) * std::cos(theta) + nx(1) * std::sin(theta)) * std::log((R + r))
307 return result / (4.*pi);
315 enum { quadrature_order = 40 };
319 template <
class elem_t>
325 using namespace boost::math::double_constants;
329 enum { N = elem_t::domain_t::num_corners };
331 Eigen::Matrix<double, 3, N> corners;
332 for (
unsigned i = 0; i < N; ++i)
333 corners.col(i) = elem.get_x(elem_t::domain_t::get_corner(i));
335 auto T =
plane_elem_transform(corners.col(1) - corners.col(0), corners.col(2) - corners.col(0));
336 auto Tdec = T.partialPivLu();
337 corners = Tdec.solve(corners);
338 x_t x0 = Tdec.solve(x0_in);
339 x_t nx = Tdec.solve(nx_in);
342 double ref_distance[N];
346 plane_elem_helper_mid(corners, x0, ref_distance, theta_lim, theta0);
349 double z = x0(2) - corners(2, 0);
352 for (
unsigned i = 0; i < N; ++i)
354 double th1 = theta_lim[i];
355 double th2 = theta_lim[(i + 1) % N];
358 if (std::abs(th2 - th1) > pi)
365 double jac = (th2 - th1) / 2.;
368 if (std::abs(jac) < 1e-10)
375 double xi = it->get_xi()(0);
376 double w = it->get_w();
379 double theta = th1 * (1. - xi) / 2. + th2 * (1. + xi) / 2.;
381 double R = ref_distance[i] / std::cos(theta - theta0[i]);
382 double r = std::sqrt(R*R + z * z);
385 rvec(0) = R * std::cos(theta);
386 rvec(1) = R * std::sin(theta);
389 double rdnx = -rvec.dot(nx) / r;
393 if (std::abs(z) > 1e-12)
394 integrand = -R * R / (r*r) / z * rdnx;
396 integrand = -nx(2) / R;
398 result += integrand * jac * w;
402 return result / (4.*pi);
414 template <
class TestField,
class TrialField>
417 typename std::enable_if<
418 is_collocational<TestField, TrialField>::value &&
419 is_constant_tria<TrialField>::value
434 double const limit = 1.5;
437 double d = (test_field.
get_elem().get_center() - trial_field.
get_elem().get_center()).norm();
438 double R = trial_field.
get_elem().get_linear_size_estimate();
439 return d / R < limit;
442 template <
class result_t>
443 static result_t &eval(
450 result(0) = laplace_3d_SLP_collocation_constant_plane_nearly_singular::eval(
452 test_field.
get_elem().get_center());
457 template <
class TestField,
class TrialField>
460 typename std::enable_if<
461 is_collocational<TestField, TrialField>::value
463 !is_constant_tria<TrialField>::value
468 typedef typename kernel_t::test_input_t test_input_t;
469 typedef TestField test_field_t;
470 typedef typename test_field_t::nset_t test_nset_t;
471 static unsigned const num_test_nodes = test_nset_t::num_nodes;
480 double const limit = 1.5;
483 double d = (test_field.
get_elem().get_center() - trial_field.
get_elem().get_center()).norm();
484 double R = trial_field.
get_elem().get_linear_size_estimate();
485 return d / R < limit;
488 template <
class result_t>
489 static result_t &eval(
497 nsc_t nsc(trial_field, kernel);
499 for (
unsigned i = 0; i < num_test_nodes; ++i)
501 test_input_t tsti(test_field.
get_elem(), test_nset_t::corner_at(i));
502 nsc.integrate(result.row(i), tsti);
512 template <
class TestField,
class TrialField>
515 typename std::enable_if<
516 is_collocational<TestField, TrialField>::value
518 is_constant_tria<TrialField>::value
529 double const limit = 1.5;
532 double d = (test_field.
get_elem().get_center() - trial_field.
get_elem().get_center()).norm();
533 double R = trial_field.
get_elem().get_linear_size_estimate();
534 return d / R < limit;
537 template <
class result_t>
538 static result_t &eval(
545 result(0) = laplace_3d_DLP_collocation_constant_plane_nearly_singular::eval(
547 test_field.
get_elem().get_center());
553 template <
class TestField,
class TrialField>
556 typename std::enable_if<
557 is_collocational<TestField, TrialField>::value
559 !is_constant_tria<TrialField>::value
565 typedef typename kernel_t::test_input_t test_input_t;
566 typedef TestField test_field_t;
567 typedef typename test_field_t::nset_t test_nset_t;
568 static unsigned const num_test_nodes = test_nset_t::num_nodes;
576 double const limit = 1.5;
579 double d = (test_field.
get_elem().get_center() - trial_field.
get_elem().get_center()).norm();
580 double R = trial_field.
get_elem().get_linear_size_estimate();
581 return d / R < limit;
584 template <
class result_t>
585 static result_t &eval(
593 nsc_t nsc(trial_field, kernel);
595 for (
unsigned i = 0; i < num_test_nodes; ++i)
597 test_input_t tsti(test_field.
get_elem(), test_nset_t::corner_at(i));
598 nsc.integrate(result.row(i), tsti);
606 template <
class TestField,
class TrialField>
609 typename std::enable_if<
610 is_collocational<TestField, TrialField>::value
612 is_constant_tria<TrialField>::value
623 double const limit = 1.5;
626 double d = (test_field.
get_elem().get_center() - trial_field.
get_elem().get_center()).norm();
627 double R = trial_field.
get_elem().get_linear_size_estimate();
628 return d / R < limit;
631 template <
class result_t>
632 static result_t &eval(
639 result(0) = laplace_3d_DLPt_collocation_constant_plane_nearly_singular::eval(
642 test_field.
get_elem().get_normal().normalized());
648 template <
class TestField,
class TrialField>
651 typename std::enable_if<
652 is_collocational<TestField, TrialField>::value
654 !is_constant_tria<TrialField>::value
659 typedef typename kernel_t::test_input_t test_input_t;
660 typedef TestField test_field_t;
661 typedef typename test_field_t::nset_t test_nset_t;
662 static unsigned const num_test_nodes = test_nset_t::num_nodes;
671 double const limit = 1.5;
674 double d = (test_field.
get_elem().get_center() - trial_field.
get_elem().get_center()).norm();
675 double R = trial_field.
get_elem().get_linear_size_estimate();
676 return d / R < limit;
679 template <
class result_t>
680 static result_t &eval(
688 nsc_t nsc(trial_field, kernel);
690 for (
unsigned i = 0; i < num_test_nodes; ++i)
692 test_input_t tsti(test_field.
get_elem(), test_nset_t::corner_at(i));
693 nsc.integrate(result.row(i), tsti);
702 template <
class TestField,
class TrialField>
705 typename std::enable_if<
706 is_collocational<TestField, TrialField>::value
708 is_constant_tria<TrialField>::value
719 double const limit = 1.5;
722 double d = (test_field.
get_elem().get_center() - trial_field.
get_elem().get_center()).norm();
723 double R = trial_field.
get_elem().get_linear_size_estimate();
724 return d / R < limit;
727 template <
class result_t>
728 static result_t &eval(
738 test_field.
get_elem().get_normal().normalized());
744 template <
class TestField,
class TrialField>
747 typename std::enable_if<
748 is_collocational<TestField, TrialField>::value
750 !is_constant_tria<TrialField>::value
755 typedef typename kernel_t::test_input_t test_input_t;
756 typedef TestField test_field_t;
757 typedef typename test_field_t::nset_t test_nset_t;
758 static unsigned const num_test_nodes = test_nset_t::num_nodes;
767 double const limit = 1.5;
770 double d = (test_field.
get_elem().get_center() - trial_field.
get_elem().get_center()).norm();
771 double R = trial_field.
get_elem().get_linear_size_estimate();
772 return d / R < limit;
775 template <
class result_t>
776 static result_t &eval(
784 nsc_t nsc(trial_field, kernel);
786 for (
unsigned i = 0; i < num_test_nodes; ++i)
788 test_input_t tsti(test_field.
get_elem(), test_nset_t::corner_at(i));
789 nsc.integrate(result.row(i), tsti);
799 template <
class Elem>
805 typedef kernel_t::result_t res_t;
808 kernel_t::test_input_t
const &test_input,
812 return laplace_3d_SLP_collocation_constant_plane_nearly_singular::eval(
813 elem, test_input.get_x());
818 template <
class Elem>
824 typedef kernel_t::result_t res_t;
827 kernel_t::test_input_t
const &test_input,
831 return laplace_3d_DLP_collocation_constant_plane_nearly_singular::eval(
832 elem, test_input.get_x());
837 template <
class Elem>
843 typedef kernel_t::result_t res_t;
846 kernel_t::test_input_t
const &test_input,
850 return laplace_3d_DLPt_collocation_constant_plane_nearly_singular::eval(
851 elem, test_input.get_x(), test_input.get_unit_normal());
856 template <
class Elem>
862 typedef kernel_t::result_t res_t;
865 kernel_t::test_input_t
const &test_input,
870 elem, test_input.get_x(), test_input.get_unit_normal());