{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Vector calculus with SageMath\n", "\n", "This worksheet illustrates the operators regarding scalar and vector fields on pseudo-Riemannian manifolds introduced in Trac ticket [#24622](https://trac.sagemath.org/ticket/24622).\n", "\n", "Since SageMath 8.3, it is rather obsolete regarding calculus in Euclidean spaces. See these \n", "[vector calculus examples](https://sagemanifolds.obspm.fr/vector_calculus.html) instead. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'SageMath version 8.2.beta4, Release Date: 2018-01-27'" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "version()" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "%display latex" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from sage.manifolds.operators import * # to get the operators grad, div, curl, etc." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The Euclidean space as a 3-dimensional Riemannian manifold" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "M = Manifold(3, 'M', structure='Riemannian', start_index=1)\n", "X. = M.chart()" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "g = dx*dx + dy*dy + dz*dz" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g = M.metric()\n", "g[1,1], g[2,2], g[3,3] = 1, 1, 1\n", "g.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Gradient of a scalar field" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "F: M --> R\n", " (x, y, z) |--> f(x, y, z)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "F = M.scalar_field(function('f')(x,y,z), name='F')\n", "F.display()" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "grad(F) = d(f)/dx d/dx + d(f)/dy d/dy + d(f)/dz d/dz" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grad(F).display()" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "curl(grad(F)) = 0" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "curl(grad(F)).display()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "|grad(F)|: M --> R\n", " (x, y, z) |--> sqrt((d(f)/dx)^2 + (d(f)/dy)^2 + (d(f)/dz)^2)" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "norm(grad(F)).display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Laplacien of a scalar field" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Delta(F): M --> R\n", " (x, y, z) |--> d^2(f)/dx^2 + d^2(f)/dy^2 + d^2(f)/dz^2" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "laplacian(F).display()" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "laplacian(F) == div(grad(F))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Vector field" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v = v_x(x, y, z) d/dx + v_y(x, y, z) d/dy + v_z(x, y, z) d/dz" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v = M.vector_field(name='v')\n", "v[1] = function('v_x')(x,y,z)\n", "v[2] = function('v_y')(x,y,z)\n", "v[3] = function('v_z')(x,y,z)\n", "v.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In order not to clutter the outputs, we omit the coordinate arguments in the display of chart functions:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "M.options.omit_function_arguments=True" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v = v_x d/dx + v_y d/dy + v_z d/dz" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Norm of a vector field:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field |v| on the 3-dimensional Riemannian manifold M\n" ] } ], "source": [ "s = norm(v)\n", "print(s)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "|v|: M --> R\n", " (x, y, z) |--> sqrt(v_x^2 + v_y^2 + v_z^2)" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Scalar product of two vector fields:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v.grad(F): M --> R\n", " (x, y, z) |--> v_x*d(f)/dx + v_y*d(f)/dy + v_z*d(f)/dz" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.dot(grad(F)).display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cross product of two vector fields:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v x grad(F) = (-v_z*d(f)/dy + v_y*d(f)/dz) d/dx + (v_z*d(f)/dx - v_x*d(f)/dz) d/dy + (-v_y*d(f)/dx + v_x*d(f)/dy) d/dz" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.cross(grad(F)).display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Divergence :" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "div(v): M --> R\n", " (x, y, z) |--> d(v_x)/dx + d(v_y)/dy + d(v_z)/dz" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s = div(v)\n", "s.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Curl:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vector field curl(v) on the 3-dimensional Riemannian manifold M\n" ] } ], "source": [ "w = curl(v)\n", "print(w)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "curl(v) = (-d(v_y)/dz + d(v_z)/dy) d/dx + (d(v_x)/dz - d(v_z)/dx) d/dy + (-d(v_x)/dy + d(v_y)/dx) d/dz" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "w.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To use the notation rot instead of curl, simply do" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "rot = curl" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An alternative is" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "from sage.manifolds.operators import curl as rot" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We have then" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "curl(v) = (-d(v_y)/dz + d(v_z)/dy) d/dx + (d(v_x)/dz - d(v_z)/dx) d/dy + (-d(v_x)/dy + d(v_y)/dx) d/dz" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rot(v).display()" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rot(v) == curl(v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The divergence of a curl is always zero:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "div(curl(v)): M --> R\n", " (x, y, z) |--> 0" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "div(curl(v)).display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Laplacian of a vector field:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Delta(v) = (d^2(v_x)/dx^2 + d^2(v_x)/dy^2 + d^2(v_x)/dz^2) d/dx + (d^2(v_y)/dx^2 + d^2(v_y)/dy^2 + d^2(v_y)/dz^2) d/dy + (d^2(v_z)/dx^2 + d^2(v_z)/dy^2 + d^2(v_z)/dz^2) d/dz" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "laplacian(v).display()" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "curl(curl(v)) = (-d^2(v_x)/dy^2 - d^2(v_x)/dz^2 + d^2(v_y)/dxdy + d^2(v_z)/dxdz) d/dx + (d^2(v_x)/dxdy - d^2(v_y)/dx^2 - d^2(v_y)/dz^2 + d^2(v_z)/dydz) d/dy + (d^2(v_x)/dxdz + d^2(v_y)/dydz - d^2(v_z)/dx^2 - d^2(v_z)/dy^2) d/dz" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "curl(curl(v)).display()" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "grad(div(v)) = (d^2(v_x)/dx^2 + d^2(v_y)/dxdy + d^2(v_z)/dxdz) d/dx + (d^2(v_x)/dxdy + d^2(v_y)/dy^2 + d^2(v_z)/dydz) d/dy + (d^2(v_x)/dxdz + d^2(v_y)/dydz + d^2(v_z)/dz^2) d/dz" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grad(div(v)).display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Check of a famous identity:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "curl(curl(v)) == grad(div(v)) - laplacian(v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Two other identities regarding any scalar field F and any vector field v:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "div(F*v) == F*div(v) + v.dot(grad(F))" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "curl(F*v) == grad(F).cross(v) + F*curl(v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The left-hand side is" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "(v_z*d(f)/dy - v_y*d(f)/dz - f*d(v_y)/dz + f*d(v_z)/dy) d/dx + (-v_z*d(f)/dx + v_x*d(f)/dz + f*d(v_x)/dz - f*d(v_z)/dx) d/dy + (v_y*d(f)/dx - v_x*d(f)/dy - f*d(v_x)/dy + f*d(v_y)/dx) d/dz" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "curl(F*v).display()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "SageMath 8.4.beta6", "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 }