NiHu  2.0
helmholtz_3d_hf_fmm.hpp
Go to the documentation of this file.
1 
7 #ifndef NIHU_HELMHOLTZ_3D_HF_FMM_HPP_INCLUDED
8 #define NIHU_HELMHOLTZ_3D_HF_FMM_HPP_INCLUDED
9 
10 #include "cluster.hpp"
11 #include "cluster_tree.hpp"
12 #include "fmm_operator.hpp"
15 #include "helmholtz_3d_hf_shift.h"
16 #include "m2l_indices.hpp"
18 #include "p2p.hpp"
19 #include "unit_sphere.h"
20 
21 #include "library/helmholtz_3d.hpp"
22 
23 #include <boost/math/constants/constants.hpp>
24 #include <boost/math/special_functions/hankel.hpp>
25 #include <boost/math/special_functions/legendre.hpp>
26 
27 #include <Eigen/Dense>
28 #include <complex>
29 
30 namespace NiHu
31 {
32 namespace fmm
33 {
34 
37 template <class WaveNumber>
39 {
40 public:
42  using wave_number_t = WaveNumber;
44  using cvector_t = Eigen::Matrix<std::complex<double>, Eigen::Dynamic, 1>;
50  using location_t = typename bounding_box_t::location_t;
53 
55 
59  : m_wave_number(k)
60  , m_accuracy(3.0)
61  {
62  }
63 
67  static size_t compute_expansion_length(double drel, double C)
68  {
69  using namespace boost::math::double_constants;
70  auto kd = two_pi * drel;
71  return size_t(std::ceil(kd + C * std::log(kd + pi)));
72  }
73 
77  void set_accuracy(double accuracy)
78  {
79  m_accuracy = accuracy;
80  }
81 
84  void init_level_data(cluster_tree_t const &tree)
85  {
86  using namespace boost::math::double_constants;
87  double lambda = two_pi / std::real(m_wave_number);
88  m_level_data_vector.clear();
89  m_level_data_vector.resize(tree.get_n_levels());
90 
91  // set the expansion length for each level
92  for (size_t i = 0; i < tree.get_n_levels(); ++i)
93  {
94  auto &ld = m_level_data_vector[i];
95  // get the diameter from the first cluster on the level
96  auto idx = tree.level_begin(i);
97  auto d = tree[idx].get_bounding_box().get_diameter();
98  auto L = compute_expansion_length(d / lambda, m_accuracy);
99  ld.set_expansion_length(L);
100  }
101 
102  // compute interpolation matrices
103  for (size_t i = 0; i < tree.get_n_levels(); ++i)
104  {
105  auto &ld = m_level_data_vector[i];
106  auto const &Sto = ld.get_unit_sphere();
107  if (i >= 3)
108  ld.set_interp_dn(interpolator(m_level_data_vector[i - 1].get_unit_sphere(), Sto));
109  if (i < tree.get_n_levels() - 1 && i >= 2)
110  ld.set_interp_up(interpolator(m_level_data_vector[i + 1].get_unit_sphere(), Sto));
111  }
112  } // end of function init_level_data
113 
118  {
119  return m_level_data_vector[idx];
120  }
121 
126  {
127  return m_level_data_vector[idx];
128  }
129 
131  class m2m
132  : public operator_with_wave_number<wave_number_t>
133  , public fmm_operator<m2m_tag>
134  {
135  public:
139 
140  m2m(wave_number_t const &wave_number)
141  : wn_base_t(wave_number)
142  {
143  }
144 
145  static size_t unique_idx(cluster_t const &to, cluster_t const &from)
146  {
147  return bounding_box_t::dist2idx(
148  from.get_bounding_box().get_center(),
150  }
151 
152  result_t operator()(cluster_t const &to, cluster_t const &from) const
153  {
154  using namespace std::complex_literals;
155  auto const &Sto = to.get_level_data().get_unit_sphere();
157  - from.get_bounding_box().get_center();
158  auto const &k = this->get_wave_number();
159  cvector_t shift = exp((-1.i * k * Sto.get_s().transpose() * D).array());
160  return result_t(shift, to.get_level_data());
161  }
162  };
163 
164 
166  class l2l
167  : public operator_with_wave_number<wave_number_t>
168  , public fmm_operator<l2l_tag>
169  {
170  public:
174 
175  l2l(wave_number_t const &wave_number)
176  : wn_base_t(wave_number)
177  {
178  }
179 
180  static size_t unique_idx(cluster_t const &to, cluster_t const &from)
181  {
182  return bounding_box_t::dist2idx(
184  from.get_bounding_box().get_center());
185  }
186 
187  result_t operator()(cluster_t const &to, cluster_t const &from) const
188  {
189  using namespace std::complex_literals;
190 #if L2L_SHIFT_FIRST
191  auto const &Sfrom = from.get_level_data().get_unit_sphere();
192 #else
193  auto const &Sto = to.get_level_data().get_unit_sphere();
194 #endif
196  - from.get_bounding_box().get_center();
197  auto const &k = this->get_wave_number();
198 #if L2L_SHIFT_FIRST
199  cvector_t shift = exp((-1.i * k * Sfrom.get_s().transpose() * D).array());
200 #else
201  cvector_t shift = exp((-1.i * k * Sto.get_s().transpose() * D).array());
202 #endif
203  return result_t(shift, to.get_level_data());
204  }
205  };
206 
207 
210  template <int Ny>
211  class p2m
212  : public operator_with_wave_number<wave_number_t>
213  , public fmm_operator<p2m_tag>
214  {
215  public:
217 
218  using test_input_t = cluster_t;
219  using trial_input_t = typename NiHu::normal_derivative_kernel<
221  >::trial_input_t;
222  using result_t = cvector_t;
223 
224  p2m(wave_number_t const &wave_number)
225  : wn_base_t(wave_number)
226  {
227  }
228 
229  size_t rows(test_input_t const &to) const
230  {
232  }
233 
234  result_t operator()(test_input_t const &to, trial_input_t const &tri) const
235  {
236  return eval(to, tri, std::integral_constant<int, Ny>());
237  }
238 
239  private:
241  result_t eval(test_input_t const &to, trial_input_t const &tri,
242  std::integral_constant<int, 0>) const
243  {
244  using namespace std::complex_literals;
245  auto const &Y = to.get_bounding_box().get_center();
246  auto const &y = tri.get_x();
247  auto const &s = to.get_level_data().get_unit_sphere().get_s();
248  auto const &k = this->get_wave_number();
249  location_t d = Y - y;
250  return Eigen::exp(-1.i * k * (s.transpose() * d).array());
251  }
252 
254  result_t eval(test_input_t const &to, trial_input_t const &tri,
255  std::integral_constant<int, 1>) const
256  {
257  using namespace std::complex_literals;
258  auto const &Y = to.get_bounding_box().get_center();
259  auto const &y = tri.get_x();
260  auto const &s = to.get_level_data().get_unit_sphere().get_s();
261  auto const &k = this->get_wave_number();
262  location_t d = Y - y;
263  return Eigen::exp(-1.i * k * (s.transpose() * d).array())
264  * ((1.i * k) * (s.transpose() * tri.get_unit_normal()).array());
265  }
266  };
267 
270  template <int Ny>
271  class p2l
272  : public operator_with_wave_number<wave_number_t>
273  , public fmm_operator<p2l_tag>
274  {
275  public:
277 
278  using test_input_t = cluster_t;
279  using trial_input_t = typename NiHu::normal_derivative_kernel<
281  >::trial_input_t;
282  using result_t = cvector_t;
283 
284  p2l(wave_number_t const &wave_number)
285  : wn_base_t(wave_number)
286  {
287  }
288 
289  size_t rows(test_input_t const &to) const
290  {
292  }
293 
294  result_t operator()(test_input_t const &to, trial_input_t const &tri) const
295  {
296  return eval(to, tri, std::integral_constant<int, Ny>());
297  }
298 
299  private:
300  result_t eval(test_input_t const &to, trial_input_t const &tri,
301  std::integral_constant<int, 0>) const
302  {
303  throw std::logic_error("Unimplemented p2l operator");
304  }
305 
306  result_t eval(test_input_t const &to, trial_input_t const &tri,
307  std::integral_constant<int, 1>) const
308  {
309  throw std::logic_error("Unimplemented p2l operator");
310  }
311  };
312 
313 
316  template <int Nx>
317  class l2p
318  : public operator_with_wave_number<wave_number_t>
319  , public fmm_operator<l2p_tag>
320  {
321  public:
323 
324  using trial_input_t = cluster_t;
325  using test_input_t = typename NiHu::normal_derivative_kernel<
327  >::test_input_t;
328  using result_t = Eigen::Matrix<std::complex<double>, 1, Eigen::Dynamic>;
329 
330  l2p(wave_number_t const &wave_number)
331  : wn_base_t(wave_number)
332  {
333  }
334 
335  size_t cols(trial_input_t const &from) const
336  {
338  }
339 
340  result_t operator()(test_input_t const &tsi, trial_input_t const &from) const
341  {
342  return eval(tsi, from, std::integral_constant<int, Nx>());
343  }
344 
345  private:
346  result_t eval(test_input_t const &tsi, trial_input_t const &from,
347  std::integral_constant<int, 0>) const
348  {
349  using namespace std::complex_literals;
350  auto const &X = from.get_bounding_box().get_center();
351  auto const &x = tsi.get_x();
352  auto const &S = from.get_level_data().get_unit_sphere();
353  auto const &s = S.get_s();
354  auto const &w = S.get_w();
355  auto const &k = this->get_wave_number();
356  location_t d = x - X;
357  return Eigen::exp(-1.i * k * (s.transpose() * d).array()) * w.array();
358  }
359 
360  result_t eval(test_input_t const &tsi, trial_input_t const &from,
361  std::integral_constant<int, 1>) const
362  {
363  using namespace std::complex_literals;
364  auto const &X = from.get_bounding_box().get_center();
365  auto const &x = tsi.get_x();
366  auto const &S = from.get_level_data().get_unit_sphere();
367  auto const &s = S.get_s();
368  auto const &w = S.get_w();
369  auto const &k = this->get_wave_number();
370  location_t d = x - X;
371  return Eigen::exp(-1.i * k * (s.transpose() * d).array())
372  * (-1.i * k) * (s.transpose() * tsi.get_unit_normal()).array()
373  * w.array();
374  }
375  };
376 
377 
380  template <int Nx>
381  class m2p
382  : public operator_with_wave_number<wave_number_t>
383  , public fmm_operator<m2p_tag>
384  {
385  public:
387 
388  using trial_input_t = cluster_t;
389  using test_input_t = typename NiHu::normal_derivative_kernel<
391  >::test_input_t;
392  using result_t = Eigen::Matrix<std::complex<double>, 1, Eigen::Dynamic>;
393 
394  m2p(wave_number_t const &wave_number)
395  : wn_base_t(wave_number)
396  {
397  }
398 
399  size_t cols(trial_input_t const &from) const
400  {
401  return from.get_level_data().get_unit_sphere().get_s().cols();
402  }
403 
404  result_t operator()(test_input_t const &tsi, trial_input_t const &from) const
405  {
406  return eval(tsi, from, std::integral_constant<int, Nx>());
407  }
408 
409  private:
410  result_t eval(test_input_t const &tsi, trial_input_t const &from,
411  std::integral_constant<int, 0>) const
412  {
413  throw std::logic_error("Unimplemented m2p operator");
414  }
415 
416  result_t eval(test_input_t const &tsi, trial_input_t const &from,
417  std::integral_constant<int, 1>) const
418  {
419  throw std::logic_error("Unimplemented m2p operator");
420  }
421  };
422 
424  class m2l
425  : public operator_with_wave_number<wave_number_t>
426  , public fmm_operator<m2l_tag>
427  {
428  public:
430  using result_t = Eigen::DiagonalMatrix<std::complex<double>, Eigen::Dynamic>;
432 
433  m2l(wave_number_t const &wave_number)
434  : wn_base_t(wave_number)
435  {
436  }
437 
438  static size_t unique_idx(cluster_t const &to, cluster_t const &from)
439  {
441  }
442 
443  result_t operator()(cluster_t const &to, cluster_t const &from) const
444  {
445  auto const &k = this->get_wave_number();
446 
447  auto const &X = to.get_bounding_box().get_center();
448  auto const &Y = from.get_bounding_box().get_center();
449  location_t Dvec = X - Y;
450 
451  auto L = to.get_level_data().get_expansion_length();
452  auto const &s = to.get_level_data().get_unit_sphere().get_s();
453 
454  return m2l_matrix_impl(Dvec, s, k, L).asDiagonal();
455  }
456 
457  private:
458  static cvector_t m2l_matrix_impl(location_t const &Dvec,
459  Eigen::Matrix<double, 3, Eigen::Dynamic> const &s,
460  wave_number_t const &k,
461  size_t L)
462  {
463  using namespace boost::math::double_constants;
464  using namespace std::complex_literals;
465  using boost::math::legendre_p;
466  using boost::math::sph_hankel_1;
467 
468  double D = Dvec.norm();
469  location_t Uvec = Dvec / D;
470  auto N = s.cols();
471 
472  Eigen::Matrix<double, 1, Eigen::Dynamic> x = Uvec.transpose() * s;
473  auto z = -k * D;
474 
475  cvector_t M2L = cvector_t::Zero(N, 1);
476 
477  for (size_t l = 0; l <= L; ++l)
478  {
479  auto h = sph_hankel_1(l, z);
480  auto c = double(2 * l + 1) * std::pow(1.i, l) * h;
481  for (int i = 0; i < s.cols(); ++i)
482  M2L(i) += c * legendre_p(int(l), x(0, i));
483  }
484  M2L *= -1.i * k / (4.0 * pi) / (4.0 * pi);
485 
486  return M2L;
487  }
488  };
489 
492  template <int Ny>
493  using p2m_type = p2m<Ny>;
494 
497  template <int Ny>
498  using p2l_type = p2l<Ny>;
499 
502  template <int Nx>
503  using m2p_type = m2p<Nx>;
504 
507  template <int Nx>
508  using l2p_type = l2p<Nx>;
509 
513  template <int Nx, int Ny>
514  using p2p_type = fmm::p2p<
517  >
518  >;
519 
523  template <int Ny>
525  {
526  return p2m<Ny>(m_wave_number);
527  }
528 
532  template <int Ny>
534  {
535  return p2l<Ny>(m_wave_number);
536  }
537 
541  template <int Nx>
543  {
544  return l2p<Nx>(m_wave_number);
545  }
546 
550  template <int Nx>
552  {
553  return m2p<Nx>(m_wave_number);
554  }
555 
560  template <int Nx, int Ny>
562  {
565  > kernel_t;
566  return p2p_type<Nx, Ny>(kernel_t(m_wave_number));
567  }
568 
571  m2m create_m2m() const
572  {
573  return m2m(m_wave_number);
574  }
575 
578  l2l create_l2l() const
579  {
580  return l2l(m_wave_number);
581  }
582 
585  m2l create_m2l() const
586  {
587  return m2l(m_wave_number);
588  }
589 
590 private:
591  wave_number_t m_wave_number;
592  std::vector<helmholtz_3d_hf_level_data> m_level_data_vector;
593  double m_accuracy; // C
594 };
595 
596 
597 } // end of namespace fmm
598 } // namespace NiHu
599 
600 #endif /* NIHU_HELMHOLTZ_3D_HF_FMM_HPP_INCLUDED */
NiHu::fmm::helmholtz_3d_hf_fmm::create_m2p
m2p_type< Nx > create_m2p() const
factory function for the M2P operator
Definition: helmholtz_3d_hf_fmm.hpp:551
NiHu::fmm::helmholtz_3d_hf_fmm::p2m
P2M operator of the FMM for the Helmholtz equation in 3D.
Definition: helmholtz_3d_hf_fmm.hpp:211
NiHu::fmm::helmholtz_3d_hf_fmm::create_p2l
p2l_type< Ny > create_p2l() const
factory function for the P2L operator
Definition: helmholtz_3d_hf_fmm.hpp:533
NiHu::fmm::cluster_tree< cluster_t >
NiHu::fmm::helmholtz_3d_hf_fmm::m2l
M2L operator of the FMM for the Helmholtz equation in 3D.
Definition: helmholtz_3d_hf_fmm.hpp:424
NiHu::fmm::helmholtz_3d_hf_fmm::create_p2m
p2m_type< Ny > create_p2m() const
factory function for the P2M operator
Definition: helmholtz_3d_hf_fmm.hpp:524
NiHu::fmm::unit_sphere::get_num_directions
size_t get_num_directions() const
return number of directions (quadrature points)
Definition: unit_sphere.h:54
NiHu::fmm::helmholtz_3d_hf_cluster::get_level_data
const helmholtz_3d_hf_level_data & get_level_data() const
return the cluster's level data
Definition: helmholtz_3d_hf_cluster.cpp:37
NiHu::fmm::cluster_base< helmholtz_3d_hf_cluster >::bounding_box_t
bounding_box< dimension, double > bounding_box_t
Bounding box type.
Definition: cluster.hpp:50
NiHu::fmm::helmholtz_3d_hf_fmm::l2l
L2L operator of the FMM for the Helmholtz equation in 3D.
Definition: helmholtz_3d_hf_fmm.hpp:166
NiHu::fmm::helmholtz_3d_hf_fmm::m2m
M2M operator of the FMM for the Helmholtz equation in 3D.
Definition: helmholtz_3d_hf_fmm.hpp:131
p2p.hpp
P2P operator.
NiHu::fmm::helmholtz_3d_hf_fmm::get_level_data
helmholtz_3d_hf_level_data & get_level_data(size_t idx)
return level data reference for a specific level
Definition: helmholtz_3d_hf_fmm.hpp:125
m2l_indices.hpp
Implementation of class template Nihu::fmm::m2l_indices.
NiHu::fmm::helmholtz_3d_hf_fmm::compute_expansion_length
static size_t compute_expansion_length(double drel, double C)
compute expansion length based on relative cluster size
Definition: helmholtz_3d_hf_fmm.hpp:67
helmholtz_3d_hf_level_data.h
level data of the the helmholtz 3d high frequency fmm
NiHu::fmm::helmholtz_3d_hf_fmm::get_level_data
const helmholtz_3d_hf_level_data & get_level_data(size_t idx) const
return level data for a specific level
Definition: helmholtz_3d_hf_fmm.hpp:117
NiHu::fmm::cluster_tree::get_n_levels
size_t get_n_levels() const
return number of levels
Definition: cluster_tree.hpp:253
NiHu::exponential_covariance_kernel
Definition: covariance_kernel.hpp:42
NiHu::fmm::helmholtz_3d_hf_fmm
the fmm for the 3D Helmholtz equation
Definition: helmholtz_3d_hf_fmm.hpp:38
NiHu::fmm::m2l_indices
Class assigning indices to M2L distances.
Definition: m2l_indices.hpp:21
NiHu::fmm::bounding_box::get_center
const location_t & get_center(void) const
return center
Definition: bounding_box.hpp:75
NiHu::fmm::helmholtz_3d_hf_fmm_upshift
Class for shifting up Multipole contributions This class is the result of the M2M operation....
Definition: helmholtz_3d_hf_shift.h:18
NiHu::fmm::unit_sphere::get_s
const Eigen::Matrix< double, 3, Eigen::Dynamic > & get_s(void) const
return Cartesian quadrature points
Definition: unit_sphere.h:94
cluster_tree.hpp
Implementation of class NiHu::fmm::cluster_tree.
NiHu::fmm::helmholtz_3d_hf_fmm::bounding_box_t
typename cluster_t::bounding_box_t bounding_box_t
the bounding box type
Definition: helmholtz_3d_hf_fmm.hpp:48
NiHu::fmm::helmholtz_3d_hf_fmm::p2l
P2L operator of the FMM for the Helmholtz equation in 3D.
Definition: helmholtz_3d_hf_fmm.hpp:271
NiHu::fmm::helmholtz_3d_hf_fmm::cvector_t
Eigen::Matrix< std::complex< double >, Eigen::Dynamic, 1 > cvector_t
complex dynamic vector
Definition: helmholtz_3d_hf_fmm.hpp:44
NiHu::fmm::helmholtz_3d_hf_fmm::wave_number_t
WaveNumber wave_number_t
template argument as nested type
Definition: helmholtz_3d_hf_fmm.hpp:42
NiHu::fmm::helmholtz_3d_hf_fmm::location_t
typename bounding_box_t::location_t location_t
the physical location type
Definition: helmholtz_3d_hf_fmm.hpp:50
NiHu::fmm::helmholtz_3d_hf_fmm::create_m2l
m2l create_m2l() const
factory function for the M2L operator
Definition: helmholtz_3d_hf_fmm.hpp:585
operator_with_wave_number.hpp
Implementation of class template NiHu::fmm::operator_with_wave_number.
NiHu::fmm::helmholtz_3d_hf_fmm::create_l2l
l2l create_l2l() const
factory function for the L2L operator
Definition: helmholtz_3d_hf_fmm.hpp:578
fmm_operator.hpp
FMM operator types and tags.
NiHu::bessel::Y
std::complex< double > Y(std::complex< double > const &z)
Bessel function Y_nu(z)
Definition: math_functions.hpp:315
NiHu::fmm::helmholtz_3d_hf_level_data::get_unit_sphere
const unit_sphere & get_unit_sphere() const
return the stored unit sphere
Definition: helmholtz_3d_hf_level_data.cpp:21
NiHu::helmholtz_kernel
Definition: helmholtz_kernel.hpp:44
NiHu::fmm::p2p
Definition: p2p.hpp:20
unit_sphere.h
Interface of class NiHu::fmm::unit_sphere.
NiHu::fmm::interpolator
class interpolating over the unit sphere
Definition: unit_sphere_interpolator.h:25
NiHu::fmm::cluster_tree::level_begin
size_t level_begin(size_t idx) const
Begin iterator to idx-th level clusters.
Definition: cluster_tree.hpp:264
NiHu::fmm::helmholtz_3d_hf_fmm::init_level_data
void init_level_data(cluster_tree_t const &tree)
initialize the level data of the fmm method
Definition: helmholtz_3d_hf_fmm.hpp:84
NiHu::fmm::helmholtz_3d_hf_fmm::m2p
M2P operator of the FMM for the Helmholtz equation in 3D.
Definition: helmholtz_3d_hf_fmm.hpp:381
NiHu::fmm::cluster_base::get_bounding_box
const bounding_box_t & get_bounding_box() const
return cluster's bounding box
Definition: cluster.hpp:111
NiHu::fmm::helmholtz_3d_hf_fmm::cluster_t
helmholtz_3d_hf_cluster cluster_t
the fmm's cluster type
Definition: helmholtz_3d_hf_fmm.hpp:46
NiHu::fmm::helmholtz_3d_hf_fmm::create_m2m
m2m create_m2m() const
factory function for the M2M operator
Definition: helmholtz_3d_hf_fmm.hpp:571
cluster.hpp
implementation of class NiHu::fmm::cluster_base
NiHu::fmm::helmholtz_3d_hf_level_data::get_expansion_length
size_t get_expansion_length() const
return the expansion length
Definition: helmholtz_3d_hf_level_data.cpp:26
NiHu::fmm::helmholtz_3d_hf_fmm_downshift
Class for shifting down Local contributions This class is the result of the L2L operation....
Definition: helmholtz_3d_hf_shift.h:50
NiHu::fmm::fmm_operator
Operator defining its tag type.
Definition: fmm_operator.hpp:85
NiHu::fmm::helmholtz_3d_hf_fmm::set_accuracy
void set_accuracy(double accuracy)
set the method's accuracy parameter
Definition: helmholtz_3d_hf_fmm.hpp:77
NiHu::fmm::operator_with_wave_number
class storing a wave number
Definition: operator_with_wave_number.hpp:17
NiHu::fmm::helmholtz_3d_hf_fmm::create_l2p
l2p_type< Nx > create_l2p() const
factory function for the L2P operator
Definition: helmholtz_3d_hf_fmm.hpp:542
NiHu::fmm::helmholtz_3d_hf_fmm::create_p2p
p2p_type< Nx, Ny > create_p2p() const
factory function for the P2P operator
Definition: helmholtz_3d_hf_fmm.hpp:561
NiHu::normal_derivative_kernel
Normal derivative of a distance dependent kernel.
Definition: normal_derivative_kernel.hpp:26
NiHu::fmm::helmholtz_3d_hf_fmm::helmholtz_3d_hf_fmm
helmholtz_3d_hf_fmm(wave_number_t const &k)
constructor
Definition: helmholtz_3d_hf_fmm.hpp:58
NiHu::fmm::helmholtz_3d_hf_cluster
cluster type of the Helmholtz 3D High frequency FMM
Definition: helmholtz_3d_hf_cluster.h:35
NiHu::fmm::helmholtz_3d_hf_level_data
level data of the helmholtz 3d hf fmm
Definition: helmholtz_3d_hf_level_data.h:23
NiHu::fmm::helmholtz_3d_hf_fmm::l2p
L2P operator of the FMM for the Helmholtz equation in 3D.
Definition: helmholtz_3d_hf_fmm.hpp:317
C
Definition: bbfmm_covariance.cpp:47
helmholtz_3d_hf_cluster.h
Interface of class fmm::helmholtz_3d_hf_cluster.