NiHu  2.0
helmholtz_3d_singular_integrals.hpp
Go to the documentation of this file.
1 // This file is a part of NiHu, a C++ BEM template library.
2 //
3 // Copyright (C) 2012-2018 Peter Fiala <fiala@hit.bme.hu>
4 // Copyright (C) 2012-2018 Peter Rucz <rucz@hit.bme.hu>
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 
21 #ifndef NIHU_HELMHOLTZ_3D_SINGULAR_INTEGRALS_HPP_INCLUDED
22 #define NIHU_HELMHOLTZ_3D_SINGULAR_INTEGRALS_HPP_INCLUDED
23 
24 #include <boost/math/constants/constants.hpp>
25 
26 #include "helmholtz_kernel.hpp"
27 #include "field_type_helpers.hpp"
28 #include "guiggiani_1992.hpp"
29 #include "lib_element.hpp"
31 #include "normal_derivative_singular_integrals.hpp"
32 #include "plane_element_helper.hpp"
33 #include "../core/match_types.hpp"
34 #include "../core/singular_integral_shortcut.hpp"
35 #include "../util/math_functions.hpp"
36 
37 #if NIHU_MEX_DEBUGGING
38 #include <mex.h>
39 #endif
40 
41 namespace NiHu
42 {
43 
47 template <unsigned order>
49 {
50 private:
56  template <class wavenumber_t>
57  static std::complex<double> dynamic_part(double const &r, wavenumber_t const &k)
58  {
59  using namespace std::complex_literals;
60  return -1.i*k * std::exp(-1.i*k*r / 2.0) * sinc(k*r / 2.0);
61  }
62 
63 public:
72  template <class elem_t, class wavenumber_t>
73  static std::complex<double> eval(
74  elem_t const &elem,
75  typename elem_t::x_t const &x0,
76  wavenumber_t const &k)
77  {
78  using namespace boost::math::double_constants;
79 
81 
82  enum { N = elem_t::domain_t::num_corners };
83 
84  double r[N], theta[N], alpha[N];
85  plane_element_helper(elem, x0, r, theta, alpha);
86 
87  // integrate static part analytically
88  double I_stat = 0.0;
89  for (unsigned i = 0; i < N; ++i)
90  I_stat += r[i] * std::sin(alpha[i]) *
91  std::log(std::tan((alpha[i] + theta[i]) / 2.0) / std::tan(alpha[i] / 2.0)
92  );
93 
94  // integrate dynamic part
95  std::complex<double> I_dyn = 0.0;
96  for (auto it = quadr_t::quadrature.begin(); it != quadr_t::quadrature.end(); ++it)
97  {
98  double r = (elem.get_x(it->get_xi()) - x0).norm();
99  double jac = elem.get_normal(it->get_xi()).norm();
100  I_dyn += dynamic_part(r, k) * it->get_w() * jac;
101  }
102 
103  // assemble result from static and dynamic parts
104  return (I_stat + I_dyn) / (4.0 * pi);
105  }
106 };
107 
109 template <unsigned order>
111 {
112 private:
113  template <class wavenumber_t>
114  static std::complex<double> dynamic_part(double const &r, wavenumber_t const &k)
115  {
116  using namespace std::complex_literals;
117  std::complex<double> const ikr(1.i*k*r);
118  if (std::abs(r) > 1e-3)
119  return (std::exp(-ikr)*(1.0 + ikr) - 1.0 + ikr*ikr / 2.0) / r / r / r;
120  else
121  return -1.i*k*k*k * (
122  1.0 / 3.0 - ikr*(1.0 / 8.0 - ikr*(1.0 / 30.0 - ikr*(1.0 / 144.0 - ikr*(1.0 / 840.0 - ikr / 5760.0))))
123  );
124  }
125 
126 public:
135  template <class elem_t, class wavenumber_t>
136  static std::complex<double> eval(
137  elem_t const &elem,
138  typename elem_t::x_t const &x0,
139  wavenumber_t const &k)
140  {
141  using namespace boost::math::double_constants;
142 
144  enum { N = elem_t::domain_t::num_corners };
145 
146 #if NIHU_MEX_DEBUGGING
147  static bool printed = false;
148  if (!printed)
149  {
150  mexPrintf("Integrating Helmholtz HSP over constant plane, N = %d\n", N);
151  printed = true;
152  }
153 #endif
154 
155  double r[N], theta[N], alpha[N];
156  plane_element_helper(elem, x0, r, theta, alpha);
157 
158  // integrate static part
159  double IG0 = 0.0, IddG0 = 0.0;
160  for (unsigned i = 0; i < N; ++i)
161  {
162  // integral is zero for highly distorted elements
164  if (theta[i] < 1e-3)
165  continue;
166  IG0 += r[i] * std::sin(alpha[i]) *
167  std::log(std::tan((alpha[i] + theta[i]) / 2.0) / tan(alpha[i] / 2.0));
168  IddG0 += (std::cos(alpha[i] + theta[i]) - std::cos(alpha[i])) / (r[i] * std::sin(alpha[i]));
169  }
170 
171  // integrate dynamic part
172  std::complex<double> I_acc = 0.0;
173  for (auto it = quadr_t::quadrature.begin(); it != quadr_t::quadrature.end(); ++it)
174  {
175  double r = (elem.get_x(it->get_xi()) - x0).norm();
176  double jac = elem.get_normal(it->get_xi()).norm();
177  I_acc += dynamic_part(r, k) * it->get_w() * jac;
178  }
179 
180  // assemble result from static and dynamic parts
181  return (IddG0 + k*k / 2.0 * IG0 + I_acc) / (4.0 * pi);
182  }
183 };
184 
189 template <class WaveNumber, class TestField, class TrialField>
191  helmholtz_3d_SLP_kernel<WaveNumber>, TestField, TrialField, match::match_2d_type,
192  typename std::enable_if<
193  is_collocational<TestField, TrialField>::value &&
194  is_constant_tria<TrialField>::value
195  >::type
196 >
197 {
198 public:
206  template <class result_t>
207  static result_t &eval(
208  result_t &result,
210  field_base<TestField> const &,
211  field_base<TrialField> const &trial_field,
212  element_match const &)
213  {
215  trial_field.get_elem(),
216  trial_field.get_elem().get_center(),
217  kernel.derived().get_wave_number());
218  return result;
219  }
220 };
221 
222 
227 template <class WaveNumber, class TestField, class TrialField>
229  helmholtz_3d_HSP_kernel<WaveNumber>, TestField, TrialField, match::match_2d_type,
230  typename std::enable_if<
231  is_collocational<TestField, TrialField>::value &&
232  is_constant_tria<TrialField>::value
233  >::type
234 >
235 {
236 public:
244  template <class result_t>
245  static result_t &eval(
246  result_t &result,
248  field_base<TestField> const &,
249  field_base<TrialField> const &trial_field,
250  element_match const &)
251  {
253  trial_field.get_elem(),
254  trial_field.get_elem().get_center(),
255  kernel.derived().get_wave_number());
256  return result;
257  }
258 };
259 
264 template <class WaveNumber, class TestField, class TrialField>
266  helmholtz_3d_HSP_kernel<WaveNumber>, TestField, TrialField, match::match_2d_type,
267  typename std::enable_if<
268  is_collocational<TestField, TrialField>::value &&
269  !is_constant_tria<TrialField>::value
270  >::type
271 >
272 {
273 public:
280  template <class result_t>
281  static result_t &eval(
282  result_t &result,
284  field_base<TestField> const &,
285  field_base<TrialField> const &trial_field,
286  element_match const &)
287  {
288 #if NIHU_MEX_DEBUGGING
289  static bool printed = false;
290  if (!printed)
291  {
292  mexPrintf("Calling Guiggiani now\n");
293  printed = true;
294  }
295 #endif
297  auto const &elem = trial_field.get_elem();
298  guiggiani_t gui(elem, kernel.derived());
299  for (unsigned r = 0; r < TestField::num_dofs; ++r)
300  {
301  auto const &xi0 = TestField::nset_t::corner_at(r);
302  gui.integrate(result.row(r), xi0, elem.get_normal(xi0));
303  }
304 
305  return result;
306  }
307 };
308 
309 } // end of namespace NiHu
310 
311 
312 #endif // NIHU_HELMHOLTZ_3D_SINGULAR_INTEGRALS_HPP_INCLUDED
313 
NiHu::plane_element_helper
void plane_element_helper(elem_t const &elem, typename elem_t::x_t const &x0, typename elem_t::scalar_t r[], typename elem_t::scalar_t theta[], typename elem_t::scalar_t alpha[])
compute angles and radii in a plane element
Definition: plane_element_helper.hpp:40
NiHu::volume_element
class describing a volume element that has no normal vector
Definition: element.hpp:455
NiHu::helmholtz_3d_SLP_collocation_constant_plane::eval
static std::complex< double > eval(elem_t const &elem, typename elem_t::x_t const &x0, wavenumber_t const &k)
Evaluate the integral.
Definition: helmholtz_3d_singular_integrals.hpp:73
NiHu::helmholtz_3d_HSP_collocation_constant_plane
Collocational singular integral of the 3D Helmholtz HSP kernel over a constant planar element.
Definition: helmholtz_3d_singular_integrals.hpp:110
plane_element_helper.hpp
helper functions to compute analytical integrals over plane elements
NiHu::volume_element::x_t
element_traits::location_value_type< Derived, 0 >::type x_t
type of the element's physical location variable
Definition: element.hpp:220
NiHu::helmholtz_3d_SLP_collocation_constant_plane
Collocational singular integral of the 3D Helmholtz SLP kernel over a constant planar element.
Definition: helmholtz_3d_singular_integrals.hpp:48
NiHu::regular_quad_store
store-wrapper of a statically stored quadrature
Definition: quadrature_store_helper.hpp:13
NiHu::singular_integral_shortcut< helmholtz_3d_HSP_kernel< WaveNumber >, TestField, TrialField, match::match_2d_type, typename std::enable_if< is_collocational< TestField, TrialField >::value &&is_constant_tria< TrialField >::value >::type >::eval
static result_t & eval(result_t &result, kernel_base< helmholtz_3d_HSP_kernel< WaveNumber > > const &kernel, field_base< TestField > const &, field_base< TrialField > const &trial_field, element_match const &)
evaluate singular integral
Definition: helmholtz_3d_singular_integrals.hpp:245
guiggiani_1992.hpp
Guiggiani's method for CPV and HPF collocational integrals.
NiHu::kernel_base
CRTP base class of all BEM kernels.
Definition: kernel.hpp:133
NiHu::match::match_2d_type
std::integral_constant< int, 2 > match_2d_type
two elements are adjacent with a 2d (surface) match
Definition: match_types.hpp:42
NiHu::element_match
class describing the adjacency (match) state of two elements
Definition: element_match.hpp:39
laplace_3d_singular_integrals.hpp
Analytical expressions for the singular integrals of Laplace kernels.
NiHu::singular_integral_shortcut< helmholtz_3d_HSP_kernel< WaveNumber >, TestField, TrialField, match::match_2d_type, typename std::enable_if< is_collocational< TestField, TrialField >::value &&!is_constant_tria< TrialField >::value >::type >::eval
static result_t & eval(result_t &result, kernel_base< helmholtz_3d_HSP_kernel< WaveNumber > > const &kernel, field_base< TestField > const &, field_base< TrialField > const &trial_field, element_match const &)
evaluate singular integral
Definition: helmholtz_3d_singular_integrals.hpp:281
NiHu::singular_integral_shortcut
a shortcut for the user to define customised singular integral methods
Definition: double_integral.hpp:709
NiHu::field_base::get_elem
const elem_t & get_elem() const
return underlying element
Definition: field.hpp:149
NiHu::field_base
CRTP base class of all fields.
Definition: field.hpp:111
NiHu::helmholtz_3d_HSP_collocation_constant_plane::eval
static std::complex< double > eval(elem_t const &elem, typename elem_t::x_t const &x0, wavenumber_t const &k)
Evaluate the integral.
Definition: helmholtz_3d_singular_integrals.hpp:136
NiHu::normal_derivative_kernel
Normal derivative of a distance dependent kernel.
Definition: normal_derivative_kernel.hpp:26
lib_element.hpp
helmholtz_kernel.hpp
Kernels of the Helmholtz equation .
NiHu::singular_integral_shortcut< helmholtz_3d_SLP_kernel< WaveNumber >, TestField, TrialField, match::match_2d_type, typename std::enable_if< is_collocational< TestField, TrialField >::value &&is_constant_tria< TrialField >::value >::type >::eval
static result_t & eval(result_t &result, kernel_base< helmholtz_3d_SLP_kernel< WaveNumber > > const &kernel, field_base< TestField > const &, field_base< TrialField > const &trial_field, element_match const &)
evaluate singular integral
Definition: helmholtz_3d_singular_integrals.hpp:207
NiHu::guiggiani
Implementation of Guiggiani's method.
Definition: guiggiani_1992.hpp:84