Bembel
HypersingularOperator.hpp
1 // This file is part of Bembel, the higher order C++ boundary element library.
2 //
3 // Copyright (C) 2024 see <http://www.bembel.eu>
4 //
5 // It was written as part of a cooperation of J. Doelz, H. Harbrecht, S. Kurz,
6 // M. Multerer, S. Schoeps, and F. Wolf at Technische Universitaet Darmstadt,
7 // Universitaet Basel, and Universita della Svizzera italiana, Lugano. This
8 // source code is subject to the GNU General Public License version 3 and
9 // provided WITHOUT ANY WARRANTY, see <http://www.bembel.eu> for further
10 // information.
11 //
12 #ifndef BEMBEL_SRC_HELMHOLTZ_HYPERSINGULAROPERATOR_HPP_
13 #define BEMBEL_SRC_HELMHOLTZ_HYPERSINGULAROPERATOR_HPP_
14 
15 namespace Bembel {
16 // forward declaration of class HelmholtzHypersingularOperator in order to
17 // define traits
18 class HelmholtzHypersingularOperator;
19 
20 template <>
22  typedef Eigen::VectorXcd EigenType;
23  typedef Eigen::VectorXcd::Scalar Scalar;
24  enum {
25  OperatorOrder = 1,
26  Form = DifferentialForm::Continuous,
27  NumberOfFMMComponents = 3
28  };
29 };
30 
35  : public LinearOperatorBase<HelmholtzHypersingularOperator> {
36  // implementation of the kernel evaluation, which may be based on the
37  // information available from the superSpace
38  public:
40  template <class T>
41  void evaluateIntegrand_impl(const T &super_space, const SurfacePoint &p1,
42  const SurfacePoint &p2,
43  Eigen::MatrixXcd *intval) const {
44  auto polynomial_degree = super_space.get_polynomial_degree();
45  auto polynomial_degree_plus_one_squared =
46  (polynomial_degree + 1) * (polynomial_degree + 1);
47 
48  // get evaluation points on unit square
49  Eigen::Vector2d s = p1.segment<2>(0);
50  Eigen::Vector2d t = p2.segment<2>(0);
51 
52  // get quadrature weights
53  double ws = p1(2);
54  double wt = p2(2);
55 
56  // get points on geometry and tangential derivatives
57  Eigen::Vector3d x_f = p1.segment<3>(3);
58  Eigen::Vector3d x_f_dx = p1.segment<3>(6);
59  Eigen::Vector3d x_f_dy = p1.segment<3>(9);
60  Eigen::Vector3d y_f = p2.segment<3>(3);
61  Eigen::Vector3d y_f_dx = p2.segment<3>(6);
62  Eigen::Vector3d y_f_dy = p2.segment<3>(9);
63 
64  // compute surface measures from tangential derivatives
65  Eigen::Vector3d x_n = x_f_dx.cross(x_f_dy);
66  Eigen::Vector3d y_n = y_f_dx.cross(y_f_dy);
67 
68  // compute h
69  double h =
70  1. / (1 << super_space.get_refinement_level()); // h = 1 ./ (2^M)
71 
72  // evaluate kernel
73  std::complex<double> kernel = evaluateKernel(x_f, y_f);
74 
75  // integrand without basis functions
76  std::complex<double> integrandScalar =
77  -kernel * x_n.dot(y_n) * wavenumber2_ * ws * wt;
78  std::complex<double> integrandCurl =
79  kernel * x_n.norm() * y_n.norm() * ws * wt / h / h;
80 
81  // multiply basis functions with integrand and add to intval, this is an
82  // efficient implementation of
83  super_space.addScaledBasisInteraction(intval, integrandScalar, s, t);
84  super_space.addScaledSurfaceCurlInteraction(intval, integrandCurl, p1, p2);
85 
86  return;
87  }
88 
89  Eigen::Matrix<std::complex<double>, 3, 3> evaluateFMMInterpolation_impl(
90  const SurfacePoint &p1, const SurfacePoint &p2) const {
91  // get evaluation points on unit square
92  Eigen::Vector2d s = p1.segment<2>(0);
93  Eigen::Vector2d t = p2.segment<2>(0);
94 
95  // get points on geometry and tangential derivatives
96  Eigen::Vector3d x_f = p1.segment<3>(3);
97  Eigen::Vector3d x_f_dx = p1.segment<3>(6);
98  Eigen::Vector3d x_f_dy = p1.segment<3>(9);
99  Eigen::Vector3d y_f = p2.segment<3>(3);
100  Eigen::Vector3d y_f_dx = p2.segment<3>(6);
101  Eigen::Vector3d y_f_dy = p2.segment<3>(9);
102 
103  // compute surface measures from tangential derivatives
104  Eigen::Vector3d x_n = x_f_dx.cross(x_f_dy);
105  Eigen::Vector3d y_n = y_f_dx.cross(y_f_dy);
106 
107  // evaluate kernel
108  std::complex<double> kernel = evaluateKernel(x_f, y_f);
109 
110  // interpolation
111  Eigen::Matrix<std::complex<double>, 3, 3> intval;
112  intval.setZero();
113  intval(0, 0) = -kernel * wavenumber2_ * x_n.dot(y_n);
114  intval(1, 1) = kernel * x_f_dy.dot(y_f_dy);
115  intval(1, 2) = -kernel * x_f_dy.dot(y_f_dx);
116  intval(2, 1) = -kernel * x_f_dx.dot(y_f_dy);
117  intval(2, 2) = kernel * x_f_dx.dot(y_f_dx);
118 
119  return intval;
120  }
121 
125  std::complex<double> evaluateKernel(const Eigen::Vector3d &x,
126  const Eigen::Vector3d &y) const {
127  auto r = (x - y).norm();
128  return std::exp(-std::complex<double>(0., 1.) * wavenumber_ * r) / 4. /
129  BEMBEL_PI / r;
130  }
132  // setters
134  void set_wavenumber(std::complex<double> wavenumber) {
135  wavenumber_ = wavenumber;
136  wavenumber2_ = wavenumber_ * wavenumber_;
137  }
139  // getters
141  std::complex<double> get_wavenumber() { return wavenumber_; }
142 
143  private:
144  std::complex<double> wavenumber_;
145  std::complex<double> wavenumber2_;
146 };
147 
153 template <typename InterpolationPoints>
154 struct H2Multipole::Moment2D<InterpolationPoints,
156  static std::vector<Eigen::MatrixXd> compute2DMoment(
158  const int cluster_level, const int cluster_refinements,
159  const int number_of_points) {
160  Eigen::MatrixXd moment = moment2DComputer<
163  super_space, cluster_level, cluster_refinements, number_of_points);
164  Eigen::MatrixXd moment_dx = moment2DComputer<
167  super_space, cluster_level, cluster_refinements, number_of_points);
168  Eigen::MatrixXd moment_dy = moment2DComputer<
170  Moment1DDerivative<InterpolationPoints,
172  super_space, cluster_level, cluster_refinements, number_of_points);
173 
174  Eigen::MatrixXd moment_total(
175  moment.rows() + moment_dx.rows() + moment_dy.rows(), moment_dx.cols());
176  moment_total << moment, moment_dx, moment_dy;
177 
178  std::vector<Eigen::MatrixXd> vector_of_moments;
179  vector_of_moments.push_back(moment_total);
180 
181  return vector_of_moments;
182  }
183 };
184 
185 } // namespace Bembel
186 #endif // BEMBEL_SRC_HELMHOLTZ_HYPERSINGULAROPERATOR_HPP_
std::complex< double > evaluateKernel(const Eigen::Vector3d &x, const Eigen::Vector3d &y) const
Fundamental solution of Helmholtz problem.
Eigen::Matrix< double, 12, 1 > SurfacePoint
typedef of SurfacePoint
Eigen::MatrixXd moment2DComputer(const SuperSpace< LinOp > &super_space, const int cluster_level, const int cluster_refinements, const int number_of_points)
Computes a single 2D moment for the FMM by tensorisation of the 1D moments.
Routines for the evalutation of pointwise errors.
Definition: AnsatzSpace.hpp:14
Computes 1D moment for FMM using derivatives of the basis functions. All calculations ar performed on...
Computes 1D moment for FMM. All calculations ar performed on [0,1].
Computes all 2D moment for the FMM by tensorisation of the 1D moments. Specialice this for your linea...
linear operator base class. this serves as a common interface for existing linear operators.
struct containing specifications on the linear operator has to be specialized or derived for any part...
The superspace manages local polynomial bases on each element of the mesh and provides an interface t...
Definition: SuperSpace.hpp:22