def test_apply_force(): f, g = symbols('f g') q, x, v1, v2 = dynamicsymbols('q x v1 v2') P1 = Point('P1') P2 = Point('P2') B1 = Body('B1') B2 = Body('B2') N = ReferenceFrame('N') P1.set_vel(B1.frame, v1 * B1.x) P2.set_vel(B2.frame, v2 * B2.x) force = f * q * N.z # time varying force B1.apply_force(force, P1, B2, P2) #applying equal and opposite force on moving points assert B1.loads == [(P1, force)] assert B2.loads == [(P2, -force)] g1 = B1.mass * g * N.y g2 = B2.mass * g * N.y B1.apply_force(g1) #applying gravity on B1 masscenter B2.apply_force(g2) #applying gravity on B2 masscenter assert B1.loads == [(P1, force), (B1.masscenter, g1)] assert B2.loads == [(P2, -force), (B2.masscenter, g2)] force2 = x * N.x B1.apply_force( force2, reaction_body=B2) #Applying time varying force on masscenter assert B1.loads == [(P1, force), (B1.masscenter, force2 + g1)] assert B2.loads == [(P2, -force), (B2.masscenter, -force2 + g2)]
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_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) assert P.pos_from(O) == q * B.x 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) 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_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) assert P.pos_from(O) == q * B.x 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) 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_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_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_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_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_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_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_remove_load(): P1 = Point('P1') P2 = Point('P2') B = Body('B') f1 = B.x f2 = B.y B.apply_force(f1, P1) B.apply_force(f2, P2) B.loads == [(P1, f1), (P2, f2)] B.remove_load(P2) B.loads == [(P1, f1)] B.apply_torque(f1.cross(f2)) B.loads == [(P1, f1), (B.frame, f1.cross(f2))] B.remove_load() B.loads == [(P1, f1)]
def test_scalar_potential_difference(): origin = Point("O") point1 = origin.locatenew("P1", 1 * R.x + 2 * R.y + 3 * R.z) point2 = origin.locatenew("P2", 4 * R.x + 5 * R.y + 6 * R.z) genericpointR = origin.locatenew("RP", R[0] * R.x + R[1] * R.y + R[2] * R.z) genericpointP = origin.locatenew("PP", P[0] * P.x + P[1] * P.y + P[2] * P.z) assert scalar_potential_difference(S.Zero, R, point1, point2, origin) == 0 assert (scalar_potential_difference(scalar_field, R, origin, genericpointR, origin) == scalar_field) assert (scalar_potential_difference(grad_field, R, origin, genericpointR, origin) == scalar_field) assert scalar_potential_difference(grad_field, R, point1, point2, origin) == 948 assert (scalar_potential_difference( R[1] * R[2] * R.x + R[0] * R[2] * R.y + R[0] * R[1] * R.z, R, point1, genericpointR, origin, ) == R[0] * R[1] * R[2] - 6) potential_diff_P = (2 * P[2] * (P[0] * sin(q) + P[1] * cos(q)) * (P[0] * cos(q) - P[1] * sin(q))**2) assert (scalar_potential_difference(grad_field, P, origin, genericpointP, origin).simplify() == potential_diff_P)
def test_partial_velocity(): q1, q2, q3, u1, u2, u3 = dynamicsymbols("q1 q2 q3 u1 u2 u3") u4, u5 = dynamicsymbols("u4, u5") r = symbols("r") N = ReferenceFrame("N") Y = N.orientnew("Y", "Axis", [q1, N.z]) L = Y.orientnew("L", "Axis", [q2, Y.x]) R = L.orientnew("R", "Axis", [q3, L.y]) R.set_ang_vel(N, u1 * L.x + u2 * L.y + u3 * L.z) C = Point("C") C.set_vel(N, u4 * L.x + u5 * (Y.z ^ L.x)) Dmc = C.locatenew("Dmc", r * L.z) Dmc.v2pt_theory(C, N, R) vel_list = [Dmc.vel(N), C.vel(N), R.ang_vel_in(N)] u_list = [u1, u2, u3, u4, u5] assert partial_velocity(vel_list, u_list, N) == [ [-r * L.y, r * L.x, 0, L.x, cos(q2) * L.y - sin(q2) * L.z], [0, 0, 0, L.x, cos(q2) * L.y - sin(q2) * L.z], [L.x, L.y, L.z, 0, 0], ] # Make sure that partial velocities can be computed regardless if the # orientation between frames is defined or not. A = ReferenceFrame("A") B = ReferenceFrame("B") v = u4 * A.x + u5 * B.y assert partial_velocity((v, ), (u4, u5), A) == [[A.x, B.y]] raises(TypeError, lambda: partial_velocity(Dmc.vel(N), u_list, N)) raises(TypeError, lambda: partial_velocity(vel_list, u1, N))
def test_body_add_force(): # Body with RigidBody. rigidbody_masscenter = Point('rigidbody_masscenter') rigidbody_mass = Symbol('rigidbody_mass') rigidbody_frame = ReferenceFrame('rigidbody_frame') body_inertia = inertia(rigidbody_frame, 1, 0, 0) rigid_body = Body('rigidbody_body', rigidbody_masscenter, rigidbody_mass, rigidbody_frame, body_inertia) l = Symbol('l') Fa = Symbol('Fa') point = rigid_body.masscenter.locatenew('rigidbody_body_point0', l * rigid_body.frame.x) point.set_vel(rigid_body.frame, 0) force_vector = Fa * rigid_body.frame.z # apply_force with point rigid_body.apply_force(force_vector, point) assert len(rigid_body.loads) == 1 force_point = rigid_body.loads[0][0] frame = rigid_body.frame assert force_point.vel(frame) == point.vel(frame) assert force_point.pos_from(force_point) == point.pos_from(force_point) assert rigid_body.loads[0][1] == force_vector # apply_force without point rigid_body.apply_force(force_vector) assert len(rigid_body.loads) == 2 assert rigid_body.loads[1][1] == force_vector # passing something else than point raises(TypeError, lambda: rigid_body.apply_force(force_vector, 0)) raises(TypeError, lambda: rigid_body.apply_force(0))
def test_custom_rigid_body(): # Body with RigidBody. rigidbody_masscenter = Point("rigidbody_masscenter") rigidbody_mass = Symbol("rigidbody_mass") rigidbody_frame = ReferenceFrame("rigidbody_frame") body_inertia = inertia(rigidbody_frame, 1, 0, 0) rigid_body = Body( "rigidbody_body", rigidbody_masscenter, rigidbody_mass, rigidbody_frame, body_inertia, ) com = rigid_body.masscenter frame = rigid_body.frame rigidbody_masscenter.set_vel(rigidbody_frame, 0) assert com.vel(frame) == rigidbody_masscenter.vel(frame) assert com.pos_from(com) == rigidbody_masscenter.pos_from(com) assert rigid_body.mass == rigidbody_mass assert rigid_body.inertia == (body_inertia, rigidbody_masscenter) assert hasattr(rigid_body, "masscenter") assert hasattr(rigid_body, "mass") assert hasattr(rigid_body, "frame") assert hasattr(rigid_body, "inertia")
def test_partial_velocity(): q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3') u4, u5 = dynamicsymbols('u4, u5') r = symbols('r') N = ReferenceFrame('N') Y = N.orientnew('Y', 'Axis', [q1, N.z]) L = Y.orientnew('L', 'Axis', [q2, Y.x]) R = L.orientnew('R', 'Axis', [q3, L.y]) R.set_ang_vel(N, u1 * L.x + u2 * L.y + u3 * L.z) C = Point('C') C.set_vel(N, u4 * L.x + u5 * (Y.z ^ L.x)) Dmc = C.locatenew('Dmc', r * L.z) Dmc.v2pt_theory(C, N, R) vel_list = [Dmc.vel(N), C.vel(N), R.ang_vel_in(N)] u_list = [u1, u2, u3, u4, u5] assert (partial_velocity(vel_list, u_list, N) == [[ -r * L.y, r * L.x, 0, L.x, cos(q2) * L.y - sin(q2) * L.z ], [0, 0, 0, L.x, cos(q2) * L.y - sin(q2) * L.z], [L.x, L.y, L.z, 0, 0]]) # Make sure that partial velocities can be computed regardless if the # orientation between frames is defined or not. A = ReferenceFrame('A') B = ReferenceFrame('B') v = u4 * A.x + u5 * B.y assert partial_velocity((v, ), (u4, u5), A) == [[A.x, B.y]] raises(TypeError, lambda: partial_velocity(Dmc.vel(N), u_list, N)) raises(TypeError, lambda: partial_velocity(vel_list, u1, N))
def test_scalar_potential_difference(): origin = Point('O') point1 = origin.locatenew('P1', 1*R.x + 2*R.y + 3*R.z) point2 = origin.locatenew('P2', 4*R.x + 5*R.y + 6*R.z) genericpointR = origin.locatenew('RP', R[0]*R.x + R[1]*R.y + R[2]*R.z) genericpointP = origin.locatenew('PP', P[0]*P.x + P[1]*P.y + P[2]*P.z) assert scalar_potential_difference(S(0), R, point1, point2, \ origin) == 0 assert scalar_potential_difference(scalar_field, R, origin, \ genericpointR, origin) == \ scalar_field assert scalar_potential_difference(grad_field, R, origin, \ genericpointR, origin) == \ scalar_field assert scalar_potential_difference(grad_field, R, point1, point2, origin) == 948 assert scalar_potential_difference(R[1]*R[2]*R.x + R[0]*R[2]*R.y + \ R[0]*R[1]*R.z, R, point1, genericpointR, origin) == \ R[0]*R[1]*R[2] - 6 potential_diff_P = 2*P[2]*(P[0]*sin(q) + P[1]*cos(q))*\ (P[0]*cos(q) - P[1]*sin(q))**2 assert scalar_potential_difference(grad_field, P, origin, \ genericpointP, \ origin).simplify() == \ potential_diff_P
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_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(): 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_clear_load(): a = symbols('a') P = Point('P') B = Body('B') force = a * B.z B.apply_force(force, P) assert B.loads == [(P, force)] B.clear_loads() assert B.loads == []
def test_apply_force_multiple_one_point(): a, b = symbols('a b') P = Point('P') B = Body('B') f1 = a * B.x f2 = b * B.y B.apply_force(f1, P) assert B.loads == [(P, f1)] B.apply_force(f2, P) assert B.loads == [(P, f1 + f2)]
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) 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 str( w[-1].message)
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) assert issubclass(w[-1].category, UserWarning) assert 'Velocity automatically calculated based on point' in str( w[-1].message) assert 'Velocities from these points are not necessarily the same. This may cause errors in your calculations.' in str( w[-1].message)
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_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_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_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_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_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