| Line | Branch | Exec | Source | 
|---|---|---|---|
| 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_UTIL_SPHERICALS_HPP_ | ||
| 13 | #define BEMBEL_SRC_UTIL_SPHERICALS_HPP_ | ||
| 14 | #include <Eigen/Dense> | ||
| 15 | |||
| 16 | #if !defined pi | ||
| 17 | #define pi BEMBEL_PI | ||
| 18 | #endif | ||
| 19 | |||
| 20 | namespace Bembel { | ||
| 21 | |||
| 22 | double evaluate_sphericals(Eigen::Vector3d x, Eigen::VectorXd cs, | ||
| 23 | unsigned int deg); | ||
| 24 | |||
| 25 | double evaluate_solid_sphericals(Eigen::Vector3d x, Eigen::VectorXd cs, | ||
| 26 | unsigned int deg, bool grad); | ||
| 27 | |||
| 28 | Eigen::Vector3d evaluate_dsphericals(Eigen::Vector3d x, Eigen::VectorXd cs, | ||
| 29 | unsigned int deg); | ||
| 30 | |||
| 31 | Eigen::Vector3d evaluate_dsolid_sphericals(Eigen::Vector3d x, | ||
| 32 | Eigen::VectorXd cs, unsigned int deg); | ||
| 33 | |||
| 34 | Eigen::Matrix<double, Eigen::Dynamic, 2> spherical_harmonics_full( | ||
| 35 | Eigen::Vector3d x, unsigned int N); | ||
| 36 | |||
| 37 | inline Eigen::Vector2d spherical_prev(Eigen::Vector3d x, int m, int n, | ||
| 38 | Eigen::Vector2d y1, Eigen::Vector2d y2); | ||
| 39 | |||
| 40 | Eigen::Matrix<double, 3, Eigen::Dynamic> Dsolid_harmonics_full( | ||
| 41 | Eigen::Vector3d x, unsigned int N, Eigen::MatrixXd spherical_val); | ||
| 42 | |||
| 43 | Eigen::Matrix<double, 3, 2> dsolid_spherical_prev(Eigen::Vector3d y, int m, | ||
| 44 | unsigned int n, Eigen::VectorXd L, double y_re, double y_im); | ||
| 45 | |||
| 46 | Eigen::VectorXd legendreFull(unsigned int N, double t); | ||
| 47 | |||
| 48 | double constant(int m, unsigned int n); | ||
| 49 | |||
| 50 | inline Eigen::Matrix3d functionalMatrix(Eigen::Vector3d z); | ||
| 51 | |||
| 52 | inline double pow_int(double x, int n); | ||
| 53 | |||
| 54 | /** | ||
| 55 | * \brief Evaluates the series \f$ \sum_{n = 0}^{\rm deg} \sum_{m = -n}^n c_m^n Y_m^n(x) \f$ for real coefficients, | ||
| 56 | * with the convenction that \f$ Y_{-m}^n := \overline{Y_m^n} \f$. | ||
| 57 | * | ||
| 58 | * \see K. Giebermann. _Schnelle Summationsverfahren zur numerischen Lösung von Integralgleichungen | ||
| 59 | * für Streuprobleme im_ \f$ \mathbb{R}^3 \f$. PhD thesis, Universität Karlsruhe (TH), Germany, 1997. | ||
| 60 | * \see R. von Rickenbach. _Boundary Element Methods for Shape Optimisation in Homogenisation_. | ||
| 61 | * MSc thesis, Universität Basel, Switzerland, 2021. | ||
| 62 | * | ||
| 63 | * @param x: The point of evaluation, a vector with length 1 | ||
| 64 | * @param cs: The coefficients stored in the order \f$ [(0, 0), (1, -1), (1, 0), (1, 1) | ||
| 65 | * (2, -2), (2, -1), ... (n, n)] \f$ | ||
| 66 | * @param deg: The degree | ||
| 67 | */ | ||
| 68 | 6615 | double evaluate_sphericals(Eigen::Vector3d x, Eigen::VectorXd cs, | |
| 69 | unsigned int deg) { | ||
| 70 | unsigned int m, n; | ||
| 71 | double z1[2], z2[2], z3[2], z1_start[2]; | ||
| 72 | double r, fac, rootTimesZ, root_2, root_3; | ||
| 73 | |||
| 74 | 2/4✓ Branch 1 taken 6615 times. ✗ Branch 2 not taken. ✗ Branch 4 not taken. ✓ Branch 5 taken 6615 times. | 6615 | assert(abs(x.norm() - 1) < Constants::generic_tolerance); | 
| 75 | |||
| 76 | 6615 | r = z1[1] = 0; | |
| 77 | 6615 | z1[0] = 0.5 / sqrt(pi); | |
| 78 | 1/2✗ Branch 0 not taken. ✓ Branch 1 taken 6615 times. | 6615 | if (deg <= 1) { | 
| 79 | ✗ | return cs(0) * z1[0]; | |
| 80 | } | ||
| 81 | |||
| 82 | 2/2✓ Branch 0 taken 72765 times. ✓ Branch 1 taken 6615 times. | 79380 | for (m = 0; m < deg - 1; m++) { | 
| 83 | 2/2✓ Branch 0 taken 6615 times. ✓ Branch 1 taken 66150 times. | 72765 | if (m == 0) { | 
| 84 | 6615 | fac = 1.0; | |
| 85 | } else { | ||
| 86 | 66150 | fac = 2.0; | |
| 87 | } | ||
| 88 | |||
| 89 | 72765 | z1_start[0] = z1[0]; | |
| 90 | 72765 | z1_start[1] = z1[1]; | |
| 91 | 1/2✓ Branch 1 taken 72765 times. ✗ Branch 2 not taken. | 72765 | rootTimesZ = sqrt(2 * m + 3) * x(2); | 
| 92 | 72765 | z2[0] = rootTimesZ * z1[0]; | |
| 93 | 72765 | z2[1] = rootTimesZ * z1[1]; | |
| 94 | 1/2✓ Branch 1 taken 72765 times. ✗ Branch 2 not taken. | 72765 | r += fac * cs(m * (m + 1) + m) * z1[0]; // + k[ m *(m+1)-m]*z1[1]; | 
| 95 | 1/2✓ Branch 1 taken 72765 times. ✗ Branch 2 not taken. | 72765 | r += fac * cs((m + 1) * (m + 2) + m) * z2[0]; // + k[(m+1)*(m+2)-m]*z2[1]; | 
| 96 | 2/2✓ Branch 0 taken 363825 times. ✓ Branch 1 taken 72765 times. | 436590 | for (n = m + 2; n < deg; n++) { | 
| 97 | 363825 | root_2 = sqrt((2 * n + 1.0) / ((n - m) * (n + m))); | |
| 98 | 1/2✓ Branch 1 taken 363825 times. ✗ Branch 2 not taken. | 363825 | rootTimesZ = sqrt(2 * n - 1) * x(2); | 
| 99 | 363825 | root_3 = sqrt(((n + m - 1.0) * (n - m - 1.0)) / (2 * n - 3)); | |
| 100 | 363825 | z3[0] = root_2 * (rootTimesZ * z2[0] - root_3 * z1[0]); | |
| 101 | 363825 | z3[1] = root_2 * (rootTimesZ * z2[1] - root_3 * z1[1]); | |
| 102 | 1/2✓ Branch 1 taken 363825 times. ✗ Branch 2 not taken. | 363825 | r += fac * cs(n * (n + 1) + m) * z3[0]; // + k[n*(n+1)-m]*z3[1]; | 
| 103 | 363825 | z1[0] = z2[0]; | |
| 104 | 363825 | z1[1] = z2[1]; | |
| 105 | 363825 | z2[0] = z3[0]; | |
| 106 | 363825 | z2[1] = z3[1]; | |
| 107 | } | ||
| 108 | 72765 | root_2 = sqrt((2 * m + 3.0) / (2 * m + 2)); | |
| 109 | 2/4✓ Branch 1 taken 72765 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 72765 times. ✗ Branch 5 not taken. | 72765 | z1[0] = root_2 * (x(0) * z1_start[0] - x(1) * z1_start[1]); | 
| 110 | 2/4✓ Branch 1 taken 72765 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 72765 times. ✗ Branch 5 not taken. | 72765 | z1[1] = root_2 * (x(0) * z1_start[1] + x(1) * z1_start[0]); | 
| 111 | } | ||
| 112 | 1/2✓ Branch 1 taken 6615 times. ✗ Branch 2 not taken. | 6615 | r += 2 * cs((deg - 1) * (deg + 1)) * z1[0]; // + k[(nk-1)*(nk-1)]*z1[1]; | 
| 113 | 6615 | return r; | |
| 114 | } | ||
| 115 | |||
| 116 | /** | ||
| 117 | * \brief Evaluates the series \f$ \sum_{n = 0}^{\rm deg} \sum_{m = -n}^n | ||
| 118 | * |x|^n c_m^n Y_m^n( \frac{x}{|x|}) \f$ for real coefficients cs if grad is false, and | ||
| 119 | * \f$ \sum_{n = 0}^{\rm deg} \sum_{m = -n}^n n |x|^{n-1} c_m^n Y_m^n(\frac{x}{|x|}) \f$ | ||
| 120 | * for real coefficients cs if grad is true | ||
| 121 | * | ||
| 122 | * @param x: The point of evaluation | ||
| 123 | * @param cs: The coefficients stored in the order \f$ [(0, 0), (1, -1), (1, 0), (1, 1) | ||
| 124 | * (2, -2), (2, -1), ... (n, n)] \f$ | ||
| 125 | * @param deg: The degree | ||
| 126 | * @param grad: distinguish the two cases. | ||
| 127 | */ | ||
| 128 | 3279303 | double evaluate_solid_sphericals(Eigen::Vector3d x, Eigen::VectorXd cs, | |
| 129 | unsigned int deg, bool grad) { | ||
| 130 | unsigned int m, n; | ||
| 131 | double z1[2], z2[2], z3[2], z1_start[2]; | ||
| 132 | double r, fac, rootTimesZ, root_2, root_3, norm, fac_tot; | ||
| 133 | 1/2✓ Branch 1 taken 3279303 times. ✗ Branch 2 not taken. | 3279303 | Eigen::Vector3d y; | 
| 134 | |||
| 135 | 3279303 | r = z1[1] = 0; | |
| 136 | 3279303 | z1[0] = 0.5 / sqrt(pi); | |
| 137 | 3/4✓ Branch 0 taken 61207 times. ✓ Branch 1 taken 3218096 times. ✗ Branch 2 not taken. ✓ Branch 3 taken 61207 times. | 3279303 | if (grad && deg <= 1) { | 
| 138 | ✗ | return 0.0; | |
| 139 | 3/4✓ Branch 0 taken 3218096 times. ✓ Branch 1 taken 61207 times. ✗ Branch 2 not taken. ✓ Branch 3 taken 3218096 times. | 3279303 | } else if (!grad && deg <= 1) { | 
| 140 | ✗ | return cs(0) * z1[0]; | |
| 141 | } | ||
| 142 | |||
| 143 | 1/2✓ Branch 1 taken 3279303 times. ✗ Branch 2 not taken. | 3279303 | norm = x.norm(); | 
| 144 | 2/4✓ Branch 1 taken 3279303 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 3279303 times. ✗ Branch 5 not taken. | 3279303 | y = x / norm; | 
| 145 | |||
| 146 | 2/2✓ Branch 0 taken 36072333 times. ✓ Branch 1 taken 3279303 times. | 39351636 | for (m = 0; m < deg - 1; m++) { | 
| 147 | 2/2✓ Branch 0 taken 3279303 times. ✓ Branch 1 taken 32793030 times. | 36072333 | if (m == 0) { | 
| 148 | 3279303 | fac = 1.0; | |
| 149 | } else { | ||
| 150 | 32793030 | fac = 2.0; | |
| 151 | } | ||
| 152 | |||
| 153 | 2/2✓ Branch 0 taken 673277 times. ✓ Branch 1 taken 35399056 times. | 36072333 | if (grad) { | 
| 154 | 673277 | fac_tot = fac * m * pow_int(norm, m - 1); | |
| 155 | } else { | ||
| 156 | 35399056 | fac_tot = fac * pow_int(norm, m); | |
| 157 | } | ||
| 158 | |||
| 159 | 36072333 | z1_start[0] = z1[0]; | |
| 160 | 36072333 | z1_start[1] = z1[1]; | |
| 161 | 1/2✓ Branch 1 taken 36072333 times. ✗ Branch 2 not taken. | 36072333 | rootTimesZ = sqrt(2 * m + 3) * y(2); | 
| 162 | 36072333 | z2[0] = rootTimesZ * z1[0]; | |
| 163 | 36072333 | z2[1] = rootTimesZ * z1[1]; | |
| 164 | 1/2✓ Branch 1 taken 36072333 times. ✗ Branch 2 not taken. | 36072333 | r += fac_tot * cs(m * (m + 1) + m) * z1[0]; | 
| 165 | |||
| 166 | 2/2✓ Branch 0 taken 673277 times. ✓ Branch 1 taken 35399056 times. | 36072333 | if (grad) { | 
| 167 | 673277 | fac_tot = fac * (m + 1) * pow_int(norm, m); | |
| 168 | } else { | ||
| 169 | 35399056 | fac_tot *= norm; | |
| 170 | } | ||
| 171 | 1/2✓ Branch 1 taken 36072333 times. ✗ Branch 2 not taken. | 36072333 | r += fac_tot * cs((m + 1) * (m + 2) + m) * z2[0]; | 
| 172 | |||
| 173 | 2/2✓ Branch 0 taken 180361665 times. ✓ Branch 1 taken 36072333 times. | 216433998 | for (n = m + 2; n < deg; n++) { | 
| 174 | 2/2✓ Branch 0 taken 3366385 times. ✓ Branch 1 taken 176995280 times. | 180361665 | if (grad) { | 
| 175 | 3366385 | fac_tot = fac * n * pow_int(norm, n - 1); | |
| 176 | } else { | ||
| 177 | 176995280 | fac_tot *= norm; | |
| 178 | } | ||
| 179 | 180361665 | root_2 = sqrt((2 * n + 1.0) / ((n - m) * (n + m))); | |
| 180 | 1/2✓ Branch 1 taken 180361665 times. ✗ Branch 2 not taken. | 180361665 | rootTimesZ = sqrt(2 * n - 1) * y(2); | 
| 181 | 180361665 | root_3 = sqrt(((n + m - 1.0) * (n - m - 1.0)) / (2 * n - 3)); | |
| 182 | 180361665 | z3[0] = root_2 * (rootTimesZ * z2[0] - root_3 * z1[0]); | |
| 183 | 180361665 | z3[1] = root_2 * (rootTimesZ * z2[1] - root_3 * z1[1]); | |
| 184 | 1/2✓ Branch 1 taken 180361665 times. ✗ Branch 2 not taken. | 180361665 | r += fac_tot * cs(n * (n + 1) + m) * z3[0]; | 
| 185 | 180361665 | z1[0] = z2[0]; | |
| 186 | 180361665 | z1[1] = z2[1]; | |
| 187 | 180361665 | z2[0] = z3[0]; | |
| 188 | 180361665 | z2[1] = z3[1]; | |
| 189 | } | ||
| 190 | 36072333 | root_2 = sqrt((2 * m + 3.0) / (2 * m + 2)); | |
| 191 | 2/4✓ Branch 1 taken 36072333 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 36072333 times. ✗ Branch 5 not taken. | 36072333 | z1[0] = root_2 * (y(0) * z1_start[0] - y(1) * z1_start[1]); | 
| 192 | 2/4✓ Branch 1 taken 36072333 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 36072333 times. ✗ Branch 5 not taken. | 36072333 | z1[1] = root_2 * (y(0) * z1_start[1] + y(1) * z1_start[0]); | 
| 193 | } | ||
| 194 | |||
| 195 | 2/2✓ Branch 0 taken 61207 times. ✓ Branch 1 taken 3218096 times. | 3279303 | if (grad) { | 
| 196 | 61207 | fac_tot = fac * deg * pow_int(norm, deg - 1); | |
| 197 | } else { | ||
| 198 | 3218096 | fac_tot *= norm; | |
| 199 | } | ||
| 200 | 1/2✓ Branch 1 taken 3279303 times. ✗ Branch 2 not taken. | 3279303 | r += fac_tot * cs((deg - 1) * (deg + 1)) * z1[0]; | 
| 201 | 3279303 | return r; | |
| 202 | } | ||
| 203 | |||
| 204 | /** | ||
| 205 | * \brief Evaluates the series \f$ \sum_{n = 0}^{\rm deg} \sum_{m = -n}^n c_m^n | ||
| 206 | * \nabla Y_m^n(x) \f$ for real coefficients. | ||
| 207 | * | ||
| 208 | * @param x: The point of evaluation, a vector with length 1 | ||
| 209 | * @param cs: The coefficients stored in the order \f$ [(0, 0), (1, -1), (1, 0), (1, 1) | ||
| 210 | * (2, -2), (2, -1), ... (n, n)] \f$ | ||
| 211 | * @param deg: The degree | ||
| 212 | */ | ||
| 213 | ✗ | Eigen::Vector3d evaluate_dsphericals(Eigen::Vector3d x, Eigen::VectorXd cs, | |
| 214 | unsigned int deg) { | ||
| 215 | unsigned int m, n; | ||
| 216 | double z1[2], z2[2], z3[2], z1_start[2]; | ||
| 217 | ✗ | Eigen::Vector3d dr; | |
| 218 | double fac, rootTimesZ, root_2, root_3; | ||
| 219 | |||
| 220 | ✗ | assert(abs(x.norm() - 1) < Constants::generic_tolerance); | |
| 221 | |||
| 222 | ✗ | z1[0] = sqrt(0.375 / pi); | |
| 223 | ✗ | z1[1] = 0; | |
| 224 | |||
| 225 | ✗ | dr = Eigen::Vector3d(0.0, 0.0, 0.0); | |
| 226 | |||
| 227 | ✗ | if (deg == 1) { | |
| 228 | ✗ | return dr; | |
| 229 | } | ||
| 230 | |||
| 231 | ✗ | for (m = 1; m < deg - 1; m++) { | |
| 232 | ✗ | z1_start[0] = z1[0]; | |
| 233 | ✗ | z1_start[1] = z1[1]; | |
| 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]); | |
| 238 | // + a[ m *(m+1)-m]*z1[1]) for imaginary coefficients; | ||
| 239 | ✗ | dr(0) += 2 * m * (cs((m + 1) * (m + 2) + m) * z2[0]); | |
| 240 | // + a[(m+1)*(m+2)-m]*z2[1]) for imaginary coefficients; | ||
| 241 | ✗ | dr(1) -= 2 * m * (cs(m * (m + 1) + m) * z1[1]); | |
| 242 | // - a[ m *(m+1)-m]*z1[0]) for imaginary coefficients; | ||
| 243 | ✗ | dr(1) -= 2 * m * (cs((m + 1) * (m + 2) + m) * z2[1]); | |
| 244 | // - a[(m+1)*(m+2)-m]*z2[0]) for imaginary coefficients; | ||
| 245 | |||
| 246 | ✗ | if (m == 1) { | |
| 247 | ✗ | fac = 1.0; | |
| 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]); | |
| 254 | } else { | ||
| 255 | ✗ | fac = 2.0; | |
| 256 | ✗ | dr(2) += fac * sqrt(2 * m) * (cs(m * (m + 1) + (m - 1)) * z1[0]); | |
| 257 | // + a[ m *(m+1)-(m-1)]*z1[1]) for imaginary coefficients; | ||
| 258 | ✗ | dr(2) += fac * sqrt(4 * m + 2) | |
| 259 | ✗ | * (cs((m + 1) * (m + 2) + (m - 1)) * z2[0]); | |
| 260 | // + a[(m+1)*(m+2)-(m-1)]*z2[1]) for imaginary coefficients; | ||
| 261 | } | ||
| 262 | |||
| 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]); // + a[n*(n+1)-m]*z3[1]); | |
| 270 | ✗ | dr(1) -= 2 * m * (cs(n * (n + 1) + m) * z3[1]); // - a[n*(n+1)-m]*z3[0]); | |
| 271 | ✗ | dr(2) += fac * sqrt((n + m) * (n - m + 1)) | |
| 272 | ✗ | * (cs(n * (n + 1) + (m - 1)) * z3[0]); // + a[n*(n+1)-(m-1)]*z3[1]); | |
| 273 | ✗ | z1[0] = z2[0]; | |
| 274 | ✗ | z1[1] = z2[1]; | |
| 275 | ✗ | z2[0] = z3[0]; | |
| 276 | ✗ | z2[1] = z3[1]; | |
| 277 | } | ||
| 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]); | |
| 281 | } | ||
| 282 | ✗ | dr(0) += (deg - 1) * (2 * cs((deg - 1) * (deg + 1)) * z1[0]); | |
| 283 | // + a[(na-1)*(na-1)]*z1[1]) for imaginary coefficients; | ||
| 284 | ✗ | dr(1) -= (deg - 1) * (2 * cs((deg - 1) * (deg + 1)) * z1[1]); | |
| 285 | // - a[(na-1)*(na-1)]*z1[0]) for imaginary coefficients; | ||
| 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]); | |
| 289 | |||
| 290 | ✗ | return dr; | |
| 291 | } | ||
| 292 | |||
| 293 | /** | ||
| 294 | * \brief Evaluates the series \f$ \sum_{n = 0}^{\rm deg} \sum_{m = -n}^n | ||
| 295 | * |x|^{n-3} c_m^n (\nabla Y_m^n)(\frac{x}{|x|}) \f$ for real coefficients. | ||
| 296 | * | ||
| 297 | * @param x: The point of evaluation | ||
| 298 | * @param cs: The coefficients stored in the order \f$ [(0, 0), (1, -1), (1, 0), (1, 1) | ||
| 299 | * (2, -2), (2, -1), ... (n, n)] \f$ | ||
| 300 | * @param deg: The degree | ||
| 301 | */ | ||
| 302 | 61207 | Eigen::Vector3d evaluate_dsolid_sphericals(Eigen::Vector3d x, | |
| 303 | Eigen::VectorXd cs, unsigned int deg) { | ||
| 304 | unsigned int m, n; | ||
| 305 | double z1[2], z2[2], z3[2], z1_start[2]; | ||
| 306 | 2/4✓ Branch 1 taken 61207 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 61207 times. ✗ Branch 5 not taken. | 61207 | Eigen::Vector3d dr, y; | 
| 307 | double fac, rootTimesZ, root_2, root_3, norm, r_n3; | ||
| 308 | |||
| 309 | 61207 | z1[0] = sqrt(0.375 / pi); | |
| 310 | 61207 | z1[1] = 0; | |
| 311 | |||
| 312 | 1/2✓ Branch 1 taken 61207 times. ✗ Branch 2 not taken. | 61207 | dr = Eigen::Vector3d(0.0, 0.0, 0.0); | 
| 313 | 1/2✓ Branch 1 taken 61207 times. ✗ Branch 2 not taken. | 61207 | norm = x.norm(); | 
| 314 | 2/4✓ Branch 1 taken 61207 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 61207 times. ✗ Branch 5 not taken. | 61207 | y = x / norm; | 
| 315 | |||
| 316 | 1/2✗ Branch 0 not taken. ✓ Branch 1 taken 61207 times. | 61207 | if (deg == 1) { | 
| 317 | ✗ | return dr; | |
| 318 | } | ||
| 319 | |||
| 320 | 2/2✓ Branch 0 taken 612070 times. ✓ Branch 1 taken 61207 times. | 673277 | for (m = 1; m < deg - 1; m++) { | 
| 321 | 612070 | r_n3 = pow_int(norm, m - 3); | |
| 322 | |||
| 323 | 612070 | z1_start[0] = z1[0]; | |
| 324 | 612070 | z1_start[1] = z1[1]; | |
| 325 | 1/2✓ Branch 1 taken 612070 times. ✗ Branch 2 not taken. | 612070 | rootTimesZ = sqrt(2 * m + 3) * y(2); | 
| 326 | 612070 | z2[0] = rootTimesZ * z1[0]; | |
| 327 | 612070 | z2[1] = rootTimesZ * z1[1]; | |
| 328 | 2/4✓ Branch 1 taken 612070 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 612070 times. ✗ Branch 5 not taken. | 612070 | dr(0) += 2 * m * r_n3 * (cs(m * (m + 1) + m) * z1[0]); | 
| 329 | 2/4✓ Branch 1 taken 612070 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 612070 times. ✗ Branch 5 not taken. | 612070 | dr(0) += 2 * m * r_n3 * norm * (cs((m + 1) * (m + 2) + m) * z2[0]); | 
| 330 | 2/4✓ Branch 1 taken 612070 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 612070 times. ✗ Branch 5 not taken. | 612070 | dr(1) -= 2 * m * r_n3 * (cs(m * (m + 1) + m) * z1[1]); | 
| 331 | 2/4✓ Branch 1 taken 612070 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 612070 times. ✗ Branch 5 not taken. | 612070 | dr(1) -= 2 * m * r_n3 * norm * (cs((m + 1) * (m + 2) + m) * z2[1]); | 
| 332 | |||
| 333 | 2/2✓ Branch 0 taken 61207 times. ✓ Branch 1 taken 550863 times. | 612070 | if (m == 1) { | 
| 334 | 61207 | fac = 1.0; | |
| 335 | 183621 | dr(2) += fac * r_n3 * sqrt(2 * m) | |
| 336 | 1/2✓ Branch 1 taken 61207 times. ✗ Branch 2 not taken. | 61207 | * (cs(m * (m + 1) + (m - 1)) * z1[0] | 
| 337 | 2/4✓ Branch 1 taken 61207 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 61207 times. ✗ Branch 5 not taken. | 61207 | + cs(m * (m + 1) - (m - 1)) * z1[1]); | 
| 338 | 61207 | dr(2) += fac * r_n3 * norm * sqrt(4 * m + 2) | |
| 339 | 1/2✓ Branch 1 taken 61207 times. ✗ Branch 2 not taken. | 61207 | * (cs((m + 1) * (m + 2) + (m - 1)) * z2[0] | 
| 340 | 2/4✓ Branch 1 taken 61207 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 61207 times. ✗ Branch 5 not taken. | 61207 | + cs((m + 1) * (m + 2) - (m - 1)) * z2[1]); | 
| 341 | } else { | ||
| 342 | 550863 | fac = 2.0; | |
| 343 | 2/4✓ Branch 1 taken 550863 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 550863 times. ✗ Branch 5 not taken. | 550863 | dr(2) += fac * r_n3 * sqrt(2 * m) * (cs(m * (m + 1) + (m - 1)) * z1[0]); | 
| 344 | 550863 | dr(2) += fac * r_n3 * norm * sqrt(4 * m + 2) | |
| 345 | 2/4✓ Branch 1 taken 550863 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 550863 times. ✗ Branch 5 not taken. | 550863 | * (cs((m + 1) * (m + 2) + (m - 1)) * z2[0]); | 
| 346 | } | ||
| 347 | |||
| 348 | 612070 | r_n3 *= norm; | |
| 349 | |||
| 350 | 2/2✓ Branch 0 taken 2754315 times. ✓ Branch 1 taken 612070 times. | 3366385 | for (n = m + 2; n < deg; n++) { | 
| 351 | 2754315 | r_n3 *= norm; | |
| 352 | 2754315 | root_2 = sqrt((2 * n + 1.0) / ((n - m) * (n + m))); | |
| 353 | 1/2✓ Branch 1 taken 2754315 times. ✗ Branch 2 not taken. | 2754315 | rootTimesZ = sqrt(2 * n - 1) * y(2); | 
| 354 | 2754315 | root_3 = sqrt(((n + m - 1.0) * (n - m - 1.0)) / (2 * n - 3)); | |
| 355 | 2754315 | z3[0] = root_2 * (rootTimesZ * z2[0] - root_3 * z1[0]); | |
| 356 | 2754315 | z3[1] = root_2 * (rootTimesZ * z2[1] - root_3 * z1[1]); | |
| 357 | 2/4✓ Branch 1 taken 2754315 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 2754315 times. ✗ Branch 5 not taken. | 2754315 | dr(0) += 2 * m * r_n3 * (cs(n * (n + 1) + m) * z3[0]); | 
| 358 | 2/4✓ Branch 1 taken 2754315 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 2754315 times. ✗ Branch 5 not taken. | 2754315 | dr(1) -= 2 * m * r_n3 * (cs(n * (n + 1) + m) * z3[1]); | 
| 359 | 8262945 | dr(2) += fac * r_n3 * sqrt((n + m) * (n - m + 1)) | |
| 360 | 2/4✓ Branch 1 taken 2754315 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 2754315 times. ✗ Branch 5 not taken. | 2754315 | * (cs(n * (n + 1) + (m - 1)) * z3[0]); | 
| 361 | 2754315 | z1[0] = z2[0]; | |
| 362 | 2754315 | z1[1] = z2[1]; | |
| 363 | 2754315 | z2[0] = z3[0]; | |
| 364 | 2754315 | z2[1] = z3[1]; | |
| 365 | } | ||
| 366 | 612070 | root_2 = sqrt((2 * m + 3.0) / (2 * m + 2)); | |
| 367 | 2/4✓ Branch 1 taken 612070 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 612070 times. ✗ Branch 5 not taken. | 612070 | z1[0] = root_2 * (y(0) * z1_start[0] - y(1) * z1_start[1]); | 
| 368 | 2/4✓ Branch 1 taken 612070 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 612070 times. ✗ Branch 5 not taken. | 612070 | z1[1] = root_2 * (y(0) * z1_start[1] + y(1) * z1_start[0]); | 
| 369 | } | ||
| 370 | 61207 | r_n3 *= norm; | |
| 371 | 2/4✓ Branch 1 taken 61207 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 61207 times. ✗ Branch 5 not taken. | 61207 | dr(0) += (deg - 1) * r_n3 * (2 * cs((deg - 1) * (deg + 1)) * z1[0]); | 
| 372 | 2/4✓ Branch 1 taken 61207 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 61207 times. ✗ Branch 5 not taken. | 61207 | dr(1) -= (deg - 1) * r_n3 * (2 * cs((deg - 1) * (deg + 1)) * z1[1]); | 
| 373 | 183621 | dr(2) += 2 * r_n3 * sqrt(2 * (deg - 1)) | |
| 374 | 1/2✓ Branch 1 taken 61207 times. ✗ Branch 2 not taken. | 61207 | * (cs(deg * (deg - 1) + (deg - 2)) * z1[0] | 
| 375 | 2/4✓ Branch 1 taken 61207 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 61207 times. ✗ Branch 5 not taken. | 61207 | + cs(deg * (deg - 1) - (deg - 2)) * z1[1]); | 
| 376 | |||
| 377 | 61207 | return dr; | |
| 378 | } | ||
| 379 | |||
| 380 | /** | ||
| 381 | * \brief Calculates the the spherical harmonics \f$ Y_n^m(\frac{x}{|x|}) \f$, | ||
| 382 | * ordered by \f$ [Y_0^0, \, Y_1^{-1}, \, Y_1^0, \, Y_1^1, \, | ||
| 383 | * Y_2^{-2}, ..., Y_N^N] \f$ | ||
| 384 | * | ||
| 385 | * @param x: the point of evaluation | ||
| 386 | * @param N: the maximal degree | ||
| 387 | */ | ||
| 388 | 13230 | Eigen::Matrix<double, Eigen::Dynamic, 2> spherical_harmonics_full( | |
| 389 | Eigen::Vector3d x, unsigned int N) { | ||
| 390 | |||
| 391 | 1/2✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. | 13230 | Eigen::VectorXd real((N + 1) * (N + 1)); | 
| 392 | 1/2✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. | 13230 | Eigen::VectorXd imag((N + 1) * (N + 1)); | 
| 393 | |||
| 394 | 3/6✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 13230 times. ✗ Branch 5 not taken. ✓ Branch 7 taken 13230 times. ✗ Branch 8 not taken. | 13230 | Eigen::Vector3d y = x / x.norm(); | 
| 395 | |||
| 396 | int m, n; | ||
| 397 | |||
| 398 | /* handle n = 0 separately */ | ||
| 399 | 1/2✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. | 13230 | real(0) = 0.5 / sqrt(pi); | 
| 400 | 1/2✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. | 13230 | imag(0) = 0.0; | 
| 401 | |||
| 402 | /* assemble two temporary vectors */ | ||
| 403 | 3/6✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 13230 times. ✗ Branch 5 not taken. ✓ Branch 7 taken 13230 times. ✗ Branch 8 not taken. | 13230 | Eigen::Vector2d z1, z2, tmp; | 
| 404 | |||
| 405 | 2/2✓ Branch 0 taken 158760 times. ✓ Branch 1 taken 13230 times. | 171990 | for (n = 1; n <= N; n++) { | 
| 406 | 2/2✓ Branch 0 taken 873180 times. ✓ Branch 1 taken 158760 times. | 1031940 | for (m = 0; m < n - 1; m++) { | 
| 407 | 2/4✓ Branch 1 taken 873180 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 873180 times. ✗ Branch 5 not taken. | 873180 | z1(0) = real((n - 1) * (n - 1) + n - 1 + m); | 
| 408 | 2/4✓ Branch 1 taken 873180 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 873180 times. ✗ Branch 5 not taken. | 873180 | z1(1) = real((n - 2) * (n - 2) + n - 2 + m); | 
| 409 | 2/4✓ Branch 1 taken 873180 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 873180 times. ✗ Branch 5 not taken. | 873180 | z2(0) = imag((n - 1) * (n - 1) + n - 1 + m); | 
| 410 | 2/4✓ Branch 1 taken 873180 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 873180 times. ✗ Branch 5 not taken. | 873180 | z2(1) = imag((n - 2) * (n - 2) + n - 2 + m); | 
| 411 | |||
| 412 | 4/8✓ Branch 1 taken 873180 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 873180 times. ✗ Branch 5 not taken. ✓ Branch 7 taken 873180 times. ✗ Branch 8 not taken. ✓ Branch 10 taken 873180 times. ✗ Branch 11 not taken. | 873180 | tmp = spherical_prev(y, m, n, z1, z2); | 
| 413 | |||
| 414 | 2/4✓ Branch 1 taken 873180 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 873180 times. ✗ Branch 5 not taken. | 873180 | real(n * n + n + m) = tmp(0); | 
| 415 | 2/4✓ Branch 1 taken 873180 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 873180 times. ✗ Branch 5 not taken. | 873180 | imag(n * n + n + m) = tmp(1); | 
| 416 | |||
| 417 | // if m > 0, copy the value with the prefactor | ||
| 418 | 2/2✓ Branch 0 taken 727650 times. ✓ Branch 1 taken 145530 times. | 873180 | if (m > 0) { | 
| 419 | 2/4✓ Branch 1 taken 727650 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 727650 times. ✗ Branch 5 not taken. | 727650 | real(n * n + n - m) = tmp(0); | 
| 420 | 2/4✓ Branch 1 taken 727650 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 727650 times. ✗ Branch 5 not taken. | 727650 | imag(n * n + n - m) = -tmp(1); | 
| 421 | } | ||
| 422 | } | ||
| 423 | |||
| 424 | /* for m = n-1 */ | ||
| 425 | 158760 | m = n - 1; | |
| 426 | 2/4✓ Branch 1 taken 158760 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 158760 times. ✗ Branch 5 not taken. | 158760 | z1(0) = real(m * m + m + m); | 
| 427 | 2/4✓ Branch 1 taken 158760 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 158760 times. ✗ Branch 5 not taken. | 158760 | z2(0) = imag(m * m + m + m); | 
| 428 | |||
| 429 | 4/8✓ Branch 1 taken 158760 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 158760 times. ✗ Branch 5 not taken. ✓ Branch 7 taken 158760 times. ✗ Branch 8 not taken. ✓ Branch 10 taken 158760 times. ✗ Branch 11 not taken. | 158760 | tmp = spherical_prev(y, m, n, z1, z2); | 
| 430 | 2/4✓ Branch 1 taken 158760 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 158760 times. ✗ Branch 5 not taken. | 158760 | real(n * n + n + m) = tmp(0); | 
| 431 | 2/4✓ Branch 1 taken 158760 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 158760 times. ✗ Branch 5 not taken. | 158760 | imag(n * n + n + m) = tmp(1); | 
| 432 | |||
| 433 | 2/2✓ Branch 0 taken 145530 times. ✓ Branch 1 taken 13230 times. | 158760 | if (m > 0) { | 
| 434 | 2/4✓ Branch 1 taken 145530 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 145530 times. ✗ Branch 5 not taken. | 145530 | real(n * n + n - m) = tmp(0); | 
| 435 | 2/4✓ Branch 1 taken 145530 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 145530 times. ✗ Branch 5 not taken. | 145530 | imag(n * n + n - m) = -tmp(1); | 
| 436 | } | ||
| 437 | |||
| 438 | /* for m = n */ | ||
| 439 | 158760 | m = n; | |
| 440 | 2/4✓ Branch 1 taken 158760 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 158760 times. ✗ Branch 5 not taken. | 158760 | z1(0) = real((n - 1) * (n - 1) + n - 1 + n - 1); | 
| 441 | 2/4✓ Branch 1 taken 158760 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 158760 times. ✗ Branch 5 not taken. | 158760 | z2(0) = imag((n - 1) * (n - 1) + n - 1 + n - 1); | 
| 442 | |||
| 443 | 4/8✓ Branch 1 taken 158760 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 158760 times. ✗ Branch 5 not taken. ✓ Branch 7 taken 158760 times. ✗ Branch 8 not taken. ✓ Branch 10 taken 158760 times. ✗ Branch 11 not taken. | 158760 | tmp = spherical_prev(y, m, n, z1, z2); | 
| 444 | 2/4✓ Branch 1 taken 158760 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 158760 times. ✗ Branch 5 not taken. | 158760 | real(n * n + n + m) = tmp(0); | 
| 445 | 2/4✓ Branch 1 taken 158760 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 158760 times. ✗ Branch 5 not taken. | 158760 | imag(n * n + n + m) = tmp(1); | 
| 446 | |||
| 447 | 1/2✓ Branch 0 taken 158760 times. ✗ Branch 1 not taken. | 158760 | if (m > 0) { | 
| 448 | 2/4✓ Branch 1 taken 158760 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 158760 times. ✗ Branch 5 not taken. | 158760 | real(n * n + n - m) = tmp(0); | 
| 449 | 2/4✓ Branch 1 taken 158760 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 158760 times. ✗ Branch 5 not taken. | 158760 | imag(n * n + n - m) = -tmp(1); | 
| 450 | } | ||
| 451 | } | ||
| 452 | |||
| 453 | 1/2✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. | 13230 | Eigen::MatrixXd res((N + 1) * (N + 1), 2); | 
| 454 | 2/4✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 13230 times. ✗ Branch 5 not taken. | 13230 | res.col(0) = real; | 
| 455 | 2/4✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 13230 times. ✗ Branch 5 not taken. | 13230 | res.col(1) = imag; | 
| 456 | |||
| 457 | 1/2✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. | 26460 | return res; | 
| 458 | 13230 | } | |
| 459 | |||
| 460 | /** | ||
| 461 | * \brief Calculates the spherical harmonic \f$ Y_n^m(x) \f$ based on previous values | ||
| 462 | */ | ||
| 463 | 1190700 | inline Eigen::Vector2d spherical_prev(Eigen::Vector3d x, int m, int n, | |
| 464 | Eigen::Vector2d y1, Eigen::Vector2d y2) { | ||
| 465 | 1190700 | Eigen::Vector2d z; | |
| 466 | |||
| 467 | 1/2✗ Branch 2 not taken. ✓ Branch 3 taken 1190700 times. | 1190700 | assert(abs(x.norm() - 1) < 1e-14); | 
| 468 | |||
| 469 | 3/4✓ Branch 0 taken 158760 times. ✓ Branch 1 taken 1031940 times. ✗ Branch 2 not taken. ✓ Branch 3 taken 158760 times. | 1190700 | if ((m == 0) && (n == 0)) { | 
| 470 | ✗ | z(0) = 0.5 / sqrt(pi); | |
| 471 | ✗ | z(1) = 0; | |
| 472 | 2/2✓ Branch 0 taken 158760 times. ✓ Branch 1 taken 1031940 times. | 1190700 | } else if (m == n) { | 
| 473 | 158760 | z(0) = sqrt((2 * m + 1.0) / (2 * m)) * (x(0) * y1(0) - x(1) * y2(0)); | |
| 474 | 158760 | z(1) = sqrt((2 * m + 1.0) / (2 * m)) * (x(0) * y2(0) + x(1) * y1(0)); | |
| 475 | 2/2✓ Branch 0 taken 158760 times. ✓ Branch 1 taken 873180 times. | 1031940 | } else if (m + 1 == n) { | 
| 476 | 158760 | z(0) = y1(0) * sqrt(2 * m + 3) * x(2); | |
| 477 | 158760 | z(1) = y2(0) * sqrt(2 * m + 3) * x(2); | |
| 478 | } else { | ||
| 479 | 2619540 | z(0) = sqrt((2 * n + 1.0) / ((n - m) * (n + m))) | |
| 480 | 873180 | * (sqrt(2 * n - 1) * x(2) * y1(0) | |
| 481 | 873180 | - sqrt(((n + m - 1.0) * (n - m - 1.0)) / (2 * n - 3)) * y1(1)); | |
| 482 | 2619540 | z(1) = sqrt((2 * n + 1.0) / ((n - m) * (n + m))) | |
| 483 | 1746360 | * (sqrt(2 * n - 1) * x(2) * y2(0) | |
| 484 | 873180 | - sqrt(((n + m - 1.0) * (n - m - 1.0)) / (2 * n - 3)) * y2(1)); | |
| 485 | } | ||
| 486 | 1190700 | return z; | |
| 487 | } | ||
| 488 | |||
| 489 | /** | ||
| 490 | * \brief Calculates all gradients of the solid harmonics, given the Legendre Coefficients L. | ||
| 491 | */ | ||
| 492 | 13230 | Eigen::Matrix<double, 3, Eigen::Dynamic> Dsolid_harmonics_full( | |
| 493 | Eigen::Vector3d x, unsigned int N, Eigen::MatrixXd spherical_val) { | ||
| 494 | |||
| 495 | 3/6✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 13230 times. ✗ Branch 5 not taken. ✓ Branch 7 taken 13230 times. ✗ Branch 8 not taken. | 13230 | Eigen::VectorXd L = legendreFull(N, x(2) / x.norm()); | 
| 496 | 1/2✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. | 13230 | Eigen::Matrix<double, 3, 2> z; | 
| 497 | |||
| 498 | 2/4✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 13230 times. ✗ Branch 5 not taken. | 13230 | Eigen::MatrixXd reals(3, (N + 1) * (N + 1)), imags(3, (N + 1) * (N + 1)); | 
| 499 | |||
| 500 | int m, n; | ||
| 501 | |||
| 502 | 2/2✓ Branch 0 taken 171990 times. ✓ Branch 1 taken 13230 times. | 185220 | for (n = 0; n <= N; n++) { | 
| 503 | 2/2✓ Branch 0 taken 1203930 times. ✓ Branch 1 taken 171990 times. | 1375920 | for (m = 0; m <= n; m++) { | 
| 504 | 3/6✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1203930 times. ✗ Branch 5 not taken. ✓ Branch 7 taken 1203930 times. ✗ Branch 8 not taken. | 2407860 | z = dsolid_spherical_prev(x, m, n, L, spherical_val(n * n + n + m, 0), | 
| 505 | 2/4✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1203930 times. ✗ Branch 5 not taken. | 2407860 | spherical_val(n * n + n + m, 1)); | 
| 506 | |||
| 507 | 2/4✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1203930 times. ✗ Branch 5 not taken. | 1203930 | reals(0, n * n + n + m) = z(0, 0); | 
| 508 | 2/4✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1203930 times. ✗ Branch 5 not taken. | 1203930 | reals(1, n * n + n + m) = z(1, 0); | 
| 509 | 2/4✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1203930 times. ✗ Branch 5 not taken. | 1203930 | reals(2, n * n + n + m) = z(2, 0); | 
| 510 | |||
| 511 | 2/4✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1203930 times. ✗ Branch 5 not taken. | 1203930 | imags(0, n * n + n + m) = z(0, 1); | 
| 512 | 2/4✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1203930 times. ✗ Branch 5 not taken. | 1203930 | imags(1, n * n + n + m) = z(1, 1); | 
| 513 | 2/4✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1203930 times. ✗ Branch 5 not taken. | 1203930 | imags(2, n * n + n + m) = z(2, 1); | 
| 514 | |||
| 515 | 2/2✓ Branch 0 taken 1031940 times. ✓ Branch 1 taken 171990 times. | 1203930 | if (m > 0) { | 
| 516 | 2/4✓ Branch 1 taken 1031940 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1031940 times. ✗ Branch 5 not taken. | 1031940 | reals(0, n * n + n - m) = z(0, 0); | 
| 517 | 2/4✓ Branch 1 taken 1031940 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1031940 times. ✗ Branch 5 not taken. | 1031940 | reals(1, n * n + n - m) = z(1, 0); | 
| 518 | 2/4✓ Branch 1 taken 1031940 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1031940 times. ✗ Branch 5 not taken. | 1031940 | reals(2, n * n + n - m) = z(2, 0); | 
| 519 | |||
| 520 | 2/4✓ Branch 1 taken 1031940 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1031940 times. ✗ Branch 5 not taken. | 1031940 | imags(0, n * n + n - m) = -z(0, 1); | 
| 521 | 2/4✓ Branch 1 taken 1031940 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1031940 times. ✗ Branch 5 not taken. | 1031940 | imags(1, n * n + n - m) = -z(1, 1); | 
| 522 | 2/4✓ Branch 1 taken 1031940 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1031940 times. ✗ Branch 5 not taken. | 1031940 | imags(2, n * n + n - m) = -z(2, 1); | 
| 523 | } | ||
| 524 | } | ||
| 525 | } | ||
| 526 | 1/2✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. | 26460 | return reals; | 
| 527 | 13230 | } | |
| 528 | |||
| 529 | /** | ||
| 530 | * \brief Calculates \f$ \nabla Y_m^n(x) \f$ based on the Legendre Coefficients L. | ||
| 531 | */ | ||
| 532 | 1203930 | inline Eigen::Matrix<double, 3, 2> dspherical_prev(Eigen::Vector3d x, int m, | |
| 533 | unsigned int n, Eigen::VectorXd L) { | ||
| 534 | |||
| 535 | double c; | ||
| 536 | unsigned int i; | ||
| 537 | |||
| 538 | 1/2✗ Branch 2 not taken. ✓ Branch 3 taken 1203930 times. | 1203930 | assert(abs(x.norm() - 1) < 1e-14); | 
| 539 | |||
| 540 | 1203930 | Eigen::Matrix<double, 3, 2> z; | |
| 541 | |||
| 542 | 2/2✓ Branch 0 taken 171990 times. ✓ Branch 1 taken 1031940 times. | 1203930 | if (m == 0) { | 
| 543 | 171990 | z(0, 0) = z(0, 1) = z(2, 1) = 0; | |
| 544 | 2/2✓ Branch 0 taken 13230 times. ✓ Branch 1 taken 158760 times. | 171990 | if (1 > n) { | 
| 545 | 13230 | z(2, 0) = 0; | |
| 546 | } else { | ||
| 547 | 158760 | z(2, 0) = L((n * (n + 1)) / 2 + 1); | |
| 548 | } | ||
| 549 | } else { | ||
| 550 | 1/2✗ Branch 0 not taken. ✓ Branch 1 taken 1031940 times. | 1031940 | if (m > n) { | 
| 551 | ✗ | z(0, 0) = 0; | |
| 552 | } else { | ||
| 553 | 1031940 | z(0, 0) = L((n * (n + 1)) / 2 + m); | |
| 554 | } | ||
| 555 | |||
| 556 | 2/2✓ Branch 0 taken 158760 times. ✓ Branch 1 taken 873180 times. | 1031940 | if (m + 1 > n) { | 
| 557 | 158760 | z(2, 0) = 0; | |
| 558 | } else { | ||
| 559 | 873180 | z(2, 0) = L((n * (n + 1)) / 2 + m + 1); | |
| 560 | } | ||
| 561 | 1031940 | z(0, 1) = z(2, 1) = 0; | |
| 562 | |||
| 563 | 1031940 | c = x(0) * z(2, 0) - x(1) * z(2, 1); | |
| 564 | 1031940 | z(2, 1) = x(0) * z(2, 1) + x(1) * z(2, 0); | |
| 565 | 1031940 | z(2, 0) = c; | |
| 566 | |||
| 567 | 2/2✓ Branch 0 taken 3783780 times. ✓ Branch 1 taken 1031940 times. | 4815720 | for (i = 1; i < m; i++) { | 
| 568 | 3783780 | c = x(0) * z(0, 0) - x(1) * z(0, 1); | |
| 569 | 3783780 | z(0, 1) = x(0) * z(0, 1) + x(1) * z(0, 0); | |
| 570 | 3783780 | z(0, 0) = c; | |
| 571 | |||
| 572 | 3783780 | c = x(0) * z(2, 0) - x(1) * z(2, 1); | |
| 573 | 3783780 | z(2, 1) = x(0) * z(2, 1) + x(1) * z(2, 0); | |
| 574 | 3783780 | z(2, 0) = c; | |
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | 1203930 | c = constant(m, n); | |
| 579 | 1203930 | z(0, 0) *= m * c; | |
| 580 | 1203930 | z(0, 1) *= m * c; | |
| 581 | 1203930 | z(1, 0) = -z(0, 1); | |
| 582 | 1203930 | z(1, 1) = +z(0, 0); | |
| 583 | 1203930 | z(2, 0) *= c; | |
| 584 | 1203930 | z(2, 1) *= c; | |
| 585 | |||
| 586 | 1203930 | return z; | |
| 587 | } | ||
| 588 | |||
| 589 | /** | ||
| 590 | * \brief Calculates the derivative of the solid harmonics function \f$ \phi_n^m \f$ at | ||
| 591 | * the point \f$ y \f$ with the spherical values. | ||
| 592 | */ | ||
| 593 | 1203930 | Eigen::Matrix<double, 3, 2> dsolid_spherical_prev(Eigen::Vector3d y, int m, | |
| 594 | unsigned int n, Eigen::VectorXd L, double y_re, double y_im) { | ||
| 595 | |||
| 596 | // normalise y | ||
| 597 | // x denotes the normalised y and is passed to the original functions | ||
| 598 | 1/2✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. | 1203930 | double r = y.norm(); | 
| 599 | 2/4✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1203930 times. ✗ Branch 5 not taken. | 1203930 | Eigen::Vector3d x = y / r; | 
| 600 | 1/2✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. | 1203930 | Eigen::Matrix<double, 3, 2> z_harm; | 
| 601 | 1/2✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. | 1203930 | Eigen::Matrix3d A; | 
| 602 | unsigned int m_tilde; | ||
| 603 | |||
| 604 | // part with the gradient of Y | ||
| 605 | 1/2✓ Branch 0 taken 1203930 times. ✗ Branch 1 not taken. | 1203930 | if (m >= 0) { | 
| 606 | 1203930 | m_tilde = m; | |
| 607 | 3/6✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1203930 times. ✗ Branch 5 not taken. ✓ Branch 7 taken 1203930 times. ✗ Branch 8 not taken. | 1203930 | z_harm = dspherical_prev(x, m_tilde, n, L); | 
| 608 | |||
| 609 | // multiply the gradient of Y by r^(n-3) and the matrix A | ||
| 610 | double r_n3; | ||
| 611 | 2/2✓ Branch 0 taken 1071630 times. ✓ Branch 1 taken 132300 times. | 1203930 | if (n > 3) { | 
| 612 | 1071630 | r_n3 = pow(r, n - 3); | |
| 613 | 2/2✓ Branch 0 taken 52920 times. ✓ Branch 1 taken 79380 times. | 132300 | } else if (n == 3) { | 
| 614 | 52920 | r_n3 = 1.0; | |
| 615 | } else { | ||
| 616 | 79380 | r_n3 = pow(1.0 / r, 3 - n); | |
| 617 | } | ||
| 618 | |||
| 619 | 2/4✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1203930 times. ✗ Branch 5 not taken. | 1203930 | A = functionalMatrix(y); | 
| 620 | 3/6✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1203930 times. ✗ Branch 5 not taken. ✓ Branch 7 taken 1203930 times. ✗ Branch 8 not taken. | 1203930 | z_harm = r_n3 * (A * z_harm); | 
| 621 | |||
| 622 | } else { | ||
| 623 | ✗ | m_tilde = -m; | |
| 624 | ✗ | z_harm = dspherical_prev(x, m_tilde, n, L); | |
| 625 | |||
| 626 | // define r^(n-3) as above | ||
| 627 | double r_n3; | ||
| 628 | ✗ | if (n > 3) { | |
| 629 | ✗ | r_n3 = pow(r, n - 3); | |
| 630 | ✗ | } else if (n == 3) { | |
| 631 | ✗ | r_n3 = 1.0; | |
| 632 | } else { | ||
| 633 | ✗ | r_n3 = pow(1 / r, 3 - n); | |
| 634 | } | ||
| 635 | |||
| 636 | // get the part of the gradient of Y, | ||
| 637 | // conjugate and multiply by the functional matrix | ||
| 638 | ✗ | A = functionalMatrix(y); | |
| 639 | ✗ | z_harm = r_n3 * (A * z_harm); | |
| 640 | |||
| 641 | // get the complex conjugation | ||
| 642 | ✗ | z_harm.col(1) *= -1.0; | |
| 643 | } | ||
| 644 | |||
| 645 | // calculate the radial part and multiply with n*r^{n-1} | ||
| 646 | 1/2✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. | 1203930 | Eigen::Matrix<double, 3, 2> z_rad; | 
| 647 | |||
| 648 | // case n = 0: r^n = 1 is constant | ||
| 649 | 2/2✓ Branch 0 taken 13230 times. ✓ Branch 1 taken 1190700 times. | 1203930 | if (n == 0) { | 
| 650 | 1/2✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. | 13230 | z_rad.setZero(); | 
| 651 | } else { | ||
| 652 | // the gradient of r^n is n*r^(n-2)*y = nr^(n-1)*x | ||
| 653 | // again adapt the power | ||
| 654 | double nr_n1; | ||
| 655 | 2/2✓ Branch 0 taken 26460 times. ✓ Branch 1 taken 1164240 times. | 1190700 | if (n == 1) { | 
| 656 | 26460 | nr_n1 = 1.0; | |
| 657 | } else { | ||
| 658 | 1164240 | nr_n1 = n * pow(r, n - 1); | |
| 659 | } | ||
| 660 | |||
| 661 | double y_imt; | ||
| 662 | 1/2✓ Branch 0 taken 1190700 times. ✗ Branch 1 not taken. | 1190700 | if (m >= 0) { | 
| 663 | 1190700 | y_imt = y_im; | |
| 664 | } else { | ||
| 665 | ✗ | y_imt = -y_im; | |
| 666 | } | ||
| 667 | |||
| 668 | 3/6✓ Branch 1 taken 1190700 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1190700 times. ✗ Branch 5 not taken. ✓ Branch 7 taken 1190700 times. ✗ Branch 8 not taken. | 1190700 | z_rad.col(0) = y_re * nr_n1 * x; | 
| 669 | 3/6✓ Branch 1 taken 1190700 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1190700 times. ✗ Branch 5 not taken. ✓ Branch 7 taken 1190700 times. ✗ Branch 8 not taken. | 1190700 | z_rad.col(1) = y_imt * nr_n1 * x; | 
| 670 | } | ||
| 671 | 2/4✓ Branch 1 taken 1203930 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 1203930 times. ✗ Branch 5 not taken. | 2407860 | return z_harm + z_rad; | 
| 672 | } | ||
| 673 | |||
| 674 | /** | ||
| 675 | * \brief Returns the values of the spherical polynomials \f$ P_n^m(t) \f$ | ||
| 676 | */ | ||
| 677 | 13230 | Eigen::VectorXd legendreFull(unsigned int N, double t) { | |
| 678 | 1/2✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. | 13230 | Eigen::VectorXd L(((N + 1) * (N + 2)) / 2); | 
| 679 | int n, s, m; | ||
| 680 | |||
| 681 | /* n = 0 */ | ||
| 682 | 1/2✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. | 13230 | L(0) = 1; | 
| 683 | |||
| 684 | /* n = 1 */ | ||
| 685 | 1/2✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. | 13230 | L(1) = t; | 
| 686 | 1/2✓ Branch 1 taken 13230 times. ✗ Branch 2 not taken. | 13230 | L(2) = 1; | 
| 687 | |||
| 688 | 2/2✓ Branch 0 taken 145530 times. ✓ Branch 1 taken 13230 times. | 158760 | for (n = 2; n <= N; n++) { | 
| 689 | 145530 | s = (n * (n + 1)) / 2; | |
| 690 | 2/2✓ Branch 0 taken 873180 times. ✓ Branch 1 taken 145530 times. | 1018710 | for (m = 0; m < n - 1; m++) { | 
| 691 | 1/2✓ Branch 1 taken 873180 times. ✗ Branch 2 not taken. | 873180 | L(s + m) = ((2 * n - 1) * t * L((n * (n - 1)) / 2 + m) | 
| 692 | 2/4✓ Branch 1 taken 873180 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 873180 times. ✗ Branch 5 not taken. | 873180 | - (n + m - 1) * L(((n - 1) * (n - 2)) / 2 + m)) / (n - m); | 
| 693 | } | ||
| 694 | |||
| 695 | /* m = n-1 */ | ||
| 696 | 145530 | m = n - 1; | |
| 697 | 2/4✓ Branch 1 taken 145530 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 145530 times. ✗ Branch 5 not taken. | 145530 | L(s + m) = (2 * m + 1) * t * L((m * (m + 1)) / 2 + m); | 
| 698 | |||
| 699 | /* m = n */ | ||
| 700 | 145530 | m = n; | |
| 701 | 2/4✓ Branch 1 taken 145530 times. ✗ Branch 2 not taken. ✓ Branch 4 taken 145530 times. ✗ Branch 5 not taken. | 145530 | L(s + m) = (2 * m - 1) * L((n * (n - 1)) / 2 + n - 1); | 
| 702 | } | ||
| 703 | 13230 | return L; | |
| 704 | ✗ | } | |
| 705 | |||
| 706 | /** | ||
| 707 | * \brief gives the norming factor of the spherical polynomials | ||
| 708 | */ | ||
| 709 | 1203930 | double constant(int m, unsigned int n) { | |
| 710 | unsigned int i; | ||
| 711 | 1203930 | double c = sqrt((2 * n + 1) / (4 * pi)); | |
| 712 | |||
| 713 | 2/2✓ Branch 0 taken 4815720 times. ✓ Branch 1 taken 1203930 times. | 6019650 | for (i = 0; i < m; i++) { | 
| 714 | 4815720 | c *= 1 / sqrt((n + i + 1) * (n - i)); | |
| 715 | } | ||
| 716 | |||
| 717 | 1203930 | return c; | |
| 718 | } | ||
| 719 | |||
| 720 | /** | ||
| 721 | * \brief gives \f$ |z|^3 \f$ times the Jacobi Matrix of the transformation \f$ z \mapsto \frac{z}{|z|} \f$ | ||
| 722 | */ | ||
| 723 | 1265137 | inline Eigen::Matrix3d functionalMatrix(Eigen::Vector3d z) { | |
| 724 | 1265137 | Eigen::Matrix3d M; | |
| 725 | |||
| 726 | 1265137 | double r = z.norm(); | |
| 727 | |||
| 728 | 1265137 | M(0, 0) = r * r - z(0) * z(0); | |
| 729 | 1265137 | M(1, 1) = r * r - z(1) * z(1); | |
| 730 | 1265137 | M(2, 2) = r * r - z(2) * z(2); | |
| 731 | |||
| 732 | 1265137 | M(1, 0) = M(0, 1) = -z(0) * z(1); | |
| 733 | 1265137 | M(2, 0) = M(0, 2) = -z(0) * z(2); | |
| 734 | 1265137 | M(2, 1) = M(1, 2) = -z(1) * z(2); | |
| 735 | |||
| 736 | 1265137 | return M; | |
| 737 | } | ||
| 738 | |||
| 739 | /** | ||
| 740 | * \brief returns the \f$ n \f$-th power of \f$ x \f$ without using pow. | ||
| 741 | */ | ||
| 742 | 40785272 | inline double pow_int(double x, int n) { | |
| 743 | 2/2✓ Branch 0 taken 3401717 times. ✓ Branch 1 taken 37383555 times. | 40785272 | if (n == 0) { | 
| 744 | 3401717 | return 1.0; | |
| 745 | } | ||
| 746 | |||
| 747 | unsigned int ul, k; | ||
| 748 | 2/2✓ Branch 0 taken 37199934 times. ✓ Branch 1 taken 183621 times. | 37383555 | if (n > 0) { | 
| 749 | 37199934 | ul = n; | |
| 750 | } else { | ||
| 751 | 183621 | ul = -n; | |
| 752 | } | ||
| 753 | |||
| 754 | 37383555 | double res = x; | |
| 755 | 2/2✓ Branch 0 taken 171929021 times. ✓ Branch 1 taken 37383555 times. | 209312576 | for (k = 1; k < ul; k++) { | 
| 756 | 171929021 | res *= x; | |
| 757 | } | ||
| 758 | |||
| 759 | 2/2✓ Branch 0 taken 37199934 times. ✓ Branch 1 taken 183621 times. | 37383555 | if (n > 0) { | 
| 760 | 37199934 | return res; | |
| 761 | } else { | ||
| 762 | 183621 | return 1.0 / res; | |
| 763 | } | ||
| 764 | } | ||
| 765 | |||
| 766 | } // namespace Bembel | ||
| 767 | |||
| 768 | #endif // BEMBEL_SRC_UTIL_SPHERICALS_HPP_ | ||
| 769 |