|
25 | 25 |
|
26 | 26 | #include "NumericalIntegrator.hpp" |
27 | 27 |
|
| 28 | +#include <algorithm> |
28 | 29 | #include <cmath> |
29 | 30 | #include <stdexcept> |
30 | 31 |
|
31 | 32 | #include "Config.hpp" |
32 | 33 |
|
33 | 34 | #include "EigenPimpl.hpp" |
34 | 35 |
|
35 | | -#include <boost/numeric/quadrature/kronrodgauss.hpp> |
36 | | -#include <boost/numeric/quadrature/error_estimator.hpp> |
| 36 | +//#include <boost/numeric/quadrature/kronrodgauss.hpp> |
| 37 | +//#include <boost/numeric/quadrature/error_estimator.hpp> |
37 | 38 |
|
38 | 39 | #include "Element.hpp" |
| 40 | +#include "MathUtils.hpp" |
| 41 | +#include "Sphere.hpp" |
39 | 42 |
|
40 | 43 | double NumericalIntegrator::computeS(const Vacuum<double> * gf, const Element & e) const { |
41 | 44 | return 0.0; |
@@ -116,7 +119,177 @@ double NumericalIntegrator::computeD(const IonicLiquid<AD_hessian> * gf, const E |
116 | 119 | } |
117 | 120 |
|
118 | 121 | double NumericalIntegrator::computeS(const AnisotropicLiquid<double> * gf, const Element & e) const { |
119 | | - return 0.0; |
| 122 | + double Sii = 0.0, S64 = 0.0; |
| 123 | + // Extract relevant data from Element |
| 124 | + int nVertices = e.nVertices(); |
| 125 | + double area = e.area(); |
| 126 | + Eigen::Vector3d center = e.center(); |
| 127 | + Eigen::Vector3d normal = e.normal(); |
| 128 | + Sphere sph = e.sphere(); |
| 129 | + Eigen::Matrix3Xd vertices = e.vertices(); |
| 130 | + Eigen::Matrix3Xd arcs = e.arcs(); |
| 131 | + |
| 132 | + double xx = 0.0, |
| 133 | + xy = 0.0, |
| 134 | + xz = normal(0), |
| 135 | + yy = 0.0, |
| 136 | + yx = 0.0, |
| 137 | + yz = normal(1), |
| 138 | + zz = normal(2), |
| 139 | + zx = 0.0, |
| 140 | + zy = 0.0; |
| 141 | + |
| 142 | + double rmin = 0.99; // Some kind of threshold |
| 143 | + if (std::abs(xz) <= rmin) { |
| 144 | + rmin = std::abs(xz); |
| 145 | + xx = 0.0; |
| 146 | + yx = -zz / std::sqrt(1.0 - std::pow(xz, 2)); |
| 147 | + zx = yz / std::sqrt(1.0 - std::pow(xz, 2)); |
| 148 | + } |
| 149 | + if (std::abs(yz) <= rmin) { |
| 150 | + rmin = std::abs(yz); |
| 151 | + xx = yz / std::sqrt(1.0 - std::pow(yz, 2)); |
| 152 | + yx = 0.0; |
| 153 | + zx = -xz / std::sqrt(1.0 - std::pow(yz, 2)); |
| 154 | + } |
| 155 | + if (std::abs(zz) <= rmin) { |
| 156 | + rmin = std::abs(yz); |
| 157 | + xx = yz / std::sqrt(1.0 - std::pow(zz, 2)); |
| 158 | + yx = -xz / std::sqrt(1.0 - std::pow(zz, 2)); |
| 159 | + zx = 0.0; |
| 160 | + } |
| 161 | + Eigen::Vector3d tangent; |
| 162 | + tangent << xx, yx, zx; // Not sure this is the tangent vector... |
| 163 | + |
| 164 | + /*xy = yz * zx - yx * zz; |
| 165 | + yy = zz * xx - zx * xz; |
| 166 | + zy = xz * yx - xx * yz; |
| 167 | + Eigen::Vector3d bitangent << xy, yy, zy; // Not sure this is the bitangent vector...*/ |
| 168 | + Eigen::Vector3d bitangent = normal.cross(tangent); |
| 169 | + |
| 170 | + std::vector<double> theta(nVertices), phi(nVertices), phinumb(nVertices+1); |
| 171 | + std::vector<int> numb(nVertices+1); |
| 172 | + // Clean-up heap crap |
| 173 | + std::fill_n(theta.begin(), nVertices, 0.0); |
| 174 | + std::fill_n(phi.begin(), nVertices, 0.0); |
| 175 | + std::fill_n(numb.begin(), nVertices+1, 0); |
| 176 | + std::fill_n(phinumb.begin(), nVertices+1, 0.0); |
| 177 | + // Calculate a number of angles |
| 178 | + for (int i = 0; i < nVertices; ++i) { |
| 179 | + Eigen::Vector3d vertex_normal = (vertices.col(i) - sph.center()) / sph.radius(); |
| 180 | + double scal1 = vertex_normal.dot(normal); |
| 181 | + if (scal1 >= 1.0) scal1 = 1.0; |
| 182 | + if (scal1 <= -1.0) scal1 = -1.0; |
| 183 | + theta[i] = std::acos(scal1); |
| 184 | + double scal2 = vertex_normal.dot(tangent) / std::sin(theta[i]); |
| 185 | + if (scal2 >= 1.0) scal2 = 1.0; |
| 186 | + if (scal2 <= -1.0) scal2 = -1.0; |
| 187 | + phi[i] = std::acos(scal2); |
| 188 | + double sin_phi = vertex_normal.dot(bitangent) / std::sin(theta[i]); |
| 189 | + if (sin_phi <= 0.0) phi[i] = 2 * M_PI - phi[i]; |
| 190 | + if (i != 0) { |
| 191 | + phi[i] -= phi[0]; |
| 192 | + if (phi[i] < 0.0) phi[i] += 2 * M_PI; |
| 193 | + } |
| 194 | + } |
| 195 | + // Recalculate tangent and bitangent vectors |
| 196 | + tangent *= std::cos(phi[0]); |
| 197 | + tangent += bitangent * std::sin(phi[0]); |
| 198 | + bitangent = normal.cross(tangent); |
| 199 | + |
| 200 | + // Populate numb and phinumb arrays |
| 201 | + phi[0] = 0.0; |
| 202 | + numb[0] = 1; numb[1] = 2; |
| 203 | + phinumb[0] = phi[0]; phinumb[1] = phinumb[1]; |
| 204 | + for (int i = 2; i < nVertices; ++i) { // This loop is 2-based |
| 205 | + for (int j = 1; j < (i - 1); ++j) { // This loop is 1-based |
| 206 | + if (phi[i] < phinumb[j]) { |
| 207 | + for (int k = 0; k < (i - j); ++k) { |
| 208 | + numb[i - k + 1] = numb[i - k]; |
| 209 | + phinumb[i - k + 1] = phinumb[i - k]; |
| 210 | + } |
| 211 | + numb[j] = i; |
| 212 | + phinumb[j] = phi[i]; |
| 213 | + goto jump; // Ugly, to be refactored!!! |
| 214 | + } |
| 215 | + numb[i] = i; |
| 216 | + phinumb[i] = phi[i]; |
| 217 | + } |
| 218 | + jump: |
| 219 | + std::cout << "jumped" << std::endl; |
| 220 | + } |
| 221 | + numb[nVertices] = numb[0]; |
| 222 | + phinumb[nVertices] = 2 * M_PI; |
| 223 | + |
| 224 | + for (int i = 0; i < nVertices; ++i) { // Loop on edges |
| 225 | + double pha = phinumb[i]; |
| 226 | + double phb = phinumb[i+1]; |
| 227 | + double aph = (pha - phb) / 2.0; |
| 228 | + double bph = (pha + phb) / 2.0; |
| 229 | + double tha = theta[numb[i]]; |
| 230 | + double thb = theta[numb[i+1]]; |
| 231 | + double thmax = 0.0; |
| 232 | + Eigen::Vector3d oc = (arcs.col(i) - sph.center()) / sph.radius(); |
| 233 | + double oc_norm = oc.norm(); |
| 234 | + double oc_norm2 = std::pow(oc_norm, 2); |
| 235 | + for (int j = 0; j < 32; ++j) { // Loop on Gaussian points (64-points rule) |
| 236 | + for (int k = 0; k <= 1; ++k) { |
| 237 | + double ph = (2*k - 1) * aph * gauss64Abscissa(j) + bph; |
| 238 | + double cos_ph = std::cos(ph); |
| 239 | + double sin_ph = std::sin(ph); |
| 240 | + if (oc_norm2 < 1.0e-07) { |
| 241 | + double cotg_thmax = std::sin(ph-pha) / std::tan(thb) + std::sin(phb-ph) / std::tan(tha); |
| 242 | + cotg_thmax /= std::sin(phb-pha); |
| 243 | + thmax = std::atan(1.0 / cotg_thmax); |
| 244 | + } else { |
| 245 | + Eigen::Vector3d scratch; |
| 246 | + scratch << tangent.dot(oc), bitangent.dot(oc), normal.dot(oc); |
| 247 | + double aa = std::pow(tangent.dot(oc)*cos_ph + bitangent.dot(oc)*sin_ph, 2) + std::pow(normal.dot(oc), 2); |
| 248 | + double bb = -normal.dot(oc) * oc_norm2; |
| 249 | + double cc = std::pow(oc_norm2, 2) - std::pow(tangent.dot(oc)*cos_ph + bitangent.dot(oc)*sin_ph, 2); |
| 250 | + double ds = std::pow(bb, 2) - aa*cc; |
| 251 | + if (ds < 0.0) ds = 0.0; |
| 252 | + double cs = (-bb + std::sqrt(ds)) / aa; |
| 253 | + if (cs > 1.0) cs = 1.0; |
| 254 | + if (cs < -1.0) cs = 1.0; |
| 255 | + thmax = std::acos(cs); |
| 256 | + } |
| 257 | + double ath = thmax / 2.0; |
| 258 | + |
| 259 | + double S16 = 0.0; |
| 260 | + if (thmax < 1.0e-08) goto jump1; // Ugly, to be refactored!!! |
| 261 | + for (int l = 0; l < 8; ++l) { // Loop on Gaussian points (16-points rule) |
| 262 | + for (int m = 0; m <= 1; ++m) { |
| 263 | + double th = (2*m - 1) * ath * gauss16Abscissa(l) + ath; |
| 264 | + double cos_th = std::cos(th); |
| 265 | + double sin_th = std::sin(th); |
| 266 | + double vx = tangent(0) * sin_th * cos_ph |
| 267 | + + bitangent(0) * sin_th * sin_ph |
| 268 | + + normal(0) * (cos_th - 1.0); |
| 269 | + double vy = tangent(1) * sin_th * cos_ph |
| 270 | + + bitangent(1) * sin_th * sin_ph |
| 271 | + + normal(1) * (cos_th - 1.0); |
| 272 | + double vz = tangent(2) * sin_th * cos_ph |
| 273 | + + bitangent(2) * sin_th * sin_ph |
| 274 | + + normal(2) * (cos_th - 1.0); |
| 275 | + Eigen::Vector3d evaluation; |
| 276 | + evaluation << vx, vy, vz; |
| 277 | + double rth = std::sqrt(2 * (1.0 - cos_th)); |
| 278 | + double rtheps = gf->function(evaluation, Eigen::Vector3d::Zero()); // Evaluate Green's function at Gaussian points |
| 279 | + S16 += sph.radius() * rtheps * sin_th * ath * gauss16Weight(l); |
| 280 | + } |
| 281 | + } |
| 282 | + S64 += S16 * aph * gauss64Weight(j); |
| 283 | + |
| 284 | + jump1: |
| 285 | + std::cout << "jumped!" << std::endl; |
| 286 | + } |
| 287 | + } |
| 288 | + } |
| 289 | + |
| 290 | + Sii = S64 * area; |
| 291 | + |
| 292 | + return Sii; |
120 | 293 | } |
121 | 294 | double NumericalIntegrator::computeS(const AnisotropicLiquid<AD_directional> * gf, const Element & e) const { |
122 | 295 | return 0.0; |
|
0 commit comments