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