123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- 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)
|