Bembel
 
Loading...
Searching...
No Matches
Coefficients.hpp
1// This file is part of Bembel, the higher order C++ boundary element library.
2//
3// Copyright (C) 2022 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
12#ifndef BEMBEL_SRC_HOMOGENISEDLAPLACE_COEFFICIENTS_HPP_
13#define BEMBEL_SRC_HOMOGENISEDLAPLACE_COEFFICIENTS_HPP_
14
15#ifndef POINT_DEGREE
16#define POINT_DEGREE 20
17#endif
18
19#include <Eigen/Dense>
20#include <Bembel/HomogenisedLaplace>
21#include <Bembel/Quadrature>
22
23#include <functional>
24
25namespace Bembel {
26
27Eigen::VectorXd getCoefficients(double precision);
28
29inline unsigned int getDegree(double precision);
30
31Eigen::VectorXd getDisplacement(Eigen::MatrixXd ps_l, Eigen::MatrixXd ps_f,
32 Eigen::MatrixXd ps_b);
33
34inline double k_mod(Eigen::Vector3d in);
35
36inline Eigen::Vector3d Dk_mod(Eigen::Vector3d in);
37
38double calculateFirstCoefficient(Eigen::VectorXd cs, unsigned int deg,
39 Eigen::MatrixXd ps_l, Eigen::MatrixXd ps_f, Eigen::MatrixXd ps_b);
40
60Eigen::VectorXd getCoefficients(double precision) {
61 Eigen::VectorXd diff;
62 Eigen::RowVectorXd difft;
63 Eigen::Vector3d v;
66
67 unsigned int deg = getDegree(precision);
68 unsigned int Msquare = (POINT_DEGREE + 1) * (POINT_DEGREE + 1);
69
70 unsigned int m, n, k;
71 double scale, fac, norm;
72
74 Eigen::MatrixXd xs = GS[POINT_DEGREE].xi_;
75 xs -= 0.5 * Eigen::MatrixXd::Ones(xs.rows(), xs.cols());
76
77 Eigen::Vector3d ex(1.0, 0.0, 0.0);
78 Eigen::Vector3d ey(0.0, 1.0, 0.0);
79 Eigen::Vector3d ez(0.0, 0.0, 1.0);
80
81 Eigen::MatrixXd ps_left(3, xs.cols());
82 ps_left.row(0) = -0.5 * Eigen::VectorXd::Ones(xs.cols());
83 ps_left.block(1, 0, 2, xs.cols()) = xs.block(0, 0, 2, xs.cols());
84
85 Eigen::MatrixXd ps_front(3, xs.cols());
86 ps_front.row(0) = xs.row(0);
87 ps_front.row(1) = -0.5 * Eigen::VectorXd::Ones(xs.cols());
88 ps_front.row(2) = xs.row(1);
89
90 Eigen::MatrixXd ps_bottom(3, xs.cols());
91 ps_bottom.block(0, 0, 2, xs.cols()) = xs.block(0, 0, 2, xs.cols());
92 ps_bottom.row(2) = -0.5 * Eigen::VectorXd::Ones(xs.cols());
93
95
96 Eigen::MatrixXd systemMatrix(6 * Msquare, ((deg + 1) * (deg + 2)) / 2 - 1);
97
98 for (k = 0; k < Msquare; k++) {
99 /* left - right difference */
100 v = ps_left.col(k);
101 norm = v.norm();
102
105
109
110 for (n = 1; n <= deg; n++) {
111 scale = pow(norm, n);
112 diff = scale
113 * (spherical_values_pre.block(n * n + n, 0, n + 1, 1)
114 - spherical_values_pst.block(n * n + n, 0, n + 1, 1));
115 difft = Dsolid_values_pre.block(0, n * n + n, 1, n + 1)
116 - Dsolid_values_pst.block(0, n * n + n, 1, n + 1);
117
118 /* adapt the scaling */
119 diff.segment(1, n) *= 2.0;
120 difft.segment(1, n) *= 2.0;
121
122 systemMatrix.block(k, (n * (n + 1)) / 2 - 1, 1, n + 1) = diff.transpose();
123 systemMatrix.block(k + Msquare, (n * (n + 1)) / 2 - 1, 1, n + 1) = difft;
124 }
125
126 /* front - back difference */
127 v = ps_front.col(k);
128 norm = v.norm();
129
132
136
137 for (n = 1; n <= deg; n++) {
138 scale = pow(norm, n);
139 diff = scale
140 * (spherical_values_pre.block(n * n + n, 0, n + 1, 1)
141 - spherical_values_pst.block(n * n + n, 0, n + 1, 1));
142 difft = Dsolid_values_pre.block(1, n * n + n, 1, n + 1)
143 - Dsolid_values_pst.block(1, n * n + n, 1, n + 1);
144
145 /* adapt the scaling */
146 diff.segment(1, n) *= 2.0;
147 difft.segment(1, n) *= 2.0;
148
149 systemMatrix.block(k + 2 * Msquare, (n * (n + 1)) / 2 - 1, 1, n + 1) =
150 diff.transpose();
151 systemMatrix.block(k + 3 * Msquare, (n * (n + 1)) / 2 - 1, 1, n + 1) =
152 difft;
153 }
154
155 /* bottom - top difference */
156 v = ps_bottom.col(k);
157 norm = v.norm();
158
161
165
166 for (n = 1; n <= deg; n++) {
167 scale = pow(norm, n);
168 diff = scale
169 * (spherical_values_pre.block(n * n + n, 0, n + 1, 1)
170 - spherical_values_pst.block(n * n + n, 0, n + 1, 1));
171 difft = Dsolid_values_pre.block(2, n * n + n, 1, n + 1)
172 - Dsolid_values_pst.block(2, n * n + n, 1, n + 1);
173
174 /* adapt the scaling */
175 diff.segment(1, n) *= 2.0;
176 difft.segment(1, n) *= 2.0;
177
178 systemMatrix.block(k + 4 * Msquare, (n * (n + 1)) / 2 - 1, 1, n + 1) =
179 diff.transpose();
180 systemMatrix.block(k + 5 * Msquare, (n * (n + 1)) / 2 - 1, 1, n + 1) =
181 difft;
182 }
183 }
184
185 /* solve the system */
186 Eigen::VectorXd coeffs(((deg + 1) * (deg + 2)) / 2);
187 coeffs.setZero();
188 coeffs.segment(1, ((deg + 1) * (deg + 2)) / 2 - 1) =
189 systemMatrix.colPivHouseholderQr().solve(-displacement);
190
191 /* Copy the stuff into the full Coefficient list */
192 Eigen::VectorXd coeffs_full((deg + 1) * (deg + 1));
193 coeffs_full(0) = 0;
194 for (n = 1; n <= deg; n++) {
195 coeffs_full(n * n + n) = coeffs((n * (n + 1)) / 2);
196 for (m = 1; m <= n; m++) {
197 coeffs_full(n * n + n + m) = coeffs((n * (n + 1)) / 2 + m);
198 coeffs_full(n * n + n - m) = coeffs((n * (n + 1)) / 2 + m);
199 }
200 }
201
202 /* calculate the first coefficient */
205
206 return coeffs_full;
207}
208
221inline unsigned int getDegree(double precision) {
222 if (precision > 1e-4) {
223 return 4;
224 } else if (precision > 1e-6) {
225 return 8;
226 } else {
227 return 12;
228 }
229}
230
238Eigen::VectorXd getDisplacement(Eigen::MatrixXd ps_l, Eigen::MatrixXd ps_f,
239 Eigen::MatrixXd ps_b) {
240
241 std::function<double(Eigen::Vector3d)> u = [](Eigen::Vector3d in) {
242 return k_mod(in);
243 };
244 std::function<Eigen::Vector3d(Eigen::Vector3d)> Du = [](Eigen::Vector3d in) {
245 return Dk_mod(in);
246 };
247
248 unsigned int Msquare = (POINT_DEGREE + 1) * (POINT_DEGREE + 1);
249 unsigned int k;
250
251 Eigen::Vector3d ex(1.0, 0.0, 0.0);
252 Eigen::Vector3d ey(0.0, 1.0, 0.0);
253 Eigen::Vector3d ez(0.0, 0.0, 1.0);
254
255 Eigen::Vector3d tmp;
256 Eigen::VectorXd d(6 * Msquare); /* the return vector */
257
258 /* left - right displacement */
259 for (k = 0; k < Msquare; k++) {
260 tmp = Du(ps_l.col(k)) - Du(ps_l.col(k) + ex);
261 d(k) = u(ps_l.col(k)) - u(ps_l.col(k) + ex);
262 d(k + Msquare) = tmp(0);
263 }
264
265 /* front - back displacement */
266 for (k = 0; k < Msquare; k++) {
267 tmp = Du(ps_f.col(k)) - Du(ps_f.col(k) + ey);
268 d(k + 2 * Msquare) = u(ps_f.col(k)) - u(ps_f.col(k) + ey);
269 d(k + 3 * Msquare) = tmp(1);
270 }
271
272 /* bottom - top displacement */
273 for (k = 0; k < Msquare; k++) {
274 tmp = Du(ps_b.col(k)) - Du(ps_b.col(k) + ez);
275 d(k + 4 * Msquare) = u(ps_b.col(k)) - u(ps_b.col(k) + ez);
276 d(k + 5 * Msquare) = tmp(2);
277 }
278
279 return d;
280}
281
286inline double k_mod(Eigen::Vector3d in) {
287 double r = 0.0;
288 int i, j, k;
289 Eigen::Vector3d m;
290
291 for (i = -1; i <= 1; i++) {
292 for (j = -1; j <= 1; j++) {
293 for (k = -1; k <= 1; k++) {
294 m = Eigen::Vector3d(i, j, k);
295 r += 1.0 / ((in - m).norm());
296 }
297 }
298 }
299
300 r /= (4 * M_PI);
301
302 /* the part to ensure the vanishing mean on the Laplacian */
303 r += (in.dot(in)) / 6.0;
304
305 return r;
306}
307
312inline Eigen::Vector3d Dk_mod(Eigen::Vector3d in) {
313 Eigen::Vector3d r, s;
314 double snorm;
315 r.setZero();
316
317 int i, j, k;
318 for (i = -1; i <= 1; i++) {
319 for (j = -1; j <= 1; j++) {
320 for (k = -1; k <= 1; k++) {
321 s = in - Eigen::Vector3d(i, j, k);
322 snorm = s.norm();
323 r -= s / (snorm * snorm * snorm);
324 }
325 }
326 }
327
328 r /= (4.0 * M_PI);
329
330 /* the part to ensure the vanishing mean on the Laplacian */
331 r += in / 3.0;
332
333 return r;
334}
335
346double calculateFirstCoefficient(Eigen::VectorXd cs, unsigned int deg,
347 Eigen::MatrixXd ps_l, Eigen::MatrixXd ps_f, Eigen::MatrixXd ps_b) {
348 double res = 0.0;
349
351 Eigen::VectorXd ws = GS[POINT_DEGREE].w_;
352
353 Eigen::VectorXd cs_tmp(cs.rows());
354 cs_tmp.setZero();
355
356 unsigned int k, n;
357 double norm;
358
359 for (k = 0; k < ps_l.cols(); k++) {
360 norm = ps_l.col(k).norm(); /* equal for ps_f and ps_b */
361 for (n = 1; n <= deg; n++) {
362 cs_tmp.segment(n * n, 2 * n + 1) = pow(norm, n)
363 * cs.segment(n * n, 2 * n + 1);
364 }
365
366 res += ws(k)
367 * (k_mod(ps_l.col(k))
368 + evaluate_sphericals(ps_l.col(k) / norm, cs_tmp, deg));
369 res += ws(k)
370 * (k_mod(ps_f.col(k))
371 + evaluate_sphericals(ps_f.col(k) / norm, cs_tmp, deg));
372 res += ws(k)
373 * (k_mod(ps_b.col(k))
374 + evaluate_sphericals(ps_b.col(k) / norm, cs_tmp, deg));
375 }
376
377 res /= 3.0;
378
379 res += (1.0 / 24);
380
381 return -2.0 * sqrt(M_PI) * res;
382}
383
384} /* namespace Bembel */
385
386#endif // BEMBEL_SRC_HOMOGENISEDLAPLACE_COEFFICIENTS_HPP_
Routines for the evalutation of pointwise errors.
Eigen::VectorXd getCoefficients(double precision)
Calculates the coefficients for the solid harmonics expansion of the periodic kernel .
double evaluate_sphericals(Eigen::Vector3d x, Eigen::VectorXd cs, unsigned int deg)
Evaluates the series for real coefficients, with the convenction that .
unsigned int getDegree(double precision)
Returns the degree of the sphericals expansion given a precision. Can be extended,...
Eigen::VectorXd getDisplacement(Eigen::MatrixXd ps_l, Eigen::MatrixXd ps_f, Eigen::MatrixXd ps_b)
Returns the right-hand side for the homogenised coefficient calculation.
Eigen::Vector3d Dk_mod(Eigen::Vector3d in)
Returns the gradient of the modified kernel .
double k_mod(Eigen::Vector3d in)
Returns the modified kernel .
constexpr int getFunctionSpaceOutputDimension()
Eigen::Matrix< double, 3, Eigen::Dynamic > Dsolid_harmonics_full(Eigen::Vector3d x, unsigned int N, Eigen::MatrixXd spherical_val)
Calculates all gradients of the solid harmonics, given the Legendre Coefficients L.
Eigen::Matrix< double, Eigen::Dynamic, 2 > spherical_harmonics_full(Eigen::Vector3d x, unsigned int N)
Calculates the the spherical harmonics , ordered by .
double calculateFirstCoefficient(Eigen::VectorXd cs, unsigned int deg, Eigen::MatrixXd ps_l, Eigen::MatrixXd ps_f, Eigen::MatrixXd ps_b)
Calculates the first coefficient such that the mean of the kernel vanishes.