Bembel
AugmentedEFIEAssembler.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 #ifndef BEMBEL_SRC_AUGMENTEDEFIE_AUGMENTEDEFIEASSEMBLER_HPP_
12 #define BEMBEL_SRC_AUGMENTEDEFIE_AUGMENTEDEFIEASSEMBLER_HPP_
13 
14 namespace Bembel {
15 template <typename MatrixFormat>
21 template <>
22 struct AugmentedEFIEAssembler<Eigen::MatrixXcd> {
23  public:
29  static std::unique_ptr<Eigen::MatrixXcd> compute(
30  Eigen::MatrixXcd *system_matrix,
31  const AnsatzSpace<MassMatrixScalarDisc> &ansatz_space_mass,
32  const AnsatzSpace<HelmholtzSingleLayerOperator> &ansatz_space_scalar,
33  const AnsatzSpace<InductanceMatrix> &ansatz_space_vector,
34  const std::complex<double> wavenumber) {
35  const int dofs_scalar = ansatz_space_scalar.get_number_of_dofs();
36  const int dofs_vector = ansatz_space_vector.get_number_of_dofs();
37 
38  assembleZ(system_matrix, ansatz_space_vector, wavenumber);
39 
41  incidence_matrix(ansatz_space_vector, ansatz_space_scalar);
42  incidence_matrix.compute();
43 
44  assembleS(system_matrix, incidence_matrix, dofs_vector, dofs_scalar);
45 
46  DiscreteLocalOperator<MassMatrixScalarDisc> mass_matrix(ansatz_space_mass);
47  mass_matrix.compute();
48 
49  assembleM(system_matrix, mass_matrix, wavenumber, dofs_vector, dofs_scalar);
50 
52  capacitive_operator(ansatz_space_scalar);
53  capacitive_operator.get_linear_operator().set_wavenumber(wavenumber);
54  capacitive_operator.compute();
55 
56  std::unique_ptr<Eigen::MatrixXcd> P_times_mass_inverse(
57  new Eigen::MatrixXcd);
58  *P_times_mass_inverse =
59  capacitive_operator.get_discrete_operator() / Constants::eps0 *
60  Eigen::MatrixXcd(mass_matrix.get_discrete_operator()).inverse();
61 
62  assembleP(system_matrix, ansatz_space_scalar, P_times_mass_inverse,
63  incidence_matrix, wavenumber, dofs_vector, dofs_scalar);
64 
65  return P_times_mass_inverse;
66  }
75  Eigen::MatrixXcd *system_matrix, Eigen::VectorXcd *excitation,
76  const AnsatzSpace<MassMatrixScalarDisc> &ansatz_space_mass,
77  const AnsatzSpace<HelmholtzSingleLayerOperator> &ansatz_space_scalar,
78  const AnsatzSpace<InductanceMatrix> &ansatz_space_vector,
79  const std::complex<double> wavenumber, const VoltageSource &source) {
80  assert(ansatz_space_scalar.get_polynomial_degree() == 0 &&
81  "This works only for lowest order!");
82  const int refinement_level = ansatz_space_scalar.get_refinement_level();
83  const int dofs_scalar = ansatz_space_scalar.get_number_of_dofs();
84  const int dofs_vector = ansatz_space_vector.get_number_of_dofs();
85 
86  std::unique_ptr<Eigen::MatrixXcd> P_times_mass_inverse =
87  compute(system_matrix, ansatz_space_mass, ansatz_space_scalar,
88  ansatz_space_vector, wavenumber);
89 
90  assembleV(system_matrix, excitation, ansatz_space_scalar,
91  P_times_mass_inverse, source, dofs_vector,
92  ansatz_space_scalar.get_number_of_dofs());
93  assembleA(system_matrix, source, refinement_level, dofs_vector,
94  dofs_scalar);
95  return;
96  }
97 
98  private:
104  static void assembleZ(
105  Eigen::MatrixXcd *system_matrix,
106  const AnsatzSpace<InductanceMatrix> &ansatz_space_vector,
107  const std::complex<double> wavenumber) {
109  ansatz_space_vector);
110  disc_op.get_linear_operator().set_wavenumber(wavenumber);
111  disc_op.compute();
112 
113  const int dofs_vector = ansatz_space_vector.get_number_of_dofs();
114  std::complex<double> omega =
115  wavenumber / std::sqrt(Constants::mu0 * Constants::eps0);
116  system_matrix->block(0, 0, dofs_vector, dofs_vector) =
117  Constants::mu0 * omega * std::complex<double>(0., 1.) *
118  disc_op.get_discrete_operator();
119  return;
120  }
125  static void assembleS(
126  Eigen::MatrixXcd *system_matrix,
127  IncidenceMatrix<InductanceMatrix, HelmholtzSingleLayerOperator>
128  incidence_matrix,
129  const int dofs_vector, const int dofs_scalar) {
130  system_matrix->block(0, dofs_vector, dofs_vector, dofs_scalar) =
131  incidence_matrix.get_incidence_matrix();
132  return;
133  }
138  static void assembleM(Eigen::MatrixXcd *system_matrix,
139  DiscreteLocalOperator<MassMatrixScalarDisc> mass_matrix,
140  const std::complex<double> wavenumber,
141  const int dofs_vector, const int dofs_scalar) {
142  std::complex<double> omega =
143  wavenumber / std::sqrt(Constants::mu0 * Constants::eps0);
144  system_matrix->block(dofs_vector, dofs_vector, dofs_scalar, dofs_scalar) =
145  -omega * std::complex<double>(0., 1.) *
146  mass_matrix.get_discrete_operator();
147  return;
148  }
153  static void assembleP(
154  Eigen::MatrixXcd *system_matrix,
155  const AnsatzSpace<HelmholtzSingleLayerOperator> &ansatz_space_scalar,
156  const std::unique_ptr<Eigen::MatrixXcd> &P_times_mass_inverse,
157  const IncidenceMatrix<InductanceMatrix, HelmholtzSingleLayerOperator>
158  &incident_matrix,
159  const std::complex<double> wavenumber, const int dofs_vector,
160  const int dofs_scalar) {
161  system_matrix->block(dofs_vector, 0, dofs_scalar, dofs_vector) =
162  *P_times_mass_inverse *
163  incident_matrix.get_incidence_matrix().transpose();
164  return;
165  }
169  static void assembleV(
170  Eigen::MatrixXcd *system_matrix, Eigen::VectorXcd *excitation,
171  const AnsatzSpace<HelmholtzSingleLayerOperator> &ansatz_space_scalar,
172  const std::unique_ptr<Eigen::MatrixXcd> &P_times_mass_inverse,
173  VoltageSource source, const int dofs_vector, const int dofs_scalar) {
174  Eigen::MatrixXcd V = get_voltage_incidence_matrix(
175  excitation, source, ansatz_space_scalar.get_number_of_dofs(),
176  ansatz_space_scalar.get_polynomial_degree(),
177  ansatz_space_scalar.get_refinement_level());
178 
179  system_matrix->block(dofs_vector, dofs_vector + dofs_scalar, dofs_scalar,
180  V.rows()) = *P_times_mass_inverse * V.transpose();
181  system_matrix->block(dofs_vector + dofs_scalar, dofs_vector, V.rows(),
182  dofs_scalar) = V;
183  return;
184  }
194  static void assembleA(Eigen::MatrixXcd *system_matrix,
195  const VoltageSource &source, const int refinement_level,
196  const int dofs_vector, const int dofs_scalar) {
197  const int dofs_excitation_positive =
198  source.positive_.size() * (1 << refinement_level);
199  const int dofs_excitation_negative =
200  source.negative_.size() * (1 << refinement_level);
201  const int dofs_excitation =
202  dofs_excitation_positive + dofs_excitation_negative + 1;
203  Eigen::MatrixXcd A = Eigen::MatrixXcd::Ones(dofs_excitation, 2);
204  A.block(1, 1, dofs_excitation_negative, 1) =
205  Eigen::VectorXcd::Zero(dofs_excitation_negative);
206  A.block(1 + dofs_excitation_negative, 0, dofs_excitation_positive, 1) =
207  Eigen::VectorXcd::Zero(dofs_excitation_positive);
208  A(0, 0) = 1;
209  A(0, 1) = -1;
210 
211  const int dofs_basis = dofs_vector + dofs_scalar;
212  system_matrix->block(dofs_basis, dofs_basis + dofs_excitation,
213  dofs_excitation, 2) = A;
214  system_matrix->block(dofs_basis + dofs_excitation, dofs_basis, 2,
215  dofs_excitation) = A.transpose();
216  return;
217  }
218  static Eigen::MatrixXcd get_voltage_incidence_matrix(
219  Eigen::VectorXcd *excitation, VoltageSource source, const int dofs_scalar,
220  const int polynomial_degree, const int refinement_level) {
221  const int elements_per_edge = (1 << refinement_level);
222  const int num_elements_per_patch = elements_per_edge * elements_per_edge;
223  const int dofs_excitation_V =
224  (source.positive_.size() + source.negative_.size()) *
225  elements_per_edge +
226  1;
227  const int number_of_basisfunctions = polynomial_degree + elements_per_edge;
228 
229  Eigen::MatrixXcd ret =
230  Eigen::MatrixXcd::Zero(dofs_excitation_V, dofs_scalar);
231 
232  const int number_of_patches_negative = source.negative_.size();
233  int row_count = 1;
234  for (auto i = 0; i < number_of_patches_negative; ++i) {
235  std::vector<int> edge_dofs = GlueRoutines::getEdgeDofIndices(
236  source.negative_[i][1], number_of_basisfunctions,
237  number_of_basisfunctions,
238  source.negative_[i][0] * num_elements_per_patch);
239  for (auto dof : edge_dofs) {
240  ret(row_count, dof) = -1;
241  excitation[0](dof) = -1;
242  ++row_count;
243  }
244  }
245 
246  const int number_of_patches_positive = source.positive_.size();
247  for (auto i = 0; i < number_of_patches_positive; ++i) {
248  std::vector<int> edge_dofs = GlueRoutines::getEdgeDofIndices(
249  source.positive_[i][1], number_of_basisfunctions,
250  number_of_basisfunctions,
251  source.positive_[i][0] * num_elements_per_patch);
252  for (auto dof : edge_dofs) {
253  ret(row_count, dof) = -1;
254  excitation[0](dof) = 1;
255  ++row_count;
256  }
257  }
258  return ret;
259  }
260 };
261 } // namespace Bembel
262 #endif // BEMBEL_SRC_AUGMENTEDEFIE_AUGMENTEDEFIEASSEMBLER_HPP_
The AnsatzSpace is the class that handles the assembly of the discrete basis.
Definition: AnsatzSpace.hpp:25
int get_polynomial_degree() const
Retrieves the polynomial degree of this AnsatzSpace.
int get_refinement_level() const
Retrieves the refinement level of this AnsatzSpace.
int get_number_of_dofs() const
Retrieves the number of degrees of freedom of this AnsatzSpace.
Routines for the evalutation of pointwise errors.
Definition: AnsatzSpace.hpp:14
static void compute_matrix_and_excitation(Eigen::MatrixXcd *system_matrix, Eigen::VectorXcd *excitation, const AnsatzSpace< MassMatrixScalarDisc > &ansatz_space_mass, const AnsatzSpace< HelmholtzSingleLayerOperator > &ansatz_space_scalar, const AnsatzSpace< InductanceMatrix > &ansatz_space_vector, const std::complex< double > wavenumber, const VoltageSource &source)
static std::unique_ptr< Eigen::MatrixXcd > compute(Eigen::MatrixXcd *system_matrix, const AnsatzSpace< MassMatrixScalarDisc > &ansatz_space_mass, const AnsatzSpace< HelmholtzSingleLayerOperator > &ansatz_space_scalar, const AnsatzSpace< InductanceMatrix > &ansatz_space_vector, const std::complex< double > wavenumber)