# Vector calculus in Cartesian and spherical coordinates¶

This worksheet illustrates some features of SageManifolds (version 1.0, as included in SageMath 7.5) regarding vector calculus in the Euclidean 3-space by means of Cartesian and spherical coordinates.

Click here to download the worksheet file (ipynb format). To run it, you must start SageMath with the Jupyter notebook, via the command sage -n jupyter

NB: a version of SageMath at least equal to 7.5 is required to run this worksheet:

In [1]:
version()

Out[1]:
'SageMath version 7.5, Release Date: 2017-01-11'

## Euclidean 3-space and Cartesian coordinates¶

First we set up the notebook to display mathematical objects using LaTeX formatting:

In [2]:
%display latex


We then introduce the Euclidean space as a 3-dimensional differentiable manifold:

In [3]:
M = Manifold(3, 'M', start_index=1)
print(M)

3-dimensional differentiable manifold M


We then introduce the Cartesian coordinates $(x,y,z)$ as the chart cart on $M$:

In [4]:
cart.<x,y,z> = M.chart()
print(cart)
cart

Chart (M, (x, y, z))

Out[4]:

## Spherical coordinates¶

We introduce spherical coordinates $(r,\theta,\phi)$ as the chart spher on $M$:

In [5]:
spher.<r,th,ph> = M.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi')
print(spher)
spher

Chart (M, (r, th, ph))

Out[5]:

Spherical coordinates do not form a regular coordinate system of the Euclidean space. So declaring that they span $M$ means that, strictly speaking, the manifold $M$ is not the whole Euclidean space, but the Euclidean space minus some half plane (the azimuthal origin). However, in this worksheet, this difference will not matter.

The change of coordinates $(r,\theta,\phi) \rightarrow (x,y,z)$ is introduced as a transition map from chart spher to chart cart:

In [6]:
spher_to_cart = spher.transition_map(cart, [r*sin(th)*cos(ph), r*sin(th)*sin(ph), r*cos(th)])
spher_to_cart.display()

Out[6]:

The inverse is also set:

In [7]:
spher_to_cart.set_inverse(sqrt(x^2+y^2+z^2), atan2(sqrt(x^2+y^2),z), atan2(y, x),
verbose=True)

Check of the inverse coordinate transformation:
r == r
th == arctan2(r*sin(th), r*cos(th))
ph == arctan2(r*sin(ph)*sin(th), r*cos(ph)*sin(th))
x == x
y == y
z == z


The check that the provided formulas do correspond to the inverse change of coordinates is passed, modulo some lack of simplification in some trigonometrical formulas involving the function arctan2.

In [8]:
cart_to_spher = spher_to_cart.inverse()
cart_to_spher.display()

Out[8]:

The natural vector frame of spherical coordinates is

In [9]:
spher.frame()

Out[9]:

We shall expand vector and tensor fields on the orthonormal frame $(e_1, e_2, e_3)$ associated with spherical coordinates, which is related to the natural frame $(\partial/\partial r, \partial/\partial\theta, \partial/\partial\phi)$ displayed above by means of the following field of automorphisms:

In [10]:
to_orthonormal = M.automorphism_field()
to_orthonormal[spher.frame(),1,1,spher] = 1
to_orthonormal[spher.frame(),2,2,spher] = 1/r
to_orthonormal[spher.frame(),3,3,spher] = 1/(r*sin(th))
to_orthonormal.display(spher.frame(), spher)

Out[10]:

In other words, the change-of-basis matrix is

In [11]:
to_orthonormal[spher.frame(),:,spher]

Out[11]:

We construct the orthonormal frame from the natural frame of spherical coordinates by this change of basis:

In [12]:
es = spher.frame().new_frame(to_orthonormal, 'e')
print(es)
es

Vector frame (M, (e_1,e_2,e_3))

Out[12]:
In [13]:
es[1].display(spher.frame(), spher)

Out[13]:
In [14]:
es[2].display(spher.frame(), spher)

Out[14]:
In [15]:
es[3].display(spher.frame(), spher)

Out[15]:

If we do not specify the frame and coordinates for the display, we get it in terms of the default ones (i.e. Cartesian frame and Cartesian coordinates):

In [16]:
es[1].display()

Out[16]:
In [17]:
es[2].display()

Out[17]:
In [18]:
es[3].display()

Out[18]:

By construction, the change of frame $(\partial/\partial r, \partial/\partial \theta, \partial/\partial \phi) \rightarrow (e_1,e_2,e_3)$ is known. We form the change of frame $(\partial/\partial x, \partial/\partial y, \partial/\partial z)\rightarrow (e_1,e_2,e_3)$ by composition of $(\partial/\partial x, \partial/\partial y, \partial/\partial z)\rightarrow (\partial/\partial r, \partial/\partial \theta, \partial/\partial \phi)$ with $(\partial/\partial r, \partial/\partial \theta, \partial/\partial \phi) \rightarrow (e_1,e_2,e_3)$:

In [19]:
M.set_change_of_frame(cart.frame(), es,
M.change_of_frame(spher.frame(), es) * M.change_of_frame(cart.frame(),
spher.frame()),
compute_inverse=False)
M.change_of_frame(cart.frame(), es)[:, spher]

Out[19]:

Similarly, we form the inverse change of frame as:

In [20]:
M.set_change_of_frame(es, cart.frame(),
M.change_of_frame(spher.frame(), cart.frame()) *
M.change_of_frame(es, spher.frame()),
compute_inverse=False)
M.change_of_frame(es, cart.frame())[:, spher]

Out[20]:

At this stage, the manifold (user) atlas is

In [21]:
M.atlas()

Out[21]:

The default chart is the first one introduced on the manifold (it can be changed by means of the function M.set_default_chart):

In [22]:
M.default_chart()

Out[22]:

The following vector frames have been introduced on the manifold:

In [23]:
M.frames()

Out[23]:

The default frame is the first one introduced on the manifold (it can be changed by means of the function M.set_default_frame):

In [24]:
M.default_frame()

Out[24]:

The following changes of frame have been defined:

In [25]:
M.changes_of_frame()

Out[25]:

## Vector field defined in terms of its Cartesian components¶

We define the vector field $U$ in terms of its components with respect to the default frame, i.e. the Cartesian frame:

In [26]:
U = M.vector_field(name='U')
U[:] = [function('U_x')(x,y,z), function('U_y')(x,y,z), function('U_z')(x,y,z)]
U.display()

Out[26]:

We can ask for its components in terms of the spherical orthonormal frame:

In [27]:
U.display(es)

Out[27]:
In [28]:
U.display_comp(es)

Out[28]:

The above components are displayed in terms of the default chart (Cartesian coordinates). If we want them in terms of spherical coordinates, we have to specify it, by setting the second argument of the function display to spher:

In [29]:
U.display(es, spher)

Out[29]:
In [30]:
U.display_comp(es, spher)

Out[30]:

We may also ask for the components of $U$ w.r.t. the natural frame of spherical coordinates:

In [31]:
U.display(spher.frame())

Out[31]:
In [32]:
U.display(spher.frame(), spher)

Out[32]:

## Vector field defined in terms of its spherical components¶

Let us consider a vector field $V$ defined by its components with respect to the orthonormal spherical frame es = $(e_1, e_2, e_3)$:

In [33]:
V = M.vector_field(name='V')
V[es,:,spher] = [function('V_1')(r,th,ph), function('V_2')(r,th,ph), function('V_3')(r,th,ph)]
V.display(es, spher)

Out[33]:

We may ask for the components of this vector field with respect to the Cartesian frame (first argument cart.frame()), each component being expressed in terms of spherical coordinates (second argument spher):

In [34]:
V.display(cart.frame(), spher)

Out[34]:
In [35]:
V.display_comp(cart.frame(), spher)

Out[35]:

## Euclidean metric¶

The standard Euclidean metric is introduced as a Riemannian metric on $M$, whose components with respect to the Cartesian frame are $\mathrm{diag}(1,1,1)$:

In [36]:
g = M.riemannian_metric('g')
g[1,1], g[2,2], g[3,3] = 1, 1, 1
g.display()

Out[36]:

The components of $g$ with respect to the spherical coordinates are then:

In [37]:
g.display(spher.frame(), spher)

Out[37]:

Since es = $(e_1,e_2,e_3)$ is an orthonormal frame, the components of $g$ with respect to it are $\mathrm{diag}(1,1,1)$:

In [38]:
g.display(es, spher)

Out[38]:

The covariant derivative operator $\nabla$ is introduced as the (Levi-Civita) connection associated with $g$:

In [39]:
nabla = g.connection()
print(nabla)
nabla

Levi-Civita connection nabla_g associated with the Riemannian metric g on the 3-dimensional differentiable manifold M

Out[39]:

The connection coefficient with respect to the natural frame of spherical coordinates (Christoffel symbols) are:

In [40]:
nabla.display(spher.frame(), spher)

Out[40]:

while those with respect to the orthonormal spherical frame are:

In [41]:
nabla.display(es, spher)

Out[41]:

The covariant derivative of $U$ is

In [42]:
nabU = nabla(U)
print(nabU)

Tensor field nabla_g(U) of type (1,1) on the 3-dimensional differentiable manifold M

In [43]:
nabU.display()

Out[43]:

while the covariant derivative of $V$ is

In [44]:
nabV = nabla(V)
print(nabV)

Tensor field nabla_g(V) of type (1,1) on the 3-dimensional differentiable manifold M

In [45]:
nabV.display(es, spher)

Out[45]:
In [ ]: