test_point.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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 + q2 * B.y)
  71. assert P.pos_from(O) == q * B.x + q2 * B.y
  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 + q2 * B.y)
  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. msg = str(w[-1].message).replace("\n", " ")
  255. assert issubclass(w[-1].category, UserWarning)
  256. assert 'Kinematic loops are defined among the positions of points. This is likely not desired and may cause errors in your calculations.' in msg
  257. def test_auto_vel_multiple_path_warning_msg():
  258. N = ReferenceFrame('N')
  259. O = Point('O')
  260. P = Point('P')
  261. Q = Point('Q')
  262. P.set_vel(N, N.x)
  263. Q.set_vel(N, N.y)
  264. O.set_pos(P, N.z)
  265. O.set_pos(Q, N.y)
  266. with warnings.catch_warnings(record = True) as w: #There are two possible paths in this point tree, thus a warning is raised
  267. warnings.simplefilter("always")
  268. O.vel(N)
  269. msg = str(w[-1].message).replace("\n", " ")
  270. assert issubclass(w[-1].category, UserWarning)
  271. assert 'Velocity' in msg
  272. assert 'automatically calculated based on point' in msg
  273. assert 'Velocities from these points are not necessarily the same. This may cause errors in your calculations.' in msg
  274. def test_auto_vel_derivative():
  275. q1, q2 = dynamicsymbols('q1:3')
  276. u1, u2 = dynamicsymbols('u1:3', 1)
  277. A = ReferenceFrame('A')
  278. B = ReferenceFrame('B')
  279. C = ReferenceFrame('C')
  280. B.orient_axis(A, A.z, q1)
  281. B.set_ang_vel(A, u1 * A.z)
  282. C.orient_axis(B, B.z, q2)
  283. C.set_ang_vel(B, u2 * B.z)
  284. Am = Point('Am')
  285. Am.set_vel(A, 0)
  286. Bm = Point('Bm')
  287. Bm.set_pos(Am, B.x)
  288. Bm.set_vel(B, 0)
  289. Bm.set_vel(C, 0)
  290. Cm = Point('Cm')
  291. Cm.set_pos(Bm, C.x)
  292. Cm.set_vel(C, 0)
  293. temp = Cm._vel_dict.copy()
  294. assert Cm.vel(A) == (u1 * B.y + (u1 + u2) * C.y)
  295. Cm._vel_dict = temp
  296. Cm.v2pt_theory(Bm, B, C)
  297. assert Cm.vel(A) == (u1 * B.y + (u1 + u2) * C.y)
  298. def test_auto_point_acc_zero_vel():
  299. N = ReferenceFrame('N')
  300. O = Point('O')
  301. O.set_vel(N, 0)
  302. assert O.acc(N) == 0 * N.x
  303. def test_auto_point_acc_compute_vel():
  304. t = dynamicsymbols._t
  305. q1 = dynamicsymbols('q1')
  306. N = ReferenceFrame('N')
  307. A = ReferenceFrame('A')
  308. A.orient_axis(N, N.z, q1)
  309. O = Point('O')
  310. O.set_vel(N, 0)
  311. P = Point('P')
  312. P.set_pos(O, A.x)
  313. assert P.acc(N) == -q1.diff(t) ** 2 * A.x + q1.diff(t, 2) * A.y
  314. def test_auto_acc_derivative():
  315. # Tests whether the Point.acc method gives the correct acceleration of the
  316. # end point of two linkages in series, while getting minimal information.
  317. q1, q2 = dynamicsymbols('q1:3')
  318. u1, u2 = dynamicsymbols('q1:3', 1)
  319. v1, v2 = dynamicsymbols('q1:3', 2)
  320. A = ReferenceFrame('A')
  321. B = ReferenceFrame('B')
  322. C = ReferenceFrame('C')
  323. B.orient_axis(A, A.z, q1)
  324. C.orient_axis(B, B.z, q2)
  325. Am = Point('Am')
  326. Am.set_vel(A, 0)
  327. Bm = Point('Bm')
  328. Bm.set_pos(Am, B.x)
  329. Bm.set_vel(B, 0)
  330. Bm.set_vel(C, 0)
  331. Cm = Point('Cm')
  332. Cm.set_pos(Bm, C.x)
  333. Cm.set_vel(C, 0)
  334. # Copy dictionaries to later check the calculation using the 2pt_theories
  335. Bm_vel_dict, Cm_vel_dict = Bm._vel_dict.copy(), Cm._vel_dict.copy()
  336. Bm_acc_dict, Cm_acc_dict = Bm._acc_dict.copy(), Cm._acc_dict.copy()
  337. check = -u1 ** 2 * B.x + v1 * B.y - (u1 + u2) ** 2 * C.x + (v1 + v2) * C.y
  338. assert Cm.acc(A) == check
  339. Bm._vel_dict, Cm._vel_dict = Bm_vel_dict, Cm_vel_dict
  340. Bm._acc_dict, Cm._acc_dict = Bm_acc_dict, Cm_acc_dict
  341. Bm.v2pt_theory(Am, A, B)
  342. Cm.v2pt_theory(Bm, A, C)
  343. Bm.a2pt_theory(Am, A, B)
  344. assert Cm.a2pt_theory(Bm, A, C) == check