def project(u, v): """Projects vector u onto vector v.""" u = matrix_to_vector(Matrix(u), C) v = matrix_to_vector(Matrix(v), C) m_v = v.magnitude() scal = u.dot(v) / m_v pprint(scal) return scal * (v / m_v)
def scipy_one_cell(points, nodes): degree = len(nodes) - 1 x, y, z = sp.symbols("x y z") a = [sp.Symbol("a{0:d}".format(i)) for i in range(degree + 1)] # Find polynomial for variation in z-direction poly = 0 for deg in range(degree + 1): poly += a[deg] * y**deg eqs = [] for node in nodes: eqs.append(poly.subs(y, points[node][-2]) - points[node][-1]) coeffs = sp.solve(eqs, a) transform = poly for i in range(len(a)): transform = transform.subs(a[i], coeffs[a[i]]) # Compute integral C = CoordSys3D("C") para = sp.Matrix([x, y, transform]) vec = matrix_to_vector(para, C) cross = (vec.diff(x) ^ vec.diff(y)).magnitude() expr = (transform + x * y) * cross approx = sp.lambdify((x, y), expr) ref = scipy.integrate.dblquad(approx, 0, 1, lambda x: 0, lambda x: 1 - x)[0] return ref
def test_SphericallySymmetricVolCondMEG_04(self): '''dipole time series''' # define symbols N = sv.CoordSys3D('') Q_x, Q_y, Q_z = sp.symbols('Q_x Q_y Q_z', real=True) R_x, R_y, R_z = sp.symbols('R_x R_y R_z', real=True) r_x, r_y, r_z = sp.symbols('r_x r_y r_z', real=True) Q = sv.matrix_to_vector(sp.Matrix([Q_x, Q_y, Q_z]), N) # dipole moment R = sv.matrix_to_vector(sp.Matrix([R_x, R_y, R_z]), N) # dipole loc. r = sv.matrix_to_vector(sp.Matrix([r_x, r_y, r_z]), N) # meas. loc. # eq. 25 in Sarvas et al. 1987: a = r - R a_ = sp.sqrt(a.dot(a)) r_ = sp.sqrt(r.dot(r)) F = a_ * (r_ * a_ + r_**2 - R.dot(r)) nabla_F = (a_**2 / r_ + a.dot(r) / a_ + 2 * a_ + 2 * r_ ) * r - (a_ + 2 * r_ + a.dot(r) / a_) * R H = (F * Q.cross(R) - Q.cross(R).dot(r) * nabla_F) / (4 * sp.pi * F**2) # check some values p = np.c_[np.eye(3), -np.eye(3)] r_p = np.array([0.1, -0.2, 0.9]) r_s = np.array([-0.3, 0.1, 1.3]) H_gt = np.zeros((1, 3, 6)) for i, p_ in enumerate(p.T): H_gt[0, :, i] = np.array(H.evalf(subs={ Q_x: p_[0], Q_y: p_[1], Q_z: p_[2], R_x: r_p[0], R_y: r_p[1], R_z: r_p[2], r_x: r_s[0], r_y: r_s[1], r_z: r_s[2], }).to_matrix(N).tolist()).flatten() meg = lfpykit.eegmegcalc.SphericallySymmetricVolCondMEG( r=np.array([r_s])) M = meg.get_transformation_matrix(r_p) np.testing.assert_almost_equal(M @ p, H_gt)
def sympy_scipy(points, nodes, L, H): """Approximated integration of z + x*y over a surface where the z-coordinate is only dependent of the y-component of the box. x in [0,L], y in [0,H] Input: points: All points of defining the geometry nodes: Points on one of the outer boundaries varying in the y-direction """ degree = len(nodes) - 1 x, y, z = sp.symbols("x y z") a = [sp.Symbol("a{0:d}".format(i)) for i in range(degree + 1)] # Find polynomial for variation in z-direction poly = 0 for deg in range(degree + 1): poly += a[deg] * y**deg eqs = [] for node in nodes: eqs.append(poly.subs(y, points[node][-2]) - points[node][-1]) coeffs = sp.solve(eqs, a) transform = poly for i in range(len(a)): transform = transform.subs(a[i], coeffs[a[i]]) # Compute integral C = CoordSys3D("C") para = sp.Matrix([x, y, transform]) vec = matrix_to_vector(para, C) cross = (vec.diff(x) ^ vec.diff(y)).magnitude() expr = (transform + x * y) * cross approx = sp.lambdify((x, y), expr) ref = scipy.integrate.nquad(approx, [[0, L], [0, H]])[0] # Slow and only works for simple integrals # integral = sp.integrate(expr, (y, 0, H)) # integral = sp.integrate(integral, (x, 0, L)) # ex = integral.evalf() return ref
def unit(v): v = matrix_to_vector(Matrix(v), C) return v.normalize()
def magnitude(v): v = matrix_to_vector(Matrix(v), C) return v.magnitude()
def cross(u, v): u = matrix_to_vector(Matrix(u), C) v = matrix_to_vector(Matrix(v), C) return u.cross(v)
def test_SphericallySymmetricVolCondMEG_03(self): '''compare with (slow) sympy predictions''' # define symbols N = sv.CoordSys3D('') Q_x, Q_y, Q_z = sp.symbols('Q_x Q_y Q_z', real=True) R_x, R_y, R_z = sp.symbols('R_x R_y R_z', real=True) r_x, r_y, r_z = sp.symbols('r_x r_y r_z', real=True) Q = sv.matrix_to_vector(sp.Matrix([Q_x, Q_y, Q_z]), N) # dipole moment R = sv.matrix_to_vector(sp.Matrix([R_x, R_y, R_z]), N) # dipole loc. r = sv.matrix_to_vector(sp.Matrix([r_x, r_y, r_z]), N) # meas. loc. # eq. 25 in Sarvas et al. 1987: a = r - R a_ = sp.sqrt(a.dot(a)) r_ = sp.sqrt(r.dot(r)) F = a_ * (r_ * a_ + r_**2 - R.dot(r)) nabla_F = (a_**2 / r_ + a.dot(r) / a_ + 2 * a_ + 2 * r_ ) * r - (a_ + 2 * r_ + a.dot(r) / a_) * R H = (F * Q.cross(R) - Q.cross(R).dot(r) * nabla_F) / (4 * sp.pi * F**2) # compare sympy pred with our implementation w. different dipole # moments in different measurement and dipole locations for p_ in np.expand_dims(np.c_[np.eye(3), [0.5, -1.7, 0.74]].T, 2): for r_p in np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1], [0.5, 0.65, 0.9]]): for r_s in np.array([[2, 0, 0], [0, 2, 0], [0, 0, 2], [0.95, -1.2, 0.75]]): F_gt = float(F.subs({ R_x: r_p[0], R_y: r_p[1], R_z: r_p[2], r_x: r_s[0], r_y: r_s[1], r_z: r_s[2], })) nabla_F_gt = np.array(nabla_F.evalf(subs={ R_x: r_p[0], R_y: r_p[1], R_z: r_p[2], r_x: r_s[0], r_y: r_s[1], r_z: r_s[2], }).to_matrix(N).tolist()).flatten() H_gt = np.expand_dims(H.evalf(subs={ Q_x: p_[0, 0], Q_y: p_[1, 0], Q_z: p_[2, 0], R_x: r_p[0], R_y: r_p[1], R_z: r_p[2], r_x: r_s[0], r_y: r_s[1], r_z: r_s[2], }).to_matrix(N).tolist(), 0) meg = lfpykit.eegmegcalc.SphericallySymmetricVolCondMEG( r=np.array([r_s])) np.testing.assert_almost_equal( F_gt, meg._compute_F(r_p, r_s, np.linalg.norm(r_s - r_p), np.linalg.norm(r_s))) np.testing.assert_almost_equal( nabla_F_gt, meg._compute_grad_F(r_p, r_s, r_s - r_p, np.linalg.norm(r_s - r_p), np.linalg.norm(r_s))) np.testing.assert_almost_equal( H_gt, meg.calculate_H(p_, r_p) )
def convert(vec): C = CoordSys3D('') return matrix_to_vector(parse_matrix(vec), C)