{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Vector calculus with SageMath\n",
"\n",
"## Part 2: Using spherical coordinates\n",
"\n",
"This notebook illustrates some vector calculus capabilities of SageMath within the 3-dimensional Euclidean space. The corresponding tools have been developed within\n",
"the [SageManifolds](https://sagemanifolds.obspm.fr) project.\n",
"\n",
"Click [here](https://raw.githubusercontent.com/sagemanifolds/SageManifolds/master/Notebooks/SM_vector_calc_spherical.ipynb) to download the notebook file (ipynb format). To run it, you must start SageMath with the Jupyter interface, via the command `sage -n jupyter`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*NB:* a version of SageMath at least equal to 8.3 is required to run this notebook:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'SageMath version 8.8.beta2, Release Date: 2019-04-14'"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"version()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First we set up the notebook to display math formulas using LaTeX formatting:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"%display latex"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## The 3-dimensional Euclidean space\n",
"\n",
"We start by declaring the 3-dimensional Euclidean space $\\mathbb{E}^3$, with $(r,\\theta,\\phi)$ as spherical coordinates:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Euclidean space E^3\n"
]
},
{
"data": {
"text/html": [
""
],
"text/plain": [
"Euclidean space E^3"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E. = EuclideanSpace(coordinates='spherical')\n",
"print(E)\n",
"E"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$\\mathbb{E}^3$ is endowed with the chart of spherical coordinates:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"[Chart (E^3, (r, th, ph))]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E.atlas()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"as well as with the associated orthonormal vector frame $(e_r, e_\\theta, e_\\phi)$:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"[Coordinate frame (E^3, (d/dr,d/dth,d/dph)),\n",
" Vector frame (E^3, (e_r,e_th,e_ph))]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E.frames()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the above output, $\\left(\\frac{\\partial}{\\partial r}, \\frac{\\partial}{\\partial\\theta}, \\frac{\\partial}{\\partial \\phi}\\right)$ is the coordinate frame associated with $(r,\\theta,\\phi)$; it is not an orthonormal frame and will not be used below."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Vector fields"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We define a vector field on $\\mathbb{E}^3$ from its components in the orthonormal vector frame $(e_r,e_\\theta,e_\\phi)$:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"v = (r*sin(2*ph)*sin(th)^2 + r) e_r + r*cos(th)*sin(2*ph)*sin(th) e_th + 2*r*cos(ph)^2*sin(th) e_ph"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v = E.vector_field(r*sin(2*ph)*sin(th)^2 + r, \n",
" r*sin(2*ph)*sin(th)*cos(th), \n",
" 2*r*cos(ph)^2*sin(th), name='v')\n",
"v.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can access to the components of $v$ via the square bracket operator:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"r*sin(2*ph)*sin(th)^2 + r"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v[1]"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"[r*sin(2*ph)*sin(th)^2 + r, r*cos(th)*sin(2*ph)*sin(th), 2*r*cos(ph)^2*sin(th)]"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v[:]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A vector field can evaluated at any point of $\\mathbb{E}^3$:"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Point p on the Euclidean space E^3\n"
]
}
],
"source": [
"p = E((1, pi/2, pi), name='p')\n",
"print(p)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"(1, 1/2*pi, pi)"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"p.coordinates()"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vector v at Point p on the Euclidean space E^3\n"
]
}
],
"source": [
"vp = v.at(p)\n",
"print(vp)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"v = e_r + 2 e_ph"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vp.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We may define a vector field with generic components:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"u = u_r(r, th, ph) e_r + u_theta(r, th, ph) e_th + u_phi(r, th, ph) e_ph"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"u = E.vector_field(function('u_r')(r,th,ph),\n",
" function('u_theta')(r,th,ph),\n",
" function('u_phi')(r,th,ph),\n",
" name='u')\n",
"u.display()"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"[u_r(r, th, ph), u_theta(r, th, ph), u_phi(r, th, ph)]"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"u[:]"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"u = u_r(1, 1/2*pi, pi) e_r + u_theta(1, 1/2*pi, pi) e_th + u_phi(1, 1/2*pi, pi) e_ph"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"up = u.at(p)\n",
"up.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Algebraic operations on vector fields\n",
"\n",
"### Dot product\n",
"\n",
"The dot (or scalar) product of the vector fields $u$ and $v$ is obtained by the method `dot_product`, which admits `dot` as a shortcut alias:"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Scalar field u.v on the Euclidean space E^3"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s = u.dot(v)\n",
"s"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Scalar field u.v on the Euclidean space E^3\n"
]
}
],
"source": [
"print(s)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$s= u\\cdot v$ is a *scalar field*, i.e. a map $\\mathbb{E}^3 \\rightarrow \\mathbb{R}$:"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"u.v: E^3 --> R\n",
" (r, th, ph) |--> 2*r*cos(ph)*sin(ph)*sin(th)^2*u_r(r, th, ph) + 2*(r*cos(ph)*cos(th)*sin(ph)*u_theta(r, th, ph) + r*cos(ph)^2*u_phi(r, th, ph))*sin(th) + r*u_r(r, th, ph)"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It maps points of $\\mathbb{E}^3$ to real numbers:"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"2*u_phi(1, 1/2*pi, pi) + u_r(1, 1/2*pi, pi)"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s(p)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Its coordinate expression is"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"2*r*cos(ph)*sin(ph)*sin(th)^2*u_r(r, th, ph) + 2*(r*cos(ph)*cos(th)*sin(ph)*u_theta(r, th, ph) + r*cos(ph)^2*u_phi(r, th, ph))*sin(th) + r*u_r(r, th, ph)"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.expr()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Norm\n",
"\n",
"The norm of a vector field is "
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Scalar field |u| on the Euclidean space E^3"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s = norm(u)\n",
"s"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"|u|: E^3 --> R\n",
" (r, th, ph) |--> sqrt(u_phi(r, th, ph)^2 + u_r(r, th, ph)^2 + u_theta(r, th, ph)^2)"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.display()"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"sqrt(u_phi(r, th, ph)^2 + u_r(r, th, ph)^2 + u_theta(r, th, ph)^2)"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.expr()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The norm is related to the dot product by $\\|u\\|^2 = u\\cdot u$, as we can check:"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"norm(u)^2 == u.dot(u)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For $v$, we have"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"sqrt(4*(cos(ph)^2 + cos(ph)*sin(ph))*sin(th)^2 + 1)*r"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"norm(v).expr()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Cross product\n",
"\n",
"The cross product of $u$ by $v$ is obtained by the method `cross_product`, which admits `cross` as a shortcut alias:"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vector field u x v on the Euclidean space E^3\n"
]
}
],
"source": [
"s = u.cross(v)\n",
"print(s)"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"u x v = -2*(r*cos(ph)*cos(th)*sin(ph)*u_phi(r, th, ph) - r*cos(ph)^2*u_theta(r, th, ph))*sin(th) e_r + (2*r*cos(ph)*sin(ph)*sin(th)^2*u_phi(r, th, ph) - 2*r*cos(ph)^2*sin(th)*u_r(r, th, ph) + r*u_phi(r, th, ph)) e_th + (2*r*cos(ph)*cos(th)*sin(ph)*sin(th)*u_r(r, th, ph) - 2*r*cos(ph)*sin(ph)*sin(th)^2*u_theta(r, th, ph) - r*u_theta(r, th, ph)) e_ph"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Scalar triple product\n",
"\n",
"Let us introduce a third vector field. As a example, we do not pass the components as arguments of `vector_field`, as we did for $u$ and $v$; instead, we set them in a second stage, via the square bracket operator, any unset component being assumed to be zero:"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"w = r e_r"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w = E.vector_field(name='w')\n",
"w[1] = r\n",
"w.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The scalar triple product of the vector fields $u$, $v$ and $w$ is obtained as follows: "
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Scalar field epsilon(u,v,w) on the Euclidean space E^3\n"
]
}
],
"source": [
"triple_product = E.scalar_triple_product()\n",
"s = triple_product(u, v, w)\n",
"print(s)"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"-2*(r^2*cos(ph)*cos(th)*sin(ph)*u_phi(r, th, ph) - r^2*cos(ph)^2*u_theta(r, th, ph))*sin(th)"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.expr()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let us check that the scalar triple product of $u$, $v$ and $w$ is $u\\cdot(v\\times w)$:"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s == u.dot(v.cross(w))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Differential operators"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"While the standard operators $\\mathrm{grad}$, $\\mathrm{div}$, $\\mathrm{curl}$, etc. involved in vector calculus are accessible via the dot notation (e.g. `v.div()`), let us import functions `grad`, `div`, `curl`, etc. that allow for using standard mathematical notations\n",
"(e.g. `div(v)`):"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"from sage.manifolds.operators import *"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Gradient of a scalar field\n",
"\n",
"We first introduce a scalar field, via its expression in terms of Cartesian coordinates; in this example, we consider a unspecified function of $(r,\\theta,\\phi)$:"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"F: E^3 --> R\n",
" (r, th, ph) |--> f(r, th, ph)"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"F = E.scalar_field(function('f')(r,th,ph), name='F')\n",
"F.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The value of $F$ at a point:"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"f(1, 1/2*pi, pi)"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"F(p)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The gradient of $F$:"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vector field grad(F) on the Euclidean space E^3\n"
]
}
],
"source": [
"print(grad(F))"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"grad(F) = d(f)/dr e_r + d(f)/dth/r e_th + d(f)/dph/(r*sin(th)) e_ph"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"grad(F).display()"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"|grad(F)|: E^3 --> R\n",
" (r, th, ph) |--> sqrt((r^2*(d(f)/dr)^2 + (d(f)/dth)^2)*sin(th)^2 + (d(f)/dph)^2)/(r*sin(th))"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"norm(grad(F)).display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Divergence \n",
"\n",
"The divergence of a vector field:"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"div(u): E^3 --> R\n",
" (r, th, ph) |--> ((r*d(u_r)/dr + 2*u_r(r, th, ph) + d(u_theta)/dth)*sin(th) + cos(th)*u_theta(r, th, ph) + d(u_phi)/dph)/(r*sin(th))"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s = div(u)\n",
"s.display()"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"2*u_r(r, th, ph)/r + cos(th)*u_theta(r, th, ph)/(r*sin(th)) + diff(u_theta(r, th, ph), th)/r + diff(u_phi(r, th, ph), ph)/(r*sin(th)) + diff(u_r(r, th, ph), r)"
]
},
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.expr().expand()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For $v$ and $w$, we have"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"3"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"div(v).expr()"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"3"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"div(w).expr()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"An identity valid for any scalar field $F$ and any vector field $u$:"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"div(F*u) == F*div(u) + u.dot(grad(F))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Curl\n",
"\n",
"The curl of a vector field:"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vector field curl(u) on the Euclidean space E^3\n"
]
}
],
"source": [
"s = curl(u)\n",
"print(s)"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"curl(u) = (cos(th)*u_phi(r, th, ph) + sin(th)*d(u_phi)/dth - d(u_theta)/dph)/(r*sin(th)) e_r - ((r*d(u_phi)/dr + u_phi(r, th, ph))*sin(th) - d(u_r)/dph)/(r*sin(th)) e_th + (r*d(u_theta)/dr + u_theta(r, th, ph) - d(u_r)/dth)/r e_ph"
]
},
"execution_count": 44,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To use the notation `rot` instead of `curl`, simply do"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {},
"outputs": [],
"source": [
"rot = curl"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"An alternative is"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {},
"outputs": [],
"source": [
"from sage.manifolds.operators import curl as rot"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We have then"
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"curl(u) = (cos(th)*u_phi(r, th, ph) + sin(th)*d(u_phi)/dth - d(u_theta)/dph)/(r*sin(th)) e_r - ((r*d(u_phi)/dr + u_phi(r, th, ph))*sin(th) - d(u_r)/dph)/(r*sin(th)) e_th + (r*d(u_theta)/dr + u_theta(r, th, ph) - d(u_r)/dth)/r e_ph"
]
},
"execution_count": 47,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"rot(u).display()"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 48,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"rot(u) == curl(u)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For $v$ and $w$, we have"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"curl(v) = 2*cos(th) e_r - 2*sin(th) e_th"
]
},
"execution_count": 49,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"curl(v).display()"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"curl(w) = 0"
]
},
"execution_count": 50,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"curl(w).display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The curl of a gradient is always zero:"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"curl(grad(F)) = 0"
]
},
"execution_count": 51,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"curl(grad(F)).display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The divergence of a curl is always zero:"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"div(curl(u)): E^3 --> R\n",
" (r, th, ph) |--> 0"
]
},
"execution_count": 52,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"div(curl(u)).display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"An identity valid for any scalar field $F$ and any vector field $u$:"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 53,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"curl(F*u) == grad(F).cross(u) + F*curl(u)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Laplacian"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The Laplacian of a scalar field:"
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Delta(F): E^3 --> R\n",
" (r, th, ph) |--> ((r^2*d^2(f)/dr^2 + 2*r*d(f)/dr + d^2(f)/dth^2)*sin(th)^2 + cos(th)*sin(th)*d(f)/dth + d^2(f)/dph^2)/(r^2*sin(th)^2)"
]
},
"execution_count": 54,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s = laplacian(F)\n",
"s.display()"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"2*diff(f(r, th, ph), r)/r + cos(th)*diff(f(r, th, ph), th)/(r^2*sin(th)) + diff(f(r, th, ph), th, th)/r^2 + diff(f(r, th, ph), ph, ph)/(r^2*sin(th)^2) + diff(f(r, th, ph), r, r)"
]
},
"execution_count": 55,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.expr().expand()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For a scalar field, the Laplacian is nothing but the divergence of the gradient:"
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 56,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"laplacian(F) == div(grad(F))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The Laplacian of a vector field:"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Delta(u) = ((r^2*d^2(u_r)/dr^2 + 2*r*d(u_r)/dr - 2*u_r(r, th, ph) + d^2(u_r)/dth^2 - 2*d(u_theta)/dth)*sin(th)^2 - ((2*u_theta(r, th, ph) - d(u_r)/dth)*cos(th) + 2*d(u_phi)/dph)*sin(th) + d^2(u_r)/dph^2)/(r^2*sin(th)^2) e_r + ((r^2*d^2(u_theta)/dr^2 + 2*r*d(u_theta)/dr + 2*d(u_r)/dth + d^2(u_theta)/dth^2)*sin(th)^2 + cos(th)*sin(th)*d(u_theta)/dth - 2*cos(th)*d(u_phi)/dph - u_theta(r, th, ph) + d^2(u_theta)/dph^2)/(r^2*sin(th)^2) e_th + ((r^2*d^2(u_phi)/dr^2 + 2*r*d(u_phi)/dr + d^2(u_phi)/dth^2)*sin(th)^2 + (cos(th)*d(u_phi)/dth + 2*d(u_r)/dph)*sin(th) + 2*cos(th)*d(u_theta)/dph - u_phi(r, th, ph) + d^2(u_phi)/dph^2)/(r^2*sin(th)^2) e_ph"
]
},
"execution_count": 57,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Du = laplacian(u)\n",
"Du.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Since this expression is quite lengthy, we may ask for a display component by component:"
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Delta(u)^1 = ((r^2*d^2(u_r)/dr^2 + 2*r*d(u_r)/dr - 2*u_r(r, th, ph) + d^2(u_r)/dth^2 - 2*d(u_theta)/dth)*sin(th)^2 - ((2*u_theta(r, th, ph) - d(u_r)/dth)*cos(th) + 2*d(u_phi)/dph)*sin(th) + d^2(u_r)/dph^2)/(r^2*sin(th)^2) \n",
"Delta(u)^2 = ((r^2*d^2(u_theta)/dr^2 + 2*r*d(u_theta)/dr + 2*d(u_r)/dth + d^2(u_theta)/dth^2)*sin(th)^2 + cos(th)*sin(th)*d(u_theta)/dth - 2*cos(th)*d(u_phi)/dph - u_theta(r, th, ph) + d^2(u_theta)/dph^2)/(r^2*sin(th)^2) \n",
"Delta(u)^3 = ((r^2*d^2(u_phi)/dr^2 + 2*r*d(u_phi)/dr + d^2(u_phi)/dth^2)*sin(th)^2 + (cos(th)*d(u_phi)/dth + 2*d(u_r)/dph)*sin(th) + 2*cos(th)*d(u_theta)/dph - u_phi(r, th, ph) + d^2(u_phi)/dph^2)/(r^2*sin(th)^2) "
]
},
"execution_count": 58,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Du.display_comp()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We may expand each component:"
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Delta(u)^1 = 2*d(u_r)/dr/r - 2*u_r(r, th, ph)/r^2 - 2*cos(th)*u_theta(r, th, ph)/(r^2*sin(th)) + cos(th)*d(u_r)/dth/(r^2*sin(th)) + d^2(u_r)/dth^2/r^2 - 2*d(u_theta)/dth/r^2 - 2*d(u_phi)/dph/(r^2*sin(th)) + d^2(u_r)/dph^2/(r^2*sin(th)^2) + d^2(u_r)/dr^2 \n",
"Delta(u)^2 = 2*d(u_theta)/dr/r + 2*d(u_r)/dth/r^2 + cos(th)*d(u_theta)/dth/(r^2*sin(th)) + d^2(u_theta)/dth^2/r^2 - 2*cos(th)*d(u_phi)/dph/(r^2*sin(th)^2) - u_theta(r, th, ph)/(r^2*sin(th)^2) + d^2(u_theta)/dph^2/(r^2*sin(th)^2) + d^2(u_theta)/dr^2 \n",
"Delta(u)^3 = 2*d(u_phi)/dr/r + cos(th)*d(u_phi)/dth/(r^2*sin(th)) + d^2(u_phi)/dth^2/r^2 + 2*d(u_r)/dph/(r^2*sin(th)) + 2*cos(th)*d(u_theta)/dph/(r^2*sin(th)^2) - u_phi(r, th, ph)/(r^2*sin(th)^2) + d^2(u_phi)/dph^2/(r^2*sin(th)^2) + d^2(u_phi)/dr^2 "
]
},
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"for i in E.irange():\n",
" Du[i].expand()\n",
"Du.display_comp()"
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"2*d(u_r)/dr/r - 2*u_r(r, th, ph)/r^2 - 2*cos(th)*u_theta(r, th, ph)/(r^2*sin(th)) + cos(th)*d(u_r)/dth/(r^2*sin(th)) + d^2(u_r)/dth^2/r^2 - 2*d(u_theta)/dth/r^2 - 2*d(u_phi)/dph/(r^2*sin(th)) + d^2(u_r)/dph^2/(r^2*sin(th)^2) + d^2(u_r)/dr^2"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Du[1]"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"2*d(u_theta)/dr/r + 2*d(u_r)/dth/r^2 + cos(th)*d(u_theta)/dth/(r^2*sin(th)) + d^2(u_theta)/dth^2/r^2 - 2*cos(th)*d(u_phi)/dph/(r^2*sin(th)^2) - u_theta(r, th, ph)/(r^2*sin(th)^2) + d^2(u_theta)/dph^2/(r^2*sin(th)^2) + d^2(u_theta)/dr^2"
]
},
"execution_count": 61,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Du[2]"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"2*d(u_phi)/dr/r + cos(th)*d(u_phi)/dth/(r^2*sin(th)) + d^2(u_phi)/dth^2/r^2 + 2*d(u_r)/dph/(r^2*sin(th)) + 2*cos(th)*d(u_theta)/dph/(r^2*sin(th)^2) - u_phi(r, th, ph)/(r^2*sin(th)^2) + d^2(u_phi)/dph^2/(r^2*sin(th)^2) + d^2(u_phi)/dr^2"
]
},
"execution_count": 62,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Du[3]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As a test, we may check that these formulas coincide with those of\n",
"Wikipedia's article [*Del in cylindrical and spherical coordinates*](https://en.wikipedia.org/wiki/Del_in_cylindrical_and_spherical_coordinates#Del_formula)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For $v$ and $w$, we have "
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Delta(v) = 0"
]
},
"execution_count": 63,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"laplacian(v).display()"
]
},
{
"cell_type": "code",
"execution_count": 64,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Delta(w) = 0"
]
},
"execution_count": 64,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"laplacian(w).display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We have"
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"curl(curl(u)) = ((r*d^2(u_theta)/drdth - d^2(u_r)/dth^2 + d(u_theta)/dth)*sin(th)^2 + ((r*d(u_theta)/dr + u_theta(r, th, ph) - d(u_r)/dth)*cos(th) + r*d^2(u_phi)/drdph + d(u_phi)/dph)*sin(th) - d^2(u_r)/dph^2)/(r^2*sin(th)^2) e_r - ((r^2*d^2(u_theta)/dr^2 - r*d^2(u_r)/drdth + 2*r*d(u_theta)/dr)*sin(th)^2 - sin(th)*d^2(u_phi)/dthdph - cos(th)*d(u_phi)/dph + d^2(u_theta)/dph^2)/(r^2*sin(th)^2) e_th - ((r^2*d^2(u_phi)/dr^2 + 2*r*d(u_phi)/dr + d^2(u_phi)/dth^2)*sin(th)^2 + (cos(th)*d(u_phi)/dth - r*d^2(u_r)/drdph - d^2(u_theta)/dthdph)*sin(th) + cos(th)*d(u_theta)/dph - u_phi(r, th, ph))/(r^2*sin(th)^2) e_ph"
]
},
"execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"curl(curl(u)).display()"
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"grad(div(u)) = ((r*d(u_theta)/dr - u_theta(r, th, ph))*cos(th) + (r^2*d^2(u_r)/dr^2 + 2*r*d(u_r)/dr + r*d^2(u_theta)/drdth - 2*u_r(r, th, ph) - d(u_theta)/dth)*sin(th) + r*d^2(u_phi)/drdph - d(u_phi)/dph)/(r^2*sin(th)) e_r + ((r*d^2(u_r)/drdth + 2*d(u_r)/dth + d^2(u_theta)/dth^2)*sin(th)^2 + (cos(th)*d(u_theta)/dth + d^2(u_phi)/dthdph)*sin(th) - cos(th)*d(u_phi)/dph - u_theta(r, th, ph))/(r^2*sin(th)^2) e_th + ((r*d^2(u_r)/drdph + 2*d(u_r)/dph + d^2(u_theta)/dthdph)*sin(th) + cos(th)*d(u_theta)/dph + d^2(u_phi)/dph^2)/(r^2*sin(th)^2) e_ph"
]
},
"execution_count": 66,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"grad(div(u)).display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"and we may check a famous identity:"
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 67,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"curl(curl(u)) == grad(div(u)) - laplacian(u)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Customizations\n",
"\n",
"### Customizing the symbols of the orthonormal frame vectors\n",
"\n",
"By default, the vectors of the orthonormal frame associated with spherical coordinates are denoted $(e_r,e_\\theta,e_\\phi)$:"
]
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Vector frame (E^3, (e_r,e_th,e_ph))"
]
},
"execution_count": 68,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"frame = E.spherical_frame()\n",
"frame"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But this can be changed, thanks to the method `set_name`:"
]
},
{
"cell_type": "code",
"execution_count": 69,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Vector frame (E^3, (a_r,a_th,a_ph))"
]
},
"execution_count": 69,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"frame.set_name('a', indices=('r', 'th', 'ph'),\n",
" latex_indices=('r', r'\\theta', r'\\phi'))\n",
"frame"
]
},
{
"cell_type": "code",
"execution_count": 70,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"v = (r*sin(2*ph)*sin(th)^2 + r) a_r + r*cos(th)*sin(2*ph)*sin(th) a_th + 2*r*cos(ph)^2*sin(th) a_ph"
]
},
"execution_count": 70,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v.display()"
]
},
{
"cell_type": "code",
"execution_count": 71,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Vector frame (E^3, (hr,hth,hph))"
]
},
"execution_count": 71,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"frame.set_name(('hr', 'hth', 'hph'), \n",
" latex_symbol=(r'\\hat{r}', r'\\hat{\\theta}', r'\\hat{\\phi}'))\n",
"frame"
]
},
{
"cell_type": "code",
"execution_count": 72,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"v = (r*sin(2*ph)*sin(th)^2 + r) hr + r*cos(th)*sin(2*ph)*sin(th) hth + 2*r*cos(ph)^2*sin(th) hph"
]
},
"execution_count": 72,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Customizing the coordinate symbols\n",
"\n",
"The coordinates symbols are defined within the angle brackets `<...>` at the construction of the Euclidean space. Above we did "
]
},
{
"cell_type": "code",
"execution_count": 73,
"metadata": {},
"outputs": [],
"source": [
"E. = EuclideanSpace(coordinates='spherical')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"which resulted in the coordinate symbols $(r,\\theta,\\phi)$ and in the corresponding Python variables `r`, `th` and `ph` (SageMath symbolic expressions). Using other symbols, for instance $(R,\\Theta,\\Phi)$, is possible through the optional argument `symbols` of the function `EuclideanSpace`. It has to be a string, usually prefixed by r (for raw string, in order to allow for the backslash character of LaTeX expressions). This string contains the coordinate fields separated by a blank space; each field contains the coordinate’s text symbol and possibly the coordinate’s LaTeX symbol (when the latter is different from the text symbol), both symbols being separated by a colon (`:`):"
]
},
{
"cell_type": "code",
"execution_count": 74,
"metadata": {},
"outputs": [],
"source": [
"E. = EuclideanSpace(coordinates='spherical', symbols=r'R Th:\\Theta Ph:\\Phi')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We have then"
]
},
{
"cell_type": "code",
"execution_count": 75,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"[Chart (E^3, (R, Th, Ph))]"
]
},
"execution_count": 75,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E.atlas()"
]
},
{
"cell_type": "code",
"execution_count": 76,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"[Coordinate frame (E^3, (d/dR,d/dTh,d/dPh)),\n",
" Vector frame (E^3, (e_R,e_Th,e_Ph))]"
]
},
"execution_count": 76,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E.frames()"
]
},
{
"cell_type": "code",
"execution_count": 77,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Vector frame (E^3, (e_R,e_Th,e_Ph))"
]
},
"execution_count": 77,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E.spherical_frame()"
]
},
{
"cell_type": "code",
"execution_count": 78,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"v = (R*sin(2*Ph)*sin(Th)^2 + R) e_R + R*cos(Th)*sin(2*Ph)*sin(Th) e_Th + 2*R*cos(Ph)^2*sin(Th) e_Ph"
]
},
"execution_count": 78,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v = E.vector_field(R*sin(2*Ph)*sin(Th)^2 + R, \n",
" R*sin(2*Ph)*sin(Th)*cos(Th), \n",
" 2*R*cos(Ph)^2*sin(Th), name='v')\n",
"v.display()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "SageMath 8.8.beta2",
"language": "",
"name": "sagemath"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.15"
}
},
"nbformat": 4,
"nbformat_minor": 2
}