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;
187 m_Tinv = m_T.inverse();
189 m_eta0 = m_T * m_xi0;
191 scalar_t det_T = m_T.determinant();
192 if (std::isnan(det_T)) {
193 throw std::runtime_error(std::string(
"Error evaluating planar helper for Guiggiani integral (") +
194 "guiggiani_1992.hpp" +
", line:" + std::to_string(
int(__LINE__)) +
"): element #" + std::to_string(m_elem.get_id()[0]) +
" is too distorted.");
197 scalar_t sqrt_det_T = std::sqrt(std::abs(det_T));
199 m_Jvec_series[0] = m_elem.get_normal(m_xi0) / det_T;
200 m_N_series[0] = trial_nset_t::template eval_shape<0>(xi0);
203 unsigned const N = domain_t::num_corners;
204 for (
unsigned n = 0; n < N; ++n)
206 xi_t c1 = m_T * domain_t::get_corner(n);
207 xi_t c2 = m_T * domain_t::get_corner((n + 1) % N);
208 xi_t l = xi_t::Zero();
212 if ((c2 - c1).norm() < 1e-2 * sqrt_det_T) {
213 throw std::runtime_error(std::string(
"Error evaluating planar helper for Guiggiani integral (") +
214 "guiggiani_1992.hpp" +
", line:" + std::to_string(
int(__LINE__)) +
"): element #" + std::to_string(m_elem.get_id()[0]) +
" is too distorted.");
217 l = (c2 - c1).normalized();
219 xi_t d1 = c1 - m_eta0;
220 xi_t d0 = d1 - l*d1.dot(l);
222 m_theta_lim[n] = std::atan2(d1(1), d1(0));
223 m_theta0[n] = std::atan2(d0(1), d0(0));
224 m_ref_distance[n] = d0.norm();
231 void compute_theta(scalar_t theta)
237 typename elem_t::dx_return_type dx = m_elem.get_dx(m_xi0);
241 if (laurent_order > 1)
243 typename elem_t::ddx_return_type ddx = m_elem.get_ddx(m_xi0);
261 ) / m_T.determinant();
263 auto dN = trial_nset_t::template eval_shape<1>(m_xi0);
276 template <
class result_t>
279 using namespace boost::math::double_constants;
281 #if NIHU_MEX_DEBUGGING
282 static bool printed =
false;
285 mexPrintf(
"Computing integral with Guiggiani.\nRadial_order: %d\nTangential order: %d\n", RadialOrder, TangentialOrder);
291 compute_xi0(xi0, normal);
295 auto bound = m_kernel.bind(test_input);
298 unsigned const N = domain_t::num_corners;
299 for (
unsigned n = 0; n < N; ++n)
303 scalar_t t2 = m_theta_lim[(n + 1) % N];
306 if (std::abs(t2-t1) < 1e-3)
310 if (std::abs(t2 - t1) > pi)
318 scalar_t theta = ((1.0 - xx) * t1 + (1.0 + xx) * t2) / 2.0;
319 scalar_t w_theta = q_theta.get_w() * (t2 - t1) / 2.0;
322 compute_theta(theta);
323 laurent_t::eval(*
this);
326 scalar_t rho_lim = m_ref_distance[n] / std::cos(theta - m_theta0[n]);
329 if (laurent_order > 1)
330 toadd -= m_Fcoeffs[1] / rho_lim;
345 scalar_t rho = (1.0 + q_rho.get_xi()(0)) * rho_lim / 2.0;
346 scalar_t w_rho = q_rho.get_w() * rho_lim / 2.0;
349 xi_t eta(rho*std::cos(theta), rho*std::sin(theta));
350 xi_t xi = m_Tinv * eta + m_xi0;
354 typename kernel_t::result_t GJrho =
355 bound(trial_input) * (trial_input.get_jacobian() / m_T.determinant() * rho);
356 typename trial_nset_t::shape_t N =
357 trial_nset_t::template eval_shape<0>(xi);
362 if (laurent_order > 1)
363 singular_part += m_Fcoeffs[1] / rho;
364 singular_part /= rho;
374 I += w_theta * w_rho * F;
381 template <
class T, T order>
384 static_assert((order-1)>=0,
"Required distance Taylor coefficient too low");
385 static_assert((order-1) < laurent_order,
"Required distance Taylor coefficient too high");
386 return m_rvec_series[order-1];
390 template <
class T, T order>
393 static_assert(order < laurent_order,
"Required Jacobian Taylor coefficient too high");
394 static_assert(order >= 0,
"Required Jacobian Taylor coefficient too low");
395 return m_Jvec_series[order];
399 template <
class T, T order>
402 static_assert(order < laurent_order,
"Required shape set Taylor coefficient too high");
403 static_assert(order >= 0,
"Required Jacobian Taylor coefficient too low");
404 return m_N_series[order];
408 template <
class T, T order>
411 static_assert(-(order+1) < laurent_order,
"Required Laurent coefficient too high");
412 static_assert(-(order+1) >= 0,
"Required Laurent coefficient too low");
413 return m_Fcoeffs[-(order+1)];
417 template <
class T, T order>
420 static_assert(-(order+1) < laurent_order,
"Required Laurent coefficient too high");
421 static_assert(-(order+1) >= 0,
"Required Laurent coefficient too low");
422 m_Fcoeffs[-(order+1)] = v;
431 kernel_t const &get_kernel(
void)
const
433 return m_kernel.derived();
438 kernel_base<kernel_t>
const &m_kernel;
449 scalar_t m_theta_lim[domain_t::num_corners];
451 scalar_t m_theta0[domain_t::num_corners];
453 scalar_t m_ref_distance[domain_t::num_corners];
455 x_t m_rvec_series[laurent_order];
456 x_t m_Jvec_series[laurent_order];
457 trial_n_shape_t m_N_series[laurent_order];
458 laurent_coeff_t m_Fcoeffs[laurent_order];
468 template <
class TrialField,
class Kernel,
unsigned RadialOrder,
unsigned TangentialOrder>
469 class guiggiani<TrialField, Kernel, RadialOrder, TangentialOrder, typename std::enable_if<
470 !element_traits::is_surface_element<typename TrialField::elem_t>::value
476 radial_order = RadialOrder,
477 tangential_order = TangentialOrder
483 typedef typename trial_field_t::elem_t
elem_t;
488 typedef typename domain_t::xi_t
xi_t;
492 typedef Eigen::Matrix<scalar_t, domain_t::dimension, domain_t::dimension>
trans_t;
539 : m_elem(elem), m_kernel(kernel)
547 void compute_xi0(xi_t
const &xi0)
550 m_x0 = m_elem.get_x(m_xi0);
551 typename elem_t::dx_return_type dx = m_elem.get_dx(m_xi0);
558 0.0, std::sqrt(1.0-cosgamma*cosgamma) * u;
561 m_Tinv = m_T.inverse();
563 m_eta0 = m_T * m_xi0;
565 m_J_series[0] = m_elem.get_dx(m_xi0).determinant() / m_T.determinant();
566 m_N_series[0] = trial_nset_t::template eval_shape<0>(xi0);
569 unsigned const N = domain_t::num_corners;
570 for (
unsigned n = 0; n < N; ++n)
572 xi_t c1 = m_T * domain_t::get_corner(n);
573 xi_t c2 = m_T * domain_t::get_corner((n + 1) % N);
574 xi_t l = (c2 - c1).normalized();
576 xi_t d1 = c1 - m_eta0;
577 xi_t d0 = d1 - l*d1.dot(l);
579 m_theta_lim[n] = std::atan2(d1(1), d1(0));
580 m_theta0[n] = std::atan2(d0(1), d0(0));
581 m_ref_distance[n] = d0.norm();
585 template <
class Input1,
class Input2>
586 typename Input1::Scalar detvectors(Eigen::DenseBase<Input1>
const &v1, Eigen::DenseBase<Input2>
const &v2)
588 return v1(0)*v2(1) - v1(1)*v2(0);
594 void compute_theta(scalar_t theta)
600 typename elem_t::dx_return_type dx = m_elem.get_dx(m_xi0);
604 if (laurent_order > 1)
606 typename elem_t::ddx_return_type ddx = m_elem.get_ddx(m_xi0);
630 ) / m_T.determinant();
632 auto dN = trial_nset_t::template eval_shape<1>(m_xi0);
645 template <
class result_t>
648 using namespace boost::math::double_constants;
650 #if NIHU_MEX_DEBUGGING
651 static bool printed =
false;
654 mexPrintf(
"Computing integral with Guiggiani.\nRadial_order: %d\nTangential order: %d\n", RadialOrder, TangentialOrder);
664 auto bound = m_kernel.bind(test_input);
667 unsigned const N = domain_t::num_corners;
668 for (
unsigned n = 0; n < N; ++n)
672 scalar_t t2 = m_theta_lim[(n + 1) % N];
675 if (std::abs(t2 - t1) > pi)
683 scalar_t theta = ((1.0 - xx) * t1 + (1.0 + xx) * t2) / 2.0;
684 scalar_t w_theta = q_theta.get_w() * (t2 - t1) / 2.0;
687 compute_theta(theta);
688 laurent_t::eval(*
this);
691 scalar_t rho_lim = m_ref_distance[n] / std::cos(theta - m_theta0[n]);
694 if (laurent_order > 1)
695 toadd -= m_Fcoeffs[1] / rho_lim;
698 for (
int r = 0; r < I.rows(); ++r)
699 for (
int c = 0; c < I.cols(); ++c)
700 I(r,c) += toadd(r,c);
706 scalar_t rho = (1.0 + q_rho.get_xi()(0)) * rho_lim / 2.0;
707 scalar_t w_rho = q_rho.get_w() * rho_lim / 2.0;
710 xi_t eta(rho*std::cos(theta), rho*std::sin(theta));
711 xi_t xi = m_Tinv * eta + m_xi0;
715 typename kernel_t::result_t GJrho =
716 bound(trial_input) * (trial_input.get_jacobian() / m_T.determinant() * rho);
717 typename trial_nset_t::shape_t N =
718 trial_nset_t::template eval_shape<0>(xi);
723 if (laurent_order > 1)
724 singular_part += m_Fcoeffs[1] / rho;
725 singular_part /= rho;
727 for (
int r = 0; r < F.rows(); ++r)
728 for (
int c = 0; c < F.cols(); ++c)
729 F(r,c) -= singular_part(r,c);
732 I += w_theta * w_rho * F;
739 template <
class T, T order>
742 static_assert((order-1)>=0,
"Required distance Taylor coefficient too low");
743 static_assert((order-1) < laurent_order,
"Required distance Taylor coefficient too high");
744 return m_rvec_series[order-1];
748 template <
class T, T order>
751 static_assert(order < laurent_order,
"Required Jacobian Taylor coefficient too high");
752 static_assert(order >= 0,
"Required Jacobian Taylor coefficient too low");
753 return m_J_series[order];
757 template <
class T, T order>
760 static_assert(order < laurent_order,
"Required shape set Taylor coefficient too high");
761 static_assert(order >= 0,
"Required Jacobian Taylor coefficient too low");
762 return m_N_series[order];
766 template <
class T, T order>
769 static_assert(-(order+1) < laurent_order,
"Required Laurent coefficient too high");
770 static_assert(-(order+1) >= 0,
"Required Laurent coefficient too low");
771 return m_Fcoeffs[-(order+1)];
775 template <
class T, T order>
778 static_assert(-(order+1) < laurent_order,
"Required Laurent coefficient too high");
779 static_assert(-(order+1) >= 0,
"Required Laurent coefficient too low");
780 m_Fcoeffs[-(order+1)] = v;
784 kernel_t const &get_kernel(
void)
const
786 return m_kernel.derived();
792 kernel_base<kernel_t>
const &m_kernel;
802 scalar_t m_theta_lim[domain_t::num_corners];
804 scalar_t m_theta0[domain_t::num_corners];
806 scalar_t m_ref_distance[domain_t::num_corners];
808 x_t m_rvec_series[laurent_order];
809 scalar_t m_J_series[laurent_order];
810 trial_n_shape_t m_N_series[laurent_order];
811 laurent_coeff_t m_Fcoeffs[laurent_order];
818 #endif // GUIGGIANI_1992_HPP_INCLUDED