test_point.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. from sympy.physics.vector import dynamicsymbols, Point, ReferenceFrame
  2. from sympy.testing.pytest import raises, ignore_warnings
  3. import warnings
  4. def test_point_v1pt_theorys():
  5. q, q2 = dynamicsymbols('q q2')
  6. qd, q2d = dynamicsymbols('q q2', 1)
  7. qdd, q2dd = dynamicsymbols('q q2', 2)
  8. N = ReferenceFrame('N')
  9. B = ReferenceFrame('B')
  10. B.set_ang_vel(N, qd * B.z)
  11. O = Point('O')
  12. P = O.locatenew('P', B.x)
  13. P.set_vel(B, 0)
  14. O.set_vel(N, 0)
  15. assert P.v1pt_theory(O, N, B) == qd * B.y
  16. O.set_vel(N, N.x)
  17. assert P.v1pt_theory(O, N, B) == N.x + qd * B.y
  18. P.set_vel(B, B.z)
  19. assert P.v1pt_theory(O, N, B) == B.z + N.x + qd * B.y
  20. def test_point_a1pt_theorys():
  21. q, q2 = dynamicsymbols('q q2')
  22. qd, q2d = dynamicsymbols('q q2', 1)
  23. qdd, q2dd = dynamicsymbols('q q2', 2)
  24. N = ReferenceFrame('N')
  25. B = ReferenceFrame('B')
  26. B.set_ang_vel(N, qd * B.z)
  27. O = Point('O')
  28. P = O.locatenew('P', B.x)
  29. P.set_vel(B, 0)
  30. O.set_vel(N, 0)
  31. assert P.a1pt_theory(O, N, B) == -(qd**2) * B.x + qdd * B.y
  32. P.set_vel(B, q2d * B.z)
  33. assert P.a1pt_theory(O, N, B) == -(qd**2) * B.x + qdd * B.y + q2dd * B.z
  34. O.set_vel(N, q2d * B.x)
  35. assert P.a1pt_theory(O, N, B) == ((q2dd - qd**2) * B.x + (q2d * qd + qdd) * B.y +
  36. q2dd * B.z)
  37. def test_point_v2pt_theorys():
  38. q = dynamicsymbols('q')
  39. qd = dynamicsymbols('q', 1)
  40. N = ReferenceFrame('N')
  41. B = N.orientnew('B', 'Axis', [q, N.z])
  42. O = Point('O')
  43. P = O.locatenew('P', 0)
  44. O.set_vel(N, 0)
  45. assert P.v2pt_theory(O, N, B) == 0
  46. P = O.locatenew('P', B.x)
  47. assert P.v2pt_theory(O, N, B) == (qd * B.z ^ B.x)
  48. O.set_vel(N, N.x)
  49. assert P.v2pt_theory(O, N, B) == N.x + qd * B.y
  50. def test_point_a2pt_theorys():
  51. q = dynamicsymbols('q')
  52. qd = dynamicsymbols('q', 1)
  53. qdd = dynamicsymbols('q', 2)
  54. N = ReferenceFrame('N')
  55. B = N.orientnew('B', 'Axis', [q, N.z])
  56. O = Point('O')
  57. P = O.locatenew('P', 0)
  58. O.set_vel(N, 0)
  59. assert P.a2pt_theory(O, N, B) == 0
  60. P.set_pos(O, B.x)
  61. assert P.a2pt_theory(O, N, B) == (-qd**2) * B.x + (qdd) * B.y
  62. def test_point_funcs():
  63. q, q2 = dynamicsymbols('q q2')
  64. qd, q2d = dynamicsymbols('q q2', 1)
  65. qdd, q2dd = dynamicsymbols('q q2', 2)
  66. N = ReferenceFrame('N')
  67. B = ReferenceFrame('B')
  68. B.set_ang_vel(N, 5 * B.y)
  69. O = Point('O')
  70. P = O.locatenew('P', q * B.x)
  71. assert P.pos_from(O) == q * B.x
  72. P.set_vel(B, qd * B.x + q2d * B.y)
  73. assert P.vel(B) == qd * B.x + q2d * B.y
  74. O.set_vel(N, 0)
  75. assert O.vel(N) == 0
  76. assert P.a1pt_theory(O, N, B) == ((-25 * q + qdd) * B.x + (q2dd) * B.y +
  77. (-10 * qd) * B.z)
  78. B = N.orientnew('B', 'Axis', [q, N.z])
  79. O = Point('O')
  80. P = O.locatenew('P', 10 * B.x)
  81. O.set_vel(N, 5 * N.x)
  82. assert O.vel(N) == 5 * N.x
  83. assert P.a2pt_theory(O, N, B) == (-10 * qd**2) * B.x + (10 * qdd) * B.y
  84. B.set_ang_vel(N, 5 * B.y)
  85. O = Point('O')
  86. P = O.locatenew('P', q * B.x)
  87. P.set_vel(B, qd * B.x + q2d * B.y)
  88. O.set_vel(N, 0)
  89. assert P.v1pt_theory(O, N, B) == qd * B.x + q2d * B.y - 5 * q * B.z
  90. def test_point_pos():
  91. q = dynamicsymbols('q')
  92. N = ReferenceFrame('N')
  93. B = N.orientnew('B', 'Axis', [q, N.z])
  94. O = Point('O')
  95. P = O.locatenew('P', 10 * N.x + 5 * B.x)
  96. assert P.pos_from(O) == 10 * N.x + 5 * B.x
  97. Q = P.locatenew('Q', 10 * N.y + 5 * B.y)
  98. assert Q.pos_from(P) == 10 * N.y + 5 * B.y
  99. assert Q.pos_from(O) == 10 * N.x + 10 * N.y + 5 * B.x + 5 * B.y
  100. assert O.pos_from(Q) == -10 * N.x - 10 * N.y - 5 * B.x - 5 * B.y
  101. def test_point_partial_velocity():
  102. N = ReferenceFrame('N')
  103. A = ReferenceFrame('A')
  104. p = Point('p')
  105. u1, u2 = dynamicsymbols('u1, u2')
  106. p.set_vel(N, u1 * A.x + u2 * N.y)
  107. assert p.partial_velocity(N, u1) == A.x
  108. assert p.partial_velocity(N, u1, u2) == (A.x, N.y)
  109. raises(ValueError, lambda: p.partial_velocity(A, u1))
  110. def test_point_vel(): #Basic functionality
  111. q1, q2 = dynamicsymbols('q1 q2')
  112. N = ReferenceFrame('N')
  113. B = ReferenceFrame('B')
  114. Q = Point('Q')
  115. O = Point('O')
  116. Q.set_pos(O, q1 * N.x)
  117. raises(ValueError , lambda: Q.vel(N)) # Velocity of O in N is not defined
  118. O.set_vel(N, q2 * N.y)
  119. assert O.vel(N) == q2 * N.y
  120. raises(ValueError , lambda : O.vel(B)) #Velocity of O is not defined in B
  121. def test_auto_point_vel():
  122. t = dynamicsymbols._t
  123. q1, q2 = dynamicsymbols('q1 q2')
  124. N = ReferenceFrame('N')
  125. B = ReferenceFrame('B')
  126. O = Point('O')
  127. Q = Point('Q')
  128. Q.set_pos(O, q1 * N.x)
  129. O.set_vel(N, q2 * N.y)
  130. assert Q.vel(N) == q1.diff(t) * N.x + q2 * N.y # Velocity of Q using O
  131. P1 = Point('P1')
  132. P1.set_pos(O, q1 * B.x)
  133. P2 = Point('P2')
  134. P2.set_pos(P1, q2 * B.z)
  135. raises(ValueError, lambda : P2.vel(B)) # O's velocity is defined in different frame, and no
  136. #point in between has its velocity defined
  137. raises(ValueError, lambda: P2.vel(N)) # Velocity of O not defined in N
  138. def test_auto_point_vel_multiple_point_path():
  139. t = dynamicsymbols._t
  140. q1, q2 = dynamicsymbols('q1 q2')
  141. B = ReferenceFrame('B')
  142. P = Point('P')
  143. P.set_vel(B, q1 * B.x)
  144. P1 = Point('P1')
  145. P1.set_pos(P, q2 * B.y)
  146. P1.set_vel(B, q1 * B.z)
  147. P2 = Point('P2')
  148. P2.set_pos(P1, q1 * B.z)
  149. P3 = Point('P3')
  150. P3.set_pos(P2, 10 * q1 * B.y)
  151. assert P3.vel(B) == 10 * q1.diff(t) * B.y + (q1 + q1.diff(t)) * B.z
  152. def test_auto_vel_dont_overwrite():
  153. t = dynamicsymbols._t
  154. q1, q2, u1 = dynamicsymbols('q1, q2, u1')
  155. N = ReferenceFrame('N')
  156. P = Point('P1')
  157. P.set_vel(N, u1 * N.x)
  158. P1 = Point('P1')
  159. P1.set_pos(P, q2 * N.y)
  160. assert P1.vel(N) == q2.diff(t) * N.y + u1 * N.x
  161. assert P.vel(N) == u1 * N.x
  162. P1.set_vel(N, u1 * N.z)
  163. assert P1.vel(N) == u1 * N.z
  164. def test_auto_point_vel_if_tree_has_vel_but_inappropriate_pos_vector():
  165. q1, q2 = dynamicsymbols('q1 q2')
  166. B = ReferenceFrame('B')
  167. S = ReferenceFrame('S')
  168. P = Point('P')
  169. P.set_vel(B, q1 * B.x)
  170. P1 = Point('P1')
  171. P1.set_pos(P, S.y)
  172. raises(ValueError, lambda : P1.vel(B)) # P1.pos_from(P) can't be expressed in B
  173. raises(ValueError, lambda : P1.vel(S)) # P.vel(S) not defined
  174. def test_auto_point_vel_shortest_path():
  175. t = dynamicsymbols._t
  176. q1, q2, u1, u2 = dynamicsymbols('q1 q2 u1 u2')
  177. B = ReferenceFrame('B')
  178. P = Point('P')
  179. P.set_vel(B, u1 * B.x)
  180. P1 = Point('P1')
  181. P1.set_pos(P, q2 * B.y)
  182. P1.set_vel(B, q1 * B.z)
  183. P2 = Point('P2')
  184. P2.set_pos(P1, q1 * B.z)
  185. P3 = Point('P3')
  186. P3.set_pos(P2, 10 * q1 * B.y)
  187. P4 = Point('P4')
  188. P4.set_pos(P3, q1 * B.x)
  189. O = Point('O')
  190. O.set_vel(B, u2 * B.y)
  191. O1 = Point('O1')
  192. O1.set_pos(O, q2 * B.z)
  193. P4.set_pos(O1, q1 * B.x + q2 * B.z)
  194. with warnings.catch_warnings(): #There are two possible paths in this point tree, thus a warning is raised
  195. warnings.simplefilter('error')
  196. with ignore_warnings(UserWarning):
  197. assert P4.vel(B) == q1.diff(t) * B.x + u2 * B.y + 2 * q2.diff(t) * B.z
  198. def test_auto_point_vel_connected_frames():
  199. t = dynamicsymbols._t
  200. q, q1, q2, u = dynamicsymbols('q q1 q2 u')
  201. N = ReferenceFrame('N')
  202. B = ReferenceFrame('B')
  203. O = Point('O')
  204. O.set_vel(N, u * N.x)
  205. P = Point('P')
  206. P.set_pos(O, q1 * N.x + q2 * B.y)
  207. raises(ValueError, lambda: P.vel(N))
  208. N.orient(B, 'Axis', (q, B.x))
  209. assert P.vel(N) == (u + q1.diff(t)) * N.x + q2.diff(t) * B.y - q2 * q.diff(t) * B.z
  210. def test_auto_point_vel_multiple_paths_warning_arises():
  211. q, u = dynamicsymbols('q u')
  212. N = ReferenceFrame('N')
  213. O = Point('O')
  214. P = Point('P')
  215. Q = Point('Q')
  216. R = Point('R')
  217. P.set_vel(N, u * N.x)
  218. Q.set_vel(N, u *N.y)
  219. R.set_vel(N, u * N.z)
  220. O.set_pos(P, q * N.z)
  221. O.set_pos(Q, q * N.y)
  222. O.set_pos(R, q * N.x)
  223. with warnings.catch_warnings(): #There are two possible paths in this point tree, thus a warning is raised
  224. warnings.simplefilter("error")
  225. raises(UserWarning ,lambda: O.vel(N))
  226. def test_auto_vel_cyclic_warning_arises():
  227. P = Point('P')
  228. P1 = Point('P1')
  229. P2 = Point('P2')
  230. P3 = Point('P3')
  231. N = ReferenceFrame('N')
  232. P.set_vel(N, N.x)
  233. P1.set_pos(P, N.x)
  234. P2.set_pos(P1, N.y)
  235. P3.set_pos(P2, N.z)
  236. P1.set_pos(P3, N.x + N.y)
  237. with warnings.catch_warnings(): #The path is cyclic at P1, thus a warning is raised
  238. warnings.simplefilter("error")
  239. raises(UserWarning ,lambda: P2.vel(N))
  240. def test_auto_vel_cyclic_warning_msg():
  241. P = Point('P')
  242. P1 = Point('P1')
  243. P2 = Point('P2')
  244. P3 = Point('P3')
  245. N = ReferenceFrame('N')
  246. P.set_vel(N, N.x)
  247. P1.set_pos(P, N.x)
  248. P2.set_pos(P1, N.y)
  249. P3.set_pos(P2, N.z)
  250. P1.set_pos(P3, N.x + N.y)
  251. with warnings.catch_warnings(record = True) as w: #The path is cyclic at P1, thus a warning is raised
  252. warnings.simplefilter("always")
  253. P2.vel(N)
  254. assert issubclass(w[-1].category, UserWarning)
  255. 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)
  256. def test_auto_vel_multiple_path_warning_msg():
  257. N = ReferenceFrame('N')
  258. O = Point('O')
  259. P = Point('P')
  260. Q = Point('Q')
  261. P.set_vel(N, N.x)
  262. Q.set_vel(N, N.y)
  263. O.set_pos(P, N.z)
  264. O.set_pos(Q, N.y)
  265. with warnings.catch_warnings(record = True) as w: #There are two possible paths in this point tree, thus a warning is raised
  266. warnings.simplefilter("always")
  267. O.vel(N)
  268. assert issubclass(w[-1].category, UserWarning)
  269. assert 'Velocity automatically calculated based on point' in str(w[-1].message)
  270. assert 'Velocities from these points are not necessarily the same. This may cause errors in your calculations.' in str(w[-1].message)
  271. def test_auto_vel_derivative():
  272. q1, q2 = dynamicsymbols('q1:3')
  273. u1, u2 = dynamicsymbols('u1:3', 1)
  274. A = ReferenceFrame('A')
  275. B = ReferenceFrame('B')
  276. C = ReferenceFrame('C')
  277. B.orient_axis(A, A.z, q1)
  278. B.set_ang_vel(A, u1 * A.z)
  279. C.orient_axis(B, B.z, q2)
  280. C.set_ang_vel(B, u2 * B.z)
  281. Am = Point('Am')
  282. Am.set_vel(A, 0)
  283. Bm = Point('Bm')
  284. Bm.set_pos(Am, B.x)
  285. Bm.set_vel(B, 0)
  286. Bm.set_vel(C, 0)
  287. Cm = Point('Cm')
  288. Cm.set_pos(Bm, C.x)
  289. Cm.set_vel(C, 0)
  290. temp = Cm._vel_dict.copy()
  291. assert Cm.vel(A) == (u1 * B.y + (u1 + u2) * C.y)
  292. Cm._vel_dict = temp
  293. Cm.v2pt_theory(Bm, B, C)
  294. assert Cm.vel(A) == (u1 * B.y + (u1 + u2) * C.y)
  295. def test_auto_point_acc_zero_vel():
  296. N = ReferenceFrame('N')
  297. O = Point('O')
  298. O.set_vel(N, 0)
  299. assert O.acc(N) == 0 * N.x
  300. def test_auto_point_acc_compute_vel():
  301. t = dynamicsymbols._t
  302. q1 = dynamicsymbols('q1')
  303. N = ReferenceFrame('N')
  304. A = ReferenceFrame('A')
  305. A.orient_axis(N, N.z, q1)
  306. O = Point('O')
  307. O.set_vel(N, 0)
  308. P = Point('P')
  309. P.set_pos(O, A.x)
  310. assert P.acc(N) == -q1.diff(t) ** 2 * A.x + q1.diff(t, 2) * A.y
  311. def test_auto_acc_derivative():
  312. # Tests whether the Point.acc method gives the correct acceleration of the
  313. # end point of two linkages in series, while getting minimal information.
  314. q1, q2 = dynamicsymbols('q1:3')
  315. u1, u2 = dynamicsymbols('q1:3', 1)
  316. v1, v2 = dynamicsymbols('q1:3', 2)
  317. A = ReferenceFrame('A')
  318. B = ReferenceFrame('B')
  319. C = ReferenceFrame('C')
  320. B.orient_axis(A, A.z, q1)
  321. C.orient_axis(B, B.z, q2)
  322. Am = Point('Am')
  323. Am.set_vel(A, 0)
  324. Bm = Point('Bm')
  325. Bm.set_pos(Am, B.x)
  326. Bm.set_vel(B, 0)
  327. Bm.set_vel(C, 0)
  328. Cm = Point('Cm')
  329. Cm.set_pos(Bm, C.x)
  330. Cm.set_vel(C, 0)
  331. # Copy dictionaries to later check the calculation using the 2pt_theories
  332. Bm_vel_dict, Cm_vel_dict = Bm._vel_dict.copy(), Cm._vel_dict.copy()
  333. Bm_acc_dict, Cm_acc_dict = Bm._acc_dict.copy(), Cm._acc_dict.copy()
  334. check = -u1 ** 2 * B.x + v1 * B.y - (u1 + u2) ** 2 * C.x + (v1 + v2) * C.y
  335. assert Cm.acc(A) == check
  336. Bm._vel_dict, Cm._vel_dict = Bm_vel_dict, Cm_vel_dict
  337. Bm._acc_dict, Cm._acc_dict = Bm_acc_dict, Cm_acc_dict
  338. Bm.v2pt_theory(Am, A, B)
  339. Cm.v2pt_theory(Bm, A, C)
  340. Bm.a2pt_theory(Am, A, B)
  341. assert Cm.a2pt_theory(Bm, A, C) == check