OpenBEM
Open-source framework for electromagnetic simulation with the boundary element method.
Loading...
Searching...
No Matches
singularity.tpp
Go to the documentation of this file.
1// OpenBEM - Copyright (C) 2026 Shashwat Sharma
2
3// This file is part of OpenBEM.
4
5// OpenBEM is free software: you can redistribute it and/or modify it under the terms of the
6// GNU General Public License as published by the Free Software Foundation, either version 3
7// of the License, or (at your option) any later version.
8
9// You should have received a copy of the GNU General Public License along with OpenBEM.
10// If not, see <https://www.gnu.org/licenses/>.
11
12
18#ifndef BEM_RWG_OPINT_SRC_SINGULARITY_I
19#define BEM_RWG_OPINT_SRC_SINGULARITY_I
20
21#include "types.hpp"
22#include "constants.hpp"
25
26
27namespace bem::rwg
28{
29
30template <typename TriangleQuadratureType, typename ScalarKernelType>
32 const Complex k,
33 const Triangle<2>& src_tri,
35 )
36{
37 compute_integral_terms(src_tri, r_obs);
38
39 SrcResult result_singular = assemble_integrals(k, src_tri, r_obs);
40
41 src_quad_.set_compute_terms(compute_g_terms_, compute_grad_g_terms_);
42 SrcResult result_nonsingular = src_quad_.integrate(k, src_tri, r_obs);
43
46 result.rs_g = result_singular.rs_g + result_nonsingular.rs_g;
47 result.grad_g = result_singular.grad_g + result_nonsingular.grad_g;
48
49 return result;
50};
51
52
53template <typename TriangleQuadratureType, typename ScalarKernelType>
55 const Triangle<2>& src_tri,
57 )
58{
59
60 const Float four_pi = four * pi;
61 const Float tol = TRIANGLE_DEFAULT_TOL * src_tri.shortest_edge_length();
62
63 // Projection of the observation point on the source triangle's local plane
64 EigMatNX<Float, 2> rho_obs = r_obs.topRows(2);
65 z_ = r_obs.row(2);
66 z_abs_ = z_.cwiseAbs();
67 EigRowVec<Float> z_sq = Eigen::pow(z_.array(), 2);
68
69 beta_ = EigRowVec<Float>::Zero(1, r_obs.cols());
70 t0_f2_ = EigRowVec<Float>::Zero(1, r_obs.cols());
71 u_f2_ = EigMatNX<Float, 2>::Zero(2, r_obs.cols());
72 u_f3_ = EigMatNX<Float, 2>::Zero(2, r_obs.cols());
73
74 for (uint8_t idx = 0; idx < 3; idx++)
75 {
76
77 // Indices of the edge's vertices
79 uint8_t idx_minus = (idx + 1) % 3;
80
82 EigColVecN<Float, 2> u_hat = { edge.unit_vec()[1], -edge.unit_vec()[0] };
83
84 // Projection of the projected observation point to the line defined by the edge
87 EigRowVec<Float> s_plus = edge.unit_vec().transpose() * plus_to_rho;
88 EigRowVec<Float> s_minus = s_plus.array() - edge.length();
89 EigRowVec<Float> t0 = -(u_hat.transpose() * plus_to_rho);
90 EigRowVec<Float> R0 = Eigen::sqrt(Eigen::pow(t0.array(), 2) + z_sq.array());
91
92 // Distance from the observation points to each end point of the edge
93 EigRowVec<Float> R_plus = Eigen::sqrt(plus_to_rho.colwise().squaredNorm().array() + z_sq.array());
94 EigRowVec<Float> R_minus = Eigen::sqrt(minus_to_rho.colwise().squaredNorm().array() + z_sq.array());
95
96 // Compute the terms which compose the final integrals
97 EigRowVec<Float> R0_sq = Eigen::pow(R0.array(), 2);
98 EigRowVec<Float> atan_plus (t0.size()), atan_minus (t0.size());
99 for (std::size_t ii = 0; ii < t0.size(); ++ii)
100 {
101 atan_plus[ii] = std::atan2(
102 t0[ii] * s_plus[ii],
103 R0_sq[ii] + z_abs_[ii] * R_plus[ii]
104 );
105 atan_minus[ii] = std::atan2(
106 t0[ii] * s_minus[ii],
107 R0_sq[ii] + z_abs_[ii] * R_minus[ii]
108 );
109 }
110
111 EigRowVec<Float> f2 = Eigen::log(((R_plus + s_plus).array() / (R_minus + s_minus).array()));
112
113 // f2 = (t0.array().abs() < tol &&
114 // ((R_plus + s_plus).array() < tol || (R_minus + s_minus).array() < tol)).select(
115 // EigRowVec<Float>::Zero(1, f2.cols()),
116 // f2
117 // );
118 f2 = (!f2.array().isFinite()).select(EigRowVec<Float>::Zero(1, f2.cols()), f2);
119
121 s_plus.array() * R_plus.array() -
122 s_minus.array() * R_minus.array() +
123 R0_sq.array() * f2.array();
124
125 beta_ += atan_plus - atan_minus;
126 t0_f2_ += (t0.array() * f2.array()).matrix();
127 u_f2_ += u_hat * f2;
128 u_f3_ += u_hat * f3;
129
130 assert(atan_plus.array().isFinite().all() &&
131 "SrcSingularity::compute_integral_terms(): atan_plus has nan or inf.");
132 assert(atan_minus.array().isFinite().all() &&
133 "SrcSingularity::compute_integral_terms(): atan_minus has nan or inf.");
134 assert(f2.array().isFinite().all() &&
135 "SrcSingularity::compute_integral_terms(): f2 has nan or inf.");
136 assert(f3.array().isFinite().all() &&
137 "SrcSingularity::compute_integral_terms(): f3 has nan or inf.");
138
139 // std::cout << R_plus << ", " << R_minus << ", " << s_plus << ", " << s_minus << ", " << t0 << ", " << R0 << ", " << atan_plus << ", " << atan_minus << ", " << it.beta << ", " << it.f2 << ", " << it.t0_f2 << ", " << it.f3 << ", " << it.f1 << std::endl;
140
141 }
142
143 // _it.beta = (_it.beta.array().isFinite()).select(_it.beta, 0.0);
144
145 // for (int ii = 0; ii < r_obs.cols(); ++ii)
146 // {
147 // EigColVecN<Float, 3> r_obs_col = r_obs.col(ii);
148 // if (src_tri.point_in_triangle(r_obs_col))
149 // std::cout << _it.u_f2.col(ii) << std::endl;
150 // }
151
152 return;
153
154};
155
156
157template <typename TriangleQuadratureType, typename ScalarKernelType>
158SrcResult SrcSingularity<TriangleQuadratureType, ScalarKernelType>::assemble_integrals(
159 const Complex k,
160 const Triangle<2>& src_tri,
162 )
163{
164
165 const Float four_pi = 4.0 * pi;
166
167 SrcResult result;
168
169 if (base::compute_g_terms_)
170 {
171 result.g = (t0_f2_ - z_abs_.cwiseProduct(beta_)) / four_pi;
172
173 result.rs_g = 0.5 * u_f3_ / four_pi;
174 result.rs_g += r_obs.topRows(2) * result.g.asDiagonal();
175 }
176
177 if (base::compute_grad_g_terms_)
178 {
179 EigRowVec<Float> sign = z_.array() / z_abs_.array();
180 sign = (
181 z_abs_.array() < TRIANGLE_DEFAULT_TOL * src_tri.shortest_edge_length()
182 ).select(1, sign);
183
184 result.grad_g = EigMatNX<Complex, 3>::Zero(3, r_obs.cols());
185 result.grad_g.topRows(2) = -u_f2_;
186 result.grad_g.row(2) = -sign.array() * beta_.array();
187
188 EigMatNX<Float, 3> grad_r = EigMatNX<Float, 3>::Zero(3, r_obs.cols());
189 grad_r.topRows(2) = 0.5 * u_f3_;
190 grad_r.row(2) = z_.array() * z_abs_.array() * beta_.array() - z_.array() * t0_f2_.array();
191
192 result.grad_g += (half * k * k) * grad_r;
193 result.grad_g /= four_pi;
194 }
195
196 return result;
197
198};
199
200}
201
202#endif
Class for 2D quadrature over the source triangle with singularity treatment for RWG-based BEM operato...
SrcResult integrate(const Complex k, const Triangle< 2 > &src_tri, ConstEigRef< EigMatNX< Float, 3 > > r_obs) override
Computes the integral over the source triangle.
const Eigen::Ref< const EigObj > ConstEigRef
Read-only reference to an Eigen object.
Definition types.hpp:98
Eigen::Matrix< T, 1, Eigen::Dynamic > EigRowVec
Dynamic-size row vector containing type T.
Definition types.hpp:90
double Float
Floating point number.
Definition types.hpp:47
std::complex< Float > Complex
Complex floating point number.
Definition types.hpp:51
Eigen::Matrix< T, N, 1 > EigColVecN
Fixed-size column vector of size N containing type T.
Definition types.hpp:86
Eigen::Matrix< T, N, Eigen::Dynamic > EigMatNX
Fixed-height matrix with N rows containing type T.
Definition types.hpp:78
Namespace for RWG-based BEM functionality.
Data structure to hold the results of integration over the source triangle.
Definition base.hpp:37