I am done

This commit is contained in:
2024-10-30 22:14:35 +01:00
parent 720dc28c09
commit 40e2a747cf
36901 changed files with 5011519 additions and 0 deletions

View File

@ -0,0 +1,36 @@
__all__ = [
'CoordinateSym', 'ReferenceFrame',
'Dyadic',
'Vector',
'Point',
'cross', 'dot', 'express', 'time_derivative', 'outer',
'kinematic_equations', 'get_motion_params', 'partial_velocity',
'dynamicsymbols',
'vprint', 'vsstrrepr', 'vsprint', 'vpprint', 'vlatex', 'init_vprinting',
'curl', 'divergence', 'gradient', 'is_conservative', 'is_solenoidal',
'scalar_potential', 'scalar_potential_difference',
]
from .frame import CoordinateSym, ReferenceFrame
from .dyadic import Dyadic
from .vector import Vector
from .point import Point
from .functions import (cross, dot, express, time_derivative, outer,
kinematic_equations, get_motion_params, partial_velocity,
dynamicsymbols)
from .printing import (vprint, vsstrrepr, vsprint, vpprint, vlatex,
init_vprinting)
from .fieldfunctions import (curl, divergence, gradient, is_conservative,
is_solenoidal, scalar_potential, scalar_potential_difference)

View File

@ -0,0 +1,545 @@
from sympy import sympify, Add, ImmutableMatrix as Matrix
from sympy.core.evalf import EvalfMixin
from sympy.printing.defaults import Printable
from mpmath.libmp.libmpf import prec_to_dps
__all__ = ['Dyadic']
class Dyadic(Printable, EvalfMixin):
"""A Dyadic object.
See:
https://en.wikipedia.org/wiki/Dyadic_tensor
Kane, T., Levinson, D. Dynamics Theory and Applications. 1985 McGraw-Hill
A more powerful way to represent a rigid body's inertia. While it is more
complex, by choosing Dyadic components to be in body fixed basis vectors,
the resulting matrix is equivalent to the inertia tensor.
"""
is_number = False
def __init__(self, inlist):
"""
Just like Vector's init, you should not call this unless creating a
zero dyadic.
zd = Dyadic(0)
Stores a Dyadic as a list of lists; the inner list has the measure
number and the two unit vectors; the outerlist holds each unique
unit vector pair.
"""
self.args = []
if inlist == 0:
inlist = []
while len(inlist) != 0:
added = 0
for i, v in enumerate(self.args):
if ((str(inlist[0][1]) == str(self.args[i][1])) and
(str(inlist[0][2]) == str(self.args[i][2]))):
self.args[i] = (self.args[i][0] + inlist[0][0],
inlist[0][1], inlist[0][2])
inlist.remove(inlist[0])
added = 1
break
if added != 1:
self.args.append(inlist[0])
inlist.remove(inlist[0])
i = 0
# This code is to remove empty parts from the list
while i < len(self.args):
if ((self.args[i][0] == 0) | (self.args[i][1] == 0) |
(self.args[i][2] == 0)):
self.args.remove(self.args[i])
i -= 1
i += 1
@property
def func(self):
"""Returns the class Dyadic. """
return Dyadic
def __add__(self, other):
"""The add operator for Dyadic. """
other = _check_dyadic(other)
return Dyadic(self.args + other.args)
__radd__ = __add__
def __mul__(self, other):
"""Multiplies the Dyadic by a sympifyable expression.
Parameters
==========
other : Sympafiable
The scalar to multiply this Dyadic with
Examples
========
>>> from sympy.physics.vector import ReferenceFrame, outer
>>> N = ReferenceFrame('N')
>>> d = outer(N.x, N.x)
>>> 5 * d
5*(N.x|N.x)
"""
newlist = list(self.args)
other = sympify(other)
for i, v in enumerate(newlist):
newlist[i] = (other * newlist[i][0], newlist[i][1],
newlist[i][2])
return Dyadic(newlist)
__rmul__ = __mul__
def dot(self, other):
"""The inner product operator for a Dyadic and a Dyadic or Vector.
Parameters
==========
other : Dyadic or Vector
The other Dyadic or Vector to take the inner product with
Examples
========
>>> from sympy.physics.vector import ReferenceFrame, outer
>>> N = ReferenceFrame('N')
>>> D1 = outer(N.x, N.y)
>>> D2 = outer(N.y, N.y)
>>> D1.dot(D2)
(N.x|N.y)
>>> D1.dot(N.y)
N.x
"""
from sympy.physics.vector.vector import Vector, _check_vector
if isinstance(other, Dyadic):
other = _check_dyadic(other)
ol = Dyadic(0)
for v in self.args:
for v2 in other.args:
ol += v[0] * v2[0] * (v[2].dot(v2[1])) * (v[1].outer(v2[2]))
else:
other = _check_vector(other)
ol = Vector(0)
for v in self.args:
ol += v[0] * v[1] * (v[2].dot(other))
return ol
# NOTE : supports non-advertised Dyadic & Dyadic, Dyadic & Vector notation
__and__ = dot
def __truediv__(self, other):
"""Divides the Dyadic by a sympifyable expression. """
return self.__mul__(1 / other)
def __eq__(self, other):
"""Tests for equality.
Is currently weak; needs stronger comparison testing
"""
if other == 0:
other = Dyadic(0)
other = _check_dyadic(other)
if (self.args == []) and (other.args == []):
return True
elif (self.args == []) or (other.args == []):
return False
return set(self.args) == set(other.args)
def __ne__(self, other):
return not self == other
def __neg__(self):
return self * -1
def _latex(self, printer):
ar = self.args # just to shorten things
if len(ar) == 0:
return str(0)
ol = [] # output list, to be concatenated to a string
for i, v in enumerate(ar):
# if the coef of the dyadic is 1, we skip the 1
if ar[i][0] == 1:
ol.append(' + ' + printer._print(ar[i][1]) + r"\otimes " +
printer._print(ar[i][2]))
# if the coef of the dyadic is -1, we skip the 1
elif ar[i][0] == -1:
ol.append(' - ' +
printer._print(ar[i][1]) +
r"\otimes " +
printer._print(ar[i][2]))
# If the coefficient of the dyadic is not 1 or -1,
# we might wrap it in parentheses, for readability.
elif ar[i][0] != 0:
arg_str = printer._print(ar[i][0])
if isinstance(ar[i][0], Add):
arg_str = '(%s)' % arg_str
if arg_str.startswith('-'):
arg_str = arg_str[1:]
str_start = ' - '
else:
str_start = ' + '
ol.append(str_start + arg_str + printer._print(ar[i][1]) +
r"\otimes " + printer._print(ar[i][2]))
outstr = ''.join(ol)
if outstr.startswith(' + '):
outstr = outstr[3:]
elif outstr.startswith(' '):
outstr = outstr[1:]
return outstr
def _pretty(self, printer):
e = self
class Fake:
baseline = 0
def render(self, *args, **kwargs):
ar = e.args # just to shorten things
mpp = printer
if len(ar) == 0:
return str(0)
bar = "\N{CIRCLED TIMES}" if printer._use_unicode else "|"
ol = [] # output list, to be concatenated to a string
for i, v in enumerate(ar):
# if the coef of the dyadic is 1, we skip the 1
if ar[i][0] == 1:
ol.extend([" + ",
mpp.doprint(ar[i][1]),
bar,
mpp.doprint(ar[i][2])])
# if the coef of the dyadic is -1, we skip the 1
elif ar[i][0] == -1:
ol.extend([" - ",
mpp.doprint(ar[i][1]),
bar,
mpp.doprint(ar[i][2])])
# If the coefficient of the dyadic is not 1 or -1,
# we might wrap it in parentheses, for readability.
elif ar[i][0] != 0:
if isinstance(ar[i][0], Add):
arg_str = mpp._print(
ar[i][0]).parens()[0]
else:
arg_str = mpp.doprint(ar[i][0])
if arg_str.startswith("-"):
arg_str = arg_str[1:]
str_start = " - "
else:
str_start = " + "
ol.extend([str_start, arg_str, " ",
mpp.doprint(ar[i][1]),
bar,
mpp.doprint(ar[i][2])])
outstr = "".join(ol)
if outstr.startswith(" + "):
outstr = outstr[3:]
elif outstr.startswith(" "):
outstr = outstr[1:]
return outstr
return Fake()
def __rsub__(self, other):
return (-1 * self) + other
def _sympystr(self, printer):
"""Printing method. """
ar = self.args # just to shorten things
if len(ar) == 0:
return printer._print(0)
ol = [] # output list, to be concatenated to a string
for i, v in enumerate(ar):
# if the coef of the dyadic is 1, we skip the 1
if ar[i][0] == 1:
ol.append(' + (' + printer._print(ar[i][1]) + '|' +
printer._print(ar[i][2]) + ')')
# if the coef of the dyadic is -1, we skip the 1
elif ar[i][0] == -1:
ol.append(' - (' + printer._print(ar[i][1]) + '|' +
printer._print(ar[i][2]) + ')')
# If the coefficient of the dyadic is not 1 or -1,
# we might wrap it in parentheses, for readability.
elif ar[i][0] != 0:
arg_str = printer._print(ar[i][0])
if isinstance(ar[i][0], Add):
arg_str = "(%s)" % arg_str
if arg_str[0] == '-':
arg_str = arg_str[1:]
str_start = ' - '
else:
str_start = ' + '
ol.append(str_start + arg_str + '*(' +
printer._print(ar[i][1]) +
'|' + printer._print(ar[i][2]) + ')')
outstr = ''.join(ol)
if outstr.startswith(' + '):
outstr = outstr[3:]
elif outstr.startswith(' '):
outstr = outstr[1:]
return outstr
def __sub__(self, other):
"""The subtraction operator. """
return self.__add__(other * -1)
def cross(self, other):
"""Returns the dyadic resulting from the dyadic vector cross product:
Dyadic x Vector.
Parameters
==========
other : Vector
Vector to cross with.
Examples
========
>>> from sympy.physics.vector import ReferenceFrame, outer, cross
>>> N = ReferenceFrame('N')
>>> d = outer(N.x, N.x)
>>> cross(d, N.y)
(N.x|N.z)
"""
from sympy.physics.vector.vector import _check_vector
other = _check_vector(other)
ol = Dyadic(0)
for v in self.args:
ol += v[0] * (v[1].outer((v[2].cross(other))))
return ol
# NOTE : supports non-advertised Dyadic ^ Vector notation
__xor__ = cross
def express(self, frame1, frame2=None):
"""Expresses this Dyadic in alternate frame(s)
The first frame is the list side expression, the second frame is the
right side; if Dyadic is in form A.x|B.y, you can express it in two
different frames. If no second frame is given, the Dyadic is
expressed in only one frame.
Calls the global express function
Parameters
==========
frame1 : ReferenceFrame
The frame to express the left side of the Dyadic in
frame2 : ReferenceFrame
If provided, the frame to express the right side of the Dyadic in
Examples
========
>>> from sympy.physics.vector import ReferenceFrame, outer, dynamicsymbols
>>> from sympy.physics.vector import init_vprinting
>>> init_vprinting(pretty_print=False)
>>> N = ReferenceFrame('N')
>>> q = dynamicsymbols('q')
>>> B = N.orientnew('B', 'Axis', [q, N.z])
>>> d = outer(N.x, N.x)
>>> d.express(B, N)
cos(q)*(B.x|N.x) - sin(q)*(B.y|N.x)
"""
from sympy.physics.vector.functions import express
return express(self, frame1, frame2)
def to_matrix(self, reference_frame, second_reference_frame=None):
"""Returns the matrix form of the dyadic with respect to one or two
reference frames.
Parameters
----------
reference_frame : ReferenceFrame
The reference frame that the rows and columns of the matrix
correspond to. If a second reference frame is provided, this
only corresponds to the rows of the matrix.
second_reference_frame : ReferenceFrame, optional, default=None
The reference frame that the columns of the matrix correspond
to.
Returns
-------
matrix : ImmutableMatrix, shape(3,3)
The matrix that gives the 2D tensor form.
Examples
========
>>> from sympy import symbols, trigsimp
>>> from sympy.physics.vector import ReferenceFrame
>>> from sympy.physics.mechanics import inertia
>>> Ixx, Iyy, Izz, Ixy, Iyz, Ixz = symbols('Ixx, Iyy, Izz, Ixy, Iyz, Ixz')
>>> N = ReferenceFrame('N')
>>> inertia_dyadic = inertia(N, Ixx, Iyy, Izz, Ixy, Iyz, Ixz)
>>> inertia_dyadic.to_matrix(N)
Matrix([
[Ixx, Ixy, Ixz],
[Ixy, Iyy, Iyz],
[Ixz, Iyz, Izz]])
>>> beta = symbols('beta')
>>> A = N.orientnew('A', 'Axis', (beta, N.x))
>>> trigsimp(inertia_dyadic.to_matrix(A))
Matrix([
[ Ixx, Ixy*cos(beta) + Ixz*sin(beta), -Ixy*sin(beta) + Ixz*cos(beta)],
[ Ixy*cos(beta) + Ixz*sin(beta), Iyy*cos(2*beta)/2 + Iyy/2 + Iyz*sin(2*beta) - Izz*cos(2*beta)/2 + Izz/2, -Iyy*sin(2*beta)/2 + Iyz*cos(2*beta) + Izz*sin(2*beta)/2],
[-Ixy*sin(beta) + Ixz*cos(beta), -Iyy*sin(2*beta)/2 + Iyz*cos(2*beta) + Izz*sin(2*beta)/2, -Iyy*cos(2*beta)/2 + Iyy/2 - Iyz*sin(2*beta) + Izz*cos(2*beta)/2 + Izz/2]])
"""
if second_reference_frame is None:
second_reference_frame = reference_frame
return Matrix([i.dot(self).dot(j) for i in reference_frame for j in
second_reference_frame]).reshape(3, 3)
def doit(self, **hints):
"""Calls .doit() on each term in the Dyadic"""
return sum([Dyadic([(v[0].doit(**hints), v[1], v[2])])
for v in self.args], Dyadic(0))
def dt(self, frame):
"""Take the time derivative of this Dyadic in a frame.
This function calls the global time_derivative method
Parameters
==========
frame : ReferenceFrame
The frame to take the time derivative in
Examples
========
>>> from sympy.physics.vector import ReferenceFrame, outer, dynamicsymbols
>>> from sympy.physics.vector import init_vprinting
>>> init_vprinting(pretty_print=False)
>>> N = ReferenceFrame('N')
>>> q = dynamicsymbols('q')
>>> B = N.orientnew('B', 'Axis', [q, N.z])
>>> d = outer(N.x, N.x)
>>> d.dt(B)
- q'*(N.y|N.x) - q'*(N.x|N.y)
"""
from sympy.physics.vector.functions import time_derivative
return time_derivative(self, frame)
def simplify(self):
"""Returns a simplified Dyadic."""
out = Dyadic(0)
for v in self.args:
out += Dyadic([(v[0].simplify(), v[1], v[2])])
return out
def subs(self, *args, **kwargs):
"""Substitution on the Dyadic.
Examples
========
>>> from sympy.physics.vector import ReferenceFrame
>>> from sympy import Symbol
>>> N = ReferenceFrame('N')
>>> s = Symbol('s')
>>> a = s*(N.x|N.x)
>>> a.subs({s: 2})
2*(N.x|N.x)
"""
return sum([Dyadic([(v[0].subs(*args, **kwargs), v[1], v[2])])
for v in self.args], Dyadic(0))
def applyfunc(self, f):
"""Apply a function to each component of a Dyadic."""
if not callable(f):
raise TypeError("`f` must be callable.")
out = Dyadic(0)
for a, b, c in self.args:
out += f(a) * (b.outer(c))
return out
def _eval_evalf(self, prec):
if not self.args:
return self
new_args = []
dps = prec_to_dps(prec)
for inlist in self.args:
new_inlist = list(inlist)
new_inlist[0] = inlist[0].evalf(n=dps)
new_args.append(tuple(new_inlist))
return Dyadic(new_args)
def xreplace(self, rule):
"""
Replace occurrences of objects within the measure numbers of the
Dyadic.
Parameters
==========
rule : dict-like
Expresses a replacement rule.
Returns
=======
Dyadic
Result of the replacement.
Examples
========
>>> from sympy import symbols, pi
>>> from sympy.physics.vector import ReferenceFrame, outer
>>> N = ReferenceFrame('N')
>>> D = outer(N.x, N.x)
>>> x, y, z = symbols('x y z')
>>> ((1 + x*y) * D).xreplace({x: pi})
(pi*y + 1)*(N.x|N.x)
>>> ((1 + x*y) * D).xreplace({x: pi, y: 2})
(1 + 2*pi)*(N.x|N.x)
Replacements occur only if an entire node in the expression tree is
matched:
>>> ((x*y + z) * D).xreplace({x*y: pi})
(z + pi)*(N.x|N.x)
>>> ((x*y*z) * D).xreplace({x*y: pi})
x*y*z*(N.x|N.x)
"""
new_args = []
for inlist in self.args:
new_inlist = list(inlist)
new_inlist[0] = new_inlist[0].xreplace(rule)
new_args.append(tuple(new_inlist))
return Dyadic(new_args)
def _check_dyadic(other):
if not isinstance(other, Dyadic):
raise TypeError('A Dyadic must be supplied')
return other

View File

@ -0,0 +1,313 @@
from sympy.core.function import diff
from sympy.core.singleton import S
from sympy.integrals.integrals import integrate
from sympy.physics.vector import Vector, express
from sympy.physics.vector.frame import _check_frame
from sympy.physics.vector.vector import _check_vector
__all__ = ['curl', 'divergence', 'gradient', 'is_conservative',
'is_solenoidal', 'scalar_potential',
'scalar_potential_difference']
def curl(vect, frame):
"""
Returns the curl of a vector field computed wrt the coordinate
symbols of the given frame.
Parameters
==========
vect : Vector
The vector operand
frame : ReferenceFrame
The reference frame to calculate the curl in
Examples
========
>>> from sympy.physics.vector import ReferenceFrame
>>> from sympy.physics.vector import curl
>>> R = ReferenceFrame('R')
>>> v1 = R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z
>>> curl(v1, R)
0
>>> v2 = R[0]*R[1]*R[2]*R.x
>>> curl(v2, R)
R_x*R_y*R.y - R_x*R_z*R.z
"""
_check_vector(vect)
if vect == 0:
return Vector(0)
vect = express(vect, frame, variables=True)
# A mechanical approach to avoid looping overheads
vectx = vect.dot(frame.x)
vecty = vect.dot(frame.y)
vectz = vect.dot(frame.z)
outvec = Vector(0)
outvec += (diff(vectz, frame[1]) - diff(vecty, frame[2])) * frame.x
outvec += (diff(vectx, frame[2]) - diff(vectz, frame[0])) * frame.y
outvec += (diff(vecty, frame[0]) - diff(vectx, frame[1])) * frame.z
return outvec
def divergence(vect, frame):
"""
Returns the divergence of a vector field computed wrt the coordinate
symbols of the given frame.
Parameters
==========
vect : Vector
The vector operand
frame : ReferenceFrame
The reference frame to calculate the divergence in
Examples
========
>>> from sympy.physics.vector import ReferenceFrame
>>> from sympy.physics.vector import divergence
>>> R = ReferenceFrame('R')
>>> v1 = R[0]*R[1]*R[2] * (R.x+R.y+R.z)
>>> divergence(v1, R)
R_x*R_y + R_x*R_z + R_y*R_z
>>> v2 = 2*R[1]*R[2]*R.y
>>> divergence(v2, R)
2*R_z
"""
_check_vector(vect)
if vect == 0:
return S.Zero
vect = express(vect, frame, variables=True)
vectx = vect.dot(frame.x)
vecty = vect.dot(frame.y)
vectz = vect.dot(frame.z)
out = S.Zero
out += diff(vectx, frame[0])
out += diff(vecty, frame[1])
out += diff(vectz, frame[2])
return out
def gradient(scalar, frame):
"""
Returns the vector gradient of a scalar field computed wrt the
coordinate symbols of the given frame.
Parameters
==========
scalar : sympifiable
The scalar field to take the gradient of
frame : ReferenceFrame
The frame to calculate the gradient in
Examples
========
>>> from sympy.physics.vector import ReferenceFrame
>>> from sympy.physics.vector import gradient
>>> R = ReferenceFrame('R')
>>> s1 = R[0]*R[1]*R[2]
>>> gradient(s1, R)
R_y*R_z*R.x + R_x*R_z*R.y + R_x*R_y*R.z
>>> s2 = 5*R[0]**2*R[2]
>>> gradient(s2, R)
10*R_x*R_z*R.x + 5*R_x**2*R.z
"""
_check_frame(frame)
outvec = Vector(0)
scalar = express(scalar, frame, variables=True)
for i, x in enumerate(frame):
outvec += diff(scalar, frame[i]) * x
return outvec
def is_conservative(field):
"""
Checks if a field is conservative.
Parameters
==========
field : Vector
The field to check for conservative property
Examples
========
>>> from sympy.physics.vector import ReferenceFrame
>>> from sympy.physics.vector import is_conservative
>>> R = ReferenceFrame('R')
>>> is_conservative(R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z)
True
>>> is_conservative(R[2] * R.y)
False
"""
# Field is conservative irrespective of frame
# Take the first frame in the result of the separate method of Vector
if field == Vector(0):
return True
frame = list(field.separate())[0]
return curl(field, frame).simplify() == Vector(0)
def is_solenoidal(field):
"""
Checks if a field is solenoidal.
Parameters
==========
field : Vector
The field to check for solenoidal property
Examples
========
>>> from sympy.physics.vector import ReferenceFrame
>>> from sympy.physics.vector import is_solenoidal
>>> R = ReferenceFrame('R')
>>> is_solenoidal(R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z)
True
>>> is_solenoidal(R[1] * R.y)
False
"""
# Field is solenoidal irrespective of frame
# Take the first frame in the result of the separate method in Vector
if field == Vector(0):
return True
frame = list(field.separate())[0]
return divergence(field, frame).simplify() is S.Zero
def scalar_potential(field, frame):
"""
Returns the scalar potential function of a field in a given frame
(without the added integration constant).
Parameters
==========
field : Vector
The vector field whose scalar potential function is to be
calculated
frame : ReferenceFrame
The frame to do the calculation in
Examples
========
>>> from sympy.physics.vector import ReferenceFrame
>>> from sympy.physics.vector import scalar_potential, gradient
>>> R = ReferenceFrame('R')
>>> scalar_potential(R.z, R) == R[2]
True
>>> scalar_field = 2*R[0]**2*R[1]*R[2]
>>> grad_field = gradient(scalar_field, R)
>>> scalar_potential(grad_field, R)
2*R_x**2*R_y*R_z
"""
# Check whether field is conservative
if not is_conservative(field):
raise ValueError("Field is not conservative")
if field == Vector(0):
return S.Zero
# Express the field exntirely in frame
# Substitute coordinate variables also
_check_frame(frame)
field = express(field, frame, variables=True)
# Make a list of dimensions of the frame
dimensions = list(frame)
# Calculate scalar potential function
temp_function = integrate(field.dot(dimensions[0]), frame[0])
for i, dim in enumerate(dimensions[1:]):
partial_diff = diff(temp_function, frame[i + 1])
partial_diff = field.dot(dim) - partial_diff
temp_function += integrate(partial_diff, frame[i + 1])
return temp_function
def scalar_potential_difference(field, frame, point1, point2, origin):
"""
Returns the scalar potential difference between two points in a
certain frame, wrt a given field.
If a scalar field is provided, its values at the two points are
considered. If a conservative vector field is provided, the values
of its scalar potential function at the two points are used.
Returns (potential at position 2) - (potential at position 1)
Parameters
==========
field : Vector/sympyfiable
The field to calculate wrt
frame : ReferenceFrame
The frame to do the calculations in
point1 : Point
The initial Point in given frame
position2 : Point
The second Point in the given frame
origin : Point
The Point to use as reference point for position vector
calculation
Examples
========
>>> from sympy.physics.vector import ReferenceFrame, Point
>>> from sympy.physics.vector import scalar_potential_difference
>>> R = ReferenceFrame('R')
>>> O = Point('O')
>>> P = O.locatenew('P', R[0]*R.x + R[1]*R.y + R[2]*R.z)
>>> vectfield = 4*R[0]*R[1]*R.x + 2*R[0]**2*R.y
>>> scalar_potential_difference(vectfield, R, O, P, O)
2*R_x**2*R_y
>>> Q = O.locatenew('O', 3*R.x + R.y + 2*R.z)
>>> scalar_potential_difference(vectfield, R, P, Q, O)
-2*R_x**2*R_y + 18
"""
_check_frame(frame)
if isinstance(field, Vector):
# Get the scalar potential function
scalar_fn = scalar_potential(field, frame)
else:
# Field is a scalar
scalar_fn = field
# Express positions in required frame
position1 = express(point1.pos_from(origin), frame, variables=True)
position2 = express(point2.pos_from(origin), frame, variables=True)
# Get the two positions as substitution dicts for coordinate variables
subs_dict1 = {}
subs_dict2 = {}
for i, x in enumerate(frame):
subs_dict1[frame[i]] = x.dot(position1)
subs_dict2[frame[i]] = x.dot(position2)
return scalar_fn.subs(subs_dict2) - scalar_fn.subs(subs_dict1)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,650 @@
from functools import reduce
from sympy import (sympify, diff, sin, cos, Matrix, symbols,
Function, S, Symbol, linear_eq_to_matrix)
from sympy.integrals.integrals import integrate
from sympy.simplify.trigsimp import trigsimp
from .vector import Vector, _check_vector
from .frame import CoordinateSym, _check_frame
from .dyadic import Dyadic
from .printing import vprint, vsprint, vpprint, vlatex, init_vprinting
from sympy.utilities.iterables import iterable
from sympy.utilities.misc import translate
__all__ = ['cross', 'dot', 'express', 'time_derivative', 'outer',
'kinematic_equations', 'get_motion_params', 'partial_velocity',
'dynamicsymbols', 'vprint', 'vsprint', 'vpprint', 'vlatex',
'init_vprinting']
def cross(vec1, vec2):
"""Cross product convenience wrapper for Vector.cross(): \n"""
if not isinstance(vec1, (Vector, Dyadic)):
raise TypeError('Cross product is between two vectors')
return vec1 ^ vec2
cross.__doc__ += Vector.cross.__doc__ # type: ignore
def dot(vec1, vec2):
"""Dot product convenience wrapper for Vector.dot(): \n"""
if not isinstance(vec1, (Vector, Dyadic)):
raise TypeError('Dot product is between two vectors')
return vec1 & vec2
dot.__doc__ += Vector.dot.__doc__ # type: ignore
def express(expr, frame, frame2=None, variables=False):
"""
Global function for 'express' functionality.
Re-expresses a Vector, scalar(sympyfiable) or Dyadic in given frame.
Refer to the local methods of Vector and Dyadic for details.
If 'variables' is True, then the coordinate variables (CoordinateSym
instances) of other frames present in the vector/scalar field or
dyadic expression are also substituted in terms of the base scalars of
this frame.
Parameters
==========
expr : Vector/Dyadic/scalar(sympyfiable)
The expression to re-express in ReferenceFrame 'frame'
frame: ReferenceFrame
The reference frame to express expr in
frame2 : ReferenceFrame
The other frame required for re-expression(only for Dyadic expr)
variables : boolean
Specifies whether to substitute the coordinate variables present
in expr, in terms of those of frame
Examples
========
>>> from sympy.physics.vector import ReferenceFrame, outer, dynamicsymbols
>>> from sympy.physics.vector import init_vprinting
>>> init_vprinting(pretty_print=False)
>>> N = ReferenceFrame('N')
>>> q = dynamicsymbols('q')
>>> B = N.orientnew('B', 'Axis', [q, N.z])
>>> d = outer(N.x, N.x)
>>> from sympy.physics.vector import express
>>> express(d, B, N)
cos(q)*(B.x|N.x) - sin(q)*(B.y|N.x)
>>> express(B.x, N)
cos(q)*N.x + sin(q)*N.y
>>> express(N[0], B, variables=True)
B_x*cos(q) - B_y*sin(q)
"""
_check_frame(frame)
if expr == 0:
return expr
if isinstance(expr, Vector):
# Given expr is a Vector
if variables:
# If variables attribute is True, substitute the coordinate
# variables in the Vector
frame_list = [x[-1] for x in expr.args]
subs_dict = {}
for f in frame_list:
subs_dict.update(f.variable_map(frame))
expr = expr.subs(subs_dict)
# Re-express in this frame
outvec = Vector([])
for v in expr.args:
if v[1] != frame:
temp = frame.dcm(v[1]) * v[0]
if Vector.simp:
temp = temp.applyfunc(lambda x:
trigsimp(x, method='fu'))
outvec += Vector([(temp, frame)])
else:
outvec += Vector([v])
return outvec
if isinstance(expr, Dyadic):
if frame2 is None:
frame2 = frame
_check_frame(frame2)
ol = Dyadic(0)
for v in expr.args:
ol += express(v[0], frame, variables=variables) * \
(express(v[1], frame, variables=variables) |
express(v[2], frame2, variables=variables))
return ol
else:
if variables:
# Given expr is a scalar field
frame_set = set()
expr = sympify(expr)
# Substitute all the coordinate variables
for x in expr.free_symbols:
if isinstance(x, CoordinateSym) and x.frame != frame:
frame_set.add(x.frame)
subs_dict = {}
for f in frame_set:
subs_dict.update(f.variable_map(frame))
return expr.subs(subs_dict)
return expr
def time_derivative(expr, frame, order=1):
"""
Calculate the time derivative of a vector/scalar field function
or dyadic expression in given frame.
References
==========
https://en.wikipedia.org/wiki/Rotating_reference_frame#Time_derivatives_in_the_two_frames
Parameters
==========
expr : Vector/Dyadic/sympifyable
The expression whose time derivative is to be calculated
frame : ReferenceFrame
The reference frame to calculate the time derivative in
order : integer
The order of the derivative to be calculated
Examples
========
>>> from sympy.physics.vector import ReferenceFrame, dynamicsymbols
>>> from sympy.physics.vector import init_vprinting
>>> init_vprinting(pretty_print=False)
>>> from sympy import Symbol
>>> q1 = Symbol('q1')
>>> u1 = dynamicsymbols('u1')
>>> N = ReferenceFrame('N')
>>> A = N.orientnew('A', 'Axis', [q1, N.x])
>>> v = u1 * N.x
>>> A.set_ang_vel(N, 10*A.x)
>>> from sympy.physics.vector import time_derivative
>>> time_derivative(v, N)
u1'*N.x
>>> time_derivative(u1*A[0], N)
N_x*u1'
>>> B = N.orientnew('B', 'Axis', [u1, N.z])
>>> from sympy.physics.vector import outer
>>> d = outer(N.x, N.x)
>>> time_derivative(d, B)
- u1'*(N.y|N.x) - u1'*(N.x|N.y)
"""
t = dynamicsymbols._t
_check_frame(frame)
if order == 0:
return expr
if order % 1 != 0 or order < 0:
raise ValueError("Unsupported value of order entered")
if isinstance(expr, Vector):
outlist = []
for v in expr.args:
if v[1] == frame:
outlist += [(express(v[0], frame, variables=True).diff(t),
frame)]
else:
outlist += (time_derivative(Vector([v]), v[1]) +
(v[1].ang_vel_in(frame) ^ Vector([v]))).args
outvec = Vector(outlist)
return time_derivative(outvec, frame, order - 1)
if isinstance(expr, Dyadic):
ol = Dyadic(0)
for v in expr.args:
ol += (v[0].diff(t) * (v[1] | v[2]))
ol += (v[0] * (time_derivative(v[1], frame) | v[2]))
ol += (v[0] * (v[1] | time_derivative(v[2], frame)))
return time_derivative(ol, frame, order - 1)
else:
return diff(express(expr, frame, variables=True), t, order)
def outer(vec1, vec2):
"""Outer product convenience wrapper for Vector.outer():\n"""
if not isinstance(vec1, Vector):
raise TypeError('Outer product is between two Vectors')
return vec1.outer(vec2)
outer.__doc__ += Vector.outer.__doc__ # type: ignore
def kinematic_equations(speeds, coords, rot_type, rot_order=''):
"""Gives equations relating the qdot's to u's for a rotation type.
Supply rotation type and order as in orient. Speeds are assumed to be
body-fixed; if we are defining the orientation of B in A using by rot_type,
the angular velocity of B in A is assumed to be in the form: speed[0]*B.x +
speed[1]*B.y + speed[2]*B.z
Parameters
==========
speeds : list of length 3
The body fixed angular velocity measure numbers.
coords : list of length 3 or 4
The coordinates used to define the orientation of the two frames.
rot_type : str
The type of rotation used to create the equations. Body, Space, or
Quaternion only
rot_order : str or int
If applicable, the order of a series of rotations.
Examples
========
>>> from sympy.physics.vector import dynamicsymbols
>>> from sympy.physics.vector import kinematic_equations, vprint
>>> u1, u2, u3 = dynamicsymbols('u1 u2 u3')
>>> q1, q2, q3 = dynamicsymbols('q1 q2 q3')
>>> vprint(kinematic_equations([u1,u2,u3], [q1,q2,q3], 'body', '313'),
... order=None)
[-(u1*sin(q3) + u2*cos(q3))/sin(q2) + q1', -u1*cos(q3) + u2*sin(q3) + q2', (u1*sin(q3) + u2*cos(q3))*cos(q2)/sin(q2) - u3 + q3']
"""
# Code below is checking and sanitizing input
approved_orders = ('123', '231', '312', '132', '213', '321', '121', '131',
'212', '232', '313', '323', '1', '2', '3', '')
# make sure XYZ => 123 and rot_type is in lower case
rot_order = translate(str(rot_order), 'XYZxyz', '123123')
rot_type = rot_type.lower()
if not isinstance(speeds, (list, tuple)):
raise TypeError('Need to supply speeds in a list')
if len(speeds) != 3:
raise TypeError('Need to supply 3 body-fixed speeds')
if not isinstance(coords, (list, tuple)):
raise TypeError('Need to supply coordinates in a list')
if rot_type in ['body', 'space']:
if rot_order not in approved_orders:
raise ValueError('Not an acceptable rotation order')
if len(coords) != 3:
raise ValueError('Need 3 coordinates for body or space')
# Actual hard-coded kinematic differential equations
w1, w2, w3 = speeds
if w1 == w2 == w3 == 0:
return [S.Zero]*3
q1, q2, q3 = coords
q1d, q2d, q3d = [diff(i, dynamicsymbols._t) for i in coords]
s1, s2, s3 = [sin(q1), sin(q2), sin(q3)]
c1, c2, c3 = [cos(q1), cos(q2), cos(q3)]
if rot_type == 'body':
if rot_order == '123':
return [q1d - (w1 * c3 - w2 * s3) / c2, q2d - w1 * s3 - w2 *
c3, q3d - (-w1 * c3 + w2 * s3) * s2 / c2 - w3]
if rot_order == '231':
return [q1d - (w2 * c3 - w3 * s3) / c2, q2d - w2 * s3 - w3 *
c3, q3d - w1 - (- w2 * c3 + w3 * s3) * s2 / c2]
if rot_order == '312':
return [q1d - (-w1 * s3 + w3 * c3) / c2, q2d - w1 * c3 - w3 *
s3, q3d - (w1 * s3 - w3 * c3) * s2 / c2 - w2]
if rot_order == '132':
return [q1d - (w1 * c3 + w3 * s3) / c2, q2d + w1 * s3 - w3 *
c3, q3d - (w1 * c3 + w3 * s3) * s2 / c2 - w2]
if rot_order == '213':
return [q1d - (w1 * s3 + w2 * c3) / c2, q2d - w1 * c3 + w2 *
s3, q3d - (w1 * s3 + w2 * c3) * s2 / c2 - w3]
if rot_order == '321':
return [q1d - (w2 * s3 + w3 * c3) / c2, q2d - w2 * c3 + w3 *
s3, q3d - w1 - (w2 * s3 + w3 * c3) * s2 / c2]
if rot_order == '121':
return [q1d - (w2 * s3 + w3 * c3) / s2, q2d - w2 * c3 + w3 *
s3, q3d - w1 + (w2 * s3 + w3 * c3) * c2 / s2]
if rot_order == '131':
return [q1d - (-w2 * c3 + w3 * s3) / s2, q2d - w2 * s3 - w3 *
c3, q3d - w1 - (w2 * c3 - w3 * s3) * c2 / s2]
if rot_order == '212':
return [q1d - (w1 * s3 - w3 * c3) / s2, q2d - w1 * c3 - w3 *
s3, q3d - (-w1 * s3 + w3 * c3) * c2 / s2 - w2]
if rot_order == '232':
return [q1d - (w1 * c3 + w3 * s3) / s2, q2d + w1 * s3 - w3 *
c3, q3d + (w1 * c3 + w3 * s3) * c2 / s2 - w2]
if rot_order == '313':
return [q1d - (w1 * s3 + w2 * c3) / s2, q2d - w1 * c3 + w2 *
s3, q3d + (w1 * s3 + w2 * c3) * c2 / s2 - w3]
if rot_order == '323':
return [q1d - (-w1 * c3 + w2 * s3) / s2, q2d - w1 * s3 - w2 *
c3, q3d - (w1 * c3 - w2 * s3) * c2 / s2 - w3]
if rot_type == 'space':
if rot_order == '123':
return [q1d - w1 - (w2 * s1 + w3 * c1) * s2 / c2, q2d - w2 *
c1 + w3 * s1, q3d - (w2 * s1 + w3 * c1) / c2]
if rot_order == '231':
return [q1d - (w1 * c1 + w3 * s1) * s2 / c2 - w2, q2d + w1 *
s1 - w3 * c1, q3d - (w1 * c1 + w3 * s1) / c2]
if rot_order == '312':
return [q1d - (w1 * s1 + w2 * c1) * s2 / c2 - w3, q2d - w1 *
c1 + w2 * s1, q3d - (w1 * s1 + w2 * c1) / c2]
if rot_order == '132':
return [q1d - w1 - (-w2 * c1 + w3 * s1) * s2 / c2, q2d - w2 *
s1 - w3 * c1, q3d - (w2 * c1 - w3 * s1) / c2]
if rot_order == '213':
return [q1d - (w1 * s1 - w3 * c1) * s2 / c2 - w2, q2d - w1 *
c1 - w3 * s1, q3d - (-w1 * s1 + w3 * c1) / c2]
if rot_order == '321':
return [q1d - (-w1 * c1 + w2 * s1) * s2 / c2 - w3, q2d - w1 *
s1 - w2 * c1, q3d - (w1 * c1 - w2 * s1) / c2]
if rot_order == '121':
return [q1d - w1 + (w2 * s1 + w3 * c1) * c2 / s2, q2d - w2 *
c1 + w3 * s1, q3d - (w2 * s1 + w3 * c1) / s2]
if rot_order == '131':
return [q1d - w1 - (w2 * c1 - w3 * s1) * c2 / s2, q2d - w2 *
s1 - w3 * c1, q3d - (-w2 * c1 + w3 * s1) / s2]
if rot_order == '212':
return [q1d - (-w1 * s1 + w3 * c1) * c2 / s2 - w2, q2d - w1 *
c1 - w3 * s1, q3d - (w1 * s1 - w3 * c1) / s2]
if rot_order == '232':
return [q1d + (w1 * c1 + w3 * s1) * c2 / s2 - w2, q2d + w1 *
s1 - w3 * c1, q3d - (w1 * c1 + w3 * s1) / s2]
if rot_order == '313':
return [q1d + (w1 * s1 + w2 * c1) * c2 / s2 - w3, q2d - w1 *
c1 + w2 * s1, q3d - (w1 * s1 + w2 * c1) / s2]
if rot_order == '323':
return [q1d - (w1 * c1 - w2 * s1) * c2 / s2 - w3, q2d - w1 *
s1 - w2 * c1, q3d - (-w1 * c1 + w2 * s1) / s2]
elif rot_type == 'quaternion':
if rot_order != '':
raise ValueError('Cannot have rotation order for quaternion')
if len(coords) != 4:
raise ValueError('Need 4 coordinates for quaternion')
# Actual hard-coded kinematic differential equations
e0, e1, e2, e3 = coords
w = Matrix(speeds + [0])
E = Matrix([[e0, -e3, e2, e1],
[e3, e0, -e1, e2],
[-e2, e1, e0, e3],
[-e1, -e2, -e3, e0]])
edots = Matrix([diff(i, dynamicsymbols._t) for i in [e1, e2, e3, e0]])
return list(edots.T - 0.5 * w.T * E.T)
else:
raise ValueError('Not an approved rotation type for this function')
def get_motion_params(frame, **kwargs):
"""
Returns the three motion parameters - (acceleration, velocity, and
position) as vectorial functions of time in the given frame.
If a higher order differential function is provided, the lower order
functions are used as boundary conditions. For example, given the
acceleration, the velocity and position parameters are taken as
boundary conditions.
The values of time at which the boundary conditions are specified
are taken from timevalue1(for position boundary condition) and
timevalue2(for velocity boundary condition).
If any of the boundary conditions are not provided, they are taken
to be zero by default (zero vectors, in case of vectorial inputs). If
the boundary conditions are also functions of time, they are converted
to constants by substituting the time values in the dynamicsymbols._t
time Symbol.
This function can also be used for calculating rotational motion
parameters. Have a look at the Parameters and Examples for more clarity.
Parameters
==========
frame : ReferenceFrame
The frame to express the motion parameters in
acceleration : Vector
Acceleration of the object/frame as a function of time
velocity : Vector
Velocity as function of time or as boundary condition
of velocity at time = timevalue1
position : Vector
Velocity as function of time or as boundary condition
of velocity at time = timevalue1
timevalue1 : sympyfiable
Value of time for position boundary condition
timevalue2 : sympyfiable
Value of time for velocity boundary condition
Examples
========
>>> from sympy.physics.vector import ReferenceFrame, get_motion_params, dynamicsymbols
>>> from sympy.physics.vector import init_vprinting
>>> init_vprinting(pretty_print=False)
>>> from sympy import symbols
>>> R = ReferenceFrame('R')
>>> v1, v2, v3 = dynamicsymbols('v1 v2 v3')
>>> v = v1*R.x + v2*R.y + v3*R.z
>>> get_motion_params(R, position = v)
(v1''*R.x + v2''*R.y + v3''*R.z, v1'*R.x + v2'*R.y + v3'*R.z, v1*R.x + v2*R.y + v3*R.z)
>>> a, b, c = symbols('a b c')
>>> v = a*R.x + b*R.y + c*R.z
>>> get_motion_params(R, velocity = v)
(0, a*R.x + b*R.y + c*R.z, a*t*R.x + b*t*R.y + c*t*R.z)
>>> parameters = get_motion_params(R, acceleration = v)
>>> parameters[1]
a*t*R.x + b*t*R.y + c*t*R.z
>>> parameters[2]
a*t**2/2*R.x + b*t**2/2*R.y + c*t**2/2*R.z
"""
def _process_vector_differential(vectdiff, condition, variable, ordinate,
frame):
"""
Helper function for get_motion methods. Finds derivative of vectdiff
wrt variable, and its integral using the specified boundary condition
at value of variable = ordinate.
Returns a tuple of - (derivative, function and integral) wrt vectdiff
"""
# Make sure boundary condition is independent of 'variable'
if condition != 0:
condition = express(condition, frame, variables=True)
# Special case of vectdiff == 0
if vectdiff == Vector(0):
return (0, 0, condition)
# Express vectdiff completely in condition's frame to give vectdiff1
vectdiff1 = express(vectdiff, frame)
# Find derivative of vectdiff
vectdiff2 = time_derivative(vectdiff, frame)
# Integrate and use boundary condition
vectdiff0 = Vector(0)
lims = (variable, ordinate, variable)
for dim in frame:
function1 = vectdiff1.dot(dim)
abscissa = dim.dot(condition).subs({variable: ordinate})
# Indefinite integral of 'function1' wrt 'variable', using
# the given initial condition (ordinate, abscissa).
vectdiff0 += (integrate(function1, lims) + abscissa) * dim
# Return tuple
return (vectdiff2, vectdiff, vectdiff0)
_check_frame(frame)
# Decide mode of operation based on user's input
if 'acceleration' in kwargs:
mode = 2
elif 'velocity' in kwargs:
mode = 1
else:
mode = 0
# All the possible parameters in kwargs
# Not all are required for every case
# If not specified, set to default values(may or may not be used in
# calculations)
conditions = ['acceleration', 'velocity', 'position',
'timevalue', 'timevalue1', 'timevalue2']
for i, x in enumerate(conditions):
if x not in kwargs:
if i < 3:
kwargs[x] = Vector(0)
else:
kwargs[x] = S.Zero
elif i < 3:
_check_vector(kwargs[x])
else:
kwargs[x] = sympify(kwargs[x])
if mode == 2:
vel = _process_vector_differential(kwargs['acceleration'],
kwargs['velocity'],
dynamicsymbols._t,
kwargs['timevalue2'], frame)[2]
pos = _process_vector_differential(vel, kwargs['position'],
dynamicsymbols._t,
kwargs['timevalue1'], frame)[2]
return (kwargs['acceleration'], vel, pos)
elif mode == 1:
return _process_vector_differential(kwargs['velocity'],
kwargs['position'],
dynamicsymbols._t,
kwargs['timevalue1'], frame)
else:
vel = time_derivative(kwargs['position'], frame)
acc = time_derivative(vel, frame)
return (acc, vel, kwargs['position'])
def partial_velocity(vel_vecs, gen_speeds, frame):
"""Returns a list of partial velocities with respect to the provided
generalized speeds in the given reference frame for each of the supplied
velocity vectors.
The output is a list of lists. The outer list has a number of elements
equal to the number of supplied velocity vectors. The inner lists are, for
each velocity vector, the partial derivatives of that velocity vector with
respect to the generalized speeds supplied.
Parameters
==========
vel_vecs : iterable
An iterable of velocity vectors (angular or linear).
gen_speeds : iterable
An iterable of generalized speeds.
frame : ReferenceFrame
The reference frame that the partial derivatives are going to be taken
in.
Examples
========
>>> from sympy.physics.vector import Point, ReferenceFrame
>>> from sympy.physics.vector import dynamicsymbols
>>> from sympy.physics.vector import partial_velocity
>>> u = dynamicsymbols('u')
>>> N = ReferenceFrame('N')
>>> P = Point('P')
>>> P.set_vel(N, u * N.x)
>>> vel_vecs = [P.vel(N)]
>>> gen_speeds = [u]
>>> partial_velocity(vel_vecs, gen_speeds, N)
[[N.x]]
"""
if not iterable(vel_vecs):
raise TypeError('Velocity vectors must be contained in an iterable.')
if not iterable(gen_speeds):
raise TypeError('Generalized speeds must be contained in an iterable')
vec_partials = []
gen_speeds = list(gen_speeds)
for vel in vel_vecs:
partials = [Vector(0) for _ in gen_speeds]
for components, ref in vel.args:
mat, _ = linear_eq_to_matrix(components, gen_speeds)
for i in range(len(gen_speeds)):
for dim, direction in enumerate(ref):
if mat[dim, i] != 0:
partials[i] += direction * mat[dim, i]
vec_partials.append(partials)
return vec_partials
def dynamicsymbols(names, level=0, **assumptions):
"""Uses symbols and Function for functions of time.
Creates a SymPy UndefinedFunction, which is then initialized as a function
of a variable, the default being Symbol('t').
Parameters
==========
names : str
Names of the dynamic symbols you want to create; works the same way as
inputs to symbols
level : int
Level of differentiation of the returned function; d/dt once of t,
twice of t, etc.
assumptions :
- real(bool) : This is used to set the dynamicsymbol as real,
by default is False.
- positive(bool) : This is used to set the dynamicsymbol as positive,
by default is False.
- commutative(bool) : This is used to set the commutative property of
a dynamicsymbol, by default is True.
- integer(bool) : This is used to set the dynamicsymbol as integer,
by default is False.
Examples
========
>>> from sympy.physics.vector import dynamicsymbols
>>> from sympy import diff, Symbol
>>> q1 = dynamicsymbols('q1')
>>> q1
q1(t)
>>> q2 = dynamicsymbols('q2', real=True)
>>> q2.is_real
True
>>> q3 = dynamicsymbols('q3', positive=True)
>>> q3.is_positive
True
>>> q4, q5 = dynamicsymbols('q4,q5', commutative=False)
>>> bool(q4*q5 != q5*q4)
True
>>> q6 = dynamicsymbols('q6', integer=True)
>>> q6.is_integer
True
>>> diff(q1, Symbol('t'))
Derivative(q1(t), t)
"""
esses = symbols(names, cls=Function, **assumptions)
t = dynamicsymbols._t
if iterable(esses):
esses = [reduce(diff, [t] * level, e(t)) for e in esses]
return esses
else:
return reduce(diff, [t] * level, esses(t))
dynamicsymbols._t = Symbol('t') # type: ignore
dynamicsymbols._str = '\'' # type: ignore

View File

@ -0,0 +1,635 @@
from .vector import Vector, _check_vector
from .frame import _check_frame
from warnings import warn
from sympy.utilities.misc import filldedent
__all__ = ['Point']
class Point:
"""This object represents a point in a dynamic system.
It stores the: position, velocity, and acceleration of a point.
The position is a vector defined as the vector distance from a parent
point to this point.
Parameters
==========
name : string
The display name of the Point
Examples
========
>>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
>>> from sympy.physics.vector import init_vprinting
>>> init_vprinting(pretty_print=False)
>>> N = ReferenceFrame('N')
>>> O = Point('O')
>>> P = Point('P')
>>> u1, u2, u3 = dynamicsymbols('u1 u2 u3')
>>> O.set_vel(N, u1 * N.x + u2 * N.y + u3 * N.z)
>>> O.acc(N)
u1'*N.x + u2'*N.y + u3'*N.z
``symbols()`` can be used to create multiple Points in a single step, for
example:
>>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
>>> from sympy.physics.vector import init_vprinting
>>> init_vprinting(pretty_print=False)
>>> from sympy import symbols
>>> N = ReferenceFrame('N')
>>> u1, u2 = dynamicsymbols('u1 u2')
>>> A, B = symbols('A B', cls=Point)
>>> type(A)
<class 'sympy.physics.vector.point.Point'>
>>> A.set_vel(N, u1 * N.x + u2 * N.y)
>>> B.set_vel(N, u2 * N.x + u1 * N.y)
>>> A.acc(N) - B.acc(N)
(u1' - u2')*N.x + (-u1' + u2')*N.y
"""
def __init__(self, name):
"""Initialization of a Point object. """
self.name = name
self._pos_dict = {}
self._vel_dict = {}
self._acc_dict = {}
self._pdlist = [self._pos_dict, self._vel_dict, self._acc_dict]
def __str__(self):
return self.name
__repr__ = __str__
def _check_point(self, other):
if not isinstance(other, Point):
raise TypeError('A Point must be supplied')
def _pdict_list(self, other, num):
"""Returns a list of points that gives the shortest path with respect
to position, velocity, or acceleration from this point to the provided
point.
Parameters
==========
other : Point
A point that may be related to this point by position, velocity, or
acceleration.
num : integer
0 for searching the position tree, 1 for searching the velocity
tree, and 2 for searching the acceleration tree.
Returns
=======
list of Points
A sequence of points from self to other.
Notes
=====
It is not clear if num = 1 or num = 2 actually works because the keys
to ``_vel_dict`` and ``_acc_dict`` are :class:`ReferenceFrame` objects
which do not have the ``_pdlist`` attribute.
"""
outlist = [[self]]
oldlist = [[]]
while outlist != oldlist:
oldlist = outlist[:]
for v in outlist:
templist = v[-1]._pdlist[num].keys()
for v2 in templist:
if not v.__contains__(v2):
littletemplist = v + [v2]
if not outlist.__contains__(littletemplist):
outlist.append(littletemplist)
for v in oldlist:
if v[-1] != other:
outlist.remove(v)
outlist.sort(key=len)
if len(outlist) != 0:
return outlist[0]
raise ValueError('No Connecting Path found between ' + other.name +
' and ' + self.name)
def a1pt_theory(self, otherpoint, outframe, interframe):
"""Sets the acceleration of this point with the 1-point theory.
The 1-point theory for point acceleration looks like this:
^N a^P = ^B a^P + ^N a^O + ^N alpha^B x r^OP + ^N omega^B x (^N omega^B
x r^OP) + 2 ^N omega^B x ^B v^P
where O is a point fixed in B, P is a point moving in B, and B is
rotating in frame N.
Parameters
==========
otherpoint : Point
The first point of the 1-point theory (O)
outframe : ReferenceFrame
The frame we want this point's acceleration defined in (N)
fixedframe : ReferenceFrame
The intermediate frame in this calculation (B)
Examples
========
>>> from sympy.physics.vector import Point, ReferenceFrame
>>> from sympy.physics.vector import dynamicsymbols
>>> from sympy.physics.vector import init_vprinting
>>> init_vprinting(pretty_print=False)
>>> q = dynamicsymbols('q')
>>> q2 = dynamicsymbols('q2')
>>> qd = dynamicsymbols('q', 1)
>>> q2d = dynamicsymbols('q2', 1)
>>> N = ReferenceFrame('N')
>>> B = ReferenceFrame('B')
>>> B.set_ang_vel(N, 5 * B.y)
>>> O = Point('O')
>>> P = O.locatenew('P', q * B.x + q2 * B.y)
>>> P.set_vel(B, qd * B.x + q2d * B.y)
>>> O.set_vel(N, 0)
>>> P.a1pt_theory(O, N, B)
(-25*q + q'')*B.x + q2''*B.y - 10*q'*B.z
"""
_check_frame(outframe)
_check_frame(interframe)
self._check_point(otherpoint)
dist = self.pos_from(otherpoint)
v = self.vel(interframe)
a1 = otherpoint.acc(outframe)
a2 = self.acc(interframe)
omega = interframe.ang_vel_in(outframe)
alpha = interframe.ang_acc_in(outframe)
self.set_acc(outframe, a2 + 2 * (omega.cross(v)) + a1 +
(alpha.cross(dist)) + (omega.cross(omega.cross(dist))))
return self.acc(outframe)
def a2pt_theory(self, otherpoint, outframe, fixedframe):
"""Sets the acceleration of this point with the 2-point theory.
The 2-point theory for point acceleration looks like this:
^N a^P = ^N a^O + ^N alpha^B x r^OP + ^N omega^B x (^N omega^B x r^OP)
where O and P are both points fixed in frame B, which is rotating in
frame N.
Parameters
==========
otherpoint : Point
The first point of the 2-point theory (O)
outframe : ReferenceFrame
The frame we want this point's acceleration defined in (N)
fixedframe : ReferenceFrame
The frame in which both points are fixed (B)
Examples
========
>>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
>>> from sympy.physics.vector import init_vprinting
>>> init_vprinting(pretty_print=False)
>>> q = dynamicsymbols('q')
>>> qd = dynamicsymbols('q', 1)
>>> N = ReferenceFrame('N')
>>> B = N.orientnew('B', 'Axis', [q, N.z])
>>> O = Point('O')
>>> P = O.locatenew('P', 10 * B.x)
>>> O.set_vel(N, 5 * N.x)
>>> P.a2pt_theory(O, N, B)
- 10*q'**2*B.x + 10*q''*B.y
"""
_check_frame(outframe)
_check_frame(fixedframe)
self._check_point(otherpoint)
dist = self.pos_from(otherpoint)
a = otherpoint.acc(outframe)
omega = fixedframe.ang_vel_in(outframe)
alpha = fixedframe.ang_acc_in(outframe)
self.set_acc(outframe, a + (alpha.cross(dist)) +
(omega.cross(omega.cross(dist))))
return self.acc(outframe)
def acc(self, frame):
"""The acceleration Vector of this Point in a ReferenceFrame.
Parameters
==========
frame : ReferenceFrame
The frame in which the returned acceleration vector will be defined
in.
Examples
========
>>> from sympy.physics.vector import Point, ReferenceFrame
>>> N = ReferenceFrame('N')
>>> p1 = Point('p1')
>>> p1.set_acc(N, 10 * N.x)
>>> p1.acc(N)
10*N.x
"""
_check_frame(frame)
if not (frame in self._acc_dict):
if self.vel(frame) != 0:
return (self._vel_dict[frame]).dt(frame)
else:
return Vector(0)
return self._acc_dict[frame]
def locatenew(self, name, value):
"""Creates a new point with a position defined from this point.
Parameters
==========
name : str
The name for the new point
value : Vector
The position of the new point relative to this point
Examples
========
>>> from sympy.physics.vector import ReferenceFrame, Point
>>> N = ReferenceFrame('N')
>>> P1 = Point('P1')
>>> P2 = P1.locatenew('P2', 10 * N.x)
"""
if not isinstance(name, str):
raise TypeError('Must supply a valid name')
if value == 0:
value = Vector(0)
value = _check_vector(value)
p = Point(name)
p.set_pos(self, value)
self.set_pos(p, -value)
return p
def pos_from(self, otherpoint):
"""Returns a Vector distance between this Point and the other Point.
Parameters
==========
otherpoint : Point
The otherpoint we are locating this one relative to
Examples
========
>>> from sympy.physics.vector import Point, ReferenceFrame
>>> N = ReferenceFrame('N')
>>> p1 = Point('p1')
>>> p2 = Point('p2')
>>> p1.set_pos(p2, 10 * N.x)
>>> p1.pos_from(p2)
10*N.x
"""
outvec = Vector(0)
plist = self._pdict_list(otherpoint, 0)
for i in range(len(plist) - 1):
outvec += plist[i]._pos_dict[plist[i + 1]]
return outvec
def set_acc(self, frame, value):
"""Used to set the acceleration of this Point in a ReferenceFrame.
Parameters
==========
frame : ReferenceFrame
The frame in which this point's acceleration is defined
value : Vector
The vector value of this point's acceleration in the frame
Examples
========
>>> from sympy.physics.vector import Point, ReferenceFrame
>>> N = ReferenceFrame('N')
>>> p1 = Point('p1')
>>> p1.set_acc(N, 10 * N.x)
>>> p1.acc(N)
10*N.x
"""
if value == 0:
value = Vector(0)
value = _check_vector(value)
_check_frame(frame)
self._acc_dict.update({frame: value})
def set_pos(self, otherpoint, value):
"""Used to set the position of this point w.r.t. another point.
Parameters
==========
otherpoint : Point
The other point which this point's location is defined relative to
value : Vector
The vector which defines the location of this point
Examples
========
>>> from sympy.physics.vector import Point, ReferenceFrame
>>> N = ReferenceFrame('N')
>>> p1 = Point('p1')
>>> p2 = Point('p2')
>>> p1.set_pos(p2, 10 * N.x)
>>> p1.pos_from(p2)
10*N.x
"""
if value == 0:
value = Vector(0)
value = _check_vector(value)
self._check_point(otherpoint)
self._pos_dict.update({otherpoint: value})
otherpoint._pos_dict.update({self: -value})
def set_vel(self, frame, value):
"""Sets the velocity Vector of this Point in a ReferenceFrame.
Parameters
==========
frame : ReferenceFrame
The frame in which this point's velocity is defined
value : Vector
The vector value of this point's velocity in the frame
Examples
========
>>> from sympy.physics.vector import Point, ReferenceFrame
>>> N = ReferenceFrame('N')
>>> p1 = Point('p1')
>>> p1.set_vel(N, 10 * N.x)
>>> p1.vel(N)
10*N.x
"""
if value == 0:
value = Vector(0)
value = _check_vector(value)
_check_frame(frame)
self._vel_dict.update({frame: value})
def v1pt_theory(self, otherpoint, outframe, interframe):
"""Sets the velocity of this point with the 1-point theory.
The 1-point theory for point velocity looks like this:
^N v^P = ^B v^P + ^N v^O + ^N omega^B x r^OP
where O is a point fixed in B, P is a point moving in B, and B is
rotating in frame N.
Parameters
==========
otherpoint : Point
The first point of the 1-point theory (O)
outframe : ReferenceFrame
The frame we want this point's velocity defined in (N)
interframe : ReferenceFrame
The intermediate frame in this calculation (B)
Examples
========
>>> from sympy.physics.vector import Point, ReferenceFrame
>>> from sympy.physics.vector import dynamicsymbols
>>> from sympy.physics.vector import init_vprinting
>>> init_vprinting(pretty_print=False)
>>> q = dynamicsymbols('q')
>>> q2 = dynamicsymbols('q2')
>>> qd = dynamicsymbols('q', 1)
>>> q2d = dynamicsymbols('q2', 1)
>>> N = ReferenceFrame('N')
>>> B = ReferenceFrame('B')
>>> B.set_ang_vel(N, 5 * B.y)
>>> O = Point('O')
>>> P = O.locatenew('P', q * B.x + q2 * B.y)
>>> P.set_vel(B, qd * B.x + q2d * B.y)
>>> O.set_vel(N, 0)
>>> P.v1pt_theory(O, N, B)
q'*B.x + q2'*B.y - 5*q*B.z
"""
_check_frame(outframe)
_check_frame(interframe)
self._check_point(otherpoint)
dist = self.pos_from(otherpoint)
v1 = self.vel(interframe)
v2 = otherpoint.vel(outframe)
omega = interframe.ang_vel_in(outframe)
self.set_vel(outframe, v1 + v2 + (omega.cross(dist)))
return self.vel(outframe)
def v2pt_theory(self, otherpoint, outframe, fixedframe):
"""Sets the velocity of this point with the 2-point theory.
The 2-point theory for point velocity looks like this:
^N v^P = ^N v^O + ^N omega^B x r^OP
where O and P are both points fixed in frame B, which is rotating in
frame N.
Parameters
==========
otherpoint : Point
The first point of the 2-point theory (O)
outframe : ReferenceFrame
The frame we want this point's velocity defined in (N)
fixedframe : ReferenceFrame
The frame in which both points are fixed (B)
Examples
========
>>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
>>> from sympy.physics.vector import init_vprinting
>>> init_vprinting(pretty_print=False)
>>> q = dynamicsymbols('q')
>>> qd = dynamicsymbols('q', 1)
>>> N = ReferenceFrame('N')
>>> B = N.orientnew('B', 'Axis', [q, N.z])
>>> O = Point('O')
>>> P = O.locatenew('P', 10 * B.x)
>>> O.set_vel(N, 5 * N.x)
>>> P.v2pt_theory(O, N, B)
5*N.x + 10*q'*B.y
"""
_check_frame(outframe)
_check_frame(fixedframe)
self._check_point(otherpoint)
dist = self.pos_from(otherpoint)
v = otherpoint.vel(outframe)
omega = fixedframe.ang_vel_in(outframe)
self.set_vel(outframe, v + (omega.cross(dist)))
return self.vel(outframe)
def vel(self, frame):
"""The velocity Vector of this Point in the ReferenceFrame.
Parameters
==========
frame : ReferenceFrame
The frame in which the returned velocity vector will be defined in
Examples
========
>>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
>>> N = ReferenceFrame('N')
>>> p1 = Point('p1')
>>> p1.set_vel(N, 10 * N.x)
>>> p1.vel(N)
10*N.x
Velocities will be automatically calculated if possible, otherwise a
``ValueError`` will be returned. If it is possible to calculate
multiple different velocities from the relative points, the points
defined most directly relative to this point will be used. In the case
of inconsistent relative positions of points, incorrect velocities may
be returned. It is up to the user to define prior relative positions
and velocities of points in a self-consistent way.
>>> p = Point('p')
>>> q = dynamicsymbols('q')
>>> p.set_vel(N, 10 * N.x)
>>> p2 = Point('p2')
>>> p2.set_pos(p, q*N.x)
>>> p2.vel(N)
(Derivative(q(t), t) + 10)*N.x
"""
_check_frame(frame)
if not (frame in self._vel_dict):
valid_neighbor_found = False
is_cyclic = False
visited = []
queue = [self]
candidate_neighbor = []
while queue: # BFS to find nearest point
node = queue.pop(0)
if node not in visited:
visited.append(node)
for neighbor, neighbor_pos in node._pos_dict.items():
if neighbor in visited:
continue
try:
# Checks if pos vector is valid
neighbor_pos.express(frame)
except ValueError:
continue
if neighbor in queue:
is_cyclic = True
try:
# Checks if point has its vel defined in req frame
neighbor_velocity = neighbor._vel_dict[frame]
except KeyError:
queue.append(neighbor)
continue
candidate_neighbor.append(neighbor)
if not valid_neighbor_found:
self.set_vel(frame, self.pos_from(neighbor).dt(frame) + neighbor_velocity)
valid_neighbor_found = True
if is_cyclic:
warn(filldedent("""
Kinematic loops are defined among the positions of points. This
is likely not desired and may cause errors in your calculations.
"""))
if len(candidate_neighbor) > 1:
warn(filldedent(f"""
Velocity of {self.name} automatically calculated based on point
{candidate_neighbor[0].name} but it is also possible from
points(s): {str(candidate_neighbor[1:])}. Velocities from these
points are not necessarily the same. This may cause errors in
your calculations."""))
if valid_neighbor_found:
return self._vel_dict[frame]
else:
raise ValueError(filldedent(f"""
Velocity of point {self.name} has not been defined in
ReferenceFrame {frame.name}."""))
return self._vel_dict[frame]
def partial_velocity(self, frame, *gen_speeds):
"""Returns the partial velocities of the linear velocity vector of this
point in the given frame with respect to one or more provided
generalized speeds.
Parameters
==========
frame : ReferenceFrame
The frame with which the velocity is defined in.
gen_speeds : functions of time
The generalized speeds.
Returns
=======
partial_velocities : tuple of Vector
The partial velocity vectors corresponding to the provided
generalized speeds.
Examples
========
>>> from sympy.physics.vector import ReferenceFrame, Point
>>> from sympy.physics.vector import dynamicsymbols
>>> N = ReferenceFrame('N')
>>> A = ReferenceFrame('A')
>>> p = Point('p')
>>> u1, u2 = dynamicsymbols('u1, u2')
>>> p.set_vel(N, u1 * N.x + u2 * A.y)
>>> p.partial_velocity(N, u1)
N.x
>>> p.partial_velocity(N, u1, u2)
(N.x, A.y)
"""
from sympy.physics.vector.functions import partial_velocity
vel = self.vel(frame)
partials = partial_velocity([vel], gen_speeds, frame)[0]
if len(partials) == 1:
return partials[0]
else:
return tuple(partials)

View File

@ -0,0 +1,371 @@
from sympy.core.function import Derivative
from sympy.core.function import UndefinedFunction, AppliedUndef
from sympy.core.symbol import Symbol
from sympy.interactive.printing import init_printing
from sympy.printing.latex import LatexPrinter
from sympy.printing.pretty.pretty import PrettyPrinter
from sympy.printing.pretty.pretty_symbology import center_accent
from sympy.printing.str import StrPrinter
from sympy.printing.precedence import PRECEDENCE
__all__ = ['vprint', 'vsstrrepr', 'vsprint', 'vpprint', 'vlatex',
'init_vprinting']
class VectorStrPrinter(StrPrinter):
"""String Printer for vector expressions. """
def _print_Derivative(self, e):
from sympy.physics.vector.functions import dynamicsymbols
t = dynamicsymbols._t
if (bool(sum(i == t for i in e.variables)) &
isinstance(type(e.args[0]), UndefinedFunction)):
ol = str(e.args[0].func)
for i, v in enumerate(e.variables):
ol += dynamicsymbols._str
return ol
else:
return StrPrinter().doprint(e)
def _print_Function(self, e):
from sympy.physics.vector.functions import dynamicsymbols
t = dynamicsymbols._t
if isinstance(type(e), UndefinedFunction):
return StrPrinter().doprint(e).replace("(%s)" % t, '')
return e.func.__name__ + "(%s)" % self.stringify(e.args, ", ")
class VectorStrReprPrinter(VectorStrPrinter):
"""String repr printer for vector expressions."""
def _print_str(self, s):
return repr(s)
class VectorLatexPrinter(LatexPrinter):
"""Latex Printer for vector expressions. """
def _print_Function(self, expr, exp=None):
from sympy.physics.vector.functions import dynamicsymbols
func = expr.func.__name__
t = dynamicsymbols._t
if (hasattr(self, '_print_' + func) and not
isinstance(type(expr), UndefinedFunction)):
return getattr(self, '_print_' + func)(expr, exp)
elif isinstance(type(expr), UndefinedFunction) and (expr.args == (t,)):
# treat this function like a symbol
expr = Symbol(func)
if exp is not None:
# copied from LatexPrinter._helper_print_standard_power, which
# we can't call because we only have exp as a string.
base = self.parenthesize(expr, PRECEDENCE['Pow'])
base = self.parenthesize_super(base)
return r"%s^{%s}" % (base, exp)
else:
return super()._print(expr)
else:
return super()._print_Function(expr, exp)
def _print_Derivative(self, der_expr):
from sympy.physics.vector.functions import dynamicsymbols
# make sure it is in the right form
der_expr = der_expr.doit()
if not isinstance(der_expr, Derivative):
return r"\left(%s\right)" % self.doprint(der_expr)
# check if expr is a dynamicsymbol
t = dynamicsymbols._t
expr = der_expr.expr
red = expr.atoms(AppliedUndef)
syms = der_expr.variables
test1 = not all(True for i in red if i.free_symbols == {t})
test2 = not all(t == i for i in syms)
if test1 or test2:
return super()._print_Derivative(der_expr)
# done checking
dots = len(syms)
base = self._print_Function(expr)
base_split = base.split('_', 1)
base = base_split[0]
if dots == 1:
base = r"\dot{%s}" % base
elif dots == 2:
base = r"\ddot{%s}" % base
elif dots == 3:
base = r"\dddot{%s}" % base
elif dots == 4:
base = r"\ddddot{%s}" % base
else: # Fallback to standard printing
return super()._print_Derivative(der_expr)
if len(base_split) != 1:
base += '_' + base_split[1]
return base
class VectorPrettyPrinter(PrettyPrinter):
"""Pretty Printer for vectorialexpressions. """
def _print_Derivative(self, deriv):
from sympy.physics.vector.functions import dynamicsymbols
# XXX use U('PARTIAL DIFFERENTIAL') here ?
t = dynamicsymbols._t
dot_i = 0
syms = list(reversed(deriv.variables))
while len(syms) > 0:
if syms[-1] == t:
syms.pop()
dot_i += 1
else:
return super()._print_Derivative(deriv)
if not (isinstance(type(deriv.expr), UndefinedFunction) and
(deriv.expr.args == (t,))):
return super()._print_Derivative(deriv)
else:
pform = self._print_Function(deriv.expr)
# the following condition would happen with some sort of non-standard
# dynamic symbol I guess, so we'll just print the SymPy way
if len(pform.picture) > 1:
return super()._print_Derivative(deriv)
# There are only special symbols up to fourth-order derivatives
if dot_i >= 5:
return super()._print_Derivative(deriv)
# Deal with special symbols
dots = {0: "",
1: "\N{COMBINING DOT ABOVE}",
2: "\N{COMBINING DIAERESIS}",
3: "\N{COMBINING THREE DOTS ABOVE}",
4: "\N{COMBINING FOUR DOTS ABOVE}"}
d = pform.__dict__
# if unicode is false then calculate number of apostrophes needed and
# add to output
if not self._use_unicode:
apostrophes = ""
for i in range(0, dot_i):
apostrophes += "'"
d['picture'][0] += apostrophes + "(t)"
else:
d['picture'] = [center_accent(d['picture'][0], dots[dot_i])]
return pform
def _print_Function(self, e):
from sympy.physics.vector.functions import dynamicsymbols
t = dynamicsymbols._t
# XXX works only for applied functions
func = e.func
args = e.args
func_name = func.__name__
pform = self._print_Symbol(Symbol(func_name))
# If this function is an Undefined function of t, it is probably a
# dynamic symbol, so we'll skip the (t). The rest of the code is
# identical to the normal PrettyPrinter code
if not (isinstance(func, UndefinedFunction) and (args == (t,))):
return super()._print_Function(e)
return pform
def vprint(expr, **settings):
r"""Function for printing of expressions generated in the
sympy.physics vector package.
Extends SymPy's StrPrinter, takes the same setting accepted by SymPy's
:func:`~.sstr`, and is equivalent to ``print(sstr(foo))``.
Parameters
==========
expr : valid SymPy object
SymPy expression to print.
settings : args
Same as the settings accepted by SymPy's sstr().
Examples
========
>>> from sympy.physics.vector import vprint, dynamicsymbols
>>> u1 = dynamicsymbols('u1')
>>> print(u1)
u1(t)
>>> vprint(u1)
u1
"""
outstr = vsprint(expr, **settings)
import builtins
if (outstr != 'None'):
builtins._ = outstr
print(outstr)
def vsstrrepr(expr, **settings):
"""Function for displaying expression representation's with vector
printing enabled.
Parameters
==========
expr : valid SymPy object
SymPy expression to print.
settings : args
Same as the settings accepted by SymPy's sstrrepr().
"""
p = VectorStrReprPrinter(settings)
return p.doprint(expr)
def vsprint(expr, **settings):
r"""Function for displaying expressions generated in the
sympy.physics vector package.
Returns the output of vprint() as a string.
Parameters
==========
expr : valid SymPy object
SymPy expression to print
settings : args
Same as the settings accepted by SymPy's sstr().
Examples
========
>>> from sympy.physics.vector import vsprint, dynamicsymbols
>>> u1, u2 = dynamicsymbols('u1 u2')
>>> u2d = dynamicsymbols('u2', level=1)
>>> print("%s = %s" % (u1, u2 + u2d))
u1(t) = u2(t) + Derivative(u2(t), t)
>>> print("%s = %s" % (vsprint(u1), vsprint(u2 + u2d)))
u1 = u2 + u2'
"""
string_printer = VectorStrPrinter(settings)
return string_printer.doprint(expr)
def vpprint(expr, **settings):
r"""Function for pretty printing of expressions generated in the
sympy.physics vector package.
Mainly used for expressions not inside a vector; the output of running
scripts and generating equations of motion. Takes the same options as
SymPy's :func:`~.pretty_print`; see that function for more information.
Parameters
==========
expr : valid SymPy object
SymPy expression to pretty print
settings : args
Same as those accepted by SymPy's pretty_print.
"""
pp = VectorPrettyPrinter(settings)
# Note that this is copied from sympy.printing.pretty.pretty_print:
# XXX: this is an ugly hack, but at least it works
use_unicode = pp._settings['use_unicode']
from sympy.printing.pretty.pretty_symbology import pretty_use_unicode
uflag = pretty_use_unicode(use_unicode)
try:
return pp.doprint(expr)
finally:
pretty_use_unicode(uflag)
def vlatex(expr, **settings):
r"""Function for printing latex representation of sympy.physics.vector
objects.
For latex representation of Vectors, Dyadics, and dynamicsymbols. Takes the
same options as SymPy's :func:`~.latex`; see that function for more
information;
Parameters
==========
expr : valid SymPy object
SymPy expression to represent in LaTeX form
settings : args
Same as latex()
Examples
========
>>> from sympy.physics.vector import vlatex, ReferenceFrame, dynamicsymbols
>>> N = ReferenceFrame('N')
>>> q1, q2 = dynamicsymbols('q1 q2')
>>> q1d, q2d = dynamicsymbols('q1 q2', 1)
>>> q1dd, q2dd = dynamicsymbols('q1 q2', 2)
>>> vlatex(N.x + N.y)
'\\mathbf{\\hat{n}_x} + \\mathbf{\\hat{n}_y}'
>>> vlatex(q1 + q2)
'q_{1} + q_{2}'
>>> vlatex(q1d)
'\\dot{q}_{1}'
>>> vlatex(q1 * q2d)
'q_{1} \\dot{q}_{2}'
>>> vlatex(q1dd * q1 / q1d)
'\\frac{q_{1} \\ddot{q}_{1}}{\\dot{q}_{1}}'
"""
latex_printer = VectorLatexPrinter(settings)
return latex_printer.doprint(expr)
def init_vprinting(**kwargs):
"""Initializes time derivative printing for all SymPy objects, i.e. any
functions of time will be displayed in a more compact notation. The main
benefit of this is for printing of time derivatives; instead of
displaying as ``Derivative(f(t),t)``, it will display ``f'``. This is
only actually needed for when derivatives are present and are not in a
physics.vector.Vector or physics.vector.Dyadic object. This function is a
light wrapper to :func:`~.init_printing`. Any keyword
arguments for it are valid here.
{0}
Examples
========
>>> from sympy import Function, symbols
>>> t, x = symbols('t, x')
>>> omega = Function('omega')
>>> omega(x).diff()
Derivative(omega(x), x)
>>> omega(t).diff()
Derivative(omega(t), t)
Now use the string printer:
>>> from sympy.physics.vector import init_vprinting
>>> init_vprinting(pretty_print=False)
>>> omega(x).diff()
Derivative(omega(x), x)
>>> omega(t).diff()
omega'
"""
kwargs['str_printer'] = vsstrrepr
kwargs['pretty_printer'] = vpprint
kwargs['latex_printer'] = vlatex
init_printing(**kwargs)
params = init_printing.__doc__.split('Examples\n ========')[0] # type: ignore
init_vprinting.__doc__ = init_vprinting.__doc__.format(params) # type: ignore

View File

@ -0,0 +1,123 @@
from sympy.core.numbers import (Float, pi)
from sympy.core.symbol import symbols
from sympy.functions.elementary.trigonometric import (cos, sin)
from sympy.matrices.immutable import ImmutableDenseMatrix as Matrix
from sympy.physics.vector import ReferenceFrame, dynamicsymbols, outer
from sympy.physics.vector.dyadic import _check_dyadic
from sympy.testing.pytest import raises
A = ReferenceFrame('A')
def test_dyadic():
d1 = A.x | A.x
d2 = A.y | A.y
d3 = A.x | A.y
assert d1 * 0 == 0
assert d1 != 0
assert d1 * 2 == 2 * A.x | A.x
assert d1 / 2. == 0.5 * d1
assert d1 & (0 * d1) == 0
assert d1 & d2 == 0
assert d1 & A.x == A.x
assert d1 ^ A.x == 0
assert d1 ^ A.y == A.x | A.z
assert d1 ^ A.z == - A.x | A.y
assert d2 ^ A.x == - A.y | A.z
assert A.x ^ d1 == 0
assert A.y ^ d1 == - A.z | A.x
assert A.z ^ d1 == A.y | A.x
assert A.x & d1 == A.x
assert A.y & d1 == 0
assert A.y & d2 == A.y
assert d1 & d3 == A.x | A.y
assert d3 & d1 == 0
assert d1.dt(A) == 0
q = dynamicsymbols('q')
qd = dynamicsymbols('q', 1)
B = A.orientnew('B', 'Axis', [q, A.z])
assert d1.express(B) == d1.express(B, B)
assert d1.express(B) == ((cos(q)**2) * (B.x | B.x) + (-sin(q) * cos(q)) *
(B.x | B.y) + (-sin(q) * cos(q)) * (B.y | B.x) + (sin(q)**2) *
(B.y | B.y))
assert d1.express(B, A) == (cos(q)) * (B.x | A.x) + (-sin(q)) * (B.y | A.x)
assert d1.express(A, B) == (cos(q)) * (A.x | B.x) + (-sin(q)) * (A.x | B.y)
assert d1.dt(B) == (-qd) * (A.y | A.x) + (-qd) * (A.x | A.y)
assert d1.to_matrix(A) == Matrix([[1, 0, 0], [0, 0, 0], [0, 0, 0]])
assert d1.to_matrix(A, B) == Matrix([[cos(q), -sin(q), 0],
[0, 0, 0],
[0, 0, 0]])
assert d3.to_matrix(A) == Matrix([[0, 1, 0], [0, 0, 0], [0, 0, 0]])
a, b, c, d, e, f = symbols('a, b, c, d, e, f')
v1 = a * A.x + b * A.y + c * A.z
v2 = d * A.x + e * A.y + f * A.z
d4 = v1.outer(v2)
assert d4.to_matrix(A) == Matrix([[a * d, a * e, a * f],
[b * d, b * e, b * f],
[c * d, c * e, c * f]])
d5 = v1.outer(v1)
C = A.orientnew('C', 'Axis', [q, A.x])
for expected, actual in zip(C.dcm(A) * d5.to_matrix(A) * C.dcm(A).T,
d5.to_matrix(C)):
assert (expected - actual).simplify() == 0
raises(TypeError, lambda: d1.applyfunc(0))
def test_dyadic_simplify():
x, y, z, k, n, m, w, f, s, A = symbols('x, y, z, k, n, m, w, f, s, A')
N = ReferenceFrame('N')
dy = N.x | N.x
test1 = (1 / x + 1 / y) * dy
assert (N.x & test1 & N.x) != (x + y) / (x * y)
test1 = test1.simplify()
assert (N.x & test1 & N.x) == (x + y) / (x * y)
test2 = (A**2 * s**4 / (4 * pi * k * m**3)) * dy
test2 = test2.simplify()
assert (N.x & test2 & N.x) == (A**2 * s**4 / (4 * pi * k * m**3))
test3 = ((4 + 4 * x - 2 * (2 + 2 * x)) / (2 + 2 * x)) * dy
test3 = test3.simplify()
assert (N.x & test3 & N.x) == 0
test4 = ((-4 * x * y**2 - 2 * y**3 - 2 * x**2 * y) / (x + y)**2) * dy
test4 = test4.simplify()
assert (N.x & test4 & N.x) == -2 * y
def test_dyadic_subs():
N = ReferenceFrame('N')
s = symbols('s')
a = s*(N.x | N.x)
assert a.subs({s: 2}) == 2*(N.x | N.x)
def test_check_dyadic():
raises(TypeError, lambda: _check_dyadic(0))
def test_dyadic_evalf():
N = ReferenceFrame('N')
a = pi * (N.x | N.x)
assert a.evalf(3) == Float('3.1416', 3) * (N.x | N.x)
s = symbols('s')
a = 5 * s * pi* (N.x | N.x)
assert a.evalf(2) == Float('5', 2) * Float('3.1416', 2) * s * (N.x | N.x)
assert a.evalf(9, subs={s: 5.124}) == Float('80.48760378', 9) * (N.x | N.x)
def test_dyadic_xreplace():
x, y, z = symbols('x y z')
N = ReferenceFrame('N')
D = outer(N.x, N.x)
v = x*y * D
assert v.xreplace({x : cos(x)}) == cos(x)*y * D
assert v.xreplace({x*y : pi}) == pi * D
v = (x*y)**z * D
assert v.xreplace({(x*y)**z : 1}) == D
assert v.xreplace({x:1, z:0}) == D
raises(TypeError, lambda: v.xreplace())
raises(TypeError, lambda: v.xreplace([x, y]))

View File

@ -0,0 +1,133 @@
from sympy.core.singleton import S
from sympy.core.symbol import Symbol
from sympy.functions.elementary.trigonometric import (cos, sin)
from sympy.physics.vector import ReferenceFrame, Vector, Point, \
dynamicsymbols
from sympy.physics.vector.fieldfunctions import divergence, \
gradient, curl, is_conservative, is_solenoidal, \
scalar_potential, scalar_potential_difference
from sympy.testing.pytest import raises
R = ReferenceFrame('R')
q = dynamicsymbols('q')
P = R.orientnew('P', 'Axis', [q, R.z])
def test_curl():
assert curl(Vector(0), R) == Vector(0)
assert curl(R.x, R) == Vector(0)
assert curl(2*R[1]**2*R.y, R) == Vector(0)
assert curl(R[0]*R[1]*R.z, R) == R[0]*R.x - R[1]*R.y
assert curl(R[0]*R[1]*R[2] * (R.x+R.y+R.z), R) == \
(-R[0]*R[1] + R[0]*R[2])*R.x + (R[0]*R[1] - R[1]*R[2])*R.y + \
(-R[0]*R[2] + R[1]*R[2])*R.z
assert curl(2*R[0]**2*R.y, R) == 4*R[0]*R.z
assert curl(P[0]**2*R.x + P.y, R) == \
- 2*(R[0]*cos(q) + R[1]*sin(q))*sin(q)*R.z
assert curl(P[0]*R.y, P) == cos(q)*P.z
def test_divergence():
assert divergence(Vector(0), R) is S.Zero
assert divergence(R.x, R) is S.Zero
assert divergence(R[0]**2*R.x, R) == 2*R[0]
assert divergence(R[0]*R[1]*R[2] * (R.x+R.y+R.z), R) == \
R[0]*R[1] + R[0]*R[2] + R[1]*R[2]
assert divergence((1/(R[0]*R[1]*R[2])) * (R.x+R.y+R.z), R) == \
-1/(R[0]*R[1]*R[2]**2) - 1/(R[0]*R[1]**2*R[2]) - \
1/(R[0]**2*R[1]*R[2])
v = P[0]*P.x + P[1]*P.y + P[2]*P.z
assert divergence(v, P) == 3
assert divergence(v, R).simplify() == 3
assert divergence(P[0]*R.x + R[0]*P.x, R) == 2*cos(q)
def test_gradient():
a = Symbol('a')
assert gradient(0, R) == Vector(0)
assert gradient(R[0], R) == R.x
assert gradient(R[0]*R[1]*R[2], R) == \
R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z
assert gradient(2*R[0]**2, R) == 4*R[0]*R.x
assert gradient(a*sin(R[1])/R[0], R) == \
- a*sin(R[1])/R[0]**2*R.x + a*cos(R[1])/R[0]*R.y
assert gradient(P[0]*P[1], R) == \
((-R[0]*sin(q) + R[1]*cos(q))*cos(q) - (R[0]*cos(q) + R[1]*sin(q))*sin(q))*R.x + \
((-R[0]*sin(q) + R[1]*cos(q))*sin(q) + (R[0]*cos(q) + R[1]*sin(q))*cos(q))*R.y
assert gradient(P[0]*R[2], P) == P[2]*P.x + P[0]*P.z
scalar_field = 2*R[0]**2*R[1]*R[2]
grad_field = gradient(scalar_field, R)
vector_field = R[1]**2*R.x + 3*R[0]*R.y + 5*R[1]*R[2]*R.z
curl_field = curl(vector_field, R)
def test_conservative():
assert is_conservative(0) is True
assert is_conservative(R.x) is True
assert is_conservative(2 * R.x + 3 * R.y + 4 * R.z) is True
assert is_conservative(R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z) is \
True
assert is_conservative(R[0] * R.y) is False
assert is_conservative(grad_field) is True
assert is_conservative(curl_field) is False
assert is_conservative(4*R[0]*R[1]*R[2]*R.x + 2*R[0]**2*R[2]*R.y) is \
False
assert is_conservative(R[2]*P.x + P[0]*R.z) is True
def test_solenoidal():
assert is_solenoidal(0) is True
assert is_solenoidal(R.x) is True
assert is_solenoidal(2 * R.x + 3 * R.y + 4 * R.z) is True
assert is_solenoidal(R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z) is \
True
assert is_solenoidal(R[1] * R.y) is False
assert is_solenoidal(grad_field) is False
assert is_solenoidal(curl_field) is True
assert is_solenoidal((-2*R[1] + 3)*R.z) is True
assert is_solenoidal(cos(q)*R.x + sin(q)*R.y + cos(q)*P.z) is True
assert is_solenoidal(R[2]*P.x + P[0]*R.z) is True
def test_scalar_potential():
assert scalar_potential(0, R) == 0
assert scalar_potential(R.x, R) == R[0]
assert scalar_potential(R.y, R) == R[1]
assert scalar_potential(R.z, R) == R[2]
assert scalar_potential(R[1]*R[2]*R.x + R[0]*R[2]*R.y + \
R[0]*R[1]*R.z, R) == R[0]*R[1]*R[2]
assert scalar_potential(grad_field, R) == scalar_field
assert scalar_potential(R[2]*P.x + P[0]*R.z, R) == \
R[0]*R[2]*cos(q) + R[1]*R[2]*sin(q)
assert scalar_potential(R[2]*P.x + P[0]*R.z, P) == P[0]*P[2]
raises(ValueError, lambda: scalar_potential(R[0] * R.y, R))
def test_scalar_potential_difference():
origin = Point('O')
point1 = origin.locatenew('P1', 1*R.x + 2*R.y + 3*R.z)
point2 = origin.locatenew('P2', 4*R.x + 5*R.y + 6*R.z)
genericpointR = origin.locatenew('RP', R[0]*R.x + R[1]*R.y + R[2]*R.z)
genericpointP = origin.locatenew('PP', P[0]*P.x + P[1]*P.y + P[2]*P.z)
assert scalar_potential_difference(S.Zero, R, point1, point2, \
origin) == 0
assert scalar_potential_difference(scalar_field, R, origin, \
genericpointR, origin) == \
scalar_field
assert scalar_potential_difference(grad_field, R, origin, \
genericpointR, origin) == \
scalar_field
assert scalar_potential_difference(grad_field, R, point1, point2,
origin) == 948
assert scalar_potential_difference(R[1]*R[2]*R.x + R[0]*R[2]*R.y + \
R[0]*R[1]*R.z, R, point1,
genericpointR, origin) == \
R[0]*R[1]*R[2] - 6
potential_diff_P = 2*P[2]*(P[0]*sin(q) + P[1]*cos(q))*\
(P[0]*cos(q) - P[1]*sin(q))**2
assert scalar_potential_difference(grad_field, P, origin, \
genericpointP, \
origin).simplify() == \
potential_diff_P

View File

@ -0,0 +1,761 @@
from sympy.core.numbers import pi
from sympy.core.symbol import symbols
from sympy.simplify import trigsimp
from sympy.functions.elementary.trigonometric import (cos, sin)
from sympy.matrices.dense import (eye, zeros)
from sympy.matrices.immutable import ImmutableDenseMatrix as Matrix
from sympy.simplify.simplify import simplify
from sympy.physics.vector import (ReferenceFrame, Vector, CoordinateSym,
dynamicsymbols, time_derivative, express,
dot)
from sympy.physics.vector.frame import _check_frame
from sympy.physics.vector.vector import VectorTypeError
from sympy.testing.pytest import raises
import warnings
import pickle
def test_dict_list():
A = ReferenceFrame('A')
B = ReferenceFrame('B')
C = ReferenceFrame('C')
D = ReferenceFrame('D')
E = ReferenceFrame('E')
F = ReferenceFrame('F')
B.orient_axis(A, A.x, 1.0)
C.orient_axis(B, B.x, 1.0)
D.orient_axis(C, C.x, 1.0)
assert D._dict_list(A, 0) == [D, C, B, A]
E.orient_axis(D, D.x, 1.0)
assert C._dict_list(A, 0) == [C, B, A]
assert C._dict_list(E, 0) == [C, D, E]
# only 0, 1, 2 permitted for second argument
raises(ValueError, lambda: C._dict_list(E, 5))
# no connecting path
raises(ValueError, lambda: F._dict_list(A, 0))
def test_coordinate_vars():
"""Tests the coordinate variables functionality"""
A = ReferenceFrame('A')
assert CoordinateSym('Ax', A, 0) == A[0]
assert CoordinateSym('Ax', A, 1) == A[1]
assert CoordinateSym('Ax', A, 2) == A[2]
raises(ValueError, lambda: CoordinateSym('Ax', A, 3))
q = dynamicsymbols('q')
qd = dynamicsymbols('q', 1)
assert isinstance(A[0], CoordinateSym) and \
isinstance(A[0], CoordinateSym) and \
isinstance(A[0], CoordinateSym)
assert A.variable_map(A) == {A[0]:A[0], A[1]:A[1], A[2]:A[2]}
assert A[0].frame == A
B = A.orientnew('B', 'Axis', [q, A.z])
assert B.variable_map(A) == {B[2]: A[2], B[1]: -A[0]*sin(q) + A[1]*cos(q),
B[0]: A[0]*cos(q) + A[1]*sin(q)}
assert A.variable_map(B) == {A[0]: B[0]*cos(q) - B[1]*sin(q),
A[1]: B[0]*sin(q) + B[1]*cos(q), A[2]: B[2]}
assert time_derivative(B[0], A) == -A[0]*sin(q)*qd + A[1]*cos(q)*qd
assert time_derivative(B[1], A) == -A[0]*cos(q)*qd - A[1]*sin(q)*qd
assert time_derivative(B[2], A) == 0
assert express(B[0], A, variables=True) == A[0]*cos(q) + A[1]*sin(q)
assert express(B[1], A, variables=True) == -A[0]*sin(q) + A[1]*cos(q)
assert express(B[2], A, variables=True) == A[2]
assert time_derivative(A[0]*A.x + A[1]*A.y + A[2]*A.z, B) == A[1]*qd*A.x - A[0]*qd*A.y
assert time_derivative(B[0]*B.x + B[1]*B.y + B[2]*B.z, A) == - B[1]*qd*B.x + B[0]*qd*B.y
assert express(B[0]*B[1]*B[2], A, variables=True) == \
A[2]*(-A[0]*sin(q) + A[1]*cos(q))*(A[0]*cos(q) + A[1]*sin(q))
assert (time_derivative(B[0]*B[1]*B[2], A) -
(A[2]*(-A[0]**2*cos(2*q) -
2*A[0]*A[1]*sin(2*q) +
A[1]**2*cos(2*q))*qd)).trigsimp() == 0
assert express(B[0]*B.x + B[1]*B.y + B[2]*B.z, A) == \
(B[0]*cos(q) - B[1]*sin(q))*A.x + (B[0]*sin(q) + \
B[1]*cos(q))*A.y + B[2]*A.z
assert express(B[0]*B.x + B[1]*B.y + B[2]*B.z, A,
variables=True).simplify() == A[0]*A.x + A[1]*A.y + A[2]*A.z
assert express(A[0]*A.x + A[1]*A.y + A[2]*A.z, B) == \
(A[0]*cos(q) + A[1]*sin(q))*B.x + \
(-A[0]*sin(q) + A[1]*cos(q))*B.y + A[2]*B.z
assert express(A[0]*A.x + A[1]*A.y + A[2]*A.z, B,
variables=True).simplify() == B[0]*B.x + B[1]*B.y + B[2]*B.z
N = B.orientnew('N', 'Axis', [-q, B.z])
assert ({k: v.simplify() for k, v in N.variable_map(A).items()} ==
{N[0]: A[0], N[2]: A[2], N[1]: A[1]})
C = A.orientnew('C', 'Axis', [q, A.x + A.y + A.z])
mapping = A.variable_map(C)
assert trigsimp(mapping[A[0]]) == (2*C[0]*cos(q)/3 + C[0]/3 -
2*C[1]*sin(q + pi/6)/3 +
C[1]/3 - 2*C[2]*cos(q + pi/3)/3 +
C[2]/3)
assert trigsimp(mapping[A[1]]) == -2*C[0]*cos(q + pi/3)/3 + \
C[0]/3 + 2*C[1]*cos(q)/3 + C[1]/3 - 2*C[2]*sin(q + pi/6)/3 + C[2]/3
assert trigsimp(mapping[A[2]]) == -2*C[0]*sin(q + pi/6)/3 + C[0]/3 - \
2*C[1]*cos(q + pi/3)/3 + C[1]/3 + 2*C[2]*cos(q)/3 + C[2]/3
def test_ang_vel():
q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4')
q1d, q2d, q3d, q4d = dynamicsymbols('q1 q2 q3 q4', 1)
N = ReferenceFrame('N')
A = N.orientnew('A', 'Axis', [q1, N.z])
B = A.orientnew('B', 'Axis', [q2, A.x])
C = B.orientnew('C', 'Axis', [q3, B.y])
D = N.orientnew('D', 'Axis', [q4, N.y])
u1, u2, u3 = dynamicsymbols('u1 u2 u3')
assert A.ang_vel_in(N) == (q1d)*A.z
assert B.ang_vel_in(N) == (q2d)*B.x + (q1d)*A.z
assert C.ang_vel_in(N) == (q3d)*C.y + (q2d)*B.x + (q1d)*A.z
A2 = N.orientnew('A2', 'Axis', [q4, N.y])
assert N.ang_vel_in(N) == 0
assert N.ang_vel_in(A) == -q1d*N.z
assert N.ang_vel_in(B) == -q1d*A.z - q2d*B.x
assert N.ang_vel_in(C) == -q1d*A.z - q2d*B.x - q3d*B.y
assert N.ang_vel_in(A2) == -q4d*N.y
assert A.ang_vel_in(N) == q1d*N.z
assert A.ang_vel_in(A) == 0
assert A.ang_vel_in(B) == - q2d*B.x
assert A.ang_vel_in(C) == - q2d*B.x - q3d*B.y
assert A.ang_vel_in(A2) == q1d*N.z - q4d*N.y
assert B.ang_vel_in(N) == q1d*A.z + q2d*A.x
assert B.ang_vel_in(A) == q2d*A.x
assert B.ang_vel_in(B) == 0
assert B.ang_vel_in(C) == -q3d*B.y
assert B.ang_vel_in(A2) == q1d*A.z + q2d*A.x - q4d*N.y
assert C.ang_vel_in(N) == q1d*A.z + q2d*A.x + q3d*B.y
assert C.ang_vel_in(A) == q2d*A.x + q3d*C.y
assert C.ang_vel_in(B) == q3d*B.y
assert C.ang_vel_in(C) == 0
assert C.ang_vel_in(A2) == q1d*A.z + q2d*A.x + q3d*B.y - q4d*N.y
assert A2.ang_vel_in(N) == q4d*A2.y
assert A2.ang_vel_in(A) == q4d*A2.y - q1d*N.z
assert A2.ang_vel_in(B) == q4d*N.y - q1d*A.z - q2d*A.x
assert A2.ang_vel_in(C) == q4d*N.y - q1d*A.z - q2d*A.x - q3d*B.y
assert A2.ang_vel_in(A2) == 0
C.set_ang_vel(N, u1*C.x + u2*C.y + u3*C.z)
assert C.ang_vel_in(N) == (u1)*C.x + (u2)*C.y + (u3)*C.z
assert N.ang_vel_in(C) == (-u1)*C.x + (-u2)*C.y + (-u3)*C.z
assert C.ang_vel_in(D) == (u1)*C.x + (u2)*C.y + (u3)*C.z + (-q4d)*D.y
assert D.ang_vel_in(C) == (-u1)*C.x + (-u2)*C.y + (-u3)*C.z + (q4d)*D.y
q0 = dynamicsymbols('q0')
q0d = dynamicsymbols('q0', 1)
E = N.orientnew('E', 'Quaternion', (q0, q1, q2, q3))
assert E.ang_vel_in(N) == (
2 * (q1d * q0 + q2d * q3 - q3d * q2 - q0d * q1) * E.x +
2 * (q2d * q0 + q3d * q1 - q1d * q3 - q0d * q2) * E.y +
2 * (q3d * q0 + q1d * q2 - q2d * q1 - q0d * q3) * E.z)
F = N.orientnew('F', 'Body', (q1, q2, q3), 313)
assert F.ang_vel_in(N) == ((sin(q2)*sin(q3)*q1d + cos(q3)*q2d)*F.x +
(sin(q2)*cos(q3)*q1d - sin(q3)*q2d)*F.y + (cos(q2)*q1d + q3d)*F.z)
G = N.orientnew('G', 'Axis', (q1, N.x + N.y))
assert G.ang_vel_in(N) == q1d * (N.x + N.y).normalize()
assert N.ang_vel_in(G) == -q1d * (N.x + N.y).normalize()
def test_dcm():
q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4')
N = ReferenceFrame('N')
A = N.orientnew('A', 'Axis', [q1, N.z])
B = A.orientnew('B', 'Axis', [q2, A.x])
C = B.orientnew('C', 'Axis', [q3, B.y])
D = N.orientnew('D', 'Axis', [q4, N.y])
E = N.orientnew('E', 'Space', [q1, q2, q3], '123')
assert N.dcm(C) == Matrix([
[- sin(q1) * sin(q2) * sin(q3) + cos(q1) * cos(q3), - sin(q1) *
cos(q2), sin(q1) * sin(q2) * cos(q3) + sin(q3) * cos(q1)], [sin(q1) *
cos(q3) + sin(q2) * sin(q3) * cos(q1), cos(q1) * cos(q2), sin(q1) *
sin(q3) - sin(q2) * cos(q1) * cos(q3)], [- sin(q3) * cos(q2), sin(q2),
cos(q2) * cos(q3)]])
# This is a little touchy. Is it ok to use simplify in assert?
test_mat = D.dcm(C) - Matrix(
[[cos(q1) * cos(q3) * cos(q4) - sin(q3) * (- sin(q4) * cos(q2) +
sin(q1) * sin(q2) * cos(q4)), - sin(q2) * sin(q4) - sin(q1) *
cos(q2) * cos(q4), sin(q3) * cos(q1) * cos(q4) + cos(q3) * (- sin(q4) *
cos(q2) + sin(q1) * sin(q2) * cos(q4))], [sin(q1) * cos(q3) +
sin(q2) * sin(q3) * cos(q1), cos(q1) * cos(q2), sin(q1) * sin(q3) -
sin(q2) * cos(q1) * cos(q3)], [sin(q4) * cos(q1) * cos(q3) -
sin(q3) * (cos(q2) * cos(q4) + sin(q1) * sin(q2) * sin(q4)), sin(q2) *
cos(q4) - sin(q1) * sin(q4) * cos(q2), sin(q3) * sin(q4) * cos(q1) +
cos(q3) * (cos(q2) * cos(q4) + sin(q1) * sin(q2) * sin(q4))]])
assert test_mat.expand() == zeros(3, 3)
assert E.dcm(N) == Matrix(
[[cos(q2)*cos(q3), sin(q3)*cos(q2), -sin(q2)],
[sin(q1)*sin(q2)*cos(q3) - sin(q3)*cos(q1), sin(q1)*sin(q2)*sin(q3) +
cos(q1)*cos(q3), sin(q1)*cos(q2)], [sin(q1)*sin(q3) +
sin(q2)*cos(q1)*cos(q3), - sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1),
cos(q1)*cos(q2)]])
def test_w_diff_dcm1():
# Ref:
# Dynamics Theory and Applications, Kane 1985
# Sec. 2.1 ANGULAR VELOCITY
A = ReferenceFrame('A')
B = ReferenceFrame('B')
c11, c12, c13 = dynamicsymbols('C11 C12 C13')
c21, c22, c23 = dynamicsymbols('C21 C22 C23')
c31, c32, c33 = dynamicsymbols('C31 C32 C33')
c11d, c12d, c13d = dynamicsymbols('C11 C12 C13', level=1)
c21d, c22d, c23d = dynamicsymbols('C21 C22 C23', level=1)
c31d, c32d, c33d = dynamicsymbols('C31 C32 C33', level=1)
DCM = Matrix([
[c11, c12, c13],
[c21, c22, c23],
[c31, c32, c33]
])
B.orient(A, 'DCM', DCM)
b1a = (B.x).express(A)
b2a = (B.y).express(A)
b3a = (B.z).express(A)
# Equation (2.1.1)
B.set_ang_vel(A, B.x*(dot((b3a).dt(A), B.y))
+ B.y*(dot((b1a).dt(A), B.z))
+ B.z*(dot((b2a).dt(A), B.x)))
# Equation (2.1.21)
expr = ( (c12*c13d + c22*c23d + c32*c33d)*B.x
+ (c13*c11d + c23*c21d + c33*c31d)*B.y
+ (c11*c12d + c21*c22d + c31*c32d)*B.z)
assert B.ang_vel_in(A) - expr == 0
def test_w_diff_dcm2():
q1, q2, q3 = dynamicsymbols('q1:4')
N = ReferenceFrame('N')
A = N.orientnew('A', 'axis', [q1, N.x])
B = A.orientnew('B', 'axis', [q2, A.y])
C = B.orientnew('C', 'axis', [q3, B.z])
DCM = C.dcm(N).T
D = N.orientnew('D', 'DCM', DCM)
# Frames D and C are the same ReferenceFrame,
# since they have equal DCM respect to frame N.
# Therefore, D and C should have same angle velocity in N.
assert D.dcm(N) == C.dcm(N) == Matrix([
[cos(q2)*cos(q3), sin(q1)*sin(q2)*cos(q3) +
sin(q3)*cos(q1), sin(q1)*sin(q3) -
sin(q2)*cos(q1)*cos(q3)], [-sin(q3)*cos(q2),
-sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3),
sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1)],
[sin(q2), -sin(q1)*cos(q2), cos(q1)*cos(q2)]])
assert (D.ang_vel_in(N) - C.ang_vel_in(N)).express(N).simplify() == 0
def test_orientnew_respects_parent_class():
class MyReferenceFrame(ReferenceFrame):
pass
B = MyReferenceFrame('B')
C = B.orientnew('C', 'Axis', [0, B.x])
assert isinstance(C, MyReferenceFrame)
def test_orientnew_respects_input_indices():
N = ReferenceFrame('N')
q1 = dynamicsymbols('q1')
A = N.orientnew('a', 'Axis', [q1, N.z])
#modify default indices:
minds = [x+'1' for x in N.indices]
B = N.orientnew('b', 'Axis', [q1, N.z], indices=minds)
assert N.indices == A.indices
assert B.indices == minds
def test_orientnew_respects_input_latexs():
N = ReferenceFrame('N')
q1 = dynamicsymbols('q1')
A = N.orientnew('a', 'Axis', [q1, N.z])
#build default and alternate latex_vecs:
def_latex_vecs = [(r"\mathbf{\hat{%s}_%s}" % (A.name.lower(),
A.indices[0])), (r"\mathbf{\hat{%s}_%s}" %
(A.name.lower(), A.indices[1])),
(r"\mathbf{\hat{%s}_%s}" % (A.name.lower(),
A.indices[2]))]
name = 'b'
indices = [x+'1' for x in N.indices]
new_latex_vecs = [(r"\mathbf{\hat{%s}_{%s}}" % (name.lower(),
indices[0])), (r"\mathbf{\hat{%s}_{%s}}" %
(name.lower(), indices[1])),
(r"\mathbf{\hat{%s}_{%s}}" % (name.lower(),
indices[2]))]
B = N.orientnew(name, 'Axis', [q1, N.z], latexs=new_latex_vecs)
assert A.latex_vecs == def_latex_vecs
assert B.latex_vecs == new_latex_vecs
assert B.indices != indices
def test_orientnew_respects_input_variables():
N = ReferenceFrame('N')
q1 = dynamicsymbols('q1')
A = N.orientnew('a', 'Axis', [q1, N.z])
#build non-standard variable names
name = 'b'
new_variables = ['notb_'+x+'1' for x in N.indices]
B = N.orientnew(name, 'Axis', [q1, N.z], variables=new_variables)
for j,var in enumerate(A.varlist):
assert var.name == A.name + '_' + A.indices[j]
for j,var in enumerate(B.varlist):
assert var.name == new_variables[j]
def test_issue_10348():
u = dynamicsymbols('u:3')
I = ReferenceFrame('I')
I.orientnew('A', 'space', u, 'XYZ')
def test_issue_11503():
A = ReferenceFrame("A")
A.orientnew("B", "Axis", [35, A.y])
C = ReferenceFrame("C")
A.orient(C, "Axis", [70, C.z])
def test_partial_velocity():
N = ReferenceFrame('N')
A = ReferenceFrame('A')
u1, u2 = dynamicsymbols('u1, u2')
A.set_ang_vel(N, u1 * A.x + u2 * N.y)
assert N.partial_velocity(A, u1) == -A.x
assert N.partial_velocity(A, u1, u2) == (-A.x, -N.y)
assert A.partial_velocity(N, u1) == A.x
assert A.partial_velocity(N, u1, u2) == (A.x, N.y)
assert N.partial_velocity(N, u1) == 0
assert A.partial_velocity(A, u1) == 0
def test_issue_11498():
A = ReferenceFrame('A')
B = ReferenceFrame('B')
# Identity transformation
A.orient(B, 'DCM', eye(3))
assert A.dcm(B) == Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
assert B.dcm(A) == Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
# x -> y
# y -> -z
# z -> -x
A.orient(B, 'DCM', Matrix([[0, 1, 0], [0, 0, -1], [-1, 0, 0]]))
assert B.dcm(A) == Matrix([[0, 1, 0], [0, 0, -1], [-1, 0, 0]])
assert A.dcm(B) == Matrix([[0, 0, -1], [1, 0, 0], [0, -1, 0]])
assert B.dcm(A).T == A.dcm(B)
def test_reference_frame():
raises(TypeError, lambda: ReferenceFrame(0))
raises(TypeError, lambda: ReferenceFrame('N', 0))
raises(ValueError, lambda: ReferenceFrame('N', [0, 1]))
raises(TypeError, lambda: ReferenceFrame('N', [0, 1, 2]))
raises(TypeError, lambda: ReferenceFrame('N', ['a', 'b', 'c'], 0))
raises(ValueError, lambda: ReferenceFrame('N', ['a', 'b', 'c'], [0, 1]))
raises(TypeError, lambda: ReferenceFrame('N', ['a', 'b', 'c'], [0, 1, 2]))
raises(TypeError, lambda: ReferenceFrame('N', ['a', 'b', 'c'],
['a', 'b', 'c'], 0))
raises(ValueError, lambda: ReferenceFrame('N', ['a', 'b', 'c'],
['a', 'b', 'c'], [0, 1]))
raises(TypeError, lambda: ReferenceFrame('N', ['a', 'b', 'c'],
['a', 'b', 'c'], [0, 1, 2]))
N = ReferenceFrame('N')
assert N[0] == CoordinateSym('N_x', N, 0)
assert N[1] == CoordinateSym('N_y', N, 1)
assert N[2] == CoordinateSym('N_z', N, 2)
raises(ValueError, lambda: N[3])
N = ReferenceFrame('N', ['a', 'b', 'c'])
assert N['a'] == N.x
assert N['b'] == N.y
assert N['c'] == N.z
raises(ValueError, lambda: N['d'])
assert str(N) == 'N'
A = ReferenceFrame('A')
B = ReferenceFrame('B')
q0, q1, q2, q3 = symbols('q0 q1 q2 q3')
raises(TypeError, lambda: A.orient(B, 'DCM', 0))
raises(TypeError, lambda: B.orient(N, 'Space', [q1, q2, q3], '222'))
raises(TypeError, lambda: B.orient(N, 'Axis', [q1, N.x + 2 * N.y], '222'))
raises(TypeError, lambda: B.orient(N, 'Axis', q1))
raises(IndexError, lambda: B.orient(N, 'Axis', [q1]))
raises(TypeError, lambda: B.orient(N, 'Quaternion', [q0, q1, q2, q3], '222'))
raises(TypeError, lambda: B.orient(N, 'Quaternion', q0))
raises(TypeError, lambda: B.orient(N, 'Quaternion', [q0, q1, q2]))
raises(NotImplementedError, lambda: B.orient(N, 'Foo', [q0, q1, q2]))
raises(TypeError, lambda: B.orient(N, 'Body', [q1, q2], '232'))
raises(TypeError, lambda: B.orient(N, 'Space', [q1, q2], '232'))
N.set_ang_acc(B, 0)
assert N.ang_acc_in(B) == Vector(0)
N.set_ang_vel(B, 0)
assert N.ang_vel_in(B) == Vector(0)
def test_check_frame():
raises(VectorTypeError, lambda: _check_frame(0))
def test_dcm_diff_16824():
# NOTE : This is a regression test for the bug introduced in PR 14758,
# identified in 16824, and solved by PR 16828.
# This is the solution to Problem 2.2 on page 264 in Kane & Lenvinson's
# 1985 book.
q1, q2, q3 = dynamicsymbols('q1:4')
s1 = sin(q1)
c1 = cos(q1)
s2 = sin(q2)
c2 = cos(q2)
s3 = sin(q3)
c3 = cos(q3)
dcm = Matrix([[c2*c3, s1*s2*c3 - s3*c1, c1*s2*c3 + s3*s1],
[c2*s3, s1*s2*s3 + c3*c1, c1*s2*s3 - c3*s1],
[-s2, s1*c2, c1*c2]])
A = ReferenceFrame('A')
B = ReferenceFrame('B')
B.orient(A, 'DCM', dcm)
AwB = B.ang_vel_in(A)
alpha2 = s3*c2*q1.diff() + c3*q2.diff()
beta2 = s1*c2*q3.diff() + c1*q2.diff()
assert simplify(AwB.dot(A.y) - alpha2) == 0
assert simplify(AwB.dot(B.y) - beta2) == 0
def test_orient_explicit():
cxx, cyy, czz = dynamicsymbols('c_{xx}, c_{yy}, c_{zz}')
cxy, cxz, cyx = dynamicsymbols('c_{xy}, c_{xz}, c_{yx}')
cyz, czx, czy = dynamicsymbols('c_{yz}, c_{zx}, c_{zy}')
dcxx, dcyy, dczz = dynamicsymbols('c_{xx}, c_{yy}, c_{zz}', 1)
dcxy, dcxz, dcyx = dynamicsymbols('c_{xy}, c_{xz}, c_{yx}', 1)
dcyz, dczx, dczy = dynamicsymbols('c_{yz}, c_{zx}, c_{zy}', 1)
A = ReferenceFrame('A')
B = ReferenceFrame('B')
B_C_A = Matrix([[cxx, cxy, cxz],
[cyx, cyy, cyz],
[czx, czy, czz]])
B_w_A = ((cyx*dczx + cyy*dczy + cyz*dczz)*B.x +
(czx*dcxx + czy*dcxy + czz*dcxz)*B.y +
(cxx*dcyx + cxy*dcyy + cxz*dcyz)*B.z)
A.orient_explicit(B, B_C_A)
assert B.dcm(A) == B_C_A
assert A.ang_vel_in(B) == B_w_A
assert B.ang_vel_in(A) == -B_w_A
def test_orient_dcm():
cxx, cyy, czz = dynamicsymbols('c_{xx}, c_{yy}, c_{zz}')
cxy, cxz, cyx = dynamicsymbols('c_{xy}, c_{xz}, c_{yx}')
cyz, czx, czy = dynamicsymbols('c_{yz}, c_{zx}, c_{zy}')
B_C_A = Matrix([[cxx, cxy, cxz],
[cyx, cyy, cyz],
[czx, czy, czz]])
A = ReferenceFrame('A')
B = ReferenceFrame('B')
B.orient_dcm(A, B_C_A)
assert B.dcm(A) == Matrix([[cxx, cxy, cxz],
[cyx, cyy, cyz],
[czx, czy, czz]])
def test_orient_axis():
A = ReferenceFrame('A')
B = ReferenceFrame('B')
A.orient_axis(B,-B.x, 1)
A1 = A.dcm(B)
A.orient_axis(B, B.x, -1)
A2 = A.dcm(B)
A.orient_axis(B, 1, -B.x)
A3 = A.dcm(B)
assert A1 == A2
assert A2 == A3
raises(TypeError, lambda: A.orient_axis(B, 1, 1))
def test_orient_body():
A = ReferenceFrame('A')
B = ReferenceFrame('B')
B.orient_body_fixed(A, (1,1,0), 'XYX')
assert B.dcm(A) == Matrix([[cos(1), sin(1)**2, -sin(1)*cos(1)], [0, cos(1), sin(1)], [sin(1), -sin(1)*cos(1), cos(1)**2]])
def test_orient_body_advanced():
q1, q2, q3 = dynamicsymbols('q1:4')
c1, c2, c3 = symbols('c1:4')
u1, u2, u3 = dynamicsymbols('q1:4', 1)
# Test with everything as dynamicsymbols
A, B = ReferenceFrame('A'), ReferenceFrame('B')
B.orient_body_fixed(A, (q1, q2, q3), 'zxy')
assert A.dcm(B) == Matrix([
[-sin(q1) * sin(q2) * sin(q3) + cos(q1) * cos(q3), -sin(q1) * cos(q2),
sin(q1) * sin(q2) * cos(q3) + sin(q3) * cos(q1)],
[sin(q1) * cos(q3) + sin(q2) * sin(q3) * cos(q1), cos(q1) * cos(q2),
sin(q1) * sin(q3) - sin(q2) * cos(q1) * cos(q3)],
[-sin(q3) * cos(q2), sin(q2), cos(q2) * cos(q3)]])
assert B.ang_vel_in(A).to_matrix(B) == Matrix([
[-sin(q3) * cos(q2) * u1 + cos(q3) * u2],
[sin(q2) * u1 + u3],
[sin(q3) * u2 + cos(q2) * cos(q3) * u1]])
# Test with constant symbol
A, B = ReferenceFrame('A'), ReferenceFrame('B')
B.orient_body_fixed(A, (q1, c2, q3), 131)
assert A.dcm(B) == Matrix([
[cos(c2), -sin(c2) * cos(q3), sin(c2) * sin(q3)],
[sin(c2) * cos(q1), -sin(q1) * sin(q3) + cos(c2) * cos(q1) * cos(q3),
-sin(q1) * cos(q3) - sin(q3) * cos(c2) * cos(q1)],
[sin(c2) * sin(q1), sin(q1) * cos(c2) * cos(q3) + sin(q3) * cos(q1),
-sin(q1) * sin(q3) * cos(c2) + cos(q1) * cos(q3)]])
assert B.ang_vel_in(A).to_matrix(B) == Matrix([
[cos(c2) * u1 + u3],
[-sin(c2) * cos(q3) * u1],
[sin(c2) * sin(q3) * u1]])
# Test all symbols not time dependent
A, B = ReferenceFrame('A'), ReferenceFrame('B')
B.orient_body_fixed(A, (c1, c2, c3), 123)
assert B.ang_vel_in(A) == Vector(0)
def test_orient_space_advanced():
# space fixed is in the end like body fixed only in opposite order
q1, q2, q3 = dynamicsymbols('q1:4')
c1, c2, c3 = symbols('c1:4')
u1, u2, u3 = dynamicsymbols('q1:4', 1)
# Test with everything as dynamicsymbols
A, B = ReferenceFrame('A'), ReferenceFrame('B')
B.orient_space_fixed(A, (q3, q2, q1), 'yxz')
assert A.dcm(B) == Matrix([
[-sin(q1) * sin(q2) * sin(q3) + cos(q1) * cos(q3), -sin(q1) * cos(q2),
sin(q1) * sin(q2) * cos(q3) + sin(q3) * cos(q1)],
[sin(q1) * cos(q3) + sin(q2) * sin(q3) * cos(q1), cos(q1) * cos(q2),
sin(q1) * sin(q3) - sin(q2) * cos(q1) * cos(q3)],
[-sin(q3) * cos(q2), sin(q2), cos(q2) * cos(q3)]])
assert B.ang_vel_in(A).to_matrix(B) == Matrix([
[-sin(q3) * cos(q2) * u1 + cos(q3) * u2],
[sin(q2) * u1 + u3],
[sin(q3) * u2 + cos(q2) * cos(q3) * u1]])
# Test with constant symbol
A, B = ReferenceFrame('A'), ReferenceFrame('B')
B.orient_space_fixed(A, (q3, c2, q1), 131)
assert A.dcm(B) == Matrix([
[cos(c2), -sin(c2) * cos(q3), sin(c2) * sin(q3)],
[sin(c2) * cos(q1), -sin(q1) * sin(q3) + cos(c2) * cos(q1) * cos(q3),
-sin(q1) * cos(q3) - sin(q3) * cos(c2) * cos(q1)],
[sin(c2) * sin(q1), sin(q1) * cos(c2) * cos(q3) + sin(q3) * cos(q1),
-sin(q1) * sin(q3) * cos(c2) + cos(q1) * cos(q3)]])
assert B.ang_vel_in(A).to_matrix(B) == Matrix([
[cos(c2) * u1 + u3],
[-sin(c2) * cos(q3) * u1],
[sin(c2) * sin(q3) * u1]])
# Test all symbols not time dependent
A, B = ReferenceFrame('A'), ReferenceFrame('B')
B.orient_space_fixed(A, (c1, c2, c3), 123)
assert B.ang_vel_in(A) == Vector(0)
def test_orient_body_simple_ang_vel():
"""This test ensures that the simplest form of that linear system solution
is returned, thus the == for the expression comparison."""
psi, theta, phi = dynamicsymbols('psi, theta, varphi')
t = dynamicsymbols._t
A = ReferenceFrame('A')
B = ReferenceFrame('B')
B.orient_body_fixed(A, (psi, theta, phi), 'ZXZ')
A_w_B = B.ang_vel_in(A)
assert A_w_B.args[0][1] == B
assert A_w_B.args[0][0][0] == (sin(theta)*sin(phi)*psi.diff(t) +
cos(phi)*theta.diff(t))
assert A_w_B.args[0][0][1] == (sin(theta)*cos(phi)*psi.diff(t) -
sin(phi)*theta.diff(t))
assert A_w_B.args[0][0][2] == cos(theta)*psi.diff(t) + phi.diff(t)
def test_orient_space():
A = ReferenceFrame('A')
B = ReferenceFrame('B')
B.orient_space_fixed(A, (0,0,0), '123')
assert B.dcm(A) == Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
def test_orient_quaternion():
A = ReferenceFrame('A')
B = ReferenceFrame('B')
B.orient_quaternion(A, (0,0,0,0))
assert B.dcm(A) == Matrix([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
def test_looped_frame_warning():
A = ReferenceFrame('A')
B = ReferenceFrame('B')
C = ReferenceFrame('C')
a, b, c = symbols('a b c')
B.orient_axis(A, A.x, a)
C.orient_axis(B, B.x, b)
with warnings.catch_warnings(record = True) as w:
warnings.simplefilter("always")
A.orient_axis(C, C.x, c)
assert issubclass(w[-1].category, UserWarning)
assert 'Loops are defined among the orientation of frames. ' + \
'This is likely not desired and may cause errors in your calculations.' in str(w[-1].message)
def test_frame_dict():
A = ReferenceFrame('A')
B = ReferenceFrame('B')
C = ReferenceFrame('C')
a, b, c = symbols('a b c')
B.orient_axis(A, A.x, a)
assert A._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(a), -sin(a)],[0, sin(a), cos(a)]])}
assert B._dcm_dict == {A: Matrix([[1, 0, 0],[0, cos(a), sin(a)],[0, -sin(a), cos(a)]])}
assert C._dcm_dict == {}
B.orient_axis(C, C.x, b)
# Previous relation is not wiped
assert A._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(a), -sin(a)],[0, sin(a), cos(a)]])}
assert B._dcm_dict == {A: Matrix([[1, 0, 0],[0, cos(a), sin(a)],[0, -sin(a), cos(a)]]), \
C: Matrix([[1, 0, 0],[0, cos(b), sin(b)],[0, -sin(b), cos(b)]])}
assert C._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(b), -sin(b)],[0, sin(b), cos(b)]])}
A.orient_axis(B, B.x, c)
# Previous relation is updated
assert B._dcm_dict == {C: Matrix([[1, 0, 0],[0, cos(b), sin(b)],[0, -sin(b), cos(b)]]),\
A: Matrix([[1, 0, 0],[0, cos(c), -sin(c)],[0, sin(c), cos(c)]])}
assert A._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(c), sin(c)],[0, -sin(c), cos(c)]])}
assert C._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(b), -sin(b)],[0, sin(b), cos(b)]])}
def test_dcm_cache_dict():
A = ReferenceFrame('A')
B = ReferenceFrame('B')
C = ReferenceFrame('C')
D = ReferenceFrame('D')
a, b, c = symbols('a b c')
B.orient_axis(A, A.x, a)
C.orient_axis(B, B.x, b)
D.orient_axis(C, C.x, c)
assert D._dcm_dict == {C: Matrix([[1, 0, 0],[0, cos(c), sin(c)],[0, -sin(c), cos(c)]])}
assert C._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(b), sin(b)],[0, -sin(b), cos(b)]]), \
D: Matrix([[1, 0, 0],[0, cos(c), -sin(c)],[0, sin(c), cos(c)]])}
assert B._dcm_dict == {A: Matrix([[1, 0, 0],[0, cos(a), sin(a)],[0, -sin(a), cos(a)]]), \
C: Matrix([[1, 0, 0],[0, cos(b), -sin(b)],[0, sin(b), cos(b)]])}
assert A._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(a), -sin(a)],[0, sin(a), cos(a)]])}
assert D._dcm_dict == D._dcm_cache
D.dcm(A) # Check calculated dcm relation is stored in _dcm_cache and not in _dcm_dict
assert list(A._dcm_cache.keys()) == [A, B, D]
assert list(D._dcm_cache.keys()) == [C, A]
assert list(A._dcm_dict.keys()) == [B]
assert list(D._dcm_dict.keys()) == [C]
assert A._dcm_dict != A._dcm_cache
A.orient_axis(B, B.x, b) # _dcm_cache of A is wiped out and new relation is stored.
assert A._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(b), sin(b)],[0, -sin(b), cos(b)]])}
assert A._dcm_dict == A._dcm_cache
assert B._dcm_dict == {C: Matrix([[1, 0, 0],[0, cos(b), -sin(b)],[0, sin(b), cos(b)]]), \
A: Matrix([[1, 0, 0],[0, cos(b), -sin(b)],[0, sin(b), cos(b)]])}
def test_xx_dyad():
N = ReferenceFrame('N')
F = ReferenceFrame('F', indices=['1', '2', '3'])
assert N.xx == Vector.outer(N.x, N.x)
assert F.xx == Vector.outer(F.x, F.x)
def test_xy_dyad():
N = ReferenceFrame('N')
F = ReferenceFrame('F', indices=['1', '2', '3'])
assert N.xy == Vector.outer(N.x, N.y)
assert F.xy == Vector.outer(F.x, F.y)
def test_xz_dyad():
N = ReferenceFrame('N')
F = ReferenceFrame('F', indices=['1', '2', '3'])
assert N.xz == Vector.outer(N.x, N.z)
assert F.xz == Vector.outer(F.x, F.z)
def test_yx_dyad():
N = ReferenceFrame('N')
F = ReferenceFrame('F', indices=['1', '2', '3'])
assert N.yx == Vector.outer(N.y, N.x)
assert F.yx == Vector.outer(F.y, F.x)
def test_yy_dyad():
N = ReferenceFrame('N')
F = ReferenceFrame('F', indices=['1', '2', '3'])
assert N.yy == Vector.outer(N.y, N.y)
assert F.yy == Vector.outer(F.y, F.y)
def test_yz_dyad():
N = ReferenceFrame('N')
F = ReferenceFrame('F', indices=['1', '2', '3'])
assert N.yz == Vector.outer(N.y, N.z)
assert F.yz == Vector.outer(F.y, F.z)
def test_zx_dyad():
N = ReferenceFrame('N')
F = ReferenceFrame('F', indices=['1', '2', '3'])
assert N.zx == Vector.outer(N.z, N.x)
assert F.zx == Vector.outer(F.z, F.x)
def test_zy_dyad():
N = ReferenceFrame('N')
F = ReferenceFrame('F', indices=['1', '2', '3'])
assert N.zy == Vector.outer(N.z, N.y)
assert F.zy == Vector.outer(F.z, F.y)
def test_zz_dyad():
N = ReferenceFrame('N')
F = ReferenceFrame('F', indices=['1', '2', '3'])
assert N.zz == Vector.outer(N.z, N.z)
assert F.zz == Vector.outer(F.z, F.z)
def test_unit_dyadic():
N = ReferenceFrame('N')
F = ReferenceFrame('F', indices=['1', '2', '3'])
assert N.u == N.xx + N.yy + N.zz
assert F.u == F.xx + F.yy + F.zz
def test_pickle_frame():
N = ReferenceFrame('N')
A = ReferenceFrame('A')
A.orient_axis(N, N.x, 1)
A_C_N = A.dcm(N)
N1 = pickle.loads(pickle.dumps(N))
A1 = tuple(N1._dcm_dict.keys())[0]
assert A1.dcm(N1) == A_C_N

View File

@ -0,0 +1,509 @@
from sympy.core.numbers import pi
from sympy.core.singleton import S
from sympy.core.symbol import symbols
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import (cos, sin)
from sympy.integrals.integrals import Integral
from sympy.physics.vector import Dyadic, Point, ReferenceFrame, Vector
from sympy.physics.vector.functions import (cross, dot, express,
time_derivative,
kinematic_equations, outer,
partial_velocity,
get_motion_params, dynamicsymbols)
from sympy.simplify import trigsimp
from sympy.testing.pytest import raises
q1, q2, q3, q4, q5 = symbols('q1 q2 q3 q4 q5')
N = ReferenceFrame('N')
A = N.orientnew('A', 'Axis', [q1, N.z])
B = A.orientnew('B', 'Axis', [q2, A.x])
C = B.orientnew('C', 'Axis', [q3, B.y])
def test_dot():
assert dot(A.x, A.x) == 1
assert dot(A.x, A.y) == 0
assert dot(A.x, A.z) == 0
assert dot(A.y, A.x) == 0
assert dot(A.y, A.y) == 1
assert dot(A.y, A.z) == 0
assert dot(A.z, A.x) == 0
assert dot(A.z, A.y) == 0
assert dot(A.z, A.z) == 1
def test_dot_different_frames():
assert dot(N.x, A.x) == cos(q1)
assert dot(N.x, A.y) == -sin(q1)
assert dot(N.x, A.z) == 0
assert dot(N.y, A.x) == sin(q1)
assert dot(N.y, A.y) == cos(q1)
assert dot(N.y, A.z) == 0
assert dot(N.z, A.x) == 0
assert dot(N.z, A.y) == 0
assert dot(N.z, A.z) == 1
assert trigsimp(dot(N.x, A.x + A.y)) == sqrt(2)*cos(q1 + pi/4)
assert trigsimp(dot(N.x, A.x + A.y)) == trigsimp(dot(A.x + A.y, N.x))
assert dot(A.x, C.x) == cos(q3)
assert dot(A.x, C.y) == 0
assert dot(A.x, C.z) == sin(q3)
assert dot(A.y, C.x) == sin(q2)*sin(q3)
assert dot(A.y, C.y) == cos(q2)
assert dot(A.y, C.z) == -sin(q2)*cos(q3)
assert dot(A.z, C.x) == -cos(q2)*sin(q3)
assert dot(A.z, C.y) == sin(q2)
assert dot(A.z, C.z) == cos(q2)*cos(q3)
def test_cross():
assert cross(A.x, A.x) == 0
assert cross(A.x, A.y) == A.z
assert cross(A.x, A.z) == -A.y
assert cross(A.y, A.x) == -A.z
assert cross(A.y, A.y) == 0
assert cross(A.y, A.z) == A.x
assert cross(A.z, A.x) == A.y
assert cross(A.z, A.y) == -A.x
assert cross(A.z, A.z) == 0
def test_cross_different_frames():
assert cross(N.x, A.x) == sin(q1)*A.z
assert cross(N.x, A.y) == cos(q1)*A.z
assert cross(N.x, A.z) == -sin(q1)*A.x - cos(q1)*A.y
assert cross(N.y, A.x) == -cos(q1)*A.z
assert cross(N.y, A.y) == sin(q1)*A.z
assert cross(N.y, A.z) == cos(q1)*A.x - sin(q1)*A.y
assert cross(N.z, A.x) == A.y
assert cross(N.z, A.y) == -A.x
assert cross(N.z, A.z) == 0
assert cross(N.x, A.x) == sin(q1)*A.z
assert cross(N.x, A.y) == cos(q1)*A.z
assert cross(N.x, A.x + A.y) == sin(q1)*A.z + cos(q1)*A.z
assert cross(A.x + A.y, N.x) == -sin(q1)*A.z - cos(q1)*A.z
assert cross(A.x, C.x) == sin(q3)*C.y
assert cross(A.x, C.y) == -sin(q3)*C.x + cos(q3)*C.z
assert cross(A.x, C.z) == -cos(q3)*C.y
assert cross(C.x, A.x) == -sin(q3)*C.y
assert cross(C.y, A.x).express(C).simplify() == sin(q3)*C.x - cos(q3)*C.z
assert cross(C.z, A.x) == cos(q3)*C.y
def test_operator_match():
"""Test that the output of dot, cross, outer functions match
operator behavior.
"""
A = ReferenceFrame('A')
v = A.x + A.y
d = v | v
zerov = Vector(0)
zerod = Dyadic(0)
# dot products
assert d & d == dot(d, d)
assert d & zerod == dot(d, zerod)
assert zerod & d == dot(zerod, d)
assert d & v == dot(d, v)
assert v & d == dot(v, d)
assert d & zerov == dot(d, zerov)
assert zerov & d == dot(zerov, d)
raises(TypeError, lambda: dot(d, S.Zero))
raises(TypeError, lambda: dot(S.Zero, d))
raises(TypeError, lambda: dot(d, 0))
raises(TypeError, lambda: dot(0, d))
assert v & v == dot(v, v)
assert v & zerov == dot(v, zerov)
assert zerov & v == dot(zerov, v)
raises(TypeError, lambda: dot(v, S.Zero))
raises(TypeError, lambda: dot(S.Zero, v))
raises(TypeError, lambda: dot(v, 0))
raises(TypeError, lambda: dot(0, v))
# cross products
raises(TypeError, lambda: cross(d, d))
raises(TypeError, lambda: cross(d, zerod))
raises(TypeError, lambda: cross(zerod, d))
assert d ^ v == cross(d, v)
assert v ^ d == cross(v, d)
assert d ^ zerov == cross(d, zerov)
assert zerov ^ d == cross(zerov, d)
assert zerov ^ d == cross(zerov, d)
raises(TypeError, lambda: cross(d, S.Zero))
raises(TypeError, lambda: cross(S.Zero, d))
raises(TypeError, lambda: cross(d, 0))
raises(TypeError, lambda: cross(0, d))
assert v ^ v == cross(v, v)
assert v ^ zerov == cross(v, zerov)
assert zerov ^ v == cross(zerov, v)
raises(TypeError, lambda: cross(v, S.Zero))
raises(TypeError, lambda: cross(S.Zero, v))
raises(TypeError, lambda: cross(v, 0))
raises(TypeError, lambda: cross(0, v))
# outer products
raises(TypeError, lambda: outer(d, d))
raises(TypeError, lambda: outer(d, zerod))
raises(TypeError, lambda: outer(zerod, d))
raises(TypeError, lambda: outer(d, v))
raises(TypeError, lambda: outer(v, d))
raises(TypeError, lambda: outer(d, zerov))
raises(TypeError, lambda: outer(zerov, d))
raises(TypeError, lambda: outer(zerov, d))
raises(TypeError, lambda: outer(d, S.Zero))
raises(TypeError, lambda: outer(S.Zero, d))
raises(TypeError, lambda: outer(d, 0))
raises(TypeError, lambda: outer(0, d))
assert v | v == outer(v, v)
assert v | zerov == outer(v, zerov)
assert zerov | v == outer(zerov, v)
raises(TypeError, lambda: outer(v, S.Zero))
raises(TypeError, lambda: outer(S.Zero, v))
raises(TypeError, lambda: outer(v, 0))
raises(TypeError, lambda: outer(0, v))
def test_express():
assert express(Vector(0), N) == Vector(0)
assert express(S.Zero, N) is S.Zero
assert express(A.x, C) == cos(q3)*C.x + sin(q3)*C.z
assert express(A.y, C) == sin(q2)*sin(q3)*C.x + cos(q2)*C.y - \
sin(q2)*cos(q3)*C.z
assert express(A.z, C) == -sin(q3)*cos(q2)*C.x + sin(q2)*C.y + \
cos(q2)*cos(q3)*C.z
assert express(A.x, N) == cos(q1)*N.x + sin(q1)*N.y
assert express(A.y, N) == -sin(q1)*N.x + cos(q1)*N.y
assert express(A.z, N) == N.z
assert express(A.x, A) == A.x
assert express(A.y, A) == A.y
assert express(A.z, A) == A.z
assert express(A.x, B) == B.x
assert express(A.y, B) == cos(q2)*B.y - sin(q2)*B.z
assert express(A.z, B) == sin(q2)*B.y + cos(q2)*B.z
assert express(A.x, C) == cos(q3)*C.x + sin(q3)*C.z
assert express(A.y, C) == sin(q2)*sin(q3)*C.x + cos(q2)*C.y - \
sin(q2)*cos(q3)*C.z
assert express(A.z, C) == -sin(q3)*cos(q2)*C.x + sin(q2)*C.y + \
cos(q2)*cos(q3)*C.z
# Check to make sure UnitVectors get converted properly
assert express(N.x, N) == N.x
assert express(N.y, N) == N.y
assert express(N.z, N) == N.z
assert express(N.x, A) == (cos(q1)*A.x - sin(q1)*A.y)
assert express(N.y, A) == (sin(q1)*A.x + cos(q1)*A.y)
assert express(N.z, A) == A.z
assert express(N.x, B) == (cos(q1)*B.x - sin(q1)*cos(q2)*B.y +
sin(q1)*sin(q2)*B.z)
assert express(N.y, B) == (sin(q1)*B.x + cos(q1)*cos(q2)*B.y -
sin(q2)*cos(q1)*B.z)
assert express(N.z, B) == (sin(q2)*B.y + cos(q2)*B.z)
assert express(N.x, C) == (
(cos(q1)*cos(q3) - sin(q1)*sin(q2)*sin(q3))*C.x -
sin(q1)*cos(q2)*C.y +
(sin(q3)*cos(q1) + sin(q1)*sin(q2)*cos(q3))*C.z)
assert express(N.y, C) == (
(sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1))*C.x +
cos(q1)*cos(q2)*C.y +
(sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3))*C.z)
assert express(N.z, C) == (-sin(q3)*cos(q2)*C.x + sin(q2)*C.y +
cos(q2)*cos(q3)*C.z)
assert express(A.x, N) == (cos(q1)*N.x + sin(q1)*N.y)
assert express(A.y, N) == (-sin(q1)*N.x + cos(q1)*N.y)
assert express(A.z, N) == N.z
assert express(A.x, A) == A.x
assert express(A.y, A) == A.y
assert express(A.z, A) == A.z
assert express(A.x, B) == B.x
assert express(A.y, B) == (cos(q2)*B.y - sin(q2)*B.z)
assert express(A.z, B) == (sin(q2)*B.y + cos(q2)*B.z)
assert express(A.x, C) == (cos(q3)*C.x + sin(q3)*C.z)
assert express(A.y, C) == (sin(q2)*sin(q3)*C.x + cos(q2)*C.y -
sin(q2)*cos(q3)*C.z)
assert express(A.z, C) == (-sin(q3)*cos(q2)*C.x + sin(q2)*C.y +
cos(q2)*cos(q3)*C.z)
assert express(B.x, N) == (cos(q1)*N.x + sin(q1)*N.y)
assert express(B.y, N) == (-sin(q1)*cos(q2)*N.x +
cos(q1)*cos(q2)*N.y + sin(q2)*N.z)
assert express(B.z, N) == (sin(q1)*sin(q2)*N.x -
sin(q2)*cos(q1)*N.y + cos(q2)*N.z)
assert express(B.x, A) == A.x
assert express(B.y, A) == (cos(q2)*A.y + sin(q2)*A.z)
assert express(B.z, A) == (-sin(q2)*A.y + cos(q2)*A.z)
assert express(B.x, B) == B.x
assert express(B.y, B) == B.y
assert express(B.z, B) == B.z
assert express(B.x, C) == (cos(q3)*C.x + sin(q3)*C.z)
assert express(B.y, C) == C.y
assert express(B.z, C) == (-sin(q3)*C.x + cos(q3)*C.z)
assert express(C.x, N) == (
(cos(q1)*cos(q3) - sin(q1)*sin(q2)*sin(q3))*N.x +
(sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1))*N.y -
sin(q3)*cos(q2)*N.z)
assert express(C.y, N) == (
-sin(q1)*cos(q2)*N.x + cos(q1)*cos(q2)*N.y + sin(q2)*N.z)
assert express(C.z, N) == (
(sin(q3)*cos(q1) + sin(q1)*sin(q2)*cos(q3))*N.x +
(sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3))*N.y +
cos(q2)*cos(q3)*N.z)
assert express(C.x, A) == (cos(q3)*A.x + sin(q2)*sin(q3)*A.y -
sin(q3)*cos(q2)*A.z)
assert express(C.y, A) == (cos(q2)*A.y + sin(q2)*A.z)
assert express(C.z, A) == (sin(q3)*A.x - sin(q2)*cos(q3)*A.y +
cos(q2)*cos(q3)*A.z)
assert express(C.x, B) == (cos(q3)*B.x - sin(q3)*B.z)
assert express(C.y, B) == B.y
assert express(C.z, B) == (sin(q3)*B.x + cos(q3)*B.z)
assert express(C.x, C) == C.x
assert express(C.y, C) == C.y
assert express(C.z, C) == C.z == (C.z)
# Check to make sure Vectors get converted back to UnitVectors
assert N.x == express((cos(q1)*A.x - sin(q1)*A.y), N).simplify()
assert N.y == express((sin(q1)*A.x + cos(q1)*A.y), N).simplify()
assert N.x == express((cos(q1)*B.x - sin(q1)*cos(q2)*B.y +
sin(q1)*sin(q2)*B.z), N).simplify()
assert N.y == express((sin(q1)*B.x + cos(q1)*cos(q2)*B.y -
sin(q2)*cos(q1)*B.z), N).simplify()
assert N.z == express((sin(q2)*B.y + cos(q2)*B.z), N).simplify()
"""
These don't really test our code, they instead test the auto simplification
(or lack thereof) of SymPy.
assert N.x == express((
(cos(q1)*cos(q3)-sin(q1)*sin(q2)*sin(q3))*C.x -
sin(q1)*cos(q2)*C.y +
(sin(q3)*cos(q1)+sin(q1)*sin(q2)*cos(q3))*C.z), N)
assert N.y == express((
(sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1))*C.x +
cos(q1)*cos(q2)*C.y +
(sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3))*C.z), N)
assert N.z == express((-sin(q3)*cos(q2)*C.x + sin(q2)*C.y +
cos(q2)*cos(q3)*C.z), N)
"""
assert A.x == express((cos(q1)*N.x + sin(q1)*N.y), A).simplify()
assert A.y == express((-sin(q1)*N.x + cos(q1)*N.y), A).simplify()
assert A.y == express((cos(q2)*B.y - sin(q2)*B.z), A).simplify()
assert A.z == express((sin(q2)*B.y + cos(q2)*B.z), A).simplify()
assert A.x == express((cos(q3)*C.x + sin(q3)*C.z), A).simplify()
# Tripsimp messes up here too.
#print express((sin(q2)*sin(q3)*C.x + cos(q2)*C.y -
# sin(q2)*cos(q3)*C.z), A)
assert A.y == express((sin(q2)*sin(q3)*C.x + cos(q2)*C.y -
sin(q2)*cos(q3)*C.z), A).simplify()
assert A.z == express((-sin(q3)*cos(q2)*C.x + sin(q2)*C.y +
cos(q2)*cos(q3)*C.z), A).simplify()
assert B.x == express((cos(q1)*N.x + sin(q1)*N.y), B).simplify()
assert B.y == express((-sin(q1)*cos(q2)*N.x +
cos(q1)*cos(q2)*N.y + sin(q2)*N.z), B).simplify()
assert B.z == express((sin(q1)*sin(q2)*N.x -
sin(q2)*cos(q1)*N.y + cos(q2)*N.z), B).simplify()
assert B.y == express((cos(q2)*A.y + sin(q2)*A.z), B).simplify()
assert B.z == express((-sin(q2)*A.y + cos(q2)*A.z), B).simplify()
assert B.x == express((cos(q3)*C.x + sin(q3)*C.z), B).simplify()
assert B.z == express((-sin(q3)*C.x + cos(q3)*C.z), B).simplify()
"""
assert C.x == express((
(cos(q1)*cos(q3)-sin(q1)*sin(q2)*sin(q3))*N.x +
(sin(q1)*cos(q3)+sin(q2)*sin(q3)*cos(q1))*N.y -
sin(q3)*cos(q2)*N.z), C)
assert C.y == express((
-sin(q1)*cos(q2)*N.x + cos(q1)*cos(q2)*N.y + sin(q2)*N.z), C)
assert C.z == express((
(sin(q3)*cos(q1)+sin(q1)*sin(q2)*cos(q3))*N.x +
(sin(q1)*sin(q3)-sin(q2)*cos(q1)*cos(q3))*N.y +
cos(q2)*cos(q3)*N.z), C)
"""
assert C.x == express((cos(q3)*A.x + sin(q2)*sin(q3)*A.y -
sin(q3)*cos(q2)*A.z), C).simplify()
assert C.y == express((cos(q2)*A.y + sin(q2)*A.z), C).simplify()
assert C.z == express((sin(q3)*A.x - sin(q2)*cos(q3)*A.y +
cos(q2)*cos(q3)*A.z), C).simplify()
assert C.x == express((cos(q3)*B.x - sin(q3)*B.z), C).simplify()
assert C.z == express((sin(q3)*B.x + cos(q3)*B.z), C).simplify()
def test_time_derivative():
#The use of time_derivative for calculations pertaining to scalar
#fields has been tested in test_coordinate_vars in test_essential.py
A = ReferenceFrame('A')
q = dynamicsymbols('q')
qd = dynamicsymbols('q', 1)
B = A.orientnew('B', 'Axis', [q, A.z])
d = A.x | A.x
assert time_derivative(d, B) == (-qd) * (A.y | A.x) + \
(-qd) * (A.x | A.y)
d1 = A.x | B.y
assert time_derivative(d1, A) == - qd*(A.x|B.x)
assert time_derivative(d1, B) == - qd*(A.y|B.y)
d2 = A.x | B.x
assert time_derivative(d2, A) == qd*(A.x|B.y)
assert time_derivative(d2, B) == - qd*(A.y|B.x)
d3 = A.x | B.z
assert time_derivative(d3, A) == 0
assert time_derivative(d3, B) == - qd*(A.y|B.z)
q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4')
q1d, q2d, q3d, q4d = dynamicsymbols('q1 q2 q3 q4', 1)
q1dd, q2dd, q3dd, q4dd = dynamicsymbols('q1 q2 q3 q4', 2)
C = B.orientnew('C', 'Axis', [q4, B.x])
v1 = q1 * A.z
v2 = q2*A.x + q3*B.y
v3 = q1*A.x + q2*A.y + q3*A.z
assert time_derivative(B.x, C) == 0
assert time_derivative(B.y, C) == - q4d*B.z
assert time_derivative(B.z, C) == q4d*B.y
assert time_derivative(v1, B) == q1d*A.z
assert time_derivative(v1, C) == - q1*sin(q)*q4d*A.x + \
q1*cos(q)*q4d*A.y + q1d*A.z
assert time_derivative(v2, A) == q2d*A.x - q3*qd*B.x + q3d*B.y
assert time_derivative(v2, C) == q2d*A.x - q2*qd*A.y + \
q2*sin(q)*q4d*A.z + q3d*B.y - q3*q4d*B.z
assert time_derivative(v3, B) == (q2*qd + q1d)*A.x + \
(-q1*qd + q2d)*A.y + q3d*A.z
assert time_derivative(d, C) == - qd*(A.y|A.x) + \
sin(q)*q4d*(A.z|A.x) - qd*(A.x|A.y) + sin(q)*q4d*(A.x|A.z)
raises(ValueError, lambda: time_derivative(B.x, C, order=0.5))
raises(ValueError, lambda: time_derivative(B.x, C, order=-1))
def test_get_motion_methods():
#Initialization
t = dynamicsymbols._t
s1, s2, s3 = symbols('s1 s2 s3')
S1, S2, S3 = symbols('S1 S2 S3')
S4, S5, S6 = symbols('S4 S5 S6')
t1, t2 = symbols('t1 t2')
a, b, c = dynamicsymbols('a b c')
ad, bd, cd = dynamicsymbols('a b c', 1)
a2d, b2d, c2d = dynamicsymbols('a b c', 2)
v0 = S1*N.x + S2*N.y + S3*N.z
v01 = S4*N.x + S5*N.y + S6*N.z
v1 = s1*N.x + s2*N.y + s3*N.z
v2 = a*N.x + b*N.y + c*N.z
v2d = ad*N.x + bd*N.y + cd*N.z
v2dd = a2d*N.x + b2d*N.y + c2d*N.z
#Test position parameter
assert get_motion_params(frame = N) == (0, 0, 0)
assert get_motion_params(N, position=v1) == (0, 0, v1)
assert get_motion_params(N, position=v2) == (v2dd, v2d, v2)
#Test velocity parameter
assert get_motion_params(N, velocity=v1) == (0, v1, v1 * t)
assert get_motion_params(N, velocity=v1, position=v0, timevalue1=t1) == \
(0, v1, v0 + v1*(t - t1))
answer = get_motion_params(N, velocity=v1, position=v2, timevalue1=t1)
answer_expected = (0, v1, v1*t - v1*t1 + v2.subs(t, t1))
assert answer == answer_expected
answer = get_motion_params(N, velocity=v2, position=v0, timevalue1=t1)
integral_vector = Integral(a, (t, t1, t))*N.x + Integral(b, (t, t1, t))*N.y \
+ Integral(c, (t, t1, t))*N.z
answer_expected = (v2d, v2, v0 + integral_vector)
assert answer == answer_expected
#Test acceleration parameter
assert get_motion_params(N, acceleration=v1) == \
(v1, v1 * t, v1 * t**2/2)
assert get_motion_params(N, acceleration=v1, velocity=v0,
position=v2, timevalue1=t1, timevalue2=t2) == \
(v1, (v0 + v1*t - v1*t2),
-v0*t1 + v1*t**2/2 + v1*t2*t1 - \
v1*t1**2/2 + t*(v0 - v1*t2) + \
v2.subs(t, t1))
assert get_motion_params(N, acceleration=v1, velocity=v0,
position=v01, timevalue1=t1, timevalue2=t2) == \
(v1, v0 + v1*t - v1*t2,
-v0*t1 + v01 + v1*t**2/2 + \
v1*t2*t1 - v1*t1**2/2 + \
t*(v0 - v1*t2))
answer = get_motion_params(N, acceleration=a*N.x, velocity=S1*N.x,
position=S2*N.x, timevalue1=t1, timevalue2=t2)
i1 = Integral(a, (t, t2, t))
answer_expected = (a*N.x, (S1 + i1)*N.x, \
(S2 + Integral(S1 + i1, (t, t1, t)))*N.x)
assert answer == answer_expected
def test_kin_eqs():
q0, q1, q2, q3 = dynamicsymbols('q0 q1 q2 q3')
q0d, q1d, q2d, q3d = dynamicsymbols('q0 q1 q2 q3', 1)
u1, u2, u3 = dynamicsymbols('u1 u2 u3')
ke = kinematic_equations([u1,u2,u3], [q1,q2,q3], 'body', 313)
assert ke == kinematic_equations([u1,u2,u3], [q1,q2,q3], 'body', '313')
kds = kinematic_equations([u1, u2, u3], [q0, q1, q2, q3], 'quaternion')
assert kds == [-0.5 * q0 * u1 - 0.5 * q2 * u3 + 0.5 * q3 * u2 + q1d,
-0.5 * q0 * u2 + 0.5 * q1 * u3 - 0.5 * q3 * u1 + q2d,
-0.5 * q0 * u3 - 0.5 * q1 * u2 + 0.5 * q2 * u1 + q3d,
0.5 * q1 * u1 + 0.5 * q2 * u2 + 0.5 * q3 * u3 + q0d]
raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2], 'quaternion'))
raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2, q3], 'quaternion', '123'))
raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2, q3], 'foo'))
raises(TypeError, lambda: kinematic_equations(u1, [q0, q1, q2, q3], 'quaternion'))
raises(TypeError, lambda: kinematic_equations([u1], [q0, q1, q2, q3], 'quaternion'))
raises(TypeError, lambda: kinematic_equations([u1, u2, u3], q0, 'quaternion'))
raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2, q3], 'body'))
raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2, q3], 'space'))
raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2], 'body', '222'))
assert kinematic_equations([0, 0, 0], [q0, q1, q2], 'space') == [S.Zero, S.Zero, S.Zero]
def test_partial_velocity():
q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3')
u4, u5 = dynamicsymbols('u4, u5')
r = symbols('r')
N = ReferenceFrame('N')
Y = N.orientnew('Y', 'Axis', [q1, N.z])
L = Y.orientnew('L', 'Axis', [q2, Y.x])
R = L.orientnew('R', 'Axis', [q3, L.y])
R.set_ang_vel(N, u1 * L.x + u2 * L.y + u3 * L.z)
C = Point('C')
C.set_vel(N, u4 * L.x + u5 * (Y.z ^ L.x))
Dmc = C.locatenew('Dmc', r * L.z)
Dmc.v2pt_theory(C, N, R)
vel_list = [Dmc.vel(N), C.vel(N), R.ang_vel_in(N)]
u_list = [u1, u2, u3, u4, u5]
assert (partial_velocity(vel_list, u_list, N) ==
[[- r*L.y, r*L.x, 0, L.x, cos(q2)*L.y - sin(q2)*L.z],
[0, 0, 0, L.x, cos(q2)*L.y - sin(q2)*L.z],
[L.x, L.y, L.z, 0, 0]])
# Make sure that partial velocities can be computed regardless if the
# orientation between frames is defined or not.
A = ReferenceFrame('A')
B = ReferenceFrame('B')
v = u4 * A.x + u5 * B.y
assert partial_velocity((v, ), (u4, u5), A) == [[A.x, B.y]]
raises(TypeError, lambda: partial_velocity(Dmc.vel(N), u_list, N))
raises(TypeError, lambda: partial_velocity(vel_list, u1, N))
def test_dynamicsymbols():
#Tests to check the assumptions applied to dynamicsymbols
f1 = dynamicsymbols('f1')
f2 = dynamicsymbols('f2', real=True)
f3 = dynamicsymbols('f3', positive=True)
f4, f5 = dynamicsymbols('f4,f5', commutative=False)
f6 = dynamicsymbols('f6', integer=True)
assert f1.is_real is None
assert f2.is_real
assert f3.is_positive
assert f4*f5 != f5*f4
assert f6.is_integer

View File

@ -0,0 +1,75 @@
from sympy.core.singleton import S
from sympy.physics.vector import Vector, ReferenceFrame, Dyadic
from sympy.testing.pytest import raises
A = ReferenceFrame('A')
def test_output_type():
A = ReferenceFrame('A')
v = A.x + A.y
d = v | v
zerov = Vector(0)
zerod = Dyadic(0)
# dot products
assert isinstance(d & d, Dyadic)
assert isinstance(d & zerod, Dyadic)
assert isinstance(zerod & d, Dyadic)
assert isinstance(d & v, Vector)
assert isinstance(v & d, Vector)
assert isinstance(d & zerov, Vector)
assert isinstance(zerov & d, Vector)
raises(TypeError, lambda: d & S.Zero)
raises(TypeError, lambda: S.Zero & d)
raises(TypeError, lambda: d & 0)
raises(TypeError, lambda: 0 & d)
assert not isinstance(v & v, (Vector, Dyadic))
assert not isinstance(v & zerov, (Vector, Dyadic))
assert not isinstance(zerov & v, (Vector, Dyadic))
raises(TypeError, lambda: v & S.Zero)
raises(TypeError, lambda: S.Zero & v)
raises(TypeError, lambda: v & 0)
raises(TypeError, lambda: 0 & v)
# cross products
raises(TypeError, lambda: d ^ d)
raises(TypeError, lambda: d ^ zerod)
raises(TypeError, lambda: zerod ^ d)
assert isinstance(d ^ v, Dyadic)
assert isinstance(v ^ d, Dyadic)
assert isinstance(d ^ zerov, Dyadic)
assert isinstance(zerov ^ d, Dyadic)
assert isinstance(zerov ^ d, Dyadic)
raises(TypeError, lambda: d ^ S.Zero)
raises(TypeError, lambda: S.Zero ^ d)
raises(TypeError, lambda: d ^ 0)
raises(TypeError, lambda: 0 ^ d)
assert isinstance(v ^ v, Vector)
assert isinstance(v ^ zerov, Vector)
assert isinstance(zerov ^ v, Vector)
raises(TypeError, lambda: v ^ S.Zero)
raises(TypeError, lambda: S.Zero ^ v)
raises(TypeError, lambda: v ^ 0)
raises(TypeError, lambda: 0 ^ v)
# outer products
raises(TypeError, lambda: d | d)
raises(TypeError, lambda: d | zerod)
raises(TypeError, lambda: zerod | d)
raises(TypeError, lambda: d | v)
raises(TypeError, lambda: v | d)
raises(TypeError, lambda: d | zerov)
raises(TypeError, lambda: zerov | d)
raises(TypeError, lambda: zerov | d)
raises(TypeError, lambda: d | S.Zero)
raises(TypeError, lambda: S.Zero | d)
raises(TypeError, lambda: d | 0)
raises(TypeError, lambda: 0 | d)
assert isinstance(v | v, Dyadic)
assert isinstance(v | zerov, Dyadic)
assert isinstance(zerov | v, Dyadic)
raises(TypeError, lambda: v | S.Zero)
raises(TypeError, lambda: S.Zero | v)
raises(TypeError, lambda: v | 0)
raises(TypeError, lambda: 0 | v)

View File

@ -0,0 +1,382 @@
from sympy.physics.vector import dynamicsymbols, Point, ReferenceFrame
from sympy.testing.pytest import raises, ignore_warnings
import warnings
def test_point_v1pt_theorys():
q, q2 = dynamicsymbols('q q2')
qd, q2d = dynamicsymbols('q q2', 1)
qdd, q2dd = dynamicsymbols('q q2', 2)
N = ReferenceFrame('N')
B = ReferenceFrame('B')
B.set_ang_vel(N, qd * B.z)
O = Point('O')
P = O.locatenew('P', B.x)
P.set_vel(B, 0)
O.set_vel(N, 0)
assert P.v1pt_theory(O, N, B) == qd * B.y
O.set_vel(N, N.x)
assert P.v1pt_theory(O, N, B) == N.x + qd * B.y
P.set_vel(B, B.z)
assert P.v1pt_theory(O, N, B) == B.z + N.x + qd * B.y
def test_point_a1pt_theorys():
q, q2 = dynamicsymbols('q q2')
qd, q2d = dynamicsymbols('q q2', 1)
qdd, q2dd = dynamicsymbols('q q2', 2)
N = ReferenceFrame('N')
B = ReferenceFrame('B')
B.set_ang_vel(N, qd * B.z)
O = Point('O')
P = O.locatenew('P', B.x)
P.set_vel(B, 0)
O.set_vel(N, 0)
assert P.a1pt_theory(O, N, B) == -(qd**2) * B.x + qdd * B.y
P.set_vel(B, q2d * B.z)
assert P.a1pt_theory(O, N, B) == -(qd**2) * B.x + qdd * B.y + q2dd * B.z
O.set_vel(N, q2d * B.x)
assert P.a1pt_theory(O, N, B) == ((q2dd - qd**2) * B.x + (q2d * qd + qdd) * B.y +
q2dd * B.z)
def test_point_v2pt_theorys():
q = dynamicsymbols('q')
qd = dynamicsymbols('q', 1)
N = ReferenceFrame('N')
B = N.orientnew('B', 'Axis', [q, N.z])
O = Point('O')
P = O.locatenew('P', 0)
O.set_vel(N, 0)
assert P.v2pt_theory(O, N, B) == 0
P = O.locatenew('P', B.x)
assert P.v2pt_theory(O, N, B) == (qd * B.z ^ B.x)
O.set_vel(N, N.x)
assert P.v2pt_theory(O, N, B) == N.x + qd * B.y
def test_point_a2pt_theorys():
q = dynamicsymbols('q')
qd = dynamicsymbols('q', 1)
qdd = dynamicsymbols('q', 2)
N = ReferenceFrame('N')
B = N.orientnew('B', 'Axis', [q, N.z])
O = Point('O')
P = O.locatenew('P', 0)
O.set_vel(N, 0)
assert P.a2pt_theory(O, N, B) == 0
P.set_pos(O, B.x)
assert P.a2pt_theory(O, N, B) == (-qd**2) * B.x + (qdd) * B.y
def test_point_funcs():
q, q2 = dynamicsymbols('q q2')
qd, q2d = dynamicsymbols('q q2', 1)
qdd, q2dd = dynamicsymbols('q q2', 2)
N = ReferenceFrame('N')
B = ReferenceFrame('B')
B.set_ang_vel(N, 5 * B.y)
O = Point('O')
P = O.locatenew('P', q * B.x + q2 * B.y)
assert P.pos_from(O) == q * B.x + q2 * B.y
P.set_vel(B, qd * B.x + q2d * B.y)
assert P.vel(B) == qd * B.x + q2d * B.y
O.set_vel(N, 0)
assert O.vel(N) == 0
assert P.a1pt_theory(O, N, B) == ((-25 * q + qdd) * B.x + (q2dd) * B.y +
(-10 * qd) * B.z)
B = N.orientnew('B', 'Axis', [q, N.z])
O = Point('O')
P = O.locatenew('P', 10 * B.x)
O.set_vel(N, 5 * N.x)
assert O.vel(N) == 5 * N.x
assert P.a2pt_theory(O, N, B) == (-10 * qd**2) * B.x + (10 * qdd) * B.y
B.set_ang_vel(N, 5 * B.y)
O = Point('O')
P = O.locatenew('P', q * B.x + q2 * B.y)
P.set_vel(B, qd * B.x + q2d * B.y)
O.set_vel(N, 0)
assert P.v1pt_theory(O, N, B) == qd * B.x + q2d * B.y - 5 * q * B.z
def test_point_pos():
q = dynamicsymbols('q')
N = ReferenceFrame('N')
B = N.orientnew('B', 'Axis', [q, N.z])
O = Point('O')
P = O.locatenew('P', 10 * N.x + 5 * B.x)
assert P.pos_from(O) == 10 * N.x + 5 * B.x
Q = P.locatenew('Q', 10 * N.y + 5 * B.y)
assert Q.pos_from(P) == 10 * N.y + 5 * B.y
assert Q.pos_from(O) == 10 * N.x + 10 * N.y + 5 * B.x + 5 * B.y
assert O.pos_from(Q) == -10 * N.x - 10 * N.y - 5 * B.x - 5 * B.y
def test_point_partial_velocity():
N = ReferenceFrame('N')
A = ReferenceFrame('A')
p = Point('p')
u1, u2 = dynamicsymbols('u1, u2')
p.set_vel(N, u1 * A.x + u2 * N.y)
assert p.partial_velocity(N, u1) == A.x
assert p.partial_velocity(N, u1, u2) == (A.x, N.y)
raises(ValueError, lambda: p.partial_velocity(A, u1))
def test_point_vel(): #Basic functionality
q1, q2 = dynamicsymbols('q1 q2')
N = ReferenceFrame('N')
B = ReferenceFrame('B')
Q = Point('Q')
O = Point('O')
Q.set_pos(O, q1 * N.x)
raises(ValueError , lambda: Q.vel(N)) # Velocity of O in N is not defined
O.set_vel(N, q2 * N.y)
assert O.vel(N) == q2 * N.y
raises(ValueError , lambda : O.vel(B)) #Velocity of O is not defined in B
def test_auto_point_vel():
t = dynamicsymbols._t
q1, q2 = dynamicsymbols('q1 q2')
N = ReferenceFrame('N')
B = ReferenceFrame('B')
O = Point('O')
Q = Point('Q')
Q.set_pos(O, q1 * N.x)
O.set_vel(N, q2 * N.y)
assert Q.vel(N) == q1.diff(t) * N.x + q2 * N.y # Velocity of Q using O
P1 = Point('P1')
P1.set_pos(O, q1 * B.x)
P2 = Point('P2')
P2.set_pos(P1, q2 * B.z)
raises(ValueError, lambda : P2.vel(B)) # O's velocity is defined in different frame, and no
#point in between has its velocity defined
raises(ValueError, lambda: P2.vel(N)) # Velocity of O not defined in N
def test_auto_point_vel_multiple_point_path():
t = dynamicsymbols._t
q1, q2 = dynamicsymbols('q1 q2')
B = ReferenceFrame('B')
P = Point('P')
P.set_vel(B, q1 * B.x)
P1 = Point('P1')
P1.set_pos(P, q2 * B.y)
P1.set_vel(B, q1 * B.z)
P2 = Point('P2')
P2.set_pos(P1, q1 * B.z)
P3 = Point('P3')
P3.set_pos(P2, 10 * q1 * B.y)
assert P3.vel(B) == 10 * q1.diff(t) * B.y + (q1 + q1.diff(t)) * B.z
def test_auto_vel_dont_overwrite():
t = dynamicsymbols._t
q1, q2, u1 = dynamicsymbols('q1, q2, u1')
N = ReferenceFrame('N')
P = Point('P1')
P.set_vel(N, u1 * N.x)
P1 = Point('P1')
P1.set_pos(P, q2 * N.y)
assert P1.vel(N) == q2.diff(t) * N.y + u1 * N.x
assert P.vel(N) == u1 * N.x
P1.set_vel(N, u1 * N.z)
assert P1.vel(N) == u1 * N.z
def test_auto_point_vel_if_tree_has_vel_but_inappropriate_pos_vector():
q1, q2 = dynamicsymbols('q1 q2')
B = ReferenceFrame('B')
S = ReferenceFrame('S')
P = Point('P')
P.set_vel(B, q1 * B.x)
P1 = Point('P1')
P1.set_pos(P, S.y)
raises(ValueError, lambda : P1.vel(B)) # P1.pos_from(P) can't be expressed in B
raises(ValueError, lambda : P1.vel(S)) # P.vel(S) not defined
def test_auto_point_vel_shortest_path():
t = dynamicsymbols._t
q1, q2, u1, u2 = dynamicsymbols('q1 q2 u1 u2')
B = ReferenceFrame('B')
P = Point('P')
P.set_vel(B, u1 * B.x)
P1 = Point('P1')
P1.set_pos(P, q2 * B.y)
P1.set_vel(B, q1 * B.z)
P2 = Point('P2')
P2.set_pos(P1, q1 * B.z)
P3 = Point('P3')
P3.set_pos(P2, 10 * q1 * B.y)
P4 = Point('P4')
P4.set_pos(P3, q1 * B.x)
O = Point('O')
O.set_vel(B, u2 * B.y)
O1 = Point('O1')
O1.set_pos(O, q2 * B.z)
P4.set_pos(O1, q1 * B.x + q2 * B.z)
with warnings.catch_warnings(): #There are two possible paths in this point tree, thus a warning is raised
warnings.simplefilter('error')
with ignore_warnings(UserWarning):
assert P4.vel(B) == q1.diff(t) * B.x + u2 * B.y + 2 * q2.diff(t) * B.z
def test_auto_point_vel_connected_frames():
t = dynamicsymbols._t
q, q1, q2, u = dynamicsymbols('q q1 q2 u')
N = ReferenceFrame('N')
B = ReferenceFrame('B')
O = Point('O')
O.set_vel(N, u * N.x)
P = Point('P')
P.set_pos(O, q1 * N.x + q2 * B.y)
raises(ValueError, lambda: P.vel(N))
N.orient(B, 'Axis', (q, B.x))
assert P.vel(N) == (u + q1.diff(t)) * N.x + q2.diff(t) * B.y - q2 * q.diff(t) * B.z
def test_auto_point_vel_multiple_paths_warning_arises():
q, u = dynamicsymbols('q u')
N = ReferenceFrame('N')
O = Point('O')
P = Point('P')
Q = Point('Q')
R = Point('R')
P.set_vel(N, u * N.x)
Q.set_vel(N, u *N.y)
R.set_vel(N, u * N.z)
O.set_pos(P, q * N.z)
O.set_pos(Q, q * N.y)
O.set_pos(R, q * N.x)
with warnings.catch_warnings(): #There are two possible paths in this point tree, thus a warning is raised
warnings.simplefilter("error")
raises(UserWarning ,lambda: O.vel(N))
def test_auto_vel_cyclic_warning_arises():
P = Point('P')
P1 = Point('P1')
P2 = Point('P2')
P3 = Point('P3')
N = ReferenceFrame('N')
P.set_vel(N, N.x)
P1.set_pos(P, N.x)
P2.set_pos(P1, N.y)
P3.set_pos(P2, N.z)
P1.set_pos(P3, N.x + N.y)
with warnings.catch_warnings(): #The path is cyclic at P1, thus a warning is raised
warnings.simplefilter("error")
raises(UserWarning ,lambda: P2.vel(N))
def test_auto_vel_cyclic_warning_msg():
P = Point('P')
P1 = Point('P1')
P2 = Point('P2')
P3 = Point('P3')
N = ReferenceFrame('N')
P.set_vel(N, N.x)
P1.set_pos(P, N.x)
P2.set_pos(P1, N.y)
P3.set_pos(P2, N.z)
P1.set_pos(P3, N.x + N.y)
with warnings.catch_warnings(record = True) as w: #The path is cyclic at P1, thus a warning is raised
warnings.simplefilter("always")
P2.vel(N)
msg = str(w[-1].message).replace("\n", " ")
assert issubclass(w[-1].category, UserWarning)
assert 'Kinematic loops are defined among the positions of points. This is likely not desired and may cause errors in your calculations.' in msg
def test_auto_vel_multiple_path_warning_msg():
N = ReferenceFrame('N')
O = Point('O')
P = Point('P')
Q = Point('Q')
P.set_vel(N, N.x)
Q.set_vel(N, N.y)
O.set_pos(P, N.z)
O.set_pos(Q, N.y)
with warnings.catch_warnings(record = True) as w: #There are two possible paths in this point tree, thus a warning is raised
warnings.simplefilter("always")
O.vel(N)
msg = str(w[-1].message).replace("\n", " ")
assert issubclass(w[-1].category, UserWarning)
assert 'Velocity' in msg
assert 'automatically calculated based on point' in msg
assert 'Velocities from these points are not necessarily the same. This may cause errors in your calculations.' in msg
def test_auto_vel_derivative():
q1, q2 = dynamicsymbols('q1:3')
u1, u2 = dynamicsymbols('u1:3', 1)
A = ReferenceFrame('A')
B = ReferenceFrame('B')
C = ReferenceFrame('C')
B.orient_axis(A, A.z, q1)
B.set_ang_vel(A, u1 * A.z)
C.orient_axis(B, B.z, q2)
C.set_ang_vel(B, u2 * B.z)
Am = Point('Am')
Am.set_vel(A, 0)
Bm = Point('Bm')
Bm.set_pos(Am, B.x)
Bm.set_vel(B, 0)
Bm.set_vel(C, 0)
Cm = Point('Cm')
Cm.set_pos(Bm, C.x)
Cm.set_vel(C, 0)
temp = Cm._vel_dict.copy()
assert Cm.vel(A) == (u1 * B.y + (u1 + u2) * C.y)
Cm._vel_dict = temp
Cm.v2pt_theory(Bm, B, C)
assert Cm.vel(A) == (u1 * B.y + (u1 + u2) * C.y)
def test_auto_point_acc_zero_vel():
N = ReferenceFrame('N')
O = Point('O')
O.set_vel(N, 0)
assert O.acc(N) == 0 * N.x
def test_auto_point_acc_compute_vel():
t = dynamicsymbols._t
q1 = dynamicsymbols('q1')
N = ReferenceFrame('N')
A = ReferenceFrame('A')
A.orient_axis(N, N.z, q1)
O = Point('O')
O.set_vel(N, 0)
P = Point('P')
P.set_pos(O, A.x)
assert P.acc(N) == -q1.diff(t) ** 2 * A.x + q1.diff(t, 2) * A.y
def test_auto_acc_derivative():
# Tests whether the Point.acc method gives the correct acceleration of the
# end point of two linkages in series, while getting minimal information.
q1, q2 = dynamicsymbols('q1:3')
u1, u2 = dynamicsymbols('q1:3', 1)
v1, v2 = dynamicsymbols('q1:3', 2)
A = ReferenceFrame('A')
B = ReferenceFrame('B')
C = ReferenceFrame('C')
B.orient_axis(A, A.z, q1)
C.orient_axis(B, B.z, q2)
Am = Point('Am')
Am.set_vel(A, 0)
Bm = Point('Bm')
Bm.set_pos(Am, B.x)
Bm.set_vel(B, 0)
Bm.set_vel(C, 0)
Cm = Point('Cm')
Cm.set_pos(Bm, C.x)
Cm.set_vel(C, 0)
# Copy dictionaries to later check the calculation using the 2pt_theories
Bm_vel_dict, Cm_vel_dict = Bm._vel_dict.copy(), Cm._vel_dict.copy()
Bm_acc_dict, Cm_acc_dict = Bm._acc_dict.copy(), Cm._acc_dict.copy()
check = -u1 ** 2 * B.x + v1 * B.y - (u1 + u2) ** 2 * C.x + (v1 + v2) * C.y
assert Cm.acc(A) == check
Bm._vel_dict, Cm._vel_dict = Bm_vel_dict, Cm_vel_dict
Bm._acc_dict, Cm._acc_dict = Bm_acc_dict, Cm_acc_dict
Bm.v2pt_theory(Am, A, B)
Cm.v2pt_theory(Bm, A, C)
Bm.a2pt_theory(Am, A, B)
assert Cm.a2pt_theory(Bm, A, C) == check

View File

@ -0,0 +1,353 @@
# -*- coding: utf-8 -*-
from sympy.core.function import Function
from sympy.core.symbol import symbols
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import (asin, cos, sin)
from sympy.physics.vector import ReferenceFrame, dynamicsymbols, Dyadic
from sympy.physics.vector.printing import (VectorLatexPrinter, vpprint,
vsprint, vsstrrepr, vlatex)
a, b, c = symbols('a, b, c')
alpha, omega, beta = dynamicsymbols('alpha, omega, beta')
A = ReferenceFrame('A')
N = ReferenceFrame('N')
v = a ** 2 * N.x + b * N.y + c * sin(alpha) * N.z
w = alpha * N.x + sin(omega) * N.y + alpha * beta * N.z
ww = alpha * N.x + asin(omega) * N.y - alpha.diff() * beta * N.z
o = a/b * N.x + (c+b)/a * N.y + c**2/b * N.z
y = a ** 2 * (N.x | N.y) + b * (N.y | N.y) + c * sin(alpha) * (N.z | N.y)
x = alpha * (N.x | N.x) + sin(omega) * (N.y | N.z) + alpha * beta * (N.z | N.x)
xx = N.x | (-N.y - N.z)
xx2 = N.x | (N.y + N.z)
def ascii_vpretty(expr):
return vpprint(expr, use_unicode=False, wrap_line=False)
def unicode_vpretty(expr):
return vpprint(expr, use_unicode=True, wrap_line=False)
def test_latex_printer():
r = Function('r')('t')
assert VectorLatexPrinter().doprint(r ** 2) == "r^{2}"
r2 = Function('r^2')('t')
assert VectorLatexPrinter().doprint(r2.diff()) == r'\dot{r^{2}}'
ra = Function('r__a')('t')
assert VectorLatexPrinter().doprint(ra.diff().diff()) == r'\ddot{r^{a}}'
def test_vector_pretty_print():
# TODO : The unit vectors should print with subscripts but they just
# print as `n_x` instead of making `x` a subscript with unicode.
# TODO : The pretty print division does not print correctly here:
# w = alpha * N.x + sin(omega) * N.y + alpha / beta * N.z
expected = """\
2 \n\
a n_x + b n_y + c*sin(alpha) n_z\
"""
uexpected = """\
2 \n\
a n_x + b n_y + c⋅sin(α) n_z\
"""
assert ascii_vpretty(v) == expected
assert unicode_vpretty(v) == uexpected
expected = 'alpha n_x + sin(omega) n_y + alpha*beta n_z'
uexpected = 'α n_x + sin(ω) n_y + α⋅β n_z'
assert ascii_vpretty(w) == expected
assert unicode_vpretty(w) == uexpected
expected = """\
2 \n\
a b + c c \n\
- n_x + ----- n_y + -- n_z\n\
b a b \
"""
uexpected = """\
2 \n\
a b + c c \n\
─ n_x + ───── n_y + ── n_z\n\
b a b \
"""
assert ascii_vpretty(o) == expected
assert unicode_vpretty(o) == uexpected
# https://github.com/sympy/sympy/issues/26731
assert ascii_vpretty(-A.x) == '-a_x'
assert unicode_vpretty(-A.x) == '-a_x'
# https://github.com/sympy/sympy/issues/26799
assert ascii_vpretty(0*A.x) == '0'
assert unicode_vpretty(0*A.x) == '0'
def test_vector_latex():
a, b, c, d, omega = symbols('a, b, c, d, omega')
v = (a ** 2 + b / c) * A.x + sqrt(d) * A.y + cos(omega) * A.z
assert vlatex(v) == (r'(a^{2} + \frac{b}{c})\mathbf{\hat{a}_x} + '
r'\sqrt{d}\mathbf{\hat{a}_y} + '
r'\cos{\left(\omega \right)}'
r'\mathbf{\hat{a}_z}')
theta, omega, alpha, q = dynamicsymbols('theta, omega, alpha, q')
v = theta * A.x + omega * omega * A.y + (q * alpha) * A.z
assert vlatex(v) == (r'\theta\mathbf{\hat{a}_x} + '
r'\omega^{2}\mathbf{\hat{a}_y} + '
r'\alpha q\mathbf{\hat{a}_z}')
phi1, phi2, phi3 = dynamicsymbols('phi1, phi2, phi3')
theta1, theta2, theta3 = symbols('theta1, theta2, theta3')
v = (sin(theta1) * A.x +
cos(phi1) * cos(phi2) * A.y +
cos(theta1 + phi3) * A.z)
assert vlatex(v) == (r'\sin{\left(\theta_{1} \right)}'
r'\mathbf{\hat{a}_x} + \cos{'
r'\left(\phi_{1} \right)} \cos{'
r'\left(\phi_{2} \right)}\mathbf{\hat{a}_y} + '
r'\cos{\left(\theta_{1} + '
r'\phi_{3} \right)}\mathbf{\hat{a}_z}')
N = ReferenceFrame('N')
a, b, c, d, omega = symbols('a, b, c, d, omega')
v = (a ** 2 + b / c) * N.x + sqrt(d) * N.y + cos(omega) * N.z
expected = (r'(a^{2} + \frac{b}{c})\mathbf{\hat{n}_x} + '
r'\sqrt{d}\mathbf{\hat{n}_y} + '
r'\cos{\left(\omega \right)}'
r'\mathbf{\hat{n}_z}')
assert vlatex(v) == expected
# Try custom unit vectors.
N = ReferenceFrame('N', latexs=(r'\hat{i}', r'\hat{j}', r'\hat{k}'))
v = (a ** 2 + b / c) * N.x + sqrt(d) * N.y + cos(omega) * N.z
expected = (r'(a^{2} + \frac{b}{c})\hat{i} + '
r'\sqrt{d}\hat{j} + '
r'\cos{\left(\omega \right)}\hat{k}')
assert vlatex(v) == expected
expected = r'\alpha\mathbf{\hat{n}_x} + \operatorname{asin}{\left(\omega ' \
r'\right)}\mathbf{\hat{n}_y} - \beta \dot{\alpha}\mathbf{\hat{n}_z}'
assert vlatex(ww) == expected
expected = r'- \mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_y} - ' \
r'\mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_z}'
assert vlatex(xx) == expected
expected = r'\mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_y} + ' \
r'\mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_z}'
assert vlatex(xx2) == expected
def test_vector_latex_arguments():
assert vlatex(N.x * 3.0, full_prec=False) == r'3.0\mathbf{\hat{n}_x}'
assert vlatex(N.x * 3.0, full_prec=True) == r'3.00000000000000\mathbf{\hat{n}_x}'
def test_vector_latex_with_functions():
N = ReferenceFrame('N')
omega, alpha = dynamicsymbols('omega, alpha')
v = omega.diff() * N.x
assert vlatex(v) == r'\dot{\omega}\mathbf{\hat{n}_x}'
v = omega.diff() ** alpha * N.x
assert vlatex(v) == (r'\dot{\omega}^{\alpha}'
r'\mathbf{\hat{n}_x}')
def test_dyadic_pretty_print():
expected = """\
2
a n_x|n_y + b n_y|n_y + c*sin(alpha) n_z|n_y\
"""
uexpected = """\
2
a n_x⊗n_y + b n_y⊗n_y + c⋅sin(α) n_z⊗n_y\
"""
assert ascii_vpretty(y) == expected
assert unicode_vpretty(y) == uexpected
expected = 'alpha n_x|n_x + sin(omega) n_y|n_z + alpha*beta n_z|n_x'
uexpected = 'α n_x⊗n_x + sin(ω) n_y⊗n_z + α⋅β n_z⊗n_x'
assert ascii_vpretty(x) == expected
assert unicode_vpretty(x) == uexpected
assert ascii_vpretty(Dyadic([])) == '0'
assert unicode_vpretty(Dyadic([])) == '0'
assert ascii_vpretty(xx) == '- n_x|n_y - n_x|n_z'
assert unicode_vpretty(xx) == '- n_x⊗n_y - n_x⊗n_z'
assert ascii_vpretty(xx2) == 'n_x|n_y + n_x|n_z'
assert unicode_vpretty(xx2) == 'n_x⊗n_y + n_x⊗n_z'
def test_dyadic_latex():
expected = (r'a^{2}\mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_y} + '
r'b\mathbf{\hat{n}_y}\otimes \mathbf{\hat{n}_y} + '
r'c \sin{\left(\alpha \right)}'
r'\mathbf{\hat{n}_z}\otimes \mathbf{\hat{n}_y}')
assert vlatex(y) == expected
expected = (r'\alpha\mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_x} + '
r'\sin{\left(\omega \right)}\mathbf{\hat{n}_y}'
r'\otimes \mathbf{\hat{n}_z} + '
r'\alpha \beta\mathbf{\hat{n}_z}\otimes \mathbf{\hat{n}_x}')
assert vlatex(x) == expected
assert vlatex(Dyadic([])) == '0'
def test_dyadic_str():
assert vsprint(Dyadic([])) == '0'
assert vsprint(y) == 'a**2*(N.x|N.y) + b*(N.y|N.y) + c*sin(alpha)*(N.z|N.y)'
assert vsprint(x) == 'alpha*(N.x|N.x) + sin(omega)*(N.y|N.z) + alpha*beta*(N.z|N.x)'
assert vsprint(ww) == "alpha*N.x + asin(omega)*N.y - beta*alpha'*N.z"
assert vsprint(xx) == '- (N.x|N.y) - (N.x|N.z)'
assert vsprint(xx2) == '(N.x|N.y) + (N.x|N.z)'
def test_vlatex(): # vlatex is broken #12078
from sympy.physics.vector import vlatex
x = symbols('x')
J = symbols('J')
f = Function('f')
g = Function('g')
h = Function('h')
expected = r'J \left(\frac{d}{d x} g{\left(x \right)} - \frac{d}{d x} h{\left(x \right)}\right)'
expr = J*f(x).diff(x).subs(f(x), g(x)-h(x))
assert vlatex(expr) == expected
def test_issue_13354():
"""
Test for proper pretty printing of physics vectors with ADD
instances in arguments.
Test is exactly the one suggested in the original bug report by
@moorepants.
"""
a, b, c = symbols('a, b, c')
A = ReferenceFrame('A')
v = a * A.x + b * A.y + c * A.z
w = b * A.x + c * A.y + a * A.z
z = w + v
expected = """(a + b) a_x + (b + c) a_y + (a + c) a_z"""
assert ascii_vpretty(z) == expected
def test_vector_derivative_printing():
# First order
v = omega.diff() * N.x
assert unicode_vpretty(v) == 'ω̇ n_x'
assert ascii_vpretty(v) == "omega'(t) n_x"
# Second order
v = omega.diff().diff() * N.x
assert vlatex(v) == r'\ddot{\omega}\mathbf{\hat{n}_x}'
assert unicode_vpretty(v) == 'ω̈ n_x'
assert ascii_vpretty(v) == "omega''(t) n_x"
# Third order
v = omega.diff().diff().diff() * N.x
assert vlatex(v) == r'\dddot{\omega}\mathbf{\hat{n}_x}'
assert unicode_vpretty(v) == 'ω⃛ n_x'
assert ascii_vpretty(v) == "omega'''(t) n_x"
# Fourth order
v = omega.diff().diff().diff().diff() * N.x
assert vlatex(v) == r'\ddddot{\omega}\mathbf{\hat{n}_x}'
assert unicode_vpretty(v) == 'ω⃜ n_x'
assert ascii_vpretty(v) == "omega''''(t) n_x"
# Fifth order
v = omega.diff().diff().diff().diff().diff() * N.x
assert vlatex(v) == r'\frac{d^{5}}{d t^{5}} \omega\mathbf{\hat{n}_x}'
expected = '''\
5 \n\
d \n\
---(omega) n_x\n\
5 \n\
dt \
'''
uexpected = '''\
5 \n\
d \n\
───(ω) n_x\n\
5 \n\
dt \
'''
assert unicode_vpretty(v) == uexpected
assert ascii_vpretty(v) == expected
def test_vector_str_printing():
assert vsprint(w) == 'alpha*N.x + sin(omega)*N.y + alpha*beta*N.z'
assert vsprint(omega.diff() * N.x) == "omega'*N.x"
assert vsstrrepr(w) == 'alpha*N.x + sin(omega)*N.y + alpha*beta*N.z'
def test_vector_str_arguments():
assert vsprint(N.x * 3.0, full_prec=False) == '3.0*N.x'
assert vsprint(N.x * 3.0, full_prec=True) == '3.00000000000000*N.x'
def test_issue_14041():
import sympy.physics.mechanics as me
A_frame = me.ReferenceFrame('A')
thetad, phid = me.dynamicsymbols('theta, phi', 1)
L = symbols('L')
assert vlatex(L*(phid + thetad)**2*A_frame.x) == \
r"L \left(\dot{\phi} + \dot{\theta}\right)^{2}\mathbf{\hat{a}_x}"
assert vlatex((phid + thetad)**2*A_frame.x) == \
r"\left(\dot{\phi} + \dot{\theta}\right)^{2}\mathbf{\hat{a}_x}"
assert vlatex((phid*thetad)**a*A_frame.x) == \
r"\left(\dot{\phi} \dot{\theta}\right)^{a}\mathbf{\hat{a}_x}"

View File

@ -0,0 +1,274 @@
from sympy.core.numbers import (Float, pi)
from sympy.core.symbol import symbols
from sympy.core.sorting import ordered
from sympy.functions.elementary.trigonometric import (cos, sin)
from sympy.matrices.immutable import ImmutableDenseMatrix as Matrix
from sympy.physics.vector import ReferenceFrame, Vector, dynamicsymbols, dot
from sympy.physics.vector.vector import VectorTypeError
from sympy.abc import x, y, z
from sympy.testing.pytest import raises
A = ReferenceFrame('A')
def test_free_dynamicsymbols():
A, B, C, D = symbols('A, B, C, D', cls=ReferenceFrame)
a, b, c, d, e, f = dynamicsymbols('a, b, c, d, e, f')
B.orient_axis(A, a, A.x)
C.orient_axis(B, b, B.y)
D.orient_axis(C, c, C.x)
v = d*D.x + e*D.y + f*D.z
assert set(ordered(v.free_dynamicsymbols(A))) == {a, b, c, d, e, f}
assert set(ordered(v.free_dynamicsymbols(B))) == {b, c, d, e, f}
assert set(ordered(v.free_dynamicsymbols(C))) == {c, d, e, f}
assert set(ordered(v.free_dynamicsymbols(D))) == {d, e, f}
def test_Vector():
assert A.x != A.y
assert A.y != A.z
assert A.z != A.x
assert A.x + 0 == A.x
v1 = x*A.x + y*A.y + z*A.z
v2 = x**2*A.x + y**2*A.y + z**2*A.z
v3 = v1 + v2
v4 = v1 - v2
assert isinstance(v1, Vector)
assert dot(v1, A.x) == x
assert dot(v1, A.y) == y
assert dot(v1, A.z) == z
assert isinstance(v2, Vector)
assert dot(v2, A.x) == x**2
assert dot(v2, A.y) == y**2
assert dot(v2, A.z) == z**2
assert isinstance(v3, Vector)
# We probably shouldn't be using simplify in dot...
assert dot(v3, A.x) == x**2 + x
assert dot(v3, A.y) == y**2 + y
assert dot(v3, A.z) == z**2 + z
assert isinstance(v4, Vector)
# We probably shouldn't be using simplify in dot...
assert dot(v4, A.x) == x - x**2
assert dot(v4, A.y) == y - y**2
assert dot(v4, A.z) == z - z**2
assert v1.to_matrix(A) == Matrix([[x], [y], [z]])
q = symbols('q')
B = A.orientnew('B', 'Axis', (q, A.x))
assert v1.to_matrix(B) == Matrix([[x],
[ y * cos(q) + z * sin(q)],
[-y * sin(q) + z * cos(q)]])
#Test the separate method
B = ReferenceFrame('B')
v5 = x*A.x + y*A.y + z*B.z
assert Vector(0).separate() == {}
assert v1.separate() == {A: v1}
assert v5.separate() == {A: x*A.x + y*A.y, B: z*B.z}
#Test the free_symbols property
v6 = x*A.x + y*A.y + z*A.z
assert v6.free_symbols(A) == {x,y,z}
raises(TypeError, lambda: v3.applyfunc(v1))
def test_Vector_diffs():
q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4')
q1d, q2d, q3d, q4d = dynamicsymbols('q1 q2 q3 q4', 1)
q1dd, q2dd, q3dd, q4dd = dynamicsymbols('q1 q2 q3 q4', 2)
N = ReferenceFrame('N')
A = N.orientnew('A', 'Axis', [q3, N.z])
B = A.orientnew('B', 'Axis', [q2, A.x])
v1 = q2 * A.x + q3 * N.y
v2 = q3 * B.x + v1
v3 = v1.dt(B)
v4 = v2.dt(B)
v5 = q1*A.x + q2*A.y + q3*A.z
assert v1.dt(N) == q2d * A.x + q2 * q3d * A.y + q3d * N.y
assert v1.dt(A) == q2d * A.x + q3 * q3d * N.x + q3d * N.y
assert v1.dt(B) == (q2d * A.x + q3 * q3d * N.x + q3d *
N.y - q3 * cos(q3) * q2d * N.z)
assert v2.dt(N) == (q2d * A.x + (q2 + q3) * q3d * A.y + q3d * B.x + q3d *
N.y)
assert v2.dt(A) == q2d * A.x + q3d * B.x + q3 * q3d * N.x + q3d * N.y
assert v2.dt(B) == (q2d * A.x + q3d * B.x + q3 * q3d * N.x + q3d * N.y -
q3 * cos(q3) * q2d * N.z)
assert v3.dt(N) == (q2dd * A.x + q2d * q3d * A.y + (q3d**2 + q3 * q3dd) *
N.x + q3dd * N.y + (q3 * sin(q3) * q2d * q3d -
cos(q3) * q2d * q3d - q3 * cos(q3) * q2dd) * N.z)
assert v3.dt(A) == (q2dd * A.x + (2 * q3d**2 + q3 * q3dd) * N.x + (q3dd -
q3 * q3d**2) * N.y + (q3 * sin(q3) * q2d * q3d -
cos(q3) * q2d * q3d - q3 * cos(q3) * q2dd) * N.z)
assert (v3.dt(B) - (q2dd*A.x - q3*cos(q3)*q2d**2*A.y + (2*q3d**2 +
q3*q3dd)*N.x + (q3dd - q3*q3d**2)*N.y + (2*q3*sin(q3)*q2d*q3d -
2*cos(q3)*q2d*q3d - q3*cos(q3)*q2dd)*N.z)).express(B).simplify() == 0
assert v4.dt(N) == (q2dd * A.x + q3d * (q2d + q3d) * A.y + q3dd * B.x +
(q3d**2 + q3 * q3dd) * N.x + q3dd * N.y + (q3 *
sin(q3) * q2d * q3d - cos(q3) * q2d * q3d - q3 *
cos(q3) * q2dd) * N.z)
assert v4.dt(A) == (q2dd * A.x + q3dd * B.x + (2 * q3d**2 + q3 * q3dd) *
N.x + (q3dd - q3 * q3d**2) * N.y + (q3 * sin(q3) *
q2d * q3d - cos(q3) * q2d * q3d - q3 * cos(q3) *
q2dd) * N.z)
assert (v4.dt(B) - (q2dd*A.x - q3*cos(q3)*q2d**2*A.y + q3dd*B.x +
(2*q3d**2 + q3*q3dd)*N.x + (q3dd - q3*q3d**2)*N.y +
(2*q3*sin(q3)*q2d*q3d - 2*cos(q3)*q2d*q3d -
q3*cos(q3)*q2dd)*N.z)).express(B).simplify() == 0
assert v5.dt(B) == q1d*A.x + (q3*q2d + q2d)*A.y + (-q2*q2d + q3d)*A.z
assert v5.dt(A) == q1d*A.x + q2d*A.y + q3d*A.z
assert v5.dt(N) == (-q2*q3d + q1d)*A.x + (q1*q3d + q2d)*A.y + q3d*A.z
assert v3.diff(q1d, N) == 0
assert v3.diff(q2d, N) == A.x - q3 * cos(q3) * N.z
assert v3.diff(q3d, N) == q3 * N.x + N.y
assert v3.diff(q1d, A) == 0
assert v3.diff(q2d, A) == A.x - q3 * cos(q3) * N.z
assert v3.diff(q3d, A) == q3 * N.x + N.y
assert v3.diff(q1d, B) == 0
assert v3.diff(q2d, B) == A.x - q3 * cos(q3) * N.z
assert v3.diff(q3d, B) == q3 * N.x + N.y
assert v4.diff(q1d, N) == 0
assert v4.diff(q2d, N) == A.x - q3 * cos(q3) * N.z
assert v4.diff(q3d, N) == B.x + q3 * N.x + N.y
assert v4.diff(q1d, A) == 0
assert v4.diff(q2d, A) == A.x - q3 * cos(q3) * N.z
assert v4.diff(q3d, A) == B.x + q3 * N.x + N.y
assert v4.diff(q1d, B) == 0
assert v4.diff(q2d, B) == A.x - q3 * cos(q3) * N.z
assert v4.diff(q3d, B) == B.x + q3 * N.x + N.y
# diff() should only express vector components in the derivative frame if
# the orientation of the component's frame depends on the variable
v6 = q2**2*N.y + q2**2*A.y + q2**2*B.y
# already expressed in N
n_measy = 2*q2
# A_C_N does not depend on q2, so don't express in N
a_measy = 2*q2
# B_C_N depends on q2, so express in N
b_measx = (q2**2*B.y).dot(N.x).diff(q2)
b_measy = (q2**2*B.y).dot(N.y).diff(q2)
b_measz = (q2**2*B.y).dot(N.z).diff(q2)
n_comp, a_comp = v6.diff(q2, N).args
assert len(v6.diff(q2, N).args) == 2 # only N and A parts
assert n_comp[1] == N
assert a_comp[1] == A
assert n_comp[0] == Matrix([b_measx, b_measy + n_measy, b_measz])
assert a_comp[0] == Matrix([0, a_measy, 0])
def test_vector_var_in_dcm():
N = ReferenceFrame('N')
A = ReferenceFrame('A')
B = ReferenceFrame('B')
u1, u2, u3, u4 = dynamicsymbols('u1 u2 u3 u4')
v = u1 * u2 * A.x + u3 * N.y + u4**2 * N.z
assert v.diff(u1, N, var_in_dcm=False) == u2 * A.x
assert v.diff(u1, A, var_in_dcm=False) == u2 * A.x
assert v.diff(u3, N, var_in_dcm=False) == N.y
assert v.diff(u3, A, var_in_dcm=False) == N.y
assert v.diff(u3, B, var_in_dcm=False) == N.y
assert v.diff(u4, N, var_in_dcm=False) == 2 * u4 * N.z
raises(ValueError, lambda: v.diff(u1, N))
def test_vector_simplify():
x, y, z, k, n, m, w, f, s, A = symbols('x, y, z, k, n, m, w, f, s, A')
N = ReferenceFrame('N')
test1 = (1 / x + 1 / y) * N.x
assert (test1 & N.x) != (x + y) / (x * y)
test1 = test1.simplify()
assert (test1 & N.x) == (x + y) / (x * y)
test2 = (A**2 * s**4 / (4 * pi * k * m**3)) * N.x
test2 = test2.simplify()
assert (test2 & N.x) == (A**2 * s**4 / (4 * pi * k * m**3))
test3 = ((4 + 4 * x - 2 * (2 + 2 * x)) / (2 + 2 * x)) * N.x
test3 = test3.simplify()
assert (test3 & N.x) == 0
test4 = ((-4 * x * y**2 - 2 * y**3 - 2 * x**2 * y) / (x + y)**2) * N.x
test4 = test4.simplify()
assert (test4 & N.x) == -2 * y
def test_vector_evalf():
a, b = symbols('a b')
v = pi * A.x
assert v.evalf(2) == Float('3.1416', 2) * A.x
v = pi * A.x + 5 * a * A.y - b * A.z
assert v.evalf(3) == Float('3.1416', 3) * A.x + Float('5', 3) * a * A.y - b * A.z
assert v.evalf(5, subs={a: 1.234, b:5.8973}) == Float('3.1415926536', 5) * A.x + Float('6.17', 5) * A.y - Float('5.8973', 5) * A.z
def test_vector_angle():
A = ReferenceFrame('A')
v1 = A.x + A.y
v2 = A.z
assert v1.angle_between(v2) == pi/2
B = ReferenceFrame('B')
B.orient_axis(A, A.x, pi)
v3 = A.x
v4 = B.x
assert v3.angle_between(v4) == 0
def test_vector_xreplace():
x, y, z = symbols('x y z')
v = x**2 * A.x + x*y * A.y + x*y*z * A.z
assert v.xreplace({x : cos(x)}) == cos(x)**2 * A.x + y*cos(x) * A.y + y*z*cos(x) * A.z
assert v.xreplace({x*y : pi}) == x**2 * A.x + pi * A.y + x*y*z * A.z
assert v.xreplace({x*y*z : 1}) == x**2*A.x + x*y*A.y + A.z
assert v.xreplace({x:1, z:0}) == A.x + y * A.y
raises(TypeError, lambda: v.xreplace())
raises(TypeError, lambda: v.xreplace([x, y]))
def test_issue_23366():
u1 = dynamicsymbols('u1')
N = ReferenceFrame('N')
N_v_A = u1*N.x
raises(VectorTypeError, lambda: N_v_A.diff(N, u1))
def test_vector_outer():
a, b, c, d, e, f = symbols('a, b, c, d, e, f')
N = ReferenceFrame('N')
v1 = a*N.x + b*N.y + c*N.z
v2 = d*N.x + e*N.y + f*N.z
v1v2 = Matrix([[a*d, a*e, a*f],
[b*d, b*e, b*f],
[c*d, c*e, c*f]])
assert v1.outer(v2).to_matrix(N) == v1v2
assert (v1 | v2).to_matrix(N) == v1v2
v2v1 = Matrix([[d*a, d*b, d*c],
[e*a, e*b, e*c],
[f*a, f*b, f*c]])
assert v2.outer(v1).to_matrix(N) == v2v1
assert (v2 | v1).to_matrix(N) == v2v1
def test_overloaded_operators():
a, b, c, d, e, f = symbols('a, b, c, d, e, f')
N = ReferenceFrame('N')
v1 = a*N.x + b*N.y + c*N.z
v2 = d*N.x + e*N.y + f*N.z
assert v1 + v2 == v2 + v1
assert v1 - v2 == -v2 + v1
assert v1 & v2 == v2 & v1
assert v1 ^ v2 == v1.cross(v2)
assert v2 ^ v1 == v2.cross(v1)

View File

@ -0,0 +1,806 @@
from sympy import (S, sympify, expand, sqrt, Add, zeros, acos,
ImmutableMatrix as Matrix, simplify)
from sympy.simplify.trigsimp import trigsimp
from sympy.printing.defaults import Printable
from sympy.utilities.misc import filldedent
from sympy.core.evalf import EvalfMixin
from mpmath.libmp.libmpf import prec_to_dps
__all__ = ['Vector']
class Vector(Printable, EvalfMixin):
"""The class used to define vectors.
It along with ReferenceFrame are the building blocks of describing a
classical mechanics system in PyDy and sympy.physics.vector.
Attributes
==========
simp : Boolean
Let certain methods use trigsimp on their outputs
"""
simp = False
is_number = False
def __init__(self, inlist):
"""This is the constructor for the Vector class. You should not be
calling this, it should only be used by other functions. You should be
treating Vectors like you would with if you were doing the math by
hand, and getting the first 3 from the standard basis vectors from a
ReferenceFrame.
The only exception is to create a zero vector:
zv = Vector(0)
"""
self.args = []
if inlist == 0:
inlist = []
if isinstance(inlist, dict):
d = inlist
else:
d = {}
for inp in inlist:
if inp[1] in d:
d[inp[1]] += inp[0]
else:
d[inp[1]] = inp[0]
for k, v in d.items():
if v != Matrix([0, 0, 0]):
self.args.append((v, k))
@property
def func(self):
"""Returns the class Vector. """
return Vector
def __hash__(self):
return hash(tuple(self.args))
def __add__(self, other):
"""The add operator for Vector. """
if other == 0:
return self
other = _check_vector(other)
return Vector(self.args + other.args)
def dot(self, other):
"""Dot product of two vectors.
Returns a scalar, the dot product of the two Vectors
Parameters
==========
other : Vector
The Vector which we are dotting with
Examples
========
>>> from sympy.physics.vector import ReferenceFrame, dot
>>> from sympy import symbols
>>> q1 = symbols('q1')
>>> N = ReferenceFrame('N')
>>> dot(N.x, N.x)
1
>>> dot(N.x, N.y)
0
>>> A = N.orientnew('A', 'Axis', [q1, N.x])
>>> dot(N.y, A.y)
cos(q1)
"""
from sympy.physics.vector.dyadic import Dyadic, _check_dyadic
if isinstance(other, Dyadic):
other = _check_dyadic(other)
ol = Vector(0)
for v in other.args:
ol += v[0] * v[2] * (v[1].dot(self))
return ol
other = _check_vector(other)
out = S.Zero
for v1 in self.args:
for v2 in other.args:
out += ((v2[0].T) * (v2[1].dcm(v1[1])) * (v1[0]))[0]
if Vector.simp:
return trigsimp(out, recursive=True)
else:
return out
def __truediv__(self, other):
"""This uses mul and inputs self and 1 divided by other. """
return self.__mul__(S.One / other)
def __eq__(self, other):
"""Tests for equality.
It is very import to note that this is only as good as the SymPy
equality test; False does not always mean they are not equivalent
Vectors.
If other is 0, and self is empty, returns True.
If other is 0 and self is not empty, returns False.
If none of the above, only accepts other as a Vector.
"""
if other == 0:
other = Vector(0)
try:
other = _check_vector(other)
except TypeError:
return False
if (self.args == []) and (other.args == []):
return True
elif (self.args == []) or (other.args == []):
return False
frame = self.args[0][1]
for v in frame:
if expand((self - other).dot(v)) != 0:
return False
return True
def __mul__(self, other):
"""Multiplies the Vector by a sympifyable expression.
Parameters
==========
other : Sympifyable
The scalar to multiply this Vector with
Examples
========
>>> from sympy.physics.vector import ReferenceFrame
>>> from sympy import Symbol
>>> N = ReferenceFrame('N')
>>> b = Symbol('b')
>>> V = 10 * b * N.x
>>> print(V)
10*b*N.x
"""
newlist = list(self.args)
other = sympify(other)
for i, v in enumerate(newlist):
newlist[i] = (other * newlist[i][0], newlist[i][1])
return Vector(newlist)
def __neg__(self):
return self * -1
def outer(self, other):
"""Outer product between two Vectors.
A rank increasing operation, which returns a Dyadic from two Vectors
Parameters
==========
other : Vector
The Vector to take the outer product with
Examples
========
>>> from sympy.physics.vector import ReferenceFrame, outer
>>> N = ReferenceFrame('N')
>>> outer(N.x, N.x)
(N.x|N.x)
"""
from sympy.physics.vector.dyadic import Dyadic
other = _check_vector(other)
ol = Dyadic(0)
for v in self.args:
for v2 in other.args:
# it looks this way because if we are in the same frame and
# use the enumerate function on the same frame in a nested
# fashion, then bad things happen
ol += Dyadic([(v[0][0] * v2[0][0], v[1].x, v2[1].x)])
ol += Dyadic([(v[0][0] * v2[0][1], v[1].x, v2[1].y)])
ol += Dyadic([(v[0][0] * v2[0][2], v[1].x, v2[1].z)])
ol += Dyadic([(v[0][1] * v2[0][0], v[1].y, v2[1].x)])
ol += Dyadic([(v[0][1] * v2[0][1], v[1].y, v2[1].y)])
ol += Dyadic([(v[0][1] * v2[0][2], v[1].y, v2[1].z)])
ol += Dyadic([(v[0][2] * v2[0][0], v[1].z, v2[1].x)])
ol += Dyadic([(v[0][2] * v2[0][1], v[1].z, v2[1].y)])
ol += Dyadic([(v[0][2] * v2[0][2], v[1].z, v2[1].z)])
return ol
def _latex(self, printer):
"""Latex Printing method. """
ar = self.args # just to shorten things
if len(ar) == 0:
return str(0)
ol = [] # output list, to be concatenated to a string
for i, v in enumerate(ar):
for j in 0, 1, 2:
# if the coef of the basis vector is 1, we skip the 1
if ar[i][0][j] == 1:
ol.append(' + ' + ar[i][1].latex_vecs[j])
# if the coef of the basis vector is -1, we skip the 1
elif ar[i][0][j] == -1:
ol.append(' - ' + ar[i][1].latex_vecs[j])
elif ar[i][0][j] != 0:
# If the coefficient of the basis vector is not 1 or -1;
# also, we might wrap it in parentheses, for readability.
arg_str = printer._print(ar[i][0][j])
if isinstance(ar[i][0][j], Add):
arg_str = "(%s)" % arg_str
if arg_str[0] == '-':
arg_str = arg_str[1:]
str_start = ' - '
else:
str_start = ' + '
ol.append(str_start + arg_str + ar[i][1].latex_vecs[j])
outstr = ''.join(ol)
if outstr.startswith(' + '):
outstr = outstr[3:]
elif outstr.startswith(' '):
outstr = outstr[1:]
return outstr
def _pretty(self, printer):
"""Pretty Printing method. """
from sympy.printing.pretty.stringpict import prettyForm
terms = []
def juxtapose(a, b):
pa = printer._print(a)
pb = printer._print(b)
if a.is_Add:
pa = prettyForm(*pa.parens())
return printer._print_seq([pa, pb], delimiter=' ')
for M, N in self.args:
for i in range(3):
if M[i] == 0:
continue
elif M[i] == 1:
terms.append(prettyForm(N.pretty_vecs[i]))
elif M[i] == -1:
terms.append(prettyForm("-1") * prettyForm(N.pretty_vecs[i]))
else:
terms.append(juxtapose(M[i], N.pretty_vecs[i]))
if terms:
pretty_result = prettyForm.__add__(*terms)
else:
pretty_result = prettyForm("0")
return pretty_result
def __rsub__(self, other):
return (-1 * self) + other
def _sympystr(self, printer, order=True):
"""Printing method. """
if not order or len(self.args) == 1:
ar = list(self.args)
elif len(self.args) == 0:
return printer._print(0)
else:
d = {v[1]: v[0] for v in self.args}
keys = sorted(d.keys(), key=lambda x: x.index)
ar = []
for key in keys:
ar.append((d[key], key))
ol = [] # output list, to be concatenated to a string
for i, v in enumerate(ar):
for j in 0, 1, 2:
# if the coef of the basis vector is 1, we skip the 1
if ar[i][0][j] == 1:
ol.append(' + ' + ar[i][1].str_vecs[j])
# if the coef of the basis vector is -1, we skip the 1
elif ar[i][0][j] == -1:
ol.append(' - ' + ar[i][1].str_vecs[j])
elif ar[i][0][j] != 0:
# If the coefficient of the basis vector is not 1 or -1;
# also, we might wrap it in parentheses, for readability.
arg_str = printer._print(ar[i][0][j])
if isinstance(ar[i][0][j], Add):
arg_str = "(%s)" % arg_str
if arg_str[0] == '-':
arg_str = arg_str[1:]
str_start = ' - '
else:
str_start = ' + '
ol.append(str_start + arg_str + '*' + ar[i][1].str_vecs[j])
outstr = ''.join(ol)
if outstr.startswith(' + '):
outstr = outstr[3:]
elif outstr.startswith(' '):
outstr = outstr[1:]
return outstr
def __sub__(self, other):
"""The subtraction operator. """
return self.__add__(other * -1)
def cross(self, other):
"""The cross product operator for two Vectors.
Returns a Vector, expressed in the same ReferenceFrames as self.
Parameters
==========
other : Vector
The Vector which we are crossing with
Examples
========
>>> from sympy import symbols
>>> from sympy.physics.vector import ReferenceFrame, cross
>>> q1 = symbols('q1')
>>> N = ReferenceFrame('N')
>>> cross(N.x, N.y)
N.z
>>> A = ReferenceFrame('A')
>>> A.orient_axis(N, q1, N.x)
>>> cross(A.x, N.y)
N.z
>>> cross(N.y, A.x)
- sin(q1)*A.y - cos(q1)*A.z
"""
from sympy.physics.vector.dyadic import Dyadic, _check_dyadic
if isinstance(other, Dyadic):
other = _check_dyadic(other)
ol = Dyadic(0)
for i, v in enumerate(other.args):
ol += v[0] * ((self.cross(v[1])).outer(v[2]))
return ol
other = _check_vector(other)
if other.args == []:
return Vector(0)
def _det(mat):
"""This is needed as a little method for to find the determinant
of a list in python; needs to work for a 3x3 list.
SymPy's Matrix will not take in Vector, so need a custom function.
You should not be calling this.
"""
return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1])
+ mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] *
mat[2][2]) + mat[0][2] * (mat[1][0] * mat[2][1] -
mat[1][1] * mat[2][0]))
outlist = []
ar = other.args # For brevity
for i, v in enumerate(ar):
tempx = v[1].x
tempy = v[1].y
tempz = v[1].z
tempm = ([[tempx, tempy, tempz],
[self.dot(tempx), self.dot(tempy), self.dot(tempz)],
[Vector([ar[i]]).dot(tempx), Vector([ar[i]]).dot(tempy),
Vector([ar[i]]).dot(tempz)]])
outlist += _det(tempm).args
return Vector(outlist)
__radd__ = __add__
__rmul__ = __mul__
def separate(self):
"""
The constituents of this vector in different reference frames,
as per its definition.
Returns a dict mapping each ReferenceFrame to the corresponding
constituent Vector.
Examples
========
>>> from sympy.physics.vector import ReferenceFrame
>>> R1 = ReferenceFrame('R1')
>>> R2 = ReferenceFrame('R2')
>>> v = R1.x + R2.x
>>> v.separate() == {R1: R1.x, R2: R2.x}
True
"""
components = {}
for x in self.args:
components[x[1]] = Vector([x])
return components
def __and__(self, other):
return self.dot(other)
__and__.__doc__ = dot.__doc__
__rand__ = __and__
def __xor__(self, other):
return self.cross(other)
__xor__.__doc__ = cross.__doc__
def __or__(self, other):
return self.outer(other)
__or__.__doc__ = outer.__doc__
def diff(self, var, frame, var_in_dcm=True):
"""Returns the partial derivative of the vector with respect to a
variable in the provided reference frame.
Parameters
==========
var : Symbol
What the partial derivative is taken with respect to.
frame : ReferenceFrame
The reference frame that the partial derivative is taken in.
var_in_dcm : boolean
If true, the differentiation algorithm assumes that the variable
may be present in any of the direction cosine matrices that relate
the frame to the frames of any component of the vector. But if it
is known that the variable is not present in the direction cosine
matrices, false can be set to skip full reexpression in the desired
frame.
Examples
========
>>> from sympy import Symbol
>>> from sympy.physics.vector import dynamicsymbols, ReferenceFrame
>>> from sympy.physics.vector import init_vprinting
>>> init_vprinting(pretty_print=False)
>>> t = Symbol('t')
>>> q1 = dynamicsymbols('q1')
>>> N = ReferenceFrame('N')
>>> A = N.orientnew('A', 'Axis', [q1, N.y])
>>> A.x.diff(t, N)
- sin(q1)*q1'*N.x - cos(q1)*q1'*N.z
>>> A.x.diff(t, N).express(A).simplify()
- q1'*A.z
>>> B = ReferenceFrame('B')
>>> u1, u2 = dynamicsymbols('u1, u2')
>>> v = u1 * A.x + u2 * B.y
>>> v.diff(u2, N, var_in_dcm=False)
B.y
"""
from sympy.physics.vector.frame import _check_frame
_check_frame(frame)
var = sympify(var)
inlist = []
for vector_component in self.args:
measure_number = vector_component[0]
component_frame = vector_component[1]
if component_frame == frame:
inlist += [(measure_number.diff(var), frame)]
else:
# If the direction cosine matrix relating the component frame
# with the derivative frame does not contain the variable.
if not var_in_dcm or (frame.dcm(component_frame).diff(var) ==
zeros(3, 3)):
inlist += [(measure_number.diff(var), component_frame)]
else: # else express in the frame
reexp_vec_comp = Vector([vector_component]).express(frame)
deriv = reexp_vec_comp.args[0][0].diff(var)
inlist += Vector([(deriv, frame)]).args
return Vector(inlist)
def express(self, otherframe, variables=False):
"""
Returns a Vector equivalent to this one, expressed in otherframe.
Uses the global express method.
Parameters
==========
otherframe : ReferenceFrame
The frame for this Vector to be described in
variables : boolean
If True, the coordinate symbols(if present) in this Vector
are re-expressed in terms otherframe
Examples
========
>>> from sympy.physics.vector import ReferenceFrame, dynamicsymbols
>>> from sympy.physics.vector import init_vprinting
>>> init_vprinting(pretty_print=False)
>>> q1 = dynamicsymbols('q1')
>>> N = ReferenceFrame('N')
>>> A = N.orientnew('A', 'Axis', [q1, N.y])
>>> A.x.express(N)
cos(q1)*N.x - sin(q1)*N.z
"""
from sympy.physics.vector import express
return express(self, otherframe, variables=variables)
def to_matrix(self, reference_frame):
"""Returns the matrix form of the vector with respect to the given
frame.
Parameters
----------
reference_frame : ReferenceFrame
The reference frame that the rows of the matrix correspond to.
Returns
-------
matrix : ImmutableMatrix, shape(3,1)
The matrix that gives the 1D vector.
Examples
========
>>> from sympy import symbols
>>> from sympy.physics.vector import ReferenceFrame
>>> a, b, c = symbols('a, b, c')
>>> N = ReferenceFrame('N')
>>> vector = a * N.x + b * N.y + c * N.z
>>> vector.to_matrix(N)
Matrix([
[a],
[b],
[c]])
>>> beta = symbols('beta')
>>> A = N.orientnew('A', 'Axis', (beta, N.x))
>>> vector.to_matrix(A)
Matrix([
[ a],
[ b*cos(beta) + c*sin(beta)],
[-b*sin(beta) + c*cos(beta)]])
"""
return Matrix([self.dot(unit_vec) for unit_vec in
reference_frame]).reshape(3, 1)
def doit(self, **hints):
"""Calls .doit() on each term in the Vector"""
d = {}
for v in self.args:
d[v[1]] = v[0].applyfunc(lambda x: x.doit(**hints))
return Vector(d)
def dt(self, otherframe):
"""
Returns a Vector which is the time derivative of
the self Vector, taken in frame otherframe.
Calls the global time_derivative method
Parameters
==========
otherframe : ReferenceFrame
The frame to calculate the time derivative in
"""
from sympy.physics.vector import time_derivative
return time_derivative(self, otherframe)
def simplify(self):
"""Returns a simplified Vector."""
d = {}
for v in self.args:
d[v[1]] = simplify(v[0])
return Vector(d)
def subs(self, *args, **kwargs):
"""Substitution on the Vector.
Examples
========
>>> from sympy.physics.vector import ReferenceFrame
>>> from sympy import Symbol
>>> N = ReferenceFrame('N')
>>> s = Symbol('s')
>>> a = N.x * s
>>> a.subs({s: 2})
2*N.x
"""
d = {}
for v in self.args:
d[v[1]] = v[0].subs(*args, **kwargs)
return Vector(d)
def magnitude(self):
"""Returns the magnitude (Euclidean norm) of self.
Warnings
========
Python ignores the leading negative sign so that might
give wrong results.
``-A.x.magnitude()`` would be treated as ``-(A.x.magnitude())``,
instead of ``(-A.x).magnitude()``.
"""
return sqrt(self.dot(self))
def normalize(self):
"""Returns a Vector of magnitude 1, codirectional with self."""
return Vector(self.args + []) / self.magnitude()
def applyfunc(self, f):
"""Apply a function to each component of a vector."""
if not callable(f):
raise TypeError("`f` must be callable.")
d = {}
for v in self.args:
d[v[1]] = v[0].applyfunc(f)
return Vector(d)
def angle_between(self, vec):
"""
Returns the smallest angle between Vector 'vec' and self.
Parameter
=========
vec : Vector
The Vector between which angle is needed.
Examples
========
>>> from sympy.physics.vector import ReferenceFrame
>>> A = ReferenceFrame("A")
>>> v1 = A.x
>>> v2 = A.y
>>> v1.angle_between(v2)
pi/2
>>> v3 = A.x + A.y + A.z
>>> v1.angle_between(v3)
acos(sqrt(3)/3)
Warnings
========
Python ignores the leading negative sign so that might give wrong
results. ``-A.x.angle_between()`` would be treated as
``-(A.x.angle_between())``, instead of ``(-A.x).angle_between()``.
"""
vec1 = self.normalize()
vec2 = vec.normalize()
angle = acos(vec1.dot(vec2))
return angle
def free_symbols(self, reference_frame):
"""Returns the free symbols in the measure numbers of the vector
expressed in the given reference frame.
Parameters
==========
reference_frame : ReferenceFrame
The frame with respect to which the free symbols of the given
vector is to be determined.
Returns
=======
set of Symbol
set of symbols present in the measure numbers of
``reference_frame``.
"""
return self.to_matrix(reference_frame).free_symbols
def free_dynamicsymbols(self, reference_frame):
"""Returns the free dynamic symbols (functions of time ``t``) in the
measure numbers of the vector expressed in the given reference frame.
Parameters
==========
reference_frame : ReferenceFrame
The frame with respect to which the free dynamic symbols of the
given vector is to be determined.
Returns
=======
set
Set of functions of time ``t``, e.g.
``Function('f')(me.dynamicsymbols._t)``.
"""
# TODO : Circular dependency if imported at top. Should move
# find_dynamicsymbols into physics.vector.functions.
from sympy.physics.mechanics.functions import find_dynamicsymbols
return find_dynamicsymbols(self, reference_frame=reference_frame)
def _eval_evalf(self, prec):
if not self.args:
return self
new_args = []
dps = prec_to_dps(prec)
for mat, frame in self.args:
new_args.append([mat.evalf(n=dps), frame])
return Vector(new_args)
def xreplace(self, rule):
"""Replace occurrences of objects within the measure numbers of the
vector.
Parameters
==========
rule : dict-like
Expresses a replacement rule.
Returns
=======
Vector
Result of the replacement.
Examples
========
>>> from sympy import symbols, pi
>>> from sympy.physics.vector import ReferenceFrame
>>> A = ReferenceFrame('A')
>>> x, y, z = symbols('x y z')
>>> ((1 + x*y) * A.x).xreplace({x: pi})
(pi*y + 1)*A.x
>>> ((1 + x*y) * A.x).xreplace({x: pi, y: 2})
(1 + 2*pi)*A.x
Replacements occur only if an entire node in the expression tree is
matched:
>>> ((x*y + z) * A.x).xreplace({x*y: pi})
(z + pi)*A.x
>>> ((x*y*z) * A.x).xreplace({x*y: pi})
x*y*z*A.x
"""
new_args = []
for mat, frame in self.args:
mat = mat.xreplace(rule)
new_args.append([mat, frame])
return Vector(new_args)
class VectorTypeError(TypeError):
def __init__(self, other, want):
msg = filldedent("Expected an instance of %s, but received object "
"'%s' of %s." % (type(want), other, type(other)))
super().__init__(msg)
def _check_vector(other):
if not isinstance(other, Vector):
raise TypeError('A Vector must be supplied')
return other