12 #ifndef BEMBEL_SRC_UTIL_SPHERICALS_HPP_
13 #define BEMBEL_SRC_UTIL_SPHERICALS_HPP_
14 #include <Eigen/Dense>
26 unsigned int deg,
bool grad);
32 Eigen::VectorXd cs,
unsigned int deg);
35 Eigen::Vector3d x,
unsigned int N);
37 inline Eigen::Vector2d
spherical_prev(Eigen::Vector3d x,
int m,
int n,
38 Eigen::Vector2d y1, Eigen::Vector2d y2);
41 Eigen::Vector3d x,
unsigned int N, Eigen::MatrixXd spherical_val);
44 unsigned int n, Eigen::VectorXd L,
double y_re,
double y_im);
48 double constant(
int m,
unsigned int n);
52 inline double pow_int(
double x,
int n);
71 double z1[2], z2[2], z3[2], z1_start[2];
72 double r, fac, rootTimesZ, root_2, root_3;
74 assert(abs(x.norm() - 1) < Constants::generic_tolerance);
77 z1[0] = 0.5 / sqrt(pi);
82 for (m = 0; m < deg - 1; m++) {
91 rootTimesZ = sqrt(2 * m + 3) * x(2);
92 z2[0] = rootTimesZ * z1[0];
93 z2[1] = rootTimesZ * z1[1];
94 r += fac * cs(m * (m + 1) + m) * z1[0];
95 r += fac * cs((m + 1) * (m + 2) + m) * z2[0];
96 for (n = m + 2; n < deg; n++) {
97 root_2 = sqrt((2 * n + 1.0) / ((n - m) * (n + m)));
98 rootTimesZ = sqrt(2 * n - 1) * x(2);
99 root_3 = sqrt(((n + m - 1.0) * (n - m - 1.0)) / (2 * n - 3));
100 z3[0] = root_2 * (rootTimesZ * z2[0] - root_3 * z1[0]);
101 z3[1] = root_2 * (rootTimesZ * z2[1] - root_3 * z1[1]);
102 r += fac * cs(n * (n + 1) + m) * z3[0];
108 root_2 = sqrt((2 * m + 3.0) / (2 * m + 2));
109 z1[0] = root_2 * (x(0) * z1_start[0] - x(1) * z1_start[1]);
110 z1[1] = root_2 * (x(0) * z1_start[1] + x(1) * z1_start[0]);
112 r += 2 * cs((deg - 1) * (deg + 1)) * z1[0];
129 unsigned int deg,
bool grad) {
131 double z1[2], z2[2], z3[2], z1_start[2];
132 double r, fac, rootTimesZ, root_2, root_3, norm, fac_tot;
136 z1[0] = 0.5 / sqrt(pi);
137 if (grad && deg <= 1) {
139 }
else if (!grad && deg <= 1) {
140 return cs(0) * z1[0];
146 for (m = 0; m < deg - 1; m++) {
154 fac_tot = fac * m *
pow_int(norm, m - 1);
156 fac_tot = fac *
pow_int(norm, m);
161 rootTimesZ = sqrt(2 * m + 3) * y(2);
162 z2[0] = rootTimesZ * z1[0];
163 z2[1] = rootTimesZ * z1[1];
164 r += fac_tot * cs(m * (m + 1) + m) * z1[0];
167 fac_tot = fac * (m + 1) *
pow_int(norm, m);
171 r += fac_tot * cs((m + 1) * (m + 2) + m) * z2[0];
173 for (n = m + 2; n < deg; n++) {
175 fac_tot = fac * n *
pow_int(norm, n - 1);
179 root_2 = sqrt((2 * n + 1.0) / ((n - m) * (n + m)));
180 rootTimesZ = sqrt(2 * n - 1) * y(2);
181 root_3 = sqrt(((n + m - 1.0) * (n - m - 1.0)) / (2 * n - 3));
182 z3[0] = root_2 * (rootTimesZ * z2[0] - root_3 * z1[0]);
183 z3[1] = root_2 * (rootTimesZ * z2[1] - root_3 * z1[1]);
184 r += fac_tot * cs(n * (n + 1) + m) * z3[0];
190 root_2 = sqrt((2 * m + 3.0) / (2 * m + 2));
191 z1[0] = root_2 * (y(0) * z1_start[0] - y(1) * z1_start[1]);
192 z1[1] = root_2 * (y(0) * z1_start[1] + y(1) * z1_start[0]);
196 fac_tot = fac * deg *
pow_int(norm, deg - 1);
200 r += fac_tot * cs((deg - 1) * (deg + 1)) * z1[0];
216 double z1[2], z2[2], z3[2], z1_start[2];
218 double fac, rootTimesZ, root_2, root_3;
220 assert(abs(x.norm() - 1) < Constants::generic_tolerance);
222 z1[0] = sqrt(0.375 / pi);
225 dr = Eigen::Vector3d(0.0, 0.0, 0.0);
231 for (m = 1; m < deg - 1; m++) {
234 rootTimesZ = sqrt(2 * m + 3) * x(2);
235 z2[0] = rootTimesZ * z1[0];
236 z2[1] = rootTimesZ * z1[1];
237 dr(0) += 2 * m * (cs(m * (m + 1) + m) * z1[0]);
239 dr(0) += 2 * m * (cs((m + 1) * (m + 2) + m) * z2[0]);
241 dr(1) -= 2 * m * (cs(m * (m + 1) + m) * z1[1]);
243 dr(1) -= 2 * m * (cs((m + 1) * (m + 2) + m) * z2[1]);
248 dr(2) += fac * sqrt(2 * m)
249 * (cs(m * (m + 1) + (m - 1)) * z1[0]
250 + cs(m * (m + 1) - (m - 1)) * z1[1]);
251 dr(2) += fac * sqrt(4 * m + 2)
252 * (cs((m + 1) * (m + 2) + (m - 1)) * z2[0]
253 + cs((m + 1) * (m + 2) - (m - 1)) * z2[1]);
256 dr(2) += fac * sqrt(2 * m) * (cs(m * (m + 1) + (m - 1)) * z1[0]);
258 dr(2) += fac * sqrt(4 * m + 2)
259 * (cs((m + 1) * (m + 2) + (m - 1)) * z2[0]);
263 for (n = m + 2; n < deg; n++) {
264 root_2 = sqrt((2 * n + 1.0) / ((n - m) * (n + m)));
265 rootTimesZ = sqrt(2 * n - 1) * x(2);
266 root_3 = sqrt(((n + m - 1.0) * (n - m - 1.0)) / (2 * n - 3));
267 z3[0] = root_2 * (rootTimesZ * z2[0] - root_3 * z1[0]);
268 z3[1] = root_2 * (rootTimesZ * z2[1] - root_3 * z1[1]);
269 dr(0) += 2 * m * (cs(n * (n + 1) + m) * z3[0]);
270 dr(1) -= 2 * m * (cs(n * (n + 1) + m) * z3[1]);
271 dr(2) += fac * sqrt((n + m) * (n - m + 1))
272 * (cs(n * (n + 1) + (m - 1)) * z3[0]);
278 root_2 = sqrt((2 * m + 3.0) / (2 * m + 2));
279 z1[0] = root_2 * (x(0) * z1_start[0] - x(1) * z1_start[1]);
280 z1[1] = root_2 * (x(0) * z1_start[1] + x(1) * z1_start[0]);
282 dr(0) += (deg - 1) * (2 * cs((deg - 1) * (deg + 1)) * z1[0]);
284 dr(1) -= (deg - 1) * (2 * cs((deg - 1) * (deg + 1)) * z1[1]);
286 dr(2) += 2 * sqrt(2 * (deg - 1))
287 * (cs(deg * (deg - 1) + (deg - 2)) * z1[0]
288 + cs(deg * (deg - 1) - (deg - 2)) * z1[1]);
303 Eigen::VectorXd cs,
unsigned int deg) {
305 double z1[2], z2[2], z3[2], z1_start[2];
306 Eigen::Vector3d dr, y;
307 double fac, rootTimesZ, root_2, root_3, norm, r_n3;
309 z1[0] = sqrt(0.375 / pi);
312 dr = Eigen::Vector3d(0.0, 0.0, 0.0);
320 for (m = 1; m < deg - 1; m++) {
325 rootTimesZ = sqrt(2 * m + 3) * y(2);
326 z2[0] = rootTimesZ * z1[0];
327 z2[1] = rootTimesZ * z1[1];
328 dr(0) += 2 * m * r_n3 * (cs(m * (m + 1) + m) * z1[0]);
329 dr(0) += 2 * m * r_n3 * norm * (cs((m + 1) * (m + 2) + m) * z2[0]);
330 dr(1) -= 2 * m * r_n3 * (cs(m * (m + 1) + m) * z1[1]);
331 dr(1) -= 2 * m * r_n3 * norm * (cs((m + 1) * (m + 2) + m) * z2[1]);
335 dr(2) += fac * r_n3 * sqrt(2 * m)
336 * (cs(m * (m + 1) + (m - 1)) * z1[0]
337 + cs(m * (m + 1) - (m - 1)) * z1[1]);
338 dr(2) += fac * r_n3 * norm * sqrt(4 * m + 2)
339 * (cs((m + 1) * (m + 2) + (m - 1)) * z2[0]
340 + cs((m + 1) * (m + 2) - (m - 1)) * z2[1]);
343 dr(2) += fac * r_n3 * sqrt(2 * m) * (cs(m * (m + 1) + (m - 1)) * z1[0]);
344 dr(2) += fac * r_n3 * norm * sqrt(4 * m + 2)
345 * (cs((m + 1) * (m + 2) + (m - 1)) * z2[0]);
350 for (n = m + 2; n < deg; n++) {
352 root_2 = sqrt((2 * n + 1.0) / ((n - m) * (n + m)));
353 rootTimesZ = sqrt(2 * n - 1) * y(2);
354 root_3 = sqrt(((n + m - 1.0) * (n - m - 1.0)) / (2 * n - 3));
355 z3[0] = root_2 * (rootTimesZ * z2[0] - root_3 * z1[0]);
356 z3[1] = root_2 * (rootTimesZ * z2[1] - root_3 * z1[1]);
357 dr(0) += 2 * m * r_n3 * (cs(n * (n + 1) + m) * z3[0]);
358 dr(1) -= 2 * m * r_n3 * (cs(n * (n + 1) + m) * z3[1]);
359 dr(2) += fac * r_n3 * sqrt((n + m) * (n - m + 1))
360 * (cs(n * (n + 1) + (m - 1)) * z3[0]);
366 root_2 = sqrt((2 * m + 3.0) / (2 * m + 2));
367 z1[0] = root_2 * (y(0) * z1_start[0] - y(1) * z1_start[1]);
368 z1[1] = root_2 * (y(0) * z1_start[1] + y(1) * z1_start[0]);
371 dr(0) += (deg - 1) * r_n3 * (2 * cs((deg - 1) * (deg + 1)) * z1[0]);
372 dr(1) -= (deg - 1) * r_n3 * (2 * cs((deg - 1) * (deg + 1)) * z1[1]);
373 dr(2) += 2 * r_n3 * sqrt(2 * (deg - 1))
374 * (cs(deg * (deg - 1) + (deg - 2)) * z1[0]
375 + cs(deg * (deg - 1) - (deg - 2)) * z1[1]);
389 Eigen::Vector3d x,
unsigned int N) {
391 Eigen::VectorXd real((N + 1) * (N + 1));
392 Eigen::VectorXd imag((N + 1) * (N + 1));
394 Eigen::Vector3d y = x / x.norm();
399 real(0) = 0.5 / sqrt(pi);
403 Eigen::Vector2d z1, z2, tmp;
405 for (n = 1; n <= N; n++) {
406 for (m = 0; m < n - 1; m++) {
407 z1(0) = real((n - 1) * (n - 1) + n - 1 + m);
408 z1(1) = real((n - 2) * (n - 2) + n - 2 + m);
409 z2(0) = imag((n - 1) * (n - 1) + n - 1 + m);
410 z2(1) = imag((n - 2) * (n - 2) + n - 2 + m);
414 real(n * n + n + m) = tmp(0);
415 imag(n * n + n + m) = tmp(1);
419 real(n * n + n - m) = tmp(0);
420 imag(n * n + n - m) = -tmp(1);
426 z1(0) = real(m * m + m + m);
427 z2(0) = imag(m * m + m + m);
430 real(n * n + n + m) = tmp(0);
431 imag(n * n + n + m) = tmp(1);
434 real(n * n + n - m) = tmp(0);
435 imag(n * n + n - m) = -tmp(1);
440 z1(0) = real((n - 1) * (n - 1) + n - 1 + n - 1);
441 z2(0) = imag((n - 1) * (n - 1) + n - 1 + n - 1);
444 real(n * n + n + m) = tmp(0);
445 imag(n * n + n + m) = tmp(1);
448 real(n * n + n - m) = tmp(0);
449 imag(n * n + n - m) = -tmp(1);
453 Eigen::MatrixXd res((N + 1) * (N + 1), 2);
464 Eigen::Vector2d y1, Eigen::Vector2d y2) {
467 assert(abs(x.norm() - 1) < 1e-14);
469 if ((m == 0) && (n == 0)) {
470 z(0) = 0.5 / sqrt(pi);
473 z(0) = sqrt((2 * m + 1.0) / (2 * m)) * (x(0) * y1(0) - x(1) * y2(0));
474 z(1) = sqrt((2 * m + 1.0) / (2 * m)) * (x(0) * y2(0) + x(1) * y1(0));
475 }
else if (m + 1 == n) {
476 z(0) = y1(0) * sqrt(2 * m + 3) * x(2);
477 z(1) = y2(0) * sqrt(2 * m + 3) * x(2);
479 z(0) = sqrt((2 * n + 1.0) / ((n - m) * (n + m)))
480 * (sqrt(2 * n - 1) * x(2) * y1(0)
481 - sqrt(((n + m - 1.0) * (n - m - 1.0)) / (2 * n - 3)) * y1(1));
482 z(1) = sqrt((2 * n + 1.0) / ((n - m) * (n + m)))
483 * (sqrt(2 * n - 1) * x(2) * y2(0)
484 - sqrt(((n + m - 1.0) * (n - m - 1.0)) / (2 * n - 3)) * y2(1));
493 Eigen::Vector3d x,
unsigned int N, Eigen::MatrixXd spherical_val) {
496 Eigen::Matrix<double, 3, 2> z;
498 Eigen::MatrixXd reals(3, (N + 1) * (N + 1)), imags(3, (N + 1) * (N + 1));
502 for (n = 0; n <= N; n++) {
503 for (m = 0; m <= n; m++) {
505 spherical_val(n * n + n + m, 1));
507 reals(0, n * n + n + m) = z(0, 0);
508 reals(1, n * n + n + m) = z(1, 0);
509 reals(2, n * n + n + m) = z(2, 0);
511 imags(0, n * n + n + m) = z(0, 1);
512 imags(1, n * n + n + m) = z(1, 1);
513 imags(2, n * n + n + m) = z(2, 1);
516 reals(0, n * n + n - m) = z(0, 0);
517 reals(1, n * n + n - m) = z(1, 0);
518 reals(2, n * n + n - m) = z(2, 0);
520 imags(0, n * n + n - m) = -z(0, 1);
521 imags(1, n * n + n - m) = -z(1, 1);
522 imags(2, n * n + n - m) = -z(2, 1);
533 unsigned int n, Eigen::VectorXd L) {
538 assert(abs(x.norm() - 1) < 1e-14);
540 Eigen::Matrix<double, 3, 2> z;
543 z(0, 0) = z(0, 1) = z(2, 1) = 0;
547 z(2, 0) = L((n * (n + 1)) / 2 + 1);
553 z(0, 0) = L((n * (n + 1)) / 2 + m);
559 z(2, 0) = L((n * (n + 1)) / 2 + m + 1);
561 z(0, 1) = z(2, 1) = 0;
563 c = x(0) * z(2, 0) - x(1) * z(2, 1);
564 z(2, 1) = x(0) * z(2, 1) + x(1) * z(2, 0);
567 for (i = 1; i < m; i++) {
568 c = x(0) * z(0, 0) - x(1) * z(0, 1);
569 z(0, 1) = x(0) * z(0, 1) + x(1) * z(0, 0);
572 c = x(0) * z(2, 0) - x(1) * z(2, 1);
573 z(2, 1) = x(0) * z(2, 1) + x(1) * z(2, 0);
594 unsigned int n, Eigen::VectorXd L,
double y_re,
double y_im) {
599 Eigen::Vector3d x = y / r;
600 Eigen::Matrix<double, 3, 2> z_harm;
602 unsigned int m_tilde;
612 r_n3 = pow(r, n - 3);
616 r_n3 = pow(1.0 / r, 3 - n);
620 z_harm = r_n3 * (A * z_harm);
629 r_n3 = pow(r, n - 3);
633 r_n3 = pow(1 / r, 3 - n);
639 z_harm = r_n3 * (A * z_harm);
642 z_harm.col(1) *= -1.0;
646 Eigen::Matrix<double, 3, 2> z_rad;
658 nr_n1 = n * pow(r, n - 1);
668 z_rad.col(0) = y_re * nr_n1 * x;
669 z_rad.col(1) = y_imt * nr_n1 * x;
671 return z_harm + z_rad;
678 Eigen::VectorXd L(((N + 1) * (N + 2)) / 2);
688 for (n = 2; n <= N; n++) {
689 s = (n * (n + 1)) / 2;
690 for (m = 0; m < n - 1; m++) {
691 L(s + m) = ((2 * n - 1) * t * L((n * (n - 1)) / 2 + m)
692 - (n + m - 1) * L(((n - 1) * (n - 2)) / 2 + m)) / (n - m);
697 L(s + m) = (2 * m + 1) * t * L((m * (m + 1)) / 2 + m);
701 L(s + m) = (2 * m - 1) * L((n * (n - 1)) / 2 + n - 1);
711 double c = sqrt((2 * n + 1) / (4 * pi));
713 for (i = 0; i < m; i++) {
714 c *= 1 / sqrt((n + i + 1) * (n - i));
728 M(0, 0) = r * r - z(0) * z(0);
729 M(1, 1) = r * r - z(1) * z(1);
730 M(2, 2) = r * r - z(2) * z(2);
732 M(1, 0) = M(0, 1) = -z(0) * z(1);
733 M(2, 0) = M(0, 2) = -z(0) * z(2);
734 M(2, 1) = M(1, 2) = -z(1) * z(2);
755 for (k = 1; k < ul; k++) {
Routines for the evalutation of pointwise errors.
double evaluate_sphericals(Eigen::Vector3d x, Eigen::VectorXd cs, unsigned int deg)
Evaluates the series for real coefficients, with the convenction that .
Eigen::Vector3d evaluate_dsolid_sphericals(Eigen::Vector3d x, Eigen::VectorXd cs, unsigned int deg)
Evaluates the series for real coefficients.
Eigen::VectorXd legendreFull(unsigned int N, double t)
Returns the values of the spherical polynomials .
Eigen::Matrix< double, 3, 2 > dsolid_spherical_prev(Eigen::Vector3d y, int m, unsigned int n, Eigen::VectorXd L, double y_re, double y_im)
Calculates the derivative of the solid harmonics function at the point with the spherical values.
double pow_int(double x, int n)
returns the -th power of without using pow.
double constant(int m, unsigned int n)
gives the norming factor of the spherical polynomials
double evaluate_solid_sphericals(Eigen::Vector3d x, Eigen::VectorXd cs, unsigned int deg, bool grad)
Evaluates the series for real coefficients cs if grad is false, and for real coefficients cs if gra...
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::Vector3d evaluate_dsphericals(Eigen::Vector3d x, Eigen::VectorXd cs, unsigned int deg)
Evaluates the series for real coefficients.
Eigen::Matrix< double, Eigen::Dynamic, 2 > spherical_harmonics_full(Eigen::Vector3d x, unsigned int N)
Calculates the the spherical harmonics , ordered by .
Eigen::Matrix3d functionalMatrix(Eigen::Vector3d z)
gives times the Jacobi Matrix of the transformation
Eigen::Vector2d spherical_prev(Eigen::Vector3d x, int m, int n, Eigen::Vector2d y1, Eigen::Vector2d y2)
Calculates the spherical harmonic based on previous values.
Eigen::Matrix< double, 3, 2 > dspherical_prev(Eigen::Vector3d x, int m, unsigned int n, Eigen::VectorXd L)
Calculates based on the Legendre Coefficients L.