Spaces:
Sleeping
Sleeping
| ===================================== | |
| Scalar and Vector Field Functionality | |
| ===================================== | |
| Implementation in sympy.vector | |
| ============================== | |
| Scalar and vector fields | |
| ------------------------ | |
| In :mod:`sympy.vector`, every ``CoordSys3D`` instance is assigned basis | |
| vectors corresponding to the :math:`X`, :math:`Y` and | |
| axes. These can be accessed using the properties | |
| named ``i``, ``j`` and ``k`` respectively. Hence, to define a vector | |
| of the form | |
| + 4\mathbf{\hat{j}} + 5\mathbf{\hat{k}}` with | |
| respect to a given frame :math:`\mathbf{R}`, you would do | |
| >>> from sympy.vector import CoordSys3D | |
| >>> R = CoordSys3D('R') | |
| >>> v = 3*R.i + 4*R.j + 5*R.k | |
| Vector math and basic calculus operations with respect to vectors have | |
| already been elaborated upon in the earlier section of this module's | |
| documentation. | |
| On the other hand, base scalars (or coordinate variables) are implemented | |
| in a special class called ``BaseScalar``, and are assigned to every | |
| coordinate system, one for each axis from :math:`X`, :math:`Y` and | |
| These coordinate variables are used to form the expressions of | |
| vector or scalar fields in 3D space. | |
| For a system ``R``, the :math:`X`, :math:`Y` and :math:`Z` | |
| ``BaseScalars`` instances can be accessed using the ``R.x``, ``R.y`` | |
| and ``R.z`` expressions respectively. | |
| Therefore, to generate the expression for the aforementioned electric | |
| potential field :math:`2{x}^{2}y`, you would have to do | |
| >>> from sympy.vector import CoordSys3D | |
| >>> R = CoordSys3D('R') | |
| >>> electric_potential = 2*R.x**2*R.y | |
| >>> electric_potential | |
| 2*R.x**2*R.y | |
| It is to be noted that ``BaseScalar`` instances can be used just | |
| like any other SymPy ``Symbol``, except that they store the information | |
| about the coordinate system and axis they correspond to. | |
| Scalar fields can be treated just as any other SymPy expression, | |
| for any math/calculus functionality. Hence, to differentiate the above | |
| electric potential with respect to :math:`x` (i.e. ``R.x``), you would | |
| use the ``diff`` method. | |
| >>> from sympy.vector import CoordSys3D | |
| >>> R = CoordSys3D('R') | |
| >>> electric_potential = 2*R.x**2*R.y | |
| >>> from sympy import diff | |
| >>> diff(electric_potential, R.x) | |
| 4*R.x*R.y | |
| It is worth noting that having a ``BaseScalar`` in the expression implies | |
| that a 'field' changes with position, in 3D space. Technically speaking, a | |
| simple ``Expr`` with no ``BaseScalar`` s is still a field, though | |
| constant. | |
| Like scalar fields, vector fields that vary with position can also be | |
| constructed using ``BaseScalar`` s in the measure-number expressions. | |
| >>> from sympy.vector import CoordSys3D | |
| >>> R = CoordSys3D('R') | |
| >>> v = R.x**2*R.i + 2*R.x*R.z*R.k | |
| The Del operator | |
| ---------------- | |
| The Del, or 'Nabla' operator - written as :math:`\mathbf{\nabla}` is | |
| commonly known as the vector differential operator. Depending on its | |
| usage in a mathematical expression, it may denote the gradient of a | |
| scalar field, the divergence of a vector field, or the curl of a | |
| vector field. | |
| Essentially, :math:`\mathbf{\nabla}` is not technically an 'operator', | |
| but a convenient mathematical notation to denote any one of the | |
| aforementioned field operations. | |
| In :mod:`sympy.vector`, :math:`\mathbf{\nabla}` has been implemented | |
| as the ``Del()`` class. The instance of this class is independent of | |
| coordinate system. Hence, the :math:`\mathbf{\nabla}` operator would | |
| be accessible as ``Del()``. | |
| Given below is an example of usage of the ``Del()`` class. | |
| >>> from sympy.vector import CoordSys3D, Del | |
| >>> C = CoordSys3D('C') | |
| >>> delop = Del() | |
| >>> gradient_field = delop(C.x*C.y*C.z) | |
| >>> gradient_field | |
| (Derivative(C.x*C.y*C.z, C.x))*C.i + (Derivative(C.x*C.y*C.z, C.y))*C.j | |
| + (Derivative(C.x*C.y*C.z, C.z))*C.k | |
| The above expression can be evaluated using the SymPy ``doit()`` | |
| routine. | |
| >>> gradient_field.doit() | |
| C.y*C.z*C.i + C.x*C.z*C.j + C.x*C.y*C.k | |
| Usage of the :math:`\mathbf{\nabla}` notation in :mod:`sympy.vector` | |
| has been described in greater detail in the subsequent subsections. | |
| Field operators and related functions | |
| ===================================== | |
| Here we describe some basic field-related functionality implemented in | |
| Curl | |
| ---- | |
| A curl is a mathematical operator that describes an infinitesimal rotation of a | |
| vector in 3D space. The direction is determined by the right-hand rule (along the | |
| axis of rotation), and the magnitude is given by the magnitude of rotation. | |
| In the 3D Cartesian system, the curl of a 3D vector :math:`\mathbf{F}` , | |
| denoted by :math:`\nabla \times \mathbf{F}` is given by: | |
| \times \mathbf{F} = \left(\frac{\partial F_z}{\partial y} - | |
| \frac{\partial F_y}{\partial z}\right) \mathbf{\hat{i}} + | |
| \left(\frac{\partial F_x}{\partial z} - | |
| \frac{\partial F_z}{\partial x}\right) \mathbf{\hat{j}} + | |
| \left(\frac{\partial F_y}{\partial x} - | |
| \frac{\partial F_x}{\partial y}\right) \mathbf{\hat{k}}` | |
| where :math:`F_x` denotes the :math:`X` component of vector :math:`\mathbf{F}`. | |
| Computing the curl of a vector field in :mod:`sympy.vector` can be | |
| accomplished in two ways. | |
| One, by using the ``Del()`` class | |
| >>> from sympy.vector import CoordSys3D, Del | |
| >>> C = CoordSys3D('C') | |
| >>> delop = Del() | |
| >>> delop.cross(C.x*C.y*C.z*C.i).doit() | |
| C.x*C.y*C.j + (-C.x*C.z)*C.k | |
| >>> (delop ^ C.x*C.y*C.z*C.i).doit() | |
| C.x*C.y*C.j + (-C.x*C.z)*C.k | |
| Or by using the dedicated function | |
| >>> from sympy.vector import curl | |
| >>> curl(C.x*C.y*C.z*C.i) | |
| C.x*C.y*C.j + (-C.x*C.z)*C.k | |
| Divergence | |
| ---------- | |
| Divergence is a vector operator that measures the magnitude of a vector field's | |
| source or sink at a given point, in terms of a signed scalar. | |
| The divergence operator always returns a scalar after operating on a vector. | |
| In the 3D Cartesian system, the divergence of a 3D vector :math:`\mathbf{F}`, | |
| denoted by :math:`\nabla\cdot\mathbf{F}` is given by: | |
| =\frac{\partial U}{\partial x} | |
| +\frac{\partial V}{\partial y} | |
| +\frac{\partial W}{\partial z | |
| }` | |
| where :math:`U`, :math:`V` and :math:`W` denote the :math:`X`, :math:`Y` and | |
| components of :math:`\mathbf{F}` respectively. | |
| Computing the divergence of a vector field in :mod:`sympy.vector` can be | |
| accomplished in two ways. | |
| One, by using the ``Del()`` class | |
| >>> from sympy.vector import CoordSys3D, Del | |
| >>> C = CoordSys3D('C') | |
| >>> delop = Del() | |
| >>> delop.dot(C.x*C.y*C.z*(C.i + C.j + C.k)).doit() | |
| C.x*C.y + C.x*C.z + C.y*C.z | |
| >>> (delop & C.x*C.y*C.z*(C.i + C.j + C.k)).doit() | |
| C.x*C.y + C.x*C.z + C.y*C.z | |
| Or by using the dedicated function | |
| >>> from sympy.vector import divergence | |
| >>> divergence(C.x*C.y*C.z*(C.i + C.j + C.k)) | |
| C.x*C.y + C.x*C.z + C.y*C.z | |
| Gradient | |
| -------- | |
| Consider a scalar field :math:`f(x, y, z)` in 3D space. The gradient of this field | |
| is defined as the vector of the 3 partial derivatives of :math:`f` with respect to | |
| :math:`y` and :math:`z` in the :math:`X`, :math:`Y` and :math:`Z` | |
| axes respectively. | |
| In the 3D Cartesian system, the divergence of a scalar field :math:`f`, | |
| denoted by :math:`\nabla f` is given by - | |
| f = \frac{\partial f}{\partial x} \mathbf{\hat{i}} + | |
| \frac{\partial f}{\partial y} \mathbf{\hat{j}} + | |
| \frac{\partial f}{\partial z} \mathbf{\hat{k}}` | |
| Computing the divergence of a vector field in :mod:`sympy.vector` can be | |
| accomplished in two ways. | |
| One, by using the ``Del()`` class | |
| >>> from sympy.vector import CoordSys3D, Del | |
| >>> C = CoordSys3D('C') | |
| >>> delop = Del() | |
| >>> delop.gradient(C.x*C.y*C.z).doit() | |
| C.y*C.z*C.i + C.x*C.z*C.j + C.x*C.y*C.k | |
| >>> delop(C.x*C.y*C.z).doit() | |
| C.y*C.z*C.i + C.x*C.z*C.j + C.x*C.y*C.k | |
| Or by using the dedicated function | |
| >>> from sympy.vector import gradient | |
| >>> gradient(C.x*C.y*C.z) | |
| C.y*C.z*C.i + C.x*C.z*C.j + C.x*C.y*C.k | |
| Directional Derivative | |
| ---------------------- | |
| Apart from the above three common applications of :math:`\mathbf{\nabla}`, | |
| it is also possible to compute the directional derivative of a field wrt | |
| a ``Vector`` in :mod:`sympy.vector`. | |
| By definition, the directional derivative of a field :math:`\mathbf{F}` | |
| along a vector :math:`v` at point :math:`x` represents the instantaneous | |
| rate of change of :math:`\mathbf{F}` moving through :math:`x` with the | |
| velocity :math:`v`. It is represented mathematically as: | |
| v \cdot \nabla) \, \mathbf{F}(x)`. | |
| Directional derivatives of vector and scalar fields can be computed in | |
| using the ``Del()`` class | |
| >>> from sympy.vector import CoordSys3D, Del | |
| >>> C = CoordSys3D('C') | |
| >>> delop = Del() | |
| >>> vel = C.i + C.j + C.k | |
| >>> scalar_field = C.x*C.y*C.z | |
| >>> vector_field = C.x*C.y*C.z*C.i | |
| >>> (vel.dot(delop))(scalar_field) | |
| C.x*C.y + C.x*C.z + C.y*C.z | |
| >>> (vel & delop)(vector_field) | |
| (C.x*C.y + C.x*C.z + C.y*C.z)*C.i | |
| Or by using the dedicated function | |
| >>> from sympy.vector import directional_derivative | |
| >>> directional_derivative(C.x*C.y*C.z, 3*C.i + 4*C.j + C.k) | |
| C.x*C.y + 4*C.x*C.z + 3*C.y*C.z | |
| Field operator in orthogonal curvilinear coordinate system | |
| ========================================================== | |
| ``vector`` package supports calculation in different kind of orthogonal | |
| curvilinear coordinate system. To do that, scaling factor (also known as | |
| Lame coefficients) are used to express ``curl``, ``divergence`` or ``gradient`` | |
| in desired type of coordinate system. | |
| For example if we want to calculate ``gradient`` in cylindrical coordinate | |
| system all we need to do is to create proper coordinate system | |
| >>> from sympy.vector import CoordSys3D | |
| >>> c = CoordSys3D('c', transformation='cylindrical', variable_names=("r", "theta", "z")) | |
| >>> gradient(c.r*c.theta*c.z) | |
| c.theta*c.z*c.i + c.z*c.j + c.r*c.theta*c.k | |
| Conservative and Solenoidal fields | |
| ================================== | |
| In vector calculus, a conservative field is a field that is the gradient of | |
| some scalar field. Conservative fields have the property that their line | |
| integral over any path depends only on the end-points, and is independent | |
| of the path travelled. | |
| A conservative vector field is also said to be 'irrotational', since the | |
| curl of a conservative field is always zero. | |
| In physics, conservative fields represent forces in physical systems where | |
| energy is conserved. | |
| To check if a vector field is conservative in :mod:`sympy.vector`, the | |
| ``is_conservative`` function can be used. | |
| >>> from sympy.vector import CoordSys3D, is_conservative | |
| >>> R = CoordSys3D('R') | |
| >>> field = R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k | |
| >>> is_conservative(field) | |
| True | |
| >>> curl(field) | |
| 0 | |
| A solenoidal field, on the other hand, is a vector field whose divergence | |
| is zero at all points in space. | |
| To check if a vector field is solenoidal in :mod:`sympy.vector`, the | |
| ``is_solenoidal`` function can be used. | |
| >>> from sympy.vector import CoordSys3D, is_solenoidal | |
| >>> R = CoordSys3D('R') | |
| >>> field = R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k | |
| >>> is_solenoidal(field) | |
| True | |
| >>> divergence(field) | |
| 0 | |
| Scalar potential functions | |
| ========================== | |
| We have previously mentioned that every conservative field can be defined as | |
| the gradient of some scalar field. This scalar field is also called the 'scalar | |
| potential field' corresponding to the aforementioned conservative field. | |
| The ``scalar_potential`` function in :mod:`sympy.vector` calculates the | |
| scalar potential field corresponding to a given conservative vector field in | |
| 3D space - minus the extra constant of integration, of course. | |
| Example of usage - | |
| >>> from sympy.vector import CoordSys3D, scalar_potential | |
| >>> R = CoordSys3D('R') | |
| >>> conservative_field = 4*R.x*R.y*R.z*R.i + 2*R.x**2*R.z*R.j + 2*R.x**2*R.y*R.k | |
| >>> scalar_potential(conservative_field, R) | |
| 2*R.x**2*R.y*R.z | |
| Providing a non-conservative vector field as an argument to | |
| ``scalar_potential`` raises a ``ValueError``. | |
| The scalar potential difference, or simply 'potential difference', | |
| corresponding to a conservative vector field can be defined as the difference | |
| between the values of its scalar potential function at two points in space. | |
| This is useful in calculating a line integral with respect to a conservative | |
| function, since it depends only on the endpoints of the path. | |
| This computation is performed as follows in :mod:`sympy.vector`. | |
| >>> from sympy.vector import CoordSys3D, Point | |
| >>> from sympy.vector import scalar_potential_difference | |
| >>> R = CoordSys3D('R') | |
| >>> P = R.origin.locate_new('P', 1*R.i + 2*R.j + 3*R.k) | |
| >>> vectfield = 4*R.x*R.y*R.i + 2*R.x**2*R.j | |
| >>> scalar_potential_difference(vectfield, R, R.origin, P) | |
| 4 | |
| If provided with a scalar expression instead of a vector field, | |
| ``scalar_potential_difference`` returns the difference between the values | |
| of that scalar field at the two given points in space. | |