11 #ifndef BEMBEL_SRC_AUGMENTEDEFIE_AUGMENTEDEFIEASSEMBLER_HPP_
12 #define BEMBEL_SRC_AUGMENTEDEFIE_AUGMENTEDEFIEASSEMBLER_HPP_
15 template <
typename MatrixFormat>
29 static std::unique_ptr<Eigen::MatrixXcd>
compute(
30 Eigen::MatrixXcd *system_matrix,
34 const std::complex<double> wavenumber) {
38 assembleZ(system_matrix, ansatz_space_vector, wavenumber);
41 incidence_matrix(ansatz_space_vector, ansatz_space_scalar);
42 incidence_matrix.compute();
44 assembleS(system_matrix, incidence_matrix, dofs_vector, dofs_scalar);
47 mass_matrix.compute();
49 assembleM(system_matrix, mass_matrix, wavenumber, dofs_vector, dofs_scalar);
52 capacitive_operator(ansatz_space_scalar);
53 capacitive_operator.get_linear_operator().set_wavenumber(wavenumber);
54 capacitive_operator.compute();
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();
62 assembleP(system_matrix, ansatz_space_scalar, P_times_mass_inverse,
63 incidence_matrix, wavenumber, dofs_vector, dofs_scalar);
65 return P_times_mass_inverse;
75 Eigen::MatrixXcd *system_matrix, Eigen::VectorXcd *excitation,
79 const std::complex<double> wavenumber,
const VoltageSource &source) {
81 "This works only for lowest order!");
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);
90 assembleV(system_matrix, excitation, ansatz_space_scalar,
91 P_times_mass_inverse, source, dofs_vector,
93 assembleA(system_matrix, source, refinement_level, dofs_vector,
104 static void assembleZ(
105 Eigen::MatrixXcd *system_matrix,
107 const std::complex<double> wavenumber) {
109 ansatz_space_vector);
110 disc_op.get_linear_operator().set_wavenumber(wavenumber);
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();
125 static void assembleS(
126 Eigen::MatrixXcd *system_matrix,
127 IncidenceMatrix<InductanceMatrix, HelmholtzSingleLayerOperator>
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();
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();
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>
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();
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());
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(),
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);
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();
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()) *
227 const int number_of_basisfunctions = polynomial_degree + elements_per_edge;
229 Eigen::MatrixXcd ret =
230 Eigen::MatrixXcd::Zero(dofs_excitation_V, dofs_scalar);
232 const int number_of_patches_negative = source.negative_.size();
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;
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;
The AnsatzSpace is the class that handles the assembly of the discrete basis.
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.
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)