11 #ifndef BEMBEL_SRC_H2MATRIX_H2MULTIPOLE_HPP_
12 #define BEMBEL_SRC_H2MATRIX_H2MULTIPOLE_HPP_
15 namespace H2Multipole {
23 init_ChebyshevRoots(number_of_points);
25 void init_ChebyshevRoots(
int n_pts) {
26 auto grid_pts = Eigen::ArrayXd::LinSpaced(n_pts, 1, n_pts).reverse();
27 double alpha = BEMBEL_PI / (2. * double(n_pts));
28 points_ = 0.5 * (alpha * (2 * grid_pts - 1)).cos() + 0.5;
31 Eigen::VectorXd points_;
39 template <
typename InterpolationPo
ints>
41 Eigen::MatrixXd retval =
42 Eigen::MatrixXd::Identity(number_of_points, number_of_points);
43 Eigen::VectorXd x = InterpolationPoints(number_of_points).points_;
44 for (
auto i = 0; i < number_of_points; ++i)
45 for (
auto j = 1; j < number_of_points; ++j)
46 for (
auto k = number_of_points - 1; k >= j; --k)
47 retval(k, i) = (retval(k, i) - retval(k - 1, i)) / (x(k) - x(k - j));
55 template <
typename InterpolationPo
ints>
57 int number_of_points = L.size();
58 Eigen::VectorXd x = InterpolationPoints(number_of_points).points_;
61 retval = L(number_of_points - 1);
63 for (
auto i = number_of_points - 2; i >= 0; --i)
64 retval = retval * (xi - x(i)) + L(i);
76 template <
typename InterpolationPo
ints>
78 int np2 = number_of_points * number_of_points;
79 Eigen::MatrixXd E(number_of_points, 2 * number_of_points);
80 Eigen::MatrixXd T(np2, 4 * np2);
82 Eigen::VectorXd x = InterpolationPoints(number_of_points).points_;
84 computeLagrangePolynomials<InterpolationPoints>(number_of_points);
94 for (
auto j = 0; j < number_of_points; ++j)
95 for (
auto i = 0; i < number_of_points; ++i) {
96 E(i, j) = evaluatePolynomial<InterpolationPoints>(L.col(j), 0.5 * x(i));
97 E(i, j + number_of_points) =
98 evaluatePolynomial<InterpolationPoints>(L.col(j), 0.5 * x(i) + 0.5);
102 Eigen::Vector4i permutation;
103 permutation << 0, 3, 1, 2;
104 for (
auto k = 0; k < 4; ++k)
105 for (
auto i = 0; i < number_of_points; ++i)
106 for (
auto ii = 0; ii < number_of_points; ++ii)
107 for (
auto j = 0; j < number_of_points; ++j)
108 for (
auto jj = 0; jj < number_of_points; ++jj)
109 T(j * number_of_points + jj,
110 i * number_of_points + ii + np2 * permutation(k)) =
111 E(i, j + (k / 2) * number_of_points) *
112 E(ii, jj + (k % 2) * number_of_points);
120 template <
typename InterpolationPo
ints,
typename LinOp>
123 const int cluster_level,
124 const int cluster_refinements,
125 const int number_of_points) {
126 int n = 1 << cluster_refinements;
128 int N = 1 << cluster_level;
130 int polynomial_degree = super_space.get_polynomial_degree();
131 int polynomial_degree_plus_one = polynomial_degree + 1;
132 int polynomial_degree_plus_one_squared =
133 polynomial_degree_plus_one * polynomial_degree_plus_one;
136 GL[(int)std::ceil(0.5 * (number_of_points + polynomial_degree - 2))];
138 Eigen::VectorXd x = InterpolationPoints(number_of_points).points_;
140 computeLagrangePolynomials<InterpolationPoints>(number_of_points);
142 Eigen::MatrixXd moment(number_of_points, n * polynomial_degree_plus_one);
144 for (
auto i = 0; i < number_of_points; ++i) {
145 Eigen::Matrix<typename LinearOperatorTraits<LinOp>::Scalar,
147 intval(polynomial_degree_plus_one, 1);
148 for (
auto j = 0; j < n; ++j) {
150 for (
auto k = 0; k < Q.w_.size(); ++k) {
153 Q.w_(k) * std::sqrt(h * H) *
154 evaluatePolynomial<InterpolationPoints>(L.col(i),
159 moment.block(i, j * polynomial_degree_plus_one, 1,
160 polynomial_degree_plus_one) = intval.real().transpose();
172 template <
typename InterpolationPo
ints,
typename LinOp>
175 const int cluster_level,
176 const int cluster_refinements,
177 const int number_of_points) {
178 int n = 1 << cluster_refinements;
180 int N = 1 << cluster_level;
182 int polynomial_degree = super_space.get_polynomial_degree();
183 int polynomial_degree_plus_one = polynomial_degree + 1;
184 int polynomial_degree_plus_one_squared =
185 polynomial_degree_plus_one * polynomial_degree_plus_one;
188 GL[(int)std::ceil(0.5 * (number_of_points + polynomial_degree - 2))];
190 Eigen::VectorXd x = InterpolationPoints(number_of_points).points_;
192 computeLagrangePolynomials<InterpolationPoints>(number_of_points);
194 Eigen::MatrixXd moment(number_of_points, n * polynomial_degree_plus_one);
196 for (
auto i = 0; i < number_of_points; ++i) {
197 Eigen::Matrix<typename LinearOperatorTraits<LinOp>::Scalar,
199 intval(polynomial_degree_plus_one, 1);
200 for (
auto j = 0; j < n; ++j) {
202 for (
auto k = 0; k < Q.w_.size(); ++k) {
205 Q.w_(k) / std::sqrt(h * H) *
206 evaluatePolynomial<InterpolationPoints>(L.col(i),
211 moment.block(i, j * polynomial_degree_plus_one, 1,
212 polynomial_degree_plus_one) = intval.real().transpose();
224 template <
typename Mom1D_1,
typename Mom1D_2,
typename LinOp>
226 const int cluster_level,
227 const int cluster_refinements,
228 const int number_of_points) {
229 int n = 1 << cluster_refinements;
231 int polynomial_degree = super_space.get_polynomial_degree();
232 int polynomial_degree_plus_one = polynomial_degree + 1;
233 int polynomial_degree_plus_one_squared =
234 polynomial_degree_plus_one * polynomial_degree_plus_one;
237 Eigen::MatrixXd moment1D_1 = Mom1D_1::computeMoment1D(
238 super_space, cluster_level, cluster_refinements, number_of_points);
239 Eigen::MatrixXd moment1D_2 = Mom1D_2::computeMoment1D(
240 super_space, cluster_level, cluster_refinements, number_of_points);
260 Eigen::VectorXi index_s(n2);
261 Eigen::VectorXi index_t(n2);
264 for (
auto j = 0; j < cluster_refinements; ++j) {
265 auto inc = 1 << 2 * j;
266 for (
auto i = 0; i < inc; ++i) {
267 index_s(4 * i) = 2 * index_s(i);
268 index_s(4 * i + 1) = 2 * index_s(i) + 1;
269 index_s(4 * i + 2) = 2 * index_s(i) + 1;
270 index_s(4 * i + 3) = 2 * index_s(i);
271 index_t(4 * i) = 2 * index_t(i);
272 index_t(4 * i + 1) = 2 * index_t(i);
273 index_t(4 * i + 2) = 2 * index_t(i) + 1;
274 index_t(4 * i + 3) = 2 * index_t(i) + 1;
279 Eigen::MatrixXd moment2D(number_of_points * number_of_points,
280 moment1D_1.cols() * moment1D_2.cols());
281 for (
auto i = 0; i < number_of_points; ++i)
282 for (
auto j = 0; j < number_of_points; ++j)
283 for (
auto k = 0; k < n2; ++k)
284 for (
auto m1 = 0; m1 < polynomial_degree_plus_one; ++m1)
285 for (
auto m2 = 0; m2 < polynomial_degree_plus_one; ++m2)
286 moment2D(i * number_of_points + j,
287 polynomial_degree_plus_one_squared * k +
288 m1 * polynomial_degree_plus_one + m2) =
289 moment1D_1(i, index_s(k) * polynomial_degree_plus_one + m2) *
290 moment1D_2(j, index_t(k) * polynomial_degree_plus_one + m1);
301 template <
typename InterpolationPo
ints,
typename LinOp>
303 static std::vector<Eigen::MatrixXd> compute2DMoment(
305 const int cluster_refinements,
const int number_of_points) {
306 std::vector<Eigen::MatrixXd> vector_of_moments;
309 getFunctionSpaceVectorDimension<LinearOperatorTraits<LinOp>::Form>();
311 vector_of_moments.push_back(
314 super_space, cluster_level, cluster_refinements,
316 return vector_of_moments;
325 Eigen::MatrixXd x2(x.size() * x.size(), 2);
326 for (
auto i = 0; i < x.size(); ++i)
327 for (
auto j = 0; j < x.size(); ++j) {
328 x2.row(i * x.size() + j) = Eigen::Vector2d(x(i), x(j));
336 template <
typename LinOp>
337 Eigen::Matrix<typename LinearOperatorTraits<LinOp>::Scalar, Eigen::Dynamic,
340 const Eigen::MatrixXd &x,
346 getFunctionSpaceVectorDimension<LinearOperatorTraits<LinOp>::Form>() *
353 const int number_of_FMM_components =
355 Eigen::Matrix<typename LinearOperatorTraits<LinOp>::Scalar, Eigen::Dynamic,
357 F(vector_dimension * number_of_FMM_components * x.rows(),
358 vector_dimension * number_of_FMM_components * x.rows());
359 for (
int i = 0; i < x.rows(); ++i) {
360 super_space.
map2surface(cluster1, x.row(i), 1., &qp1);
361 for (
int j = 0; j < x.rows(); ++j) {
362 super_space.
map2surface(cluster2, x.row(j), 1., &qp2);
363 auto FMM_output = linOp.evaluateFMMInterpolation(qp1, qp2);
364 for (
int ii = 0; ii < vector_dimension; ++ii)
365 for (
int jj = 0; jj < vector_dimension; ++jj)
366 for (
int iii = 0; iii < number_of_FMM_components; ++iii)
367 for (
int jjj = 0; jjj < number_of_FMM_components; ++jjj)
368 F(i + (ii * number_of_FMM_components + iii) * x.rows(),
369 j + (jj * number_of_FMM_components + jjj) * x.rows()) =
370 FMM_output(iii + ii * number_of_FMM_components,
371 jjj + jj * number_of_FMM_components);
380 template <
typename Scalar>
381 std::vector<Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>>
383 const Eigen::MatrixXd &transfer_matrices,
const int steps,
384 const Eigen::Matrix<Scalar, Eigen::Dynamic,
385 Eigen::Dynamic> &long_rhs_matrix) {
387 int number_of_points = transfer_matrices.rows();
388 int number_of_FMM_components = moment_matrices.rows() / number_of_points;
390 std::vector<Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>>
392 long_rhs_forward.push_back(moment_matrices * long_rhs_matrix);
394 for (
int i = 0; i < steps; ++i) {
395 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> reshaped =
396 Eigen::Map<Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>>(
397 long_rhs_forward.back().data(), 4 * long_rhs_forward.back().rows(),
398 long_rhs_forward.back().cols() / 4);
399 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> transferred(
400 reshaped.rows() / 4, reshaped.cols());
403 for (
int j = 0; j < number_of_FMM_components; ++j) {
404 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> to_transfer(
405 4 * number_of_points, reshaped.cols());
406 to_transfer << reshaped.block(
407 (j + 0 * number_of_FMM_components) * number_of_points, 0,
408 number_of_points, reshaped.cols()),
409 reshaped.block((j + 1 * number_of_FMM_components) * number_of_points,
410 0, number_of_points, reshaped.cols()),
411 reshaped.block((j + 2 * number_of_FMM_components) * number_of_points,
412 0, number_of_points, reshaped.cols()),
413 reshaped.block((j + 3 * number_of_FMM_components) * number_of_points,
414 0, number_of_points, reshaped.cols());
415 transferred.block(j * number_of_points, 0, number_of_points,
416 reshaped.cols()) = transfer_matrices * to_transfer;
419 long_rhs_forward.push_back(transferred);
421 return long_rhs_forward;
428 template <
typename Scalar>
430 const Eigen::MatrixXd &moment_matrices,
431 const Eigen::MatrixXd &transfer_matrices,
const int steps,
432 std::vector<Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>>
433 &long_dst_backward) {
435 int number_of_points = transfer_matrices.rows();
436 int number_of_FMM_components = moment_matrices.rows() / number_of_points;
438 for (
int i = steps; i > 0; --i) {
439 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> transferred(
440 4 * long_dst_backward[i].rows(), long_dst_backward[i].cols());
441 for (
int j = 0; j < number_of_FMM_components; ++j) {
442 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> prod =
443 transfer_matrices.transpose() *
444 long_dst_backward[i].block(j * number_of_points, 0, number_of_points,
445 long_dst_backward[i].cols());
446 transferred.block((j + 0 * number_of_FMM_components) * number_of_points,
447 0, number_of_points, prod.cols()) =
448 prod.block(0 * number_of_points, 0, number_of_points, prod.cols());
449 transferred.block((j + 1 * number_of_FMM_components) * number_of_points,
450 0, number_of_points, prod.cols()) =
451 prod.block(1 * number_of_points, 0, number_of_points, prod.cols());
452 transferred.block((j + 2 * number_of_FMM_components) * number_of_points,
453 0, number_of_points, prod.cols()) =
454 prod.block(2 * number_of_points, 0, number_of_points, prod.cols());
455 transferred.block((j + 3 * number_of_FMM_components) * number_of_points,
456 0, number_of_points, prod.cols()) =
457 prod.block(3 * number_of_points, 0, number_of_points, prod.cols());
459 long_dst_backward[i - 1] +=
460 Eigen::Map<Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>>(
461 transferred.data(), long_dst_backward[i - 1].rows(),
462 long_dst_backward[i - 1].cols());
465 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> long_dst_matrix =
466 moment_matrices.transpose() * long_dst_backward[0];
467 return Eigen::Map<Eigen::Matrix<Scalar, Eigen::Dynamic, 1>>(
468 long_dst_matrix.data(), long_dst_matrix.size());
The ElementTreeNode corresponds to an element in the element tree.
Eigen::Matrix< double, 12, 1 > SurfacePoint
typedef of SurfacePoint
Eigen::MatrixXd computeLagrangePolynomials(int number_of_points)
computes the Lagrange polynomials wrt the interpolation points given by the InterpolationPoints struc...
Eigen::MatrixXd interpolationPoints2D(const Eigen::VectorXd &x)
Compute tensor interpolation points on unit square from 1D interpolation points.
Eigen::Matrix< typename LinearOperatorTraits< LinOp >::Scalar, Eigen::Dynamic, Eigen::Dynamic > interpolateKernel(const LinOp &linOp, const SuperSpace< LinOp > &super_space, const Eigen::MatrixXd &x, const Bembel::ElementTreeNode &cluster1, const Bembel::ElementTreeNode &cluster2)
Interpolate kernel function on reference domain for FMM.
Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic > backwardTransformation(const Eigen::MatrixXd &moment_matrices, const Eigen::MatrixXd &transfer_matrices, const int steps, std::vector< Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic >> &long_dst_backward)
Backward transformation for FMM. The content of long_dst_backward is destroyed.
std::vector< Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic > > forwardTransformation(const Eigen::MatrixXd &moment_matrices, const Eigen::MatrixXd &transfer_matrices, const int steps, const Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic > &long_rhs_matrix)
Forward transformation for FMM.
double evaluatePolynomial(const Eigen::VectorXd &L, double xi)
evaluates a given polynomial in the Newton basis wrt the interpolation points at a given location
Eigen::MatrixXd moment2DComputer(const SuperSpace< LinOp > &super_space, const int cluster_level, const int cluster_refinements, const int number_of_points)
Computes a single 2D moment for the FMM by tensorisation of the 1D moments.
Eigen::MatrixXd computeTransferMatrices(int number_of_points)
Computes transfer matrices in required order to apply them all-at-once in a matrix-vector-product,...
Routines for the evalutation of pointwise errors.
constexpr int getFunctionSpaceVectorDimension()
Computes the number_of_points Chebychev points.
Computes 1D moment for FMM using derivatives of the basis functions. All calculations ar performed on...
Computes 1D moment for FMM. All calculations ar performed on [0,1].
Computes all 2D moment for the FMM by tensorisation of the 1D moments. Specialice this for your linea...
struct containing specifications on the linear operator has to be specialized or derived for any part...
this struct wraps all the defined quadrature Rules in a nice structure overloading the [] operator su...
The superspace manages local polynomial bases on each element of the mesh and provides an interface t...
void addScaledBasis1DDx(Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > *intval, Scalar w, double s) const
Evaluate derivatives of local shape functions on the unit interval at coordinate s,...
void addScaledBasis1D(Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > *intval, Scalar w, double s) const
Evaluate local shape functions on the unit interval at coordinate s, scale by w and add to intval.
void map2surface(const ElementTreeNode &e, const Eigen::Vector2d &xi, double w, SurfacePoint *surf_pt) const
Evaluation of a point in the element and its Jacobian matrix.