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 // Projection of the observation point on the source triangle's local plane
61 EigMatNX<Float, 2> rho_obs = r_obs.topRows(2);
62 z_ = r_obs.row(2);
63 z_abs_ = z_.cwiseAbs();
64 EigRowVec<Float> z_sq = z_.array() * z_.array();
65
66 beta_ = EigRowVec<Float>::Zero(1, r_obs.cols());
67 t0_f2_ = EigRowVec<Float>::Zero(1, r_obs.cols());
68 u_f2_ = EigMatNX<Float, 2>::Zero(2, r_obs.cols());
69 u_f3_ = EigMatNX<Float, 2>::Zero(2, r_obs.cols());
70
71 for (uint8_t idx = 0; idx < 3; idx++)
72 {
73
74 // Indices of the edge's vertices
76 uint8_t idx_minus = (idx + 1) % 3;
77
79 EigColVecN<Float, 2> u_hat = { edge.unit_vec()[1], -edge.unit_vec()[0] };
80
81 // Projection of the projected observation point to the line defined by the edge
82 EigMatNX<Float, 2> plus_to_rho = rho_obs.colwise() - edge.v(0);
84 EigRowVec<Float> s_plus = edge.unit_vec().transpose() * plus_to_rho;
85 EigRowVec<Float> s_minus = s_plus.array() - edge.length();
86 EigRowVec<Float> t0 = -(u_hat.transpose() * plus_to_rho);
87 EigRowVec<Float> R0 = Eigen::sqrt((t0.array() * t0.array()) + z_sq.array());
88
89 // Distance from the observation points to each end point of the edge
90 EigRowVec<Float> R_plus = Eigen::sqrt(plus_to_rho.colwise().squaredNorm().array() + z_sq.array());
91 EigRowVec<Float> R_minus = Eigen::sqrt(minus_to_rho.colwise().squaredNorm().array() + z_sq.array());
92
93 // Compute the terms which compose the final integrals
94 EigRowVec<Float> R0_sq = R0.array() * R0.array();
95 EigRowVec<Float> atan_plus (t0.size()), atan_minus (t0.size());
96 for (std::size_t ii = 0; ii < t0.size(); ++ii)
97 {
98 atan_plus[ii] = std::atan2(
99 t0[ii] * s_plus[ii],
100 R0_sq[ii] + z_abs_[ii] * R_plus[ii]
101 );
102 atan_minus[ii] = std::atan2(
103 t0[ii] * s_minus[ii],
104 R0_sq[ii] + z_abs_[ii] * R_minus[ii]
105 );
106 }
107
108 EigRowVec<Float> f2 = Eigen::log(((R_plus + s_plus).array() / (R_minus + s_minus).array()));
109
110 // f2 = (t0.array().abs() < tol &&
111 // ((R_plus + s_plus).array() < tol || (R_minus + s_minus).array() < tol)).select(
112 // EigRowVec<Float>::Zero(1, f2.cols()),
113 // f2
114 // );
115 f2 = (!f2.array().isFinite()).select(EigRowVec<Float>::Zero(1, f2.cols()), f2);
116
118 s_plus.array() * R_plus.array() -
119 s_minus.array() * R_minus.array() +
120 R0_sq.array() * f2.array();
121
122 beta_ += atan_plus - atan_minus;
123 t0_f2_ += (t0.array() * f2.array()).matrix();
124 u_f2_ += u_hat * f2;
125 u_f3_ += u_hat * f3;
126
127 assert(atan_plus.array().isFinite().all() &&
128 "SrcSingularity::compute_integral_terms(): atan_plus has nan or inf.");
129 assert(atan_minus.array().isFinite().all() &&
130 "SrcSingularity::compute_integral_terms(): atan_minus has nan or inf.");
131 assert(f2.array().isFinite().all() &&
132 "SrcSingularity::compute_integral_terms(): f2 has nan or inf.");
133 assert(f3.array().isFinite().all() &&
134 "SrcSingularity::compute_integral_terms(): f3 has nan or inf.");
135
136 // 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;
137
138 }
139
140 // _it.beta = (_it.beta.array().isFinite()).select(_it.beta, 0.0);
141
142 // for (int ii = 0; ii < r_obs.cols(); ++ii)
143 // {
144 // EigColVecN<Float, 3> r_obs_col = r_obs.col(ii);
145 // if (src_tri.point_in_triangle(r_obs_col))
146 // std::cout << _it.u_f2.col(ii) << std::endl;
147 // }
148
149 return;
150
151};
152
153
154template <typename TriangleQuadratureType, typename ScalarKernelType>
155SrcResult SrcSingularity<TriangleQuadratureType, ScalarKernelType>::assemble_integrals(
156 const Complex k,
157 const Triangle<2>& src_tri,
159 )
160{
161
162 const Float four_pi = 4.0 * pi;
163
164 SrcResult result;
165
166 if (base::compute_g_terms_)
167 {
168 result.g = (t0_f2_ - z_abs_.cwiseProduct(beta_)) / four_pi;
169
170 result.rs_g = 0.5 * u_f3_ / four_pi;
171 result.rs_g += r_obs.topRows(2) * result.g.asDiagonal();
172 }
173
174 if (base::compute_grad_g_terms_)
175 {
176 EigRowVec<Float> sign = z_.array() / z_abs_.array();
177 sign = (
178 z_abs_.array() < TRIANGLE_DEFAULT_TOL * src_tri.shortest_edge_length()
179 ).select(1, sign);
180
181 result.grad_g = EigMatNX<Complex, 3>::Zero(3, r_obs.cols());
182 result.grad_g.topRows(2) = -u_f2_;
183 result.grad_g.row(2) = -sign.array() * beta_.array();
184
185 EigMatNX<Float, 3> grad_r = EigMatNX<Float, 3>::Zero(3, r_obs.cols());
186 grad_r.topRows(2) = 0.5 * u_f3_;
187 grad_r.row(2) = z_.array() * z_abs_.array() * beta_.array() - z_.array() * t0_f2_.array();
188
189 result.grad_g += (half * k * k) * grad_r;
190 result.grad_g /= four_pi;
191 }
192
193 return result;
194
195};
196
197}
198
199#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