How to compute a gradient, a divergence or a curl¶
This tutorial introduces some vector calculus capabilities of SageMath within the 3-dimensional Euclidean space. The corresponding tools have been developed via the SageManifolds project.
The tutorial is also available as a Jupyter notebook, either
passive (nbviewer
)
or interactive (binder
).
First stage: introduce the Euclidean 3-space¶
Before evaluating some vector-field operators, one needs to define the arena
in which vector fields live, namely the 3-dimensional Euclidean space
EuclideanSpace
:
sage: E.<x,y,z> = EuclideanSpace()
sage: E
Euclidean space E^3
>>> from sage.all import *
>>> E = EuclideanSpace(names=('x', 'y', 'z',)); (x, y, z,) = E._first_ngens(3)
>>> E
Euclidean space E^3
E.<x,y,z> = EuclideanSpace() E
Thanks to the notation <x,y,z>
in the above declaration, the coordinates
x
,
y
and z
(there is no need to declare them via var()
, i.e. to type
x, y, z = var('x y z')
):
sage: x is E.cartesian_coordinates()[1]
True
sage: y is E.cartesian_coordinates()[2]
True
sage: z is E.cartesian_coordinates()[3]
True
sage: type(z)
<class 'sage.symbolic.expression.Expression'>
>>> from sage.all import *
>>> x is E.cartesian_coordinates()[Integer(1)]
True
>>> y is E.cartesian_coordinates()[Integer(2)]
True
>>> z is E.cartesian_coordinates()[Integer(3)]
True
>>> type(z)
<class 'sage.symbolic.expression.Expression'>
x is E.cartesian_coordinates()[1] y is E.cartesian_coordinates()[2] z is E.cartesian_coordinates()[3] type(z)
Besides,
sage: E.frames()
[Coordinate frame (E^3, (e_x,e_y,e_z))]
>>> from sage.all import *
>>> E.frames()
[Coordinate frame (E^3, (e_x,e_y,e_z))]
E.frames()
At this stage, this is the default vector frame on
sage: E.default_frame()
Coordinate frame (E^3, (e_x,e_y,e_z))
>>> from sage.all import *
>>> E.default_frame()
Coordinate frame (E^3, (e_x,e_y,e_z))
E.default_frame()
Defining a vector field¶
We define a vector field on
sage: v = E.vector_field(-y, x, sin(x*y*z), name='v')
sage: v.display()
v = -y e_x + x e_y + sin(x*y*z) e_z
>>> from sage.all import *
>>> v = E.vector_field(-y, x, sin(x*y*z), name='v')
>>> v.display()
v = -y e_x + x e_y + sin(x*y*z) e_z
v = E.vector_field(-y, x, sin(x*y*z), name='v') v.display()
We can access to the components of
sage: v[1]
-y
sage: v[:]
[-y, x, sin(x*y*z)]
>>> from sage.all import *
>>> v[Integer(1)]
-y
>>> v[:]
[-y, x, sin(x*y*z)]
v[1] v[:]
A vector field can evaluated at any point of
sage: p = E((3,-2,1), name='p')
sage: p
Point p on the Euclidean space E^3
sage: p.coordinates()
(3, -2, 1)
sage: vp = v.at(p)
sage: vp
Vector v at Point p on the Euclidean space E^3
sage: vp.display()
v = 2 e_x + 3 e_y - sin(6) e_z
>>> from sage.all import *
>>> p = E((Integer(3),-Integer(2),Integer(1)), name='p')
>>> p
Point p on the Euclidean space E^3
>>> p.coordinates()
(3, -2, 1)
>>> vp = v.at(p)
>>> vp
Vector v at Point p on the Euclidean space E^3
>>> vp.display()
v = 2 e_x + 3 e_y - sin(6) e_z
p = E((3,-2,1), name='p') p p.coordinates() vp = v.at(p) vp vp.display()
Vector fields can be plotted:
sage: v.plot(max_range=1.5, scale=0.5)
Graphics3d Object
>>> from sage.all import *
>>> v.plot(max_range=RealNumber('1.5'), scale=RealNumber('0.5'))
Graphics3d Object
v.plot(max_range=1.5, scale=0.5)
For customizing the plot, see the list of options in the documentation of
plot()
.
For instance, to get a view of the orthogonal projection of
sage: v.plot(fixed_coords={y: 1}, ambient_coords=(x,z), max_range=1.5,
....: scale=0.25)
Graphics object consisting of 81 graphics primitives
>>> from sage.all import *
>>> v.plot(fixed_coords={y: Integer(1)}, ambient_coords=(x,z), max_range=RealNumber('1.5'),
... scale=RealNumber('0.25'))
Graphics object consisting of 81 graphics primitives
v.plot(fixed_coords={y: 1}, ambient_coords=(x,z), max_range=1.5, scale=0.25)
We may define a vector field
sage: u = E.vector_field(function('u_x')(x,y,z),
....: function('u_y')(x,y,z),
....: function('u_z')(x,y,z),
....: name='u')
sage: u.display()
u = u_x(x, y, z) e_x + u_y(x, y, z) e_y + u_z(x, y, z) e_z
sage: u[:]
[u_x(x, y, z), u_y(x, y, z), u_z(x, y, z)]
>>> from sage.all import *
>>> u = E.vector_field(function('u_x')(x,y,z),
... function('u_y')(x,y,z),
... function('u_z')(x,y,z),
... name='u')
>>> u.display()
u = u_x(x, y, z) e_x + u_y(x, y, z) e_y + u_z(x, y, z) e_z
>>> u[:]
[u_x(x, y, z), u_y(x, y, z), u_z(x, y, z)]
u = E.vector_field(function('u_x')(x,y,z), function('u_y')(x,y,z), function('u_z')(x,y,z), name='u') u.display() u[:]
Its value at the point
sage: up = u.at(p)
sage: up.display()
u = u_x(3, -2, 1) e_x + u_y(3, -2, 1) e_y + u_z(3, -2, 1) e_z
>>> from sage.all import *
>>> up = u.at(p)
>>> up.display()
u = u_x(3, -2, 1) e_x + u_y(3, -2, 1) e_y + u_z(3, -2, 1) e_z
up = u.at(p) up.display()
How to compute various vector products¶
Dot product¶
The dot (or scalar) product dot_product()
,
which admits dot()
as a shortcut alias:
sage: u.dot(v) == u[1]*v[1] + u[2]*v[2] + u[3]*v[3]
True
>>> from sage.all import *
>>> u.dot(v) == u[Integer(1)]*v[Integer(1)] + u[Integer(2)]*v[Integer(2)] + u[Integer(3)]*v[Integer(3)]
True
u.dot(v) == u[1]*v[1] + u[2]*v[2] + u[3]*v[3]
sage: s = u.dot(v)
sage: s
Scalar field u.v on the Euclidean space E^3
sage: s.display()
u.v: E^3 → ℝ
(x, y, z) ↦ -y*u_x(x, y, z) + x*u_y(x, y, z) + sin(x*y*z)*u_z(x, y, z)
>>> from sage.all import *
>>> s = u.dot(v)
>>> s
Scalar field u.v on the Euclidean space E^3
>>> s.display()
u.v: E^3 → ℝ
(x, y, z) ↦ -y*u_x(x, y, z) + x*u_y(x, y, z) + sin(x*y*z)*u_z(x, y, z)
s = u.dot(v) s s.display()
It maps points of
sage: s(p)
-sin(6)*u_z(3, -2, 1) + 2*u_x(3, -2, 1) + 3*u_y(3, -2, 1)
>>> from sage.all import *
>>> s(p)
-sin(6)*u_z(3, -2, 1) + 2*u_x(3, -2, 1) + 3*u_y(3, -2, 1)
s(p)
Its coordinate expression is:
sage: s.expr()
-y*u_x(x, y, z) + x*u_y(x, y, z) + sin(x*y*z)*u_z(x, y, z)
>>> from sage.all import *
>>> s.expr()
-y*u_x(x, y, z) + x*u_y(x, y, z) + sin(x*y*z)*u_z(x, y, z)
s.expr()
Norm¶
The norm
sage: norm(u) == sqrt(u.dot(u))
True
>>> from sage.all import *
>>> norm(u) == sqrt(u.dot(u))
True
norm(u) == sqrt(u.dot(u))
It is a scalar field on
sage: s = norm(u)
sage: s
Scalar field |u| on the Euclidean space E^3
sage: s.display()
|u|: E^3 → ℝ
(x, y, z) ↦ sqrt(u_x(x, y, z)^2 + u_y(x, y, z)^2 + u_z(x, y, z)^2)
sage: s.expr()
sqrt(u_x(x, y, z)^2 + u_y(x, y, z)^2 + u_z(x, y, z)^2)
>>> from sage.all import *
>>> s = norm(u)
>>> s
Scalar field |u| on the Euclidean space E^3
>>> s.display()
|u|: E^3 → ℝ
(x, y, z) ↦ sqrt(u_x(x, y, z)^2 + u_y(x, y, z)^2 + u_z(x, y, z)^2)
>>> s.expr()
sqrt(u_x(x, y, z)^2 + u_y(x, y, z)^2 + u_z(x, y, z)^2)
s = norm(u) s s.display() s.expr()
For
sage: norm(v).expr()
sqrt(x^2 + y^2 + sin(x*y*z)^2)
>>> from sage.all import *
>>> norm(v).expr()
sqrt(x^2 + y^2 + sin(x*y*z)^2)
norm(v).expr()
Cross product¶
The cross product cross_product()
,
which admits cross()
as a shortcut alias:
sage: s = u.cross(v)
sage: s
Vector field u x v on the Euclidean space E^3
sage: s.display()
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
>>> from sage.all import *
>>> s = u.cross(v)
>>> s
Vector field u x v on the Euclidean space E^3
>>> s.display()
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
s = u.cross(v) s s.display()
We can check the standard formulas expressing the cross product in terms of the components:
sage: all([s[1] == u[2]*v[3] - u[3]*v[2],
....: s[2] == u[3]*v[1] - u[1]*v[3],
....: s[3] == u[1]*v[2] - u[2]*v[1]])
True
>>> from sage.all import *
>>> all([s[Integer(1)] == u[Integer(2)]*v[Integer(3)] - u[Integer(3)]*v[Integer(2)],
... s[Integer(2)] == u[Integer(3)]*v[Integer(1)] - u[Integer(1)]*v[Integer(3)],
... s[Integer(3)] == u[Integer(1)]*v[Integer(2)] - u[Integer(2)]*v[Integer(1)]])
True
all([s[1] == u[2]*v[3] - u[3]*v[2], s[2] == u[3]*v[1] - u[1]*v[3], s[3] == u[1]*v[2] - u[2]*v[1]])
Scalar triple product¶
Let us introduce a third vector field, vector_field()
,
as we did for
sage: w = E.vector_field(name='w')
sage: w[1] = x*z
sage: w[2] = y*z
sage: w.display()
w = x*z e_x + y*z e_y
>>> from sage.all import *
>>> w = E.vector_field(name='w')
>>> w[Integer(1)] = x*z
>>> w[Integer(2)] = y*z
>>> w.display()
w = x*z e_x + y*z e_y
w = E.vector_field(name='w') w[1] = x*z w[2] = y*z w.display()
The scalar triple product of the vector fields
sage: triple_product = E.scalar_triple_product()
sage: s = triple_product(u, v, w)
sage: s
Scalar field epsilon(u,v,w) on the Euclidean space E^3
sage: s.expr()
-(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
>>> from sage.all import *
>>> triple_product = E.scalar_triple_product()
>>> s = triple_product(u, v, w)
>>> s
Scalar field epsilon(u,v,w) on the Euclidean space E^3
>>> s.expr()
-(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
triple_product = E.scalar_triple_product() s = triple_product(u, v, w) s s.expr()
Let us check that the scalar triple product of
sage: s == u.dot(v.cross(w))
True
>>> from sage.all import *
>>> s == u.dot(v.cross(w))
True
s == u.dot(v.cross(w))
How to evaluate the standard differential operators¶
The standard operators v.div()
). However, to allow for standard mathematical
notations (e.g. div(v)
), let us import the functions
grad()
, div()
,
curl()
and
laplacian()
:
sage: from sage.manifolds.operators import *
>>> from sage.all import *
>>> from sage.manifolds.operators import *
from sage.manifolds.operators import *
Gradient¶
We first introduce a scalar field, via its expression in terms of
Cartesian coordinates; in this example, we consider some unspecified
function of
sage: F = E.scalar_field(function('f')(x,y,z), name='F')
sage: F.display()
F: E^3 → ℝ
(x, y, z) ↦ f(x, y, z)
>>> from sage.all import *
>>> F = E.scalar_field(function('f')(x,y,z), name='F')
>>> F.display()
F: E^3 → ℝ
(x, y, z) ↦ f(x, y, z)
F = E.scalar_field(function('f')(x,y,z), name='F') F.display()
The value of
sage: F(p)
f(3, -2, 1)
>>> from sage.all import *
>>> F(p)
f(3, -2, 1)
F(p)
The gradient of
sage: grad(F)
Vector field grad(F) on the Euclidean space E^3
sage: grad(F).display()
grad(F) = d(f)/dx e_x + d(f)/dy e_y + d(f)/dz e_z
sage: norm(grad(F)).display()
|grad(F)|: E^3 → ℝ
(x, y, z) ↦ sqrt((d(f)/dx)^2 + (d(f)/dy)^2 + (d(f)/dz)^2)
>>> from sage.all import *
>>> grad(F)
Vector field grad(F) on the Euclidean space E^3
>>> grad(F).display()
grad(F) = d(f)/dx e_x + d(f)/dy e_y + d(f)/dz e_z
>>> norm(grad(F)).display()
|grad(F)|: E^3 → ℝ
(x, y, z) ↦ sqrt((d(f)/dx)^2 + (d(f)/dy)^2 + (d(f)/dz)^2)
grad(F) grad(F).display() norm(grad(F)).display()
Divergence¶
The divergence of the vector field
sage: s = div(u)
sage: s.display()
div(u): E^3 → ℝ
(x, y, z) ↦ d(u_x)/dx + d(u_y)/dy + d(u_z)/dz
>>> from sage.all import *
>>> s = div(u)
>>> s.display()
div(u): E^3 → ℝ
(x, y, z) ↦ d(u_x)/dx + d(u_y)/dy + d(u_z)/dz
s = div(u) s.display()
For
sage: div(v).expr()
x*y*cos(x*y*z)
sage: div(w).expr()
2*z
>>> from sage.all import *
>>> div(v).expr()
x*y*cos(x*y*z)
>>> div(w).expr()
2*z
div(v).expr() div(w).expr()
An identity valid for any scalar field
sage: div(F*u) == F*div(u) + u.dot(grad(F))
True
>>> from sage.all import *
>>> div(F*u) == F*div(u) + u.dot(grad(F))
True
div(F*u) == F*div(u) + u.dot(grad(F))
Curl¶
The curl of the vector field
sage: s = curl(u)
sage: s
Vector field curl(u) on the Euclidean space E^3
sage: s.display()
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
>>> from sage.all import *
>>> s = curl(u)
>>> s
Vector field curl(u) on the Euclidean space E^3
>>> s.display()
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
s = curl(u) s s.display()
To use the notation rot
instead of curl
, simply do:
sage: rot = curl
>>> from sage.all import *
>>> rot = curl
rot = curl
An alternative is:
sage: from sage.manifolds.operators import curl as rot
>>> from sage.all import *
>>> from sage.manifolds.operators import curl as rot
from sage.manifolds.operators import curl as rot
We have then:
sage: rot(u).display()
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
sage: rot(u) == curl(u)
True
>>> from sage.all import *
>>> rot(u).display()
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
>>> rot(u) == curl(u)
True
rot(u).display() rot(u) == curl(u)
For
sage: curl(v).display()
curl(v) = x*z*cos(x*y*z) e_x - y*z*cos(x*y*z) e_y + 2 e_z
>>> from sage.all import *
>>> curl(v).display()
curl(v) = x*z*cos(x*y*z) e_x - y*z*cos(x*y*z) e_y + 2 e_z
curl(v).display()
sage: curl(w).display()
curl(w) = -y e_x + x e_y
>>> from sage.all import *
>>> curl(w).display()
curl(w) = -y e_x + x e_y
curl(w).display()
The curl of a gradient is always zero:
sage: curl(grad(F)).display()
curl(grad(F)) = 0
>>> from sage.all import *
>>> curl(grad(F)).display()
curl(grad(F)) = 0
curl(grad(F)).display()
The divergence of a curl is always zero:
sage: div(curl(u)).display()
div(curl(u)): E^3 → ℝ
(x, y, z) ↦ 0
>>> from sage.all import *
>>> div(curl(u)).display()
div(curl(u)): E^3 → ℝ
(x, y, z) ↦ 0
div(curl(u)).display()
An identity valid for any scalar field
as we can check:
sage: curl(F*u) == grad(F).cross(u) + F*curl(u)
True
>>> from sage.all import *
>>> curl(F*u) == grad(F).cross(u) + F*curl(u)
True
curl(F*u) == grad(F).cross(u) + F*curl(u)
Laplacian¶
The Laplacian
sage: s = laplacian(F)
sage: s.display()
Delta(F): E^3 → ℝ
(x, y, z) ↦ d^2(f)/dx^2 + d^2(f)/dy^2 + d^2(f)/dz^2
>>> from sage.all import *
>>> s = laplacian(F)
>>> s.display()
Delta(F): E^3 → ℝ
(x, y, z) ↦ d^2(f)/dx^2 + d^2(f)/dy^2 + d^2(f)/dz^2
s = laplacian(F) s.display()
The following identity holds:
as we can check:
sage: laplacian(F) == div(grad(F))
True
>>> from sage.all import *
>>> laplacian(F) == div(grad(F))
True
laplacian(F) == div(grad(F))
The Laplacian
sage: Du = laplacian(u)
sage: Du
Vector field Delta(u) on the Euclidean space E^3
>>> from sage.all import *
>>> Du = laplacian(u)
>>> Du
Vector field Delta(u) on the Euclidean space E^3
Du = laplacian(u) Du
whose components are:
sage: Du.display()
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
>>> from sage.all import *
>>> Du.display()
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
Du.display()
In the Cartesian frame, the components of
sage: e = E.cartesian_frame()
sage: Du == sum(laplacian(u[[i]])*e[i] for i in E.irange())
True
>>> from sage.all import *
>>> e = E.cartesian_frame()
>>> Du == sum(laplacian(u[[i]])*e[i] for i in E.irange())
True
e = E.cartesian_frame() Du == sum(laplacian(u[[i]])*e[i] for i in E.irange())
In the above formula, u[[i]]
return the u[i]
would have returned the coordinate expression of
this scalar field; besides, e
is the Cartesian frame:
sage: e[:]
(Vector field e_x on the Euclidean space E^3,
Vector field e_y on the Euclidean space E^3,
Vector field e_z on the Euclidean space E^3)
>>> from sage.all import *
>>> e[:]
(Vector field e_x on the Euclidean space E^3,
Vector field e_y on the Euclidean space E^3,
Vector field e_z on the Euclidean space E^3)
e[:]
For the vector fields
sage: laplacian(v).display()
Delta(v) = -(x^2*y^2 + (x^2 + y^2)*z^2)*sin(x*y*z) e_z
sage: laplacian(w).display()
Delta(w) = 0
>>> from sage.all import *
>>> laplacian(v).display()
Delta(v) = -(x^2*y^2 + (x^2 + y^2)*z^2)*sin(x*y*z) e_z
>>> laplacian(w).display()
Delta(w) = 0
laplacian(v).display() laplacian(w).display()
We have:
sage: curl(curl(u)).display()
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
sage: grad(div(u)).display()
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
>>> from sage.all import *
>>> curl(curl(u)).display()
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
>>> grad(div(u)).display()
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
curl(curl(u)).display() grad(div(u)).display()
A famous identity is
Let us check it:
sage: curl(curl(u)) == grad(div(u)) - laplacian(u)
True
>>> from sage.all import *
>>> curl(curl(u)) == grad(div(u)) - laplacian(u)
True
curl(curl(u)) == grad(div(u)) - laplacian(u)
How to customize various symbols¶
Customizing the symbols of the orthonormal frame vectors¶
By default, the vectors of the orthonormal frame associated with Cartesian
coordinates are denoted
sage: frame = E.cartesian_frame()
sage: frame
Coordinate frame (E^3, (e_x,e_y,e_z))
>>> from sage.all import *
>>> frame = E.cartesian_frame()
>>> frame
Coordinate frame (E^3, (e_x,e_y,e_z))
frame = E.cartesian_frame() frame
But this can be changed, thanks to the method
set_name()
:
sage: frame.set_name('a', indices=('x', 'y', 'z'))
sage: frame
Coordinate frame (E^3, (a_x,a_y,a_z))
sage: v.display()
v = -y a_x + x a_y + sin(x*y*z) a_z
>>> from sage.all import *
>>> frame.set_name('a', indices=('x', 'y', 'z'))
>>> frame
Coordinate frame (E^3, (a_x,a_y,a_z))
>>> v.display()
v = -y a_x + x a_y + sin(x*y*z) a_z
frame.set_name('a', indices=('x', 'y', 'z')) frame v.display()
sage: frame.set_name(('hx', 'hy', 'hz'),
....: latex_symbol=(r'\mathbf{\hat{x}}', r'\mathbf{\hat{y}}',
....: r'\mathbf{\hat{z}}'))
sage: frame
Coordinate frame (E^3, (hx,hy,hz))
sage: v.display()
v = -y hx + x hy + sin(x*y*z) hz
>>> from sage.all import *
>>> frame.set_name(('hx', 'hy', 'hz'),
... latex_symbol=(r'\mathbf{\hat{x}}', r'\mathbf{\hat{y}}',
... r'\mathbf{\hat{z}}'))
>>> frame
Coordinate frame (E^3, (hx,hy,hz))
>>> v.display()
v = -y hx + x hy + sin(x*y*z) hz
frame.set_name(('hx', 'hy', 'hz'), latex_symbol=(r'\mathbf{\hat{x}}', r'\mathbf{\hat{y}}', r'\mathbf{\hat{z}}')) frame v.display()
Customizing the coordinate symbols¶
The coordinates symbols are defined within the angle brackets <...>
at the
construction of the Euclidean space. Above we did:
sage: E.<x,y,z> = EuclideanSpace()
>>> from sage.all import *
>>> E = EuclideanSpace(names=('x', 'y', 'z',)); (x, y, z,) = E._first_ngens(3)
E.<x,y,z> = EuclideanSpace()
which resulted in the coordinate symbols x
, y
and z
(SageMath symbolic expressions). To
use other symbols, for instance E
as:
sage: E.<X,Y,Z> = EuclideanSpace()
>>> from sage.all import *
>>> E = EuclideanSpace(names=('X', 'Y', 'Z',)); (X, Y, Z,) = E._first_ngens(3)
E.<X,Y,Z> = EuclideanSpace()
We have then:
sage: E.atlas()
[Chart (E^3, (X, Y, Z))]
sage: E.cartesian_frame()
Coordinate frame (E^3, (e_X,e_Y,e_Z))
sage: v = E.vector_field(-Y, X, sin(X*Y*Z), name='v')
sage: v.display()
v = -Y e_X + X e_Y + sin(X*Y*Z) e_Z
>>> from sage.all import *
>>> E.atlas()
[Chart (E^3, (X, Y, Z))]
>>> E.cartesian_frame()
Coordinate frame (E^3, (e_X,e_Y,e_Z))
>>> v = E.vector_field(-Y, X, sin(X*Y*Z), name='v')
>>> v.display()
v = -Y e_X + X e_Y + sin(X*Y*Z) e_Z
E.atlas() E.cartesian_frame() v = E.vector_field(-Y, X, sin(X*Y*Z), name='v') v.display()
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
(:
):
sage: E.<xi,et,ze> = EuclideanSpace(symbols=r"xi:\xi et:\eta ze:\zeta")
sage: E.atlas()
[Chart (E^3, (xi, et, ze))]
sage: v = E.vector_field(-et, xi, sin(xi*et*ze), name='v')
sage: v.display()
v = -et e_xi + xi e_et + sin(et*xi*ze) e_ze
>>> from sage.all import *
>>> E = EuclideanSpace(symbols=r"xi:\xi et:\eta ze:\zeta", names=('xi', 'et', 'ze',)); (xi, et, ze,) = E._first_ngens(3)
>>> E.atlas()
[Chart (E^3, (xi, et, ze))]
>>> v = E.vector_field(-et, xi, sin(xi*et*ze), name='v')
>>> v.display()
v = -et e_xi + xi e_et + sin(et*xi*ze) e_ze
E.<xi,et,ze> = EuclideanSpace(symbols=r"xi:\xi et:\eta ze:\zeta") E.atlas() v = E.vector_field(-et, xi, sin(xi*et*ze), name='v') v.display()