m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

315 lines
8.4 KiB

7 months ago
  1. from sympy.core.function import diff
  2. from sympy.core.singleton import S
  3. from sympy.integrals.integrals import integrate
  4. from sympy.physics.vector import Vector, express
  5. from sympy.physics.vector.frame import _check_frame
  6. from sympy.physics.vector.vector import _check_vector
  7. __all__ = ['curl', 'divergence', 'gradient', 'is_conservative',
  8. 'is_solenoidal', 'scalar_potential',
  9. 'scalar_potential_difference']
  10. def curl(vect, frame):
  11. """
  12. Returns the curl of a vector field computed wrt the coordinate
  13. symbols of the given frame.
  14. Parameters
  15. ==========
  16. vect : Vector
  17. The vector operand
  18. frame : ReferenceFrame
  19. The reference frame to calculate the curl in
  20. Examples
  21. ========
  22. >>> from sympy.physics.vector import ReferenceFrame
  23. >>> from sympy.physics.vector import curl
  24. >>> R = ReferenceFrame('R')
  25. >>> v1 = R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z
  26. >>> curl(v1, R)
  27. 0
  28. >>> v2 = R[0]*R[1]*R[2]*R.x
  29. >>> curl(v2, R)
  30. R_x*R_y*R.y - R_x*R_z*R.z
  31. """
  32. _check_vector(vect)
  33. if vect == 0:
  34. return Vector(0)
  35. vect = express(vect, frame, variables=True)
  36. #A mechanical approach to avoid looping overheads
  37. vectx = vect.dot(frame.x)
  38. vecty = vect.dot(frame.y)
  39. vectz = vect.dot(frame.z)
  40. outvec = Vector(0)
  41. outvec += (diff(vectz, frame[1]) - diff(vecty, frame[2])) * frame.x
  42. outvec += (diff(vectx, frame[2]) - diff(vectz, frame[0])) * frame.y
  43. outvec += (diff(vecty, frame[0]) - diff(vectx, frame[1])) * frame.z
  44. return outvec
  45. def divergence(vect, frame):
  46. """
  47. Returns the divergence of a vector field computed wrt the coordinate
  48. symbols of the given frame.
  49. Parameters
  50. ==========
  51. vect : Vector
  52. The vector operand
  53. frame : ReferenceFrame
  54. The reference frame to calculate the divergence in
  55. Examples
  56. ========
  57. >>> from sympy.physics.vector import ReferenceFrame
  58. >>> from sympy.physics.vector import divergence
  59. >>> R = ReferenceFrame('R')
  60. >>> v1 = R[0]*R[1]*R[2] * (R.x+R.y+R.z)
  61. >>> divergence(v1, R)
  62. R_x*R_y + R_x*R_z + R_y*R_z
  63. >>> v2 = 2*R[1]*R[2]*R.y
  64. >>> divergence(v2, R)
  65. 2*R_z
  66. """
  67. _check_vector(vect)
  68. if vect == 0:
  69. return S.Zero
  70. vect = express(vect, frame, variables=True)
  71. vectx = vect.dot(frame.x)
  72. vecty = vect.dot(frame.y)
  73. vectz = vect.dot(frame.z)
  74. out = S.Zero
  75. out += diff(vectx, frame[0])
  76. out += diff(vecty, frame[1])
  77. out += diff(vectz, frame[2])
  78. return out
  79. def gradient(scalar, frame):
  80. """
  81. Returns the vector gradient of a scalar field computed wrt the
  82. coordinate symbols of the given frame.
  83. Parameters
  84. ==========
  85. scalar : sympifiable
  86. The scalar field to take the gradient of
  87. frame : ReferenceFrame
  88. The frame to calculate the gradient in
  89. Examples
  90. ========
  91. >>> from sympy.physics.vector import ReferenceFrame
  92. >>> from sympy.physics.vector import gradient
  93. >>> R = ReferenceFrame('R')
  94. >>> s1 = R[0]*R[1]*R[2]
  95. >>> gradient(s1, R)
  96. R_y*R_z*R.x + R_x*R_z*R.y + R_x*R_y*R.z
  97. >>> s2 = 5*R[0]**2*R[2]
  98. >>> gradient(s2, R)
  99. 10*R_x*R_z*R.x + 5*R_x**2*R.z
  100. """
  101. _check_frame(frame)
  102. outvec = Vector(0)
  103. scalar = express(scalar, frame, variables=True)
  104. for i, x in enumerate(frame):
  105. outvec += diff(scalar, frame[i]) * x
  106. return outvec
  107. def is_conservative(field):
  108. """
  109. Checks if a field is conservative.
  110. Parameters
  111. ==========
  112. field : Vector
  113. The field to check for conservative property
  114. Examples
  115. ========
  116. >>> from sympy.physics.vector import ReferenceFrame
  117. >>> from sympy.physics.vector import is_conservative
  118. >>> R = ReferenceFrame('R')
  119. >>> is_conservative(R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z)
  120. True
  121. >>> is_conservative(R[2] * R.y)
  122. False
  123. """
  124. #Field is conservative irrespective of frame
  125. #Take the first frame in the result of the
  126. #separate method of Vector
  127. if field == Vector(0):
  128. return True
  129. frame = list(field.separate())[0]
  130. return curl(field, frame).simplify() == Vector(0)
  131. def is_solenoidal(field):
  132. """
  133. Checks if a field is solenoidal.
  134. Parameters
  135. ==========
  136. field : Vector
  137. The field to check for solenoidal property
  138. Examples
  139. ========
  140. >>> from sympy.physics.vector import ReferenceFrame
  141. >>> from sympy.physics.vector import is_solenoidal
  142. >>> R = ReferenceFrame('R')
  143. >>> is_solenoidal(R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z)
  144. True
  145. >>> is_solenoidal(R[1] * R.y)
  146. False
  147. """
  148. #Field is solenoidal irrespective of frame
  149. #Take the first frame in the result of the
  150. #separate method in Vector
  151. if field == Vector(0):
  152. return True
  153. frame = list(field.separate())[0]
  154. return divergence(field, frame).simplify() is S.Zero
  155. def scalar_potential(field, frame):
  156. """
  157. Returns the scalar potential function of a field in a given frame
  158. (without the added integration constant).
  159. Parameters
  160. ==========
  161. field : Vector
  162. The vector field whose scalar potential function is to be
  163. calculated
  164. frame : ReferenceFrame
  165. The frame to do the calculation in
  166. Examples
  167. ========
  168. >>> from sympy.physics.vector import ReferenceFrame
  169. >>> from sympy.physics.vector import scalar_potential, gradient
  170. >>> R = ReferenceFrame('R')
  171. >>> scalar_potential(R.z, R) == R[2]
  172. True
  173. >>> scalar_field = 2*R[0]**2*R[1]*R[2]
  174. >>> grad_field = gradient(scalar_field, R)
  175. >>> scalar_potential(grad_field, R)
  176. 2*R_x**2*R_y*R_z
  177. """
  178. #Check whether field is conservative
  179. if not is_conservative(field):
  180. raise ValueError("Field is not conservative")
  181. if field == Vector(0):
  182. return S.Zero
  183. #Express the field exntirely in frame
  184. #Substitute coordinate variables also
  185. _check_frame(frame)
  186. field = express(field, frame, variables=True)
  187. #Make a list of dimensions of the frame
  188. dimensions = [x for x in frame]
  189. #Calculate scalar potential function
  190. temp_function = integrate(field.dot(dimensions[0]), frame[0])
  191. for i, dim in enumerate(dimensions[1:]):
  192. partial_diff = diff(temp_function, frame[i + 1])
  193. partial_diff = field.dot(dim) - partial_diff
  194. temp_function += integrate(partial_diff, frame[i + 1])
  195. return temp_function
  196. def scalar_potential_difference(field, frame, point1, point2, origin):
  197. """
  198. Returns the scalar potential difference between two points in a
  199. certain frame, wrt a given field.
  200. If a scalar field is provided, its values at the two points are
  201. considered. If a conservative vector field is provided, the values
  202. of its scalar potential function at the two points are used.
  203. Returns (potential at position 2) - (potential at position 1)
  204. Parameters
  205. ==========
  206. field : Vector/sympyfiable
  207. The field to calculate wrt
  208. frame : ReferenceFrame
  209. The frame to do the calculations in
  210. point1 : Point
  211. The initial Point in given frame
  212. position2 : Point
  213. The second Point in the given frame
  214. origin : Point
  215. The Point to use as reference point for position vector
  216. calculation
  217. Examples
  218. ========
  219. >>> from sympy.physics.vector import ReferenceFrame, Point
  220. >>> from sympy.physics.vector import scalar_potential_difference
  221. >>> R = ReferenceFrame('R')
  222. >>> O = Point('O')
  223. >>> P = O.locatenew('P', R[0]*R.x + R[1]*R.y + R[2]*R.z)
  224. >>> vectfield = 4*R[0]*R[1]*R.x + 2*R[0]**2*R.y
  225. >>> scalar_potential_difference(vectfield, R, O, P, O)
  226. 2*R_x**2*R_y
  227. >>> Q = O.locatenew('O', 3*R.x + R.y + 2*R.z)
  228. >>> scalar_potential_difference(vectfield, R, P, Q, O)
  229. -2*R_x**2*R_y + 18
  230. """
  231. _check_frame(frame)
  232. if isinstance(field, Vector):
  233. #Get the scalar potential function
  234. scalar_fn = scalar_potential(field, frame)
  235. else:
  236. #Field is a scalar
  237. scalar_fn = field
  238. #Express positions in required frame
  239. position1 = express(point1.pos_from(origin), frame, variables=True)
  240. position2 = express(point2.pos_from(origin), frame, variables=True)
  241. #Get the two positions as substitution dicts for coordinate variables
  242. subs_dict1 = {}
  243. subs_dict2 = {}
  244. for i, x in enumerate(frame):
  245. subs_dict1[frame[i]] = x.dot(position1)
  246. subs_dict2[frame[i]] = x.dot(position2)
  247. return scalar_fn.subs(subs_dict2) - scalar_fn.subs(subs_dict1)