{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# How to compute a gradient, a divergence or a curl?\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/VectorCalculus/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 9.0, Release Date: 2020-01-01'" ] }, "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": [ "## First stage: introduce the Euclidean 3-space\n", "\n", "Before evaluating some vector-field operators, one needs to define the arena\n", "in which vector fields live, namely the *3-dimensional Euclidean space*\n", "$\\mathbb{E}^3$. In SageMath, we declare it, along with the standard\n", "*Cartesian coordinates* $(x,y,z)$, as follows:" ] }, { "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": [ "Thanks to the notation `` in the above declaration, the coordinates\n", "$(x,y,z)$ are immediately available as three symbolic variables ``x``,\n", "``y`` and ``z`` (there is no need to type ``x, y, z = var('x y z')``):" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x is E.cartesian_coordinates()[1]" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y is E.cartesian_coordinates()[2]" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z is E.cartesian_coordinates()[3]" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(z)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Besides, $\\mathbb{E}^3$ is endowed with the *orthonormal vector frame*\n", "$(e_x, e_y, e_z)$ associated with Cartesian coordinates:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[Coordinate frame (E^3, (e_x,e_y,e_z))]" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "E.frames()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "At this stage, this is the *default* vector frame on $\\mathbb{E}^3$\n", "(being the only vector frame introduced so far):" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Coordinate frame (E^3, (e_x,e_y,e_z))" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "E.default_frame()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Defining a vector field" ] }, { "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": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v = -y e_x + x e_y + sin(x*y*z) e_z" ] }, "execution_count": 10, "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": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "-y" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v[1]" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[-y, x, sin(x*y*z)]" ] }, "execution_count": 12, "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": 13, "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": 14, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "(3, -2, 1)" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.coordinates()" ] }, { "cell_type": "code", "execution_count": 15, "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": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v = 2 e_x + 3 e_y - sin(6) e_z" ] }, "execution_count": 16, "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": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.plot(max_range=1.5, scale=0.5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We may define a vector field with generic components $(u_x, u_y, u_z)$:" ] }, { "cell_type": "code", "execution_count": 18, "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": 18, "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": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[u_x(x, y, z), u_y(x, y, z), u_z(x, y, z)]" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u[:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Its value at the point $p$ is then" ] }, { "cell_type": "code", "execution_count": 20, "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": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "up = u.at(p)\n", "up.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## How to compute various vector products?\n", "\n", "### Dot product\n", "\n", "The dot (or scalar) product $u\\cdot v$ 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": 21, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u.dot(v) == u[1]*v[1] + u[2]*v[2] + u[3]*v[3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$s= u\\cdot v$ is a *scalar field*, i.e. a map\n", "$\\mathbb{E}^3 \\to \\mathbb{R}$:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Scalar field u.v on the Euclidean space E^3" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s = u.dot(v)\n", "s" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field u.v on the Euclidean space E^3\n" ] } ], "source": [ "print(s)" ] }, { "cell_type": "code", "execution_count": 24, "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": 24, "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": 25, "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": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s(p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Its coordinate expression is" ] }, { "cell_type": "code", "execution_count": 26, "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": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s.expr()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Norm\n", "\n", "The norm $\\|u\\|$ of the vector field $u$ is defined in terms\n", "of the dot product by $\\|u\\| = \\sqrt{u\\cdot u}$:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "norm(u) == sqrt(u.dot(u))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is a scalar field on $\\mathbb{E}^3$:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field |u| on the Euclidean space E^3\n" ] } ], "source": [ "s = norm(u)\n", "print(s)" ] }, { "cell_type": "code", "execution_count": 29, "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": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s.display()" ] }, { "cell_type": "code", "execution_count": 30, "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": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s.expr()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For $v$, we have" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "sqrt(x^2 + y^2 + sin(x*y*z)^2)" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "norm(v).expr()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Cross product\n", "\n", "The cross product $u\\times v$ is obtained by the method `cross_product`, which admits `cross` as a shortcut alias:" ] }, { "cell_type": "code", "execution_count": 32, "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": 33, "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": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can check the standard formulas expressing the cross product in terms of\n", "the components:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "all([s[1] == u[2]*v[3] - u[3]*v[2],\n", " s[2] == u[3]*v[1] - u[1]*v[3],\n", " s[3] == u[1]*v[2] - u[2]*v[1]])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Scalar triple product\n", "\n", "Let us introduce a third vector field, $w$ say. 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": 35, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "w = x*z e_x + y*z e_y" ] }, "execution_count": 35, "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": 36, "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": 37, "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": 37, "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": 38, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s == u.dot(v.cross(w))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## How to evaluate the standard 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": 39, "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 some unspecified function of $(x,y,z)$:" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "F: E^3 --> R\n", " (x, y, z) |--> f(x, y, z)" ] }, "execution_count": 40, "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": 41, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "f(3, -2, 1)" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "F(p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The gradient of $F$:" ] }, { "cell_type": "code", "execution_count": 42, "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": 43, "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": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grad(F).display()" ] }, { "cell_type": "code", "execution_count": 44, "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": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "norm(grad(F)).display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Divergence \n", "\n", "The divergence of the vector field $u$:" ] }, { "cell_type": "code", "execution_count": 45, "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": 45, "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": 46, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "x*y*cos(x*y*z)" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "div(v).expr()" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "2*z" ] }, "execution_count": 47, "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": 48, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 48, "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 the vector field $u$:" ] }, { "cell_type": "code", "execution_count": 49, "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": 50, "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": 50, "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": 51, "metadata": {}, "outputs": [], "source": [ "rot = curl" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An alternative is" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [], "source": [ "from sage.manifolds.operators import curl as rot" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We have then" ] }, { "cell_type": "code", "execution_count": 53, "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": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rot(u).display()" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 54, "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": 55, "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": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "curl(v).display()" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "curl(w) = -y e_x + x e_y" ] }, "execution_count": 56, "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": 57, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "curl(grad(F)) = 0" ] }, "execution_count": 57, "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": 58, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "div(curl(u)): E^3 --> R\n", " (x, y, z) |--> 0" ] }, "execution_count": 58, "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$ is\n", "$$ \\mathrm{curl}(Fu) = \\mathrm{grad}\\, F\\times u + F\\, \\mathrm{curl}\\, u, $$\n", "as we can check:" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 59, "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 $\\Delta F$ of a scalar field $F$ is another scalar\n", "field:" ] }, { "cell_type": "code", "execution_count": 60, "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": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s = laplacian(F)\n", "s.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following identity holds:\n", "$$\\Delta F = \\mathrm{div}\\left(\\mathrm{grad}\\, F\\right)$$\n", "as we can check:" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "laplacian(F) == div(grad(F))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Laplacian $\\Delta u$ of a vector field $u$ is another vector field:" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vector field Delta(u) on the Euclidean space E^3\n" ] } ], "source": [ "Du = laplacian(u)\n", "print(Du)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "whose components are" ] }, { "cell_type": "code", "execution_count": 63, "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": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Du.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the Cartesian frame, the components of $\\Delta u$ are nothing but the\n", "(scalar) Laplacians of the components of $u$, as we can check:" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "e = E.cartesian_frame()\n", "Du == 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": 65, "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": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "e[:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For the vector fields $v$ and $w$, we have " ] }, { "cell_type": "code", "execution_count": 66, "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": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "laplacian(v).display()" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Delta(w) = 0" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "laplacian(w).display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We have" ] }, { "cell_type": "code", "execution_count": 68, "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": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "curl(curl(u)).display()" ] }, { "cell_type": "code", "execution_count": 69, "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": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grad(div(u)).display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A famous identity is\n", "\n", "$$ \\mathrm{curl}\\left(\\mathrm{curl}\\, u\\right) =\n", "\\mathrm{grad}\\left(\\mathrm{div}\\, u\\right) - \\Delta u.$$\n", "Let us check it:" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "curl(curl(u)) == grad(div(u)) - laplacian(u)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## How to customize various symbols?\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": 71, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Coordinate frame (E^3, (e_x,e_y,e_z))" ] }, "execution_count": 71, "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": 72, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Coordinate frame (E^3, (a_x,a_y,a_z))" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "frame.set_name('a', indices=('x', 'y', 'z'))\n", "frame" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v = -y a_x + x a_y + sin(x*y*z) a_z" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.display()" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Coordinate frame (E^3, (hx,hy,hz))" ] }, "execution_count": 74, "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": 75, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v = -y hx + x hy + sin(x*y*z) hz" ] }, "execution_count": 75, "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": 76, "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": 77, "metadata": {}, "outputs": [], "source": [ "E. = EuclideanSpace()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We have then:" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[Chart (E^3, (X, Y, Z))]" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "E.atlas()" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Coordinate frame (E^3, (e_X,e_Y,e_Z))" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "E.cartesian_frame()" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v = -Y e_X + X e_Y + sin(X*Y*Z) e_Z" ] }, "execution_count": 80, "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": 81, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[Chart (E^3, (xi, et, ze))]" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "E. = EuclideanSpace(symbols=r\"xi:\\xi et:\\eta ze:\\zeta\")\n", "E.atlas()" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v = -et e_xi + xi e_et + sin(et*xi*ze) e_ze" ] }, "execution_count": 82, "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 9.0", "language": "sage", "name": "sagemath" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }