OpenBEM
Open-source framework for electromagnetic simulation with the boundary element method.
Loading...
Searching...
No Matches
base.hpp
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_LUMPED_ELEM_BASE_H
19#define BEM_RWG_LUMPED_ELEM_BASE_H
20
21#include <vector>
22#include <array>
23#include <stdexcept>
24#include <algorithm>
25
26#include "types.hpp"
32
33#include "matrix/base.hpp"
35
36
37namespace bem::rwg
38{
39
49template <typename MatrixType = EigenDenseMatrix<Complex>>
51{
52public:
53
64 const std::vector<MeshView<TriangleMesh<3>>>& terminals,
65 const std::vector<std::vector<Index>>& terminal_components,
66 const std::vector<std::array<Index, 2>>& ports,
67 const std::vector<Complex>& impedances
68 ):
69 structure_(structure),
70 terminals_(terminals),
71 terminal_components_(terminal_components),
72 ports_(ports),
73 impedances_(impedances)
74 {
76 return;
77 };
78
79
90 const std::vector<EigMatNX<Float, 3>>& terminal_polygons,
91 const std::vector<std::array<Index, 2>>& ports,
92 const std::vector<Complex>& impedances,
93 const bool single_element = false
94 ):
95 structure_(structure),
96 terminal_polygons_(terminal_polygons),
97 ports_(ports),
98 impedances_(impedances)
99 {
101 set_terminals_from_polygons(terminal_polygons_, single_element);
102 return;
103 };
104
105
111 { return ports().size(); };
112
113
119 {
120 Index num_elems = 0;
121 for (Index ii = 0; ii < num_ports(); ++ii)
122 for (Index term: ports()[ii])
123 num_elems += terminals()[term].elem_inds().size();
124 return num_elems;
125 }
126
127
133 {
134 Index num_elems = 0;
135 for (Index term: ports()[idx])
136 num_elems += terminals()[term].elem_inds().size();
137 return num_elems;
138 }
139
140
146 {
148 Index col = 0;
149 for (Index ii = 0; ii < num_ports(); ++ii)
150 {
151 for (Index term: ports()[ii])
152 {
153 elem_inds.middleCols(col, terminals()[term].elem_inds().size()) = terminals()[term].elem_inds();
154 col += terminals()[term].elem_inds().size();
155 }
156 }
157 return MeshView(structure_.mesh(), elem_inds, "port_mesh");
158 }
159
160
166 {
168 Index col = 0;
169 for (Index term: ports()[idx])
170 {
171 elem_inds.middleCols(col, terminals()[term].elem_inds().size()) = terminals()[term].elem_inds();
172 col += terminals()[term].elem_inds().size();
173 }
174 return MeshView(structure_.mesh(), elem_inds, "port_mesh");
175 }
176
177
183 virtual MatrixType coupling_matrix(const Float f) const = 0;
184
185
191 virtual MatrixType voltage_matrix(const Float f) const = 0;
192
193
199 virtual MatrixType current_matrix(const Float f) const = 0;
200
201
207 virtual MatrixType exc_matrix(const Float f) const
208 {
209 MatrixType mat (num_ports(), num_ports());
210 mat.set_identity();
211 return mat;
212 };
213
214
219 virtual MatrixType current_mapping_matrix() const
220 {
221 MatrixType mat (num_port_elems(), num_ports());
222
223 Index row = 0;
224 for (Index ii = 0; ii < num_ports(); ++ii)
225 {
226 Float sign = one;
227 for (Index term: ports()[ii])
228 {
230
231 for (Index jj = 0; jj < terminals()[term].elem_inds().size(); ++jj)
232 {
233 Index elem = terminals()[term].elem_inds()[jj];
234 mat.set_value(row++, ii, sign * structure_.mesh().elem_primitive(elem).area() / term_area);
235 }
236
237 sign *= -one;
238 }
239 }
240
241 mat.assemble();
242
243 return mat;
244 };
245
246
251 virtual MatrixType voltage_mapping_matrix() const
252 {
253 MatrixType mat (num_ports(), num_port_elems());
254
255 Index col = 0;
256 for (Index ii = 0; ii < num_ports(); ++ii)
257 {
258 Float sign = one;
259 for (Index term: ports()[ii])
260 {
262
263 for (Index jj = 0; jj < terminals()[term].elem_inds().size(); ++jj)
264 {
265 Index elem = terminals()[term].elem_inds()[jj];
266 mat.set_value(ii, col++, sign * structure_.mesh().elem_primitive(elem).area() / term_area);
267 }
268
269 sign *= -one;
270 }
271 }
272
273 return mat;
274 };
275
276
281 virtual MatrixType terminal_mapping_matrix() const
282 {
284
285 MatrixType mat (structure_.mesh().num_elems(), view.elem_inds().size());
286
287 for (Index ii = 0; ii < view.elem_inds().size(); ++ii)
288 mat.set_value(view.elem_inds()[ii], ii, one);
289 mat.assemble();
290
291 return mat;
292 };
293
294
301 {
302 Float area = 0;
303 for (const Index elem: terminal.elem_inds())
304 area += structure_.mesh().elem_primitive(elem).area();
305 return area;
306 };
307
308
312 const std::vector<MeshView<TriangleMesh<3>>>& terminals() const { return terminals_; };
313
314
318 const std::vector<std::array<Index, 2>>& ports() const { return ports_; };
319
320
324 const std::vector<Complex>& impedances() const { return impedances_; };
325
326
330 const std::vector<std::vector<Index>>& terminal_components() const { return terminal_components_; };
331
332
333protected:
334
339 {
340 if (ports_.size() != impedances_.size() && impedances_.size() != 1)
341 throw std::invalid_argument("LumpedElementBase(): Number of `impedances` must equal number of `ports`, or be a single value.");
342 if (impedances_.size() == 1 && ports_.size() > 1)
343 {
344 Complex imp = impedances_[0];
345 impedances_.resize(ports_.size(), imp);
346 }
347 return;
348 };
349
350
360 {
361 terminals_.clear();
362 terminal_components_.resize(terminal_polygons.size());
363
364 // Find all mesh triangles whose centroid lies within the terminal polygon
365 for (Index ii = 0; ii < terminal_polygons.size(); ++ii)
366 {
367 std::vector<Index> term_elems;
368
369 for (Index jj = 0; jj < structure_.components().size(); ++jj)
370 {
371 // TODO: for efficiency, first check if the polygon is in the component's bounding box
372
373 for (Index kk = 0; kk < structure_.components()[jj].mesh_view().elem_inds().size(); ++kk)
374 {
375 Triangle<3> tri = structure_.mesh().elem_primitive(structure_.components()[jj].mesh_view().elem_inds()[kk]);
377
379 continue;
380
382 continue;
383
384 term_elems.push_back(structure_.components()[jj].mesh_view().elem_inds()[kk]);
385 terminal_components_[ii].push_back(jj);
386 }
387 }
388
389 if (term_elems.size() == 0)
390 throw std::runtime_error(
391 "LumpedElementBase::set_terminals_from_polygons(): No mesh triangles found for terminal " + std::to_string(ii)
392 );
393
394 // Keep only the mesh triangle closest to the terminal polygon centroid
395 if (single_element)
396 {
397 Float offset = 1e30;
400 for (Index jj = 0; jj < term_elems.size(); ++jj)
401 {
402 Float dist = (structure_.mesh().elem_primitive(term_elems[jj]).centroid() - term_centroid).norm();
403 if (dist < offset)
404 {
405 offset = dist;
406 term_elem = jj;
407 }
408 }
410 terminal_components_[ii] = { terminal_components_[ii][term_elem] };
411 }
412
413 std::sort(terminal_components_[ii].begin(), terminal_components_[ii].end());
414 auto iter = std::unique(terminal_components_[ii].begin(), terminal_components_[ii].end());
415 terminal_components_[ii].erase(iter, terminal_components_[ii].end());
416
417 EigRowVec<Index> elem_inds = Eigen::Map<EigRowVec<Index>, Eigen::Unaligned> (term_elems.data(), term_elems.size());
418 MeshView<TriangleMesh<3>> view (structure_.mesh(), elem_inds, "terminal_" + std::to_string(ii));
419 terminals_.push_back(view);
420 }
421
422 return;
423 };
424
425
426 const Structure<TriangleMesh<3>>& structure_;
427 const std::vector<EigMatNX<Float, 3>> terminal_polygons_;
428 const std::vector<std::array<Index, 2>> ports_;
429 std::vector<MeshView<TriangleMesh<3>>> terminals_;
430 std::vector<std::vector<Index>> terminal_components_;
431 std::vector<Complex> impedances_;
432
433};
434
439}
440
441#endif
Geometry operations class.
Class that provides a lightweight view into a MeshBase object.
Definition base.hpp:185
Class that defines a structure.
Definition structure.hpp:45
Base class for generating excitation coefficients and coupling matrices for lumped ports.
Definition base.hpp:51
virtual MatrixType voltage_mapping_matrix() const
Returns the matrix that maps the scalar potential on terminal triangles to the average voltage on the...
Definition base.hpp:251
virtual MatrixType exc_matrix(const Float f) const
Returns the right-hand side excitation matrix to set a voltage source at each lumped element.
Definition base.hpp:207
void set_terminals_from_polygons(const std::vector< EigMatNX< Float, 3 > > &terminal_polygons, const bool single_element=false)
Populates terminals_ by finding mesh elements inside each terminal polygon.
Definition base.hpp:359
void check_impedances()
Ensures correct number of impedances are set.
Definition base.hpp:338
virtual MatrixType current_mapping_matrix() const
Returns the matrix that maps the total port currents to the volume current densities on terminal tria...
Definition base.hpp:219
Index num_ports() const
Returns the number of excitations (right-hand sides), which equals the number of ports.
Definition base.hpp:110
virtual MatrixType current_matrix(const Float f) const =0
Returns the matrix associated with terminal currents.
LumpedElementBase(const Structure< TriangleMesh< 3 > > &structure, const std::vector< MeshView< TriangleMesh< 3 > > > &terminals, const std::vector< std::vector< Index > > &terminal_components, const std::vector< std::array< Index, 2 > > &ports, const std::vector< Complex > &impedances)
Constructs a LumpedElementBase object.
Definition base.hpp:62
virtual MatrixType voltage_matrix(const Float f) const =0
Returns the matrix associated with the potential differences between terminals.
const std::vector< MeshView< TriangleMesh< 3 > > > & terminals() const
Returns a read-only reference to the terminal mesh views.
Definition base.hpp:312
LumpedElementBase(const Structure< TriangleMesh< 3 > > &structure, const std::vector< EigMatNX< Float, 3 > > &terminal_polygons, const std::vector< std::array< Index, 2 > > &ports, const std::vector< Complex > &impedances, const bool single_element=false)
Constructs a LumpedElementBase object.
Definition base.hpp:88
const std::vector< std::array< Index, 2 > > & ports() const
Returns a read-only reference to the port map.
Definition base.hpp:318
virtual MatrixType terminal_mapping_matrix() const
Returns the matrix that maps terminal triangles to their parent mesh triangles.
Definition base.hpp:281
Index num_port_elems(Index idx) const
Returns the number of mesh elements associated with a given port.
Definition base.hpp:132
MeshView< TriangleMesh< 3 > > port_mesh_view() const
Returns a mesh view consisting of all elements associated with the ports.
Definition base.hpp:145
Index num_port_elems() const
Returns the number of mesh elements associated with ports.
Definition base.hpp:118
Float terminal_area(const MeshView< TriangleMesh< 3 > > &terminal) const
Returns the total area spanned by the mesh triangles associated with a given terminal.
Definition base.hpp:300
const std::vector< std::vector< Index > > & terminal_components() const
Returns a read-only reference to the components associated with each terminal.
Definition base.hpp:330
MeshView< TriangleMesh< 3 > > port_mesh_view(Index idx) const
Returns a mesh view consisting of all elements associated with a given port.
Definition base.hpp:165
virtual MatrixType coupling_matrix(const Float f) const =0
Returns the matrix the couples the port current to the integral equation.
const std::vector< Complex > & impedances() const
Returns a read-only reference to the lumped impedances.
Definition base.hpp:324
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
std::size_t Index
Unsigned integer type for indices and container sizes.
Definition types.hpp:54
Namespace for RWG-based BEM functionality.