inertia.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. from sympy import sympify
  2. from sympy.physics.vector import Point, Dyadic, ReferenceFrame, outer
  3. from collections import namedtuple
  4. __all__ = ['inertia', 'inertia_of_point_mass', 'Inertia']
  5. def inertia(frame, ixx, iyy, izz, ixy=0, iyz=0, izx=0):
  6. """Simple way to create inertia Dyadic object.
  7. Explanation
  8. ===========
  9. Creates an inertia Dyadic based on the given tensor values and a body-fixed
  10. reference frame.
  11. Parameters
  12. ==========
  13. frame : ReferenceFrame
  14. The frame the inertia is defined in.
  15. ixx : Sympifyable
  16. The xx element in the inertia dyadic.
  17. iyy : Sympifyable
  18. The yy element in the inertia dyadic.
  19. izz : Sympifyable
  20. The zz element in the inertia dyadic.
  21. ixy : Sympifyable
  22. The xy element in the inertia dyadic.
  23. iyz : Sympifyable
  24. The yz element in the inertia dyadic.
  25. izx : Sympifyable
  26. The zx element in the inertia dyadic.
  27. Examples
  28. ========
  29. >>> from sympy.physics.mechanics import ReferenceFrame, inertia
  30. >>> N = ReferenceFrame('N')
  31. >>> inertia(N, 1, 2, 3)
  32. (N.x|N.x) + 2*(N.y|N.y) + 3*(N.z|N.z)
  33. """
  34. if not isinstance(frame, ReferenceFrame):
  35. raise TypeError('Need to define the inertia in a frame')
  36. ixx, iyy, izz = sympify(ixx), sympify(iyy), sympify(izz)
  37. ixy, iyz, izx = sympify(ixy), sympify(iyz), sympify(izx)
  38. return (ixx*outer(frame.x, frame.x) + ixy*outer(frame.x, frame.y) +
  39. izx*outer(frame.x, frame.z) + ixy*outer(frame.y, frame.x) +
  40. iyy*outer(frame.y, frame.y) + iyz*outer(frame.y, frame.z) +
  41. izx*outer(frame.z, frame.x) + iyz*outer(frame.z, frame.y) +
  42. izz*outer(frame.z, frame.z))
  43. def inertia_of_point_mass(mass, pos_vec, frame):
  44. """Inertia dyadic of a point mass relative to point O.
  45. Parameters
  46. ==========
  47. mass : Sympifyable
  48. Mass of the point mass
  49. pos_vec : Vector
  50. Position from point O to point mass
  51. frame : ReferenceFrame
  52. Reference frame to express the dyadic in
  53. Examples
  54. ========
  55. >>> from sympy import symbols
  56. >>> from sympy.physics.mechanics import ReferenceFrame, inertia_of_point_mass
  57. >>> N = ReferenceFrame('N')
  58. >>> r, m = symbols('r m')
  59. >>> px = r * N.x
  60. >>> inertia_of_point_mass(m, px, N)
  61. m*r**2*(N.y|N.y) + m*r**2*(N.z|N.z)
  62. """
  63. return mass*(
  64. (outer(frame.x, frame.x) +
  65. outer(frame.y, frame.y) +
  66. outer(frame.z, frame.z)) *
  67. (pos_vec.dot(pos_vec)) - outer(pos_vec, pos_vec))
  68. class Inertia(namedtuple('Inertia', ['dyadic', 'point'])):
  69. """Inertia object consisting of a Dyadic and a Point of reference.
  70. Explanation
  71. ===========
  72. This is a simple class to store the Point and Dyadic, belonging to an
  73. inertia.
  74. Attributes
  75. ==========
  76. dyadic : Dyadic
  77. The dyadic of the inertia.
  78. point : Point
  79. The reference point of the inertia.
  80. Examples
  81. ========
  82. >>> from sympy.physics.mechanics import ReferenceFrame, Point, Inertia
  83. >>> N = ReferenceFrame('N')
  84. >>> Po = Point('Po')
  85. >>> Inertia(N.x.outer(N.x) + N.y.outer(N.y) + N.z.outer(N.z), Po)
  86. ((N.x|N.x) + (N.y|N.y) + (N.z|N.z), Po)
  87. In the example above the Dyadic was created manually, one can however also
  88. use the ``inertia`` function for this or the class method ``from_tensor`` as
  89. shown below.
  90. >>> Inertia.from_inertia_scalars(Po, N, 1, 1, 1)
  91. ((N.x|N.x) + (N.y|N.y) + (N.z|N.z), Po)
  92. """
  93. __slots__ = ()
  94. def __new__(cls, dyadic, point):
  95. # Switch order if given in the wrong order
  96. if isinstance(dyadic, Point) and isinstance(point, Dyadic):
  97. point, dyadic = dyadic, point
  98. if not isinstance(point, Point):
  99. raise TypeError('Reference point should be of type Point')
  100. if not isinstance(dyadic, Dyadic):
  101. raise TypeError('Inertia value should be expressed as a Dyadic')
  102. return super().__new__(cls, dyadic, point)
  103. @classmethod
  104. def from_inertia_scalars(cls, point, frame, ixx, iyy, izz, ixy=0, iyz=0,
  105. izx=0):
  106. """Simple way to create an Inertia object based on the tensor values.
  107. Explanation
  108. ===========
  109. This class method uses the :func`~.inertia` to create the Dyadic based
  110. on the tensor values.
  111. Parameters
  112. ==========
  113. point : Point
  114. The reference point of the inertia.
  115. frame : ReferenceFrame
  116. The frame the inertia is defined in.
  117. ixx : Sympifyable
  118. The xx element in the inertia dyadic.
  119. iyy : Sympifyable
  120. The yy element in the inertia dyadic.
  121. izz : Sympifyable
  122. The zz element in the inertia dyadic.
  123. ixy : Sympifyable
  124. The xy element in the inertia dyadic.
  125. iyz : Sympifyable
  126. The yz element in the inertia dyadic.
  127. izx : Sympifyable
  128. The zx element in the inertia dyadic.
  129. Examples
  130. ========
  131. >>> from sympy import symbols
  132. >>> from sympy.physics.mechanics import ReferenceFrame, Point, Inertia
  133. >>> ixx, iyy, izz, ixy, iyz, izx = symbols('ixx iyy izz ixy iyz izx')
  134. >>> N = ReferenceFrame('N')
  135. >>> P = Point('P')
  136. >>> I = Inertia.from_inertia_scalars(P, N, ixx, iyy, izz, ixy, iyz, izx)
  137. The tensor values can easily be seen when converting the dyadic to a
  138. matrix.
  139. >>> I.dyadic.to_matrix(N)
  140. Matrix([
  141. [ixx, ixy, izx],
  142. [ixy, iyy, iyz],
  143. [izx, iyz, izz]])
  144. """
  145. return cls(inertia(frame, ixx, iyy, izz, ixy, iyz, izx), point)
  146. def __add__(self, other):
  147. raise TypeError(f"unsupported operand type(s) for +: "
  148. f"'{self.__class__.__name__}' and "
  149. f"'{other.__class__.__name__}'")
  150. def __mul__(self, other):
  151. raise TypeError(f"unsupported operand type(s) for *: "
  152. f"'{self.__class__.__name__}' and "
  153. f"'{other.__class__.__name__}'")
  154. __radd__ = __add__
  155. __rmul__ = __mul__