123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564 |
- from sympy.core.backend import Symbol
- from sympy.physics.vector import Point, Vector, ReferenceFrame
- from sympy.physics.mechanics import RigidBody, Particle, inertia
- __all__ = ['Body']
- # XXX: We use type:ignore because the classes RigidBody and Particle have
- # inconsistent parallel axis methods that take different numbers of arguments.
- class Body(RigidBody, Particle): # type: ignore
- """
- Body is a common representation of either a RigidBody or a Particle SymPy
- object depending on what is passed in during initialization. If a mass is
- passed in and central_inertia is left as None, the Particle object is
- created. Otherwise a RigidBody object will be created.
- Explanation
- ===========
- The attributes that Body possesses will be the same as a Particle instance
- or a Rigid Body instance depending on which was created. Additional
- attributes are listed below.
- Attributes
- ==========
- name : string
- The body's name
- masscenter : Point
- The point which represents the center of mass of the rigid body
- frame : ReferenceFrame
- The reference frame which the body is fixed in
- mass : Sympifyable
- The body's mass
- inertia : (Dyadic, Point)
- The body's inertia around its center of mass. This attribute is specific
- to the rigid body form of Body and is left undefined for the Particle
- form
- loads : iterable
- This list contains information on the different loads acting on the
- Body. Forces are listed as a (point, vector) tuple and torques are
- listed as (reference frame, vector) tuples.
- Parameters
- ==========
- name : String
- Defines the name of the body. It is used as the base for defining
- body specific properties.
- masscenter : Point, optional
- A point that represents the center of mass of the body or particle.
- If no point is given, a point is generated.
- mass : Sympifyable, optional
- A Sympifyable object which represents the mass of the body. If no
- mass is passed, one is generated.
- frame : ReferenceFrame, optional
- The ReferenceFrame that represents the reference frame of the body.
- If no frame is given, a frame is generated.
- central_inertia : Dyadic, optional
- Central inertia dyadic of the body. If none is passed while creating
- RigidBody, a default inertia is generated.
- Examples
- ========
- Default behaviour. This results in the creation of a RigidBody object for
- which the mass, mass center, frame and inertia attributes are given default
- values. ::
- >>> from sympy.physics.mechanics import Body
- >>> body = Body('name_of_body')
- This next example demonstrates the code required to specify all of the
- values of the Body object. Note this will also create a RigidBody version of
- the Body object. ::
- >>> from sympy import Symbol
- >>> from sympy.physics.mechanics import ReferenceFrame, Point, inertia
- >>> from sympy.physics.mechanics import Body
- >>> mass = Symbol('mass')
- >>> masscenter = Point('masscenter')
- >>> frame = ReferenceFrame('frame')
- >>> ixx = Symbol('ixx')
- >>> body_inertia = inertia(frame, ixx, 0, 0)
- >>> body = Body('name_of_body', masscenter, mass, frame, body_inertia)
- The minimal code required to create a Particle version of the Body object
- involves simply passing in a name and a mass. ::
- >>> from sympy import Symbol
- >>> from sympy.physics.mechanics import Body
- >>> mass = Symbol('mass')
- >>> body = Body('name_of_body', mass=mass)
- The Particle version of the Body object can also receive a masscenter point
- and a reference frame, just not an inertia.
- """
- def __init__(self, name, masscenter=None, mass=None, frame=None,
- central_inertia=None):
- self.name = name
- self._loads = []
- if frame is None:
- frame = ReferenceFrame(name + '_frame')
- if masscenter is None:
- masscenter = Point(name + '_masscenter')
- if central_inertia is None and mass is None:
- ixx = Symbol(name + '_ixx')
- iyy = Symbol(name + '_iyy')
- izz = Symbol(name + '_izz')
- izx = Symbol(name + '_izx')
- ixy = Symbol(name + '_ixy')
- iyz = Symbol(name + '_iyz')
- _inertia = (inertia(frame, ixx, iyy, izz, ixy, iyz, izx),
- masscenter)
- else:
- _inertia = (central_inertia, masscenter)
- if mass is None:
- _mass = Symbol(name + '_mass')
- else:
- _mass = mass
- masscenter.set_vel(frame, 0)
- # If user passes masscenter and mass then a particle is created
- # otherwise a rigidbody. As a result a body may or may not have inertia.
- if central_inertia is None and mass is not None:
- self.frame = frame
- self.masscenter = masscenter
- Particle.__init__(self, name, masscenter, _mass)
- self._central_inertia = None
- else:
- RigidBody.__init__(self, name, masscenter, frame, _mass, _inertia)
- @property
- def loads(self):
- return self._loads
- @property
- def x(self):
- """The basis Vector for the Body, in the x direction. """
- return self.frame.x
- @property
- def y(self):
- """The basis Vector for the Body, in the y direction. """
- return self.frame.y
- @property
- def z(self):
- """The basis Vector for the Body, in the z direction. """
- return self.frame.z
- @property
- def is_rigidbody(self):
- if self.central_inertia is not None:
- return True
- return False
- def kinetic_energy(self, frame):
- """Kinetic energy of the body.
- Parameters
- ==========
- frame : ReferenceFrame or Body
- The Body's angular velocity and the velocity of it's mass
- center are typically defined with respect to an inertial frame but
- any relevant frame in which the velocities are known can be supplied.
- Examples
- ========
- >>> from sympy.physics.mechanics import Body, ReferenceFrame, Point
- >>> from sympy import symbols
- >>> m, v, r, omega = symbols('m v r omega')
- >>> N = ReferenceFrame('N')
- >>> O = Point('O')
- >>> P = Body('P', masscenter=O, mass=m)
- >>> P.masscenter.set_vel(N, v * N.y)
- >>> P.kinetic_energy(N)
- m*v**2/2
- >>> N = ReferenceFrame('N')
- >>> b = ReferenceFrame('b')
- >>> b.set_ang_vel(N, omega * b.x)
- >>> P = Point('P')
- >>> P.set_vel(N, v * N.x)
- >>> B = Body('B', masscenter=P, frame=b)
- >>> B.kinetic_energy(N)
- B_ixx*omega**2/2 + B_mass*v**2/2
- See Also
- ========
- sympy.physics.mechanics : Particle, RigidBody
- """
- if isinstance(frame, Body):
- frame = Body.frame
- if self.is_rigidbody:
- return RigidBody(self.name, self.masscenter, self.frame, self.mass,
- (self.central_inertia, self.masscenter)).kinetic_energy(frame)
- return Particle(self.name, self.masscenter, self.mass).kinetic_energy(frame)
- def apply_force(self, force, point=None, reaction_body=None, reaction_point=None):
- """Add force to the body(s).
- Explanation
- ===========
- Applies the force on self or equal and oppposite forces on
- self and other body if both are given on the desried point on the bodies.
- The force applied on other body is taken opposite of self, i.e, -force.
- Parameters
- ==========
- force: Vector
- The force to be applied.
- point: Point, optional
- The point on self on which force is applied.
- By default self's masscenter.
- reaction_body: Body, optional
- Second body on which equal and opposite force
- is to be applied.
- reaction_point : Point, optional
- The point on other body on which equal and opposite
- force is applied. By default masscenter of other body.
- Example
- =======
- >>> from sympy import symbols
- >>> from sympy.physics.mechanics import Body, Point, dynamicsymbols
- >>> m, g = symbols('m g')
- >>> B = Body('B')
- >>> force1 = m*g*B.z
- >>> B.apply_force(force1) #Applying force on B's masscenter
- >>> B.loads
- [(B_masscenter, g*m*B_frame.z)]
- We can also remove some part of force from any point on the body by
- adding the opposite force to the body on that point.
- >>> f1, f2 = dynamicsymbols('f1 f2')
- >>> P = Point('P') #Considering point P on body B
- >>> B.apply_force(f1*B.x + f2*B.y, P)
- >>> B.loads
- [(B_masscenter, g*m*B_frame.z), (P, f1(t)*B_frame.x + f2(t)*B_frame.y)]
- Let's remove f1 from point P on body B.
- >>> B.apply_force(-f1*B.x, P)
- >>> B.loads
- [(B_masscenter, g*m*B_frame.z), (P, f2(t)*B_frame.y)]
- To further demonstrate the use of ``apply_force`` attribute,
- consider two bodies connected through a spring.
- >>> from sympy.physics.mechanics import Body, dynamicsymbols
- >>> N = Body('N') #Newtonion Frame
- >>> x = dynamicsymbols('x')
- >>> B1 = Body('B1')
- >>> B2 = Body('B2')
- >>> spring_force = x*N.x
- Now let's apply equal and opposite spring force to the bodies.
- >>> P1 = Point('P1')
- >>> P2 = Point('P2')
- >>> B1.apply_force(spring_force, point=P1, reaction_body=B2, reaction_point=P2)
- We can check the loads(forces) applied to bodies now.
- >>> B1.loads
- [(P1, x(t)*N_frame.x)]
- >>> B2.loads
- [(P2, - x(t)*N_frame.x)]
- Notes
- =====
- If a new force is applied to a body on a point which already has some
- force applied on it, then the new force is added to the already applied
- force on that point.
- """
- if not isinstance(point, Point):
- if point is None:
- point = self.masscenter # masscenter
- else:
- raise TypeError("Force must be applied to a point on the body.")
- if not isinstance(force, Vector):
- raise TypeError("Force must be a vector.")
- if reaction_body is not None:
- reaction_body.apply_force(-force, point=reaction_point)
- for load in self._loads:
- if point in load:
- force += load[1]
- self._loads.remove(load)
- break
- self._loads.append((point, force))
- def apply_torque(self, torque, reaction_body=None):
- """Add torque to the body(s).
- Explanation
- ===========
- Applies the torque on self or equal and oppposite torquess on
- self and other body if both are given.
- The torque applied on other body is taken opposite of self,
- i.e, -torque.
- Parameters
- ==========
- torque: Vector
- The torque to be applied.
- reaction_body: Body, optional
- Second body on which equal and opposite torque
- is to be applied.
- Example
- =======
- >>> from sympy import symbols
- >>> from sympy.physics.mechanics import Body, dynamicsymbols
- >>> t = symbols('t')
- >>> B = Body('B')
- >>> torque1 = t*B.z
- >>> B.apply_torque(torque1)
- >>> B.loads
- [(B_frame, t*B_frame.z)]
- We can also remove some part of torque from the body by
- adding the opposite torque to the body.
- >>> t1, t2 = dynamicsymbols('t1 t2')
- >>> B.apply_torque(t1*B.x + t2*B.y)
- >>> B.loads
- [(B_frame, t1(t)*B_frame.x + t2(t)*B_frame.y + t*B_frame.z)]
- Let's remove t1 from Body B.
- >>> B.apply_torque(-t1*B.x)
- >>> B.loads
- [(B_frame, t2(t)*B_frame.y + t*B_frame.z)]
- To further demonstrate the use, let us consider two bodies such that
- a torque `T` is acting on one body, and `-T` on the other.
- >>> from sympy.physics.mechanics import Body, dynamicsymbols
- >>> N = Body('N') #Newtonion frame
- >>> B1 = Body('B1')
- >>> B2 = Body('B2')
- >>> v = dynamicsymbols('v')
- >>> T = v*N.y #Torque
- Now let's apply equal and opposite torque to the bodies.
- >>> B1.apply_torque(T, B2)
- We can check the loads (torques) applied to bodies now.
- >>> B1.loads
- [(B1_frame, v(t)*N_frame.y)]
- >>> B2.loads
- [(B2_frame, - v(t)*N_frame.y)]
- Notes
- =====
- If a new torque is applied on body which already has some torque applied on it,
- then the new torque is added to the previous torque about the body's frame.
- """
- if not isinstance(torque, Vector):
- raise TypeError("A Vector must be supplied to add torque.")
- if reaction_body is not None:
- reaction_body.apply_torque(-torque)
- for load in self._loads:
- if self.frame in load:
- torque += load[1]
- self._loads.remove(load)
- break
- self._loads.append((self.frame, torque))
- def clear_loads(self):
- """
- Clears the Body's loads list.
- Example
- =======
- >>> from sympy.physics.mechanics import Body
- >>> B = Body('B')
- >>> force = B.x + B.y
- >>> B.apply_force(force)
- >>> B.loads
- [(B_masscenter, B_frame.x + B_frame.y)]
- >>> B.clear_loads()
- >>> B.loads
- []
- """
- self._loads = []
- def remove_load(self, about=None):
- """
- Remove load about a point or frame.
- Parameters
- ==========
- about : Point or ReferenceFrame, optional
- The point about which force is applied,
- and is to be removed.
- If about is None, then the torque about
- self's frame is removed.
- Example
- =======
- >>> from sympy.physics.mechanics import Body, Point
- >>> B = Body('B')
- >>> P = Point('P')
- >>> f1 = B.x
- >>> f2 = B.y
- >>> B.apply_force(f1)
- >>> B.apply_force(f2, P)
- >>> B.loads
- [(B_masscenter, B_frame.x), (P, B_frame.y)]
- >>> B.remove_load(P)
- >>> B.loads
- [(B_masscenter, B_frame.x)]
- """
- if about is not None:
- if not isinstance(about, Point):
- raise TypeError('Load is applied about Point or ReferenceFrame.')
- else:
- about = self.frame
- for load in self._loads:
- if about in load:
- self._loads.remove(load)
- break
- def masscenter_vel(self, body):
- """
- Returns the velocity of the mass center with respect to the provided
- rigid body or reference frame.
- Parameters
- ==========
- body: Body or ReferenceFrame
- The rigid body or reference frame to calculate the velocity in.
- Example
- =======
- >>> from sympy.physics.mechanics import Body
- >>> A = Body('A')
- >>> B = Body('B')
- >>> A.masscenter.set_vel(B.frame, 5*B.frame.x)
- >>> A.masscenter_vel(B)
- 5*B_frame.x
- >>> A.masscenter_vel(B.frame)
- 5*B_frame.x
- """
- if isinstance(body, ReferenceFrame):
- frame=body
- elif isinstance(body, Body):
- frame = body.frame
- return self.masscenter.vel(frame)
- def ang_vel_in(self, body):
- """
- Returns this body's angular velocity with respect to the provided
- rigid body or reference frame.
- Parameters
- ==========
- body: Body or ReferenceFrame
- The rigid body or reference frame to calculate the angular velocity in.
- Example
- =======
- >>> from sympy.physics.mechanics import Body, ReferenceFrame
- >>> A = Body('A')
- >>> N = ReferenceFrame('N')
- >>> B = Body('B', frame=N)
- >>> A.frame.set_ang_vel(N, 5*N.x)
- >>> A.ang_vel_in(B)
- 5*N.x
- >>> A.ang_vel_in(N)
- 5*N.x
- """
- if isinstance(body, ReferenceFrame):
- frame=body
- elif isinstance(body, Body):
- frame = body.frame
- return self.frame.ang_vel_in(frame)
- def dcm(self, body):
- """
- Returns the direction cosine matrix of this body relative to the
- provided rigid body or reference frame.
- Parameters
- ==========
- body: Body or ReferenceFrame
- The rigid body or reference frame to calculate the dcm.
- Example
- =======
- >>> from sympy.physics.mechanics import Body
- >>> A = Body('A')
- >>> B = Body('B')
- >>> A.frame.orient_axis(B.frame, B.frame.x, 5)
- >>> A.dcm(B)
- Matrix([
- [1, 0, 0],
- [0, cos(5), sin(5)],
- [0, -sin(5), cos(5)]])
- >>> A.dcm(B.frame)
- Matrix([
- [1, 0, 0],
- [0, cos(5), sin(5)],
- [0, -sin(5), cos(5)]])
- """
- if isinstance(body, ReferenceFrame):
- frame=body
- elif isinstance(body, Body):
- frame = body.frame
- return self.frame.dcm(frame)
|