NiHu  2.0
laplace_3d_fmm.hpp
Go to the documentation of this file.
1 
7 #ifndef NIHU_LAPLACE_3D_FMM_HPP_INCLUDED
8 #define NIHU_LAPLACE_3D_FMM_HPP_INCLUDED
9 
10 #include "cluster.hpp"
11 #include "m2l_indices.hpp"
12 #include "p2p.hpp"
13 
14 #include "library/laplace_3d.hpp"
15 
16 #include <boost/math/constants/constants.hpp>
17 #include <boost/math/special_functions/spherical_harmonic.hpp>
18 #include <boost/math/special_functions/factorials.hpp>
19 
20 #include <Eigen/Dense>
21 
22 #include <complex>
23 
24 namespace NiHu
25 {
26 namespace fmm
27 {
28 
30 class laplace_3d_cluster;
31 
33 template <>
35 {
36 private:
37  typedef Eigen::Matrix<std::complex<double>, Eigen::Dynamic, 1> cvector_t;
38 
39 public:
41  static size_t const dimension = 3;
43  typedef cvector_t multipole_t;
45  typedef cvector_t local_t;
46 };
47 
50  : public cluster_base<laplace_3d_cluster>
51 {
53 
54 public:
56  typedef typename base_t::multipole_t multipole_t;
58  typedef typename base_t::local_t local_t;
59 
61  void set_expansion_length(size_t L);
62 
65  size_t get_expansion_length() const;
66 
67  size_t data_size() const;
68 
71 
73  local_t zero_local() const;
74 
75  Eigen::Index linear_index(Eigen::Index n, Eigen::Index m) const;
76 
77 private:
78  size_t m_expansion_length;
79 };
80 
83 {
84 public:
91 
92 public:
97  template <int Nx, int Ny>
100  > >
101  create_p2p() const
102  {
105  > kernel_t;
106  return fmm::p2p<kernel_t>(kernel_t());
107  }
108 
109  static std::complex<double> Y(size_t n, int m, double theta, double phi)
110  {
111  using boost::math::spherical_harmonic;
112  using namespace boost::math::double_constants;
113 
114  std::complex<double> res =
115  spherical_harmonic(unsigned(n), std::abs(m), theta, phi)
116  / std::sqrt((2 * n + 1.0) / (4.0 * pi));
117  return (m < 0) ? std::conj(res) : res;
118  }
119 
120  static double A(int n, int m)
121  {
122  using boost::math::factorial;
123  double res = std::pow(-1, n) / std::sqrt(
124  factorial<double>(n - m) * factorial<double>(n + m));
125  return res;
126  }
127 
128 
131  template <unsigned Ny>
132  class p2m
133  {
134  public:
135  typedef cluster_t test_input_t;
137 
138  typedef typename NiHu::normal_derivative_kernel<
140  0, Ny
141  >::trial_input_t trial_input_t;
142 
143  typedef cluster_t::multipole_t result_t;
144 
145  size_t rows(test_input_t const &to) const
146  {
147  return to.data_size();
148  }
149 
150  result_t operator()(test_input_t const &to, trial_input_t const & from) const
151  {
152  return eval(to, from, std::integral_constant<unsigned, Ny>());
153  }
154 
155  result_t eval(test_input_t const &to,
156  trial_input_t const &from,
157  std::integral_constant<unsigned, 0>) const
158  {
159  using namespace boost::math::double_constants;
160 
161  result_t res(to.data_size(), 1);
162 
163  x_t x = from.get_x() - to.get_bounding_box().get_center();
164  double r = x.norm();
165  double phi = std::atan2(x(1), x(0));
166  double theta = std::acos(x(2) / r);
167 
168  for (int n = 0; n <= to.get_expansion_length(); ++n)
169  {
170  double rn = std::pow(r, n);
171  for (int m = -n; m <= n; ++m)
172  {
173  auto idx = to.linear_index(n, m);
174  res(idx, 0) = rn * Y(n, -m, theta, phi);
175  }
176  }
177 
178  return res / (4. * pi);
179  }
180 
181  result_t eval(test_input_t const &to,
182  trial_input_t const &from,
183  std::integral_constant<unsigned, 1>) const
184  {
185  using namespace boost::math::double_constants;
186 
187  result_t res = to.zero_multipole();
188  return res / (4. * pi);
189  }
190  };
191 
192 
195  template <unsigned Ny>
196  class p2l
197  {
198  public:
200  typedef cluster_t test_input_t;
201  typedef typename NiHu::normal_derivative_kernel<
203  0, Ny
204  >::trial_input_t trial_input_t;
205  typedef Eigen::Matrix<std::complex<double>, Eigen::Dynamic, 1> result_t;
206 
207  size_t rows(test_input_t const &to) const
208  {
209  return to.data_size();
210  }
211 
212  result_t operator()(test_input_t const &to, trial_input_t const &from) const
213  {
214  return eval(to, from, std::integral_constant<unsigned, Ny>());
215  }
216 
217  private:
218  result_t eval(test_input_t const &to, trial_input_t const & from,
219  std::integral_constant<unsigned, 0>) const
220  {
221  using namespace boost::math::double_constants;
222 
223  result_t res(rows(to), 1);
224 
225  x_t x = from.get_x() - to.get_bounding_box().get_center();
226  double r = x.norm();
227  double phi = std::atan2(x(1), x(0));
228  double theta = std::acos(x(2) / r);
229 
230  for (int n = 0; n <= to.get_expansion_length(); ++n)
231  {
232  double rn = std::pow(r, -(n + 1));
233  for (int m = -n; m <= n; ++m)
234  {
235  auto idx = to.linear_index(n, m);
236  res(idx, 0) = rn * Y(n, -m, theta, phi);
237  }
238  }
239 
240  return res / (4.0 * pi);
241  }
242 
243  result_t eval(test_input_t const &to, trial_input_t const & from,
244  std::integral_constant<unsigned, 1>) const
245  {
246  throw std::logic_error("Unimplemented");
247  return result_t();
248  }
249  };
250 
251 
254  template <unsigned Nx>
255  class l2p
256  {
257  public:
258  typedef typename NiHu::normal_derivative_kernel<
260  Nx, 0
261  >::test_input_t test_input_t;
263 
264  typedef cluster_t trial_input_t;
265  typedef Eigen::Matrix<std::complex<double>, 1, Eigen::Dynamic> complex_result_t;
266  typedef complex_result_t result_t;
267 
268  size_t cols(trial_input_t const &from) const
269  {
270  return from.data_size();
271  }
272 
273  result_t operator()(test_input_t const &to, trial_input_t const & from) const
274  {
275  return eval(to, from, std::integral_constant<unsigned, Nx>());
276  }
277 
278  private:
279  result_t eval(test_input_t const &to,
280  trial_input_t const &from,
281  std::integral_constant<unsigned, 0>) const
282  {
283  result_t res(1, from.data_size());
284 
285  x_t x = to.get_x() - from.get_bounding_box().get_center();
286  double r = x.norm();
287  double phi = std::atan2(x(1), x(0));
288  double theta = std::acos(x(2) / r);
289 
290  for (int n = 0; n <= from.get_expansion_length(); ++n)
291  {
292  double rn = std::pow(r, n);
293  for (int m = -n; m <= n; ++m)
294  {
295  auto idx = from.linear_index(n, m);
296  res(0, idx) = rn * Y(n, m, theta, phi);
297  }
298  }
299 
300  return res;
301  }
302 
303  result_t eval(test_input_t const &to,
304  trial_input_t const &from,
305  std::integral_constant<unsigned, 1>) const
306  {
307  throw std::logic_error("Unimplemented");
308  return result_t();
309  }
310  };
311 
312 
315  template <unsigned Nx>
316  class m2p
317  {
318  public:
319  typedef typename NiHu::normal_derivative_kernel<
321  Nx, 0
322  >::test_input_t test_input_t;
323  typedef cluster_t trial_input_t;
324  typedef Eigen::Matrix<std::complex<double>, 1, Eigen::Dynamic> complex_result_t;
325  typedef complex_result_t result_t;
327 
328  size_t cols(trial_input_t const &from) const
329  {
330  return from.data_size();
331  }
332 
333  result_t operator()(test_input_t const &to, trial_input_t const &from) const
334  {
335  return eval(to, from, std::integral_constant<unsigned, Nx>());
336  }
337 
338  private:
339  result_t eval(test_input_t const &to,
340  trial_input_t const &from,
341  std::integral_constant<unsigned, 0>) const
342  {
343  result_t res(1, from.data_size());
344 
345  x_t x = to.get_x() - from.get_bounding_box().get_center();
346  double r = x.norm();
347  double phi = std::atan2(x(1), x(0));
348  double theta = std::acos(x(2) / r);
349 
350  for (size_t n = 0; n <= from.get_expansion_length(); ++n)
351  {
352  double rn = std::pow(r, -int(n+1));
353  for (int m = -int(n); m <= int(n); ++m)
354  {
355  auto idx = from.linear_index(n, m);
356  res(0, idx) = rn * Y(n, m, theta, phi);
357  }
358  }
359 
360  return res;
361  }
362 
363  result_t eval(test_input_t const &to,
364  trial_input_t const &from,
365  std::integral_constant<unsigned, 1>) const
366  {
367  throw std::logic_error("Unimplemented");
368  return result_t();
369  }
370  };
371 
372 
374  class m2m
375  {
376  public:
377  typedef Eigen::Matrix<std::complex<double>, Eigen::Dynamic, Eigen::Dynamic> result_t;
379 
380  static size_t unique_idx(cluster_t const &to, cluster_t const &from);
381 
382  result_t operator()(cluster_t to, cluster_t from) const;
383  };
384 
385 
387  class l2l
388  {
389  public:
390  typedef Eigen::Matrix<std::complex<double>, Eigen::Dynamic, Eigen::Dynamic> result_t;
392 
393  static size_t unique_idx(cluster_t const &to, cluster_t const &from);
394 
395  result_t operator()(cluster_t to, cluster_t from) const;
396  };
397 
398 
400  class m2l
401  {
402  public:
403  typedef Eigen::Matrix<std::complex<double>, Eigen::Dynamic, Eigen::Dynamic> result_t;
405 
406  static size_t unique_idx(cluster_t const &to, cluster_t const &from);
407 
408  result_t operator()(cluster_t to, cluster_t from) const;
409  };
410 
411 
415  template <unsigned Ny>
417  {
418  return p2m<Ny>();
419  }
420 
421 
425  template <unsigned Ny>
427  {
428  return p2l<Ny>();
429  }
430 
431 
435  template <unsigned Nx>
437  {
438  return m2p<Nx>();
439  }
440 
441 
445  template <unsigned Nx>
447  {
448  return l2p<Nx>();
449  }
450 
451 
454  m2m create_m2m() const;
455 
456 
459  l2l create_l2l() const;
460 
461 
464  m2l create_m2l() const;
465 };
466 
467 } // end of namespace fmm
468 } // namespace NiHu
469 
470 #endif /* NIHU_LAPLACE_3D_FMM_HPP_INCLUDED */
NiHu::fmm::laplace_3d_fmm::m2l
M2L operator of the Laplace 3D FMM.
Definition: laplace_3d_fmm.hpp:400
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::laplace_3d_fmm::p2l
P2L operator of the Laplace 3D FMM.
Definition: laplace_3d_fmm.hpp:196
NiHu::fmm::laplace_3d_fmm::create_p2p
fmm::p2p< NiHu::normal_derivative_kernel< NiHu::laplace_kernel< NiHu::space_3d< double > >, Nx, Ny > > create_p2p() const
return an instance of the P2P operator
Definition: laplace_3d_fmm.hpp:101
NiHu::fmm::cluster_base::local_t
traits_t::local_t local_t
Local type.
Definition: cluster.hpp:60
NiHu::fmm::laplace_3d_fmm::create_p2l
p2l< Ny > create_p2l() const
return an instance of the P2L operator
Definition: laplace_3d_fmm.hpp:426
NiHu::fmm::cluster_traits< laplace_3d_cluster >::multipole_t
cvector_t multipole_t
the multipole type
Definition: laplace_3d_fmm.hpp:43
NiHu::fmm::laplace_3d_fmm::create_l2l
l2l create_l2l() const
return an instance of the L2L operator
Definition: laplace_3d_fmm.cpp:191
NiHu::fmm::laplace_3d_fmm::bounding_box_t
cluster_t::bounding_box_t bounding_box_t
the bounding box type
Definition: laplace_3d_fmm.hpp:88
NiHu::fmm::laplace_3d_cluster::local_t
base_t::local_t local_t
the local type
Definition: laplace_3d_fmm.hpp:58
NiHu::fmm::laplace_3d_cluster::get_expansion_length
size_t get_expansion_length() const
get the expansion length
Definition: laplace_3d_fmm.cpp:20
NiHu::fmm::laplace_3d_cluster::set_expansion_length
void set_expansion_length(size_t L)
set the expansion length
Definition: laplace_3d_fmm.cpp:15
NiHu::fmm::laplace_3d_fmm::create_m2m
m2m create_m2m() const
return an instance of the M2M operator
Definition: laplace_3d_fmm.cpp:185
NiHu::fmm::laplace_3d_fmm::l2l
L2L operator of the Laplace 3D FMM.
Definition: laplace_3d_fmm.hpp:387
NiHu::exponential_covariance_kernel
Definition: covariance_kernel.hpp:42
NiHu::fmm::laplace_3d_fmm::m2p
M2P operator of the Laplace 3D FMM.
Definition: laplace_3d_fmm.hpp:316
p2p.hpp
P2P operator.
NiHu::fmm::laplace_3d_fmm::p2m
P2M operator of the Laplace 3D FMM.
Definition: laplace_3d_fmm.hpp:132
m2l_indices.hpp
Implementation of class template Nihu::fmm::m2l_indices.
NiHu::laplace_kernel
Kernel of the Laplace equation in two and three dimensions.
Definition: laplace_kernel.hpp:45
NiHu::fmm::laplace_3d_fmm::cluster_t
laplace_3d_cluster cluster_t
the cluster type
Definition: laplace_3d_fmm.hpp:86
NiHu::fmm::laplace_3d_fmm::create_m2p
m2p< Nx > create_m2p() const
return an instance of the M2P operator
Definition: laplace_3d_fmm.hpp:436
NiHu::fmm::cluster_traits< laplace_3d_cluster >::local_t
cvector_t local_t
the local type
Definition: laplace_3d_fmm.hpp:45
NiHu::fmm::laplace_3d_fmm::m2m
M2M operator of the Laplace 3D FMM.
Definition: laplace_3d_fmm.hpp:374
NiHu::fmm::cluster_traits
CRTP traits structure of a cluster.
Definition: cluster.hpp:33
NiHu::fmm::laplace_3d_cluster
cluster type of the Laplace 3D FMM
Definition: laplace_3d_fmm.hpp:49
NiHu::fmm::laplace_3d_fmm::l2p
L2P operator of the Laplace 3D FMM.
Definition: laplace_3d_fmm.hpp:255
NiHu::fmm::cluster_base
CRTP base class of clusters.
Definition: cluster.hpp:40
NiHu::fmm::laplace_3d_fmm::create_l2p
l2p< Nx > create_l2p() const
return an instance of the L2P operator
Definition: laplace_3d_fmm.hpp:446
NiHu::fmm::laplace_3d_fmm
the fmm for the Laplace equation in 3D
Definition: laplace_3d_fmm.hpp:82
NiHu::fmm::laplace_3d_cluster::zero_local
local_t zero_local() const
return a cleared local contribution
Definition: laplace_3d_fmm.cpp:37
NiHu::fmm::cluster_base::multipole_t
traits_t::multipole_t multipole_t
Multipole type.
Definition: cluster.hpp:58
NiHu::fmm::laplace_3d_cluster::zero_multipole
multipole_t zero_multipole() const
return a cleared multipole contribution
Definition: laplace_3d_fmm.cpp:31
NiHu::fmm::laplace_3d_fmm::create_p2m
p2m< Ny > create_p2m() const
return an instance of the P2M operator
Definition: laplace_3d_fmm.hpp:416
NiHu::fmm::laplace_3d_fmm::location_t
cluster_t::location_t location_t
the location type
Definition: laplace_3d_fmm.hpp:90
NiHu::fmm::bounding_box::get_center
const location_t & get_center(void) const
return center
Definition: bounding_box.hpp:75
NiHu::fmm::bounding_box< dimension, double >
NiHu::normal_derivative_kernel
Normal derivative of a distance dependent kernel.
Definition: normal_derivative_kernel.hpp:26
NiHu::fmm::cluster_base< laplace_3d_cluster >::location_t
bounding_box_t::location_t location_t
Location type.
Definition: cluster.hpp:52
cluster.hpp
implementation of class NiHu::fmm::cluster_base
NiHu::fmm::laplace_3d_fmm::create_m2l
m2l create_m2l() const
return an instance of the M2L operator
Definition: laplace_3d_fmm.cpp:197
NiHu::fmm::p2p
Definition: p2p.hpp:20
NiHu::fmm::laplace_3d_cluster::multipole_t
base_t::multipole_t multipole_t
the multipole type
Definition: laplace_3d_fmm.hpp:56