from sympy.physics.vector import dynamicsymbols, Point, ReferenceFrame from sympy.testing.pytest import raises, ignore_warnings import warnings def test_point_v1pt_theorys(): q, q2 = dynamicsymbols('q q2') qd, q2d = dynamicsymbols('q q2', 1) qdd, q2dd = dynamicsymbols('q q2', 2) N = ReferenceFrame('N') B = ReferenceFrame('B') B.set_ang_vel(N, qd * B.z) O = Point('O') P = O.locatenew('P', B.x) P.set_vel(B, 0) O.set_vel(N, 0) assert P.v1pt_theory(O, N, B) == qd * B.y O.set_vel(N, N.x) assert P.v1pt_theory(O, N, B) == N.x + qd * B.y P.set_vel(B, B.z) assert P.v1pt_theory(O, N, B) == B.z + N.x + qd * B.y def test_point_a1pt_theorys(): q, q2 = dynamicsymbols('q q2') qd, q2d = dynamicsymbols('q q2', 1) qdd, q2dd = dynamicsymbols('q q2', 2) N = ReferenceFrame('N') B = ReferenceFrame('B') B.set_ang_vel(N, qd * B.z) O = Point('O') P = O.locatenew('P', B.x) P.set_vel(B, 0) O.set_vel(N, 0) assert P.a1pt_theory(O, N, B) == -(qd**2) * B.x + qdd * B.y P.set_vel(B, q2d * B.z) assert P.a1pt_theory(O, N, B) == -(qd**2) * B.x + qdd * B.y + q2dd * B.z O.set_vel(N, q2d * B.x) assert P.a1pt_theory(O, N, B) == ((q2dd - qd**2) * B.x + (q2d * qd + qdd) * B.y + q2dd * B.z) def test_point_v2pt_theorys(): q = dynamicsymbols('q') qd = dynamicsymbols('q', 1) N = ReferenceFrame('N') B = N.orientnew('B', 'Axis', [q, N.z]) O = Point('O') P = O.locatenew('P', 0) O.set_vel(N, 0) assert P.v2pt_theory(O, N, B) == 0 P = O.locatenew('P', B.x) assert P.v2pt_theory(O, N, B) == (qd * B.z ^ B.x) O.set_vel(N, N.x) assert P.v2pt_theory(O, N, B) == N.x + qd * B.y def test_point_a2pt_theorys(): q = dynamicsymbols('q') qd = dynamicsymbols('q', 1) qdd = dynamicsymbols('q', 2) N = ReferenceFrame('N') B = N.orientnew('B', 'Axis', [q, N.z]) O = Point('O') P = O.locatenew('P', 0) O.set_vel(N, 0) assert P.a2pt_theory(O, N, B) == 0 P.set_pos(O, B.x) assert P.a2pt_theory(O, N, B) == (-qd**2) * B.x + (qdd) * B.y def test_point_funcs(): q, q2 = dynamicsymbols('q q2') qd, q2d = dynamicsymbols('q q2', 1) qdd, q2dd = dynamicsymbols('q q2', 2) N = ReferenceFrame('N') B = ReferenceFrame('B') B.set_ang_vel(N, 5 * B.y) O = Point('O') P = O.locatenew('P', q * B.x + q2 * B.y) assert P.pos_from(O) == q * B.x + q2 * B.y P.set_vel(B, qd * B.x + q2d * B.y) assert P.vel(B) == qd * B.x + q2d * B.y O.set_vel(N, 0) assert O.vel(N) == 0 assert P.a1pt_theory(O, N, B) == ((-25 * q + qdd) * B.x + (q2dd) * B.y + (-10 * qd) * B.z) B = N.orientnew('B', 'Axis', [q, N.z]) O = Point('O') P = O.locatenew('P', 10 * B.x) O.set_vel(N, 5 * N.x) assert O.vel(N) == 5 * N.x assert P.a2pt_theory(O, N, B) == (-10 * qd**2) * B.x + (10 * qdd) * B.y B.set_ang_vel(N, 5 * B.y) O = Point('O') P = O.locatenew('P', q * B.x + q2 * B.y) P.set_vel(B, qd * B.x + q2d * B.y) O.set_vel(N, 0) assert P.v1pt_theory(O, N, B) == qd * B.x + q2d * B.y - 5 * q * B.z def test_point_pos(): q = dynamicsymbols('q') N = ReferenceFrame('N') B = N.orientnew('B', 'Axis', [q, N.z]) O = Point('O') P = O.locatenew('P', 10 * N.x + 5 * B.x) assert P.pos_from(O) == 10 * N.x + 5 * B.x Q = P.locatenew('Q', 10 * N.y + 5 * B.y) assert Q.pos_from(P) == 10 * N.y + 5 * B.y assert Q.pos_from(O) == 10 * N.x + 10 * N.y + 5 * B.x + 5 * B.y assert O.pos_from(Q) == -10 * N.x - 10 * N.y - 5 * B.x - 5 * B.y def test_point_partial_velocity(): N = ReferenceFrame('N') A = ReferenceFrame('A') p = Point('p') u1, u2 = dynamicsymbols('u1, u2') p.set_vel(N, u1 * A.x + u2 * N.y) assert p.partial_velocity(N, u1) == A.x assert p.partial_velocity(N, u1, u2) == (A.x, N.y) raises(ValueError, lambda: p.partial_velocity(A, u1)) def test_point_vel(): #Basic functionality q1, q2 = dynamicsymbols('q1 q2') N = ReferenceFrame('N') B = ReferenceFrame('B') Q = Point('Q') O = Point('O') Q.set_pos(O, q1 * N.x) raises(ValueError , lambda: Q.vel(N)) # Velocity of O in N is not defined O.set_vel(N, q2 * N.y) assert O.vel(N) == q2 * N.y raises(ValueError , lambda : O.vel(B)) #Velocity of O is not defined in B def test_auto_point_vel(): t = dynamicsymbols._t q1, q2 = dynamicsymbols('q1 q2') N = ReferenceFrame('N') B = ReferenceFrame('B') O = Point('O') Q = Point('Q') Q.set_pos(O, q1 * N.x) O.set_vel(N, q2 * N.y) assert Q.vel(N) == q1.diff(t) * N.x + q2 * N.y # Velocity of Q using O P1 = Point('P1') P1.set_pos(O, q1 * B.x) P2 = Point('P2') P2.set_pos(P1, q2 * B.z) raises(ValueError, lambda : P2.vel(B)) # O's velocity is defined in different frame, and no #point in between has its velocity defined raises(ValueError, lambda: P2.vel(N)) # Velocity of O not defined in N def test_auto_point_vel_multiple_point_path(): t = dynamicsymbols._t q1, q2 = dynamicsymbols('q1 q2') B = ReferenceFrame('B') P = Point('P') P.set_vel(B, q1 * B.x) P1 = Point('P1') P1.set_pos(P, q2 * B.y) P1.set_vel(B, q1 * B.z) P2 = Point('P2') P2.set_pos(P1, q1 * B.z) P3 = Point('P3') P3.set_pos(P2, 10 * q1 * B.y) assert P3.vel(B) == 10 * q1.diff(t) * B.y + (q1 + q1.diff(t)) * B.z def test_auto_vel_dont_overwrite(): t = dynamicsymbols._t q1, q2, u1 = dynamicsymbols('q1, q2, u1') N = ReferenceFrame('N') P = Point('P1') P.set_vel(N, u1 * N.x) P1 = Point('P1') P1.set_pos(P, q2 * N.y) assert P1.vel(N) == q2.diff(t) * N.y + u1 * N.x assert P.vel(N) == u1 * N.x P1.set_vel(N, u1 * N.z) assert P1.vel(N) == u1 * N.z def test_auto_point_vel_if_tree_has_vel_but_inappropriate_pos_vector(): q1, q2 = dynamicsymbols('q1 q2') B = ReferenceFrame('B') S = ReferenceFrame('S') P = Point('P') P.set_vel(B, q1 * B.x) P1 = Point('P1') P1.set_pos(P, S.y) raises(ValueError, lambda : P1.vel(B)) # P1.pos_from(P) can't be expressed in B raises(ValueError, lambda : P1.vel(S)) # P.vel(S) not defined def test_auto_point_vel_shortest_path(): t = dynamicsymbols._t q1, q2, u1, u2 = dynamicsymbols('q1 q2 u1 u2') B = ReferenceFrame('B') P = Point('P') P.set_vel(B, u1 * B.x) P1 = Point('P1') P1.set_pos(P, q2 * B.y) P1.set_vel(B, q1 * B.z) P2 = Point('P2') P2.set_pos(P1, q1 * B.z) P3 = Point('P3') P3.set_pos(P2, 10 * q1 * B.y) P4 = Point('P4') P4.set_pos(P3, q1 * B.x) O = Point('O') O.set_vel(B, u2 * B.y) O1 = Point('O1') O1.set_pos(O, q2 * B.z) P4.set_pos(O1, q1 * B.x + q2 * B.z) with warnings.catch_warnings(): #There are two possible paths in this point tree, thus a warning is raised warnings.simplefilter('error') with ignore_warnings(UserWarning): assert P4.vel(B) == q1.diff(t) * B.x + u2 * B.y + 2 * q2.diff(t) * B.z def test_auto_point_vel_connected_frames(): t = dynamicsymbols._t q, q1, q2, u = dynamicsymbols('q q1 q2 u') N = ReferenceFrame('N') B = ReferenceFrame('B') O = Point('O') O.set_vel(N, u * N.x) P = Point('P') P.set_pos(O, q1 * N.x + q2 * B.y) raises(ValueError, lambda: P.vel(N)) N.orient(B, 'Axis', (q, B.x)) assert P.vel(N) == (u + q1.diff(t)) * N.x + q2.diff(t) * B.y - q2 * q.diff(t) * B.z def test_auto_point_vel_multiple_paths_warning_arises(): q, u = dynamicsymbols('q u') N = ReferenceFrame('N') O = Point('O') P = Point('P') Q = Point('Q') R = Point('R') P.set_vel(N, u * N.x) Q.set_vel(N, u *N.y) R.set_vel(N, u * N.z) O.set_pos(P, q * N.z) O.set_pos(Q, q * N.y) O.set_pos(R, q * N.x) with warnings.catch_warnings(): #There are two possible paths in this point tree, thus a warning is raised warnings.simplefilter("error") raises(UserWarning ,lambda: O.vel(N)) def test_auto_vel_cyclic_warning_arises(): P = Point('P') P1 = Point('P1') P2 = Point('P2') P3 = Point('P3') N = ReferenceFrame('N') P.set_vel(N, N.x) P1.set_pos(P, N.x) P2.set_pos(P1, N.y) P3.set_pos(P2, N.z) P1.set_pos(P3, N.x + N.y) with warnings.catch_warnings(): #The path is cyclic at P1, thus a warning is raised warnings.simplefilter("error") raises(UserWarning ,lambda: P2.vel(N)) def test_auto_vel_cyclic_warning_msg(): P = Point('P') P1 = Point('P1') P2 = Point('P2') P3 = Point('P3') N = ReferenceFrame('N') P.set_vel(N, N.x) P1.set_pos(P, N.x) P2.set_pos(P1, N.y) P3.set_pos(P2, N.z) P1.set_pos(P3, N.x + N.y) with warnings.catch_warnings(record = True) as w: #The path is cyclic at P1, thus a warning is raised warnings.simplefilter("always") P2.vel(N) msg = str(w[-1].message).replace("\n", " ") assert issubclass(w[-1].category, UserWarning) assert 'Kinematic loops are defined among the positions of points. This is likely not desired and may cause errors in your calculations.' in msg def test_auto_vel_multiple_path_warning_msg(): N = ReferenceFrame('N') O = Point('O') P = Point('P') Q = Point('Q') P.set_vel(N, N.x) Q.set_vel(N, N.y) O.set_pos(P, N.z) O.set_pos(Q, N.y) with warnings.catch_warnings(record = True) as w: #There are two possible paths in this point tree, thus a warning is raised warnings.simplefilter("always") O.vel(N) msg = str(w[-1].message).replace("\n", " ") assert issubclass(w[-1].category, UserWarning) assert 'Velocity' in msg assert 'automatically calculated based on point' in msg assert 'Velocities from these points are not necessarily the same. This may cause errors in your calculations.' in msg def test_auto_vel_derivative(): q1, q2 = dynamicsymbols('q1:3') u1, u2 = dynamicsymbols('u1:3', 1) A = ReferenceFrame('A') B = ReferenceFrame('B') C = ReferenceFrame('C') B.orient_axis(A, A.z, q1) B.set_ang_vel(A, u1 * A.z) C.orient_axis(B, B.z, q2) C.set_ang_vel(B, u2 * B.z) Am = Point('Am') Am.set_vel(A, 0) Bm = Point('Bm') Bm.set_pos(Am, B.x) Bm.set_vel(B, 0) Bm.set_vel(C, 0) Cm = Point('Cm') Cm.set_pos(Bm, C.x) Cm.set_vel(C, 0) temp = Cm._vel_dict.copy() assert Cm.vel(A) == (u1 * B.y + (u1 + u2) * C.y) Cm._vel_dict = temp Cm.v2pt_theory(Bm, B, C) assert Cm.vel(A) == (u1 * B.y + (u1 + u2) * C.y) def test_auto_point_acc_zero_vel(): N = ReferenceFrame('N') O = Point('O') O.set_vel(N, 0) assert O.acc(N) == 0 * N.x def test_auto_point_acc_compute_vel(): t = dynamicsymbols._t q1 = dynamicsymbols('q1') N = ReferenceFrame('N') A = ReferenceFrame('A') A.orient_axis(N, N.z, q1) O = Point('O') O.set_vel(N, 0) P = Point('P') P.set_pos(O, A.x) assert P.acc(N) == -q1.diff(t) ** 2 * A.x + q1.diff(t, 2) * A.y def test_auto_acc_derivative(): # Tests whether the Point.acc method gives the correct acceleration of the # end point of two linkages in series, while getting minimal information. q1, q2 = dynamicsymbols('q1:3') u1, u2 = dynamicsymbols('q1:3', 1) v1, v2 = dynamicsymbols('q1:3', 2) A = ReferenceFrame('A') B = ReferenceFrame('B') C = ReferenceFrame('C') B.orient_axis(A, A.z, q1) C.orient_axis(B, B.z, q2) Am = Point('Am') Am.set_vel(A, 0) Bm = Point('Bm') Bm.set_pos(Am, B.x) Bm.set_vel(B, 0) Bm.set_vel(C, 0) Cm = Point('Cm') Cm.set_pos(Bm, C.x) Cm.set_vel(C, 0) # Copy dictionaries to later check the calculation using the 2pt_theories Bm_vel_dict, Cm_vel_dict = Bm._vel_dict.copy(), Cm._vel_dict.copy() Bm_acc_dict, Cm_acc_dict = Bm._acc_dict.copy(), Cm._acc_dict.copy() check = -u1 ** 2 * B.x + v1 * B.y - (u1 + u2) ** 2 * C.x + (v1 + v2) * C.y assert Cm.acc(A) == check Bm._vel_dict, Cm._vel_dict = Bm_vel_dict, Cm_vel_dict Bm._acc_dict, Cm._acc_dict = Bm_acc_dict, Cm_acc_dict Bm.v2pt_theory(Am, A, B) Cm.v2pt_theory(Bm, A, C) Bm.a2pt_theory(Am, A, B) assert Cm.a2pt_theory(Bm, A, C) == check