Navigation

Source code for sympy.physics.mechanics.functions

from__future__importprint_function,divisionfromsympy.utilities.exceptionsimportSymPyDeprecationWarningfromsympy.utilities.miscimportfilldedentfromsympy.utilitiesimportdict_mergefromsympy.utilities.iterablesimportiterablefromsympy.physics.vectorimportVector,ReferenceFrame,Point,dynamicsymbolsfromsympy.physics.vector.printingimport(vprint,vsprint,vpprint,vlatex,init_vprinting)fromsympy.physics.mechanics.particleimportParticlefromsympy.physics.mechanics.rigidbodyimportRigidBodyfromsympyimportsympify,Matrix,Derivative,sin,cos,tan,simplify,Mulfromsympy.core.functionimportAppliedUndeffromsympy.core.basicimportS__all__=['inertia','inertia_of_point_mass','linear_momentum','angular_momentum','kinetic_energy','potential_energy','Lagrangian','mechanics_printing','mprint','msprint','mpprint','mlatex','msubs','find_dynamicsymbols']# These are functions that we've moved and renamed during extracting the# basic vector calculus code from the mechanics packages.mprint=vprintmsprint=vsprintmpprint=vpprintmlatex=vlatexdefmechanics_printing(**kwargs):init_vprinting(**kwargs)mechanics_printing.__doc__=init_vprinting.__doc__

[docs]definertia(frame,ixx,iyy,izz,ixy=0,iyz=0,izx=0):"""Simple way to create inertia Dyadic object. If you don't know what a Dyadic is, just treat this like the inertia tensor. Then, do the easy thing and define it in a body-fixed frame. Parameters ========== frame : ReferenceFrame The frame the inertia is defined in ixx : Sympifyable the xx element in the inertia dyadic iyy : Sympifyable the yy element in the inertia dyadic izz : Sympifyable the zz element in the inertia dyadic ixy : Sympifyable the xy element in the inertia dyadic iyz : Sympifyable the yz element in the inertia dyadic izx : Sympifyable the zx element in the inertia dyadic Examples ======== >>> from sympy.physics.mechanics import ReferenceFrame, inertia >>> N = ReferenceFrame('N') >>> inertia(N, 1, 2, 3) (N.x|N.x) + 2*(N.y|N.y) + 3*(N.z|N.z) """ifnotisinstance(frame,ReferenceFrame):raiseTypeError('Need to define the inertia in a frame')ol=sympify(ixx)*(frame.x|frame.x)ol+=sympify(ixy)*(frame.x|frame.y)ol+=sympify(izx)*(frame.x|frame.z)ol+=sympify(ixy)*(frame.y|frame.x)ol+=sympify(iyy)*(frame.y|frame.y)ol+=sympify(iyz)*(frame.y|frame.z)ol+=sympify(izx)*(frame.z|frame.x)ol+=sympify(iyz)*(frame.z|frame.y)ol+=sympify(izz)*(frame.z|frame.z)returnol

deffind_dynamicsymbols(expression,exclude=None):"""Find all dynamicsymbols in expression. >>> from sympy.physics.mechanics import dynamicsymbols, find_dynamicsymbols >>> x, y = dynamicsymbols('x, y') >>> expr = x + x.diff()*y >>> find_dynamicsymbols(expr) set([x(t), y(t), Derivative(x(t), t)]) If the optional ``exclude`` kwarg is used, only dynamicsymbols not in the iterable ``exclude`` are returned. >>> find_dynamicsymbols(expr, [x, y]) set([Derivative(x(t), t)]) """t_set=set([dynamicsymbols._t])ifexclude:ifiterable(exclude):exclude_set=set(exclude)else:raiseTypeError("exclude kwarg must be iterable")else:exclude_set=set()returnset([iforiinexpression.atoms(AppliedUndef,Derivative)ifi.free_symbols==t_set])-exclude_setdefmsubs(expr,*sub_dicts,**kwargs):"""A custom subs for use on expressions derived in physics.mechanics. Traverses the expression tree once, performing the subs found in sub_dicts. Terms inside ``Derivative`` expressions are ignored: >>> from sympy.physics.mechanics import dynamicsymbols, msubs >>> x = dynamicsymbols('x') >>> msubs(x.diff() + x, {x: 1}) Derivative(x(t), t) + 1 Note that sub_dicts can be a single dictionary, or several dictionaries: >>> x, y, z = dynamicsymbols('x, y, z') >>> sub1 = {x: 1, y: 2} >>> sub2 = {z: 3, x.diff(): 4} >>> msubs(x.diff() + x + y + z, sub1, sub2) 10 If smart=True (default False), also checks for conditions that may result in ``nan``, but if simplified would yield a valid expression. For example: >>> from sympy import sin, tan >>> (sin(x)/tan(x)).subs(x, 0) nan >>> msubs(sin(x)/tan(x), {x: 0}, smart=True) 1 It does this by first replacing all ``tan`` with ``sin/cos``. Then each node is traversed. If the node is a fraction, subs is first evaluated on the denominator. If this results in 0, simplification of the entire fraction is attempted. Using this selective simplification, only subexpressions that result in 1/0 are targeted, resulting in faster performance."""sub_dict=dict_merge(*sub_dicts)smart=kwargs.pop('smart',False)ifsmart:func=_smart_subselse:func=lambdaexpr,sub_dict:_crawl(expr,_sub_func,sub_dict)ifisinstance(expr,Matrix):returnexpr.applyfunc(lambdax:func(x,sub_dict))else:returnfunc(expr,sub_dict)def_crawl(expr,func,*args,**kwargs):"""Crawl the expression tree, and apply func to every node."""val=func(expr,*args,**kwargs)ifvalisnotNone:returnvalnew_args=(_crawl(arg,func,*args,**kwargs)forarginexpr.args)returnexpr.func(*new_args)def_sub_func(expr,sub_dict):"""Perform direct matching substitution, ignoring derivatives."""ifexprinsub_dict:returnsub_dict[expr]elifnotexpr.argsorexpr.is_Derivative:returnexprdef_tan_repl_func(expr):"""Replace tan with sin/cos."""ifisinstance(expr,tan):returnsin(*expr.args)/cos(*expr.args)elifnotexpr.argsorexpr.is_Derivative:returnexprdef_smart_subs(expr,sub_dict):"""Performs subs, checking for conditions that may result in `nan` or `oo`, and attempts to simplify them out. The expression tree is traversed twice, and the following steps are performed on each expression node: - First traverse: Replace all `tan` with `sin/cos`. - Second traverse: If node is a fraction, check if the denominator evaluates to 0. If so, attempt to simplify it out. Then if node is in sub_dict, sub in the corresponding value."""expr=_crawl(expr,_tan_repl_func)def_recurser(expr,sub_dict):# Decompose the expression into num, dennum,den=_fraction_decomp(expr)ifden!=1:# If there is a non trivial denominator, we need to handle itdenom_subbed=_recurser(den,sub_dict)ifdenom_subbed.evalf()==0:# If denom is 0 after this, attempt to simplify the bad exprexpr=simplify(expr)else:# Expression won't result in nan, find numeratornum_subbed=_recurser(num,sub_dict)returnnum_subbed/denom_subbed# We have to crawl the tree manually, because `expr` may have been# modified in the simplify step. First, perform subs as normal:val=_sub_func(expr,sub_dict)ifvalisnotNone:returnvalnew_args=(_recurser(arg,sub_dict)forarginexpr.args)returnexpr.func(*new_args)return_recurser(expr,sub_dict)def_fraction_decomp(expr):"""Return num, den such that expr = num/den"""ifnotisinstance(expr,Mul):returnexpr,1num=[]den=[]forainexpr.args:ifa.is_Powanda.args[1]<0:den.append(1/a)else:num.append(a)ifnotden:returnexpr,1num=Mul(*num)den=Mul(*den)returnnum,dendef_f_list_parser(fl,ref_frame):"""Parses the provided forcelist composed of items of the form (obj, force). Returns a tuple containing: vlist: The velocity (ang_vel for Frames, vel for Points) in the provided reference frame. flist: The forces. Used internally in the KanesMethod and LagrangesMethod classes. """defflist_iter():forobj,forceinfl:ifisinstance(obj,ReferenceFrame):yieldobj.ang_vel_in(ref_frame),forceelifisinstance(obj,Point):yieldobj.vel(ref_frame),forceelse:raiseTypeError('First entry in each forcelist pair must ''be a point or frame.')unzip=lambdal:list(zip(*l))ifl[0]else[(),()]vel_list,f_list=unzip(list(flist_iter()))returnvel_list,f_list