28 #ifndef GUIGGIANI_1992_HPP_INCLUDED
29 #define GUIGGIANI_1992_HPP_INCLUDED
31 #include <boost/math/constants/constants.hpp>
33 #include "line_quad_store.hpp"
36 #include "../core/field.hpp"
37 #include "../core/kernel.hpp"
38 #include "../core/shapeset.hpp"
39 #include "../util/block_product.hpp"
40 #include "../util/store_pattern.hpp"
43 #if NIHU_MEX_DEBUGGING
63 template <
class singularity_type>
67 typedef std::integral_constant<int, -2>
_m2;
69 typedef std::integral_constant<int, -1>
_m1;
71 typedef std::integral_constant<int, 0>
_0;
73 typedef std::integral_constant<int, 1>
_1;
75 typedef std::integral_constant<int, 2>
_2;
83 template <
class TrialField,
class Kernel,
unsigned RadialOrder,
unsigned TangentialOrder = RadialOrder,
class Enable =
void>
88 template <
class TrialField,
class Kernel,
unsigned RadialOrder,
unsigned TangentialOrder>
89 class guiggiani<TrialField, Kernel, RadialOrder, TangentialOrder, typename std::enable_if<
90 element_traits::is_surface_element<typename TrialField::elem_t>::value
96 radial_order = RadialOrder,
97 tangential_order = TangentialOrder
103 typedef typename trial_field_t::elem_t
elem_t;
108 typedef typename domain_t::xi_t
xi_t;
112 typedef Eigen::Matrix<scalar_t, domain_t::dimension, domain_t::dimension>
trans_t;
115 typedef typename elem_t::x_t
x_t;
159 : m_elem(elem), m_kernel(kernel)
168 void compute_xi0(xi_t
const &xi0, x_t
const &normal)
172 m_n0 = normal.normalized();
175 m_x0 = m_elem.get_x(m_xi0);
176 typename elem_t::dx_return_type dx = m_elem.get_dx(m_xi0);
183 0.0, std::sqrt(1.0-cosgamma*cosgamma) * u;
186 m_Tinv = m_T.inverse();
188 m_eta0 = m_T * m_xi0;
190 m_Jvec_series[0] = m_elem.get_normal(m_xi0) / m_T.determinant();
191 m_N_series[0] = trial_nset_t::template eval_shape<0>(xi0);
194 unsigned const N = domain_t::num_corners;
195 for (
unsigned n = 0; n < N; ++n)
197 xi_t c1 = m_T * domain_t::get_corner(n);
198 xi_t c2 = m_T * domain_t::get_corner((n + 1) % N);
199 xi_t l = xi_t::Zero();
201 if ((c2-c1).norm() > 1e-3)
202 l = (c2 - c1).normalized();
204 xi_t d1 = c1 - m_eta0;
205 xi_t d0 = d1 - l*d1.dot(l);
207 m_theta_lim[n] = std::atan2(d1(1), d1(0));
208 m_theta0[n] = std::atan2(d0(1), d0(0));
209 m_ref_distance[n] = d0.norm();
216 void compute_theta(scalar_t theta)
222 typename elem_t::dx_return_type dx = m_elem.get_dx(m_xi0);
226 if (laurent_order > 1)
228 typename elem_t::ddx_return_type ddx = m_elem.get_ddx(m_xi0);
246 ) / m_T.determinant();
248 auto dN = trial_nset_t::template eval_shape<1>(m_xi0);
261 template <
class result_t>
264 using namespace boost::math::double_constants;
266 #if NIHU_MEX_DEBUGGING
267 static bool printed =
false;
270 mexPrintf(
"Computing integral with Guiggiani.\nRadial_order: %d\nTangential order: %d\n", RadialOrder, TangentialOrder);
276 compute_xi0(xi0, normal);
280 auto bound = m_kernel.bind(test_input);
283 unsigned const N = domain_t::num_corners;
284 for (
unsigned n = 0; n < N; ++n)
288 scalar_t t2 = m_theta_lim[(n + 1) % N];
291 if (std::abs(t2-t1) < 1e-3)
295 if (std::abs(t2 - t1) > pi)
303 scalar_t theta = ((1.0 - xx) * t1 + (1.0 + xx) * t2) / 2.0;
304 scalar_t w_theta = q_theta.get_w() * (t2 - t1) / 2.0;
307 compute_theta(theta);
308 laurent_t::eval(*
this);
311 scalar_t rho_lim = m_ref_distance[n] / std::cos(theta - m_theta0[n]);
314 if (laurent_order > 1)
315 toadd -= m_Fcoeffs[1] / rho_lim;
330 scalar_t rho = (1.0 + q_rho.get_xi()(0)) * rho_lim / 2.0;
331 scalar_t w_rho = q_rho.get_w() * rho_lim / 2.0;
334 xi_t eta(rho*std::cos(theta), rho*std::sin(theta));
335 xi_t xi = m_Tinv * eta + m_xi0;
339 typename kernel_t::result_t GJrho =
340 bound(trial_input) * (trial_input.get_jacobian() / m_T.determinant() * rho);
341 typename trial_nset_t::shape_t N =
342 trial_nset_t::template eval_shape<0>(xi);
347 if (laurent_order > 1)
348 singular_part += m_Fcoeffs[1] / rho;
349 singular_part /= rho;
359 I += w_theta * w_rho * F;
366 template <
class T, T order>
369 static_assert((order-1)>=0,
"Required distance Taylor coefficient too low");
370 static_assert((order-1) < laurent_order,
"Required distance Taylor coefficient too high");
371 return m_rvec_series[order-1];
375 template <
class T, T order>
378 static_assert(order < laurent_order,
"Required Jacobian Taylor coefficient too high");
379 static_assert(order >= 0,
"Required Jacobian Taylor coefficient too low");
380 return m_Jvec_series[order];
384 template <
class T, T order>
387 static_assert(order < laurent_order,
"Required shape set Taylor coefficient too high");
388 static_assert(order >= 0,
"Required Jacobian Taylor coefficient too low");
389 return m_N_series[order];
393 template <
class T, T order>
396 static_assert(-(order+1) < laurent_order,
"Required Laurent coefficient too high");
397 static_assert(-(order+1) >= 0,
"Required Laurent coefficient too low");
398 return m_Fcoeffs[-(order+1)];
402 template <
class T, T order>
405 static_assert(-(order+1) < laurent_order,
"Required Laurent coefficient too high");
406 static_assert(-(order+1) >= 0,
"Required Laurent coefficient too low");
407 m_Fcoeffs[-(order+1)] = v;
416 kernel_t const &get_kernel(
void)
const
418 return m_kernel.derived();
423 kernel_base<kernel_t>
const &m_kernel;
434 scalar_t m_theta_lim[domain_t::num_corners];
436 scalar_t m_theta0[domain_t::num_corners];
438 scalar_t m_ref_distance[domain_t::num_corners];
440 x_t m_rvec_series[laurent_order];
441 x_t m_Jvec_series[laurent_order];
442 trial_n_shape_t m_N_series[laurent_order];
443 laurent_coeff_t m_Fcoeffs[laurent_order];
453 template <
class TrialField,
class Kernel,
unsigned RadialOrder,
unsigned TangentialOrder>
454 class guiggiani<TrialField, Kernel, RadialOrder, TangentialOrder, typename std::enable_if<
455 !element_traits::is_surface_element<typename TrialField::elem_t>::value
461 radial_order = RadialOrder,
462 tangential_order = TangentialOrder
468 typedef typename trial_field_t::elem_t
elem_t;
473 typedef typename domain_t::xi_t
xi_t;
477 typedef Eigen::Matrix<scalar_t, domain_t::dimension, domain_t::dimension>
trans_t;
524 : m_elem(elem), m_kernel(kernel)
532 void compute_xi0(xi_t
const &xi0)
535 m_x0 = m_elem.get_x(m_xi0);
536 typename elem_t::dx_return_type dx = m_elem.get_dx(m_xi0);
543 0.0, std::sqrt(1.0-cosgamma*cosgamma) * u;
546 m_Tinv = m_T.inverse();
548 m_eta0 = m_T * m_xi0;
550 m_J_series[0] = m_elem.get_dx(m_xi0).determinant() / m_T.determinant();
551 m_N_series[0] = trial_nset_t::template eval_shape<0>(xi0);
554 unsigned const N = domain_t::num_corners;
555 for (
unsigned n = 0; n < N; ++n)
557 xi_t c1 = m_T * domain_t::get_corner(n);
558 xi_t c2 = m_T * domain_t::get_corner((n + 1) % N);
559 xi_t l = (c2 - c1).normalized();
561 xi_t d1 = c1 - m_eta0;
562 xi_t d0 = d1 - l*d1.dot(l);
564 m_theta_lim[n] = std::atan2(d1(1), d1(0));
565 m_theta0[n] = std::atan2(d0(1), d0(0));
566 m_ref_distance[n] = d0.norm();
570 template <
class Input1,
class Input2>
571 typename Input1::Scalar detvectors(Eigen::DenseBase<Input1>
const &v1, Eigen::DenseBase<Input2>
const &v2)
573 return v1(0)*v2(1) - v1(1)*v2(0);
579 void compute_theta(scalar_t theta)
585 typename elem_t::dx_return_type dx = m_elem.get_dx(m_xi0);
589 if (laurent_order > 1)
591 typename elem_t::ddx_return_type ddx = m_elem.get_ddx(m_xi0);
615 ) / m_T.determinant();
617 auto dN = trial_nset_t::template eval_shape<1>(m_xi0);
630 template <
class result_t>
633 using namespace boost::math::double_constants;
635 #if NIHU_MEX_DEBUGGING
636 static bool printed =
false;
639 mexPrintf(
"Computing integral with Guiggiani.\nRadial_order: %d\nTangential order: %d\n", RadialOrder, TangentialOrder);
649 auto bound = m_kernel.bind(test_input);
652 unsigned const N = domain_t::num_corners;
653 for (
unsigned n = 0; n < N; ++n)
657 scalar_t t2 = m_theta_lim[(n + 1) % N];
660 if (std::abs(t2 - t1) > pi)
668 scalar_t theta = ((1.0 - xx) * t1 + (1.0 + xx) * t2) / 2.0;
669 scalar_t w_theta = q_theta.get_w() * (t2 - t1) / 2.0;
672 compute_theta(theta);
673 laurent_t::eval(*
this);
676 scalar_t rho_lim = m_ref_distance[n] / std::cos(theta - m_theta0[n]);
679 if (laurent_order > 1)
680 toadd -= m_Fcoeffs[1] / rho_lim;
683 for (
int r = 0; r < I.rows(); ++r)
684 for (
int c = 0; c < I.cols(); ++c)
685 I(r,c) += toadd(r,c);
691 scalar_t rho = (1.0 + q_rho.get_xi()(0)) * rho_lim / 2.0;
692 scalar_t w_rho = q_rho.get_w() * rho_lim / 2.0;
695 xi_t eta(rho*std::cos(theta), rho*std::sin(theta));
696 xi_t xi = m_Tinv * eta + m_xi0;
700 typename kernel_t::result_t GJrho =
701 bound(trial_input) * (trial_input.get_jacobian() / m_T.determinant() * rho);
702 typename trial_nset_t::shape_t N =
703 trial_nset_t::template eval_shape<0>(xi);
708 if (laurent_order > 1)
709 singular_part += m_Fcoeffs[1] / rho;
710 singular_part /= rho;
712 for (
int r = 0; r < F.rows(); ++r)
713 for (
int c = 0; c < F.cols(); ++c)
714 F(r,c) -= singular_part(r,c);
717 I += w_theta * w_rho * F;
724 template <
class T, T order>
727 static_assert((order-1)>=0,
"Required distance Taylor coefficient too low");
728 static_assert((order-1) < laurent_order,
"Required distance Taylor coefficient too high");
729 return m_rvec_series[order-1];
733 template <
class T, T order>
736 static_assert(order < laurent_order,
"Required Jacobian Taylor coefficient too high");
737 static_assert(order >= 0,
"Required Jacobian Taylor coefficient too low");
738 return m_J_series[order];
742 template <
class T, T order>
745 static_assert(order < laurent_order,
"Required shape set Taylor coefficient too high");
746 static_assert(order >= 0,
"Required Jacobian Taylor coefficient too low");
747 return m_N_series[order];
751 template <
class T, T order>
754 static_assert(-(order+1) < laurent_order,
"Required Laurent coefficient too high");
755 static_assert(-(order+1) >= 0,
"Required Laurent coefficient too low");
756 return m_Fcoeffs[-(order+1)];
760 template <
class T, T order>
763 static_assert(-(order+1) < laurent_order,
"Required Laurent coefficient too high");
764 static_assert(-(order+1) >= 0,
"Required Laurent coefficient too low");
765 m_Fcoeffs[-(order+1)] = v;
769 kernel_t const &get_kernel(
void)
const
771 return m_kernel.derived();
777 kernel_base<kernel_t>
const &m_kernel;
787 scalar_t m_theta_lim[domain_t::num_corners];
789 scalar_t m_theta0[domain_t::num_corners];
791 scalar_t m_ref_distance[domain_t::num_corners];
793 x_t m_rvec_series[laurent_order];
794 scalar_t m_J_series[laurent_order];
795 trial_n_shape_t m_N_series[laurent_order];
796 laurent_coeff_t m_Fcoeffs[laurent_order];
803 #endif // GUIGGIANI_1992_HPP_INCLUDED