Adding all project files
This commit is contained in:
parent
6c9e127bdc
commit
cd4316ad0f
42289 changed files with 8009643 additions and 0 deletions
36
venv/Lib/site-packages/sympy/physics/vector/__init__.py
Normal file
36
venv/Lib/site-packages/sympy/physics/vector/__init__.py
Normal 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)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
545
venv/Lib/site-packages/sympy/physics/vector/dyadic.py
Normal file
545
venv/Lib/site-packages/sympy/physics/vector/dyadic.py
Normal 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 in range(len(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 v in ar:
|
||||
# if the coef of the dyadic is 1, we skip the 1
|
||||
if v[0] == 1:
|
||||
ol.append(' + ' + printer._print(v[1]) + r"\otimes " +
|
||||
printer._print(v[2]))
|
||||
# if the coef of the dyadic is -1, we skip the 1
|
||||
elif v[0] == -1:
|
||||
ol.append(' - ' +
|
||||
printer._print(v[1]) +
|
||||
r"\otimes " +
|
||||
printer._print(v[2]))
|
||||
# If the coefficient of the dyadic is not 1 or -1,
|
||||
# we might wrap it in parentheses, for readability.
|
||||
elif v[0] != 0:
|
||||
arg_str = printer._print(v[0])
|
||||
if isinstance(v[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(v[1]) +
|
||||
r"\otimes " + printer._print(v[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 v in ar:
|
||||
# if the coef of the dyadic is 1, we skip the 1
|
||||
if v[0] == 1:
|
||||
ol.extend([" + ",
|
||||
mpp.doprint(v[1]),
|
||||
bar,
|
||||
mpp.doprint(v[2])])
|
||||
|
||||
# if the coef of the dyadic is -1, we skip the 1
|
||||
elif v[0] == -1:
|
||||
ol.extend([" - ",
|
||||
mpp.doprint(v[1]),
|
||||
bar,
|
||||
mpp.doprint(v[2])])
|
||||
|
||||
# If the coefficient of the dyadic is not 1 or -1,
|
||||
# we might wrap it in parentheses, for readability.
|
||||
elif v[0] != 0:
|
||||
if isinstance(v[0], Add):
|
||||
arg_str = mpp._print(
|
||||
v[0]).parens()[0]
|
||||
else:
|
||||
arg_str = mpp.doprint(v[0])
|
||||
if arg_str.startswith("-"):
|
||||
arg_str = arg_str[1:]
|
||||
str_start = " - "
|
||||
else:
|
||||
str_start = " + "
|
||||
ol.extend([str_start, arg_str, " ",
|
||||
mpp.doprint(v[1]),
|
||||
bar,
|
||||
mpp.doprint(v[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 v in ar:
|
||||
# if the coef of the dyadic is 1, we skip the 1
|
||||
if v[0] == 1:
|
||||
ol.append(' + (' + printer._print(v[1]) + '|' +
|
||||
printer._print(v[2]) + ')')
|
||||
# if the coef of the dyadic is -1, we skip the 1
|
||||
elif v[0] == -1:
|
||||
ol.append(' - (' + printer._print(v[1]) + '|' +
|
||||
printer._print(v[2]) + ')')
|
||||
# If the coefficient of the dyadic is not 1 or -1,
|
||||
# we might wrap it in parentheses, for readability.
|
||||
elif v[0] != 0:
|
||||
arg_str = printer._print(v[0])
|
||||
if isinstance(v[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(v[1]) +
|
||||
'|' + printer._print(v[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
|
313
venv/Lib/site-packages/sympy/physics/vector/fieldfunctions.py
Normal file
313
venv/Lib/site-packages/sympy/physics/vector/fieldfunctions.py
Normal 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 # noqa: PLR1736
|
||||
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)
|
1575
venv/Lib/site-packages/sympy/physics/vector/frame.py
Normal file
1575
venv/Lib/site-packages/sympy/physics/vector/frame.py
Normal file
File diff suppressed because it is too large
Load diff
650
venv/Lib/site-packages/sympy/physics/vector/functions.py
Normal file
650
venv/Lib/site-packages/sympy/physics/vector/functions.py
Normal 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
|
635
venv/Lib/site-packages/sympy/physics/vector/point.py
Normal file
635
venv/Lib/site-packages/sympy/physics/vector/point.py
Normal 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.copy()
|
||||
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)
|
371
venv/Lib/site-packages/sympy/physics/vector/printing.py
Normal file
371
venv/Lib/site-packages/sympy/physics/vector/printing.py
Normal 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
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
123
venv/Lib/site-packages/sympy/physics/vector/tests/test_dyadic.py
Normal file
123
venv/Lib/site-packages/sympy/physics/vector/tests/test_dyadic.py
Normal 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]))
|
|
@ -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
|
761
venv/Lib/site-packages/sympy/physics/vector/tests/test_frame.py
Normal file
761
venv/Lib/site-packages/sympy/physics/vector/tests/test_frame.py
Normal 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
|
|
@ -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
|
|
@ -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)
|
382
venv/Lib/site-packages/sympy/physics/vector/tests/test_point.py
Normal file
382
venv/Lib/site-packages/sympy/physics/vector/tests/test_point.py
Normal 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
|
|
@ -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}"
|
274
venv/Lib/site-packages/sympy/physics/vector/tests/test_vector.py
Normal file
274
venv/Lib/site-packages/sympy/physics/vector/tests/test_vector.py
Normal 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)
|
806
venv/Lib/site-packages/sympy/physics/vector/vector.py
Normal file
806
venv/Lib/site-packages/sympy/physics/vector/vector.py
Normal 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 in range(len(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 v in ar:
|
||||
for j in 0, 1, 2:
|
||||
# if the coef of the basis vector is 1, we skip the 1
|
||||
if v[0][j] == 1:
|
||||
ol.append(' + ' + v[1].latex_vecs[j])
|
||||
# if the coef of the basis vector is -1, we skip the 1
|
||||
elif v[0][j] == -1:
|
||||
ol.append(' - ' + v[1].latex_vecs[j])
|
||||
elif v[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(v[0][j])
|
||||
if isinstance(v[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 + v[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 v in ar:
|
||||
for j in 0, 1, 2:
|
||||
# if the coef of the basis vector is 1, we skip the 1
|
||||
if v[0][j] == 1:
|
||||
ol.append(' + ' + v[1].str_vecs[j])
|
||||
# if the coef of the basis vector is -1, we skip the 1
|
||||
elif v[0][j] == -1:
|
||||
ol.append(' - ' + v[1].str_vecs[j])
|
||||
elif v[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(v[0][j])
|
||||
if isinstance(v[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 + '*' + v[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 v in 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([v]).dot(tempx), Vector([v]).dot(tempy),
|
||||
Vector([v]).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
|
Loading…
Add table
Add a link
Reference in a new issue