test_autolev.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import os
  2. from sympy.functions.elementary.trigonometric import (cos, sin)
  3. from sympy.external import import_module
  4. from sympy.testing.pytest import skip
  5. from sympy.parsing.autolev import parse_autolev
  6. antlr4 = import_module("antlr4")
  7. if not antlr4:
  8. disabled = True
  9. FILE_DIR = os.path.dirname(
  10. os.path.dirname(os.path.abspath(os.path.realpath(__file__))))
  11. def _test_examples(in_filename, out_filename, test_name=""):
  12. in_file_path = os.path.join(FILE_DIR, 'autolev', 'test-examples',
  13. in_filename)
  14. correct_file_path = os.path.join(FILE_DIR, 'autolev', 'test-examples',
  15. out_filename)
  16. with open(in_file_path) as f:
  17. generated_code = parse_autolev(f, include_numeric=True)
  18. with open(correct_file_path) as f:
  19. for idx, line1 in enumerate(f):
  20. if line1.startswith("#"):
  21. break
  22. try:
  23. line2 = generated_code.split('\n')[idx]
  24. assert line1.rstrip() == line2.rstrip()
  25. except Exception:
  26. msg = 'mismatch in ' + test_name + ' in line no: {0}'
  27. raise AssertionError(msg.format(idx+1))
  28. def test_rule_tests():
  29. l = ["ruletest1", "ruletest2", "ruletest3", "ruletest4", "ruletest5",
  30. "ruletest6", "ruletest7", "ruletest8", "ruletest9", "ruletest10",
  31. "ruletest11", "ruletest12"]
  32. for i in l:
  33. in_filepath = i + ".al"
  34. out_filepath = i + ".py"
  35. _test_examples(in_filepath, out_filepath, i)
  36. def test_pydy_examples():
  37. l = ["mass_spring_damper", "chaos_pendulum", "double_pendulum",
  38. "non_min_pendulum"]
  39. for i in l:
  40. in_filepath = os.path.join("pydy-example-repo", i + ".al")
  41. out_filepath = os.path.join("pydy-example-repo", i + ".py")
  42. _test_examples(in_filepath, out_filepath, i)
  43. def test_autolev_tutorial():
  44. dir_path = os.path.join(FILE_DIR, 'autolev', 'test-examples',
  45. 'autolev-tutorial')
  46. if os.path.isdir(dir_path):
  47. l = ["tutor1", "tutor2", "tutor3", "tutor4", "tutor5", "tutor6",
  48. "tutor7"]
  49. for i in l:
  50. in_filepath = os.path.join("autolev-tutorial", i + ".al")
  51. out_filepath = os.path.join("autolev-tutorial", i + ".py")
  52. _test_examples(in_filepath, out_filepath, i)
  53. def test_dynamics_online():
  54. dir_path = os.path.join(FILE_DIR, 'autolev', 'test-examples',
  55. 'dynamics-online')
  56. if os.path.isdir(dir_path):
  57. ch1 = ["1-4", "1-5", "1-6", "1-7", "1-8", "1-9_1", "1-9_2", "1-9_3"]
  58. ch2 = ["2-1", "2-2", "2-3", "2-4", "2-5", "2-6", "2-7", "2-8", "2-9",
  59. "circular"]
  60. ch3 = ["3-1_1", "3-1_2", "3-2_1", "3-2_2", "3-2_3", "3-2_4", "3-2_5",
  61. "3-3"]
  62. ch4 = ["4-1_1", "4-2_1", "4-4_1", "4-4_2", "4-5_1", "4-5_2"]
  63. chapters = [(ch1, "ch1"), (ch2, "ch2"), (ch3, "ch3"), (ch4, "ch4")]
  64. for ch, name in chapters:
  65. for i in ch:
  66. in_filepath = os.path.join("dynamics-online", name, i + ".al")
  67. out_filepath = os.path.join("dynamics-online", name, i + ".py")
  68. _test_examples(in_filepath, out_filepath, i)
  69. def test_output_01():
  70. """Autolev example calculates the position, velocity, and acceleration of a
  71. point and expresses in a single reference frame::
  72. (1) FRAMES C,D,F
  73. (2) VARIABLES FD'',DC''
  74. (3) CONSTANTS R,L
  75. (4) POINTS O,E
  76. (5) SIMPROT(F,D,1,FD)
  77. -> (6) F_D = [1, 0, 0; 0, COS(FD), -SIN(FD); 0, SIN(FD), COS(FD)]
  78. (7) SIMPROT(D,C,2,DC)
  79. -> (8) D_C = [COS(DC), 0, SIN(DC); 0, 1, 0; -SIN(DC), 0, COS(DC)]
  80. (9) W_C_F> = EXPRESS(W_C_F>, F)
  81. -> (10) W_C_F> = FD'*F1> + COS(FD)*DC'*F2> + SIN(FD)*DC'*F3>
  82. (11) P_O_E>=R*D2>-L*C1>
  83. (12) P_O_E>=EXPRESS(P_O_E>, D)
  84. -> (13) P_O_E> = -L*COS(DC)*D1> + R*D2> + L*SIN(DC)*D3>
  85. (14) V_E_F>=EXPRESS(DT(P_O_E>,F),D)
  86. -> (15) V_E_F> = L*SIN(DC)*DC'*D1> - L*SIN(DC)*FD'*D2> + (R*FD'+L*COS(DC)*DC')*D3>
  87. (16) A_E_F>=EXPRESS(DT(V_E_F>,F),D)
  88. -> (17) A_E_F> = L*(COS(DC)*DC'^2+SIN(DC)*DC'')*D1> + (-R*FD'^2-2*L*COS(DC)*DC'*FD'-L*SIN(DC)*FD'')*D2> + (R*FD''+L*COS(DC)*DC''-L*SIN(DC)*DC'^2-L*SIN(DC)*FD'^2)*D3>
  89. """
  90. if not antlr4:
  91. skip('Test skipped: antlr4 is not installed.')
  92. autolev_input = """\
  93. FRAMES C,D,F
  94. VARIABLES FD'',DC''
  95. CONSTANTS R,L
  96. POINTS O,E
  97. SIMPROT(F,D,1,FD)
  98. SIMPROT(D,C,2,DC)
  99. W_C_F>=EXPRESS(W_C_F>,F)
  100. P_O_E>=R*D2>-L*C1>
  101. P_O_E>=EXPRESS(P_O_E>,D)
  102. V_E_F>=EXPRESS(DT(P_O_E>,F),D)
  103. A_E_F>=EXPRESS(DT(V_E_F>,F),D)\
  104. """
  105. sympy_input = parse_autolev(autolev_input)
  106. g = {}
  107. l = {}
  108. exec(sympy_input, g, l)
  109. w_c_f = l['frame_c'].ang_vel_in(l['frame_f'])
  110. # P_O_E> means "the position of point E wrt to point O"
  111. p_o_e = l['point_e'].pos_from(l['point_o'])
  112. v_e_f = l['point_e'].vel(l['frame_f'])
  113. a_e_f = l['point_e'].acc(l['frame_f'])
  114. # NOTE : The Autolev outputs above were manually transformed into
  115. # equivalent SymPy physics vector expressions. Would be nice to automate
  116. # this transformation.
  117. expected_w_c_f = (l['fd'].diff()*l['frame_f'].x +
  118. cos(l['fd'])*l['dc'].diff()*l['frame_f'].y +
  119. sin(l['fd'])*l['dc'].diff()*l['frame_f'].z)
  120. assert (w_c_f - expected_w_c_f).simplify() == 0
  121. expected_p_o_e = (-l['l']*cos(l['dc'])*l['frame_d'].x +
  122. l['r']*l['frame_d'].y +
  123. l['l']*sin(l['dc'])*l['frame_d'].z)
  124. assert (p_o_e - expected_p_o_e).simplify() == 0
  125. expected_v_e_f = (l['l']*sin(l['dc'])*l['dc'].diff()*l['frame_d'].x -
  126. l['l']*sin(l['dc'])*l['fd'].diff()*l['frame_d'].y +
  127. (l['r']*l['fd'].diff() +
  128. l['l']*cos(l['dc'])*l['dc'].diff())*l['frame_d'].z)
  129. assert (v_e_f - expected_v_e_f).simplify() == 0
  130. expected_a_e_f = (l['l']*(cos(l['dc'])*l['dc'].diff()**2 +
  131. sin(l['dc'])*l['dc'].diff().diff())*l['frame_d'].x +
  132. (-l['r']*l['fd'].diff()**2 -
  133. 2*l['l']*cos(l['dc'])*l['dc'].diff()*l['fd'].diff() -
  134. l['l']*sin(l['dc'])*l['fd'].diff().diff())*l['frame_d'].y +
  135. (l['r']*l['fd'].diff().diff() +
  136. l['l']*cos(l['dc'])*l['dc'].diff().diff() -
  137. l['l']*sin(l['dc'])*l['dc'].diff()**2 -
  138. l['l']*sin(l['dc'])*l['fd'].diff()**2)*l['frame_d'].z)
  139. assert (a_e_f - expected_a_e_f).simplify() == 0