// triangle-winding-number second-order approximation // t is triangle, p is 'center' of cluster of dipoles, q is evaluation point // (This is really just for testing) public static double Order2Approx(ref Triangle3d t, ref Vector3d p, ref Vector3d xn, ref double xA, ref Vector3d q) { Vector3d dpq = (p - q); double len = dpq.Length; double len3 = len * len * len; // first-order approximation - integrated_normal_area * \grad(G) double order1 = (xA / MathUtil.FourPI) * xn.Dot(dpq / len3); // second-order hessian \grad^2(G) Matrix3d xqxq = new Matrix3d(ref dpq, ref dpq); xqxq *= 3.0 / (MathUtil.FourPI * len3 * len * len); double diag = 1 / (MathUtil.FourPI * len3); Matrix3d hessian = new Matrix3d(diag, diag, diag) - xqxq; // second-order LHS - integrated second-order area matrix (formula 26) Vector3d centroid = new Vector3d( (t.V0.x + t.V1.x + t.V2.x) / 3.0, (t.V0.y + t.V1.y + t.V2.y) / 3.0, (t.V0.z + t.V1.z + t.V2.z) / 3.0); Vector3d dcp = centroid - p; Matrix3d o2_lhs = new Matrix3d(ref dcp, ref xn); double order2 = xA * o2_lhs.InnerProduct(ref hessian); return(order1 + order2); }
/// <summary> /// Evaluate second-order FWN approximation at point q, relative to center c /// </summary> public static double EvaluateOrder2Approx(ref Vector3d center, ref Vector3d order1Coeff, ref Matrix3d order2Coeff, ref Vector3d q) { Vector3d dpq = (center - q); double len = dpq.Length; double len3 = len * len * len; double fourPi_len3 = 1.0 / (MathUtil.FourPI * len3); double order1 = fourPi_len3 * order1Coeff.Dot(ref dpq); // second-order hessian \grad^2(G) double c = -3.0 / (MathUtil.FourPI * len3 * len * len); // expanded-out version below avoids extra constructors //Matrix3d xqxq = new Matrix3d(ref dpq, ref dpq); //Matrix3d hessian = new Matrix3d(fourPi_len3, fourPi_len3, fourPi_len3) - c * xqxq; Matrix3d hessian = new Matrix3d( fourPi_len3 + c * dpq.x * dpq.x, c * dpq.x * dpq.y, c * dpq.x * dpq.z, c * dpq.y * dpq.x, fourPi_len3 + c * dpq.y * dpq.y, c * dpq.y * dpq.z, c * dpq.z * dpq.x, c * dpq.z * dpq.y, fourPi_len3 + c * dpq.z * dpq.z); double order2 = order2Coeff.InnerProduct(ref hessian); return(order1 + order2); }
// point-winding-number second-order approximation // x is dipole point, p is 'center' of cluster of dipoles, q is evaluation point public static double Order2Approx(ref Vector3d x, ref Vector3d p, ref Vector3d xn, double xA, ref Vector3d q) { Vector3d dpq = (p - q); Vector3d dxp = (x - p); double len = dpq.Length; double len3 = len * len * len; // first-order approximation - area*normal*\grad(G) double order1 = (xA / MathUtil.FourPI) * xn.Dot(dpq / len3); // second-order hessian \grad^2(G) Matrix3d xqxq = new Matrix3d(ref dpq, ref dpq); xqxq *= 3.0 / (MathUtil.FourPI * len3 * len * len); double diag = 1 / (MathUtil.FourPI * len3); Matrix3d hessian = new Matrix3d(diag, diag, diag) - xqxq; // second-order LHS area * \outer(x-p, normal) Matrix3d o2_lhs = new Matrix3d(ref dxp, ref xn); double order2 = xA * o2_lhs.InnerProduct(ref hessian); return(order1 + order2); }