Source code for sympy.vector.functions

from sympy.vector.coordsysrect import CoordSysCartesian
from sympy.vector.dyadic import Dyadic
from sympy.vector.vector import Vector, BaseVector
from sympy.vector.scalar import BaseScalar
from sympy import sympify, diff, integrate, S, simplify


[docs]def express(expr, system, system2=None, variables=False): """ Global function for 'express' functionality. Re-expresses a Vector, Dyadic or scalar(sympyfiable) in the given coordinate system. If 'variables' is True, then the coordinate variables (base scalars) of other coordinate systems present in the vector/scalar field or dyadic are also substituted in terms of the base scalars of the given system. Parameters ========== expr : Vector/Dyadic/scalar(sympyfiable) The expression to re-express in CoordSysCartesian 'system' system: CoordSysCartesian The coordinate system the expr is to be expressed in system2: CoordSysCartesian The other coordinate system required for re-expression (only for a Dyadic Expr) variables : boolean Specifies whether to substitute the coordinate variables present in expr, in terms of those of parameter system Examples ======== >>> from sympy.vector import CoordSysCartesian >>> from sympy import Symbol, cos, sin >>> N = CoordSysCartesian('N') >>> q = Symbol('q') >>> B = N.orient_new_axis('B', q, N.k) >>> from sympy.vector import express >>> express(B.i, N) (cos(q))*N.i + (sin(q))*N.j >>> express(N.x, B, variables=True) -sin(q)*B.y + cos(q)*B.x >>> d = N.i.outer(N.i) >>> express(d, B, N) == (cos(q))*(B.i|N.i) + (-sin(q))*(B.j|N.i) True """ if expr == 0 or expr == Vector.zero: return expr if not isinstance(system, CoordSysCartesian): raise TypeError("system should be a CoordSysCartesian \ instance") if isinstance(expr, Vector): if system2 is not None: raise ValueError("system2 should not be provided for \ Vectors") # Given expr is a Vector if variables: # If variables attribute is True, substitute # the coordinate variables in the Vector system_list = [] for x in expr.atoms(BaseScalar, BaseVector): if x.system != system: system_list.append(x.system) system_list = set(system_list) subs_dict = {} for f in system_list: subs_dict.update(f.scalar_map(system)) expr = expr.subs(subs_dict) # Re-express in this coordinate system outvec = Vector.zero parts = expr.separate() for x in parts: if x != system: temp = system.rotation_matrix(x) * parts[x].to_matrix(x) outvec += matrix_to_vector(temp, system) else: outvec += parts[x] return outvec elif isinstance(expr, Dyadic): if system2 is None: system2 = system if not isinstance(system2, CoordSysCartesian): raise TypeError("system2 should be a CoordSysCartesian \ instance") outdyad = Dyadic.zero var = variables for k, v in expr.components.items(): outdyad += (express(v, system, variables=var) * (express(k.args[0], system, variables=var) | express(k.args[1], system2, variables=var))) return outdyad else: if system2 is not None: raise ValueError("system2 should not be provided for \ Vectors") if variables: # Given expr is a scalar field system_set = set([]) expr = sympify(expr) # Subsitute all the coordinate variables for x in expr.atoms(BaseScalar): if x.system != system: system_set.add(x.system) subs_dict = {} for f in system_set: subs_dict.update(f.scalar_map(system)) return expr.subs(subs_dict) return expr
[docs]def curl(vect, coord_sys): """ Returns the curl of a vector field computed wrt the base scalars of the given coordinate system. Parameters ========== vect : Vector The vector operand coord_sys : CoordSysCartesian The coordinate system to calculate the curl in Examples ======== >>> from sympy.vector import CoordSysCartesian, curl >>> R = CoordSysCartesian('R') >>> v1 = R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k >>> curl(v1, R) 0 >>> v2 = R.x*R.y*R.z*R.i >>> curl(v2, R) R.x*R.y*R.j + (-R.x*R.z)*R.k """ return coord_sys.delop.cross(vect).doit()
[docs]def divergence(vect, coord_sys): """ Returns the divergence of a vector field computed wrt the base scalars of the given coordinate system. Parameters ========== vect : Vector The vector operand coord_sys : CoordSysCartesian The cooordinate system to calculate the divergence in Examples ======== >>> from sympy.vector import CoordSysCartesian, divergence >>> R = CoordSysCartesian('R') >>> v1 = R.x*R.y*R.z * (R.i+R.j+R.k) >>> divergence(v1, R) R.x*R.y + R.x*R.z + R.y*R.z >>> v2 = 2*R.y*R.z*R.j >>> divergence(v2, R) 2*R.z """ return coord_sys.delop.dot(vect).doit()
[docs]def gradient(scalar, coord_sys): """ Returns the vector gradient of a scalar field computed wrt the base scalars of the given coordinate system. Parameters ========== scalar : SymPy Expr The scalar field to compute the gradient of coord_sys : CoordSysCartesian The coordinate system to calculate the gradient in Examples ======== >>> from sympy.vector import CoordSysCartesian, gradient >>> R = CoordSysCartesian('R') >>> s1 = R.x*R.y*R.z >>> gradient(s1, R) R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k >>> s2 = 5*R.x**2*R.z >>> gradient(s2, R) 10*R.x*R.z*R.i + 5*R.x**2*R.k """ return coord_sys.delop(scalar).doit()
[docs]def is_conservative(field): """ Checks if a field is conservative. Paramaters ========== field : Vector The field to check for conservative property Examples ======== >>> from sympy.vector import CoordSysCartesian >>> from sympy.vector import is_conservative >>> R = CoordSysCartesian('R') >>> is_conservative(R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k) True >>> is_conservative(R.z*R.j) False """ # Field is conservative irrespective of system # Take the first coordinate system in the result of the # separate method of Vector if not isinstance(field, Vector): raise TypeError("field should be a Vector") if field == Vector.zero: return True coord_sys = list(field.separate())[0] return curl(field, coord_sys).simplify() == Vector.zero
[docs]def is_solenoidal(field): """ Checks if a field is solenoidal. Paramaters ========== field : Vector The field to check for solenoidal property Examples ======== >>> from sympy.vector import CoordSysCartesian >>> from sympy.vector import is_solenoidal >>> R = CoordSysCartesian('R') >>> is_solenoidal(R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k) True >>> is_solenoidal(R.y * R.j) False """ # Field is solenoidal irrespective of system # Take the first coordinate system in the result of the # separate method in Vector if not isinstance(field, Vector): raise TypeError("field should be a Vector") if field == Vector.zero: return True coord_sys = list(field.separate())[0] return divergence(field, coord_sys).simplify() == S(0)
[docs]def scalar_potential(field, coord_sys): """ Returns the scalar potential function of a field in a given coordinate system (without the added integration constant). Parameters ========== field : Vector The vector field whose scalar potential function is to be calculated coord_sys : CoordSysCartesian The coordinate system to do the calculation in Examples ======== >>> from sympy.vector import CoordSysCartesian >>> from sympy.vector import scalar_potential, gradient >>> R = CoordSysCartesian('R') >>> scalar_potential(R.k, R) == R.z True >>> scalar_field = 2*R.x**2*R.y*R.z >>> 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.zero: return S(0) # Express the field exntirely in coord_sys # Subsitute coordinate variables also if not isinstance(coord_sys, CoordSysCartesian): raise TypeError("coord_sys must be a CoordSysCartesian") field = express(field, coord_sys, variables=True) dimensions = coord_sys.base_vectors() scalars = coord_sys.base_scalars() # Calculate scalar potential function temp_function = integrate(field.dot(dimensions[0]), scalars[0]) for i, dim in enumerate(dimensions[1:]): partial_diff = diff(temp_function, scalars[i + 1]) partial_diff = field.dot(dim) - partial_diff temp_function += integrate(partial_diff, scalars[i + 1]) return temp_function
[docs]def scalar_potential_difference(field, coord_sys, point1, point2): """ Returns the scalar potential difference between two points in a certain coordinate system, 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 point2) - (potential at point1) The position vectors of the two Points are calculated wrt the origin of the coordinate system provided. Parameters ========== field : Vector/Expr The field to calculate wrt coord_sys : CoordSysCartesian The coordinate system to do the calculations in point1 : Point The initial Point in given coordinate system position2 : Point The second Point in the given coordinate system Examples ======== >>> from sympy.vector import CoordSysCartesian, Point >>> from sympy.vector import scalar_potential_difference >>> R = CoordSysCartesian('R') >>> P = R.origin.locate_new('P', R.x*R.i + R.y*R.j + R.z*R.k) >>> vectfield = 4*R.x*R.y*R.i + 2*R.x**2*R.j >>> scalar_potential_difference(vectfield, R, R.origin, P) 2*R.x**2*R.y >>> Q = R.origin.locate_new('O', 3*R.i + R.j + 2*R.k) >>> scalar_potential_difference(vectfield, R, P, Q) -2*R.x**2*R.y + 18 """ if not isinstance(coord_sys, CoordSysCartesian): raise TypeError("coord_sys must be a CoordSysCartesian") if isinstance(field, Vector): # Get the scalar potential function scalar_fn = scalar_potential(field, coord_sys) else: # Field is a scalar scalar_fn = field # Express positions in required coordinate system origin = coord_sys.origin position1 = express(point1.position_wrt(origin), coord_sys, variables=True) position2 = express(point2.position_wrt(origin), coord_sys, variables=True) # Get the two positions as substitution dicts for coordinate variables subs_dict1 = {} subs_dict2 = {} scalars = coord_sys.base_scalars() for i, x in enumerate(coord_sys.base_vectors()): subs_dict1[scalars[i]] = x.dot(position1) subs_dict2[scalars[i]] = x.dot(position2) return scalar_fn.subs(subs_dict2) - scalar_fn.subs(subs_dict1)
[docs]def matrix_to_vector(matrix, system): """ Converts a vector in matrix form to a Vector instance. It is assumed that the elements of the Matrix represent the measure numbers of the components of the vector along basis vectors of 'system'. Parameters ========== matrix : SymPy Matrix, Dimensions: (3, 1) The matrix to be converted to a vector system : CoordSysCartesian The coordinate system the vector is to be defined in Examples ======== >>> from sympy import ImmutableMatrix as Matrix >>> m = Matrix([1, 2, 3]) >>> from sympy.vector import CoordSysCartesian, matrix_to_vector >>> C = CoordSysCartesian('C') >>> v = matrix_to_vector(m, C) >>> v C.i + 2*C.j + 3*C.k >>> v.to_matrix(C) == m True """ outvec = Vector.zero vects = system.base_vectors() for i, x in enumerate(matrix): outvec += x * vects[i] return outvec
def _path(from_object, to_object): """ Calculates the 'path' of objects starting from 'from_object' to 'to_object', along with the index of the first common ancestor in the tree. Returns (index, list) tuple. """ if from_object._root != to_object._root: raise ValueError("No connecting path found between " + str(from_object) + " and " + str(to_object)) other_path = [] obj = to_object while obj._parent is not None: other_path.append(obj) obj = obj._parent other_path.append(obj) object_set = set(other_path) from_path = [] obj = from_object while obj not in object_set: from_path.append(obj) obj = obj._parent index = len(from_path) i = other_path.index(obj) while i >= 0: from_path.append(other_path[i]) i -= 1 return index, from_path def orthogonalize(*vlist, **kwargs): """ Takes a sequence of independent vectors and orthogonalizes them using the Gram - Schmidt process. Returns a list of orthogonal or orthonormal vectors. Parameters ========== vlist : sequence of independent vectors to be made orthogonal. orthonormal : Optional parameter Set to True if the the vectors returned should be orthonormal. Default: False Examples ======== >>> from sympy.vector.coordsysrect import CoordSysCartesian >>> from sympy.vector.vector import Vector, BaseVector >>> from sympy.vector.functions import orthogonalize >>> C = CoordSysCartesian('C') >>> i, j, k = C.base_vectors() >>> v1 = i + 2*j >>> v2 = 2*i + 3*j >>> orthogonalize(v1, v2) [C.i + 2*C.j, 2/5*C.i + (-1/5)*C.j] References ========== .. [1] https://en.wikipedia.org/wiki/Gram-Schmidt_process """ orthonormal = kwargs.get('orthonormal', False) if not all(isinstance(vec, Vector) for vec in vlist): raise TypeError('Each element must be of Type Vector') ortho_vlist = [] for i, term in enumerate(vlist): for j in range(i): term -= ortho_vlist[j].projection(vlist[i]) # TODO : The following line introduces a performance issue # and needs to be changed once a good solution for issue #10279 is # found. if simplify(term).equals(Vector.zero): raise ValueError("Vector set not linearly independent") ortho_vlist.append(term) if orthonormal: ortho_vlist = [vec.normalize() for vec in ortho_vlist] return ortho_vlist