{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Vector calculus with SageMath\n",
"\n",
"## Part 1: Using Cartesian 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_cartesian.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 $(x,y,z)$ as Cartesian 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()\n",
"print(E)\n",
"E"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$\\mathbb{E}^3$ is endowed with the chart of Cartesian coordinates:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"[Chart (E^3, (x, y, z))]"
]
},
"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:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"[Coordinate frame (E^3, (e_x,e_y,e_z))]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E.frames()"
]
},
{
"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 vector frame $(e_x,e_y,e_z)$:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"v = -y e_x + x e_y + sin(x*y*z) e_z"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v = E.vector_field(-y, x, sin(x*y*z), 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": [
"-y"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v[1]"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"[-y, x, sin(x*y*z)]"
]
},
"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((3,-2,1), name='p')\n",
"print(p)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"(3, -2, 1)"
]
},
"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 = 2 e_x + 3 e_y - sin(6) e_z"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vp.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vector fields can be plotted (see the [list of options](http://doc.sagemath.org/html/en/reference/manifolds/sage/manifolds/differentiable/vectorfield.html#sage.manifolds.differentiable.vectorfield.VectorField.plot) for customizing the plot)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n"
],
"text/plain": [
"Graphics3d Object"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v.plot(max_range=1.5, scale=0.5, viewer='threejs', online=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We may define a vector field with generic components:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"u = u_x(x, y, z) e_x + u_y(x, y, z) e_y + u_z(x, y, z) e_z"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"u = E.vector_field(function('u_x')(x,y,z),\n",
" function('u_y')(x,y,z),\n",
" function('u_z')(x,y,z),\n",
" name='u')\n",
"u.display()"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"[u_x(x, y, z), u_y(x, y, z), u_z(x, y, z)]"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"u[:]"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"u = u_x(3, -2, 1) e_x + u_y(3, -2, 1) e_y + u_z(3, -2, 1) e_z"
]
},
"execution_count": 16,
"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": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Scalar field u.v on the Euclidean space E^3"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s = u.dot(v)\n",
"s"
]
},
{
"cell_type": "code",
"execution_count": 18,
"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": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"u.v: E^3 --> R\n",
" (x, y, z) |--> -y*u_x(x, y, z) + x*u_y(x, y, z) + sin(x*y*z)*u_z(x, y, z)"
]
},
"execution_count": 19,
"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": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"-sin(6)*u_z(3, -2, 1) + 2*u_x(3, -2, 1) + 3*u_y(3, -2, 1)"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s(p)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Its coordinate expression is"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"-y*u_x(x, y, z) + x*u_y(x, y, z) + sin(x*y*z)*u_z(x, y, z)"
]
},
"execution_count": 21,
"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": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Scalar field |u| on the Euclidean space E^3"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s = norm(u)\n",
"s"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"|u|: E^3 --> R\n",
" (x, y, z) |--> sqrt(u_x(x, y, z)^2 + u_y(x, y, z)^2 + u_z(x, y, z)^2)"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.display()"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"sqrt(u_x(x, y, z)^2 + u_y(x, y, z)^2 + u_z(x, y, z)^2)"
]
},
"execution_count": 24,
"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": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 25,
"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": 26,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"sqrt(x^2 + y^2 + sin(x*y*z)^2)"
]
},
"execution_count": 26,
"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": 27,
"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": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"u x v = (sin(x*y*z)*u_y(x, y, z) - x*u_z(x, y, z)) e_x + (-sin(x*y*z)*u_x(x, y, z) - y*u_z(x, y, z)) e_y + (x*u_x(x, y, z) + y*u_y(x, y, z)) e_z"
]
},
"execution_count": 28,
"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": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"w = x*z e_x + y*z e_y"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w = E.vector_field(name='w')\n",
"w[1] = x*z\n",
"w[2] = y*z\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": 30,
"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": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"-(y*u_x(x, y, z) - x*u_y(x, y, z))*z*sin(x*y*z) - (x^2*u_z(x, y, z) + y^2*u_z(x, y, z))*z"
]
},
"execution_count": 31,
"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": 32,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 32,
"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": 33,
"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 $(x,y,z)$:"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"F: E^3 --> R\n",
" (x, y, z) |--> f(x, y, z)"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"F = E.scalar_field(function('f')(x,y,z), name='F')\n",
"F.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The value of $F$ at a point:"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"f(3, -2, 1)"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"F(p)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The gradient of $F$:"
]
},
{
"cell_type": "code",
"execution_count": 36,
"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": 37,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"grad(F) = d(f)/dx e_x + d(f)/dy e_y + d(f)/dz e_z"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"grad(F).display()"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"|grad(F)|: E^3 --> R\n",
" (x, y, z) |--> sqrt((d(f)/dx)^2 + (d(f)/dy)^2 + (d(f)/dz)^2)"
]
},
"execution_count": 38,
"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": 39,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"div(u): E^3 --> R\n",
" (x, y, z) |--> d(u_x)/dx + d(u_y)/dy + d(u_z)/dz"
]
},
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s = div(u)\n",
"s.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For $v$ and $w$, we have"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"x*y*cos(x*y*z)"
]
},
"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": [
"2*z"
]
},
"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) = (-d(u_y)/dz + d(u_z)/dy) e_x + (d(u_x)/dz - d(u_z)/dx) e_y + (-d(u_x)/dy + d(u_y)/dx) e_z"
]
},
"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) = (-d(u_y)/dz + d(u_z)/dy) e_x + (d(u_x)/dz - d(u_z)/dx) e_y + (-d(u_x)/dy + d(u_y)/dx) e_z"
]
},
"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) = x*z*cos(x*y*z) e_x - y*z*cos(x*y*z) e_y + 2 e_z"
]
},
"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) = -y e_x + x e_y"
]
},
"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",
" (x, y, z) |--> 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",
" (x, y, z) |--> d^2(f)/dx^2 + d^2(f)/dy^2 + d^2(f)/dz^2"
]
},
"execution_count": 54,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s = laplacian(F)\n",
"s.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For a scalar field, the Laplacian is nothing but the divergence of the gradient:"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 55,
"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": 56,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Delta(u) = (d^2(u_x)/dx^2 + d^2(u_x)/dy^2 + d^2(u_x)/dz^2) e_x + (d^2(u_y)/dx^2 + d^2(u_y)/dy^2 + d^2(u_y)/dz^2) e_y + (d^2(u_z)/dx^2 + d^2(u_z)/dy^2 + d^2(u_z)/dz^2) e_z"
]
},
"execution_count": 56,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"laplacian(u).display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the Cartesian frame, the components of the Laplacian of a vector field are nothing but the Laplacians of the components of the vector field, as we can check:"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 57,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"e = E.cartesian_frame()\n",
"laplacian(u) == sum(laplacian(u[[i]])*e[i] for i in E.irange())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the above formula, `u[[i]]` return the $i$-th component of $u$ as a scalar field, while `u[i]` would have returned the coordinate expression of this scalar field; besides, `e` is the Cartesian frame:"
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"(Vector field e_x on the Euclidean space E^3,\n",
" Vector field e_y on the Euclidean space E^3,\n",
" Vector field e_z on the Euclidean space E^3)"
]
},
"execution_count": 58,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"e[:]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For $v$ and $w$, we have "
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Delta(v) = -(x^2*y^2 + (x^2 + y^2)*z^2)*sin(x*y*z) e_z"
]
},
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"laplacian(v).display()"
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Delta(w) = 0"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"laplacian(w).display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We have"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"curl(curl(u)) = (-d^2(u_x)/dy^2 - d^2(u_x)/dz^2 + d^2(u_y)/dxdy + d^2(u_z)/dxdz) e_x + (d^2(u_x)/dxdy - d^2(u_y)/dx^2 - d^2(u_y)/dz^2 + d^2(u_z)/dydz) e_y + (d^2(u_x)/dxdz + d^2(u_y)/dydz - d^2(u_z)/dx^2 - d^2(u_z)/dy^2) e_z"
]
},
"execution_count": 61,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"curl(curl(u)).display()"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"grad(div(u)) = (d^2(u_x)/dx^2 + d^2(u_y)/dxdy + d^2(u_z)/dxdz) e_x + (d^2(u_x)/dxdy + d^2(u_y)/dy^2 + d^2(u_z)/dydz) e_y + (d^2(u_x)/dxdz + d^2(u_y)/dydz + d^2(u_z)/dz^2) e_z"
]
},
"execution_count": 62,
"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": 63,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 63,
"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 Cartesian coordinates are denoted $(e_x,e_y,e_z)$:"
]
},
{
"cell_type": "code",
"execution_count": 64,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Coordinate frame (E^3, (e_x,e_y,e_z))"
]
},
"execution_count": 64,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"frame = E.cartesian_frame()\n",
"frame"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But this can be changed, thanks to the method `set_name`:"
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Coordinate frame (E^3, (a_x,a_y,a_z))"
]
},
"execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"frame.set_name('a', indices=('x', 'y', 'z'))\n",
"frame"
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"v = -y a_x + x a_y + sin(x*y*z) a_z"
]
},
"execution_count": 66,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v.display()"
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Coordinate frame (E^3, (hx,hy,hz))"
]
},
"execution_count": 67,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"frame.set_name(('hx', 'hy', 'hz'), \n",
" latex_symbol=(r'\\mathbf{\\hat{x}}', r'\\mathbf{\\hat{y}}', \n",
" r'\\mathbf{\\hat{z}}'))\n",
"frame"
]
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"v = -y hx + x hy + sin(x*y*z) hz"
]
},
"execution_count": 68,
"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": 69,
"metadata": {},
"outputs": [],
"source": [
"E. = EuclideanSpace()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"which resulted in the coordinate symbols $(x,y,z)$ and in the corresponding Python variables `x`, `y` and `z` (SageMath symbolic expressions). To use other symbols, for instance $(X,Y,Z)$, it suffices to create `E` as"
]
},
{
"cell_type": "code",
"execution_count": 70,
"metadata": {},
"outputs": [],
"source": [
"E. = EuclideanSpace()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We have then:"
]
},
{
"cell_type": "code",
"execution_count": 71,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"[Chart (E^3, (X, Y, Z))]"
]
},
"execution_count": 71,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E.atlas()"
]
},
{
"cell_type": "code",
"execution_count": 72,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Coordinate frame (E^3, (e_X,e_Y,e_Z))"
]
},
"execution_count": 72,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E.cartesian_frame()"
]
},
{
"cell_type": "code",
"execution_count": 73,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"v = -Y e_X + X e_Y + sin(X*Y*Z) e_Z"
]
},
"execution_count": 73,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v = E.vector_field(-Y, X, sin(X*Y*Z), name='v')\n",
"v.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"By default the LaTeX symbols of the coordinate coincide with the letters given within the angle brackets. But this can be adjusted through the optional argument `symbols` of the function `EuclideanSpace`, which 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": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"[Chart (E^3, (xi, et, ze))]"
]
},
"execution_count": 74,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E. = EuclideanSpace(symbols=r\"xi:\\xi et:\\eta ze:\\zeta\")\n",
"E.atlas()"
]
},
{
"cell_type": "code",
"execution_count": 75,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"v = -et e_xi + xi e_et + sin(et*xi*ze) e_ze"
]
},
"execution_count": 75,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v = E.vector_field(-et, xi, sin(xi*et*ze), 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
}