| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- from abc import ABC
- from collections import namedtuple
- from sympy.physics.mechanics.body_base import BodyBase
- from sympy.physics.vector import Vector, ReferenceFrame, Point
- __all__ = ['LoadBase', 'Force', 'Torque']
- class LoadBase(ABC, namedtuple('LoadBase', ['location', 'vector'])):
- """Abstract base class for the various loading types."""
- def __add__(self, other):
- raise TypeError(f"unsupported operand type(s) for +: "
- f"'{self.__class__.__name__}' and "
- f"'{other.__class__.__name__}'")
- def __mul__(self, other):
- raise TypeError(f"unsupported operand type(s) for *: "
- f"'{self.__class__.__name__}' and "
- f"'{other.__class__.__name__}'")
- __radd__ = __add__
- __rmul__ = __mul__
- class Force(LoadBase):
- """Force acting upon a point.
- Explanation
- ===========
- A force is a vector that is bound to a line of action. This class stores
- both a point, which lies on the line of action, and the vector. A tuple can
- also be used, with the location as the first entry and the vector as second
- entry.
- Examples
- ========
- A force of magnitude 2 along N.x acting on a point Po can be created as
- follows:
- >>> from sympy.physics.mechanics import Point, ReferenceFrame, Force
- >>> N = ReferenceFrame('N')
- >>> Po = Point('Po')
- >>> Force(Po, 2 * N.x)
- (Po, 2*N.x)
- If a body is supplied, then the center of mass of that body is used.
- >>> from sympy.physics.mechanics import Particle
- >>> P = Particle('P', point=Po)
- >>> Force(P, 2 * N.x)
- (Po, 2*N.x)
- """
- def __new__(cls, point, force):
- if isinstance(point, BodyBase):
- point = point.masscenter
- if not isinstance(point, Point):
- raise TypeError('Force location should be a Point.')
- if not isinstance(force, Vector):
- raise TypeError('Force vector should be a Vector.')
- return super().__new__(cls, point, force)
- def __repr__(self):
- return (f'{self.__class__.__name__}(point={self.point}, '
- f'force={self.force})')
- @property
- def point(self):
- return self.location
- @property
- def force(self):
- return self.vector
- class Torque(LoadBase):
- """Torque acting upon a frame.
- Explanation
- ===========
- A torque is a free vector that is acting on a reference frame, which is
- associated with a rigid body. This class stores both the frame and the
- vector. A tuple can also be used, with the location as the first item and
- the vector as second item.
- Examples
- ========
- A torque of magnitude 2 about N.x acting on a frame N can be created as
- follows:
- >>> from sympy.physics.mechanics import ReferenceFrame, Torque
- >>> N = ReferenceFrame('N')
- >>> Torque(N, 2 * N.x)
- (N, 2*N.x)
- If a body is supplied, then the frame fixed to that body is used.
- >>> from sympy.physics.mechanics import RigidBody
- >>> rb = RigidBody('rb', frame=N)
- >>> Torque(rb, 2 * N.x)
- (N, 2*N.x)
- """
- def __new__(cls, frame, torque):
- if isinstance(frame, BodyBase):
- frame = frame.frame
- if not isinstance(frame, ReferenceFrame):
- raise TypeError('Torque location should be a ReferenceFrame.')
- if not isinstance(torque, Vector):
- raise TypeError('Torque vector should be a Vector.')
- return super().__new__(cls, frame, torque)
- def __repr__(self):
- return (f'{self.__class__.__name__}(frame={self.frame}, '
- f'torque={self.torque})')
- @property
- def frame(self):
- return self.location
- @property
- def torque(self):
- return self.vector
- def gravity(acceleration, *bodies):
- """
- Returns a list of gravity forces given the acceleration
- due to gravity and any number of particles or rigidbodies.
- Example
- =======
- >>> from sympy.physics.mechanics import ReferenceFrame, Particle, RigidBody
- >>> from sympy.physics.mechanics.loads import gravity
- >>> from sympy import symbols
- >>> N = ReferenceFrame('N')
- >>> g = symbols('g')
- >>> P = Particle('P')
- >>> B = RigidBody('B')
- >>> gravity(g*N.y, P, B)
- [(P_masscenter, P_mass*g*N.y),
- (B_masscenter, B_mass*g*N.y)]
- """
- gravity_force = []
- for body in bodies:
- if not isinstance(body, BodyBase):
- raise TypeError(f'{type(body)} is not a body type')
- gravity_force.append(Force(body.masscenter, body.mass * acceleration))
- return gravity_force
- def _parse_load(load):
- """Helper function to parse loads and convert tuples to load objects."""
- if isinstance(load, LoadBase):
- return load
- elif isinstance(load, tuple):
- if len(load) != 2:
- raise ValueError(f'Load {load} should have a length of 2.')
- if isinstance(load[0], Point):
- return Force(load[0], load[1])
- elif isinstance(load[0], ReferenceFrame):
- return Torque(load[0], load[1])
- else:
- raise ValueError(f'Load not recognized. The load location {load[0]}'
- f' should either be a Point or a ReferenceFrame.')
- raise TypeError(f'Load type {type(load)} not recognized as a load. It '
- f'should be a Force, Torque or tuple.')
|